diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 7729845a464..28ba75bfd2b 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,7 +2,7 @@ "build": { "dockerfile": "Dockerfile", "args": { - "GEOS_TPL_TAG": "256-147" + "GEOS_TPL_TAG": "288-584" } }, "runArgs": [ diff --git a/.devcontainer/postCreateCommand.sh b/.devcontainer/postCreateCommand.sh index 7267acb2d1d..b2ad6cbf9e0 100755 --- a/.devcontainer/postCreateCommand.sh +++ b/.devcontainer/postCreateCommand.sh @@ -2,5 +2,6 @@ /usr/bin/ln -s /workspaces/GEOS/.vscode-codespaces /workspaces/GEOS/.vscode # Activate the appropriate submodules git submodule init -git submodule deinit integratedTests git submodule update +# Load the pretty printer for LvArray +echo "source /workspaces/GEOS/src/coreComponents/LvArray/scripts/gdb-printers-shallow.py" > ~/.gdbinit diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000000..58e544196ff --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,179 @@ + + + +# These owners will be the default owners for everything in +# the repo. Unless a later match takes precedence, +# @global-owner1 and @global-owner2 will be requested for +# review when someone opens a pull request. +* @rrsettgast + +/.github/ @rrsettgast + +/BASELINE_NOTES.md +/.integrated_tests.yaml @rrsettgast @CusiniM @cssherman @wrtobin @castelletto1 @jhuang2601 @paveltomin +/inputFiles @rrsettgast @CusiniM @cssherman @paveltomin @jhuang2601 +/inputFiles/compositionalMultiphaseFlow @paveltomin @dkachuma +/inputFiles/compositionalMultiphaseWell @CusiniM @paveltomin @tjb-ltk @dkachuma +/inputFiles/efemFractureMechanics @CusiniM @matteofrigo5 @Guotong-Ren +/inputFiles/hydraulicFracturing @CusiniM @rrsettgast @frankfeifan @Guotong-Ren @cssherman @jhuang2601 +/inputFiles/inducedSeismicity @CusiniM @matteofrigo5 @VidarStiernstrom +/inputFiles/initialization @rrsettgast @jhuang2601 +/inputFiles/lagrangianContactMechanics @CusiniM @jhuang2601 @matteofrigo5 +/inputFiles/materialPointMethod @homel1 @cmcrook5 +/inputFiles/meshGeneration @rrsettgast @cssherman +/inputFiles/multiphaseFlowFractures @CusiniM @paveltomin @jhuang2601 +/inputFiles/multipleMeshBodies @rrsettgast @wrtobin +/inputFiles/phaseField @CusiniM @frankfeifan +/inputFiles/poromechanics @CusiniM @castelletto1 @paveltomin @jhuang2601 @ryar9534 +/inputFiles/poromechanicsFractures @CusiniM @castelletto1 @paveltomin @jhuang2601 +/inputFiles/proppant @rrsettgast @jhuang2601 +/inputFiles/relpermDriver @dkachuma @paveltomin @jafranc +/inputFiles/simplePDE @rrsettgast @castelletto1 +/inputFiles/singlePhaseFlow @CusiniM @castelletto1 @paveltomin +/inputFiles/singlePhaseFlowFractures @CusiniM @castelletto1 @paveltomin @jhuang2601 +/inputFiles/singlePhaseWell @CusiniM @paveltomin @tjb-ltk +/inputFiles/solidMechanics @CusiniM @castelletto1 @jhuang2601 +/inputFiles/surfaceGeneration @CusiniM @castelletto1 @rrsettgast +/inputFiles/thermalMultiphaseFlow @paveltomin @dkachuma +/inputFiles/thermalSinglePhaseFlowFractures @CusiniM @castelletto1 @paveltomin @jhuang2601 @frankfeifan +/inputFiles/thermoPoromechanics @paveltomin @jhuang2601 @castelletto1 @frankfeifan +/inputFiles/thermoPoromechanicsFractures @CusiniM @castelletto1 @paveltomin @jhuang2601 +/inputFiles/triaxialDriver @rrsettgast @jhuang2601 +/inputFiles/wavePropagation @acitrain @sframba +/inputFiles/wellbore @rrsettgast @jhuang2601 +/inputFiles/wellboreECP @rrsettgast +/src/coreComponents/LvArray @rrsettgast @CusiniM @wrtobin @corbett5 +/src/coreComponents/codingUtilities @rrsettgast @untereiner @corbett5 @wrtobin @MelReyCG +/src/coreComponents/common @rrsettgast @MelReyCG @corbett5 @wrtobin +/src/coreComponents/constitutive @rrsettgast @CusiniM @dkachuma @paveltomin @castelletto1 +/src/coreComponents/constitutive/capillaryPressure @CusiniM @dkachuma @paveltomin +/src/coreComponents/constitutive/contact @rrsettgast @CusiniM @matteofrigo5 @Guotong-Ren @jhuang2601 +/src/coreComponents/constitutive/diffusion @CusiniM @dkachuma @paveltomin +/src/coreComponents/constitutive/dispersion @CusiniM @dkachuma @paveltomin +/src/coreComponents/constitutive/docs +/src/coreComponents/constitutive/fluid @CusiniM @dkachuma @paveltomin +/src/coreComponents/constitutive/permeability @CusiniM @dkachuma @paveltomin @jhuang2601 +/src/coreComponents/constitutive/pvtPackage @CusiniM @dkachuma @paveltomin +/src/coreComponents/constitutive/relativePermeability @dkachuma @paveltomin +/src/coreComponents/constitutive/solid @rrsettgast @CusiniM @paveltomin @castelletto1 @jhuang2601 +/src/coreComponents/constitutive/thermalConductivity @CusiniM @dkachuma @paveltomin @jhuang2601 +/src/coreComponents/constitutive/unitTests @rrsettgast @CusiniM @dkachuma @paveltomin +/src/coreComponents/constitutiveDrivers @rrsettgast @CusiniM @dkachuma @jhuang2601 +/src/coreComponents/dataRepository @rrsettgast @wrtobin @corbett5 @MelReyCG +/src/coreComponents/denseLinearAlgebra @rrsettgast @CusiniM @castelletto1 +/src/coreComponents/discretizationMethods @rrsettgast @CusiniM @castelletto1 +/src/coreComponents/events @rrsettgast @corbett5 @cssherman +/src/coreComponents/fieldSpecification @rrsettgast @CusiniM @corbett5 @cssherman +/src/coreComponents/fileIO @rrsettgast @wrtobin @MelReyCG @untereiner +/src/coreComponents/finiteElement @rrsettgast @castelletto1 @andrea-borio @CusiniM +/src/coreComponents/finiteVolume @rrsettgast @castelletto1 @CusiniM @paveltomin @ryar9534 +/src/coreComponents/functions @rrsettgast @cssherman @wrtobin +/src/coreComponents/linearAlgebra @rrsettgast @CusiniM @castelletto1 @victorapm +/src/coreComponents/mainInterface @rrsettgast @corbett5 @wrtobin +/src/coreComponents/math @rrsettgast @corbett5 @wrtobin +/src/coreComponents/mesh @rrsettgast @CusiniM @wrtobin @untereiner +/src/coreComponents/physicsSolvers @rrsettgast @CusiniM +/src/coreComponents/physicsSolvers/contact @rrsettgast @CusiniM @matteofrigo5 @Guotong-Ren +/src/coreComponents/physicsSolvers/fluidFlow @CusiniM @paveltomin @ryar9534 +/src/coreComponents/physicsSolvers/inducedSeismicity @rrsettgast @CusiniM @matteofrigo5 @VidarStiernstrom +/src/coreComponents/physicsSolvers/multiphysics @rrsettgast @CusiniM @paveltomin @castelletto1 @frankfeifan @ryar9534 @jhuang2601 +/src/coreComponents/physicsSolvers/python @cssherman @corbett5 @alexbenedicto +/src/coreComponents/physicsSolvers/simplePDE @CusiniM @castelletto1 @rrsettgast @frankfeifan +/src/coreComponents/physicsSolvers/solidMechanics @rrsettgast @CusiniM @castelletto1 @jhuang2601 +/src/coreComponents/physicsSolvers/surfaceGeneration @rrsettgast @CusiniM @jhuang2601 +/src/coreComponents/physicsSolvers/wavePropagation @sframba @acitrain +/src/coreComponents/schema +/src/coreComponents/unitTests @rrsettgast @CusiniM @corbett5 @wrtobin + +# Here is a list of GEOS-DEV members as of 2024-07-02 +# username name +# acitrain +# aguitton +# AL0230162 Éric Cassagnard +# Algiane Algiane Froehly +# andrea-borio Andrea Borio +# andrea-francesch Andrea Franceschini +# annavarapusr1 +# AntoineMazuyer Antoine Mazuyer +# arng40 Arnaud DUDES +# Bertbk Bertrand Thierry +# binw1 +# bmhan12 Brian Han +# Bubusch Gaetan +# castelletto1 Nicola Castelletto +# chakshinglee Chak Shing Lee +# cmcrook5 +# cmorency1 Christina Morency +# corbett5 Ben Corbett +# cssherman Christopher Sherman +# CusiniM Matteo Cusini +# dkachuma Dickson Kachuma +# drmichaeltcvx Michael E. Thomadakis +# estelledirand Estelle Dirand +# francoishamon Francois Hamon +# frankfeifan +# fuyuli123456 Fuyu Li +# geosxCI +# Guotong-Ren Guotong +# henricalandra64 +# herve-gross Herve Gross +# homel1 Michael Homel +# IsaacJu-debug Isaac Ju +# jafranc Jacques Franc +# jameshcorbett James Corbett +# Jay-A Jay Appleton +# jeannepellerin Jeanne Pellerin +# jedbrown Jed Brown +# jessielu001 +# jhuang2601 Jian Huang +# jiemeng-total +# jiyer28 +# jkwashbourne John Washbourne +# johnbowen42 John Bowen +# joshua-white Joshua White +# jschen83 Jinsong Chen +# juliat-camargo +# karimifard Mohammad Karimi-Fard +# kimtaeho07 +# klevzoff Sergey Klevtsov +# ktnihei Kurt Nihei +# labesse40 +# matteofrigo5 Matteo Frigo +# MatthiasCremon Matthias Cremon +# MelReyCG +# MichaelSekachev Michael Sekachev +# mndiaye24 Mamadou N'diaye +# npillardou Nicolas Pillardou +# ol-n-ga +# oseikuffuor1 Daniel Osei-Kuffuor +# ouassimkh +# paloma-martinez +# paveltomin Pavel Tomin +# philippeVerney Philippe Verney +# raminammour Rami +# rasimHZ +# rmadec-cs Ronan Madec +# rrsettgast Randolph Settgast +# ryanhaagenson Ryan Haagenson +# ryar9534 Ryan Aronson +# samtkaplan Sam Kaplan +# samuelpmishLLNL +# sframba Stefano Frambati +# shabnamjs +# sohailwaziri +# sytuannguyen Sy-Tuan Nguyen +# tang39 Hewei Tang +# tbeltzun +# TheLastBlockbend Phillip Chacon +# tjb-ltk Tom Byer +# TNemethCVX +# TotoGaz TotoGaz +# txlx +# untereiner Lionel Untereiner +# victorapm Victor A. P. Magri +# VidarStiernstrom Vidar Stiernström +# wcy41gtc Chaoyi Wang +# wrtobin William R Tobin +# yue-2018 Yue Hao +# yylicvx +# zhishuaizhang Zhishuai Zhang diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index ab76d9288e3..b34012e1d8d 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -27,7 +27,7 @@ If applicable, add screenshots to help explain your problem. **Platform (please complete the following information):** - Machine [e.g. LLNL/Quartz] - Compiler: [e.g. gcc 8.1.0] -- GEOSX Version [e.g. 0.2] +- GEOS Version [e.g. 0.2] **Additional context** Add any other context about the problem here. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..7e248436149 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 +updates: +- package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + groups: + # open a single pull-request for all GitHub actions updates + github-actions: + patterns: + - '*' \ No newline at end of file diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 2da2c18ea9b..970fb02d01f 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -5,10 +5,17 @@ on: BUILD_AND_TEST_CLI_ARGS: required: false type: string + BUILD_SHARED_LIBS: + required: false + type: string + default: 'ON' BUILD_TYPE: required: false type: string default: build + DOCKER_CERTS_UPDATE_COMMAND: + required: false + type: string CMAKE_BUILD_TYPE: required: true type: string @@ -16,6 +23,10 @@ on: required: false type: boolean default: false + DOCKER_CERTS_DIR: + required: false + type: string + default: '' DOCKER_IMAGE_TAG: required: true type: string @@ -40,6 +51,13 @@ on: HOST_CONFIG: required: false type: string + NPROC: + required: false + type: string + default: '' + HOST_ARCH: + required: false + type: string RUNS_ON: required: true type: string @@ -47,6 +65,16 @@ on: required: false type: boolean default: true + REQUIRED_LABEL: + required: false + type: string + LOCAL_BASELINE_DIR: + required: false + type: string + BUILD_GENERATOR: + required: false + type: string + default: '--ninja' secrets: GOOGLE_CLOUD_GCP: required: false @@ -54,8 +82,28 @@ jobs: build_test_deploy: runs-on: ${{ inputs.RUNS_ON }} steps: + - name: does_pr_have_necessary_labels + if: ${{inputs.REQUIRED_LABEL && github.event_name == 'pull_request'}} + run: | + pr_json=$(curl -H "Accept: application/vnd.github+json" https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.number }}) + LABELS=$(echo ${pr_json} | jq -crM '[.labels[].name]') + echo " the labels are ${LABELS}" + echo " the required label is ${{inputs.REQUIRED_LABEL}}" + if [[ "${LABELS}" != *"${{inputs.REQUIRED_LABEL}}"* ]]; then + exit 1 + fi + + - name: 'Cleanup build folder' + run: | + pwd + echo "cleaning ${GITHUB_WORKSPACE}" + ls -la ./ + rm -rf ./* ./.*|| true + echo "expecting ${GITHUB_WORKSPACE} to be empty" + ls -la ./ + - name: Checkout Repository - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.2 with: submodules: true lfs: ${{ inputs.BUILD_TYPE == 'integrated_tests' }} @@ -63,20 +111,26 @@ jobs: - id: 'auth' if: ${{ inputs.GCP_BUCKET || inputs.USE_SCCACHE }} - uses: 'google-github-actions/auth@v2.1.0' + uses: 'google-github-actions/auth@v2.1.7' with: credentials_json: '${{ secrets.GOOGLE_CLOUD_GCP }}' create_credentials_file: true - name: 'Set up Cloud SDK' if: inputs.GCP_BUCKET - uses: 'google-github-actions/setup-gcloud@v2.1.0' + uses: 'google-github-actions/setup-gcloud@v2.1.2' with: version: '>= 363.0.0' - name: Print environment run: printenv + - name: Setup QEMU for ${{ inputs.HOST_ARCH }} emulation + if: ${{ inputs.HOST_ARCH }} + uses: docker/setup-qemu-action@v3 + with: + platforms: ${{ inputs.HOST_ARCH }} + - name: Build, test, deploy. run: | # Those two bash arrays will be populated depending on the required options, @@ -84,18 +138,35 @@ jobs: docker_args=() script_args=() + if [[ -n "${{ inputs.DOCKER_CERTS_DIR }}" ]]; then + DOCKER_CERTS_DIR=${{ inputs.DOCKER_CERTS_DIR }} + docker_args+=(-e DOCKER_CERTS_DIR=${DOCKER_CERTS_DIR}) + fi + + if [[ -n "${{ inputs.DOCKER_CERTS_UPDATE_COMMAND }}" ]]; then + DOCKER_CERTS_UPDATE_COMMAND=${{ inputs.DOCKER_CERTS_UPDATE_COMMAND }} + docker_args+=(-e DOCKER_CERTS_UPDATE_COMMAND=${DOCKER_CERTS_UPDATE_COMMAND}) + fi + + if [[ -n "${{ inputs.NPROC }}" ]]; then + NPROC=${{ inputs.NPROC }} + script_args+=(--nproc ${NPROC}) + fi + if [[ -n "${{ inputs.BUILD_GENERATOR }}" ]]; then + script_args+=(${{ inputs.BUILD_GENERATOR }}) + fi docker_args+=(${{ inputs.DOCKER_RUN_ARGS }}) COMMIT=${{ github.event.pull_request.head.sha }} SHORT_COMMIT=${COMMIT:0:7} - script_args+=(--install-dir-basename GEOSX-${SHORT_COMMIT}) + script_args+=(--install-dir-basename GEOS-${SHORT_COMMIT}) - # All the data exchanged with the docker container is eventually meant to be send to the cloud. + # All the data exchanged with the docker container is eventually meant to be sent to the cloud. if [[ ! -z "${{ inputs.GCP_BUCKET }}" ]]; then if [ "${{ inputs.BUILD_TYPE }}" = "build" ]; then - DATA_BASENAME=GEOSX-and-TPL-${SHORT_COMMIT}.tar.gz + DATA_BASENAME=GEOS-and-TPL-${SHORT_COMMIT}.tar.gz elif [ "${{ inputs.BUILD_TYPE }}" = "integrated_tests" ]; then DATA_BASENAME=integratedTests-pr${{ github.event.number }}-${{ github.run_number }}-${SHORT_COMMIT}.tar.gz script_args+=(--run-integrated-tests) @@ -103,9 +174,9 @@ jobs: script_args+=(--data-basename ${DATA_BASENAME}) - DATA_EXCHANGE_DIR=/mnt/geos-exchange # Exchange folder outside of the container + DATA_EXCHANGE_DIR=${GITHUB_WORKSPACE}/geos-exchange # Exchange folder outside of the container if [ ! -d "${DATA_EXCHANGE_DIR}" ]; then - sudo mkdir -p ${DATA_EXCHANGE_DIR} + mkdir -p ${DATA_EXCHANGE_DIR} fi DATA_EXCHANGE_MOUNT_POINT=/tmp/exchange # Exchange folder inside of the container docker_args+=(--volume=${DATA_EXCHANGE_DIR}:${DATA_EXCHANGE_MOUNT_POINT}) @@ -119,11 +190,6 @@ jobs: script_args+=(--sccache-credentials $(basename ${GOOGLE_GHA_CREDS_PATH})) fi - if [ ${{ inputs.RUNS_ON }} == 'self-hosted' ]; then - RUNNER_CERTIFICATES_DIR=/etc/pki/ca-trust/source/anchors/ - mkdir -p ${GITHUB_WORKSPACE}/certificates - cp ${RUNNER_CERTIFICATES_DIR}/*.crt* ${GITHUB_WORKSPACE}/certificates - fi # We need to know where the code folder is mounted inside the container so we can run the script at the proper location! # Since this information is repeated twice, we use a variable. GITHUB_WORKSPACE_MOUNT_POINT=/tmp/geos @@ -139,13 +205,15 @@ jobs: docker_args+=(-e ENABLE_HYPRE=${ENABLE_HYPRE:-OFF}) docker_args+=(-e ENABLE_HYPRE_DEVICE=${ENABLE_HYPRE_DEVICE:-CPU}) docker_args+=(-e ENABLE_TRILINOS=${ENABLE_TRILINOS:-ON}) + docker_args+=(-e GEOS_BUILD_SHARED_LIBS=${{ inputs.BUILD_SHARED_LIBS }}) docker_args+=(--cap-add=SYS_PTRACE --rm) script_args+=(--cmake-build-type ${{ inputs.CMAKE_BUILD_TYPE }}) script_args+=(${{ inputs.BUILD_AND_TEST_CLI_ARGS }}) - + + DOCKER_REPOSITORY=${{ inputs.DOCKER_REPOSITORY }} SPLIT_DOCKER_REPOSITORY=(${DOCKER_REPOSITORY//// }) CONTAINER_NAME=geosx_build_${SPLIT_DOCKER_REPOSITORY[1]}_${GITHUB_SHA:0:7} echo "CONTAINER_NAME: ${CONTAINER_NAME}" @@ -159,6 +227,53 @@ jobs: script_args+=(--code-coverage) fi + if [[ -n "${{ inputs.LOCAL_BASELINE_DIR }}" ]]; then + # Extract the 'baseline' value + + # Define the path to the YAML file + YAML_FILE_PATH="${GITHUB_WORKSPACE}/.integrated_tests.yaml" + + # Verify the YAML file path + if [[ ! -f "${YAML_FILE_PATH}" ]]; then + echo "Error: File $YAML_FILE_PATH does not exist." + else + echo "Found integratedTests file: $YAML_FILE_PATH." + fi + + # Extract the baseline field + BASELINE_FULL_PATH=$(grep -A 2 'baselines:' "${YAML_FILE_PATH}" | grep 'baseline:' | awk '{print $2}') + + # Remove the 'integratedTests/' prefix + BASELINE_TAG=${BASELINE_FULL_PATH#integratedTests/} + echo "Baseline: ${BASELINE_TAG}" + + # Extract the folder name + PR_NUMBER=$(echo "$BASELINE_TAG" | grep -o 'pr[0-9]*') + PR_BASELINE_FOLDER_NAME=baselines_${PR_NUMBER} + echo "Baseline folder name: ${PR_BASELINE_FOLDER_NAME}" + + CURRENT_BASELINE_DIR=${{ inputs.LOCAL_BASELINE_DIR }}/${PR_BASELINE_FOLDER_NAME} + echo "Current baseline dir: ${CURRENT_BASELINE_DIR}" + + if [ -d ${CURRENT_BASELINE_DIR} ];then + echo "Current baseline dir found." + ls -l ${CURRENT_BASELINE_DIR} + + # We defined a mount point and mount it read-only inside the container. + CURRENT_BASELINE_DIR_MOUNT=/tmp/geos/baselines + docker_args+=(--volume=${CURRENT_BASELINE_DIR}:${CURRENT_BASELINE_DIR_MOUNT}:ro) + else + echo "Current baselines directory (${CURRENT_BASELINE_DIR}) not found" + fi + fi + + echo running "docker run \ + ${docker_args[@]} \ + -h=`hostname` \ + ${{ inputs.DOCKER_REPOSITORY }}:${{ inputs.DOCKER_IMAGE_TAG }} \ + ${GITHUB_WORKSPACE_MOUNT_POINT}/scripts/ci_build_and_test_in_container.sh \ + ${script_args[@]}" + # In case of integrated tests run, we still want to send the results to the cloud for inspection. # While for standard build (if even possible), pushing a failed build would be pointless. # GHA set `-e` to bash scripts by default to fail asap, @@ -169,7 +284,7 @@ jobs: -h=`hostname` \ ${{ inputs.DOCKER_REPOSITORY }}:${{ inputs.DOCKER_IMAGE_TAG }} \ ${GITHUB_WORKSPACE_MOUNT_POINT}/scripts/ci_build_and_test_in_container.sh \ - ${script_args[@]} + ${script_args[@]} EXIT_STATUS=$? echo "Received exit status ${EXIT_STATUS} from the build process." set -e @@ -177,23 +292,60 @@ jobs: # Send to the bucket and print the download link when it makes sense. if [[ ! -z "${{ inputs.GCP_BUCKET }}" ]]; then if [[ "${{ inputs.BUILD_TYPE }}" = "integrated_tests" || ${EXIT_STATUS} -eq 0 ]]; then - CLOUDSDK_PYTHON=python3 gsutil cp -a public-read ${DATA_EXCHANGE_DIR}/${DATA_BASENAME} gs://${{ inputs.GCP_BUCKET }}/ - echo "Download the bundle at https://storage.googleapis.com/${{ inputs.GCP_BUCKET }}/${DATA_BASENAME}" + if [ -f ${DATA_EXCHANGE_DIR}/${DATA_BASENAME} ]; then + CLOUDSDK_PYTHON=python3 gsutil cp -a public-read ${DATA_EXCHANGE_DIR}/${DATA_BASENAME} gs://${{ inputs.GCP_BUCKET }}/ + echo "Download the bundle at https://storage.googleapis.com/${{ inputs.GCP_BUCKET }}/${DATA_BASENAME}" + fi + + if [ -f ${DATA_EXCHANGE_DIR}/test_logs_${DATA_BASENAME} ]; then + CLOUDSDK_PYTHON=python3 gsutil cp -a public-read ${DATA_EXCHANGE_DIR}/test_logs_${DATA_BASENAME} gs://${{ inputs.GCP_BUCKET }}/ + echo "Download integrated test logs here: https://storage.googleapis.com/${{ inputs.GCP_BUCKET }}/test_logs_${DATA_BASENAME}" + fi + + if [ -f ${DATA_EXCHANGE_DIR}/baseline_${DATA_BASENAME} ];then + + if [[ -n "${{ inputs.LOCAL_BASELINE_DIR }}" ]]; then + # 1. We copy the baselines to a local directory to store them + + # 1.a Create the new target directory to store the new baselines + THIS_PR_NUMBER=pr${{ github.event.number }} + NEW_PR_BASELINE_FOLDER_NAME=baselines_${THIS_PR_NUMBER} + TARGET_DIR="${{ inputs.LOCAL_BASELINE_DIR }}/${NEW_PR_BASELINE_FOLDER_NAME}" + echo "Create folder ${TARGET_DIR}" + mkdir -p "${TARGET_DIR}" + + # 1.b We copy the new baselines to the new target directory + SOURCE_FILE="${DATA_EXCHANGE_DIR}/baseline_${DATA_BASENAME}" + echo "Copy ${SOURCE_FILE} to ${TARGET_DIR}" + cp "${SOURCE_FILE}" "${TARGET_DIR}" + fi + + # 2. We push the baselines to the cloud + CLOUDSDK_PYTHON=python3 gsutil cp -a public-read ${DATA_EXCHANGE_DIR}/baseline_${DATA_BASENAME} gs://${{ inputs.GCP_BUCKET }}/ + echo "Download test baselines here: https://storage.googleapis.com/${{ inputs.GCP_BUCKET }}/baseline_${DATA_BASENAME}" + echo "New baseline ID: baseline_${DATA_BASENAME::-7}" + else + echo "Baselines ${DATA_EXCHANGE_DIR}/baseline_${DATA_BASENAME} were not uploaded. Likeyly because no rebaseline was necessary." + fi fi fi - # Remove the container and the workspace to avoid any conflict with the next run. - echo github.workspace = ${{ github.workspace }} - #rm -rf ${{ github.workspace }}/* - #docker rm -f ${CONTAINER_NAME} - exit ${EXIT_STATUS} - name: Upload coverage to Codecov if: inputs.CODE_COVERAGE - uses: codecov/codecov-action@v4.0.1 + uses: codecov/codecov-action@v4.6.0 with: - files: geos_coverage.info.cleaned + files: ${GITHUB_WORKSPACE}/geos_coverage.info.cleaned fail_ci_if_error: true env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + - name: 'Cleanup build folder' + run: | + pwd + echo "cleaning ${GITHUB_WORKSPACE}" + ls -la ./ + rm -rf ./* ./.*|| true + echo "expecting ${GITHUB_WORKSPACE} to be empty" + ls -la ./ diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index 46b45151698..32d77b0cc5e 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -5,6 +5,7 @@ on: branches: - develop pull_request: + types: [opened, synchronize, reopened] workflow_dispatch: # Cancels in-progress workflows for a PR when updated @@ -15,15 +16,41 @@ concurrency: # Please define `build.args.GEOS_TPL_TAG` in `.devcontainer/devcontainer.json` jobs: + # Checks if PR title follows conventional semantics + semantic_pull_request: + permissions: + pull-requests: write # for amannn/action-semantic-pull-request to analyze PRs and + statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR + contents: read + runs-on: ubuntu-latest + + steps: + - name: Check if the PR name has conventional semantics + if: github.event_name == 'pull_request' + uses: amannn/action-semantic-pull-request@v5.5.3 + id: lint_pr_title + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + wip: true + # Configure that a scope doesn't need to be provided. + requireScope: false + + - name: Skip the check on develop branch + if: github.ref_name == 'develop' + run: | + echo "This in't a Pull-Request, skipping" + # Jobs will be cancelled if PR is a draft. # PR status must be "Open" to run CI. is_not_draft_pull_request: + # if: ${{ always() }} + needs: [semantic_pull_request] # Everywhere in this workflow, we use the most recent ubuntu distribution available in Github Actions # to ensure maximum support of google cloud's sdk. runs-on: ubuntu-22.04 outputs: DOCKER_IMAGE_TAG: ${{ steps.extract_docker_image_tag.outputs.DOCKER_IMAGE_TAG }} - LABELS: ${{ steps.extract_pr_info.outputs.LABELS }} steps: - name: Check that the PR is not a draft (cancel rest of jobs otherwise) id: extract_pr_info @@ -37,17 +64,12 @@ jobs: draft_status=$(echo ${pr_json} | jq '.draft') echo "Draft status of PR is ${draft_status}." if [[ $draft_status == true ]]; then exit 1 ; fi - - # If the workflow is meant to continue, we extract additional information for the json of the pr. - echo "LABELS=$(echo ${pr_json} | jq -crM '[.labels[].name]')" >> "$GITHUB_OUTPUT" - else - echo "LABELS=['ci: ready to be merged']" >> "$GITHUB_OUTPUT" fi # The TPL tag is contained in the codespaces configuration to avoid duplications. - name: Checkout .devcontainer/devcontainer.json - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.2 with: sparse-checkout: | .devcontainer/devcontainer.json @@ -83,7 +105,7 @@ jobs: # The integrated test submodule repository contains large data (using git lfs). # To save time (and money) we do not let Github Actions automatically clone all our (lfs) subrepositories and do it by hand. - name: Checkout Repository - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.2 with: # Let script update submodules; Github Actions submodule history causes error submodules: false @@ -124,61 +146,52 @@ jobs: fail-fast : false matrix: include: - - name: Ubuntu (20.04, gcc 9.3.0, open-mpi 4.0.3) + - name: Ubuntu (20.04, gcc 9.4.0, open-mpi 4.0.3) CMAKE_BUILD_TYPE: Release DOCKER_REPOSITORY: geosx/ubuntu20.04-gcc9 + BUILD_SHARED_LIBS: ON - - name: Ubuntu debug (20.04, gcc 10.3.0, open-mpi 4.0.3) - github codespaces + - name: Ubuntu debug (20.04, gcc 10.5.0, open-mpi 4.0.3) - github codespaces CMAKE_BUILD_TYPE: Debug DOCKER_REPOSITORY: geosx/ubuntu20.04-gcc10 + BUILD_SHARED_LIBS: ON - - name: Ubuntu (20.04, gcc 10.3.0, open-mpi 4.0.3) - github codespaces + - name: Ubuntu (20.04, gcc 10.5.0, open-mpi 4.0.3) - github codespaces CMAKE_BUILD_TYPE: Release DOCKER_REPOSITORY: geosx/ubuntu20.04-gcc10 + BUILD_SHARED_LIBS: ON - - name: Ubuntu (22.04, gcc 11.2.0, open-mpi 4.1.2) + - name: Ubuntu (22.04, gcc 11.4.0, open-mpi 4.1.2) CMAKE_BUILD_TYPE: Release DOCKER_REPOSITORY: geosx/ubuntu22.04-gcc11 ENABLE_HYPRE: ON ENABLE_TRILINOS: OFF GCP_BUCKET: geosx/ubuntu22.04-gcc11 + BUILD_SHARED_LIBS: ON - name: Ubuntu (22.04, gcc 12.3.0, open-mpi 4.1.2) CMAKE_BUILD_TYPE: Release DOCKER_REPOSITORY: geosx/ubuntu22.04-gcc12 ENABLE_HYPRE: ON ENABLE_TRILINOS: OFF + BUILD_SHARED_LIBS: ON - - name: Pecan CPU (centos 7.7, gcc 8.2.0, open-mpi 4.0.1, mkl 2019.5) + - name: Ubuntu (22.04, clang 15.0.7, open-mpi 4.1.2) CMAKE_BUILD_TYPE: Release - DOCKER_REPOSITORY: geosx/pecan-cpu-gcc8.2.0-openmpi4.0.1-mkl2019.5 - HOST_CONFIG: host-configs/TOTAL/pecan-CPU.cmake - GCP_BUCKET: geosx/Pecan-CPU - - - name: Pangea 2 (centos 7.6, gcc 8.3.0, open-mpi 2.1.5, mkl 2019.3) - CMAKE_BUILD_TYPE: Release - DOCKER_REPOSITORY: geosx/pangea2-gcc8.3.0-openmpi2.1.5-mkl2019.3 + DOCKER_REPOSITORY: geosx/ubuntu22.04-clang15 ENABLE_HYPRE: ON ENABLE_TRILINOS: OFF - GCP_BUCKET: geosx/Pangea2 - - - name: Sherlock CPU (centos 7.9.2009, gcc 10.1.0, open-mpi 4.1.2, openblas 0.3.10) - CMAKE_BUILD_TYPE: Release - DOCKER_REPOSITORY: geosx/sherlock-gcc10.1.0-openmpi4.1.2-openblas0.3.10-zlib1.2.11 - ENABLE_HYPRE: ON - ENABLE_TRILINOS: OFF - GCP_BUCKET: geosx/Sherlock-CPU - HOST_CONFIG: host-configs/Stanford/sherlock-gcc10-ompi4.1.2-openblas0.3.10.cmake + BUILD_SHARED_LIBS: ON uses: ./.github/workflows/build_and_test.yml with: + BUILD_SHARED_LIBS: ${{ matrix.BUILD_SHARED_LIBS }} CMAKE_BUILD_TYPE: ${{ matrix.CMAKE_BUILD_TYPE }} DOCKER_IMAGE_TAG: ${{ needs.is_not_draft_pull_request.outputs.DOCKER_IMAGE_TAG }} DOCKER_REPOSITORY: ${{ matrix.DOCKER_REPOSITORY }} ENABLE_HYPRE: ${{ matrix.ENABLE_HYPRE }} ENABLE_TRILINOS: ${{ matrix.ENABLE_TRILINOS }} GCP_BUCKET: ${{ matrix.GCP_BUCKET }} - HOST_CONFIG: ${{ matrix.HOST_CONFIG }} RUNS_ON: ubuntu-22.04 secrets: inherit @@ -188,7 +201,6 @@ jobs: needs: - is_not_draft_pull_request - cpu_builds - if: "${{ contains( fromJSON( needs.is_not_draft_pull_request.outputs.LABELS ), 'ci: run integrated tests') || github.event_name != 'pull_request' }}" uses: ./.github/workflows/build_and_test.yml secrets: inherit with: @@ -200,7 +212,28 @@ jobs: ENABLE_HYPRE: ON ENABLE_TRILINOS: OFF GCP_BUCKET: geosx/integratedTests - RUNS_ON: ubuntu-22.04 + RUNS_ON: streak2-32core + NPROC: 32 + DOCKER_RUN_ARGS: "--cpus=32 --memory=384g -v /etc/pki/ca-trust/source/anchors/:/usr/local/share/ca-certificates/llnl:ro" + DOCKER_CERTS_DIR: "/usr/local/share/ca-certificates" + DOCKER_CERTS_UPDATE_COMMAND: "update-ca-certificates" + REQUIRED_LABEL: "ci: run integrated tests" + LOCAL_BASELINE_DIR: /data/GEOS/baselines + + baseline_log: + needs: [is_not_draft_pull_request] + runs-on: ubuntu-22.04 + steps: + - name: Checkout Repository + uses: actions/checkout@v4.2.2 + with: + submodules: false + lfs: false + fetch-depth: 0 + sparse-checkout: | + scripts + - name: Check that the baseline logs are modified if rebaselines are detected + run: "scripts/check_baseline_log.sh" code_coverage: needs: @@ -217,14 +250,25 @@ jobs: ENABLE_TRILINOS: OFF GCP_BUCKET: geosx/ubuntu22.04-gcc11 RUNS_ON: Runner_4core_16GB + REQUIRED_LABEL: "ci: run code coverage" + - # If the 'ci: ready to be merged' PR label is found, the cuda jobs run immediately along side linux jobs. + # mac_builds: + # needs: + # - is_not_draft_pull_request + # runs-on: macos-14-xlarge + # steps: + # - run: sysctl -n hw.physicalcpu + # - run: sysctl -h hw.memsize + # - run: sysctl -n machdep.cpu.brand_string + + + # If the 'ci: run CUDA builds' PR label is found, the cuda jobs run immediately along side linux jobs. # Note: CUDA jobs should only be run if PR is ready to merge. cuda_builds: name: ${{ matrix.name }} needs: - is_not_draft_pull_request - if: "${{ contains( fromJSON( needs.is_not_draft_pull_request.outputs.LABELS ), 'ci: ready to be merged') }}" strategy: # In-progress jobs will not be cancelled if there is a failure fail-fast : false @@ -233,52 +277,85 @@ jobs: - name: Ubuntu CUDA debug (20.04, clang 10.0.0 + gcc 9.4.0, open-mpi 4.0.3, cuda-11.8.89) BUILD_AND_TEST_CLI_ARGS: "--build-exe-only --no-install-schema" CMAKE_BUILD_TYPE: Debug + BUILD_GENERATOR: "--ninja" DOCKER_REPOSITORY: geosx/ubuntu20.04-clang10.0.0-cuda11.8.89 ENABLE_HYPRE_DEVICE: CUDA ENABLE_HYPRE: ON ENABLE_TRILINOS: OFF - RUNS_ON: Runner_8core_32GB - + RUNS_ON: streak2 + NPROC: 8 + DOCKER_RUN_ARGS: "--cpus=8 --memory=128g --runtime=nvidia -v /etc/pki/ca-trust/source/anchors/:/usr/local/share/ca-certificates/llnl:ro" + DOCKER_CERTS_DIR: "/usr/local/share/ca-certificates" + DOCKER_CERTS_UPDATE_COMMAND: "update-ca-certificates" + - name: Ubuntu CUDA (20.04, clang 10.0.0 + gcc 9.4.0, open-mpi 4.0.3, cuda-11.8.89) BUILD_AND_TEST_CLI_ARGS: "--no-install-schema" CMAKE_BUILD_TYPE: Release + BUILD_GENERATOR: "--ninja" DOCKER_REPOSITORY: geosx/ubuntu20.04-clang10.0.0-cuda11.8.89 ENABLE_HYPRE_DEVICE: CUDA ENABLE_HYPRE: ON ENABLE_TRILINOS: OFF - RUNS_ON: self-hosted - DOCKER_RUN_ARGS: "--cpus=8 --memory=128g --runtime=nvidia --gpus all" - - - - name: Centos (7.7, gcc 8.3.1, open-mpi 1.10.7, cuda 11.8.89) + RUNS_ON: streak + NPROC: 8 + DOCKER_RUN_ARGS: "--cpus=8 --memory=256g --runtime=nvidia --gpus all -v /etc/pki/ca-trust/source/anchors/:/usr/local/share/ca-certificates/llnl:ro" + DOCKER_CERTS_DIR: "/usr/local/share/ca-certificates" + DOCKER_CERTS_UPDATE_COMMAND: "update-ca-certificates" + + - name: Rockylinux CUDA (8, clang 17.0.6, cuda 12.5.1) + BUILD_AND_TEST_CLI_ARGS: "--no-install-schema" + CMAKE_BUILD_TYPE: Release + BUILD_GENERATOR: "--ninja" + ENABLE_HYPRE_DEVICE: CUDA + ENABLE_HYPRE: ON + ENABLE_TRILINOS: OFF + DOCKER_REPOSITORY: geosx/rockylinux8-clang17-cuda12.5 + RUNS_ON: streak + NPROC: 8 + DOCKER_RUN_ARGS: "--cpus=8 --memory=256g --runtime=nvidia --gpus all -v /etc/pki/ca-trust/source/anchors/:/usr/local/share/ca-certificates/llnl:ro" + DOCKER_CERTS_DIR: "/usr/local/share/ca-certificates" + DOCKER_CERTS_UPDATE_COMMAND: "update-ca-trust" + + - name: Rockylinux CUDA (8, gcc 8.5, cuda 12.5.1) BUILD_AND_TEST_CLI_ARGS: "--no-run-unit-tests --no-install-schema" CMAKE_BUILD_TYPE: Release - DOCKER_REPOSITORY: geosx/centos7.7-gcc8.3.1-cuda11.8.89 - RUNS_ON: Runner_4core_16GB + BUILD_GENERATOR: "--ninja" + ENABLE_HYPRE_DEVICE: CUDA + ENABLE_HYPRE: ON + ENABLE_TRILINOS: OFF + DOCKER_REPOSITORY: geosx/rockylinux8-gcc8-cuda12.5 + RUNS_ON: streak2 + NPROC: 8 + DOCKER_RUN_ARGS: "--cpus=8 --memory=128g --runtime=nvidia -v /etc/pki/ca-trust/source/anchors/:/etc/pki/ca-trust/source/anchors/llnl:ro" + DOCKER_CERTS_DIR: "/etc/pki/ca-trust/source/anchors" + DOCKER_CERTS_UPDATE_COMMAND: "update-ca-trust" - # Below this line, jobs that deploy to Google Cloud. - - name: Pecan GPU (centos 7.7, gcc 8.2.0, open-mpi 4.0.1, mkl 2019.5, cuda 11.5.119) + - name: Pangea 3 CUDA (AlmaLinux 8.8, gcc 9.4.0, open-mpi 4.1.2, cuda 11.5.0, openblas 0.3.10) BUILD_AND_TEST_CLI_ARGS: "--build-exe-only --no-install-schema" CMAKE_BUILD_TYPE: Release - DOCKER_REPOSITORY: geosx/pecan-gpu-gcc8.2.0-openmpi4.0.1-mkl2019.5-cuda11.5.119 - HOST_CONFIG: host-configs/TOTAL/pecan-GPU.cmake - RUNS_ON: Runner_4core_16GB - - - name: Sherlock GPU (centos 7.9.2009, gcc 10.1.0, open-mpi 4.1.2, openblas 0.3.10, cuda 11.7.1,) - BUILD_AND_TEST_CLI_ARGS: "--no-run-unit-tests --no-install-schema" - CMAKE_BUILD_TYPE: Release - DOCKER_REPOSITORY: geosx/sherlock-gcc10.1.0-openmpi4.1.2-cuda11.7.1-openblas0.3.10-zlib1.2.11 + BUILD_GENERATOR: "--makefile" + DOCKER_REPOSITORY: geosx/pangea3-almalinux8-gcc9.4-openmpi4.1.2-cuda11.5.0-openblas0.3.18 + HOST_CONFIG: host-configs/TOTAL/pangea3-gcc8.4.1-openmpi-4.1.2-wave-solver.cmake ENABLE_HYPRE_DEVICE: CUDA ENABLE_HYPRE: ON ENABLE_TRILINOS: OFF - GCP_BUCKET: geosx/Sherlock-GPU - HOST_CONFIG: host-configs/Stanford/sherlock-gcc10-ompi4.1.2-openblas0.3.10-cuda11.7.1-sm70.cmake - RUNS_ON: Runner_4core_16GB + HOST_ARCH: ppc64le + RUNS_ON: streak2 + NPROC: 8 + DOCKER_RUN_ARGS: "--cpus=8 --memory=128g -v /etc/pki/ca-trust/source/anchors/:/etc/pki/ca-trust/source/anchors/llnl:ro" + DOCKER_CERTS_DIR: "/etc/pki/ca-trust/source/anchors" + DOCKER_CERTS_UPDATE_COMMAND: "update-ca-trust" + + + # Below this line, jobs that deploy to Google Cloud. uses: ./.github/workflows/build_and_test.yml with: BUILD_AND_TEST_CLI_ARGS: ${{ matrix.BUILD_AND_TEST_CLI_ARGS }} CMAKE_BUILD_TYPE: ${{ matrix.CMAKE_BUILD_TYPE }} + BUILD_GENERATOR: ${{ matrix.BUILD_GENERATOR }} + DOCKER_CERTS_DIR: ${{ matrix.DOCKER_CERTS_DIR }} + DOCKER_CERTS_UPDATE_COMMAND: ${{ matrix.DOCKER_CERTS_UPDATE_COMMAND }} DOCKER_IMAGE_TAG: ${{ needs.is_not_draft_pull_request.outputs.DOCKER_IMAGE_TAG }} DOCKER_REPOSITORY: ${{ matrix.DOCKER_REPOSITORY }} DOCKER_RUN_ARGS: ${{ matrix.DOCKER_RUN_ARGS }} @@ -286,8 +363,11 @@ jobs: ENABLE_HYPRE: ${{ matrix.ENABLE_HYPRE }} ENABLE_TRILINOS: ${{ matrix.ENABLE_TRILINOS }} GCP_BUCKET: ${{ matrix.GCP_BUCKET }} + HOST_ARCH: ${{ matrix.HOST_ARCH }} HOST_CONFIG: ${{ matrix.HOST_CONFIG }} + NPROC: ${{ matrix.NPROC }} RUNS_ON: ${{ matrix.RUNS_ON }} + REQUIRED_LABEL: "ci: run CUDA builds" secrets: inherit # Convenience job - passes when all other jobs have passed (must pass the CUDA jobs). @@ -299,6 +379,7 @@ jobs: - check_code_style_and_documentation - cpu_builds - cuda_builds + - run_integrated_tests if: ${{ always() }} steps: - run: | @@ -307,10 +388,12 @@ jobs: echo "check_code_style_and_documentation: ${{needs.check_code_style_and_documentation.result}}" echo "cpu_builds: ${{needs.cpu_builds.result}}" echo "cuda_builds: ${{needs.cuda_builds.result}}" + echo "run_integrated_tests: ${{needs.run_integrated_tests.result}} " ${{ needs.if_not_unassigned_pull_request.result == 'success' && needs.are_submodules_in_sync.result == 'success' && needs.check_code_style_and_documentation.result == 'success' && needs.cpu_builds.result == 'success' && - needs.cuda_builds.result == 'success' + needs.cuda_builds.result == 'success' && + needs.run_integrated_tests.result == 'success' }} diff --git a/.gitignore b/.gitignore index d00a78b3725..8b641c28a31 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ /Debug/ uberenv_libs spack-*.txt +/src/docs/sphinx/datastructure *~ __pycache__ diff --git a/.gitmodules b/.gitmodules index a2d2fa8ccf5..029ba71a9ab 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,9 +7,6 @@ [submodule "src/coreComponents/constitutive/PVTPackage"] path = src/coreComponents/constitutive/PVTPackage url = ../../GEOS-DEV/PVTPackage.git -[submodule "integratedTests"] - path = integratedTests - url = ../../GEOS-DEV/integratedTests.git [submodule "src/coreComponents/fileIO/coupling/hdf5_interface"] path = src/coreComponents/fileIO/coupling/hdf5_interface url = ../../GEOS-DEV/hdf5_interface.git diff --git a/.integrated_tests.yaml b/.integrated_tests.yaml new file mode 100644 index 00000000000..6dfbf981b0c --- /dev/null +++ b/.integrated_tests.yaml @@ -0,0 +1,6 @@ +baselines: + bucket: geosx + baseline: integratedTests/baseline_integratedTests-pr3479-9362-cffefcc +allow_fail: + all: '' + streak: '' diff --git a/.readthedocs.yml b/.readthedocs.yml index cac04680e9d..5f3f5d49dbf 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -4,18 +4,24 @@ version: 2 build: - os: "ubuntu-20.04" + os: "ubuntu-22.04" apt_packages: + - curl + - graphviz - npm - - plantuml + - openjdk-21-jre-headless - texlive tools: nodejs: "16" python: "3.10" jobs: + pre_build: + - python3 scripts/SchemaToRSTDocumentation.py -s src/coreComponents/schema/schema.xsd -o src/docs/sphinx post_install: - npm install -g npm@9.8.1 - npm install -g @mermaid-js/mermaid-cli@10.3.1 + # If you change the `/tmp/plantuml.jar` path, be sure to also update where this path is used as well (e.g. in `conf.py`). + - curl -fsSL https://github.com/plantuml/plantuml/releases/download/v1.2024.3/plantuml-gplv2-1.2024.3.jar -o /tmp/plantuml.jar # Set requirements to build the docs python: @@ -26,12 +32,14 @@ python: sphinx: configuration: src/conf.py builder: html + fail_on_warning: true + # Optionally build your docs in additional formats such as PDF and ePub -formats: all +formats: + - pdf submodules: include: - src/coreComponents/constitutive/PVTPackage - - integratedTests recursive: true diff --git a/BASELINE_NOTES.md b/BASELINE_NOTES.md new file mode 100644 index 00000000000..0bc5c80f561 --- /dev/null +++ b/BASELINE_NOTES.md @@ -0,0 +1,309 @@ + +Notes +========== + +This file is designed to track changes to the integrated test baselines. +Any developer who updates the baseline ID in the .integrated_tests.yaml file is expected to create an entry in this file with the pull request number, date, and their justification for rebaselining. +These notes should be in reverse-chronological order, and use the following time format: (YYYY-MM-DD). + +PR #3479 (2024-12-15) +===================== +Refine inputFiles/compositionalMultiphaseFlow: shift reference pressures to initial pressures, make nonlinear tuning more reasonable, minimize output. + +PR #3450 (2024-12-14) +===================== +Fix timestep selector flaw in SolidMechanicsLagrangeContact. + +PR #3450 (2024-12-08) +===================== +Added test for explicit runge kutta sprinslider. + +PR #3480 (2024-12-06) +===================== +Add "logLevel" parameter under /Problem/Outputs in baseline files + +PR #3361 (2024-12-03) +===================== +Revert default gravity treatment to old version. Make the way introduced in #3337 optional. + +PR #3361 (2024-12-03) +===================== +Baseline diffs after reimplementation of wave equation acoustic gradient for velocity and density parameters: new field "partialGradient2" and "pressureForward" field replacing "pressureDoubleDerivative". + +PR #3393 (2024-12-02) +===================== +Fix netToGross bug. + +PR #3381 (2024-12-01) +===================== +A few baseline diffs for order FaceElementSubRegion::m_toFacesRelation map. Not sure why this was changed by this PR, but the previous order seems incorrect for a couple of cases. + +PR #2957 (2024-11-27) +===================== +Added ExternalDataRepository. + +PR #3448 (2024-11-21) +===================== +Switched the FaceElementSubRegion::m_toFacesRelation and FaceElementSubRegion::m_2dElemToElems back to array2d instead of ArrayOfArray. This results in a reordering m_toFacesRelation back to the "correct" assumed order of "original face first". This fixes a bug that failed to remove the CellStencil entry when a FaceElement splits two cells. + +PR #2637 (2024-11-21) +===================== +Added numberOfTargetProcesses. + +PR #3439 (2024-11-20) +===================== +EDFM bugfixes: derivatives sign, frac/cell element volume, fix apertures inconsistency in test cases. + +PR ##3440 (2024-11-18) +===================== +Added Lagrange multiplier with bubble functions stabilization (sli only) and possibility to specify a slip. + +PR #3339 (2024-11-14) +===================== +Hypre improvements, rebaseline is due to field value change (amgNumFunctions). + +PR #3434 (2024-11-09) +===================== +Bugfix: Fixed output of ArrayOfArray objects to restart files. + +PR #3374 (2024-11-09) +==================== +Bugfix for gravity treatment in flux for thermal. + +PR #3372 (2024-11-09) +==================== +Fix a bug related to mass and energy updates for poromechanics. + +PR #3426 (2024-11-08) +==================== +Bugfix: reset accumulation in fracture when time step cut occurs in hydrofrac solver. + +PR #3413 (2024-11-07) +==================== +Add tests for poro-thermo-plastic model. + +PR #3337 (2024-11-06) +==================== +Change density treatment for gravity in multiphase flow solver. + +PR #3408 (2024-11-06) +==================== +EFEM bugfixes: effective traction + oldStress. + +PR #3280 (2024-11-05) +==================== +Added Sprig-slider test. + +PR #2909 (2024-10-30) +===================== +Add routine for automatic time steps in waveSolvers with new attributes + +PR #3156 (2024-10-29) +==================== +Restart check errors due to 1) schema node added to enable thermal option in well model and 2) arrays removed/added for option. Max difference errors due treatment of shutin wells. Previously non-zero rate value reported for shutin well, new code will set rate arrays to zero. + +PR #2878 (2024-10-17) +===================== +Sorted region cellBlocks names alphabetically. Therefore affected ordering of: faceManager/elemSubRegionList, nodeManager/elemList, nodeManager/elemSubRegionList, SurfaceElementSubRegion::fractureElementsToCellSubRegions, field::perforation::reservoirElementSubregion. + +PR #3364( 2024-10-15) +===================== +Enable reservoir+wells+contact mechanics. Rebaseline needed because of 'allowNegativePressure' flag added for wells. + +PR #3364( 2024-10-01) +===================== +Separate mass and volume residuals for output in compositional flow solver. Baseline update because of minor numerical diffs. + +PR #3149( 2024-09-30) +===================== +Added new field "writeCSV" + +PR #3163 (2024-09-20) +===================== +Added new fields (krylovStrongestTol, adaptiveGamma, adaptiveExponent) to the LinearSolverParameters for adaptive tolerances. + +PR #3338 (2024-09-19) +====================== +Updated time-stepping logic. Rebaseline due to new input parameter and minor numerical diffs. + +PR #3217 (2024-09-16) +====================== +ALM slip and open modes with relative tests. + +PR #3318 (2024-09-12) +====================== +Modified SeismicityRate poroelastic case. + +PR #3322 (2024-09-06) +====================== +Print out fracture state for contact model. Rebaseline the corresponding cases. + +PR #3302 (2024-09-05) +====================== +Added restartcheks to hydrofrac cases and reduced time of cases that were too long. + +PR #3135 (2024-09-04) +====================== +Temperature dependent single phase thermal conductivity. Rebaseline all thermal cases. + +PR #3294 (2024-09-01) +====================== +Re-enable enforcement of wave propagation integrated test pass. + +PR #3300 (2024-08-28) +====================== +Re-enable floating point exceptions. Rebaseline due to minor changing default value of maxRelativeCompDensChange from 1.7976931348623157e+308 to 1.7976931348623157e+208. + +PR #3283 (2024-08-22) +====================== +Reuse computeSinglePhaseFlux. Rebaseline due to minor numerical diffs. + +PR #3249 (2024-08-14) +====================== +Two initialization options for poromechanical models. Rebaseline the corresponding cases. + +PR #3278 (2024-08-12) +====================== +Renamed GEOSX to GEOS in enternal mesh import, so rebaseline to change these names is the baselines. + +PR #3202 (2024-08-03) +====================== +Acoustic VTI tests needed rebaselining after update in source and receiver location algorithm. + +PR #3215 (2024-07-23) +====================== +Changed the default value for massCreation and name of the wrapper. + +PR #3194 (2024-07-22) +====================== +Check pore volume for all element types, also check that default aperture > 0. Rebaseline for modified tests. No real results change. + +PR #3213 (2024-07-12) +====================== +Added baselines for new tests on Dirichlet boundary conditions for multiphase flow. + +PR #3194 (2024-07-10) +====================== +Use aperture table in poromechanics with conforming fractures. Rebaseline the corresponding cases. + +PR #3006 (2024-07-01) +====================== +Added baselines for new tests. Relaxing tolerances for singlePhasePoromechanics_FaultModel_smoke. + +PR #3196 (2024-06-28) +====================== +Added isLaggingFractureStencilWeightsUpdate to hydrofracture solve. Rebaseline because of the new input. + +PR #3177 (2024-06-28) +====================== +Added logLevel to TimeHistoryOutput. Rebaseline because of the new input flag. + +PR #3181 (2024-06-25) +====================== +Decouple debug matrix output from logLevel. Rebaseline because of the new input flag. + +PR #3142 (2024-06-20) +====================== +Adding output of total strain. Rebaseline because of new inclusion of strain in output. + +PR #3170 (2024-06-19) +====================== +Fix tutorial example for thermal debonding wellbore problem. Test case modified. + +PR #3130 (2024-06-19) +====================== +New solver for contact mechanics based on the Augmented Lagrangian Method (ALM). New test case added. + +PR #3160 (2024-06-18) +====================== +Two experimental options for compositional flow solver. Rebaseline because of the new input flags. + +PR #3165 (2024-06-18) +====================== +Small bug fix. Rebaseline required due to appearance of useTotalMassEquation in well solver params. No real results change. + +PR #3088 (2024-06-17) +====================== +Adding temperature-dependent Solid Volumetric Heat Capacity. Rebaseline because of the parameter change in SolidInternalEnergy. + +PR #3100 (2024-06-14) +====================== +Adding pressure stabilization for single phase poromechanics. + +PR #3133 (2024-06-14) +====================== +Fix node ordering for faceElements. + +PR #3021 (2024-06-13) +====================== +Preparatory work for fractures + wells. New test case added. + +PR #3152 (2024-06-13) +====================== +Some random things. Baseline update because of the new parameter (minScalingFactor). + +PR #3138 (2024-06-11) +====================== +Properly sync nonlinear solver params for coupled solver. Baseline update mostly due to number of iterations change in baseline files. + +PR #3140 (2024-06-11) +====================== +Fixed derivative in EzrokhiBrineDensity + +PR #3080 (2024-06-07) +===================== +Rebaseline after adding viscoelastic wave propagator. + +PR #3075 (2024-06-05) +===================== +Introduce configuration tolerance. Rebaseline because of the new parameter in NonlinearSolverParameters. + +PR #3120 (2024-06-05) +===================== +Add missing compositionalMultiphaseFlow tests into ATS and adjust output naming. Rebaseline accordingly. + +PR #3113 (2024-06-05) +===================== +Add general version updateConfiguration. Rebaseline of some edfm cases is needed. + +PR #3050 (2024-05-20) +===================== +Spatially varying grain bulk modulus. Rebaseline of all poromechanics cases needed. + +PR #3141 (2024-05-28) +===================== +Test cashing baselines locally. + +PR #3125 (2024-05-16) +===================== +Remove field to store pressure gradient cell-wise for solvers that don't need it. + +PR #2110 (2024-05-13) +===================== +new field to store pressure gradient cell-wise. + +PR #3060 (2024-05-13) +====================== +Rebaselined after addition of elastic VTI wave propagator. + +PR #4950 (2024-05-10) +====================== +Added smoke tests for SeismicityRate solver in inducedSeismicity. + +PR #3086 (2024-05-09) +====================== +Added a presure-dependent permeability model and the transmissibility calculation in the CellElementStencil + +PR #3105 (2024-05-08) +====================== +Added missing derivative for temperature, hence small numerical diffs in thermal tests results and numeracal behavior + +PR #2917 (2024-05-07) +====================== +New fields for wellsControls: wellControls1_ConstantMassRate_table, targetMassRate, massDensity, ... + +PR #3044 (2024-05-02) +====================== +Removed old integratedTests submodule +Implemented new baseline storage +Implemented new CI integrated tests diff --git a/CITATION.cff b/CITATION.cff index 2a02e009860..d3e83dcea10 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,12 +1,12 @@ cff-version: 1.2.0 -message: "Publications that present GEOSX simulations and/or results should cite as follows:" +message: If you use this software, please cite this repository and our article in the + Journal of Open Source Software. authors: - family-names: "Settgast" given-names: "Randolph Richard" orcid: "https://orcid.org/0000-0002-2536-7867" - family-names: "Corbett" given-names: "Benjamin Curtice" - orcid: "https://orcid.org/0000-0000-0000-0000" - family-names: "Klevtsov" given-names: "Sergey" orcid: "https://orcid.org/0000-0001-9044-1827" @@ -24,7 +24,6 @@ authors: orcid: "https://orcid.org/0000-0002-6103-4605" - family-names: "Tobin" given-names: "William" - orcid: "https://orcid.org/0000-0000-0000-0000" - family-names: "White" given-names: "Joshua" orcid: "https://orcid.org/0000-0003-3491-142X" @@ -42,7 +41,6 @@ authors: orcid: "https://orcid.org/0000-0002-5380-2563" - family-names: "Han" given-names: "Brian" - orcid: "https://orcid.org/0000-0000-0000-0000" - family-names: "Gross" given-names: "Herve" orcid: "https://orcid.org/0000-0002-1747-2018" @@ -51,45 +49,285 @@ authors: orcid: "https://orcid.org/0000-0002-8833-9425" - family-names: "Mazuyer" given-names: "Antoine" - orcid: "https://orcid.org/0000-0000-0000-0000" - family-names: "Besset" given-names: "Julien" - orcid: "https://orcid.org/0000-0000-0000-0000" - family-names: "Citrain" given-names: "Aurelien" - orcid: "https://orcid.org/0000-0000-0000-0000" - family-names: "Vargas" given-names: "Arturo" - orcid: "https://orcid.org/0000-0000-0000-0000" - family-names: "Cremon" given-names: "Matthias" orcid: "https://orcid.org/0000-0001-7458-6401" - family-names: "Hao" given-names: "Yue" - orcid: "https://orcid.org/0000-0000-0000-0000" - family-names: "Khait" given-names: "Mark" - orcid: "https://orcid.org/0000-0000-0000-0000" - family-names: "Lacoste" given-names: "Xavier" - orcid: "https://orcid.org/0000-0000-0000-0000" - family-names: "Semnani" given-names: "Shabnam" - orcid: "https://orcid.org/0000-0000-0000-0000" - family-names: "Frambati" given-names: "Stefano" - orcid: "https://orcid.org/0000-0000-0000-0000" - family-names: "N'diaye" given-names: "Mamadou" - orcid: "https://orcid.org/0000-0000-0000-0000" - family-names: "Nguyen" given-names: "Sy-Tuan" - orcid: "https://orcid.org/0000-0000-0000-0000" - family-names: "Morgan" given-names: "Hannah Mairs" - orcid: "https://orcid.org/0000-0000-0000-0000" +- family-names: "Crook" + given-names: "Cameron Mikel" +- family-names: "Jin" + given-names: "Tao" +- family-names: "Froehly" + given-names: "Algiane" +- family-names: "Homel" + given-names: "Michael" +- family-names: "Magri" + given-names: "Victor Paludetto" +- family-names: "Ju" + given-names: "Isaac" +- family-names: "Rey" + given-names: "Mel" +- family-names: "Povolny" + given-names: "Stefan" +- family-names: "Wu" + given-names: "Hui" +- family-names: "Bui" + given-names: "Quan" +- family-names: "Tang" + given-names: "Hewei" +- family-names: "Camargo" + given-names: "Julia T." +- family-names: "Chourdakis" + given-names: "Gerasimos" +- family-names: "Hui" + given-names: "Wu" +- family-names: "Ren" + given-names: "Guotong" +- family-names: "Yang" + given-names: "Li" +- family-names: "Taeho" + given-names: "Kim" +- family-names: "Waziri" + given-names: "Sohail" +- family-names: "White" + given-names: "Chris" +- family-names: "Fu" + given-names: "Pengcheng" +- family-names: "Lapene" + given-names: "Alexandre" +- family-names: "Thierry" + given-names: "Bertrand" +- family-names: "Fei" + given-names: "Fan" +- family-names: "Meng" + given-names: "Jie" +- family-names: "Untereiner" + given-names: "Lionel" +- family-names: "Raji" + given-names: "Oluwatobi Quadri" +- family-names: "Karimi-Fard" + given-names: "Mohammad" +- family-names: "Fuss" + given-names: "Gaetan" +- family-names: "Huang" + given-names: "Jixian" +- family-names: "Frigo" + given-names: "Matteo" +- family-names: "Martinez" + given-names: "Paloma" +- family-names: "Kachuma" + given-names: "Dickson" +- family-names: "Tomin" + given-names: "Pavel" +- family-names: "Byer" + given-names: "Thomas James" +- family-names: "Ligocki" + given-names: "Terry" +- family-names: "Shovkun" + given-names: "Igor" +- family-names: "Bader" + given-names: "Milad" +- family-names: "Robinson" + given-names: "Peter B." +- family-names: "Hasanzade" + given-names: "Rasim" +- family-names: "Dudes" + given-names: "Arnaud" +- family-names: "Costa" + given-names: "Andre Macieira Braga" +- family-names: "Pellerin" + given-names: "Jeanne" +- family-names: "Aronson" + given-names: "Ryan" +- family-names: "Osei-Kuffuor" + given-names: "Daniel" title: "GEOSX" -version: 0.2.1 -doi: 10.5281/zenodo.7151032 -date-released: 2022-10-06 +version: 1.1.0 +doi: "10.5281/zenodo.7151031" +date-released: 2024-09-14 url: "https://github.com/GEOS-DEV/GEOS" +preferred-citation: + authors: + - family-names: Settgast + given-names: Randolph R. + orcid: "https://orcid.org/0000-0002-2536-7867" + - family-names: Aronson + given-names: Ryan M. + orcid: "https://orcid.org/0009-0004-0785-5084" + - family-names: Besset + given-names: Julien R. + - family-names: Borio + given-names: Andrea + orcid: "https://orcid.org/0000-0003-2016-5403" + - family-names: Bui + given-names: Quan M. + orcid: "https://orcid.org/0000-0003-2648-0586" + - family-names: Byer + given-names: Thomas J. + - family-names: Castelletto + given-names: Nicola + orcid: "https://orcid.org/0000-0001-6816-6769" + - family-names: Citrain + given-names: Aurélien + orcid: "https://orcid.org/0009-0006-3742-1425" + - family-names: Corbett + given-names: Benjamin C. + orcid: "https://orcid.org/0009-0008-7108-9651" + - family-names: Corbett + given-names: James + - family-names: Cordier + given-names: Philippe + orcid: "https://orcid.org/0000-0002-6439-9263" + - family-names: Cremon + given-names: Matthias A. + orcid: "https://orcid.org/0000-0001-7458-6401" + - family-names: Crook + given-names: Cameron M. + orcid: "https://orcid.org/0000-0002-5366-6418" + - family-names: Cusini + given-names: Matteo + orcid: "https://orcid.org/0000-0002-6024-861X" + - family-names: Fei + given-names: Fan + orcid: "https://orcid.org/0000-0001-7273-4458" + - family-names: Frambati + given-names: Stefano + orcid: "https://orcid.org/0000-0003-0683-1203" + - family-names: Franc + given-names: Jacques + orcid: "https://orcid.org/0000-0002-8833-9425" + - family-names: Franceschini + given-names: Andrea + orcid: "https://orcid.org/0000-0003-4395-5125" + - family-names: Frigo + given-names: Matteo + orcid: "https://orcid.org/0000-0001-8150-1090" + - family-names: Fu + given-names: Pengcheng + orcid: "https://orcid.org/0000-0002-7408-3350" + - family-names: Gazzola + given-names: Thomas + orcid: "https://orcid.org/0000-0002-6103-4605" + - family-names: Gross + given-names: Herve + orcid: "https://orcid.org/0000-0002-1747-2018" + - family-names: Hamon + given-names: Francois + orcid: "https://orcid.org/0000-0001-8229-963X" + - family-names: Han + given-names: Brian M. + orcid: "https://orcid.org/0009-0002-8549-7644" + - family-names: Hao + given-names: Yue + orcid: "https://orcid.org/0000-0002-4543-8618" + - family-names: Hasanzade + given-names: Rasim + - family-names: Homel + given-names: Michael + orcid: "https://orcid.org/0000-0002-0399-0092" + - family-names: Huang + given-names: Jian + orcid: "https://orcid.org/0000-0002-5380-2563" + - family-names: Jin + given-names: Tao + orcid: "https://orcid.org/0000-0001-6658-8941" + - family-names: Ju + given-names: Isaac + orcid: "https://orcid.org/0000-0003-4110-7472" + - family-names: Kachuma + given-names: Dickson + - family-names: Karimi-Fard + given-names: Mohammad + orcid: "https://orcid.org/0000-0001-5707-165X" + - family-names: Kim + given-names: Taeho + - family-names: Klevtsov + given-names: Sergey + orcid: "https://orcid.org/0000-0001-9044-1827" + - family-names: Lapene + given-names: Alexandre + - family-names: Magri + given-names: Victor A. P. + orcid: "https://orcid.org/0000-0002-3389-523X" + - family-names: Mazuyer + given-names: Antoine + orcid: "https://orcid.org/0000-0002-0329-3385" + - family-names: N'diaye + given-names: Mamadou + - family-names: Osei-Kuffuor + given-names: Daniel + orcid: "https://orcid.org/0000-0002-6111-6205" + - family-names: Povolny + given-names: Stefan + - family-names: Ren + given-names: Guotong + orcid: "https://orcid.org/0000-0002-5821-9158" + - family-names: Semnani + given-names: Shabnam J. + - family-names: Sherman + given-names: Chris S. + orcid: "https://orcid.org/0000-0003-3550-0657" + - family-names: Rey + given-names: Melvin + - family-names: Tchelepi + given-names: Hamdi A. + orcid: "https://orcid.org/0000-0002-3084-6635" + - family-names: Tobin + given-names: William R. + orcid: "https://orcid.org/0009-0001-3960-6064" + - family-names: Tomin + given-names: Pavel + orcid: "https://orcid.org/0000-0003-4862-4288" + - family-names: Untereiner + given-names: Lionel + orcid: "https://orcid.org/0000-0002-8025-2616" + - family-names: Vargas + given-names: Arturo + orcid: "https://orcid.org/0000-0001-8001-5517" + - family-names: Waziri + given-names: Sohail + - family-names: Wen + given-names: Xianhuan + orcid: "https://orcid.org/0000-0002-6055-4553" + - family-names: White + given-names: Joshua A. + orcid: "https://orcid.org/0000-0003-3491-142X" + - family-names: Wu + given-names: Hui + orcid: "https://orcid.org/0000-0002-9575-3886" + date-published: 2024-10-10 + doi: 10.21105/joss.06973 + issn: 2475-9066 + issue: 102 + journal: Journal of Open Source Software + publisher: + name: Open Journals + start: 6973 + title: "GEOS: A performance portable multi-physics simulation + framework for subsurface applications" + type: article + url: "https://joss.theoj.org/papers/10.21105/joss.06973" + volume: 9 +title: "GEOS: A performance portable multi-physics simulation framework + for subsurface applications" diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..51b8667db23 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,133 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +settgast1@llnl.gov. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000000..5d9b612c2fd --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,3 @@ +To contribute to GEOS, please refer to the [Contributing](https://geosx-geosx.readthedocs-hosted.com/en/latest/docs/sphinx/developerGuide/Contributing/index_contributing.html) section in the [GEOS developer guide](https://geosx-geosx.readthedocs-hosted.com/en/latest/docs/sphinx/developerGuide/Index.html#). + +To report a bug please open an [issue](https://github.com/GEOS-DEV/GEOS/issues) \ No newline at end of file diff --git a/COPYRIGHT b/COPYRIGHT index fa82eaed68c..8f0b0b47cbd 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,19 +1,20 @@ Intellectual Property Notice ---------------------------- -GEOSX is licensed under the GNU Lesser General Public License, Version 2.1. +GEOS is licensed under the GNU Lesser General Public License, Version 2.1. See the toplevel LICENSE file for details. -Copyrights and patents in the GEOSX project are retained by individual -contributors. The following copyright applies to each file in the GEOSX +Copyrights and patents in the GEOS project are retained by individual +contributors. The following copyright applies to each file in the GEOS distribution, unless otherwise stated in the file: - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved -No copyright assignment is required to contribute to GEOSX. See the +No copyright assignment is required to contribute to GEOS. See the toplevel CONTRIBUTORS file for a list of contributors. diff --git a/README.md b/README.md index ee7671ba61e..6d4cfee25ff 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![DOI](https://zenodo.org/badge/131810578.svg)](https://zenodo.org/badge/latestdoi/131810578) [![codecov](https://codecov.io/github/GEOS-DEV/GEOS/graph/badge.svg?token=0VTEHPQG58)](https://codecov.io/github/GEOS-DEV/GEOS) -![CI](https://github.com/GEOS-DEV/GEOS/actions/workflows/ci_tests.yml/badge.svg) +[![CI](https://github.com/GEOS-DEV/GEOS/actions/workflows/ci_tests.yml/badge.svg)](https://github.com/GEOS-DEV/GEOS/actions?query=branch%3Adevelop) [![docs](https://readthedocs.com/projects/geosx-geosx/badge/?version=latest)](https://geosx-geosx.readthedocs-hosted.com/en/latest/) Welcome to the GEOS project! @@ -21,10 +21,13 @@ page for more details on the HPC, numerics, and applied engineering components of this effort. Documentation ---------------------- +------------- -Our documentation is hosted [here](https://geosx-geosx.readthedocs-hosted.com/en/latest/?). +Please visit the [Main documentation for GEOS](https://geosx-geosx.readthedocs-hosted.com/en/latest/?). +If you would like to contribute to GEOS, please see the [developer guide](https://geosx-geosx.readthedocs-hosted.com/en/latest/docs/sphinx/developerGuide/Index.html) + +If you would like to report a bug, please submit an [issue](https://github.com/GEOS-DEV/GEOS/issues/new/choose). Who develops GEOS? ------------------- diff --git a/RELEASE b/RELEASE deleted file mode 100644 index 4d39ef0a36e..00000000000 --- a/RELEASE +++ /dev/null @@ -1,13 +0,0 @@ -******************************************************************************* - -GEOSX version 0.2.0 - - Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - Copyright (c) 2018-2020 TotalEnergies - Copyright (c) 2019- GEOSX Contributors - All rights reserved. See details in the file LICENSE. - -Unlimited Open Source - LGPL v2.1 Distribution -LLNL-CODE-812638 -OCEC-18-039 diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md deleted file mode 100644 index 5a0dc167c94..00000000000 --- a/RELEASE_NOTES.md +++ /dev/null @@ -1,82 +0,0 @@ -[comment]: # (-----------------------------------------------------------------) -[comment]: # (SPDX-License-Identifier: LGPL-2.1-only) -[comment]: # -[comment]: # (Copyright 2018-2020 Lawrence Livermore National Security LLC) -[comment]: # (Copyright 2018-2020 The Board of Trustees of the Leland Stanford) -[comment]: # ( Junior University) -[comment]: # (Copyright 2018-2020 Total, S.A) -[comment]: # (Copyright 2019- GEOSX Contributors) -[comment]: # (All right reserved) -[comment]: # -[comment]: # (For more details see:) -[comment]: # ( https://github.com/GEOS-DEV/GEOS/LICENSE) -[comment]: # ( https://github.com/GEOS-DEV/GEOS/COPYRIGHT) -[comment]: # ( https://github.com/GEOS-DEV/GEOS/CONTRIBUTORS) -[comment]: # ( https://github.com/GEOS-DEV/GEOS/NOTICE) -[comment]: # ( https://github.com/GEOS-DEV/GEOS/ACKNOWLEDGEMENTS) -[comment]: # ( https://github.com/GEOS-DEV/GEOS/RELEASE) - - -Version v0.2.0 -- Release date 2020-06-20 -========================================== -* Extensive updates to Data Repository -* Discretization - * Finite element interface - * Kernel launching interface looping abstraction - * Element formulations for 1st order: - * 8-node hexahedron - * 6-node wedge - * 5-node pyramid - * 4-node tetrahedron - * Cell-centered Finite Volume method with Two-point Flux Approximation (TPFA) - * Hybrid Finite Volume method with TPFA and quasi-TPFA inner products -* Physics Solvers - * Solid mechanics explicit on GPU, implicit assembly on GPU - * Single-phase flow (assembly on GPU) - * Classical FVM and Hybrid FVM formulations - * Porous matrix and DFM fracture flow - * Compositional multiphase flow (assembly on GPU) - * Fully implicit isothermal overall composition formulation - * Fluid constitutive models: - * Equation-of-state hydrocarbon compositional - * Three-phase extended black-oil - * Two-phase CO2-brine - * Multi-segmented wells for single phase and compositional multiphase flow (assembly on GPU) - * Surface Generation - * Topology change (legacy GEOS approach) -* Embedded Discrete Fractures - * Enriched finite element method for the discretization of the mechanics - * Piecewise constant displacement jump enrichment - * Hydrofracture solver (legacy GEOS approach) - * Small strain aligned contact using Lagrange multipliers - * Discrete fracture model using a low-order stabilized mixed finite element method - * Proppant Transport Solver - * FVM formulation - * Major physical processes modeled: - * Proppant-fluid slurry flow and multicomponent transport in fractures - * Proppant gravitational settling - * Proppant bed build-up and development space -* Mesh Structure - * Introduced the concept of extrinsic mesh data - * Fracture elements to represent FV cells in fractures -* VTK output -* Linear algebra interface layers for Hypre, Trilinos, Petsc - * Common interface for supported linear algebra packages - * Krylov solvers (CG, GMRES, BiCGSTAB) - * Preconditioners (algebraic multigrid, incomplete factorizations) - * Block matrix and vector support - * Serial and parallel direct solvers - - -Version v0.1.0 -- Release date 2018-02-15 -========================================== -Initial Code Release containing: -* Data Repository - * Group - * Wrapper - * Input processing -* Physics solver hierarchy - * Solid Mechanics -* Mesh data structure - * NodeManager, EdgeManager, FaceManager, ElementManager - * Silo Output diff --git a/examples/GPU/beamBending.xml b/examples/GPU/beamBending.xml index 85f7acfb6ae..755d34970e4 100644 --- a/examples/GPU/beamBending.xml +++ b/examples/GPU/beamBending.xml @@ -77,7 +77,7 @@ diff --git a/examples/ObjectCatalog/Base.hpp b/examples/ObjectCatalog/Base.hpp index 6269bf70b46..2075058c05a 100644 --- a/examples/ObjectCatalog/Base.hpp +++ b/examples/ObjectCatalog/Base.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/examples/ObjectCatalog/Derived1.cpp b/examples/ObjectCatalog/Derived1.cpp index 0308729cbbf..ef257e85a78 100644 --- a/examples/ObjectCatalog/Derived1.cpp +++ b/examples/ObjectCatalog/Derived1.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/examples/ObjectCatalog/Derived1.hpp b/examples/ObjectCatalog/Derived1.hpp index c7821219a2e..557ae84e409 100644 --- a/examples/ObjectCatalog/Derived1.hpp +++ b/examples/ObjectCatalog/Derived1.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/examples/ObjectCatalog/Derived2.cpp b/examples/ObjectCatalog/Derived2.cpp index 8c135c22002..59e61ad94d1 100644 --- a/examples/ObjectCatalog/Derived2.cpp +++ b/examples/ObjectCatalog/Derived2.cpp @@ -2,15 +2,17 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ + #include "Derived2.hpp" diff --git a/examples/ObjectCatalog/Derived2.hpp b/examples/ObjectCatalog/Derived2.hpp index bb299a83603..bc3ebede41a 100644 --- a/examples/ObjectCatalog/Derived2.hpp +++ b/examples/ObjectCatalog/Derived2.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/examples/ObjectCatalog/main.cpp b/examples/ObjectCatalog/main.cpp index 2fa0426759a..2a9ed5ba436 100644 --- a/examples/ObjectCatalog/main.cpp +++ b/examples/ObjectCatalog/main.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,7 +17,7 @@ #include -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" #include "Base.hpp" #include "Derived1.hpp" diff --git a/examples/advanced_xml_features/included/included_b.xml b/examples/advanced_xml_features/included/included_b.xml index bc052d6a51e..ba2aa87baed 100644 --- a/examples/advanced_xml_features/included/included_b.xml +++ b/examples/advanced_xml_features/included/included_b.xml @@ -30,7 +30,7 @@ diff --git a/examples/advanced_xml_features/parameters_example.xml b/examples/advanced_xml_features/parameters_example.xml index 7124be3aa8f..fa31e5d4bd3 100644 --- a/examples/advanced_xml_features/parameters_example.xml +++ b/examples/advanced_xml_features/parameters_example.xml @@ -96,7 +96,7 @@ XML Units: diff --git a/examples/advanced_xml_features/symbolic_math_example.xml b/examples/advanced_xml_features/symbolic_math_example.xml index a0a71b65547..e4d3f4942dd 100644 --- a/examples/advanced_xml_features/symbolic_math_example.xml +++ b/examples/advanced_xml_features/symbolic_math_example.xml @@ -106,7 +106,7 @@ XML Symbolic Math: diff --git a/examples/pygeosxExamples/modifyBoundaryCondition/pkn_example.xml b/examples/pygeosxExamples/modifyBoundaryCondition/pkn_example.xml index 18702b7b27f..94db4f07eb6 100644 --- a/examples/pygeosxExamples/modifyBoundaryCondition/pkn_example.xml +++ b/examples/pygeosxExamples/modifyBoundaryCondition/pkn_example.xml @@ -22,7 +22,6 @@ name="hydrofracture" solidSolverName="lagsolve" logLevel="1" - contactRelationName="fractureContact" flowSolverName="SinglePhaseFlow" surfaceGeneratorName="SurfaceGen" targetRegions="{ Domain, Fracture }"> @@ -39,8 +38,8 @@ timeIntegrationOption="QuasiStatic" discretization="FE1" name="lagsolve" - contactRelationName="fractureContact" - targetRegions="{ Domain, Fracture }"> + targetRegions="{ Domain, Fracture }" + contactPenaltyStiffness="1.0e0"> + materialList="{ water, rock, fractureFilling, fracturePorosity, fracturePerm, nullSolid, hApertureTable }"/> @@ -112,9 +111,11 @@ compressibility="0.0"/> + name="fractureContact"/> + + diff --git a/examples/pygeosxExamples/parametricSurfaceMapping/parametricMesh.xml b/examples/pygeosxExamples/parametricSurfaceMapping/parametricMesh.xml index 5b8ce510898..37f399f1b06 100644 --- a/examples/pygeosxExamples/parametricSurfaceMapping/parametricMesh.xml +++ b/examples/pygeosxExamples/parametricSurfaceMapping/parametricMesh.xml @@ -58,7 +58,7 @@ diff --git a/examples/sedovKernelTest.xml b/examples/sedovKernelTest.xml index 99b79f3d217..9d56d5b7bf7 100644 --- a/examples/sedovKernelTest.xml +++ b/examples/sedovKernelTest.xml @@ -68,7 +68,7 @@ diff --git a/host-configs/LBL/cori-gcc@8.1.0.cmake b/host-configs/LBL/cori-gcc@8.1.0.cmake index 8b6f5af6517..b0a50872aa3 100644 --- a/host-configs/LBL/cori-gcc@8.1.0.cmake +++ b/host-configs/LBL/cori-gcc@8.1.0.cmake @@ -24,11 +24,7 @@ set(MPI_Fortran_COMPILER ${MPI_HOME}/bin/mpifort CACHE PATH "") set(MPIEXEC /usr/bin/srun CACHE PATH "") set(MPIEXEC_NUMPROC_FLAG "-n" CACHE STRING "") -set(GEOSX_TPL_DIR "/global/project/projectdirs/m1411/GEOSX/tpls/install-cori-gcc\@8.1.0-release-24-07-20" CACHE PATH "" ) - - -set(GEOSX_LINK_PREPEND_FLAG "-Wl,--whole-archive" CACHE STRING "" FORCE) -set(GEOSX_LINK_POSTPEND_FLAG "-Wl,--no-whole-archive" CACHE STRING "" FORCE) +set(GEOS_TPL_DIR "/global/project/projectdirs/m1411/GEOSX/tpls/install-cori-gcc\@8.1.0-release-24-07-20" CACHE PATH "" ) set(ENABLE_SPHINX_EXECUTABLE OFF CACHE BOOL "") set(ENABLE_UNCRUSTIFY OFF CACHE BOOL "") diff --git a/host-configs/LBL/cori-intel.cmake b/host-configs/LBL/cori-intel.cmake index 85044651337..f9ff8ec447c 100644 --- a/host-configs/LBL/cori-intel.cmake +++ b/host-configs/LBL/cori-intel.cmake @@ -24,10 +24,7 @@ set(MPI_Fortran_COMPILER "ftn" CACHE PATH "" FORCE) set(MPIEXEC "/usr/bin/srun" CACHE PATH "") set(MPIEXEC_NUMPROC_FLAG "-n" CACHE STRING "") -set(GEOSX_TPL_DIR "/global/project/projectdirs/m1411/GEOSX/tpls/install-cori-intel-release-22-07-20" CACHE PATH "" ) - -set(GEOSX_LINK_PREPEND_FLAG "-Wl,--whole-archive" CACHE STRING "" FORCE) -set(GEOSX_LINK_POSTPEND_FLAG "-Wl,--no-whole-archive" CACHE STRING "" FORCE) +set(GEOS_TPL_DIR "/global/project/projectdirs/m1411/GEOSX/tpls/install-cori-intel-release-22-07-20" CACHE PATH "" ) set(ENABLE_SPHINX_EXECUTABLE OFF CACHE BOOL "") set(ENABLE_UNCRUSTIFY OFF CACHE BOOL "") diff --git a/host-configs/LLNL/dane-gcc-12.cmake b/host-configs/LLNL/dane-gcc-12.cmake new file mode 100644 index 00000000000..b45d2dba68a --- /dev/null +++ b/host-configs/LLNL/dane-gcc-12.cmake @@ -0,0 +1,12 @@ +include(${CMAKE_CURRENT_LIST_DIR}/../../src/coreComponents/LvArray/host-configs/LLNL/dane-gcc-12.cmake) + +# MPI +set(MPI_HOME /usr/tce/packages/mvapich2/mvapich2-2.3.7-gcc-12.1.1-magic CACHE PATH "") + +# ATS +set(ATS_ARGUMENTS "--machine slurm112" CACHE STRING "") + +# This is here to note the required flags for using valgrind. These will have to be propagated to the TPL's +#set( CMAKE_CXX_FLAGS "-march=x86-64-v2 -mno-avx512f" CACHE STRING "" FORCE) + +include(${CMAKE_CURRENT_LIST_DIR}/llnl-cpu-base.cmake) diff --git a/host-configs/LLNL/lassen-base.cmake b/host-configs/LLNL/lassen-base.cmake index 72747c4f7d8..b8014d6410b 100644 --- a/host-configs/LLNL/lassen-base.cmake +++ b/host-configs/LLNL/lassen-base.cmake @@ -7,8 +7,7 @@ # ############################################################################### -set( GEOSX_BUILD_SHARED_LIBS ON CACHE BOOL "" ) -set( GEOSX_BUILD_OBJ_LIBS OFF CACHE BOOL "" ) +set( GEOS_BUILD_OBJ_LIBS OFF CACHE BOOL "" ) # Fortran set(ENABLE_FORTRAN OFF CACHE BOOL "") @@ -31,19 +30,19 @@ set(ENABLE_CUDA_NVTOOLSEXT OFF CACHE BOOL "") # ESSL set(ENABLE_ESSL ON CACHE BOOL "" FORCE ) -set(ESSL_INCLUDE_DIRS /usr/tcetmp/packages/essl/essl-6.3.0.2/include CACHE STRING "" FORCE ) -set(ESSL_LIBRARIES /usr/tcetmp/packages/essl/essl-6.3.0.2/lib64/libesslsmpcuda.so +set(ESSL_DIR /usr/tcetmp/packages/essl/essl-6.3.0.2 CACHE STRING "" FORCE ) +set(ESSL_INCLUDE_DIRS ${ESSL_DIR}/include CACHE STRING "" FORCE ) +set(ESSL_LIBRARIES ${ESSL_DIR}/lib64/libesslsmpcuda.so ${CUDA_TOOLKIT_ROOT_DIR}/lib64/libcublas.so ${CUDA_TOOLKIT_ROOT_DIR}/lib64/libcublasLt.so ${CUDA_TOOLKIT_ROOT_DIR}/lib64/libcudart.so - /usr/tcetmp/packages/essl/essl-6.3.0.2/lib64/liblapackforessl.so - /usr/tcetmp/packages/essl/essl-6.3.0.2/lib64/liblapackforessl_.so + ${ESSL_DIR}/lib64/liblapackforessl.so + ${ESSL_DIR}/lib64/liblapackforessl_.so CACHE PATH "" FORCE ) - + # TPL set(ENABLE_PAPI OFF CACHE BOOL "") set(SILO_BUILD_TYPE powerpc64-unknown-linux-gnu CACHE STRING "") -set(ENABLE_FESAPI OFF CACHE BOOL "" FORCE) # GEOSX specific options set(ENABLE_PVTPackage ON CACHE BOOL "") @@ -54,7 +53,7 @@ if( ${ENABLE_HYPRE_DEVICE} STREQUAL "HIP" OR ${ENABLE_HYPRE_DEVICE} STREQUAL "CU set(ENABLE_TRILINOS OFF CACHE BOOL "" FORCE ) else() set(ENABLE_HYPRE OFF CACHE BOOL "" FORCE ) - set(GEOSX_LA_INTERFACE "Trilinos" CACHE STRING "" FORCE ) + set(GEOS_LA_INTERFACE "Trilinos" CACHE STRING "" FORCE ) endif() # Documentation diff --git a/host-configs/LLNL/lassen-clang-10-cuda-11.cmake b/host-configs/LLNL/lassen-clang-10-cuda-11.cmake index 74c04803ed8..9c9ff7de26c 100644 --- a/host-configs/LLNL/lassen-clang-10-cuda-11.cmake +++ b/host-configs/LLNL/lassen-clang-10-cuda-11.cmake @@ -1,7 +1,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/../../src/coreComponents/LvArray/host-configs/LLNL/lassen-clang-10-cuda-11.cmake) # Fortran -set(CMAKE_Fortran_COMPILER /usr/tce/packages/xl/xl-2022.08.19-cuda-11.8.0/bin/xlf_r CACHE PATH "") +set(CMAKE_Fortran_COMPILER /usr/tce/packages/xl/xl-2023.06.28/xlf/16.1.1/bin/xlf CACHE PATH "") set(CMAKE_Fortran_FLAGS_RELEASE "-O3 -DNDEBUG -qarch=pwr9 -qtune=pwr9" CACHE STRING "") set(FORTRAN_MANGLE_NO_UNDERSCORE ON CACHE BOOL "") set(OpenMP_Fortran_FLAGS "-qsmp=omp" CACHE STRING "") @@ -9,8 +9,8 @@ set(OpenMP_Fortran_LIB_NAMES "" CACHE STRING "") # MPI set(MPI_HOME /usr/tce/packages/spectrum-mpi/spectrum-mpi-rolling-release-clang-10.0.1-gcc-8.3.1 CACHE PATH "") -set(MPI_Fortran_COMPILER /usr/tce/packages/spectrum-mpi/spectrum-mpi-rolling-release-xl-2022.08.19-cuda-11.8.0/bin/mpifort CACHE PATH "") +set(MPI_Fortran_COMPILER /usr/tce/packages/spectrum-mpi/spectrum-mpi-rolling-release-xl-2023.06.28-cuda-11.8.0/bin/mpifort CACHE PATH "") include(${CMAKE_CURRENT_LIST_DIR}/lassen-base.cmake) -set(ENABLE_CUDA_NVTOOLSEXT OFF CACHE BOOL "") \ No newline at end of file +set(ENABLE_CUDA_NVTOOLSEXT ON CACHE BOOL "") \ No newline at end of file diff --git a/host-configs/LLNL/lassen-clang-13-cuda-11.cmake b/host-configs/LLNL/lassen-clang-13-cuda-11.cmake index 428274e26d2..c57f0014e51 100644 --- a/host-configs/LLNL/lassen-clang-13-cuda-11.cmake +++ b/host-configs/LLNL/lassen-clang-13-cuda-11.cmake @@ -1,7 +1,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/../../src/coreComponents/LvArray/host-configs/LLNL/lassen-clang-13-cuda-11.cmake) # Fortran -set(CMAKE_Fortran_COMPILER /usr/tce/packages/xl/xl-2022.08.19-cuda-11.8.0/bin/xlf_r CACHE PATH "") +set(CMAKE_Fortran_COMPILER /usr/tce/packages/xl/xl-2023.06.28/xlf/16.1.1/bin/xlf CACHE PATH "") set(CMAKE_Fortran_FLAGS_RELEASE "-O3 -DNDEBUG -qarch=pwr9 -qtune=pwr9" CACHE STRING "") set(FORTRAN_MANGLE_NO_UNDERSCORE ON CACHE BOOL "") set(OpenMP_Fortran_FLAGS "-qsmp=omp" CACHE STRING "") @@ -9,7 +9,7 @@ set(OpenMP_Fortran_LIB_NAMES "" CACHE STRING "") # MPI set(MPI_HOME /usr/tce/packages/spectrum-mpi/spectrum-mpi-rolling-release-clang-13.0.1-gcc-8.3.1 CACHE PATH "") -set(MPI_Fortran_COMPILER /usr/tce/packages/spectrum-mpi/spectrum-mpi-rolling-release-xl-2022.08.19-cuda-11.8.0/bin/mpifort CACHE PATH "") +set(MPI_Fortran_COMPILER /usr/tce/packages/spectrum-mpi/spectrum-mpi-rolling-release-xl-2023.06.28-cuda-11.8.0/bin/mpifort CACHE PATH "") include(${CMAKE_CURRENT_LIST_DIR}/lassen-base.cmake) diff --git a/host-configs/LLNL/lassen-clang-13-cuda-12.cmake b/host-configs/LLNL/lassen-clang-13-cuda-12.cmake new file mode 100644 index 00000000000..14ee23d0c81 --- /dev/null +++ b/host-configs/LLNL/lassen-clang-13-cuda-12.cmake @@ -0,0 +1,25 @@ +include(${CMAKE_CURRENT_LIST_DIR}/../../src/coreComponents/LvArray/host-configs/LLNL/lassen-clang-13-cuda-12.cmake) + +# Fortran +set(CMAKE_Fortran_COMPILER /usr/tce/packages/gcc/gcc-8.3.1/bin/gfortran CACHE PATH "") +set(CMAKE_Fortran_FLAGS_RELEASE "-O3 -DNDEBUG -mtune=power9" CACHE STRING "") +set(FORTRAN_MANGLE_NO_UNDERSCORE ON CACHE BOOL "") +set(OpenMP_Fortran_FLAGS "-fopenmp" CACHE STRING "") +set(OpenMP_Fortran_LIB_NAMES "" CACHE STRING "") + +# MPI +set(MPI_HOME /usr/tce/packages/spectrum-mpi/spectrum-mpi-rolling-release-clang-13.0.1-gcc-8.3.1/ CACHE PATH "") +set(MPI_Fortran_COMPILER /usr/tce/packages/spectrum-mpi/spectrum-mpi-rolling-release-gcc-8.3.1/bin/mpifort CACHE PATH "") + +include(${CMAKE_CURRENT_LIST_DIR}/lassen-base.cmake) + +# Overwrite options set on lassen-base.cmake +set(ENABLE_OPENMP OFF CACHE BOOL "" FORCE) +set(ENABLE_CUDA_NVTOOLSEXT ON CACHE BOOL "") + +# Overwrite ESSL defaults from lassen-base.cmake +# Reason: libesslsmpcuda.so depends on cuda-11 +set(ESSL_LIBRARIES ${ESSL_DIR}/lib64/libessl.so + ${ESSL_DIR}/lib64/liblapackforessl.so + ${ESSL_DIR}/lib64/liblapackforessl_.so + CACHE PATH "" FORCE ) diff --git a/host-configs/LLNL/lassen-gcc-8-cuda-11.cmake b/host-configs/LLNL/lassen-gcc-8-cuda-11.cmake index fa12811e52e..3e9fd6783d7 100644 --- a/host-configs/LLNL/lassen-gcc-8-cuda-11.cmake +++ b/host-configs/LLNL/lassen-gcc-8-cuda-11.cmake @@ -14,4 +14,6 @@ set(FORTRAN_MANGLE_NO_UNDERSCORE OFF CACHE BOOL "") set(MPI_HOME /usr/tce/packages/spectrum-mpi/spectrum-mpi-rolling-release-gcc-8.3.1 CACHE PATH "") set(MPI_Fortran_COMPILER ${MPI_HOME}/bin/mpifort CACHE PATH "") +set(ENABLE_CUDA_NVTOOLSEXT ON CACHE BOOL "") + include(${CMAKE_CURRENT_LIST_DIR}/lassen-base.cmake) diff --git a/host-configs/LLNL/llnl-cpu-base.cmake b/host-configs/LLNL/llnl-cpu-base.cmake new file mode 100644 index 00000000000..58847109bac --- /dev/null +++ b/host-configs/LLNL/llnl-cpu-base.cmake @@ -0,0 +1,72 @@ +############################################################################### +# +# Base configuration for LC cpu builds +# Calling configuration file must define the following CMAKE variables: +# +# MPI_HOME +# +############################################################################### + +# Fortran +set(ENABLE_FORTRAN OFF CACHE BOOL "") + +# Fortran +set(CMAKE_Fortran_COMPILER /usr/tce/packages/gcc/gcc-12.1.1-magic/bin/gfortran CACHE PATH "") +set(CMAKE_Fortran_FLAGS_RELEASE "-O3 -DNDEBUG -march=native -mtune=native" CACHE STRING "") + +# PYGEOSX +set(ENABLE_PYGEOSX ON CACHE BOOL "") +set(Python3_ROOT_DIR /usr/gapps/GEOSX/thirdPartyLibs/python/quartz-gcc-python/python CACHE PATH "") +set(Python3_EXECUTABLE ${Python3_ROOT_DIR}/bin/python3 CACHE PATH "") + +# YAPF python formatting +set(YAPF_EXECUTABLE /usr/gapps/GEOSX/thirdPartyLibs/python/quartz-gcc-python/python/bin/yapf CACHE PATH "" FORCE) + +# Sphinx +set(SPHINX_EXECUTABLE /usr/gapps/GEOSX/thirdPartyLibs/python/quartz-gcc-python/python/bin/sphinx-build CACHE PATH "" FORCE) + +# ATS +set(ATS_ARGUMENTS "--machine slurm56" CACHE STRING "") + +# MPI +set(ENABLE_MPI ON CACHE BOOL "") +set(MPI_C_COMPILER ${MPI_HOME}/bin/mpicc CACHE PATH "") +set(MPI_CXX_COMPILER ${MPI_HOME}/bin/mpicxx CACHE PATH "") +set(MPI_Fortran_COMPILER ${MPI_HOME}/bin/mpifort CACHE PATH "") +set(MPIEXEC /usr/bin/srun CACHE PATH "") +set(MPIEXEC_NUMPROC_FLAG "-n" CACHE STRING "") + +# PAPI (For TPL caliper builds) +set(ENABLE_PAPI ON CACHE BOOL "") +set(PAPI_PREFIX /usr/tce/packages/papi/papi-6.0.0.1/ CACHE PATH "") + +# OpenMP +set(ENABLE_OPENMP ON CACHE BOOL "") + +# GEOSX specific options +set(ENABLE_PVTPackage ON CACHE BOOL "") +set(ENABLE_PETSC OFF CACHE BOOL "Enables PETSc." FORCE) + +# PYGEOSX +set(ENABLE_PYGEOSX ON CACHE BOOL "") +set(Python3_ROOT_DIR /usr/apps/python-3.11.5 CACHE PATH "") +set(Python3_EXECUTABLE ${Python3_ROOT_DIR}/bin/python3 CACHE PATH "") + +# caliper +set(ENABLE_CALIPER ON CACHE BOOL "" FORCE) +set(ENABLE_CALIPER_HYPRE ON CACHE BOOL "" FORCE) + +# MKL +set(ENABLE_MKL ON CACHE BOOL "") +set(MKL_ROOT /usr/tce/packages/mkl/mkl-2022.1.0) +set(MKL_INCLUDE_DIRS ${MKL_ROOT}/include CACHE STRING "") +set(MKL_LIBRARIES ${MKL_ROOT}/lib/intel64/libmkl_intel_lp64.so + ${MKL_ROOT}/lib/intel64/libmkl_gnu_thread.so + ${MKL_ROOT}/lib/intel64/libmkl_core.so + CACHE STRING "") + +# ATS +set(USER $ENV{USER} CACHE STRING "") +set(ATS_WORKING_DIR "/p/lustre2/${USER}/integratedTestsGEOS/${CONFIG_NAME}" CACHE PATH "") +set(ATS_BASELINE_DIR "/p/lustre2/${USER}/integratedTestsGEOS/baselines" CACHE PATH "") +include(${CMAKE_CURRENT_LIST_DIR}/../tpls.cmake) diff --git a/host-configs/LLNL/quartz-base.cmake b/host-configs/LLNL/quartz-base.cmake deleted file mode 100644 index 38047f8e0ce..00000000000 --- a/host-configs/LLNL/quartz-base.cmake +++ /dev/null @@ -1,69 +0,0 @@ -############################################################################### -# -# Base configuration for LC Quartz builds -# Calling configuration file must define the following CMAKE variables: -# -# MPI_HOME -# -############################################################################### - -# Fortran -set(ENABLE_FORTRAN OFF CACHE BOOL "") - -# MPI -set(ENABLE_MPI ON CACHE BOOL "") -set(MPI_C_COMPILER ${MPI_HOME}/bin/mpicc CACHE PATH "") -set(MPI_CXX_COMPILER ${MPI_HOME}/bin/mpicxx CACHE PATH "") -set(MPI_Fortran_COMPILER ${MPI_HOME}/bin/mpifort CACHE PATH "") -set(MPIEXEC /usr/bin/srun CACHE PATH "") -set(MPIEXEC_NUMPROC_FLAG "-n" CACHE STRING "") - -# PAPI (For TPL caliper builds) -set(ENABLE_PAPI ON CACHE BOOL "") -set(PAPI_PREFIX /usr/tce/packages/papi/papi-5.4.3 CACHE PATH "") - -# OpenMP -set(ENABLE_OPENMP ON CACHE BOOL "") - -# GEOSX specific options -set(ENABLE_PVTPackage ON CACHE BOOL "") -set(ENABLE_PETSC OFF CACHE BOOL "Enables PETSc." FORCE) - -# PYGEOSX -set(ENABLE_PYGEOSX ON CACHE BOOL "") -set(Python3_ROOT_DIR /usr/gapps/GEOSX/thirdPartyLibs/python/quartz-gcc-python/python CACHE PATH "") -set(Python3_EXECUTABLE ${Python3_ROOT_DIR}/bin/python3 CACHE PATH "") - -# YAPF python formatting -set(YAPF_EXECUTABLE /usr/gapps/GEOSX/thirdPartyLibs/python/quartz-gcc-python/python/bin/yapf CACHE PATH "" FORCE) - -# Sphinx -set(SPHINX_EXECUTABLE /usr/gapps/GEOSX/thirdPartyLibs/python/quartz-gcc-python/python/bin/sphinx-build CACHE PATH "" FORCE) - - -set(ENABLE_FESAPI OFF CACHE BOOL "" FORCE) - -# caliper -set(ENABLE_CALIPER ON CACHE BOOL "" FORCE) -set(ENABLE_CALIPER_HYPRE ON CACHE BOOL "" FORCE) - -# MKL -set(ENABLE_MKL ON CACHE BOOL "") -set(MKL_ROOT /usr/tce/packages/mkl/mkl-2022.1.0) -set(MKL_INCLUDE_DIRS ${MKL_ROOT}/include CACHE STRING "") -set(MKL_LIBRARIES ${MKL_ROOT}/lib/intel64/libmkl_intel_lp64.so - ${MKL_ROOT}/lib/intel64/libmkl_gnu_thread.so - ${MKL_ROOT}/lib/intel64/libmkl_core.so - CACHE STRING "") - -# ATS -set(ATS_ARGUMENTS "--machine slurm36" CACHE STRING "") -# set(USER $ENV{USER} CACHE STRING "") -# set(ATS_WORKING_DIR "/p/lustre2/${USER}/integratedTests/${CONFIG_NAME}" CACHE PATH "") -# set(ATS_BASELINE_DIR "/p/lustre2/${USER}/integratedTests/baselines" CACHE PATH "") - -# Temporary argument for python module change testing -# set(GEOS_PYTHON_PACKAGES_BRANCH "feature/sherman/outOfPlaceATS" CACHE STRING "" FORCE) - - -include(${CMAKE_CURRENT_LIST_DIR}/../tpls.cmake) diff --git a/host-configs/LLNL/quartz-clang-14.cmake b/host-configs/LLNL/quartz-clang-14.cmake deleted file mode 100644 index 797e6acb2f3..00000000000 --- a/host-configs/LLNL/quartz-clang-14.cmake +++ /dev/null @@ -1,10 +0,0 @@ -include(${CMAKE_CURRENT_LIST_DIR}/../../src/coreComponents/LvArray/host-configs/LLNL/quartz-clang-14.cmake) - -# Fortran -set(CMAKE_Fortran_COMPILER /usr/tce/packages/gcc/gcc-12.1.1-magic/bin/gfortran CACHE PATH "") -set(CMAKE_Fortran_FLAGS_RELEASE "-O3 -DNDEBUG -march=native -mtune=native" CACHE STRING "") - -# MPI -set(MPI_HOME /usr/tce/packages/mvapich2/mvapich2-2.3.6-clang-14.0.6-magic CACHE PATH "") - -include(${CMAKE_CURRENT_LIST_DIR}/quartz-base.cmake) diff --git a/host-configs/LLNL/quartz-gcc-12.cmake b/host-configs/LLNL/quartz-gcc-12.cmake deleted file mode 100644 index a4e92537ad6..00000000000 --- a/host-configs/LLNL/quartz-gcc-12.cmake +++ /dev/null @@ -1,16 +0,0 @@ -include(${CMAKE_CURRENT_LIST_DIR}/../../src/coreComponents/LvArray/host-configs/LLNL/quartz-gcc-12.cmake) - -# C++ -# The "-march=native -mtune=native" which LvArray adds breaks the PVT package. -set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "" FORCE) - -# Fortran -set(CMAKE_Fortran_COMPILER /usr/tce/packages/gcc/gcc-12.1.1-magic/bin/gfortran CACHE PATH "") -set(CMAKE_Fortran_FLAGS_RELEASE "-O3 -DNDEBUG -march=native -mtune=native" CACHE STRING "") - -# MPI -set(MPI_HOME /usr/tce/packages/mvapich2/mvapich2-2.3.6-gcc-12.1.1-magic CACHE PATH "") - -set(ENABLE_TRILINOS OFF CACHE BOOL "" FORCE) - -include(${CMAKE_CURRENT_LIST_DIR}/quartz-base.cmake) diff --git a/host-configs/LLNL/quartz-icc-19.cmake b/host-configs/LLNL/quartz-icc-19.cmake deleted file mode 100644 index a18d3f3da03..00000000000 --- a/host-configs/LLNL/quartz-icc-19.cmake +++ /dev/null @@ -1,24 +0,0 @@ -include(${CMAKE_CURRENT_LIST_DIR}/../../src/coreComponents/LvArray/host-configs/LLNL/quartz-icc-19.cmake) - -# Fortran -set(CMAKE_Fortran_COMPILER ${COMPILER_DIR}/bin/intel64/ifort CACHE PATH "") -set(CMAKE_Fortran_FLAGS_RELEASE "-DNDEBUG -march=native -mtune=native -qoverride-limits" CACHE STRING "") -set(CMAKE_Fortran_FLAGS_RELWITHDEBINFO "-g ${CMAKE_Fortran_FLAGS_RELEASE}" CACHE STRING "") - -# MPI -set(MPI_HOME /usr/tce/packages/mvapich2/mvapich2-2.3-intel-19.0.4 CACHE PATH "") - -# GEOSX specific options -set(ENABLE_XML_UPDATES OFF CACHE BOOL "") - -# MKL -set(ENABLE_MKL ON CACHE BOOL "") -set(MKL_ROOT /usr/tce/packages/mkl/mkl-2019.0) -set(MKL_INCLUDE_DIRS ${MKL_ROOT}/include CACHE STRING "") -set(MKL_LIBRARIES ${MKL_ROOT}/lib/libmkl_intel_lp64.so - ${MKL_ROOT}/lib/libmkl_intel_thread.so - ${MKL_ROOT}/lib/libmkl_core.so - ${COMPILER_DIR}/compiler/lib/intel64/libiomp5.so - CACHE STRING "") - -include(${CMAKE_CURRENT_LIST_DIR}/quartz-base.cmake) diff --git a/host-configs/LLNL/ruby-clang-14.cmake b/host-configs/LLNL/ruby-clang-14.cmake new file mode 100644 index 00000000000..c9d928a1d37 --- /dev/null +++ b/host-configs/LLNL/ruby-clang-14.cmake @@ -0,0 +1,10 @@ +include(${CMAKE_CURRENT_LIST_DIR}/../../src/coreComponents/LvArray/host-configs/LLNL/ruby-clang-14.cmake) + +# MPI +set(MPI_HOME /usr/tce/packages/mvapich2/mvapich2-2.3.7-clang-14.0.6-magic CACHE PATH "") +# This is here to note the required flags for using valgrind. These will have to be propagated to the TPL's +#set( CMAKE_CXX_FLAGS "-march=x86-64-v2 -mno-avx512f" CACHE STRING "" FORCE) +# This is what is required for using address sanitizer. This should be put into GeosxOptions.cmake when it is incorporated into the build options. +#set( CMAKE_CXX_FLAGS "-g -O2 -fno-omit-frame-pointer -fsanitize=address" CACHE STRING "" FORCE) + +include(${CMAKE_CURRENT_LIST_DIR}/llnl-cpu-base.cmake) diff --git a/host-configs/LLNL/ruby-gcc-12.cmake b/host-configs/LLNL/ruby-gcc-12.cmake new file mode 100644 index 00000000000..2c369280809 --- /dev/null +++ b/host-configs/LLNL/ruby-gcc-12.cmake @@ -0,0 +1,9 @@ +include(${CMAKE_CURRENT_LIST_DIR}/../../src/coreComponents/LvArray/host-configs/LLNL/ruby-gcc-12.cmake) + +# MPI +set(MPI_HOME /usr/tce/packages/mvapich2/mvapich2-2.3.7-gcc-12.1.1-magic CACHE PATH "") + +# ATS +set(ATS_ARGUMENTS "--machine slurm56" CACHE STRING "") + +include(${CMAKE_CURRENT_LIST_DIR}/llnl-cpu-base.cmake) diff --git a/host-configs/LLNL/tioga-base.cmake b/host-configs/LLNL/tioga-base.cmake index 7f87bf40bc4..02a9317b688 100644 --- a/host-configs/LLNL/tioga-base.cmake +++ b/host-configs/LLNL/tioga-base.cmake @@ -19,7 +19,7 @@ set( CAMP_STANDALONE TRUE CACHE BOOL "" ) set( ENABLE_ROCM ON CACHE BOOL "" FORCE ) set( ROCM_ROOT "${HIP_ROOT}" CACHE PATH "" ) -set( GEOSX_BUILD_OBJ_LIBS OFF CACHE BOOL "" FORCE ) +set( GEOS_BUILD_OBJ_LIBS OFF CACHE BOOL "" FORCE ) set( ENABLE_GTEST_DEATH_TESTS OFF CACHE BOOL "" ) set( gtest_disable_pthreads ON CACHE BOOL "" ) diff --git a/host-configs/LLNL/tioga-cce-15.cmake b/host-configs/LLNL/tioga-cce-15.cmake index c832a481ebf..1d63b429c2b 100644 --- a/host-configs/LLNL/tioga-cce-15.cmake +++ b/host-configs/LLNL/tioga-cce-15.cmake @@ -1,22 +1,22 @@ include(${CMAKE_CURRENT_LIST_DIR}/../../src/coreComponents/LvArray/host-configs/LLNL/tioga-cce-15.cmake) include(${CMAKE_CURRENT_LIST_DIR}/tioga-base.cmake) -set( CONDUIT_DIR "${GEOSX_TPL_DIR}/conduit-0.8.7" CACHE PATH "" ) -set( HDF5_DIR "${GEOSX_TPL_DIR}/hdf5-1.14.1-2" CACHE PATH "" ) +set( CONDUIT_DIR "${GEOS_TPL_DIR}/conduit-0.8.7" CACHE PATH "" ) +set( HDF5_DIR "${GEOS_TPL_DIR}/hdf5-1.14.1-2" CACHE PATH "" ) set( BLAS_DIR "/opt/rocm-5.4.3/" CACHE PATH "" ) -set( PUGIXML_DIR "${GEOSX_TPL_DIR}/pugixml-1.13" CACHE PATH "" ) -set( FMT_DIR "${GEOSX_TPL_DIR}/fmt-10.0.0" CACHE PATH "" ) -set( SUITESPARSE_DIR "${GEOSX_TPL_DIR}/suite-sparse-5.10.1" CACHE PATH "" ) +set( PUGIXML_DIR "${GEOS_TPL_DIR}/pugixml-1.13" CACHE PATH "" ) +set( FMT_DIR "${GEOS_TPL_DIR}/fmt-10.0.0" CACHE PATH "" ) +set( SUITESPARSE_DIR "${GEOS_TPL_DIR}/suite-sparse-5.10.1" CACHE PATH "" ) # HYPRE options set( ENABLE_HYPRE_DEVICE "HIP" CACHE STRING "" ) set( ENABLE_HYPRE_MIXINT FALSE CACHE STRING "" ) -set( HYPRE_DIR "${GEOSX_TPL_DIR}/hypre-develop" CACHE PATH "" ) +set( HYPRE_DIR "${GEOS_TPL_DIR}/hypre-develop" CACHE PATH "" ) set( ENABLE_CALIPER ON CACHE BOOL "" FORCE ) -set( CALIPER_DIR "${GEOSX_TPL_DIR}/caliper-2.8.0" CACHE PATH "" ) +set( CALIPER_DIR "${GEOS_TPL_DIR}/caliper-2.8.0" CACHE PATH "" ) # haven't build I/O TPLs on tioga yet set( ENABLE_SILO OFF CACHE BOOL "" FORCE ) \ No newline at end of file diff --git a/host-configs/ORNL/ascent-gcc@8.1.1.cmake b/host-configs/ORNL/ascent-gcc@8.1.1.cmake index 10c24638537..dcbdf329c40 100644 --- a/host-configs/ORNL/ascent-gcc@8.1.1.cmake +++ b/host-configs/ORNL/ascent-gcc@8.1.1.cmake @@ -21,7 +21,7 @@ set(ESSL_LIBRARIES /sw/ascent/essl/6.2.0-20190419/essl/6.2/lib64/libesslsmpcuda. /sw/ascent/xl/16.1.1-3/lib/libxlf90_r.so.1 ${CUDA_TOOLKIT_ROOT_DIR}/lib64/libcublas.so ${CUDA_TOOLKIT_ROOT_DIR}/lib64/libcudart.so - ${GEOSX_TPL_ROOT_DIR}/liblapackforessl.a + ${GEOS_TPL_ROOT_DIR}/liblapackforessl.a /sw/ascent/xl/16.1.1-3/xlC/16.1.1/lib/libxl.a CACHE PATH "") diff --git a/host-configs/ORNL/frontier-base.cmake b/host-configs/ORNL/frontier-base.cmake index 63555a10201..7337dbf387b 100644 --- a/host-configs/ORNL/frontier-base.cmake +++ b/host-configs/ORNL/frontier-base.cmake @@ -18,7 +18,7 @@ set( CAMP_STANDALONE TRUE CACHE BOOL "" ) set( ENABLE_ROCM ON CACHE BOOL "" FORCE ) set( ROCM_ROOT "${HIP_ROOT}" CACHE PATH "" ) -set( GEOSX_BUILD_OBJ_LIBS OFF CACHE BOOL "" FORCE ) +set( GEOS_BUILD_OBJ_LIBS OFF CACHE BOOL "" FORCE ) set( ENABLE_GTEST_DEATH_TESTS OFF CACHE BOOL "" ) set( gtest_disable_pthreads ON CACHE BOOL "" ) @@ -31,8 +31,7 @@ set( ENABLE_DOCS OFF CACHE BOOL "" FORCE ) set( ENABLE_SCOTCH OFF CACHE BOOL "" FORCE ) set( ENABLE_SUPERLU_DIST OFF CACHE BOOL "" FORCE ) -set( GEOSX_BUILD_SHARED_LIBS ON CACHE BOOL "" FORCE ) -set( GEOSX_BUILD_OBJ_LIBS OFF CACHE BOOL "" FORCE ) +set( GEOS_BUILD_OBJ_LIBS OFF CACHE BOOL "" FORCE ) set( CMAKE_CXX_STANDARD 17 CACHE STRING "" ) set( BLT_CXX_STD c++17 CACHE STRING "" ) diff --git a/host-configs/ORNL/frontier-cce@15.0.0.cmake b/host-configs/ORNL/frontier-cce@15.0.0.cmake index d4aa1182b9b..f72fce7c636 100644 --- a/host-configs/ORNL/frontier-cce@15.0.0.cmake +++ b/host-configs/ORNL/frontier-cce@15.0.0.cmake @@ -3,17 +3,17 @@ set(CCE_VERSION 15.0.0) include(${CMAKE_CURRENT_LIST_DIR}/../../src/coreComponents/LvArray/host-configs/ORNL/frontier-cce@${CCE_VERSION}.cmake) include(${CMAKE_CURRENT_LIST_DIR}/frontier-base.cmake) -set( CONDUIT_DIR "${GEOSX_TPL_DIR}/conduit-0.8.7" CACHE PATH "" ) -set( HDF5_DIR "${GEOSX_TPL_DIR}/hdf5-1.12.2" CACHE PATH "" ) +set( CONDUIT_DIR "${GEOS_TPL_DIR}/conduit-0.8.7" CACHE PATH "" ) +set( HDF5_DIR "${GEOS_TPL_DIR}/hdf5-1.12.2" CACHE PATH "" ) set( ENABLE_SILO FALSE CACHE BOOL "" ) set( ENABLE_VTK FALSE CACHE BOOL "" ) set( BLAS_DIR "/opt/rocm-${ROCM_VERSION}/" CACHE PATH "" ) -set( PUGIXML_DIR "${GEOSX_TPL_DIR}/pugixml-1.11.4" CACHE PATH "" ) -set( FMT_DIR "${GEOSX_TPL_DIR}/fmt-8.0.1" CACHE PATH "" ) -set( SUITESPARSE_DIR "${GEOSX_TPL_DIR}/suite-sparse-5.10.1" CACHE PATH "" ) +set( PUGIXML_DIR "${GEOS_TPL_DIR}/pugixml-1.11.4" CACHE PATH "" ) +set( FMT_DIR "${GEOS_TPL_DIR}/fmt-8.0.1" CACHE PATH "" ) +set( SUITESPARSE_DIR "${GEOS_TPL_DIR}/suite-sparse-5.10.1" CACHE PATH "" ) # HYPRE options set( ENABLE_HYPRE_DEVICE "HIP" CACHE STRING "" ) @@ -22,4 +22,4 @@ set( ENABLE_HYPRE_MIXINT TRUE CACHE STRING "" ) set( HYPRE_DIR "/lustre/orion/geo127/world-shared/hypre/hypre_v2.27.0-218-ge2806c33d_cce-15.0.0_rocm-5.4.3_mixint_umpire-2022.03.0_caliper-2.8.0_rel/" CACHE PATH "" ) set( ENABLE_CALIPER ON CACHE BOOL "" FORCE ) -set( CALIPER_DIR "${GEOSX_TPL_DIR}/caliper-2.8.0" CACHE PATH "" ) +set( CALIPER_DIR "${GEOS_TPL_DIR}/caliper-2.8.0" CACHE PATH "" ) diff --git a/host-configs/Stanford/sherlock-base.cmake b/host-configs/Stanford/sherlock-base.cmake index 2e45c12491c..e7e0e0ee83a 100644 --- a/host-configs/Stanford/sherlock-base.cmake +++ b/host-configs/Stanford/sherlock-base.cmake @@ -43,8 +43,8 @@ set(ENABLE_CALIPER ON CACHE BOOL "") if( ${ENABLE_HYPRE_DEVICE} STREQUAL "CUDA" ) set(ENABLE_PETSC OFF CACHE BOOL "") set(ENABLE_TRILINOS OFF CACHE BOOL "") - set(GEOSX_LA_INTERFACE "Hypre" CACHE STRING "") + set(GEOS_LA_INTERFACE "Hypre" CACHE STRING "") endif() -set(GEOSX_TPL_DIR /home/groups/tchelepi/geosx/thirdPartyLibs/install-${CONFIG_NAME}-release CACHE PATH "") +set(GEOS_TPL_DIR /home/groups/tchelepi/geosx/thirdPartyLibs/install-${CONFIG_NAME}-release CACHE PATH "") include(/home/groups/tchelepi/geosx/GEOSX/host-configs/tpls.cmake) diff --git a/host-configs/Stanford/sherlock-gcc10-ompi4.1.2-openblas0.3.10-cuda11.5.0-sm80.cmake b/host-configs/Stanford/sherlock-gcc10-ompi4.1.2-openblas0.3.10-cuda11.5.0-sm80.cmake index c87eee9c96e..4d33559f0ad 100644 --- a/host-configs/Stanford/sherlock-gcc10-ompi4.1.2-openblas0.3.10-cuda11.5.0-sm80.cmake +++ b/host-configs/Stanford/sherlock-gcc10-ompi4.1.2-openblas0.3.10-cuda11.5.0-sm80.cmake @@ -21,7 +21,7 @@ set(CMAKE_CUDA_FLAGS_RELWITHDEBINFO "-g -lineinfo ${CMAKE_CUDA_FLAGS_RELEASE}" C set(CMAKE_CUDA_FLAGS_DEBUG "-g -G -O0 -Xcompiler -O0" CACHE STRING "") # LAI options -set(GEOSX_LA_INTERFACE "Hypre" CACHE STRING "" FORCE) +set(GEOS_LA_INTERFACE "Hypre" CACHE STRING "" FORCE) set(ENABLE_HYPRE ON CACHE BOOL "" FORCE) set(ENABLE_HYPRE_DEVICE "CUDA" CACHE STRING "" FORCE) set(ENABLE_PETSC OFF CACHE BOOL "" FORCE) diff --git a/host-configs/Stanford/sherlock-gcc10-ompi4.1.2-openblas0.3.10-cuda11.7.1-sm70.cmake b/host-configs/Stanford/sherlock-gcc10-ompi4.1.2-openblas0.3.10-cuda11.7.1-sm70.cmake index 51031871d6b..0fd52e8d3bf 100644 --- a/host-configs/Stanford/sherlock-gcc10-ompi4.1.2-openblas0.3.10-cuda11.7.1-sm70.cmake +++ b/host-configs/Stanford/sherlock-gcc10-ompi4.1.2-openblas0.3.10-cuda11.7.1-sm70.cmake @@ -21,7 +21,7 @@ set(CMAKE_CUDA_FLAGS_RELWITHDEBINFO "-g -lineinfo ${CMAKE_CUDA_FLAGS_RELEASE}" C set(CMAKE_CUDA_FLAGS_DEBUG "-g -G -O0 -Xcompiler -O0" CACHE STRING "") # LAI options -set(GEOSX_LA_INTERFACE "Hypre" CACHE STRING "" FORCE) +set(GEOS_LA_INTERFACE "Hypre" CACHE STRING "" FORCE) set(ENABLE_HYPRE ON CACHE BOOL "" FORCE) set(ENABLE_HYPRE_DEVICE "CUDA" CACHE STRING "" FORCE) set(ENABLE_PETSC OFF CACHE BOOL "" FORCE) diff --git a/host-configs/Stanford/sherlock-gcc10-ompi4.1.2-openblas0.3.10.cmake b/host-configs/Stanford/sherlock-gcc10-ompi4.1.2-openblas0.3.10.cmake index 2fb9add4657..d29b6180e11 100644 --- a/host-configs/Stanford/sherlock-gcc10-ompi4.1.2-openblas0.3.10.cmake +++ b/host-configs/Stanford/sherlock-gcc10-ompi4.1.2-openblas0.3.10.cmake @@ -40,5 +40,4 @@ set(LAPACK_LIBRARIES "${OPENBLAS_ROOT}/lib/libopenblas.so" CACHE STRING "") set(ENABLE_VALGRIND OFF CACHE BOOL "") set(ENABLE_CALIPER ON CACHE BOOL "") -set(GEOSX_TPL_DIR "$ENV{GEOSX_TPL_DIR}" CACHE PATH "" FORCE) include(${CMAKE_CURRENT_LIST_DIR}/../tpls.cmake) diff --git a/host-configs/TOTAL/pangea3-gcc8.4.1-openmpi-4.1.2-wave-solver.cmake b/host-configs/TOTAL/pangea3-gcc8.4.1-openmpi-4.1.2-wave-solver.cmake new file mode 100644 index 00000000000..46c8080ddb7 --- /dev/null +++ b/host-configs/TOTAL/pangea3-gcc8.4.1-openmpi-4.1.2-wave-solver.cmake @@ -0,0 +1,13 @@ +# hostconfig to build only the wave solver on pangea3 +# +# +include( ${CMAKE_CURRENT_LIST_DIR}/pangea3-gcc8.4.1-openmpi-4.1.2.cmake ) + +set ( GEOS_ENABLE_CONTACT OFF CACHE BOOL "" FORCE ) +set ( GEOS_ENABLE_FLUIDFLOW OFF CACHE BOOL "" FORCE ) +set ( GEOS_ENABLE_INDUCEDSEISMICITY OFF CACHE BOOL "" FORCE ) +set ( GEOS_ENABLE_MULTIPHYSICS OFF CACHE BOOL "" FORCE ) +set ( GEOS_ENABLE_SIMPLEPDE OFF CACHE BOOL "" FORCE ) +set ( GEOS_ENABLE_SOLIDMECHANICS OFF CACHE BOOL "" FORCE ) +set ( GEOS_ENABLE_SURFACEGENERATION OFF CACHE BOOL "" FORCE ) + diff --git a/host-configs/TOTAL/pangea3-gcc8.4.1-openmpi-4.1.2.cmake b/host-configs/TOTAL/pangea3-gcc8.4.1-openmpi-4.1.2.cmake index c2b8e96c328..320a7842279 100644 --- a/host-configs/TOTAL/pangea3-gcc8.4.1-openmpi-4.1.2.cmake +++ b/host-configs/TOTAL/pangea3-gcc8.4.1-openmpi-4.1.2.cmake @@ -4,9 +4,9 @@ set(CONFIG_NAME "pangea3-gcc8.4.1-ompi-4.1.2" CACHE PATH "") # Set up the tpls -set(GEOSX_TPL_DIR "$ENV{GEOSX_TPL_DIR}" CACHE PATH "" FORCE) -if (NOT DEFINED GEOSX_TPL_DIR) - message(FATAL_ERROR "You must set GEOSX_TPL_DIR with -D GEOSX_TPL_DIR=") +set(GEOS_TPL_DIR "$ENV{GEOSX_TPL_DIR}" CACHE PATH "" FORCE) +if (NOT DEFINED GEOS_TPL_DIR) + message(FATAL_ERROR "You must set GEOS_TPL_DIR with -D GEOS_TPL_DIR=") endif () @@ -77,7 +77,6 @@ set(ENABLE_MATHPRESSO OFF CACHE BOOL "") # Silo configure script doesn't recognize systype set(SILO_BUILD_TYPE powerpc64-unknown-linux-gnu CACHE STRING "") -set(GEOSX_BUILD_SHARED_LIBS OFF CACHE BOOL "") set(ENABLE_PVTPackage ON CACHE BOOL "") set(ENABLE_CALIPER ON CACHE BOOL "") @@ -98,7 +97,7 @@ endif() set(ENABLE_DOXYGEN OFF CACHE PATH "") -set(PETSC_OMP_DIR ${GEOSX_TPL_ROOT_DIR}/omp-links-for-petsc CACHE STRING "") +set(PETSC_OMP_DIR ${GEOS_TPL_ROOT_DIR}/omp-links-for-petsc CACHE STRING "") # PETSc doesn't seem to work correctly with clang. set(ENABLE_PETSC OFF CACHE BOOL "") diff --git a/host-configs/TOTAL/pangea4-base.cmake b/host-configs/TOTAL/pangea4-base.cmake new file mode 100644 index 00000000000..17caf065580 --- /dev/null +++ b/host-configs/TOTAL/pangea4-base.cmake @@ -0,0 +1,65 @@ +####################################### +# +# Pangea4 - base config for CPU cluster +# +# - RAJA CPU +# - CHAI CPU +# - CUDA OFF +# - OPENMP OFF +# - HYPRE ON +# +####################################### + +####################################### +# SCIENTIFIC LIBRARIES +####################################### + +set( ENABLE_HYPRE ON CACHE BOOL "" FORCE ) +set( ENABLE_MATHPRESSO ON CACHE BOOL "" FORCE ) +set( ENABLE_PAMELA ON CACHE BOOL "" FORCE ) +set( ENABLE_PETSC OFF CACHE BOOL "" FORCE ) +set( ENABLE_PVTPackage ON CACHE BOOL "" FORCE ) +set( ENABLE_SCOTCH ON CACHE BOOL "" FORCE ) +set( ENABLE_SUITESPARSE ON CACHE BOOL "" FORCE ) +set( ENABLE_TRILINOS OFF CACHE BOOL "" FORCE ) +set( ENABLE_VTK ON CACHE BOOL "" FORCE ) + +####################################### +# DEVELOPMENT TOOLS +####################################### + +set( ENABLE_DOXYGEN ON CACHE BOOL "" FORCE ) +set( ENABLE_GTEST_DEATH_TESTS ON CACHE BOOL "" FORCE ) +set( ENABLE_SPHINX ON CACHE BOOL "" FORCE ) +set( ENABLE_UNCRUSTIFY ON CACHE BOOL "" FORCE ) +set( ENABLE_XML_UPDATES ON CACHE BOOL "" FORCE ) + +####################################### +# PERFORMANCE TOOLS +####################################### + +set( ENABLE_BENCHMARKS ON CACHE BOOL "" FORCE ) +set( ENABLE_CALIPER ON CACHE BOOL "" FORCE ) + +####################################### +# RAJA/CHAI SETUP +####################################### + +set( ENABLE_OPENMP OFF CACHE BOOL "" FORCE ) +set( ENABLE_CUDA OFF CACHE BOOL "" FORCE ) + +set( ENABLE_CHAI ON CACHE BOOL "" FORCE ) +set( CHAI_BUILD_TYPE "cpu-no-rm" CACHE STRING "" FORCE ) +set( CHAI_ARGS "" CACHE STRING "" FORCE ) + +set( ENABLE_RAJA ON CACHE BOOL "" FORCE ) +set( RAJA_ENABLE_HIP OFF CACHE BOOL "" FORCE ) +set( RAJA_ENABLE_OPENMP OFF CACHE BOOL "" FORCE ) +set( RAJA_ENABLE_TBB OFF CACHE BOOL "" FORCE ) + +####################################### +# PYTHON SETUP +####################################### + +set( ENABLE_PYGEOSX ON CACHE BOOL "" ) +set( ENABLE_VTK_WRAP_PYTHON ON CACHE BOOL "" ) diff --git a/host-configs/TOTAL/pangea4-gcc12.1-hpcxompi2.17.1-onemkl2023.2.0.cmake b/host-configs/TOTAL/pangea4-gcc12.1-hpcxompi2.17.1-onemkl2023.2.0.cmake new file mode 100644 index 00000000000..b84e1040be4 --- /dev/null +++ b/host-configs/TOTAL/pangea4-gcc12.1-hpcxompi2.17.1-onemkl2023.2.0.cmake @@ -0,0 +1,99 @@ +####################################### +# +# Pangea4 - gcc - hpcxompi - onemkl +# +# Uses : +# - cray wrappers for gcc (cc, CC, ftn) +# - oneAPI MKL for BLAS and LAPACK +# - HPC-X OpenMPI for MPI +# +####################################### +# +# Requires modules : +# - PrgEnv-gnu = 8.4.0, which loads : +# . gcc = 12.1 +# . craype = 2.7.23 +# . cray-dsmml = 0.2.2 +# . craype-network-ofi = 1.0 +# . libfabric = 1.13.1 +# - cmake = 3.27.2 +# - cray-python = 3.10.10 +# - craype-x86-milan = 1.0 +# PrgEnv-gnu loads gcc 12 that does not support craype-x86-genoa +# - hpcx = 2.17.1 +# - intel-oneapi-mkl = 2023.2.0 +# +# Load modules this way : +# - module purge +# - module load PrgEnv-gnu/8.4.0 craype-x86-milan cmake/3.27.2 cray-python/3.10.10 +# - module unload cray-libsci/23.09.1.1 cray-mpich/8.1.27 +# - module load hpcx intel-oneapi-mkl/2023.2.0 +# +######################################## + +set( CONFIG_NAME "pangea4-gcc12.1-hpcxompi2.17.1-onemkl2023.2.0" CACHE PATH "" ) + +include(${CMAKE_CURRENT_LIST_DIR}/pangea4-base.cmake) + +####################################### +# COMPILER SETUP +####################################### + +# use : +# - cray wrappers for gnu compilers so that we link properly with infiniband network +# - explicit optimization flags even when using cray wrappers + +if( NOT DEFINED ENV{GCC_PATH} ) + message( FATAL_ERROR "GCC is not loaded. Please load the PrgEnv-gnu/8.4.0 module." ) +endif() + +set( CMAKE_C_COMPILER "cc" CACHE PATH "" ) +set( CMAKE_CXX_COMPILER "CC" CACHE PATH "" ) +set( CMAKE_Fortran_COMPILER "ftn" CACHE PATH "" ) + +set( COMMON_FLAGS "-march=native -mtune=native" ) +set( RELEASE_FLAGS "-O3 -DNDEBUG" ) +set( DEBUG_FLAGS "-O0 -g" ) + +set( CMAKE_C_FLAGS ${COMMON_FLAGS} CACHE STRING "" ) +set( CMAKE_CXX_FLAGS ${COMMON_FLAGS} CACHE STRING "" ) +set( CMAKE_Fortran_FLAGS ${COMMON_FLAGS} CACHE STRING "" ) +set( CMAKE_CXX_FLAGS_RELEASE ${RELEASE_FLAGS} CACHE STRING "" ) +set( CMAKE_C_FLAGS_RELEASE ${RELEASE_FLAGS} CACHE STRING "" ) +set( CMAKE_Fortran_FLAGS_RELEASE ${RELEASE_FLAGS} CACHE STRING "" ) +set( CMAKE_CXX_FLAGS_DEBUG ${DEBUG_FLAGS} CACHE STRING "" ) +set( CMAKE_C_FLAGS_DEBUG ${DEBUG_FLAGS} CACHE STRING "" ) +set( CMAKE_Fortran_FLAGS_DEBUG ${DEBUG_FLAGS} CACHE STRING "" ) + +####################################### +# MPI SETUP +####################################### + +# use : +# - HPC-X OpenMPI library + +set( ENABLE_MPI ON CACHE BOOL "" ) + +if( NOT DEFINED ENV{HPCX_MPI_DIR} ) + message( FATAL_ERROR "HPC-X OpenMPI is not loaded. Please load the hpcx module." ) +endif() + +####################################### +# BLAS/LAPACK SETUP +####################################### + +# use : +# - intel oneAPI MKL library + +set( ENABLE_MKL ON CACHE BOOL "" FORCE ) + +if( NOT DEFINED ENV{MKLROOT} ) + message( FATAL_ERROR "MKL is not loaded. Please load the intel-oneapi-mkl/2023.2.0 module." ) +endif() + +set( MKL_INCLUDE_DIRS $ENV{MKLROOT}/include CACHE STRING "" ) +set( MKL_LIBRARIES $ENV{MKLROOT}/lib/intel64/libmkl_rt.so + $ENV{GCC_PATH}/lib/gcc/x86_64-redhat-linux/12/libgomp.so + CACHE STRING "" ) + +include( ${CMAKE_CURRENT_LIST_DIR}/../tpls.cmake ) diff --git a/host-configs/TOTAL/pangea4-gcc12.1-hpcxompi2.17.1-openblas0.3.23.cmake b/host-configs/TOTAL/pangea4-gcc12.1-hpcxompi2.17.1-openblas0.3.23.cmake new file mode 100644 index 00000000000..53080a4d708 --- /dev/null +++ b/host-configs/TOTAL/pangea4-gcc12.1-hpcxompi2.17.1-openblas0.3.23.cmake @@ -0,0 +1,94 @@ +####################################### +# +# Pangea4 - gcc - hpcxompi - openblas +# +# Uses : +# - cray wrappers for gcc (cc, CC, ftn) +# - OpenBLAS for BLAS and LAPACK +# - HPC-X OpenMPI for MPI +# +####################################### +# +# Requires modules : +# - PrgEnv-gnu = 8.4.0, which loads : +# . gcc = 12.1 +# . craype = 2.7.23 +# . cray-dsmml = 0.2.2 +# . craype-network-ofi = 1.0 +# . libfabric = 1.13.1 +# - cmake = 3.27.2 +# - cray-python = 3.10.10 +# - craype-x86-milan = 1.0 +# PrgEnv-gnu loads gcc 12 that does not support craype-x86-genoa +# - hpcx = 2.17.1 +# - openblas = 0.3.23 +# +# Load modules this way : +# - module purge +# - module load PrgEnv-gnu/8.4.0 craype-x86-milan cmake/3.27.2 cray-python/3.10.10 +# - module unload cray-libsci/23.09.1.1 cray-mpich/8.1.27 +# - module load hpcx openblas/0.3.23 +# +######################################## + +set( CONFIG_NAME "pangea4-gcc12.1-hpcxompi2.17.1-openblas0.3.23" CACHE PATH "" ) + +include(${CMAKE_CURRENT_LIST_DIR}/pangea4-base.cmake) + +####################################### +# COMPILER SETUP +####################################### + +# use : +# - cray wrappers for gnu compilers so that we link properly with infiniband network +# - explicit optimization flags even when using cray wrappers + +if( NOT DEFINED ENV{GCC_PATH} ) + message( FATAL_ERROR "GCC is not loaded. Please load the PrgEnv-gnu/8.4.0 module." ) +endif() + +set( CMAKE_C_COMPILER "cc" CACHE PATH "" ) +set( CMAKE_CXX_COMPILER "CC" CACHE PATH "" ) +set( CMAKE_Fortran_COMPILER "ftn" CACHE PATH "" ) + +set( COMMON_FLAGS "-march=native -mtune=native" ) +set( RELEASE_FLAGS "-O3 -DNDEBUG" ) +set( DEBUG_FLAGS "-O0 -g" ) + +set( CMAKE_C_FLAGS ${COMMON_FLAGS} CACHE STRING "" ) +set( CMAKE_CXX_FLAGS ${COMMON_FLAGS} CACHE STRING "" ) +set( CMAKE_Fortran_FLAGS ${COMMON_FLAGS} CACHE STRING "" ) +set( CMAKE_CXX_FLAGS_RELEASE ${RELEASE_FLAGS} CACHE STRING "" ) +set( CMAKE_C_FLAGS_RELEASE ${RELEASE_FLAGS} CACHE STRING "" ) +set( CMAKE_Fortran_FLAGS_RELEASE ${RELEASE_FLAGS} CACHE STRING "" ) +set( CMAKE_CXX_FLAGS_DEBUG ${DEBUG_FLAGS} CACHE STRING "" ) +set( CMAKE_C_FLAGS_DEBUG ${DEBUG_FLAGS} CACHE STRING "" ) +set( CMAKE_Fortran_FLAGS_DEBUG ${DEBUG_FLAGS} CACHE STRING "" ) + +####################################### +# MPI SETUP +####################################### + +# use : +# - HPC-X OpenMPI library + +set( ENABLE_MPI ON CACHE BOOL "" ) + +if( NOT DEFINED ENV{HPCX_MPI_DIR} ) + message( FATAL_ERROR "HPC-X OpenMPI is not loaded. Please load the hpcx module." ) +endif() + +####################################### +# BLAS/LAPACK SETUP +####################################### + +# use : +# - OpenBLAS library + +find_library(OPENBLAS_LIB openblas) + +if(NOT OPENBLAS_LIB) + message(FATAL_ERROR "OpenBLAS is not loaded. Please load the openblas/0.3.23 module.") +endif() + +include( ${CMAKE_CURRENT_LIST_DIR}/../tpls.cmake ) diff --git a/host-configs/TOTAL/pangea4-gcc12.1-openmpi4.1.6-onemkl2023.2.0.cmake b/host-configs/TOTAL/pangea4-gcc12.1-openmpi4.1.6-onemkl2023.2.0.cmake new file mode 100644 index 00000000000..e4265966ef0 --- /dev/null +++ b/host-configs/TOTAL/pangea4-gcc12.1-openmpi4.1.6-onemkl2023.2.0.cmake @@ -0,0 +1,99 @@ +####################################### +# +# Pangea4 - gcc - openmpi - onemkl +# +# Uses : +# - cray wrappers for gcc (cc, CC, ftn) +# - OpenMPI for MPI +# - oneAPI MKL for BLAS and LAPACK +# +####################################### +# +# Requires modules : +# - PrgEnv-gnu = 8.4.0, which loads : +# . gcc = 12.1 +# . craype = 2.7.23 +# . cray-dsmml = 0.2.2 +# . craype-network-ofi = 1.0 +# . libfabric = 1.13.1 +# - cmake = 3.27.2 +# - cray-python = 3.10.10 +# - craype-x86-milan = 1.0 +# PrgEnv-gnu loads gcc 12 that does not support craype-x86-genoa +# - openmpi = 4.1.6 +# - intel-oneapi-mkl = 2023.2.0 +# +# Load modules this way : +# - module purge +# - module load PrgEnv-gnu/8.4.0 craype-x86-milan cmake/3.27.2 cray-python/3.10.10 +# - module unload cray-libsci/23.09.1.1 cray-mpich/8.1.27 +# - module load openmpi/4.1.6 intel-oneapi-mkl/2023.2.0 +# +######################################## + +set( CONFIG_NAME "pangea4-gcc12.1-openmpi4.1.6-onemkl2023.2.0" CACHE PATH "" ) + +include(${CMAKE_CURRENT_LIST_DIR}/pangea4-base.cmake) + +####################################### +# COMPILER SETUP +####################################### + +# use : +# - cray wrappers for gnu compilers so that we link properly with infiniband network +# - explicit optimization flags even when using cray wrappers + +if( NOT DEFINED ENV{GCC_PATH} ) + message( FATAL_ERROR "GCC is not loaded. Please load the PrgEnv-gnu/8.4.0 module." ) +endif() + +set( CMAKE_C_COMPILER "cc" CACHE PATH "" ) +set( CMAKE_CXX_COMPILER "CC" CACHE PATH "" ) +set( CMAKE_Fortran_COMPILER "ftn" CACHE PATH "" ) + +set( COMMON_FLAGS "-march=native -mtune=native" ) +set( RELEASE_FLAGS "-O3 -DNDEBUG" ) +set( DEBUG_FLAGS "-O0 -g" ) + +set( CMAKE_C_FLAGS ${COMMON_FLAGS} CACHE STRING "" ) +set( CMAKE_CXX_FLAGS ${COMMON_FLAGS} CACHE STRING "" ) +set( CMAKE_Fortran_FLAGS ${COMMON_FLAGS} CACHE STRING "" ) +set( CMAKE_CXX_FLAGS_RELEASE ${RELEASE_FLAGS} CACHE STRING "" ) +set( CMAKE_C_FLAGS_RELEASE ${RELEASE_FLAGS} CACHE STRING "" ) +set( CMAKE_Fortran_FLAGS_RELEASE ${RELEASE_FLAGS} CACHE STRING "" ) +set( CMAKE_CXX_FLAGS_DEBUG ${DEBUG_FLAGS} CACHE STRING "" ) +set( CMAKE_C_FLAGS_DEBUG ${DEBUG_FLAGS} CACHE STRING "" ) +set( CMAKE_Fortran_FLAGS_DEBUG ${DEBUG_FLAGS} CACHE STRING "" ) + +####################################### +# MPI SETUP +####################################### + +# use : +# - OpenMPI library + +set( ENABLE_MPI ON CACHE BOOL "" ) + +if( NOT "$ENV{LMOD_MPI_NAME}" STREQUAL "openmpi" ) + message(FATAL_ERROR "OpenMPI is not loaded. Please load the openmpi/4.1.6 module.") +endif() + +####################################### +# BLAS/LAPACK SETUP +####################################### + +# use : +# - intel oneAPI MKL library + +set( ENABLE_MKL ON CACHE BOOL "" FORCE ) + +if( NOT DEFINED ENV{MKLROOT} ) + message( FATAL_ERROR "MKL is not loaded. Please load the intel-oneapi-mkl/2023.2.0 module." ) +endif() + +set( MKL_INCLUDE_DIRS $ENV{MKLROOT}/include CACHE STRING "" ) +set( MKL_LIBRARIES $ENV{MKLROOT}/lib/intel64/libmkl_rt.so + $ENV{GCC_PATH}/lib/gcc/x86_64-redhat-linux/12/libgomp.so + CACHE STRING "" ) + +include( ${CMAKE_CURRENT_LIST_DIR}/../tpls.cmake ) diff --git a/host-configs/TOTAL/pangea4-gcc12.1-openmpi4.1.6-openblas0.3.23.cmake b/host-configs/TOTAL/pangea4-gcc12.1-openmpi4.1.6-openblas0.3.23.cmake new file mode 100644 index 00000000000..e3a7c22b0c7 --- /dev/null +++ b/host-configs/TOTAL/pangea4-gcc12.1-openmpi4.1.6-openblas0.3.23.cmake @@ -0,0 +1,94 @@ +####################################### +# +# Pangea4 - gcc - openmpi - onemkl +# +# Uses : +# - cray wrappers for gcc (cc, CC, ftn) +# - OpenMPI for MPI +# - OpenBLAS for BLAS and LAPACK +# +####################################### +# +# Requires modules : +# - PrgEnv-gnu = 8.4.0, which loads : +# . gcc = 12.1 +# . craype = 2.7.23 +# . cray-dsmml = 0.2.2 +# . craype-network-ofi = 1.0 +# . libfabric = 1.13.1 +# - cmake = 3.27.2 +# - cray-python = 3.10.10 +# - craype-x86-milan = 1.0 +# PrgEnv-gnu loads gcc 12 that does not support craype-x86-genoa +# - openmpi = 4.1.6 +# - openbla = 0.3.23 +# +# Load modules this way : +# - module purge +# - module load PrgEnv-gnu/8.4.0 craype-x86-milan cmake/3.27.2 cray-python/3.10.10 +# - module unload cray-libsci/23.09.1.1 cray-mpich/8.1.27 +# - module load openmpi/4.1.6 openblas/0.3.23 +# +######################################## + +set( CONFIG_NAME "pangea4-gcc12.1-openmpi4.1.6-openblas0.3.23" CACHE PATH "" ) + +include(${CMAKE_CURRENT_LIST_DIR}/pangea4-base.cmake) + +####################################### +# COMPILER SETUP +####################################### + +# use : +# - cray wrappers for gnu compilers so that we link properly with infiniband network +# - explicit optimization flags even when using cray wrappers + +if( NOT DEFINED ENV{GCC_PATH} ) + message( FATAL_ERROR "GCC is not loaded. Please load the PrgEnv-gnu/8.4.0 module." ) +endif() + +set( CMAKE_C_COMPILER "cc" CACHE PATH "" ) +set( CMAKE_CXX_COMPILER "CC" CACHE PATH "" ) +set( CMAKE_Fortran_COMPILER "ftn" CACHE PATH "" ) + +set( COMMON_FLAGS "-march=native -mtune=native" ) +set( RELEASE_FLAGS "-O3 -DNDEBUG" ) +set( DEBUG_FLAGS "-O0 -g" ) + +set( CMAKE_C_FLAGS ${COMMON_FLAGS} CACHE STRING "" ) +set( CMAKE_CXX_FLAGS ${COMMON_FLAGS} CACHE STRING "" ) +set( CMAKE_Fortran_FLAGS ${COMMON_FLAGS} CACHE STRING "" ) +set( CMAKE_CXX_FLAGS_RELEASE ${RELEASE_FLAGS} CACHE STRING "" ) +set( CMAKE_C_FLAGS_RELEASE ${RELEASE_FLAGS} CACHE STRING "" ) +set( CMAKE_Fortran_FLAGS_RELEASE ${RELEASE_FLAGS} CACHE STRING "" ) +set( CMAKE_CXX_FLAGS_DEBUG ${DEBUG_FLAGS} CACHE STRING "" ) +set( CMAKE_C_FLAGS_DEBUG ${DEBUG_FLAGS} CACHE STRING "" ) +set( CMAKE_Fortran_FLAGS_DEBUG ${DEBUG_FLAGS} CACHE STRING "" ) + +####################################### +# MPI SETUP +####################################### + +# use : +# - OpenMPI library + +set( ENABLE_MPI ON CACHE BOOL "" ) + +if( NOT "$ENV{LMOD_MPI_NAME}" STREQUAL "openmpi" ) + message(FATAL_ERROR "OpenMPI is not loaded. Please load the openmpi/4.1.6 module.") +endif() + +####################################### +# BLAS/LAPACK SETUP +####################################### + +# use : +# - OpenBLAS library + +find_library(OPENBLAS_LIB openblas) + +if(NOT OPENBLAS_LIB) + message(FATAL_ERROR "OpenBLAS is not loaded. Please load the openblas/0.3.23 module.") +endif() + +include( ${CMAKE_CURRENT_LIST_DIR}/../tpls.cmake ) diff --git a/host-configs/TOTAL/pecan-CPU.cmake b/host-configs/TOTAL/pecan-CPU.cmake index 09d6bc79b94..a68d14fbc62 100644 --- a/host-configs/TOTAL/pecan-CPU.cmake +++ b/host-configs/TOTAL/pecan-CPU.cmake @@ -21,7 +21,7 @@ set(ENABLE_HYPRE ON CACHE BOOL "" FORCE ) set(ENABLE_GTEST_DEATH_TESTS ON CACHE BOOL "" FORCE) set(ENABLE_CALIPER ON CACHE BOOL "") -set(ENABLE_GEOSX_PTP ON CACHE BOOL "" FORCE) +set(ENABLE_GEOS_PTP ON CACHE BOOL "" FORCE) set(ENABLE_MKL ON CACHE BOOL "") set(INTEL_ROOT "/apps/intel/2019/u5/compilers_and_libraries_2019.5.281/linux" ) @@ -33,5 +33,5 @@ set(MKL_LIBRARIES ${MKL_ROOT}/lib/intel64/libmkl_intel_lp64.so ${INTEL_ROOT}/compiler/lib/intel64_lin/libiomp5.so CACHE STRING "") -set(GEOSX_TPL_DIR "$ENV{GEOSX_TPL_DIR}" CACHE PATH "" FORCE) +set(GEOS_TPL_DIR "$ENV{GEOSX_TPL_DIR}" CACHE PATH "" FORCE) include(${CMAKE_CURRENT_LIST_DIR}/../tpls.cmake) diff --git a/host-configs/apple/darwin-clang.cmake b/host-configs/apple/darwin-clang.cmake deleted file mode 100644 index adbc7ac1fa7..00000000000 --- a/host-configs/apple/darwin-clang.cmake +++ /dev/null @@ -1,38 +0,0 @@ -site_name(HOST_NAME) -set(CONFIG_NAME "${HOST_NAME}-darwin-x86_64-clang@apple-mp" CACHE PATH "") -message("CONFIG_NAME = ${CONFIG_NAME}") - -set(CMAKE_C_COMPILER "/usr/bin/clang" CACHE PATH "") -set(CMAKE_CXX_COMPILER "/usr/bin/clang++" CACHE PATH "") -set(ENABLE_FORTRAN OFF CACHE BOOL "" FORCE) - -set(ENABLE_MPI ON CACHE PATH "") -set(MPI_C_COMPILER "/usr/local/bin/mpicc" CACHE PATH "") -set(MPI_CXX_COMPILER "/usr/local/bin/mpicxx" CACHE PATH "") -set(MPIEXEC "/usr/local/bin/mpirun" CACHE PATH "") - -set(ENABLE_GTEST_DEATH_TESTS ON CACHE BOOL "" FORCE) - -set(ENABLE_PVTPackage ON CACHE BOOL "" FORCE) - -set(ENABLE_CUDA "OFF" CACHE PATH "" FORCE) -set(ENABLE_OPENMP "OFF" CACHE PATH "" FORCE) - -set(ENABLE_CALIPER "OFF" CACHE PATH "" FORCE ) - -set(GEOSX_BUILD_OBJ_LIBS ON CACHE BOOL "" FORCE) - -set( BLAS_LIBRARIES /usr/local/opt/openblas/lib/libblas.dylib CACHE PATH "" FORCE ) -set( LAPACK_LIBRARIES /usr/local/opt/openblas/lib/liblapack.dylib CACHE PATH "" FORCE ) - -set(ENABLE_DOXYGEN OFF CACHE BOOL "" FORCE) - -#set( DOXYGEN_EXECUTABLE /usr/local/bin/doxygen CACHE PATH "" FORCE ) -#set( SPHINX_EXECUTABLE /usr/local/bin/sphinx-build CACHE PATH "" FORCE ) - -set(GEOSX_TPL_DIR "/usr/local/GEOSX/GEOSX_TPL" CACHE PATH "" FORCE ) -if(NOT ( EXISTS "${GEOSX_TPL_DIR}" AND IS_DIRECTORY "${GEOSX_TPL_DIR}" ) ) - set(GEOSX_TPL_DIR "${CMAKE_SOURCE_DIR}/../../thirdPartyLibs/install-darwin-clang-release" CACHE PATH "" FORCE ) -endif() - -include(${CMAKE_CURRENT_LIST_DIR}/tpls.cmake) diff --git a/host-configs/apple/macOS_Matteo.cmake b/host-configs/apple/macOS_Matteo.cmake deleted file mode 100644 index 6edb525f1aa..00000000000 --- a/host-configs/apple/macOS_Matteo.cmake +++ /dev/null @@ -1,4 +0,0 @@ -set( HOMEBREW_DIR "/Users/cusini1/local" ) -set( CONFIG_NAME "macOS_Matteo" ) - -include(${CMAKE_CURRENT_LIST_DIR}/macOS_base.cmake) diff --git a/host-configs/apple/macOS_base.cmake b/host-configs/apple/macOS_base.cmake index 142fbd40d6d..ec74d15b9c1 100644 --- a/host-configs/apple/macOS_base.cmake +++ b/host-configs/apple/macOS_base.cmake @@ -25,17 +25,19 @@ set(ENABLE_CALIPER "OFF" CACHE PATH "" FORCE ) set( BLAS_LIBRARIES ${HOMEBREW_DIR}/opt/lapack/lib/libblas.dylib CACHE PATH "" FORCE ) set( LAPACK_LIBRARIES ${HOMEBREW_DIR}/opt/lapack/lib/liblapack.dylib CACHE PATH "" FORCE ) -set(ENABLE_DOXYGEN OFF CACHE BOOL "" FORCE) -set(ENABLE_MATHPRESSO OFF CACHE BOOL "" FORCE ) -set(GEOSX_BUILD_OBJ_LIBS ON CACHE BOOL "" FORCE) +set(ENABLE_DOXYGEN ON CACHE BOOL "" FORCE) +set(ENABLE_SPHINX ON CACHE BOOL "" FORCE) +set(ENABLE_MATHPRESSO ON CACHE BOOL "" FORCE ) +set(GEOS_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) -#set( DOXYGEN_EXECUTABLE /usr/local/bin/doxygen CACHE PATH "" FORCE ) -#set( SPHINX_EXECUTABLE /usr/local/bin/sphinx-build CACHE PATH "" FORCE ) -if(NOT ( EXISTS "${GEOSX_TPL_DIR}" AND IS_DIRECTORY "${GEOSX_TPL_DIR}" ) ) - set(GEOSX_TPL_DIR "${CMAKE_SOURCE_DIR}/../../thirdPartyLibs/install-${CONFIG_NAME}-release" CACHE PATH "" FORCE ) +set( DOXYGEN_EXECUTABLE ${HOMEBREW_DIR}/bin/doxygen CACHE PATH "" FORCE ) +set( SPHINX_EXECUTABLE ${HOMEBREW_DIR}/opt/sphinx-doc/bin/sphinx-build CACHE PATH "" FORCE ) + +if(NOT ( EXISTS "${GEOS_TPL_DIR}" AND IS_DIRECTORY "${GEOS_TPL_DIR}" ) ) + set(GEOS_TPL_DIR "${CMAKE_SOURCE_DIR}/../../thirdPartyLibs/install-${CONFIG_NAME}-release" CACHE PATH "" FORCE ) endif() # ATS diff --git a/host-configs/environment.cmake b/host-configs/environment.cmake index c4db8c745a2..001d28cb425 100644 --- a/host-configs/environment.cmake +++ b/host-configs/environment.cmake @@ -19,7 +19,7 @@ if(NOT DEFINED ENABLE_HYPRE) endif() # ... and then check the value. if(ENABLE_HYPRE) - set(GEOSX_LA_INTERFACE "Hypre" CACHE STRING "" FORCE) + set(GEOS_LA_INTERFACE "Hypre" CACHE STRING "" FORCE) else() set(ENABLE_HYPRE OFF CACHE BOOL "" FORCE) endif() @@ -29,7 +29,7 @@ if(NOT DEFINED ENABLE_TRILINOS) set(ENABLE_TRILINOS "$ENV{ENABLE_TRILINOS}" CACHE BOOL "" FORCE) endif() if(ENABLE_TRILINOS) - set(GEOSX_LA_INTERFACE "Trilinos" CACHE STRING "" FORCE) + set(GEOS_LA_INTERFACE "Trilinos" CACHE STRING "" FORCE) else() set(ENABLE_TRILINOS FALSE CACHE BOOL "" FORCE) endif() @@ -40,7 +40,7 @@ if( (ENABLE_HYPRE AND ENABLE_TRILINOS) OR (NOT ENABLE_TRILINOS AND NOT ENABLE_HY MESSAGE(SEND_ERROR "ENABLE_TRILINOS = ${ENABLE_TRILINOS}.") endif() -MESSAGE(STATUS "GEOSX_LA_INTERFACE = ${GEOSX_LA_INTERFACE}") +MESSAGE(STATUS "GEOS_LA_INTERFACE = ${GEOS_LA_INTERFACE}") set(ENABLE_CUDA "$ENV{ENABLE_CUDA}" CACHE BOOL "" FORCE) if(ENABLE_CUDA) @@ -70,5 +70,17 @@ if(ENABLE_CUDA) endif() -set(GEOSX_TPL_DIR "$ENV{GEOSX_TPL_DIR}" CACHE PATH "" FORCE) +if(DEFINED ENV{BLAS_LIBRARIES}) + set(BLAS_LIBRARIES "$ENV{BLAS_LIBRARIES}" CACHE PATH "" FORCE) +endif() + +if(DEFINED ENV{LAPACK_LIBRARIES}) + set(LAPACK_LIBRARIES "$ENV{LAPACK_LIBRARIES}" CACHE PATH "" FORCE) +endif() + +if(DEFINED ENV{GEOS_BUILD_SHARED_LIBS}) + set(GEOS_BUILD_SHARED_LIBS "$ENV{GEOS_BUILD_SHARED_LIBS}" CACHE BOOL "" FORCE) +endif() + +set(GEOS_TPL_DIR "$ENV{GEOSX_TPL_DIR}" CACHE PATH "" FORCE) include(${CMAKE_CURRENT_LIST_DIR}/tpls.cmake) diff --git a/host-configs/quick-start-template.cmake b/host-configs/quick-start-template.cmake new file mode 100644 index 00000000000..239f52e202f --- /dev/null +++ b/host-configs/quick-start-template.cmake @@ -0,0 +1,32 @@ +set( CONFIG_NAME "quick-start" ) + +# Set compilers path +set(CMAKE_C_COMPILER "path-to-gcc/bin/gcc" CACHE PATH "") # This is typically something like /usr/bin/gcc ... or clang +set(CMAKE_CXX_COMPILER "path-to-gcc/bin/g++" CACHE PATH "") # This is typically something like /usr/bin/g++ ... or clang++ +set(ENABLE_FORTRAN OFF CACHE BOOL "" FORCE) + +# Set paths to mpi +set(ENABLE_MPI ON CACHE PATH "") +set(MPI_C_COMPILER "path-to-mpi/bin/mpicc" CACHE PATH "") # This is typically something like /usr/bin/mpicc +set(MPI_CXX_COMPILER "path-to-mpi/bin/mpicxx" CACHE PATH "") # This is typically something like /usr/bin/mpicxx +set(MPIEXEC "path-to-mpi/bin/mpirun" CACHE PATH "") # This is typically something like /usr/bin/mpirun + +# Set paths to blas and lapack +set( BLAS_LIBRARIES "path-to-blas" CACHE PATH "" FORCE ) # This is typically something like /usr/lib64/libblas.so +set( LAPACK_LIBRARIES "path-to-lapack" CACHE PATH "" FORCE ) # This is typically something like /usr/lib64/liblapack.so + +# Cuda and openMP +set( ENABLE_CUDA OFF CACHE PATH "" FORCE ) +set( ENABLE_OPENMP OFF CACHE PATH "" FORCE ) + +# TPLs +set( ENABLE_TRILINOS OFF CACHE PATH "" FORCE ) +set( ENABLE_CALIPER OFF CACHE PATH "" FORCE ) +set( ENABLE_DOXYGEN OFF CACHE BOOL "" FORCE) +set( ENABLE_MATHPRESSO OFF CACHE BOOL "" FORCE ) + +if(NOT ( EXISTS "${GEOS_TPL_DIR}" AND IS_DIRECTORY "${GEOS_TPL_DIR}" ) ) + set(GEOS_TPL_DIR "${CMAKE_SOURCE_DIR}/../../thirdPartyLibs/install-${CONFIG_NAME}-release" CACHE PATH "" FORCE ) +endif() + +include(${CMAKE_CURRENT_LIST_DIR}/tpls.cmake) diff --git a/host-configs/tpls.cmake b/host-configs/tpls.cmake index 08e605d79bf..1a4ab1701e6 100644 --- a/host-configs/tpls.cmake +++ b/host-configs/tpls.cmake @@ -1,106 +1,111 @@ # # Performance portability # -message("in tpls.cmake GEOSX_TPL_DIR=${GEOSX_TPL_DIR}") +message("in tpls.cmake GEOS_TPL_DIR=${GEOS_TPL_DIR}") -if(EXISTS ${GEOSX_TPL_DIR}/raja) - set(RAJA_DIR ${GEOSX_TPL_DIR}/raja CACHE PATH "" FORCE) +# +# General TPL Folder verifications +# +if(NOT EXISTS ${GEOS_TPL_DIR}) + message(WARNING "'GEOS_TPL_DIR' does not exist.\n") endif() -if(EXISTS ${GEOSX_TPL_DIR}/chai) - set(UMPIRE_DIR ${GEOSX_TPL_DIR}/chai CACHE PATH "" FORCE) - set(CHAI_DIR ${GEOSX_TPL_DIR}/chai CACHE PATH "" FORCE) + +if(EXISTS ${GEOS_TPL_DIR}/raja) + set(RAJA_DIR ${GEOS_TPL_DIR}/raja CACHE PATH "" FORCE) +endif() + +if(EXISTS ${GEOS_TPL_DIR}/chai) + set(UMPIRE_DIR ${GEOS_TPL_DIR}/chai CACHE PATH "" FORCE) + set(CHAI_DIR ${GEOS_TPL_DIR}/chai CACHE PATH "" FORCE) endif() # # IO TPLs # -if(EXISTS ${GEOSX_TPL_DIR}/hdf5) - set(HDF5_DIR ${GEOSX_TPL_DIR}/hdf5 CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/hdf5) + set(HDF5_DIR ${GEOS_TPL_DIR}/hdf5 CACHE PATH "" FORCE) message(STATUS "HDF5_DIR = ${HDF5_DIR}") endif() -if(EXISTS ${GEOSX_TPL_DIR}/conduit) - set(CONDUIT_DIR ${GEOSX_TPL_DIR}/conduit CACHE PATH "" FORCE) -endif() - -if(EXISTS ${GEOSX_TPL_DIR}/silo) - set(SILO_DIR ${GEOSX_TPL_DIR}/silo CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/conduit) + set(CONDUIT_DIR ${GEOS_TPL_DIR}/conduit CACHE PATH "" FORCE) endif() -if(EXISTS ${GEOSX_TPL_DIR}/adiak) - set(ADIAK_DIR ${GEOSX_TPL_DIR}/adiak CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/silo) + set(SILO_DIR ${GEOS_TPL_DIR}/silo CACHE PATH "" FORCE) endif() -if(EXISTS ${GEOSX_TPL_DIR}/caliper) - set(CALIPER_DIR ${GEOSX_TPL_DIR}/caliper CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/adiak) + set(ADIAK_DIR ${GEOS_TPL_DIR}/adiak CACHE PATH "" FORCE) endif() -if(EXISTS ${GEOSX_TPL_DIR}/pugixml) - set(PUGIXML_DIR ${GEOSX_TPL_DIR}/pugixml CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/caliper) + set(CALIPER_DIR ${GEOS_TPL_DIR}/caliper CACHE PATH "" FORCE) endif() -if(EXISTS ${GEOSX_TPL_DIR}/vtk) - set(VTK_DIR ${GEOSX_TPL_DIR}/vtk CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/pugixml) + set(PUGIXML_DIR ${GEOS_TPL_DIR}/pugixml CACHE PATH "" FORCE) endif() -if(EXISTS ${GEOSX_TPL_DIR}/fmt) - set(FMT_DIR ${GEOSX_TPL_DIR}/fmt CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/vtk) + set(VTK_DIR ${GEOS_TPL_DIR}/vtk CACHE PATH "" FORCE) endif() -if(EXISTS ${GEOSX_TPL_DIR}/fesapi) - set(FESAPI_DIR ${GEOSX_TPL_DIR}/fesapi CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/fmt) +# set(FMT_DIR ${GEOS_TPL_DIR}/fmt CACHE PATH "" FORCE) + set(FMT_DIR ${GEOS_TPL_DIR}/chai CACHE PATH "" FORCE) endif() # # Math TPLs # -if(EXISTS ${GEOSX_TPL_DIR}/metis) - set(METIS_DIR ${GEOSX_TPL_DIR}/metis CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/metis) + set(METIS_DIR ${GEOS_TPL_DIR}/metis CACHE PATH "" FORCE) endif() -if(EXISTS ${GEOSX_TPL_DIR}/parmetis) - set(PARMETIS_DIR ${GEOSX_TPL_DIR}/parmetis CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/parmetis) + set(PARMETIS_DIR ${GEOS_TPL_DIR}/parmetis CACHE PATH "" FORCE) endif() -if(EXISTS ${GEOSX_TPL_DIR}/superlu_dist) - set(SUPERLU_DIST_DIR ${GEOSX_TPL_DIR}/superlu_dist CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/superlu_dist) + set(SUPERLU_DIST_DIR ${GEOS_TPL_DIR}/superlu_dist CACHE PATH "" FORCE) endif() -if(EXISTS ${GEOSX_TPL_DIR}/suitesparse) - set(SUITESPARSE_DIR ${GEOSX_TPL_DIR}/suitesparse CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/suitesparse) + set(SUITESPARSE_DIR ${GEOS_TPL_DIR}/suitesparse CACHE PATH "" FORCE) endif() -if(EXISTS ${GEOSX_TPL_DIR}/trilinos) - set(TRILINOS_DIR ${GEOSX_TPL_DIR}/trilinos CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/trilinos) + set(TRILINOS_DIR ${GEOS_TPL_DIR}/trilinos CACHE PATH "" FORCE) endif() -if(EXISTS ${GEOSX_TPL_DIR}/hypre) - set(HYPRE_DIR ${GEOSX_TPL_DIR}/hypre CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/hypre) + set(HYPRE_DIR ${GEOS_TPL_DIR}/hypre CACHE PATH "" FORCE) endif() -if(EXISTS ${GEOSX_TPL_DIR}/scotch) - set(SCOTCH_DIR ${GEOSX_TPL_DIR}/scotch CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/scotch) + set(SCOTCH_DIR ${GEOS_TPL_DIR}/scotch CACHE PATH "" FORCE) endif() -if(EXISTS ${GEOSX_TPL_DIR}/petsc AND (NOT DEFINED ENABLE_PETSC OR ENABLE_PETSC)) - set(PETSC_DIR ${GEOSX_TPL_DIR}/petsc CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/petsc AND (NOT DEFINED ENABLE_PETSC OR ENABLE_PETSC)) + set(PETSC_DIR ${GEOS_TPL_DIR}/petsc CACHE PATH "" FORCE) endif() # # Development tools # -if(EXISTS ${GEOSX_TPL_DIR}/uncrustify/bin/uncrustify) - set(UNCRUSTIFY_EXECUTABLE ${GEOSX_TPL_DIR}/uncrustify/bin/uncrustify CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/uncrustify/bin/uncrustify) + set(UNCRUSTIFY_EXECUTABLE ${GEOS_TPL_DIR}/uncrustify/bin/uncrustify CACHE PATH "" FORCE) endif() -if(EXISTS ${GEOSX_TPL_DIR}/doxygen/bin/doxygen) - set(DOXYGEN_EXECUTABLE ${GEOSX_TPL_DIR}/doxygen/bin/doxygen CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/doxygen/bin/doxygen) + set(DOXYGEN_EXECUTABLE ${GEOS_TPL_DIR}/doxygen/bin/doxygen CACHE PATH "" FORCE) endif() # # Other # -if(EXISTS ${GEOSX_TPL_DIR}/mathpresso) - set(MATHPRESSO_DIR ${GEOSX_TPL_DIR}/mathpresso CACHE PATH "" FORCE) +if(EXISTS ${GEOS_TPL_DIR}/mathpresso) + set(MATHPRESSO_DIR ${GEOS_TPL_DIR}/mathpresso CACHE PATH "" FORCE) endif() diff --git a/inputFiles/compositionalMultiphaseFlow/2ph_cap_1d_ihu.xml b/inputFiles/compositionalMultiphaseFlow/2ph_cap_1d_ihu.xml new file mode 100644 index 00000000000..8c25605b332 --- /dev/null +++ b/inputFiles/compositionalMultiphaseFlow/2ph_cap_1d_ihu.xml @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/compositionalMultiphaseFlow/4comp_2ph_1d.xml b/inputFiles/compositionalMultiphaseFlow/4comp_2ph_1d.xml index 556e49fdea4..0f3273c6c7f 100644 --- a/inputFiles/compositionalMultiphaseFlow/4comp_2ph_1d.xml +++ b/inputFiles/compositionalMultiphaseFlow/4comp_2ph_1d.xml @@ -72,7 +72,7 @@ @@ -104,7 +104,7 @@ + name="vtkOutput" + plotFileRoot="4comp_2ph_1d"/> diff --git a/inputFiles/compositionalMultiphaseFlow/4comp_2ph_cap_1d.xml b/inputFiles/compositionalMultiphaseFlow/4comp_2ph_cap_1d.xml index 9072e840981..38bc945f889 100644 --- a/inputFiles/compositionalMultiphaseFlow/4comp_2ph_cap_1d.xml +++ b/inputFiles/compositionalMultiphaseFlow/4comp_2ph_cap_1d.xml @@ -45,7 +45,7 @@ maxTime="2e7"> + name="fluidTPFA"/> @@ -117,7 +116,7 @@ diff --git a/inputFiles/compositionalMultiphaseFlow/benchmarks/SPE10/deadOilSpe10Layers84_85_base_iterative.xml b/inputFiles/compositionalMultiphaseFlow/benchmarks/SPE10/deadOilSpe10Layers84_85_base_iterative.xml index 68a933abd5a..5ca7d741433 100644 --- a/inputFiles/compositionalMultiphaseFlow/benchmarks/SPE10/deadOilSpe10Layers84_85_base_iterative.xml +++ b/inputFiles/compositionalMultiphaseFlow/benchmarks/SPE10/deadOilSpe10Layers84_85_base_iterative.xml @@ -66,7 +66,7 @@ diff --git a/inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverettProblem.ats b/inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverettProblem.ats index 30944577aa4..266e7b25a48 100644 --- a/inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverettProblem.ats +++ b/inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverettProblem.ats @@ -1,5 +1,4 @@ -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params["atol"] = 1.0E-6 diff --git a/inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverett_base.xml b/inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverett_base.xml index ae3ddb8c7b1..a715c16b3a2 100644 --- a/inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverett_base.xml +++ b/inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverett_base.xml @@ -37,7 +37,7 @@ diff --git a/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell.ats b/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell.ats index acc7382aa8f..e84fb9ef269 100644 --- a/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell.ats +++ b/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell.ats @@ -1,5 +1,4 @@ -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params["atol"] = 1.0E-6 diff --git a/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_base_direct.xml b/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_base_direct.xml index 921966dad20..25668102c78 100644 --- a/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_base_direct.xml +++ b/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_base_direct.xml @@ -47,7 +47,7 @@ target="/Solvers/compflow"/> diff --git a/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_base_iterative.xml b/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_base_iterative.xml index dea8dc17e22..a70fd719ee6 100644 --- a/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_base_iterative.xml +++ b/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_base_iterative.xml @@ -2,7 +2,7 @@ - + diff --git a/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_benchmark.xml b/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_benchmark.xml index cd134e9e2f1..3edd2f02657 100644 --- a/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_benchmark.xml +++ b/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_benchmark.xml @@ -18,21 +18,15 @@ nx="{ 50, 1, 20, 1, 40 }" ny="{ 50, 1, 50 }" nz="{ 20, 30, 10 }" - cellBlockNames="{ aquiferBottom00, aquitard00, aquiferTop00, - aquiferBottom01, aquitard01, aquiferTop01, - aquiferBottom02, aquitard02, aquiferTop02, - aquiferBottom10, aquitard10, aquiferTop10, - aquiferBottom11, aquitard11, aquiferTop11, - aquiferBottom12, aquitard12, aquiferTop12, - aquiferBottom20, aquitard20, aquiferTop20, - aquiferBottom21, aquitard21, aquiferTop21, - aquiferBottom22, aquitard22, aquiferTop22, - aquiferBottom30, aquitard30, aquiferTop30, - aquiferBottom31, aquitard31, aquiferTop31, - aquiferBottom32, aquitard32, aquiferTop32, - aquiferBottom40, aquitard40, aquiferTop40, - aquiferBottom41, aquitard41, aquiferTop41, - aquiferBottom42, aquitard42, aquiferTop42 }"/> + cellBlockNames="{ aquiferBottom00, aquiferBottom10, aquiferBottom20, aquiferBottom30, aquiferBottom40, + aquiferBottom01, aquiferBottom11, aquiferBottom21, aquiferBottom31, aquiferBottom41, + aquiferBottom02, aquiferBottom12, aquiferBottom22, aquiferBottom32, aquiferBottom42, + aquitard00, aquitard10, aquitard20, aquitard30, aquitard40, + aquitard01, aquitard11, aquitard21, aquitard31, aquitard41, + aquitard02, aquitard12, aquitard22, aquitard32, aquitard42, + aquiferTop00, aquiferTop10, aquiferTop20, aquiferTop30, aquiferTop40, + aquiferTop01, aquiferTop11, aquiferTop21, aquiferTop31, aquiferTop41, + aquiferTop02, aquiferTop12, aquiferTop22, aquiferTop32, aquiferTop42 }"/> diff --git a/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_smoke_3d.xml b/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_smoke_3d.xml index 775890d368f..69362de80c4 100644 --- a/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_smoke_3d.xml +++ b/inputFiles/compositionalMultiphaseFlow/benchmarks/isothermalLeakyWell/isothermalLeakyWell_smoke_3d.xml @@ -18,21 +18,15 @@ nx="{ 5, 1, 2, 1, 4 }" ny="{ 5, 1, 5 }" nz="{ 5, 30, 5 }" - cellBlockNames="{ aquiferBottom00, aquitard00, aquiferTop00, - aquiferBottom01, aquitard01, aquiferTop01, - aquiferBottom02, aquitard02, aquiferTop02, - aquiferBottom10, aquitard10, aquiferTop10, - aquiferBottom11, aquitard11, aquiferTop11, - aquiferBottom12, aquitard12, aquiferTop12, - aquiferBottom20, aquitard20, aquiferTop20, - aquiferBottom21, aquitard21, aquiferTop21, - aquiferBottom22, aquitard22, aquiferTop22, - aquiferBottom30, aquitard30, aquiferTop30, - aquiferBottom31, aquitard31, aquiferTop31, - aquiferBottom32, aquitard32, aquiferTop32, - aquiferBottom40, aquitard40, aquiferTop40, - aquiferBottom41, aquitard41, aquiferTop41, - aquiferBottom42, aquitard42, aquiferTop42 }"/> + cellBlockNames="{ aquiferBottom00, aquiferBottom10, aquiferBottom20, aquiferBottom30, aquiferBottom40, + aquiferBottom01, aquiferBottom11, aquiferBottom21, aquiferBottom31, aquiferBottom41, + aquiferBottom02, aquiferBottom12, aquiferBottom22, aquiferBottom32, aquiferBottom42, + aquitard00, aquitard10, aquitard20, aquitard30, aquitard40, + aquitard01, aquitard11, aquitard21, aquitard31, aquitard41, + aquitard02, aquitard12, aquitard22, aquitard32, aquitard42, + aquiferTop00, aquiferTop10, aquiferTop20, aquiferTop30, aquiferTop40, + aquiferTop01, aquiferTop11, aquiferTop21, aquiferTop31, aquiferTop41, + aquiferTop02, aquiferTop12, aquiferTop22, aquiferTop32, aquiferTop42 }"/> diff --git a/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell.ats b/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell.ats index f0a149ff298..e473d997e2f 100644 --- a/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell.ats +++ b/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell.ats @@ -1,5 +1,4 @@ -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params["atol"] = 1.0E-6 diff --git a/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_base_direct.xml b/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_base_direct.xml index 9680e6ef85f..961d7c6d00d 100644 --- a/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_base_direct.xml +++ b/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_base_direct.xml @@ -73,19 +73,15 @@ diff --git a/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_base_iterative.xml b/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_base_iterative.xml index 91ec5e502d4..985cec900ae 100644 --- a/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_base_iterative.xml +++ b/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_base_iterative.xml @@ -61,19 +61,15 @@ diff --git a/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_benchmark.xml b/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_benchmark.xml index 7cd5d9467cd..45e0669af83 100644 --- a/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_benchmark.xml +++ b/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_benchmark.xml @@ -18,21 +18,15 @@ nx="{ 50, 1, 20, 1, 40 }" ny="{ 50, 1, 50 }" nz="{ 20, 30, 10 }" - cellBlockNames="{ aquiferBottom00, aquitard00, aquiferTop00, - aquiferBottom01, aquitard01, aquiferTop01, - aquiferBottom02, aquitard02, aquiferTop02, - aquiferBottom10, aquitard10, aquiferTop10, - aquiferBottom11, aquitard11, aquiferTop11, - aquiferBottom12, aquitard12, aquiferTop12, - aquiferBottom20, aquitard20, aquiferTop20, - aquiferBottom21, aquitard21, aquiferTop21, - aquiferBottom22, aquitard22, aquiferTop22, - aquiferBottom30, aquitard30, aquiferTop30, - aquiferBottom31, aquitard31, aquiferTop31, - aquiferBottom32, aquitard32, aquiferTop32, - aquiferBottom40, aquitard40, aquiferTop40, - aquiferBottom41, aquitard41, aquiferTop41, - aquiferBottom42, aquitard42, aquiferTop42 }"/> + cellBlockNames="{ aquiferBottom00, aquiferBottom10, aquiferBottom20, aquiferBottom30, aquiferBottom40, + aquiferBottom01, aquiferBottom11, aquiferBottom21, aquiferBottom31, aquiferBottom41, + aquiferBottom02, aquiferBottom12, aquiferBottom22, aquiferBottom32, aquiferBottom42, + aquitard00, aquitard10, aquitard20, aquitard30, aquitard40, + aquitard01, aquitard11, aquitard21, aquitard31, aquitard41, + aquitard02, aquitard12, aquitard22, aquitard32, aquitard42, + aquiferTop00, aquiferTop10, aquiferTop20, aquiferTop30, aquiferTop40, + aquiferTop01, aquiferTop11, aquiferTop21, aquiferTop31, aquiferTop41, + aquiferTop02, aquiferTop12, aquiferTop22, aquiferTop32, aquiferTop42 }"/> diff --git a/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_smoke_3d.xml b/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_smoke_3d.xml index ac2e8ae02d5..3aabd020d74 100644 --- a/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_smoke_3d.xml +++ b/inputFiles/compositionalMultiphaseFlow/benchmarks/thermalLeakyWell/thermalLeakyWell_smoke_3d.xml @@ -18,21 +18,15 @@ nx="{ 5, 1, 2, 1, 4 }" ny="{ 5, 1, 5 }" nz="{ 5, 30, 5 }" - cellBlockNames="{ aquiferBottom00, aquitard00, aquiferTop00, - aquiferBottom01, aquitard01, aquiferTop01, - aquiferBottom02, aquitard02, aquiferTop02, - aquiferBottom10, aquitard10, aquiferTop10, - aquiferBottom11, aquitard11, aquiferTop11, - aquiferBottom12, aquitard12, aquiferTop12, - aquiferBottom20, aquitard20, aquiferTop20, - aquiferBottom21, aquitard21, aquiferTop21, - aquiferBottom22, aquitard22, aquiferTop22, - aquiferBottom30, aquitard30, aquiferTop30, - aquiferBottom31, aquitard31, aquiferTop31, - aquiferBottom32, aquitard32, aquiferTop32, - aquiferBottom40, aquitard40, aquiferTop40, - aquiferBottom41, aquitard41, aquiferTop41, - aquiferBottom42, aquitard42, aquiferTop42 }"/> + cellBlockNames="{ aquiferBottom00, aquiferBottom10, aquiferBottom20, aquiferBottom30, aquiferBottom40, + aquiferBottom01, aquiferBottom11, aquiferBottom21, aquiferBottom31, aquiferBottom41, + aquiferBottom02, aquiferBottom12, aquiferBottom22, aquiferBottom32, aquiferBottom42, + aquitard00, aquitard10, aquitard20, aquitard30, aquitard40, + aquitard01, aquitard11, aquitard21, aquitard31, aquitard41, + aquitard02, aquitard12, aquitard22, aquitard32, aquitard42, + aquiferTop00, aquiferTop10, aquiferTop20, aquiferTop30, aquiferTop40, + aquiferTop01, aquiferTop11, aquiferTop21, aquiferTop31, aquiferTop41, + aquiferTop02, aquiferTop12, aquiferTop22, aquiferTop32, aquiferTop42 }"/> diff --git a/inputFiles/compositionalMultiphaseFlow/c1-ppu/c1_ppu.ats b/inputFiles/compositionalMultiphaseFlow/c1-ppu/c1_ppu.ats index 52d47c61ff4..5b68a2cb9f4 100644 --- a/inputFiles/compositionalMultiphaseFlow/c1-ppu/c1_ppu.ats +++ b/inputFiles/compositionalMultiphaseFlow/c1-ppu/c1_ppu.ats @@ -1,5 +1,4 @@ -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params["atol"] = 1.0E-6 @@ -9,8 +8,8 @@ decks = [ TestDeck(name="grav_seg_c1ppu_hyst", description="Smoke test for C1-PPU (1D displacement, C1-PPU)", partitions=((1, 1, 1), (1, 1, 2)), - restart_step=87, - check_step=109, + restart_step=50, + check_step=88, restartcheck_params=RestartcheckParameters(atol=1e-4, rtol=1e-3)), ] diff --git a/inputFiles/compositionalMultiphaseFlow/c1-ppu/grav_seg_c1ppu_base.xml b/inputFiles/compositionalMultiphaseFlow/c1-ppu/grav_seg_c1ppu_base.xml index 89e2c9149b6..0ddb4a08cb2 100644 --- a/inputFiles/compositionalMultiphaseFlow/c1-ppu/grav_seg_c1ppu_base.xml +++ b/inputFiles/compositionalMultiphaseFlow/c1-ppu/grav_seg_c1ppu_base.xml @@ -44,7 +44,7 @@ diff --git a/inputFiles/compositionalMultiphaseFlow/c1-ppu/grav_seg_c1ppu_hyst.xml b/inputFiles/compositionalMultiphaseFlow/c1-ppu/grav_seg_c1ppu_hyst.xml index a82c573ad0f..d47f6ff14ea 100644 --- a/inputFiles/compositionalMultiphaseFlow/c1-ppu/grav_seg_c1ppu_hyst.xml +++ b/inputFiles/compositionalMultiphaseFlow/c1-ppu/grav_seg_c1ppu_hyst.xml @@ -50,7 +50,7 @@ diff --git a/inputFiles/compositionalMultiphaseFlow/co2_flux_3d.xml b/inputFiles/compositionalMultiphaseFlow/co2_flux_3d.xml index e0b3cecde11..5620659caa9 100644 --- a/inputFiles/compositionalMultiphaseFlow/co2_flux_3d.xml +++ b/inputFiles/compositionalMultiphaseFlow/co2_flux_3d.xml @@ -9,12 +9,10 @@ temperature="368.15" useMass="1" useTotalMassEquation="0" - useSimpleAccumulation="1" targetRegions="{ region }"> @@ -92,7 +90,7 @@ @@ -136,7 +134,7 @@ + name="vtkOutput" + plotFileRoot="co2_flux_3d"/> diff --git a/inputFiles/compositionalMultiphaseFlow/co2_flux_dirichlet.xml b/inputFiles/compositionalMultiphaseFlow/co2_flux_dirichlet.xml new file mode 100644 index 00000000000..53a90de1e32 --- /dev/null +++ b/inputFiles/compositionalMultiphaseFlow/co2_flux_dirichlet.xml @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/compositionalMultiphaseFlow/co2_hybrid_1d.xml b/inputFiles/compositionalMultiphaseFlow/co2_hybrid_1d.xml index 296cd04fbc4..345c17b0b96 100644 --- a/inputFiles/compositionalMultiphaseFlow/co2_hybrid_1d.xml +++ b/inputFiles/compositionalMultiphaseFlow/co2_hybrid_1d.xml @@ -14,8 +14,7 @@ targetRegions="{ region }"> + newtonMaxIter="10"/> @@ -50,7 +49,7 @@ maxTime="1e5"> @@ -100,7 +99,7 @@ + name="vtkOutput" + plotFileRoot="co2_hybrid_1d"/> diff --git a/inputFiles/compositionalMultiphaseFlow/compositionalMultiphaseFlow.ats b/inputFiles/compositionalMultiphaseFlow/compositionalMultiphaseFlow.ats index a0072bc2653..18a5ee01dc5 100644 --- a/inputFiles/compositionalMultiphaseFlow/compositionalMultiphaseFlow.ats +++ b/inputFiles/compositionalMultiphaseFlow/compositionalMultiphaseFlow.ats @@ -1,5 +1,4 @@ -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params["atol"] = 1.0E-6 @@ -22,6 +21,22 @@ decks = [ restart_step=118, check_step=218, restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="co2_hybrid_1d", + description= + "Compositional co2-brine flow test (1D displacement, hybrid FVM, Brooks-Corey pairwise 2-phase relperm curves)", + partitions=((1, 1, 1), (2, 1, 1), (3, 1, 1)), + restart_step=5, + check_step=10, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="2ph_cap_1d_ihu", + description= + "Two-phase flow test for IHU (1D displacement, 2-phase, capillary pressure)", + partitions=((1, 1, 1), (3, 1, 1)), + restart_step=34, + check_step=60, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), TestDeck( name="deadoil_3ph_corey_1d", description= @@ -31,12 +46,20 @@ decks = [ check_step=209, restartcheck_params=RestartcheckParameters(**restartcheck_params)), TestDeck( - name="co2_hybrid_1d", + name="deadoil_3ph_stone2_1d", description= - "Compositional co2-brine flow test (1D displacement, hybrid FVM, Brooks-Corey pairwise 2-phase relperm curves)", - partitions=((1, 1, 1), (2, 1, 1), (3, 1, 1)), - restart_step=5, - check_step=10, + "Compositional multiphase flow test (1D displacement, 3-phase dead-oil, Stone2 relperm curves)", + partitions=((1, 1, 1), (3, 1, 1)), + restart_step=109, + check_step=209, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="deadoil_3ph_corey_1d_fractured", + description= + "Compositional multiphase flow test with EDFM (1D displacement, 3-phase dead-oil, Brooks-Corey pairwise 2-phase relperm curves)", + partitions=((1, 1, 1), (3, 1, 1)), + restart_step=0, + check_step=209, restartcheck_params=RestartcheckParameters(**restartcheck_params)), TestDeck( name="deadoil_3ph_baker_1d", @@ -62,6 +85,14 @@ decks = [ restart_step=28, check_step=38, restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="deadoil_3ph_staircase_obl_3d", + description= + "Smoke test for a staircase deadoil test (3D displacement, 3-phase dead-oil, OBL)", + partitions=((1, 1, 1), (2, 2, 2)), + restart_step=28, + check_step=38, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), TestDeck( name="deadoil_2ph_staircase_gravity_segregation_3d", description= @@ -79,13 +110,13 @@ decks = [ check_step=20, restartcheck_params=RestartcheckParameters(**restartcheck_params)), TestDeck( - name="deadoil_3ph_staircase_obl_3d", + name="co2_flux_dirichlet", description= - "Smoke test for a staircase deadoil test (3D displacement, 3-phase dead-oil, OBL)", - partitions=((1, 1, 1), (2, 2, 2)), - restart_step=28, - check_step=38, - restartcheck_params=RestartcheckParameters(**restartcheck_params)), + "Compositional co2-brine flow test (2D co2 injection, 2-phase co2-brine, Table 2-phase relperm curves, Dirichlet boundary)", + partitions=((1, 1, 1), (2, 1, 3)), + restart_step=23, + check_step=46, + restartcheck_params=RestartcheckParameters(**restartcheck_params)) ] generate_geos_tests(decks) diff --git a/inputFiles/compositionalMultiphaseFlow/dbc/bottom_layer_SPE10/bottom_layer_SPE10_base.xml b/inputFiles/compositionalMultiphaseFlow/dbc/bottom_layer_SPE10/bottom_layer_SPE10_base.xml index 9a7515aa2e8..a1d89df6bd9 100755 --- a/inputFiles/compositionalMultiphaseFlow/dbc/bottom_layer_SPE10/bottom_layer_SPE10_base.xml +++ b/inputFiles/compositionalMultiphaseFlow/dbc/bottom_layer_SPE10/bottom_layer_SPE10_base.xml @@ -11,7 +11,7 @@ diff --git a/inputFiles/compositionalMultiphaseFlow/dbc/buckleyLeverett_1d/buckleyLeverett_1d.xml b/inputFiles/compositionalMultiphaseFlow/dbc/buckleyLeverett_1d/buckleyLeverett_1d.xml index b7978a7ba52..c2cb4574d62 100755 --- a/inputFiles/compositionalMultiphaseFlow/dbc/buckleyLeverett_1d/buckleyLeverett_1d.xml +++ b/inputFiles/compositionalMultiphaseFlow/dbc/buckleyLeverett_1d/buckleyLeverett_1d.xml @@ -41,7 +41,7 @@ diff --git a/inputFiles/compositionalMultiphaseFlow/dbc/buckleyLeverett_1d/buckleyLeverett_1d_DBC.xml b/inputFiles/compositionalMultiphaseFlow/dbc/buckleyLeverett_1d/buckleyLeverett_1d_DBC.xml index 980fd46f7b9..38eef01c374 100755 --- a/inputFiles/compositionalMultiphaseFlow/dbc/buckleyLeverett_1d/buckleyLeverett_1d_DBC.xml +++ b/inputFiles/compositionalMultiphaseFlow/dbc/buckleyLeverett_1d/buckleyLeverett_1d_DBC.xml @@ -47,7 +47,7 @@ diff --git a/inputFiles/compositionalMultiphaseFlow/dbc/grav_seg_1d/grav_seg_1d.xml b/inputFiles/compositionalMultiphaseFlow/dbc/grav_seg_1d/grav_seg_1d.xml index 8da5b23a782..2fd8219bf3c 100755 --- a/inputFiles/compositionalMultiphaseFlow/dbc/grav_seg_1d/grav_seg_1d.xml +++ b/inputFiles/compositionalMultiphaseFlow/dbc/grav_seg_1d/grav_seg_1d.xml @@ -44,7 +44,7 @@ diff --git a/inputFiles/compositionalMultiphaseFlow/dbc/grav_seg_1d/grav_seg_1d_DBC.xml b/inputFiles/compositionalMultiphaseFlow/dbc/grav_seg_1d/grav_seg_1d_DBC.xml index 283c3f5623c..ad39d37d01f 100755 --- a/inputFiles/compositionalMultiphaseFlow/dbc/grav_seg_1d/grav_seg_1d_DBC.xml +++ b/inputFiles/compositionalMultiphaseFlow/dbc/grav_seg_1d/grav_seg_1d_DBC.xml @@ -50,7 +50,7 @@ diff --git a/inputFiles/compositionalMultiphaseFlow/deadoil_2ph_staircase_gravity_segregation_3d.xml b/inputFiles/compositionalMultiphaseFlow/deadoil_2ph_staircase_gravity_segregation_3d.xml index 23af6f08231..de5f6ae2f47 100644 --- a/inputFiles/compositionalMultiphaseFlow/deadoil_2ph_staircase_gravity_segregation_3d.xml +++ b/inputFiles/compositionalMultiphaseFlow/deadoil_2ph_staircase_gravity_segregation_3d.xml @@ -13,8 +13,7 @@ temperature="300"> + newtonMaxIter="15"/> @@ -30,7 +29,10 @@ nx="{ 5, 5 }" ny="{ 5, 5 }" nz="{ 3, 3, 3, 3 }" - cellBlockNames="{ b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11, b12, b13, b14, b15 }"/> + cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, + cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1, + cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2, + cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }"/> @@ -71,12 +73,12 @@ @@ -105,7 +107,7 @@ + name="vtkOutput" + plotFileRoot="deadoil_2ph_staircase_gravity_segregation_3d"/> diff --git a/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_baker_1d.xml b/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_baker_1d.xml index 30eb6334ce6..0b21ae2e0e4 100644 --- a/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_baker_1d.xml +++ b/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_baker_1d.xml @@ -10,8 +10,7 @@ temperature="300"> + newtonMaxIter="10"/> @@ -46,7 +45,7 @@ maxTime="2e7"> @@ -107,7 +106,7 @@ @@ -102,7 +102,7 @@ + directParallel="0"/> @@ -88,11 +86,11 @@ beginTime="1e5" target="/Solvers/compflow"/> - + target="/Outputs/restartOutput"/> @@ -110,19 +108,19 @@ + cellBlocks="{ * }" + materialList="{ fluid, rock, relperm }"/> + name="vtkOutput" + plotFileRoot="deadoil_3ph_corey_1d_fractured"/> diff --git a/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_staircase_3d.xml b/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_staircase_3d.xml index 2b90105cff6..f6240c8517e 100644 --- a/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_staircase_3d.xml +++ b/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_staircase_3d.xml @@ -13,7 +13,7 @@ temperature="300"> + newtonMaxIter="10"/> @@ -31,7 +31,10 @@ nx="{ 5, 5 }" ny="{ 5, 5 }" nz="{ 3, 3, 3, 3 }" - cellBlockNames="{ b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11, b12, b13, b14, b15 }"/> + cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, + cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1, + cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2, + cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }"/> @@ -54,11 +57,11 @@ maxTime="2e8"> @@ -137,7 +140,7 @@ + name="vtkOutput" + plotFileRoot="deadoil_3ph_staircase_3d"/> diff --git a/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_staircase_3d_transmi_output.xml b/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_staircase_3d_transmi_output.xml new file mode 100644 index 00000000000..121881e8650 --- /dev/null +++ b/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_staircase_3d_transmi_output.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_staircase_hybrid_3d.xml b/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_staircase_hybrid_3d.xml index e4daec34867..62852bc55a5 100644 --- a/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_staircase_hybrid_3d.xml +++ b/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_staircase_hybrid_3d.xml @@ -12,7 +12,7 @@ maxCompFractionChange="0.5"> @@ -29,7 +29,10 @@ nx="{ 5, 5 }" ny="{ 5, 5 }" nz="{ 3, 3, 3, 3 }" - cellBlockNames="{ b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11, b12, b13, b14, b15 }"/> + cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, + cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1, + cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2, + cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }"/> @@ -48,7 +51,7 @@ maxTime="2e8"> @@ -118,7 +121,7 @@ + newtonMaxIter="10"/> @@ -34,7 +34,10 @@ nx="{ 5, 5 }" ny="{ 5, 5 }" nz="{ 3, 3, 3, 3 }" - cellBlockNames="{ b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11, b12, b13, b14, b15 }"/> + cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, + cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1, + cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2, + cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }"/> @@ -57,7 +60,7 @@ maxTime="2e8"> @@ -125,7 +128,7 @@ + name="vtkOutput" + plotFileRoot="deadoil_3ph_staircase_obl_3d"/> diff --git a/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_stone2_1d.xml b/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_stone2_1d.xml index 6392da9c380..64c58482fbb 100644 --- a/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_stone2_1d.xml +++ b/inputFiles/compositionalMultiphaseFlow/deadoil_3ph_stone2_1d.xml @@ -6,8 +6,8 @@ name="compflow" logLevel="1" discretization="fluidTPFA" - targetRegions="{ region }" - temperature="300"> + temperature="300" + targetRegions="{ region }"> @@ -107,7 +107,7 @@ - + + fieldNamesInGEOS="{ rockPerm_permeability, rockPorosity_referencePorosity }" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_benchmark_mct.xml b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_benchmark_mct.xml new file mode 100644 index 00000000000..92acf46ae7e --- /dev/null +++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_benchmark_mct.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_direct_base.xml b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_direct_base.xml index 56d39f42bfb..fba559385dc 100644 --- a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_direct_base.xml +++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_direct_base.xml @@ -51,7 +51,7 @@ + + @@ -62,7 +90,7 @@ + diff --git a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_hystRelperm_direct_base.xml b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_hystRelperm_direct_base.xml index 31e28d56aea..cfd5ead5e46 100644 --- a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_hystRelperm_direct_base.xml +++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_hystRelperm_direct_base.xml @@ -51,7 +51,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_direct.xml b/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_direct.xml index 60591a45404..7ac8dd517d2 100644 --- a/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_direct.xml +++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_direct.xml @@ -225,7 +225,7 @@ + krylovWeakestTol="1e-2" + logLevel="1"/> @@ -209,7 +210,7 @@ timeFrequency="7.5e6" targetExactTimestep="0" target="/Outputs/restartOutput"/> - + @@ -226,7 +227,7 @@ - + diff --git a/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_benchmark.xml b/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_benchmark.xml index 539cbbb9909..0f46dff5621 100644 --- a/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_benchmark.xml +++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_benchmark.xml @@ -13,7 +13,7 @@ name="mesh" file="../../../../../GEOSDATA/DataSets/Egg/egg.vtu" fieldsToImport="{ PERM }" - fieldNamesInGEOSX="{ rockPerm_permeability }"> + fieldNamesInGEOS="{ rockPerm_permeability }"> - diff --git a/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_3d.xml b/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_3d.xml index 2c66c759f13..93f9b1469eb 100644 --- a/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_3d.xml +++ b/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_3d.xml @@ -65,7 +65,10 @@ nx="{ 5, 5 }" ny="{ 5, 5 }" nz="{ 3, 3, 3, 3 }" - cellBlockNames="{ b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11, b12, b13, b14, b15 }"> + cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, + cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1, + cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2, + cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }"> @@ -117,7 +117,7 @@ + logLevel="1" + contactPenaltyStiffness="1.0e12"> @@ -60,12 +61,10 @@ defaultShearModulus="1.0e10"/> + frictionCoefficient = "0.8"/> @@ -116,13 +115,6 @@ scale="0.0" setNames="{ zneg, zpos }"/> - - - - + logLevel="1" + contactPenaltyStiffness="1.0e8"> @@ -60,18 +61,9 @@ defaultShearModulus="1.0e10"/> + name="frictionLaw"/> - - - - + useStaticCondensation="1" + contactPenaltyStiffness="0.0e8"> + useStaticCondensation="1" + contactPenaltyStiffness="0.0e8"> + useStaticCondensation="1" + contactPenaltyStiffness="0.0e8"> + logLevel="1" + contactPenaltyStiffness="0.0e8"> @@ -85,19 +86,10 @@ defaultShearModulus="1.0e10"/> + name="frictionLaw"/> - - - - @@ -35,19 +35,10 @@ defaultShearModulus="1.0e10"/> + name="frictionLaw"/> - - - - + format="binary" + plotFileRoot="sneddon_embFrac"/> + logLevel="1" + contactPenaltyStiffness="0.0e8"> + logLevel="1" + contactPenaltyStiffness="0.0e8"> + useStaticCondensation="1" + contactPenaltyStiffness="0.0e8"> + useStaticCondensation="1" + contactPenaltyStiffness="0.0e8"> + logLevel="1" + contactPenaltyStiffness="0.0e8"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0e0"/> + materialList="{ water, fractureFilling, fractureContact, hApertureModel }"/> @@ -126,9 +126,11 @@ name="fracturePerm"/> + name="fractureContact"/> + + diff --git a/inputFiles/hydraulicFracturing/heterogeneousInSitu_base.xml b/inputFiles/hydraulicFracturing/heterogeneousInSitu_base.xml index bbf01a6a976..c8d741170ae 100644 --- a/inputFiles/hydraulicFracturing/heterogeneousInSitu_base.xml +++ b/inputFiles/hydraulicFracturing/heterogeneousInSitu_base.xml @@ -11,7 +11,6 @@ surfaceGeneratorName="SurfaceGen" logLevel="1" targetRegions="{ Fracture }" - contactRelationName="fractureContact" maxNumResolves="2"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1e12"> + materialList="{ water, fractureFilling, fractureContact, hApertureModel }"/> @@ -157,9 +157,11 @@ compressibility="0.0"/> + name="fractureContact"/> + + diff --git a/inputFiles/hydraulicFracturing/heterogeneousInSitu_smoke.xml b/inputFiles/hydraulicFracturing/heterogeneousInSitu_smoke.xml index b75048cd2c2..eb7b96bf286 100644 --- a/inputFiles/hydraulicFracturing/heterogeneousInSitu_smoke.xml +++ b/inputFiles/hydraulicFracturing/heterogeneousInSitu_smoke.xml @@ -44,7 +44,6 @@ surfaceGeneratorName="SurfaceGen" logLevel="1" targetRegions="{ Fracture }" - contactRelationName="fractureContact" maxNumResolves="2"> + contactRelationName="fractureContact" + contactPenaltyStiffness="0.0e12"> + materialList="{ water, fractureFilling, fractureContact, hApertureModel }"/> @@ -167,9 +167,11 @@ compressibility="0.0"/> + name="fractureContact"/> + + diff --git a/inputFiles/hydraulicFracturing/hydrofractureSinglePhase2d.xml b/inputFiles/hydraulicFracturing/hydrofractureSinglePhase2d.xml index 5d1e865b642..7ac70ce7a6f 100644 --- a/inputFiles/hydraulicFracturing/hydrofractureSinglePhase2d.xml +++ b/inputFiles/hydraulicFracturing/hydrofractureSinglePhase2d.xml @@ -9,8 +9,7 @@ solidSolverName="lagsolve" flowSolverName="SinglePhaseFlow" surfaceGeneratorName="SurfaceGen" - targetRegions="{ Fracture }" - contactRelationName="fractureContact"> + targetRegions="{ Fracture }"> + contactRelationName="fractureContact" + contactPenaltyStiffness="0.0e12"/> @@ -160,9 +160,11 @@ name="fracturePerm"/> + name="fractureContact"/> + + diff --git a/inputFiles/hydraulicFracturing/kgdBase_C3D6_base.xml b/inputFiles/hydraulicFracturing/kgdBase_C3D6_base.xml index 19f102b76c5..77243fc9078 100644 --- a/inputFiles/hydraulicFracturing/kgdBase_C3D6_base.xml +++ b/inputFiles/hydraulicFracturing/kgdBase_C3D6_base.xml @@ -18,13 +18,13 @@ + materialList="{ water, fractureFilling, fractureContact, hApertureModel }"/> @@ -62,10 +62,11 @@ name="fracturePerm"/> + name="fractureContact"/> + diff --git a/inputFiles/hydraulicFracturing/kgdEdgeBased_C3D6_base.xml b/inputFiles/hydraulicFracturing/kgdEdgeBased_C3D6_base.xml index 298684e5927..cc461b52ba3 100644 --- a/inputFiles/hydraulicFracturing/kgdEdgeBased_C3D6_base.xml +++ b/inputFiles/hydraulicFracturing/kgdEdgeBased_C3D6_base.xml @@ -13,12 +13,11 @@ solidSolverName="lagsolve" flowSolverName="SinglePhaseFlow" surfaceGeneratorName="SurfaceGen" - targetRegions="{ Fracture }" - contactRelationName="fractureContact"> + targetRegions="{ Fracture }"> + lineSearchAction="None"/> @@ -28,7 +27,8 @@ timeIntegrationOption="QuasiStatic" discretization="FE1" targetRegions="{ Domain, Fracture }" - contactRelationName="fractureContact"> + contactRelationName="fractureContact" + contactPenaltyStiffness="0.0e8"> + targetRegions="{ Fracture }"> + lineSearchAction="None"/> @@ -29,7 +28,8 @@ timeIntegrationOption="QuasiStatic" discretization="FE1" targetRegions="{ Domain, Fracture }" - contactRelationName="fractureContact"/> + contactRelationName="fractureContact" + contactPenaltyStiffness="0.0e8"/> @@ -30,7 +29,8 @@ timeIntegrationOption="QuasiStatic" discretization="FE1" targetRegions="{ Domain, Fracture }" - contactRelationName="fractureContact"/> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0"/> @@ -66,13 +66,13 @@ + materialList="{ water, fractureFilling, fractureContact, hApertureModel }"/> @@ -114,9 +114,11 @@ name="fracturePerm"/> + name="fractureContact"/> + + diff --git a/inputFiles/hydraulicFracturing/kgdToughnessDominated_poroelastic_base.xml b/inputFiles/hydraulicFracturing/kgdToughnessDominated_poroelastic_base.xml index e7296af5629..8f4284dd838 100644 --- a/inputFiles/hydraulicFracturing/kgdToughnessDominated_poroelastic_base.xml +++ b/inputFiles/hydraulicFracturing/kgdToughnessDominated_poroelastic_base.xml @@ -11,7 +11,6 @@ logLevel="1" targetRegions="{ Domain, Fracture }" isMatrixPoroelastic="1" - contactRelationName="fractureContact" maxNumResolves="2"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0"/> + materialList="{ water, fractureFilling, fractureContact, hApertureModel }"/> @@ -91,7 +91,7 @@ + name="fractureContact"/> + + diff --git a/inputFiles/hydraulicFracturing/kgdToughnessDominated_smoke.xml b/inputFiles/hydraulicFracturing/kgdToughnessDominated_smoke.xml index b21bb677c40..26195e1f67a 100644 --- a/inputFiles/hydraulicFracturing/kgdToughnessDominated_smoke.xml +++ b/inputFiles/hydraulicFracturing/kgdToughnessDominated_smoke.xml @@ -38,7 +38,7 @@ + maxTime="10.0"> @@ -64,7 +64,7 @@ @@ -75,8 +75,7 @@ diff --git a/inputFiles/hydraulicFracturing/kgdValidation_base.xml b/inputFiles/hydraulicFracturing/kgdValidation_base.xml index 59c48a60734..e2d16b6d247 100644 --- a/inputFiles/hydraulicFracturing/kgdValidation_base.xml +++ b/inputFiles/hydraulicFracturing/kgdValidation_base.xml @@ -11,7 +11,6 @@ surfaceGeneratorName="SurfaceGen" logLevel="1" targetRegions="{ Fracture }" - contactRelationName="fractureContact" maxNumResolves="2"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0"/> @@ -69,13 +69,13 @@ + materialList="{ water, fractureFilling, fractureContact, hApertureModel }"/> @@ -115,9 +115,11 @@ name="fracturePerm"/> + name="fractureContact"/> + + diff --git a/inputFiles/hydraulicFracturing/kgdViscosityDominated_base.xml b/inputFiles/hydraulicFracturing/kgdViscosityDominated_base.xml index 28cb49e72b3..e9b55058b17 100644 --- a/inputFiles/hydraulicFracturing/kgdViscosityDominated_base.xml +++ b/inputFiles/hydraulicFracturing/kgdViscosityDominated_base.xml @@ -12,7 +12,6 @@ logLevel="1" initialDt="0.1" targetRegions="{ Fracture }" - contactRelationName="fractureContact" maxNumResolves="2"> @@ -30,7 +29,8 @@ timeIntegrationOption="QuasiStatic" discretization="FE1" targetRegions="{ Domain, Fracture }" - contactRelationName="fractureContact"/> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0e0"/> @@ -67,13 +67,13 @@ + materialList="{ water, fractureFilling, fractureContact, hApertureModel }"/> @@ -115,9 +115,11 @@ name="fracturePerm"/> + name="fractureContact"/> + + diff --git a/inputFiles/hydraulicFracturing/kgdViscosityDominated_poroelastic_base.xml b/inputFiles/hydraulicFracturing/kgdViscosityDominated_poroelastic_base.xml index c8f35cb12c4..15a381c8365 100644 --- a/inputFiles/hydraulicFracturing/kgdViscosityDominated_poroelastic_base.xml +++ b/inputFiles/hydraulicFracturing/kgdViscosityDominated_poroelastic_base.xml @@ -11,7 +11,6 @@ logLevel="1" targetRegions="{ Domain, Fracture }" isMatrixPoroelastic="1" - contactRelationName="fractureContact" maxNumResolves="2"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0e0"/> + materialList="{ water, fractureFilling, fractureContact, hApertureModel }"/> @@ -92,7 +92,7 @@ + name="fractureContact"/> + + diff --git a/inputFiles/hydraulicFracturing/kgdViscosityDominated_smoke.xml b/inputFiles/hydraulicFracturing/kgdViscosityDominated_smoke.xml index 87c12c67c72..7ab3f2483c1 100644 --- a/inputFiles/hydraulicFracturing/kgdViscosityDominated_smoke.xml +++ b/inputFiles/hydraulicFracturing/kgdViscosityDominated_smoke.xml @@ -38,7 +38,7 @@ + maxTime="2.0"> @@ -52,21 +52,21 @@ diff --git a/inputFiles/hydraulicFracturing/pennyShapedToughnessDominated_base.xml b/inputFiles/hydraulicFracturing/pennyShapedToughnessDominated_base.xml index bf1560af82a..3254023c350 100644 --- a/inputFiles/hydraulicFracturing/pennyShapedToughnessDominated_base.xml +++ b/inputFiles/hydraulicFracturing/pennyShapedToughnessDominated_base.xml @@ -5,13 +5,13 @@ + materialList="{ water, fractureFilling, fractureContact, hApertureModel }"/> @@ -51,9 +51,12 @@ name="fracturePerm"/> + name="fractureContact"/> + + + diff --git a/inputFiles/hydraulicFracturing/pennyShapedToughnessDominated_benchmark.xml b/inputFiles/hydraulicFracturing/pennyShapedToughnessDominated_benchmark.xml index be67d03b8e2..59abb35871a 100644 --- a/inputFiles/hydraulicFracturing/pennyShapedToughnessDominated_benchmark.xml +++ b/inputFiles/hydraulicFracturing/pennyShapedToughnessDominated_benchmark.xml @@ -16,7 +16,6 @@ surfaceGeneratorName="SurfaceGen" logLevel="1" targetRegions="{ Fracture }" - contactRelationName="fractureContact" maxNumResolves="5" initialDt="0.1"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0e0"> + materialList="{ water, fractureFilling, fractureContact, hApertureModel }"/> @@ -40,7 +40,7 @@ + name="fractureContact"/> + + @@ -82,8 +84,7 @@ + name="singlePhaseTPFA"/> diff --git a/inputFiles/hydraulicFracturing/pennyShapedToughnessDominated_poroelastic_benchmark.xml b/inputFiles/hydraulicFracturing/pennyShapedToughnessDominated_poroelastic_benchmark.xml index dff5dd1605c..e830a52c5fd 100644 --- a/inputFiles/hydraulicFracturing/pennyShapedToughnessDominated_poroelastic_benchmark.xml +++ b/inputFiles/hydraulicFracturing/pennyShapedToughnessDominated_poroelastic_benchmark.xml @@ -17,7 +17,6 @@ logLevel="1" targetRegions="{ Domain, Fracture }" isMatrixPoroelastic="1" - contactRelationName="fractureContact" maxNumResolves="5" initialDt="0.1"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0e0"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0e0"> + maxTime="1.0" + maxCycle="10"> @@ -94,17 +94,20 @@ @@ -114,7 +117,7 @@ diff --git a/inputFiles/hydraulicFracturing/pennyShapedViscosityDominated_base.xml b/inputFiles/hydraulicFracturing/pennyShapedViscosityDominated_base.xml index 5ab4f148e39..4e035594dd6 100644 --- a/inputFiles/hydraulicFracturing/pennyShapedViscosityDominated_base.xml +++ b/inputFiles/hydraulicFracturing/pennyShapedViscosityDominated_base.xml @@ -5,13 +5,13 @@ + materialList="{ water, fractureFilling, fractureContact, hApertureModel }"/> @@ -51,9 +51,11 @@ name="fracturePerm"/> + name="fractureContact"/> + + diff --git a/inputFiles/hydraulicFracturing/pennyShapedViscosityDominated_benchmark.xml b/inputFiles/hydraulicFracturing/pennyShapedViscosityDominated_benchmark.xml index 06b52ff40af..a8f78adf606 100644 --- a/inputFiles/hydraulicFracturing/pennyShapedViscosityDominated_benchmark.xml +++ b/inputFiles/hydraulicFracturing/pennyShapedViscosityDominated_benchmark.xml @@ -16,7 +16,6 @@ surfaceGeneratorName="SurfaceGen" logLevel="1" targetRegions="{ Fracture }" - contactRelationName="fractureContact" maxNumResolves="1" initialDt="0.1"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0e0"> + materialList="{ water, fractureFilling, fractureContact, hApertureModel }"/> @@ -40,7 +40,7 @@ + name="fractureContact"/> + + diff --git a/inputFiles/hydraulicFracturing/pennyShapedViscosityDominated_poroelastic_benchmark.xml b/inputFiles/hydraulicFracturing/pennyShapedViscosityDominated_poroelastic_benchmark.xml index cf731e4fe59..0d1b9485772 100644 --- a/inputFiles/hydraulicFracturing/pennyShapedViscosityDominated_poroelastic_benchmark.xml +++ b/inputFiles/hydraulicFracturing/pennyShapedViscosityDominated_poroelastic_benchmark.xml @@ -17,7 +17,6 @@ logLevel="1" targetRegions="{ Domain, Fracture }" isMatrixPoroelastic="1" - contactRelationName="fractureContact" maxNumResolves="1" initialDt="0.1"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0e0"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0e0"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0e0"> + maxTime="1.0" + maxCycle="10"> @@ -93,17 +94,21 @@ @@ -113,7 +118,7 @@ diff --git a/inputFiles/hydraulicFracturing/pknViscosityDominated_base.xml b/inputFiles/hydraulicFracturing/pknViscosityDominated_base.xml index 2d3507534f4..366c146ea90 100644 --- a/inputFiles/hydraulicFracturing/pknViscosityDominated_base.xml +++ b/inputFiles/hydraulicFracturing/pknViscosityDominated_base.xml @@ -5,13 +5,13 @@ + materialList="{ water, fractureFilling, fractureContact, hApertureModel }"/> @@ -51,9 +51,12 @@ name="fracturePerm"/> + name="fractureContact"/> + + + diff --git a/inputFiles/hydraulicFracturing/pknViscosityDominated_benchmark.xml b/inputFiles/hydraulicFracturing/pknViscosityDominated_benchmark.xml index 9b4d96a8d12..2b8dce7a719 100644 --- a/inputFiles/hydraulicFracturing/pknViscosityDominated_benchmark.xml +++ b/inputFiles/hydraulicFracturing/pknViscosityDominated_benchmark.xml @@ -16,7 +16,6 @@ surfaceGeneratorName="SurfaceGen" logLevel="1" targetRegions="{ Fracture }" - contactRelationName="fractureContact" maxNumResolves="5" initialDt="0.1"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0e0"> + materialList="{ water, fractureFilling, fractureContact, hApertureModel }"/> @@ -40,7 +40,7 @@ + name="fractureContact"/> + + diff --git a/inputFiles/hydraulicFracturing/pknViscosityDominated_poroelastic_benchmark.xml b/inputFiles/hydraulicFracturing/pknViscosityDominated_poroelastic_benchmark.xml index 4dde5d644d2..72b1be2f4d8 100644 --- a/inputFiles/hydraulicFracturing/pknViscosityDominated_poroelastic_benchmark.xml +++ b/inputFiles/hydraulicFracturing/pknViscosityDominated_poroelastic_benchmark.xml @@ -17,7 +17,6 @@ logLevel="1" targetRegions="{ Domain, Fracture }" isMatrixPoroelastic="1" - contactRelationName="fractureContact" maxNumResolves="5" initialDt="0.1"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0e0"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0e0"> + contactRelationName="fractureContact" + contactPenaltyStiffness="1.0e0"> + maxTime="4" + maxCycle="10"> @@ -107,13 +108,13 @@ targetExactTimestep="0" target="/Outputs/curveOutput"/> - + target="/Outputs/vtkOutput"/> --> diff --git a/inputFiles/hydraulicFracturing/scripts/hydrofractureFigure.py b/inputFiles/hydraulicFracturing/scripts/hydrofractureFigure.py index 739777bb336..c8cb897201d 100644 --- a/inputFiles/hydraulicFracturing/scripts/hydrofractureFigure.py +++ b/inputFiles/hydraulicFracturing/scripts/hydrofractureFigure.py @@ -5,10 +5,10 @@ import sys -def getParametersFromXML(xmlFilePath): - prefix = "../../../../../../../inputFiles/hydraulicFracturing/" +def getParametersFromXML( geosDir, xmlFilePrefix): + prefix = geosDir + "/inputFiles/hydraulicFracturing/" - tree = ElementTree.parse(prefix + xmlFilePath + "_benchmark.xml") + tree = ElementTree.parse(prefix + xmlFilePrefix + "_benchmark.xml") maxTime = float(tree.find('Events').get('maxTime')) @@ -22,7 +22,7 @@ def getParametersFromXML(xmlFilePath): found_source = True if found_source: break - tree = ElementTree.parse(prefix + xmlFilePath + "_base.xml") + tree = ElementTree.parse(prefix + xmlFilePrefix + "_base.xml") elasticParam = tree.find('Constitutive/ElasticIsotropic') @@ -30,30 +30,30 @@ def getParametersFromXML(xmlFilePath): fluidDensity = float(tree.find('Constitutive/CompressibleSinglePhaseFluid').get('defaultDensity')) - if xmlFilePath == 'kgdToughnessDominated' or xmlFilePath == 'kgdViscosityDominated': + if xmlFilePrefix == 'kgdToughnessDominated' or xmlFilePrefix == 'kgdViscosityDominated': youngModulus = float(elasticParam.get('defaultYoungModulus')) poissonRatio = float(elasticParam.get('defaultPoissonRatio')) injectionRate = -2.0 * float(tree.find('FieldSpecifications/SourceFlux').get('scale')) / fluidDensity - tree = ElementTree.parse(prefix + xmlFilePath + "_base.xml") + tree = ElementTree.parse(prefix + xmlFilePrefix + "_base.xml") toughness = float(tree.find('Solvers/SurfaceGenerator').get('rockToughness')) - elif xmlFilePath == 'pennyShapedToughnessDominated' or xmlFilePath == 'pennyShapedViscosityDominated': + elif xmlFilePrefix == 'pennyShapedToughnessDominated' or xmlFilePrefix == 'pennyShapedViscosityDominated': K = float(elasticParam.get('defaultBulkModulus')) G = float(elasticParam.get('defaultShearModulus')) youngModulus = (9.0 * K * G) / (3.0 * K + G) poissonRatio = youngModulus / (2.0 * G) - 1.0 injectionRate = -4.0 * float(tree.find('FieldSpecifications/SourceFlux').get('scale')) / fluidDensity - tree = ElementTree.parse(prefix + xmlFilePath + "_benchmark.xml") + tree = ElementTree.parse(prefix + xmlFilePrefix + "_benchmark.xml") toughness = float(tree.find('Solvers/SurfaceGenerator').get('rockToughness')) - elif xmlFilePath == 'pknViscosityDominated': + elif xmlFilePrefix == 'pknViscosityDominated': K = float(elasticParam.get('defaultBulkModulus')) G = float(elasticParam.get('defaultShearModulus')) youngModulus = (9.0 * K * G) / (3.0 * K + G) poissonRatio = youngModulus / (2.0 * G) - 1.0 injectionRate = -4.0 * float(tree.find('FieldSpecifications/SourceFlux').get('scale')) / fluidDensity - tree = ElementTree.parse(prefix + xmlFilePath + "_benchmark.xml") + tree = ElementTree.parse(prefix + xmlFilePrefix + "_benchmark.xml") toughness = float(tree.find('Solvers/SurfaceGenerator').get('rockToughness')) found_core = False for elem in param: @@ -68,17 +68,17 @@ def getParametersFromXML(xmlFilePath): -def main(xmlFilePathPrefix=''): - if not xmlFilePathPrefix: - xmlFilePathPrefix = sys.argv[1] +def main( geosDir, xmlFilePrefix=''): + if not xmlFilePrefix: + xmlFilePrefix = sys.argv[1] - tMax, E, nu, KIC, mu, Q0, xSource = getParametersFromXML(xmlFilePathPrefix) + tMax, E, nu, KIC, mu, Q0, xSource = getParametersFromXML( geosDir, xmlFilePrefix) Ep = E / (1.0 - nu**2.0) t = np.arange(0.01 * tMax, tMax, 0.01 * tMax) radTimes = np.array([tMax]) - if xmlFilePathPrefix == 'kgdToughnessDominated': + if xmlFilePrefix == 'kgdToughnessDominated': hfsolns = HydrofractureSolutions.KGDSolutions() kgdFrac = hfsolns.Solutions(mu, Ep, Q0, KIC, t, radTimes, xSource) inletPressure = kgdFrac[5] @@ -86,7 +86,7 @@ def main(xmlFilePathPrefix=''): inletAperture = kgdFrac[7] lablelist = ['Asymptotic ( $\mu$ => 0, $C_{L}$ => 0 )', 'GEOSX ( $\mu$ => 0, $C_{L}$ => 0 )'] - elif xmlFilePathPrefix == 'kgdViscosityDominated': + elif xmlFilePrefix == 'kgdViscosityDominated': hfsolns = HydrofractureSolutions.KGDSolutions() kgdFrac = hfsolns.Solutions(mu, Ep, Q0, KIC, t, radTimes, xSource) inletPressure = kgdFrac[8] @@ -94,7 +94,7 @@ def main(xmlFilePathPrefix=''): inletAperture = kgdFrac[10] lablelist = ['Asymptotic ( $K_{IC}$ => 0, $C_{L}$ => 0 )', 'GEOSX ( $K_{IC}$ => 0, $C_{L}$ => 0 )'] - elif xmlFilePathPrefix == 'pennyShapedToughnessDominated': + elif xmlFilePrefix == 'pennyShapedToughnessDominated': hfsolns = HydrofractureSolutions.PennySolutions() pennyFrac = hfsolns.Solutions(mu, Ep, Q0, KIC, t, radTimes, xSource) inletPressure = pennyFrac[5] @@ -102,7 +102,7 @@ def main(xmlFilePathPrefix=''): inletAperture = pennyFrac[7] lablelist = ['Asymptotic ( $\mu$ => 0, $C_{L}$ => 0 )', 'GEOSX ( $\mu$ => 0, $C_{L}$ => 0 )'] - elif xmlFilePathPrefix == 'pennyShapedViscosityDominated': + elif xmlFilePrefix == 'pennyShapedViscosityDominated': hfsolns = HydrofractureSolutions.PennySolutions() pennyFrac = hfsolns.Solutions(mu, Ep, Q0, KIC, t, radTimes, xSource) inletPressure = pennyFrac[8] @@ -110,7 +110,7 @@ def main(xmlFilePathPrefix=''): inletAperture = pennyFrac[10] lablelist = ['Asymptotic ( $K_{IC}$ => 0, $C_{L}$ => 0 )', 'GEOSX ( $K_{IC}$ => 0, $C_{L}$ => 0 )'] - elif xmlFilePathPrefix == 'pknViscosityDominated': + elif xmlFilePrefix == 'pknViscosityDominated': pknFrac = HydrofractureSolutions.PKN_viscosityStorageDominated(E, nu, KIC, mu, Q0, t, xSource) halfLength, inletAperture, inletPressure = pknFrac.analyticalSolution() lablelist = ['Asymptotic ( $K_{IC}$ => 0, $C_{L}$ => 0 )', 'GEOSX ( $K_{IC}$ => 0, $C_{L}$ => 0 )'] diff --git a/inputFiles/hydraulicFracturing/scripts/hydrofractureQueries.py b/inputFiles/hydraulicFracturing/scripts/hydrofractureQueries.py index 4bc35027610..24a466ebcbf 100644 --- a/inputFiles/hydraulicFracturing/scripts/hydrofractureQueries.py +++ b/inputFiles/hydraulicFracturing/scripts/hydrofractureQueries.py @@ -8,8 +8,8 @@ import xml.etree.ElementTree as ElementTree -def getFracHeightFromXML(fracType): - prefix = "../../../../../../../inputFiles/hydraulicFracturing/" +def getFracHeightFromXML(fracType, geosDir): + prefix = geosDir + "/inputFiles/hydraulicFracturing/" tree = ElementTree.parse(prefix + fracType + "_benchmark.xml") @@ -36,35 +36,47 @@ def getFracHeightFromXML(fracType): def main(): + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + + # Parse the command-line arguments + args = parser.parse_args() + # Load and process GEOSX results # File path + geosDir = args.geosDir + fracType = sys.argv[1] - prefix = "../../../../../../../inputFiles/hydraulicFracturing/" + prefix = geosDir + "/inputFiles/hydraulicFracturing/" hdf5File = prefix + fracType + '_output.hdf5' # Get frac height from XML file if fracType == 'kgdToughnessDominated' or fracType == 'kgdViscosityDominated' or fracType == 'pknViscosityDominated': - fracHeight = getFracHeightFromXML(fracType) + fracHeight = getFracHeightFromXML(fracType, geosDir) # Read simulation output from HDF5 file # Global Coordinate of Element Center hf = hdf5_wrapper.hdf5_wrapper(hdf5File) xl = hf['pressure elementCenter'] - xl = np.array(xl) + xl = np.asarray(xl) xcord = xl[-1, :, 0] ycord = xl[-1, :, 1] zcord = xl[-1, :, 2] tl = hf['pressure Time'] - tl = np.array(tl) + tl = np.asarray(tl) # Load pressure fpre = hf['pressure'] - fpre = np.array(fpre) + fpre = np.asarray(fpre) # Load elementAperture aper = hf['elementAperture'] - aper = np.array(aper) + aper = np.asarray(aper) # Load elementArea area = hf['elementArea'] - area = np.array(area) + area = np.asarray(area) # Find injection location ind = np.argmin(ycord) diff --git a/inputFiles/hydraulicFracturing/walshQuarterNoChombo_base.xml b/inputFiles/hydraulicFracturing/walshQuarterNoChombo_base.xml index cb889c700b3..31967ad1941 100644 --- a/inputFiles/hydraulicFracturing/walshQuarterNoChombo_base.xml +++ b/inputFiles/hydraulicFracturing/walshQuarterNoChombo_base.xml @@ -37,7 +37,7 @@ + materialList="{water, rock, fractureFilling, fractureContact, hApertureModel}"/> @@ -74,9 +74,11 @@ name="fracturePerm"/> + name="fractureContact"/> + + diff --git a/inputFiles/hydraulicFracturing/walshQuarterNoChombo_benchmark.xml b/inputFiles/hydraulicFracturing/walshQuarterNoChombo_benchmark.xml index 0a715d4089a..957b63bd278 100644 --- a/inputFiles/hydraulicFracturing/walshQuarterNoChombo_benchmark.xml +++ b/inputFiles/hydraulicFracturing/walshQuarterNoChombo_benchmark.xml @@ -28,7 +28,6 @@ surfaceGeneratorName="SurfaceGen" logLevel="1" targetRegions="{Fracture}" - contactRelationName="fractureContact" maxNumResolves="5" initialDt="0.1"> diff --git a/inputFiles/hydraulicFracturing/walshQuarterNoChombo_smoke.xml b/inputFiles/hydraulicFracturing/walshQuarterNoChombo_smoke.xml index 3d0d8a5c3e8..9990dd5c291 100644 --- a/inputFiles/hydraulicFracturing/walshQuarterNoChombo_smoke.xml +++ b/inputFiles/hydraulicFracturing/walshQuarterNoChombo_smoke.xml @@ -29,7 +29,6 @@ surfaceGeneratorName="SurfaceGen" logLevel="1" targetRegions="{Fracture}" - contactRelationName="fractureContact" maxNumResolves="5" initialDt="0.1"> diff --git a/inputFiles/inducedSeismicity/SeismicityRate_analytical_verification_smoke.xml b/inputFiles/inducedSeismicity/SeismicityRate_analytical_verification_smoke.xml new file mode 100644 index 00000000000..060fa699b91 --- /dev/null +++ b/inputFiles/inducedSeismicity/SeismicityRate_analytical_verification_smoke.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inputFiles/inducedSeismicity/SeismicityRate_poromechanics_base.xml b/inputFiles/inducedSeismicity/SeismicityRate_poromechanics_base.xml new file mode 100644 index 00000000000..7c353e1c4b5 --- /dev/null +++ b/inputFiles/inducedSeismicity/SeismicityRate_poromechanics_base.xml @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/inducedSeismicity/SeismicityRate_poromechanics_benchmark.xml b/inputFiles/inducedSeismicity/SeismicityRate_poromechanics_benchmark.xml new file mode 100644 index 00000000000..81c26f17495 --- /dev/null +++ b/inputFiles/inducedSeismicity/SeismicityRate_poromechanics_benchmark.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + diff --git a/inputFiles/inducedSeismicity/SeismicityRate_poromechanics_smoke.xml b/inputFiles/inducedSeismicity/SeismicityRate_poromechanics_smoke.xml new file mode 100644 index 00000000000..21e07439132 --- /dev/null +++ b/inputFiles/inducedSeismicity/SeismicityRate_poromechanics_smoke.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + diff --git a/inputFiles/inducedSeismicity/SpringSliderExplicit_base.xml b/inputFiles/inducedSeismicity/SpringSliderExplicit_base.xml new file mode 100644 index 00000000000..a0c0381fb23 --- /dev/null +++ b/inputFiles/inducedSeismicity/SpringSliderExplicit_base.xml @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inputFiles/inducedSeismicity/SpringSliderExplicit_smoke.xml b/inputFiles/inducedSeismicity/SpringSliderExplicit_smoke.xml new file mode 100644 index 00000000000..2de09b79a03 --- /dev/null +++ b/inputFiles/inducedSeismicity/SpringSliderExplicit_smoke.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inputFiles/inducedSeismicity/SpringSlider_base.xml b/inputFiles/inducedSeismicity/SpringSlider_base.xml new file mode 100644 index 00000000000..5f6aefc94ad --- /dev/null +++ b/inputFiles/inducedSeismicity/SpringSlider_base.xml @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inputFiles/inducedSeismicity/SpringSlider_smoke.xml b/inputFiles/inducedSeismicity/SpringSlider_smoke.xml new file mode 100644 index 00000000000..b10580131d8 --- /dev/null +++ b/inputFiles/inducedSeismicity/SpringSlider_smoke.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inputFiles/inducedSeismicity/inducedSeismicity.ats b/inputFiles/inducedSeismicity/inducedSeismicity.ats new file mode 100644 index 00000000000..813bdf08b8b --- /dev/null +++ b/inputFiles/inducedSeismicity/inducedSeismicity.ats @@ -0,0 +1,40 @@ +import os +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests, CurveCheckParameters + +curvecheck_params = {} +curvecheck_params["filename"] = "seismicityRate.hdf5" +curvecheck_params["tolerance"] = [1e-3] +curvecheck_params["script_instructions"] = [ ["./scripts/SeismicityRate_curveChecks.py", "curve_check_solution", "seismicityRate"] ] +curvecheck_params["curves"] = "seismicityRate" + +decks = [ + TestDeck( + name="SeismicityRate_poromechanics_smoke", + description="", + partitions=((1, 1, 1), (2, 2, 2)), + restart_step=20, + check_step=30, + restartcheck_params=RestartcheckParameters(atol=1e-4, rtol=1e-3)), + TestDeck( + name="SeismicityRate_analytical_verification_smoke", + description="Prescribed logarithmic stressing history", + partitions=((1, 1, 1), ), + restart_step=0, + check_step=100, + curvecheck_params=CurveCheckParameters(**curvecheck_params)), + TestDeck( + name="SpringSlider_smoke", + description="Spring slider 0D system", + partitions=((1, 1, 1), ), + restart_step=0, + check_step=3262, + restartcheck_params=RestartcheckParameters(atol=1e-4, rtol=1e-3)), + TestDeck( + name="SpringSliderExplicit_smoke", + description="Spring slider 0D system", + partitions=((1, 1, 1), ), + restart_step=0, + check_step=532, + restartcheck_params=RestartcheckParameters(atol=1e-4, rtol=1e-3)) + ] +generate_geos_tests(decks) diff --git a/inputFiles/inducedSeismicity/scripts/SeismicityRate_curveChecks.py b/inputFiles/inducedSeismicity/scripts/SeismicityRate_curveChecks.py new file mode 100644 index 00000000000..c1e40e9bba6 --- /dev/null +++ b/inputFiles/inducedSeismicity/scripts/SeismicityRate_curveChecks.py @@ -0,0 +1,120 @@ + +import argparse +import numpy as np +import xml.etree.ElementTree as ElementTree +import matplotlib.pyplot as plt + +class analyticalSolution(): + def __init__( self, parameters ): + self.cTau = 1e-3 + self.aSigma = 1e6 + self.t_a = 1e6/parameters['backgroundStressingRate'] + self.initial_normal_traction = parameters['initialFaultNormalTraction'] + self.initial_fault_shear_traction = parameters['initialFaultShearTraction'] + + def compute_shear_stress( self, time_n, dt ): + return self.aSigma * np.log( self.cTau*( time_n + dt ) + 1 ) + self.initial_fault_shear_traction + + def compute_seismic_rate(self, time_n, dt, shear_stress): + K = np.exp( shear_stress / self.aSigma - self.initial_fault_shear_traction / self.aSigma ) + denom = ( self.cTau*(time_n + dt - self.t_a ) + 1) * np.exp( (time_n+dt) / self.t_a ) + self.cTau*self.t_a + return K/denom + +def getParametersFromXML( xmlFilePath ): + tree = ElementTree.parse( xmlFilePath ) + root = tree.getroot() + + parameters = dict.fromkeys(["initialFaultNormalTraction", "initialFaultShearTraction", "backgroundStressingRate"]) + + solver = tree.find('Solvers/SeismicityRate') + parameters["backgroundStressingRate"] = float(solver.get("backgroundStressingRate")) + + for field_spec in root.findall(".//FieldSpecification"): + if field_spec.get('name') == 'initialShearTraction': + parameters["initialFaultShearTraction"] = float(field_spec.get("scale")) + elif field_spec.get('name') == 'initialNormalTraction': + parameters["initialFaultNormalTraction"] = float(field_spec.get("scale")) + + return parameters + +def curve_check_solution(**kwargs): + + xmlFilePath = "./SeismicityRate_analytical_verification_smoke.xml" + parameters = getParametersFromXML( xmlFilePath ) + + analytical_solution = analyticalSolution( parameters ) + + times = np.squeeze(kwargs['seismicityRate Time'][:]) + analytical_rates = [] + dt = 3600.0 + for time in times: + tau = analytical_solution.compute_shear_stress(time, dt) + analytical_rate = analytical_solution.compute_seismic_rate(time, dt, tau) + analytical_rates.append(analytical_rate) + + return np.array(analytical_rates) + + +def debug( xmlFilePath ): + #-------- Extract info from XML + parameters = getParametersFromXML( xmlFilePath ) + + analytical_solution = analyticalSolution( parameters ) + + time = 0.0 + dt = 3600.0 + final_time = 360000.0 + times = [] + analytical_rates = [] + tau_plot = [] + while time < final_time: + tau = analytical_solution.compute_shear_stress(time, dt) + analytical_rate = analytical_solution.compute_seismic_rate(time, dt, tau) + time += dt + times.append(time) + analytical_rates.append(analytical_rate) + tau_plot.append(tau) + + import csv + + # Write times to a CSV file without headers + with open('shearStress_time.csv', 'w', newline='') as file: + writer = csv.writer(file) + for time in times: + writer.writerow([time]) + + # Write tau_plot to a CSV file without headers + with open('shearStress_values.csv', 'w', newline='') as file: + writer = csv.writer(file) + for tau in tau_plot: + writer.writerow([tau]) + + import h5py + file_path = '/usr/workspace/cusini1/geosx/geosx_dev/GEOS_2/build-quartz-gcc-12-release/Output/seismicityRate.hdf5' + with h5py.File(file_path, 'r') as file: + # List all groups + print("Keys: %s" % file.keys()) + + # Get the data + time = np.squeeze(file['seismicityRate Time'][:]) + seismicityRate = np.squeeze(file['seismicityRate'][:]) + print(time) + print(seismicityRate) + + # Plot analytical (continuous line) and numerical (markers) aperture solution + fig, ax = plt.subplots(figsize=(16, 12), nrows=2, ncols=1) + + ax[0].plot(times, tau_plot) + ax[0].set_xlabel('time [s]', weight="bold") + ax[0].set_ylabel('shear stress', weight="bold") + + ax[1].plot(times, analytical_rates) + ax[1].set_xlabel('time [s]', weight="bold") + ax[1].set_ylabel('seismic rate', weight="bold") + plt.savefig("seismicRate.png") + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('-f', '--xml-file', type=str, help='Path to XML file') + args = parser.parse_args() + debug( args.xml_file ) diff --git a/inputFiles/inducedSeismicity/shearStress_time.csv b/inputFiles/inducedSeismicity/shearStress_time.csv new file mode 100644 index 00000000000..c2c5da0c9c3 --- /dev/null +++ b/inputFiles/inducedSeismicity/shearStress_time.csv @@ -0,0 +1,101 @@ +0.0 +3600.0 +7200.0 +10800.0 +14400.0 +18000.0 +21600.0 +25200.0 +28800.0 +32400.0 +36000.0 +39600.0 +43200.0 +46800.0 +50400.0 +54000.0 +57600.0 +61200.0 +64800.0 +68400.0 +72000.0 +75600.0 +79200.0 +82800.0 +86400.0 +90000.0 +93600.0 +97200.0 +100800.0 +104400.0 +108000.0 +111600.0 +115200.0 +118800.0 +122400.0 +126000.0 +129600.0 +133200.0 +136800.0 +140400.0 +144000.0 +147600.0 +151200.0 +154800.0 +158400.0 +162000.0 +165600.0 +169200.0 +172800.0 +176400.0 +180000.0 +183600.0 +187200.0 +190800.0 +194400.0 +198000.0 +201600.0 +205200.0 +208800.0 +212400.0 +216000.0 +219600.0 +223200.0 +226800.0 +230400.0 +234000.0 +237600.0 +241200.0 +244800.0 +248400.0 +252000.0 +255600.0 +259200.0 +262800.0 +266400.0 +270000.0 +273600.0 +277200.0 +280800.0 +284400.0 +288000.0 +291600.0 +295200.0 +298800.0 +302400.0 +306000.0 +309600.0 +313200.0 +316800.0 +320400.0 +324000.0 +327600.0 +331200.0 +334800.0 +338400.0 +342000.0 +345600.0 +349200.0 +352800.0 +356400.0 +360000.0 diff --git a/inputFiles/inducedSeismicity/shearStress_values.csv b/inputFiles/inducedSeismicity/shearStress_values.csv new file mode 100644 index 00000000000..2b9ae809bac --- /dev/null +++ b/inputFiles/inducedSeismicity/shearStress_values.csv @@ -0,0 +1,101 @@ +60.0e6 +61526056.30349505 +62104134.15427021 +62468099.53147162 +62734367.50941958 +62944438.97916644 +63117949.90627824 +63265759.41076705 +63394508.393511355 +63508555.89998265 +63610917.91264422 +63703768.066607684 +63788724.78908365 +63867025.639497414 +63939638.17246112 +64007333.18523247 +64070734.696582966 +64130354.99974513 +64186619.838331275 +64239886.86751276 +64290459.44114839 +64338597.076746546 +64384523.51487247 +64428433.007488035 +64470495.28266149 +64510859.50651685 +64549657.476057835 +64587006.21536042 +64623010.104116425 +64657762.636107266 +64691347.88222914 +64723841.71570559 +64755312.84441781 +64785823.68568135 +64815431.11147129 +64844187.08645859 +64872139.21684233 +64899331.22453758 +64925803.35857956 +64951592.75346247 +64976733.74242058 +65001258.13228366 +65025195.44542758 +65048573.13343665 +65071416.76635611 +65093750.20080676 +65115595.729732744 +65136974.21613927 +65157905.21283129 +65178407.06987548 +65198497.031265825 +65218191.32206875 +65237505.22715128 +65256453.16244934 +65275048.73960868 +65293304.824724495 +65311233.591814585 +65328846.57158286 +65346154.6959622 +65363168.33886765 +65379897.35354046 +65396351.106819406 +65412538.51063806 +65428468.05101308 +65444147.814759575 +65459585.51414416 +65474788.50966381 +65489763.83111899 +65504518.19713193 +65519058.033245936 +65533389.48872752 +65547518.45218153 +65561450.5660784 +65575191.24028321 +65588745.664667845 +65602118.8208797 +65615315.49333387 +65628340.27948934 +65641197.59946458 +65653891.705042735 +65666426.68811243 +65678806.48858602 +65691034.9018337 +65703115.5856685 +65715052.06691443 +65726847.7475872 +65738505.91071459 +65750029.725821525 +65761422.25410262 +65772686.45330341 +65783825.18232974 +65794841.20560317 +65805737.1971792 +65816515.74464344 +65827179.35280012 +65837730.447165936 +65848171.3772815 +65858504.41985175 +65868731.78172568 +65878855.60272533 +65888877.95833288 diff --git a/inputFiles/initialization/gravityInducedStress_initialization_base.xml b/inputFiles/initialization/gravityInducedStress_initialization_base.xml new file mode 100644 index 00000000000..7a9ce532b27 --- /dev/null +++ b/inputFiles/initialization/gravityInducedStress_initialization_base.xml @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/initialization/gravityInducedStress_initialization_benchmark.xml b/inputFiles/initialization/gravityInducedStress_initialization_benchmark.xml new file mode 100644 index 00000000000..921334e6944 --- /dev/null +++ b/inputFiles/initialization/gravityInducedStress_initialization_benchmark.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/initialization/gravityInducedStress_initialization_smoke.xml b/inputFiles/initialization/gravityInducedStress_initialization_smoke.xml new file mode 100644 index 00000000000..53dfbba70e7 --- /dev/null +++ b/inputFiles/initialization/gravityInducedStress_initialization_smoke.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/initialization/initialization.ats b/inputFiles/initialization/initialization.ats new file mode 100644 index 00000000000..3bb7cf04cab --- /dev/null +++ b/inputFiles/initialization/initialization.ats @@ -0,0 +1,27 @@ +import os +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests + +restartcheck_params = {} +restartcheck_params["atol"] = 2.0E-4 +restartcheck_params["rtol"] = 1.0E-7 + +decks = [ + TestDeck( + name="gravityInducedStress_initialization_smoke", + description= + "model intialization with gravity induced stress", + partitions=((1, 1, 1), (2, 2, 1)), + restart_step=1, + check_step=2, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="userdefinedStress_initialization_smoke", + description= + "model intialization with user defined tables", + partitions=((1, 1, 1), (2, 2, 1)), + restart_step=1, + check_step=2, + restartcheck_params=RestartcheckParameters(**restartcheck_params)) +] + +generate_geos_tests(decks) diff --git a/inputFiles/initialization/userTables/effectiveSigma_xx.csv b/inputFiles/initialization/userTables/effectiveSigma_xx.csv new file mode 100644 index 00000000000..a1dca328d57 --- /dev/null +++ b/inputFiles/initialization/userTables/effectiveSigma_xx.csv @@ -0,0 +1,2 @@ +-7000000.00 +0.00 diff --git a/inputFiles/initialization/userTables/effectiveSigma_yy.csv b/inputFiles/initialization/userTables/effectiveSigma_yy.csv new file mode 100644 index 00000000000..d1f4f182344 --- /dev/null +++ b/inputFiles/initialization/userTables/effectiveSigma_yy.csv @@ -0,0 +1,2 @@ +-17000000.00 +0.00 diff --git a/inputFiles/initialization/userTables/effectiveSigma_zz.csv b/inputFiles/initialization/userTables/effectiveSigma_zz.csv new file mode 100644 index 00000000000..53910c07f32 --- /dev/null +++ b/inputFiles/initialization/userTables/effectiveSigma_zz.csv @@ -0,0 +1,2 @@ +-14000000.00 +0.00 diff --git a/inputFiles/initialization/userTables/porePressure.csv b/inputFiles/initialization/userTables/porePressure.csv new file mode 100644 index 00000000000..5e92619dc6a --- /dev/null +++ b/inputFiles/initialization/userTables/porePressure.csv @@ -0,0 +1,2 @@ +10000000.00 +0.00 diff --git a/inputFiles/initialization/userTables/x.csv b/inputFiles/initialization/userTables/x.csv new file mode 100644 index 00000000000..fb1088c65aa --- /dev/null +++ b/inputFiles/initialization/userTables/x.csv @@ -0,0 +1 @@ +0.00 diff --git a/inputFiles/initialization/userTables/y.csv b/inputFiles/initialization/userTables/y.csv new file mode 100644 index 00000000000..fb1088c65aa --- /dev/null +++ b/inputFiles/initialization/userTables/y.csv @@ -0,0 +1 @@ +0.00 diff --git a/inputFiles/initialization/userTables/z.csv b/inputFiles/initialization/userTables/z.csv new file mode 100644 index 00000000000..eb40c4056f7 --- /dev/null +++ b/inputFiles/initialization/userTables/z.csv @@ -0,0 +1,2 @@ +-1000.00 +0.00 diff --git a/inputFiles/initialization/userdefinedStress_initialization_base.xml b/inputFiles/initialization/userdefinedStress_initialization_base.xml new file mode 100644 index 00000000000..7d216b2786a --- /dev/null +++ b/inputFiles/initialization/userdefinedStress_initialization_base.xml @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/initialization/userdefinedStress_initialization_benchmark.xml b/inputFiles/initialization/userdefinedStress_initialization_benchmark.xml new file mode 100644 index 00000000000..518b4a925a5 --- /dev/null +++ b/inputFiles/initialization/userdefinedStress_initialization_benchmark.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/initialization/userdefinedStress_initialization_smoke.xml b/inputFiles/initialization/userdefinedStress_initialization_smoke.xml new file mode 100644 index 00000000000..7dd0a6a9f76 --- /dev/null +++ b/inputFiles/initialization/userdefinedStress_initialization_smoke.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ALM_PassingCrack_smoke.xml b/inputFiles/lagrangianContactMechanics/ALM_PassingCrack_smoke.xml new file mode 100644 index 00000000000..2025d1e4e19 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ALM_PassingCrack_smoke.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ALM_SimpleCubes_smoke.xml b/inputFiles/lagrangianContactMechanics/ALM_SimpleCubes_smoke.xml new file mode 100644 index 00000000000..d0c48b78bdf --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ALM_SimpleCubes_smoke.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ALM_SingleFracCompression_benchmark.xml b/inputFiles/lagrangianContactMechanics/ALM_SingleFracCompression_benchmark.xml new file mode 100644 index 00000000000..2202aa2f739 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ALM_SingleFracCompression_benchmark.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ALM_SingleFracCompression_smoke.xml b/inputFiles/lagrangianContactMechanics/ALM_SingleFracCompression_smoke.xml new file mode 100644 index 00000000000..8b09acbea67 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ALM_SingleFracCompression_smoke.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ALM_Sneddon_benchmark.xml b/inputFiles/lagrangianContactMechanics/ALM_Sneddon_benchmark.xml new file mode 100644 index 00000000000..ba0462cbe05 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ALM_Sneddon_benchmark.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ALM_Sneddon_smoke.xml b/inputFiles/lagrangianContactMechanics/ALM_Sneddon_smoke.xml new file mode 100644 index 00000000000..41c125ef0e5 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ALM_Sneddon_smoke.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ALM_TFrac_benchmark.xml b/inputFiles/lagrangianContactMechanics/ALM_TFrac_benchmark.xml new file mode 100644 index 00000000000..8acc35c09b1 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ALM_TFrac_benchmark.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ALM_TFrac_smoke.xml b/inputFiles/lagrangianContactMechanics/ALM_TFrac_smoke.xml new file mode 100644 index 00000000000..c7a5bf66543 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ALM_TFrac_smoke.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ALM_UnstructuredCrack_benchmark.xml b/inputFiles/lagrangianContactMechanics/ALM_UnstructuredCrack_benchmark.xml new file mode 100644 index 00000000000..4a893d5dc0a --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ALM_UnstructuredCrack_benchmark.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ALM_UnstructuredCrack_smoke.xml b/inputFiles/lagrangianContactMechanics/ALM_UnstructuredCrack_smoke.xml new file mode 100644 index 00000000000..4b230c006ce --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ALM_UnstructuredCrack_smoke.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ALM_slippingFault_horizontal_smoke.xml b/inputFiles/lagrangianContactMechanics/ALM_slippingFault_horizontal_smoke.xml new file mode 100644 index 00000000000..4060a64af2e --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ALM_slippingFault_horizontal_smoke.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ALM_slippingFault_vertical_smoke.xml b/inputFiles/lagrangianContactMechanics/ALM_slippingFault_vertical_smoke.xml new file mode 100644 index 00000000000..7beefc7386d --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ALM_slippingFault_vertical_smoke.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_PEBICrack_base.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_PEBICrack_base.xml new file mode 100644 index 00000000000..09667b5e88f --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ContactMechanics_PEBICrack_base.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_PEBICrack_smoke.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_PEBICrack_smoke.xml new file mode 100644 index 00000000000..b1dc79f49b6 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ContactMechanics_PEBICrack_smoke.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_PassingCrack_base.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_PassingCrack_base.xml deleted file mode 100644 index 31654d1bb44..00000000000 --- a/inputFiles/lagrangianContactMechanics/ContactMechanics_PassingCrack_base.xml +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_PassingCrack_smoke.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_PassingCrack_smoke.xml index 4ba2c33f6d8..cccc821fc54 100644 --- a/inputFiles/lagrangianContactMechanics/ContactMechanics_PassingCrack_smoke.xml +++ b/inputFiles/lagrangianContactMechanics/ContactMechanics_PassingCrack_smoke.xml @@ -3,57 +3,35 @@ + name="./PassingCrack_smoke.xml"/> - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + @@ -61,26 +39,23 @@ name="preFracture" target="/Solvers/SurfaceGen"/> - - - + target="/Outputs/vtkOutput"/> + + diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_SimpleCubes_base.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_SimpleCubes_base.xml deleted file mode 100644 index a36624ce39c..00000000000 --- a/inputFiles/lagrangianContactMechanics/ContactMechanics_SimpleCubes_base.xml +++ /dev/null @@ -1,172 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_SimpleCubes_smoke.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_SimpleCubes_smoke.xml index 74ef1533500..733a439db2e 100644 --- a/inputFiles/lagrangianContactMechanics/ContactMechanics_SimpleCubes_smoke.xml +++ b/inputFiles/lagrangianContactMechanics/ContactMechanics_SimpleCubes_smoke.xml @@ -3,54 +3,37 @@ + name="./SimpleCubes_smoke.xml"/> + + + + + + - - - - - - - - - - - - - - - - - + + + + + @@ -74,9 +57,6 @@ targetExactTimestep="0" target="/Outputs/restartOutput"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_SingleFracCompression_benchmark.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_SingleFracCompression_benchmark.xml index 3dd01d27524..4bd3864871f 100644 --- a/inputFiles/lagrangianContactMechanics/ContactMechanics_SingleFracCompression_benchmark.xml +++ b/inputFiles/lagrangianContactMechanics/ContactMechanics_SingleFracCompression_benchmark.xml @@ -3,74 +3,41 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + @@ -81,7 +48,6 @@ @@ -90,6 +56,12 @@ timeFrequency="1" targetExactTimestep="0" target="/Outputs/vtkOutput"/> + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_Sneddon_benchmark.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_Sneddon_benchmark.xml new file mode 100644 index 00000000000..cefdf59664b --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ContactMechanics_Sneddon_benchmark.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_Sneddon_smoke.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_Sneddon_smoke.xml new file mode 100644 index 00000000000..92e406cbfb3 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/ContactMechanics_Sneddon_smoke.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_base.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_base.xml deleted file mode 100644 index e68f003b6e3..00000000000 --- a/inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_base.xml +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_benchmark.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_benchmark.xml index a4678fac840..89e2f4854df 100644 --- a/inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_benchmark.xml +++ b/inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_benchmark.xml @@ -2,60 +2,44 @@ - + - - + + targetRegions="{ Region, Fracture }"> + newtonTol="1.0e-8" + logLevel="2" + maxNumConfigurationAttempts="10" + newtonMaxIter="10" + lineSearchAction="Require" + lineSearchMaxCuts="2" + maxTimeStepCuts="2"/> - + solverType="direct" + directParallel="0" + logLevel="0"/> + + + - - - + + + + + - - - - - - + maxTime="0.2"> @@ -63,7 +47,7 @@ @@ -93,6 +77,12 @@ name="displacementHistoryOutput" timeFrequency="0.2" targetExactTimestep="0" - target="/Outputs/displacementOutput"/> + target="/Outputs/displacementOutput"/> + + diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_smoke.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_smoke.xml index ef470599b58..d3a1a91319c 100644 --- a/inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_smoke.xml +++ b/inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_smoke.xml @@ -2,7 +2,7 @@ - + - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_UnstructuredCrack_benchmark.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_UnstructuredCrack_benchmark.xml index 73497b3b596..82aee1a0f2a 100644 --- a/inputFiles/lagrangianContactMechanics/ContactMechanics_UnstructuredCrack_benchmark.xml +++ b/inputFiles/lagrangianContactMechanics/ContactMechanics_UnstructuredCrack_benchmark.xml @@ -1,76 +1,39 @@ - + name="./UnstructuredCrack_benchmark.xml"/> - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - + diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_UnstructuredCrack_smoke.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_UnstructuredCrack_smoke.xml index 71b7da13653..ea9c2adfe64 100644 --- a/inputFiles/lagrangianContactMechanics/ContactMechanics_UnstructuredCrack_smoke.xml +++ b/inputFiles/lagrangianContactMechanics/ContactMechanics_UnstructuredCrack_smoke.xml @@ -1,75 +1,38 @@ - + name="./UnstructuredCrack_smoke.xml"/> - - - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - @@ -90,14 +53,12 @@ targetExactTimestep="0" target="/Outputs/restartOutput"/> - + diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_slippingFault_base.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_slippingFault_base.xml deleted file mode 100644 index 2137d612521..00000000000 --- a/inputFiles/lagrangianContactMechanics/ContactMechanics_slippingFault_base.xml +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_slippingFault_horizontal_smoke.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_slippingFault_horizontal_smoke.xml index 6b59abebbbf..7584144aec3 100644 --- a/inputFiles/lagrangianContactMechanics/ContactMechanics_slippingFault_horizontal_smoke.xml +++ b/inputFiles/lagrangianContactMechanics/ContactMechanics_slippingFault_horizontal_smoke.xml @@ -3,132 +3,64 @@ - + - - - - - - - - - - - - - - - - - + + + + + + - + + + + + - + + - + - + - - - - - - - - - - - - - + + + diff --git a/inputFiles/lagrangianContactMechanics/ContactMechanics_slippingFault_vertical_smoke.xml b/inputFiles/lagrangianContactMechanics/ContactMechanics_slippingFault_vertical_smoke.xml index b520f3498c6..9a6ca75ddba 100644 --- a/inputFiles/lagrangianContactMechanics/ContactMechanics_slippingFault_vertical_smoke.xml +++ b/inputFiles/lagrangianContactMechanics/ContactMechanics_slippingFault_vertical_smoke.xml @@ -3,107 +3,64 @@ - + - - - + + + + + + - - + + + + + - - - + + - - + - + - + + - - - - - - - - - - - - - - diff --git a/inputFiles/lagrangianContactMechanics/LagrangeContactBubbleStab_FixedSlip_base.xml b/inputFiles/lagrangianContactMechanics/LagrangeContactBubbleStab_FixedSlip_base.xml new file mode 100644 index 00000000000..91a143df5b2 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/LagrangeContactBubbleStab_FixedSlip_base.xml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inputFiles/lagrangianContactMechanics/LagrangeContactBubbleStab_FixedSlip_smoke.xml b/inputFiles/lagrangianContactMechanics/LagrangeContactBubbleStab_FixedSlip_smoke.xml new file mode 100644 index 00000000000..8258d2cc4a3 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/LagrangeContactBubbleStab_FixedSlip_smoke.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inputFiles/lagrangianContactMechanics/LagrangeContactBubbleStab_singleFracCompression_base.xml b/inputFiles/lagrangianContactMechanics/LagrangeContactBubbleStab_singleFracCompression_base.xml new file mode 100644 index 00000000000..854136ed032 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/LagrangeContactBubbleStab_singleFracCompression_base.xml @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/LagrangeContactBubbleStab_singleFracCompression_smoke.xml b/inputFiles/lagrangianContactMechanics/LagrangeContactBubbleStab_singleFracCompression_smoke.xml new file mode 100644 index 00000000000..bb51f950d38 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/LagrangeContactBubbleStab_singleFracCompression_smoke.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/PassingCrack_base.xml b/inputFiles/lagrangianContactMechanics/PassingCrack_base.xml new file mode 100644 index 00000000000..1f38c231aa9 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/PassingCrack_base.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/PassingCrack_smoke.xml b/inputFiles/lagrangianContactMechanics/PassingCrack_smoke.xml new file mode 100644 index 00000000000..5af8f7534a5 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/PassingCrack_smoke.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/SimpleCubes_base.xml b/inputFiles/lagrangianContactMechanics/SimpleCubes_base.xml new file mode 100644 index 00000000000..32e64f498de --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/SimpleCubes_base.xml @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/SimpleCubes_smoke.xml b/inputFiles/lagrangianContactMechanics/SimpleCubes_smoke.xml new file mode 100644 index 00000000000..157f01ceda1 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/SimpleCubes_smoke.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/SingleFracCompression_base.xml b/inputFiles/lagrangianContactMechanics/SingleFracCompression_base.xml new file mode 100644 index 00000000000..d9da50caf95 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/SingleFracCompression_base.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/SingleFracCompression_benchmark.xml b/inputFiles/lagrangianContactMechanics/SingleFracCompression_benchmark.xml new file mode 100644 index 00000000000..346528e4bea --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/SingleFracCompression_benchmark.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/SingleFracCompression_smoke.xml b/inputFiles/lagrangianContactMechanics/SingleFracCompression_smoke.xml new file mode 100644 index 00000000000..a724d175616 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/SingleFracCompression_smoke.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/SlippingFault_base.xml b/inputFiles/lagrangianContactMechanics/SlippingFault_base.xml new file mode 100644 index 00000000000..5299794fe0f --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/SlippingFault_base.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/SlippingFault_horizontal_smoke.xml b/inputFiles/lagrangianContactMechanics/SlippingFault_horizontal_smoke.xml new file mode 100644 index 00000000000..2d81f9a0593 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/SlippingFault_horizontal_smoke.xml @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/SlippingFault_vertical_smoke.xml b/inputFiles/lagrangianContactMechanics/SlippingFault_vertical_smoke.xml new file mode 100644 index 00000000000..8c70450485d --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/SlippingFault_vertical_smoke.xml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/Sneddon_base.xml b/inputFiles/lagrangianContactMechanics/Sneddon_base.xml new file mode 100644 index 00000000000..73d61b18f6e --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/Sneddon_base.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/Sneddon_benchmark.xml b/inputFiles/lagrangianContactMechanics/Sneddon_benchmark.xml new file mode 100644 index 00000000000..7750053d6fa --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/Sneddon_benchmark.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_base.xml b/inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_base.xml deleted file mode 100755 index b7bced7dede..00000000000 --- a/inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_base.xml +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_benchmark.xml b/inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_benchmark.xml deleted file mode 100755 index 8071d746e91..00000000000 --- a/inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_benchmark.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_smoke.xml b/inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_smoke.xml deleted file mode 100755 index e7962f070c1..00000000000 --- a/inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_smoke.xml +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/inputFiles/lagrangianContactMechanics/Sneddon_smoke.xml b/inputFiles/lagrangianContactMechanics/Sneddon_smoke.xml new file mode 100644 index 00000000000..5e64b204ad1 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/Sneddon_smoke.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/TFrac_base.xml b/inputFiles/lagrangianContactMechanics/TFrac_base.xml new file mode 100644 index 00000000000..498b09616b2 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/TFrac_base.xml @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/TFrac_benchmark.xml b/inputFiles/lagrangianContactMechanics/TFrac_benchmark.xml new file mode 100644 index 00000000000..60f1a1f537a --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/TFrac_benchmark.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/TFrac_smoke.xml b/inputFiles/lagrangianContactMechanics/TFrac_smoke.xml new file mode 100644 index 00000000000..5ab56b69af9 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/TFrac_smoke.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/UnstructuredCrack_base.xml b/inputFiles/lagrangianContactMechanics/UnstructuredCrack_base.xml new file mode 100644 index 00000000000..628fd884589 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/UnstructuredCrack_base.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/UnstructuredCrack_benchmark.xml b/inputFiles/lagrangianContactMechanics/UnstructuredCrack_benchmark.xml new file mode 100644 index 00000000000..bb32766c947 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/UnstructuredCrack_benchmark.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/UnstructuredCrack_smoke.xml b/inputFiles/lagrangianContactMechanics/UnstructuredCrack_smoke.xml new file mode 100644 index 00000000000..faf2455cbf1 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/UnstructuredCrack_smoke.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/contactMechanics.ats b/inputFiles/lagrangianContactMechanics/contactMechanics.ats index 6b1e224987d..6f35259f76c 100644 --- a/inputFiles/lagrangianContactMechanics/contactMechanics.ats +++ b/inputFiles/lagrangianContactMechanics/contactMechanics.ats @@ -1,11 +1,19 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, CurveCheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params["atol"] = 2.0E-4 restartcheck_params["rtol"] = 1.0E-7 + +curvecheck_params = {} +curvecheck_params["filename"] = "traction.hdf5" +curvecheck_params["tolerance"] = [1e-1] +curvecheck_params["script_instructions"] = [[ + "./scripts/fixedFaultSlip.py", "curve_check_solution", + "traction" +]] +curvecheck_params["curves"] = "traction" + decks = [ TestDeck( name="ContactMechanics_SimpleCubes_smoke", @@ -23,7 +31,7 @@ decks = [ check_step=2, restartcheck_params=RestartcheckParameters(**restartcheck_params)), TestDeck( - name="Sneddon_contactMechanics_smoke", + name="ContactMechanics_Sneddon_smoke", description= "Testing Sneddon problem using contact mechanics (structured grid)", partitions=((1, 1, 1), ), @@ -45,7 +53,62 @@ decks = [ partitions=((1, 1, 1), ), restart_step=1, check_step=2, - restartcheck_params=RestartcheckParameters(**restartcheck_params)) + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="ContactMechanics_PEBICrack_smoke", + description= + "Two cubes with a fracture separating them (unstructured PEBI grid)", + partitions=((1, 1, 1), (2, 1, 1)), + restart_step=5, + check_step=10, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="ALM_SimpleCubes_smoke", + description= + "Two cubes with a fracture separating them (structured grid)", + partitions=((1, 1, 1), (2, 2, 2), (1, 3, 3)), + restart_step=10, + check_step=20, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="ALM_UnstructuredCrack_smoke", + description="A thick plane with a crack in it (unstructured grid)", + partitions=((1, 1, 1), ), + restart_step=1, + check_step=2, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="ALM_Sneddon_smoke", + description= + "Testing Sneddon problem using contact mechanics (structured grid)", + partitions=((1, 1, 1), ), + restart_step=1, + check_step=2, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="ALM_TFrac_smoke", + description= + "Two fractures intersecting at a right angle (structured grid)", + partitions=((1, 1, 1), (2, 2, 1)), + restart_step=1, + check_step=2, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="ALM_SingleFracCompression_smoke", + description= + "Single tilted fracture subjected to remote compression (unstructured grid)", + partitions=((1, 1, 1), ), + restart_step=1, + check_step=2, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="LagrangeContactBubbleStab_FixedSlip_smoke", + description="Lagrange multiplier with bubble stab and fixed jump on the fault. " + "Fault with imposed slip", + partitions=((1, 1, 1), (2, 2, 1)), + restart_step=1, + check_step=2, + restartcheck_params=RestartcheckParameters(**restartcheck_params)) ] generate_geos_tests(decks) diff --git a/inputFiles/lagrangianContactMechanics/contact_vem.vtm b/inputFiles/lagrangianContactMechanics/contact_vem.vtm new file mode 100644 index 00000000000..810d9b1390a --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/contact_vem.vtm @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/inputFiles/lagrangianContactMechanics/dataTables/gaussianSlip.csv b/inputFiles/lagrangianContactMechanics/dataTables/gaussianSlip.csv new file mode 100644 index 00000000000..9d62405dcb4 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/dataTables/gaussianSlip.csv @@ -0,0 +1,10000 @@ +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000005 +0.000005 +0.000005 +0.000005 +0.000005 +0.000005 +0.000005 +0.000005 +0.000005 +0.000005 +0.000006 +0.000006 +0.000006 +0.000006 +0.000006 +0.000006 +0.000006 +0.000006 +0.000006 +0.000007 +0.000007 +0.000007 +0.000007 +0.000007 +0.000007 +0.000007 +0.000008 +0.000008 +0.000008 +0.000008 +0.000008 +0.000008 +0.000008 +0.000009 +0.000009 +0.000009 +0.000009 +0.000009 +0.000010 +0.000010 +0.000010 +0.000010 +0.000010 +0.000010 +0.000011 +0.000011 +0.000011 +0.000011 +0.000011 +0.000012 +0.000012 +0.000012 +0.000012 +0.000013 +0.000013 +0.000013 +0.000013 +0.000014 +0.000014 +0.000014 +0.000014 +0.000015 +0.000015 +0.000015 +0.000016 +0.000016 +0.000016 +0.000016 +0.000017 +0.000017 +0.000017 +0.000018 +0.000018 +0.000018 +0.000019 +0.000019 +0.000019 +0.000020 +0.000020 +0.000021 +0.000021 +0.000021 +0.000022 +0.000022 +0.000023 +0.000023 +0.000023 +0.000024 +0.000024 +0.000025 +0.000025 +0.000026 +0.000026 +0.000027 +0.000027 +0.000028 +0.000028 +0.000029 +0.000029 +0.000030 +0.000030 +0.000031 +0.000031 +0.000032 +0.000033 +0.000033 +0.000034 +0.000034 +0.000035 +0.000036 +0.000036 +0.000037 +0.000038 +0.000038 +0.000039 +0.000040 +0.000040 +0.000041 +0.000042 +0.000043 +0.000043 +0.000044 +0.000045 +0.000046 +0.000047 +0.000048 +0.000048 +0.000049 +0.000050 +0.000051 +0.000052 +0.000053 +0.000054 +0.000055 +0.000056 +0.000057 +0.000058 +0.000059 +0.000060 +0.000061 +0.000062 +0.000063 +0.000064 +0.000065 +0.000067 +0.000068 +0.000069 +0.000070 +0.000071 +0.000073 +0.000074 +0.000075 +0.000077 +0.000078 +0.000079 +0.000081 +0.000082 +0.000084 +0.000085 +0.000087 +0.000088 +0.000090 +0.000091 +0.000093 +0.000094 +0.000096 +0.000098 +0.000099 +0.000101 +0.000103 +0.000105 +0.000107 +0.000108 +0.000110 +0.000112 +0.000114 +0.000116 +0.000118 +0.000120 +0.000122 +0.000124 +0.000126 +0.000129 +0.000131 +0.000133 +0.000135 +0.000138 +0.000140 +0.000142 +0.000145 +0.000147 +0.000150 +0.000152 +0.000155 +0.000158 +0.000160 +0.000163 +0.000166 +0.000169 +0.000172 +0.000174 +0.000177 +0.000180 +0.000183 +0.000187 +0.000190 +0.000193 +0.000196 +0.000199 +0.000203 +0.000206 +0.000210 +0.000213 +0.000217 +0.000220 +0.000224 +0.000228 +0.000232 +0.000235 +0.000239 +0.000243 +0.000247 +0.000252 +0.000256 +0.000260 +0.000264 +0.000269 +0.000273 +0.000278 +0.000282 +0.000287 +0.000292 +0.000296 +0.000301 +0.000306 +0.000311 +0.000316 +0.000321 +0.000327 +0.000332 +0.000338 +0.000343 +0.000349 +0.000354 +0.000360 +0.000366 +0.000372 +0.000378 +0.000384 +0.000390 +0.000397 +0.000403 +0.000410 +0.000416 +0.000423 +0.000430 +0.000437 +0.000444 +0.000451 +0.000458 +0.000465 +0.000473 +0.000481 +0.000488 +0.000496 +0.000504 +0.000512 +0.000520 +0.000529 +0.000537 +0.000545 +0.000554 +0.000563 +0.000572 +0.000581 +0.000590 +0.000599 +0.000609 +0.000619 +0.000628 +0.000638 +0.000648 +0.000659 +0.000669 +0.000679 +0.000690 +0.000701 +0.000712 +0.000723 +0.000734 +0.000746 +0.000757 +0.000769 +0.000781 +0.000793 +0.000806 +0.000818 +0.000831 +0.000844 +0.000857 +0.000870 +0.000884 +0.000897 +0.000911 +0.000925 +0.000939 +0.000954 +0.000968 +0.000983 +0.000998 +0.001014 +0.001029 +0.001045 +0.001061 +0.001077 +0.001094 +0.001110 +0.001127 +0.001144 +0.001162 +0.001179 +0.001197 +0.001215 +0.001234 +0.001252 +0.001271 +0.001290 +0.001310 +0.001330 +0.001350 +0.001370 +0.001390 +0.001411 +0.001432 +0.001454 +0.001476 +0.001498 +0.001520 +0.001543 +0.001566 +0.001589 +0.001613 +0.001637 +0.001661 +0.001686 +0.001711 +0.001736 +0.001761 +0.001788 +0.001814 +0.001841 +0.001868 +0.001895 +0.001923 +0.001951 +0.001980 +0.002009 +0.002038 +0.002068 +0.002098 +0.002129 +0.002160 +0.002191 +0.002223 +0.002256 +0.002288 +0.002322 +0.002355 +0.002389 +0.002424 +0.002459 +0.002494 +0.002530 +0.002567 +0.002604 +0.002641 +0.002679 +0.002717 +0.002756 +0.002796 +0.002836 +0.002876 +0.002917 +0.002959 +0.003001 +0.003044 +0.003087 +0.003131 +0.003175 +0.003220 +0.003266 +0.003312 +0.003359 +0.003406 +0.003454 +0.003503 +0.003552 +0.003602 +0.003652 +0.003704 +0.003756 +0.003808 +0.003861 +0.003915 +0.003970 +0.004025 +0.004081 +0.004138 +0.004195 +0.004254 +0.004313 +0.004372 +0.004433 +0.004494 +0.004556 +0.004619 +0.004682 +0.004747 +0.004812 +0.004878 +0.004945 +0.005013 +0.005081 +0.005151 +0.005221 +0.005292 +0.005364 +0.005437 +0.005511 +0.005586 +0.005662 +0.005739 +0.005816 +0.005895 +0.005975 +0.006055 +0.006137 +0.006220 +0.006303 +0.006388 +0.006474 +0.006560 +0.006648 +0.006737 +0.006827 +0.006918 +0.007011 +0.007104 +0.007198 +0.007294 +0.007391 +0.007489 +0.007588 +0.007688 +0.007790 +0.007893 +0.007997 +0.008102 +0.008209 +0.008317 +0.008426 +0.008536 +0.008648 +0.008761 +0.008876 +0.008992 +0.009109 +0.009227 +0.009348 +0.009469 +0.009592 +0.009716 +0.009842 +0.009969 +0.010098 +0.010229 +0.010360 +0.010494 +0.010629 +0.010765 +0.010904 +0.011043 +0.011185 +0.011328 +0.011473 +0.011619 +0.011767 +0.011917 +0.012068 +0.012222 +0.012377 +0.012534 +0.012692 +0.012853 +0.013015 +0.013179 +0.013345 +0.013513 +0.013683 +0.013855 +0.014029 +0.014204 +0.014382 +0.014562 +0.014744 +0.014927 +0.015113 +0.015301 +0.015491 +0.015684 +0.015878 +0.016074 +0.016273 +0.016474 +0.016677 +0.016883 +0.017091 +0.017301 +0.017513 +0.017728 +0.017945 +0.018165 +0.018387 +0.018611 +0.018838 +0.019067 +0.019299 +0.019533 +0.019770 +0.020010 +0.020252 +0.020497 +0.020744 +0.020995 +0.021247 +0.021503 +0.021761 +0.022022 +0.022286 +0.022553 +0.022823 +0.023095 +0.023371 +0.023649 +0.023930 +0.024215 +0.024502 +0.024793 +0.025086 +0.025383 +0.025682 +0.025985 +0.026291 +0.026601 +0.026913 +0.027229 +0.027548 +0.027871 +0.028197 +0.028526 +0.028859 +0.029195 +0.029534 +0.029878 +0.030224 +0.030575 +0.030929 +0.031286 +0.031647 +0.032012 +0.032381 +0.032753 +0.033130 +0.033510 +0.033894 +0.034282 +0.034673 +0.035069 +0.035469 +0.035873 +0.036281 +0.036693 +0.037109 +0.037529 +0.037954 +0.038382 +0.038815 +0.039253 +0.039694 +0.040141 +0.040591 +0.041046 +0.041506 +0.041970 +0.042438 +0.042912 +0.043389 +0.043872 +0.044359 +0.044851 +0.045348 +0.045850 +0.046357 +0.046868 +0.047384 +0.047906 +0.048432 +0.048964 +0.049501 +0.050043 +0.050590 +0.051142 +0.051700 +0.052262 +0.052831 +0.053404 +0.053983 +0.054568 +0.055158 +0.055754 +0.056355 +0.056962 +0.057575 +0.058193 +0.058818 +0.059448 +0.060084 +0.060726 +0.061374 +0.062027 +0.062687 +0.063353 +0.064026 +0.064704 +0.065389 +0.066080 +0.066777 +0.067480 +0.068191 +0.068907 +0.069630 +0.070360 +0.071096 +0.071839 +0.072589 +0.073345 +0.074108 +0.074878 +0.075655 +0.076439 +0.077230 +0.078028 +0.078833 +0.079646 +0.080465 +0.081292 +0.082126 +0.082967 +0.083816 +0.084672 +0.085536 +0.086407 +0.087286 +0.088173 +0.089067 +0.089969 +0.090879 +0.091797 +0.092723 +0.093656 +0.094598 +0.095548 +0.096506 +0.097472 +0.098446 +0.099429 +0.100420 +0.101420 +0.102428 +0.103444 +0.104469 +0.105503 +0.106545 +0.107596 +0.108656 +0.109725 +0.110803 +0.111889 +0.112985 +0.114090 +0.115204 +0.116327 +0.117459 +0.118601 +0.119752 +0.120912 +0.122082 +0.123261 +0.124450 +0.125649 +0.126858 +0.128076 +0.129304 +0.130542 +0.131789 +0.133047 +0.134315 +0.135593 +0.136881 +0.138180 +0.139488 +0.140808 +0.142137 +0.143477 +0.144828 +0.146189 +0.147561 +0.148943 +0.150336 +0.151740 +0.153155 +0.154581 +0.156018 +0.157467 +0.158926 +0.160396 +0.161878 +0.163371 +0.164875 +0.166391 +0.167919 +0.169458 +0.171008 +0.172570 +0.174144 +0.175730 +0.177328 +0.178938 +0.180559 +0.182193 +0.183839 +0.185497 +0.187167 +0.188850 +0.190545 +0.192252 +0.193972 +0.195704 +0.197449 +0.199207 +0.200978 +0.202761 +0.204557 +0.206366 +0.208188 +0.210023 +0.211872 +0.213733 +0.215608 +0.217495 +0.219397 +0.221311 +0.223240 +0.225181 +0.227137 +0.229106 +0.231089 +0.233085 +0.235095 +0.237120 +0.239158 +0.241210 +0.243277 +0.245357 +0.247452 +0.249561 +0.251684 +0.253822 +0.255974 +0.258141 +0.260322 +0.262518 +0.264729 +0.266954 +0.269195 +0.271450 +0.273720 +0.276005 +0.278305 +0.280620 +0.282951 +0.285296 +0.287657 +0.290033 +0.292425 +0.294832 +0.297254 +0.299693 +0.302146 +0.304616 +0.307101 +0.309602 +0.312119 +0.314652 +0.317201 +0.319765 +0.322346 +0.324943 +0.327556 +0.330186 +0.332832 +0.335494 +0.338172 +0.340867 +0.343578 +0.346306 +0.349051 +0.351812 +0.354590 +0.357385 +0.360197 +0.363025 +0.365870 +0.368733 +0.371612 +0.374508 +0.377422 +0.380353 +0.383301 +0.386266 +0.389248 +0.392248 +0.395265 +0.398300 +0.401352 +0.404422 +0.407509 +0.410614 +0.413737 +0.416877 +0.420036 +0.423212 +0.426405 +0.429617 +0.432847 +0.436094 +0.439360 +0.442643 +0.445945 +0.449265 +0.452603 +0.455959 +0.459334 +0.462727 +0.466138 +0.469567 +0.473015 +0.476481 +0.479966 +0.483469 +0.486991 +0.490531 +0.494090 +0.497668 +0.501264 +0.504879 +0.508513 +0.512165 +0.515836 +0.519526 +0.523235 +0.526962 +0.530709 +0.534474 +0.538259 +0.542062 +0.545884 +0.549726 +0.553586 +0.557465 +0.561364 +0.565281 +0.569218 +0.573174 +0.577148 +0.581143 +0.585156 +0.589188 +0.593240 +0.597311 +0.601401 +0.605510 +0.609639 +0.613787 +0.617954 +0.622140 +0.626346 +0.630571 +0.634816 +0.639080 +0.643363 +0.647665 +0.651987 +0.656328 +0.660689 +0.665069 +0.669468 +0.673886 +0.678324 +0.682781 +0.687258 +0.691754 +0.696269 +0.700804 +0.705358 +0.709931 +0.714524 +0.719136 +0.723767 +0.728418 +0.733088 +0.737777 +0.742485 +0.747213 +0.751960 +0.756726 +0.761511 +0.766315 +0.771139 +0.775982 +0.780844 +0.785725 +0.790625 +0.795544 +0.800482 +0.805439 +0.810415 +0.815410 +0.820424 +0.825457 +0.830509 +0.835580 +0.840669 +0.845777 +0.850904 +0.856050 +0.861214 +0.866397 +0.871598 +0.876818 +0.882057 +0.887314 +0.892589 +0.897883 +0.903195 +0.908526 +0.913875 +0.919242 +0.924627 +0.930030 +0.935451 +0.940890 +0.946347 +0.951822 +0.957315 +0.962826 +0.968354 +0.973900 +0.979464 +0.985045 +0.990644 +0.996260 +1.001893 +1.007544 +1.013212 +1.018897 +1.024599 +1.030319 +1.036055 +1.041808 +1.047578 +1.053364 +1.059167 +1.064987 +1.070823 +1.076676 +1.082545 +1.088430 +1.094332 +1.100249 +1.106183 +1.112132 +1.118098 +1.124079 +1.130075 +1.136087 +1.142115 +1.148158 +1.154217 +1.160290 +1.166379 +1.172483 +1.178601 +1.184735 +1.190883 +1.197045 +1.203223 +1.209414 +1.215620 +1.221840 +1.228074 +1.234322 +1.240584 +1.246860 +1.253149 +1.259452 +1.265768 +1.272097 +1.278440 +1.284796 +1.291164 +1.297546 +1.303940 +1.310347 +1.316766 +1.323197 +1.329641 +1.336097 +1.342564 +1.349044 +1.355535 +1.362037 +1.368551 +1.375077 +1.381613 +1.388161 +1.394719 +1.401288 +1.407868 +1.414458 +1.421058 +1.427669 +1.434289 +1.440919 +1.447560 +1.454209 +1.460868 +1.467537 +1.474214 +1.480901 +1.487596 +1.494300 +1.501013 +1.507734 +1.514463 +1.521200 +1.527945 +1.534697 +1.541458 +1.548225 +1.555000 +1.561782 +1.568571 +1.575366 +1.582169 +1.588977 +1.595792 +1.602613 +1.609439 +1.616272 +1.623110 +1.629953 +1.636801 +1.643655 +1.650513 +1.657376 +1.664244 +1.671115 +1.677991 +1.684871 +1.691755 +1.698642 +1.705532 +1.712426 +1.719323 +1.726222 +1.733124 +1.740029 +1.746936 +1.753845 +1.760755 +1.767668 +1.774582 +1.781497 +1.788413 +1.795330 +1.802248 +1.809167 +1.816085 +1.823004 +1.829923 +1.836841 +1.843759 +1.850676 +1.857592 +1.864508 +1.871421 +1.878334 +1.885244 +1.892153 +1.899059 +1.905964 +1.912865 +1.919764 +1.926660 +1.933553 +1.940442 +1.947328 +1.954210 +1.961087 +1.967961 +1.974830 +1.981695 +1.988554 +1.995409 +2.002258 +2.009101 +2.015939 +2.022771 +2.029597 +2.036416 +2.043229 +2.050034 +2.056833 +2.063624 +2.070408 +2.077185 +2.083953 +2.090713 +2.097465 +2.104208 +2.110942 +2.117667 +2.124383 +2.131089 +2.137786 +2.144472 +2.151149 +2.157815 +2.164470 +2.171115 +2.177748 +2.184370 +2.190981 +2.197580 +2.204166 +2.210741 +2.217303 +2.223853 +2.230389 +2.236913 +2.243423 +2.249919 +2.256402 +2.262871 +2.269325 +2.275765 +2.282190 +2.288600 +2.294996 +2.301375 +2.307739 +2.314087 +2.320419 +2.326735 +2.333034 +2.339317 +2.345582 +2.351831 +2.358061 +2.364274 +2.370470 +2.376647 +2.382805 +2.388946 +2.395067 +2.401169 +2.407252 +2.413316 +2.419360 +2.425384 +2.431387 +2.437371 +2.443334 +2.449276 +2.455197 +2.461096 +2.466974 +2.472831 +2.478665 +2.484478 +2.490268 +2.496035 +2.501780 +2.507501 +2.513200 +2.518874 +2.524525 +2.530153 +2.535756 +2.541335 +2.546889 +2.552418 +2.557923 +2.563402 +2.568856 +2.574284 +2.579687 +2.585063 +2.590413 +2.595737 +2.601034 +2.606304 +2.611547 +2.616763 +2.621951 +2.627112 +2.632245 +2.637349 +2.642426 +2.647473 +2.652493 +2.657483 +2.662444 +2.667376 +2.672278 +2.677150 +2.681993 +2.686806 +2.691588 +2.696340 +2.701061 +2.705751 +2.710411 +2.715039 +2.719635 +2.724200 +2.728734 +2.733235 +2.737704 +2.742141 +2.746545 +2.750917 +2.755255 +2.759561 +2.763833 +2.768072 +2.772278 +2.776449 +2.780587 +2.784691 +2.788760 +2.792795 +2.796795 +2.800761 +2.804692 +2.808587 +2.812447 +2.816272 +2.820062 +2.823815 +2.827533 +2.831215 +2.834860 +2.838469 +2.842042 +2.845578 +2.849077 +2.852539 +2.855964 +2.859352 +2.862703 +2.866016 +2.869291 +2.872529 +2.875729 +2.878890 +2.882014 +2.885099 +2.888146 +2.891154 +2.894123 +2.897053 +2.899945 +2.902798 +2.905611 +2.908385 +2.911119 +2.913814 +2.916470 +2.919085 +2.921661 +2.924196 +2.926692 +2.929147 +2.931562 +2.933936 +2.936270 +2.938564 +2.940816 +2.943028 +2.945199 +2.947329 +2.949418 +2.951465 +2.953472 +2.955436 +2.957360 +2.959242 +2.961082 +2.962881 +2.964638 +2.966353 +2.968026 +2.969657 +2.971246 +2.972793 +2.974298 +2.975760 +2.977180 +2.978558 +2.979893 +2.981186 +2.982436 +2.983644 +2.984809 +2.985931 +2.987010 +2.988047 +2.989041 +2.989992 +2.990900 +2.991765 +2.992587 +2.993366 +2.994101 +2.994794 +2.995444 +2.996050 +2.996613 +2.997133 +2.997610 +2.998043 +2.998434 +2.998780 +2.999084 +2.999344 +2.999561 +2.999734 +2.999864 +2.999951 +2.999995 +2.999995 +2.999951 +2.999864 +2.999734 +2.999561 +2.999344 +2.999084 +2.998780 +2.998434 +2.998043 +2.997610 +2.997133 +2.996613 +2.996050 +2.995444 +2.994794 +2.994101 +2.993366 +2.992587 +2.991765 +2.990900 +2.989992 +2.989041 +2.988047 +2.987010 +2.985931 +2.984809 +2.983644 +2.982436 +2.981186 +2.979893 +2.978558 +2.977180 +2.975760 +2.974298 +2.972793 +2.971246 +2.969657 +2.968026 +2.966353 +2.964638 +2.962881 +2.961082 +2.959242 +2.957360 +2.955436 +2.953472 +2.951465 +2.949418 +2.947329 +2.945199 +2.943028 +2.940816 +2.938564 +2.936270 +2.933936 +2.931562 +2.929147 +2.926692 +2.924196 +2.921661 +2.919085 +2.916470 +2.913814 +2.911119 +2.908385 +2.905611 +2.902798 +2.899945 +2.897053 +2.894123 +2.891154 +2.888146 +2.885099 +2.882014 +2.878890 +2.875729 +2.872529 +2.869291 +2.866016 +2.862703 +2.859352 +2.855964 +2.852539 +2.849077 +2.845578 +2.842042 +2.838469 +2.834860 +2.831215 +2.827533 +2.823815 +2.820062 +2.816272 +2.812447 +2.808587 +2.804692 +2.800761 +2.796795 +2.792795 +2.788760 +2.784691 +2.780587 +2.776449 +2.772278 +2.768072 +2.763833 +2.759561 +2.755255 +2.750917 +2.746545 +2.742141 +2.737704 +2.733235 +2.728734 +2.724200 +2.719635 +2.715039 +2.710411 +2.705751 +2.701061 +2.696340 +2.691588 +2.686806 +2.681993 +2.677150 +2.672278 +2.667376 +2.662444 +2.657483 +2.652493 +2.647473 +2.642426 +2.637349 +2.632245 +2.627112 +2.621951 +2.616763 +2.611547 +2.606304 +2.601034 +2.595737 +2.590413 +2.585063 +2.579687 +2.574284 +2.568856 +2.563402 +2.557923 +2.552418 +2.546889 +2.541335 +2.535756 +2.530153 +2.524525 +2.518874 +2.513200 +2.507501 +2.501780 +2.496035 +2.490268 +2.484478 +2.478665 +2.472831 +2.466974 +2.461096 +2.455197 +2.449276 +2.443334 +2.437371 +2.431387 +2.425384 +2.419360 +2.413316 +2.407252 +2.401169 +2.395067 +2.388946 +2.382805 +2.376647 +2.370470 +2.364274 +2.358061 +2.351831 +2.345582 +2.339317 +2.333034 +2.326735 +2.320419 +2.314087 +2.307739 +2.301375 +2.294996 +2.288600 +2.282190 +2.275765 +2.269325 +2.262871 +2.256402 +2.249919 +2.243423 +2.236913 +2.230389 +2.223853 +2.217303 +2.210741 +2.204166 +2.197580 +2.190981 +2.184370 +2.177748 +2.171115 +2.164470 +2.157815 +2.151149 +2.144472 +2.137786 +2.131089 +2.124383 +2.117667 +2.110942 +2.104208 +2.097465 +2.090713 +2.083953 +2.077185 +2.070408 +2.063624 +2.056833 +2.050034 +2.043229 +2.036416 +2.029597 +2.022771 +2.015939 +2.009101 +2.002258 +1.995409 +1.988554 +1.981695 +1.974830 +1.967961 +1.961087 +1.954210 +1.947328 +1.940442 +1.933553 +1.926660 +1.919764 +1.912865 +1.905964 +1.899059 +1.892153 +1.885244 +1.878334 +1.871421 +1.864508 +1.857592 +1.850676 +1.843759 +1.836841 +1.829923 +1.823004 +1.816085 +1.809167 +1.802248 +1.795330 +1.788413 +1.781497 +1.774582 +1.767668 +1.760755 +1.753845 +1.746936 +1.740029 +1.733124 +1.726222 +1.719323 +1.712426 +1.705532 +1.698642 +1.691755 +1.684871 +1.677991 +1.671115 +1.664244 +1.657376 +1.650513 +1.643655 +1.636801 +1.629953 +1.623110 +1.616272 +1.609439 +1.602613 +1.595792 +1.588977 +1.582169 +1.575366 +1.568571 +1.561782 +1.555000 +1.548225 +1.541458 +1.534697 +1.527945 +1.521200 +1.514463 +1.507734 +1.501013 +1.494300 +1.487596 +1.480901 +1.474214 +1.467537 +1.460868 +1.454209 +1.447560 +1.440919 +1.434289 +1.427669 +1.421058 +1.414458 +1.407868 +1.401288 +1.394719 +1.388161 +1.381613 +1.375077 +1.368551 +1.362037 +1.355535 +1.349044 +1.342564 +1.336097 +1.329641 +1.323197 +1.316766 +1.310347 +1.303940 +1.297546 +1.291164 +1.284796 +1.278440 +1.272097 +1.265768 +1.259452 +1.253149 +1.246860 +1.240584 +1.234322 +1.228074 +1.221840 +1.215620 +1.209414 +1.203223 +1.197045 +1.190883 +1.184735 +1.178601 +1.172483 +1.166379 +1.160290 +1.154217 +1.148158 +1.142115 +1.136087 +1.130075 +1.124079 +1.118098 +1.112132 +1.106183 +1.100249 +1.094332 +1.088430 +1.082545 +1.076676 +1.070823 +1.064987 +1.059167 +1.053364 +1.047578 +1.041808 +1.036055 +1.030319 +1.024599 +1.018897 +1.013212 +1.007544 +1.001893 +0.996260 +0.990644 +0.985045 +0.979464 +0.973900 +0.968354 +0.962826 +0.957315 +0.951822 +0.946347 +0.940890 +0.935451 +0.930030 +0.924627 +0.919242 +0.913875 +0.908526 +0.903195 +0.897883 +0.892589 +0.887314 +0.882057 +0.876818 +0.871598 +0.866397 +0.861214 +0.856050 +0.850904 +0.845777 +0.840669 +0.835580 +0.830509 +0.825457 +0.820424 +0.815410 +0.810415 +0.805439 +0.800482 +0.795544 +0.790625 +0.785725 +0.780844 +0.775982 +0.771139 +0.766315 +0.761511 +0.756726 +0.751960 +0.747213 +0.742485 +0.737777 +0.733088 +0.728418 +0.723767 +0.719136 +0.714524 +0.709931 +0.705358 +0.700804 +0.696269 +0.691754 +0.687258 +0.682781 +0.678324 +0.673886 +0.669468 +0.665069 +0.660689 +0.656328 +0.651987 +0.647665 +0.643363 +0.639080 +0.634816 +0.630571 +0.626346 +0.622140 +0.617954 +0.613787 +0.609639 +0.605510 +0.601401 +0.597311 +0.593240 +0.589188 +0.585156 +0.581143 +0.577148 +0.573174 +0.569218 +0.565281 +0.561364 +0.557465 +0.553586 +0.549726 +0.545884 +0.542062 +0.538259 +0.534474 +0.530709 +0.526962 +0.523235 +0.519526 +0.515836 +0.512165 +0.508513 +0.504879 +0.501264 +0.497668 +0.494090 +0.490531 +0.486991 +0.483469 +0.479966 +0.476481 +0.473015 +0.469567 +0.466138 +0.462727 +0.459334 +0.455959 +0.452603 +0.449265 +0.445945 +0.442643 +0.439360 +0.436094 +0.432847 +0.429617 +0.426405 +0.423212 +0.420036 +0.416877 +0.413737 +0.410614 +0.407509 +0.404422 +0.401352 +0.398300 +0.395265 +0.392248 +0.389248 +0.386266 +0.383301 +0.380353 +0.377422 +0.374508 +0.371612 +0.368733 +0.365870 +0.363025 +0.360197 +0.357385 +0.354590 +0.351812 +0.349051 +0.346306 +0.343578 +0.340867 +0.338172 +0.335494 +0.332832 +0.330186 +0.327556 +0.324943 +0.322346 +0.319765 +0.317201 +0.314652 +0.312119 +0.309602 +0.307101 +0.304616 +0.302146 +0.299693 +0.297254 +0.294832 +0.292425 +0.290033 +0.287657 +0.285296 +0.282951 +0.280620 +0.278305 +0.276005 +0.273720 +0.271450 +0.269195 +0.266954 +0.264729 +0.262518 +0.260322 +0.258141 +0.255974 +0.253822 +0.251684 +0.249561 +0.247452 +0.245357 +0.243277 +0.241210 +0.239158 +0.237120 +0.235095 +0.233085 +0.231089 +0.229106 +0.227137 +0.225181 +0.223240 +0.221311 +0.219397 +0.217495 +0.215608 +0.213733 +0.211872 +0.210023 +0.208188 +0.206366 +0.204557 +0.202761 +0.200978 +0.199207 +0.197449 +0.195704 +0.193972 +0.192252 +0.190545 +0.188850 +0.187167 +0.185497 +0.183839 +0.182193 +0.180559 +0.178938 +0.177328 +0.175730 +0.174144 +0.172570 +0.171008 +0.169458 +0.167919 +0.166391 +0.164875 +0.163371 +0.161878 +0.160396 +0.158926 +0.157467 +0.156018 +0.154581 +0.153155 +0.151740 +0.150336 +0.148943 +0.147561 +0.146189 +0.144828 +0.143477 +0.142137 +0.140808 +0.139488 +0.138180 +0.136881 +0.135593 +0.134315 +0.133047 +0.131789 +0.130542 +0.129304 +0.128076 +0.126858 +0.125649 +0.124450 +0.123261 +0.122082 +0.120912 +0.119752 +0.118601 +0.117459 +0.116327 +0.115204 +0.114090 +0.112985 +0.111889 +0.110803 +0.109725 +0.108656 +0.107596 +0.106545 +0.105503 +0.104469 +0.103444 +0.102428 +0.101420 +0.100420 +0.099429 +0.098446 +0.097472 +0.096506 +0.095548 +0.094598 +0.093656 +0.092723 +0.091797 +0.090879 +0.089969 +0.089067 +0.088173 +0.087286 +0.086407 +0.085536 +0.084672 +0.083816 +0.082967 +0.082126 +0.081292 +0.080465 +0.079646 +0.078833 +0.078028 +0.077230 +0.076439 +0.075655 +0.074878 +0.074108 +0.073345 +0.072589 +0.071839 +0.071096 +0.070360 +0.069630 +0.068907 +0.068191 +0.067480 +0.066777 +0.066080 +0.065389 +0.064704 +0.064026 +0.063353 +0.062687 +0.062027 +0.061374 +0.060726 +0.060084 +0.059448 +0.058818 +0.058193 +0.057575 +0.056962 +0.056355 +0.055754 +0.055158 +0.054568 +0.053983 +0.053404 +0.052831 +0.052262 +0.051700 +0.051142 +0.050590 +0.050043 +0.049501 +0.048964 +0.048432 +0.047906 +0.047384 +0.046868 +0.046357 +0.045850 +0.045348 +0.044851 +0.044359 +0.043872 +0.043389 +0.042912 +0.042438 +0.041970 +0.041506 +0.041046 +0.040591 +0.040141 +0.039694 +0.039253 +0.038815 +0.038382 +0.037954 +0.037529 +0.037109 +0.036693 +0.036281 +0.035873 +0.035469 +0.035069 +0.034673 +0.034282 +0.033894 +0.033510 +0.033130 +0.032753 +0.032381 +0.032012 +0.031647 +0.031286 +0.030929 +0.030575 +0.030224 +0.029878 +0.029534 +0.029195 +0.028859 +0.028526 +0.028197 +0.027871 +0.027548 +0.027229 +0.026913 +0.026601 +0.026291 +0.025985 +0.025682 +0.025383 +0.025086 +0.024793 +0.024502 +0.024215 +0.023930 +0.023649 +0.023371 +0.023095 +0.022823 +0.022553 +0.022286 +0.022022 +0.021761 +0.021503 +0.021247 +0.020995 +0.020744 +0.020497 +0.020252 +0.020010 +0.019770 +0.019533 +0.019299 +0.019067 +0.018838 +0.018611 +0.018387 +0.018165 +0.017945 +0.017728 +0.017513 +0.017301 +0.017091 +0.016883 +0.016677 +0.016474 +0.016273 +0.016074 +0.015878 +0.015684 +0.015491 +0.015301 +0.015113 +0.014927 +0.014744 +0.014562 +0.014382 +0.014204 +0.014029 +0.013855 +0.013683 +0.013513 +0.013345 +0.013179 +0.013015 +0.012853 +0.012692 +0.012534 +0.012377 +0.012222 +0.012068 +0.011917 +0.011767 +0.011619 +0.011473 +0.011328 +0.011185 +0.011043 +0.010904 +0.010765 +0.010629 +0.010494 +0.010360 +0.010229 +0.010098 +0.009969 +0.009842 +0.009716 +0.009592 +0.009469 +0.009348 +0.009227 +0.009109 +0.008992 +0.008876 +0.008761 +0.008648 +0.008536 +0.008426 +0.008317 +0.008209 +0.008102 +0.007997 +0.007893 +0.007790 +0.007688 +0.007588 +0.007489 +0.007391 +0.007294 +0.007198 +0.007104 +0.007011 +0.006918 +0.006827 +0.006737 +0.006648 +0.006560 +0.006474 +0.006388 +0.006303 +0.006220 +0.006137 +0.006055 +0.005975 +0.005895 +0.005816 +0.005739 +0.005662 +0.005586 +0.005511 +0.005437 +0.005364 +0.005292 +0.005221 +0.005151 +0.005081 +0.005013 +0.004945 +0.004878 +0.004812 +0.004747 +0.004682 +0.004619 +0.004556 +0.004494 +0.004433 +0.004372 +0.004313 +0.004254 +0.004195 +0.004138 +0.004081 +0.004025 +0.003970 +0.003915 +0.003861 +0.003808 +0.003756 +0.003704 +0.003652 +0.003602 +0.003552 +0.003503 +0.003454 +0.003406 +0.003359 +0.003312 +0.003266 +0.003220 +0.003175 +0.003131 +0.003087 +0.003044 +0.003001 +0.002959 +0.002917 +0.002876 +0.002836 +0.002796 +0.002756 +0.002717 +0.002679 +0.002641 +0.002604 +0.002567 +0.002530 +0.002494 +0.002459 +0.002424 +0.002389 +0.002355 +0.002322 +0.002288 +0.002256 +0.002223 +0.002191 +0.002160 +0.002129 +0.002098 +0.002068 +0.002038 +0.002009 +0.001980 +0.001951 +0.001923 +0.001895 +0.001868 +0.001841 +0.001814 +0.001788 +0.001761 +0.001736 +0.001711 +0.001686 +0.001661 +0.001637 +0.001613 +0.001589 +0.001566 +0.001543 +0.001520 +0.001498 +0.001476 +0.001454 +0.001432 +0.001411 +0.001390 +0.001370 +0.001350 +0.001330 +0.001310 +0.001290 +0.001271 +0.001252 +0.001234 +0.001215 +0.001197 +0.001179 +0.001162 +0.001144 +0.001127 +0.001110 +0.001094 +0.001077 +0.001061 +0.001045 +0.001029 +0.001014 +0.000998 +0.000983 +0.000968 +0.000954 +0.000939 +0.000925 +0.000911 +0.000897 +0.000884 +0.000870 +0.000857 +0.000844 +0.000831 +0.000818 +0.000806 +0.000793 +0.000781 +0.000769 +0.000757 +0.000746 +0.000734 +0.000723 +0.000712 +0.000701 +0.000690 +0.000679 +0.000669 +0.000659 +0.000648 +0.000638 +0.000628 +0.000619 +0.000609 +0.000599 +0.000590 +0.000581 +0.000572 +0.000563 +0.000554 +0.000545 +0.000537 +0.000529 +0.000520 +0.000512 +0.000504 +0.000496 +0.000488 +0.000481 +0.000473 +0.000465 +0.000458 +0.000451 +0.000444 +0.000437 +0.000430 +0.000423 +0.000416 +0.000410 +0.000403 +0.000397 +0.000390 +0.000384 +0.000378 +0.000372 +0.000366 +0.000360 +0.000354 +0.000349 +0.000343 +0.000338 +0.000332 +0.000327 +0.000321 +0.000316 +0.000311 +0.000306 +0.000301 +0.000296 +0.000292 +0.000287 +0.000282 +0.000278 +0.000273 +0.000269 +0.000264 +0.000260 +0.000256 +0.000252 +0.000247 +0.000243 +0.000239 +0.000235 +0.000232 +0.000228 +0.000224 +0.000220 +0.000217 +0.000213 +0.000210 +0.000206 +0.000203 +0.000199 +0.000196 +0.000193 +0.000190 +0.000187 +0.000183 +0.000180 +0.000177 +0.000174 +0.000172 +0.000169 +0.000166 +0.000163 +0.000160 +0.000158 +0.000155 +0.000152 +0.000150 +0.000147 +0.000145 +0.000142 +0.000140 +0.000138 +0.000135 +0.000133 +0.000131 +0.000129 +0.000126 +0.000124 +0.000122 +0.000120 +0.000118 +0.000116 +0.000114 +0.000112 +0.000110 +0.000108 +0.000107 +0.000105 +0.000103 +0.000101 +0.000099 +0.000098 +0.000096 +0.000094 +0.000093 +0.000091 +0.000090 +0.000088 +0.000087 +0.000085 +0.000084 +0.000082 +0.000081 +0.000079 +0.000078 +0.000077 +0.000075 +0.000074 +0.000073 +0.000071 +0.000070 +0.000069 +0.000068 +0.000067 +0.000065 +0.000064 +0.000063 +0.000062 +0.000061 +0.000060 +0.000059 +0.000058 +0.000057 +0.000056 +0.000055 +0.000054 +0.000053 +0.000052 +0.000051 +0.000050 +0.000049 +0.000048 +0.000048 +0.000047 +0.000046 +0.000045 +0.000044 +0.000043 +0.000043 +0.000042 +0.000041 +0.000040 +0.000040 +0.000039 +0.000038 +0.000038 +0.000037 +0.000036 +0.000036 +0.000035 +0.000034 +0.000034 +0.000033 +0.000033 +0.000032 +0.000031 +0.000031 +0.000030 +0.000030 +0.000029 +0.000029 +0.000028 +0.000028 +0.000027 +0.000027 +0.000026 +0.000026 +0.000025 +0.000025 +0.000024 +0.000024 +0.000023 +0.000023 +0.000023 +0.000022 +0.000022 +0.000021 +0.000021 +0.000021 +0.000020 +0.000020 +0.000019 +0.000019 +0.000019 +0.000018 +0.000018 +0.000018 +0.000017 +0.000017 +0.000017 +0.000016 +0.000016 +0.000016 +0.000016 +0.000015 +0.000015 +0.000015 +0.000014 +0.000014 +0.000014 +0.000014 +0.000013 +0.000013 +0.000013 +0.000013 +0.000012 +0.000012 +0.000012 +0.000012 +0.000011 +0.000011 +0.000011 +0.000011 +0.000011 +0.000010 +0.000010 +0.000010 +0.000010 +0.000010 +0.000010 +0.000009 +0.000009 +0.000009 +0.000009 +0.000009 +0.000008 +0.000008 +0.000008 +0.000008 +0.000008 +0.000008 +0.000008 +0.000007 +0.000007 +0.000007 +0.000007 +0.000007 +0.000007 +0.000007 +0.000006 +0.000006 +0.000006 +0.000006 +0.000006 +0.000006 +0.000006 +0.000006 +0.000006 +0.000005 +0.000005 +0.000005 +0.000005 +0.000005 +0.000005 +0.000005 +0.000005 +0.000005 +0.000005 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000004 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000003 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000002 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000001 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 diff --git a/inputFiles/lagrangianContactMechanics/dataTables/singularCrackSlip.csv b/inputFiles/lagrangianContactMechanics/dataTables/singularCrackSlip.csv new file mode 100644 index 00000000000..edf811e7742 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/dataTables/singularCrackSlip.csv @@ -0,0 +1,10000 @@ +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.128977 +0.225371 +0.291349 +0.344835 +0.390990 +0.432169 +0.469683 +0.504350 +0.536722 +0.567193 +0.596053 +0.623527 +0.649790 +0.674984 +0.699225 +0.722608 +0.745213 +0.767111 +0.788359 +0.809010 +0.829106 +0.848689 +0.867793 +0.886448 +0.904683 +0.922522 +0.939988 +0.957101 +0.973881 +0.990343 +1.006504 +1.022377 +1.037977 +1.053314 +1.068401 +1.083248 +1.097864 +1.112259 +1.126442 +1.140419 +1.154199 +1.167789 +1.181194 +1.194422 +1.207478 +1.220368 +1.233097 +1.245670 +1.258091 +1.270365 +1.282496 +1.294488 +1.306346 +1.318072 +1.329670 +1.341143 +1.352496 +1.363729 +1.374848 +1.385854 +1.396749 +1.407538 +1.418221 +1.428802 +1.439282 +1.449664 +1.459950 +1.470142 +1.480242 +1.490251 +1.500172 +1.510006 +1.519756 +1.529422 +1.539006 +1.548509 +1.557934 +1.567281 +1.576553 +1.585749 +1.594872 +1.603923 +1.612903 +1.621814 +1.630655 +1.639429 +1.648137 +1.656779 +1.665357 +1.673872 +1.682324 +1.690714 +1.699044 +1.707315 +1.715526 +1.723680 +1.731776 +1.739816 +1.747800 +1.755730 +1.763605 +1.771427 +1.779196 +1.786914 +1.794580 +1.802195 +1.809760 +1.817276 +1.824744 +1.832163 +1.839534 +1.846858 +1.854136 +1.861368 +1.868555 +1.875696 +1.882794 +1.889847 +1.896857 +1.903824 +1.910749 +1.917632 +1.924473 +1.931273 +1.938033 +1.944752 +1.951432 +1.958072 +1.964673 +1.971235 +1.977760 +1.984246 +1.990695 +1.997107 +2.003482 +2.009821 +2.016123 +2.022390 +2.028622 +2.034818 +2.040980 +2.047107 +2.053200 +2.059259 +2.065285 +2.071277 +2.077237 +2.083164 +2.089058 +2.094921 +2.100751 +2.106550 +2.112318 +2.118055 +2.123760 +2.129436 +2.135080 +2.140695 +2.146280 +2.151836 +2.157361 +2.162858 +2.168326 +2.173765 +2.179176 +2.184558 +2.189913 +2.195239 +2.200538 +2.205809 +2.211053 +2.216270 +2.221460 +2.226623 +2.231760 +2.236870 +2.241954 +2.247013 +2.252045 +2.257052 +2.262033 +2.266989 +2.271920 +2.276826 +2.281707 +2.286564 +2.291396 +2.296204 +2.300987 +2.305747 +2.310482 +2.315194 +2.319882 +2.324547 +2.329189 +2.333807 +2.338402 +2.342975 +2.347525 +2.352052 +2.356556 +2.361038 +2.365498 +2.369936 +2.374352 +2.378746 +2.383118 +2.387468 +2.391797 +2.396105 +2.400391 +2.404656 +2.408901 +2.413124 +2.417326 +2.421508 +2.425669 +2.429809 +2.433929 +2.438029 +2.442108 +2.446168 +2.450207 +2.454227 +2.458227 +2.462207 +2.466167 +2.470108 +2.474029 +2.477932 +2.481814 +2.485678 +2.489523 +2.493349 +2.497155 +2.500943 +2.504713 +2.508463 +2.512195 +2.515909 +2.519604 +2.523281 +2.526940 +2.530581 +2.534203 +2.537808 +2.541394 +2.544963 +2.548514 +2.552047 +2.555563 +2.559061 +2.562542 +2.566005 +2.569451 +2.572880 +2.576292 +2.579686 +2.583063 +2.586424 +2.589767 +2.593094 +2.596404 +2.599697 +2.602973 +2.606233 +2.609476 +2.612703 +2.615913 +2.619107 +2.622285 +2.625447 +2.628592 +2.631721 +2.634834 +2.637931 +2.641013 +2.644078 +2.647127 +2.650161 +2.653179 +2.656181 +2.659168 +2.662139 +2.665094 +2.668034 +2.670959 +2.673868 +2.676762 +2.679641 +2.682505 +2.685353 +2.688186 +2.691004 +2.693807 +2.696595 +2.699369 +2.702127 +2.704870 +2.707599 +2.710313 +2.713012 +2.715697 +2.718367 +2.721022 +2.723663 +2.726289 +2.728901 +2.731499 +2.734082 +2.736651 +2.739205 +2.741746 +2.744272 +2.746783 +2.749281 +2.751765 +2.754235 +2.756690 +2.759132 +2.761560 +2.763973 +2.766373 +2.768759 +2.771132 +2.773490 +2.775835 +2.778166 +2.780484 +2.782788 +2.785078 +2.787355 +2.789618 +2.791868 +2.794104 +2.796327 +2.798536 +2.800732 +2.802915 +2.805085 +2.807241 +2.809384 +2.811514 +2.813630 +2.815734 +2.817824 +2.819901 +2.821966 +2.824017 +2.826055 +2.828080 +2.830092 +2.832092 +2.834078 +2.836052 +2.838013 +2.839960 +2.841896 +2.843818 +2.845728 +2.847625 +2.849509 +2.851381 +2.853240 +2.855086 +2.856920 +2.858741 +2.860550 +2.862346 +2.864130 +2.865901 +2.867660 +2.869407 +2.871141 +2.872862 +2.874572 +2.876269 +2.877953 +2.879626 +2.881286 +2.882934 +2.884570 +2.886193 +2.887804 +2.889404 +2.890991 +2.892565 +2.894128 +2.895679 +2.897218 +2.898744 +2.900259 +2.901762 +2.903252 +2.904731 +2.906198 +2.907652 +2.909095 +2.910526 +2.911945 +2.913353 +2.914748 +2.916132 +2.917503 +2.918863 +2.920212 +2.921548 +2.922873 +2.924186 +2.925487 +2.926777 +2.928055 +2.929321 +2.930576 +2.931819 +2.933050 +2.934270 +2.935478 +2.936675 +2.937860 +2.939033 +2.940195 +2.941345 +2.942484 +2.943612 +2.944728 +2.945832 +2.946925 +2.948007 +2.949077 +2.950136 +2.951183 +2.952219 +2.953244 +2.954257 +2.955259 +2.956250 +2.957229 +2.958197 +2.959153 +2.960098 +2.961032 +2.961955 +2.962867 +2.963767 +2.964656 +2.965533 +2.966400 +2.967255 +2.968099 +2.968932 +2.969754 +2.970564 +2.971363 +2.972152 +2.972929 +2.973694 +2.974449 +2.975193 +2.975925 +2.976647 +2.977357 +2.978056 +2.978744 +2.979421 +2.980087 +2.980742 +2.981386 +2.982019 +2.982640 +2.983251 +2.983851 +2.984439 +2.985017 +2.985584 +2.986139 +2.986684 +2.987218 +2.987740 +2.988252 +2.988753 +2.989243 +2.989721 +2.990189 +2.990646 +2.991092 +2.991527 +2.991951 +2.992364 +2.992766 +2.993158 +2.993538 +2.993908 +2.994266 +2.994614 +2.994950 +2.995276 +2.995591 +2.995895 +2.996188 +2.996471 +2.996742 +2.997003 +2.997252 +2.997491 +2.997719 +2.997936 +2.998142 +2.998337 +2.998522 +2.998695 +2.998858 +2.999010 +2.999151 +2.999281 +2.999401 +2.999509 +2.999607 +2.999693 +2.999769 +2.999834 +2.999889 +2.999932 +2.999964 +2.999986 +2.999997 +2.999997 +2.999986 +2.999964 +2.999932 +2.999889 +2.999834 +2.999769 +2.999693 +2.999607 +2.999509 +2.999401 +2.999281 +2.999151 +2.999010 +2.998858 +2.998695 +2.998522 +2.998337 +2.998142 +2.997936 +2.997719 +2.997491 +2.997252 +2.997003 +2.996742 +2.996471 +2.996188 +2.995895 +2.995591 +2.995276 +2.994950 +2.994614 +2.994266 +2.993908 +2.993538 +2.993158 +2.992766 +2.992364 +2.991951 +2.991527 +2.991092 +2.990646 +2.990189 +2.989721 +2.989243 +2.988753 +2.988252 +2.987740 +2.987218 +2.986684 +2.986139 +2.985584 +2.985017 +2.984439 +2.983851 +2.983251 +2.982640 +2.982019 +2.981386 +2.980742 +2.980087 +2.979421 +2.978744 +2.978056 +2.977357 +2.976647 +2.975925 +2.975193 +2.974449 +2.973694 +2.972929 +2.972152 +2.971363 +2.970564 +2.969754 +2.968932 +2.968099 +2.967255 +2.966400 +2.965533 +2.964656 +2.963767 +2.962867 +2.961955 +2.961032 +2.960098 +2.959153 +2.958197 +2.957229 +2.956250 +2.955259 +2.954257 +2.953244 +2.952219 +2.951183 +2.950136 +2.949077 +2.948007 +2.946925 +2.945832 +2.944728 +2.943612 +2.942484 +2.941345 +2.940195 +2.939033 +2.937860 +2.936675 +2.935478 +2.934270 +2.933050 +2.931819 +2.930576 +2.929321 +2.928055 +2.926777 +2.925487 +2.924186 +2.922873 +2.921548 +2.920212 +2.918863 +2.917503 +2.916132 +2.914748 +2.913353 +2.911945 +2.910526 +2.909095 +2.907652 +2.906198 +2.904731 +2.903252 +2.901762 +2.900259 +2.898744 +2.897218 +2.895679 +2.894128 +2.892565 +2.890991 +2.889404 +2.887804 +2.886193 +2.884570 +2.882934 +2.881286 +2.879626 +2.877953 +2.876269 +2.874572 +2.872862 +2.871141 +2.869407 +2.867660 +2.865901 +2.864130 +2.862346 +2.860550 +2.858741 +2.856920 +2.855086 +2.853240 +2.851381 +2.849509 +2.847625 +2.845728 +2.843818 +2.841896 +2.839960 +2.838013 +2.836052 +2.834078 +2.832092 +2.830092 +2.828080 +2.826055 +2.824017 +2.821966 +2.819901 +2.817824 +2.815734 +2.813630 +2.811514 +2.809384 +2.807241 +2.805085 +2.802915 +2.800732 +2.798536 +2.796327 +2.794104 +2.791868 +2.789618 +2.787355 +2.785078 +2.782788 +2.780484 +2.778166 +2.775835 +2.773490 +2.771132 +2.768759 +2.766373 +2.763973 +2.761560 +2.759132 +2.756690 +2.754235 +2.751765 +2.749281 +2.746783 +2.744272 +2.741746 +2.739205 +2.736651 +2.734082 +2.731499 +2.728901 +2.726289 +2.723663 +2.721022 +2.718367 +2.715697 +2.713012 +2.710313 +2.707599 +2.704870 +2.702127 +2.699369 +2.696595 +2.693807 +2.691004 +2.688186 +2.685353 +2.682505 +2.679641 +2.676762 +2.673868 +2.670959 +2.668034 +2.665094 +2.662139 +2.659168 +2.656181 +2.653179 +2.650161 +2.647127 +2.644078 +2.641013 +2.637931 +2.634834 +2.631721 +2.628592 +2.625447 +2.622285 +2.619107 +2.615913 +2.612703 +2.609476 +2.606233 +2.602973 +2.599697 +2.596404 +2.593094 +2.589767 +2.586424 +2.583063 +2.579686 +2.576292 +2.572880 +2.569451 +2.566005 +2.562542 +2.559061 +2.555563 +2.552047 +2.548514 +2.544963 +2.541394 +2.537808 +2.534203 +2.530581 +2.526940 +2.523281 +2.519604 +2.515909 +2.512195 +2.508463 +2.504713 +2.500943 +2.497155 +2.493349 +2.489523 +2.485678 +2.481814 +2.477932 +2.474029 +2.470108 +2.466167 +2.462207 +2.458227 +2.454227 +2.450207 +2.446168 +2.442108 +2.438029 +2.433929 +2.429809 +2.425669 +2.421508 +2.417326 +2.413124 +2.408901 +2.404656 +2.400391 +2.396105 +2.391797 +2.387468 +2.383118 +2.378746 +2.374352 +2.369936 +2.365498 +2.361038 +2.356556 +2.352052 +2.347525 +2.342975 +2.338402 +2.333807 +2.329189 +2.324547 +2.319882 +2.315194 +2.310482 +2.305747 +2.300987 +2.296204 +2.291396 +2.286564 +2.281707 +2.276826 +2.271920 +2.266989 +2.262033 +2.257052 +2.252045 +2.247013 +2.241954 +2.236870 +2.231760 +2.226623 +2.221460 +2.216270 +2.211053 +2.205809 +2.200538 +2.195239 +2.189913 +2.184558 +2.179176 +2.173765 +2.168326 +2.162858 +2.157361 +2.151836 +2.146280 +2.140695 +2.135080 +2.129436 +2.123760 +2.118055 +2.112318 +2.106550 +2.100751 +2.094921 +2.089058 +2.083164 +2.077237 +2.071277 +2.065285 +2.059259 +2.053200 +2.047107 +2.040980 +2.034818 +2.028622 +2.022390 +2.016123 +2.009821 +2.003482 +1.997107 +1.990695 +1.984246 +1.977760 +1.971235 +1.964673 +1.958072 +1.951432 +1.944752 +1.938033 +1.931273 +1.924473 +1.917632 +1.910749 +1.903824 +1.896857 +1.889847 +1.882794 +1.875696 +1.868555 +1.861368 +1.854136 +1.846858 +1.839534 +1.832163 +1.824744 +1.817276 +1.809760 +1.802195 +1.794580 +1.786914 +1.779196 +1.771427 +1.763605 +1.755730 +1.747800 +1.739816 +1.731776 +1.723680 +1.715526 +1.707315 +1.699044 +1.690714 +1.682324 +1.673872 +1.665357 +1.656779 +1.648137 +1.639429 +1.630655 +1.621814 +1.612903 +1.603923 +1.594872 +1.585749 +1.576553 +1.567281 +1.557934 +1.548509 +1.539006 +1.529422 +1.519756 +1.510006 +1.500172 +1.490251 +1.480242 +1.470142 +1.459950 +1.449664 +1.439282 +1.428802 +1.418221 +1.407538 +1.396749 +1.385854 +1.374848 +1.363729 +1.352496 +1.341143 +1.329670 +1.318072 +1.306346 +1.294488 +1.282496 +1.270365 +1.258091 +1.245670 +1.233097 +1.220368 +1.207478 +1.194422 +1.181194 +1.167789 +1.154199 +1.140419 +1.126442 +1.112259 +1.097864 +1.083248 +1.068401 +1.053314 +1.037977 +1.022377 +1.006504 +0.990343 +0.973881 +0.957101 +0.939988 +0.922522 +0.904683 +0.886448 +0.867793 +0.848689 +0.829106 +0.809010 +0.788359 +0.767111 +0.745213 +0.722608 +0.699225 +0.674984 +0.649790 +0.623527 +0.596053 +0.567193 +0.536722 +0.504350 +0.469683 +0.432169 +0.390990 +0.344835 +0.291349 +0.225371 +0.128977 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 +0.000000 diff --git a/inputFiles/lagrangianContactMechanics/dataTables/x.csv b/inputFiles/lagrangianContactMechanics/dataTables/x.csv new file mode 100644 index 00000000000..aef9f0ca8b1 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/dataTables/x.csv @@ -0,0 +1,10000 @@ +-19.010000 +-19.006198 +-19.002395 +-18.998593 +-18.994790 +-18.990988 +-18.987186 +-18.983383 +-18.979581 +-18.975779 +-18.971976 +-18.968174 +-18.964371 +-18.960569 +-18.956767 +-18.952964 +-18.949162 +-18.945360 +-18.941557 +-18.937755 +-18.933952 +-18.930150 +-18.926348 +-18.922545 +-18.918743 +-18.914940 +-18.911138 +-18.907336 +-18.903533 +-18.899731 +-18.895929 +-18.892126 +-18.888324 +-18.884521 +-18.880719 +-18.876917 +-18.873114 +-18.869312 +-18.865510 +-18.861707 +-18.857905 +-18.854102 +-18.850300 +-18.846498 +-18.842695 +-18.838893 +-18.835091 +-18.831288 +-18.827486 +-18.823683 +-18.819881 +-18.816079 +-18.812276 +-18.808474 +-18.804671 +-18.800869 +-18.797067 +-18.793264 +-18.789462 +-18.785660 +-18.781857 +-18.778055 +-18.774252 +-18.770450 +-18.766648 +-18.762845 +-18.759043 +-18.755241 +-18.751438 +-18.747636 +-18.743833 +-18.740031 +-18.736229 +-18.732426 +-18.728624 +-18.724821 +-18.721019 +-18.717217 +-18.713414 +-18.709612 +-18.705810 +-18.702007 +-18.698205 +-18.694402 +-18.690600 +-18.686798 +-18.682995 +-18.679193 +-18.675391 +-18.671588 +-18.667786 +-18.663983 +-18.660181 +-18.656379 +-18.652576 +-18.648774 +-18.644971 +-18.641169 +-18.637367 +-18.633564 +-18.629762 +-18.625960 +-18.622157 +-18.618355 +-18.614552 +-18.610750 +-18.606948 +-18.603145 +-18.599343 +-18.595541 +-18.591738 +-18.587936 +-18.584133 +-18.580331 +-18.576529 +-18.572726 +-18.568924 +-18.565122 +-18.561319 +-18.557517 +-18.553714 +-18.549912 +-18.546110 +-18.542307 +-18.538505 +-18.534702 +-18.530900 +-18.527098 +-18.523295 +-18.519493 +-18.515691 +-18.511888 +-18.508086 +-18.504283 +-18.500481 +-18.496679 +-18.492876 +-18.489074 +-18.485272 +-18.481469 +-18.477667 +-18.473864 +-18.470062 +-18.466260 +-18.462457 +-18.458655 +-18.454852 +-18.451050 +-18.447248 +-18.443445 +-18.439643 +-18.435841 +-18.432038 +-18.428236 +-18.424433 +-18.420631 +-18.416829 +-18.413026 +-18.409224 +-18.405422 +-18.401619 +-18.397817 +-18.394014 +-18.390212 +-18.386410 +-18.382607 +-18.378805 +-18.375003 +-18.371200 +-18.367398 +-18.363595 +-18.359793 +-18.355991 +-18.352188 +-18.348386 +-18.344583 +-18.340781 +-18.336979 +-18.333176 +-18.329374 +-18.325572 +-18.321769 +-18.317967 +-18.314164 +-18.310362 +-18.306560 +-18.302757 +-18.298955 +-18.295153 +-18.291350 +-18.287548 +-18.283745 +-18.279943 +-18.276141 +-18.272338 +-18.268536 +-18.264733 +-18.260931 +-18.257129 +-18.253326 +-18.249524 +-18.245722 +-18.241919 +-18.238117 +-18.234314 +-18.230512 +-18.226710 +-18.222907 +-18.219105 +-18.215303 +-18.211500 +-18.207698 +-18.203895 +-18.200093 +-18.196291 +-18.192488 +-18.188686 +-18.184883 +-18.181081 +-18.177279 +-18.173476 +-18.169674 +-18.165872 +-18.162069 +-18.158267 +-18.154464 +-18.150662 +-18.146860 +-18.143057 +-18.139255 +-18.135453 +-18.131650 +-18.127848 +-18.124045 +-18.120243 +-18.116441 +-18.112638 +-18.108836 +-18.105034 +-18.101231 +-18.097429 +-18.093626 +-18.089824 +-18.086022 +-18.082219 +-18.078417 +-18.074614 +-18.070812 +-18.067010 +-18.063207 +-18.059405 +-18.055603 +-18.051800 +-18.047998 +-18.044195 +-18.040393 +-18.036591 +-18.032788 +-18.028986 +-18.025184 +-18.021381 +-18.017579 +-18.013776 +-18.009974 +-18.006172 +-18.002369 +-17.998567 +-17.994764 +-17.990962 +-17.987160 +-17.983357 +-17.979555 +-17.975753 +-17.971950 +-17.968148 +-17.964345 +-17.960543 +-17.956741 +-17.952938 +-17.949136 +-17.945334 +-17.941531 +-17.937729 +-17.933926 +-17.930124 +-17.926322 +-17.922519 +-17.918717 +-17.914914 +-17.911112 +-17.907310 +-17.903507 +-17.899705 +-17.895903 +-17.892100 +-17.888298 +-17.884495 +-17.880693 +-17.876891 +-17.873088 +-17.869286 +-17.865484 +-17.861681 +-17.857879 +-17.854076 +-17.850274 +-17.846472 +-17.842669 +-17.838867 +-17.835065 +-17.831262 +-17.827460 +-17.823657 +-17.819855 +-17.816053 +-17.812250 +-17.808448 +-17.804645 +-17.800843 +-17.797041 +-17.793238 +-17.789436 +-17.785634 +-17.781831 +-17.778029 +-17.774226 +-17.770424 +-17.766622 +-17.762819 +-17.759017 +-17.755215 +-17.751412 +-17.747610 +-17.743807 +-17.740005 +-17.736203 +-17.732400 +-17.728598 +-17.724795 +-17.720993 +-17.717191 +-17.713388 +-17.709586 +-17.705784 +-17.701981 +-17.698179 +-17.694376 +-17.690574 +-17.686772 +-17.682969 +-17.679167 +-17.675365 +-17.671562 +-17.667760 +-17.663957 +-17.660155 +-17.656353 +-17.652550 +-17.648748 +-17.644945 +-17.641143 +-17.637341 +-17.633538 +-17.629736 +-17.625934 +-17.622131 +-17.618329 +-17.614526 +-17.610724 +-17.606922 +-17.603119 +-17.599317 +-17.595515 +-17.591712 +-17.587910 +-17.584107 +-17.580305 +-17.576503 +-17.572700 +-17.568898 +-17.565096 +-17.561293 +-17.557491 +-17.553688 +-17.549886 +-17.546084 +-17.542281 +-17.538479 +-17.534676 +-17.530874 +-17.527072 +-17.523269 +-17.519467 +-17.515665 +-17.511862 +-17.508060 +-17.504257 +-17.500455 +-17.496653 +-17.492850 +-17.489048 +-17.485246 +-17.481443 +-17.477641 +-17.473838 +-17.470036 +-17.466234 +-17.462431 +-17.458629 +-17.454826 +-17.451024 +-17.447222 +-17.443419 +-17.439617 +-17.435815 +-17.432012 +-17.428210 +-17.424407 +-17.420605 +-17.416803 +-17.413000 +-17.409198 +-17.405396 +-17.401593 +-17.397791 +-17.393988 +-17.390186 +-17.386384 +-17.382581 +-17.378779 +-17.374976 +-17.371174 +-17.367372 +-17.363569 +-17.359767 +-17.355965 +-17.352162 +-17.348360 +-17.344557 +-17.340755 +-17.336953 +-17.333150 +-17.329348 +-17.325546 +-17.321743 +-17.317941 +-17.314138 +-17.310336 +-17.306534 +-17.302731 +-17.298929 +-17.295127 +-17.291324 +-17.287522 +-17.283719 +-17.279917 +-17.276115 +-17.272312 +-17.268510 +-17.264707 +-17.260905 +-17.257103 +-17.253300 +-17.249498 +-17.245696 +-17.241893 +-17.238091 +-17.234288 +-17.230486 +-17.226684 +-17.222881 +-17.219079 +-17.215277 +-17.211474 +-17.207672 +-17.203869 +-17.200067 +-17.196265 +-17.192462 +-17.188660 +-17.184857 +-17.181055 +-17.177253 +-17.173450 +-17.169648 +-17.165846 +-17.162043 +-17.158241 +-17.154438 +-17.150636 +-17.146834 +-17.143031 +-17.139229 +-17.135427 +-17.131624 +-17.127822 +-17.124019 +-17.120217 +-17.116415 +-17.112612 +-17.108810 +-17.105008 +-17.101205 +-17.097403 +-17.093600 +-17.089798 +-17.085996 +-17.082193 +-17.078391 +-17.074588 +-17.070786 +-17.066984 +-17.063181 +-17.059379 +-17.055577 +-17.051774 +-17.047972 +-17.044169 +-17.040367 +-17.036565 +-17.032762 +-17.028960 +-17.025158 +-17.021355 +-17.017553 +-17.013750 +-17.009948 +-17.006146 +-17.002343 +-16.998541 +-16.994738 +-16.990936 +-16.987134 +-16.983331 +-16.979529 +-16.975727 +-16.971924 +-16.968122 +-16.964319 +-16.960517 +-16.956715 +-16.952912 +-16.949110 +-16.945308 +-16.941505 +-16.937703 +-16.933900 +-16.930098 +-16.926296 +-16.922493 +-16.918691 +-16.914888 +-16.911086 +-16.907284 +-16.903481 +-16.899679 +-16.895877 +-16.892074 +-16.888272 +-16.884469 +-16.880667 +-16.876865 +-16.873062 +-16.869260 +-16.865458 +-16.861655 +-16.857853 +-16.854050 +-16.850248 +-16.846446 +-16.842643 +-16.838841 +-16.835039 +-16.831236 +-16.827434 +-16.823631 +-16.819829 +-16.816027 +-16.812224 +-16.808422 +-16.804619 +-16.800817 +-16.797015 +-16.793212 +-16.789410 +-16.785608 +-16.781805 +-16.778003 +-16.774200 +-16.770398 +-16.766596 +-16.762793 +-16.758991 +-16.755189 +-16.751386 +-16.747584 +-16.743781 +-16.739979 +-16.736177 +-16.732374 +-16.728572 +-16.724769 +-16.720967 +-16.717165 +-16.713362 +-16.709560 +-16.705758 +-16.701955 +-16.698153 +-16.694350 +-16.690548 +-16.686746 +-16.682943 +-16.679141 +-16.675339 +-16.671536 +-16.667734 +-16.663931 +-16.660129 +-16.656327 +-16.652524 +-16.648722 +-16.644919 +-16.641117 +-16.637315 +-16.633512 +-16.629710 +-16.625908 +-16.622105 +-16.618303 +-16.614500 +-16.610698 +-16.606896 +-16.603093 +-16.599291 +-16.595489 +-16.591686 +-16.587884 +-16.584081 +-16.580279 +-16.576477 +-16.572674 +-16.568872 +-16.565070 +-16.561267 +-16.557465 +-16.553662 +-16.549860 +-16.546058 +-16.542255 +-16.538453 +-16.534650 +-16.530848 +-16.527046 +-16.523243 +-16.519441 +-16.515639 +-16.511836 +-16.508034 +-16.504231 +-16.500429 +-16.496627 +-16.492824 +-16.489022 +-16.485220 +-16.481417 +-16.477615 +-16.473812 +-16.470010 +-16.466208 +-16.462405 +-16.458603 +-16.454800 +-16.450998 +-16.447196 +-16.443393 +-16.439591 +-16.435789 +-16.431986 +-16.428184 +-16.424381 +-16.420579 +-16.416777 +-16.412974 +-16.409172 +-16.405370 +-16.401567 +-16.397765 +-16.393962 +-16.390160 +-16.386358 +-16.382555 +-16.378753 +-16.374950 +-16.371148 +-16.367346 +-16.363543 +-16.359741 +-16.355939 +-16.352136 +-16.348334 +-16.344531 +-16.340729 +-16.336927 +-16.333124 +-16.329322 +-16.325520 +-16.321717 +-16.317915 +-16.314112 +-16.310310 +-16.306508 +-16.302705 +-16.298903 +-16.295101 +-16.291298 +-16.287496 +-16.283693 +-16.279891 +-16.276089 +-16.272286 +-16.268484 +-16.264681 +-16.260879 +-16.257077 +-16.253274 +-16.249472 +-16.245670 +-16.241867 +-16.238065 +-16.234262 +-16.230460 +-16.226658 +-16.222855 +-16.219053 +-16.215251 +-16.211448 +-16.207646 +-16.203843 +-16.200041 +-16.196239 +-16.192436 +-16.188634 +-16.184831 +-16.181029 +-16.177227 +-16.173424 +-16.169622 +-16.165820 +-16.162017 +-16.158215 +-16.154412 +-16.150610 +-16.146808 +-16.143005 +-16.139203 +-16.135401 +-16.131598 +-16.127796 +-16.123993 +-16.120191 +-16.116389 +-16.112586 +-16.108784 +-16.104981 +-16.101179 +-16.097377 +-16.093574 +-16.089772 +-16.085970 +-16.082167 +-16.078365 +-16.074562 +-16.070760 +-16.066958 +-16.063155 +-16.059353 +-16.055551 +-16.051748 +-16.047946 +-16.044143 +-16.040341 +-16.036539 +-16.032736 +-16.028934 +-16.025132 +-16.021329 +-16.017527 +-16.013724 +-16.009922 +-16.006120 +-16.002317 +-15.998515 +-15.994712 +-15.990910 +-15.987108 +-15.983305 +-15.979503 +-15.975701 +-15.971898 +-15.968096 +-15.964293 +-15.960491 +-15.956689 +-15.952886 +-15.949084 +-15.945282 +-15.941479 +-15.937677 +-15.933874 +-15.930072 +-15.926270 +-15.922467 +-15.918665 +-15.914862 +-15.911060 +-15.907258 +-15.903455 +-15.899653 +-15.895851 +-15.892048 +-15.888246 +-15.884443 +-15.880641 +-15.876839 +-15.873036 +-15.869234 +-15.865432 +-15.861629 +-15.857827 +-15.854024 +-15.850222 +-15.846420 +-15.842617 +-15.838815 +-15.835013 +-15.831210 +-15.827408 +-15.823605 +-15.819803 +-15.816001 +-15.812198 +-15.808396 +-15.804593 +-15.800791 +-15.796989 +-15.793186 +-15.789384 +-15.785582 +-15.781779 +-15.777977 +-15.774174 +-15.770372 +-15.766570 +-15.762767 +-15.758965 +-15.755163 +-15.751360 +-15.747558 +-15.743755 +-15.739953 +-15.736151 +-15.732348 +-15.728546 +-15.724743 +-15.720941 +-15.717139 +-15.713336 +-15.709534 +-15.705732 +-15.701929 +-15.698127 +-15.694324 +-15.690522 +-15.686720 +-15.682917 +-15.679115 +-15.675313 +-15.671510 +-15.667708 +-15.663905 +-15.660103 +-15.656301 +-15.652498 +-15.648696 +-15.644893 +-15.641091 +-15.637289 +-15.633486 +-15.629684 +-15.625882 +-15.622079 +-15.618277 +-15.614474 +-15.610672 +-15.606870 +-15.603067 +-15.599265 +-15.595463 +-15.591660 +-15.587858 +-15.584055 +-15.580253 +-15.576451 +-15.572648 +-15.568846 +-15.565044 +-15.561241 +-15.557439 +-15.553636 +-15.549834 +-15.546032 +-15.542229 +-15.538427 +-15.534624 +-15.530822 +-15.527020 +-15.523217 +-15.519415 +-15.515613 +-15.511810 +-15.508008 +-15.504205 +-15.500403 +-15.496601 +-15.492798 +-15.488996 +-15.485194 +-15.481391 +-15.477589 +-15.473786 +-15.469984 +-15.466182 +-15.462379 +-15.458577 +-15.454774 +-15.450972 +-15.447170 +-15.443367 +-15.439565 +-15.435763 +-15.431960 +-15.428158 +-15.424355 +-15.420553 +-15.416751 +-15.412948 +-15.409146 +-15.405344 +-15.401541 +-15.397739 +-15.393936 +-15.390134 +-15.386332 +-15.382529 +-15.378727 +-15.374924 +-15.371122 +-15.367320 +-15.363517 +-15.359715 +-15.355913 +-15.352110 +-15.348308 +-15.344505 +-15.340703 +-15.336901 +-15.333098 +-15.329296 +-15.325494 +-15.321691 +-15.317889 +-15.314086 +-15.310284 +-15.306482 +-15.302679 +-15.298877 +-15.295075 +-15.291272 +-15.287470 +-15.283667 +-15.279865 +-15.276063 +-15.272260 +-15.268458 +-15.264655 +-15.260853 +-15.257051 +-15.253248 +-15.249446 +-15.245644 +-15.241841 +-15.238039 +-15.234236 +-15.230434 +-15.226632 +-15.222829 +-15.219027 +-15.215225 +-15.211422 +-15.207620 +-15.203817 +-15.200015 +-15.196213 +-15.192410 +-15.188608 +-15.184805 +-15.181003 +-15.177201 +-15.173398 +-15.169596 +-15.165794 +-15.161991 +-15.158189 +-15.154386 +-15.150584 +-15.146782 +-15.142979 +-15.139177 +-15.135375 +-15.131572 +-15.127770 +-15.123967 +-15.120165 +-15.116363 +-15.112560 +-15.108758 +-15.104955 +-15.101153 +-15.097351 +-15.093548 +-15.089746 +-15.085944 +-15.082141 +-15.078339 +-15.074536 +-15.070734 +-15.066932 +-15.063129 +-15.059327 +-15.055525 +-15.051722 +-15.047920 +-15.044117 +-15.040315 +-15.036513 +-15.032710 +-15.028908 +-15.025106 +-15.021303 +-15.017501 +-15.013698 +-15.009896 +-15.006094 +-15.002291 +-14.998489 +-14.994686 +-14.990884 +-14.987082 +-14.983279 +-14.979477 +-14.975675 +-14.971872 +-14.968070 +-14.964267 +-14.960465 +-14.956663 +-14.952860 +-14.949058 +-14.945256 +-14.941453 +-14.937651 +-14.933848 +-14.930046 +-14.926244 +-14.922441 +-14.918639 +-14.914836 +-14.911034 +-14.907232 +-14.903429 +-14.899627 +-14.895825 +-14.892022 +-14.888220 +-14.884417 +-14.880615 +-14.876813 +-14.873010 +-14.869208 +-14.865406 +-14.861603 +-14.857801 +-14.853998 +-14.850196 +-14.846394 +-14.842591 +-14.838789 +-14.834986 +-14.831184 +-14.827382 +-14.823579 +-14.819777 +-14.815975 +-14.812172 +-14.808370 +-14.804567 +-14.800765 +-14.796963 +-14.793160 +-14.789358 +-14.785556 +-14.781753 +-14.777951 +-14.774148 +-14.770346 +-14.766544 +-14.762741 +-14.758939 +-14.755137 +-14.751334 +-14.747532 +-14.743729 +-14.739927 +-14.736125 +-14.732322 +-14.728520 +-14.724717 +-14.720915 +-14.717113 +-14.713310 +-14.709508 +-14.705706 +-14.701903 +-14.698101 +-14.694298 +-14.690496 +-14.686694 +-14.682891 +-14.679089 +-14.675287 +-14.671484 +-14.667682 +-14.663879 +-14.660077 +-14.656275 +-14.652472 +-14.648670 +-14.644867 +-14.641065 +-14.637263 +-14.633460 +-14.629658 +-14.625856 +-14.622053 +-14.618251 +-14.614448 +-14.610646 +-14.606844 +-14.603041 +-14.599239 +-14.595437 +-14.591634 +-14.587832 +-14.584029 +-14.580227 +-14.576425 +-14.572622 +-14.568820 +-14.565018 +-14.561215 +-14.557413 +-14.553610 +-14.549808 +-14.546006 +-14.542203 +-14.538401 +-14.534598 +-14.530796 +-14.526994 +-14.523191 +-14.519389 +-14.515587 +-14.511784 +-14.507982 +-14.504179 +-14.500377 +-14.496575 +-14.492772 +-14.488970 +-14.485168 +-14.481365 +-14.477563 +-14.473760 +-14.469958 +-14.466156 +-14.462353 +-14.458551 +-14.454748 +-14.450946 +-14.447144 +-14.443341 +-14.439539 +-14.435737 +-14.431934 +-14.428132 +-14.424329 +-14.420527 +-14.416725 +-14.412922 +-14.409120 +-14.405318 +-14.401515 +-14.397713 +-14.393910 +-14.390108 +-14.386306 +-14.382503 +-14.378701 +-14.374898 +-14.371096 +-14.367294 +-14.363491 +-14.359689 +-14.355887 +-14.352084 +-14.348282 +-14.344479 +-14.340677 +-14.336875 +-14.333072 +-14.329270 +-14.325468 +-14.321665 +-14.317863 +-14.314060 +-14.310258 +-14.306456 +-14.302653 +-14.298851 +-14.295049 +-14.291246 +-14.287444 +-14.283641 +-14.279839 +-14.276037 +-14.272234 +-14.268432 +-14.264629 +-14.260827 +-14.257025 +-14.253222 +-14.249420 +-14.245618 +-14.241815 +-14.238013 +-14.234210 +-14.230408 +-14.226606 +-14.222803 +-14.219001 +-14.215199 +-14.211396 +-14.207594 +-14.203791 +-14.199989 +-14.196187 +-14.192384 +-14.188582 +-14.184779 +-14.180977 +-14.177175 +-14.173372 +-14.169570 +-14.165768 +-14.161965 +-14.158163 +-14.154360 +-14.150558 +-14.146756 +-14.142953 +-14.139151 +-14.135349 +-14.131546 +-14.127744 +-14.123941 +-14.120139 +-14.116337 +-14.112534 +-14.108732 +-14.104929 +-14.101127 +-14.097325 +-14.093522 +-14.089720 +-14.085918 +-14.082115 +-14.078313 +-14.074510 +-14.070708 +-14.066906 +-14.063103 +-14.059301 +-14.055499 +-14.051696 +-14.047894 +-14.044091 +-14.040289 +-14.036487 +-14.032684 +-14.028882 +-14.025080 +-14.021277 +-14.017475 +-14.013672 +-14.009870 +-14.006068 +-14.002265 +-13.998463 +-13.994660 +-13.990858 +-13.987056 +-13.983253 +-13.979451 +-13.975649 +-13.971846 +-13.968044 +-13.964241 +-13.960439 +-13.956637 +-13.952834 +-13.949032 +-13.945230 +-13.941427 +-13.937625 +-13.933822 +-13.930020 +-13.926218 +-13.922415 +-13.918613 +-13.914810 +-13.911008 +-13.907206 +-13.903403 +-13.899601 +-13.895799 +-13.891996 +-13.888194 +-13.884391 +-13.880589 +-13.876787 +-13.872984 +-13.869182 +-13.865380 +-13.861577 +-13.857775 +-13.853972 +-13.850170 +-13.846368 +-13.842565 +-13.838763 +-13.834960 +-13.831158 +-13.827356 +-13.823553 +-13.819751 +-13.815949 +-13.812146 +-13.808344 +-13.804541 +-13.800739 +-13.796937 +-13.793134 +-13.789332 +-13.785530 +-13.781727 +-13.777925 +-13.774122 +-13.770320 +-13.766518 +-13.762715 +-13.758913 +-13.755111 +-13.751308 +-13.747506 +-13.743703 +-13.739901 +-13.736099 +-13.732296 +-13.728494 +-13.724691 +-13.720889 +-13.717087 +-13.713284 +-13.709482 +-13.705680 +-13.701877 +-13.698075 +-13.694272 +-13.690470 +-13.686668 +-13.682865 +-13.679063 +-13.675261 +-13.671458 +-13.667656 +-13.663853 +-13.660051 +-13.656249 +-13.652446 +-13.648644 +-13.644841 +-13.641039 +-13.637237 +-13.633434 +-13.629632 +-13.625830 +-13.622027 +-13.618225 +-13.614422 +-13.610620 +-13.606818 +-13.603015 +-13.599213 +-13.595411 +-13.591608 +-13.587806 +-13.584003 +-13.580201 +-13.576399 +-13.572596 +-13.568794 +-13.564991 +-13.561189 +-13.557387 +-13.553584 +-13.549782 +-13.545980 +-13.542177 +-13.538375 +-13.534572 +-13.530770 +-13.526968 +-13.523165 +-13.519363 +-13.515561 +-13.511758 +-13.507956 +-13.504153 +-13.500351 +-13.496549 +-13.492746 +-13.488944 +-13.485142 +-13.481339 +-13.477537 +-13.473734 +-13.469932 +-13.466130 +-13.462327 +-13.458525 +-13.454722 +-13.450920 +-13.447118 +-13.443315 +-13.439513 +-13.435711 +-13.431908 +-13.428106 +-13.424303 +-13.420501 +-13.416699 +-13.412896 +-13.409094 +-13.405292 +-13.401489 +-13.397687 +-13.393884 +-13.390082 +-13.386280 +-13.382477 +-13.378675 +-13.374872 +-13.371070 +-13.367268 +-13.363465 +-13.359663 +-13.355861 +-13.352058 +-13.348256 +-13.344453 +-13.340651 +-13.336849 +-13.333046 +-13.329244 +-13.325442 +-13.321639 +-13.317837 +-13.314034 +-13.310232 +-13.306430 +-13.302627 +-13.298825 +-13.295023 +-13.291220 +-13.287418 +-13.283615 +-13.279813 +-13.276011 +-13.272208 +-13.268406 +-13.264603 +-13.260801 +-13.256999 +-13.253196 +-13.249394 +-13.245592 +-13.241789 +-13.237987 +-13.234184 +-13.230382 +-13.226580 +-13.222777 +-13.218975 +-13.215173 +-13.211370 +-13.207568 +-13.203765 +-13.199963 +-13.196161 +-13.192358 +-13.188556 +-13.184753 +-13.180951 +-13.177149 +-13.173346 +-13.169544 +-13.165742 +-13.161939 +-13.158137 +-13.154334 +-13.150532 +-13.146730 +-13.142927 +-13.139125 +-13.135323 +-13.131520 +-13.127718 +-13.123915 +-13.120113 +-13.116311 +-13.112508 +-13.108706 +-13.104903 +-13.101101 +-13.097299 +-13.093496 +-13.089694 +-13.085892 +-13.082089 +-13.078287 +-13.074484 +-13.070682 +-13.066880 +-13.063077 +-13.059275 +-13.055473 +-13.051670 +-13.047868 +-13.044065 +-13.040263 +-13.036461 +-13.032658 +-13.028856 +-13.025054 +-13.021251 +-13.017449 +-13.013646 +-13.009844 +-13.006042 +-13.002239 +-12.998437 +-12.994634 +-12.990832 +-12.987030 +-12.983227 +-12.979425 +-12.975623 +-12.971820 +-12.968018 +-12.964215 +-12.960413 +-12.956611 +-12.952808 +-12.949006 +-12.945204 +-12.941401 +-12.937599 +-12.933796 +-12.929994 +-12.926192 +-12.922389 +-12.918587 +-12.914784 +-12.910982 +-12.907180 +-12.903377 +-12.899575 +-12.895773 +-12.891970 +-12.888168 +-12.884365 +-12.880563 +-12.876761 +-12.872958 +-12.869156 +-12.865354 +-12.861551 +-12.857749 +-12.853946 +-12.850144 +-12.846342 +-12.842539 +-12.838737 +-12.834934 +-12.831132 +-12.827330 +-12.823527 +-12.819725 +-12.815923 +-12.812120 +-12.808318 +-12.804515 +-12.800713 +-12.796911 +-12.793108 +-12.789306 +-12.785504 +-12.781701 +-12.777899 +-12.774096 +-12.770294 +-12.766492 +-12.762689 +-12.758887 +-12.755085 +-12.751282 +-12.747480 +-12.743677 +-12.739875 +-12.736073 +-12.732270 +-12.728468 +-12.724665 +-12.720863 +-12.717061 +-12.713258 +-12.709456 +-12.705654 +-12.701851 +-12.698049 +-12.694246 +-12.690444 +-12.686642 +-12.682839 +-12.679037 +-12.675235 +-12.671432 +-12.667630 +-12.663827 +-12.660025 +-12.656223 +-12.652420 +-12.648618 +-12.644815 +-12.641013 +-12.637211 +-12.633408 +-12.629606 +-12.625804 +-12.622001 +-12.618199 +-12.614396 +-12.610594 +-12.606792 +-12.602989 +-12.599187 +-12.595385 +-12.591582 +-12.587780 +-12.583977 +-12.580175 +-12.576373 +-12.572570 +-12.568768 +-12.564965 +-12.561163 +-12.557361 +-12.553558 +-12.549756 +-12.545954 +-12.542151 +-12.538349 +-12.534546 +-12.530744 +-12.526942 +-12.523139 +-12.519337 +-12.515535 +-12.511732 +-12.507930 +-12.504127 +-12.500325 +-12.496523 +-12.492720 +-12.488918 +-12.485116 +-12.481313 +-12.477511 +-12.473708 +-12.469906 +-12.466104 +-12.462301 +-12.458499 +-12.454696 +-12.450894 +-12.447092 +-12.443289 +-12.439487 +-12.435685 +-12.431882 +-12.428080 +-12.424277 +-12.420475 +-12.416673 +-12.412870 +-12.409068 +-12.405266 +-12.401463 +-12.397661 +-12.393858 +-12.390056 +-12.386254 +-12.382451 +-12.378649 +-12.374846 +-12.371044 +-12.367242 +-12.363439 +-12.359637 +-12.355835 +-12.352032 +-12.348230 +-12.344427 +-12.340625 +-12.336823 +-12.333020 +-12.329218 +-12.325416 +-12.321613 +-12.317811 +-12.314008 +-12.310206 +-12.306404 +-12.302601 +-12.298799 +-12.294996 +-12.291194 +-12.287392 +-12.283589 +-12.279787 +-12.275985 +-12.272182 +-12.268380 +-12.264577 +-12.260775 +-12.256973 +-12.253170 +-12.249368 +-12.245566 +-12.241763 +-12.237961 +-12.234158 +-12.230356 +-12.226554 +-12.222751 +-12.218949 +-12.215147 +-12.211344 +-12.207542 +-12.203739 +-12.199937 +-12.196135 +-12.192332 +-12.188530 +-12.184727 +-12.180925 +-12.177123 +-12.173320 +-12.169518 +-12.165716 +-12.161913 +-12.158111 +-12.154308 +-12.150506 +-12.146704 +-12.142901 +-12.139099 +-12.135297 +-12.131494 +-12.127692 +-12.123889 +-12.120087 +-12.116285 +-12.112482 +-12.108680 +-12.104877 +-12.101075 +-12.097273 +-12.093470 +-12.089668 +-12.085866 +-12.082063 +-12.078261 +-12.074458 +-12.070656 +-12.066854 +-12.063051 +-12.059249 +-12.055447 +-12.051644 +-12.047842 +-12.044039 +-12.040237 +-12.036435 +-12.032632 +-12.028830 +-12.025028 +-12.021225 +-12.017423 +-12.013620 +-12.009818 +-12.006016 +-12.002213 +-11.998411 +-11.994608 +-11.990806 +-11.987004 +-11.983201 +-11.979399 +-11.975597 +-11.971794 +-11.967992 +-11.964189 +-11.960387 +-11.956585 +-11.952782 +-11.948980 +-11.945178 +-11.941375 +-11.937573 +-11.933770 +-11.929968 +-11.926166 +-11.922363 +-11.918561 +-11.914758 +-11.910956 +-11.907154 +-11.903351 +-11.899549 +-11.895747 +-11.891944 +-11.888142 +-11.884339 +-11.880537 +-11.876735 +-11.872932 +-11.869130 +-11.865328 +-11.861525 +-11.857723 +-11.853920 +-11.850118 +-11.846316 +-11.842513 +-11.838711 +-11.834908 +-11.831106 +-11.827304 +-11.823501 +-11.819699 +-11.815897 +-11.812094 +-11.808292 +-11.804489 +-11.800687 +-11.796885 +-11.793082 +-11.789280 +-11.785478 +-11.781675 +-11.777873 +-11.774070 +-11.770268 +-11.766466 +-11.762663 +-11.758861 +-11.755059 +-11.751256 +-11.747454 +-11.743651 +-11.739849 +-11.736047 +-11.732244 +-11.728442 +-11.724639 +-11.720837 +-11.717035 +-11.713232 +-11.709430 +-11.705628 +-11.701825 +-11.698023 +-11.694220 +-11.690418 +-11.686616 +-11.682813 +-11.679011 +-11.675209 +-11.671406 +-11.667604 +-11.663801 +-11.659999 +-11.656197 +-11.652394 +-11.648592 +-11.644789 +-11.640987 +-11.637185 +-11.633382 +-11.629580 +-11.625778 +-11.621975 +-11.618173 +-11.614370 +-11.610568 +-11.606766 +-11.602963 +-11.599161 +-11.595359 +-11.591556 +-11.587754 +-11.583951 +-11.580149 +-11.576347 +-11.572544 +-11.568742 +-11.564939 +-11.561137 +-11.557335 +-11.553532 +-11.549730 +-11.545928 +-11.542125 +-11.538323 +-11.534520 +-11.530718 +-11.526916 +-11.523113 +-11.519311 +-11.515509 +-11.511706 +-11.507904 +-11.504101 +-11.500299 +-11.496497 +-11.492694 +-11.488892 +-11.485090 +-11.481287 +-11.477485 +-11.473682 +-11.469880 +-11.466078 +-11.462275 +-11.458473 +-11.454670 +-11.450868 +-11.447066 +-11.443263 +-11.439461 +-11.435659 +-11.431856 +-11.428054 +-11.424251 +-11.420449 +-11.416647 +-11.412844 +-11.409042 +-11.405240 +-11.401437 +-11.397635 +-11.393832 +-11.390030 +-11.386228 +-11.382425 +-11.378623 +-11.374820 +-11.371018 +-11.367216 +-11.363413 +-11.359611 +-11.355809 +-11.352006 +-11.348204 +-11.344401 +-11.340599 +-11.336797 +-11.332994 +-11.329192 +-11.325390 +-11.321587 +-11.317785 +-11.313982 +-11.310180 +-11.306378 +-11.302575 +-11.298773 +-11.294970 +-11.291168 +-11.287366 +-11.283563 +-11.279761 +-11.275959 +-11.272156 +-11.268354 +-11.264551 +-11.260749 +-11.256947 +-11.253144 +-11.249342 +-11.245540 +-11.241737 +-11.237935 +-11.234132 +-11.230330 +-11.226528 +-11.222725 +-11.218923 +-11.215121 +-11.211318 +-11.207516 +-11.203713 +-11.199911 +-11.196109 +-11.192306 +-11.188504 +-11.184701 +-11.180899 +-11.177097 +-11.173294 +-11.169492 +-11.165690 +-11.161887 +-11.158085 +-11.154282 +-11.150480 +-11.146678 +-11.142875 +-11.139073 +-11.135271 +-11.131468 +-11.127666 +-11.123863 +-11.120061 +-11.116259 +-11.112456 +-11.108654 +-11.104851 +-11.101049 +-11.097247 +-11.093444 +-11.089642 +-11.085840 +-11.082037 +-11.078235 +-11.074432 +-11.070630 +-11.066828 +-11.063025 +-11.059223 +-11.055421 +-11.051618 +-11.047816 +-11.044013 +-11.040211 +-11.036409 +-11.032606 +-11.028804 +-11.025002 +-11.021199 +-11.017397 +-11.013594 +-11.009792 +-11.005990 +-11.002187 +-10.998385 +-10.994582 +-10.990780 +-10.986978 +-10.983175 +-10.979373 +-10.975571 +-10.971768 +-10.967966 +-10.964163 +-10.960361 +-10.956559 +-10.952756 +-10.948954 +-10.945152 +-10.941349 +-10.937547 +-10.933744 +-10.929942 +-10.926140 +-10.922337 +-10.918535 +-10.914732 +-10.910930 +-10.907128 +-10.903325 +-10.899523 +-10.895721 +-10.891918 +-10.888116 +-10.884313 +-10.880511 +-10.876709 +-10.872906 +-10.869104 +-10.865302 +-10.861499 +-10.857697 +-10.853894 +-10.850092 +-10.846290 +-10.842487 +-10.838685 +-10.834882 +-10.831080 +-10.827278 +-10.823475 +-10.819673 +-10.815871 +-10.812068 +-10.808266 +-10.804463 +-10.800661 +-10.796859 +-10.793056 +-10.789254 +-10.785452 +-10.781649 +-10.777847 +-10.774044 +-10.770242 +-10.766440 +-10.762637 +-10.758835 +-10.755033 +-10.751230 +-10.747428 +-10.743625 +-10.739823 +-10.736021 +-10.732218 +-10.728416 +-10.724613 +-10.720811 +-10.717009 +-10.713206 +-10.709404 +-10.705602 +-10.701799 +-10.697997 +-10.694194 +-10.690392 +-10.686590 +-10.682787 +-10.678985 +-10.675183 +-10.671380 +-10.667578 +-10.663775 +-10.659973 +-10.656171 +-10.652368 +-10.648566 +-10.644763 +-10.640961 +-10.637159 +-10.633356 +-10.629554 +-10.625752 +-10.621949 +-10.618147 +-10.614344 +-10.610542 +-10.606740 +-10.602937 +-10.599135 +-10.595333 +-10.591530 +-10.587728 +-10.583925 +-10.580123 +-10.576321 +-10.572518 +-10.568716 +-10.564913 +-10.561111 +-10.557309 +-10.553506 +-10.549704 +-10.545902 +-10.542099 +-10.538297 +-10.534494 +-10.530692 +-10.526890 +-10.523087 +-10.519285 +-10.515483 +-10.511680 +-10.507878 +-10.504075 +-10.500273 +-10.496471 +-10.492668 +-10.488866 +-10.485064 +-10.481261 +-10.477459 +-10.473656 +-10.469854 +-10.466052 +-10.462249 +-10.458447 +-10.454644 +-10.450842 +-10.447040 +-10.443237 +-10.439435 +-10.435633 +-10.431830 +-10.428028 +-10.424225 +-10.420423 +-10.416621 +-10.412818 +-10.409016 +-10.405214 +-10.401411 +-10.397609 +-10.393806 +-10.390004 +-10.386202 +-10.382399 +-10.378597 +-10.374794 +-10.370992 +-10.367190 +-10.363387 +-10.359585 +-10.355783 +-10.351980 +-10.348178 +-10.344375 +-10.340573 +-10.336771 +-10.332968 +-10.329166 +-10.325364 +-10.321561 +-10.317759 +-10.313956 +-10.310154 +-10.306352 +-10.302549 +-10.298747 +-10.294944 +-10.291142 +-10.287340 +-10.283537 +-10.279735 +-10.275933 +-10.272130 +-10.268328 +-10.264525 +-10.260723 +-10.256921 +-10.253118 +-10.249316 +-10.245514 +-10.241711 +-10.237909 +-10.234106 +-10.230304 +-10.226502 +-10.222699 +-10.218897 +-10.215095 +-10.211292 +-10.207490 +-10.203687 +-10.199885 +-10.196083 +-10.192280 +-10.188478 +-10.184675 +-10.180873 +-10.177071 +-10.173268 +-10.169466 +-10.165664 +-10.161861 +-10.158059 +-10.154256 +-10.150454 +-10.146652 +-10.142849 +-10.139047 +-10.135245 +-10.131442 +-10.127640 +-10.123837 +-10.120035 +-10.116233 +-10.112430 +-10.108628 +-10.104825 +-10.101023 +-10.097221 +-10.093418 +-10.089616 +-10.085814 +-10.082011 +-10.078209 +-10.074406 +-10.070604 +-10.066802 +-10.062999 +-10.059197 +-10.055395 +-10.051592 +-10.047790 +-10.043987 +-10.040185 +-10.036383 +-10.032580 +-10.028778 +-10.024975 +-10.021173 +-10.017371 +-10.013568 +-10.009766 +-10.005964 +-10.002161 +-9.998359 +-9.994556 +-9.990754 +-9.986952 +-9.983149 +-9.979347 +-9.975545 +-9.971742 +-9.967940 +-9.964137 +-9.960335 +-9.956533 +-9.952730 +-9.948928 +-9.945126 +-9.941323 +-9.937521 +-9.933718 +-9.929916 +-9.926114 +-9.922311 +-9.918509 +-9.914706 +-9.910904 +-9.907102 +-9.903299 +-9.899497 +-9.895695 +-9.891892 +-9.888090 +-9.884287 +-9.880485 +-9.876683 +-9.872880 +-9.869078 +-9.865276 +-9.861473 +-9.857671 +-9.853868 +-9.850066 +-9.846264 +-9.842461 +-9.838659 +-9.834856 +-9.831054 +-9.827252 +-9.823449 +-9.819647 +-9.815845 +-9.812042 +-9.808240 +-9.804437 +-9.800635 +-9.796833 +-9.793030 +-9.789228 +-9.785426 +-9.781623 +-9.777821 +-9.774018 +-9.770216 +-9.766414 +-9.762611 +-9.758809 +-9.755007 +-9.751204 +-9.747402 +-9.743599 +-9.739797 +-9.735995 +-9.732192 +-9.728390 +-9.724587 +-9.720785 +-9.716983 +-9.713180 +-9.709378 +-9.705576 +-9.701773 +-9.697971 +-9.694168 +-9.690366 +-9.686564 +-9.682761 +-9.678959 +-9.675157 +-9.671354 +-9.667552 +-9.663749 +-9.659947 +-9.656145 +-9.652342 +-9.648540 +-9.644737 +-9.640935 +-9.637133 +-9.633330 +-9.629528 +-9.625726 +-9.621923 +-9.618121 +-9.614318 +-9.610516 +-9.606714 +-9.602911 +-9.599109 +-9.595307 +-9.591504 +-9.587702 +-9.583899 +-9.580097 +-9.576295 +-9.572492 +-9.568690 +-9.564887 +-9.561085 +-9.557283 +-9.553480 +-9.549678 +-9.545876 +-9.542073 +-9.538271 +-9.534468 +-9.530666 +-9.526864 +-9.523061 +-9.519259 +-9.515457 +-9.511654 +-9.507852 +-9.504049 +-9.500247 +-9.496445 +-9.492642 +-9.488840 +-9.485038 +-9.481235 +-9.477433 +-9.473630 +-9.469828 +-9.466026 +-9.462223 +-9.458421 +-9.454618 +-9.450816 +-9.447014 +-9.443211 +-9.439409 +-9.435607 +-9.431804 +-9.428002 +-9.424199 +-9.420397 +-9.416595 +-9.412792 +-9.408990 +-9.405188 +-9.401385 +-9.397583 +-9.393780 +-9.389978 +-9.386176 +-9.382373 +-9.378571 +-9.374768 +-9.370966 +-9.367164 +-9.363361 +-9.359559 +-9.355757 +-9.351954 +-9.348152 +-9.344349 +-9.340547 +-9.336745 +-9.332942 +-9.329140 +-9.325338 +-9.321535 +-9.317733 +-9.313930 +-9.310128 +-9.306326 +-9.302523 +-9.298721 +-9.294918 +-9.291116 +-9.287314 +-9.283511 +-9.279709 +-9.275907 +-9.272104 +-9.268302 +-9.264499 +-9.260697 +-9.256895 +-9.253092 +-9.249290 +-9.245488 +-9.241685 +-9.237883 +-9.234080 +-9.230278 +-9.226476 +-9.222673 +-9.218871 +-9.215069 +-9.211266 +-9.207464 +-9.203661 +-9.199859 +-9.196057 +-9.192254 +-9.188452 +-9.184649 +-9.180847 +-9.177045 +-9.173242 +-9.169440 +-9.165638 +-9.161835 +-9.158033 +-9.154230 +-9.150428 +-9.146626 +-9.142823 +-9.139021 +-9.135219 +-9.131416 +-9.127614 +-9.123811 +-9.120009 +-9.116207 +-9.112404 +-9.108602 +-9.104799 +-9.100997 +-9.097195 +-9.093392 +-9.089590 +-9.085788 +-9.081985 +-9.078183 +-9.074380 +-9.070578 +-9.066776 +-9.062973 +-9.059171 +-9.055369 +-9.051566 +-9.047764 +-9.043961 +-9.040159 +-9.036357 +-9.032554 +-9.028752 +-9.024949 +-9.021147 +-9.017345 +-9.013542 +-9.009740 +-9.005938 +-9.002135 +-8.998333 +-8.994530 +-8.990728 +-8.986926 +-8.983123 +-8.979321 +-8.975519 +-8.971716 +-8.967914 +-8.964111 +-8.960309 +-8.956507 +-8.952704 +-8.948902 +-8.945100 +-8.941297 +-8.937495 +-8.933692 +-8.929890 +-8.926088 +-8.922285 +-8.918483 +-8.914680 +-8.910878 +-8.907076 +-8.903273 +-8.899471 +-8.895669 +-8.891866 +-8.888064 +-8.884261 +-8.880459 +-8.876657 +-8.872854 +-8.869052 +-8.865250 +-8.861447 +-8.857645 +-8.853842 +-8.850040 +-8.846238 +-8.842435 +-8.838633 +-8.834830 +-8.831028 +-8.827226 +-8.823423 +-8.819621 +-8.815819 +-8.812016 +-8.808214 +-8.804411 +-8.800609 +-8.796807 +-8.793004 +-8.789202 +-8.785400 +-8.781597 +-8.777795 +-8.773992 +-8.770190 +-8.766388 +-8.762585 +-8.758783 +-8.754980 +-8.751178 +-8.747376 +-8.743573 +-8.739771 +-8.735969 +-8.732166 +-8.728364 +-8.724561 +-8.720759 +-8.716957 +-8.713154 +-8.709352 +-8.705550 +-8.701747 +-8.697945 +-8.694142 +-8.690340 +-8.686538 +-8.682735 +-8.678933 +-8.675131 +-8.671328 +-8.667526 +-8.663723 +-8.659921 +-8.656119 +-8.652316 +-8.648514 +-8.644711 +-8.640909 +-8.637107 +-8.633304 +-8.629502 +-8.625700 +-8.621897 +-8.618095 +-8.614292 +-8.610490 +-8.606688 +-8.602885 +-8.599083 +-8.595281 +-8.591478 +-8.587676 +-8.583873 +-8.580071 +-8.576269 +-8.572466 +-8.568664 +-8.564861 +-8.561059 +-8.557257 +-8.553454 +-8.549652 +-8.545850 +-8.542047 +-8.538245 +-8.534442 +-8.530640 +-8.526838 +-8.523035 +-8.519233 +-8.515431 +-8.511628 +-8.507826 +-8.504023 +-8.500221 +-8.496419 +-8.492616 +-8.488814 +-8.485012 +-8.481209 +-8.477407 +-8.473604 +-8.469802 +-8.466000 +-8.462197 +-8.458395 +-8.454592 +-8.450790 +-8.446988 +-8.443185 +-8.439383 +-8.435581 +-8.431778 +-8.427976 +-8.424173 +-8.420371 +-8.416569 +-8.412766 +-8.408964 +-8.405162 +-8.401359 +-8.397557 +-8.393754 +-8.389952 +-8.386150 +-8.382347 +-8.378545 +-8.374742 +-8.370940 +-8.367138 +-8.363335 +-8.359533 +-8.355731 +-8.351928 +-8.348126 +-8.344323 +-8.340521 +-8.336719 +-8.332916 +-8.329114 +-8.325312 +-8.321509 +-8.317707 +-8.313904 +-8.310102 +-8.306300 +-8.302497 +-8.298695 +-8.294892 +-8.291090 +-8.287288 +-8.283485 +-8.279683 +-8.275881 +-8.272078 +-8.268276 +-8.264473 +-8.260671 +-8.256869 +-8.253066 +-8.249264 +-8.245462 +-8.241659 +-8.237857 +-8.234054 +-8.230252 +-8.226450 +-8.222647 +-8.218845 +-8.215043 +-8.211240 +-8.207438 +-8.203635 +-8.199833 +-8.196031 +-8.192228 +-8.188426 +-8.184623 +-8.180821 +-8.177019 +-8.173216 +-8.169414 +-8.165612 +-8.161809 +-8.158007 +-8.154204 +-8.150402 +-8.146600 +-8.142797 +-8.138995 +-8.135193 +-8.131390 +-8.127588 +-8.123785 +-8.119983 +-8.116181 +-8.112378 +-8.108576 +-8.104773 +-8.100971 +-8.097169 +-8.093366 +-8.089564 +-8.085762 +-8.081959 +-8.078157 +-8.074354 +-8.070552 +-8.066750 +-8.062947 +-8.059145 +-8.055343 +-8.051540 +-8.047738 +-8.043935 +-8.040133 +-8.036331 +-8.032528 +-8.028726 +-8.024923 +-8.021121 +-8.017319 +-8.013516 +-8.009714 +-8.005912 +-8.002109 +-7.998307 +-7.994504 +-7.990702 +-7.986900 +-7.983097 +-7.979295 +-7.975493 +-7.971690 +-7.967888 +-7.964085 +-7.960283 +-7.956481 +-7.952678 +-7.948876 +-7.945074 +-7.941271 +-7.937469 +-7.933666 +-7.929864 +-7.926062 +-7.922259 +-7.918457 +-7.914654 +-7.910852 +-7.907050 +-7.903247 +-7.899445 +-7.895643 +-7.891840 +-7.888038 +-7.884235 +-7.880433 +-7.876631 +-7.872828 +-7.869026 +-7.865224 +-7.861421 +-7.857619 +-7.853816 +-7.850014 +-7.846212 +-7.842409 +-7.838607 +-7.834804 +-7.831002 +-7.827200 +-7.823397 +-7.819595 +-7.815793 +-7.811990 +-7.808188 +-7.804385 +-7.800583 +-7.796781 +-7.792978 +-7.789176 +-7.785374 +-7.781571 +-7.777769 +-7.773966 +-7.770164 +-7.766362 +-7.762559 +-7.758757 +-7.754954 +-7.751152 +-7.747350 +-7.743547 +-7.739745 +-7.735943 +-7.732140 +-7.728338 +-7.724535 +-7.720733 +-7.716931 +-7.713128 +-7.709326 +-7.705524 +-7.701721 +-7.697919 +-7.694116 +-7.690314 +-7.686512 +-7.682709 +-7.678907 +-7.675105 +-7.671302 +-7.667500 +-7.663697 +-7.659895 +-7.656093 +-7.652290 +-7.648488 +-7.644685 +-7.640883 +-7.637081 +-7.633278 +-7.629476 +-7.625674 +-7.621871 +-7.618069 +-7.614266 +-7.610464 +-7.606662 +-7.602859 +-7.599057 +-7.595255 +-7.591452 +-7.587650 +-7.583847 +-7.580045 +-7.576243 +-7.572440 +-7.568638 +-7.564835 +-7.561033 +-7.557231 +-7.553428 +-7.549626 +-7.545824 +-7.542021 +-7.538219 +-7.534416 +-7.530614 +-7.526812 +-7.523009 +-7.519207 +-7.515405 +-7.511602 +-7.507800 +-7.503997 +-7.500195 +-7.496393 +-7.492590 +-7.488788 +-7.484985 +-7.481183 +-7.477381 +-7.473578 +-7.469776 +-7.465974 +-7.462171 +-7.458369 +-7.454566 +-7.450764 +-7.446962 +-7.443159 +-7.439357 +-7.435555 +-7.431752 +-7.427950 +-7.424147 +-7.420345 +-7.416543 +-7.412740 +-7.408938 +-7.405136 +-7.401333 +-7.397531 +-7.393728 +-7.389926 +-7.386124 +-7.382321 +-7.378519 +-7.374716 +-7.370914 +-7.367112 +-7.363309 +-7.359507 +-7.355705 +-7.351902 +-7.348100 +-7.344297 +-7.340495 +-7.336693 +-7.332890 +-7.329088 +-7.325286 +-7.321483 +-7.317681 +-7.313878 +-7.310076 +-7.306274 +-7.302471 +-7.298669 +-7.294866 +-7.291064 +-7.287262 +-7.283459 +-7.279657 +-7.275855 +-7.272052 +-7.268250 +-7.264447 +-7.260645 +-7.256843 +-7.253040 +-7.249238 +-7.245436 +-7.241633 +-7.237831 +-7.234028 +-7.230226 +-7.226424 +-7.222621 +-7.218819 +-7.215017 +-7.211214 +-7.207412 +-7.203609 +-7.199807 +-7.196005 +-7.192202 +-7.188400 +-7.184597 +-7.180795 +-7.176993 +-7.173190 +-7.169388 +-7.165586 +-7.161783 +-7.157981 +-7.154178 +-7.150376 +-7.146574 +-7.142771 +-7.138969 +-7.135167 +-7.131364 +-7.127562 +-7.123759 +-7.119957 +-7.116155 +-7.112352 +-7.108550 +-7.104747 +-7.100945 +-7.097143 +-7.093340 +-7.089538 +-7.085736 +-7.081933 +-7.078131 +-7.074328 +-7.070526 +-7.066724 +-7.062921 +-7.059119 +-7.055317 +-7.051514 +-7.047712 +-7.043909 +-7.040107 +-7.036305 +-7.032502 +-7.028700 +-7.024897 +-7.021095 +-7.017293 +-7.013490 +-7.009688 +-7.005886 +-7.002083 +-6.998281 +-6.994478 +-6.990676 +-6.986874 +-6.983071 +-6.979269 +-6.975467 +-6.971664 +-6.967862 +-6.964059 +-6.960257 +-6.956455 +-6.952652 +-6.948850 +-6.945048 +-6.941245 +-6.937443 +-6.933640 +-6.929838 +-6.926036 +-6.922233 +-6.918431 +-6.914628 +-6.910826 +-6.907024 +-6.903221 +-6.899419 +-6.895617 +-6.891814 +-6.888012 +-6.884209 +-6.880407 +-6.876605 +-6.872802 +-6.869000 +-6.865198 +-6.861395 +-6.857593 +-6.853790 +-6.849988 +-6.846186 +-6.842383 +-6.838581 +-6.834778 +-6.830976 +-6.827174 +-6.823371 +-6.819569 +-6.815767 +-6.811964 +-6.808162 +-6.804359 +-6.800557 +-6.796755 +-6.792952 +-6.789150 +-6.785348 +-6.781545 +-6.777743 +-6.773940 +-6.770138 +-6.766336 +-6.762533 +-6.758731 +-6.754928 +-6.751126 +-6.747324 +-6.743521 +-6.739719 +-6.735917 +-6.732114 +-6.728312 +-6.724509 +-6.720707 +-6.716905 +-6.713102 +-6.709300 +-6.705498 +-6.701695 +-6.697893 +-6.694090 +-6.690288 +-6.686486 +-6.682683 +-6.678881 +-6.675079 +-6.671276 +-6.667474 +-6.663671 +-6.659869 +-6.656067 +-6.652264 +-6.648462 +-6.644659 +-6.640857 +-6.637055 +-6.633252 +-6.629450 +-6.625648 +-6.621845 +-6.618043 +-6.614240 +-6.610438 +-6.606636 +-6.602833 +-6.599031 +-6.595229 +-6.591426 +-6.587624 +-6.583821 +-6.580019 +-6.576217 +-6.572414 +-6.568612 +-6.564809 +-6.561007 +-6.557205 +-6.553402 +-6.549600 +-6.545798 +-6.541995 +-6.538193 +-6.534390 +-6.530588 +-6.526786 +-6.522983 +-6.519181 +-6.515379 +-6.511576 +-6.507774 +-6.503971 +-6.500169 +-6.496367 +-6.492564 +-6.488762 +-6.484959 +-6.481157 +-6.477355 +-6.473552 +-6.469750 +-6.465948 +-6.462145 +-6.458343 +-6.454540 +-6.450738 +-6.446936 +-6.443133 +-6.439331 +-6.435529 +-6.431726 +-6.427924 +-6.424121 +-6.420319 +-6.416517 +-6.412714 +-6.408912 +-6.405110 +-6.401307 +-6.397505 +-6.393702 +-6.389900 +-6.386098 +-6.382295 +-6.378493 +-6.374690 +-6.370888 +-6.367086 +-6.363283 +-6.359481 +-6.355679 +-6.351876 +-6.348074 +-6.344271 +-6.340469 +-6.336667 +-6.332864 +-6.329062 +-6.325260 +-6.321457 +-6.317655 +-6.313852 +-6.310050 +-6.306248 +-6.302445 +-6.298643 +-6.294840 +-6.291038 +-6.287236 +-6.283433 +-6.279631 +-6.275829 +-6.272026 +-6.268224 +-6.264421 +-6.260619 +-6.256817 +-6.253014 +-6.249212 +-6.245410 +-6.241607 +-6.237805 +-6.234002 +-6.230200 +-6.226398 +-6.222595 +-6.218793 +-6.214990 +-6.211188 +-6.207386 +-6.203583 +-6.199781 +-6.195979 +-6.192176 +-6.188374 +-6.184571 +-6.180769 +-6.176967 +-6.173164 +-6.169362 +-6.165560 +-6.161757 +-6.157955 +-6.154152 +-6.150350 +-6.146548 +-6.142745 +-6.138943 +-6.135141 +-6.131338 +-6.127536 +-6.123733 +-6.119931 +-6.116129 +-6.112326 +-6.108524 +-6.104721 +-6.100919 +-6.097117 +-6.093314 +-6.089512 +-6.085710 +-6.081907 +-6.078105 +-6.074302 +-6.070500 +-6.066698 +-6.062895 +-6.059093 +-6.055291 +-6.051488 +-6.047686 +-6.043883 +-6.040081 +-6.036279 +-6.032476 +-6.028674 +-6.024871 +-6.021069 +-6.017267 +-6.013464 +-6.009662 +-6.005860 +-6.002057 +-5.998255 +-5.994452 +-5.990650 +-5.986848 +-5.983045 +-5.979243 +-5.975441 +-5.971638 +-5.967836 +-5.964033 +-5.960231 +-5.956429 +-5.952626 +-5.948824 +-5.945022 +-5.941219 +-5.937417 +-5.933614 +-5.929812 +-5.926010 +-5.922207 +-5.918405 +-5.914602 +-5.910800 +-5.906998 +-5.903195 +-5.899393 +-5.895591 +-5.891788 +-5.887986 +-5.884183 +-5.880381 +-5.876579 +-5.872776 +-5.868974 +-5.865172 +-5.861369 +-5.857567 +-5.853764 +-5.849962 +-5.846160 +-5.842357 +-5.838555 +-5.834752 +-5.830950 +-5.827148 +-5.823345 +-5.819543 +-5.815741 +-5.811938 +-5.808136 +-5.804333 +-5.800531 +-5.796729 +-5.792926 +-5.789124 +-5.785322 +-5.781519 +-5.777717 +-5.773914 +-5.770112 +-5.766310 +-5.762507 +-5.758705 +-5.754902 +-5.751100 +-5.747298 +-5.743495 +-5.739693 +-5.735891 +-5.732088 +-5.728286 +-5.724483 +-5.720681 +-5.716879 +-5.713076 +-5.709274 +-5.705472 +-5.701669 +-5.697867 +-5.694064 +-5.690262 +-5.686460 +-5.682657 +-5.678855 +-5.675053 +-5.671250 +-5.667448 +-5.663645 +-5.659843 +-5.656041 +-5.652238 +-5.648436 +-5.644633 +-5.640831 +-5.637029 +-5.633226 +-5.629424 +-5.625622 +-5.621819 +-5.618017 +-5.614214 +-5.610412 +-5.606610 +-5.602807 +-5.599005 +-5.595203 +-5.591400 +-5.587598 +-5.583795 +-5.579993 +-5.576191 +-5.572388 +-5.568586 +-5.564783 +-5.560981 +-5.557179 +-5.553376 +-5.549574 +-5.545772 +-5.541969 +-5.538167 +-5.534364 +-5.530562 +-5.526760 +-5.522957 +-5.519155 +-5.515353 +-5.511550 +-5.507748 +-5.503945 +-5.500143 +-5.496341 +-5.492538 +-5.488736 +-5.484933 +-5.481131 +-5.477329 +-5.473526 +-5.469724 +-5.465922 +-5.462119 +-5.458317 +-5.454514 +-5.450712 +-5.446910 +-5.443107 +-5.439305 +-5.435503 +-5.431700 +-5.427898 +-5.424095 +-5.420293 +-5.416491 +-5.412688 +-5.408886 +-5.405084 +-5.401281 +-5.397479 +-5.393676 +-5.389874 +-5.386072 +-5.382269 +-5.378467 +-5.374664 +-5.370862 +-5.367060 +-5.363257 +-5.359455 +-5.355653 +-5.351850 +-5.348048 +-5.344245 +-5.340443 +-5.336641 +-5.332838 +-5.329036 +-5.325234 +-5.321431 +-5.317629 +-5.313826 +-5.310024 +-5.306222 +-5.302419 +-5.298617 +-5.294814 +-5.291012 +-5.287210 +-5.283407 +-5.279605 +-5.275803 +-5.272000 +-5.268198 +-5.264395 +-5.260593 +-5.256791 +-5.252988 +-5.249186 +-5.245384 +-5.241581 +-5.237779 +-5.233976 +-5.230174 +-5.226372 +-5.222569 +-5.218767 +-5.214964 +-5.211162 +-5.207360 +-5.203557 +-5.199755 +-5.195953 +-5.192150 +-5.188348 +-5.184545 +-5.180743 +-5.176941 +-5.173138 +-5.169336 +-5.165534 +-5.161731 +-5.157929 +-5.154126 +-5.150324 +-5.146522 +-5.142719 +-5.138917 +-5.135115 +-5.131312 +-5.127510 +-5.123707 +-5.119905 +-5.116103 +-5.112300 +-5.108498 +-5.104695 +-5.100893 +-5.097091 +-5.093288 +-5.089486 +-5.085684 +-5.081881 +-5.078079 +-5.074276 +-5.070474 +-5.066672 +-5.062869 +-5.059067 +-5.055265 +-5.051462 +-5.047660 +-5.043857 +-5.040055 +-5.036253 +-5.032450 +-5.028648 +-5.024845 +-5.021043 +-5.017241 +-5.013438 +-5.009636 +-5.005834 +-5.002031 +-4.998229 +-4.994426 +-4.990624 +-4.986822 +-4.983019 +-4.979217 +-4.975415 +-4.971612 +-4.967810 +-4.964007 +-4.960205 +-4.956403 +-4.952600 +-4.948798 +-4.944995 +-4.941193 +-4.937391 +-4.933588 +-4.929786 +-4.925984 +-4.922181 +-4.918379 +-4.914576 +-4.910774 +-4.906972 +-4.903169 +-4.899367 +-4.895565 +-4.891762 +-4.887960 +-4.884157 +-4.880355 +-4.876553 +-4.872750 +-4.868948 +-4.865146 +-4.861343 +-4.857541 +-4.853738 +-4.849936 +-4.846134 +-4.842331 +-4.838529 +-4.834726 +-4.830924 +-4.827122 +-4.823319 +-4.819517 +-4.815715 +-4.811912 +-4.808110 +-4.804307 +-4.800505 +-4.796703 +-4.792900 +-4.789098 +-4.785296 +-4.781493 +-4.777691 +-4.773888 +-4.770086 +-4.766284 +-4.762481 +-4.758679 +-4.754876 +-4.751074 +-4.747272 +-4.743469 +-4.739667 +-4.735865 +-4.732062 +-4.728260 +-4.724457 +-4.720655 +-4.716853 +-4.713050 +-4.709248 +-4.705446 +-4.701643 +-4.697841 +-4.694038 +-4.690236 +-4.686434 +-4.682631 +-4.678829 +-4.675027 +-4.671224 +-4.667422 +-4.663619 +-4.659817 +-4.656015 +-4.652212 +-4.648410 +-4.644607 +-4.640805 +-4.637003 +-4.633200 +-4.629398 +-4.625596 +-4.621793 +-4.617991 +-4.614188 +-4.610386 +-4.606584 +-4.602781 +-4.598979 +-4.595177 +-4.591374 +-4.587572 +-4.583769 +-4.579967 +-4.576165 +-4.572362 +-4.568560 +-4.564757 +-4.560955 +-4.557153 +-4.553350 +-4.549548 +-4.545746 +-4.541943 +-4.538141 +-4.534338 +-4.530536 +-4.526734 +-4.522931 +-4.519129 +-4.515327 +-4.511524 +-4.507722 +-4.503919 +-4.500117 +-4.496315 +-4.492512 +-4.488710 +-4.484907 +-4.481105 +-4.477303 +-4.473500 +-4.469698 +-4.465896 +-4.462093 +-4.458291 +-4.454488 +-4.450686 +-4.446884 +-4.443081 +-4.439279 +-4.435477 +-4.431674 +-4.427872 +-4.424069 +-4.420267 +-4.416465 +-4.412662 +-4.408860 +-4.405058 +-4.401255 +-4.397453 +-4.393650 +-4.389848 +-4.386046 +-4.382243 +-4.378441 +-4.374638 +-4.370836 +-4.367034 +-4.363231 +-4.359429 +-4.355627 +-4.351824 +-4.348022 +-4.344219 +-4.340417 +-4.336615 +-4.332812 +-4.329010 +-4.325208 +-4.321405 +-4.317603 +-4.313800 +-4.309998 +-4.306196 +-4.302393 +-4.298591 +-4.294788 +-4.290986 +-4.287184 +-4.283381 +-4.279579 +-4.275777 +-4.271974 +-4.268172 +-4.264369 +-4.260567 +-4.256765 +-4.252962 +-4.249160 +-4.245358 +-4.241555 +-4.237753 +-4.233950 +-4.230148 +-4.226346 +-4.222543 +-4.218741 +-4.214938 +-4.211136 +-4.207334 +-4.203531 +-4.199729 +-4.195927 +-4.192124 +-4.188322 +-4.184519 +-4.180717 +-4.176915 +-4.173112 +-4.169310 +-4.165508 +-4.161705 +-4.157903 +-4.154100 +-4.150298 +-4.146496 +-4.142693 +-4.138891 +-4.135089 +-4.131286 +-4.127484 +-4.123681 +-4.119879 +-4.116077 +-4.112274 +-4.108472 +-4.104669 +-4.100867 +-4.097065 +-4.093262 +-4.089460 +-4.085658 +-4.081855 +-4.078053 +-4.074250 +-4.070448 +-4.066646 +-4.062843 +-4.059041 +-4.055239 +-4.051436 +-4.047634 +-4.043831 +-4.040029 +-4.036227 +-4.032424 +-4.028622 +-4.024819 +-4.021017 +-4.017215 +-4.013412 +-4.009610 +-4.005808 +-4.002005 +-3.998203 +-3.994400 +-3.990598 +-3.986796 +-3.982993 +-3.979191 +-3.975389 +-3.971586 +-3.967784 +-3.963981 +-3.960179 +-3.956377 +-3.952574 +-3.948772 +-3.944969 +-3.941167 +-3.937365 +-3.933562 +-3.929760 +-3.925958 +-3.922155 +-3.918353 +-3.914550 +-3.910748 +-3.906946 +-3.903143 +-3.899341 +-3.895539 +-3.891736 +-3.887934 +-3.884131 +-3.880329 +-3.876527 +-3.872724 +-3.868922 +-3.865120 +-3.861317 +-3.857515 +-3.853712 +-3.849910 +-3.846108 +-3.842305 +-3.838503 +-3.834700 +-3.830898 +-3.827096 +-3.823293 +-3.819491 +-3.815689 +-3.811886 +-3.808084 +-3.804281 +-3.800479 +-3.796677 +-3.792874 +-3.789072 +-3.785270 +-3.781467 +-3.777665 +-3.773862 +-3.770060 +-3.766258 +-3.762455 +-3.758653 +-3.754850 +-3.751048 +-3.747246 +-3.743443 +-3.739641 +-3.735839 +-3.732036 +-3.728234 +-3.724431 +-3.720629 +-3.716827 +-3.713024 +-3.709222 +-3.705420 +-3.701617 +-3.697815 +-3.694012 +-3.690210 +-3.686408 +-3.682605 +-3.678803 +-3.675001 +-3.671198 +-3.667396 +-3.663593 +-3.659791 +-3.655989 +-3.652186 +-3.648384 +-3.644581 +-3.640779 +-3.636977 +-3.633174 +-3.629372 +-3.625570 +-3.621767 +-3.617965 +-3.614162 +-3.610360 +-3.606558 +-3.602755 +-3.598953 +-3.595151 +-3.591348 +-3.587546 +-3.583743 +-3.579941 +-3.576139 +-3.572336 +-3.568534 +-3.564731 +-3.560929 +-3.557127 +-3.553324 +-3.549522 +-3.545720 +-3.541917 +-3.538115 +-3.534312 +-3.530510 +-3.526708 +-3.522905 +-3.519103 +-3.515301 +-3.511498 +-3.507696 +-3.503893 +-3.500091 +-3.496289 +-3.492486 +-3.488684 +-3.484881 +-3.481079 +-3.477277 +-3.473474 +-3.469672 +-3.465870 +-3.462067 +-3.458265 +-3.454462 +-3.450660 +-3.446858 +-3.443055 +-3.439253 +-3.435451 +-3.431648 +-3.427846 +-3.424043 +-3.420241 +-3.416439 +-3.412636 +-3.408834 +-3.405032 +-3.401229 +-3.397427 +-3.393624 +-3.389822 +-3.386020 +-3.382217 +-3.378415 +-3.374612 +-3.370810 +-3.367008 +-3.363205 +-3.359403 +-3.355601 +-3.351798 +-3.347996 +-3.344193 +-3.340391 +-3.336589 +-3.332786 +-3.328984 +-3.325182 +-3.321379 +-3.317577 +-3.313774 +-3.309972 +-3.306170 +-3.302367 +-3.298565 +-3.294762 +-3.290960 +-3.287158 +-3.283355 +-3.279553 +-3.275751 +-3.271948 +-3.268146 +-3.264343 +-3.260541 +-3.256739 +-3.252936 +-3.249134 +-3.245332 +-3.241529 +-3.237727 +-3.233924 +-3.230122 +-3.226320 +-3.222517 +-3.218715 +-3.214912 +-3.211110 +-3.207308 +-3.203505 +-3.199703 +-3.195901 +-3.192098 +-3.188296 +-3.184493 +-3.180691 +-3.176889 +-3.173086 +-3.169284 +-3.165482 +-3.161679 +-3.157877 +-3.154074 +-3.150272 +-3.146470 +-3.142667 +-3.138865 +-3.135063 +-3.131260 +-3.127458 +-3.123655 +-3.119853 +-3.116051 +-3.112248 +-3.108446 +-3.104643 +-3.100841 +-3.097039 +-3.093236 +-3.089434 +-3.085632 +-3.081829 +-3.078027 +-3.074224 +-3.070422 +-3.066620 +-3.062817 +-3.059015 +-3.055213 +-3.051410 +-3.047608 +-3.043805 +-3.040003 +-3.036201 +-3.032398 +-3.028596 +-3.024793 +-3.020991 +-3.017189 +-3.013386 +-3.009584 +-3.005782 +-3.001979 +-2.998177 +-2.994374 +-2.990572 +-2.986770 +-2.982967 +-2.979165 +-2.975363 +-2.971560 +-2.967758 +-2.963955 +-2.960153 +-2.956351 +-2.952548 +-2.948746 +-2.944943 +-2.941141 +-2.937339 +-2.933536 +-2.929734 +-2.925932 +-2.922129 +-2.918327 +-2.914524 +-2.910722 +-2.906920 +-2.903117 +-2.899315 +-2.895513 +-2.891710 +-2.887908 +-2.884105 +-2.880303 +-2.876501 +-2.872698 +-2.868896 +-2.865094 +-2.861291 +-2.857489 +-2.853686 +-2.849884 +-2.846082 +-2.842279 +-2.838477 +-2.834674 +-2.830872 +-2.827070 +-2.823267 +-2.819465 +-2.815663 +-2.811860 +-2.808058 +-2.804255 +-2.800453 +-2.796651 +-2.792848 +-2.789046 +-2.785244 +-2.781441 +-2.777639 +-2.773836 +-2.770034 +-2.766232 +-2.762429 +-2.758627 +-2.754824 +-2.751022 +-2.747220 +-2.743417 +-2.739615 +-2.735813 +-2.732010 +-2.728208 +-2.724405 +-2.720603 +-2.716801 +-2.712998 +-2.709196 +-2.705394 +-2.701591 +-2.697789 +-2.693986 +-2.690184 +-2.686382 +-2.682579 +-2.678777 +-2.674974 +-2.671172 +-2.667370 +-2.663567 +-2.659765 +-2.655963 +-2.652160 +-2.648358 +-2.644555 +-2.640753 +-2.636951 +-2.633148 +-2.629346 +-2.625544 +-2.621741 +-2.617939 +-2.614136 +-2.610334 +-2.606532 +-2.602729 +-2.598927 +-2.595125 +-2.591322 +-2.587520 +-2.583717 +-2.579915 +-2.576113 +-2.572310 +-2.568508 +-2.564705 +-2.560903 +-2.557101 +-2.553298 +-2.549496 +-2.545694 +-2.541891 +-2.538089 +-2.534286 +-2.530484 +-2.526682 +-2.522879 +-2.519077 +-2.515275 +-2.511472 +-2.507670 +-2.503867 +-2.500065 +-2.496263 +-2.492460 +-2.488658 +-2.484855 +-2.481053 +-2.477251 +-2.473448 +-2.469646 +-2.465844 +-2.462041 +-2.458239 +-2.454436 +-2.450634 +-2.446832 +-2.443029 +-2.439227 +-2.435425 +-2.431622 +-2.427820 +-2.424017 +-2.420215 +-2.416413 +-2.412610 +-2.408808 +-2.405006 +-2.401203 +-2.397401 +-2.393598 +-2.389796 +-2.385994 +-2.382191 +-2.378389 +-2.374586 +-2.370784 +-2.366982 +-2.363179 +-2.359377 +-2.355575 +-2.351772 +-2.347970 +-2.344167 +-2.340365 +-2.336563 +-2.332760 +-2.328958 +-2.325156 +-2.321353 +-2.317551 +-2.313748 +-2.309946 +-2.306144 +-2.302341 +-2.298539 +-2.294736 +-2.290934 +-2.287132 +-2.283329 +-2.279527 +-2.275725 +-2.271922 +-2.268120 +-2.264317 +-2.260515 +-2.256713 +-2.252910 +-2.249108 +-2.245306 +-2.241503 +-2.237701 +-2.233898 +-2.230096 +-2.226294 +-2.222491 +-2.218689 +-2.214886 +-2.211084 +-2.207282 +-2.203479 +-2.199677 +-2.195875 +-2.192072 +-2.188270 +-2.184467 +-2.180665 +-2.176863 +-2.173060 +-2.169258 +-2.165456 +-2.161653 +-2.157851 +-2.154048 +-2.150246 +-2.146444 +-2.142641 +-2.138839 +-2.135037 +-2.131234 +-2.127432 +-2.123629 +-2.119827 +-2.116025 +-2.112222 +-2.108420 +-2.104617 +-2.100815 +-2.097013 +-2.093210 +-2.089408 +-2.085606 +-2.081803 +-2.078001 +-2.074198 +-2.070396 +-2.066594 +-2.062791 +-2.058989 +-2.055187 +-2.051384 +-2.047582 +-2.043779 +-2.039977 +-2.036175 +-2.032372 +-2.028570 +-2.024767 +-2.020965 +-2.017163 +-2.013360 +-2.009558 +-2.005756 +-2.001953 +-1.998151 +-1.994348 +-1.990546 +-1.986744 +-1.982941 +-1.979139 +-1.975337 +-1.971534 +-1.967732 +-1.963929 +-1.960127 +-1.956325 +-1.952522 +-1.948720 +-1.944917 +-1.941115 +-1.937313 +-1.933510 +-1.929708 +-1.925906 +-1.922103 +-1.918301 +-1.914498 +-1.910696 +-1.906894 +-1.903091 +-1.899289 +-1.895487 +-1.891684 +-1.887882 +-1.884079 +-1.880277 +-1.876475 +-1.872672 +-1.868870 +-1.865068 +-1.861265 +-1.857463 +-1.853660 +-1.849858 +-1.846056 +-1.842253 +-1.838451 +-1.834648 +-1.830846 +-1.827044 +-1.823241 +-1.819439 +-1.815637 +-1.811834 +-1.808032 +-1.804229 +-1.800427 +-1.796625 +-1.792822 +-1.789020 +-1.785218 +-1.781415 +-1.777613 +-1.773810 +-1.770008 +-1.766206 +-1.762403 +-1.758601 +-1.754798 +-1.750996 +-1.747194 +-1.743391 +-1.739589 +-1.735787 +-1.731984 +-1.728182 +-1.724379 +-1.720577 +-1.716775 +-1.712972 +-1.709170 +-1.705368 +-1.701565 +-1.697763 +-1.693960 +-1.690158 +-1.686356 +-1.682553 +-1.678751 +-1.674948 +-1.671146 +-1.667344 +-1.663541 +-1.659739 +-1.655937 +-1.652134 +-1.648332 +-1.644529 +-1.640727 +-1.636925 +-1.633122 +-1.629320 +-1.625518 +-1.621715 +-1.617913 +-1.614110 +-1.610308 +-1.606506 +-1.602703 +-1.598901 +-1.595099 +-1.591296 +-1.587494 +-1.583691 +-1.579889 +-1.576087 +-1.572284 +-1.568482 +-1.564679 +-1.560877 +-1.557075 +-1.553272 +-1.549470 +-1.545668 +-1.541865 +-1.538063 +-1.534260 +-1.530458 +-1.526656 +-1.522853 +-1.519051 +-1.515249 +-1.511446 +-1.507644 +-1.503841 +-1.500039 +-1.496237 +-1.492434 +-1.488632 +-1.484829 +-1.481027 +-1.477225 +-1.473422 +-1.469620 +-1.465818 +-1.462015 +-1.458213 +-1.454410 +-1.450608 +-1.446806 +-1.443003 +-1.439201 +-1.435399 +-1.431596 +-1.427794 +-1.423991 +-1.420189 +-1.416387 +-1.412584 +-1.408782 +-1.404979 +-1.401177 +-1.397375 +-1.393572 +-1.389770 +-1.385968 +-1.382165 +-1.378363 +-1.374560 +-1.370758 +-1.366956 +-1.363153 +-1.359351 +-1.355549 +-1.351746 +-1.347944 +-1.344141 +-1.340339 +-1.336537 +-1.332734 +-1.328932 +-1.325130 +-1.321327 +-1.317525 +-1.313722 +-1.309920 +-1.306118 +-1.302315 +-1.298513 +-1.294710 +-1.290908 +-1.287106 +-1.283303 +-1.279501 +-1.275699 +-1.271896 +-1.268094 +-1.264291 +-1.260489 +-1.256687 +-1.252884 +-1.249082 +-1.245280 +-1.241477 +-1.237675 +-1.233872 +-1.230070 +-1.226268 +-1.222465 +-1.218663 +-1.214860 +-1.211058 +-1.207256 +-1.203453 +-1.199651 +-1.195849 +-1.192046 +-1.188244 +-1.184441 +-1.180639 +-1.176837 +-1.173034 +-1.169232 +-1.165430 +-1.161627 +-1.157825 +-1.154022 +-1.150220 +-1.146418 +-1.142615 +-1.138813 +-1.135011 +-1.131208 +-1.127406 +-1.123603 +-1.119801 +-1.115999 +-1.112196 +-1.108394 +-1.104591 +-1.100789 +-1.096987 +-1.093184 +-1.089382 +-1.085580 +-1.081777 +-1.077975 +-1.074172 +-1.070370 +-1.066568 +-1.062765 +-1.058963 +-1.055161 +-1.051358 +-1.047556 +-1.043753 +-1.039951 +-1.036149 +-1.032346 +-1.028544 +-1.024741 +-1.020939 +-1.017137 +-1.013334 +-1.009532 +-1.005730 +-1.001927 +-0.998125 +-0.994322 +-0.990520 +-0.986718 +-0.982915 +-0.979113 +-0.975311 +-0.971508 +-0.967706 +-0.963903 +-0.960101 +-0.956299 +-0.952496 +-0.948694 +-0.944891 +-0.941089 +-0.937287 +-0.933484 +-0.929682 +-0.925880 +-0.922077 +-0.918275 +-0.914472 +-0.910670 +-0.906868 +-0.903065 +-0.899263 +-0.895461 +-0.891658 +-0.887856 +-0.884053 +-0.880251 +-0.876449 +-0.872646 +-0.868844 +-0.865042 +-0.861239 +-0.857437 +-0.853634 +-0.849832 +-0.846030 +-0.842227 +-0.838425 +-0.834622 +-0.830820 +-0.827018 +-0.823215 +-0.819413 +-0.815611 +-0.811808 +-0.808006 +-0.804203 +-0.800401 +-0.796599 +-0.792796 +-0.788994 +-0.785192 +-0.781389 +-0.777587 +-0.773784 +-0.769982 +-0.766180 +-0.762377 +-0.758575 +-0.754772 +-0.750970 +-0.747168 +-0.743365 +-0.739563 +-0.735761 +-0.731958 +-0.728156 +-0.724353 +-0.720551 +-0.716749 +-0.712946 +-0.709144 +-0.705342 +-0.701539 +-0.697737 +-0.693934 +-0.690132 +-0.686330 +-0.682527 +-0.678725 +-0.674922 +-0.671120 +-0.667318 +-0.663515 +-0.659713 +-0.655911 +-0.652108 +-0.648306 +-0.644503 +-0.640701 +-0.636899 +-0.633096 +-0.629294 +-0.625492 +-0.621689 +-0.617887 +-0.614084 +-0.610282 +-0.606480 +-0.602677 +-0.598875 +-0.595073 +-0.591270 +-0.587468 +-0.583665 +-0.579863 +-0.576061 +-0.572258 +-0.568456 +-0.564653 +-0.560851 +-0.557049 +-0.553246 +-0.549444 +-0.545642 +-0.541839 +-0.538037 +-0.534234 +-0.530432 +-0.526630 +-0.522827 +-0.519025 +-0.515223 +-0.511420 +-0.507618 +-0.503815 +-0.500013 +-0.496211 +-0.492408 +-0.488606 +-0.484803 +-0.481001 +-0.477199 +-0.473396 +-0.469594 +-0.465792 +-0.461989 +-0.458187 +-0.454384 +-0.450582 +-0.446780 +-0.442977 +-0.439175 +-0.435373 +-0.431570 +-0.427768 +-0.423965 +-0.420163 +-0.416361 +-0.412558 +-0.408756 +-0.404953 +-0.401151 +-0.397349 +-0.393546 +-0.389744 +-0.385942 +-0.382139 +-0.378337 +-0.374534 +-0.370732 +-0.366930 +-0.363127 +-0.359325 +-0.355523 +-0.351720 +-0.347918 +-0.344115 +-0.340313 +-0.336511 +-0.332708 +-0.328906 +-0.325104 +-0.321301 +-0.317499 +-0.313696 +-0.309894 +-0.306092 +-0.302289 +-0.298487 +-0.294684 +-0.290882 +-0.287080 +-0.283277 +-0.279475 +-0.275673 +-0.271870 +-0.268068 +-0.264265 +-0.260463 +-0.256661 +-0.252858 +-0.249056 +-0.245254 +-0.241451 +-0.237649 +-0.233846 +-0.230044 +-0.226242 +-0.222439 +-0.218637 +-0.214834 +-0.211032 +-0.207230 +-0.203427 +-0.199625 +-0.195823 +-0.192020 +-0.188218 +-0.184415 +-0.180613 +-0.176811 +-0.173008 +-0.169206 +-0.165404 +-0.161601 +-0.157799 +-0.153996 +-0.150194 +-0.146392 +-0.142589 +-0.138787 +-0.134984 +-0.131182 +-0.127380 +-0.123577 +-0.119775 +-0.115973 +-0.112170 +-0.108368 +-0.104565 +-0.100763 +-0.096961 +-0.093158 +-0.089356 +-0.085554 +-0.081751 +-0.077949 +-0.074146 +-0.070344 +-0.066542 +-0.062739 +-0.058937 +-0.055135 +-0.051332 +-0.047530 +-0.043727 +-0.039925 +-0.036123 +-0.032320 +-0.028518 +-0.024715 +-0.020913 +-0.017111 +-0.013308 +-0.009506 +-0.005704 +-0.001901 +0.001901 +0.005704 +0.009506 +0.013308 +0.017111 +0.020913 +0.024715 +0.028518 +0.032320 +0.036123 +0.039925 +0.043727 +0.047530 +0.051332 +0.055135 +0.058937 +0.062739 +0.066542 +0.070344 +0.074146 +0.077949 +0.081751 +0.085554 +0.089356 +0.093158 +0.096961 +0.100763 +0.104565 +0.108368 +0.112170 +0.115973 +0.119775 +0.123577 +0.127380 +0.131182 +0.134984 +0.138787 +0.142589 +0.146392 +0.150194 +0.153996 +0.157799 +0.161601 +0.165404 +0.169206 +0.173008 +0.176811 +0.180613 +0.184415 +0.188218 +0.192020 +0.195823 +0.199625 +0.203427 +0.207230 +0.211032 +0.214834 +0.218637 +0.222439 +0.226242 +0.230044 +0.233846 +0.237649 +0.241451 +0.245254 +0.249056 +0.252858 +0.256661 +0.260463 +0.264265 +0.268068 +0.271870 +0.275673 +0.279475 +0.283277 +0.287080 +0.290882 +0.294684 +0.298487 +0.302289 +0.306092 +0.309894 +0.313696 +0.317499 +0.321301 +0.325104 +0.328906 +0.332708 +0.336511 +0.340313 +0.344115 +0.347918 +0.351720 +0.355523 +0.359325 +0.363127 +0.366930 +0.370732 +0.374534 +0.378337 +0.382139 +0.385942 +0.389744 +0.393546 +0.397349 +0.401151 +0.404953 +0.408756 +0.412558 +0.416361 +0.420163 +0.423965 +0.427768 +0.431570 +0.435373 +0.439175 +0.442977 +0.446780 +0.450582 +0.454384 +0.458187 +0.461989 +0.465792 +0.469594 +0.473396 +0.477199 +0.481001 +0.484803 +0.488606 +0.492408 +0.496211 +0.500013 +0.503815 +0.507618 +0.511420 +0.515223 +0.519025 +0.522827 +0.526630 +0.530432 +0.534234 +0.538037 +0.541839 +0.545642 +0.549444 +0.553246 +0.557049 +0.560851 +0.564653 +0.568456 +0.572258 +0.576061 +0.579863 +0.583665 +0.587468 +0.591270 +0.595073 +0.598875 +0.602677 +0.606480 +0.610282 +0.614084 +0.617887 +0.621689 +0.625492 +0.629294 +0.633096 +0.636899 +0.640701 +0.644503 +0.648306 +0.652108 +0.655911 +0.659713 +0.663515 +0.667318 +0.671120 +0.674922 +0.678725 +0.682527 +0.686330 +0.690132 +0.693934 +0.697737 +0.701539 +0.705342 +0.709144 +0.712946 +0.716749 +0.720551 +0.724353 +0.728156 +0.731958 +0.735761 +0.739563 +0.743365 +0.747168 +0.750970 +0.754772 +0.758575 +0.762377 +0.766180 +0.769982 +0.773784 +0.777587 +0.781389 +0.785192 +0.788994 +0.792796 +0.796599 +0.800401 +0.804203 +0.808006 +0.811808 +0.815611 +0.819413 +0.823215 +0.827018 +0.830820 +0.834622 +0.838425 +0.842227 +0.846030 +0.849832 +0.853634 +0.857437 +0.861239 +0.865042 +0.868844 +0.872646 +0.876449 +0.880251 +0.884053 +0.887856 +0.891658 +0.895461 +0.899263 +0.903065 +0.906868 +0.910670 +0.914472 +0.918275 +0.922077 +0.925880 +0.929682 +0.933484 +0.937287 +0.941089 +0.944891 +0.948694 +0.952496 +0.956299 +0.960101 +0.963903 +0.967706 +0.971508 +0.975311 +0.979113 +0.982915 +0.986718 +0.990520 +0.994322 +0.998125 +1.001927 +1.005730 +1.009532 +1.013334 +1.017137 +1.020939 +1.024741 +1.028544 +1.032346 +1.036149 +1.039951 +1.043753 +1.047556 +1.051358 +1.055161 +1.058963 +1.062765 +1.066568 +1.070370 +1.074172 +1.077975 +1.081777 +1.085580 +1.089382 +1.093184 +1.096987 +1.100789 +1.104591 +1.108394 +1.112196 +1.115999 +1.119801 +1.123603 +1.127406 +1.131208 +1.135011 +1.138813 +1.142615 +1.146418 +1.150220 +1.154022 +1.157825 +1.161627 +1.165430 +1.169232 +1.173034 +1.176837 +1.180639 +1.184441 +1.188244 +1.192046 +1.195849 +1.199651 +1.203453 +1.207256 +1.211058 +1.214860 +1.218663 +1.222465 +1.226268 +1.230070 +1.233872 +1.237675 +1.241477 +1.245280 +1.249082 +1.252884 +1.256687 +1.260489 +1.264291 +1.268094 +1.271896 +1.275699 +1.279501 +1.283303 +1.287106 +1.290908 +1.294710 +1.298513 +1.302315 +1.306118 +1.309920 +1.313722 +1.317525 +1.321327 +1.325130 +1.328932 +1.332734 +1.336537 +1.340339 +1.344141 +1.347944 +1.351746 +1.355549 +1.359351 +1.363153 +1.366956 +1.370758 +1.374560 +1.378363 +1.382165 +1.385968 +1.389770 +1.393572 +1.397375 +1.401177 +1.404979 +1.408782 +1.412584 +1.416387 +1.420189 +1.423991 +1.427794 +1.431596 +1.435399 +1.439201 +1.443003 +1.446806 +1.450608 +1.454410 +1.458213 +1.462015 +1.465818 +1.469620 +1.473422 +1.477225 +1.481027 +1.484829 +1.488632 +1.492434 +1.496237 +1.500039 +1.503841 +1.507644 +1.511446 +1.515249 +1.519051 +1.522853 +1.526656 +1.530458 +1.534260 +1.538063 +1.541865 +1.545668 +1.549470 +1.553272 +1.557075 +1.560877 +1.564679 +1.568482 +1.572284 +1.576087 +1.579889 +1.583691 +1.587494 +1.591296 +1.595099 +1.598901 +1.602703 +1.606506 +1.610308 +1.614110 +1.617913 +1.621715 +1.625518 +1.629320 +1.633122 +1.636925 +1.640727 +1.644529 +1.648332 +1.652134 +1.655937 +1.659739 +1.663541 +1.667344 +1.671146 +1.674948 +1.678751 +1.682553 +1.686356 +1.690158 +1.693960 +1.697763 +1.701565 +1.705368 +1.709170 +1.712972 +1.716775 +1.720577 +1.724379 +1.728182 +1.731984 +1.735787 +1.739589 +1.743391 +1.747194 +1.750996 +1.754798 +1.758601 +1.762403 +1.766206 +1.770008 +1.773810 +1.777613 +1.781415 +1.785218 +1.789020 +1.792822 +1.796625 +1.800427 +1.804229 +1.808032 +1.811834 +1.815637 +1.819439 +1.823241 +1.827044 +1.830846 +1.834648 +1.838451 +1.842253 +1.846056 +1.849858 +1.853660 +1.857463 +1.861265 +1.865068 +1.868870 +1.872672 +1.876475 +1.880277 +1.884079 +1.887882 +1.891684 +1.895487 +1.899289 +1.903091 +1.906894 +1.910696 +1.914498 +1.918301 +1.922103 +1.925906 +1.929708 +1.933510 +1.937313 +1.941115 +1.944917 +1.948720 +1.952522 +1.956325 +1.960127 +1.963929 +1.967732 +1.971534 +1.975337 +1.979139 +1.982941 +1.986744 +1.990546 +1.994348 +1.998151 +2.001953 +2.005756 +2.009558 +2.013360 +2.017163 +2.020965 +2.024767 +2.028570 +2.032372 +2.036175 +2.039977 +2.043779 +2.047582 +2.051384 +2.055187 +2.058989 +2.062791 +2.066594 +2.070396 +2.074198 +2.078001 +2.081803 +2.085606 +2.089408 +2.093210 +2.097013 +2.100815 +2.104617 +2.108420 +2.112222 +2.116025 +2.119827 +2.123629 +2.127432 +2.131234 +2.135037 +2.138839 +2.142641 +2.146444 +2.150246 +2.154048 +2.157851 +2.161653 +2.165456 +2.169258 +2.173060 +2.176863 +2.180665 +2.184467 +2.188270 +2.192072 +2.195875 +2.199677 +2.203479 +2.207282 +2.211084 +2.214886 +2.218689 +2.222491 +2.226294 +2.230096 +2.233898 +2.237701 +2.241503 +2.245306 +2.249108 +2.252910 +2.256713 +2.260515 +2.264317 +2.268120 +2.271922 +2.275725 +2.279527 +2.283329 +2.287132 +2.290934 +2.294736 +2.298539 +2.302341 +2.306144 +2.309946 +2.313748 +2.317551 +2.321353 +2.325156 +2.328958 +2.332760 +2.336563 +2.340365 +2.344167 +2.347970 +2.351772 +2.355575 +2.359377 +2.363179 +2.366982 +2.370784 +2.374586 +2.378389 +2.382191 +2.385994 +2.389796 +2.393598 +2.397401 +2.401203 +2.405006 +2.408808 +2.412610 +2.416413 +2.420215 +2.424017 +2.427820 +2.431622 +2.435425 +2.439227 +2.443029 +2.446832 +2.450634 +2.454436 +2.458239 +2.462041 +2.465844 +2.469646 +2.473448 +2.477251 +2.481053 +2.484855 +2.488658 +2.492460 +2.496263 +2.500065 +2.503867 +2.507670 +2.511472 +2.515275 +2.519077 +2.522879 +2.526682 +2.530484 +2.534286 +2.538089 +2.541891 +2.545694 +2.549496 +2.553298 +2.557101 +2.560903 +2.564705 +2.568508 +2.572310 +2.576113 +2.579915 +2.583717 +2.587520 +2.591322 +2.595125 +2.598927 +2.602729 +2.606532 +2.610334 +2.614136 +2.617939 +2.621741 +2.625544 +2.629346 +2.633148 +2.636951 +2.640753 +2.644555 +2.648358 +2.652160 +2.655963 +2.659765 +2.663567 +2.667370 +2.671172 +2.674974 +2.678777 +2.682579 +2.686382 +2.690184 +2.693986 +2.697789 +2.701591 +2.705394 +2.709196 +2.712998 +2.716801 +2.720603 +2.724405 +2.728208 +2.732010 +2.735813 +2.739615 +2.743417 +2.747220 +2.751022 +2.754824 +2.758627 +2.762429 +2.766232 +2.770034 +2.773836 +2.777639 +2.781441 +2.785244 +2.789046 +2.792848 +2.796651 +2.800453 +2.804255 +2.808058 +2.811860 +2.815663 +2.819465 +2.823267 +2.827070 +2.830872 +2.834674 +2.838477 +2.842279 +2.846082 +2.849884 +2.853686 +2.857489 +2.861291 +2.865094 +2.868896 +2.872698 +2.876501 +2.880303 +2.884105 +2.887908 +2.891710 +2.895513 +2.899315 +2.903117 +2.906920 +2.910722 +2.914524 +2.918327 +2.922129 +2.925932 +2.929734 +2.933536 +2.937339 +2.941141 +2.944943 +2.948746 +2.952548 +2.956351 +2.960153 +2.963955 +2.967758 +2.971560 +2.975363 +2.979165 +2.982967 +2.986770 +2.990572 +2.994374 +2.998177 +3.001979 +3.005782 +3.009584 +3.013386 +3.017189 +3.020991 +3.024793 +3.028596 +3.032398 +3.036201 +3.040003 +3.043805 +3.047608 +3.051410 +3.055213 +3.059015 +3.062817 +3.066620 +3.070422 +3.074224 +3.078027 +3.081829 +3.085632 +3.089434 +3.093236 +3.097039 +3.100841 +3.104643 +3.108446 +3.112248 +3.116051 +3.119853 +3.123655 +3.127458 +3.131260 +3.135063 +3.138865 +3.142667 +3.146470 +3.150272 +3.154074 +3.157877 +3.161679 +3.165482 +3.169284 +3.173086 +3.176889 +3.180691 +3.184493 +3.188296 +3.192098 +3.195901 +3.199703 +3.203505 +3.207308 +3.211110 +3.214912 +3.218715 +3.222517 +3.226320 +3.230122 +3.233924 +3.237727 +3.241529 +3.245332 +3.249134 +3.252936 +3.256739 +3.260541 +3.264343 +3.268146 +3.271948 +3.275751 +3.279553 +3.283355 +3.287158 +3.290960 +3.294762 +3.298565 +3.302367 +3.306170 +3.309972 +3.313774 +3.317577 +3.321379 +3.325182 +3.328984 +3.332786 +3.336589 +3.340391 +3.344193 +3.347996 +3.351798 +3.355601 +3.359403 +3.363205 +3.367008 +3.370810 +3.374612 +3.378415 +3.382217 +3.386020 +3.389822 +3.393624 +3.397427 +3.401229 +3.405032 +3.408834 +3.412636 +3.416439 +3.420241 +3.424043 +3.427846 +3.431648 +3.435451 +3.439253 +3.443055 +3.446858 +3.450660 +3.454462 +3.458265 +3.462067 +3.465870 +3.469672 +3.473474 +3.477277 +3.481079 +3.484881 +3.488684 +3.492486 +3.496289 +3.500091 +3.503893 +3.507696 +3.511498 +3.515301 +3.519103 +3.522905 +3.526708 +3.530510 +3.534312 +3.538115 +3.541917 +3.545720 +3.549522 +3.553324 +3.557127 +3.560929 +3.564731 +3.568534 +3.572336 +3.576139 +3.579941 +3.583743 +3.587546 +3.591348 +3.595151 +3.598953 +3.602755 +3.606558 +3.610360 +3.614162 +3.617965 +3.621767 +3.625570 +3.629372 +3.633174 +3.636977 +3.640779 +3.644581 +3.648384 +3.652186 +3.655989 +3.659791 +3.663593 +3.667396 +3.671198 +3.675001 +3.678803 +3.682605 +3.686408 +3.690210 +3.694012 +3.697815 +3.701617 +3.705420 +3.709222 +3.713024 +3.716827 +3.720629 +3.724431 +3.728234 +3.732036 +3.735839 +3.739641 +3.743443 +3.747246 +3.751048 +3.754850 +3.758653 +3.762455 +3.766258 +3.770060 +3.773862 +3.777665 +3.781467 +3.785270 +3.789072 +3.792874 +3.796677 +3.800479 +3.804281 +3.808084 +3.811886 +3.815689 +3.819491 +3.823293 +3.827096 +3.830898 +3.834700 +3.838503 +3.842305 +3.846108 +3.849910 +3.853712 +3.857515 +3.861317 +3.865120 +3.868922 +3.872724 +3.876527 +3.880329 +3.884131 +3.887934 +3.891736 +3.895539 +3.899341 +3.903143 +3.906946 +3.910748 +3.914550 +3.918353 +3.922155 +3.925958 +3.929760 +3.933562 +3.937365 +3.941167 +3.944969 +3.948772 +3.952574 +3.956377 +3.960179 +3.963981 +3.967784 +3.971586 +3.975389 +3.979191 +3.982993 +3.986796 +3.990598 +3.994400 +3.998203 +4.002005 +4.005808 +4.009610 +4.013412 +4.017215 +4.021017 +4.024819 +4.028622 +4.032424 +4.036227 +4.040029 +4.043831 +4.047634 +4.051436 +4.055239 +4.059041 +4.062843 +4.066646 +4.070448 +4.074250 +4.078053 +4.081855 +4.085658 +4.089460 +4.093262 +4.097065 +4.100867 +4.104669 +4.108472 +4.112274 +4.116077 +4.119879 +4.123681 +4.127484 +4.131286 +4.135089 +4.138891 +4.142693 +4.146496 +4.150298 +4.154100 +4.157903 +4.161705 +4.165508 +4.169310 +4.173112 +4.176915 +4.180717 +4.184519 +4.188322 +4.192124 +4.195927 +4.199729 +4.203531 +4.207334 +4.211136 +4.214938 +4.218741 +4.222543 +4.226346 +4.230148 +4.233950 +4.237753 +4.241555 +4.245358 +4.249160 +4.252962 +4.256765 +4.260567 +4.264369 +4.268172 +4.271974 +4.275777 +4.279579 +4.283381 +4.287184 +4.290986 +4.294788 +4.298591 +4.302393 +4.306196 +4.309998 +4.313800 +4.317603 +4.321405 +4.325208 +4.329010 +4.332812 +4.336615 +4.340417 +4.344219 +4.348022 +4.351824 +4.355627 +4.359429 +4.363231 +4.367034 +4.370836 +4.374638 +4.378441 +4.382243 +4.386046 +4.389848 +4.393650 +4.397453 +4.401255 +4.405058 +4.408860 +4.412662 +4.416465 +4.420267 +4.424069 +4.427872 +4.431674 +4.435477 +4.439279 +4.443081 +4.446884 +4.450686 +4.454488 +4.458291 +4.462093 +4.465896 +4.469698 +4.473500 +4.477303 +4.481105 +4.484907 +4.488710 +4.492512 +4.496315 +4.500117 +4.503919 +4.507722 +4.511524 +4.515327 +4.519129 +4.522931 +4.526734 +4.530536 +4.534338 +4.538141 +4.541943 +4.545746 +4.549548 +4.553350 +4.557153 +4.560955 +4.564757 +4.568560 +4.572362 +4.576165 +4.579967 +4.583769 +4.587572 +4.591374 +4.595177 +4.598979 +4.602781 +4.606584 +4.610386 +4.614188 +4.617991 +4.621793 +4.625596 +4.629398 +4.633200 +4.637003 +4.640805 +4.644607 +4.648410 +4.652212 +4.656015 +4.659817 +4.663619 +4.667422 +4.671224 +4.675027 +4.678829 +4.682631 +4.686434 +4.690236 +4.694038 +4.697841 +4.701643 +4.705446 +4.709248 +4.713050 +4.716853 +4.720655 +4.724457 +4.728260 +4.732062 +4.735865 +4.739667 +4.743469 +4.747272 +4.751074 +4.754876 +4.758679 +4.762481 +4.766284 +4.770086 +4.773888 +4.777691 +4.781493 +4.785296 +4.789098 +4.792900 +4.796703 +4.800505 +4.804307 +4.808110 +4.811912 +4.815715 +4.819517 +4.823319 +4.827122 +4.830924 +4.834726 +4.838529 +4.842331 +4.846134 +4.849936 +4.853738 +4.857541 +4.861343 +4.865146 +4.868948 +4.872750 +4.876553 +4.880355 +4.884157 +4.887960 +4.891762 +4.895565 +4.899367 +4.903169 +4.906972 +4.910774 +4.914576 +4.918379 +4.922181 +4.925984 +4.929786 +4.933588 +4.937391 +4.941193 +4.944995 +4.948798 +4.952600 +4.956403 +4.960205 +4.964007 +4.967810 +4.971612 +4.975415 +4.979217 +4.983019 +4.986822 +4.990624 +4.994426 +4.998229 +5.002031 +5.005834 +5.009636 +5.013438 +5.017241 +5.021043 +5.024845 +5.028648 +5.032450 +5.036253 +5.040055 +5.043857 +5.047660 +5.051462 +5.055265 +5.059067 +5.062869 +5.066672 +5.070474 +5.074276 +5.078079 +5.081881 +5.085684 +5.089486 +5.093288 +5.097091 +5.100893 +5.104695 +5.108498 +5.112300 +5.116103 +5.119905 +5.123707 +5.127510 +5.131312 +5.135115 +5.138917 +5.142719 +5.146522 +5.150324 +5.154126 +5.157929 +5.161731 +5.165534 +5.169336 +5.173138 +5.176941 +5.180743 +5.184545 +5.188348 +5.192150 +5.195953 +5.199755 +5.203557 +5.207360 +5.211162 +5.214964 +5.218767 +5.222569 +5.226372 +5.230174 +5.233976 +5.237779 +5.241581 +5.245384 +5.249186 +5.252988 +5.256791 +5.260593 +5.264395 +5.268198 +5.272000 +5.275803 +5.279605 +5.283407 +5.287210 +5.291012 +5.294814 +5.298617 +5.302419 +5.306222 +5.310024 +5.313826 +5.317629 +5.321431 +5.325234 +5.329036 +5.332838 +5.336641 +5.340443 +5.344245 +5.348048 +5.351850 +5.355653 +5.359455 +5.363257 +5.367060 +5.370862 +5.374664 +5.378467 +5.382269 +5.386072 +5.389874 +5.393676 +5.397479 +5.401281 +5.405084 +5.408886 +5.412688 +5.416491 +5.420293 +5.424095 +5.427898 +5.431700 +5.435503 +5.439305 +5.443107 +5.446910 +5.450712 +5.454514 +5.458317 +5.462119 +5.465922 +5.469724 +5.473526 +5.477329 +5.481131 +5.484933 +5.488736 +5.492538 +5.496341 +5.500143 +5.503945 +5.507748 +5.511550 +5.515353 +5.519155 +5.522957 +5.526760 +5.530562 +5.534364 +5.538167 +5.541969 +5.545772 +5.549574 +5.553376 +5.557179 +5.560981 +5.564783 +5.568586 +5.572388 +5.576191 +5.579993 +5.583795 +5.587598 +5.591400 +5.595203 +5.599005 +5.602807 +5.606610 +5.610412 +5.614214 +5.618017 +5.621819 +5.625622 +5.629424 +5.633226 +5.637029 +5.640831 +5.644633 +5.648436 +5.652238 +5.656041 +5.659843 +5.663645 +5.667448 +5.671250 +5.675053 +5.678855 +5.682657 +5.686460 +5.690262 +5.694064 +5.697867 +5.701669 +5.705472 +5.709274 +5.713076 +5.716879 +5.720681 +5.724483 +5.728286 +5.732088 +5.735891 +5.739693 +5.743495 +5.747298 +5.751100 +5.754902 +5.758705 +5.762507 +5.766310 +5.770112 +5.773914 +5.777717 +5.781519 +5.785322 +5.789124 +5.792926 +5.796729 +5.800531 +5.804333 +5.808136 +5.811938 +5.815741 +5.819543 +5.823345 +5.827148 +5.830950 +5.834752 +5.838555 +5.842357 +5.846160 +5.849962 +5.853764 +5.857567 +5.861369 +5.865172 +5.868974 +5.872776 +5.876579 +5.880381 +5.884183 +5.887986 +5.891788 +5.895591 +5.899393 +5.903195 +5.906998 +5.910800 +5.914602 +5.918405 +5.922207 +5.926010 +5.929812 +5.933614 +5.937417 +5.941219 +5.945022 +5.948824 +5.952626 +5.956429 +5.960231 +5.964033 +5.967836 +5.971638 +5.975441 +5.979243 +5.983045 +5.986848 +5.990650 +5.994452 +5.998255 +6.002057 +6.005860 +6.009662 +6.013464 +6.017267 +6.021069 +6.024871 +6.028674 +6.032476 +6.036279 +6.040081 +6.043883 +6.047686 +6.051488 +6.055291 +6.059093 +6.062895 +6.066698 +6.070500 +6.074302 +6.078105 +6.081907 +6.085710 +6.089512 +6.093314 +6.097117 +6.100919 +6.104721 +6.108524 +6.112326 +6.116129 +6.119931 +6.123733 +6.127536 +6.131338 +6.135141 +6.138943 +6.142745 +6.146548 +6.150350 +6.154152 +6.157955 +6.161757 +6.165560 +6.169362 +6.173164 +6.176967 +6.180769 +6.184571 +6.188374 +6.192176 +6.195979 +6.199781 +6.203583 +6.207386 +6.211188 +6.214990 +6.218793 +6.222595 +6.226398 +6.230200 +6.234002 +6.237805 +6.241607 +6.245410 +6.249212 +6.253014 +6.256817 +6.260619 +6.264421 +6.268224 +6.272026 +6.275829 +6.279631 +6.283433 +6.287236 +6.291038 +6.294840 +6.298643 +6.302445 +6.306248 +6.310050 +6.313852 +6.317655 +6.321457 +6.325260 +6.329062 +6.332864 +6.336667 +6.340469 +6.344271 +6.348074 +6.351876 +6.355679 +6.359481 +6.363283 +6.367086 +6.370888 +6.374690 +6.378493 +6.382295 +6.386098 +6.389900 +6.393702 +6.397505 +6.401307 +6.405110 +6.408912 +6.412714 +6.416517 +6.420319 +6.424121 +6.427924 +6.431726 +6.435529 +6.439331 +6.443133 +6.446936 +6.450738 +6.454540 +6.458343 +6.462145 +6.465948 +6.469750 +6.473552 +6.477355 +6.481157 +6.484959 +6.488762 +6.492564 +6.496367 +6.500169 +6.503971 +6.507774 +6.511576 +6.515379 +6.519181 +6.522983 +6.526786 +6.530588 +6.534390 +6.538193 +6.541995 +6.545798 +6.549600 +6.553402 +6.557205 +6.561007 +6.564809 +6.568612 +6.572414 +6.576217 +6.580019 +6.583821 +6.587624 +6.591426 +6.595229 +6.599031 +6.602833 +6.606636 +6.610438 +6.614240 +6.618043 +6.621845 +6.625648 +6.629450 +6.633252 +6.637055 +6.640857 +6.644659 +6.648462 +6.652264 +6.656067 +6.659869 +6.663671 +6.667474 +6.671276 +6.675079 +6.678881 +6.682683 +6.686486 +6.690288 +6.694090 +6.697893 +6.701695 +6.705498 +6.709300 +6.713102 +6.716905 +6.720707 +6.724509 +6.728312 +6.732114 +6.735917 +6.739719 +6.743521 +6.747324 +6.751126 +6.754928 +6.758731 +6.762533 +6.766336 +6.770138 +6.773940 +6.777743 +6.781545 +6.785348 +6.789150 +6.792952 +6.796755 +6.800557 +6.804359 +6.808162 +6.811964 +6.815767 +6.819569 +6.823371 +6.827174 +6.830976 +6.834778 +6.838581 +6.842383 +6.846186 +6.849988 +6.853790 +6.857593 +6.861395 +6.865198 +6.869000 +6.872802 +6.876605 +6.880407 +6.884209 +6.888012 +6.891814 +6.895617 +6.899419 +6.903221 +6.907024 +6.910826 +6.914628 +6.918431 +6.922233 +6.926036 +6.929838 +6.933640 +6.937443 +6.941245 +6.945048 +6.948850 +6.952652 +6.956455 +6.960257 +6.964059 +6.967862 +6.971664 +6.975467 +6.979269 +6.983071 +6.986874 +6.990676 +6.994478 +6.998281 +7.002083 +7.005886 +7.009688 +7.013490 +7.017293 +7.021095 +7.024897 +7.028700 +7.032502 +7.036305 +7.040107 +7.043909 +7.047712 +7.051514 +7.055317 +7.059119 +7.062921 +7.066724 +7.070526 +7.074328 +7.078131 +7.081933 +7.085736 +7.089538 +7.093340 +7.097143 +7.100945 +7.104747 +7.108550 +7.112352 +7.116155 +7.119957 +7.123759 +7.127562 +7.131364 +7.135167 +7.138969 +7.142771 +7.146574 +7.150376 +7.154178 +7.157981 +7.161783 +7.165586 +7.169388 +7.173190 +7.176993 +7.180795 +7.184597 +7.188400 +7.192202 +7.196005 +7.199807 +7.203609 +7.207412 +7.211214 +7.215017 +7.218819 +7.222621 +7.226424 +7.230226 +7.234028 +7.237831 +7.241633 +7.245436 +7.249238 +7.253040 +7.256843 +7.260645 +7.264447 +7.268250 +7.272052 +7.275855 +7.279657 +7.283459 +7.287262 +7.291064 +7.294866 +7.298669 +7.302471 +7.306274 +7.310076 +7.313878 +7.317681 +7.321483 +7.325286 +7.329088 +7.332890 +7.336693 +7.340495 +7.344297 +7.348100 +7.351902 +7.355705 +7.359507 +7.363309 +7.367112 +7.370914 +7.374716 +7.378519 +7.382321 +7.386124 +7.389926 +7.393728 +7.397531 +7.401333 +7.405136 +7.408938 +7.412740 +7.416543 +7.420345 +7.424147 +7.427950 +7.431752 +7.435555 +7.439357 +7.443159 +7.446962 +7.450764 +7.454566 +7.458369 +7.462171 +7.465974 +7.469776 +7.473578 +7.477381 +7.481183 +7.484985 +7.488788 +7.492590 +7.496393 +7.500195 +7.503997 +7.507800 +7.511602 +7.515405 +7.519207 +7.523009 +7.526812 +7.530614 +7.534416 +7.538219 +7.542021 +7.545824 +7.549626 +7.553428 +7.557231 +7.561033 +7.564835 +7.568638 +7.572440 +7.576243 +7.580045 +7.583847 +7.587650 +7.591452 +7.595255 +7.599057 +7.602859 +7.606662 +7.610464 +7.614266 +7.618069 +7.621871 +7.625674 +7.629476 +7.633278 +7.637081 +7.640883 +7.644685 +7.648488 +7.652290 +7.656093 +7.659895 +7.663697 +7.667500 +7.671302 +7.675105 +7.678907 +7.682709 +7.686512 +7.690314 +7.694116 +7.697919 +7.701721 +7.705524 +7.709326 +7.713128 +7.716931 +7.720733 +7.724535 +7.728338 +7.732140 +7.735943 +7.739745 +7.743547 +7.747350 +7.751152 +7.754954 +7.758757 +7.762559 +7.766362 +7.770164 +7.773966 +7.777769 +7.781571 +7.785374 +7.789176 +7.792978 +7.796781 +7.800583 +7.804385 +7.808188 +7.811990 +7.815793 +7.819595 +7.823397 +7.827200 +7.831002 +7.834804 +7.838607 +7.842409 +7.846212 +7.850014 +7.853816 +7.857619 +7.861421 +7.865224 +7.869026 +7.872828 +7.876631 +7.880433 +7.884235 +7.888038 +7.891840 +7.895643 +7.899445 +7.903247 +7.907050 +7.910852 +7.914654 +7.918457 +7.922259 +7.926062 +7.929864 +7.933666 +7.937469 +7.941271 +7.945074 +7.948876 +7.952678 +7.956481 +7.960283 +7.964085 +7.967888 +7.971690 +7.975493 +7.979295 +7.983097 +7.986900 +7.990702 +7.994504 +7.998307 +8.002109 +8.005912 +8.009714 +8.013516 +8.017319 +8.021121 +8.024923 +8.028726 +8.032528 +8.036331 +8.040133 +8.043935 +8.047738 +8.051540 +8.055343 +8.059145 +8.062947 +8.066750 +8.070552 +8.074354 +8.078157 +8.081959 +8.085762 +8.089564 +8.093366 +8.097169 +8.100971 +8.104773 +8.108576 +8.112378 +8.116181 +8.119983 +8.123785 +8.127588 +8.131390 +8.135193 +8.138995 +8.142797 +8.146600 +8.150402 +8.154204 +8.158007 +8.161809 +8.165612 +8.169414 +8.173216 +8.177019 +8.180821 +8.184623 +8.188426 +8.192228 +8.196031 +8.199833 +8.203635 +8.207438 +8.211240 +8.215043 +8.218845 +8.222647 +8.226450 +8.230252 +8.234054 +8.237857 +8.241659 +8.245462 +8.249264 +8.253066 +8.256869 +8.260671 +8.264473 +8.268276 +8.272078 +8.275881 +8.279683 +8.283485 +8.287288 +8.291090 +8.294892 +8.298695 +8.302497 +8.306300 +8.310102 +8.313904 +8.317707 +8.321509 +8.325312 +8.329114 +8.332916 +8.336719 +8.340521 +8.344323 +8.348126 +8.351928 +8.355731 +8.359533 +8.363335 +8.367138 +8.370940 +8.374742 +8.378545 +8.382347 +8.386150 +8.389952 +8.393754 +8.397557 +8.401359 +8.405162 +8.408964 +8.412766 +8.416569 +8.420371 +8.424173 +8.427976 +8.431778 +8.435581 +8.439383 +8.443185 +8.446988 +8.450790 +8.454592 +8.458395 +8.462197 +8.466000 +8.469802 +8.473604 +8.477407 +8.481209 +8.485012 +8.488814 +8.492616 +8.496419 +8.500221 +8.504023 +8.507826 +8.511628 +8.515431 +8.519233 +8.523035 +8.526838 +8.530640 +8.534442 +8.538245 +8.542047 +8.545850 +8.549652 +8.553454 +8.557257 +8.561059 +8.564861 +8.568664 +8.572466 +8.576269 +8.580071 +8.583873 +8.587676 +8.591478 +8.595281 +8.599083 +8.602885 +8.606688 +8.610490 +8.614292 +8.618095 +8.621897 +8.625700 +8.629502 +8.633304 +8.637107 +8.640909 +8.644711 +8.648514 +8.652316 +8.656119 +8.659921 +8.663723 +8.667526 +8.671328 +8.675131 +8.678933 +8.682735 +8.686538 +8.690340 +8.694142 +8.697945 +8.701747 +8.705550 +8.709352 +8.713154 +8.716957 +8.720759 +8.724561 +8.728364 +8.732166 +8.735969 +8.739771 +8.743573 +8.747376 +8.751178 +8.754980 +8.758783 +8.762585 +8.766388 +8.770190 +8.773992 +8.777795 +8.781597 +8.785400 +8.789202 +8.793004 +8.796807 +8.800609 +8.804411 +8.808214 +8.812016 +8.815819 +8.819621 +8.823423 +8.827226 +8.831028 +8.834830 +8.838633 +8.842435 +8.846238 +8.850040 +8.853842 +8.857645 +8.861447 +8.865250 +8.869052 +8.872854 +8.876657 +8.880459 +8.884261 +8.888064 +8.891866 +8.895669 +8.899471 +8.903273 +8.907076 +8.910878 +8.914680 +8.918483 +8.922285 +8.926088 +8.929890 +8.933692 +8.937495 +8.941297 +8.945100 +8.948902 +8.952704 +8.956507 +8.960309 +8.964111 +8.967914 +8.971716 +8.975519 +8.979321 +8.983123 +8.986926 +8.990728 +8.994530 +8.998333 +9.002135 +9.005938 +9.009740 +9.013542 +9.017345 +9.021147 +9.024949 +9.028752 +9.032554 +9.036357 +9.040159 +9.043961 +9.047764 +9.051566 +9.055369 +9.059171 +9.062973 +9.066776 +9.070578 +9.074380 +9.078183 +9.081985 +9.085788 +9.089590 +9.093392 +9.097195 +9.100997 +9.104799 +9.108602 +9.112404 +9.116207 +9.120009 +9.123811 +9.127614 +9.131416 +9.135219 +9.139021 +9.142823 +9.146626 +9.150428 +9.154230 +9.158033 +9.161835 +9.165638 +9.169440 +9.173242 +9.177045 +9.180847 +9.184649 +9.188452 +9.192254 +9.196057 +9.199859 +9.203661 +9.207464 +9.211266 +9.215069 +9.218871 +9.222673 +9.226476 +9.230278 +9.234080 +9.237883 +9.241685 +9.245488 +9.249290 +9.253092 +9.256895 +9.260697 +9.264499 +9.268302 +9.272104 +9.275907 +9.279709 +9.283511 +9.287314 +9.291116 +9.294918 +9.298721 +9.302523 +9.306326 +9.310128 +9.313930 +9.317733 +9.321535 +9.325338 +9.329140 +9.332942 +9.336745 +9.340547 +9.344349 +9.348152 +9.351954 +9.355757 +9.359559 +9.363361 +9.367164 +9.370966 +9.374768 +9.378571 +9.382373 +9.386176 +9.389978 +9.393780 +9.397583 +9.401385 +9.405188 +9.408990 +9.412792 +9.416595 +9.420397 +9.424199 +9.428002 +9.431804 +9.435607 +9.439409 +9.443211 +9.447014 +9.450816 +9.454618 +9.458421 +9.462223 +9.466026 +9.469828 +9.473630 +9.477433 +9.481235 +9.485038 +9.488840 +9.492642 +9.496445 +9.500247 +9.504049 +9.507852 +9.511654 +9.515457 +9.519259 +9.523061 +9.526864 +9.530666 +9.534468 +9.538271 +9.542073 +9.545876 +9.549678 +9.553480 +9.557283 +9.561085 +9.564887 +9.568690 +9.572492 +9.576295 +9.580097 +9.583899 +9.587702 +9.591504 +9.595307 +9.599109 +9.602911 +9.606714 +9.610516 +9.614318 +9.618121 +9.621923 +9.625726 +9.629528 +9.633330 +9.637133 +9.640935 +9.644737 +9.648540 +9.652342 +9.656145 +9.659947 +9.663749 +9.667552 +9.671354 +9.675157 +9.678959 +9.682761 +9.686564 +9.690366 +9.694168 +9.697971 +9.701773 +9.705576 +9.709378 +9.713180 +9.716983 +9.720785 +9.724587 +9.728390 +9.732192 +9.735995 +9.739797 +9.743599 +9.747402 +9.751204 +9.755007 +9.758809 +9.762611 +9.766414 +9.770216 +9.774018 +9.777821 +9.781623 +9.785426 +9.789228 +9.793030 +9.796833 +9.800635 +9.804437 +9.808240 +9.812042 +9.815845 +9.819647 +9.823449 +9.827252 +9.831054 +9.834856 +9.838659 +9.842461 +9.846264 +9.850066 +9.853868 +9.857671 +9.861473 +9.865276 +9.869078 +9.872880 +9.876683 +9.880485 +9.884287 +9.888090 +9.891892 +9.895695 +9.899497 +9.903299 +9.907102 +9.910904 +9.914706 +9.918509 +9.922311 +9.926114 +9.929916 +9.933718 +9.937521 +9.941323 +9.945126 +9.948928 +9.952730 +9.956533 +9.960335 +9.964137 +9.967940 +9.971742 +9.975545 +9.979347 +9.983149 +9.986952 +9.990754 +9.994556 +9.998359 +10.002161 +10.005964 +10.009766 +10.013568 +10.017371 +10.021173 +10.024975 +10.028778 +10.032580 +10.036383 +10.040185 +10.043987 +10.047790 +10.051592 +10.055395 +10.059197 +10.062999 +10.066802 +10.070604 +10.074406 +10.078209 +10.082011 +10.085814 +10.089616 +10.093418 +10.097221 +10.101023 +10.104825 +10.108628 +10.112430 +10.116233 +10.120035 +10.123837 +10.127640 +10.131442 +10.135245 +10.139047 +10.142849 +10.146652 +10.150454 +10.154256 +10.158059 +10.161861 +10.165664 +10.169466 +10.173268 +10.177071 +10.180873 +10.184675 +10.188478 +10.192280 +10.196083 +10.199885 +10.203687 +10.207490 +10.211292 +10.215095 +10.218897 +10.222699 +10.226502 +10.230304 +10.234106 +10.237909 +10.241711 +10.245514 +10.249316 +10.253118 +10.256921 +10.260723 +10.264525 +10.268328 +10.272130 +10.275933 +10.279735 +10.283537 +10.287340 +10.291142 +10.294944 +10.298747 +10.302549 +10.306352 +10.310154 +10.313956 +10.317759 +10.321561 +10.325364 +10.329166 +10.332968 +10.336771 +10.340573 +10.344375 +10.348178 +10.351980 +10.355783 +10.359585 +10.363387 +10.367190 +10.370992 +10.374794 +10.378597 +10.382399 +10.386202 +10.390004 +10.393806 +10.397609 +10.401411 +10.405214 +10.409016 +10.412818 +10.416621 +10.420423 +10.424225 +10.428028 +10.431830 +10.435633 +10.439435 +10.443237 +10.447040 +10.450842 +10.454644 +10.458447 +10.462249 +10.466052 +10.469854 +10.473656 +10.477459 +10.481261 +10.485064 +10.488866 +10.492668 +10.496471 +10.500273 +10.504075 +10.507878 +10.511680 +10.515483 +10.519285 +10.523087 +10.526890 +10.530692 +10.534494 +10.538297 +10.542099 +10.545902 +10.549704 +10.553506 +10.557309 +10.561111 +10.564913 +10.568716 +10.572518 +10.576321 +10.580123 +10.583925 +10.587728 +10.591530 +10.595333 +10.599135 +10.602937 +10.606740 +10.610542 +10.614344 +10.618147 +10.621949 +10.625752 +10.629554 +10.633356 +10.637159 +10.640961 +10.644763 +10.648566 +10.652368 +10.656171 +10.659973 +10.663775 +10.667578 +10.671380 +10.675183 +10.678985 +10.682787 +10.686590 +10.690392 +10.694194 +10.697997 +10.701799 +10.705602 +10.709404 +10.713206 +10.717009 +10.720811 +10.724613 +10.728416 +10.732218 +10.736021 +10.739823 +10.743625 +10.747428 +10.751230 +10.755033 +10.758835 +10.762637 +10.766440 +10.770242 +10.774044 +10.777847 +10.781649 +10.785452 +10.789254 +10.793056 +10.796859 +10.800661 +10.804463 +10.808266 +10.812068 +10.815871 +10.819673 +10.823475 +10.827278 +10.831080 +10.834882 +10.838685 +10.842487 +10.846290 +10.850092 +10.853894 +10.857697 +10.861499 +10.865302 +10.869104 +10.872906 +10.876709 +10.880511 +10.884313 +10.888116 +10.891918 +10.895721 +10.899523 +10.903325 +10.907128 +10.910930 +10.914732 +10.918535 +10.922337 +10.926140 +10.929942 +10.933744 +10.937547 +10.941349 +10.945152 +10.948954 +10.952756 +10.956559 +10.960361 +10.964163 +10.967966 +10.971768 +10.975571 +10.979373 +10.983175 +10.986978 +10.990780 +10.994582 +10.998385 +11.002187 +11.005990 +11.009792 +11.013594 +11.017397 +11.021199 +11.025002 +11.028804 +11.032606 +11.036409 +11.040211 +11.044013 +11.047816 +11.051618 +11.055421 +11.059223 +11.063025 +11.066828 +11.070630 +11.074432 +11.078235 +11.082037 +11.085840 +11.089642 +11.093444 +11.097247 +11.101049 +11.104851 +11.108654 +11.112456 +11.116259 +11.120061 +11.123863 +11.127666 +11.131468 +11.135271 +11.139073 +11.142875 +11.146678 +11.150480 +11.154282 +11.158085 +11.161887 +11.165690 +11.169492 +11.173294 +11.177097 +11.180899 +11.184701 +11.188504 +11.192306 +11.196109 +11.199911 +11.203713 +11.207516 +11.211318 +11.215121 +11.218923 +11.222725 +11.226528 +11.230330 +11.234132 +11.237935 +11.241737 +11.245540 +11.249342 +11.253144 +11.256947 +11.260749 +11.264551 +11.268354 +11.272156 +11.275959 +11.279761 +11.283563 +11.287366 +11.291168 +11.294970 +11.298773 +11.302575 +11.306378 +11.310180 +11.313982 +11.317785 +11.321587 +11.325390 +11.329192 +11.332994 +11.336797 +11.340599 +11.344401 +11.348204 +11.352006 +11.355809 +11.359611 +11.363413 +11.367216 +11.371018 +11.374820 +11.378623 +11.382425 +11.386228 +11.390030 +11.393832 +11.397635 +11.401437 +11.405240 +11.409042 +11.412844 +11.416647 +11.420449 +11.424251 +11.428054 +11.431856 +11.435659 +11.439461 +11.443263 +11.447066 +11.450868 +11.454670 +11.458473 +11.462275 +11.466078 +11.469880 +11.473682 +11.477485 +11.481287 +11.485090 +11.488892 +11.492694 +11.496497 +11.500299 +11.504101 +11.507904 +11.511706 +11.515509 +11.519311 +11.523113 +11.526916 +11.530718 +11.534520 +11.538323 +11.542125 +11.545928 +11.549730 +11.553532 +11.557335 +11.561137 +11.564939 +11.568742 +11.572544 +11.576347 +11.580149 +11.583951 +11.587754 +11.591556 +11.595359 +11.599161 +11.602963 +11.606766 +11.610568 +11.614370 +11.618173 +11.621975 +11.625778 +11.629580 +11.633382 +11.637185 +11.640987 +11.644789 +11.648592 +11.652394 +11.656197 +11.659999 +11.663801 +11.667604 +11.671406 +11.675209 +11.679011 +11.682813 +11.686616 +11.690418 +11.694220 +11.698023 +11.701825 +11.705628 +11.709430 +11.713232 +11.717035 +11.720837 +11.724639 +11.728442 +11.732244 +11.736047 +11.739849 +11.743651 +11.747454 +11.751256 +11.755059 +11.758861 +11.762663 +11.766466 +11.770268 +11.774070 +11.777873 +11.781675 +11.785478 +11.789280 +11.793082 +11.796885 +11.800687 +11.804489 +11.808292 +11.812094 +11.815897 +11.819699 +11.823501 +11.827304 +11.831106 +11.834908 +11.838711 +11.842513 +11.846316 +11.850118 +11.853920 +11.857723 +11.861525 +11.865328 +11.869130 +11.872932 +11.876735 +11.880537 +11.884339 +11.888142 +11.891944 +11.895747 +11.899549 +11.903351 +11.907154 +11.910956 +11.914758 +11.918561 +11.922363 +11.926166 +11.929968 +11.933770 +11.937573 +11.941375 +11.945178 +11.948980 +11.952782 +11.956585 +11.960387 +11.964189 +11.967992 +11.971794 +11.975597 +11.979399 +11.983201 +11.987004 +11.990806 +11.994608 +11.998411 +12.002213 +12.006016 +12.009818 +12.013620 +12.017423 +12.021225 +12.025028 +12.028830 +12.032632 +12.036435 +12.040237 +12.044039 +12.047842 +12.051644 +12.055447 +12.059249 +12.063051 +12.066854 +12.070656 +12.074458 +12.078261 +12.082063 +12.085866 +12.089668 +12.093470 +12.097273 +12.101075 +12.104877 +12.108680 +12.112482 +12.116285 +12.120087 +12.123889 +12.127692 +12.131494 +12.135297 +12.139099 +12.142901 +12.146704 +12.150506 +12.154308 +12.158111 +12.161913 +12.165716 +12.169518 +12.173320 +12.177123 +12.180925 +12.184727 +12.188530 +12.192332 +12.196135 +12.199937 +12.203739 +12.207542 +12.211344 +12.215147 +12.218949 +12.222751 +12.226554 +12.230356 +12.234158 +12.237961 +12.241763 +12.245566 +12.249368 +12.253170 +12.256973 +12.260775 +12.264577 +12.268380 +12.272182 +12.275985 +12.279787 +12.283589 +12.287392 +12.291194 +12.294996 +12.298799 +12.302601 +12.306404 +12.310206 +12.314008 +12.317811 +12.321613 +12.325416 +12.329218 +12.333020 +12.336823 +12.340625 +12.344427 +12.348230 +12.352032 +12.355835 +12.359637 +12.363439 +12.367242 +12.371044 +12.374846 +12.378649 +12.382451 +12.386254 +12.390056 +12.393858 +12.397661 +12.401463 +12.405266 +12.409068 +12.412870 +12.416673 +12.420475 +12.424277 +12.428080 +12.431882 +12.435685 +12.439487 +12.443289 +12.447092 +12.450894 +12.454696 +12.458499 +12.462301 +12.466104 +12.469906 +12.473708 +12.477511 +12.481313 +12.485116 +12.488918 +12.492720 +12.496523 +12.500325 +12.504127 +12.507930 +12.511732 +12.515535 +12.519337 +12.523139 +12.526942 +12.530744 +12.534546 +12.538349 +12.542151 +12.545954 +12.549756 +12.553558 +12.557361 +12.561163 +12.564965 +12.568768 +12.572570 +12.576373 +12.580175 +12.583977 +12.587780 +12.591582 +12.595385 +12.599187 +12.602989 +12.606792 +12.610594 +12.614396 +12.618199 +12.622001 +12.625804 +12.629606 +12.633408 +12.637211 +12.641013 +12.644815 +12.648618 +12.652420 +12.656223 +12.660025 +12.663827 +12.667630 +12.671432 +12.675235 +12.679037 +12.682839 +12.686642 +12.690444 +12.694246 +12.698049 +12.701851 +12.705654 +12.709456 +12.713258 +12.717061 +12.720863 +12.724665 +12.728468 +12.732270 +12.736073 +12.739875 +12.743677 +12.747480 +12.751282 +12.755085 +12.758887 +12.762689 +12.766492 +12.770294 +12.774096 +12.777899 +12.781701 +12.785504 +12.789306 +12.793108 +12.796911 +12.800713 +12.804515 +12.808318 +12.812120 +12.815923 +12.819725 +12.823527 +12.827330 +12.831132 +12.834934 +12.838737 +12.842539 +12.846342 +12.850144 +12.853946 +12.857749 +12.861551 +12.865354 +12.869156 +12.872958 +12.876761 +12.880563 +12.884365 +12.888168 +12.891970 +12.895773 +12.899575 +12.903377 +12.907180 +12.910982 +12.914784 +12.918587 +12.922389 +12.926192 +12.929994 +12.933796 +12.937599 +12.941401 +12.945204 +12.949006 +12.952808 +12.956611 +12.960413 +12.964215 +12.968018 +12.971820 +12.975623 +12.979425 +12.983227 +12.987030 +12.990832 +12.994634 +12.998437 +13.002239 +13.006042 +13.009844 +13.013646 +13.017449 +13.021251 +13.025054 +13.028856 +13.032658 +13.036461 +13.040263 +13.044065 +13.047868 +13.051670 +13.055473 +13.059275 +13.063077 +13.066880 +13.070682 +13.074484 +13.078287 +13.082089 +13.085892 +13.089694 +13.093496 +13.097299 +13.101101 +13.104903 +13.108706 +13.112508 +13.116311 +13.120113 +13.123915 +13.127718 +13.131520 +13.135323 +13.139125 +13.142927 +13.146730 +13.150532 +13.154334 +13.158137 +13.161939 +13.165742 +13.169544 +13.173346 +13.177149 +13.180951 +13.184753 +13.188556 +13.192358 +13.196161 +13.199963 +13.203765 +13.207568 +13.211370 +13.215173 +13.218975 +13.222777 +13.226580 +13.230382 +13.234184 +13.237987 +13.241789 +13.245592 +13.249394 +13.253196 +13.256999 +13.260801 +13.264603 +13.268406 +13.272208 +13.276011 +13.279813 +13.283615 +13.287418 +13.291220 +13.295023 +13.298825 +13.302627 +13.306430 +13.310232 +13.314034 +13.317837 +13.321639 +13.325442 +13.329244 +13.333046 +13.336849 +13.340651 +13.344453 +13.348256 +13.352058 +13.355861 +13.359663 +13.363465 +13.367268 +13.371070 +13.374872 +13.378675 +13.382477 +13.386280 +13.390082 +13.393884 +13.397687 +13.401489 +13.405292 +13.409094 +13.412896 +13.416699 +13.420501 +13.424303 +13.428106 +13.431908 +13.435711 +13.439513 +13.443315 +13.447118 +13.450920 +13.454722 +13.458525 +13.462327 +13.466130 +13.469932 +13.473734 +13.477537 +13.481339 +13.485142 +13.488944 +13.492746 +13.496549 +13.500351 +13.504153 +13.507956 +13.511758 +13.515561 +13.519363 +13.523165 +13.526968 +13.530770 +13.534572 +13.538375 +13.542177 +13.545980 +13.549782 +13.553584 +13.557387 +13.561189 +13.564991 +13.568794 +13.572596 +13.576399 +13.580201 +13.584003 +13.587806 +13.591608 +13.595411 +13.599213 +13.603015 +13.606818 +13.610620 +13.614422 +13.618225 +13.622027 +13.625830 +13.629632 +13.633434 +13.637237 +13.641039 +13.644841 +13.648644 +13.652446 +13.656249 +13.660051 +13.663853 +13.667656 +13.671458 +13.675261 +13.679063 +13.682865 +13.686668 +13.690470 +13.694272 +13.698075 +13.701877 +13.705680 +13.709482 +13.713284 +13.717087 +13.720889 +13.724691 +13.728494 +13.732296 +13.736099 +13.739901 +13.743703 +13.747506 +13.751308 +13.755111 +13.758913 +13.762715 +13.766518 +13.770320 +13.774122 +13.777925 +13.781727 +13.785530 +13.789332 +13.793134 +13.796937 +13.800739 +13.804541 +13.808344 +13.812146 +13.815949 +13.819751 +13.823553 +13.827356 +13.831158 +13.834960 +13.838763 +13.842565 +13.846368 +13.850170 +13.853972 +13.857775 +13.861577 +13.865380 +13.869182 +13.872984 +13.876787 +13.880589 +13.884391 +13.888194 +13.891996 +13.895799 +13.899601 +13.903403 +13.907206 +13.911008 +13.914810 +13.918613 +13.922415 +13.926218 +13.930020 +13.933822 +13.937625 +13.941427 +13.945230 +13.949032 +13.952834 +13.956637 +13.960439 +13.964241 +13.968044 +13.971846 +13.975649 +13.979451 +13.983253 +13.987056 +13.990858 +13.994660 +13.998463 +14.002265 +14.006068 +14.009870 +14.013672 +14.017475 +14.021277 +14.025080 +14.028882 +14.032684 +14.036487 +14.040289 +14.044091 +14.047894 +14.051696 +14.055499 +14.059301 +14.063103 +14.066906 +14.070708 +14.074510 +14.078313 +14.082115 +14.085918 +14.089720 +14.093522 +14.097325 +14.101127 +14.104929 +14.108732 +14.112534 +14.116337 +14.120139 +14.123941 +14.127744 +14.131546 +14.135349 +14.139151 +14.142953 +14.146756 +14.150558 +14.154360 +14.158163 +14.161965 +14.165768 +14.169570 +14.173372 +14.177175 +14.180977 +14.184779 +14.188582 +14.192384 +14.196187 +14.199989 +14.203791 +14.207594 +14.211396 +14.215199 +14.219001 +14.222803 +14.226606 +14.230408 +14.234210 +14.238013 +14.241815 +14.245618 +14.249420 +14.253222 +14.257025 +14.260827 +14.264629 +14.268432 +14.272234 +14.276037 +14.279839 +14.283641 +14.287444 +14.291246 +14.295049 +14.298851 +14.302653 +14.306456 +14.310258 +14.314060 +14.317863 +14.321665 +14.325468 +14.329270 +14.333072 +14.336875 +14.340677 +14.344479 +14.348282 +14.352084 +14.355887 +14.359689 +14.363491 +14.367294 +14.371096 +14.374898 +14.378701 +14.382503 +14.386306 +14.390108 +14.393910 +14.397713 +14.401515 +14.405318 +14.409120 +14.412922 +14.416725 +14.420527 +14.424329 +14.428132 +14.431934 +14.435737 +14.439539 +14.443341 +14.447144 +14.450946 +14.454748 +14.458551 +14.462353 +14.466156 +14.469958 +14.473760 +14.477563 +14.481365 +14.485168 +14.488970 +14.492772 +14.496575 +14.500377 +14.504179 +14.507982 +14.511784 +14.515587 +14.519389 +14.523191 +14.526994 +14.530796 +14.534598 +14.538401 +14.542203 +14.546006 +14.549808 +14.553610 +14.557413 +14.561215 +14.565018 +14.568820 +14.572622 +14.576425 +14.580227 +14.584029 +14.587832 +14.591634 +14.595437 +14.599239 +14.603041 +14.606844 +14.610646 +14.614448 +14.618251 +14.622053 +14.625856 +14.629658 +14.633460 +14.637263 +14.641065 +14.644867 +14.648670 +14.652472 +14.656275 +14.660077 +14.663879 +14.667682 +14.671484 +14.675287 +14.679089 +14.682891 +14.686694 +14.690496 +14.694298 +14.698101 +14.701903 +14.705706 +14.709508 +14.713310 +14.717113 +14.720915 +14.724717 +14.728520 +14.732322 +14.736125 +14.739927 +14.743729 +14.747532 +14.751334 +14.755137 +14.758939 +14.762741 +14.766544 +14.770346 +14.774148 +14.777951 +14.781753 +14.785556 +14.789358 +14.793160 +14.796963 +14.800765 +14.804567 +14.808370 +14.812172 +14.815975 +14.819777 +14.823579 +14.827382 +14.831184 +14.834986 +14.838789 +14.842591 +14.846394 +14.850196 +14.853998 +14.857801 +14.861603 +14.865406 +14.869208 +14.873010 +14.876813 +14.880615 +14.884417 +14.888220 +14.892022 +14.895825 +14.899627 +14.903429 +14.907232 +14.911034 +14.914836 +14.918639 +14.922441 +14.926244 +14.930046 +14.933848 +14.937651 +14.941453 +14.945256 +14.949058 +14.952860 +14.956663 +14.960465 +14.964267 +14.968070 +14.971872 +14.975675 +14.979477 +14.983279 +14.987082 +14.990884 +14.994686 +14.998489 +15.002291 +15.006094 +15.009896 +15.013698 +15.017501 +15.021303 +15.025106 +15.028908 +15.032710 +15.036513 +15.040315 +15.044117 +15.047920 +15.051722 +15.055525 +15.059327 +15.063129 +15.066932 +15.070734 +15.074536 +15.078339 +15.082141 +15.085944 +15.089746 +15.093548 +15.097351 +15.101153 +15.104955 +15.108758 +15.112560 +15.116363 +15.120165 +15.123967 +15.127770 +15.131572 +15.135375 +15.139177 +15.142979 +15.146782 +15.150584 +15.154386 +15.158189 +15.161991 +15.165794 +15.169596 +15.173398 +15.177201 +15.181003 +15.184805 +15.188608 +15.192410 +15.196213 +15.200015 +15.203817 +15.207620 +15.211422 +15.215225 +15.219027 +15.222829 +15.226632 +15.230434 +15.234236 +15.238039 +15.241841 +15.245644 +15.249446 +15.253248 +15.257051 +15.260853 +15.264655 +15.268458 +15.272260 +15.276063 +15.279865 +15.283667 +15.287470 +15.291272 +15.295075 +15.298877 +15.302679 +15.306482 +15.310284 +15.314086 +15.317889 +15.321691 +15.325494 +15.329296 +15.333098 +15.336901 +15.340703 +15.344505 +15.348308 +15.352110 +15.355913 +15.359715 +15.363517 +15.367320 +15.371122 +15.374924 +15.378727 +15.382529 +15.386332 +15.390134 +15.393936 +15.397739 +15.401541 +15.405344 +15.409146 +15.412948 +15.416751 +15.420553 +15.424355 +15.428158 +15.431960 +15.435763 +15.439565 +15.443367 +15.447170 +15.450972 +15.454774 +15.458577 +15.462379 +15.466182 +15.469984 +15.473786 +15.477589 +15.481391 +15.485194 +15.488996 +15.492798 +15.496601 +15.500403 +15.504205 +15.508008 +15.511810 +15.515613 +15.519415 +15.523217 +15.527020 +15.530822 +15.534624 +15.538427 +15.542229 +15.546032 +15.549834 +15.553636 +15.557439 +15.561241 +15.565044 +15.568846 +15.572648 +15.576451 +15.580253 +15.584055 +15.587858 +15.591660 +15.595463 +15.599265 +15.603067 +15.606870 +15.610672 +15.614474 +15.618277 +15.622079 +15.625882 +15.629684 +15.633486 +15.637289 +15.641091 +15.644893 +15.648696 +15.652498 +15.656301 +15.660103 +15.663905 +15.667708 +15.671510 +15.675313 +15.679115 +15.682917 +15.686720 +15.690522 +15.694324 +15.698127 +15.701929 +15.705732 +15.709534 +15.713336 +15.717139 +15.720941 +15.724743 +15.728546 +15.732348 +15.736151 +15.739953 +15.743755 +15.747558 +15.751360 +15.755163 +15.758965 +15.762767 +15.766570 +15.770372 +15.774174 +15.777977 +15.781779 +15.785582 +15.789384 +15.793186 +15.796989 +15.800791 +15.804593 +15.808396 +15.812198 +15.816001 +15.819803 +15.823605 +15.827408 +15.831210 +15.835013 +15.838815 +15.842617 +15.846420 +15.850222 +15.854024 +15.857827 +15.861629 +15.865432 +15.869234 +15.873036 +15.876839 +15.880641 +15.884443 +15.888246 +15.892048 +15.895851 +15.899653 +15.903455 +15.907258 +15.911060 +15.914862 +15.918665 +15.922467 +15.926270 +15.930072 +15.933874 +15.937677 +15.941479 +15.945282 +15.949084 +15.952886 +15.956689 +15.960491 +15.964293 +15.968096 +15.971898 +15.975701 +15.979503 +15.983305 +15.987108 +15.990910 +15.994712 +15.998515 +16.002317 +16.006120 +16.009922 +16.013724 +16.017527 +16.021329 +16.025132 +16.028934 +16.032736 +16.036539 +16.040341 +16.044143 +16.047946 +16.051748 +16.055551 +16.059353 +16.063155 +16.066958 +16.070760 +16.074562 +16.078365 +16.082167 +16.085970 +16.089772 +16.093574 +16.097377 +16.101179 +16.104981 +16.108784 +16.112586 +16.116389 +16.120191 +16.123993 +16.127796 +16.131598 +16.135401 +16.139203 +16.143005 +16.146808 +16.150610 +16.154412 +16.158215 +16.162017 +16.165820 +16.169622 +16.173424 +16.177227 +16.181029 +16.184831 +16.188634 +16.192436 +16.196239 +16.200041 +16.203843 +16.207646 +16.211448 +16.215251 +16.219053 +16.222855 +16.226658 +16.230460 +16.234262 +16.238065 +16.241867 +16.245670 +16.249472 +16.253274 +16.257077 +16.260879 +16.264681 +16.268484 +16.272286 +16.276089 +16.279891 +16.283693 +16.287496 +16.291298 +16.295101 +16.298903 +16.302705 +16.306508 +16.310310 +16.314112 +16.317915 +16.321717 +16.325520 +16.329322 +16.333124 +16.336927 +16.340729 +16.344531 +16.348334 +16.352136 +16.355939 +16.359741 +16.363543 +16.367346 +16.371148 +16.374950 +16.378753 +16.382555 +16.386358 +16.390160 +16.393962 +16.397765 +16.401567 +16.405370 +16.409172 +16.412974 +16.416777 +16.420579 +16.424381 +16.428184 +16.431986 +16.435789 +16.439591 +16.443393 +16.447196 +16.450998 +16.454800 +16.458603 +16.462405 +16.466208 +16.470010 +16.473812 +16.477615 +16.481417 +16.485220 +16.489022 +16.492824 +16.496627 +16.500429 +16.504231 +16.508034 +16.511836 +16.515639 +16.519441 +16.523243 +16.527046 +16.530848 +16.534650 +16.538453 +16.542255 +16.546058 +16.549860 +16.553662 +16.557465 +16.561267 +16.565070 +16.568872 +16.572674 +16.576477 +16.580279 +16.584081 +16.587884 +16.591686 +16.595489 +16.599291 +16.603093 +16.606896 +16.610698 +16.614500 +16.618303 +16.622105 +16.625908 +16.629710 +16.633512 +16.637315 +16.641117 +16.644919 +16.648722 +16.652524 +16.656327 +16.660129 +16.663931 +16.667734 +16.671536 +16.675339 +16.679141 +16.682943 +16.686746 +16.690548 +16.694350 +16.698153 +16.701955 +16.705758 +16.709560 +16.713362 +16.717165 +16.720967 +16.724769 +16.728572 +16.732374 +16.736177 +16.739979 +16.743781 +16.747584 +16.751386 +16.755189 +16.758991 +16.762793 +16.766596 +16.770398 +16.774200 +16.778003 +16.781805 +16.785608 +16.789410 +16.793212 +16.797015 +16.800817 +16.804619 +16.808422 +16.812224 +16.816027 +16.819829 +16.823631 +16.827434 +16.831236 +16.835039 +16.838841 +16.842643 +16.846446 +16.850248 +16.854050 +16.857853 +16.861655 +16.865458 +16.869260 +16.873062 +16.876865 +16.880667 +16.884469 +16.888272 +16.892074 +16.895877 +16.899679 +16.903481 +16.907284 +16.911086 +16.914888 +16.918691 +16.922493 +16.926296 +16.930098 +16.933900 +16.937703 +16.941505 +16.945308 +16.949110 +16.952912 +16.956715 +16.960517 +16.964319 +16.968122 +16.971924 +16.975727 +16.979529 +16.983331 +16.987134 +16.990936 +16.994738 +16.998541 +17.002343 +17.006146 +17.009948 +17.013750 +17.017553 +17.021355 +17.025158 +17.028960 +17.032762 +17.036565 +17.040367 +17.044169 +17.047972 +17.051774 +17.055577 +17.059379 +17.063181 +17.066984 +17.070786 +17.074588 +17.078391 +17.082193 +17.085996 +17.089798 +17.093600 +17.097403 +17.101205 +17.105008 +17.108810 +17.112612 +17.116415 +17.120217 +17.124019 +17.127822 +17.131624 +17.135427 +17.139229 +17.143031 +17.146834 +17.150636 +17.154438 +17.158241 +17.162043 +17.165846 +17.169648 +17.173450 +17.177253 +17.181055 +17.184857 +17.188660 +17.192462 +17.196265 +17.200067 +17.203869 +17.207672 +17.211474 +17.215277 +17.219079 +17.222881 +17.226684 +17.230486 +17.234288 +17.238091 +17.241893 +17.245696 +17.249498 +17.253300 +17.257103 +17.260905 +17.264707 +17.268510 +17.272312 +17.276115 +17.279917 +17.283719 +17.287522 +17.291324 +17.295127 +17.298929 +17.302731 +17.306534 +17.310336 +17.314138 +17.317941 +17.321743 +17.325546 +17.329348 +17.333150 +17.336953 +17.340755 +17.344557 +17.348360 +17.352162 +17.355965 +17.359767 +17.363569 +17.367372 +17.371174 +17.374976 +17.378779 +17.382581 +17.386384 +17.390186 +17.393988 +17.397791 +17.401593 +17.405396 +17.409198 +17.413000 +17.416803 +17.420605 +17.424407 +17.428210 +17.432012 +17.435815 +17.439617 +17.443419 +17.447222 +17.451024 +17.454826 +17.458629 +17.462431 +17.466234 +17.470036 +17.473838 +17.477641 +17.481443 +17.485246 +17.489048 +17.492850 +17.496653 +17.500455 +17.504257 +17.508060 +17.511862 +17.515665 +17.519467 +17.523269 +17.527072 +17.530874 +17.534676 +17.538479 +17.542281 +17.546084 +17.549886 +17.553688 +17.557491 +17.561293 +17.565096 +17.568898 +17.572700 +17.576503 +17.580305 +17.584107 +17.587910 +17.591712 +17.595515 +17.599317 +17.603119 +17.606922 +17.610724 +17.614526 +17.618329 +17.622131 +17.625934 +17.629736 +17.633538 +17.637341 +17.641143 +17.644945 +17.648748 +17.652550 +17.656353 +17.660155 +17.663957 +17.667760 +17.671562 +17.675365 +17.679167 +17.682969 +17.686772 +17.690574 +17.694376 +17.698179 +17.701981 +17.705784 +17.709586 +17.713388 +17.717191 +17.720993 +17.724795 +17.728598 +17.732400 +17.736203 +17.740005 +17.743807 +17.747610 +17.751412 +17.755215 +17.759017 +17.762819 +17.766622 +17.770424 +17.774226 +17.778029 +17.781831 +17.785634 +17.789436 +17.793238 +17.797041 +17.800843 +17.804645 +17.808448 +17.812250 +17.816053 +17.819855 +17.823657 +17.827460 +17.831262 +17.835065 +17.838867 +17.842669 +17.846472 +17.850274 +17.854076 +17.857879 +17.861681 +17.865484 +17.869286 +17.873088 +17.876891 +17.880693 +17.884495 +17.888298 +17.892100 +17.895903 +17.899705 +17.903507 +17.907310 +17.911112 +17.914914 +17.918717 +17.922519 +17.926322 +17.930124 +17.933926 +17.937729 +17.941531 +17.945334 +17.949136 +17.952938 +17.956741 +17.960543 +17.964345 +17.968148 +17.971950 +17.975753 +17.979555 +17.983357 +17.987160 +17.990962 +17.994764 +17.998567 +18.002369 +18.006172 +18.009974 +18.013776 +18.017579 +18.021381 +18.025184 +18.028986 +18.032788 +18.036591 +18.040393 +18.044195 +18.047998 +18.051800 +18.055603 +18.059405 +18.063207 +18.067010 +18.070812 +18.074614 +18.078417 +18.082219 +18.086022 +18.089824 +18.093626 +18.097429 +18.101231 +18.105034 +18.108836 +18.112638 +18.116441 +18.120243 +18.124045 +18.127848 +18.131650 +18.135453 +18.139255 +18.143057 +18.146860 +18.150662 +18.154464 +18.158267 +18.162069 +18.165872 +18.169674 +18.173476 +18.177279 +18.181081 +18.184883 +18.188686 +18.192488 +18.196291 +18.200093 +18.203895 +18.207698 +18.211500 +18.215303 +18.219105 +18.222907 +18.226710 +18.230512 +18.234314 +18.238117 +18.241919 +18.245722 +18.249524 +18.253326 +18.257129 +18.260931 +18.264733 +18.268536 +18.272338 +18.276141 +18.279943 +18.283745 +18.287548 +18.291350 +18.295153 +18.298955 +18.302757 +18.306560 +18.310362 +18.314164 +18.317967 +18.321769 +18.325572 +18.329374 +18.333176 +18.336979 +18.340781 +18.344583 +18.348386 +18.352188 +18.355991 +18.359793 +18.363595 +18.367398 +18.371200 +18.375003 +18.378805 +18.382607 +18.386410 +18.390212 +18.394014 +18.397817 +18.401619 +18.405422 +18.409224 +18.413026 +18.416829 +18.420631 +18.424433 +18.428236 +18.432038 +18.435841 +18.439643 +18.443445 +18.447248 +18.451050 +18.454852 +18.458655 +18.462457 +18.466260 +18.470062 +18.473864 +18.477667 +18.481469 +18.485272 +18.489074 +18.492876 +18.496679 +18.500481 +18.504283 +18.508086 +18.511888 +18.515691 +18.519493 +18.523295 +18.527098 +18.530900 +18.534702 +18.538505 +18.542307 +18.546110 +18.549912 +18.553714 +18.557517 +18.561319 +18.565122 +18.568924 +18.572726 +18.576529 +18.580331 +18.584133 +18.587936 +18.591738 +18.595541 +18.599343 +18.603145 +18.606948 +18.610750 +18.614552 +18.618355 +18.622157 +18.625960 +18.629762 +18.633564 +18.637367 +18.641169 +18.644971 +18.648774 +18.652576 +18.656379 +18.660181 +18.663983 +18.667786 +18.671588 +18.675391 +18.679193 +18.682995 +18.686798 +18.690600 +18.694402 +18.698205 +18.702007 +18.705810 +18.709612 +18.713414 +18.717217 +18.721019 +18.724821 +18.728624 +18.732426 +18.736229 +18.740031 +18.743833 +18.747636 +18.751438 +18.755241 +18.759043 +18.762845 +18.766648 +18.770450 +18.774252 +18.778055 +18.781857 +18.785660 +18.789462 +18.793264 +18.797067 +18.800869 +18.804671 +18.808474 +18.812276 +18.816079 +18.819881 +18.823683 +18.827486 +18.831288 +18.835091 +18.838893 +18.842695 +18.846498 +18.850300 +18.854102 +18.857905 +18.861707 +18.865510 +18.869312 +18.873114 +18.876917 +18.880719 +18.884521 +18.888324 +18.892126 +18.895929 +18.899731 +18.903533 +18.907336 +18.911138 +18.914940 +18.918743 +18.922545 +18.926348 +18.930150 +18.933952 +18.937755 +18.941557 +18.945360 +18.949162 +18.952964 +18.956767 +18.960569 +18.964371 +18.968174 +18.971976 +18.975779 +18.979581 +18.983383 +18.987186 +18.990988 +18.994790 +18.998593 +19.002395 +19.006198 +19.010000 diff --git a/inputFiles/lagrangianContactMechanics/dataTables/y.csv b/inputFiles/lagrangianContactMechanics/dataTables/y.csv new file mode 100644 index 00000000000..1d65b3e555f --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/dataTables/y.csv @@ -0,0 +1 @@ +0.00 \ No newline at end of file diff --git a/inputFiles/lagrangianContactMechanics/dataTables/z.csv b/inputFiles/lagrangianContactMechanics/dataTables/z.csv new file mode 100644 index 00000000000..1d65b3e555f --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/dataTables/z.csv @@ -0,0 +1 @@ +0.00 \ No newline at end of file diff --git a/inputFiles/lagrangianContactMechanics/domain_id.vtu b/inputFiles/lagrangianContactMechanics/domain_id.vtu new file mode 100644 index 00000000000..892ff0397be --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/domain_id.vtu @@ -0,0 +1,148 @@ + + + + + + + 0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 + + + + + AQAAAACAAABQAAAADAAAAA==eJxjYKAuAAAAUAAB + + + AQAAAACAAADwAAAADwAAAA==eJzjsO5T4xhBGAAuETnl + + + 1.7094007438e-15 + + + 1.7094007438e-15 + + + + + AQAAAACAAABQAAAADwAAAA==eJw7e8bH7iwVMQDZKiq9 + + + AQAAAACAAABQAAAAEAAAAA==eJxjZGBgYCQCEwsAArwACw== + + + AQAAAACAAACgAAAAMAAAAA==eJwtxUkCgBAAAECpiKLt/391MHOZEKbF0as3707OPlxcffpyc/ftx68//x4qMAC/ + + + + + AQAAAACAAAAgBAAA5QAAAA==eJzlkrENwlAQQ7MAQkIMQMcEiO6fC2pKkNiAERAUNwIFA7ACEgMgUdKySRZA4XKxE0YglfXj7/O9pKr6z+nuJXXZwfjGv/pVz0p6bo95oYf3Gr1frErq6WEtHs9MO07Oeccu12V7rjNhzIExp/FEznu8sewwem6N/b3XXc+ls/V9ES4cIBwguRAOEA4QDhAOEA4QDhAOEA4QDhAOEA4QDhAOEA6Q/SAcIBwgHKDMuEvo6ODG3SM7NTnEOXXunpnKvdMth9DBodH6rZJDaGZ2c4y7u5HJ7zz294Fn+E/8N4cP++C9cQ== + + + 0 + + + 2.4494897428 + + + + + + + AQAAAACAAABABgAAQAEAAA==eJxdkLVCA0AUBIO7OwSCu1twdw0S+P8/oWCm2WumubVXKPy/RtgE62ENXIVrcB1uwM34r74B1sY/dVtwO/6pa4YtsC7+q9+Bu3AverirFbaFv3n2ct8+LEeOud6tHXZEjrne7QAehr959rFfJ+yC3sEe9jqCx9A72MNePbA7/M2zj/1O4GnkmOvuXtgXOea6+wyeh7959lKvX3/0UKfPBXSPPuoGoHd0h37qL6F3vILX8Abewjs4CItwHI7Cofiv/h4+xD91Y3A4/ql7hE/wOf6rn4AlOBI93PUCX8PfPHu5bxJORY653u0NvkeOud5tGs6Ev3n2sV8FfkDvYA97zcI56B3sYa9P+BX+5tnHfgtwPnLMdfc3rEaOue5ehEvhb5691Ov3Ez3U6bMM3aOPul/oHd2hn/oV6B3/AHIHIeM= + + + AQAAAACAAACgAAAAPgAAAA==eJzjYoAAISgtA6U1oLQRlLaB0h5QOghKR0HpFCidB6XLoHQDlO6B0tOg9AIovQZKb4PS+6D0CSgNAOCvCDU= + + + AQAAAACAAAAUAAAAEwAAAA==eJzj5+EX4AciHn5+OAsADA4BJQ== + + + + + diff --git a/inputFiles/lagrangianContactMechanics/fracture_id_new.vtu b/inputFiles/lagrangianContactMechanics/fracture_id_new.vtu new file mode 100644 index 00000000000..ae71d526125 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/fracture_id_new.vtu @@ -0,0 +1,52 @@ + + + + + + + AQAAAACAAABgAQAAVgAAAA==eJwtxUkCgQAAAEAPolBItpREilD8/ycOZi6Tj/7Gnvrsi+e+eeHSoWeuXHjikwNfHbl27MZLt1458d1rP9w59dMbv73zy1v33nvwwZk/PvrrH4gxC0M= + + + 79.32212806 + + + 108.60018416 + + + + + AQAAAACAAACwAAAAMwAAAA==eJwtxbcBgCAAADCsiApY/3+VgWRJCN3g0ZNnL14dvTl59+HT2cXVl28/fv35dwM4CADo + + + + + AQAAAACAAABQAAAAIgAAAA==eJwtxbcBACAIADAsiP7/sAPJkog2PL28nT4uXz9/BXgALg== + + + + + AQAAAACAAAAIAQAAbQAAAA==eJxjYICBBnsQWbOlwQ7GtotysIexIXSD/enPCnYwNRsPqNsh1IDE4OrsMk1d7GBskUo/JDUNMDPtq4UmwOyyn7LAHCrugGSfgz3CHAd7hDlwO+2v8IfZw9zAezjcHuF+VHcjiyO5GY4B++o2Mg== + + + 1 + + + 1.7320508076 + + + + + + + AQAAAACAAACQAQAAWwAAAA==eJxdjkcShEAQw4AlLHlI//8qB6yL5qIq18jtqvpeHw5hG9YieRc2Ivk/HMOffO5M4SyPHnYt4SqPHjx6tnDXDjx6jrDIo4e7Z3jJo6co59+t3qL80c4XMZ8CDg== + + + AQAAAACAAABQAAAAIwAAAA==eJxjZYAATijNB6VFoLQklJaD0ipQWhNK60JpIygNACJgARQ= + + + AQAAAACAAAAKAAAACwAAAA==eJxjZ4cBAAGLAEc= + + + + + diff --git a/inputFiles/lagrangianContactMechanics/scripts/fixedFaultSlip.py b/inputFiles/lagrangianContactMechanics/scripts/fixedFaultSlip.py new file mode 100644 index 00000000000..64cbb7e5575 --- /dev/null +++ b/inputFiles/lagrangianContactMechanics/scripts/fixedFaultSlip.py @@ -0,0 +1,213 @@ +import numpy as np +import os +import sys +import xml.etree.ElementTree as ElementTree +import matplotlib +import matplotlib.pyplot as plt +import argparse + +class SingularCrackSlip: + + def __init__(self, mechanicalParameters, length ): + K = mechanicalParameters["bulkModulus"] + G = mechanicalParameters["shearModulus"] + poisson_ratio= (3 * K - 2 * G) / (2 * (3 * K + G)) + + mu_star = G /( 1 - poisson_ratio) + self.tau_0 = 0.0 + self.tau_r = -1.0 + + self.scaling = 2*(self.tau_0 - self.tau_r)/mu_star + self.halfLength = length + + def computeSlip(self, x): + return self.scaling * np.sqrt(self.halfLength**2 - x**2) + + def computeTraction(self, x): + if x < -self.halfLength or x > self.halfLength: + return self.tau_0 + (self.tau_0-self.tau_r) * ( np.abs(x)/np.sqrt(x**2 - self.halfLength**2) - 1 ) + else: + return self.tau_r +class GaussianSlip: + + def __init__(self, peakStrength, length ): + self.scaling = peakStrength + self.halfLength = length + + def computeSlip(self, x): + denom = 1 / (self.halfLength/2) + return self.scaling*np.exp(-0.5*((x)/denom)**2) + +def getMechanicalParametersFromXML(xmlFilePath): + tree = ElementTree.parse(xmlFilePath) + + param = tree.find('Constitutive/ElasticIsotropic') + + mechanicalParameters = dict.fromkeys(["bulkModulus", "shearModulus"]) + mechanicalParameters["bulkModulus"] = float(param.get("defaultBulkModulus")) + mechanicalParameters["shearModulus"] = float(param.get("defaultShearModulus")) + return mechanicalParameters + +def getFractureLengthFromXML(xmlFilePath): + tree = ElementTree.parse(xmlFilePath) + + rectangle = tree.find('Geometry/Box') + xmin = rectangle.get("xMin") + xmax = rectangle.get("xMax") + xmin = [float(i) for i in xmin[1:-1].split(",")] + xmax = [float(i) for i in xmax[1:-1].split(",")] + length = ( xmax[0] - xmin[0] ) / 2 + origin = 0.0 + + return length, origin + +def curve_check_solution(**kwargs): + #-------- Extract info from XML + xmlFilePath = f'./LagrangeContactBubbleStab_FixedSlip_base.xml' + + mechanicalParameters = getMechanicalParametersFromXML(xmlFilePath) + + # Get length of the fracture + xmlFilePath = f'./LagrangeContactBubbleStab_FixedSlip_smoke.xml' + totalHalfLength, originShift = getFractureLengthFromXML(xmlFilePath) + halfLength = 2.0 + + x = kwargs['traction elementCenter'] + x_geos = x[0, :, 0] + + return analytical_solution(x, mechanicalParameters, totalHalfLength, halfLength) + +def analytical_solution(x, mechanicalParameters, totalHalfLength, halfLength): + + singularCrackSlipSolution = SingularCrackSlip(mechanicalParameters, halfLength) + x = np.linspace(-totalHalfLength, totalHalfLength, 10000, endpoint=True) + traction_analytical = np.zeros(len(x)) + i = 0 + for xCell in x: + traction_analytical[i] = singularCrackSlipSolution.computeTraction(xCell) + i += 1 + return traction_analytical + +def plot_traction_solution(inputFileDirectory, outputDirectory): + # Read HDF5 + import hdf5_wrapper + hdf5File1Path = f'outputDirectory/traction.hdf5' + + # Read HDF5 + data = hdf5_wrapper.hdf5_wrapper(hdf5File1Path).get_copy() + traction = data['traction'] + traction = np.asarray(traction) + traction_geos = traction[0, :, 1] + x = data['traction elementCenter'] + x_geos = x[0, :, 0] + + #-------- Extract info from XML + xmlFilePath = f'{inputFileDirectory}/lagrangianContactMechanics/LagrangeContactBubbleStab_FixedSlip_base.xml' + + mechanicalParameters = getMechanicalParametersFromXML(xmlFilePath) + + # Get length of the fracture + xmlFilePath = f'{inputFileDirectory}lagrangianContactMechanics/LagrangeContactBubbleStab_FixedSlip_smoke.xml' + totalHalfLength, originShift = getFractureLengthFromXML(xmlFilePath) + halfLength = 2.0 + + traction_analytical = analytical_solution(x, mechanicalParameters, totalHalfLength, halfLength) + + fsize = 30 + msize = 15 + lw = 2 + fig, ax = plt.subplots(1, figsize=(16, 12)) + cmap = plt.get_cmap("tab10") + + # Plot analytical (continuous line) and numerical (markers) aperture solution + ax.plot(x, traction_analytical, color='r', label='Traction analytical', lw=lw) + ax.plot(x_geos, traction_geos, color='k', label='geos', marker="o", lw=lw) + + ax.set_xlabel('Fault coordinate [m]', size=fsize, weight="bold") + ax.set_ylabel('Shear traction', size=fsize, weight="bold") + ax.legend(bbox_to_anchor=(0.75, 0.9), loc='center', borderaxespad=0., fontsize=fsize) + ax.xaxis.set_tick_params(labelsize=fsize) + ax.yaxis.set_tick_params(labelsize=fsize) + plt.savefig("traction.png") + +def output_tables(x, slip, name): + # Save x to x.csv with one value per row + np.savetxt('x.csv', x, fmt='%f') + + # Save aperture_analytical to jump.csv with one value per row + np.savetxt(f'{name}.csv', slip, fmt='%f') + + +def generate_tables(inputFileDirectory): + #-------- Extract info from XML + xmlFilePath = f'{inputFileDirectory}/lagrangianContactMechanics/LagrangeContactBubbleStab_FixedSlip_base.xml' + + mechanicalParameters = getMechanicalParametersFromXML(xmlFilePath) + appliedPressure = 1.0 + + # Get length of the fracture + xmlFilePath = f'{inputFileDirectory}/lagrangianContactMechanics/LagrangeContactBubbleStab_FixedSlip_smoke.xml' + totalHalfLength, originShift = getFractureLengthFromXML(xmlFilePath) + halfLength = 2.0 + + # Initialize Sneddon's analytical solution + singularCrackSlipSolution = SingularCrackSlip(mechanicalParameters, halfLength ) + peakStrength = 3.0 + gaussianSlipSolution = GaussianSlip( peakStrength, halfLength) + + # Plot analytical (continuous line) and numerical (markers) aperture solution + x = np.linspace(-totalHalfLength, totalHalfLength, 10000, endpoint=True) + singularCrackSlip = np.zeros(len(x)) + gaussianSlip = np.zeros(len(x)) + i = 0 + for xCell in x: + if xCell > -halfLength and xCell < halfLength: + singularCrackSlip[i] = singularCrackSlipSolution.computeSlip(xCell) + gaussianSlip[i] = gaussianSlipSolution.computeSlip(xCell) + i += 1 + + fsize = 24 + msize = 15 + lw = 6 + fig, ax = plt.subplots(1, figsize=(16, 12)) + cmap = plt.get_cmap("tab10") + + ax.plot(x, singularCrackSlip , color='k', label='Analytical Solution', lw=lw) + ax.grid() + ax.set_xlabel('Fault coordinate [m]', size=fsize, weight="bold") + ax.set_ylabel('slip [m]', size=fsize, weight="bold") + ax.legend(bbox_to_anchor=(0.7, 1), loc='center', borderaxespad=0., fontsize=fsize) + ax.xaxis.set_tick_params(labelsize=fsize) + ax.yaxis.set_tick_params(labelsize=fsize) + plt.savefig("singularCrackSlip.png") + + fig, ax = plt.subplots(1, figsize=(16, 12)) + cmap = plt.get_cmap("tab10") + + ax.plot(x, gaussianSlip , color='k', label='Analytical Solution', lw=lw) + ax.grid() + ax.set_xlabel('Fault coordinate [m]', size=fsize, weight="bold") + ax.set_ylabel('slip [m]', size=fsize, weight="bold") + ax.legend(bbox_to_anchor=(0.75, 0.9), loc='center', borderaxespad=0., fontsize=fsize) + ax.xaxis.set_tick_params(labelsize=fsize) + ax.yaxis.set_tick_params(labelsize=fsize) + plt.savefig("gaussianSlip.png") + + output_tables(x, singularCrackSlip, "singularCrackSlip") + output_tables(x, gaussianSlip, "gaussianSlip") + +if __name__ == "__main__": + + parser = argparse.ArgumentParser() + parser.add_argument('-a', '--action', type=str, choices=['generate_tables', 'plotTractions'], required=True, help='Action to perform: generate_tables or plotTractions') + parser.add_argument('-i', '--input-files-path', type=str, required=True, help='Path to the inputFilesFolder') + parser.add_argument('-o', '--output-dir', type=str, help='Directory containing the output files') + + args = parser.parse_args() + + if args.action == 'generate_tables': + print("Generating tables...") + generate_tables(os.path.normpath(args.input_files_path)) + elif args.action == 'plotTractions': + print("Plotting tractions...") + plot_traction_solution(os.path.normpath(args.input_files_path), os.path.normpath(args.output_dir)) diff --git a/inputFiles/main.ats b/inputFiles/main.ats index a76815a8700..c85f018bb1a 100644 --- a/inputFiles/main.ats +++ b/inputFiles/main.ats @@ -1,7 +1,6 @@ """ Primary ATS script """ -import os import ats from pathlib import Path diff --git a/inputFiles/materialPointMethod/dfgMovingGrid/mpm_dfgMovingGrid.xml b/inputFiles/materialPointMethod/dfgMovingGrid/mpm_dfgMovingGrid.xml index c55e39b4825..6086342f1b6 100644 --- a/inputFiles/materialPointMethod/dfgMovingGrid/mpm_dfgMovingGrid.xml +++ b/inputFiles/materialPointMethod/dfgMovingGrid/mpm_dfgMovingGrid.xml @@ -29,7 +29,7 @@ srun -n 4 /usr/workspace/homel1/GEOS/build-quartz-gcc@12-release/bin/geosx -i mp @@ -133,4 +133,3 @@ boundaryConditionTypes="{ 1, 0, 2, 2, 1, 1 }" - diff --git a/inputFiles/materialPointMethod/dfgMovingGrid/solidMechanicsMPM_dfgMovingGrid.ats b/inputFiles/materialPointMethod/dfgMovingGrid/solidMechanicsMPM_dfgMovingGrid.ats index 0050fbc9c28..614cec27195 100644 --- a/inputFiles/materialPointMethod/dfgMovingGrid/solidMechanicsMPM_dfgMovingGrid.ats +++ b/inputFiles/materialPointMethod/dfgMovingGrid/solidMechanicsMPM_dfgMovingGrid.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params['atol'] = 1.0E-8 diff --git a/inputFiles/materialPointMethod/particleRepartition/mpm_particleRepartition.xml b/inputFiles/materialPointMethod/particleRepartition/mpm_particleRepartition.xml index ea4fe422923..685e4c3479e 100644 --- a/inputFiles/materialPointMethod/particleRepartition/mpm_particleRepartition.xml +++ b/inputFiles/materialPointMethod/particleRepartition/mpm_particleRepartition.xml @@ -29,7 +29,7 @@ srun -n 4 /usr/workspace/homel1/GEOS/build-quartz-gcc@12-release/bin/geosx -i mp @@ -119,4 +119,3 @@ boundaryConditionTypes="{ 0, 0, 0, 0, 0, 0 }" - diff --git a/inputFiles/materialPointMethod/particleRepartition/solidMechanicsMPM_particleRepartition.ats b/inputFiles/materialPointMethod/particleRepartition/solidMechanicsMPM_particleRepartition.ats index 91170fe400d..3fb5432df5e 100644 --- a/inputFiles/materialPointMethod/particleRepartition/solidMechanicsMPM_particleRepartition.ats +++ b/inputFiles/materialPointMethod/particleRepartition/solidMechanicsMPM_particleRepartition.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params['atol'] = 1.0E-8 diff --git a/inputFiles/materialPointMethod/singleParticle/mpm_singleParticle.xml b/inputFiles/materialPointMethod/singleParticle/mpm_singleParticle.xml index bb795ae6e7f..4fa388009a5 100644 --- a/inputFiles/materialPointMethod/singleParticle/mpm_singleParticle.xml +++ b/inputFiles/materialPointMethod/singleParticle/mpm_singleParticle.xml @@ -29,7 +29,7 @@ srun -n 1 /usr/workspace/homel1/GEOS/build-quartz-gcc@12-release/bin/geosx -i mp @@ -119,4 +119,3 @@ boundaryConditionTypes="{ 0, 0, 0, 0, 0, 0 }" - diff --git a/inputFiles/materialPointMethod/singleParticle/solidMechanicsMPM_singleParticle.ats b/inputFiles/materialPointMethod/singleParticle/solidMechanicsMPM_singleParticle.ats index 4432464bd90..6860cbe2d56 100644 --- a/inputFiles/materialPointMethod/singleParticle/solidMechanicsMPM_singleParticle.ats +++ b/inputFiles/materialPointMethod/singleParticle/solidMechanicsMPM_singleParticle.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params['atol'] = 1.0E-8 diff --git a/inputFiles/meshGeneration/multiBodyMeshGen_base.xml b/inputFiles/meshGeneration/multiBodyMeshGen_base.xml index e714f179254..51477c54cb9 100644 --- a/inputFiles/meshGeneration/multiBodyMeshGen_base.xml +++ b/inputFiles/meshGeneration/multiBodyMeshGen_base.xml @@ -41,7 +41,7 @@ diff --git a/inputFiles/multiphaseFlowFractures/deadOil_fractureMatrixFlow_edfm_base.xml b/inputFiles/multiphaseFlowFractures/deadOil_fractureMatrixFlow_edfm_base.xml index 0243011b1b0..2ac98ea35b3 100644 --- a/inputFiles/multiphaseFlowFractures/deadOil_fractureMatrixFlow_edfm_base.xml +++ b/inputFiles/multiphaseFlowFractures/deadOil_fractureMatrixFlow_edfm_base.xml @@ -90,7 +90,7 @@ diff --git a/inputFiles/phaseField/PhaseFieldFracture_DamageAndLoad.xml b/inputFiles/phaseField/PhaseFieldFracture_DamageAndLoad.xml index c24b08aa8c9..14b6d92f8a3 100644 --- a/inputFiles/phaseField/PhaseFieldFracture_DamageAndLoad.xml +++ b/inputFiles/phaseField/PhaseFieldFracture_DamageAndLoad.xml @@ -103,7 +103,7 @@ diff --git a/inputFiles/phaseField/PhaseFieldFracture_DamageOnly.xml b/inputFiles/phaseField/PhaseFieldFracture_DamageOnly.xml index e7bcab72523..99064e92686 100644 --- a/inputFiles/phaseField/PhaseFieldFracture_DamageOnly.xml +++ b/inputFiles/phaseField/PhaseFieldFracture_DamageOnly.xml @@ -105,7 +105,7 @@ diff --git a/inputFiles/phaseField/PhaseFieldFracture_Nucleation_base.xml b/inputFiles/phaseField/PhaseFieldFracture_Nucleation_base.xml index c961f5c52b3..e339684d116 100644 --- a/inputFiles/phaseField/PhaseFieldFracture_Nucleation_base.xml +++ b/inputFiles/phaseField/PhaseFieldFracture_Nucleation_base.xml @@ -67,7 +67,7 @@ diff --git a/inputFiles/phaseField/PhaseFieldFracture_SpectralSplit.xml b/inputFiles/phaseField/PhaseFieldFracture_SpectralSplit.xml index 2cb24468fd0..f7423b48112 100644 --- a/inputFiles/phaseField/PhaseFieldFracture_SpectralSplit.xml +++ b/inputFiles/phaseField/PhaseFieldFracture_SpectralSplit.xml @@ -116,7 +116,7 @@ diff --git a/inputFiles/phaseField/PhaseFieldFracture_VolDevSplit.xml b/inputFiles/phaseField/PhaseFieldFracture_VolDevSplit.xml index e077817c194..26893feb2ce 100644 --- a/inputFiles/phaseField/PhaseFieldFracture_VolDevSplit.xml +++ b/inputFiles/phaseField/PhaseFieldFracture_VolDevSplit.xml @@ -116,7 +116,7 @@ diff --git a/inputFiles/poromechanics/PoroDelftEggWellbore_base.xml b/inputFiles/poromechanics/PoroDelftEggWellbore_base.xml index 6bd3aa9ce7d..60fef34af70 100644 --- a/inputFiles/poromechanics/PoroDelftEggWellbore_base.xml +++ b/inputFiles/poromechanics/PoroDelftEggWellbore_base.xml @@ -40,7 +40,7 @@ /> diff --git a/inputFiles/poromechanics/PoroDruckerPragerWellbore_base.xml b/inputFiles/poromechanics/PoroDruckerPragerWellbore_base.xml index 96ad724ff65..2fe870777b9 100644 --- a/inputFiles/poromechanics/PoroDruckerPragerWellbore_base.xml +++ b/inputFiles/poromechanics/PoroDruckerPragerWellbore_base.xml @@ -41,7 +41,7 @@ /> diff --git a/inputFiles/poromechanics/PoroElasticWellbore_base.xml b/inputFiles/poromechanics/PoroElasticWellbore_base.xml index 9f1431df95a..635883163d1 100644 --- a/inputFiles/poromechanics/PoroElasticWellbore_base.xml +++ b/inputFiles/poromechanics/PoroElasticWellbore_base.xml @@ -36,7 +36,7 @@ /> diff --git a/inputFiles/poromechanics/PoroElastic_Mandel_base.xml b/inputFiles/poromechanics/PoroElastic_Mandel_base.xml index a1c9af280ee..d1eb25f9673 100644 --- a/inputFiles/poromechanics/PoroElastic_Mandel_base.xml +++ b/inputFiles/poromechanics/PoroElastic_Mandel_base.xml @@ -21,7 +21,7 @@ @@ -42,7 +42,7 @@ @@ -77,7 +77,7 @@ @@ -78,7 +78,7 @@ @@ -121,7 +121,7 @@ diff --git a/inputFiles/poromechanics/PoroElastic_gravity.xml b/inputFiles/poromechanics/PoroElastic_gravity.xml index 54aacf9ee1f..91c9e679224 100644 --- a/inputFiles/poromechanics/PoroElastic_gravity.xml +++ b/inputFiles/poromechanics/PoroElastic_gravity.xml @@ -81,7 +81,7 @@ @@ -110,7 +110,7 @@ @@ -79,7 +79,7 @@ @@ -116,7 +116,7 @@ permeabilityComponents="{ 9.8e-13, 9.8e-13, 9.8e-13 }"/> diff --git a/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_base.xml b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_base.xml index 53ca032ac5f..c2aea226cf6 100755 --- a/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_base.xml +++ b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_base.xml @@ -12,7 +12,10 @@ nx="{ 3, 3 }" ny="{ 3, 3 }" nz="{ 2, 2, 2, 2 }" - cellBlockNames="{ b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11, b12, b13, b14, b15 }"> + cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, + cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1, + cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2, + cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }"> diff --git a/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_base_stab.xml b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_base_stab.xml new file mode 100755 index 00000000000..a80766e45d7 --- /dev/null +++ b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_base_stab.xml @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_fim.xml b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_fim.xml index eaf0aa683e2..bf49f42200f 100644 --- a/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_fim.xml +++ b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_fim.xml @@ -27,9 +27,9 @@ solidSolverName="linearElasticity" flowSolverName="twoPhaseFlow" stabilizationType="Global" - stabilizationRegionNames="{ channel, barrier }" + stabilizationRegionNames="{ channel }" logLevel="1" - targetRegions="{ channel, barrier }"/> + targetRegions="{ channel }"/> @@ -90,32 +90,11 @@ target="/Outputs/vtkOutput"/> - - + target="/Tasks/multiphasePoroelasticityEquilibrationStep"/> - - - - - + + - - + name="multiphasePoroelasticityEquilibrationStep" + poromechanicsSolverName="multiphasePoroelasticity" + solidMechanicsStatisticsName="linearElasticityStatistics"/> diff --git a/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_fim_stab.xml b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_fim_stab.xml new file mode 100644 index 00000000000..2bf5cfbd434 --- /dev/null +++ b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_fim_stab.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_sequential.xml b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_sequential.xml index 2775e1326bf..e0f04762409 100755 --- a/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_sequential.xml +++ b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_sequential.xml @@ -13,7 +13,7 @@ solidSolverName="linearElasticity" reservoirAndWellsSolverName="reservoirAndWells" logLevel="1" - targetRegions="{ channel, barrier }"> + targetRegions="{ channel }"> + targetRegions="{ channel, wellRegion1, wellRegion2 }"> @@ -97,32 +97,11 @@ target="/Outputs/vtkOutput_seq"/> - - + target="/Tasks/multiphasePoroelasticityEquilibrationStep"/> - - - - - + + - - + name="multiphasePoroelasticityEquilibrationStep" + poromechanicsSolverName="reservoirSystem" + solidMechanicsStatisticsName="linearElasticityStatistics"/> diff --git a/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_sequential_stab.xml b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_sequential_stab.xml new file mode 100755 index 00000000000..1470a078714 --- /dev/null +++ b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_sequential_stab.xml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_base.xml b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_base.xml index 5a69dfa2842..3b25c03e021 100755 --- a/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_base.xml +++ b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_base.xml @@ -12,7 +12,10 @@ nx="{ 3, 3 }" ny="{ 3, 3 }" nz="{ 2, 2, 2, 2 }" - cellBlockNames="{ b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11, b12, b13, b14, b15 }"> + cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, + cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1, + cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2, + cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }"> diff --git a/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_base_stab.xml b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_base_stab.xml new file mode 100755 index 00000000000..9855e123f79 --- /dev/null +++ b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_base_stab.xml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_fim.xml b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_fim.xml index 62345094c30..3be995c1621 100644 --- a/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_fim.xml +++ b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_fim.xml @@ -79,23 +79,16 @@ target="/Outputs/vtkOutput"/> + target="/Tasks/singlePhasePoroelasticityEquilibrationStep"/> - - - - - - + name="singlePhasePoroelasticityEquilibrationStep" + poromechanicsSolverName="singlePhasePoroelasticity" + solidMechanicsStatisticsName="linearElasticityStatistics"/> diff --git a/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_fim_stab.xml b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_fim_stab.xml new file mode 100644 index 00000000000..34f0f9adbe8 --- /dev/null +++ b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_fim_stab.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_sequential.xml b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_sequential.xml index a95a1d1d185..58e14123fef 100755 --- a/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_sequential.xml +++ b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_sequential.xml @@ -86,23 +86,18 @@ name="outputs" timeFrequency="1e6" target="/Outputs/vtkOutput_seq"/> + + target="/Tasks/singlePhasePoroelasticityEquilibrationStep"/> - - - - - - + name="singlePhasePoroelasticityEquilibrationStep" + poromechanicsSolverName="reservoirPoromechanics" + solidMechanicsStatisticsName="linearElasticityStatistics"/> diff --git a/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_sequential_stab.xml b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_sequential_stab.xml new file mode 100755 index 00000000000..354bff0f51d --- /dev/null +++ b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_sequential_stab.xml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanics/PoroModifiedCamClayWellbore_base.xml b/inputFiles/poromechanics/PoroModifiedCamClayWellbore_base.xml index 9f005e4fc44..5d9149bf22e 100644 --- a/inputFiles/poromechanics/PoroModifiedCamClayWellbore_base.xml +++ b/inputFiles/poromechanics/PoroModifiedCamClayWellbore_base.xml @@ -40,7 +40,7 @@ /> diff --git a/inputFiles/poromechanics/PoroViscoDruckerPrager_base.xml b/inputFiles/poromechanics/PoroViscoDruckerPrager_base.xml index d4d042e5ae2..58b27c73122 100644 --- a/inputFiles/poromechanics/PoroViscoDruckerPrager_base.xml +++ b/inputFiles/poromechanics/PoroViscoDruckerPrager_base.xml @@ -41,7 +41,7 @@ /> diff --git a/inputFiles/poromechanics/PoroViscoExtendedDruckerPrager_base.xml b/inputFiles/poromechanics/PoroViscoExtendedDruckerPrager_base.xml index 072aa138f0a..7e066c4bf0d 100644 --- a/inputFiles/poromechanics/PoroViscoExtendedDruckerPrager_base.xml +++ b/inputFiles/poromechanics/PoroViscoExtendedDruckerPrager_base.xml @@ -42,7 +42,7 @@ /> diff --git a/inputFiles/poromechanics/PoroViscoModifiedCamClay_base.xml b/inputFiles/poromechanics/PoroViscoModifiedCamClay_base.xml index b48274d0c7a..405d4bb3f01 100644 --- a/inputFiles/poromechanics/PoroViscoModifiedCamClay_base.xml +++ b/inputFiles/poromechanics/PoroViscoModifiedCamClay_base.xml @@ -42,7 +42,7 @@ /> diff --git a/inputFiles/poromechanics/faultPoroelastic_base.xml b/inputFiles/poromechanics/faultPoroelastic_base.xml index c593405e7e9..6b69e6836c1 100755 --- a/inputFiles/poromechanics/faultPoroelastic_base.xml +++ b/inputFiles/poromechanics/faultPoroelastic_base.xml @@ -5,7 +5,7 @@ @@ -55,7 +55,7 @@ diff --git a/inputFiles/poromechanics/nonlinearAcceleration/smallEggModel/smallEggModel.xml b/inputFiles/poromechanics/nonlinearAcceleration/smallEggModel/smallEggModel.xml index a8259a6e66d..277776298a8 100755 --- a/inputFiles/poromechanics/nonlinearAcceleration/smallEggModel/smallEggModel.xml +++ b/inputFiles/poromechanics/nonlinearAcceleration/smallEggModel/smallEggModel.xml @@ -69,7 +69,7 @@ file="../../../GEOSDATA/DataSets/Egg/egg_withBurdens_small.vts" regionAttribute="elementRegionMarker" fieldsToImport="{ PERM }" - fieldNamesInGEOSX="{ rockPermeability_permeability }"/> + fieldNamesInGEOS="{ rockPermeability_permeability }"/> @@ -154,22 +154,22 @@ @@ -202,7 +202,7 @@ diff --git a/inputFiles/poromechanics/nonlinearAcceleration/validationCase/poroelasticCoupling_validation.ats b/inputFiles/poromechanics/nonlinearAcceleration/validationCase/poroelasticCoupling_validation.ats index ae39bd6c1d7..78c50420484 100644 --- a/inputFiles/poromechanics/nonlinearAcceleration/validationCase/poroelasticCoupling_validation.ats +++ b/inputFiles/poromechanics/nonlinearAcceleration/validationCase/poroelasticCoupling_validation.ats @@ -1,5 +1,4 @@ -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests class Description(object): @@ -77,7 +76,7 @@ def _build_NonlinearAccelerationValidation_cases(): description = Description("Nonlinear acceleration validation problem ", "auto", "Sohail Waziri", True) restartcheck_params = {"atol": 1.0e-4, "rtol": 2.0e-6} - return _build_poro_elastic_coupling_case("validationCase.xml", (3, 6), + return _build_poro_elastic_coupling_case("validationCase.xml", (1, 2), ((1, 1, 1), ), description, restartcheck_params) diff --git a/inputFiles/poromechanics/nonlinearAcceleration/validationCase/validationCase.xml b/inputFiles/poromechanics/nonlinearAcceleration/validationCase/validationCase.xml index af9a6c20b5c..9b460dbba01 100755 --- a/inputFiles/poromechanics/nonlinearAcceleration/validationCase/validationCase.xml +++ b/inputFiles/poromechanics/nonlinearAcceleration/validationCase/validationCase.xml @@ -16,12 +16,6 @@ lineSearchAction="None" subcycling="1" nonlinearAccelerationType="Aitken"/> - @@ -36,10 +30,8 @@ newtonTol="1.0e-7" newtonMaxIter="40"/> + solverType="direct" + directParallel="0"/> @@ -54,10 +46,8 @@ newtonTol="1.0e-7" newtonMaxIter="40"/> + solverType="direct" + directParallel="0"/> @@ -89,15 +79,13 @@ nx="{ 5, 11, 5 }" ny="{ 5, 11, 5 }" nz="{ 2, 5, 1, 1, 1, 1, 1 }" - cellBlockNames="{ b00,b01,b02,b03,b04,b05,b06, - b07,b08,b09,b10,b11,b12,b13, - b14,b15,b16,b17,b18,b19,b20, - b21,b22,b23,b24,b25,b26,b27, - b28,b29,b30,b31,b32,b33,b34, - b35,b36,b37,b38,b39,b40,b41, - b42,b43,b44,b45,b46,b47,b48, - b49,b50,b51,b52,b53,b54,b55, - b56,b57,b58,b59,b60,b61,b62 }"> + cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-2_0_0, cb-0_1_0, cb-1_1_0, cb-2_1_0, cb-0_2_0, cb-1_2_0, cb-2_2_0, + cb-0_0_1, cb-1_0_1, cb-2_0_1, cb-0_1_1, cb-1_1_1, cb-2_1_1, cb-0_2_1, cb-1_2_1, cb-2_2_1, + cb-0_0_2, cb-1_0_2, cb-2_0_2, cb-0_1_2, cb-1_1_2, cb-2_1_2, cb-0_2_2, cb-1_2_2, cb-2_2_2, + cb-0_0_3, cb-1_0_3, cb-2_0_3, cb-0_1_3, cb-1_1_3, cb-2_1_3, cb-0_2_3, cb-1_2_3, cb-2_2_3, + cb-0_0_4, cb-1_0_4, cb-2_0_4, cb-0_1_4, cb-1_1_4, cb-2_1_4, cb-0_2_4, cb-1_2_4, cb-2_2_4, + cb-0_0_5, cb-1_0_5, cb-2_0_5, cb-0_1_5, cb-1_1_5, cb-2_1_5, cb-0_2_5, cb-1_2_5, cb-2_2_5, + cb-0_0_6, cb-1_0_6, cb-2_0_6, cb-0_1_6, cb-1_1_6, cb-2_1_6, cb-0_2_6, cb-1_2_6, cb-2_2_6 }"> @@ -167,18 +155,16 @@ @@ -195,7 +181,7 @@ + maxTime="3456000"> @@ -255,7 +241,7 @@ permeabilityComponents="{ 9.869233e-14, 9.869233e-14, 9.869233e-15 }"/> @@ -391,7 +377,7 @@ name="sigma_xx_Res" initialCondition="1" setNames="{ all }" - objectPath="ElementRegions/reservoir/b29" + objectPath="ElementRegions/reservoir/cb-1_1_1" fieldName="skeletonRes_stress" component="0" scale="0.0"/> @@ -407,7 +393,7 @@ name="sigma_yy_Res" initialCondition="1" setNames="{ all }" - objectPath="ElementRegions/reservoir/b29" + objectPath="ElementRegions/reservoir/cb-1_1_1" fieldName="skeletonRes_stress" component="1" scale="0.0"/> @@ -423,7 +409,7 @@ name="sigma_zz_Res" initialCondition="1" setNames="{ all }" - objectPath="ElementRegions/reservoir/b29" + objectPath="ElementRegions/reservoir/cb-1_1_1" fieldName="skeletonRes_stress" component="2" scale="0.0"/> @@ -463,7 +449,7 @@ @@ -481,7 +467,7 @@ diff --git a/inputFiles/poromechanics/poroElasticCoupling.ats b/inputFiles/poromechanics/poroElasticCoupling.ats index 6f3bf4afe32..4627c12c41a 100644 --- a/inputFiles/poromechanics/poroElasticCoupling.ats +++ b/inputFiles/poromechanics/poroElasticCoupling.ats @@ -1,5 +1,4 @@ -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests class Description(object): @@ -223,6 +222,43 @@ def _build_PoroStaircaseCO2PeacemanWell_sequential_cases(): ((1, 1, 1), (2, 2, 1)), description, restartcheck_params) +def _build_PoroStaircaseSinglePhaseStabilized_fim_cases(): + description = Description( + "Staircase single-phase poroelastic problem with pressure jump stabilization ", + "auto", "Ryan Aronson", True) + restartcheck_params = {"atol": 1.0e-5, "rtol": 2.0e-7} + return _build_poro_elastic_coupling_case( + "PoroElastic_staircase_singlephase_3d_fim_stab.xml", (4, 7), + ((1, 1, 1), (2, 2, 1)), description, restartcheck_params) + + +def _build_PoroStaircaseSinglePhaseStabilized_seq_cases(): + description = Description( + "Staircase single-phase poroelastic problem with pressure jump stabilization ", + "auto", "Ryan Aronson", True) + restartcheck_params = {"atol": 1.0e-5, "rtol": 2.0e-7} + return _build_poro_elastic_coupling_case( + "PoroElastic_staircase_singlephase_3d_sequential_stab.xml", (4, 7), + ((1, 1, 1), (2, 2, 1)), description, restartcheck_params) + +def _build_PoroStaircaseCO2Stabilized_fim_cases(): + description = Description( + "Staircase CO2 poroelastic problem with pressure jump stabilization ", + "auto", "Ryan Aronson", True) + restartcheck_params = {"atol": 1.0e-5, "rtol": 2.0e-7} + return _build_poro_elastic_coupling_case( + "PoroElastic_staircase_co2_3d_fim_stab.xml", (4, 7), + ((1, 1, 1), (2, 2, 1)), description, restartcheck_params) + +def _build_PoroStaircaseCO2Stabilized_seq_cases(): + description = Description( + "Staircase CO2 poroelastic problem with pressure jump stabilization ", + "auto", "Ryan Aronson", True) + restartcheck_params = {"atol": 1.0e-5, "rtol": 2.0e-7} + return _build_poro_elastic_coupling_case( + "PoroElastic_staircase_co2_3d_sequential_stab.xml", (4, 7), + ((1, 1, 1), (2, 2, 1)), description, restartcheck_params) + def _build_PoroElasticPEBICO2FIM_cases(): description = Description( "CO2 poroelastic problem with VEM-TPFA (FIM) on a PEBI mesh ", "auto", diff --git a/inputFiles/poromechanics/viscoPlastic.ats b/inputFiles/poromechanics/viscoPlastic.ats index 1f2a7db87fe..b28ff80a6b9 100644 --- a/inputFiles/poromechanics/viscoPlastic.ats +++ b/inputFiles/poromechanics/viscoPlastic.ats @@ -1,5 +1,4 @@ -import geos_ats -from geos_ats.test_builder import generate_geos_tests, RestartcheckParameters, TestDeck +from geos.ats.test_builder import generate_geos_tests, RestartcheckParameters, TestDeck restartcheck_params = {} restartcheck_params["atol"] = 1.0E-5 diff --git a/inputFiles/poromechanicsFractures/DATATABLES/effectiveSigma_xx.csv b/inputFiles/poromechanicsFractures/DATATABLES/effectiveSigma_xx.csv new file mode 100644 index 00000000000..14a2427db2d --- /dev/null +++ b/inputFiles/poromechanicsFractures/DATATABLES/effectiveSigma_xx.csv @@ -0,0 +1,2 @@ +-27621898.34 +0.00 diff --git a/inputFiles/poromechanicsFractures/DATATABLES/effectiveSigma_yy.csv b/inputFiles/poromechanicsFractures/DATATABLES/effectiveSigma_yy.csv new file mode 100644 index 00000000000..a0a8255c490 --- /dev/null +++ b/inputFiles/poromechanicsFractures/DATATABLES/effectiveSigma_yy.csv @@ -0,0 +1,2 @@ +-69831843.20 +0.00 diff --git a/inputFiles/poromechanicsFractures/DATATABLES/effectiveSigma_zz.csv b/inputFiles/poromechanicsFractures/DATATABLES/effectiveSigma_zz.csv new file mode 100644 index 00000000000..83aac38ac24 --- /dev/null +++ b/inputFiles/poromechanicsFractures/DATATABLES/effectiveSigma_zz.csv @@ -0,0 +1,2 @@ +-57898141.60 +0.00 diff --git a/inputFiles/poromechanicsFractures/DATATABLES/porePressure.csv b/inputFiles/poromechanicsFractures/DATATABLES/porePressure.csv new file mode 100644 index 00000000000..3c67d97be4f --- /dev/null +++ b/inputFiles/poromechanicsFractures/DATATABLES/porePressure.csv @@ -0,0 +1,2 @@ +40444400.00 +0.00 diff --git a/inputFiles/poromechanicsFractures/DATATABLES/x.csv b/inputFiles/poromechanicsFractures/DATATABLES/x.csv new file mode 100644 index 00000000000..fb1088c65aa --- /dev/null +++ b/inputFiles/poromechanicsFractures/DATATABLES/x.csv @@ -0,0 +1 @@ +0.00 diff --git a/inputFiles/poromechanicsFractures/DATATABLES/y.csv b/inputFiles/poromechanicsFractures/DATATABLES/y.csv new file mode 100644 index 00000000000..fb1088c65aa --- /dev/null +++ b/inputFiles/poromechanicsFractures/DATATABLES/y.csv @@ -0,0 +1 @@ +0.00 diff --git a/inputFiles/poromechanicsFractures/DATATABLES/z.csv b/inputFiles/poromechanicsFractures/DATATABLES/z.csv new file mode 100644 index 00000000000..1fc446ae0e8 --- /dev/null +++ b/inputFiles/poromechanicsFractures/DATATABLES/z.csv @@ -0,0 +1,2 @@ +-4000.00 +0.00 diff --git a/inputFiles/poromechanicsFractures/Domain_Mesh_FaultModel.vtu b/inputFiles/poromechanicsFractures/Domain_Mesh_FaultModel.vtu new file mode 100644 index 00000000000..0b851b7cea7 --- /dev/null +++ b/inputFiles/poromechanicsFractures/Domain_Mesh_FaultModel.vtu @@ -0,0 +1,50 @@ + + + + + + + AgAAAACAAADoZwAATBgAAMMTAAA=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 + + + + + AgAAAACAAACAOwAAzgAAAC8AAAA=eJzt0iEKQwEQQ8G29z90xXeFiEDEUuaZcVH5vJ4+JEmSJEmSJEmSJEmSJEmSJEmSJEmSJEky9v7xX/bIxtSVP6/3yMbUlT+v98jG1JU/r/fIxtSVP6/3yMbUlT+v98jG1JU/r/fIxtSVP6/3yMbUlT+v98jG1JU/r/fIxtSVP6/3yMbUlT+v98jG1JU/r/fIxtSVP6/3yMbUlT+v98jG1JU/r/fIxtSVP6/3yMbUlT+v98jG1JU/r/fIxtSVP6/3yMbUlT+v9/j0BcUYHgl4nO3FMQ0AAAACIGf/0B7WgIfmatu2bdu2bdu2bdu2bdu2bdu2bdu2bTsDGPUO4Q== + + + AgAAAACAAACAOwAAUQAAADUAAAA=eJztxTERADAIBLC/w0PNsmAWHxVCsmT2dSUZ27Zt27Zt27Zt27Zt27Zt27Zt27Zt27Zt27Zt27Zt27Zt27Zt27Zt27Zt27Zt27YP/wFH9JHSeJztxTENAAAIA7AleMAsD2bxgZH26V5PJVnbtm3btm3btm3btm3btm3btm3btm3beaYkrMM= + + + AgAAAACAAACAOwAANAAAACUAAAA=eJztwQEBAAAAgJD+r+4ICgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYgAAAAXic7cExAQAAAMKg9U/tZQugAAAAAAAAAAAAAAAAAACAGzuAAAE= + + + AgAAAACAAACAOwAATBgAAGULAAA=eJw13dMWIMqSBcDbtm3btm3btm3btm3btm3bdvc8TJx6iU+olVWZO//3v/8/ARiQgRiYQRiUwRicIRiSoRiaYRiW4RieERiRkRiZURiV0RidMRiTsRibcRiX8RifCZiQiZiYSZiUyZicKZiSqZiaaZiW6ZieGZiRmZiZWZiV2ZidOZiTuZibeZiX+ZifBViQhViYRViUxVicJViSpViaZViW5VieFViRlViZVViV1VidNViTtVibdViX9VifDdiQjdiYTdiUzdicLdiSrdiabdiW7dieHdiRndiZXdiV3didPdiTvdibfdiX/difAziQgziYQziUwzicIziSoziaYziW4zieEziRkziZUziV0zidMziTszibcziX8zifC7iQi7iYS7iUy7icK7iSq7iaa7iW67ieG7iRm7iZW7iV27idO7iTu7ibe7iX+7ifB3iQh3iYR3iUx3icJ3iSp3iaZ3iW53ieF3iRl3iZV3iV13idN3iTt3ibd3iX93ifD/iQj/iYT/iUz/icL/iSr/iab/iW7/ieH/iRn/iZX/iV3/idP/iTv/ibf/iX//jfxR+AARmIgRmEQRmMwRmCIRmKoRmGYRmO4RmBERmJkRmFURmN0RmDMRmLsRmHcRmP8ZmACZmIiZmESZmMyZmCKZmKqZmGaZmO6ZmBGZmJmZmFWZmN2ZmDOZmLuZmHeZmP+VmABVmIhVmERVmMxVmCJVmKpVmGZVmO5VmBFVmJlVmFVVmN1VmDNVmLtVmHdVmP9dmADdmIjdmETdmMzdmCLdmKrdmGbdmO7dmBHdmJndmFXdmN3dmDPdmLvdmHfdmP/TmAAzmIgzmEQzmMwzmCIzmKozmGYzmO4zmBEzmJkzmFUzmN0zmDMzmLszmHczmP87mAC7mIi7mES7mMy7mCK7mKq7mGa7mO67mBG7mJm7mFW7mN27mDO7mLu7mHe7mP+3mAB3mIh3mER3mMx3mCJ3mKp3mGZ3mO53mBF3mJl3mFV3mN13mDN3mLt3mHd3mP9/mAD/mIj/mET/mMz/mCL/mKr/mGb/mO7/mBH/mJn/mFX/mN3/mDP/mLv/mHf/mP/xX8ARiQgRiYQRiUwRicIRiSoRiaYRiW4RieERiRkRiZURiV0RidMRiTsRibcRiX8RifCZiQiZiYSZiUyZicKZiSqZiaaZiW6ZieGZiRmZiZWZiV2ZidOZiTuZibeZiX+ZifBViQhViYRViUxVicJViSpViaZViW5VieFViRlViZVViV1VidNViTtVibdViX9VifDdiQjdiYTdiUzdicLdiSrdiabdiW7dieHdiRndiZXdiV3didPdiTvdibfdiX/difAziQgziYQziUwzicIziSoziaYziW4zieEziRkziZUziV0zidMziTszibcziX8zifC7iQi7iYS7iUy7icK7iSq7iaa7iW67ieG7iRm7iZW7iV27idO7iTu7ibe7iX+7ifB3iQh3iYR3iUx3icJ3iSp3iaZ3iW53ieF3iRl3iZV3iV13idN3iTt3ibd3iX93ifD/iQj/iYT/iUz/icL/iSr/iab/iW7/ieH/iRn/iZX/iV3/idP/iTv/ibf/iX//jfQ38ABmQgBmYQBmUwBmcIhmQohmYYhmU4hmcERmQkRmYURmU0RmcMxmQsxmYcxmU8xmcCJmQiJmYSJmUyJmcKpmQqpmYapmU6pmcGZmQmZmYWZmU2ZmcO5mQu5mYe5mU+5mcBFmQhFmYRFmUxFmcJlmQplmYZlmU5lmcFVmQlVmYVVmU1VmcN1mQt1mYd1mU91mcDNmQjNmYTNmUzNmcLtmQrtmYbtmU7tmcHdmQndmYXdmU3dmcP9mQv9mYf9mU/9ucADuQgDuYQDuUwDucIjuQojuYYjuU4jucETuQkTuYUTuU0TucMzuQszuYczuU8zucCLuQiLuYSLuUyLucKruQqruYaruU6rucGbuQmbuYWbuU2bucO7uQu7uYe7uU+7ucBHuQhHuYRHuUxHucJnuQpnuYZnuU5nucFXuQlXuYVXuU1XucN3uQt3uYd3uU93ucDPuQjPuYTPuUzPucLvuQrvuYbvuU7vucHfuQnfuYXfuU3fucP/uQv/uYf/uU//vfBH4ABGYiBGYRBGYzBGYIhGYqhGYZhGY7hGYERGYmRGYVRGY3RGYMxGYuxGYdxGY/xmYAJmYiJmYRJmYzJmYIpmYqpmYZpmY7pmYEZmYmZmYVZmY3ZmYM5mYu5mYd5mY/5WYAFWYiFWYRFWYzFWYIlWYqlWYZlWY7lWYEVWYmVWYVVWY3VWYM1WYu1WYd1WY/12YAN2YiN2YRN2YzN2YIt2Yqt2YZt2Y7t2YEd2Ymd2YVd2Y3d2YM92Yu92Yd92Y/9OYADOYiDOYRDOYzDOYIjOYqjOYZjOY7jOYETOYmTOYVTOY3TOYMzOYuzOYdzOY/zuYALuYiLuYRLuYzLuYIruYqruYZruY7ruYEbuYmbuYVbuY3buYM7uYu7uYd7uY/7eYAHeYiHeYRHeYzHeYIneYqneYZneY7neYEXeYmXeYVXeY3XeYM3eYu3eYd3eY/3+YAP+YiP+YRP+YzP+YIv+Yqv+YZv+Y7v+YEf+Ymf+YVf+Y3f+YM/+Yu/+Yd/+Y//NfYFYEAGYmAGYVAGY3CGYEiGYmiGYViGY3hGYERGYmRGYVRGY3TGYEzGYmzGYVzGY3wmYEImYmImYVImY3KmYEqmYmqmYVqmY3pmYEZmYmZmYVZmY3bmYE7mYm7mYV7mY34WYEEWYmEWYVEWY3GWYEmWYmmWYVmWY3lWYEVWYmVWYVVWY3XWYE3WYm3WYV3WY302YEM2YmM2YVM2Y3O2YEu2Ymu2YVu2Y3t2YEd2Ymd2YVd2Y3f2YE/2Ym/2YV/2Y38O4EAO4mAO4VAO43CO4EiO4miO4ViO43hO4ERO4mRO4VRO43TO4EzO4mzO4VzO43wu4EIu4mIu4VIu43Ku4Equ4mqu4Vqu43pu4EZu4mZu4VZu43bu4E7u4m7u4V7u434e4EEe4mEe4VEe43Ge4Eme4mme4Vme43le4EVe4mVe4VVe43Xe4E3e4m3e4V3e430+4EM+4mM+4VM+43O+4Eu+4mu+4Vu+43t+4Ed+4md+4Vd+43f+4E/+4m/+4V/+438N/QEYkIEYmEEYlMEYnCEYkqEYmmEYluEYnhEYkZEYmVEYldEYnTEYk7EYm3EYl/EYnwmYkImYmEmYlMmYnCmYkqmYmmmYlumYnhmYkZmYmVmYldmYnTmYk7mYm3mYl/mYnwVYkIVYmEVYlMVYnCVYkqVYmmVYluVYnhVYkZVYmVVYldVYnTVYk7VYm3VYl/VYnw3YkI3YmE3YlM3YnC3Ykq3Ymm3Ylu3Ynh3YkZ3YmV3Yld3YnT3Yk73Ym33Yl/3YnwM4kIM4mEM4lMM4nCM4kqM4mmM4luM4nhM4kZM4mVM4ldM4nTM4k7M4m3M4l/M4nwu4kIu4mEu4lMu4nCu4kqu4mmu4luu4nhu4kZu4mVu4ldu4nTu4k7u4m3u4l/u4nwd4kId4mEd4lMd4nCd4kqd4mmd4lud4nhd4kZd4mVd4ldd4nTd4k7d4m3d4l/d4nw/4kI/4mE/4lM/4nC/4kq/4mm/4lu/4nh/4kZ/4mV/4ld/4nT/4k7/4m3/4l//43yBfAAZkIAZmEAZlMAZnCIZkKIZmGIZlOIZnBEZkJEZmFEZlNEZnDMZkLMZmHMZlPMZnAiZkIiZmEiZlMiZnCqZkKqZmGqZlOqZnBmZkJmZmFmZlNmZnDuZkLuZmHuZlPuZnARZkIRZmERZlMRZnCZZkKZZmGZZlOZZnBVZkJVZmFVZlNVZnDdZkLdZmHdZlPdZnAzZkIzZmEzZlMzZnC7ZkK7ZmG7ZlO7ZnB3ZkJ3ZmF3ZlN3ZnD/ZkL/ZmH/ZlP/bnAA7kIA7mEA7lMA7nCI7kKI7mGI7lOI7nBE7kJE7mFE7lNE7nDM7kLM7mHM7lPM7nAi7kIi7mEi7lMi7nCq7kKq7mGq7lOq7nBm7kJm7mFm7lNm7nDu7kLu7mHu7lPu7nAR7kIR7mER7lMR7nCZ7kKZ7mGZ7lOZ7nBV7kJV7mFV7lNV7nDd7kLd7mHd7lPd7nAz7kIz7mEz7lMz7nC77kK77mG77lO77nB37kJ37mF37lN37nD/7kL/7mH/7lP/43wB+AARmIgRmEQRmMwRmCIRmKoRmGYRmO4RmBERmJkRmFURmN0RmDMRmLsRmHcRmP8ZmACZmIiZmESZmMyZmCKZmKqZmGaZmO6ZmBGZmJmZmFWZmN2ZmDOZmLuZmHeZmP+VmABVmIhVmERVmMxVmCJVmKpVmGZVmO5VmBFVmJlVmFVVmN1VmDNVmLtVmHdVmP9dmADdmIjdmETdmMzdmCLdmKrdmGbdmO7dmBHdmJndmFXdmN3dmDPdmLvdmHfdmP/TmAAzmIgzmEQzmMwzmCIzmKozmGYzmO4zmBEzmJkzmFUzmN0zmDMzmLszmHczmP87mAC7mIi7mES7mMy7mCK7mKq7mGa7mO67mBG7mJm7mFW7mN27mDO7mLu7mHe7mP+3mAB3mIh3mER3mMx3mCJ3mKp3mGZ3mO53mBF3mJl3mFV3mN13mDN3mLt3mHd3mP9/mAD/mIj/mET/mMz/mCL/mKr/mGb/mO7/mBH/mJn/mFX/mN3/mDP/mLv/mHf/mP/wX3BGBABmJgBmFQBmNwhmBIhmJohmFYhmN4RmBERmJkRmFURmN0xmBMxmJsxmFcxmN8JmBCJmJiJmFSJmNypmBKpmJqpmFapmN6ZmBGZmJmZmFWZmN25mBO5mJu5mFe5mN+FmBBFmJhFmFRFmNxlmBJlmJplmFZlmN5VmBFVmJlVmFVVmN11mBN1mJt1mFd1mN9NmBDNmJjNmFTNmNztmBLtmJrtmFbtmN7dmBHdmJndmFXdmN39mBP9mJv9mFf9mN/DuBADuJgDuFQDuNwjuBIjuJojuFYjuN4TuBETuJkTuFUTuN0zuBMzuJszuFczuN8LuBCLuJiLuFSLuNyruBKruJqruFaruN6buBGbuJmbuFWbuN27uBO7uJu7uFe7uN+HuBBHuJhHuFRHuNxnuBJnuJpnuFZnuN5XuBFXuJlXuFVXuN13uBN3uJt3uFd3uN9PuBDPuJjPuFTPuNzvuBLvuJrvuFbvuN7fuBHfuJnfuFXfuN3/uBP/uJv/uFf/uN/gX0BGJCBGJhBGJTBGJwhGJKhGJphGJbhGJ4RGJGRGJlRGJXRGJ0xGJOxGJtxGJfxGJ8JmJCJmJhJmJTJmJwpmJKpmJppmJbpmJ4ZmJGZmJlZmJXZmJ05mJO5mJt5mJf5mJ8FWJCFWJhFWJTFWJwlWJKlWJplWJblWJ4VWJGVWJlVWJXVWJ01WJO1WJt1WJf1WJ8N2JCN2JhN2JTN2Jwt2JKt2Jpt2Jbt2J4d2JGd2Jld2JXd2J092JO92Jt92Jf92J8DOJCDOJhDOJTDOJwjOJKjOJpjOJbjOJ4TOJGTOJlTOJXTOJ0zOJOzOJtzOJfzOJ8LuJCLuJhLuJTLuJwruJKruJpruJbruJ4buJGbuJlbuJXbuJ07uJO7uJt7uJf7uJ8HeJCHeJhHeJTHeJwneJKneJpneJbneJ4XeJGXeJlXeJXXeJ03eJO3eJt3eJf3eJ8P+JCP+JhP+JTP+Jwv+JKv+Jpv+Jbv+J4f+JGf+Jlf+JXf+J0/+JO/+Jt/+Jf/+F9QbwAGZCAGZhAGZTAGZwiGZCiGZhiGZTiGZwRGZCRGZhRGZTRGZwzGZCzGZhzGZTzGZwImZCImZhImZTImZwqmZCqmZhqmZTqmZwZmZCZmZhZmZTZmZw7mZC7mZh7mZT7mZwEWZCEWZhEWZTEWZwmWZCmWZhmWZTmWZwVWZCVWZhVWZTVWZw3WZC3WZh3WZT3WZwM2ZCM2ZhM2ZTM2Zwu2ZCu2Zhu2ZTu2Zwd2ZCd2Zhd2ZTd2Zw/2ZC/2Zh/2ZT/25wAO5CAO5hAO5TAO5wiO5CiO5hiO5TiO5wRO5CRO5hRO5TRO5wzO5CzO5hzO5TzO5wIu5CIu5hIu5TIu5wqu5Cqu5hqu5Tqu5wZu5CZu5hZu5TZu5w7u5C7u5h7u5T7u5wEe5CEe5hEe5TEe5wme5Cme5hme5Tme5wVe5CVe5hVe5TVe5w3e5C3e5h3e5T3e5wM+5CM+5hM+5TM+5wu+5Cu+5hu+5Tu+5wd+5Cd+5hd+5Td+5w/+5C/+5h/+5T/+F9AfgAEZiIEZhEEZjMEZgiEZiqEZhmEZjuEZgREZiZEZhVEZjdEZgzEZi7EZh3EZj/GZgAmZiImZhEmZjMmZgimZiqmZhmmZjumZgRmZiZmZhVmZjdmZgzmZi7mZh3mZj/lZgAVZiIVZhEVZjMVZgiVZiqVZhmVZjuVZgRVZiZVZhVVZjdVZgzVZi7VZh3VZj/XZgA3ZiI3ZhE3ZjM3Zgi3Ziq3Zhm3Zju3ZgR3ZiZ3ZhV3Zjd3Zgz3Zi73Zh33Zj/05gAM5iIM5hEM5jMM5giM5iqM5hmM5juM5gRM5iZM5hVM5jdM5gzM5i7M5h3M5j/O5gAu5iIu5hEu5jMu5giu5iqu5hmu5juu5gRu5iZu5hVu5jdu5gzu5i7u5h3u5j/t5gAd5iId5hEd5jMd5gid5iqd5hmd5jud5gRd5iZd5hVd5jdd5gzd5i7d5h3d5j/f5gA/5iI/5hE/5jM/5gi/5iq/5hm/5ju/5gR/5iZ/5hV/5jd/5gz/5i7/5h3/5j/8t5gnAgAzEwAzCoAzG4AzBkAzF0AzDsAzH8IzAiIzEyIzCqIzG6IzBmIzF2IzDuIzH+EzAhEzExEzCpEzG5EzBlEzF1EzDtEzH9MzAjMzEzMzCrMzG7MzBnMzF3MzDvMzH/CzAgizEwizCoizG4izBkizF0izDsizH8qzAiqzEyqzCqqzG6qzBmqzF2qzDuqzH+mzAhmzExmzCpmzG5mzBlmzF1mzDtmzH9uzAjuzEzuzCruzG7uzBnuzF3uzDvuzH/hzAgRzEwRzCoRzG4RzBkRzF0RzDsRzH8ZzAiZzEyZzCqZzG6ZzBmZzF2ZzDuZzH+VzAhVzExVzCpVzG5VzBlVzF1VzDtVzH9dzAjdzEzdzCrdzG7dzBndzF3dzDvdzH/TzAgzzEwzzCozzG4zzBkzzF0zzDszzH87zAi7zEy7zCq7zG67zBm7zF27zDu7zH+3zAh3zEx3zCp3zG53zBl3zF13zDt3zH9/zAj/zEz/zCr/zG7/zBn/zF3/zDv/zH/xbyBWBABmJgBmFQBmNwhmBIhmJohmFYhmN4RmBERmJkRmFURmN0xmBMxmJsxmFcxmN8JmBCJmJiJmFSJmNypmBKpmJqpmFapmN6ZmBGZmJmZmFWZmN25mBO5mJu5mFe5mN+FmBBFmJhFmFRFmNxlmBJlmJplmFZlmN5VmBFVmJlVmFVVmN11mBN1mJt1mFd1mN9NmBDNmJjNmFTNmNztmBLtmJrtmFbtmN7dmBHdmJndmFXdmN39mBP9mJv9mFf9mN/DuBADuJgDuFQDuNwjuBIjuJojuFYjuN4TuBETuJkTuFUTuN0zuBMzuJszuFczuN8LuBCLuJiLuFSLuNyruBKruJqruFaruN6buBGbuJmbuFWbuN27uBO7uJu7uFe7uN+HuBBHuJhHuFRHuNxnuBJnuJpnuFZnuN5XuBFXuJlXuFVXuN13uBN3uJt3uFd3uN9PuBDPuJjPuFTPuNzvuBLvuJrvuFbvuN7fuBHfuJnfuFXfuN3/uBP/uJv/uFf/uN/i3gDMCADMTCDMCiDMThDMCRDMTTDMCzDMTwjMCIjMTKjMCqjMTpjMCZjMTbjMC7jMT4TMCETMTGTMCmTMTlTMCVTMTXTMC3TMT0zMCMzMTOzMCuzMTtzMCdzMTfzMC/zMT8LsCALsTCLsCiLsThLsCRLsTTLsCzLsTwrsCIrsTKrsCqrsTprsCZrsTbrsC7rsT4bsCEbsTGbsCmbsTlbsCVbsTXbsC3bsT07sCM7sTO7sCu7sTt7sCd7sTf7sC/7sT8HcCAHcTCHcCiHcThHcCRHcTTHcCzHcTwncCIncTKncCqncTpncCZncTbncC7ncT4XcCEXcTGXcCmXcTlXcCVXcTXXcC3XcT03cCM3cTO3cCu3cTt3cCd3cTf3cC/3cT8P8CAP8TCP8CiP8ThP8CRP8TTP8CzP8Twv8CIv8TKv8Cqv8Tpv8CZv8Tbv8C7v8T4f8CEf8TGf8Cmf8Tlf8CVf8TXf8C3f8T0/8CM/8TO/8Cu/8Tt/8Cd/8Tf/8C//8f8AkFtweXicLcVDEBgGAgDA2LZt27Zt2zYb27Zt27adtLFt42Yuu58NECHA/wV0IAd2EAd1MAd3CId0KId2GId1OId3BEd0JEd2FEd1NEd3DMd0LMd2HMd1PMd3Aid0Iid2Eid1Mid3Cqd0Kqd2Gqd1Oqd3Bmd0Jmd2Fmd1Nmd3Dud0Lud2Hud1Pud3ARd0IRd2ERd1MRd3CZd0KZd2GZd1OZd3BVd0JVd2FVd1NVd3Ddd0Ldd2Hdd1Pdd3Azd0Izd2Ezd1Mzd3C7d0K7d2G7d1O7d3B3d0J3d2F3d1N3d3D/d0L/d2H/f1P+7n/h7ggR7kwR7ioR7m4R7hkR7l0R7jsR7n8Z7giZ7kyZ7iqZ7m6Z7hmZ7l2Z7juZ7n+V7ghV7kxV7ipV7m5V7hlV7l1V7jtV7n9d7gjd7kzd7ird7m7d7hnd7l3d7jvd7n/T7ggz7kwz7ioz7m4z7hkz7l0z7jsz7n877gi77ky77iq77m677hm77lf/2fb/uO7/qe7/uBH/qRH/uJn/qZn/uFX/qVX/uN3/qd3/uDP/qTP/uLv/qbv/uHf/qXf/uPA0T8W0AHcmAHcVAHc3CHcEiHcmiHcViHc3hHcERHcmRHcVRHc3THcEzHcmzHcVzHc3wncEIncmIncVInc3KncEqncmqncVqnc3pncEZncmZncVZnc3bncE7ncm7ncV7nc34XcEEXcmEXcVEXc3GXcEmXcmmXcVmXc3lXcEVXcmVXcVVXc3XXcE3Xcm3XcV3Xc303cEM3cmM3cVM3c3O3cEu3cmu3cVu3c3t3cEd3cmd3cVd3c3f3cE/3cm/3cV//437u7wEe6EEe7CEe6mEe7hEe6VEe7TEe63Ee7wme6Eme7Cme6mme7hme6Vme7Tme63me7wVe6EVe7CVe6mVe7hVe6VVe7TVe63Ve7w3e6E3e7C3e6m3e7h3e6V3e7T3e633e7wM+6EM+7CM+6mM+7hM+6VM+7TM+63M+7wu+6Eu+7Cu+6mu+7hu+6Vv+1//5tu/4ru/5vh/4oR/5sZ/4qZ/5uV/4pV/5td/4rd/5vT/4oz/5s7/4q7/5u3/4p3/5t/84QKS/BXQgB3YQB3UwB3cIh3Qoh3YYh3U4h3cER3QkR3YUR3U0R3cMx3Qsx3Ycx3U8x3cCJ3QiJ3YSJ3UyJ3cKp3Qqp3Yap3U6p3cGZ3QmZ3YWZ3U2Z3cO53Qu53Ye53U+53cBF3QhF3YRF3UxF3cJl3Qpl3YZl3U5l3cFV3QlV3YVV3U1V3cN13Qt13Yd13U913cDN3QjN3YTN3UzN3cLt3Qrt3Ybt3U7t3cHd3Qnd3YXd3U3d3cP93Qv93Yf9/U/7uf+HuCBHuTBHuKhHubhHuGRHuXRHuOxHufxnuCJnuTJnuKpnubpnuGZnuXZnuO5nuf5XuCFXuTFXuKlXublXuGVXuXVXuO1Xuf13uCN3uTN3uKt3ubt3uGd3uXd3uO93uf9PuCDPuTDPuKjPubjPuGTPuXTPuOzPufzvuCLvuTLvuKrvubrvuGbvuV//Z9v+47v+p7v+4Ef+pEf+4mf+pmf+4Vf+pVf+43f+p3f+4M/+pM/+4u/+pu/+4d/+pd/+48DRP5bQAdyYAdxUAdzcIdwSIdyaIdxWIdzeEdwREdyZEdxVEdzdMdwTMdybMdxXMdzfCdwQidyYidxUidzcqdwSqdyaqdxWqdzemdwRmdyZmdxVmdzdudwTudybudxXudzfhdwQRdyYRdxURdzcZdwSZdyaZdxWZdzeVdwRVdyZVdxVVdzdddwTddybddxXddzfTdwQzdyYzdxUzdzc7dwS7dya7dxW7dze3dwR3dyZ3dxV3dzd/dwT/dyb/dxX//jfu7vAR7oQR7sIR7qYR7uER7pUR7tMR7rcR7vCZ7oSZ7sKZ7qaZ7uGZ7pWZ7tOZ7reZ7vBV7oRV7sJV7qZV7uFV7pVV7tNV7rdV7vDd7oTd7sLd7qbd7uHd7pXd7tPd7rfd7vAz7oQz7sIz7qYz7uEz7pUz7tMz7rcz7vC77oS77sK77qa77uG77pW/7X//m27/iu7/m+H/ihH/mxn/ipn/m5X/ilX/m13/it3/m9P/ijP/mzv/irv/m7f/inf/m3/zhAlL8FdCAHdhAHdTAHdwiHdCiHdhiHdTiHdwRHdCRHdhRHdTRHdwzHdCzHdhzHdTzHdwIndCIndhIndTIndwqndCqndhqndTqndwZndCZndhZndTZndw7ndC7ndh7ndT7ndwEXdCEXdhEXdTEXdwmXdCmXdhmXdTmXdwVXdCVXdhVXdTVXdw3XdC3Xdh3XdT3XdwM3dCM3dhM3dTM3dwu3dCu3dhu3dTu3dwd3dCd3dhd3dTd3dw/3dC/3dh/39T/u5/4e4IEe5MEe4qEe5uEe4ZEe5dEe47Ee5/Ge4Ime5Mme4qme5ume4Zme5dme47me5/le4IVe5MVe4qVe5uVe4ZVe5dVe47Ve5/Xe4I3e5M3e4q3e5u3e4Z3e5d3e473e5/0+4IM+5MM+4qM+5uM+4ZM+5dM+47M+5/O+4Iu+5Mu+4qu+5uu+4Zu+5X/9n2/7ju/6nu/7gR/6kR/7iZ/6mZ/7hV/6lV/7jd/6nd/7gz/6kz/7i7/6m7/7h3/6l3/7jwNE/VtAB3JgB3FQB3Nwh3BIh3Joh3FYh3N4R3BER3JkR3FUR3N0x3BMx3Jsx3Fcx3N8J3BCJ3JiJ3FSJ3Nyp3BKp3Jqp3Fap3N6Z3BGZ3JmZ3FWZ3N253BO53Ju53Fe53N+F3BBF3JhF3FRF3Nxl3BJl3Jpl3FZl3N5V3BFV3JlV3FVV3N113BN13Jt13Fd13N9N3BDN3JjN3FTN3Nzt3BLt3Jrt3Fbt3N7d3BHd3Jnd3FXd3N393BP93Jv93Ff/+N+7u8BHuhBHuwhHuphHu4RHulRHu0xHutxHu8JnuhJnuwpnuppnu4ZnulZnu05nut5nu8FXuhFXuwlXuplXu4VXulVXu01Xut1Xu8N3uhN3uwt3upt3u4d3uld3u093ut93u8DPuhDPuwjPupjPu4TPulTPu0zPutzPu8LvuhLvuwrvuprvu4bvulb/tf/+bbv+K7v+b4f+KEf+bGf+Kmf+blf+KVf+bXf+K3f+b0/+KM/+bO/+Ku/+bt/+Kd/+bf/OEC0vwV0IAd2EAd1MAd3CId0KId2GId1OId3BEd0JEd2FEd1NEd3DMd0LMd2HMd1PMd3Aid0Iid2Eid1Mid3Cqd0Kqd2Gqd1Oqd3Bmd0Jmd2Fmd1Nmd3Dud0Lud2Hud1Pud3ARd0IRd2ERd1MRd3CZd0KZd2GZd1OZd3BVd0JVd2FVd1NVd3Ddd0Ldd2Hdd1Pdd3Azd0Izd2Ezd1Mzd3C7d0K7d2G7d1O7d3B3d0J3d2F3d1N3d3D/d0L/d2H/f1P+7n/h7ggR7kwR7ioR7m4R7hkR7l0R7jsR7n8Z7giZ7kyZ7iqZ7m6Z7hmZ7l2Z7juZ7n+V7ghV7kxV7ipV7m5V7hlV7l1V7jtV7n9d7gjd7kzd7ird7m7d7hnd7l3d7jvd7n/T7ggz7kwz7ioz7m4z7hkz7l0z7jsz7n877gi77ky77iq77m677hm77lf/2fb/uO7/qe7/uBH/qRH/uJn/qZn/uFX/qVX/uN3/qd3/uDP/qTP/uLv/qbv/uHf/qXf/uPA0T/W0AHcmAHcVAHc3CHcEiHcmiHcViHc3hHcERHcmRHcVRHc3THcEzHcmzHcVzHc3wncEIncmIncVInc3KncEqncmqncVqnc3pncEZncmZncVZnc3bncE7ncm7ncV7nc34XcEEXcmEXcVEXc3GXcEmXcmmXcVmXc3lXcEVXcmVXcVVXc3XXcE3Xcm3XcV3Xc303cEM3cmM3cVM3c3O3cEu3cmu3cVu3c3v/D7sXJBU= + + + + + AwAAAACAAADcWwAAvxUAAEoWAABFEAAAeJxN2rGNZFmOheFwYFQKK5W4DqxewPAasA4s6uhjwUptBeX2Y5QWmH4MpvxY7IuMS57/AQmcyGEwv+K9j6P0649/fr3eP6//fX4KWcjBmnZ+Hv8+UX/QB7mc//gn8+dvj2GzkIM17fx+ygbXH/RBLue3wfn+vTEIBsEgGASDYBAMgkEwCAbBEDAEDAFDwBAwBAwBQ8AQMAQMAcO7755F4ywaZ9E2TP4+i7Zh6w/6IJfz5yzahvczhslCDta08zxj2PqDPsjl/G3YfL+/c0jMITGHxBwSc0jMITGHxBwSc0jMIW14f2fvw8F9OLgPx4bJ3/fh2LD1B32Qy/lzH44NgkEwCAbBIBgEg2AQDIJBMAiGgqFgKBgKhoKhYCgYCoaCoWAoG74/7560YXOwpp2/96QNrj/og1zOnz1Jw9fr1z/GcLOQgzXtfHf15/eJ+oM+yOU8u/qTP397DJuFHKxp57urx+D6gz7I5Ty7eg2CQTAIBsEgGASDYBAMgkEwCIaAIWAIGAKGgCFgCBgChoAhYAgYnr4+i8ZZNM6ibZh8d7XPom3YPsjlPLt6Dc+zhslCDta0833WsPUHfZDLeXa155CYQ2IOiTkk5pCYQ2IOiTkk5pCYQ2IOacPzHd+Hg/twcB+ODZPvrvZ9ODZsH+Rynl3t9wIGwSAYBINgEAyCQTAIBsEgGAqGgqFgKBgKhoKhYCgYCoaCoWx4f/aetGFzsKad7672nrTBfZDLeXa1DV+vv/5nDDcLOVjTzndXf36fqD/og1zOs6s/+fO3x7BZyMGadr67egyuP+iDXM6zq9cgGASDYBAMgkEwCAbBIBgEg2AIGAKGgCFgCBgChoAhYAgYAoaA4enrs2icReMs2obJd1f7LNqG7YNczrOr1/A8a5gs5GBNO99nDVt/0Ae5nGdXew6JOSTmkJhDYg6JOSTmkJhDYg6JOSTmkDY83/F9OLgPB/fh2DD57mrfh2PD9kEu59nVfi9gEAyCQTAIBsEgGASDYBAMgqFgKBgKhoKhYCgYCoaCoWAoGMqG92fvSRs2B2va+e5q70kb3Ae5nGdX2/D1+vHfY7hZyMGadr67+vP7RP1BH+Rynl39yZ+/PYbNQg7WtPPd1WNw/UEf5HKeXb0GwSAYBINgEAyCQTAIBsEgGARDwBAwBAwBQ8AQMAQMAUPAEDAEDE9fn0XjLBpn0TZMvrvaZ9E2bB/kcp5dvYbnWcNkIQdr2vk+a9j6gz7I5Ty72nNIzCExh8QcEnNIzCExh8QcEnNIzCExh7Th+Y7vw8F9OLgPx4bJd1f7Phwbtg9yOc+u9nsBg2AQDIJBMAgGwSAYBINgEAwFQ8FQMBQMBUPBUDAUDAVDwVA2vD97T9qwOVjTzndXe0/a4D7I5Ty72obn5+9juFnIwZp2vrv68/tE/UEf5HKeXf3J92//fc7Chs3Bmna+u3oMrj/og1zOs6vXIBgEg2AQDIJBMAgGwSAYBINgCBgChoAhYAgYAoaAIWAIGAKGgOF9xnsWjbNonEXbMPnuap9F27B9kMt5dvUa3ndrDJOFHKxp5/usYesP+iCX8+xqzyExh8QcEnNIzCExh8QcEnNIzCExh8Qc0ob3u7T34eA+HNyHY8Pku6t9H44N2we5nGdX+72AQTAIBsEgGASDYBAMgkEwCIaCoWAoGAqGgqFgKBgKhoKhYCgbvnfW7kkbNgdr2vnuau9JG9wHuZxnV9vw9frXf43hZiEHa9r57urP7xP1B32Qy3l29Sd//vYYNgs5WNPOd1ePwfUHfZDLeXb1GgSDYBAMgkEwCAbBIBgEg2AQDAFDwBAwBAwBQ8AQMAQMAUPAEDA8fX0WjbNonEXbMPnuap9F27B9kMt5dvUanmcNk4UcrGnn+6xh6w/6IJfz7GrPITGHxBwSc0jMITGHxBwSc0jMITGHxBzShuc7vg8H9+HgPhwbJt9d7ftwbNg+yOU8u9rvBQyCQTAIBsEgGASDYBAMgkEwFAwFQ8FQMBQMBUPBUDAUDAVD2fD+7D1pw+ZgTTvfXe09aYP7IJfz7Gobvl4//3MMNws5WNPOd1d/fp+oP+iDXM6zqz/587fHsFnIwZp2vrt6DK4/6INczrOr1yAYBINgEAyCQTAIBsEgGASDYAgYAoaAIWAIGAKGgCFgCBgChoDh6euzaJxF4yzahsl3V/ss2obtg1zOs6vX8DxrmCzkYE0732cNW3/QB7mcZ1d7Dok5JOaQmENiDok5JOaQmENiDok5JOaQNjzf8X04uA8H9+HYMPnuat+HY8P2QS7n2dV+L2AQDIJBMAgGwSAYBINgEAyCoWAoGAqGgqFgKBgKhoKhYCgYyob3Z+9JGzYHa9r57mrvSRvcB7mcZ1fb8PX68z/GcLOQgzXtfHf15/eJ+oM+yOU8u/qTP397DJuFHKxp57urx+D6gz7I5Ty7eg2CQTAIBsEgGASDYBAMgkEwCIaAIWAIGAKGgCFgCBgChoAhYAgYnr4+i8ZZNM6ibZh8d7XPom3YPsjlPLt6Dc+zhslCDta0833WsPUHfZDLeXa155CYQ2IOiTkk5pCYQ2IOiTkk5pCYQ2IOacPzHd+Hg/twcB+ODZPvrvZ9ODZsH+Rynl3t9wIGwSAYBINgEAyCQTAIBsEgGAqGgqFgKBgKhoKhYCgYCoaCoWx4f/aetGFzsKad7672nrTBfZDLeXa1Dc///rcx3CzkYE073139+X2i/qAPcjnPrv7kewZ/m7OwYXOwpp3vrh6D6w/6IJfz7Oo1CAbBIBgEg2AQDIJBMAgGwSAYAoaAIWAIGAKGgCFgCBgChoAhYHj33bNonEXjLNqGyXdX+yzahu2DXM6zq9fwfsYwWcjBmnaeZwxbf9AHuZxnV3sOiTkk5pCYQ2IOiTkk5pCYQ2IOiTkk5pA2vL+z9+HgPhzch2PD5LurfR+ODdsHuZxnV/u9gEEwCAbBIBgEg2AQDIJBMAiGgqFgKBgKhoKhYCgYCoaCoWAoG74/7560YXOwpp3vrvaetMF9kMt5drUNX6+//q93V39nIQdr2vnu6s/vE/UHfZDLeXb1J3/+/WPYLORgTTvfXT0G1x/0QS7n2dVrEAyCQTAIBsEgGASDYBAMgkEwBAwBQ8AQMAQMAUPAEDAEDAFDwPD09Vk0zqJxFm3D5LurfRZtw/ZBLufZ1Wt4njVMFnKwpp3vs4atP+iDXM6zqz2HxBwSc0jMITGHxBwSc0jMITGHxBwSc0gbnu/4Phzch4P7cGyYfHe178OxYfsgl/Psar8XMAgGwSAYBINgEAyCQTAIBsFQMBQMBUPBUDAUDAVDwVAwFAxlw/uz96QNm4M17Xx3tfekDe6DXM6zq214fn57V39nIQdr2vnu6s/vE/UHfZDLeXb1J9//r/rtXT2GzcGadr67egyuP+iDXM6zq9cgGASDYBAMgkEwCAbBIBgEg2AIGAKGgCFgCBgChoAhYAgYAoaA4X3GexaNs2icRdsw+e5qn0XbsH2Qy3l29Rred2sMk4UcrGnn+6xh6w/6IJfz7GrPITGHxBwSc0jMITGHxBwSc0jMITGHxBzShve7tPfh4D4c3Idjw+S7q30fjg3bB7mcZ1f7vYBBMAgGwSAYBINgEAyCQTAIhoKhYCgYCoaCoWAoGAqGgqFgKBu+d9Zv72rvSRtc0853V3tP2uA+yOU8u9qGr9evNdws5GBNO99d/WsNU3/QB7mcZ1f/2rOwYbOQgzXtfHf1GFx/0Ae5nGdXr0EwCAbBIBgEg2AQDIJBMAgGwRAwBAwBQ8AQMAQMAUPAEDAEDAHD09dn0TiLxlm0DZPvrvZZtA3bB7mcZ1ev4XnWMFnIwZp2vs8atv6gD3I5z672HBJzSMwhMYfEHBJzSMwhMYfEHBJzSMwhbXi+4/twcB8O7sOxYfLd1b4Px4btg1zOs6v9XsAgGASDYBAMgkEwCAbBIBgEQ8FQMBQMBUPBUDAUDAVDwVAwlA3vz96TNmwO1rTz3dXekza4D3I5z6624ev1cw03CzlY0853V/9cw9Qf9EEu59nVP397V49hs5CDNe18d/UYXH/QB7mcZ1evQTAIBsEgGASDYBAMgkEwCAbBEDAEDAFDwBAwBAwBQ8AQMAQMAcP7v8fYs2icReMs2obJd1f7LNqG7YNczrOr1/A8a5gs5GBNO99nDVt/0Ae5nGdXew6JOSTmkJhDYg6JOSTmkJhDYg6JOSTmkDY83/F9OLgPB/fh2DD57mrfh2PD9kEu59nVfi9gEAyCQTAIBsEgGASDYBAMgqFgKBgKhoKhYCgYCoaCoWAoGMqG7/8eY/ekDZuDNe18d7X3pA3ug1zOs6tt+Hr9WMPNQg7WtPPd1T/WMPUHfZDLeXb1j9/e1WPYLORgTTvfXT0G1x/0QS7n2dVrEAyCQTAIBsEgGASDYBAMgkEwBAwBQ8AQMAQMAUPAEDAEDAFDwPD09Vk0zqJxFm3D5LurfRZtw/ZBLufZ1Wt4njVMFnKwpp3vs4atP+iDXM6zqz2HxBwSc0jMITGHxBwSc0jMITGHxBwSc0gbnu/4Phzch4P7cGyYfHe178OxYfsgl/Psar8XMAgGwSAYBINgEAyCQTAIBsFQMBQMBUPBUDAUDAVDwVAwFAxlw/uz96QNm4M17Xx3tfekDe6DXM6zq214/p1ruFnIwZp2vrv6tYapP+iDXM6zq1+/vavHsFnIwZp2vrt6DK4/6INczrOr1yAYBINgEAyCQTAIBsEgGASDYAgYAoaAIWAIGAKGgCFgCBgChoDh3XfPonEWjbNoGybfXe2zaBu2D3I5z65ew/sZw2QhB2vaeZ4xbP1BH+Rynl3tOSTmkJhDYg6JOSTmkJhDYg6JOSTmkJhD2vD+zt6Hg/twcB+ODZPvrvZ9ODZsH+Rynl3t9wIGwSAYBINgEAyCQTAIBsEgGAqGgqFgKBgKhoKhYCgYCoaCoWz4/rx70obNwZp2vrvae9IG90Eu59nVNny9/vXvMdws5GBNO99d/fl9ov6gD3I5z67+5K/vvz2GzUIO1rTz3dVjcP1BH+Rynl29BsEgGASDYBAMgkEwCAbBIBgEQ8AQMAQMAUPAEDAEDAFDwBAwBAxPX59F4ywaZ9E2TL672mfRNmwf5HKeXb2G51nDZCEHa9r5PmvY+oM+yOU8u9pzSMwhMYfEHBJzSMwhMYfEHBJzSMwhMYe04fmO78PBfTi4D8eGyXdX+z4cG7YPcjnPrvZ7AYNgEAyCQTAIBsEgGASDYBAMBUPBUDAUDAVDwVAwFAwFQ8FQNrw/e0/asDlY0853V3tP2uA+yOU8u9qGr9dfa7hZyMGadr67+q81TP1BH+Rynl39156FDZuFHKxp57urx+D6gz7I5Ty7eg2CQTAIBsEgGASDYBAMgkEwCIaAIWAIGAKGgCFgCBgChoAhYAgYnr4+i8ZZNM6ibZh8d7XPom3YPsjlPLt6Dc+zhslCDta0833WsPUHfZDLeXa155CYQ2IOiTkk5pCYQ2IOiTkk5pCYQ2IOacPzHd+Hg/twcB+ODZPvrvZ9ODZsH+Rynl3t9wIGwSAYBINgEAyCQTAIBsEgGAqGgqFgKBgKhoKhYCgYCoaCoWx4f/aetGFzsKad7672nrTBfZDLeXa1DV+vP9dws5CDNe18d/Wfa5j6gz7I5Ty7+s89Cxs2CzlY0853V4/B9Qd9kMt5dvUaBINgEAyCQTAIBsEgGASDYBAMAUPAEDAEDAFDwBAwBAwBQ8AQMDx9fRaNs2icRdsw+e5qn0XbsH2Qy3l29RqeZw2ThRysaef7rGHrD/ogl/Psas8hMYfEHBJzSMwhMYfEHBJzSMwhMYfEHNKG5zu+Dwf34eA+HBsm313t+3Bs2D7I5Ty72u8FDIJBMAgGwSAYBINgEAyCQTAUDAVDwVAwFAwFQ8FQMBQMBUPZ8P7sPWnD5mBNO99d7T1pg/sgl/PsahuenzXcLORgTTvfXf3HGqb+oA9yOc+u/mPPwobNQg7WtPPd1WNw/UEf5HKeXb0GwSAYBINgEAyCQTAIBsEgGARDwBAwBAwBQ8AQMAQMAUPAEDAEDO8z3rNonEXjLNqGyXdX+yzahu2DXM6zq9fwvltjmCzkYE0732cNW3/QB7mcZ1d7Dok5JOaQmENiDok5JOaQmENiDok5JOaQNrzfpb0PB/fh4D4cGybfXe37cGzYPsjlPLva7wUMgkEwCAbBIBgEg2AQDIJBMBQMBUPBUDAUDAVDwVAwFAwFQ9nwvbP+7V3tPWmDa9r57mrvSRvcB7mcZ1fb8PX6tYabhRysaee7q3+tYeoP+iCX8+zqX3sWNmwWcrCmne+uHoPrD/ogl/Ps6jUIBsEgGASDYBAMgkEwCAbBIBgChoAhYAgYAoaAIWAIGAKGgCFgePr6LBpn0TiLtmHy3dU+i7Zh+yCX8+zqNTzPGiYLOVjTzvdZw9Yf9EEu59nVnkNiDok5JOaQmENiDok5JOaQmENiDok5pA3Pd3wfDu7DwX04Nky+u9r34diwfZDLeXa13wsYBINgEAyCQTAIBsEgGASDYCgYCoaCoWAoGAqGgqFgKBgKhrLh/dl70obNwZp2vrvae9IG90Eu59nVNny9fq7hZiEHa9r57uqfa5j6gz7I5Ty7+ueehQ2bhRysaee7q8fg+oM+yOU8u3oNgkEwCAbBIBgEg2AQDIJBMAiGgCFgCBgChoAhYAgYAoaAIWAIGJ6+PovGWTTOom2YfHe1z6Jt2D7I5Ty7eg3Ps4bJQg7WtPN91rD1B32Qy3l2teeQmENiDok5JOaQmENiDok5JOaQmENiDmnD8x3fh4P7cHAfjg2T7672fTg2bB/kcp5d7fcCBsEgGASDYBAMgkEwCAbBIBgKhoKhYCgYCoaCoWAoGAqGgqFseH/2nrRhc7Cmne+u9p60wX2Qy3l2tQ1frx9ruFnIwZp2vrv6xxqm/qAPcjnPrv6xZ2HDZiEHa9r57uoxuP6gD3I5z65eg2AQDIJBMAgGwSAYBINgEAyCIWAIGAKGgCFgCBgChoAhYAgYAoanr8+icRaNs2gbJt9d7bNoG7YPcjnPrl7D86xhspCDNe18nzVs/UEf5HKeXe05JOaQmENiDok5JOaQmENiDok5JOaQmEPa8HzH9+HgPhzch2PD5LurfR+ODdsHuZxnV/u9gEEwCAbBIBgEg2AQDIJBMAiGgqFgKBgKhoKhYCgYCoaCoWAoG96fvSdt2Bysaee7q70nbXAf5HKeXW3D8+9cw81CDta0893VrzVM/UEf5HKeXf3as7Bhs5CDNe18d/UYXH/QB7mcZ1evQTAIBsEgGASDYBAMgkEwCAbBEDAEDAFDwBAwBAwBQ8AQMAQMAcO7755F4ywaZ9E2TL672mfRNmwf5HKeXb2G9zOGyUIO1rTzPGPY+oM+yOU8u9pzSMwhMYf8f7f+gCJ4nE3aMW5kyXKF4buKsLkUGpH74NkJVxGuaMqWOw6NpNvAADIaEDDT0kp0qyojzn+BxjsksvJ9HZl1UKie6/q/fV3xc12V1zPXdn488/t0juUs5HL+/Iv55/Wa5xpkIQfXbOfHM79PrF/YB7mcn4bJP691bRAMgkEwCAbBIBgEg2AQDIKhYCgYCoaCoWAoGAqGgqFgKBjKhufPxzBZyME12/l+/PvE+oV9kMv58b/OP88/f/63DScLObhmOz8N/fvE+oV9kMv5Zej88/z/bsNkIQfXbOfnWdjg9Qv7IJfz6yxgEAyCQTAIBsEgGASDYBAMgkEwBAwBQ8AQMAQMAUPAEDAEDAFDwHDv67PYOIuNs9g2dH6exbZh1i/sg1zOr7PYNtzPGDoLObhmO59nDLN+YR/kcn4aJr962HNIzCExh8QcEnNIzCExh8QcEnNIzCFtuF/j+7BwHxbuw7Kh8+lq34dlw+yDXM7d1X5fwCAYBINgEAyCQTAIBsEgGARDwVAwFAwFQ8FQMBQMBUPBUDCUDY+f3ZM2TA6u2c6nq92TNngf5HLurrbh5/pGV3+jq7/R1d/o6m909Te6+htd/Y2u/kZXf6Orv9HVbZgs5OCa7Xy6ug1ev7APcjl3V49BMAgGwSAYBINgEAyCQTAIBsEQMAQMAUPAEDAEDAFDwBAwBAwBw72vz2LjLDbOYtvQ+XS1z2LbMPsgl3N39RjuZwydhRxcs53PM4ZZv7APcjl3V3sOiTkk5pCYQ2IOiTkk5pCYQ2IOiTkk5pA23K/xfVi4Dwv3YdnQ+XS178OyYfZBLufuar8vYBAMgkEwCAbBIBgEg2AQDIKhYCgYCoaCoWAoGAqGgqFgKBjKhsfP7kkbJgfXbOfT1e5JG7wPcjl3V9vwc32hq7/Q1V/o6i909Re6+gtd/YWu/kJXf6Grv9DVX+jqNkwWcnDNdj5d3QavX9gHuZy7q8cgGASDYBAMgkEwCAbBIBgEg2AIGAKGgCFgCBgChoAhYAgYAoaA4d7XZ7FxFhtnsW3ofLraZ7FtmH2Qy7m7egz3M4bOQg6u2c7nGcOsX9gHuZy7qz2HxBwSc0jMITGHxBwSc0jMITGHxBwSc0gb7tf4Pizch4X7sGzofLra92HZMPsgl3N3td8XMAgGwSAYBINgEAyCQTAIBsFQMBQMBUPBUDAUDAVDwVAwFAxlw+Nn96QNk4NrtvPpavekDd4HuZy7q224/6CrP9HVn+jqT3T1J7r6E139ia7+RFd/oqs/0dWf6Oo2TBZycM12Pl3dBq9f2Ae5nLurxyAYBINgEAyCQTAIBsEgGASDYAgYAoaAIWAIGAKGgCFgCBgChoDhccboap/FxllsGzqfrvZZbBtmH+Ry7q4ew+NuoavH0Dm4ZjufZwyzfmEf5HLurvYcEnNIzCExh8QcEnNIzCExh8QcEnNIzCFteLyX0NW+Dwv3YdnQ+XS178OyYfZBLufuar8vYBAMgkEwCAbBIBgEg2AQDIKhYCgYCoaCoWAoGAqGgqFgKBjKhmdnoavdkzZ4zXY+Xe2etMH7IJdzd7UNP9cHuvoDXf2Brv5AV3+gqz/Q1R/o6g909Qe6+gNd/YGubsNkIQfXbOfT1W3w+oV9kMu5u3oMgkEwCAbBIBgEg2AQDIJBMAiGgCFgCBgChoAhYAgYAoaAIWAIGO59fRYbZ7FxFtuGzqerfRbbhtkHuZy7q8dwP2PoLOTgmu18njHM+oV9kMu5u9pzSMwhMYfEHBJzSMwhMYfEHBJzSMwhMYe04X6N78PCfVi4D8uGzqerfR+WDbMPcjl3V/t9AYNgEAyCQTAIBsEgGASDYBAMBUPBUDAUDAVDwVAwFAwFQ8FQNjx+dk/aMDm4ZjufrnZP2uB9kMu5u9qGn+sdXf2Orn5HV7+jq9/R1e/o6nd09Tu6+h1d/Y6ufkdXt2GykINrtvPp6jZ4/cI+yOXcXT0GwSAYBINgEAyCQTAIBsEgGARDwBAwBAwBQ8AQMAQMAUPAEDAEDPe+PouNs9g4i21D59PVPottw+yDXM7d1WO4nzF0FnJwzXY+zxhm/cI+yOXcXe05JOaQmENiDok5JOaQmENiDok5JOaQmEPacL/G92HhPizch2VD59PVvg/LhtkHuZy7q/2+gEEwCAbBIBgEg2AQDIJBMAiGgqFgKBgKhoKhYCgYCoaCoWAoGx4/uydtmBxcs51PV7snbfA+yOXcXW3Dz/WGrn5DV7+hq9/Q1W/o6jd09Ru6+g1d/YaufkNXv6Gr2zBZyME12/l0dRu8fmEf5HLurh6DYBAMgkEwCAbBIBgEg2AQDIIhYAgYAoaAIWAIGAKGgCFgCBgChntfn8XGWWycxbah8+lqn8W2YfZBLufu6jHczxg6Czm4ZjufZwyzfmEf5HLurvYcEnNIzCExh8QcEnNIzCExh8QcEnNIzCFtuF/j+7BwHxbuw7Kh8+lq34dlw+yDXM7d1X5fwCAYBINgEAyCQTAIBsEgGARDwVAwFAwFQ8FQMBQMBUPBUDCUDY+f3ZM2TA6u2c6nq92TNngf5HLurrbh/nuiqy909YWuvtDVF7r6Qldf6OoLXX2hqy909YWubsNkIQfXbOfT1W3w+oV9kMu5u3oMgkEwCAbBIBgEg2AQDIJBMAiGgCFgCBgChoAhYAgYAoaAIWAIGB77oqt9FhtnsW3ofLraZ7FtmH2Qy7m7egyPB109hs7BNdu5H3T1GGYf5HLurvYcEnNIzCExh8QcEnNIzCExh8QcEnNIzCFteLwGXe37sHAflg2dT1f7PiwbZh/kcu6u9vsCBsEgGASDYBAMgkEwCAbBIBgKhoKhYCgYCoaCoWAoGAqGgqFseP6MrnZP2uA12/l0tXvSBu+DXM7d1Tbcf/604WQhB9ds59PVr98n1i/sg1zO82+Lf9zVbZgs5OCa7Xy6ug1ev7APcjnPvy3+cVePQTAIBsEgGASDYBAMgkEwCIaAIWAIGAKGgCFgCBgChoAhYAgYHmc8Z7FxFhtnsW3ofLraZ7FtmH2Qy3n+bbENj7vVhs5CDq7ZzucZw6xf2Ae5nOffFmcOiTkk5pCYQ2IOiTkk5pCYQ2IOiTkk5pA2PN5Lcx8W7sPCfVg2dD5d7fuwbJh9kMt5/m1x3hcwCAbBIBgEg2AQDIJBMAgGwVAwFAwFQ8FQMBQMBUPBUDAUDGXDs7OmJ22YHFyznU9Xuydt8D7I5Tz/tjiG+++Jrr7Q1Re6+kJXX+jqC119oasvdPWFrr7Q1Re6ug2ThRxcs51PV7fB6xf2QS7n+VyNrh6DYBAMgkEwCAbBIBgEg2AQDAFDwBAwBAwBQ8AQMAQMAUPAEDA89kVX+yw2zmLb0Pl0tc9i2zD7IJfzfK5GV4+hs5CDa7ZzP+jqMcw+yOU8n6vR1Z5DYg6JOSTmkJhDYg6JOSTmkJhDYg5pw+M16Grfh4X7sGzofLra92HZMPsgl/N8rkZX+30Bg2AQDIJBMAgGwSAYBINgKBgKhoKhYCgYCoaCoWAoGAqGsuH5M7raPWmD12zn09XuSRu8D3I5z+dqdPXnv204WcjBNdv5dPXr94n1C/sgl/N8rv4Xn6v/7bOwYXJwzXY+Xd0Gr1/YB7mc53P1v+7qMQgGwSAYBINgEAyCQTAIBsEQMAQMAUPAEDAEDAFDwBAwBAwBw+OM5yw2zmLjLLYNnU9X+yy2DbMPcjnP5+o2PO5WGzoLObhmO59nDLN+YR/kcp7P1TOHxBwSc0jMITGHxBwSc0jMITGHxBwSc0gbHu+luQ8L92HhPiwbOp+u9n1YNsw+yOU8n6vnfQGDYBAMgkEwCAbBIBgEg2AQDAVDwVAwFAwFQ8FQMBQMBUPBUDY8O2t60obJwTXb+XS1e9IG74NczvO5egz33xNdfaGrL3T1ha6+0NUXuvpCV1/o6gtdfaGrL3R1GyYLObhmO5+uboPXL+yDXM7zuRpdPQbBIBgEg2AQDIJBMAgGwSAYAoaAIWAIGAKGgCFgCBgChoAhYHjsi672WWycxbah8+lqn8W2YfZBLuf5XI2uHkNnIQfXbOd+0NVjmH2Qy3k+V6OrPYfEHBJzSMwhMYfEHBJzSMwhMYfEHNKGx2vQ1b4PC/dh2dD5dLXvw7Jh9kEu5/lcja72+wIGwSAYBINgEAyCQTAIBsFQMBQMBUPBUDAUDAVDwVAwFAxlw/NndLV70gav2c6nq92TNngf5HKez9Xo6s9/2nCykINrtvPp6tfvE+sX9kEu5/lc/Q8+V//TZ2HD5OCa7Xy6ug1ev7APcjnP5+p/3NVjEAyCQTAIBsEgGASDYBAMgiFgCBgChoAhYAgYAoaAIWAIGAKGxxnPWWycxcZZbBs6n672WWwbZh/kcp7P1W143K02dBZycM12Ps8YZv3CPsjlPJ+rZw6JOSTmkJhDYg6JOSTmkJhDYg6JOSTmkDY83ktzHxbuw8J9WDZ0Pl3t+7BsmH2Qy3k+V8/7AgbBIBgEg2AQDIJBMAgGwSAYCoaCoWAoGAqGgqFgKBgKhoKhbHh21vSkDZODa7bz6Wr3pA3eB7mc53P1GH6u9/9xVz+zkINrtvPp6tfvE+sX9kEu5+7qV371cBsmCzm4Zjufrm6D1y/sg1zO3dVjEAyCQTAIBsEgGASDYBAMgkEwBAwBQ8AQMAQMAUPAEDAEDAFDwHDv67PYOIuNs9g2dD5d7bPYNsw+yOXcXT2G+xlDZyEH12zn84xh1i/sg1zO3dWeQ2IOiTkk5pCYQ2IOiTkk5pCYQ2IOiTmkDfdrfB8W7sPCfVg2dD5d7fuwbJh9kMu5u9rvCxgEg2AQDIJBMAgGwSAYBINgKBgKhoKhYCgYCoaCoWAoGAqGsuHxs3vShsnBNdv5dLV70gbvg1zO3dU23H/P3+7qZxZycM12Pl39+n1i/cI+yOU834H8xncgv93VbZgcXLOdT1e3wesX9kEu5/kO5Le7egyCQTAIBsEgGASDYBAMgkEwBAwBQ8AQMAQMAUPAEDAEDAFDwPDYd85i4yw2zmLb0Pl0tc9i2zD7IJfzfAfy2109hs5CDq7Zzv20YdYv7INczvMdyG93teeQmENiDok5JOaQmENiDok5JOaQmEPa8HjN3IeF+7BwH5YNnU9X+z4sG2Yf5HKe70B+u6v9voBBMAgGwSAYBINgEAyCQTAUDAVDwVAwFAwFQ8FQMBQMBUPZ8Px5etKGycE12/l0tXvSBu+DXM7zHchvd/X3f7fhZCEH12zn09Wv3yfWL+yDXM7d1a/88/z/bsNkIQfXbOfT1W3w+oV9kMu5u3oMgkEwCAbBIBgEg2AQDIJBMAiGgCFgCBgChoAhYAgYAoaAIWAIGO59fRYbZ7FxFtuGzqerfRbbhtkHuZy7q8dwP2PoLOTgmu18njHM+oV9kMu5u9pzSMwhMYfEHBJzSMwhMYfEHBJzSMwhMYe04X6N78PCfVi4D8uGzqerfR+WDbMPcjl3V/t9AYNgEAyCQTAIBsEgGASDYBAMBUPBUDAUDAVDwVAwFAwFQ8FQNjx+dk/aMDm4ZjufrnZP2uB9kMu5u9qG+8/f7upnFnJwzXY+Xf36fWL9wj7I5TzfV/+N76v/dle3YXJwzXY+Xd0Gr1/YB7mc5/vqv93VYxAMgkEwCAbBIBgEg2AQDIIhYAgYAoaAIWAIGAKGgCFgCBgChscZz1lsnMXGWWwbOp+u9llsG2Yf5HKe76vb8Lhbbegs5OCa7XyeMcz6hX2Qy3m+r545JOaQmENiDok5JOaQmENiDok5JOaQmEPa8HgvzX1YuA8L92HZ0Pl0te/DsmH2QS7n+b563hcwCAbBIBgEg2AQDIJBMAgGwVAwFAwFQ8FQMBQMBUPBUDAUDGXDs7OmJ22YHFyznU9Xuydt8D7I5TzfV4/h53r/5a5+ZiEH12zn09Wv3yfWL+yDXM7zffUvfF/9y13dhsnBNdv5dHUbvH5hH+Rynu+r2yAYBINgEAyCQTAIBsEgGASDYAgYAoaAIWAIGAKGgCFgCBgChoDh8b3xnMXGWWycxbah8+lqn8W2YfZBLuf5vroN9zOGzkIOrtnO5xnDrF/YB7mc5/vqmUNiDok5JOaQmENiDok5JOaQmENiDok5pA33a3wfFu7Dwn1YNnQ+Xe37sGyYfZDLeb6v/uWu9vsCBsEgGASDYBAMgkEwCAbBUDAUDAVDwVAwFAwFQ8FQMBQMZcPze+PpSRsmB9ds59PV7kkbvA9yOc/31b/c1X+2u/qZhRxcs51PV79+n1i/sA9yOXdXv/Krh9swWcjBNdv5dHUbvH5hH+Ry7q4eg2AQDIJBMAgGwSAYBINgEAyCIWAIGAKGgCFgCBgChoAhYAgYAoZ7X5/FxllsnMW2ofPpap/FtmH2QS7n7uoxXJcNnYUcXLOdzzOGWb+wD3I5d1d7Dok5JOaQmENiDok5JOaQmENiDok5JOaQNtyv8X1YuA8L92HZ0Pl0te/DsmH2QS7n7mq/L2AQDIJBMAgGwSAYBINgEAyCoWAoGAqGgqFgKBgKhoKhYCgYyobHz+5JGyYH12zn09XuSRu8D3I5d1fb8Pjjrn5mIQfXbOfT1a/fJ9Yv7INczvMdyF/4DuQvd3UbJgfXbOfT1W3w+oV9kMt5vgP5y109BsEgGASDYBAMgkEwCAbBIBgChoAhYAgYAoaAIWAIGAKGgCFgeJ6xu9pnsXEW24bOp6t9FtuG2Qe5nOc7kDY875a7egydg2u283nGMOsX9kEu5/kOZOaQmENiDok5JOaQmENiDok5JOaQmENiDmnD873krvZ9WLgPy4bOp6t9H5YNsw9yOc93IPO+gEEwCAbBIBgEg2AQDIJBMAiGgqFgKBgKhoKhYCgYCoaCoWAoG16d5a52T9rgNdv5dLV70gbvg1zO8x3IGH6ut/9yVz+zkINrtvPp6tfvE+sX9kEu5+7qV371cBsmCzm4Zjufrm6D1y/sg1zO3dVjEAyCQTAIBsEgGASDYBAMgkEwBAwBQ8AQMAQMAUPAEDAEDAFDwHDv67PYOIuNs9g2dD5d7bPYNsw+yOXcXT2G+xlDZyEH12zn84xh1i/sg1zO3dWeQ2IOiTkk5pCYQ2IOiTkk5pCYQ2IOiTmkDfdrfB8W7sPCfVg2dD5d7fuwbJh9kMu5u9rvCxgEg2AQDIJBMAgGwSAYBINgKBgKhoKhYCgYCoaCoWAoGAqGsuHxs3vShsnBNdv5dLV70gbvg1zO3dU2/Fzf/+mufmYhB9ds59PVr98n1i/sg1zO3dWv/OrhNkwWcnDNdj5d3QavX9gHuZy7q8cgGASDYBAMgkEwCAbBIBgEg2AIGAKGgCFgCBgChoAhYAgYAoaA4fHfY8xZbJzFxllsGzqfrvZZbBtmH+Ry7q4ew/2MobOQg2u283nGMOsX9kEu5+5qzyExh8QcEnNIzCExh8QcEnNIzCExh8Qc0ob7Nb4PC/dh4T4sGzqfrvZ9WDbMPsjl3F3t9wUMgkEwCAbBIBgEg2AQDIJBMBQMBUPBUDAUDAVDwVAwFAwFQ9nw/O8xpidtmBxcs51PV7snbfA+yOXcXW3Dz/XxH+7qZxZycM12Pl39+n1i/cI+yOXcXf3Krx5uw2QhB9ds5+v6f+EZkGB4nG3aP66jx9HFYWazg8oG0CK4AAXViVahswZvYAAHTBxXai2CmZPBuJkKEKDAgAD98UrMl3yrzm8GJmB8575f357nVjcPCNqXSz0uP/5zXy6Vl8mxnIVczp/+xfx4rus1yEIOrtnOx0swCAbBIBgEg2AIGAKGgCFgCBgChoAhYAgYAoaA4bnvGDoLObhmOx+veZ5Yv7APcjm/z2Lb8HyNobOQg2u28/kaw6xf2Ae5nF+GyY/X73sOiTkk5pCYQ2IOiTkk5pCYQ2IOiTmkDc/f8X1YuA8L92HZ0Pl1H5YNs35hH+Ryft+HZYNgEAyCQTAIBsEgGASDYBAMgqFgKBgKhoKhYCgYCoaCoWAoGMqG4+c2TBZycM12fr78PLF+YR/kcj7+r/Nj3p9vw2N6aHJwjd/Pb0M/T6xf2Ae5nN+GB/azYbKQg2vcI++zsMHrF/ZBLufu6jEIBsEgGASDYBAMgkEwCAbBIBgChoAhYAgYAoaAIWAIGAKGgCFg+HbG/Fv5b377n7OrfRbuD++DXM7d1WOYvZCFHI+v/73O/WrDrF/YB7mcu6s9h7Shs5CDa/A3n13tZ2nD7INczt3Vvg/Lhs5CjsfX8+18drXvw/L/f/ZBLufuar8vYBAMgoHnKhgEg2AQDIJBMAiGgqFgKBhwnyafXe2zgKFgKBgKhrLBdxRZyPH45h7b4OeJ9Qv7IJdzd7UNj8tP/2jDmYUcXLOdz65+P0+sX9gHuZy7q9/58fq32zBZyME12/ns6jZ4/cI+yOXcXT0GwSAYBINgEAyCQTAIBsEgGARDwBAwBAwBQ8AQMAQMAUPAEDAEDM99fRYbZ7FxFtuGzmfP+Sy2DbMPcjn3fRzD8zWGzkIOrtnO52sMs35hH+Ry7q72HBJzSMwhMYfEHBJzSMwhMYfEHBJzSMwhbXj+ju/Dwn1YuA/Lhs5nV/s+LBtmH+Ry7q72+wIGwSAYBINgEAyCQTAIBsEgGAqGgqFgKBgKhoKhYCgYCoaCoWw4fnZP2jA5uGY7n13tnrTB+yCXc3e1DY/L9393V7+ykINrtvPZ1e/nifUL+yCXc3f1O797uA2ThRxcs53Prm6D1y/sg1zO3dVjEAyCQTAIBsEgGASDYBAMgkEwBAwBQ8AQMAQMAUPAEDAEDAFDwPDc12excRYbZ7Ft6Hx2tc9i2zD7IJdzd/UYnq8xdBZycM12Pl9jmPUL+yCXc3e155CYQ2IOiTkk5pCYQ2IOiTkk5pCYQ2IOacPzd3wfFu7Dwn1YNnQ+u9r3Ydkw+yCXc3e13xcwCAbBIBgEg2AQDIJBMAgGwVAwFAwFQ8FQMBQMBUPBUDAUDGXD8bN70obJwTXb+exq96QN3ge5nLurbXhcPv/NXf3KQg6u2c5nV7+fJ9Yv7INczt3V7/zu4TZMFnJwzXY+u7oNXr+wD3I5d1ePQTAIBsEgGASDYBAMgkEwCAbBEDAEDAFDwBAwBAwBQ8AQMAQMAcNzX5/FxllsnMW2ofPZ1T6LbcPsg1zO3dVjeL7G0FnIwTXb+XyNYdYv7INczt3VnkNiDok5JOaQmENiDok5JOaQmENiDok5pA3P3/F9WLgPC/dh2dD57Grfh2XD7INczt3Vfl/AIBgEg2AQDIJBMAgGwSAYBEPBUDAUDAVDwVAwFAwFQ8FQMJQNx8/uSRsmB9ds57Or3ZM2eB/kcu6utuGYtbv6lYUcXLOdz65+P0+sX9gHuZzn+2rh+2q5q9swObhmO59d3QavX9gHuZzn+2q5q8cgGASDYBAMgkEwCAbBIBgEQ8AQMAQMAUPAEDAEDAFDwBAwBAyvv81d7bPYOIttQ+ezq30W24bZB7mc/b0dvq9uQ2chB9ds5361YdYv7INczvN9tdzVnkNiDok5JOaQmENiDok5JOaQmENiDmnD6w71fVi4Dwv3YdnQ+exq34dlw+yDXM7zfbXc1X5fwCAYBINgEAyCQTAIBsEgGAqGgqFgKBgKhoKhYCgYCoaCoWx4m/Z0tXvSBq/ZzmdXuydt8D7I5TzfV8td/emHNpxZyME12/ns6vfzxPqFfZDLubv6nR/vf/uHPgsbJgfXbOezq9vg9Qv7IJdzd/UYBINgEAyCQTAIBsEgGASDYBAMAUPAEDAEDAFDwBAwBAwBQ8AQMBxnPGexcRYbZ7Ft6Hx2tc9i2zD7IJfz/PcnbTjuVhs6Czm4ZjufrzHM+oV9kMu5u9pzSMwhMYfEHBJzSMwhMYfEHBJzSMwhMYe04XgvzX1YuA8L92HZ0Pnsat+HZcPsg1zO3dV+X8AgGASDYBAMgkEwCAbBIBgEQ8FQMBQMBUPBUDAUDAVDwVAwlA2vzpqetGFycM12PrvaPWmD90Eu5+5qG55/59Vd/cpCDq7ZzmdXv58n1i/sg1zO87n6is/VV3d1GyYH12zns6vb4PUL+yCX83yuboNgEAyCQTAIBsEgGASDYBAMgiFgCBgChoAhYAgYAoaAIWAIGAKGY985i42z2DiLbUPns6t9FtuG2Qe5nOdzdRuOVxs6Czm4Zjv3qw2zfmEf5HKez9Uzh8QcEnNIzCExh8QcEnNIzCExh8QcEnNIG47fmfuwcB8W7sOyofPZ1b4Py4bZB7mc53P11V3t9wUMgkEwCAbBIBgEg2AQDIKhYCgYCoaCoWAoGAqGgqFgKBjKhtfP05M2TA6u2c5nV7snbfA+yOU8n6uv7upPH9twZiEH12zns6vfzxPrF/ZBLuf5XP0Rn6s/9lnYMDm4ZjufXd0Gr1/YB7mc53P1R3f1GASDYBAMgkEwCAbBIBgEg2AIGAKGgCFgCBgChoAhYAgYAoaA4TjjOYuNs9g4i21D57OrfRbbhtkHuZznc3UbjrvVhs5CDq7ZzudrDLN+YR/kcp7P1TOHxBwSc0jMITGHxBwSc0jMITGHxBwSc0gbjvfS3IeF+7BwH5YNnc+u9n1YNsw+yOU8n6vnfQGDYBAMgkEwCAbBIBgEg2AQDAVDwVAwFAwFQ8FQMBQMBUPBUDa8Omt60obJwTXb+exq96QN3ge5nOdz9Rief+cHd/UrCzm4ZjufXf1+nli/sA9yOc/n6g/4XP3BXd2GycE12/ns6jZ4/cI+yOU8n6vbIBgEg2AQDIJBMAgGwSAYBINgCBgChoAhYAgYAoaAIWAIGAKGgOHYd85i4yw2zmLb0Pnsap/FtmH2QS7n+VzdhuPVhs5CDq7Zzv1qw6xf2Ae5nOdz9cwhMYfEHBJzSMwhMYfEHBJzSMwhMYfEHNKG43fmPizch4X7sGzofHa178OyYfZBLuf5XP3BXe33BQyCQTAIBsEgGASDYBAMgqFgKBgKhoKhYCgYCoaCoWAoGMqG18/TkzZMDq7ZzmdXuydt8D7I5Tyfqz+gq//6t7v6yEIOrtnO3dWv54n1C/sgl/N09Ss/3mdwGiYLObhmO3dXnwavX9gHuZynq9sgGASDYBAMgkEwCAbBIBgEg2AIGAKGgCFgCBgChoAhYAgYAoaA4dh3zmLjLDbOYtvQubt6zmLbMPsgl/N0dRuOVxs6Czm4Zjv3qw2zfmEf5HKerp45JOaQmENiDok5JOaQmENiDok5JOaQmEPacPzO3IeF+7BwH5YNnbur5z4sG2Yf5HKerp73BQyCQTAIBsEgGASDYBAMgkEwFAwFQ8FQMBQMBUPBUDAUDAVD2fD6eXrShsnBNdu5u3p60gbvg1zO09VjeP6dd3T1HV19R1ff0dV3dPUdXX1HV9/R1Xd09R1dfUdX39HVd3T1HV19R1ff0dV3dPUdXX1HV9/R1Xd09R1d3QbBIBgEg2AQDIJBMAgGwSAYAoaAIWAIGAKGgCFgCBgChoAhYDj2nbPYOIuNs9g2dO6unrPYNsw+yOU8XX1HV7ehs5CDa7Zzv9ow6xf2QS7n6eo7unrmkJhDYg6JOSTmkJhDYg6JOSTmkJhD2nD8ztyHhfuwcB+WDZ27q+c+LBtmH+Rynq6+o6vnfQGDYBAMgkEwCAbBIBgEg2AoGAqGgqFgKBgKhoKhYCgYCoay4fXz9KQNk4NrtnN39fSkDd4HuZynq+/o6hu6+oauvqGrb+jqG7r6hq6+oatv6OobuvqGrr6hq2/o6hu6+oauvqGrb+jqG7r6hq6+oatv6OobuvqGrm6DYBAMgkEwCAbBIBgEg2AQDAFDwBAwBAwBQ8AQMAQMAUPAEDAc+85ZbJzFxllsGzp3V89ZbBtmH+Rynq6+oavb0FnIwTXbuV9tmPUL+yCX83T1DV09c0jMITGHxBwSc0jMITGHxBwSc0jMIW04fmfuw8J9WLgPy4bO3dVzH5YNsw9yOU9X39DV876AQTAIBsEgGASDYBAMgkEwFAwFQ8FQMBQMBUPBUDAUDAVD2fD6eXrShsnBNdu5u3p60gbvg1zO09U3dPUVXX1FV1/R1Vd09RVdfUVXX9HVV3T1FV19RVdf0dVXdPUVXX1FV1/R1Vd09RVdfUVXX9HVV3T1FV19RVe3QTAIBsEgGASDYBAMgkEwCIaAIWAIGAKGgCFgCBgChoAhYAgYXv97DHT1nMXGWWwbOndXz1lsG2Yf5HKerr6iq9vQWcjBNdu5X22Y9Qv7IJfzdPUVXT1zSMwhMYfEHBJzSMwhMYfEHBJzSMwhbTh+Z+7Dwn1YuA/Lhs7d1XMflg2zD3I5T1df0dXzvoBBMAgGwSAYBINgEAyCQTAUDAVDwVAwFAwFQ8FQMBQMBUPZ8P7fY6Crpydt8Jrt3F09PWmD90Eu5+nqK7r6/sVdfWQhB9ds5+7q1/PE+oV9kMvZ34F8cVefhslCDq7Zzt3Vp8HrF/ZBLmd/B/LFXd0GwSAYBINgEAyCQTAIBsEgGAKGgCFgCBgChoAhYAgYAoaAIWB4fRfRZ7FxFhtnsW3o3F09Z7FtmH2Qy9nfgXxxV7ehs5CDa7Zzv9ow6xf2QS5nfwfSc0jMITGHxBwSc0jMITGHxBwSc0jMITGHtOH1XUTfh4X7sHAflg2du6vnPiwbZh/kcvZ3IP2+gEEwCAbBIBgEg2AQDIJBMAiGgqFgKBgKhoKhYCgYCoaCoWAoG97fRXRP2jA5uGY7d1dPT9rgfZDL2d+BtOExnTdZyME1+O/pu6vPu+n1C/sgl/N0de9RNkwWcnDNdu7f6fdH2eB9kMt5uroNgkEwCAbBIBgEg2AQDIJBMAiGgCFgCBgChoAhYAgYAoaAIWAIGLr7ClnIwTXbuX9uw6xf2Ae5nKerL5ev7tdX56z/87fy3/z21V3dhtkHuZynq9vQv1/IQg6u2V//e/M8sX5hH+Rynq5uQ7sLWcjBNfvrv3OeJ9Yv7INcztPVbRAMgkEwCAbOVzAIBsEgGASDYCgYCoaCoWDAufp5Yv3CPsjlPF19GuZ+FLKQg2v2N/fJBq9f2Ae5nKerx78v3/3Xd23y8Tfj+QXP//zLzyc/n3/G8894/hOe/4Tnn/D8E57/iOc/4vn3eP49nn+H59/h+QXPL/x3/8S/+yfW4/kFzz/9gfV/YD2eX/D80+9Y/7uff/8b/L9hn/9gn//4+edfMc9fsf8v2P8X7P8z9v95/w/hGE0H + + + 0 + + + 9380.8315196 + + + + + + + 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 + + + AgAAAACAAACAOwAApRMAAC8JAAA=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z4EjJ85c+OHKjTsPnrx48+HrP30JGDJizIQpM+Ys+GbJijUbtuzYc+DIiTMXfrhy486DJy/efPj6z18ChowYM2HKjDkLvlmyYs2GLTv2HDhy4syFH67cuPPgyYs3H77+y5eAISPGTJgyY86Cb5asWLNhy449B46cOHPhhys37jx48uLNh6//+iVgyIgxE6bMmLPgmyUr1mzYsmPPgSMnzlz44cqNOw+evHjz4eu/fQkYMmLMhCkz5iz4ZsmKNRu27Nhz4MiJMxd+uHLjzoMnL958+OMQb8CQEWMmTJkxZ8E3S1as2bBlx54DR06cufDDlRt3Hjx58ebD13//EjBkxJgJU2bMWfDNkhVrNmzZsefAkRNnLvxw5cadB09evPnw9T++BAwZMWbClBlzFnyzZMWaDVt27Dlw5MSZCz9cuXHnwZMXbz58/c8vAUNGjJkwZcacBd8sWbFmw5Ydew4cOXHmwg9Xbtx58OTFmw9f/+tLwJARYyZMmTFnwTdLVqzZsGXHngNHTpy58MOVG3cePHnx5sPX//4SMGTEmAlTZsxZ8M2SFWs2bNmx58CRE2cu/HDlxp0HT168+fD1f74EDBkxZsKUGXMWfLNkxZoNW3bsOXDkxJkLP1y5cefBkxdvPnz93y8BQ0aMmTBlxpwF3yxZsWbDlh17Dhw5cebCD1du3Hnw5MWbD1/dl/8HE+m5JnicLcUpGIUAYBBgIpFIJBKJRCKRSCQSiUS8NrxxXnht6KbijdeGWogvvkgkEl8k+n3j/8sfDsFfihw7cerMuQuXrly7cevOvQePnjx78erNuw9//PXpy7d/fhz8lbfQkWMnTp05d+HSlWs3bt259+DRk2cvXr159+GPvz59+fbPj4O/+hY6cuzEqTPnLly6cu3GrTv3Hjx68uzFqzfvPvzx16cv3/75cfDX3kJHjp04debchUtXrt24defeg0dPnr149ebdhz/++vTl2z8/Dv76W+jIsROnzpy7cOnKtRu37tx78OjJsxev3rz78Mdfn758++fHwd94Cx05duLUmXMXLl25duPWnXsPHj159uLVm3cf/vjr05dv//w4+IO30JFjJ06dOXfh0pVrN27duffg0ZNnL169effhj78+ffn2z4+DP3wLHTl24tSZcxcuXbl249adew8ePXn24tWbdx/++OvTl2///DgY30JHjp04debchUtXrt24defeg0dPnr149ebdhz/++vTl2z8/Dv7mW+jIsROnzpy7cOnKtRu37tx78OjJsxev3rz78Mdfn758++fHwd96Cx05duLUmXMXLl25duPWnXsPHj159uLVm3cf/vjr05dv//w4+NtvoSPHTpw6c+7CpSvXbty6c+/BoyfPXrx68+7DH399+vLtnx8Hf+ctdOTYiVNnzl24dOXajVt37j149OTZi1dv3n34469PX7798+Pg776Fjhw7cerMuQuXrly7cevOvQePnjx78erNuw9//PXpy7d/fhz8vbfQkWMnTp05d+HSlWs3bt259+DRk2cvXr159+GPvz59+fbPj4O//xY6cuzEqTPnLly6cu3GrTv3Hjx68uzFqzfvPvzx16cv3/75cTC9hY4cO3HqzLkLl65cu3Hrzr0Hj548e/HqzbsPf/z16cu3f34c/IO30JFjJ06dOXfh0pVrN27duffg0ZNnL169effhj78+ffn2z4+DP3oLHTl24tSZcxcuXbl249adew8ePXn24tWbdx/++OvTl2///Dj4h2+hI8dOnDpz7sKlK9du3Lpz78GjJ89evHrz7sMff3368u2fHwf/6C105NiJU2fOXbh05dqNW3fuPXj05NmLV2/effjjr09fvv3z4+Afv4WOHDtx6sy5C5euXLtx6869B4+ePHvx6s27D3/89enLt39+HPyTt9CRYydOnTl34dKVazdu3bn34NGTZy9evXn34Y+/Pn359s+Pg3/6Fjpy7MSpM+cuXLpy7catO/cePHry7MWrN+8+/PHXpy/f/vlxML+Fjhw7cerMuQuXrly7cevOvQePnjx78erNuw9//PXpy7d/fhz8s7fQkWMnTp05d+HSlWs3bt259+DRk2cvXr159+GPvz59+fbPj4N//hY6cuzEqTPnLly6cu3GrTv3Hjx68uzFqzfvPvzx16cv3/75cfAv3kJHjp04debchUtXrt24defeg0dPnr149ebdhz/++vTl2z8/Dv7lW+jIsROnzpy7cOnKtRu37tx78OjJsxev3rz78Mdfn758++fHwb96Cx05duLUmXMXLl25duPWnXsPHj159uLVm3cf/vjr05dv//w4+OO30JFjJ06dOXfh0pVrN27duffg0ZNnL169effhj78+ffn2z4+DP3kLHTl24tSZcxcuXbl249adew8ePXn24tWbdx/++OvTl2///DhY3kJHjp04debchUtXrt24defeg0dPnr149ebdhz/++vTl2z8/Dv71W+jIsROnzpy7cOnKtRu37tx78OjJsxev3rz78Mdfn758++fHwb95Cx05duLUmXMXLl25duPWnXsPHj159uLVm3cf/vjr05dv//w4+NO30JFjJ06dOXfh0pVrN27duffg0ZNnL169effhj78+ffn2z4+DP3sLHTl24tSZcxcuXbl249adew8ePXn24tWbdx/++OvTl2///Dj4t2+hI8dOnDpz7sKlK9du3Lpz78GjJ89evHrz7sMff3368u2fHwf/7i105NiJU2fOXbh05dqNW3fuPXj05NmLV2/effjjr09fvv3z4+Dfv4WOHDtx6sy5C5euXLtx6869B4+ePHvx6s27D3/89enLt39+HKxvoSPHTpw6c+7CpSvXbty6c+/BoyfPXrx68+7DH399+vLtnx8H/+EtdOTYiVNnzl24dOXajVt37j149OTZi1dv3n34469PX7798+PgP76Fjhw7cerMuQuXrly7cevOvQePnjx78erNuw9//PXpy7d/fhz8p7fQkWMnTp05d+HSlWs3bt259+DRk2cvXr159+GPvz59+fbPj4P//BY6cuzEqTPnLly6cu3GrTv3Hjx68uzFqzfvPvzx16cv3/75cfBf3kJHjp04debchUtXrt24defeg0dPnr149ebdhz/++vTl2z8/Dv7rW+jIsROnzpy7cOnKtRu37tx78OjJsxev3rz78Mdfn758++fHwX97Cx05duLUmXMXLl25duPWnXsPHj159uLVm3cf/vjr05dv//w42N5CR46dOHXm3IVLV67duHXn3oNHT569ePXm3Yc//vr05ds/Pw7++1voyLETp86cu3DpyrUbt+7ce/DoybMXr968+/DHX5++fPvnx8H/eAsdOXbi1JlzFy5duXbj1p17Dx49efbi1Zt3H/7469OXb//8OPifb6Ejx06cOnPuwqUr127cunPvwaMnz168evPuwx9/ffry7Z8fB//rLXTk2IlTZ85duHTl2o1bd+49ePTk2YtXb959+OOvT1++/fPj4H+/hY4cO3HqzLkLl65cu3Hrzr0Hj548e/HqzbsPf/z16cu3f34c/Plb6MixE6fOnLtw6cq1G7fu3Hvw6MmzF6/evPvwx1+fvnz758fBX7yFjhw7cerMuQuXrly7cevOvQePnjx78erNuw9//PXpy7d/fhzsb6Ejx06cOnPuwqUr127cunPvwaMnz168evPuwx9/ffry7Z8fB//nLXTk2IlTZ85duHTl2o1bd+49ePTk2YtXb959+OOvT1++/fPj4P++hY4cO3HqzLkLl65cu3Hrzr0Hj548e/HqzbsPf/z16cu3f34c/L+30JFjJ06dOXfh0pVrN27duffg/w9fWSkE + + + AQAAAACAAABwFwAAHgAAAA==eJztwTEBAAAAwqAC65/XEL5AAQAAAAAArwFLPxlQ + + + + + diff --git a/inputFiles/poromechanicsFractures/ExponentialDecayPermeability_conformingFracture_base.xml b/inputFiles/poromechanicsFractures/ExponentialDecayPermeability_conformingFracture_base.xml index 9f47a0127e8..d21f7f7fb80 100644 --- a/inputFiles/poromechanicsFractures/ExponentialDecayPermeability_conformingFracture_base.xml +++ b/inputFiles/poromechanicsFractures/ExponentialDecayPermeability_conformingFracture_base.xml @@ -82,14 +82,14 @@ + materialList="{ water, fractureFilling, fractureContact, rock, hApertureModel}" + defaultAperture="1.0e-3"/> @@ -120,7 +120,7 @@ + frictionCoefficient="0.01"/> + + @@ -262,7 +265,7 @@ + values="{ 1.0e-6, 1.0e-3 }"/> + discretization="FE1" + contactPenaltyStiffness="2.0e11"/> + targetRegions="{ Domain, Fracture }"/> + materialList="{ water, fractureFilling, frictionLaw, hApertureModel }" + defaultAperture="1.0e-3"/> @@ -96,7 +96,7 @@ + name="frictionLaw"/> + + + values="{ 1.0e-6, 1.0e-3 }"/> diff --git a/inputFiles/poromechanicsFractures/Fault_Mesh_FaultModel.vtu b/inputFiles/poromechanicsFractures/Fault_Mesh_FaultModel.vtu new file mode 100644 index 00000000000..25c57076885 --- /dev/null +++ b/inputFiles/poromechanicsFractures/Fault_Mesh_FaultModel.vtu @@ -0,0 +1,52 @@ + + + + + + + AQAAAACAAACABQAAWwEAAA==eJxdi00ow3Ech1dKsTfDhaadRFyUKBellItSykUp5aKUclFKuShSLkRKiUgpERclykUp5aKNMS9jjHkZY8xblP9z+X2+l0/P0/OdzLD93y83L7wivCGcm2my32uxD1/CBvAV0g8LT8AH9IfsLH5J+nS7yR44yN8R68UXSd8nPAQf8xdix/DT0qeE0xwWn/B3yrrweQ6z7xLuhc/4O2cH8CPSx4TD9Em8zWnNBd7uNPs24Uu6TnwPG8H3Sx8SvqKL4hPsNf5H+iaXya1wlP6G7cB3S78nHIRv+YuxEXxc+jq3yY3wHX/3bAu+Xfot4V34gb8A/AiHpa/KMrkWjtM/sQ34ZulXhZ/pN/E7bAK/L32px+QXukp8DfuKr5d+TjhJt4xfZ9/w29IXZJtcDL/Tp9hyfLX048Iz8Ad/n+wifk16d47J+fAXf99sIb5M+kHhUeEp4QXhP65+1tE= + + + 2459.0002033 + + + 8892.4800253 + + + + + AQAAAACAAADAAgAAnAAAAA==eJwtxdciAgAAAMBKympIaNBCyChCZCcRSbL+/0966O7lAoGpoEOecdizjjjqOc97wYtecsxxJ5z0slNecdqrXvO6M84657w3vOmCiy657Iq3vO0dV73rPe+75gMf+sjHrrvhE5+66TOf+8ItX/rKbV/7xre+870f/OiOn9z1s3t+8av7fvO7B/7w0J8e+ctjf/vHv/7zvyfgYw71 + + + + + AQAAAACAAAD4AQAAbQAAAA==eJwtxUOCAwEAALCpbdvmosb/n9VDk0uC4CvksCOOOua4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565LEnnnrmuRdeeuW1N956570PPvrHv/7zv08+++Krb7774adffvsDGEMHog== + + + + + AQAAAACAAAAgBAAA4gAAAA==eJxN070JwzAYhOGbIrVGUaFBPIqmcK1RVDitwZDCYLCcTBLJhe9VdXw8HJ/8I81Jer0Vf4vuPC/O/XienLsP8AE+wAd4wQte8IK/vvZP7sfz5Nx9ha/wFb7CF/gCX+ALfIbP8Bk+w0/wE/wEP8FH+Agf4SN8gA/wAT7AC17wghfve+G+l73nyXn0wwte8ILPDf0N/Q39Df3wghe84POJ/hP9J/pP+3jg+R/2nifnsc+OfXbss2Of3b5+8H1+7D1PzmP/Dftv9p4n57H/iv1Xe8+T8/i/Fvsn36/Lvuc/fxk9eg== + + + 1980.0568174 + + + 3236.6803982 + + + + + + + AQAAAACAAADgBwAAPwEAAA==eJxdzNsyAgAURuEQQgghRCGEEEIIIYSQ8/u/iQt73ax988+s+WYnEv/XE9sfm1TvjR2Qo/fFDsol5YdiU+r4YTk6f0fkUvKjsWl1/Jgcnb/jcmn5idiMOn5Sjs7fKbmM/HRsVh0/I0fn76xcVn4uNqeOn5ej83dBLie/GJtXxy/J0flbkMvLL8cW1fErcnT+rsoV5ddiS+r4dTk6fzfkSvKbsWV1/JYcnb/bcmX5ndiKOn5Xjs7fPbmK/H5sVR1/IEfn76FcVf4otqaOP5aj8/dEriZ/GltXx5/J0fl7LleXv4htqOMv5ej8vZJryF/HNtXxN3J0/t7KNeXvYlvq+Hs5On8f5Fryj7FtdfyTHJ2/z3Jt+ZfYjjr+VY7O3ze5jvx7bFcd/yFH5++nXFf+O/ZLHf8jR+fvr9wfDAUq0w== + + + AQAAAACAAAD4AQAAlAAAAA==eJwtxRFgAgAAALAgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCILgcDgcgiAIgiAIgiAI2mTBwFfIYUccdcxxJ5x0ymlnnHXOeRdcdMllV1x1zXU33HTLbXfcdc99Dzz0yGNPPPXMcy+89Mprb7z1znsf/ONf//nfR5989sVX33z3w0+//PYHVzMfgQ== + + + AQAAAACAAAA/AAAADAAAAA==eJxjZ6cIAAA3XwG6 + + + + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_base.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_base.xml index a1f1bfdf98a..33d0b64c379 100644 --- a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_base.xml +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_base.xml @@ -1,54 +1,6 @@ - - - - - - - - - - - - - - - - @@ -111,7 +63,7 @@ + frictionCoefficient="0.1"/> + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_benchmark.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_benchmark.xml index 611a6c50f7b..b25239f76f3 100644 --- a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_benchmark.xml +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_benchmark.xml @@ -1,6 +1,10 @@ + + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_sequential_benchmark.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_sequential_benchmark.xml new file mode 100755 index 00000000000..d9312aade45 --- /dev/null +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_sequential_benchmark.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_sequential_smoke.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_sequential_smoke.xml new file mode 100755 index 00000000000..99098cfeb82 --- /dev/null +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_sequential_smoke.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_sequential_solvers.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_sequential_solvers.xml new file mode 100755 index 00000000000..845f3151232 --- /dev/null +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_sequential_solvers.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_smoke.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_smoke.xml index 42cee5e69c0..6da3d3746bd 100644 --- a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_smoke.xml +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_smoke.xml @@ -1,6 +1,10 @@ + + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_solvers.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_solvers.xml new file mode 100755 index 00000000000..2c8d9f8936b --- /dev/null +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_faultSlip_solvers.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_base.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_base.xml index 259cf4e34d8..530bcd104d2 100644 --- a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_base.xml +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_base.xml @@ -1,54 +1,6 @@ - - - - - - - - - - - - - - - - - @@ -104,7 +56,7 @@ + frictionCoefficient="0.577350269"/> + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_horizontal_sequential_smoke.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_horizontal_sequential_smoke.xml new file mode 100755 index 00000000000..ebd3885830c --- /dev/null +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_horizontal_sequential_smoke.xml @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_horizontal_smoke.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_horizontal_smoke.xml index 3e9282ccb5d..993b40bfaae 100644 --- a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_horizontal_smoke.xml +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_horizontal_smoke.xml @@ -1,6 +1,10 @@ + + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_sequential_solvers.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_sequential_solvers.xml new file mode 100755 index 00000000000..4112be144f1 --- /dev/null +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_sequential_solvers.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_solvers.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_solvers.xml new file mode 100755 index 00000000000..cc365b429c6 --- /dev/null +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_solvers.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_vertical_benchmark.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_vertical_benchmark.xml index 897967aefa3..20c65d99a94 100644 --- a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_vertical_benchmark.xml +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_vertical_benchmark.xml @@ -1,6 +1,10 @@ + + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_vertical_sequential_benchmark.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_vertical_sequential_benchmark.xml new file mode 100755 index 00000000000..a7b5775a538 --- /dev/null +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_vertical_sequential_benchmark.xml @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_vertical_sequential_smoke.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_vertical_sequential_smoke.xml new file mode 100755 index 00000000000..3feed452401 --- /dev/null +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_vertical_sequential_smoke.xml @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_vertical_smoke.xml b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_vertical_smoke.xml index 88891999ccb..3feed452401 100644 --- a/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_vertical_smoke.xml +++ b/inputFiles/poromechanicsFractures/PoroElastic_conformingFracture_2d_openingFrac_vertical_smoke.xml @@ -1,6 +1,10 @@ + + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_dfm_PEBICrack_base.xml b/inputFiles/poromechanicsFractures/PoroElastic_dfm_PEBICrack_base.xml new file mode 100644 index 00000000000..1aa468ae144 --- /dev/null +++ b/inputFiles/poromechanicsFractures/PoroElastic_dfm_PEBICrack_base.xml @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_dfm_PEBICrack_smoke.xml b/inputFiles/poromechanicsFractures/PoroElastic_dfm_PEBICrack_smoke.xml new file mode 100644 index 00000000000..77ea6c8ca5e --- /dev/null +++ b/inputFiles/poromechanicsFractures/PoroElastic_dfm_PEBICrack_smoke.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_base.xml b/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_base.xml index 06bdf9ac505..a6703adfc2c 100644 --- a/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_base.xml +++ b/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_base.xml @@ -23,7 +23,8 @@ name="fractureMechSolver" targetRegions="{ Domain, Fracture }" timeIntegrationOption="QuasiStatic" - discretization="FE1"/> + discretization="FE1" + contactPenaltyStiffness="4.0e9"/> @@ -98,7 +99,7 @@ + name="fractureContact"/> + + + + + discretization="FE1" + contactPenaltyStiffness="1e12"> + fieldNamesInGEOS="{ rockPermeability_permeability }"/> @@ -172,28 +173,28 @@ @@ -225,7 +226,7 @@ + name="fractureContact"/> + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_eggModel_small.xml b/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_eggModel_small.xml index fc3c78854b6..b362151b399 100644 --- a/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_eggModel_small.xml +++ b/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_eggModel_small.xml @@ -25,7 +25,8 @@ name="fractureMechSolver" targetRegions="{ Reservoir, Overburden, Underburden, Sideburden, Fracture }" timeIntegrationOption="QuasiStatic" - discretization="FE1"> + discretization="FE1" + contactPenaltyStiffness="1e12"> + fieldNamesInGEOS="{ rockPermeability_permeability }"/> @@ -172,28 +173,28 @@ @@ -225,7 +226,7 @@ + name="fractureContact"/> + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_pennyCrack_base.xml b/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_pennyCrack_base.xml index 47711919ec2..cd620c11905 100644 --- a/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_pennyCrack_base.xml +++ b/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_pennyCrack_base.xml @@ -31,14 +31,14 @@ @@ -70,7 +70,7 @@ + name="fractureContact"/> + + diff --git a/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_pennyCrack_benchmark.xml b/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_pennyCrack_benchmark.xml index a2979a5b39a..3ca8d754e85 100644 --- a/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_pennyCrack_benchmark.xml +++ b/inputFiles/poromechanicsFractures/PoroElastic_efem-edfm_pennyCrack_benchmark.xml @@ -28,7 +28,8 @@ name="fractureMechSolver" targetRegions="{ Domain, Fracture }" timeIntegrationOption="QuasiStatic" - discretization="FE1"/> + discretization="FE1" + contactPenaltyStiffness="1e12"/> + discretization="FE1" + contactPenaltyStiffness="1e12"/> + discretization="FE1" + contactPenaltyStiffness="0.0e8"/> @@ -141,7 +142,7 @@ + name="fractureContact"/> + + diff --git a/inputFiles/poromechanicsFractures/SlipPermeability_embeddedFrac.xml b/inputFiles/poromechanicsFractures/SlipPermeability_embeddedFrac.xml old mode 100755 new mode 100644 index 6d855d7effd..b0426e12899 --- a/inputFiles/poromechanicsFractures/SlipPermeability_embeddedFrac.xml +++ b/inputFiles/poromechanicsFractures/SlipPermeability_embeddedFrac.xml @@ -22,7 +22,8 @@ name="fractureMechSolver" targetRegions="{ Domain, Fracture }" timeIntegrationOption="QuasiStatic" - discretization="FE1"/> + discretization="FE1" + contactPenaltyStiffness="2.0e11"/> + materialList="{ water, fractureFilling, fractureContact, hApertureModel }" + defaultAperture="1.0e-3"/> @@ -203,7 +204,7 @@ + name="fractureContact"/> + + + values="{ 1.0e-6, 1.0e-3 }"/> diff --git a/inputFiles/poromechanicsFractures/SlipPermeability_pEDFM_base.xml b/inputFiles/poromechanicsFractures/SlipPermeability_pEDFM_base.xml old mode 100755 new mode 100644 index 9b1e5683fc3..089a856d6a7 --- a/inputFiles/poromechanicsFractures/SlipPermeability_pEDFM_base.xml +++ b/inputFiles/poromechanicsFractures/SlipPermeability_pEDFM_base.xml @@ -12,7 +12,7 @@ logLevel="1"> @@ -22,7 +22,8 @@ name="fractureMechSolver" targetRegions="{ Domain, Fracture }" timeIntegrationOption="QuasiStatic" - discretization="FE1"/> + discretization="FE1" + contactPenaltyStiffness="2.0e11"/> + usePEDFM="1"/> + materialList="{ water, fractureFilling, fractureContact, hApertureModel}" + defaultAperture="1.0e-3"/> @@ -96,7 +96,7 @@ + name="fractureContact"/> + + + values="{ 1.0e-6, 1.0e-3 }"/> diff --git a/inputFiles/poromechanicsFractures/WillisRichardsPermeability_efem-edfm_base.xml b/inputFiles/poromechanicsFractures/WillisRichardsPermeability_efem-edfm_base.xml old mode 100755 new mode 100644 index 46dc1483bd9..03f827efd1d --- a/inputFiles/poromechanicsFractures/WillisRichardsPermeability_efem-edfm_base.xml +++ b/inputFiles/poromechanicsFractures/WillisRichardsPermeability_efem-edfm_base.xml @@ -22,7 +22,8 @@ name="fractureMechSolver" targetRegions="{ Domain, Fracture }" timeIntegrationOption="QuasiStatic" - discretization="FE1"/> + discretization="FE1" + contactPenaltyStiffness="2.0e11"/> + materialList="{ water, fractureFilling, fractureContact, hApertureModel }" + defaultAperture="1.0e-3"/> @@ -98,7 +99,7 @@ + name="fractureContact"/> + + + values="{ 1.0e-6, 1.0e-3 }"/> diff --git a/inputFiles/poromechanicsFractures/displacedFault.vtm b/inputFiles/poromechanicsFractures/displacedFault.vtm new file mode 100644 index 00000000000..2cf49998a4d --- /dev/null +++ b/inputFiles/poromechanicsFractures/displacedFault.vtm @@ -0,0 +1,7 @@ + + + + + + + diff --git a/inputFiles/poromechanicsFractures/domain_res5_id.vtu b/inputFiles/poromechanicsFractures/domain_res5_id.vtu new file mode 100644 index 00000000000..0ecafafb5fd --- /dev/null +++ b/inputFiles/poromechanicsFractures/domain_res5_id.vtu @@ -0,0 +1,67 @@ + + + + + + + AQAAAACAAADgfwAARhgAAA==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 + + + + + AQAAAACAAAAwGwAABAEAAA==eJztlksOxDAIQ9PO/e88mq3lZ6JoVKURC5SGfADjUO4xxv1yuUA+BwjF9k95IkenYNX52CsfapNivWVddTTSWrXf+aO66p50ZsZvnV9wD9msbLk67HCajTt9u7WK34ShyythnHhA8VB8Dh/CM+FGOFexJRySn2rbYULcUl4QpitvKPHW2a14f4p0P9T/36ew6nzslY+Z+ubqp+popLVqv/NHddU96cyM3zrvfoh5QRgnHlA8FF/3Q4zpyhtKvHV2K96fIt0P9f/3Kaw6H3vlY6a+ufqpOhpprdrv/FFddU86M+O3zrsfYl4QxokHFA/F1/0QY7ryhhJvnd2K9z/5Ao84Duw= + + + AQAAAACAAACQUQAAMQAAAA==eJztwzENAAAIA7B3SjCBx2lGCG3SbCeqqqqqqqqqqqqqqqqqqqqqqqqqqo8eaqCtmg== + + + 1.7094007438e-15 + + + 1.7094007438e-15 + + + + + AQAAAACAAAAwGwAAIwAAAA==eJztwwENAAAIA6BmJjC67/QgwkZuJ6qqqqqqqvp0AWlKhrc= + + + AQAAAACAAAAwGwAAPQAAAA==eJzt1rEJADAIRUGH/dl/hbSp0oiFcAci2Nm9VFUG5wxPnp3Pfet/AMC87b2ghwCAru29oIcAgK4L9At6fQ== + + + AQAAAACAAABgNgAAawoAAA==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 + + + + + AgAAAACAAADQPwAAnzAAAG4eAAA=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4q6xxV1ji7umNcq6axpP665pjbXumtYi666xxV1ji7vGFneNLe4aW9w1trhrbHHX2OKuaX2z7prWSeuuscVdY4u7xhZ3TfPfumtpdNfY4q6xxV3T+mbdNV1T666xxV1ji7vGFneNLe4aW9w17ce6a7pe1l1ji7umdcO6a2xx19jirul+t+5aOvzOxu5aOpy37K6l0V2H28i8ZXdN65J119jirrHFXdM8se6a1g3rrrHFXdP9aN01trhrmhvWXWOLu8YWd23XZ3LX0mo9J3ctje463EbOhd01trhrbHHXNFetu6Z737prGnPrrrHFXdN6Zd01trhrbHHX/LnsrqXDY84O9inuWhrdNba4a2xx17QmWHdN18K6a1pPrLum9dm6a1pzrLvGFneNLe4aW9w1trhrbHHX2OKuscVdY4u7xhZ3jS3ums+L3bV0OA7srlXL78zkrrHFXWOLu8YWd40t7ppet+4aW9w1trhrbHHX2OKu6XOtu5YOjtO6a9WuNLprbHHXdC9Yd01zzLprbHHX2OKuscVdY4u7xhZ3jS3umseH3bW0eh6Ru5ZG8xNuEzyPyF1ji7vGFneNLe4aW9w1trhrbHHXPA7srqXDcWN3Ld1Xjse6a2l019jirmkNt+4aW9w1reHWXWOLu8YWd40t7pruI+uu+dzZXUuH48buWrpPMG6JatzYXWOLu8YWd03roXXXtO5Zd01rmnXXfL7srqXDsWJ3LT0iGKskNVbsrulzrbum9cG6a2xx13TvWHeNLe4aW9w1trhrbHHX2OKuscVdY4u7pnXAumtaf6y7xhZ3zePG7lpaPYPIXUujuw63CZ5B5K6xxV1ji7umNdm6a1rHrLvGFneNLe6a1gTrrrHFXdNnWXctHRynddfS6K7DbexxWndNa4t119jirrHFXWOLu8YWd033uHXX2OKuad227prWMeuuscVd8/myu+Z5wu5aOpxj7K6l0V2H28gcY3eNLe4aW9w1trhrbHHXdL7WXdN+rLuWDo7BumtpdNfhNvYYrLvGFneNLe4aW9w1trhrbHHX2OKuscVd87xidy2tvkuo51G6mofsrmm+WXdN64x119jirnk+sLsOOphLGeH+rbuWRndNa75119jirrHFXWOLu8YWd40t7pqvI7tr6XAOZKlnWZa67uyu6Vpbd40t7hpb3DW2uGua29Zd03yw7pqv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 + + + 0 + + + 3221.0246817 + + + + + + + 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 + + + AQAAAACAAABgNgAARQoAAA==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 + + + AQAAAACAAADMBgAAFgAAAA==eJzT0hoFo2AUjIJRMAqGNgAA9C4diA== + + + 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 + + + AQAAAACAAABgNgAAMAwAAA==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 + + + + + diff --git a/inputFiles/poromechanicsFractures/fracture_res5_id.vtu b/inputFiles/poromechanicsFractures/fracture_res5_id.vtu new file mode 100644 index 00000000000..0fba5b6159e --- /dev/null +++ b/inputFiles/poromechanicsFractures/fracture_res5_id.vtu @@ -0,0 +1,52 @@ + + + + + + + AQAAAACAAABADQAABgMAAA==eJwtyMVSFgAAhVFduHDh+Ah2d2GD2I0NdnchJnZiYmCLgYmtKHZid3djgo0dG2f8z918c27B7Jn+LyVzoIX4BBfmk1yET3FRPs3F+AwX57N8Tkv4S+p5fym+wKX5IpfhS1yWL3M5vsJBfJWvaXl/Bb3ur8g3uBLf5Mp8i6vwba7KdziY7/I9DfFX0/v+UH7A1fkh1+BHXJMfcy1+wrX5KT/TOv66muqvx8+5Pr/gBvySG/IrbsSvuTG/4TQN8zfRdH9TfsvN+B035/fcgj9wS/7IrfgTf9Zwf4Rm+FvzF27DX7ktf+N2/J1nZgm0vX8Wd+BY7siddLa/M8/hudrFP4+7chx34/ncnRdwD17IPbmXLvL35sW8RPv4l3JfXsb9OJ7783IewCt4IEfqSv8gXsUJGuVfzYN5DQ/htTyU1/EwXs/DeYRu8EdzIm/Ukf5NPIo382jewmN4K4/lbTyOx+t2/wTewTt1oj+JJ/Eunsy7eQoncwzv4ak8Tff6p/M+3q8z/Ad4Jh/kWXyIY/kwz+YjPIfn6lH/PD7Gcdwya6DzuRUv4HCO0IX+1ryI2/BiXqJt/Uu5HS/j9hzPHXg5d+ROusLfmVdyF17FCdrVv5q78Rruzmu5B6/jntxL1/t78wbuw4m8Ufv6N3E/3sz9eQsP4K08kCN1m38Qb+co3sE7dbA/iYfwLh7Ku3kYJ/NwHqF7/NG8l0fyPt6vo/wHeDQf5DF8iMfyYR7H4/WIfwIf5Yl8jI/rJH8KT+YTPIVPcgyf4qk8TU/7p/MZPqs5sgWaU8/5c/F5vqC5/Xn0ov+S5vVf5nx8hfPzVS7ABfWavxBf5xta2F9Eb/pvaVH/bS7Gd7g43+USXFLv+UvxfX6gpf1l9KH/kZb1P+Zy/ISD+CmX5wr6zF+RU7kSP+fK/IJfahX/K67KrzmY33AIV9M0fyinc3V+yzX4Hb/Xmv4PXIs/cm3+xHW4rn721+MMrs9fuAF/5W/a0P+dG/EPbsw/OYyb6C9/U/7NzfgPN+e//A+qS/z/ + + + 3905.8931117 + + + 5326.4624283 + + + + + AQAAAACAAACgBgAAbgEAAA==eJwtxdciEAAAAEBRUmlpK9q0aEpbey/tTUMb0d57T6VBO+2NSGjvoflDHrp7uYCA/6o40EGu6moOdnWHuIZrupZDXdt1XNf1XN9hbuCGbuTGbuKmbuZwN3cLRzjSLd3Krd3Gbd3O7R3laHdwR3dyZ3dxjGPd1d3c3T3c070c596Odx/3dT/39wAP9CAneLCHeKiHebhHeKRHebTHeKzHebwneKInebITPcVTPc3TPcMzPcuzPcdzPc/zvcBJTvZCL/JiL3GKl3qZl3uFV3qVVzvVaU73Gmc402u9zuu9wRu9yZu9xVu9zdu9wzu9y7u9x3u9z/t9wAd9yId9xEd9zMd9wid9ylk+7TPO9lmf83lfcI5zfdGXfNlXfNXXfN03nOebvuXbvuO7vuf7fuCHfuTHfuKnzneBC/3MRS72c5f4hUtd5nK/9Cu/9hu/9Tu/9wd/9Cd/9hd/9Td/9w9X+Kd/+bf/+K//uRLqf1df + + + + + AQAAAACAAADgBAAAEgEAAA==eJwtxddCCAAAAMAiozSkoaGh0NAeqGhrSNEg7SFkJKFhlIhoaCBUP9tDdy8XEHAo0Ed81EE+5uM+4ZMOdohPOdRhDneETzvSZxzlaMc41mcd53gnONHnnORkpzjV553mdF/wRV9yhjOd5Wxfdo5zned8F7jQRS52iUt9xVd9zWUud4Wv+4YrXeVq17jWda73TTe40U1u9i23+LZb3eY7vut2d7jTXb7n++72A/e4133u94AHPeRhj3jUDz3mR37sJx73Uz/zc7/whF960q885dd+47ee9oxnPed3fu8P/uh5L/iTF/3ZX7zkr/7mZX/3D6941Wte909veNNb3vYv//Yf7/iv//m/d73nfR8ARZMvOw== + + + + + AQAAAACAAADwCQAAXQIAAA==eJxtlaFOK1EQhheFQZCKq1E3+xQN6Zm+QR8ATdKER1iPQVVvVhxxa6rQtNy6DcFhGzwJkhzF9ITO/93kVn3Z7M78Z86XTtP4r7/YN6dfey7enInvvv4Gdx/ih3dx/ybejOKnrfj1UXxYiz97cbMSX96LrzrxzS3yLJBhir4tek1QvzwHXr+IuwG8FDe/wKtd89/faob3E+qAB/H1i7gp4sPEkF/cT8XdQnxzK77qxJf34mYl/uzFh7X49RF9t+LNiAxv4od35PkQ333h27N5cHsu7i/I+/Wf3+nnHbG7F+zuBbt7we5esLunb0exuxfs7gW7e8HuXrC7F+zuBbt7we6e8iyQYYq+LXpNUL88B7t7qjOAl2J3D9l24qbB8xneT6gDHhL6JuRJyGnIbziX4byGORjmY5ibIZthzob5i9093JfY3cP9it09+CB29+DPHF6J3T2wO5bhXoZ7Ge5luJfhXoZ7p29HcXUvw70M9zLcy3Avw70M9zLcO+VZIMMUfVv0mqD+0b0M9051BvBSXN2LbDvx0b14PsP7CXXAQ0LfhDwJOQ35DecynNcwB8N8DHMzZDPM2TB/cXUv7ktc3Yv7FVf3wgdxdS/8mcMrcXUveB//+3XnlnAvuO7cEu4F151bwj19O4rrzi3hXnDduSXc0+5ZievOLeFecN25pzwLZJiib4teE9Q/7twS7qnOAF6K686NbLt/dqSez/B+Qh3wkNA3IU9CTkN+w7kM5zXMwTAfw9wM2QxzFtedG/eCvltx3blxv+K6c8MHcd254c8cXonrzi3pG10/Tpw= + + + 0 + + + 2304.8861143 + + + + + + + AQAAAACAAACAEwAAWQMAAA==eJxd1Vf7CAQYhnEjpKiUWYmiREX29rf33nvvvffee29KoShbpE2plJXxhRy474Oe9+R3Xff1nL/1Cz2/BjgFJ2M9rB99EtaNnX0ifho7+wSsEzv7eKwdO/s4/CR29rH4cezsY/Cj2NlHY63Y2UdhzdjZR+KHsbOPwBqxsw/HD2JnH4bvx84+FKvHzj4Eq8XOPhjfi519EL4bO/tArBo7+wCsEjt7f3wndvZ+WDl29r74duzsffCt2Nl745uxs/fCSrGz98SKsbP3wAqxs3fH8rGzd8NysbN3xbKxs3fBN2Jn74yvx87eCcvEzt4RX4udvQO+Gjt7e3wldvZ2WDp29rZYKnb2Nvhy7Oyt8aXY2QuwZOzsrfDF2NlbYonY2Vtg8djZm2Ox2Nmb4QuxszfForGzN8EisbM3xsKxszcq9P8rHL0h+k/8O5/jZzgpdvbjODF29mM4IXb2ozg+dvYjOC529sM4Nnb2QzgmdvaDODp29gM4Knb2/TgydvZ9OCJ29r04PHb2PTgsdvbdODR29l04JHb2nTg4dvYdOCh29u04MHb2bTggdvat2D929i3YL3b2zdg3dvZN2Cd29o3YO3b2Ddgrdvb12DN29nXYI3b2tdg9dvY12C129tXYNXb2VdgldvaV2Dl29hXYKXb25dgxdvZl2CF29qXYPnb2JdgudvbF2DZ29kXYJnb2hdg6dvYFWBA7+3xsFTv7PGwZO/tcbBE7+xxsHjv7bGwWO/ssbBo7+0xsEjv7DGwcO/t0bBQ7+zRsGDv7VPSf+Hee4hM8Hjv7YzwWO/sjPBo7+394JHb2h3g4dvYHeCh29vt4MHb2e3ggdva7uD929n9xX+zs/+De2Nnv4J7Y2f/G3bGz/4W7Ymf/E3fGzn4bd8TO/gduj539d9wWO/st3Bo7+03cEjv7b7g5dvZfcVPs7L/gxtjZf8YNsbP/hOtjZ/8R18XO/gOujZ39Bq6Jnf17XB07+3VcFTv7NVwZO/t3uCJ29qu4PHb2K7gsdvbLuDR29ku4JHb2i7g4dvYLuCh29vO4MHb2c7ggdvZvcX7s7N/gvNjZz+Lc2NnP4JzY2b/G2bGzf4WzYmc/jTNjZz+FM2JnP4nTY2f/EqfFzv4FTo2d/QQ+A6EeATg= + + + AQAAAACAAADgBAAADgEAAA==eJwtxRFwAgAAAMC2C4IgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCAaDwSAIgiAIgiAIBkEQDPqXDwbeQg474qhjjjvhpFNOO+Osc8674KJLLrviqmuuu+GmW26746577nvgoUcee+KpZ5574aVXXnvjrb/87R//eue9Dz765LMvvvrmu//88NMvBz7eBR1y2BFHHXPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898tgTTz3z3AsvvfLaG2/95W//+Nc7733w0SefffHVN9/954effjnw+S7okMOOOOqY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvu+B9fwUXT + + + AQAAAACAAACcAAAADAAAAA==eJxjZx+8AABPhQRF + + + + + diff --git a/inputFiles/poromechanicsFractures/poromechanicsFractures.ats b/inputFiles/poromechanicsFractures/poromechanicsFractures.ats index 02dfc957812..4b1a097f90c 100644 --- a/inputFiles/poromechanicsFractures/poromechanicsFractures.ats +++ b/inputFiles/poromechanicsFractures/poromechanicsFractures.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {'atol': 1e-07, 'rtol': 4e-06} @@ -26,6 +24,13 @@ decks = [ restart_step=0, check_step=10, restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="PoroElastic_conformingFracture_2d_openingFrac_horizontal_sequential_smoke", + description='PoroElastic conformingFracture 2d case (sequential)', + partitions=((1, 1, 1), (2, 2, 1)), + restart_step=0, + check_step=10, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), TestDeck( name="PoroElastic_conformingFracture_2d_openingFrac_vertical_smoke", description='PoroElastic conformingFracture 2d case', @@ -33,6 +38,13 @@ decks = [ restart_step=0, check_step=10, restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="PoroElastic_conformingFracture_2d_openingFrac_vertical_sequential_smoke", + description='PoroElastic conformingFracture 2d case (sequential)', + partitions=((1, 1, 1), (2, 2, 1)), + restart_step=0, + check_step=10, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), TestDeck( name="PoroElastic_efem-edfm_pressurizedFrac_smoke", description='poromechanics efem-edfm pressurized vertical frac', @@ -68,7 +80,22 @@ decks = [ restart_step=0, check_step=12, restartcheck_params=RestartcheckParameters(atol=1e-05, - rtol=4e-04)) + rtol=4e-04)), + TestDeck( + name="PoroElastic_dfm_PEBICrack_smoke", + description='Plane strain poro-elastic problems with conforming vertical fracture (unstructured PEBI grid)', + partitions=((1, 1, 1), (3, 1, 1)), + restart_step=5, + check_step=10, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="singlePhasePoromechanics_FaultModel_smoke", + description='PoroElastic conformingFracture intialization with external mesh', + partitions=((1, 1, 1), (2, 2, 1)), + restart_step=0, + check_step=1, + restartcheck_params=RestartcheckParameters(atol=1e-05, + rtol=1e-04)) ] generate_geos_tests(decks) diff --git a/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_base.xml b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_base.xml new file mode 100644 index 00000000000..0623d767f54 --- /dev/null +++ b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_base.xml @@ -0,0 +1,227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_smoke.xml b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_smoke.xml new file mode 100644 index 00000000000..78bb944d446 --- /dev/null +++ b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_smoke.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_base.xml b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_base.xml new file mode 100644 index 00000000000..b86106ea73d --- /dev/null +++ b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_base.xml @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_fim_smoke.xml b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_fim_smoke.xml new file mode 100644 index 00000000000..8a0e0e30138 --- /dev/null +++ b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_fim_smoke.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_seq_smoke.xml b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_seq_smoke.xml new file mode 100644 index 00000000000..4ff5d4e8669 --- /dev/null +++ b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_seq_smoke.xml @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/poromechanicsFractures/verticalFault_ExternalMesh.vtm b/inputFiles/poromechanicsFractures/verticalFault_ExternalMesh.vtm new file mode 100644 index 00000000000..abb0265a6ca --- /dev/null +++ b/inputFiles/poromechanicsFractures/verticalFault_ExternalMesh.vtm @@ -0,0 +1,14 @@ + + + + + + + diff --git a/inputFiles/proppant/FlowProppantBedTransport2d_base.xml b/inputFiles/proppant/FlowProppantBedTransport2d_base.xml index 3006bf33ed7..177a83e6c00 100644 --- a/inputFiles/proppant/FlowProppantBedTransport2d_base.xml +++ b/inputFiles/proppant/FlowProppantBedTransport2d_base.xml @@ -81,7 +81,7 @@ diff --git a/inputFiles/relpermDriver/testRelpermDriverBCStoneII.xml b/inputFiles/relpermDriver/testRelpermDriverBCStoneII.xml index ab0c4abaaa7..80c5ab16abb 100644 --- a/inputFiles/relpermDriver/testRelpermDriverBCStoneII.xml +++ b/inputFiles/relpermDriver/testRelpermDriverBCStoneII.xml @@ -47,7 +47,7 @@ diff --git a/inputFiles/relpermDriver/testRelpermDriverTableHyst2ph.xml b/inputFiles/relpermDriver/testRelpermDriverTableHyst2ph.xml index 000003049c7..60614391abf 100644 --- a/inputFiles/relpermDriver/testRelpermDriverTableHyst2ph.xml +++ b/inputFiles/relpermDriver/testRelpermDriverTableHyst2ph.xml @@ -46,7 +46,7 @@ diff --git a/inputFiles/simplePDE/10x10x10Hex_LaplaceFEM_smoke.xml b/inputFiles/simplePDE/10x10x10Hex_LaplaceFEM_smoke.xml index eb35e4b7ccc..0709dcbfcb8 100644 --- a/inputFiles/simplePDE/10x10x10Hex_LaplaceFEM_smoke.xml +++ b/inputFiles/simplePDE/10x10x10Hex_LaplaceFEM_smoke.xml @@ -22,7 +22,7 @@ diff --git a/inputFiles/simplePDE/10x10x10Hex_LaplaceVEM_smoke.xml b/inputFiles/simplePDE/10x10x10Hex_LaplaceVEM_smoke.xml index b05378fb3ed..1c5cd08d1de 100644 --- a/inputFiles/simplePDE/10x10x10Hex_LaplaceVEM_smoke.xml +++ b/inputFiles/simplePDE/10x10x10Hex_LaplaceVEM_smoke.xml @@ -22,7 +22,7 @@ diff --git a/inputFiles/simplePDE/10x5x15Wedges_LaplaceVEM_smoke.xml b/inputFiles/simplePDE/10x5x15Wedges_LaplaceVEM_smoke.xml index 220b273e56c..fbb1ebddd32 100644 --- a/inputFiles/simplePDE/10x5x15Wedges_LaplaceVEM_smoke.xml +++ b/inputFiles/simplePDE/10x5x15Wedges_LaplaceVEM_smoke.xml @@ -22,7 +22,7 @@ diff --git a/inputFiles/simplePDE/15x5x10Tets_LaplaceVEM_smoke.xml b/inputFiles/simplePDE/15x5x10Tets_LaplaceVEM_smoke.xml index 76594883a4c..0cda8414a01 100644 --- a/inputFiles/simplePDE/15x5x10Tets_LaplaceVEM_smoke.xml +++ b/inputFiles/simplePDE/15x5x10Tets_LaplaceVEM_smoke.xml @@ -22,7 +22,7 @@ diff --git a/inputFiles/simplePDE/50x10x5Hex_LaplaceFEM_smoke.xml b/inputFiles/simplePDE/50x10x5Hex_LaplaceFEM_smoke.xml index aff5d97ec10..49913b72224 100644 --- a/inputFiles/simplePDE/50x10x5Hex_LaplaceFEM_smoke.xml +++ b/inputFiles/simplePDE/50x10x5Hex_LaplaceFEM_smoke.xml @@ -22,7 +22,7 @@ diff --git a/inputFiles/simplePDE/SimpleSolvers.ats b/inputFiles/simplePDE/SimpleSolvers.ats index 8e5de718d0d..f164d86ed16 100644 --- a/inputFiles/simplePDE/SimpleSolvers.ats +++ b/inputFiles/simplePDE/SimpleSolvers.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params['atol'] = 1e-08 diff --git a/inputFiles/simplePDE/hybridHexPrism_LaplaceVEM_smoke.xml b/inputFiles/simplePDE/hybridHexPrism_LaplaceVEM_smoke.xml index 85f31ec5340..80e6b4d50b7 100644 --- a/inputFiles/simplePDE/hybridHexPrism_LaplaceVEM_smoke.xml +++ b/inputFiles/simplePDE/hybridHexPrism_LaplaceVEM_smoke.xml @@ -29,4 +29,3 @@ - diff --git a/inputFiles/singlePhaseFlow/3D_10x10x10_compressible_base.xml b/inputFiles/singlePhaseFlow/3D_10x10x10_compressible_base.xml index 502b8a22bd9..d9157d9b2b0 100644 --- a/inputFiles/singlePhaseFlow/3D_10x10x10_compressible_base.xml +++ b/inputFiles/singlePhaseFlow/3D_10x10x10_compressible_base.xml @@ -50,7 +50,7 @@ diff --git a/inputFiles/singlePhaseFlow/3D_10x10x10_thermalCompressible_base.xml b/inputFiles/singlePhaseFlow/3D_10x10x10_thermalCompressible_base.xml index 33608531c56..1e529f1a41e 100644 --- a/inputFiles/singlePhaseFlow/3D_10x10x10_thermalCompressible_base.xml +++ b/inputFiles/singlePhaseFlow/3D_10x10x10_thermalCompressible_base.xml @@ -39,7 +39,7 @@ @@ -63,7 +63,7 @@ @@ -83,9 +83,9 @@ specificHeatCapacity="4.0e3" referenceInternalEnergy="1.1e6"/> - + defaultThermalConductivityComponents="{ 3.5, 3.5, 3.5 }"/> diff --git a/inputFiles/singlePhaseFlow/FieldCaseTutorial3_base.xml b/inputFiles/singlePhaseFlow/FieldCaseTutorial3_base.xml index d9efb08892d..6de436890ed 100644 --- a/inputFiles/singlePhaseFlow/FieldCaseTutorial3_base.xml +++ b/inputFiles/singlePhaseFlow/FieldCaseTutorial3_base.xml @@ -5,12 +5,12 @@ diff --git a/inputFiles/singlePhaseFlow/FieldCaseTutorial3_composite_smoke.xml b/inputFiles/singlePhaseFlow/FieldCaseTutorial3_composite_smoke.xml new file mode 100644 index 00000000000..9312ecaae37 --- /dev/null +++ b/inputFiles/singlePhaseFlow/FieldCaseTutorial3_composite_smoke.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/singlePhaseFlow/PressurePerm_1d_base.xml b/inputFiles/singlePhaseFlow/PressurePerm_1d_base.xml new file mode 100755 index 00000000000..73147f4d729 --- /dev/null +++ b/inputFiles/singlePhaseFlow/PressurePerm_1d_base.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/singlePhaseFlow/PressurePerm_1d_smoke.xml b/inputFiles/singlePhaseFlow/PressurePerm_1d_smoke.xml new file mode 100755 index 00000000000..db98e62b1b3 --- /dev/null +++ b/inputFiles/singlePhaseFlow/PressurePerm_1d_smoke.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/singlePhaseFlow/PressurePerm_2d_base.xml b/inputFiles/singlePhaseFlow/PressurePerm_2d_base.xml new file mode 100755 index 00000000000..97ac626c60d --- /dev/null +++ b/inputFiles/singlePhaseFlow/PressurePerm_2d_base.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/singlePhaseFlow/PressurePerm_2d_smoke.xml b/inputFiles/singlePhaseFlow/PressurePerm_2d_smoke.xml new file mode 100755 index 00000000000..34dd7411aee --- /dev/null +++ b/inputFiles/singlePhaseFlow/PressurePerm_2d_smoke.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/singlePhaseFlow/compressible_1d.xml b/inputFiles/singlePhaseFlow/compressible_1d.xml index 168809613cb..d4a937ad4b3 100644 --- a/inputFiles/singlePhaseFlow/compressible_1d.xml +++ b/inputFiles/singlePhaseFlow/compressible_1d.xml @@ -70,7 +70,7 @@ diff --git a/inputFiles/singlePhaseFlow/compressible_1d_2solids.xml b/inputFiles/singlePhaseFlow/compressible_1d_2solids.xml index 1f28c8d3e13..b6c38999957 100644 --- a/inputFiles/singlePhaseFlow/compressible_1d_2solids.xml +++ b/inputFiles/singlePhaseFlow/compressible_1d_2solids.xml @@ -25,7 +25,7 @@ nx="{ 5, 5 }" ny="{ 1 }" nz="{ 1 }" - cellBlockNames="{ block1, block2 }"/> + cellBlockNames="{ cb-0_0_0, cb-1_0_0 }"/> @@ -69,12 +69,12 @@ diff --git a/inputFiles/singlePhaseFlow/compressible_2d_2fluids.xml b/inputFiles/singlePhaseFlow/compressible_2d_2fluids.xml index 96110f04bbf..17b28f92439 100644 --- a/inputFiles/singlePhaseFlow/compressible_2d_2fluids.xml +++ b/inputFiles/singlePhaseFlow/compressible_2d_2fluids.xml @@ -25,7 +25,7 @@ nx="{ 5, 5 }" ny="{ 3 }" nz="{ 1 }" - cellBlockNames="{ block1, block2 }"/> + cellBlockNames="{ cb-0_0_0, cb-1_0_0 }"/> @@ -85,12 +85,12 @@ diff --git a/inputFiles/singlePhaseFlow/compressible_2d_2fluids_hybrid.xml b/inputFiles/singlePhaseFlow/compressible_2d_2fluids_hybrid.xml index 2c934611c49..c7589636004 100644 --- a/inputFiles/singlePhaseFlow/compressible_2d_2fluids_hybrid.xml +++ b/inputFiles/singlePhaseFlow/compressible_2d_2fluids_hybrid.xml @@ -25,7 +25,7 @@ nx="{ 5, 5 }" ny="{ 3 }" nz="{ 1 }" - cellBlockNames="{ block1, block2 }"/> + cellBlockNames="{ cb-0_0_0, cb-1_0_0 }"/> @@ -85,12 +85,12 @@ @@ -137,7 +137,7 @@ name="Porosity" initialCondition="1" setNames="{ all }" - objectPath="ElementRegions/Region1/block1" + objectPath="ElementRegions/Region1/cb-0_0_0" fieldName="rockPorosity_referencePorosity" scale="0.05"/> diff --git a/inputFiles/singlePhaseFlow/incompressible_1d.xml b/inputFiles/singlePhaseFlow/incompressible_1d.xml index e4f37618cd2..670099cebbf 100644 --- a/inputFiles/singlePhaseFlow/incompressible_1d.xml +++ b/inputFiles/singlePhaseFlow/incompressible_1d.xml @@ -69,7 +69,7 @@ diff --git a/inputFiles/singlePhaseFlow/incompressible_pebi3d.xml b/inputFiles/singlePhaseFlow/incompressible_pebi3d.xml index 75c3035c87e..162b2667e51 100644 --- a/inputFiles/singlePhaseFlow/incompressible_pebi3d.xml +++ b/inputFiles/singlePhaseFlow/incompressible_pebi3d.xml @@ -23,7 +23,7 @@ partitionRefinement="3" useGlobalIds="1" fieldsToImport="{ PERM, PORO, NTG }" - fieldNamesInGEOSX="{ rockPerm_permeability, rockPorosity_referencePorosity, netToGross }" + fieldNamesInGEOS="{ rockPerm_permeability, rockPorosity_referencePorosity, netToGross }" file="pebi3d_with_properties.vtu"/> @@ -68,7 +68,7 @@ diff --git a/inputFiles/singlePhaseFlow/singlePhaseFlow.ats b/inputFiles/singlePhaseFlow/singlePhaseFlow.ats index 2f0bb232b86..e6795bbe42f 100644 --- a/inputFiles/singlePhaseFlow/singlePhaseFlow.ats +++ b/inputFiles/singlePhaseFlow/singlePhaseFlow.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params['atol'] = 1e-10 @@ -75,6 +73,22 @@ decks = [ partitions=((1, 1, 1), (2, 2, 2), (3, 3, 3)), restart_step=10, check_step=20, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="PressurePerm_1d_smoke", + description= + 'Single phase flow test (1D, compressible, pressure dependent perm)', + partitions=((1, 1, 1), (2, 1, 1), (3, 1, 1)), + restart_step=10, + check_step=20, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="PressurePerm_2d_smoke", + description= + 'Single phase flow test (2D, compressible, pressure dependent perm)', + partitions=((1, 1, 1), (2, 2, 1), (3, 3, 1)), + restart_step=10, + check_step=20, restartcheck_params=RestartcheckParameters(**restartcheck_params)) ] diff --git a/inputFiles/singlePhaseFlow/sourceFlux_1d.xml b/inputFiles/singlePhaseFlow/sourceFlux_1d.xml index 8fdf76542f5..2cae841d4da 100644 --- a/inputFiles/singlePhaseFlow/sourceFlux_1d.xml +++ b/inputFiles/singlePhaseFlow/sourceFlux_1d.xml @@ -68,7 +68,7 @@ diff --git a/inputFiles/singlePhaseFlow/sourceFlux_2d.xml b/inputFiles/singlePhaseFlow/sourceFlux_2d.xml index a455b137720..4a0d5cf3a28 100644 --- a/inputFiles/singlePhaseFlow/sourceFlux_2d.xml +++ b/inputFiles/singlePhaseFlow/sourceFlux_2d.xml @@ -94,7 +94,7 @@ diff --git a/inputFiles/singlePhaseFlow/staircase_3d.xml b/inputFiles/singlePhaseFlow/staircase_3d.xml index 95628bc339d..2722e20c150 100644 --- a/inputFiles/singlePhaseFlow/staircase_3d.xml +++ b/inputFiles/singlePhaseFlow/staircase_3d.xml @@ -1,6 +1,7 @@ - + + cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, + cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1, + cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2, + cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }"/> @@ -73,12 +77,12 @@ diff --git a/inputFiles/singlePhaseFlow/synthetic.vtpc b/inputFiles/singlePhaseFlow/synthetic.vtpc new file mode 100644 index 00000000000..6fa5973442a --- /dev/null +++ b/inputFiles/singlePhaseFlow/synthetic.vtpc @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxSb290IHR5cGU9InZ0a0RhdGFBc3NlbWJseSIgdmVyc2lvbj0iMS4wIiBpZD0iMCIgdnRrX3R5cGU9IjM4IiB2dGtfY2F0ZWdvcnk9Inhmb3JtZWRfaGllcmFyY2h5IiBsYWJlbD0iZGF0YSI+CiAgPE1lc2ggaWQ9IjEiIGxhYmVsPSJTeW50aGV0aWNNZXNoIj4KICAgIDxSZWdpb24xIGlkPSIyIiBsYWJlbD0iUmVnaW9uMSIgbnVtYmVyX29mX3BhcnRpdGlvbnM9IjEiPgogICAgICA8ZGF0YXNldCBpZD0iMCIgLz4KICAgIDwvUmVnaW9uMT4KICAgIDxSZWdpb24yIGlkPSIzIiBsYWJlbD0iUmVnaW9uMiIgbnVtYmVyX29mX3BhcnRpdGlvbnM9IjEiPgogICAgICA8ZGF0YXNldCBpZD0iMSIgLz4KICAgIDwvUmVnaW9uMj4KICAgIDxSZWdpb24zIGlkPSI0IiBsYWJlbD0iUmVnaW9uMyIgbnVtYmVyX29mX3BhcnRpdGlvbnM9IjEiPgogICAgICA8ZGF0YXNldCBpZD0iMiIgLz4KICAgIDwvUmVnaW9uMz4KICA8L01lc2g+CjwvUm9vdD4K + + + diff --git a/inputFiles/singlePhaseFlow/synthetic/synthetic_0_0.vtu b/inputFiles/singlePhaseFlow/synthetic/synthetic_0_0.vtu new file mode 100644 index 00000000000..f3c0c2da30a --- /dev/null +++ b/inputFiles/singlePhaseFlow/synthetic/synthetic_0_0.vtu @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + _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cc8DjzzxzAuvvPHOB5988c3Pn4HOv/9LgEGGGGaEUcYY5zcTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz5/OOCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754dc/+CXAIEMMM8IoY4zzmwkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnz8ccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zw6//7JcAgQwwzwihjjPObCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfPxxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDPQH+AQYYYZoRRxhjnNxNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPn844JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvn5s8jxD38JMMgQw4wwyhjj/GaCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OcPBxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PpHvwQYZIhhRhhljHF+M8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvs84cDDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9+/eNfAgwyxDAjjDLGOL+ZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfb5wwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND/8s8gUYZIhhRhhljHF+M8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvs84cDDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnim58/C5z/5JcAgwwxzAijjDHObyaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPff5wwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDr3/6S4BBhhhmhFHGGOc3E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+fzjgkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eHXP/slwCBDDDPCKGOM85sJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58/HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88M8Cf4BBhhhmhFHGGOc3E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+fzjgkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eHXP/8lwCBDDDPCKGOM85sJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58/HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88Otf/BJgkCGGGWGUMcb5zQSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzx8OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3749S9/CTDIEMOMMMoY4/xmgkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjnDwcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/wT3BNgkCGGGWGUMcb5zQSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzx8OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3749a9+CTDIEMOMMMoY4/xmgkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjnDwcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/z6178EGGSIYUYYZYxxfjPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577POHAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffv2bXwIMMsQwI4wyxji/mWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32+cMBhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ//BPYFGGSIYUYYZYxxfjPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577POHAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffv3bXwIMMsQwI4wyxji/mWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32+cMBhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//t0vAQYZYpgRRhljnN9MMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvv84YBDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1///pcAgwwxzAijjDHObyaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPff5wwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDP0G9AQYZYpgRRhljnN9MMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvv84YBDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1//4ZcAgwwxzAijjDHObyaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPff5wwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDr//4S4BBhhhmhFHGGOc3E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+fzjgkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eHXf/olwCBDDDPCKGOM85sJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58/HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88E9Af4BBhhhmhFHGGOc3E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+fzjgkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eHX//9LgEGGGGaEUcYY5zcTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz5/OOCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754dd//iXAIEMMM8IoY4zzmwkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnz8ccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zw67/8EmCQIYYZYZQxxvnNBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPHw445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745ItvfvjnME+AQYYYZoRRxhjnNxNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPn844JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnh13/9JcAgQwwzwihjjPObCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfPxxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDrv/0SYJAhhhlhlDHG+c0Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8fDjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++PXffwkwyBDDjDDKGOP8ZoJJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY5w8HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/8c5AvwCBDDDPCKGOM85sJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58/HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88Ot//BJgkCGGGWGUMcb5zQSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzx8OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3749T9/CTDIEMOMMMoY4/xmgkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjnDwcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/z6X78EGGSIYUYYZYxxfjPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577POHAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psf/jnEG2CQIYYZYZQxxvnNBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPHw445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvj1v38JMMgQw4wwyhjj/GaCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OcPBxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//Po/vwQYZIhhRhhljHF+M8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvs84cDDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9+/d9fAgwyxDAjjDLGOL+ZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfb5wwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND79yv/w/dLzYyHicLcUhuAEAACBmQRAEQRAEQRAEQRAEd7OdbbbZZnd2ZzvbbLPNNtvczW7uThCEFwRBEARBEARBEARBEF4QBEEQBEEQhBf2ffP/5Q8WAv+/kMOOOOqY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvuuOue+x546JF/PPbEU88898JLr7z2xlvvvPfBR5/867Mvvvrmux9++uW3P/5z4B98CzrksCOOOua4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565B+PPfHUM8+98NIrr73x1jvvffDRJ//67Iuvvvnuh59++e2P/xz4h9+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B/6db0GHHHbEUcccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDj/zjsSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fDTL7/98Z8DxW9Bhxx2xFHHHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4/847EnnnrmuRdeeuW1N956570PPvrkX5998dU33/3w0y+//fGfA//ut6BDDjviqGOOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChR/7x2BNPPfPcCy+98tobb73z3gcfffKvz7746pvvfvjpl9/++M+Bf+9b0CGHHXHUMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAj/3jsiaeeee6Fl1557Y233nnvg48++ddnX3z1zXc//PTLb3/858A/+hZ0yGFHHHXMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889Mg/HnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q8//fLbH/85UPoWdMhhRxx1zHEnnHTKaWecdc55F1x0yWVXXHXNdTfcdMttd9x1z30PPPTIPx574qlnnnvhpVdee+Otd9774KNP/vXZF199890PP/3y2x//OfDvfws65LAjjjrmuBNOOuW0M84657wLLrrksiuuuua6G2665bY77rrnvgceeuQfjz3x1DPPvfDSK6+98dY7733w0Sf/+uyLr7757oeffvntj/8c+A++BR1y2BFHHXPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898o/HnnjqmedeeOmV19546533Pvjok3999sVX33z3w0+//PbHfw78h9+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B8rfgg457IijjjnuhJNOOe2Ms84574KLLrnsiquuue6Gm2657Y677rnvgYce+cdjTzz1zHMvvPTKa2+89c57H3z0yb8+++Krb7774adffvvjPwf+o29Bhxx2xFHHHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4/847EnnnrmuRdeeuW1N956570PPvrkX5998dU33/3w0y+//fGfA//xt6BDDjviqGOOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChR/7x2BNPPfPcCy+98tobb73z3gcfffKvz7746pvvfvjpl9/++M+B/+Rb0CGHHXHUMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAj/3jsiaeeee6Fl1557Y233nnvg48++ddnX3z1zXc//PTLb3/850DlW9Ahhx1x1DHHnXDSKaedcdY5511w0SWXXXHVNdfdcNMtt91x1z33PfDQI/947ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/z0y29//OfAf/ot6JDDjjjqmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRfzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsffvrltz/+c+A/+xZ0yGFHHHXMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889Mg/HnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q8//fLbH/858J9/CzrksCOOOua4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565B+PPfHUM8+98NIrr73x1jvvffDRJ//67Iuvvvnuh59++e2P/xyofgs65LAjjjrmuBNOOuW0M84657wLLrrksiuuuua6G2665bY77rrnvgceeuQfjz3x1DPPvfDSK6+98dY7733w0Sf/+uyLr7757oeffvntj/8c+C++BR1y2BFHHXPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898o/HnnjqmedeeOmV19546533Pvjok3999sVX33z3w0+//PbHfw78429Bhxx2xFHHHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4/847EnnnrmuRdeeuW1N956570PPvrkX5998dU33/3w0y+//fGfA//kW9Ahhx1x1DHHnXDSKaedcdY5511w0SWXXXHVNdfdcNMtt91x1z33PfDQI/947ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/z0y29//OdA7VvQIYcdcdQxx51w0imnnXHWOeddcNEll11x1TXX3XDTLbfdcdc99z3w0CP/eOyJp5557oWXXnntjbfeee+Djz7512dffPXNdz/89Mtvf/znwH/5LeiQw4446pjjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokX889sRTzzz3wkuvvPbGW++898FHn/zrsy+++ua7H3765bc//nPgn34LOuSwI4465rgTTjrltDPOOue8Cy665LIrrrrmuhtuuuW2O+66574HHnrkH4898dQzz73w0iuvvfHWO+998NEn//rsi6+++e6Hn3757Y//HPhn34IOOeyIo4457oSTTjntjLPOOe+Ciy657Iqrrrnuhptuue2Ou+6574GHHvnHY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++GnX3774z8H6t+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B/6rb0GHHHbEUcccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDj/zjsSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fDTL7/98Z8D//W3oEMOO+KoY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFH/vHYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++OmX3/74z4F//i3okMOOOOqY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvuuOue+x546JF/PPbEU88898JLr7z2xlvvvPfBR5/867Mvvvrmux9++uW3P/5zoPEt6JDDjjjqmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRfzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsffvrltz/+c+C/+RZ0yGFHHHXMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889Mg/HnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q8//fLbH/858N9+CzrksCOOOua4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565B+PPfHUM8+98NIrr73x1jvvffDRJ//67Iuvvvnuh59++e2P/xz4774FHXLYEUcdc9wJJ51y2hlnnXPeBRddctkVV11z3Q033XLbHXfdc98DDz3yj8eeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDT7/89sd/DjS/BR1y2BFHHXPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898o/HnnjqmedeeOmV19546533Pvjok3999sVX33z3w0+//PbHfw7899+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B/6Hb0GHHHbEUcccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDj/zjsSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fDTL7/98Z8D/+O3oEMOO+KoY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFH/vHYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++OmX3/74z4HWt6BDDjviqGOOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChR/7x2BNPPfPcCy+98tobb73z3gcfffKvz7746pvvfvjpl9/++M+B/+lb0CGHHXHUMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAj/3jsiaeeee6Fl1557Y233nnvg48++ddnX3z1zXc//PTLb3/858D//C3okMOOOOqY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvuuOue+x546JF/PPbEU88898JLr7z2xlvvvPfBR5/867Mvvvrmux9++uW3P/5z4H/5FnTIYUccdcxxJ5x0ymlnnHXOeRdcdMllV1x1zXU33HTLbXfcdc99Dzz0yD8ee+KpZ5574aVXXnvjrXfe++CjT/712RdfffPdDz/98tsf/znQ/hZ0yGFHHHXMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889Mg/HnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q8//fLbH/858L9+CzrksCOOOua4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565B+PPfHUM8+98NIrr73x1jvvffDRJ//67Iuvvvnuh59++e2P/xz4374FHXLYEUcdc9wJJ51y2hlnnXPeBRddctkVV11z3Q033XLbHXfdc98DDz3yj8eeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDT7/89sd/Dvzv34IOOeyIo4457oSTTjntjLPOOe+Ciy657Iqrrrnuhptuue2Ou+6574GHHvnHY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++GnX3774z8HOt+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B/6Pb0GHHHbEUcccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDj/zjsSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fDTL7/98Z8D/+e3oEMOO+KoY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFH/vHYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++OmX3/74z4H/61vQIYcdcdQxx51w0imnnXHWOeddcNEll11x1TXX3XDTLbfdcdc99z3w0CP/eOyJp5557oWXXnntjbfeee+Djz7512dffPXNdz/89Mtvf/znQPdb0CGHHXHUMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAj/3jsiaeeee6Fl1557Y233nnvg48++ddnX3z1zXc//PTLb3/858C/+BZ0yGFHHHXMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889Mg/HnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q8//fLbH/858C+/BR1y2BFHHXPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898o/HnnjqmedeeOmV19546533Pvjok3999sVX33z3w0+//PbHfw7839+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B3rfgg457IijjjnuhJNOOe2Ms84574KLLrnsiquuue6Gm2657Y677rnvgYce+cdjTzz1zHMvvPTKa2+89c57H3z0yb8+++Krb7774adffvvjPwf+n29Bhxx2xFHHHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4/847EnnnrmuRdeeuW1N956570PPvrkX5998dU33/3w0y+//fGfA//qW9Ahhx1x1DHHnXDSKaedcdY5511w0SWXXXHVNdfdcNMtt91x1z33PfDQI/947ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/z0y29//OfA//st6JDDjjjqmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRfzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsffvrltz/+c6D/LeiQw4446pjjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokX889sRTzzz3wkuvvPbGW++898FHn/zrsy+++ua7H3765bc//nPgX38LOuSwI4465rgTTjrltDPOOue8Cy665LIrrrrmuhtuuuW2O+66574HHnrkH4898dQzz73w0iuvvfHWO+998NEn//rsi6+++e6Hn3757Y//HPg334IOOeyIo4457oSTTjntjLPOOe+Ciy657Iqrrrnuhptuue2Ou+6574GHHvnHY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++GnX3774z8H/u23oEMOO+KoY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFH/vHYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++OmX3/74z4HBt/8PdlHZBHicLcUhuAEAACBmQRAEQXhBEARBEARBEARBEARBEARBEARBsJu7s80222yzzTa7s5vtbOfubLPN3QRBEF4QBEEQhBcEQRD2ffP/5Q/2A/+/kMOOOOofxxx3wkmnnHbGWeecd8FFl1x2xVXXXHfDTbfcdsdd99z3wEOPPPbEU88898JLr7z2xlvvvPfBR5/867Mvvvrmux/+89Mvv/1x4N/5FnTIYUcc9Y9jjjvhpFNOO+Osc8674KJLLrviqmuuu+GmW26746577nvgoUcee+KpZ5574aVXXnvjrXfe++CjT/712RdfffPdD//56Zff/jjwD74FHXLYEUf945jjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokceeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDf3765bc/Dvy734IOOeyIo/5xzHEnnHTKaWecdc55F1x0yWVXXHXNdTfcdMttd9x1z30PPPTIY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++E/P/3y2x8HBt+CDjnsiKP+ccxxJ5x0ymlnnHXOeRdcdMllV1x1zXU33HTLbXfcdc99Dzz0yGNPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhPz/98tsfB/7ht6BDDjviqH8cc9wJJ51y2hlnnXPeBRddctkVV11z3Q033XLbHXfdc98DDz3y2BNPPfPcCy+98tobb73z3gcfffKvz7746pvvfvjPT7/89seBf/Qt6JDDjjjqH8ccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDjzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsf/vPTL7/9ceAffws65LAjjvrHMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAjjz3x1DPPvfDSK6+98dY7733w0Sf/+uyLr7757of//PTLb38cGH4LOuSwI476xzHHnXDSKaedcdY5511w0SWXXXHVNdfdcNMtt91x1z33PfDQI4898dQzz73w0iuvvfHWO+998NEn//rsi6+++e6H//z0y29/HPj3vgUdctgRR/3jmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRx5546pnnXnjpldfeeOud9z746JN/ffbFV99898N/fvrltz8O/Pvfgg457Iij/nHMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889MhjTzz1zHMvvPTKa2+89c57H3z0yb8+++Krb7774T8//fLbHwf+g29Bhxx2xFH/OOa4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565LEnnnrmuRdeeuW1N956570PPvrkX5998dU33/3wn59++e2PA6NvQYccdsRR/zjmuBNOOuW0M84657wLLrrksiuuuua6G2665bY77rrnvgceeuSxJ5565rkXXnrltTfeeue9Dz765F+fffHVN9/98J+ffvntjwP/4begQw474qh/HHPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898tgTTz3z3AsvvfLaG2+9894HH33yr8+++Oqb7374z0+//PbHgf/oW9Ahhx1x1D+OOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx557ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/znp19+++PAf/wt6JDDjjjqH8ccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDjzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsf/vPTL7/9cWD8LeiQw4446h/HHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4889sRTzzz3wkuvvPbGW++898FHn/zrsy+++ua7H/7z0y+//XHgP/kWdMhhRxz1j2OOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChRx574qlnnnvhpVdee+Otd9774KNP/vXZF199890P//npl9/+OPCffgs65LAjjvrHMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAjjz3x1DPPvfDSK6+98dY7733w0Sf/+uyLr7757of//PTLb38c+M++BR1y2BFH/eOY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvuuOue+x546JHHnnjqmedeeOmV19546533Pvjok3999sVX33z3w39++uW3Pw5MvgUdctgRR/3jmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRx5546pnnXnjpldfeeOud9z746JN/ffbFV99898N/fvrltz8O/Offgg457Iij/nHMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889MhjTzz1zHMvvPTKa2+89c57H3z0yb8+++Krb7774T8//fLbHwf+i29Bhxx2xFH/OOa4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565LEnnnrmuRdeeuW1N956570PPvrkX5998dU33/3wn59++e2PA//lt6BDDjviqH8cc9wJJ51y2hlnnXPeBRddctkVV11z3Q033XLbHXfdc98DDz3y2BNPPfPcCy+98tobb73z3gcfffKvz7746pvvfvjPT7/89seB6begQw474qh/HHPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898tgTTz3z3AsvvfLaG2+9894HH33yr8+++Oqb7374z0+//PbHgf/qW9Ahhx1x1D+OOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx557ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/znp19+++PAf/0t6JDDjjjqH8ccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDjzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsf/vPTL7/9ceC/+RZ0yGFHHPWPY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFHHnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q//+emX3/44MPsWdMhhRxz1j2OOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChRx574qlnnnvhpVdee+Otd9774KNP/vXZF199890P//npl9/+OPDffgs65LAjjvrHMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAjjz3x1DPPvfDSK6+98dY7733w0Sf/+uyLr7757of//PTLb38c+O++BR1y2BFH/eOY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvuuOue+x546JHHnnjqmedeeOmV19546533Pvjok3999sVX33z3w39++uW3Pw7899+CDjnsiKP+ccxxJ5x0ymlnnHXOeRdcdMllV1x1zXU33HTLbXfcdc99Dzz0yGNPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhPz/98tsfB+bfgg457Iij/nHMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889MhjTzz1zHMvvPTKa2+89c57H3z0yb8+++Krb7774T8//fLbHwf+h29Bhxx2xFH/OOa4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565LEnnnrmuRdeeuW1N956570PPvrkX5998dU33/3wn59++e2PA//kW9Ahhx1x1D+OOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx557ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/znp19+++PAP/0WdMhhRxz1j2OOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChRx574qlnnnvhpVdee+Otd9774KNP/vXZF199890P//npl9/+OLD4FnTIYUcc9Y9jjjvhpFNOO+Osc8674KJLLrviqmuuu+GmW26746577nvgoUcee+KpZ5574aVXXnvjrXfe++CjT/712RdfffPdD//56Zff/jjwP34LOuSwI476xzHHnXDSKaedcdY5511w0SWXXXHVNdfdcNMtt91x1z33PfDQI4898dQzz73w0iuvvfHWO+998NEn//rsi6+++e6H//z0y29/HPhn34IOOeyIo/5xzHEnnHTKaWecdc55F1x0yWVXXHXNdTfcdMttd9x1z30PPPTIY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++E/P/3y2x8H/qdvQYccdsRR/zjmuBNOOuW0M84657wLLrrksiuuuua6G2665bY77rrnvgceeuSxJ5565rkXXnrltTfeeue9Dz765F+fffHVN9/98J+ffvntjwPLb0GHHHbEUf845rgTTjrltDPOOue8Cy665LIrrrrmuhtuuuW2O+66574HHnrksSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fCfn3757Y8D//O3oEMOO+Kofxxz3AknnXLaGWedc94FF11y2RVXXXPdDTfdctsdd91z3wMPPfLYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++M9Pv/z2x4H/5VvQIYcdcdQ/jjnuhJNOOe2Ms84574KLLrnsiquuue6Gm2657Y677rnvgYceeeyJp5557oWXXnntjbfeee+Djz7512dffPXNdz/856dffvvjwD//FnTIYUcc9Y9jjjvhpFNOO+Osc8674KJLLrviqmuuu+GmW26746577nvgoUcee+KpZ5574aVXXnvjrXfe++CjT/712RdfffPdD//56Zff/jiw+hZ0yGFHHPWPY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFHHnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q//+emX3/448L9+CzrksCOO+scxx51w0imnnXHWOeddcNEll11x1TXX3XDTLbfdcdc99z3w0COPPfHUM8+98NIrr73x1jvvffDRJ//67Iuvvvnuh//89Mtvfxz4374FHXLYEUf945jjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokceeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDf3765bc/DvyLb0GHHHbEUf845rgTTjrltDPOOue8Cy665LIrrrrmuhtuuuW2O+66574HHnrksSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fCfn3757Y8D629Bhxx2xFH/OOa4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565LEnnnrmuRdeeuW1N956570PPvrkX5998dU33/3wn59++e2PA//yW9Ahhx1x1D+OOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx557ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/znp19+++PAv/oWdMhhRxz1j2OOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChRx574qlnnnvhpVdee+Otd9774KNP/vXZF199890P//npl9/+OPCvvwUdctgRR/3jmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRx5546pnnXnjpldfeeOud9z746JN/ffbFV99898N/fvrltz8ObL4FHXLYEUf945jjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokceeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDf3765bc/Dvzv34IOOeyIo/5xzHEnnHTKaWecdc55F1x0yWVXXHXNdTfcdMttd9x1z30PPPTIY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++E/P/3y2x8H/o9vQYccdsRR/zjmuBNOOuW0M84657wLLrrksiuuuua6G2665bY77rrnvgceeuSxJ5565rkXXnrltTfeeue9Dz765F+fffHVN9/98J+ffvntjwP/57egQw474qh/HHPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898tgTTz3z3AsvvfLaG2+9894HH33yr8+++Oqb7374z0+//PbHge23oEMOO+Kofxxz3AknnXLaGWedc94FF11y2RVXXXPdDTfdctsdd91z3wMPPfLYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++M9Pv/z2x4H/61vQIYcdcdQ/jjnuhJNOOe2Ms84574KLLrnsiquuue6Gm2657Y677rnvgYceeeyJp5557oWXXnntjbfeee+Djz7512dffPXNdz/856dffvvjwP/9LeiQw4446h/HHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4889sRTzzz3wkuvvPbGW++898FHn/zrsy+++ua7H/7z0y+//XHg//kWdMhhRxz1j2OOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChRx574qlnnnvhpVdee+Otd9774KNP/vXZF199890P//npl9/+OLD7FnTIYUcc9Y9jjjvhpFNOO+Osc8674KJLLrviqmuuu+GmW26746577nvgoUcee+KpZ5574aVXXnvjrXfe++CjT/712RdfffPdD//56Zff/jjwb74FHXLYEUf945jjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokceeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDf3765bc/Dvzbb0GHHHbEUf845rgTTjrltDPOOue8Cy665LIrrrrmuhtuuuW2O+66574HHnrksSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fCfn3757Y8D/++3oEMOO+Kofxxz3AknnXLaGWedc94FF11y2RVXXXPdDTfdctsdd91z3wMPPfLYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++M9Pv/z2x4H9t/8Pd+bZQHicLcUv2AEAAOBnex5BEARBEARBEARBEARBEAThC8IXBEEQBEEQBEEQBEEQBEEQBEFwN9tss83dbLOd29zNNtu5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EsussMof1vjLOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/8MvB//hFkiGFGGGWMcSaYZIppZphljnkWWGSJZVZY5Q9r/GWdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH34Z+PwRZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWOUPa/xlnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9+GfjXfwQZYpgRRhljnAkmmWKaGWaZY54FFllimRVW+cMaf1lng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh18G/q8/ggwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqv8YY2/rLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDLwP/9x9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVf6wxl/W2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXge8fQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVX+sMZf1tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhl4H/548gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKn9Y4y/rbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLwP/7R5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVP6zxl3U22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++GXg//sjyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMof1vjLOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/8MhD4t/7N/39ygdh9eJwt1yETAgCXllFWPxUVlVVUVFR0UVFRUVFRUQkEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEFz9zi3nBzwz78z9Q+BPAv/v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IYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+vv4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sdAVH8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgH+jPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/EP9GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgX+kP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MRDTn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPjH+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/RH8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgn+rPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38MxPVnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/pn+DDLEMCOM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GWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375YyCrP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfDf9WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+h/4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfA/9SfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4YyOnPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/C/9GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgf+tP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfB/9GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwbyf/T/AtC86Mh4nC3RoRcBAIDYYXvvgiAIgiAIgiAIgiDYZpttdrOb3dlmm2222WZ3ttmd22wTBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEHY27vvV74/4PcH+b8W+P8FGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgr/+Vf8AgQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8Df8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bv+k/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wxUPCfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Fv+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA3/bfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+Dv+M8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888MvfwwU/WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+rv8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfA3/OfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Pv+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfAyX/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgX/gP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfCH/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/0H8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WOg7D+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwj/xnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/sh/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4B/7zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DFT8Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv6J/wwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8Af+88gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8if8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sdA1X8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgn/rPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/DP/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgX/uP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MVDzn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPgX/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/0n8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgX/nPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M1P1nkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/rX/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwL/xn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPi3/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwMN/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4F/5z+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHw7/1nkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/oP/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHQNN/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4D/6zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPwn/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4H/7D+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHQ8p9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4L/4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8Df+o/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8Gf+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA23/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgf/qP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfDf/GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+u/8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sdAx38GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgf/jPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/Ln/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwF/4zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DHT9Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv7SfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+B/+s8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8L/8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bnv8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfA//afQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+D/+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA//XfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y6D/V/4/0lHpBHicLdGhFwEAgNhh994FQRAEQRAEQRAEQRAEQRAEQRAEQRAEQbDNdrZzm2222WY322yzzTa32WZ3bhMEQRAEQRAEQRAEQdjbu+9Xvj/g94f9Pwj8/4IMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfDX/so/ZJAhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv66/wwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8Df8J9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hgY+M8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8Tf8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bv+U/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8Ef+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA0P/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgb/tP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfB3/GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+2H8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WNg5D+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwJ/4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8Df9d/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4O/5zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DIz9Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv6+/wwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8A/8J9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4h/4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8DE/8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bf+Q/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8I/9Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv6J/wwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8DUfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+Cf+s8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8M/8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bf+4/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wxMPOfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Bf+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA3/qP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfAv/WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwbm/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/yn8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgX/vPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/Bv/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgYX/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwL/1n0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPh3/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/3n8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WNg6T+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwH/xnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/qP/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwH/yn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GFj5zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPxn/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4H/4j+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwX/1nkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G1v4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8Df+Y/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8N/8Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv67/wwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8DGfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+B/+M8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8T/8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+B/+U/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wxsPWfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+N/+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA3/uP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfAX/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwM7/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4G/9J9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4P/4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8D/9d/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvljYP9X/j/T5ulAeJwt0a8fAQCA3mG3zwVBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBsM0229zNNttss80227nNbbZzm23247PtecP7/AHfP9z/QeD/LsgQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA3/5//uHDDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwF/Rn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPir+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwMH/RlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4G/pj+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHw1/VnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/ob+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwFF/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4G/qzyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPwt/RlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4G/rT+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DFw0p9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4I/0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+BP9afQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Dv6M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA2f9GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgb+rP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfD39GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+vv4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfARX8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgH+jPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/EP9GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgX+kP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MXDVn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPjH+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/RH8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgn+rPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M3PRnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/pn+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwD/Xn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPgX+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwN3/RlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4F/qT+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwr/RnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/rX+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwEN/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsu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cy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgb+kP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfCX9WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+iv4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sc/f/j/P39gkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/qr+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwF/Tn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPjr+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwMh/RlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4G/oT+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwN/VnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/pb+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHQFh/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4E/1Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv62/gwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8Df0Z9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hiI6M8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8Xf0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bv6c/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8Pf1Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/BqL6M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA/9AfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+Af6s8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8I/0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+BmP4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfAP9afQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Cf6M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA/9UfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375YyCuP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfDP9GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+uf4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfAn+nPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38MJPRnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/oX+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xy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vPLGOx988sU3P/zyx0BOfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+B/6c8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8b/0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+B/6M/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wxkP+j/xcsy/jIeJwt0aEXAQCA2GFv74IgCIIgCIIgCIIg2GabbXazm93ZZpttttlmd7bZndtsEwRBEARBEARBEARBEARBEARBEARBEARB2Nu771e+P+D3B/m/Fvj/BRlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4K//lX/AIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/A3/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgb/pP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MVDwn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPhb/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwN/238GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPg7/jPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38MFP1nkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/q7/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwN/zn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPj7/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwMl/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4F/4D+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwh/4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8D/9B/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvljoOw/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8I/8Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv7IfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+Af+88gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888MvfwxU/GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+if8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfAH/vPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/In/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHQNV/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4J/6zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPwz/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4F/7j+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+8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/DHw3/xnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/rv/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHQMd/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4H/4zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPy5/wwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8Bf+M8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwx0/WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+0n8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgf/rPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/C//GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgZ7/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwP/2n0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPg//jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/138GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WOg/1f+Py5g+QR4nC3RIRMBAIKAUXOzQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRDcrd1zt/bO7toZQRAEQRAEQRAEQRAEQRAEQRAEQbjZufeV9wO+P/T/LfCvggwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8O//7x8YZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+B//CfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+KP/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwMB/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4E/+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA3/2n0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPhP/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4Gh/wwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8B/+c8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8t/8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfAX/xnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8GRv4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8Df/WfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+B//GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgf/1n0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GBj7zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPzNfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+Dv/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/8J9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hiY+M8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8038GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjni/wG4JJNeAgAAAACAAABjJQAANQAAACEAAAA=eJztwSEBAAAAgKDu/8EeAQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGME7AEx4nO3BMQEAAADCoH/9A5vABkABAAAAAAAAAABwDE9gde4= + + diff --git a/inputFiles/singlePhaseFlow/synthetic/synthetic_1_0.vtu b/inputFiles/singlePhaseFlow/synthetic/synthetic_1_0.vtu new file mode 100644 index 00000000000..5f6097344cb --- /dev/null +++ b/inputFiles/singlePhaseFlow/synthetic/synthetic_1_0.vtu @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + _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cc8DjzzxzAuvvPHOB5988c3Pn4HOv/9LgEGGGGaEUcYY5zcTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz5/OOCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754dc/+CXAIEMMM8IoY4zzmwkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnz8ccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zw6//7JcAgQwwzwihjjPObCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfPxxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDPQH+AQYYYZoRRxhjnNxNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPn844JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvn5s8jxD38JMMgQw4wwyhjj/GaCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OcPBxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PpHvwQYZIhhRhhljHF+M8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvs84cDDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9+/eNfAgwyxDAjjDLGOL+ZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfb5wwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND/8s8gUYZIhhRhhljHF+M8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvs84cDDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnim58/C5z/5JcAgwwxzAijjDHObyaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPff5wwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDr3/6S4BBhhhmhFHGGOc3E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+fzjgkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eHXP/slwCBDDDPCKGOM85sJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58/HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88M8Cf4BBhhhmhFHGGOc3E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+fzjgkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eHXP/8lwCBDDDPCKGOM85sJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58/HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88Otf/BJgkCGGGWGUMcb5zQSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzx8OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3749S9/CTDIEMOMMMoY4/xmgkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjnDwcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/wT3BNgkCGGGWGUMcb5zQSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzx8OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3749a9+CTDIEMOMMMoY4/xmgkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjnDwcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/z6178EGGSIYUYYZYxxfjPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577POHAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffv2bXwIMMsQwI4wyxji/mWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32+cMBhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ//BPYFGGSIYUYYZYxxfjPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577POHAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffv3bXwIMMsQwI4wyxji/mWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32+cMBhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//t0vAQYZYpgRRhljnN9MMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvv84YBDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1///pcAgwwxzAijjDHObyaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPff5wwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDP0G9AQYZYpgRRhljnN9MMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvv84YBDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1//4ZcAgwwxzAijjDHObyaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPff5wwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDr//4S4BBhhhmhFHGGOc3E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+fzjgkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eHXf/olwCBDDDPCKGOM85sJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58/HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88E9Af4BBhhhmhFHGGOc3E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+fzjgkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eHX//9LgEGGGGaEUcYY5zcTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz5/OOCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754dd//iXAIEMMM8IoY4zzmwkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnz8ccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zw67/8EmCQIYYZYZQxxvnNBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPHw445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745ItvfvjnME+AQYYYZoRRxhjnNxNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPn844JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnh13/9JcAgQwwzwihjjPObCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfPxxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDrv/0SYJAhhhlhlDHG+c0Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8fDjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++PXffwkwyBDDjDDKGOP8ZoJJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY5w8HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/8c5AvwCBDDDPCKGOM85sJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58/HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88Ot//BJgkCGGGWGUMcb5zQSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzx8OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3749T9/CTDIEMOMMMoY4/xmgkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjnDwcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/z6X78EGGSIYUYYZYxxfjPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577POHAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psf/jnEG2CQIYYZYZQxxvnNBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPHw445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvj1v38JMMgQw4wwyhjj/GaCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OcPBxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//Po/vwQYZIhhRhhljHF+M8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvs84cDDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9+/d9fAgwyxDAjjDLGOL+ZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfb5wwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND79yv/w/dLzYyHicLcUhuAEAACBmQRAEQRAEQRAEQRAEd7OdbbbZZnd2ZzvbbLPNNtvczW7uThCEFwRBEARBEARBEARBEF4QBEEQBEEQhBf2ffP/5Q8WAv+/kMOOOOqY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvuuOue+x546JF/PPbEU88898JLr7z2xlvvvPfBR5/867Mvvvrmux9++uW3P/5z4B98CzrksCOOOua4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565B+PPfHUM8+98NIrr73x1jvvffDRJ//67Iuvvvnuh59++e2P/xz4h9+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B/6db0GHHHbEUcccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDj/zjsSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fDTL7/98Z8DxW9Bhxx2xFHHHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4/847EnnnrmuRdeeuW1N956570PPvrkX5998dU33/3w0y+//fGfA//ut6BDDjviqGOOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChR/7x2BNPPfPcCy+98tobb73z3gcfffKvz7746pvvfvjpl9/++M+Bf+9b0CGHHXHUMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAj/3jsiaeeee6Fl1557Y233nnvg48++ddnX3z1zXc//PTLb3/858A/+hZ0yGFHHHXMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889Mg/HnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q8//fLbH/85UPoWdMhhRxx1zHEnnHTKaWecdc55F1x0yWVXXHXNdTfcdMttd9x1z30PPPTIPx574qlnnnvhpVdee+Otd9774KNP/vXZF199890PP/3y2x//OfDvfws65LAjjjrmuBNOOuW0M84657wLLrrksiuuuua6G2665bY77rrnvgceeuQfjz3x1DPPvfDSK6+98dY7733w0Sf/+uyLr7757oeffvntj/8c+A++BR1y2BFHHXPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898o/HnnjqmedeeOmV19546533Pvjok3999sVX33z3w0+//PbHfw78h9+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B8rfgg457IijjjnuhJNOOe2Ms84574KLLrnsiquuue6Gm2657Y677rnvgYce+cdjTzz1zHMvvPTKa2+89c57H3z0yb8+++Krb7774adffvvjPwf+o29Bhxx2xFHHHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4/847EnnnrmuRdeeuW1N956570PPvrkX5998dU33/3w0y+//fGfA//xt6BDDjviqGOOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChR/7x2BNPPfPcCy+98tobb73z3gcfffKvz7746pvvfvjpl9/++M+B/+Rb0CGHHXHUMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAj/3jsiaeeee6Fl1557Y233nnvg48++ddnX3z1zXc//PTLb3/850DlW9Ahhx1x1DHHnXDSKaedcdY5511w0SWXXXHVNdfdcNMtt91x1z33PfDQI/947ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/z0y29//OfAf/ot6JDDjjjqmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRfzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsffvrltz/+c+A/+xZ0yGFHHHXMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889Mg/HnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q8//fLbH/858J9/CzrksCOOOua4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565B+PPfHUM8+98NIrr73x1jvvffDRJ//67Iuvvvnuh59++e2P/xyofgs65LAjjjrmuBNOOuW0M84657wLLrrksiuuuua6G2665bY77rrnvgceeuQfjz3x1DPPvfDSK6+98dY7733w0Sf/+uyLr7757oeffvntj/8c+C++BR1y2BFHHXPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898o/HnnjqmedeeOmV19546533Pvjok3999sVX33z3w0+//PbHfw78429Bhxx2xFHHHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4/847EnnnrmuRdeeuW1N956570PPvrkX5998dU33/3w0y+//fGfA//kW9Ahhx1x1DHHnXDSKaedcdY5511w0SWXXXHVNdfdcNMtt91x1z33PfDQI/947ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/z0y29//OdA7VvQIYcdcdQxx51w0imnnXHWOeddcNEll11x1TXX3XDTLbfdcdc99z3w0CP/eOyJp5557oWXXnntjbfeee+Djz7512dffPXNdz/89Mtvf/znwH/5LeiQw4446pjjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokX889sRTzzz3wkuvvPbGW++898FHn/zrsy+++ua7H3765bc//nPgn34LOuSwI4465rgTTjrltDPOOue8Cy665LIrrrrmuhtuuuW2O+66574HHnrkH4898dQzz73w0iuvvfHWO+998NEn//rsi6+++e6Hn3757Y//HPhn34IOOeyIo4457oSTTjntjLPOOe+Ciy657Iqrrrnuhptuue2Ou+6574GHHvnHY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++GnX3774z8H6t+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B/6rb0GHHHbEUcccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDj/zjsSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fDTL7/98Z8D//W3oEMOO+KoY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFH/vHYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++OmX3/74z4F//i3okMOOOOqY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvuuOue+x546JF/PPbEU88898JLr7z2xlvvvPfBR5/867Mvvvrmux9++uW3P/5zoPEt6JDDjjjqmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRfzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsffvrltz/+c+C/+RZ0yGFHHHXMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889Mg/HnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q8//fLbH/858N9+CzrksCOOOua4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565B+PPfHUM8+98NIrr73x1jvvffDRJ//67Iuvvvnuh59++e2P/xz4774FHXLYEUcdc9wJJ51y2hlnnXPeBRddctkVV11z3Q033XLbHXfdc98DDz3yj8eeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDT7/89sd/DjS/BR1y2BFHHXPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898o/HnnjqmedeeOmV19546533Pvjok3999sVX33z3w0+//PbHfw7899+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B/6Hb0GHHHbEUcccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDj/zjsSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fDTL7/98Z8D/+O3oEMOO+KoY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFH/vHYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++OmX3/74z4HWt6BDDjviqGOOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChR/7x2BNPPfPcCy+98tobb73z3gcfffKvz7746pvvfvjpl9/++M+B/+lb0CGHHXHUMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAj/3jsiaeeee6Fl1557Y233nnvg48++ddnX3z1zXc//PTLb3/858D//C3okMOOOOqY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvuuOue+x546JF/PPbEU88898JLr7z2xlvvvPfBR5/867Mvvvrmux9++uW3P/5z4H/5FnTIYUccdcxxJ5x0ymlnnHXOeRdcdMllV1x1zXU33HTLbXfcdc99Dzz0yD8ee+KpZ5574aVXXnvjrXfe++CjT/712RdfffPdDz/98tsf/znQ/hZ0yGFHHHXMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889Mg/HnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q8//fLbH/858L9+CzrksCOOOua4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565B+PPfHUM8+98NIrr73x1jvvffDRJ//67Iuvvvnuh59++e2P/xz4374FHXLYEUcdc9wJJ51y2hlnnXPeBRddctkVV11z3Q033XLbHXfdc98DDz3yj8eeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDT7/89sd/Dvzv34IOOeyIo4457oSTTjntjLPOOe+Ciy657Iqrrrnuhptuue2Ou+6574GHHvnHY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++GnX3774z8HOt+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B/6Pb0GHHHbEUcccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDj/zjsSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fDTL7/98Z8D/+e3oEMOO+KoY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFH/vHYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++OmX3/74z4H/61vQIYcdcdQxx51w0imnnXHWOeddcNEll11x1TXX3XDTLbfdcdc99z3w0CP/eOyJp5557oWXXnntjbfeee+Djz7512dffPXNdz/89Mtvf/znQPdb0CGHHXHUMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAj/3jsiaeeee6Fl1557Y233nnvg48++ddnX3z1zXc//PTLb3/858C/+BZ0yGFHHHXMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889Mg/HnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q8//fLbH/858C+/BR1y2BFHHXPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898o/HnnjqmedeeOmV19546533Pvjok3999sVX33z3w0+//PbHfw7839+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B3rfgg457IijjjnuhJNOOe2Ms84574KLLrnsiquuue6Gm2657Y677rnvgYce+cdjTzz1zHMvvPTKa2+89c57H3z0yb8+++Krb7774adffvvjPwf+n29Bhxx2xFHHHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4/847EnnnrmuRdeeuW1N956570PPvrkX5998dU33/3w0y+//fGfA//qW9Ahhx1x1DHHnXDSKaedcdY5511w0SWXXXHVNdfdcNMtt91x1z33PfDQI/947ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/z0y29//OfA//st6JDDjjjqmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRfzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsffvrltz/+c6D/LeiQw4446pjjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokX889sRTzzz3wkuvvPbGW++898FHn/zrsy+++ua7H3765bc//nPgX38LOuSwI4465rgTTjrltDPOOue8Cy665LIrrrrmuhtuuuW2O+66574HHnrkH4898dQzz73w0iuvvfHWO+998NEn//rsi6+++e6Hn3757Y//HPg334IOOeyIo4457oSTTjntjLPOOe+Ciy657Iqrrrnuhptuue2Ou+6574GHHvnHY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++GnX3774z8H/u23oEMOO+KoY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFH/vHYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++OmX3/74z4HBt/8PdlHZBHicLcUhuAEAACBmQRAEQXhBEARBEARBEARBEARBEARBEARBsJu7s80222yzzTa7s5vtbOfubLPN3QRBEF4QBEEQhBcEQRD2ffP/5Q/2A/+/kMOOOOofxxx3wkmnnHbGWeecd8FFl1x2xVXXXHfDTbfcdsdd99z3wEOPPPbEU88898JLr7z2xlvvvPfBR5/867Mvvvrmux/+89Mvv/1x4N/5FnTIYUcc9Y9jjjvhpFNOO+Osc8674KJLLrviqmuuu+GmW26746577nvgoUcee+KpZ5574aVXXnvjrXfe++CjT/712RdfffPdD//56Zff/jjwD74FHXLYEUf945jjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokceeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDf3765bc/Dvy734IOOeyIo/5xzHEnnHTKaWecdc55F1x0yWVXXHXNdTfcdMttd9x1z30PPPTIY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++E/P/3y2x8HBt+CDjnsiKP+ccxxJ5x0ymlnnHXOeRdcdMllV1x1zXU33HTLbXfcdc99Dzz0yGNPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhPz/98tsfB/7ht6BDDjviqH8cc9wJJ51y2hlnnXPeBRddctkVV11z3Q033XLbHXfdc98DDz3y2BNPPfPcCy+98tobb73z3gcfffKvz7746pvvfvjPT7/89seBf/Qt6JDDjjjqH8ccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDjzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsf/vPTL7/9ceAffws65LAjjvrHMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAjjz3x1DPPvfDSK6+98dY7733w0Sf/+uyLr7757of//PTLb38cGH4LOuSwI476xzHHnXDSKaedcdY5511w0SWXXXHVNdfdcNMtt91x1z33PfDQI4898dQzz73w0iuvvfHWO+998NEn//rsi6+++e6H//z0y29/HPj3vgUdctgRR/3jmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRx5546pnnXnjpldfeeOud9z746JN/ffbFV99898N/fvrltz8O/Pvfgg457Iij/nHMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889MhjTzz1zHMvvPTKa2+89c57H3z0yb8+++Krb7774T8//fLbHwf+g29Bhxx2xFH/OOa4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565LEnnnrmuRdeeuW1N956570PPvrkX5998dU33/3wn59++e2PA6NvQYccdsRR/zjmuBNOOuW0M84657wLLrrksiuuuua6G2665bY77rrnvgceeuSxJ5565rkXXnrltTfeeue9Dz765F+fffHVN9/98J+ffvntjwP/4begQw474qh/HHPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898tgTTz3z3AsvvfLaG2+9894HH33yr8+++Oqb7374z0+//PbHgf/oW9Ahhx1x1D+OOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx557ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/znp19+++PAf/wt6JDDjjjqH8ccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDjzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsf/vPTL7/9cWD8LeiQw4446h/HHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4889sRTzzz3wkuvvPbGW++898FHn/zrsy+++ua7H/7z0y+//XHgP/kWdMhhRxz1j2OOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChRx574qlnnnvhpVdee+Otd9774KNP/vXZF199890P//npl9/+OPCffgs65LAjjvrHMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAjjz3x1DPPvfDSK6+98dY7733w0Sf/+uyLr7757of//PTLb38c+M++BR1y2BFH/eOY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvuuOue+x546JHHnnjqmedeeOmV19546533Pvjok3999sVX33z3w39++uW3Pw5MvgUdctgRR/3jmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRx5546pnnXnjpldfeeOud9z746JN/ffbFV99898N/fvrltz8O/Offgg457Iij/nHMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889MhjTzz1zHMvvPTKa2+89c57H3z0yb8+++Krb7774T8//fLbHwf+i29Bhxx2xFH/OOa4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565LEnnnrmuRdeeuW1N956570PPvrkX5998dU33/3wn59++e2PA//lt6BDDjviqH8cc9wJJ51y2hlnnXPeBRddctkVV11z3Q033XLbHXfdc98DDz3y2BNPPfPcCy+98tobb73z3gcfffKvz7746pvvfvjPT7/89seB6begQw474qh/HHPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898tgTTz3z3AsvvfLaG2+9894HH33yr8+++Oqb7374z0+//PbHgf/qW9Ahhx1x1D+OOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx557ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/znp19+++PAf/0t6JDDjjjqH8ccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDjzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsf/vPTL7/9ceC/+RZ0yGFHHPWPY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFHHnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q//+emX3/44MPsWdMhhRxz1j2OOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChRx574qlnnnvhpVdee+Otd9774KNP/vXZF199890P//npl9/+OPDffgs65LAjjvrHMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAjjz3x1DPPvfDSK6+98dY7733w0Sf/+uyLr7757of//PTLb38c+O++BR1y2BFH/eOY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvuuOue+x546JHHnnjqmedeeOmV19546533Pvjok3999sVX33z3w39++uW3Pw7899+CDjnsiKP+ccxxJ5x0ymlnnHXOeRdcdMllV1x1zXU33HTLbXfcdc99Dzz0yGNPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhPz/98tsfB+bfgg457Iij/nHMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889MhjTzz1zHMvvPTKa2+89c57H3z0yb8+++Krb7774T8//fLbHwf+h29Bhxx2xFH/OOa4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565LEnnnrmuRdeeuW1N956570PPvrkX5998dU33/3wn59++e2PA//kW9Ahhx1x1D+OOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx557ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/znp19+++PAP/0WdMhhRxz1j2OOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChRx574qlnnnvhpVdee+Otd9774KNP/vXZF199890P//npl9/+OLD4FnTIYUcc9Y9jjjvhpFNOO+Osc8674KJLLrviqmuuu+GmW26746577nvgoUcee+KpZ5574aVXXnvjrXfe++CjT/712RdfffPdD//56Zff/jjwP34LOuSwI476xzHHnXDSKaedcdY5511w0SWXXXHVNdfdcNMtt91x1z33PfDQI4898dQzz73w0iuvvfHWO+998NEn//rsi6+++e6H//z0y29/HPhn34IOOeyIo/5xzHEnnHTKaWecdc55F1x0yWVXXHXNdTfcdMttd9x1z30PPPTIY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++E/P/3y2x8H/qdvQYccdsRR/zjmuBNOOuW0M84657wLLrrksiuuuua6G2665bY77rrnvgceeuSxJ5565rkXXnrltTfeeue9Dz765F+fffHVN9/98J+ffvntjwPLb0GHHHbEUf845rgTTjrltDPOOue8Cy665LIrrrrmuhtuuuW2O+66574HHnrksSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fCfn3757Y8D//O3oEMOO+Kofxxz3AknnXLaGWedc94FF11y2RVXXXPdDTfdctsdd91z3wMPPfLYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++M9Pv/z2x4H/5VvQIYcdcdQ/jjnuhJNOOe2Ms84574KLLrnsiquuue6Gm2657Y677rnvgYceeeyJp5557oWXXnntjbfeee+Djz7512dffPXNdz/856dffvvjwD//FnTIYUcc9Y9jjjvhpFNOO+Osc8674KJLLrviqmuuu+GmW26746577nvgoUcee+KpZ5574aVXXnvjrXfe++CjT/712RdfffPdD//56Zff/jiw+hZ0yGFHHPWPY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFHHnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q//+emX3/448L9+CzrksCOO+scxx51w0imnnXHWOeddcNEll11x1TXX3XDTLbfdcdc99z3w0COPPfHUM8+98NIrr73x1jvvffDRJ//67Iuvvvnuh//89Mtvfxz4374FHXLYEUf945jjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokceeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDf3765bc/DvyLb0GHHHbEUf845rgTTjrltDPOOue8Cy665LIrrrrmuhtuuuW2O+66574HHnrksSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fCfn3757Y8D629Bhxx2xFH/OOa4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565LEnnnrmuRdeeuW1N956570PPvrkX5998dU33/3wn59++e2PA//yW9Ahhx1x1D+OOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx557ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/znp19+++PAv/oWdMhhRxz1j2OOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChRx574qlnnnvhpVdee+Otd9774KNP/vXZF199890P//npl9/+OPCvvwUdctgRR/3jmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRx5546pnnXnjpldfeeOud9z746JN/ffbFV99898N/fvrltz8ObL4FHXLYEUf945jjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokceeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDf3765bc/Dvzv34IOOeyIo/5xzHEnnHTKaWecdc55F1x0yWVXXHXNdTfcdMttd9x1z30PPPTIY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++E/P/3y2x8H/o9vQYccdsRR/zjmuBNOOuW0M84657wLLrrksiuuuua6G2665bY77rrnvgceeuSxJ5565rkXXnrltTfeeue9Dz765F+fffHVN9/98J+ffvntjwP/57egQw474qh/HHPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898tgTTz3z3AsvvfLaG2+9894HH33yr8+++Oqb7374z0+//PbHge23oEMOO+Kofxxz3AknnXLaGWedc94FF11y2RVXXXPdDTfdctsdd91z3wMPPfLYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++M9Pv/z2x4H/61vQIYcdcdQ/jjnuhJNOOe2Ms84574KLLrnsiquuue6Gm2657Y677rnvgYceeeyJp5557oWXXnntjbfeee+Djz7512dffPXNdz/856dffvvjwP/9LeiQw4446h/HHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4889sRTzzz3wkuvvPbGW++898FHn/zrsy+++ua7H/7z0y+//XHg//kWdMhhRxz1j2OOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChRx574qlnnnvhpVdee+Otd9774KNP/vXZF199890P//npl9/+OLD7FnTIYUcc9Y9jjjvhpFNOO+Osc8674KJLLrviqmuuu+GmW26746577nvgoUcee+KpZ5574aVXXnvjrXfe++CjT/712RdfffPdD//56Zff/jjwb74FHXLYEUf945jjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokceeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDf3765bc/Dvzbb0GHHHbEUf845rgTTjrltDPOOue8Cy665LIrrrrmuhtuuuW2O+66574HHnrksSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fCfn3757Y8D/++3oEMOO+Kofxxz3AknnXLaGWedc94FF11y2RVXXXPdDTfdctsdd91z3wMPPfLYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++M9Pv/z2x4H9t/8Pd+bZQHicLcUv2AEAAOBnex5BEARBEARBEARBEARBEAThC8IXBEEQBEEQBEEQBEEQBEEQBEFwN9tss83dbLOd29zNNtu5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EsussMof1vjLOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/8MvB//hFkiGFGGGWMcSaYZIppZphljnkWWGSJZVZY5Q9r/GWdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH34Z+PwRZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWOUPa/xlnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9+GfjXfwQZYpgRRhljnAkmmWKaGWaZY54FFllimRVW+cMaf1lng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh18G/q8/ggwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqv8YY2/rLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDLwP/9x9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVf6wxl/W2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXge8fQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVX+sMZf1tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhl4H/548gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKn9Y4y/rbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLwP/7R5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVP6zxl3U22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++GXg//sjyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMof1vjLOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/8MhD4t/7N/39ygdh9eJwt1yETAgCXllFWPxUVlVVUVFR0UVFRUVFRUQkEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEFz9zi3nBzwz78z9Q+BPAv/v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IYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+vv4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sdAVH8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgH+jPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/EP9GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgX+kP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MRDTn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPjH+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/RH8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgn+rPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38MxPVnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/pn+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwD/Xn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPgz/RlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4GE/gwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8C/0J9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4l/ozyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8D/0p/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvljIKk/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8K/1Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv6N/gwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8C/1Z9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hhI6c8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8O/0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bf68/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8B/0Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/BtL6M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA/9RfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+A/6c8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8Z/0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+BjP4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfAf9GfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+K/6M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA/9NfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375YyCrP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfDf9WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+h/4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfA/9SfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4YyOnPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/C/9GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgf+tP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfB/9GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwbyf/T/AtC86Mh4nC3RoRcBAIDYYXvvgiAIgiAIgiAIgiDYZpttdrOb3dlmm2222WZ3ttmd22wTBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEHY27vvV74/4PcH+b8W+P8FGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgr/+Vf8AgQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8Df8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bv+k/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wxUPCfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Fv+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA3/bfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+Dv+M8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888MvfwwU/WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+rv8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfA3/OfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Pv+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfAyX/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgX/gP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfCH/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/0H8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WOg7D+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwj/xnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/sh/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4B/7zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DFT8Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv6J/wwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8Af+88gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8if8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sdA1X8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgn/rPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/DP/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgX/uP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MVDzn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPgX/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/0n8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgX/nPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M1P1nkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/rX/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwL/xn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPi3/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwMN/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4F/5z+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHw7/1nkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/oP/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHQNN/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4D/6zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPwn/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4H/7D+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHQ8p9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4L/4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsus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YpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+Cf+s8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8M/8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bf+4/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wxMPOfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Bf+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA3/qP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfAv/WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwbm/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/yn8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgX/vPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/Bv/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgYX/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwL/1n0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPh3/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/3n8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WNg6T+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwH/xnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/qP/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwH/yn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GFj5zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPxn/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4H/4j+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwX/1nkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G1v4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8Df+Y/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8N/8Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv67/wwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8DGfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+B/+M8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8T/8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+B/+U/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wxsPWfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+N/+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA3/uP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfAX/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwM7/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4G/9J9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4P/4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8D/9d/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvljYP9X/j/T5ulAeJwt0a8fAQCA3mG3zwVBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBsM0229zNNttss80227nNbbZzm23247PtecP7/AHfP9z/QeD/LsgQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA3/5//uHDDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwF/Rn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPir+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwMH/RlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4G/pj+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHw1/VnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/ob+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwFF/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4G/qzyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPwt/RlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4G/rT+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DFw0p9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4I/0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+BP9afQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Dv6M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA2f9GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgb+rP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfD39GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+vv4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfARX8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgH+jPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/EP9GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgX+kP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MXDVn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPjH+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/RH8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgn+rPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M3PRnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/pn+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwD/Xn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPgX+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwN3/RlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4F/qT+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwr/RnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/rX+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwEN/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsu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cy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgb+kP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfCX9WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+iv4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sc/f/j/P39gkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/qr+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwF/Tn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPjr+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwMh/RlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4G/oT+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwN/VnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/pb+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHQFh/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4E/1Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv62/gwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8Df0Z9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hiI6M8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8Xf0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bv6c/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8Pf1Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/BqL6M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA/9AfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+Af6s8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8I/0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+BmP4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfAP9afQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Cf6M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA/9UfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375YyCuP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfDP9GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+uf4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfAn+nPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38MJPRnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/oX+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xy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vPLGOx988sU3P/zyx0BOfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+B/6c8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8b/0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+B/6M/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wxkP+j/xcsy/jIeJwt0aEXAQCA2GFv74IgCIIgCIIgCIIg2GabbXazm93ZZpttttlmd7bZndtsEwRBEARBEARBEARBEARBEARBEARBEARB2Nu771e+P+D3B/m/Fvj/BRlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4K//lX/AIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/A3/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgb/pP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MVDwn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPhb/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwN/238GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPg7/jPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38MFP1nkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/q7/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwN/zn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPj7/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwMl/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4F/4D+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwh/4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8D/9B/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvljoOw/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8I/8Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv7IfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+Af+88gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888MvfwxU/GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+if8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfAH/vPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/In/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHQNV/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4J/6zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPwz/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4F/7j+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+8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/DHw3/xnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/rv/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHQMd/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4H/4zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPy5/wwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8Bf+M8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwx0/WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+0n8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgf/rPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/C//GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgZ7/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwP/2n0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPg//jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/138GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WOg/1f+Py5g+QR4nC3RoRcBAIDYYe/eBUEQBEEQBEEQBEEQBEEQBEEQBEEQBEGwzXa2c5ttttlmN9tss802t9lmd24TBEEQBEEQBEEQBEHY27vvV74/4PeH/T8I/P+CDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHw1/7KP2SQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+uv8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfA3/CfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4YGPjPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/E3/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgb/lP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfBH/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwND/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4G/7T+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwd/xnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/th/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvljYOQ/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8Cf+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA3/XfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+Dv+c8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888MvfwyM/WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+vv8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfAP/CfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+If+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfAxP/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgX/kP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfCP/WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+if8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfA1H8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgn/rPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/DP/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgX/uP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MTDzn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPgX/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwN/6j+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwL/1nkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G5v4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8D/8p/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4F/7zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPwb/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4GF/wwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8C/9Z9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4d/4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8D/95/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvljYOk/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8B/8Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv6j/wwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8B/8p9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hhY+c8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8Z/8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+B/+I/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8F/9Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Btb+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA3/mP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfDf/GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+u/8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfAxn8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgf/jPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/E//GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgf/lP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MbD1n0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPjf/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwN/7j+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwF/4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8DO/8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bv/SfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+D/+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA//XfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y2D/V/4/L/X5QHicLdGvHwEAgN5hn9sFQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQbDNNtvczTbbbLPNNtu5zW22c5tt9uOz7XnD+/wB3z/c/0Hg/y7IEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwN/+f/7hwwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8Bf0Z9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4q/ozyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8DB/0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bv6Y/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8Nf1Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv6G/gwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8BRfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+Bv6s8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8Lf0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bv60/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wxcNKfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+CP9GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgT/Wn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPg7+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwNn/RlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4G/qz+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHw9/RnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/r7+DDLEMCOMMsY4E0wy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ssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwL/Tn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPj3+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwMv/RlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4E/059BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4D/ozyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8D/1F/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4K0/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8J/0Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv6z/gwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8Cf688gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwx89GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+Qn8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgv+jPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/Ff9GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPga/+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwH/Tn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPjv+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/Q38GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgpz+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwP/VnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/pf+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwP/Wn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhn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nQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPg3/RnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/l1/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4D/0Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/BqL6M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA/+pP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfBf+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/rT+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DEQ059BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4H/0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimv+L/DvIhI=AgAAAACAAABsRwAANQAAACkAAAA=eJztwSEBAAAAgKDu/8EeAQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGME7AEx4nO3BMQ0AAADDoL/+Bc/HAhQAAAAAAAAAAAAAAAAAAAAAAHwb7zDKVw== + + diff --git a/inputFiles/singlePhaseFlow/synthetic/synthetic_2_0.vtu b/inputFiles/singlePhaseFlow/synthetic/synthetic_2_0.vtu new file mode 100644 index 00000000000..d6b77b62910 --- /dev/null +++ b/inputFiles/singlePhaseFlow/synthetic/synthetic_2_0.vtu @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + _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cc8DjzzxzAuvvPHOB5988c3Pn4HOv/9LgEGGGGaEUcYY5zcTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz5/OOCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754dc/+CXAIEMMM8IoY4zzmwkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnz8ccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zw6//7JcAgQwwzwihjjPObCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfPxxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDPQH+AQYYYZoRRxhjnNxNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPn844JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvn5s8jxD38JMMgQw4wwyhjj/GaCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OcPBxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PpHvwQYZIhhRhhljHF+M8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvs84cDDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9+/eNfAgwyxDAjjDLGOL+ZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfb5wwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND/8s8gUYZIhhRhhljHF+M8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvs84cDDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnim58/C5z/5JcAgwwxzAijjDHObyaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPff5wwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDr3/6S4BBhhhmhFHGGOc3E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+fzjgkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eHXP/slwCBDDDPCKGOM85sJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58/HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88M8Cf4BBhhhmhFHGGOc3E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+fzjgkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eHXP/8lwCBDDDPCKGOM85sJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58/HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88Otf/BJgkCGGGWGUMcb5zQSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzx8OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3749S9/CTDIEMOMMMoY4/xmgkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjnDwcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/wT3BNgkCGGGWGUMcb5zQSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzx8OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3749a9+CTDIEMOMMMoY4/xmgkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjnDwcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/z6178EGGSIYUYYZYxxfjPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577POHAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffv2bXwIMMsQwI4wyxji/mWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32+cMBhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ//BPYFGGSIYUYYZYxxfjPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577POHAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffv3bXwIMMsQwI4wyxji/mWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32+cMBhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//t0vAQYZYpgRRhljnN9MMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvv84YBDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1///pcAgwwxzAijjDHObyaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPff5wwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDP0G9AQYZYpgRRhljnN9MMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvv84YBDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1//4ZcAgwwxzAijjDHObyaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPff5wwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDr//4S4BBhhhmhFHGGOc3E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+fzjgkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eHXf/olwCBDDDPCKGOM85sJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58/HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88E9Af4BBhhhmhFHGGOc3E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+fzjgkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eHX//9LgEGGGGaEUcYY5zcTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz5/OOCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754dd//iXAIEMMM8IoY4zzmwkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnz8ccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zw67/8EmCQIYYZYZQxxvnNBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPHw445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745ItvfvjnME+AQYYYZoRRxhjnNxNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPn844JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnh13/9JcAgQwwzwihjjPObCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfPxxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDrv/0SYJAhhhlhlDHG+c0Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8fDjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++PXffwkwyBDDjDDKGOP8ZoJJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY5w8HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/8c5AvwCBDDDPCKGOM85sJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58/HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88Ot//BJgkCGGGWGUMcb5zQSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzx8OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3749T9/CTDIEMOMMMoY4/xmgkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjnDwcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/z6X78EGGSIYUYYZYxxfjPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577POHAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psf/jnEG2CQIYYZYZQxxvnNBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPHw445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvj1v38JMMgQw4wwyhjj/GaCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OcPBxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//Po/vwQYZIhhRhhljHF+M8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvs84cDDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9+/d9fAgwyxDAjjDLGOL+ZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfb5wwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND79yv/w/dLzYyHicLcUhuAEAACBmQRAEQRAEQRAEQRAEd7OdbbbZZnd2ZzvbbLPNNtvczW7uThCEFwRBEARBEARBEARBEF4QBEEQBEEQhBf2ffP/5Q8WAv+/kMOOOOqY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvuuOue+x546JF/PPbEU88898JLr7z2xlvvvPfBR5/867Mvvvrmux9++uW3P/5z4B98CzrksCOOOua4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565B+PPfHUM8+98NIrr73x1jvvffDRJ//67Iuvvvnuh59++e2P/xz4h9+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B/6db0GHHHbEUcccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDj/zjsSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fDTL7/98Z8DxW9Bhxx2xFHHHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4/847EnnnrmuRdeeuW1N956570PPvrkX5998dU33/3w0y+//fGfA//ut6BDDjviqGOOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChR/7x2BNPPfPcCy+98tobb73z3gcfffKvz7746pvvfvjpl9/++M+Bf+9b0CGHHXHUMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAj/3jsiaeeee6Fl1557Y233nnvg48++ddnX3z1zXc//PTLb3/858A/+hZ0yGFHHHXMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889Mg/HnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q8//fLbH/85UPoWdMhhRxx1zHEnnHTKaWecdc55F1x0yWVXXHXNdTfcdMttd9x1z30PPPTIPx574qlnnnvhpVdee+Otd9774KNP/vXZF199890PP/3y2x//OfDvfws65LAjjjrmuBNOOuW0M84657wLLrrksiuuuua6G2665bY77rrnvgceeuQfjz3x1DPPvfDSK6+98dY7733w0Sf/+uyLr7757oeffvntj/8c+A++BR1y2BFHHXPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898o/HnnjqmedeeOmV19546533Pvjok3999sVX33z3w0+//PbHfw78h9+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B8rfgg457IijjjnuhJNOOe2Ms84574KLLrnsiquuue6Gm2657Y677rnvgYce+cdjTzz1zHMvvPTKa2+89c57H3z0yb8+++Krb7774adffvvjPwf+o29Bhxx2xFHHHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4/847EnnnrmuRdeeuW1N956570PPvrkX5998dU33/3w0y+//fGfA//xt6BDDjviqGOOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChR/7x2BNPPfPcCy+98tobb73z3gcfffKvz7746pvvfvjpl9/++M+B/+Rb0CGHHXHUMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAj/3jsiaeeee6Fl1557Y233nnvg48++ddnX3z1zXc//PTLb3/850DlW9Ahhx1x1DHHnXDSKaedcdY5511w0SWXXXHVNdfdcNMtt91x1z33PfDQI/947ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/z0y29//OfAf/ot6JDDjjjqmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRfzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsffvrltz/+c+A/+xZ0yGFHHHXMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889Mg/HnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q8//fLbH/858J9/CzrksCOOOua4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565B+PPfHUM8+98NIrr73x1jvvffDRJ//67Iuvvvnuh59++e2P/xyofgs65LAjjjrmuBNOOuW0M84657wLLrrksiuuuua6G2665bY77rrnvgceeuQfjz3x1DPPvfDSK6+98dY7733w0Sf/+uyLr7757oeffvntj/8c+C++BR1y2BFHHXPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898o/HnnjqmedeeOmV19546533Pvjok3999sVX33z3w0+//PbHfw78429Bhxx2xFHHHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4/847EnnnrmuRdeeuW1N956570PPvrkX5998dU33/3w0y+//fGfA//kW9Ahhx1x1DHHnXDSKaedcdY5511w0SWXXXHVNdfdcNMtt91x1z33PfDQI/947ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/z0y29//OdA7VvQIYcdcdQxx51w0imnnXHWOeddcNEll11x1TXX3XDTLbfdcdc99z3w0CP/eOyJp5557oWXXnntjbfeee+Djz7512dffPXNdz/89Mtvf/znwH/5LeiQw4446pjjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokX889sRTzzz3wkuvvPbGW++898FHn/zrsy+++ua7H3765bc//nPgn34LOuSwI4465rgTTjrltDPOOue8Cy665LIrrrrmuhtuuuW2O+66574HHnrkH4898dQzz73w0iuvvfHWO+998NEn//rsi6+++e6Hn3757Y//HPhn34IOOeyIo4457oSTTjntjLPOOe+Ciy657Iqrrrnuhptuue2Ou+6574GHHvnHY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++GnX3774z8H6t+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B/6rb0GHHHbEUcccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDj/zjsSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fDTL7/98Z8D//W3oEMOO+KoY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFH/vHYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++OmX3/74z4F//i3okMOOOOqY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvuuOue+x546JF/PPbEU88898JLr7z2xlvvvPfBR5/867Mvvvrmux9++uW3P/5zoPEt6JDDjjjqmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRfzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsffvrltz/+c+C/+RZ0yGFHHHXMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889Mg/HnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q8//fLbH/858N9+CzrksCOOOua4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565B+PPfHUM8+98NIrr73x1jvvffDRJ//67Iuvvvnuh59++e2P/xz4774FHXLYEUcdc9wJJ51y2hlnnXPeBRddctkVV11z3Q033XLbHXfdc98DDz3yj8eeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDT7/89sd/DjS/BR1y2BFHHXPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898o/HnnjqmedeeOmV19546533Pvjok3999sVX33z3w0+//PbHfw7899+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B/6Hb0GHHHbEUcccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDj/zjsSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fDTL7/98Z8D/+O3oEMOO+KoY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFH/vHYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++OmX3/74z4HWt6BDDjviqGOOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChR/7x2BNPPfPcCy+98tobb73z3gcfffKvz7746pvvfvjpl9/++M+B/+lb0CGHHXHUMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAj/3jsiaeeee6Fl1557Y233nnvg48++ddnX3z1zXc//PTLb3/858D//C3okMOOOOqY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvuuOue+x546JF/PPbEU88898JLr7z2xlvvvPfBR5/867Mvvvrmux9++uW3P/5z4H/5FnTIYUccdcxxJ5x0ymlnnHXOeRdcdMllV1x1zXU33HTLbXfcdc99Dzz0yD8ee+KpZ5574aVXXnvjrXfe++CjT/712RdfffPdDz/98tsf/znQ/hZ0yGFHHHXMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889Mg/HnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q8//fLbH/858L9+CzrksCOOOua4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565B+PPfHUM8+98NIrr73x1jvvffDRJ//67Iuvvvnuh59++e2P/xz4374FHXLYEUcdc9wJJ51y2hlnnXPeBRddctkVV11z3Q033XLbHXfdc98DDz3yj8eeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDT7/89sd/Dvzv34IOOeyIo4457oSTTjntjLPOOe+Ciy657Iqrrrnuhptuue2Ou+6574GHHvnHY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++GnX3774z8HOt+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B/6Pb0GHHHbEUcccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDj/zjsSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fDTL7/98Z8D/+e3oEMOO+KoY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFH/vHYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++OmX3/74z4H/61vQIYcdcdQxx51w0imnnXHWOeddcNEll11x1TXX3XDTLbfdcdc99z3w0CP/eOyJp5557oWXXnntjbfeee+Djz7512dffPXNdz/89Mtvf/znQPdb0CGHHXHUMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAj/3jsiaeeee6Fl1557Y233nnvg48++ddnX3z1zXc//PTLb3/858C/+BZ0yGFHHHXMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889Mg/HnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q8//fLbH/858C+/BR1y2BFHHXPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898o/HnnjqmedeeOmV19546533Pvjok3999sVX33z3w0+//PbHfw7839+CDjnsiKOOOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx75x2NPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhp19+++M/B3rfgg457IijjjnuhJNOOe2Ms84574KLLrnsiquuue6Gm2657Y677rnvgYce+cdjTzz1zHMvvPTKa2+89c57H3z0yb8+++Krb7774adffvvjPwf+n29Bhxx2xFHHHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4/847EnnnrmuRdeeuW1N956570PPvrkX5998dU33/3w0y+//fGfA//qW9Ahhx1x1DHHnXDSKaedcdY5511w0SWXXXHVNdfdcNMtt91x1z33PfDQI/947ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/z0y29//OfA//st6JDDjjjqmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRfzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsffvrltz/+c6D/LeiQw4446pjjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokX889sRTzzz3wkuvvPbGW++898FHn/zrsy+++ua7H3765bc//nPgX38LOuSwI4465rgTTjrltDPOOue8Cy665LIrrrrmuhtuuuW2O+66574HHnrkH4898dQzz73w0iuvvfHWO+998NEn//rsi6+++e6Hn3757Y//HPg334IOOeyIo4457oSTTjntjLPOOe+Ciy657Iqrrrnuhptuue2Ou+6574GHHvnHY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++GnX3774z8H/u23oEMOO+KoY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFH/vHYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++OmX3/74z4HBt/8PdlHZBHicLcUhuAEAACBmQRAEQXhBEARBEARBEARBEARBEARBEARBsJu7s80222yzzTa7s5vtbOfubLPN3QRBEF4QBEEQhBcEQRD2ffP/5Q/2A/+/kMOOOOofxxx3wkmnnHbGWeecd8FFl1x2xVXXXHfDTbfcdsdd99z3wEOPPPbEU88898JLr7z2xlvvvPfBR5/867Mvvvrmux/+89Mvv/1x4N/5FnTIYUcc9Y9jjjvhpFNOO+Osc8674KJLLrviqmuuu+GmW26746577nvgoUcee+KpZ5574aVXXnvjrXfe++CjT/712RdfffPdD//56Zff/jjwD74FHXLYEUf945jjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokceeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDf3765bc/Dvy734IOOeyIo/5xzHEnnHTKaWecdc55F1x0yWVXXHXNdTfcdMttd9x1z30PPPTIY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++E/P/3y2x8HBt+CDjnsiKP+ccxxJ5x0ymlnnHXOeRdcdMllV1x1zXU33HTLbXfcdc99Dzz0yGNPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhPz/98tsfB/7ht6BDDjviqH8cc9wJJ51y2hlnnXPeBRddctkVV11z3Q033XLbHXfdc98DDz3y2BNPPfPcCy+98tobb73z3gcfffKvz7746pvvfvjPT7/89seBf/Qt6JDDjjjqH8ccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDjzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsf/vPTL7/9ceAffws65LAjjvrHMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAjjz3x1DPPvfDSK6+98dY7733w0Sf/+uyLr7757of//PTLb38cGH4LOuSwI476xzHHnXDSKaedcdY5511w0SWXXXHVNdfdcNMtt91x1z33PfDQI4898dQzz73w0iuvvfHWO+998NEn//rsi6+++e6H//z0y29/HPj3vgUdctgRR/3jmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRx5546pnnXnjpldfeeOud9z746JN/ffbFV99898N/fvrltz8O/Pvfgg457Iij/nHMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889MhjTzz1zHMvvPTKa2+89c57H3z0yb8+++Krb7774T8//fLbHwf+g29Bhxx2xFH/OOa4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565LEnnnrmuRdeeuW1N956570PPvrkX5998dU33/3wn59++e2PA6NvQYccdsRR/zjmuBNOOuW0M84657wLLrrksiuuuua6G2665bY77rrnvgceeuSxJ5565rkXXnrltTfeeue9Dz765F+fffHVN9/98J+ffvntjwP/4begQw474qh/HHPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898tgTTz3z3AsvvfLaG2+9894HH33yr8+++Oqb7374z0+//PbHgf/oW9Ahhx1x1D+OOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx557ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/znp19+++PAf/wt6JDDjjjqH8ccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDjzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsf/vPTL7/9cWD8LeiQw4446h/HHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4889sRTzzz3wkuvvPbGW++898FHn/zrsy+++ua7H/7z0y+//XHgP/kWdMhhRxz1j2OOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChRx574qlnnnvhpVdee+Otd9774KNP/vXZF199890P//npl9/+OPCffgs65LAjjvrHMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAjjz3x1DPPvfDSK6+98dY7733w0Sf/+uyLr7757of//PTLb38c+M++BR1y2BFH/eOY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvuuOue+x546JHHnnjqmedeeOmV19546533Pvjok3999sVX33z3w39++uW3Pw5MvgUdctgRR/3jmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRx5546pnnXnjpldfeeOud9z746JN/ffbFV99898N/fvrltz8O/Offgg457Iij/nHMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889MhjTzz1zHMvvPTKa2+89c57H3z0yb8+++Krb7774T8//fLbHwf+i29Bhxx2xFH/OOa4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565LEnnnrmuRdeeuW1N956570PPvrkX5998dU33/3wn59++e2PA//lt6BDDjviqH8cc9wJJ51y2hlnnXPeBRddctkVV11z3Q033XLbHXfdc98DDz3y2BNPPfPcCy+98tobb73z3gcfffKvz7746pvvfvjPT7/89seB6begQw474qh/HHPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898tgTTz3z3AsvvfLaG2+9894HH33yr8+++Oqb7374z0+//PbHgf/qW9Ahhx1x1D+OOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx557ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/znp19+++PAf/0t6JDDjjjqH8ccd8JJp5x2xlnnnHfBRZdcdsVV11x3w0233HbHXffc98BDjzz2xFPPPPfCS6+89sZb77z3wUef/OuzL7765rsf/vPTL7/9ceC/+RZ0yGFHHPWPY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFHHnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q//+emX3/44MPsWdMhhRxz1j2OOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChRx574qlnnnvhpVdee+Otd9774KNP/vXZF199890P//npl9/+OPDffgs65LAjjvrHMcedcNIpp51x1jnnXXDRJZddcdU1191w0y233XHXPfc98NAjjz3x1DPPvfDSK6+98dY7733w0Sf/+uyLr7757of//PTLb38c+O++BR1y2BFH/eOY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvuuOue+x546JHHnnjqmedeeOmV19546533Pvjok3999sVX33z3w39++uW3Pw7899+CDjnsiKP+ccxxJ5x0ymlnnHXOeRdcdMllV1x1zXU33HTLbXfcdc99Dzz0yGNPPPXMcy+89Mprb7z1znsffPTJvz774qtvvvvhPz/98tsfB+bfgg457Iij/nHMcSecdMppZ5x1znkXXHTJZVdcdc11N9x0y2133HXPfQ889MhjTzz1zHMvvPTKa2+89c57H3z0yb8+++Krb7774T8//fLbHwf+h29Bhxx2xFH/OOa4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565LEnnnrmuRdeeuW1N956570PPvrkX5998dU33/3wn59++e2PA//kW9Ahhx1x1D+OOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx557ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/znp19+++PAP/0WdMhhRxz1j2OOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChRx574qlnnnvhpVdee+Otd9774KNP/vXZF199890P//npl9/+OLD4FnTIYUcc9Y9jjjvhpFNOO+Osc8674KJLLrviqmuuu+GmW26746577nvgoUcee+KpZ5574aVXXnvjrXfe++CjT/712RdfffPdD//56Zff/jjwP34LOuSwI476xzHHnXDSKaedcdY5511w0SWXXXHVNdfdcNMtt91x1z33PfDQI4898dQzz73w0iuvvfHWO+998NEn//rsi6+++e6H//z0y29/HPhn34IOOeyIo/5xzHEnnHTKaWecdc55F1x0yWVXXHXNdTfcdMttd9x1z30PPPTIY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++E/P/3y2x8H/qdvQYccdsRR/zjmuBNOOuW0M84657wLLrrksiuuuua6G2665bY77rrnvgceeuSxJ5565rkXXnrltTfeeue9Dz765F+fffHVN9/98J+ffvntjwPLb0GHHHbEUf845rgTTjrltDPOOue8Cy665LIrrrrmuhtuuuW2O+66574HHnrksSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fCfn3757Y8D//O3oEMOO+Kofxxz3AknnXLaGWedc94FF11y2RVXXXPdDTfdctsdd91z3wMPPfLYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++M9Pv/z2x4H/5VvQIYcdcdQ/jjnuhJNOOe2Ms84574KLLrnsiquuue6Gm2657Y677rnvgYceeeyJp5557oWXXnntjbfeee+Djz7512dffPXNdz/856dffvvjwD//FnTIYUcc9Y9jjjvhpFNOO+Osc8674KJLLrviqmuuu+GmW26746577nvgoUcee+KpZ5574aVXXnvjrXfe++CjT/712RdfffPdD//56Zff/jiw+hZ0yGFHHPWPY4474aRTTjvjrHPOu+CiSy674qprrrvhpltuu+Oue+574KFHHnviqWeee+GlV15746133vvgo0/+9dkXX33z3Q//+emX3/448L9+CzrksCOO+scxx51w0imnnXHWOeddcNEll11x1TXX3XDTLbfdcdc99z3w0COPPfHUM8+98NIrr73x1jvvffDRJ//67Iuvvvnuh//89Mtvfxz4374FHXLYEUf945jjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokceeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDf3765bc/DvyLb0GHHHbEUf845rgTTjrltDPOOue8Cy665LIrrrrmuhtuuuW2O+66574HHnrksSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fCfn3757Y8D629Bhxx2xFH/OOa4E0465bQzzjrnvAsuuuSyK6665robbrrltjvuuue+Bx565LEnnnrmuRdeeuW1N956570PPvrkX5998dU33/3wn59++e2PA//yW9Ahhx1x1D+OOe6Ek0457YyzzjnvgosuueyKq6657oabbrntjrvuue+Bhx557ImnnnnuhZdeee2Nt95574OPPvnXZ1989c13P/znp19+++PAv/oWdMhhRxz1j2OOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChRx574qlnnnvhpVdee+Otd9774KNP/vXZF199890P//npl9/+OPCvvwUdctgRR/3jmONOOOmU084465zzLrjoksuuuOqa62646Zbb7rjrnvseeOiRx5546pnnXnjpldfeeOud9z746JN/ffbFV99898N/fvrltz8ObL4FHXLYEUf945jjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokceeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDf3765bc/Dvzv34IOOeyIo/5xzHEnnHTKaWecdc55F1x0yWVXXHXNdTfcdMttd9x1z30PPPTIY0889cxzL7z0ymtvvPXOex989Mm/Pvviq2++++E/P/3y2x8H/o9vQYccdsRR/zjmuBNOOuW0M84657wLLrrksiuuuua6G2665bY77rrnvgceeuSxJ5565rkXXnrltTfeeue9Dz765F+fffHVN9/98J+ffvntjwP/57egQw474qh/HHPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898tgTTz3z3AsvvfLaG2+9894HH33yr8+++Oqb7374z0+//PbHge23oEMOO+Kofxxz3AknnXLaGWedc94FF11y2RVXXXPdDTfdctsdd91z3wMPPfLYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++M9Pv/z2x4H/61vQIYcdcdQ/jjnuhJNOOe2Ms84574KLLrnsiquuue6Gm2657Y677rnvgYceeeyJp5557oWXXnntjbfeee+Djz7512dffPXNdz/856dffvvjwP/9LeiQw4446h/HHHfCSaecdsZZ55x3wUWXXHbFVddcd8NNt9x2x1333PfAQ4889sRTzzz3wkuvvPbGW++898FHn/zrsy+++ua7H/7z0y+//XHg//kWdMhhRxz1j2OOO+GkU04746xzzrvgoksuu+Kqa6674aZbbrvjrnvue+ChRx574qlnnnvhpVdee+Otd9774KNP/vXZF199890P//npl9/+OLD7FnTIYUcc9Y9jjjvhpFNOO+Osc8674KJLLrviqmuuu+GmW26746577nvgoUcee+KpZ5574aVXXnvjrXfe++CjT/712RdfffPdD//56Zff/jjwb74FHXLYEUf945jjTjjplNPOOOuc8y646JLLrrjqmutuuOmW2+646577HnjokceeeOqZ51546ZXX3njrnfc++OiTf332xVfffPfDf3765bc/Dvzbb0GHHHbEUf845rgTTjrltDPOOue8Cy665LIrrrrmuhtuuuW2O+66574HHnrksSeeeua5F1565bU33nrnvQ8++uRfn33x1Tff/fCfn3757Y8D/++3oEMOO+Kofxxz3AknnXLaGWedc94FF11y2RVXXXPdDTfdctsdd91z3wMPPfLYE08989wLL73y2htvvfPeBx998q/Pvvjqm+9++M9Pv/z2x4H9t/8Pd+bZQHicLcUv2AEAAOBnex5BEARBEARBEARBEARBEAThC8IXBEEQBEEQBEEQBEEQBEEQBEFwN9tss83dbLOd29zNNtu5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EsussMof1vjLOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/8MvB//hFkiGFGGGWMcSaYZIppZphljnkWWGSJZVZY5Q9r/GWdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH34Z+PwRZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWOUPa/xlnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9+GfjXfwQZYpgRRhljnAkmmWKaGWaZY54FFllimRVW+cMaf1lng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh18G/q8/ggwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqv8YY2/rLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDLwP/9x9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVf6wxl/W2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXge8fQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVX+sMZf1tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhl4H/548gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKn9Y4y/rbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLwP/7R5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVP6zxl3U22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++GXg//sjyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMof1vjLOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/8MhD4t/7N/39ygdh9eJwt1yETAgCXllFWPxUVlVVUVFR0UVFRUVFRUQkEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEFz9zi3nBzwz78z9Q+BPAv/v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IYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+vv4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sdAVH8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgH+jPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/EP9GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgX+kP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MRDTn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPjH+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/RH8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgn+rPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38MxPVnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/pn+DDLEMCOM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GWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375YyCrP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfDf9WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+h/4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfA/9SfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4YyOnPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/C/9GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgf+tP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfB/9GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwbyf/T/AtC86Mh4nC3RoRcBAIDYYXvvgiAIgiAIgiAIgiDYZpttdrOb3dlmm2222WZ3ttmd22wTBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEHY27vvV74/4PcH+b8W+P8FGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgr/+Vf8AgQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8Df8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bv+k/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wxUPCfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Fv+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA3/bfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+Dv+M8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888MvfwwU/WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+rv8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfA3/OfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Pv+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfAyX/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgX/gP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfCH/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/0H8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WOg7D+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwj/xnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/sh/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4B/7zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DFT8Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv6J/wwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8Af+88gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8if8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sdA1X8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgn/rPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/DP/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgX/uP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MVDzn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPgX/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/0n8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgX/nPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M1P1nkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/rX/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwL/xn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPi3/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwMN/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4F/5z+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHw7/1nkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/oP/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHQNN/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4D/6zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPwn/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4H/7D+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHQ8p9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4L/4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsus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YpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+Cf+s8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8M/8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bf+4/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wxMPOfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Bf+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA3/qP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfAv/WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwbm/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/yn8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgX/vPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/Bv/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgYX/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwL/1n0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPh3/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/3n8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WNg6T+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwH/xnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/qP/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwH/yn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GFj5zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPxn/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4H/4j+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwX/1nkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G1v4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8Df+Y/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8N/8Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv67/wwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8DGfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+B/+M8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8T/8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+B/+U/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wxsPWfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+N/+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA3/uP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfAX/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwM7/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4G/9J9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4P/4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8D/9d/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvljYP9X/j/T5ulAeJwt0a8fAQCA3mG3zwVBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBsM0229zNNttss80227nNbbZzm23247PtecP7/AHfP9z/QeD/LsgQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA3/5//uHDDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwF/Rn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPir+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwMH/RlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4G/pj+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHw1/VnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/ob+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwFF/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4G/qzyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPwt/RlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4G/rT+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DFw0p9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4I/0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+BP9afQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Dv6M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA2f9GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgb+rP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfD39GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+vv4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfARX8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgH+jPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/EP9GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgX+kP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MXDVn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPjH+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/RH8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgn+rPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M3PRnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/pn+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwD/Xn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPgX+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwN3/RlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4F/qT+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwr/RnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/rX+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwEN/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsu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cy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgb+kP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfCX9WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+iv4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sc/f/j/P39gkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/qr+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwF/Tn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPjr+jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwMh/RlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4G/oT+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwN/VnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/pb+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHQFh/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4E/1Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv62/gwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8Df0Z9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hiI6M8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8Xf0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bv6c/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8Pf1Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/BqL6M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA/9AfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+Af6s8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8I/0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+BmP4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfAP9afQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Cf6M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA/9UfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375YyCuP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfDP9GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+uf4MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfAn+nPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38MJPRnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/oX+DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xy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vPLGOx988sU3P/zyx0BOfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+B/6c8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwz8b/0ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+B/6M/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wxkP+j/xcsy/jIeJwt0aEXAQCA2GFv74IgCIIgCIIgCIIg2GabbXazm93ZZpttttlmd7bZndtsEwRBEARBEARBEARBEARBEARBEARBEARB2Nu771e+P+D3B/m/Fvj/BRlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4K//lX/AIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/A3/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgb/pP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MVDwn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPhb/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwN/238GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPg7/jPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38MFP1nkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/q7/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwN/zn0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPj7/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwMl/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4F/4D+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+88c4Hn3zxzQ+//DHwh/4zyBDDjDDKGONMMMkU08wwyxzzLLDIEsussMoa62ywyRbb7LDLHvsccMgRx5xwyhnnXHDJFdfccMsd9zzwyBPPvPDKG+988MkX3/zwyx8D/9B/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvljoOw/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8I/8Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv7IfwYZYpgRRhljnAkmmWKaGWaZY54FFllimRVWWWOdDTbZYpsddtljnwMOOeKYE04545wLLrnimhtuueOeBx554pkXXnnjnQ8++eKbH375Y+Af+88gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888MvfwxU/GeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+if8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfAH/vPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/In/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHQNV/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4J/6zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPwz/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4F/7j+DDDHMCKOMMc4Ek0wxzQyzzDHPAossscwKq6yxzgabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPPPHMC6+8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/DHw3/xnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/rv/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHQMd/BhlimBFGGWOcCSaZYpoZZpljngUWWWKZFVZZY50NNtlimx122WOfAw454pgTTjnjnAsuueKaG265454HHnnimRdeeeOdDz754psffvlj4H/4zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DPy5/wwyxDAjjDLGOBNMMsU0M8wyxzwLLLLEMiusssY6G2yyxTY77LLHPgcccsQxJ5xyxjkXXHLFNTfccsc9DzzyxDMvvPLGOx988sU3P/zyx8Bf+M8gQwwzwihjjDPBJFNMM8Msc8yzwCJLLLPCKmuss8EmW2yzwy577HPAIUccc8IpZ5xzwSVXXHPDLXfc88AjTzzzwitvvPPBJ19888Mvfwx0/WeQIYYZYZQxxplgkimmmWGWOeZZYJEllllhlTXW2WCTLbbZYZc99jngkCOOOeGUM8654JIrrrnhljvueeCRJ5554ZU33vngky+++eGXPwb+0n8GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WPgf/rPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/C//GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgZ7/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwP/2n0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPg//jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwP/138GGWKYEUYZY5wJJplimhlmmWOeBRZZYpkVVlljnQ022WKbHXbZY58DDjnimBNOOeOcCy654pobbrnjngceeeKZF155450PPvnimx9++WOg/1f+Py5g+QR4nC3RoRcBAGLAYW/vgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiC4zd1s5zbbbLP3BEEQBEEQBEEQBEEQBEEQBEEQhL179/3K9wf8/tD/h8DfCjLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwB//7h8YZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bf/SfQYYYZoRRxhhngkmmmGaGWeaYZ4FFllhmhVXWWGeDTbbYZodd9tjngEOOOOaEU84454JLrrjmhlvuuOeBR5545oVX3njng0+++OaHX/4Y+Cf/GWSIYUYYZYxxJphkimlmmGWOeRZYZIllVlhljXU22GSLbXbYZY99DjjkiGNOOOWMcy645IprbrjljnseeOSJZ1545Y13Pvjki29++OWPgYH/DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwJ/8Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv7sP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MfDP/jPIEMOMMMoY40wwyRTTzDDLHPMssMgSy6ywyhrrbLDJFtvssMse+xxwyBHHnHDKGedccMkV19xwyx33PPDIE8+88Mob73zwyRff/PDLHwND/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4F/8Z9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4V/8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bv/jPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38MjPxnkCGGGWGUMcaZYJIppplhljnmWWCRJZZZYZU11tlgky222WGXPfY54JAjjjnhlDPOueCSK6654ZY77nngkSeeeeGVN9754JMvvvnhlz8G/uo/gwwxzAijjDHOBJNMMc0Ms8wxzwKLLLHMCqussc4Gm2yxzQ677LHPAYccccwJp5xxzgWXXHHNDbfccc8DjzzxzAuvvPHOB5988c0Pv/wx8G/+M8gQw4wwyhjjTDDJFNPMMMsc8yywyBLLrLDKGutssMkW2+ywyx77HHDIEceccMoZ51xwyRXX3HDLHfc88MgTz7zwyhvvfPDJF9/88MsfA//uP4MMMcwIo4wxzgSTTDHNDLPMMc8CiyyxzAqrrLHOBptssc0Ou+yxzwGHHHHMCaeccc4Fl1xxzQ233HHPA4888cwLr7zxzgeffPHND7/8MTD2n0GGGGaEUcYYZ4JJpphmhlnmmGeBRZZYZoVV1lhng0222GaHXfbY54BDjjjmhFPOOOeCS6645oZb7rjngUeeeOaFV95454NPvvjmh1/+GPgP/xlkiGFGGGWMcSaYZIppZphljnkWWGSJZVZYZY11Nthki2122GWPfQ445IhjTjjljHMuuOSKa2645Y57HnjkiWdeeOWNdz745Itvfvjlj4H/9J9BhhhmhFHGGGeCSaaYZoZZ5phngUWWWGaFVdZYZ4NNtthmh1322OeAQ4445oRTzjjngkuuuOaGW+6454FHnnjmhVfeeOeDT7745odf/hj4L/8ZZIhhRhhljHEmmGSKaWaYZY55FlhkiWVWWGWNdTbYZIttdthlj30OOOSIY0445YxzLrjkimtuuOWOex545IlnXnjljXc++OSLb3745Y+Bif8MMsQwI4wyxjgTTDLFNDPMMsc8CyyyxDIrrLLGOhtsssU2O+yyxz4HHHLEMSeccsY5F1xyxTU33HLHPQ888sQzL7zyxjsffPLFNz/88sfAf/vPIEMMM8IoY4wzwSRTTDPDLHPMs8AiSyyzwiprrLPBJltss8Mue+xzwCFHHHPCKWecc8ElV1xzwy133PPAI08888Irb7zzwSdffPPDL38M/I//DDLEMCOMMsY4E0wyxTQzzDLHPAssssQyK6yyxjobbLLFNjvsssc+BxxyxDEnnHLGORdccsU1N9xyxz0PPPLEMy+88sY7H3zyxTc//PLHwP/6zyBDDDPCKGOMM8EkU0wzwyxzzLPAIksss8Iqa6yzwSZbbLPDLnvsc8AhRxxzwilnnHPBJVdcc8Mtd9zzwCNPPPPCK2+888EnX3zzwy9/DEz9Z5AhhhlhlDHGmWCSKaaZYZY55llgkSWWWWGVNdbZYJMtttlhlz32OeCQI4454ZQzzrngkiuuueGWO+554JEnnnnhlTfe+eCTL7754Zc/Bv7PfwYZYpgRRvn/KGWPag==AgAAAACAAABGJgAANQAAACAAAAA=eJztwSEBAAAAgKDu/8EeAQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGME7AEx4nO3BMQEAAADCoH/9AxtEoAAAAAAAAAAAAPg12pp+zA== + + diff --git a/inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml b/inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml index 98db3647020..f51963bf385 100644 --- a/inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml +++ b/inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml @@ -11,7 +11,7 @@ targetRegions="{ region }"> + newtonMaxIter="100"/> @@ -24,21 +24,21 @@ - - - - + + + solidInternalEnergyModelName="rockInternalEnergy_nonLinear"/> @@ -49,13 +49,22 @@ referencePressure="0.0" compressibility="3.0e-11"/> - + + + + + - + - - - + + + + + + + @@ -116,21 +135,21 @@ setNames="{ all }" objectPath="ElementRegions/region/cb" fieldName="temperature" - scale="0"/> + scale="100"/> + scale="100"/> + scale="-20.0"/> diff --git a/inputFiles/singlePhaseFlow/thermalCompressible_2d_benchmark.xml b/inputFiles/singlePhaseFlow/thermalCompressible_2d_benchmark.xml index 4c33c44d234..c4b66910e8b 100644 --- a/inputFiles/singlePhaseFlow/thermalCompressible_2d_benchmark.xml +++ b/inputFiles/singlePhaseFlow/thermalCompressible_2d_benchmark.xml @@ -5,7 +5,14 @@ - + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/singlePhaseFlow/thermalCompressible_temperatureDependentSinglePhaseThermalConductivity_smoke.xml b/inputFiles/singlePhaseFlow/thermalCompressible_temperatureDependentSinglePhaseThermalConductivity_smoke.xml new file mode 100644 index 00000000000..195ceabe14c --- /dev/null +++ b/inputFiles/singlePhaseFlow/thermalCompressible_temperatureDependentSinglePhaseThermalConductivity_smoke.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/singlePhaseFlow/thermalCompressible_temperatureDependentVolumetricHeatCapacity_benchmark.xml b/inputFiles/singlePhaseFlow/thermalCompressible_temperatureDependentVolumetricHeatCapacity_benchmark.xml new file mode 100644 index 00000000000..fa9af06fd2f --- /dev/null +++ b/inputFiles/singlePhaseFlow/thermalCompressible_temperatureDependentVolumetricHeatCapacity_benchmark.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/singlePhaseFlow/thermalCompressible_temperatureDependentVolumetricHeatCapacity_smoke.xml b/inputFiles/singlePhaseFlow/thermalCompressible_temperatureDependentVolumetricHeatCapacity_smoke.xml new file mode 100644 index 00000000000..013e81c76c2 --- /dev/null +++ b/inputFiles/singlePhaseFlow/thermalCompressible_temperatureDependentVolumetricHeatCapacity_smoke.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/singlePhaseFlow/thermalSinglePhaseFlow.ats b/inputFiles/singlePhaseFlow/thermalSinglePhaseFlow.ats index 532b1b1f989..886d8add60a 100644 --- a/inputFiles/singlePhaseFlow/thermalSinglePhaseFlow.ats +++ b/inputFiles/singlePhaseFlow/thermalSinglePhaseFlow.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params['atol'] = 1e-06 @@ -22,6 +20,22 @@ decks = [ partitions=((1, 1, 1), (2, 2, 2)), restart_step=6, check_step=20, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="thermalCompressible_temperatureDependentVolumetricHeatCapacity_smoke", + description= + 'a wellbore problem with temperature dependent volumetric heat capacity)', + partitions=((1, 1, 1), (2, 2, 1)), + restart_step=1, + check_step=2, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="thermalCompressible_temperatureDependentSinglePhaseThermalConductivity_smoke", + description= + 'a wellbore problem with temperature dependent thermal conductivity)', + partitions=((1, 1, 1), (2, 2, 1)), + restart_step=1, + check_step=2, restartcheck_params=RestartcheckParameters(**restartcheck_params)) ] diff --git a/inputFiles/singlePhaseFlowFractures/fractureFlowWithGravity_conforming_2d_smoke.xml b/inputFiles/singlePhaseFlowFractures/fractureFlowWithGravity_conforming_2d_smoke.xml index f9ce504d5d7..9dbce69a6a6 100644 --- a/inputFiles/singlePhaseFlowFractures/fractureFlowWithGravity_conforming_2d_smoke.xml +++ b/inputFiles/singlePhaseFlowFractures/fractureFlowWithGravity_conforming_2d_smoke.xml @@ -84,7 +84,7 @@ - + + cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, + cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1, + cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2, + cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }"> + cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, + cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1, + cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2, + cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }"> diff --git a/inputFiles/solidMechanics/ExtendedDruckerPragerWellbore_base.xml b/inputFiles/solidMechanics/ExtendedDruckerPragerWellbore_base.xml index a2e0bd5cd8e..9881628d292 100644 --- a/inputFiles/solidMechanics/ExtendedDruckerPragerWellbore_base.xml +++ b/inputFiles/solidMechanics/ExtendedDruckerPragerWellbore_base.xml @@ -32,7 +32,7 @@ diff --git a/inputFiles/solidMechanics/KirschProblem_base.xml b/inputFiles/solidMechanics/KirschProblem_base.xml index 11eee1612ca..c0f724d29b0 100755 --- a/inputFiles/solidMechanics/KirschProblem_base.xml +++ b/inputFiles/solidMechanics/KirschProblem_base.xml @@ -17,7 +17,7 @@ diff --git a/inputFiles/solidMechanics/ModifiedCamClayWellbore_base.xml b/inputFiles/solidMechanics/ModifiedCamClayWellbore_base.xml index 1e216ebc48d..81ac82e3f23 100644 --- a/inputFiles/solidMechanics/ModifiedCamClayWellbore_base.xml +++ b/inputFiles/solidMechanics/ModifiedCamClayWellbore_base.xml @@ -31,7 +31,7 @@ diff --git a/inputFiles/solidMechanics/OpenWellbore.xml b/inputFiles/solidMechanics/OpenWellbore.xml index 8c7c591862d..a6dfa394f5f 100644 --- a/inputFiles/solidMechanics/OpenWellbore.xml +++ b/inputFiles/solidMechanics/OpenWellbore.xml @@ -79,7 +79,7 @@ diff --git a/inputFiles/solidMechanics/SSLE.ats b/inputFiles/solidMechanics/SSLE.ats index 38b590c519d..41213dd2199 100644 --- a/inputFiles/solidMechanics/SSLE.ats +++ b/inputFiles/solidMechanics/SSLE.ats @@ -1,5 +1,4 @@ -import geos_ats -from geos_ats.test_builder import generate_geos_tests, RestartcheckParameters, TestDeck +from geos.ats.test_builder import generate_geos_tests, RestartcheckParameters, TestDeck restartcheck_params = {} restartcheck_params["atol"] = 1.0E-10 diff --git a/inputFiles/solidMechanics/anisotropic.ats b/inputFiles/solidMechanics/anisotropic.ats index a6afc13b144..5a4db820d7a 100644 --- a/inputFiles/solidMechanics/anisotropic.ats +++ b/inputFiles/solidMechanics/anisotropic.ats @@ -1,5 +1,4 @@ -import geos_ats -from geos_ats.test_builder import generate_geos_tests, TestDeck, RestartcheckParameters +from geos.ats.test_builder import generate_geos_tests, TestDeck, RestartcheckParameters restartcheck_params = {} restartcheck_params["atol"] = 1.0E-5 diff --git a/inputFiles/solidMechanics/beamBending.ats b/inputFiles/solidMechanics/beamBending.ats index 352a2ae5d3f..3ca10958216 100644 --- a/inputFiles/solidMechanics/beamBending.ats +++ b/inputFiles/solidMechanics/beamBending.ats @@ -1,5 +1,4 @@ -import geos_ats -from geos_ats.test_builder import RestartcheckParameters, CurveCheckParameters, TestDeck, generate_geos_tests +from geos.ats.test_builder import RestartcheckParameters, CurveCheckParameters, TestDeck, generate_geos_tests restartcheck_params = RestartcheckParameters(atol=1.0E-3, rtol=1.0E-7) diff --git a/inputFiles/solidMechanics/beamBending_base.xml b/inputFiles/solidMechanics/beamBending_base.xml index 83ef0821a02..764cb822641 100644 --- a/inputFiles/solidMechanics/beamBending_base.xml +++ b/inputFiles/solidMechanics/beamBending_base.xml @@ -38,12 +38,11 @@ target="/Outputs/restartOutput"/> - diff --git a/inputFiles/solidMechanics/beamBending_hybridHexPrism_smoke.xml b/inputFiles/solidMechanics/beamBending_hybridHexPrism_smoke.xml index 0c23d01b854..f0f5db09631 100644 --- a/inputFiles/solidMechanics/beamBending_hybridHexPrism_smoke.xml +++ b/inputFiles/solidMechanics/beamBending_hybridHexPrism_smoke.xml @@ -28,7 +28,7 @@ diff --git a/inputFiles/solidMechanics/benchmarks/SSLE-QS-small.xml b/inputFiles/solidMechanics/benchmarks/SSLE-QS-small.xml index 4df98119448..486f533a5bc 100644 --- a/inputFiles/solidMechanics/benchmarks/SSLE-QS-small.xml +++ b/inputFiles/solidMechanics/benchmarks/SSLE-QS-small.xml @@ -51,7 +51,7 @@ diff --git a/inputFiles/solidMechanics/benchmarks/SSLE-io.xml b/inputFiles/solidMechanics/benchmarks/SSLE-io.xml index 8a64bd59e77..5c0ecc605cf 100644 --- a/inputFiles/solidMechanics/benchmarks/SSLE-io.xml +++ b/inputFiles/solidMechanics/benchmarks/SSLE-io.xml @@ -112,7 +112,7 @@ diff --git a/inputFiles/solidMechanics/benchmarks/VerticalElasticWellbore.xml b/inputFiles/solidMechanics/benchmarks/VerticalElasticWellbore.xml index 35f4635aeb4..e17d1caa837 100644 --- a/inputFiles/solidMechanics/benchmarks/VerticalElasticWellbore.xml +++ b/inputFiles/solidMechanics/benchmarks/VerticalElasticWellbore.xml @@ -79,7 +79,7 @@ diff --git a/inputFiles/solidMechanics/elasticHollowCylinder_isotropic_smoke.xml b/inputFiles/solidMechanics/elasticHollowCylinder_isotropic_smoke.xml index 4882dd593b6..f43377dcb0b 100644 --- a/inputFiles/solidMechanics/elasticHollowCylinder_isotropic_smoke.xml +++ b/inputFiles/solidMechanics/elasticHollowCylinder_isotropic_smoke.xml @@ -10,7 +10,7 @@ diff --git a/inputFiles/solidMechanics/elasticHollowCylinder_orthotropic_smoke.xml b/inputFiles/solidMechanics/elasticHollowCylinder_orthotropic_smoke.xml index ede5290a53c..69b254072cc 100644 --- a/inputFiles/solidMechanics/elasticHollowCylinder_orthotropic_smoke.xml +++ b/inputFiles/solidMechanics/elasticHollowCylinder_orthotropic_smoke.xml @@ -10,7 +10,7 @@ diff --git a/inputFiles/solidMechanics/elasticHollowCylinder_transverseIsotropic_smoke.xml b/inputFiles/solidMechanics/elasticHollowCylinder_transverseIsotropic_smoke.xml index 96433871e09..522d21d57d6 100644 --- a/inputFiles/solidMechanics/elasticHollowCylinder_transverseIsotropic_smoke.xml +++ b/inputFiles/solidMechanics/elasticHollowCylinder_transverseIsotropic_smoke.xml @@ -10,7 +10,7 @@ diff --git a/inputFiles/solidMechanics/gravity.ats b/inputFiles/solidMechanics/gravity.ats index 0da665c416e..411744dc844 100644 --- a/inputFiles/solidMechanics/gravity.ats +++ b/inputFiles/solidMechanics/gravity.ats @@ -1,5 +1,4 @@ -import geos_ats -from geos_ats.test_builder import generate_geos_tests, TestDeck, RestartcheckParameters +from geos.ats.test_builder import generate_geos_tests, TestDeck, RestartcheckParameters restartcheck_params = {} restartcheck_params["atol"] = 1.0E-5 diff --git a/inputFiles/solidMechanics/mechanicsWithHeterogeneousMaterials.xml b/inputFiles/solidMechanics/mechanicsWithHeterogeneousMaterials.xml index a13c81842e1..d1dfd7352b2 100644 --- a/inputFiles/solidMechanics/mechanicsWithHeterogeneousMaterials.xml +++ b/inputFiles/solidMechanics/mechanicsWithHeterogeneousMaterials.xml @@ -63,7 +63,7 @@ diff --git a/inputFiles/solidMechanics/plasticCubeReset.ats b/inputFiles/solidMechanics/plasticCubeReset.ats index 9efdc1738c5..1048f140f81 100644 --- a/inputFiles/solidMechanics/plasticCubeReset.ats +++ b/inputFiles/solidMechanics/plasticCubeReset.ats @@ -1,5 +1,4 @@ -import geos_ats -from geos_ats.test_builder import generate_geos_tests, RestartcheckParameters, TestDeck +from geos.ats.test_builder import generate_geos_tests, RestartcheckParameters, TestDeck restartcheck_params = {} restartcheck_params["atol"] = 1.0E-5 diff --git a/inputFiles/solidMechanics/plasticCubeReset.xml b/inputFiles/solidMechanics/plasticCubeReset.xml index 78007a7ef20..8f923860899 100644 --- a/inputFiles/solidMechanics/plasticCubeReset.xml +++ b/inputFiles/solidMechanics/plasticCubeReset.xml @@ -19,7 +19,7 @@ @@ -160,4 +160,3 @@ name="restartOutput"/> - diff --git a/inputFiles/solidMechanics/plasticWellbore.ats b/inputFiles/solidMechanics/plasticWellbore.ats index 4c285454533..740b3782d8b 100644 --- a/inputFiles/solidMechanics/plasticWellbore.ats +++ b/inputFiles/solidMechanics/plasticWellbore.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params['atol'] = 1e-06 diff --git a/inputFiles/solidMechanics/sedov.ats b/inputFiles/solidMechanics/sedov.ats index 07d74a25999..5c353c27462 100644 --- a/inputFiles/solidMechanics/sedov.ats +++ b/inputFiles/solidMechanics/sedov.ats @@ -1,5 +1,5 @@ -import geos_ats -from geos_ats.test_builder import generate_geos_tests, RestartcheckParameters, TestDeck, CurveCheckParameters +# Integrated Test Docs Begin Parameters +from geos.ats.test_builder import generate_geos_tests, RestartcheckParameters, TestDeck, CurveCheckParameters restartcheck_params = {} restartcheck_params["atol"] = 2.0E-10 @@ -10,7 +10,9 @@ curvecheck_params['filename'] = 'veloc_history.hdf5' curvecheck_params['tolerance'] = 1e-10 curvecheck_params['time_units'] = 'milliseconds' curvecheck_params['curves'] = [['velocity', 'source']] +# Integrated Test Docs End Parameters +# Integrated Test Docs Begin Test Loop partitions = ((1, 1, 1), (2, 2, 2), (3, 3, 3)) decks = [ @@ -25,3 +27,4 @@ decks = [ ] generate_geos_tests(decks) +# Integrated Test Docs End Test Loop \ No newline at end of file diff --git a/inputFiles/solidMechanics/sedov_base.xml b/inputFiles/solidMechanics/sedov_base.xml index 49419832a75..fef292ad48d 100644 --- a/inputFiles/solidMechanics/sedov_base.xml +++ b/inputFiles/solidMechanics/sedov_base.xml @@ -12,7 +12,7 @@ diff --git a/inputFiles/solidMechanics/solidMechBlock.xml b/inputFiles/solidMechanics/solidMechBlock.xml index d3daec92f13..0aaf2aa0255 100644 --- a/inputFiles/solidMechanics/solidMechBlock.xml +++ b/inputFiles/solidMechanics/solidMechBlock.xml @@ -67,7 +67,7 @@ diff --git a/inputFiles/solidMechanics/viscoExtendedDruckerPrager_relaxation_base.xml b/inputFiles/solidMechanics/viscoExtendedDruckerPrager_relaxation_base.xml index 0afc57f9faa..c2e2dbf4da0 100644 --- a/inputFiles/solidMechanics/viscoExtendedDruckerPrager_relaxation_base.xml +++ b/inputFiles/solidMechanics/viscoExtendedDruckerPrager_relaxation_base.xml @@ -38,7 +38,7 @@ @@ -155,7 +155,7 @@ + cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, + cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1 }"/> diff --git a/inputFiles/solidMechanics/viscoExtendedDruckerPrager_relaxation_smoke.xml b/inputFiles/solidMechanics/viscoExtendedDruckerPrager_relaxation_smoke.xml index 0d50bd21c23..172adadc4f4 100644 --- a/inputFiles/solidMechanics/viscoExtendedDruckerPrager_relaxation_smoke.xml +++ b/inputFiles/solidMechanics/viscoExtendedDruckerPrager_relaxation_smoke.xml @@ -15,7 +15,8 @@ nx="{ 1, 1 }" ny="{ 1, 1 }" nz="{ 1, 1 }" - cellBlockNames="{ cb1, cb2, cb3, cb4, cb5, cb6, cb7, cb8 }"/> + cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, + cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1 }"/> + + + + + 0 1 2 + 3 4 5 + 6 7 8 + 9 10 11 + 12 13 14 + 15 16 17 + 18 19 20 + 21 22 23 + 24 25 26 + + + + + 0 1 2 3 4 5 6 7 + + + 3 3 3 3 3 3 + 3 3 3 3 3 3 + + + + + -1 -1 -1 + 0 -1 -1 + 1 -1 -1 + -1 0 -1 + 0 0 -1 + 1 0 -1 + -1 1 -1 + 0 1 -1 + 1 1 -1 + -1 -1 0 + 0 -1 0 + 1 -1 0 + -1 0 0 + 0 0 0 + 1 0 0 + -1 1 0 + 0 1 0 + 1 1 0 + -1 -1 1 + 0 -1 1 + 1 -1 1 + -1 0 1 + 0 0 1 + 1 0 1 + -1 1 1 + 0 1 1 + 1 1 1 + + + + + 0 1 4 3 9 10 13 12 + 1 2 5 4 10 11 14 13 + 3 4 7 6 12 13 16 15 + 4 5 8 7 13 14 17 16 + 9 10 13 12 18 19 22 21 + 10 11 14 13 19 20 23 22 + 12 13 16 15 21 22 25 24 + 13 14 17 16 22 23 26 25 + + + 8 + 16 + 24 + 32 + 40 + 48 + 56 + 64 + + + 12 12 12 12 12 12 12 12 + + + + + diff --git a/inputFiles/surfaceGeneration/cube_8.xml b/inputFiles/surfaceGeneration/cube_8.xml new file mode 100644 index 00000000000..2f002bb34b9 --- /dev/null +++ b/inputFiles/surfaceGeneration/cube_8.xml @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/thermalMultiphaseFlow/co2_thermal_2d.xml b/inputFiles/thermalMultiphaseFlow/co2_thermal_2d.xml index 19b770ede18..08d3522cbaf 100644 --- a/inputFiles/thermalMultiphaseFlow/co2_thermal_2d.xml +++ b/inputFiles/thermalMultiphaseFlow/co2_thermal_2d.xml @@ -83,7 +83,7 @@ @@ -104,7 +104,7 @@ compressibility="1.0e-9"/> diff --git a/inputFiles/thermalMultiphaseFlow/thermalMultiphaseFlow.ats b/inputFiles/thermalMultiphaseFlow/thermalMultiphaseFlow.ats index 63f0a1eb79e..ea6193427d9 100644 --- a/inputFiles/thermalMultiphaseFlow/thermalMultiphaseFlow.ats +++ b/inputFiles/thermalMultiphaseFlow/thermalMultiphaseFlow.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params['atol'] = 1e-06 diff --git a/inputFiles/thermalSinglePhaseFlowFractures/egsCollab_thermalFlow/egsCollab_thermalFlow_base.xml b/inputFiles/thermalSinglePhaseFlowFractures/egsCollab_thermalFlow/egsCollab_thermalFlow_base.xml index afba24559c9..4f238dee779 100644 --- a/inputFiles/thermalSinglePhaseFlowFractures/egsCollab_thermalFlow/egsCollab_thermalFlow_base.xml +++ b/inputFiles/thermalSinglePhaseFlowFractures/egsCollab_thermalFlow/egsCollab_thermalFlow_base.xml @@ -60,9 +60,9 @@ specificHeatCapacity="4.2e6" referenceInternalEnergy="0.99"/> - + defaultThermalConductivityComponents="{ 3.81, 3.81, 3.81 }"/> diff --git a/inputFiles/thermalSinglePhaseFlowFractures/egsCollab_thermalFlow/egsCollab_thermalFlow_initialCond_base.xml b/inputFiles/thermalSinglePhaseFlowFractures/egsCollab_thermalFlow/egsCollab_thermalFlow_initialCond_base.xml index 0ec3e35393b..e0d4cb7f585 100644 --- a/inputFiles/thermalSinglePhaseFlowFractures/egsCollab_thermalFlow/egsCollab_thermalFlow_initialCond_base.xml +++ b/inputFiles/thermalSinglePhaseFlowFractures/egsCollab_thermalFlow/egsCollab_thermalFlow_initialCond_base.xml @@ -10,7 +10,7 @@ @@ -49,7 +49,7 @@ @@ -73,9 +73,9 @@ name="rockPerm" permeabilityComponents="{ 4.0e-9, 4.0e-9, 4.0e-9 }"/> - + defaultThermalConductivityComponents="{ 836, 836, 836 }"/> diff --git a/inputFiles/thermoPoromechanics/ThermoPoroElastic_staircase_co2_smoke.xml b/inputFiles/thermoPoromechanics/ThermoPoroElastic_staircase_co2_smoke.xml index 97101133740..da964fb4008 100644 --- a/inputFiles/thermoPoromechanics/ThermoPoroElastic_staircase_co2_smoke.xml +++ b/inputFiles/thermoPoromechanics/ThermoPoroElastic_staircase_co2_smoke.xml @@ -49,7 +49,10 @@ nx="{ 3, 3 }" ny="{ 3, 3 }" nz="{ 2, 2, 2, 2 }" - cellBlockNames="{ b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11, b12, b13, b14, b15 }"/> + cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, + cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1, + cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2, + cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }"/> @@ -73,23 +76,21 @@ target="/Outputs/vtkOutput"/> + target="/Tasks/multiphasePoroelasticityEquilibrationStep"/> + - - - - - - @@ -171,7 +161,7 @@ permeabilityComponents="{ 9.8e-13, 9.8e-13, 9.8e-13 }"/> @@ -192,13 +182,13 @@ permeabilityComponents="{ 9.8e-16, 9.8e-16, 9.8e-16 }"/> @@ -335,16 +325,9 @@ - - - + diff --git a/inputFiles/thermoPoromechanics/ThermoPoroExtendedDruckerPrager_consolidation_smoke.xml b/inputFiles/thermoPoromechanics/ThermoPoroExtendedDruckerPrager_consolidation_smoke.xml new file mode 100644 index 00000000000..f45d88ffb3e --- /dev/null +++ b/inputFiles/thermoPoromechanics/ThermoPoroExtendedDruckerPrager_consolidation_smoke.xml @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/thermoPoromechanics/ThermoPoroMCC_consolidation_smoke.xml b/inputFiles/thermoPoromechanics/ThermoPoroMCC_consolidation_smoke.xml new file mode 100644 index 00000000000..d3151c11cfd --- /dev/null +++ b/inputFiles/thermoPoromechanics/ThermoPoroMCC_consolidation_smoke.xml @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/thermoPoromechanics/ThermoPoroPlastic_consolidation_base.xml b/inputFiles/thermoPoromechanics/ThermoPoroPlastic_consolidation_base.xml new file mode 100644 index 00000000000..950f7158f7e --- /dev/null +++ b/inputFiles/thermoPoromechanics/ThermoPoroPlastic_consolidation_base.xml @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/thermoPoromechanics/thermoPoromechanics.ats b/inputFiles/thermoPoromechanics/thermoPoromechanics.ats index 561fe62ba25..81b0072a4e8 100644 --- a/inputFiles/thermoPoromechanics/thermoPoromechanics.ats +++ b/inputFiles/thermoPoromechanics/thermoPoromechanics.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {'atol': 1e-06, 'rtol': 4e-06} @@ -26,6 +24,30 @@ decks = [ partitions=((1, 1, 1), (2, 2, 1)), restart_step=22, check_step=33, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="ThermoPoroDruckerPrager_consolidation_smoke", + description= + '1D thermo poro consolidation problem with Drucker Prager model', + partitions=((1, 1, 1), (1, 2, 1)), + restart_step=633, + check_step=683, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="ThermoPoroExtendedDruckerPrager_consolidation_smoke", + description= + '1D thermo poro consolidation problem with Extended Drucker Prager model', + partitions=((1, 1, 1), (1, 2, 1)), + restart_step=633, + check_step=683, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="ThermoPoroMCC_consolidation_smoke", + description= + '1D thermo poro consolidation problem with Modified Cam-Clay model', + partitions=((1, 1, 1), (1, 2, 1)), + restart_step=633, + check_step=683, restartcheck_params=RestartcheckParameters(**restartcheck_params)) ] diff --git a/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_base.xml b/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_base.xml index dd727469509..fc20919e014 100644 --- a/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_base.xml +++ b/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_base.xml @@ -31,19 +31,19 @@ specificHeatCapacity="1.672e2" referenceInternalEnergy="0.001"/> - + defaultThermalConductivityComponents="{ 1, 1, 1 }"/> + name="fractureContact"/> + + diff --git a/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_conforming_base.xml b/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_conforming_base.xml index e8ca36eaade..e32a27879d0 100644 --- a/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_conforming_base.xml +++ b/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_conforming_base.xml @@ -69,12 +69,12 @@ diff --git a/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_efem-edfm_base.xml b/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_efem-edfm_base.xml index 3d8cf3e4a03..5c6d88eb665 100644 --- a/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_efem-edfm_base.xml +++ b/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_efem-edfm_base.xml @@ -29,7 +29,8 @@ name="fractureMechSolver" targetRegions="{ RockMatrix, Fracture }" timeIntegrationOption="QuasiStatic" - discretization="FE1"/> + discretization="FE1" + contactPenaltyStiffness="4.0e9"/> diff --git a/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_efem-edfm_eggModel_small.xml b/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_efem-edfm_eggModel_small.xml index 3f721fd6264..ebf90ee493d 100644 --- a/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_efem-edfm_eggModel_small.xml +++ b/inputFiles/thermoPoromechanicsFractures/ThermoPoroElastic_efem-edfm_eggModel_small.xml @@ -27,7 +27,8 @@ name="fractureMechSolver" targetRegions="{ Reservoir, Overburden, Underburden, Sideburden, Fracture }" timeIntegrationOption="QuasiStatic" - discretization="FE1"> + discretization="FE1" + contactPenaltyStiffness="0.0e8"> + fieldNamesInGEOS="{ rockPermeability_permeability }"/> @@ -219,7 +220,7 @@ @@ -235,13 +236,13 @@ specificHeatCapacity="1.672e2" referenceInternalEnergy="0.001"/> - + defaultThermalConductivityComponents="{ 10, 10, 10 }"/> + name="fractureContact"/> + + diff --git a/inputFiles/thermoPoromechanicsFractures/thermoPoromechanicsFractures.ats b/inputFiles/thermoPoromechanicsFractures/thermoPoromechanicsFractures.ats index cca95c6e68e..a00790e4bf4 100644 --- a/inputFiles/thermoPoromechanicsFractures/thermoPoromechanicsFractures.ats +++ b/inputFiles/thermoPoromechanicsFractures/thermoPoromechanicsFractures.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {'atol': 1e-06, 'rtol': 4e-06} diff --git a/inputFiles/triaxialDriver/triaxialDriver_ExtendedDruckerPrager_basicExample.xml b/inputFiles/triaxialDriver/triaxialDriver_ExtendedDruckerPrager_basicExample.xml index 026648d2529..0cdb00d6354 100755 --- a/inputFiles/triaxialDriver/triaxialDriver_ExtendedDruckerPrager_basicExample.xml +++ b/inputFiles/triaxialDriver/triaxialDriver_ExtendedDruckerPrager_basicExample.xml @@ -73,7 +73,7 @@ diff --git a/inputFiles/triaxialDriver/triaxialDriver_base.xml b/inputFiles/triaxialDriver/triaxialDriver_base.xml index 3fb0f62fe84..efd380e39d5 100644 --- a/inputFiles/triaxialDriver/triaxialDriver_base.xml +++ b/inputFiles/triaxialDriver/triaxialDriver_base.xml @@ -139,7 +139,7 @@ diff --git a/inputFiles/wavePropagation/AcousticElasticSEM.ats b/inputFiles/wavePropagation/AcousticElasticSEM.ats index 642390f5b7d..0af4b2a90a2 100644 --- a/inputFiles/wavePropagation/AcousticElasticSEM.ats +++ b/inputFiles/wavePropagation/AcousticElasticSEM.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params['atol'] = 0.0001 diff --git a/inputFiles/wavePropagation/AcousticFirstOrderSEM.ats b/inputFiles/wavePropagation/AcousticFirstOrderSEM.ats index 4eafac6e6bb..3e825f697c7 100644 --- a/inputFiles/wavePropagation/AcousticFirstOrderSEM.ats +++ b/inputFiles/wavePropagation/AcousticFirstOrderSEM.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params['atol'] = 0.0001 diff --git a/inputFiles/wavePropagation/AcousticSEM.ats b/inputFiles/wavePropagation/AcousticSEM.ats index 006d7958153..0aceac62888 100644 --- a/inputFiles/wavePropagation/AcousticSEM.ats +++ b/inputFiles/wavePropagation/AcousticSEM.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params['atol'] = 0.0001 @@ -52,6 +50,14 @@ decks = [ partitions=((1, 1, 1), (2, 2, 2)), restart_step=100, check_step=200, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="acous3D_Q1_srcTable_dtCFL_smoke", + description= + 'Acoustic wave solver, first-order FE, source tables and automatic CFL limit', + partitions=((1, 1, 1), (2, 2, 2)), + restart_step=100, + check_step=200, restartcheck_params=RestartcheckParameters(**restartcheck_params)) ] diff --git a/inputFiles/wavePropagation/ElasticFirstOrderSEM.ats b/inputFiles/wavePropagation/ElasticFirstOrderSEM.ats index dfad33d399f..4f94cbb5a91 100644 --- a/inputFiles/wavePropagation/ElasticFirstOrderSEM.ats +++ b/inputFiles/wavePropagation/ElasticFirstOrderSEM.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params['atol'] = 0.0001 diff --git a/inputFiles/wavePropagation/ElasticSEM.ats b/inputFiles/wavePropagation/ElasticSEM.ats index 7ea1adb9713..363da183eee 100644 --- a/inputFiles/wavePropagation/ElasticSEM.ats +++ b/inputFiles/wavePropagation/ElasticSEM.ats @@ -1,6 +1,4 @@ -import os -import geos_ats -from geos_ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests restartcheck_params = {} restartcheck_params['atol'] = 0.0001 @@ -36,6 +34,22 @@ decks = [ partitions=((1, 1, 1), (2, 2, 2)), restart_step=100, check_step=200, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="elas3D_att_smoke", + description= + 'Elastic wave solver, first-order FE, with SLS attenuation mechanism', + partitions=((1, 1, 1), (2, 2, 2)), + restart_step=100, + check_step=200, + restartcheck_params=RestartcheckParameters(**restartcheck_params)), + TestDeck( + name="elas3D_DAS_smoke", + description= + 'Elastic wave solver, first-order FE, DAS signal', + partitions=((1, 1, 1), (2, 2, 2)), + restart_step=100, + check_step=200, restartcheck_params=RestartcheckParameters(**restartcheck_params)) ] diff --git a/inputFiles/wavePropagation/ElasticVTISEM.ats b/inputFiles/wavePropagation/ElasticVTISEM.ats new file mode 100644 index 00000000000..ebecafe2783 --- /dev/null +++ b/inputFiles/wavePropagation/ElasticVTISEM.ats @@ -0,0 +1,18 @@ +import os +from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests + +restartcheck_params = {} +restartcheck_params['atol'] = 0.0001 +restartcheck_params['rtol'] = 2e-05 + +decks = [ + TestDeck( + name="elas3D_vti_abc_smoke", + description='Elastic VTI wave solver, first-order FE, absorbing BC', + partitions=((1, 1, 1), (2, 2, 2)), + restart_step=100, + check_step=200, + restartcheck_params=RestartcheckParameters(**restartcheck_params)) +] + +generate_geos_tests(decks) diff --git a/inputFiles/wavePropagation/acous3D_Q1_srcTable_dtCFL_smoke.xml b/inputFiles/wavePropagation/acous3D_Q1_srcTable_dtCFL_smoke.xml new file mode 100755 index 00000000000..81b503d592f --- /dev/null +++ b/inputFiles/wavePropagation/acous3D_Q1_srcTable_dtCFL_smoke.xml @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wavePropagation/acous3D_Q3_firstOrder_small_base.xml b/inputFiles/wavePropagation/acous3D_Q3_firstOrder_small_base.xml index cb071a26703..e68f1e00460 100644 --- a/inputFiles/wavePropagation/acous3D_Q3_firstOrder_small_base.xml +++ b/inputFiles/wavePropagation/acous3D_Q3_firstOrder_small_base.xml @@ -32,7 +32,7 @@ diff --git a/inputFiles/wavePropagation/acous3D_Q3_small_base.xml b/inputFiles/wavePropagation/acous3D_Q3_small_base.xml index 26f0631f8fa..ee89af2f316 100644 --- a/inputFiles/wavePropagation/acous3D_Q3_small_base.xml +++ b/inputFiles/wavePropagation/acous3D_Q3_small_base.xml @@ -31,7 +31,7 @@ diff --git a/inputFiles/wavePropagation/acous3D_Q5_firstOrder_small_base.xml b/inputFiles/wavePropagation/acous3D_Q5_firstOrder_small_base.xml index 32018f54c95..4fd8f1f781e 100644 --- a/inputFiles/wavePropagation/acous3D_Q5_firstOrder_small_base.xml +++ b/inputFiles/wavePropagation/acous3D_Q5_firstOrder_small_base.xml @@ -32,7 +32,7 @@ diff --git a/inputFiles/wavePropagation/acous3D_Q5_small_base.xml b/inputFiles/wavePropagation/acous3D_Q5_small_base.xml index 0ad60b621bf..f6a8afffb11 100644 --- a/inputFiles/wavePropagation/acous3D_Q5_small_base.xml +++ b/inputFiles/wavePropagation/acous3D_Q5_small_base.xml @@ -31,7 +31,7 @@ diff --git a/inputFiles/wavePropagation/acous3D_firstOrder_small_base.xml b/inputFiles/wavePropagation/acous3D_firstOrder_small_base.xml index 90e96ffc053..8bfdbe6f218 100644 --- a/inputFiles/wavePropagation/acous3D_firstOrder_small_base.xml +++ b/inputFiles/wavePropagation/acous3D_firstOrder_small_base.xml @@ -32,7 +32,7 @@ diff --git a/inputFiles/wavePropagation/acous3D_pml_smoke.xml b/inputFiles/wavePropagation/acous3D_pml_smoke.xml index 7e2b978d31d..3a1e3db0f47 100644 --- a/inputFiles/wavePropagation/acous3D_pml_smoke.xml +++ b/inputFiles/wavePropagation/acous3D_pml_smoke.xml @@ -31,15 +31,15 @@ nx="{ 1, 3, 1}" ny="{ 1, 3, 1}" nz="{ 1, 3, 1}" - cellBlockNames="{ pmlLeftFrontBottom, pmlLeftFrontMid, pmlLeftFrontTop, - pmlLeftMidBottom, pmlLeftMidMid, pmlLeftMidTop, - pmlLeftBackBottom, pmlLeftBackMid, pmlLeftBackTop, - pmlMidFrontBottom, pmlMidFrontMid, pmlMidFrontTop, - pmlMidMidBottom, interiorMidMidMid, pmlMidMidTop, - pmlMidBackBottom, pmlMidBackMid, pmlMidBackTop, - pmlRightFrontBottom, pmlRightFrontMid, pmlRightFrontTop, - pmlRightMidBottom, pmlRightMidMid, pmlRightMidTop, - pmlRightBackBottom, pmlRightBackMid, pmlRightBackTop }"/> + cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-2_0_0, + cb-0_1_0, cb-1_1_0, cb-2_1_0, + cb-0_2_0, cb-1_2_0, cb-2_2_0, + cb-0_0_1, cb-1_0_1, cb-2_0_1, + cb-0_1_1, cb-1_1_1, cb-2_1_1, + cb-0_2_1, cb-1_2_1, cb-2_2_1, + cb-0_0_2, cb-1_0_2, cb-2_0_2, + cb-0_1_2, cb-1_1_2, cb-2_1_2, + cb-0_2_2, cb-1_2_2, cb-2_2_2 }"/> @@ -115,20 +115,20 @@ diff --git a/inputFiles/wavePropagation/acous3D_small_base.xml b/inputFiles/wavePropagation/acous3D_small_base.xml index 694ced3e1e0..7a57de721cf 100644 --- a/inputFiles/wavePropagation/acous3D_small_base.xml +++ b/inputFiles/wavePropagation/acous3D_small_base.xml @@ -31,7 +31,7 @@ diff --git a/inputFiles/wavePropagation/acous3D_vti_smoke.xml b/inputFiles/wavePropagation/acous3D_vti_smoke.xml index ef9127fe278..4305ac12319 100644 --- a/inputFiles/wavePropagation/acous3D_vti_smoke.xml +++ b/inputFiles/wavePropagation/acous3D_vti_smoke.xml @@ -114,7 +114,7 @@ diff --git a/inputFiles/wavePropagation/benchmarks/acous3D_benchmark_base.xml b/inputFiles/wavePropagation/benchmarks/acous3D_benchmark_base.xml index d8a475ea54f..15372829ea5 100644 --- a/inputFiles/wavePropagation/benchmarks/acous3D_benchmark_base.xml +++ b/inputFiles/wavePropagation/benchmarks/acous3D_benchmark_base.xml @@ -69,7 +69,7 @@ diff --git a/inputFiles/wavePropagation/benchmarks/acouselas3D.xml b/inputFiles/wavePropagation/benchmarks/acouselas3D.xml deleted file mode 100644 index 7ee7cc3e86e..00000000000 --- a/inputFiles/wavePropagation/benchmarks/acouselas3D.xml +++ /dev/null @@ -1,215 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/inputFiles/wavePropagation/benchmarks/acouselas3D_komatitsch_base.xml b/inputFiles/wavePropagation/benchmarks/acouselas3D_komatitsch_base.xml new file mode 100644 index 00000000000..80fe7332730 --- /dev/null +++ b/inputFiles/wavePropagation/benchmarks/acouselas3D_komatitsch_base.xml @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wavePropagation/benchmarks/acouselas3D_komatitsch_flu.xml b/inputFiles/wavePropagation/benchmarks/acouselas3D_komatitsch_flu.xml new file mode 100644 index 00000000000..a1367ef4128 --- /dev/null +++ b/inputFiles/wavePropagation/benchmarks/acouselas3D_komatitsch_flu.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + diff --git a/inputFiles/wavePropagation/benchmarks/acouselas3D_komatitsch_sol.xml b/inputFiles/wavePropagation/benchmarks/acouselas3D_komatitsch_sol.xml new file mode 100644 index 00000000000..5a4e3ff62ee --- /dev/null +++ b/inputFiles/wavePropagation/benchmarks/acouselas3D_komatitsch_sol.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + diff --git a/inputFiles/wavePropagation/benchmarks/acouselas3D_layers_aea.xml b/inputFiles/wavePropagation/benchmarks/acouselas3D_layers_aea.xml new file mode 100644 index 00000000000..141cf84d7a6 --- /dev/null +++ b/inputFiles/wavePropagation/benchmarks/acouselas3D_layers_aea.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wavePropagation/benchmarks/acouselas3D_layers_base.xml b/inputFiles/wavePropagation/benchmarks/acouselas3D_layers_base.xml new file mode 100644 index 00000000000..83922fb1c8c --- /dev/null +++ b/inputFiles/wavePropagation/benchmarks/acouselas3D_layers_base.xml @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wavePropagation/benchmarks/acouselas3D_layers_eae.xml b/inputFiles/wavePropagation/benchmarks/acouselas3D_layers_eae.xml new file mode 100644 index 00000000000..e75b0cb0c93 --- /dev/null +++ b/inputFiles/wavePropagation/benchmarks/acouselas3D_layers_eae.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wavePropagation/benchmarks/elas3D_benchmark_base.xml b/inputFiles/wavePropagation/benchmarks/elas3D_benchmark_base.xml index fc3b967238b..aacd50aca96 100644 --- a/inputFiles/wavePropagation/benchmarks/elas3D_benchmark_base.xml +++ b/inputFiles/wavePropagation/benchmarks/elas3D_benchmark_base.xml @@ -98,7 +98,7 @@ @@ -241,4 +241,3 @@ - diff --git a/inputFiles/wavePropagation/elas3D_DAS_smoke.xml b/inputFiles/wavePropagation/elas3D_DAS_smoke.xml index 916d9a8fc38..cac61db881f 100644 --- a/inputFiles/wavePropagation/elas3D_DAS_smoke.xml +++ b/inputFiles/wavePropagation/elas3D_DAS_smoke.xml @@ -72,7 +72,7 @@ diff --git a/inputFiles/wavePropagation/elas3D_Q3_firstOrder_small_base.xml b/inputFiles/wavePropagation/elas3D_Q3_firstOrder_small_base.xml index 9c833d44be1..aacb0be1d1b 100644 --- a/inputFiles/wavePropagation/elas3D_Q3_firstOrder_small_base.xml +++ b/inputFiles/wavePropagation/elas3D_Q3_firstOrder_small_base.xml @@ -32,7 +32,7 @@ diff --git a/inputFiles/wavePropagation/elas3D_Q3_small_base.xml b/inputFiles/wavePropagation/elas3D_Q3_small_base.xml index c8e1063beb9..13d6a186dbf 100644 --- a/inputFiles/wavePropagation/elas3D_Q3_small_base.xml +++ b/inputFiles/wavePropagation/elas3D_Q3_small_base.xml @@ -81,7 +81,7 @@ diff --git a/inputFiles/wavePropagation/elas3D_Q5_firstOrder_small_base.xml b/inputFiles/wavePropagation/elas3D_Q5_firstOrder_small_base.xml index b360569bb0e..0ce1207ed0b 100644 --- a/inputFiles/wavePropagation/elas3D_Q5_firstOrder_small_base.xml +++ b/inputFiles/wavePropagation/elas3D_Q5_firstOrder_small_base.xml @@ -32,7 +32,7 @@ diff --git a/inputFiles/wavePropagation/elas3D_Q5_small_base.xml b/inputFiles/wavePropagation/elas3D_Q5_small_base.xml index 67e137325f8..0afb065f3c3 100644 --- a/inputFiles/wavePropagation/elas3D_Q5_small_base.xml +++ b/inputFiles/wavePropagation/elas3D_Q5_small_base.xml @@ -81,7 +81,7 @@ diff --git a/inputFiles/wavePropagation/elas3D_att_smoke.xml b/inputFiles/wavePropagation/elas3D_att_smoke.xml new file mode 100644 index 00000000000..86e331399f9 --- /dev/null +++ b/inputFiles/wavePropagation/elas3D_att_smoke.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wavePropagation/elas3D_firstOrder_small_base.xml b/inputFiles/wavePropagation/elas3D_firstOrder_small_base.xml index 7c3fa5783a6..565d48b0115 100644 --- a/inputFiles/wavePropagation/elas3D_firstOrder_small_base.xml +++ b/inputFiles/wavePropagation/elas3D_firstOrder_small_base.xml @@ -32,7 +32,7 @@ diff --git a/inputFiles/wavePropagation/elas3D_small_base.xml b/inputFiles/wavePropagation/elas3D_small_base.xml index 2f79d894055..3233345e59a 100644 --- a/inputFiles/wavePropagation/elas3D_small_base.xml +++ b/inputFiles/wavePropagation/elas3D_small_base.xml @@ -88,7 +88,7 @@ diff --git a/inputFiles/wavePropagation/elas3D_vti_abc_smoke.xml b/inputFiles/wavePropagation/elas3D_vti_abc_smoke.xml new file mode 100644 index 00000000000..fdee7d173f5 --- /dev/null +++ b/inputFiles/wavePropagation/elas3D_vti_abc_smoke.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + diff --git a/inputFiles/wavePropagation/elas3D_vti_small_base.xml b/inputFiles/wavePropagation/elas3D_vti_small_base.xml new file mode 100644 index 00000000000..c4cd9bb5af5 --- /dev/null +++ b/inputFiles/wavePropagation/elas3D_vti_small_base.xml @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wavePropagation/source1.txt b/inputFiles/wavePropagation/source1.txt new file mode 100644 index 00000000000..511fd3179f0 --- /dev/null +++ b/inputFiles/wavePropagation/source1.txt @@ -0,0 +1,1501 @@ +3.72008e-44 +1.0087e-43 +2.72143e-43 +7.30573e-43 +1.95145e-42 +5.18658e-42 +1.37161e-41 +3.60921e-41 +9.44975e-41 +2.46183e-40 +6.3815e-40 +1.64595e-39 +4.22415e-39 +1.07868e-38 +2.74076e-38 +6.92912e-38 +1.74307e-37 +4.36295e-37 +1.08661e-36 +2.69275e-36 +6.63968e-36 +1.62902e-35 +3.9768e-35 +9.65985e-35 +2.33472e-34 +5.61473e-34 +1.34354e-33 +3.1989e-33 +7.57845e-33 +1.78644e-32 +4.19009e-32 +9.77886e-32 +2.27081e-31 +5.2469e-31 +1.20629e-30 +2.75951e-30 +6.28115e-30 +1.42257e-29 +3.20582e-29 +7.18839e-29 +1.60381e-28 +3.56043e-28 +7.86469e-28 +1.72858e-27 +3.78028e-27 +8.22598e-27 +1.78107e-26 +3.83708e-26 +8.22528e-26 +1.7544e-25 +3.72336e-25 +7.86268e-25 +1.65209e-24 +3.45403e-24 +7.18534e-24 +1.48729e-23 +3.06319e-23 +6.27741e-23 +1.28002e-22 +2.59704e-22 +5.24289e-22 +1.05315e-21 +2.10494e-21 +4.18617e-21 +8.28368e-21 +1.63101e-20 +3.19537e-20 +6.22891e-20 +1.20818e-19 +2.33174e-19 +4.47773e-19 +8.55586e-19 +1.62666e-18 +3.07724e-18 +5.79231e-18 +1.08486e-17 +2.02172e-17 +3.74884e-17 +6.91675e-17 +1.2698e-16 +2.31952e-16 +4.21589e-16 +7.62446e-16 +1.37201e-15 +2.4566e-15 +4.37662e-15 +7.7584e-15 +1.36847e-14 +2.40173e-14 +4.19415e-14 +7.28772e-14 +1.25999e-13 +2.16757e-13 +3.71028e-13 +6.31929e-13 +1.07092e-12 +1.80583e-12 +3.02987e-12 +5.05825e-12 +8.40243e-12 +1.38879e-11 +2.28402e-11 +3.73757e-11 +6.08567e-11 +9.85951e-11 +1.58939e-10 +2.54938e-10 +4.06881e-10 +6.46143e-10 +1.02098e-09 +1.60523e-09 +2.51121e-09 +3.90894e-09 +6.05428e-09 +9.33029e-09 +1.43072e-08 +2.18296e-08 +3.31408e-08 +5.00622e-08 +7.52462e-08 +1.12535e-07 +1.67464e-07 +2.4796e-07 +3.65317e-07 +5.35535e-07 +7.81149e-07 +1.13373e-06 +1.63724e-06 +2.35258e-06 +3.3636e-06 +4.78512e-06 +6.77345e-06 +9.54016e-06 +1.337e-05 +1.86437e-05 +2.58681e-05 +3.57128e-05 +4.90584e-05 +6.70548e-05 +9.1196e-05 +0.00012341 +0.00016617 +0.00022263 +0.000296786 +0.000393669 +0.000519575 +0.000682328 +0.000891594 +0.00115923 +0.00149969 +0.00193045 +0.00247256 +0.00315111 +0.00399585 +0.00504176 +0.00632972 +0.00790705 +0.00982819 +0.0121552 +0.0149581 +0.0183156 +0.0223149 +0.0270518 +0.0326308 +0.0391639 +0.0467706 +0.0555762 +0.0657103 +0.0773047 +0.0904914 +0.105399 +0.122151 +0.140858 +0.161621 +0.18452 +0.209611 +0.236928 +0.266468 +0.298197 +0.33204 +0.367879 +0.405555 +0.444858 +0.485537 +0.527292 +0.569783 +0.612626 +0.655406 +0.697676 +0.738968 +0.778801 +0.816686 +0.852144 +0.884706 +0.913931 +0.939413 +0.960789 +0.977751 +0.99005 +0.997503 +1 +0.997503 +0.99005 +0.977751 +0.960789 +0.939413 +0.913931 +0.884706 +0.852144 +0.816686 +0.778801 +0.738968 +0.697676 +0.655406 +0.612626 +0.569783 +0.527292 +0.485537 +0.444858 +0.405555 +0.367879 +0.33204 +0.298197 +0.266468 +0.236928 +0.209611 +0.18452 +0.161621 +0.140858 +0.122151 +0.105399 +0.0904914 +0.0773047 +0.0657103 +0.0555762 +0.0467706 +0.0391639 +0.0326308 +0.0270518 +0.0223149 +0.0183156 +0.0149581 +0.0121552 +0.00982819 +0.00790705 +0.00632972 +0.00504176 +0.00399585 +0.00315111 +0.00247256 +0.00193045 +0.00149969 +0.00115923 +0.000891594 +0.000682328 +0.000519575 +0.000393669 +0.000296786 +0.00022263 +0.00016617 +0.00012341 +9.1196e-05 +6.70548e-05 +4.90584e-05 +3.57128e-05 +2.58681e-05 +1.86437e-05 +1.337e-05 +9.54016e-06 +6.77345e-06 +4.78512e-06 +3.3636e-06 +2.35258e-06 +1.63724e-06 +1.13373e-06 +7.81149e-07 +5.35535e-07 +3.65317e-07 +2.4796e-07 +1.67464e-07 +1.12535e-07 +7.52462e-08 +5.00622e-08 +3.31408e-08 +2.18296e-08 +1.43072e-08 +9.33029e-09 +6.05428e-09 +3.90894e-09 +2.51121e-09 +1.60523e-09 +1.02098e-09 +6.46143e-10 +4.06881e-10 +2.54938e-10 +1.58939e-10 +9.85951e-11 +6.08567e-11 +3.73757e-11 +2.28402e-11 +1.38879e-11 +8.40243e-12 +5.05825e-12 +3.02987e-12 +1.80583e-12 +1.07092e-12 +6.31929e-13 +3.71028e-13 +2.16757e-13 +1.25999e-13 +7.28772e-14 +4.19415e-14 +2.40173e-14 +1.36847e-14 +7.7584e-15 +4.37662e-15 +2.4566e-15 +1.37201e-15 +7.62446e-16 +4.21589e-16 +2.31952e-16 +1.2698e-16 +6.91675e-17 +3.74884e-17 +2.02172e-17 +1.08486e-17 +5.79231e-18 +3.07724e-18 +1.62666e-18 +8.55586e-19 +4.47773e-19 +2.33174e-19 +1.20818e-19 +6.22891e-20 +3.19537e-20 +1.63101e-20 +8.28368e-21 +4.18617e-21 +2.10494e-21 +1.05315e-21 +5.24289e-22 +2.59704e-22 +1.28002e-22 +6.27741e-23 +3.06319e-23 +1.48729e-23 +7.18534e-24 +3.45403e-24 +1.65209e-24 +7.86268e-25 +3.72336e-25 +1.7544e-25 +8.22528e-26 +3.83708e-26 +1.78107e-26 +8.22598e-27 +3.78028e-27 +1.72858e-27 +7.86469e-28 +3.56043e-28 +1.60381e-28 +7.18839e-29 +3.20582e-29 +1.42257e-29 +6.28115e-30 +2.75951e-30 +1.20629e-30 +5.2469e-31 +2.27081e-31 +9.77886e-32 +4.19009e-32 +1.78644e-32 +7.57845e-33 +3.1989e-33 +1.34354e-33 +5.61473e-34 +2.33472e-34 +9.65985e-35 +3.9768e-35 +1.62902e-35 +6.63968e-36 +2.69275e-36 +1.08661e-36 +4.36295e-37 +1.74307e-37 +6.92912e-38 +2.74076e-38 +1.07868e-38 +4.22415e-39 +1.64595e-39 +6.3815e-40 +2.46183e-40 +9.44975e-41 +3.60921e-41 +1.37161e-41 +5.18658e-42 +1.95145e-42 +7.30573e-43 +2.72143e-43 +1.0087e-43 +3.72008e-44 +1.36512e-44 +4.98448e-45 +1.81091e-45 +6.54639e-46 +2.3547e-46 +8.42749e-47 +3.00116e-47 +1.06343e-47 +3.74936e-48 +1.31533e-48 +4.59133e-49 +1.59467e-49 +5.51105e-50 +1.89507e-50 +6.48401e-51 +2.20745e-51 +7.4777e-52 +2.52042e-52 +8.4529e-53 +2.82077e-53 +9.36608e-54 +3.0944e-54 +1.01724e-54 +3.32736e-55 +1.08294e-55 +3.50701e-56 +1.13005e-56 +3.62317e-57 +1.15587e-57 +3.66906e-58 +1.15886e-58 +3.64195e-59 +1.13885e-59 +3.54347e-60 +1.09703e-60 +3.37937e-61 +1.03582e-61 +3.15906e-62 +9.58655e-63 +2.89464e-63 +8.69672e-64 +2.59983e-64 +7.73326e-65 +2.28881e-65 +6.74038e-66 +1.97509e-66 +5.75864e-67 +1.67063e-67 +4.82247e-68 +1.38512e-68 +3.95852e-69 +1.12566e-69 +3.18501e-70 +8.96691e-71 +2.51191e-71 +7.00152e-72 +1.94182e-72 +5.35865e-73 +1.4714e-73 +4.02006e-74 +1.09286e-74 +2.95613e-75 +7.95632e-76 +2.13074e-76 +5.67773e-77 +1.50539e-77 +3.97147e-78 +1.04252e-78 +2.72297e-79 +7.0767e-80 +1.82998e-80 +4.70861e-81 +1.2055e-81 +3.07092e-82 +7.78394e-83 +1.96317e-83 +4.92659e-84 +1.23016e-84 +3.05639e-85 +7.55582e-86 +1.85859e-86 +4.54898e-87 +1.10783e-87 +2.68448e-88 +6.47257e-89 +1.55282e-89 +3.70676e-90 +8.80433e-91 +2.08078e-91 +4.89311e-92 +1.14491e-92 +2.66556e-93 +6.17494e-94 +1.42333e-94 +3.26443e-95 +7.44966e-96 +1.69159e-96 +3.82192e-97 +8.59207e-98 +1.92195e-98 +4.27774e-99 +9.4736e-100 +2.08759e-100 +4.57723e-101 +9.98595e-102 +2.16773e-102 +4.68218e-103 +1.00628e-103 +2.1519e-104 +4.57879e-105 +9.69412e-106 +2.04218e-106 +4.28065e-107 +8.92798e-108 +1.85279e-108 +3.82583e-109 +7.86058e-110 +1.60699e-110 +3.26887e-111 +6.61626e-112 +1.33246e-112 +2.6701e-113 +5.32387e-114 +1.05622e-114 +2.08504e-115 +4.09543e-116 +8.00412e-117 +1.55653e-117 +3.01181e-118 +5.79866e-119 +1.11085e-119 +2.11745e-120 +4.01604e-121 +7.579e-122 +1.42316e-122 +2.65904e-123 +4.94339e-124 +9.14435e-125 +1.6831e-125 +3.08244e-126 +5.61705e-127 +1.01848e-127 +1.83747e-128 +3.29853e-129 +5.8918e-130 +1.04714e-130 +1.85178e-131 +3.25839e-132 +5.70485e-133 +9.93836e-134 +1.72272e-134 +2.97126e-135 +5.09914e-136 +8.70727e-137 +1.47943e-137 +2.50113e-138 +4.20733e-139 +7.04215e-140 +1.17282e-140 +1.94351e-141 +3.20459e-142 +5.25757e-143 +8.58274e-144 +1.39411e-144 +2.25317e-145 +3.62344e-146 +5.79797e-147 +9.23124e-148 +1.46242e-148 +2.30523e-149 +3.61562e-150 +5.64262e-151 +8.76209e-152 +1.35383e-152 +2.08136e-153 +3.18389e-154 +4.84617e-155 +7.33953e-156 +1.10603e-156 +1.65841e-157 +2.47427e-158 +3.67308e-159 +5.42553e-160 +7.97411e-161 +1.16614e-161 +1.69687e-162 +2.45683e-163 +3.53939e-164 +5.07355e-165 +7.23641e-166 +1.02698e-166 +1.45021e-167 +2.03765e-168 +2.84875e-169 +3.96286e-170 +5.48519e-171 +7.55444e-172 +1.03524e-172 +1.4116e-173 +1.91517e-174 +2.58543e-175 +3.47285e-176 +4.64161e-177 +6.17276e-178 +8.16806e-179 +1.07544e-179 +1.40891e-180 +1.83657e-181 +2.38211e-182 +3.07428e-183 +3.94779e-184 +5.04422e-185 +6.413e-186 +8.11255e-187 +1.02113e-187 +1.2789e-188 +1.59374e-189 +1.97618e-190 +2.43818e-191 +2.99318e-192 +3.65619e-193 +4.44379e-194 +5.37411e-195 +6.46678e-196 +7.7428e-197 +9.22437e-198 +1.09346e-198 +1.28973e-199 +1.51364e-200 +1.76757e-201 +2.05379e-202 +2.37447e-203 +2.73152e-204 +3.12659e-205 +3.56096e-206 +4.03544e-207 +4.55033e-208 +5.10533e-209 +5.69945e-210 +6.33098e-211 +6.99741e-212 +7.69542e-213 +8.42084e-214 +9.1687e-215 +9.93317e-216 +1.07077e-216 +1.14851e-217 +1.22575e-218 +1.30165e-219 +1.37537e-220 +1.44601e-221 +1.51269e-222 +1.57456e-223 +1.63078e-224 +1.68059e-225 +1.72328e-226 +1.75824e-227 +1.78497e-228 +1.80306e-229 +1.81225e-230 +1.81241e-231 +1.80352e-232 +1.78573e-233 +1.75929e-234 +1.7246e-235 +1.68217e-236 +1.63259e-237 +1.57657e-238 +1.51488e-239 +1.44835e-240 +1.37783e-241 +1.3042e-242 +1.22836e-243 +1.15115e-244 +1.07342e-245 +9.95941e-247 +9.19448e-248 +8.44596e-249 +7.71968e-250 +7.02067e-251 +6.3531e-252 +5.72034e-253 +5.12491e-254 +4.56856e-255 +4.0523e-256 +3.57644e-257 +3.14073e-258 +2.74434e-259 +2.38601e-260 +2.06413e-261 +1.77677e-262 +1.52178e-263 +1.29688e-264 +1.09971e-265 +9.27868e-267 +7.78972e-268 +6.50707e-269 +5.40852e-270 +4.473e-271 +3.68086e-272 +3.01389e-273 +2.45546e-274 +1.99053e-275 +1.60558e-276 +1.28862e-277 +1.02907e-278 +8.17701e-280 +6.46505e-281 +5.08602e-282 +3.98119e-283 +3.10082e-284 +2.40308e-285 +1.85306e-286 +1.4218e-287 +1.08546e-288 +8.24558e-290 +6.2324e-291 +4.68726e-292 +3.5076e-293 +2.61174e-294 +1.93499e-295 +1.42645e-296 +1.04631e-297 +7.63653e-299 +5.54573e-300 +4.00728e-301 +2.88117e-302 +2.06119e-303 +1.46722e-304 +1.0392e-305 +7.32376e-307 +5.13566e-308 +3.58333e-309 +2.48775e-310 +1.71852e-311 +1.18122e-312 +8.0786e-314 +5.49756e-315 +3.72248e-316 +2.50797e-317 +1.68129e-318 +1.12148e-319 +7.44557e-321 +4.89125e-322 +3.45846e-323 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/inputFiles/wavePropagation/source2.txt b/inputFiles/wavePropagation/source2.txt new file mode 100644 index 00000000000..0de4a75cb17 --- /dev/null +++ b/inputFiles/wavePropagation/source2.txt @@ -0,0 +1,1501 @@ +1.24003e-44 +3.36233e-44 +9.07143e-44 +2.43524e-43 +6.50483e-43 +1.72886e-42 +4.57203e-42 +1.20307e-41 +3.14992e-41 +8.2061e-41 +2.12717e-40 +5.4865e-40 +1.40805e-39 +3.5956e-39 +9.13587e-39 +2.30971e-38 +5.81023e-38 +1.45432e-37 +3.62203e-37 +8.97583e-37 +2.21323e-36 +5.43007e-36 +1.3256e-35 +3.21995e-35 +7.7824e-35 +1.87158e-34 +4.47847e-34 +1.0663e-33 +2.52615e-33 +5.9548e-33 +1.3967e-32 +3.25962e-32 +7.56937e-32 +1.74897e-31 +4.02097e-31 +9.19837e-31 +2.09372e-30 +4.7419e-30 +1.06861e-29 +2.39613e-29 +5.34603e-29 +1.18681e-28 +2.62156e-28 +5.76193e-28 +1.26009e-27 +2.74199e-27 +5.9369e-27 +1.27903e-26 +2.74176e-26 +5.848e-26 +1.24112e-25 +2.62089e-25 +5.50697e-25 +1.15134e-24 +2.39511e-24 +4.95763e-24 +1.02106e-23 +2.09247e-23 +4.26673e-23 +8.6568e-23 +1.74763e-22 +3.5105e-22 +7.01647e-22 +1.39539e-21 +2.76123e-21 +5.4367e-21 +1.06512e-20 +2.0763e-20 +4.02727e-20 +7.77247e-20 +1.49258e-19 +2.85195e-19 +5.4222e-19 +1.02575e-18 +1.93077e-18 +3.6162e-18 +6.73907e-18 +1.24961e-17 +2.30558e-17 +4.23267e-17 +7.73173e-17 +1.4053e-16 +2.54149e-16 +4.57337e-16 +8.18867e-16 +1.45887e-15 +2.58613e-15 +4.56157e-15 +8.00577e-15 +1.39805e-14 +2.42924e-14 +4.19997e-14 +7.22523e-14 +1.23676e-13 +2.10643e-13 +3.56973e-13 +6.01943e-13 +1.00996e-12 +1.68608e-12 +2.80081e-12 +4.6293e-12 +7.6134e-12 +1.24586e-11 +2.02856e-11 +3.2865e-11 +5.29797e-11 +8.49793e-11 +1.35627e-10 +2.15381e-10 +3.40327e-10 +5.35077e-10 +8.3707e-10 +1.30298e-09 +2.01809e-09 +3.1101e-09 +4.76907e-09 +7.27653e-09 +1.10469e-08 +1.66874e-08 +2.50821e-08 +3.75117e-08 +5.58213e-08 +8.26533e-08 +1.21772e-07 +1.78512e-07 +2.60383e-07 +3.7791e-07 +5.45747e-07 +7.84193e-07 +1.1212e-06 +1.59504e-06 +2.25782e-06 +3.18005e-06 +4.45667e-06 +6.21457e-06 +8.6227e-06 +1.19043e-05 +1.63528e-05 +2.23516e-05 +3.03987e-05 +4.11367e-05 +5.539e-05 +7.421e-05 +9.89287e-05 +0.000131223 +0.000173192 +0.000227443 +0.000297198 +0.00038641 +0.000499897 +0.000643483 +0.000824187 +0.00105037 +0.00133195 +0.00168059 +0.00210991 +0.00263568 +0.00327606 +0.00405173 +0.00498603 +0.0061052 +0.0074383 +0.00901727 +0.0108769 +0.0130546 +0.0155902 +0.0185254 +0.0219034 +0.0257682 +0.0301638 +0.035133 +0.040717 +0.0469527 +0.0538737 +0.0615067 +0.0698703 +0.078976 +0.0888227 +0.099399 +0.11068 +0.122626 +0.135185 +0.148286 +0.161846 +0.175764 +0.189928 +0.204209 +0.218469 +0.232559 +0.246323 +0.2596 +0.272229 +0.284048 +0.294902 +0.304644 +0.313138 +0.320263 +0.325917 +0.330017 +0.332501 +0.333333 +0.332501 +0.330017 +0.325917 +0.320263 +0.313138 +0.304644 +0.294902 +0.284048 +0.272229 +0.2596 +0.246323 +0.232559 +0.218469 +0.204209 +0.189928 +0.175764 +0.161846 +0.148286 +0.135185 +0.122626 +0.11068 +0.099399 +0.0888227 +0.078976 +0.0698703 +0.0615067 +0.0538737 +0.0469527 +0.040717 +0.035133 +0.0301638 +0.0257682 +0.0219034 +0.0185254 +0.0155902 +0.0130546 +0.0108769 +0.00901727 +0.0074383 +0.0061052 +0.00498603 +0.00405173 +0.00327606 +0.00263568 +0.00210991 +0.00168059 +0.00133195 +0.00105037 +0.000824187 +0.000643483 +0.000499897 +0.00038641 +0.000297198 +0.000227443 +0.000173192 +0.000131223 +9.89287e-05 +7.421e-05 +5.539e-05 +4.11367e-05 +3.03987e-05 +2.23516e-05 +1.63528e-05 +1.19043e-05 +8.6227e-06 +6.21457e-06 +4.45667e-06 +3.18005e-06 +2.25782e-06 +1.59504e-06 +1.1212e-06 +7.84193e-07 +5.45747e-07 +3.7791e-07 +2.60383e-07 +1.78512e-07 +1.21772e-07 +8.26533e-08 +5.58213e-08 +3.75117e-08 +2.50821e-08 +1.66874e-08 +1.10469e-08 +7.27653e-09 +4.76907e-09 +3.1101e-09 +2.01809e-09 +1.30298e-09 +8.3707e-10 +5.35077e-10 +3.40327e-10 +2.15381e-10 +1.35627e-10 +8.49793e-11 +5.29797e-11 +3.2865e-11 +2.02856e-11 +1.24586e-11 +7.6134e-12 +4.6293e-12 +2.80081e-12 +1.68608e-12 +1.00996e-12 +6.01943e-13 +3.56973e-13 +2.10643e-13 +1.23676e-13 +7.22523e-14 +4.19997e-14 +2.42924e-14 +1.39805e-14 +8.00577e-15 +4.56157e-15 +2.58613e-15 +1.45887e-15 +8.18867e-16 +4.57337e-16 +2.54149e-16 +1.4053e-16 +7.73173e-17 +4.23267e-17 +2.30558e-17 +1.24961e-17 +6.73907e-18 +3.6162e-18 +1.93077e-18 +1.02575e-18 +5.4222e-19 +2.85195e-19 +1.49258e-19 +7.77247e-20 +4.02727e-20 +2.0763e-20 +1.06512e-20 +5.4367e-21 +2.76123e-21 +1.39539e-21 +7.01647e-22 +3.5105e-22 +1.74763e-22 +8.6568e-23 +4.26673e-23 +2.09247e-23 +1.02106e-23 +4.95763e-24 +2.39511e-24 +1.15134e-24 +5.50697e-25 +2.62089e-25 +1.24112e-25 +5.848e-26 +2.74176e-26 +1.27903e-26 +5.9369e-27 +2.74199e-27 +1.26009e-27 +5.76193e-28 +2.62156e-28 +1.18681e-28 +5.34603e-29 +2.39613e-29 +1.06861e-29 +4.7419e-30 +2.09372e-30 +9.19837e-31 +4.02097e-31 +1.74897e-31 +7.56937e-32 +3.25962e-32 +1.3967e-32 +5.9548e-33 +2.52615e-33 +1.0663e-33 +4.47847e-34 +1.87158e-34 +7.7824e-35 +3.21995e-35 +1.3256e-35 +5.43007e-36 +2.21323e-36 +8.97583e-37 +3.62203e-37 +1.45432e-37 +5.81023e-38 +2.30971e-38 +9.13587e-39 +3.5956e-39 +1.40805e-39 +5.4865e-40 +2.12717e-40 +8.2061e-41 +3.14992e-41 +1.20307e-41 +4.57203e-42 +1.72886e-42 +6.50483e-43 +2.43524e-43 +9.07143e-44 +3.36233e-44 +1.24003e-44 +4.5504e-45 +1.66149e-45 +6.03637e-46 +2.18213e-46 +7.849e-47 +2.80916e-47 +1.00039e-47 +3.54477e-48 +1.24979e-48 +4.38443e-49 +1.53044e-49 +5.31557e-50 +1.83702e-50 +6.3169e-51 +2.16134e-51 +7.35817e-52 +2.49257e-52 +8.4014e-53 +2.81763e-53 +9.40257e-54 +3.12203e-54 +1.03147e-54 +3.3908e-55 +1.10912e-55 +3.6098e-56 +1.169e-56 +3.76683e-57 +1.20772e-57 +3.8529e-58 +1.22302e-58 +3.86287e-59 +1.21398e-59 +3.79617e-60 +1.18116e-60 +3.65677e-61 +1.12646e-61 +3.45273e-62 +1.05302e-62 +3.19552e-63 +9.6488e-64 +2.89891e-64 +8.6661e-65 +2.57775e-65 +7.62937e-66 +2.24679e-66 +6.58363e-67 +1.91955e-67 +5.56877e-68 +1.60749e-68 +4.61707e-69 +1.31951e-69 +3.7522e-70 +1.06167e-70 +2.98897e-71 +8.37303e-72 +2.33384e-72 +6.47273e-73 +1.78622e-73 +4.90467e-74 +1.34002e-74 +3.64287e-75 +9.85377e-76 +2.65211e-76 +7.10247e-77 +1.89258e-77 +5.01797e-78 +1.32382e-78 +3.47507e-79 +9.07657e-80 +2.3589e-80 +6.09993e-81 +1.56954e-81 +4.01833e-82 +1.02364e-82 +2.59465e-83 +6.5439e-84 +1.6422e-84 +4.10053e-85 +1.0188e-85 +2.51861e-86 +6.1953e-87 +1.51633e-87 +3.69277e-88 +8.94827e-89 +2.15752e-89 +5.17607e-90 +1.23559e-90 +2.93478e-91 +6.93593e-92 +1.63104e-92 +3.81637e-93 +8.8852e-94 +2.05831e-94 +4.74443e-95 +1.08814e-95 +2.48322e-96 +5.63863e-97 +1.27397e-97 +2.86402e-98 +6.4065e-99 +1.42591e-99 +3.15787e-100 +6.95863e-101 +1.52574e-101 +3.32865e-102 +7.22577e-103 +1.56073e-103 +3.35427e-104 +7.173e-105 +1.52626e-105 +3.23137e-106 +6.80727e-107 +1.42688e-107 +2.97599e-108 +6.17597e-109 +1.27528e-109 +2.62019e-110 +5.35663e-111 +1.08962e-111 +2.20542e-112 +4.44153e-113 +8.90033e-114 +1.77462e-114 +3.52073e-115 +6.95013e-116 +1.36514e-116 +2.66804e-117 +5.18843e-118 +1.00394e-118 +1.93289e-119 +3.70283e-120 +7.05817e-121 +1.33868e-121 +2.52633e-122 +4.74387e-123 +8.86347e-124 +1.6478e-124 +3.04812e-125 +5.61033e-126 +1.02748e-126 +1.87235e-127 +3.39493e-128 +6.1249e-129 +1.09951e-129 +1.96393e-130 +3.49047e-131 +6.1726e-132 +1.08613e-132 +1.90162e-133 +3.31279e-134 +5.7424e-135 +9.9042e-136 +1.69971e-136 +2.90242e-137 +4.93143e-138 +8.3371e-139 +1.40244e-139 +2.34738e-140 +3.9094e-141 +6.47837e-142 +1.0682e-142 +1.75252e-143 +2.86091e-144 +4.64703e-145 +7.51057e-146 +1.20781e-146 +1.93266e-147 +3.07708e-148 +4.87473e-149 +7.6841e-150 +1.20521e-150 +1.88087e-151 +2.9207e-152 +4.51277e-153 +6.93787e-154 +1.0613e-154 +1.61539e-155 +2.44651e-156 +3.68677e-157 +5.52803e-158 +8.24757e-159 +1.22436e-159 +1.80851e-160 +2.65804e-161 +3.88713e-162 +5.65623e-163 +8.18943e-164 +1.1798e-164 +1.69118e-165 +2.41214e-166 +3.42327e-167 +4.83403e-168 +6.79217e-169 +9.49583e-170 +1.32095e-170 +1.8284e-171 +2.51815e-172 +3.4508e-173 +4.70533e-174 +6.3839e-175 +8.6181e-176 +1.15762e-176 +1.5472e-177 +2.05759e-178 +2.72269e-179 +3.5848e-180 +4.69637e-181 +6.1219e-182 +7.94037e-183 +1.02476e-183 +1.31593e-184 +1.68141e-185 +2.13767e-186 +2.70418e-187 +3.40377e-188 +4.263e-189 +5.31247e-190 +6.58727e-191 +8.12727e-192 +9.97727e-193 +1.21873e-193 +1.48126e-194 +1.79137e-195 +2.15559e-196 +2.58093e-197 +3.07479e-198 +3.64487e-199 +4.2991e-200 +5.04547e-201 +5.8919e-202 +6.84597e-203 +7.9149e-204 +9.10507e-205 +1.0422e-205 +1.18699e-206 +1.34515e-207 +1.51678e-208 +1.70178e-209 +1.89982e-210 +2.11033e-211 +2.33247e-212 +2.56514e-213 +2.80695e-214 +3.05623e-215 +3.31106e-216 +3.56923e-217 +3.82837e-218 +4.08583e-219 +4.33883e-220 +4.58457e-221 +4.82003e-222 +5.0423e-223 +5.24853e-224 +5.43593e-225 +5.60197e-226 +5.74427e-227 +5.8608e-228 +5.9499e-229 +6.0102e-230 +6.04083e-231 +6.04137e-232 +6.01173e-233 +5.95243e-234 +5.8643e-235 +5.74867e-236 +5.60723e-237 +5.44197e-238 +5.25523e-239 +5.0496e-240 +4.82783e-241 +4.59277e-242 +4.34733e-243 +4.09453e-244 +3.83717e-245 +3.57807e-246 +3.3198e-247 +3.06483e-248 +2.81532e-249 +2.57323e-250 +2.34022e-251 +2.1177e-252 +1.90678e-253 +1.7083e-254 +1.52285e-255 +1.35077e-256 +1.19215e-257 +1.04691e-258 +9.1478e-260 +7.95337e-261 +6.88043e-262 +5.92257e-263 +5.0726e-264 +4.32293e-265 +3.6657e-266 +3.09289e-267 +2.59657e-268 +2.16902e-269 +1.80284e-270 +1.491e-271 +1.22695e-272 +1.00463e-273 +8.18487e-275 +6.6351e-276 +5.35193e-277 +4.2954e-278 +3.43023e-279 +2.72567e-280 +2.15502e-281 +1.69534e-282 +1.32706e-283 +1.03361e-284 +8.01027e-286 +6.17687e-287 +4.73933e-288 +3.6182e-289 +2.74853e-290 +2.07747e-291 +1.56242e-292 +1.1692e-293 +8.7058e-295 +6.44997e-296 +4.75483e-297 +3.4877e-298 +2.54551e-299 +1.84858e-300 +1.33576e-301 +9.6039e-303 +6.87063e-304 +4.89073e-305 +3.464e-306 +2.44125e-307 +1.71189e-308 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/inputFiles/wavePropagation/time.txt b/inputFiles/wavePropagation/time.txt new file mode 100644 index 00000000000..fef6bc55b33 --- /dev/null +++ b/inputFiles/wavePropagation/time.txt @@ -0,0 +1,1501 @@ +0.000 +0.001 +0.002 +0.003 +0.004 +0.005 +0.006 +0.007 +0.008 +0.009 +0.010 +0.011 +0.012 +0.013 +0.014 +0.015 +0.016 +0.017 +0.018 +0.019 +0.020 +0.021 +0.022 +0.023 +0.024 +0.025 +0.026 +0.027 +0.028 +0.029 +0.030 +0.031 +0.032 +0.033 +0.034 +0.035 +0.036 +0.037 +0.038 +0.039 +0.040 +0.041 +0.042 +0.043 +0.044 +0.045 +0.046 +0.047 +0.048 +0.049 +0.050 +0.051 +0.052 +0.053 +0.054 +0.055 +0.056 +0.057 +0.058 +0.059 +0.060 +0.061 +0.062 +0.063 +0.064 +0.065 +0.066 +0.067 +0.068 +0.069 +0.070 +0.071 +0.072 +0.073 +0.074 +0.075 +0.076 +0.077 +0.078 +0.079 +0.080 +0.081 +0.082 +0.083 +0.084 +0.085 +0.086 +0.087 +0.088 +0.089 +0.090 +0.091 +0.092 +0.093 +0.094 +0.095 +0.096 +0.097 +0.098 +0.099 +0.100 +0.101 +0.102 +0.103 +0.104 +0.105 +0.106 +0.107 +0.108 +0.109 +0.110 +0.111 +0.112 +0.113 +0.114 +0.115 +0.116 +0.117 +0.118 +0.119 +0.120 +0.121 +0.122 +0.123 +0.124 +0.125 +0.126 +0.127 +0.128 +0.129 +0.130 +0.131 +0.132 +0.133 +0.134 +0.135 +0.136 +0.137 +0.138 +0.139 +0.140 +0.141 +0.142 +0.143 +0.144 +0.145 +0.146 +0.147 +0.148 +0.149 +0.150 +0.151 +0.152 +0.153 +0.154 +0.155 +0.156 +0.157 +0.158 +0.159 +0.160 +0.161 +0.162 +0.163 +0.164 +0.165 +0.166 +0.167 +0.168 +0.169 +0.170 +0.171 +0.172 +0.173 +0.174 +0.175 +0.176 +0.177 +0.178 +0.179 +0.180 +0.181 +0.182 +0.183 +0.184 +0.185 +0.186 +0.187 +0.188 +0.189 +0.190 +0.191 +0.192 +0.193 +0.194 +0.195 +0.196 +0.197 +0.198 +0.199 +0.200 +0.201 +0.202 +0.203 +0.204 +0.205 +0.206 +0.207 +0.208 +0.209 +0.210 +0.211 +0.212 +0.213 +0.214 +0.215 +0.216 +0.217 +0.218 +0.219 +0.220 +0.221 +0.222 +0.223 +0.224 +0.225 +0.226 +0.227 +0.228 +0.229 +0.230 +0.231 +0.232 +0.233 +0.234 +0.235 +0.236 +0.237 +0.238 +0.239 +0.240 +0.241 +0.242 +0.243 +0.244 +0.245 +0.246 +0.247 +0.248 +0.249 +0.250 +0.251 +0.252 +0.253 +0.254 +0.255 +0.256 +0.257 +0.258 +0.259 +0.260 +0.261 +0.262 +0.263 +0.264 +0.265 +0.266 +0.267 +0.268 +0.269 +0.270 +0.271 +0.272 +0.273 +0.274 +0.275 +0.276 +0.277 +0.278 +0.279 +0.280 +0.281 +0.282 +0.283 +0.284 +0.285 +0.286 +0.287 +0.288 +0.289 +0.290 +0.291 +0.292 +0.293 +0.294 +0.295 +0.296 +0.297 +0.298 +0.299 +0.300 +0.301 +0.302 +0.303 +0.304 +0.305 +0.306 +0.307 +0.308 +0.309 +0.310 +0.311 +0.312 +0.313 +0.314 +0.315 +0.316 +0.317 +0.318 +0.319 +0.320 +0.321 +0.322 +0.323 +0.324 +0.325 +0.326 +0.327 +0.328 +0.329 +0.330 +0.331 +0.332 +0.333 +0.334 +0.335 +0.336 +0.337 +0.338 +0.339 +0.340 +0.341 +0.342 +0.343 +0.344 +0.345 +0.346 +0.347 +0.348 +0.349 +0.350 +0.351 +0.352 +0.353 +0.354 +0.355 +0.356 +0.357 +0.358 +0.359 +0.360 +0.361 +0.362 +0.363 +0.364 +0.365 +0.366 +0.367 +0.368 +0.369 +0.370 +0.371 +0.372 +0.373 +0.374 +0.375 +0.376 +0.377 +0.378 +0.379 +0.380 +0.381 +0.382 +0.383 +0.384 +0.385 +0.386 +0.387 +0.388 +0.389 +0.390 +0.391 +0.392 +0.393 +0.394 +0.395 +0.396 +0.397 +0.398 +0.399 +0.400 +0.401 +0.402 +0.403 +0.404 +0.405 +0.406 +0.407 +0.408 +0.409 +0.410 +0.411 +0.412 +0.413 +0.414 +0.415 +0.416 +0.417 +0.418 +0.419 +0.420 +0.421 +0.422 +0.423 +0.424 +0.425 +0.426 +0.427 +0.428 +0.429 +0.430 +0.431 +0.432 +0.433 +0.434 +0.435 +0.436 +0.437 +0.438 +0.439 +0.440 +0.441 +0.442 +0.443 +0.444 +0.445 +0.446 +0.447 +0.448 +0.449 +0.450 +0.451 +0.452 +0.453 +0.454 +0.455 +0.456 +0.457 +0.458 +0.459 +0.460 +0.461 +0.462 +0.463 +0.464 +0.465 +0.466 +0.467 +0.468 +0.469 +0.470 +0.471 +0.472 +0.473 +0.474 +0.475 +0.476 +0.477 +0.478 +0.479 +0.480 +0.481 +0.482 +0.483 +0.484 +0.485 +0.486 +0.487 +0.488 +0.489 +0.490 +0.491 +0.492 +0.493 +0.494 +0.495 +0.496 +0.497 +0.498 +0.499 +0.500 +0.501 +0.502 +0.503 +0.504 +0.505 +0.506 +0.507 +0.508 +0.509 +0.510 +0.511 +0.512 +0.513 +0.514 +0.515 +0.516 +0.517 +0.518 +0.519 +0.520 +0.521 +0.522 +0.523 +0.524 +0.525 +0.526 +0.527 +0.528 +0.529 +0.530 +0.531 +0.532 +0.533 +0.534 +0.535 +0.536 +0.537 +0.538 +0.539 +0.540 +0.541 +0.542 +0.543 +0.544 +0.545 +0.546 +0.547 +0.548 +0.549 +0.550 +0.551 +0.552 +0.553 +0.554 +0.555 +0.556 +0.557 +0.558 +0.559 +0.560 +0.561 +0.562 +0.563 +0.564 +0.565 +0.566 +0.567 +0.568 +0.569 +0.570 +0.571 +0.572 +0.573 +0.574 +0.575 +0.576 +0.577 +0.578 +0.579 +0.580 +0.581 +0.582 +0.583 +0.584 +0.585 +0.586 +0.587 +0.588 +0.589 +0.590 +0.591 +0.592 +0.593 +0.594 +0.595 +0.596 +0.597 +0.598 +0.599 +0.600 +0.601 +0.602 +0.603 +0.604 +0.605 +0.606 +0.607 +0.608 +0.609 +0.610 +0.611 +0.612 +0.613 +0.614 +0.615 +0.616 +0.617 +0.618 +0.619 +0.620 +0.621 +0.622 +0.623 +0.624 +0.625 +0.626 +0.627 +0.628 +0.629 +0.630 +0.631 +0.632 +0.633 +0.634 +0.635 +0.636 +0.637 +0.638 +0.639 +0.640 +0.641 +0.642 +0.643 +0.644 +0.645 +0.646 +0.647 +0.648 +0.649 +0.650 +0.651 +0.652 +0.653 +0.654 +0.655 +0.656 +0.657 +0.658 +0.659 +0.660 +0.661 +0.662 +0.663 +0.664 +0.665 +0.666 +0.667 +0.668 +0.669 +0.670 +0.671 +0.672 +0.673 +0.674 +0.675 +0.676 +0.677 +0.678 +0.679 +0.680 +0.681 +0.682 +0.683 +0.684 +0.685 +0.686 +0.687 +0.688 +0.689 +0.690 +0.691 +0.692 +0.693 +0.694 +0.695 +0.696 +0.697 +0.698 +0.699 +0.700 +0.701 +0.702 +0.703 +0.704 +0.705 +0.706 +0.707 +0.708 +0.709 +0.710 +0.711 +0.712 +0.713 +0.714 +0.715 +0.716 +0.717 +0.718 +0.719 +0.720 +0.721 +0.722 +0.723 +0.724 +0.725 +0.726 +0.727 +0.728 +0.729 +0.730 +0.731 +0.732 +0.733 +0.734 +0.735 +0.736 +0.737 +0.738 +0.739 +0.740 +0.741 +0.742 +0.743 +0.744 +0.745 +0.746 +0.747 +0.748 +0.749 +0.750 +0.751 +0.752 +0.753 +0.754 +0.755 +0.756 +0.757 +0.758 +0.759 +0.760 +0.761 +0.762 +0.763 +0.764 +0.765 +0.766 +0.767 +0.768 +0.769 +0.770 +0.771 +0.772 +0.773 +0.774 +0.775 +0.776 +0.777 +0.778 +0.779 +0.780 +0.781 +0.782 +0.783 +0.784 +0.785 +0.786 +0.787 +0.788 +0.789 +0.790 +0.791 +0.792 +0.793 +0.794 +0.795 +0.796 +0.797 +0.798 +0.799 +0.800 +0.801 +0.802 +0.803 +0.804 +0.805 +0.806 +0.807 +0.808 +0.809 +0.810 +0.811 +0.812 +0.813 +0.814 +0.815 +0.816 +0.817 +0.818 +0.819 +0.820 +0.821 +0.822 +0.823 +0.824 +0.825 +0.826 +0.827 +0.828 +0.829 +0.830 +0.831 +0.832 +0.833 +0.834 +0.835 +0.836 +0.837 +0.838 +0.839 +0.840 +0.841 +0.842 +0.843 +0.844 +0.845 +0.846 +0.847 +0.848 +0.849 +0.850 +0.851 +0.852 +0.853 +0.854 +0.855 +0.856 +0.857 +0.858 +0.859 +0.860 +0.861 +0.862 +0.863 +0.864 +0.865 +0.866 +0.867 +0.868 +0.869 +0.870 +0.871 +0.872 +0.873 +0.874 +0.875 +0.876 +0.877 +0.878 +0.879 +0.880 +0.881 +0.882 +0.883 +0.884 +0.885 +0.886 +0.887 +0.888 +0.889 +0.890 +0.891 +0.892 +0.893 +0.894 +0.895 +0.896 +0.897 +0.898 +0.899 +0.900 +0.901 +0.902 +0.903 +0.904 +0.905 +0.906 +0.907 +0.908 +0.909 +0.910 +0.911 +0.912 +0.913 +0.914 +0.915 +0.916 +0.917 +0.918 +0.919 +0.920 +0.921 +0.922 +0.923 +0.924 +0.925 +0.926 +0.927 +0.928 +0.929 +0.930 +0.931 +0.932 +0.933 +0.934 +0.935 +0.936 +0.937 +0.938 +0.939 +0.940 +0.941 +0.942 +0.943 +0.944 +0.945 +0.946 +0.947 +0.948 +0.949 +0.950 +0.951 +0.952 +0.953 +0.954 +0.955 +0.956 +0.957 +0.958 +0.959 +0.960 +0.961 +0.962 +0.963 +0.964 +0.965 +0.966 +0.967 +0.968 +0.969 +0.970 +0.971 +0.972 +0.973 +0.974 +0.975 +0.976 +0.977 +0.978 +0.979 +0.980 +0.981 +0.982 +0.983 +0.984 +0.985 +0.986 +0.987 +0.988 +0.989 +0.990 +0.991 +0.992 +0.993 +0.994 +0.995 +0.996 +0.997 +0.998 +0.999 +1.000 +1.001 +1.002 +1.003 +1.004 +1.005 +1.006 +1.007 +1.008 +1.009 +1.010 +1.011 +1.012 +1.013 +1.014 +1.015 +1.016 +1.017 +1.018 +1.019 +1.020 +1.021 +1.022 +1.023 +1.024 +1.025 +1.026 +1.027 +1.028 +1.029 +1.030 +1.031 +1.032 +1.033 +1.034 +1.035 +1.036 +1.037 +1.038 +1.039 +1.040 +1.041 +1.042 +1.043 +1.044 +1.045 +1.046 +1.047 +1.048 +1.049 +1.050 +1.051 +1.052 +1.053 +1.054 +1.055 +1.056 +1.057 +1.058 +1.059 +1.060 +1.061 +1.062 +1.063 +1.064 +1.065 +1.066 +1.067 +1.068 +1.069 +1.070 +1.071 +1.072 +1.073 +1.074 +1.075 +1.076 +1.077 +1.078 +1.079 +1.080 +1.081 +1.082 +1.083 +1.084 +1.085 +1.086 +1.087 +1.088 +1.089 +1.090 +1.091 +1.092 +1.093 +1.094 +1.095 +1.096 +1.097 +1.098 +1.099 +1.100 +1.101 +1.102 +1.103 +1.104 +1.105 +1.106 +1.107 +1.108 +1.109 +1.110 +1.111 +1.112 +1.113 +1.114 +1.115 +1.116 +1.117 +1.118 +1.119 +1.120 +1.121 +1.122 +1.123 +1.124 +1.125 +1.126 +1.127 +1.128 +1.129 +1.130 +1.131 +1.132 +1.133 +1.134 +1.135 +1.136 +1.137 +1.138 +1.139 +1.140 +1.141 +1.142 +1.143 +1.144 +1.145 +1.146 +1.147 +1.148 +1.149 +1.150 +1.151 +1.152 +1.153 +1.154 +1.155 +1.156 +1.157 +1.158 +1.159 +1.160 +1.161 +1.162 +1.163 +1.164 +1.165 +1.166 +1.167 +1.168 +1.169 +1.170 +1.171 +1.172 +1.173 +1.174 +1.175 +1.176 +1.177 +1.178 +1.179 +1.180 +1.181 +1.182 +1.183 +1.184 +1.185 +1.186 +1.187 +1.188 +1.189 +1.190 +1.191 +1.192 +1.193 +1.194 +1.195 +1.196 +1.197 +1.198 +1.199 +1.200 +1.201 +1.202 +1.203 +1.204 +1.205 +1.206 +1.207 +1.208 +1.209 +1.210 +1.211 +1.212 +1.213 +1.214 +1.215 +1.216 +1.217 +1.218 +1.219 +1.220 +1.221 +1.222 +1.223 +1.224 +1.225 +1.226 +1.227 +1.228 +1.229 +1.230 +1.231 +1.232 +1.233 +1.234 +1.235 +1.236 +1.237 +1.238 +1.239 +1.240 +1.241 +1.242 +1.243 +1.244 +1.245 +1.246 +1.247 +1.248 +1.249 +1.250 +1.251 +1.252 +1.253 +1.254 +1.255 +1.256 +1.257 +1.258 +1.259 +1.260 +1.261 +1.262 +1.263 +1.264 +1.265 +1.266 +1.267 +1.268 +1.269 +1.270 +1.271 +1.272 +1.273 +1.274 +1.275 +1.276 +1.277 +1.278 +1.279 +1.280 +1.281 +1.282 +1.283 +1.284 +1.285 +1.286 +1.287 +1.288 +1.289 +1.290 +1.291 +1.292 +1.293 +1.294 +1.295 +1.296 +1.297 +1.298 +1.299 +1.300 +1.301 +1.302 +1.303 +1.304 +1.305 +1.306 +1.307 +1.308 +1.309 +1.310 +1.311 +1.312 +1.313 +1.314 +1.315 +1.316 +1.317 +1.318 +1.319 +1.320 +1.321 +1.322 +1.323 +1.324 +1.325 +1.326 +1.327 +1.328 +1.329 +1.330 +1.331 +1.332 +1.333 +1.334 +1.335 +1.336 +1.337 +1.338 +1.339 +1.340 +1.341 +1.342 +1.343 +1.344 +1.345 +1.346 +1.347 +1.348 +1.349 +1.350 +1.351 +1.352 +1.353 +1.354 +1.355 +1.356 +1.357 +1.358 +1.359 +1.360 +1.361 +1.362 +1.363 +1.364 +1.365 +1.366 +1.367 +1.368 +1.369 +1.370 +1.371 +1.372 +1.373 +1.374 +1.375 +1.376 +1.377 +1.378 +1.379 +1.380 +1.381 +1.382 +1.383 +1.384 +1.385 +1.386 +1.387 +1.388 +1.389 +1.390 +1.391 +1.392 +1.393 +1.394 +1.395 +1.396 +1.397 +1.398 +1.399 +1.400 +1.401 +1.402 +1.403 +1.404 +1.405 +1.406 +1.407 +1.408 +1.409 +1.410 +1.411 +1.412 +1.413 +1.414 +1.415 +1.416 +1.417 +1.418 +1.419 +1.420 +1.421 +1.422 +1.423 +1.424 +1.425 +1.426 +1.427 +1.428 +1.429 +1.430 +1.431 +1.432 +1.433 +1.434 +1.435 +1.436 +1.437 +1.438 +1.439 +1.440 +1.441 +1.442 +1.443 +1.444 +1.445 +1.446 +1.447 +1.448 +1.449 +1.450 +1.451 +1.452 +1.453 +1.454 +1.455 +1.456 +1.457 +1.458 +1.459 +1.460 +1.461 +1.462 +1.463 +1.464 +1.465 +1.466 +1.467 +1.468 +1.469 +1.470 +1.471 +1.472 +1.473 +1.474 +1.475 +1.476 +1.477 +1.478 +1.479 +1.480 +1.481 +1.482 +1.483 +1.484 +1.485 +1.486 +1.487 +1.488 +1.489 +1.490 +1.491 +1.492 +1.493 +1.494 +1.495 +1.496 +1.497 +1.498 +1.499 +1.500 diff --git a/inputFiles/wellbore/CasedElasticWellbore_ImperfectInterfaces_base.xml b/inputFiles/wellbore/CasedElasticWellbore_ImperfectInterfaces_base.xml index 04a17b7ea8b..0f782918ec9 100644 --- a/inputFiles/wellbore/CasedElasticWellbore_ImperfectInterfaces_base.xml +++ b/inputFiles/wellbore/CasedElasticWellbore_ImperfectInterfaces_base.xml @@ -12,8 +12,7 @@ + newtonMaxIter="10"/> @@ -49,7 +48,7 @@ @@ -75,9 +74,7 @@ + frictionCoefficient="0.5"/> - diff --git a/inputFiles/wellbore/CasedThermoElasticWellbore_ImperfectInterfaces_base.xml b/inputFiles/wellbore/CasedThermoElasticWellbore_ImperfectInterfaces_base.xml index b2028906503..ae8b6baea35 100644 --- a/inputFiles/wellbore/CasedThermoElasticWellbore_ImperfectInterfaces_base.xml +++ b/inputFiles/wellbore/CasedThermoElasticWellbore_ImperfectInterfaces_base.xml @@ -24,15 +24,14 @@ + newtonMaxIter="10"/> @@ -67,8 +66,10 @@ - + @@ -77,8 +78,8 @@ + materialList="{ fluid, fractureFilling, frictionLaw, contactThermalCond, hApertureModel }" + defaultAperture="5.0e-4"/> + frictionCoefficient="0.5"/> + + + defaultGrainBulkModulus="159.4202899e9"/> + defaultGrainBulkModulus="2.298850575e9"/> + defaultGrainBulkModulus="5.535714286e9"/> @@ -199,22 +202,22 @@ - + defaultThermalConductivityComponents="{ 15, 15, 15 }"/> - + defaultThermalConductivityComponents="{ 1.0, 1.0, 1.0 }"/> - + defaultThermalConductivityComponents="{ 1.66, 1.66, 1.66 }"/> - + defaultThermalConductivityComponents="{ 1.0, 1.0, 1.0 }"/> diff --git a/inputFiles/wellbore/CasedThermoElasticWellbore_base.xml b/inputFiles/wellbore/CasedThermoElasticWellbore_base.xml index 133d834fdd3..e56790eff7c 100644 --- a/inputFiles/wellbore/CasedThermoElasticWellbore_base.xml +++ b/inputFiles/wellbore/CasedThermoElasticWellbore_base.xml @@ -94,35 +94,35 @@ + defaultGrainBulkModulus="159.4202899e9"/> + defaultGrainBulkModulus="2.298850575e9"/> + defaultGrainBulkModulus="5.535714286e9"/> @@ -142,17 +142,17 @@ - + defaultThermalConductivityComponents="{ 15, 15, 15 }"/> - + defaultThermalConductivityComponents="{ 1.0, 1.0, 1.0 }"/> - + defaultThermalConductivityComponents="{ 1.66, 1.66, 1.66 }"/> @@ -265,7 +265,7 @@ fieldName="casingSolid_stress" component="2" scale="573913043.5"/> - + diff --git a/inputFiles/wellbore/DeviatedPoroElasticWellbore_Drilling_base.xml b/inputFiles/wellbore/DeviatedPoroElasticWellbore_Drilling_base.xml index 5d6697daa66..c769ceac580 100644 --- a/inputFiles/wellbore/DeviatedPoroElasticWellbore_Drilling_base.xml +++ b/inputFiles/wellbore/DeviatedPoroElasticWellbore_Drilling_base.xml @@ -45,7 +45,7 @@ @@ -75,7 +75,7 @@ @@ -71,7 +71,7 @@ @@ -66,14 +66,14 @@ @@ -85,9 +85,9 @@ - + defaultThermalConductivityComponents="{ 6.6, 6.6, 6.6 }"/> @@ -161,6 +161,7 @@ setNames="{ zneg, zpos }"/> + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/ECP_Wellbore_geom02.xml b/inputFiles/wellboreECP/ECP_Wellbore_geom02.xml new file mode 100644 index 00000000000..dcd2f82f4d2 --- /dev/null +++ b/inputFiles/wellboreECP/ECP_Wellbore_geom02.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/ECP_Wellbore_geom03.xml b/inputFiles/wellboreECP/ECP_Wellbore_geom03.xml new file mode 100644 index 00000000000..d9e0265862c --- /dev/null +++ b/inputFiles/wellboreECP/ECP_Wellbore_geom03.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/ECP_Wellbore_geom04.xml b/inputFiles/wellboreECP/ECP_Wellbore_geom04.xml new file mode 100644 index 00000000000..f89b5a7df8c --- /dev/null +++ b/inputFiles/wellboreECP/ECP_Wellbore_geom04.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/ECP_Wellbore_geom05.xml b/inputFiles/wellboreECP/ECP_Wellbore_geom05.xml new file mode 100644 index 00000000000..b6ff8b22bfc --- /dev/null +++ b/inputFiles/wellboreECP/ECP_Wellbore_geom05.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/ECP_Wellbore_geom06.xml b/inputFiles/wellboreECP/ECP_Wellbore_geom06.xml new file mode 100644 index 00000000000..46653587fab --- /dev/null +++ b/inputFiles/wellboreECP/ECP_Wellbore_geom06.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/ECP_Wellbore_probdef.xml b/inputFiles/wellboreECP/compositionalMultiphaseFlow/ECP_Wellbore_probdef.xml new file mode 100644 index 00000000000..4b426eae484 --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/ECP_Wellbore_probdef.xml @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/co2flash.txt b/inputFiles/wellboreECP/compositionalMultiphaseFlow/co2flash.txt new file mode 100644 index 00000000000..ec46548d345 --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/co2flash.txt @@ -0,0 +1 @@ +FlashModel CO2Solubility 1e6 5e7 5e5 367.15 369.15 1 0 diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/level01/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level01/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..d7f365e4ac3 --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level01/ECP_Wellbore_gpu.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/level01/launch_frontier b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level01/launch_frontier new file mode 100644 index 00000000000..550f5402193 --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level01/launch_frontier @@ -0,0 +1,13 @@ +#!/bin/bash +#SBATCH -N 1 +#SBATCH -n 1 +#SBATCH -t 1:00:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-compflow-geom01.out + +echo `date` +cmd="srun -N 1 -n 1 -c 1 --gpus-per-node=1 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 1 -y 1 -z 1 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/level02/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level02/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..968c53afb99 --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level02/ECP_Wellbore_gpu.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/level02/launch_frontier b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level02/launch_frontier new file mode 100644 index 00000000000..15379ad037a --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level02/launch_frontier @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -N 1 +#SBATCH -n 4 +#SBATCH -t 2:00:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-compflow-geom02.out + +echo `date` +module load cpe/23.12 +module load craype-accel-amd-gfx90a +module load rocm/5.4.3 +export MPICH_GPU_SUPPORT_ENABLED=1 +ldd ${1} +cmd="srun -N 1 -n 4 -c 1 --gpus-per-node=4 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 1 -y 1 -z 4 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/level03/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level03/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..299faa6e0d5 --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level03/ECP_Wellbore_gpu.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/level03/launch_frontier b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level03/launch_frontier new file mode 100644 index 00000000000..b64624e817e --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level03/launch_frontier @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -N 4 +#SBATCH -n 32 +#SBATCH -t 2:00:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-compflow-geom03.out + +echo `date` +module load cpe/23.12 +module load craype-accel-amd-gfx90a +module load rocm/5.4.3 +export MPICH_GPU_SUPPORT_ENABLED=1 +ldd ${1} +cmd="srun -N 4 -n 32 -c 1 --gpus-per-node=8 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 2 -y 2 -z 8 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/level04/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level04/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..75790211238 --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level04/ECP_Wellbore_gpu.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/level04/launch_frontier b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level04/launch_frontier new file mode 100644 index 00000000000..8068a2eafb8 --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level04/launch_frontier @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -N 32 +#SBATCH -n 256 +#SBATCH -t 2:00:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-compflow-geom04.out + +echo `date` +module load cpe/23.12 +module load craype-accel-amd-gfx90a +module load rocm/5.4.3 +export MPICH_GPU_SUPPORT_ENABLED=1 +ldd ${1} +cmd="srun -N 32 -n 256 -c 1 --gpus-per-node=8 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 4 -y 4 -z 16 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/level05/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level05/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..bb2a7a50ffe --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level05/ECP_Wellbore_gpu.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/level05/launch_frontier b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level05/launch_frontier new file mode 100644 index 00000000000..7b26b022959 --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level05/launch_frontier @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -N 256 +#SBATCH -n 2048 +#SBATCH -t 4:00:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-compflow-geom05.out + +echo `date` +module load cpe/23.12 +module load craype-accel-amd-gfx90a +module load rocm/5.4.3 +export MPICH_GPU_SUPPORT_ENABLED=1 +ldd ${1} +cmd="srun -N 256 -n 2048 -c 1 --gpus-per-node=8 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 8 -y 8 -z 32 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/level06/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level06/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..bdfaaf7384b --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level06/ECP_Wellbore_gpu.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/level06/launch_frontier b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level06/launch_frontier new file mode 100644 index 00000000000..e8f3c24bf51 --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/level06/launch_frontier @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -N 2048 +#SBATCH -n 16384 +#SBATCH -t 4:00:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-compflow-geom06.out + +echo `date` +module load cpe/23.12 +module load craype-accel-amd-gfx90a +module load rocm/5.4.3 +export MPICH_GPU_SUPPORT_ENABLED=1 +ldd ${1} +cmd="srun -N 2048 -n 16384 -c 1 --gpus-per-node=8 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 16 -y 16 -z 64 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/pvtgas.txt b/inputFiles/wellboreECP/compositionalMultiphaseFlow/pvtgas.txt new file mode 100644 index 00000000000..6442bd866a3 --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/pvtgas.txt @@ -0,0 +1,2 @@ +DensityFun SpanWagnerCO2Density 1e6 5e7 5e5 367.15 369.15 1 +ViscosityFun FenghourCO2Viscosity 1e6 5e7 5e5 367.15 369.15 1 diff --git a/inputFiles/wellboreECP/compositionalMultiphaseFlow/pvtliquid.txt b/inputFiles/wellboreECP/compositionalMultiphaseFlow/pvtliquid.txt new file mode 100644 index 00000000000..a4b549a84ca --- /dev/null +++ b/inputFiles/wellboreECP/compositionalMultiphaseFlow/pvtliquid.txt @@ -0,0 +1,2 @@ +DensityFun PhillipsBrineDensity 1e6 5e7 5e5 367.15 369.15 1 0 +ViscosityFun PhillipsBrineViscosity 0 diff --git a/inputFiles/wellboreECP/dispatch.py b/inputFiles/wellboreECP/dispatch.py new file mode 100755 index 00000000000..63249ecf0e2 --- /dev/null +++ b/inputFiles/wellboreECP/dispatch.py @@ -0,0 +1,52 @@ +#!/opt/cray/pe/python/3.11.5/bin/python + +import argparse +import os +import sys + +def main(args): + parser = argparse.ArgumentParser() + parser.add_argument('-a','--account',required=True) + parser.add_argument('-b','--binary',required=True) + parser.add_argument('-c','--caliper',default="") + parser.add_argument('-p','--problem',required=True) + parser.add_argument('-s','--script',default="launch_frontier") + parser.add_argument('-d','--dispatch',default="sbatch") + parser.add_argument('-v','--verbosity',type=int,default=0) + parser.add_argument('-l','--levels',nargs='+') + args = parser.parse_args(args) + + if args.caliper in ("default", "def", "standard", "std"): + profiling="\"-t runtime-report,max_column_width=200,calc.inclusive,output=stdout,mpi-report\"" + else: + profiling=args.caliper + + avail_problems = [ d for d in os.listdir(os.getcwd()) if os.path.isdir(d) ] + + if args.problem not in avail_problems: + print(f"Unkown problem {args.problem}") + raise SystemExit(1) + + os.chdir(os.path.join(os.getcwd(),args.problem)) + prob_dir = os.getcwd() + + levels = list( sorted( ( d for d in os.listdir(prob_dir) if os.path.isdir(d) and d.startswith("level") ), key=lambda v: int(v[5:]) ) ) + if args.levels is not None: + args.levels = [ int(l) for l in args.levels ] + levels = [ l for l in levels if int(l[5:]) in args.levels ] + + if args.verbosity: + print(f"{levels = }") + + launch = ' '.join([args.dispatch, "-A", args.account, args.script, args.binary, profiling]) + if args.verbosity: + print(f"{launch = }") + + for level in levels: + os.chdir(level) + print(os.getcwd()) + os.system(launch) + os.chdir(prob_dir) + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/inputFiles/wellboreECP/mechanics/ECP_Wellbore_probdef.xml b/inputFiles/wellboreECP/mechanics/ECP_Wellbore_probdef.xml new file mode 100644 index 00000000000..03565ea7c62 --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/ECP_Wellbore_probdef.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/mechanics/level01/ECP_Wellbore_cpu.xml b/inputFiles/wellboreECP/mechanics/level01/ECP_Wellbore_cpu.xml new file mode 100644 index 00000000000..ff1e6e2786b --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level01/ECP_Wellbore_cpu.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/mechanics/level01/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/mechanics/level01/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..955caa1251f --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level01/ECP_Wellbore_gpu.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/mechanics/level01/launch_frontier b/inputFiles/wellboreECP/mechanics/level01/launch_frontier new file mode 100644 index 00000000000..1e292da4fa3 --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level01/launch_frontier @@ -0,0 +1,13 @@ +#!/bin/bash +#SBATCH -N 1 +#SBATCH -n 1 +#SBATCH -t 0:30:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-mechanics-geom01.out + +echo `date` +cmd="srun -N 1 -n 1 -c 1 --gpus-per-node=1 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 1 -y 1 -z 1 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/mechanics/level02/ECP_Wellbore_cpu.xml b/inputFiles/wellboreECP/mechanics/level02/ECP_Wellbore_cpu.xml new file mode 100644 index 00000000000..0ce1e921b86 --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level02/ECP_Wellbore_cpu.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/mechanics/level02/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/mechanics/level02/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..42b793fd141 --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level02/ECP_Wellbore_gpu.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/mechanics/level02/launch_frontier b/inputFiles/wellboreECP/mechanics/level02/launch_frontier new file mode 100644 index 00000000000..dc892143c51 --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level02/launch_frontier @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -N 1 +#SBATCH -n 8 +#SBATCH -t 0:30:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-mechanics-geom02.out + +echo `date` +module load cpe/23.12 +module load craype-accel-amd-gfx90a +module load rocm/5.4.3 +export MPICH_GPU_SUPPORT_ENABLED=1; +ldd ${1} +cmd="srun -N 1 -n 8 -c 1 --gpus-per-node=8 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 1 -y 1 -z 8 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/mechanics/level03/ECP_Wellbore_cpu.xml b/inputFiles/wellboreECP/mechanics/level03/ECP_Wellbore_cpu.xml new file mode 100644 index 00000000000..f293dbac569 --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level03/ECP_Wellbore_cpu.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/mechanics/level03/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/mechanics/level03/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..2f45ff7d84a --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level03/ECP_Wellbore_gpu.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/mechanics/level03/launch_frontier b/inputFiles/wellboreECP/mechanics/level03/launch_frontier new file mode 100644 index 00000000000..ec1946ef77f --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level03/launch_frontier @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -N 8 +#SBATCH -n 64 +#SBATCH -t 0:30:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-mechanics-geom03.out + +echo `date` +module load cpe/23.12 +module load craype-accel-amd-gfx90a +module load rocm/5.4.3 +export MPICH_GPU_SUPPORT_ENABLED=1 +ldd ${1} +cmd="srun -N 8 -n 64 -c 1 --gpus-per-node=8 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 2 -y 2 -z 16 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/mechanics/level04/ECP_Wellbore_cpu.xml b/inputFiles/wellboreECP/mechanics/level04/ECP_Wellbore_cpu.xml new file mode 100644 index 00000000000..0275158d56e --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level04/ECP_Wellbore_cpu.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/mechanics/level04/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/mechanics/level04/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..0daa1f3b2e1 --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level04/ECP_Wellbore_gpu.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/mechanics/level04/launch_frontier b/inputFiles/wellboreECP/mechanics/level04/launch_frontier new file mode 100644 index 00000000000..30504f5a86b --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level04/launch_frontier @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -N 64 +#SBATCH -n 512 +#SBATCH -t 0:30:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-mechanics-geom04.out + +echo `date` +module load cpe/23.12 +module load craype-accel-amd-gfx90a +module load rocm/5.4.3 +export MPICH_GPU_SUPPORT_ENABLED=1 +ldd ${1} +cmd="srun -N 64 -n 512 -c 1 --gpus-per-node=8 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 4 -y 4 -z 32 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/mechanics/level05/ECP_Wellbore_cpu.xml b/inputFiles/wellboreECP/mechanics/level05/ECP_Wellbore_cpu.xml new file mode 100644 index 00000000000..e175ad452cc --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level05/ECP_Wellbore_cpu.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/mechanics/level05/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/mechanics/level05/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..35793297b48 --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level05/ECP_Wellbore_gpu.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/mechanics/level05/launch_frontier b/inputFiles/wellboreECP/mechanics/level05/launch_frontier new file mode 100644 index 00000000000..d69845ff39a --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level05/launch_frontier @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -N 512 +#SBATCH -n 4096 +#SBATCH -t 0:30:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-mechanics-geom05.out + +echo `date` +module load cpe/23.12 +module load craype-accel-amd-gfx90a +module load rocm/5.4.3 +export MPICH_GPU_SUPPORT_ENABLED=1 +ldd ${1} +cmd="srun -N 512 -n 4096 -c 1 --gpus-per-node=8 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 8 -y 8 -z 64 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/mechanics/level06/ECP_Wellbore_cpu.xml b/inputFiles/wellboreECP/mechanics/level06/ECP_Wellbore_cpu.xml new file mode 100644 index 00000000000..d1901ff9371 --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level06/ECP_Wellbore_cpu.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/mechanics/level06/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/mechanics/level06/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..8ebe7b9238e --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level06/ECP_Wellbore_gpu.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/mechanics/level06/launch_frontier b/inputFiles/wellboreECP/mechanics/level06/launch_frontier new file mode 100644 index 00000000000..2fd2ad14edc --- /dev/null +++ b/inputFiles/wellboreECP/mechanics/level06/launch_frontier @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -N 4096 +#SBATCH -n 32768 +#SBATCH -t 0:30:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-mechanics-geom06.out + +echo `date` +module load cpe/23.12 +module load craype-accel-amd-gfx90a +module load rocm/5.4.3 +export MPICH_GPU_SUPPORT_ENABLED=1 +ldd ${1} +cmd="srun -N 4096 -n 32768 -c 1 --gpus-per-node=8 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 16 -y 16 -z 128 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/postprocess.py b/inputFiles/wellboreECP/postprocess.py new file mode 100755 index 00000000000..914c1abd038 --- /dev/null +++ b/inputFiles/wellboreECP/postprocess.py @@ -0,0 +1,241 @@ +#!/opt/cray/pe/python/3.11.5/bin/python + +import matplotlib.pyplot as plt +import argparse +import glob +import sys +import re +import os + +def parse_log_file(file_path): + """Parse the log file from GEOS and extract required statistics.""" + try: + print(f"Parsing {file_path = }") + with open(file_path, 'r') as file: + data = file.read() + + except FileNotFoundError: + print(f"Error: File not found - {file_path}", file=sys.stderr) + + except Exception as e: + print(f"Error processing file {file_path}: {str(e)}", file=sys.stderr) + + # Regex patterns to extract the required information + patterns = { + 'non_linear_iters': re.compile(r'number of successful nonlinear iterations: (\d+).*number of discarded nonlinear iterations: (\d+)', re.S), + 'linear_iters': re.compile(r'number of successful linear iterations: (\d+).*number of discarded linear iterations: (\d+)', re.S), + 'applysol_time': re.compile(r'apply solution time = (\d+\.\d+) s'), + 'assemble_time': re.compile(r'assemble time = (\d+\.\d+) s'), + 'convcheck_time': re.compile(r'convergence check time = (\d+\.\d+) s'), + 'update_state_time': re.compile(r'update state time = (\d+\.\d+) s'), + 'ls_create_time': re.compile(r'linear solver create time = (\d+.\d+) s'), + 'ls_setup_time': re.compile(r'linear solver setup time = (\d+.\d+) s'), + 'ls_solve_time': re.compile(r'linear solver solve time = (\d+.\d+) s'), + 'run_time': re.compile(r'run time\s+.*\((\d+\.\d+) s\)') + } + + # Dictionary to hold the results + stats = {} + + # Extract and process all patterns + for key, pattern in patterns.items(): + if key in ['non_linear_iters', 'linear_iters']: + xmatch = pattern.search(data) + stats[key] = int(xmatch.group(1)) + int(xmatch.group(2)) if xmatch else 0 + + else: + xmatch = pattern.search(data) + stats[key] = float(xmatch.group(1)) if xmatch else 0 + + # Calculate GEOS time (run time excluding hypre time) + stats['geos_time'] = stats['run_time'] - (stats['ls_create_time'] + stats['ls_setup_time'] + stats['ls_solve_time']) + + # Calculate averages + averages = { + 'avg_geos_time': 'geos_time', + 'avg_ls_create_time': 'ls_create_time', + 'avg_ls_setup_time': 'ls_setup_time', + 'avg_ls_solve_time': 'ls_solve_time', + 'avg_ls_iters': 'linear_iters', + 'avg_run_time': 'run_time' + } + + if stats['non_linear_iters'] <= 0: + print(f"Invalid number of non-linear iterations!", file=sys.stderr) + return None + + for avg_key, total_key in averages.items(): + stats[avg_key] = stats[total_key] / stats['non_linear_iters'] + + # Store level + xmatch = re.search(r'level(\d+)', file_path) + stats['level'] = int(xmatch.group(1)) if xmatch else -1 + + return stats + +def print_results(model, results): + """Print results in markdown table format""" + if not results or not all(results): + print(f"Invalid results!", file=sys.stderr) + return + + # Setup header + headers = ["Level", "GEOS (s)", "Matrix creation (s)", "Hypre setup (s)", "Hypre solve (s)", "Total (s)", "Hypre iters"] + + # Gather all rows data including headers + data_rows = [ + headers, + *[ + [ + "{:02d}".format(result['level']), + "{:.4f}".format(result['avg_geos_time']), + "{:.4f}".format(result['avg_ls_create_time']), + "{:.4f}".format(result['avg_ls_setup_time']), + "{:.4f}".format(result['avg_ls_solve_time']), + "{:.4f}".format(result['avg_run_time']), + "{:.1f}".format(result['avg_ls_iters']), + ] + for result in results + ] + ] + + # Calculate maximum column widths + max_widths = [max(len(row[i]) for row in data_rows) for i in range(len(headers))] + + # Print header row with adjusted widths + header_row = "| " + " | ".join(header.ljust(max_widths[i]) for i, header in enumerate(headers)) + " |" + print(f"\nSummary table for {model}:\n") + print(header_row) + + # Adjust the divider line based on maximum widths + divider_line = "|" + "|".join(["-" * (max_widths[i] + 2) for i in range(len(headers))]) + "|" + print(divider_line) + + # Print each data row with adjusted widths + for row in data_rows[1:]: # Skip the header in data_rows for output + formatted_row = "| " + " | ".join(item.ljust(max_widths[i]) for i, item in enumerate(row)) + " |" + print(formatted_row) + +def plot_results(model, model_data, results, fs=16, ms=10): + if not results: + return + + plt.rcParams.update({'font.size': fs}) + fig, ax = plt.subplots(figsize=(10, 6)) + + # Extracting ranks and global DOFs + levels = [result['level'] for result in results] + ranks = [entry['ranks'] for entry in model_data if entry['level'] in levels] + global_dofs = [entry['global_dofs'] for entry in model_data if entry['level'] in levels] + + # Setting up data for plotting + geos_times = [result['avg_geos_time'] for result in results] + ls_create_times = [result['avg_ls_create_time'] for result in results] + ls_setup_times = [result['avg_ls_setup_time'] for result in results] + ls_solve_times = [result['avg_ls_solve_time'] for result in results] + total_times = [result['avg_run_time'] for result in results] + + # Plotting each metric + ax.plot(ranks, geos_times, 'o-', markersize=ms, label='GEOS') + ax.plot(ranks, ls_create_times, 's-', markersize=ms, label='Matrix Creation') + ax.plot(ranks, ls_setup_times, '^-', markersize=ms, label='Hypre Setup') + ax.plot(ranks, ls_solve_times, 'v-', markersize=ms, label='Hypre Solve') + ax.plot(ranks, total_times, 'd-', markersize=ms, label='Total') + + # Adding labels and legend + ax.set_title(f"Weak scaling - {model}", fontsize=fs+4) + ax.set_xlabel('Number of GPUs (Global DOFs)', labelpad=18, fontsize=fs+1) + ax.set_ylabel('Time (s)', labelpad=18, fontsize=fs+1) + ax.set_xscale('log', base=2) + ax.set_xticks(ranks) + ax.set_xticklabels([f"{r:,} ({d})" for r, d in zip(ranks, global_dofs)]) + ax.legend(fontsize=fs) + + # Show grid lines + ax.grid(True, which='both', linestyle='--', linewidth=0.5, color='gray') # Add gridlines with custom settings + + # Update margins + plt.tight_layout() + + # Save figure to file + figname = f"weakscal_{model}.png" + print(f"Saving figure to file {figname}...") + plt.savefig(figname, format='png', dpi=450) + + # Show the plot + plt.show() + +def find_newest_file(model, level): + """Finds the newest output file under the directory relative to a physics model and for certain problem level (mesh refinement).""" + target_dir = os.path.join(model, f"level{level:02d}") + files = glob.glob(os.path.join(target_dir, '*.out')) + if not files: + return target_dir, None + + # Extract the job ID numbers and sort the files by these IDs + suffixes = {'mechanics': 'mechanics', + 'singlePhaseFlow': 'singlePhaseFlow', + 'compositionalMultiphaseFlow': 'compflow'} + files_with_ids = [(file, int(re.search(rf"(\d+)-{suffixes[model]}", file).group(1))) for file in files] + + # Sort by the job ID number + return target_dir, max(files_with_ids, key=lambda x: x[1])[0] + +def main(): + """Process multiple input files and store results using command line arguments.""" + valid_models = ['mechanics', 'singlePhaseFlow', 'compositionalMultiphaseFlow'] + + parser = argparse.ArgumentParser() + parser.add_argument('-m', '--model', required=True, choices=valid_models, help="Physics model") + parser.add_argument('-l', '--levels', nargs='+', type=int, help="Levels to process") + args = parser.parse_args() + + # Setup problem info + problems = { + "mechanics": [ + {"level": 2, "ranks": 8, "global_dofs": "20.7M"}, + {"level": 3, "ranks": 64, "global_dofs": "162M"}, + {"level": 4, "ranks": 512, "global_dofs": "1.3B"}, + {"level": 5, "ranks": 4096, "global_dofs": "10.2B"}, + {"level": 6, "ranks": 32768, "global_dofs": "81.3B"} + ], + "singlePhaseFlow": [ + {"level": 2, "ranks": 4, "global_dofs": "6.6M"}, + {"level": 3, "ranks": 32, "global_dofs": "52.8M"}, + {"level": 4, "ranks": 256, "global_dofs": "422M"}, + {"level": 5, "ranks": 2048, "global_dofs": "3.4B"}, + {"level": 6, "ranks": 16384, "global_dofs": "27B"} + ], + "compositionalMultiphaseFlow": [ + {"level": 2, "ranks": 4, "global_dofs": "19.8M"}, + {"level": 3, "ranks": 32, "global_dofs": "153M"}, + {"level": 4, "ranks": 256, "global_dofs": "1.2B"}, + {"level": 5, "ranks": 2048, "global_dofs": "9.8B"} + ] + } + + # Set default levels if not passed in + if args.levels is None: + args.levels = [entry['level'] for entry in problems[args.model]] + + # Read log files + results = [] + file_paths = [] + for level in args.levels: + target_dir, file_path = find_newest_file(args.model, level) + if file_path: + file_paths.append(file_path) + else: + print(f"No suitable files found in {target_dir}") + + # Parse statistics + results = [parse_log_file(fp) for fp in file_paths] + + # Print summary table + print_results(args.model, results) + + # Plot results + plot_results(args.model, problems[args.model], results) + +if __name__ == "__main__": + main() diff --git a/inputFiles/wellboreECP/singlePhaseFlow/ECP_Wellbore_probdef.xml b/inputFiles/wellboreECP/singlePhaseFlow/ECP_Wellbore_probdef.xml new file mode 100644 index 00000000000..73411abc18e --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/ECP_Wellbore_probdef.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level01/ECP_Wellbore_cpu.xml b/inputFiles/wellboreECP/singlePhaseFlow/level01/ECP_Wellbore_cpu.xml new file mode 100644 index 00000000000..56163cee621 --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level01/ECP_Wellbore_cpu.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level01/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/singlePhaseFlow/level01/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..81a0b3b84b6 --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level01/ECP_Wellbore_gpu.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level01/launch_frontier b/inputFiles/wellboreECP/singlePhaseFlow/level01/launch_frontier new file mode 100644 index 00000000000..d31e8dd39c3 --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level01/launch_frontier @@ -0,0 +1,13 @@ +#!/bin/bash +#SBATCH -N 1 +#SBATCH -n 1 +#SBATCH -t 0:30:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-singlePhaseFlow-geom01.out + +echo `date` +cmd="srun -N 1 -n 1 -c 1 --gpus-per-node=1 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 1 -y 1 -z 1 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level02/ECP_Wellbore_cpu.xml b/inputFiles/wellboreECP/singlePhaseFlow/level02/ECP_Wellbore_cpu.xml new file mode 100644 index 00000000000..dffc9e5be37 --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level02/ECP_Wellbore_cpu.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level02/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/singlePhaseFlow/level02/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..e784ec8cf0a --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level02/ECP_Wellbore_gpu.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level02/launch_frontier b/inputFiles/wellboreECP/singlePhaseFlow/level02/launch_frontier new file mode 100644 index 00000000000..2741050a32c --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level02/launch_frontier @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -N 1 +#SBATCH -n 4 +#SBATCH -t 0:30:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-singlePhaseFlow-geom02.out + +echo `date` +module load cpe/23.12 +module load craype-accel-amd-gfx90a +module load rocm/5.4.3 +export MPICH_GPU_SUPPORT_ENABLED=1 +ldd ${1} +cmd="srun -N 1 -n 4 -c 1 --gpus-per-node=4 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 1 -y 1 -z 4 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level03/ECP_Wellbore_cpu.xml b/inputFiles/wellboreECP/singlePhaseFlow/level03/ECP_Wellbore_cpu.xml new file mode 100644 index 00000000000..0f58cf96b36 --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level03/ECP_Wellbore_cpu.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level03/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/singlePhaseFlow/level03/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..33bc77be4fc --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level03/ECP_Wellbore_gpu.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level03/launch_frontier b/inputFiles/wellboreECP/singlePhaseFlow/level03/launch_frontier new file mode 100644 index 00000000000..b549f4c4ff5 --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level03/launch_frontier @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -N 4 +#SBATCH -n 32 +#SBATCH -t 0:30:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-singlePhaseFlow-geom03.out + +echo `date` +module load cpe/23.12 +module load craype-accel-amd-gfx90a +module load rocm/5.4.3 +export MPICH_GPU_SUPPORT_ENABLED=1 +ldd ${1} +cmd="srun -N 4 -n 32 -c 1 --gpus-per-node=8 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 2 -y 2 -z 8 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level04/ECP_Wellbore_cpu.xml b/inputFiles/wellboreECP/singlePhaseFlow/level04/ECP_Wellbore_cpu.xml new file mode 100644 index 00000000000..caf966a8b6e --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level04/ECP_Wellbore_cpu.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level04/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/singlePhaseFlow/level04/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..69294a7faca --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level04/ECP_Wellbore_gpu.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level04/launch_frontier b/inputFiles/wellboreECP/singlePhaseFlow/level04/launch_frontier new file mode 100644 index 00000000000..80748a5e6d7 --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level04/launch_frontier @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -N 32 +#SBATCH -n 256 +#SBATCH -t 0:30:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-singlePhaseFlow-geom04.out + +echo `date` +module load cpe/23.12 +module load craype-accel-amd-gfx90a +module load rocm/5.4.3 +export MPICH_GPU_SUPPORT_ENABLED=1 +ldd ${1} +cmd="srun -N 32 -n 256 -c 1 --gpus-per-node=8 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 4 -y 4 -z 16 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level05/ECP_Wellbore_cpu.xml b/inputFiles/wellboreECP/singlePhaseFlow/level05/ECP_Wellbore_cpu.xml new file mode 100644 index 00000000000..2b784e869dd --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level05/ECP_Wellbore_cpu.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level05/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/singlePhaseFlow/level05/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..4bfc1ff0df2 --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level05/ECP_Wellbore_gpu.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level05/launch_frontier b/inputFiles/wellboreECP/singlePhaseFlow/level05/launch_frontier new file mode 100644 index 00000000000..88572e1e96d --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level05/launch_frontier @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -N 256 +#SBATCH -n 2048 +#SBATCH -t 0:30:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-singlePhaseFlow-geom05.out + +echo `date` +module load cpe/23.12 +module load craype-accel-amd-gfx90a +module load rocm/5.4.3 +export MPICH_GPU_SUPPORT_ENABLED=1 +ldd ${1} +cmd="srun -N 256 -n 2048 -c 1 --gpus-per-node=8 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 8 -y 8 -z 32 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level06/ECP_Wellbore_gpu.xml b/inputFiles/wellboreECP/singlePhaseFlow/level06/ECP_Wellbore_gpu.xml new file mode 100644 index 00000000000..2cfaca7d3d5 --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level06/ECP_Wellbore_gpu.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/wellboreECP/singlePhaseFlow/level06/launch_frontier b/inputFiles/wellboreECP/singlePhaseFlow/level06/launch_frontier new file mode 100644 index 00000000000..3791ac44860 --- /dev/null +++ b/inputFiles/wellboreECP/singlePhaseFlow/level06/launch_frontier @@ -0,0 +1,18 @@ +#!/bin/bash +#SBATCH -N 2048 +#SBATCH -n 16384 +#SBATCH -t 0:30:00 +#SBATCH -J geos +#SBATCH -o frontier-%j-singlePhaseFlow-geom06.out + +echo `date` +module load cpe/23.12 +module load craype-accel-amd-gfx90a +module load rocm/5.4.3 +export MPICH_GPU_SUPPORT_ENABLED=1 +ldd ${1} +cmd="srun -N 2048 -n 16384 -c 1 --gpus-per-node=8 --ntasks-per-gpu=1 --gpu-bind=closest ${1} -i ECP_Wellbore_gpu.xml -x 16 -y 16 -z 64 ${2}" +echo "${cmd}" +${cmd} +echo `date` +echo 'Done' diff --git a/integratedTests b/integratedTests deleted file mode 160000 index 093d2eee4bb..00000000000 --- a/integratedTests +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 093d2eee4bb287983183991b49edb2956523b475 diff --git a/scripts/SchemaToRSTDocumentation.py b/scripts/SchemaToRSTDocumentation.py index 0710515381c..8a7b1a8cda7 100644 --- a/scripts/SchemaToRSTDocumentation.py +++ b/scripts/SchemaToRSTDocumentation.py @@ -1,7 +1,7 @@ import os import re -import sys -#import numpy as np +import shutil +import argparse from xml.etree import ElementTree as etree @@ -13,9 +13,11 @@ def comment(self, data): self.end(etree.Comment) -def writeTableRST(file_name, values): +def writeTableRST(type_name, file_name, title_prefix, values): + + element_header = '%s: %s' % (title_prefix, type_name) + L = [[len(x) for x in row] for row in values] - # M = tuple(np.amax(np.array(L), axis=0)) # np isn't in the docker images for our CI MAX = [None] * len(L[0]) @@ -55,7 +57,9 @@ def writeTableRST(file_name, values): # Build table with open(file_name, 'w') as f: - f.write('\n\n') + f.write('%s\n' % (element_header)) + f.write('=' * len(element_header) + '\n') + f.write('\n') f.write(boundary) f.write(formatted_lines[0]) f.write(boundary) @@ -191,6 +195,10 @@ def buildTableValues(type_map, link_string='XML', include_defaults=True): if k in type_map[att_name]: table_row[jj] = type_map[att_name][k] + # Fix type strings + if ('Type' in k): + table_row[jj] = table_row[jj].replace('_lt_', '<').replace('_gt_', '>').replace('_cm_', ',').replace('-', ' ') + # Format any registration entries as links if ('Registered' in k): table_row[jj] = ", ".join([':ref:`%s_%s`' % (link_string, x) for x in table_row[jj]]) @@ -207,107 +215,91 @@ def buildTableValues(type_map, link_string='XML', include_defaults=True): return table_values -# Config -if len(sys.argv) < 2: - print("Usage: %s " % sys.argv[0]) - sys.exit(1) -schema_dir = sys.argv[1] -schema_name = os.path.join(schema_dir, 'schema.xsd') -additional_documentation_name = os.path.join(schema_dir, 'schema.xsd.other') -complete_output = os.path.join(schema_dir, '../../docs/sphinx/CompleteXMLSchema') -output_folder = os.path.join(schema_dir, 'docs') -sphinx_path = '../../coreComponents/schema/docs' -xsd = '{http://www.w3.org/2001/XMLSchema}' - -# Parse the input/non-input schemas -parser = etree.XMLParser(target=TreeBuilderWithComments()) -include_tree = etree.parse(schema_name, parser=parser) -include_root = include_tree.getroot() -input_attribute_map = buildAttributeMap(include_root) - -parser = etree.XMLParser(target=TreeBuilderWithComments()) -include_tree = etree.parse(additional_documentation_name, parser=parser) -include_root = include_tree.getroot() -other_attribute_map = buildAttributeMap(include_root) - -# Check for non-unique (ignoring case) links -input_keys = sorted(input_attribute_map.keys()) -input_keys_lower = [k.lower() for k in input_keys] -input_keys_count = [input_keys_lower.count(k) for k in input_keys_lower] -input_repeated_keys = [input_keys[ii] for ii in range(0, len(input_keys)) if input_keys_count[ii] > 1] - -other_keys = sorted(other_attribute_map.keys()) -other_keys_lower = [k.lower() for k in other_keys] -other_keys_count = [other_keys_lower.count(k) for k in other_keys_lower] -other_repeated_keys = [other_keys[ii] for ii in range(0, len(other_keys)) if other_keys_count[ii] > 1] - -if ((len(input_repeated_keys) > 0) | (len(other_repeated_keys) > 0)): - print('Duplicate input documentation table names:') - print(input_repeated_keys) - print('Duplicate other documentation table names:') - print(other_repeated_keys) - raise ValueError('Duplicate data structure names are not allowed due to .rst limitations (case-insensitive)!') - -# Setup directory -os.system('mkdir -p %s' % (output_folder)) - -# Keep track of existing/touched files -old_files = [f for f in os.listdir(output_folder) if '.rst' in f] -touched_files = [] - -# Build documentation tables -with open('%s.rst' % (complete_output), 'w') as output_handle: - # Write the file header - output_handle.write('######################\n') - output_handle.write('Datastructure Index\n') - output_handle.write('######################\n\n') - - # Parse the input schema definitions - output_handle.write('**************************\n\n') - output_handle.write('Input Schema Definitions\n') - output_handle.write('**************************\n\n') - - output_handle.write(':download:`XML Schema <%s/../schema.xsd>`\n\n' % (sphinx_path)) - - for type_name in sorted(input_attribute_map.keys()): - # Write the individual tables - table_values = buildTableValues(input_attribute_map[type_name]) - writeTableRST('%s/%s.rst' % (output_folder, type_name), table_values) - touched_files.append('%s.rst' % (type_name)) - - # Write to the master list - element_header = 'Element: %s' % (type_name) - output_handle.write('\n.. _XML_%s:\n\n' % (type_name)) - output_handle.write('%s\n' % (element_header)) - output_handle.write('=' * len(element_header) + '\n') - output_handle.write('.. include:: %s/%s.rst\n\n' % (sphinx_path, type_name)) - - # Parse the non-input schema definitions - output_handle.write('********************************\n') - output_handle.write('Datastructure Definitions\n') - output_handle.write('********************************\n\n') - - for type_name in sorted(other_attribute_map.keys()): - # Write the individual tables - table_values = buildTableValues(other_attribute_map[type_name], - link_string='DATASTRUCTURE', - include_defaults=False) - writeTableRST('%s/%s_other.rst' % (output_folder, type_name), table_values) - touched_files.append('%s_other.rst' % (type_name)) - - # Write to the master list - element_header = 'Datastructure: %s' % (type_name) - output_handle.write('\n.. _DATASTRUCTURE_%s:\n\n' % (type_name)) - output_handle.write('%s\n' % (element_header)) - output_handle.write('=' * len(element_header) + '\n') - output_handle.write('.. include:: %s/%s_other.rst\n\n' % (sphinx_path, type_name)) - -# Check for any untouched tables -untouched_files = [] -for f in old_files: - if f not in touched_files: - untouched_files.append(f) - -if len(untouched_files): - tmp = '\n '.join(untouched_files) - raise ValueError('Obsolete autogenerated .rst table files detected:%s' % (tmp)) +def main(schema_name='schema.xsd', output_folder='./', xsd='{http://www.w3.org/2001/XMLSchema}'): + """ + Build RST Documentation Tables + """ + # Setup folders + additional_documentation_name = f'{schema_name}.other' + output_folder = os.path.abspath(os.path.expanduser(output_folder)) + datastructure_folder = os.path.join(output_folder, 'datastructure') + summary_file = os.path.join(datastructure_folder, 'CompleteXMLSchema.rst') + os.makedirs(datastructure_folder, exist_ok=True) + shutil.copy(schema_name, os.path.join(datastructure_folder, 'schema.xsd')) + shutil.copy(additional_documentation_name, os.path.join(datastructure_folder, 'schema.xsd.other')) + + # Parse the input/non-input schemas + parser = etree.XMLParser(target=TreeBuilderWithComments()) + include_tree = etree.parse(schema_name, parser=parser) + include_root = include_tree.getroot() + input_attribute_map = buildAttributeMap(include_root) + + parser = etree.XMLParser(target=TreeBuilderWithComments()) + include_tree = etree.parse(additional_documentation_name, parser=parser) + include_root = include_tree.getroot() + other_attribute_map = buildAttributeMap(include_root) + + # Check for non-unique (ignoring case) links + input_keys = sorted(input_attribute_map.keys()) + input_keys_lower = [k.lower() for k in input_keys] + input_keys_count = [input_keys_lower.count(k) for k in input_keys_lower] + input_repeated_keys = [input_keys[ii] for ii in range(0, len(input_keys)) if input_keys_count[ii] > 1] + + other_keys = sorted(other_attribute_map.keys()) + other_keys_lower = [k.lower() for k in other_keys] + other_keys_count = [other_keys_lower.count(k) for k in other_keys_lower] + other_repeated_keys = [other_keys[ii] for ii in range(0, len(other_keys)) if other_keys_count[ii] > 1] + + if ((len(input_repeated_keys) > 0) | (len(other_repeated_keys) > 0)): + print('Duplicate input documentation table names:') + print(input_repeated_keys) + print('Duplicate other documentation table names:') + print(other_repeated_keys) + raise ValueError('Duplicate data structure names are not allowed due to .rst limitations (case-insensitive)!') + + # Build documentation tables + with open(summary_file, 'w') as output_handle: + # Write the file header + output_handle.write('###################\n') + output_handle.write('Datastructure Index\n') + output_handle.write('###################\n\n') + + # Parse the input schema definitions + output_handle.write('************************\n') + output_handle.write('Input Schema Definitions\n') + output_handle.write('************************\n\n') + + output_handle.write(':download:`XML Schema `\n\n') + + for type_name in sorted(input_attribute_map.keys()): + # Write the individual tables + table_values = buildTableValues(input_attribute_map[type_name]) + writeTableRST( type_name, '%s/%s.rst' % (datastructure_folder, type_name), 'XML Element', table_values) + + # Write to the master list + output_handle.write('\n.. _XML_%s:\n\n' % (type_name)) + output_handle.write('.. include:: %s.rst\n\n' % (type_name)) + + # Parse the non-input schema definitions + output_handle.write('*************************\n') + output_handle.write('Datastructure Definitions\n') + output_handle.write('*************************\n\n') + + for type_name in sorted(other_attribute_map.keys()): + # Write the individual tables + table_values = buildTableValues(other_attribute_map[type_name], + link_string='DATASTRUCTURE', + include_defaults=False) + writeTableRST( type_name, '%s/%s_other.rst' % (datastructure_folder, type_name), 'Datastructure', table_values) + + # Write to the master list + output_handle.write('\n.. _DATASTRUCTURE_%s:\n\n' % (type_name)) + output_handle.write('.. include:: %s_other.rst\n\n' % (type_name)) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('-s', '--schema', type=str, help='GEOS schema file', default='schema.xsd') + parser.add_argument('-o', '--output', type=str, help='Output directory', default='./') + args = parser.parse_args() + main(schema_name=args.schema, output_folder=args.output) diff --git a/scripts/check_baseline_log.sh b/scripts/check_baseline_log.sh new file mode 100755 index 00000000000..85fa5aee8db --- /dev/null +++ b/scripts/check_baseline_log.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +DIFF=$(git diff --name-only origin/develop) + +if [[ $DIFF == *".integrated_tests.yaml"* ]]; then + echo "Changes to the integrated test baseline detected" + if [[ $DIFF != *"BASELINE_NOTES.md"* ]]; then + echo "You need to add a note to the BASELINE_NOTES.md file to justify changes to the test baselines" + exit 1 + fi +fi + diff --git a/scripts/ci_build_and_test_in_container.sh b/scripts/ci_build_and_test_in_container.sh index c292755a605..23bff96bfa3 100755 --- a/scripts/ci_build_and_test_in_container.sh +++ b/scripts/ci_build_and_test_in_container.sh @@ -1,19 +1,19 @@ #!/bin/bash set -o pipefail +export PYTHONDONTWRITEBYTECODE=1 + printenv SCRIPT_NAME=$0 echo "Running CLI ${SCRIPT_NAME} $@" -echo "running nproc" -nproc # docs.docker.com/config/containers/resource_constraints # Inside the container, tools like free report the host's available swap, not what's available inside the container. # Don't rely on the output of free or similar tools to determine whether swap is present. -echo "running free -m" -free -m +echo "running free -g" +free -g # The or_die function run the passed command line and # exits the program in case of non zero error code @@ -44,10 +44,16 @@ Usage: $0 The host-config. Path is relative to the root of the repository. --install-dir-basename GEOS-e42ffc1 GEOS installation basename. + --makefile + Use "Unix Makefiles" as build system generator. + --ninja + Use "Ninja" as build system generator. --no-install-schema Do not install the xsd schema. --no-run-unit-tests Do not run the unit tests (but they will be built). + --nproc N + Number of cores to use for the build. --repository /path/to/repository Internal mountpoint where the geos repository will be available. --run-integrated-tests @@ -66,17 +72,20 @@ exit 1 or_die cd $(dirname $0)/.. # Parsing using getopt -args=$(or_die getopt -a -o h --long build-exe-only,cmake-build-type:,code-coverage,data-basename:,exchange-dir:,host-config:,install-dir-basename:,no-install-schema,no-run-unit-tests,repository:,run-integrated-tests,sccache-credentials:,test-code-style,test-documentation,help -- "$@") +args=$(or_die getopt -a -o h --long build-exe-only,cmake-build-type:,code-coverage,data-basename:,exchange-dir:,host-config:,install-dir-basename:,makefile,ninja,no-install-schema,no-run-unit-tests,nproc:,repository:,run-integrated-tests,sccache-credentials:,test-code-style,test-documentation,help -- "$@") # Variables with default values BUILD_EXE_ONLY=false -GEOSX_INSTALL_SCHEMA=true +BUILD_GENERATOR="" +GEOS_INSTALL_SCHEMA=true HOST_CONFIG="host-configs/environment.cmake" RUN_UNIT_TESTS=true RUN_INTEGRATED_TESTS=false +UPLOAD_TEST_BASELINES=false TEST_CODE_STYLE=false TEST_DOCUMENTATION=false CODE_COVERAGE=false +NPROC="$(nproc)" eval set -- ${args} while : @@ -87,6 +96,9 @@ do RUN_UNIT_TESTS=false shift;; --cmake-build-type) CMAKE_BUILD_TYPE=$2; shift 2;; + --ninja) + BUILD_GENERATOR=$1; + shift;; --data-basename) DATA_BASENAME=$2 DATA_BASENAME_WE=${DATA_BASENAME%%.*} @@ -99,11 +111,14 @@ do shift 2;; --exchange-dir) DATA_EXCHANGE_DIR=$2; shift 2;; --host-config) HOST_CONFIG=$2; shift 2;; - --install-dir-basename) GEOSX_DIR=${GEOSX_TPL_DIR}/../$2; shift 2;; - --no-install-schema) GEOSX_INSTALL_SCHEMA=false; shift;; + --install-dir-basename) GEOS_DIR=${GEOSX_TPL_DIR}/../$2; shift 2;; + --makefile) BUILD_GENERATOR=""; shift;; + --no-install-schema) GEOS_INSTALL_SCHEMA=false; shift;; --no-run-unit-tests) RUN_UNIT_TESTS=false; shift;; + --nproc) NPROC=$2; shift 2;; --repository) GEOS_SRC_DIR=$2; shift 2;; --run-integrated-tests) RUN_INTEGRATED_TESTS=true; shift;; + --upload-test-baselines) UPLOAD_TEST_BASELINES=true; shift;; --code-coverage) CODE_COVERAGE=true; shift;; --sccache-credentials) SCCACHE_CREDS=$2; shift 2;; --test-code-style) TEST_CODE_STYLE=true; shift;; @@ -121,9 +136,9 @@ if [[ -z "${GEOS_SRC_DIR}" ]]; then exit 1 fi -if [[ -z "${GEOSX_DIR}" ]]; then +if [[ -z "${GEOS_DIR}" ]]; then echo "Installation folder undefined. Set to default value '/dev/null'. You can define it using '--install-dir-basename'." - GEOSX_DIR=/dev/null + GEOS_DIR=/dev/null fi if [[ ! -z "${SCCACHE_CREDS}" ]]; then @@ -143,9 +158,9 @@ EOT # The path to the `sccache` executable is available through the SCCACHE environment variable. SCCACHE_CMAKE_ARGS="-DCMAKE_CXX_COMPILER_LAUNCHER=${SCCACHE} -DCMAKE_CUDA_COMPILER_LAUNCHER=${SCCACHE}" - if [[ ${HOSTNAME} == 'streak.llnl.gov' ]]; then - DOCKER_CERTS_DIR=/usr/local/share/ca-certificates - for file in "${GEOS_SRC_DIR}"/certificates/*.crt.pem; do + if [ -n "${DOCKER_CERTS_DIR}" ] && [ -n "${DOCKER_CERTS_UPDATE_COMMAND}" ]; then + echo "updating certificates." + for file in "${DOCKER_CERTS_DIR}"/llnl/*.crt.pem; do if [ -f "$file" ]; then filename=$(basename -- "$file") filename_no_ext="${filename%.*}" @@ -154,19 +169,19 @@ EOT echo "Copied $filename to $new_filename" fi done - update-ca-certificates - # gcloud config set core/custom_ca_certs_file cert.pem' - - NPROC=8 - else - NPROC=$(nproc) + ${DOCKER_CERTS_UPDATE_COMMAND} fi - echo "Using ${NPROC} cores." echo "sccache initial state" ${SCCACHE} --show-stats fi +if [ -z "${NPROC}" ]; then + NPROC=$(nproc) + echo "NPROC unset, setting to ${NPROC}..." +fi +echo "Using ${NPROC} cores." + if [[ "${RUN_INTEGRATED_TESTS}" = true ]]; then echo "Running the integrated tests has been requested." # We install the python environment required by ATS to run the integrated tests. @@ -174,7 +189,18 @@ if [[ "${RUN_INTEGRATED_TESTS}" = true ]]; then or_die apt-get install -y virtualenv python3-dev python-is-python3 ATS_PYTHON_HOME=/tmp/run_integrated_tests_virtualenv or_die virtualenv ${ATS_PYTHON_HOME} - ATS_CMAKE_ARGS="-DATS_ARGUMENTS=\"--machine openmpi --ats openmpi_mpirun=/usr/bin/mpirun --ats openmpi_args=--allow-run-as-root --ats openmpi_procspernode=2 --ats openmpi_maxprocs=2\" -DPython3_ROOT_DIR=${ATS_PYTHON_HOME}" + + python3 -m pip cache purge + + # Setup a temporary directory to hold tests + tempdir=$(mktemp -d) + echo "Setting up a temporary directory to hold tests and baselines: $tempdir" + trap "rm -rf $tempdir" EXIT + ATS_BASELINE_DIR=$tempdir/GEOS_integratedTests_baselines + ATS_WORKING_DIR=$tempdir/GEOS_integratedTests_working + + export ATS_FILTER="np<=32" + ATS_CMAKE_ARGS="-DATS_ARGUMENTS=\"--machine openmpi --ats openmpi_mpirun=/usr/bin/mpirun --ats openmpi_args=--allow-run-as-root --ats openmpi_procspernode=32 --ats openmpi_maxprocs=32\" -DPython3_ROOT_DIR=${ATS_PYTHON_HOME} -DATS_BASELINE_DIR=${ATS_BASELINE_DIR} -DATS_WORKING_DIR=${ATS_WORKING_DIR}" fi @@ -194,25 +220,25 @@ fi # The option `--oversubscribe` tells OpenMPI to allow more MPI ranks than the node has cores. # This is needed because our unit test `blt_mpi_smoke` is run in parallel with _hard coded_ 4 ranks. # While some of our ci nodes may have less cores available. -# +# # In case we have more powerful nodes, consider removing `--oversubscribe` and use `--use-hwthread-cpus` instead. # This will tells OpenMPI to discover the number of hardware threads on the node, # and use that as the number of slots available. (There is a distinction between threads and cores). -GEOSX_BUILD_DIR=/tmp/geos-build +GEOS_BUILD_DIR=/tmp/geos-build or_die python3 scripts/config-build.py \ -hc ${HOST_CONFIG} \ -bt ${CMAKE_BUILD_TYPE} \ - -bp ${GEOSX_BUILD_DIR} \ - -ip ${GEOSX_DIR} \ - --ninja \ + -bp ${GEOS_BUILD_DIR} \ + -ip ${GEOS_DIR} \ + ${BUILD_GENERATOR} \ -DBLT_MPI_COMMAND_APPEND='"--allow-run-as-root;--oversubscribe"' \ - -DGEOSX_INSTALL_SCHEMA=${GEOSX_INSTALL_SCHEMA} \ + -DGEOS_INSTALL_SCHEMA=${GEOS_INSTALL_SCHEMA} \ -DENABLE_COVERAGE=$([[ "${CODE_COVERAGE}" = true ]] && echo 1 || echo 0) \ ${SCCACHE_CMAKE_ARGS} \ ${ATS_CMAKE_ARGS} # The configuration step is now over, we can now move to the build directory for the build! -or_die cd ${GEOSX_BUILD_DIR} +or_die cd ${GEOS_BUILD_DIR} # Code style check if [[ "${TEST_CODE_STYLE}" = true ]]; then @@ -228,15 +254,21 @@ fi # Performing the requested build. if [[ "${BUILD_EXE_ONLY}" = true ]]; then - or_die ninja -j $NPROC geosx + or_die cmake --build . -j $NPROC --target geosx else - or_die ninja -j $NPROC - or_die ninja install + or_die cmake --build . -j $NPROC + or_die cmake --install . if [[ ! -z "${DATA_BASENAME_WE}" ]]; then # Here we pack the installation. # The `--transform` parameter provides consistency between the tarball name and the unpacked folder. - or_die tar czf ${DATA_EXCHANGE_DIR}/${DATA_BASENAME_WE}.tar.gz --directory=${GEOSX_TPL_DIR}/.. --transform "s|^./|${DATA_BASENAME_WE}/|" . + echo "DATA_EXCHANGE_DIR=${DATA_EXCHANGE_DIR}" + echo "DATA_BASENAME_WE=${DATA_BASENAME_WE}" + echo "GEOS_TPL_DIR=${GEOS_TPL_DIR}" + echo "GEOSX_TPL_DIR=${GEOSX_TPL_DIR}" + GEOS_TPL_DIR=${GEOSX_TPL_DIR} + echo tar czf ${DATA_EXCHANGE_DIR}/${DATA_BASENAME_WE}.tar.gz --directory=${GEOS_TPL_DIR}/.. --transform "s|^./|${DATA_BASENAME_WE}/|" . + or_die tar czf ${DATA_EXCHANGE_DIR}/${DATA_BASENAME_WE}.tar.gz --directory=${GEOS_TPL_DIR}/.. --transform "s|^./|${DATA_BASENAME_WE}/|" . fi fi @@ -246,14 +278,14 @@ if [[ ! -z "${SCCACHE_CREDS}" ]]; then fi if [[ "${CODE_COVERAGE}" = true ]]; then - or_die ninja coreComponents_coverage - cp -r ${GEOSX_BUILD_DIR}/coreComponents_coverage.info.cleaned ${GEOS_SRC_DIR}/geos_coverage.info.cleaned + or_die cmake --build . --target coreComponents_coverage + cp -r ${GEOS_BUILD_DIR}/coreComponents_coverage.info.cleaned ${GEOS_SRC_DIR}/geos_coverage.info.cleaned fi # Run the unit tests (excluding previously ran checks). if [[ "${RUN_UNIT_TESTS}" = true ]]; then - if [[ ${HOSTNAME} == 'streak.llnl.gov' ]]; then - or_die ctest --output-on-failure -E "testUncrustifyCheck|testDoxygenCheck|testLifoStorage|testExternalSolvers" + if [ ${HOSTNAME} == 'streak.llnl.gov' ] || [ ${HOSTNAME} == 'streak2.llnl.gov' ]; then + or_die ctest --output-on-failure -E "testUncrustifyCheck|testDoxygenCheck|testExternalSolvers" else or_die ctest --output-on-failure -E "testUncrustifyCheck|testDoxygenCheck" fi @@ -261,32 +293,52 @@ fi if [[ "${RUN_INTEGRATED_TESTS}" = true ]]; then # We split the process in two steps. First installing the environment, then running the tests. - or_die ninja ats_environment - # The tests are not run using ninja (`ninja --verbose ats_run`) because it swallows the output while all the simulations are running. + or_die cmake --build . --target ats_environment + + # The tests are not run using cmake (`cmake --build . --verbose --target ats_run`) + # because with ninja it swallows the output while all the + # simulations are running. # We directly use the script instead... - # Temporarily, we are not adding the `--failIfTestsFail` options to `geos_ats.sh`. - # Therefore, `ats` will exit with error code 0, even if some tests fail. - # Add `--failIfTestsFail` when you want `failIfTestsFail` to reflect the content of the tests. - integratedTests/geos_ats.sh - # Even (and even moreover) if the integrated tests fail, we want to pack the results for further investigations. - # So we store the status code for further use. - INTEGRATED_TEST_EXIT_STATUS=$? - echo "The return code of the integrated tests is ${INTEGRATED_TEST_EXIT_STATUS}" + echo "Available baselines:" + ls -lR /tmp/geos/baselines + + echo "Running integrated tests..." + integratedTests/geos_ats.sh --baselineCacheDirectory /tmp/geos/baselines + tar -czf ${DATA_EXCHANGE_DIR}/test_logs_${DATA_BASENAME_WE}.tar.gz integratedTests/TestResults - # Whatever the result of the integrated tests, we want to pack both the logs and the computed results. - # They are not in the same folder, so we do it in 2 steps. - # The `--transform` parameter is here to separate the two informations (originally in a folder with the same name) - # in two different folder with meaningful names when unpacking. - or_die tar cfM ${DATA_EXCHANGE_DIR}/${DATA_BASENAME_WE}.tar --directory ${GEOS_SRC_DIR} --transform "s/^integratedTests/${DATA_BASENAME_WE}\/repo/" integratedTests - or_die tar rfM ${DATA_EXCHANGE_DIR}/${DATA_BASENAME_WE}.tar --directory ${GEOSX_BUILD_DIR} --transform "s/^integratedTests/${DATA_BASENAME_WE}\/logs/" integratedTests - or_die gzip ${DATA_EXCHANGE_DIR}/${DATA_BASENAME_WE}.tar + echo "Checking results..." + bin/geos_ats_log_check integratedTests/TestResults/test_results.ini -y ${GEOS_SRC_DIR}/.integrated_tests.yaml &> $tempdir/log_check.txt + cat $tempdir/log_check.txt - # want to clean the integrated tests folder to avoid polluting the next build. - or_die integratedTests/geos_ats.sh -a clean + if grep -q "Overall status: PASSED" "$tempdir/log_check.txt"; then + echo "IntegratedTests passed. No rebaseline required." + INTEGRATED_TEST_EXIT_STATUS=0 + else + echo "IntegratedTests failed. Rebaseline is required." + + # Rebaseline and pack into an archive + echo "Rebaselining..." + integratedTests/geos_ats.sh -a rebaselinefailed + + echo "Packing baselines..." + integratedTests/geos_ats.sh -a pack_baselines --baselineArchiveName ${DATA_EXCHANGE_DIR}/baseline_${DATA_BASENAME_WE}.tar.gz --baselineCacheDirectory /tmp/geos/baselines + INTEGRATED_TEST_EXIT_STATUS=1 + fi + + echo "Done!" + + # INTEGRATED_TEST_EXIT_STATUS=$? + echo "The return code of the integrated tests is ${INTEGRATED_TEST_EXIT_STATUS}" fi # Cleaning the build directory. -or_die ninja clean +or_die cmake --build . --target clean + + +# Clean the repository +or_die cd ${GEOS_SRC_DIR}/inputFiles +find . -name *.pyc | xargs rm -f + # If we're here, either everything went OK or we have to deal with the integrated tests manually. if [[ ! -z "${INTEGRATED_TEST_EXIT_STATUS+x}" ]]; then @@ -295,4 +347,4 @@ if [[ ! -z "${INTEGRATED_TEST_EXIT_STATUS+x}" ]]; then else echo "Exiting the build process with exit status 0." exit 0 -fi \ No newline at end of file +fi diff --git a/scripts/copyrightPrepender.py b/scripts/copyrightPrepender.py index 9ddd06aa943..1fb3a3f3925 100644 --- a/scripts/copyrightPrepender.py +++ b/scripts/copyrightPrepender.py @@ -23,70 +23,49 @@ # # Modified from an initial script by P. Sinha +# this is a handy command to check if there are any files that have not be changed from HEAD +# git ls-files --full-name | grep -v "$(git diff --name-only HEAD)" + import os import sys import argparse copyright_str = \ - """/* +"""/* * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ - """ old_copyright_str = \ -"""/* - *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Copyright (c) 2019, Lawrence Livermore National Security, LLC. - * - * Produced at the Lawrence Livermore National Laboratory - * - * LLNL-CODE-746361 - * - * All rights reserved. See COPYRIGHT for details. +""" +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only * - * This file is part of the GEOSX Simulation Framework. + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * - * GEOSX is a free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License (as published by the - * Free Software Foundation) version 2.1 dated February 1999. - *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ */ - """ -# old_copyright_str = \ -# """/* -# *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# * Copyright (c) 2018, Lawrence Livermore National Security, LLC. -# * -# * Produced at the Lawrence Livermore National Laboratory -# * -# * LLNL-CODE-746361 -# * -# * All rights reserved. See COPYRIGHT for details. -# * -# * This file is part of the GEOSX Simulation Framework. -# * -# * GEOSX is a free software; you can redistribute it and/or modify it under -# * the terms of the GNU Lesser General Public License (as published by the -# * Free Software Foundation) version 2.1 dated February 1999. -# *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# */ -# -# """ - copyright_str_arr = copyright_str.split("\n")[:-1] old_copyright_str_arr = old_copyright_str.split("\n")[:-1] @@ -114,10 +93,10 @@ def getLineToBeginAt(lines): # If the file has the copyright header check if it needs to be updated. if copyright_match: if lines[1][:-1] == copyright_str_arr[1]: - print "\t Already has copyright statement." + print( "\t Already has copyright statement." ) return -1 - print "\t Need to update copyright statement." + print( "\t Need to update copyright statement." ) return len(copyright_str_arr) # Check if the file has the old header. @@ -131,10 +110,10 @@ def getLineToBeginAt(lines): break if old_copyright_match: - print "\t Has old copyright statement." + print( "\t Has old copyright statement." ) return len(old_copyright_str_arr) - print "\t Missing copyright statement." + print( "\t Missing copyright statement." ) return -2 @@ -143,7 +122,7 @@ def checkAndAddCopyrightHeader(filename, testOnly=False): """ with open(filename, "r+") as f: - # print " Processing file {}:".format(filename) + # print( " Processing file {}:".format(filename) ) lines = [] for i in range(max_copyright_lines): @@ -163,7 +142,7 @@ def checkAndAddCopyrightHeader(filename, testOnly=False): f.seek(0) f.write(copyright_str) f.writelines(lines[line_to_begin_at:]) - print "\t Prepended copyright statement." + print ( "\t Prepended copyright statement." ) def fileNameGenerator(rootDir, validExtensions, isRecursive=False): @@ -215,6 +194,6 @@ def fileNameGenerator(rootDir, validExtensions, isRecursive=False): args = parser.parse_args() ## Iterate through files, check for and add copyright notice - print "Looking at directory {}".format(args.dir) + print( "Looking at directory {}".format(args.dir) ) for fullFileName in fileNameGenerator(args.dir, valid_extensions, args.isRecursive): checkAndAddCopyrightHeader(fullFileName, args.test) diff --git a/scripts/postProcessing/SneddonValidation.py b/scripts/postProcessing/SneddonValidation.py index c49d4b4c254..ca5708d83c5 100644 --- a/scripts/postProcessing/SneddonValidation.py +++ b/scripts/postProcessing/SneddonValidation.py @@ -77,7 +77,7 @@ def main(filesPaths): # Read HDF5 hf = h5py.File(hdf5File1Path, 'r') jump = hf.get('displacementJump') - jump = np.array(jump) + jump = np.asarray(jump) aperture = jump[0, :, 0] hf = h5py.File(hdf5File1Path, 'r') diff --git a/scripts/postProcessing/plotsolution_thermalFlow.py b/scripts/postProcessing/plotsolution_thermalFlow.py index a7fc5695da3..283bc0d12af 100644 --- a/scripts/postProcessing/plotsolution_thermalFlow.py +++ b/scripts/postProcessing/plotsolution_thermalFlow.py @@ -17,21 +17,21 @@ def main(directory): # Read simulation output from HDF5 file hf = h5py.File(hdf5FilePathTemperature, 'r') timeTemperature = hf.get('temperature Time') - timeTemperature = np.array(timeTemperature) + timeTemperature = np.asarray(timeTemperature) centerTemperature = hf.get('temperature elementCenter') - centerTemperature = np.array(centerTemperature) + centerTemperature = np.asarray(centerTemperature) xcord_elm = centerTemperature[0,:,0] ycord_elm = centerTemperature[0,:,1] zcord_elm = centerTemperature[0,:,2] temperature = hf.get('temperature') - temperature = np.array(temperature) + temperature = np.asarray(temperature) print(ycord_elm) filename = "pressure_history.hdf5" hdf5FilePathPressure = os.path.join( directory, filename ) hf = h5py.File(hdf5FilePathPressure, 'r') - pressure = np.array( hf.get('pressure') ) + pressure = np.asarray( hf.get('pressure') ) t_index = [0, 1, 2, 9] tstar = [0, 100, 200, 900] @@ -57,9 +57,9 @@ def main(directory): pplist.append(ptemp) temperaturelist.append(ttemp) - xlist = np.array(xlist) - pplist = np.array(pplist) - temperaturelist = np.array(temperaturelist) + xlist = np.asarray(xlist) + pplist = np.asarray(pplist) + temperaturelist = np.asarray(temperaturelist) #Visualization diff --git a/scripts/processIntegratedTestCheckFailures.py b/scripts/processIntegratedTestCheckFailures.py index ab5183322b9..db503687f42 100644 --- a/scripts/processIntegratedTestCheckFailures.py +++ b/scripts/processIntegratedTestCheckFailures.py @@ -48,9 +48,11 @@ def findFiles(folder, extension): matchStrings = ['Error:'] # What stings to look for in order to exclude a block +print( args.exclusionStrings ) +exclusionStrings = [] #exclusionStrings = [ 'sizedFromParent', 'different shapes' ] -#exclusionStrings = [ 'sizedFromParent', 'different shapes', 'but not the' ] -exclusionStrings = ['logLevel', 'NonlinearSolverParameters', 'has a child', 'different shapes', 'different types', 'differing types'] +#exclusionStrings = [ 'but not the' ] +#exclusionStrings = ['logLevel', 'NonlinearSolverParameters', 'has a child', 'different shapes', 'different types', 'differing types'] exclusionStrings += args.exclusionStrings directory = args.directory diff --git a/scripts/pygeosx_configs/blueos_3_ppc64le_ib_p9/spack.yaml b/scripts/pygeosx_configs/blueos_3_ppc64le_ib_p9/spack.yaml index 565a12075fc..008808c9726 100644 --- a/scripts/pygeosx_configs/blueos_3_ppc64le_ib_p9/spack.yaml +++ b/scripts/pygeosx_configs/blueos_3_ppc64le_ib_p9/spack.yaml @@ -1,10 +1,10 @@ #------------------------------------------------------------------------------------------------------------ # SPDX-License-Identifier: LGPL-2.1-only # -# Copyright (c) 2018-2020 Lawrence Livermore National Security LLC -# Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University -# Copyright (c) 2018-2020 TotalEnergies -# Copyright (c) 2019- GEOSX Contributors +# Copyright (c) 2018-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2019- GEOS/GEOSX Contributors # All rights reserved # # See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/scripts/pygeosx_configs/toss_4_x86_64_ib/spack.yaml b/scripts/pygeosx_configs/toss_4_x86_64_ib/spack.yaml index 0fb9dc34d75..efc5a9acbf0 100644 --- a/scripts/pygeosx_configs/toss_4_x86_64_ib/spack.yaml +++ b/scripts/pygeosx_configs/toss_4_x86_64_ib/spack.yaml @@ -1,10 +1,10 @@ #------------------------------------------------------------------------------------------------------------ # SPDX-License-Identifier: LGPL-2.1-only # -# Copyright (c) 2018-2020 Lawrence Livermore National Security LLC -# Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University -# Copyright (c) 2018-2020 TotalEnergies -# Copyright (c) 2019- GEOSX Contributors +# Copyright (c) 2018-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2019- GEOS/GEOSX Contributors # All rights reserved # # See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/scripts/repositoryStats.sh b/scripts/repositoryStats.sh new file mode 100644 index 00000000000..62b6b996909 --- /dev/null +++ b/scripts/repositoryStats.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# This script is used to get the number of line changes with time +# Usage: +# bash repositoryStats.sh +# + +months=`seq 1 12` +years=`seq 2016 2024` + +echo "Month-Year NumDevelopersMonth numDevelopers3MonthWindow NumDevelopersTotal NumCommitsMonth NumCommitsTotal NumLinesInMonth" +for year in $years +do + for month in $months + do + numLines=$(git log --since="$year-$month-01" --until="$year-$month-31" --format= --numstat | awk '{s+=$1; s+=$2} END {print s}') + #numDevelopersMonth=$(git log --since="$year-$month-01" --until="$year-$month-31" --all --pretty="%an" | sort | uniq | tr -d " ' " | xargs python3 repositoryStats_condenseDev.py) + numDevelopersMonth=$(git log --since="$year-$month-01" --until="$year-$month-31" | grep -E 'Author:|Co-authored-by:' | sed 's/^.*: //' | sed 's/<.*//' | sort | uniq | tr -d " ' " | xargs python3 repositoryStats_condenseDev.py) + + minus1month=$(date -j -v-1m -f "%Y-%m-%d" "$year-$month-15" "+%Y-%m-%d") + plus1month=$(date -j -v+1m -f "%Y-%m-%d" "$year-$month-15" "+%Y-%m-%d") + +# echo "Begin: $minus1month End: $plus1month" + + # numDevelopers3Month=$(git log --since="$minus1month" --until="$plus1month" --all --pretty="%an" | sort | uniq | tr -d " ' " | xargs python3 repositoryStats_condenseDev.py) + # numDevelopersTotal=$(git log --since="2010-01-01" --until="$year-$month-31" --all --pretty="%an" | sort | uniq | tr -d " ' " | xargs python3 repositoryStats_condenseDev.py) + numDevelopers3Month=$(git log --since="$minus1month" --until="$plus1month" | grep -E 'Author:|Co-authored-by:' | sed 's/^.*: //' | sed 's/<.*//' | sort | uniq | tr -d " ' " | xargs python3 repositoryStats_condenseDev.py) + numDevelopersTotal=$(git log --since="2010-01-01" --until="$year-$month-31" | grep -E 'Author:|Co-authored-by:' | sed 's/^.*: //' | sed 's/<.*//' | sort | uniq | tr -d " ' " | xargs python3 repositoryStats_condenseDev.py) + + numCommitsMonth=$(git rev-list --count HEAD --since="$year-$month-01" --before="$year-$month-31") + numCommitsTotal=$(git rev-list --count HEAD --since="2010-01-01" --before="$year-$month-31") + echo "$month-$year $numDevelopersMonth $numDevelopers3Month $numDevelopersTotal $numCommitsMonth $numCommitsTotal $numLines" + done +done + + diff --git a/scripts/repositoryStats_condenseDev.py b/scripts/repositoryStats_condenseDev.py new file mode 100644 index 00000000000..3146a5a1412 --- /dev/null +++ b/scripts/repositoryStats_condenseDev.py @@ -0,0 +1,321 @@ +import sys + +# +# git log --since="2010-01-01" --until="2026-11-31" --all --pretty="%an" | sort | uniq | tr -d " ' " | xargs python3 repositoryStats_condenseDev.py +# + +# Define the username mapping dictionary +username_mapping = { +"AleksNovikov" : "aleksnovikov", +"AlexandreLapene" : "alexandrelapene", +"Algiane" : "algiane", +"AlgianeFroehly" : "algianefroehly", +"AmmarAlali" : "ammaralali", +"AndreaBorio" : "andreaborio", +"AndreaFranceschini" : "andreafranceschini", +"AndreCosta" : "andrecosta", +"AndreMacieiraBragaCosta" : "andrecosta", +"andrembcosta" : "andrecosta", +"AntoineMazuyer" : "antoinemazuyer", +"mazuyer" : "antoinemazuyer", +"ArnaudDUDES" : "arnauddudes", +"arng40" : "arnauddudes", +"ArturoVargas" : "arturovargas", +"Aurelien" : "aurelien", +"acitrain" : "aurelien", +"aure-lily" : "aurelily", +"Ben" : "bencorbett", +"BenCorbett" : "bencorbett", +"BenjaminCorbett" : "bencorbett", +"BenjaminCurticeCorbett" : "bencorbett", +"BenjaminT.Liu" : "benjamintliu", +"BertrandThierry" : "bertrandthierry", +"BrianHan" : "brianhan", +"BrianManhHienHan" : "brianhan", +"CameronCrook" : "cameroncrook", +"CameronMikelCrook" : "cameroncrook", +"cmcrook5" : "cameroncrook", +"Castelletto" : "castelletto", +"Castelletto1" : "castelletto", +"NicolaCastelletto" : "castelletto", +"castelletto1" : "castelletto", +"ChaoyiWang" : "chaoyiwang", +"ChristopherSherman" : "christophersherman", +"ChrisWhite" : "chriswhite", +"DanielOsei-Kuffuor" : "danieloseikuffuor", +"david4utd" : "ruiwang", +"DicksonKachuma" : "dicksonkachuma", +"dkachuma" : "dicksonkachuma", +"FrancoisHamon" : "francoishamon", +"francoishamon" : "francoishamon", +"FanFei" : "frankfeifan", +"Fei" : "frankfeifan", +"frankfeifan" : "frankfeifan", +"fanfei" : "frankfeifan", +"fei2" : "frankfeifan", +"Gaetan" : "gaetanfuss", +"GaetanFuss" : "gaetanfuss", +"GerasimosChourdakis" : "gerasimoschourdakis", +"Guotong" : "guotongren", +"GuotongRen" : "guotongren", +"Guotong-Ren" : "guotongren", +"hannah_mairs" : "hannahmairs", +"HerveGross" : "hervegross", +"HeweiTang" : "heweitang", +"HuiWu" : "huiwu", +"IbrahimIsraa" : "ibrahimisraa", +"IgorShovkun" : "igorshovkun", +"IsaacJu" : "isaacju", +"IsaacJu-debug" : "isaacju", +"JacquesFranc" : "jacquesfranc", +"jacques" : "jacquesfranc", +"jacquesn7" : "jacquesfranc", +"jafranc" : "jacquesfranc", +"jfranc" : "jacquesfranc", +"JaisreeIyer" : "jaisreeiyer", +"JamesCorbett" : "jamescorbett", +"jay-a" : "jay-a", +"JeannePellerin" : "jeannepellerin", +"JieMeng" : "jiemeng", +"jiamin.jiang" : "jiaminjiang", +"jiemeng-total" : "jiemeng", +"jhuang2601" : "jianhuang", +"JianHUANG" : "jianhuang", +"JianHuang" : "jianhuang", +"JixiangHuang" : "jixianghuang", +"JoshuaWhite" : "joshuawhite", +"joshua-white" : "joshuawhite", +"joshwhite" : "joshuawhite", +"julia.camargo" : "juliacamargo", +"juliatcamargo" : "juliacamargo", +"BESSETJulien" : "julienrenethomasbesset", +"Julien" : "julienrenethomasbesset", +"JulienReneThomasBesset" : "julienrenethomasbesset", +"KevinJ.Dugan" : "kevinjdugan", +"labesse40" : "julienrenethomasbesset", +"liyangrock" : "liyangrock", +"LionelUntereiner" : "lioneluntereiner", +"LucasVALARCHER" : "lucasvalarcher", +"ŁukaszŁaniewski-Wołłk" : "lukaszlaniewski-wollk", +"MadonnaYoder" : "madonnayoder", +"MamadouN'diaye" : "mamadoundiaye", +"MamadouNdiaye" : "mamadoundiaye", +"mndiaye24" : "mamadoundiaye", +"MarkKhait" : "markkhait", +"mkhait" : "markkhait", +"Cusini" : "matteocusini", +"Matteo" : "matteocusini", +"MatteoCusini" : "matteocusini", +"MatteoFrigo" : "matteofrigo5", +"matteofrigo5" : "matteofrigo5", +"mfrigo" : "matteofrigo5", +"Matthias" : "matthiascremon", +"MatthiasCremon" : "matthiascremon", +"MelReyCG" : "melreycg", +"MichaelHomel" : "michaelhomel", +"MiladBader" : "miladbader", +"MohammadKarimi-Fard" : "mohammadkarimifard", +"OluwatobiQuadriRaji" : "oluwatobiquadri", +"Oluwatobi-PM" : "oluwatobiquadri", +"Ouassim" : "ouassim", +"paloma-martinez" : "palomamartinez", +"PavelTomin" : "paveltomin", +"paveltomin" : "paveltomin", +"PengchengFu" : "pengchengfu", +"PeterB.Robinson" : "peterbrobinson", +"robinspb" : "peterbrobinson", +"PhillipChacon" : "phillipchacon", +"TheLastBlockbender" : "phillipchacon", +"QuanBui" : "quanbui", +"RandolphR.Settgast" : "randolphrsettgast", +"RandolphSettgast" : "randolphrsettgast", +"RandySettgast" : "randolphrsettgast", +"UncrustifyRobot" : "randolphrsettgast", +"dependabot[bot]" : "randolphrsettgast", +"geosadmn" : "randolphrsettgast", +"rasimHZ" : "rasimhz", +"Ron-Wang" : "ronwang", +"rustem.zaydullin@totalenergies.com" : "rustemzaydullin", +"RyanARONSON(X)" : "ryanaronson", +"RyanAronson" : "ryanaronson", +"SergeyKlevtsov" : "sergeyklevtsov", +"Shabnam" : "shabnamjandaghisemnani", +"ShabnamJandaghiSemnani" : "shabnamjandaghisemnani", +"shabnamjs" : "shabnamjandaghisemnani", +"SohailWaziri" : "sohailwaziri", +"sohailwaziri" : "sohailwaziri", +"StefanoFrambati" : "stefanoframbati", +"j0405284" : "stefanoframbati", +"sframba" : "stefanoframbati", +"StefanPovolny" : "stefanpovolny", +"povolny1" : "stefanpovolny", +"stenix" : "stenix", +"Sy-TuanNguyen" : "sytuannguyen", +"sytuannguyen" : "sytuannguyen", +"TaehoKim" : "taehokim", +"kimtaeho07" : "taehokim", +"TaoJin" : "taojin", +"tbeltzun" : "tbeltzun", +"TerryLigocki" : "terryligocki", +"ThomasGAZZOLA" : "thomasgazzola", +"ThomasGazzola" : "thomasgazzola", +"TotoGaz" : "thomasgazzola", +"TomByer" : "tombyer", +"ThomasJamesByer" : "tombyer", +"tjb" : "tombyer", +"tony" : "tony", +"VictorA.P.Magri" : "victorapmagri", +"VictorA.PaludettoMagri" : "victorapmagri", +"WilliamRTobin" : "williamrtobin", +"WilliamTobin" : "williamrtobin", +"wrtobin" : "williamrtobin", +"WuHuiLLNL" : "wuhuillnl", +"XavierLacoste" : "xavierlacoste", +"YohannDudouit" : "yohanndudouit", +"YueHao" : "yuehao" +} + +inverse_username_mapping = { + "aleksnovikov":"Aleks Novikov" , + "alexandrelapene":"Alexandre Lapene" , + "algianefroehly":"Algiane Froehly" , + "ammaralali":"Ammar Alali" , + "andreaborio":"Andrea Borio" , + "andreafranceschini":"Andrea Franceschini" , + "andrecosta":"Andre Macieira Braga Costa" , + "antoinemazuyer":"Antoine Mazuyer" , + "arnauddudes":"Arnaud Dudes" , + "arturovargas":"Arturo Vargas" , + "aurelien":"Aurelien Citrain" , + "aurelily":"aure-lily" , + "bencorbett":"Benjamin Curtice Corbett" , + "benjamintliu":"Benjamin T. Liu" , + "bertrandthierry":"Bertrand Thierry" , + "brianhan":"Brian Manh Hien Han" , + "cameroncrook":"Cameron Mikel Crook" , + "castelletto":"Nicola Castelletto" , + "chaoyiwang":"Chaoyi Wang" , + "christophersherman":"Christopher Sherman" , + "chriswhite":"Chris White" , + "danieloseikuffuor":"Daniel Osei-Kuffuor" , + "ruiwang":"Rui Wang" , + "dicksonkachuma":"Dickson Kachuma" , + "francoishamon":"Francois Hamon" , + "frankfeifan":"Fan Fei" , + "gaetanfuss":"Gaetan Fuss" , + "gerasimoschourdakis":"Gerasimos Chourdakis" , + "guotongren":"Guotong" , + "guotongren":"Guotong Ren" , + "hannahmairs" : "hannah mairs", + "hervegross":"Herve Gross" , + "heweitang":"Hewei Tang" , + "huiwu":"Hui Wu" , + "ibrahimisraa":"Ibrahim Israa" , + "igorshovkun":"Igor Shovkun" , + "isaacju":"Isaac Ju" , + "jacquesfranc":"Jacques Franc" , + "jaisreeiyer":"Jaisree Iyer" , + "jamescorbett":"James Corbett" , + "jay-a":"Jay Appleton" , + "jeannepellerin":"Jeanne Pellerin" , + "jiemeng":"Jie Meng" , + "jiaminjiang":"Jiamin Jiang" , + "jianhuang":"Jian Huang" , + "jixianghuang":"Jixian Huang" , + "joshuawhite":"Joshua White" , + "juliacamargo":"Julia T. Camargo" , + "julienrenethomasbesset":"Julien Rene Thomas Besset" , + "kevinjdugan":"Kevin J. Dugan" , + "kimtaeho07":"Taeho Kim" , + "liyangrock":"Li Yang" , + "lioneluntereiner":"Lionel Untereiner" , + "lucasvalarcher":"Lucas Valarcher" , + "lukaszlaniewski-wollk":"ŁukaszŁaniewski-Wołłk" , + "madonnayoder":"Madonna Yoder" , + "mamadoundiaye":"Mamadou N'diaye" , + "markkhait":"Mark Khait" , + "matteocusini":"Matteo Cusini" , + "matteofrigo5":"Matteo Frigo" , + "matthiascremon":"Matthias Cremon" , + "melreycg":"Mel Rey" , + "michaelhomel":"Michael Homel" , + "miladbader":"Milad Bader" , + "mohammadkarimifard":"Mohammad Karimi-Fard" , + "oluwatobiquadri":"Oluwatobi Quadri Raji" , + "ouassim":"Ouassim Khebzegga" , + "palomamartinez":"Paloma Martinez" , + "paveltomin":"Pavel Tomin" , + "pengchengfu":"Pengcheng Fu" , + "peterbrobinson":"Peter B. Robinson" , + "phillipchacon":"Phillip Chacon" , + "quanbui":"Quan Bui" , + "randolphrsettgast":"Randolph R.Settgast" , + "rasimhz":"Rasim Hasanzade" , + "ronwang":"Ron Wang" , + "rustemzaydullin":"Rustem Zaydullin" , + "ryanaronson":"Ryan Aronson" , + "sergeyklevtsov":"Sergey Klevtsov" , + "shabnamjandaghisemnani":"Shabnam Jandaghi Semnani" , + "sohailwaziri":"Sohail Waziri" , + "stefanoframbati":"Stefano Frambati" , + "stefanpovolny":"Stefan Povolny" , + "stenix":"stenix" , + "sytuannguyen":"Sy-Tuan Nguyen" , + "taehokim":"TaehoKim" , + "taojin":"Tao Jin" , + "tbeltzun":"tbeltzun" , + "terryligocki":"Terry Ligocki" , + "thomasgazzola":"ThomasGazzola" , + "tombyer":"Thomas James Byer" , + "tony":"Tony ?" , + "victorapmagri":"Victor Paludetto Magri" , + "williamrtobin":"William R. Tobin" , + "wuhuillnl":"Wu Hui" , + "xavierlacoste":"Xavier Lacoste" , + "yohanndudouit":"Yohann Dudouit" , + "yuehao":"Yue Hao" +} + +def count_unique_users(usernames): + # Substitute usernames using the username mapping dictionary + #substituted_usernames = [username_mapping.get(username.strip(), username.strip()) for username in usernames] + + # sorted_username_mapping = dict(sorted(username_mapping.items(), key=lambda item: item[1])) + # for key, value in sorted_username_mapping.items(): + # print(f'{key}: {value}') + + substituted_usernames = [] + for username in usernames: + stripped_username = username.strip() + if stripped_username not in username_mapping: + raise ValueError(f"Username '{stripped_username}' not found in username_mapping") + substituted_usernames.append(username_mapping[stripped_username]) + + + # Count the number of unique usernames + unique_usernames = set(substituted_usernames) +# print ("unique_usernames:", sorted(unique_usernames)) + + for username in unique_usernames: +# print( "- username: \"" + username + "\"") + name = inverse_username_mapping[username] + splitName = name.split() + givenNames = " ".join(splitName[:-1]) + lastName = splitName[-1] + print( "- family-names: \"" + lastName + "\"") + print( " given-names: \"" + givenNames + "\"") + + num_unique_users = len(unique_usernames) + return num_unique_users + +# Example usage: +if __name__ == "__main__": + # Read usernames from command line arguments + usernames = sys.argv[1:] + #print ("usernames:", usernames) + + # Count unique users + num_unique_users = count_unique_users(usernames) + + # Output the number of unique users + print(num_unique_users) diff --git a/scripts/setupPythonEnvironment.bash b/scripts/setupPythonEnvironment.bash index edd5c91296f..9e7babb894a 100755 --- a/scripts/setupPythonEnvironment.bash +++ b/scripts/setupPythonEnvironment.bash @@ -11,17 +11,20 @@ PIP_CMD="pip --disable-pip-version-check" PACKAGE_BRANCH=main -declare -a TARGET_PACKAGES=("geosx_mesh_tools_package" - "geosx_mesh_doctor" - "geosx_xml_tools_package" - "hdf5_wrapper_package" - "pygeosx_tools_package" - "geos_ats_package") +declare -a TARGET_PACKAGES=("geos-mesh" + "geos-xml-tools" + "hdf5-wrapper" + "pygeos-tools" + "geos-ats") declare -a LINK_SCRIPTS=("preprocess_xml" "format_xml" "convert_abaqus" "run_geos_ats" "setup_ats_environment" + "geos_ats_log_check" + "geos_ats_restart_check" + "geos_ats_curve_check" + "mesh-doctor" "activate" "python") @@ -113,6 +116,10 @@ then fi +# Updating pip +echo "Updating pip" +$PYTHON_TARGET -m pip install --upgrade pip + # Install packages echo "Installing python packages..." for p in "${TARGET_PACKAGES[@]}" diff --git a/scripts/spack_configs/blueos_3_ppc64le_ib_p9/spack.yaml b/scripts/spack_configs/blueos_3_ppc64le_ib_p9/spack.yaml index 798f19bff0b..9c737836c86 100644 --- a/scripts/spack_configs/blueos_3_ppc64le_ib_p9/spack.yaml +++ b/scripts/spack_configs/blueos_3_ppc64le_ib_p9/spack.yaml @@ -1,10 +1,10 @@ #------------------------------------------------------------------------------------------------------------ # SPDX-License-Identifier: LGPL-2.1-only # -# Copyright (c) 2018-2020 Lawrence Livermore National Security LLC -# Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University -# Copyright (c) 2018-2020 TotalEnergies -# Copyright (c) 2019- GEOSX Contributors +# Copyright (c) 2018-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2019- GEOS/GEOSX Contributors # All rights reserved # # See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/scripts/spack_configs/toss_3_x86_64_ib/spack.yaml b/scripts/spack_configs/toss_3_x86_64_ib/spack.yaml index ce601ad9237..cf89682e891 100644 --- a/scripts/spack_configs/toss_3_x86_64_ib/spack.yaml +++ b/scripts/spack_configs/toss_3_x86_64_ib/spack.yaml @@ -1,10 +1,10 @@ #------------------------------------------------------------------------------------------------------------ # SPDX-License-Identifier: LGPL-2.1-only # -# Copyright (c) 2018-2020 Lawrence Livermore National Security LLC -# Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University -# Copyright (c) 2018-2020 TotalEnergies -# Copyright (c) 2019- GEOSX Contributors +# Copyright (c) 2018-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2019- GEOS/GEOSX Contributors # All rights reserved # # See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/scripts/spack_configs/toss_4_x86_64_ib/spack.yaml b/scripts/spack_configs/toss_4_x86_64_ib/spack.yaml index 817a6e8199d..7e061aa7e33 100644 --- a/scripts/spack_configs/toss_4_x86_64_ib/spack.yaml +++ b/scripts/spack_configs/toss_4_x86_64_ib/spack.yaml @@ -1,10 +1,10 @@ #------------------------------------------------------------------------------------------------------------ # SPDX-License-Identifier: LGPL-2.1-only # -# Copyright (c) 2018-2020 Lawrence Livermore National Security LLC -# Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University -# Copyright (c) 2018-2020 TotalEnergies -# Copyright (c) 2019- GEOSX Contributors +# Copyright (c) 2018-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2019- GEOS/GEOSX Contributors # All rights reserved # # See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/scripts/spack_packages/packages/geosx/package.py b/scripts/spack_packages/packages/geosx/package.py index 85548940940..0fafded6d37 100644 --- a/scripts/spack_packages/packages/geosx/package.py +++ b/scripts/spack_packages/packages/geosx/package.py @@ -458,11 +458,11 @@ def geos_hostconfig(self, spec, prefix, py_site_pkgs_dir=None): cfg.write(cmake_cache_option('ENABLE_CALIPER_HYPRE', True)) if 'lai=trilinos' in spec: - cfg.write(cmake_cache_entry('GEOSX_LA_INTERFACE', 'Trilinos')) + cfg.write(cmake_cache_entry('GEOS_LA_INTERFACE', 'Trilinos')) if 'lai=hypre' in spec: - cfg.write(cmake_cache_entry('GEOSX_LA_INTERFACE', 'Hypre')) + cfg.write(cmake_cache_entry('GEOS_LA_INTERFACE', 'Hypre')) if 'lai=petsc' in spec: - cfg.write(cmake_cache_entry('GEOSX_LA_INTERFACE', 'Petsc')) + cfg.write(cmake_cache_entry('GEOS_LA_INTERFACE', 'Petsc')) cfg.write('#{0}\n'.format('-' * 80)) cfg.write('# Python\n') diff --git a/scripts/test_submodule_updated.sh b/scripts/test_submodule_updated.sh index e2668a41f60..604d95f2f80 100755 --- a/scripts/test_submodule_updated.sh +++ b/scripts/test_submodule_updated.sh @@ -30,7 +30,7 @@ declare -Ar main_branches=( ["LvArray"]="origin/develop" ["integratedTests"]="origin/develop" ["hdf5_interface"]="origin/master" - ["PVTPackage"]="origin/master" + ["PVTPackage"]="origin/develop" ) diff --git a/src/CMakeGraphVizOptions.cmake b/src/CMakeGraphVizOptions.cmake index c1445d96d92..fbce48fe7e8 100644 --- a/src/CMakeGraphVizOptions.cmake +++ b/src/CMakeGraphVizOptions.cmake @@ -1,4 +1,6 @@ -set( GRAPHVIZ_EXECUTABLES FALSE ) +set( GRAPHVIZ_EXECUTABLES TRUE ) set( GRAPHVIZ_OBJECT_LIBS TRUE ) set( GRAPHVIZ_EXTERNAL_LIBS FALSE ) -set( GRAPHVIZ_GENERATE_DEPENDERS FALSE ) \ No newline at end of file +set( GRAPHVIZ_GENERATE_DEPENDERS FALSE ) +set( GRAPHVIZ_IGNORE_TARGETS "test*;example*;benchmark*" ) +set( GRAPHVIZ_CUSTOM_TARGETS FALSE ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7fb71e7cbe9..09988abe2fd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,10 +1,8 @@ -cmake_minimum_required( VERSION 3.23 ) +cmake_minimum_required( VERSION 3.24 ) # At the moment we are manually passing the cuda arch flag. -if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.23.0") - cmake_policy(SET CMP0104 OLD) # when using nvcc populate CMAKE_CUDA_ARCHITECTURES, raise error if we can't -endif() +cmake_policy(SET CMP0104 OLD) # when using nvcc populate CMAKE_CUDA_ARCHITECTURES, raise error if we can't cmake_policy(SET CMP0074 NEW) # dont ignore _ROOT env vars when searching for packages via find_package() cmake_policy(SET CMP0066 NEW) # use CMAKE__FLAGS_ for try_compile() instead of only CMAKE__FLAGS cmake_policy(SET CMP0056 NEW) # use CMAKE_EXE_LINKER_FLAGS in try_compile() in addition to CMAKE__FLAGS @@ -106,7 +104,7 @@ install( DIRECTORY ${PROJECT_BINARY_DIR}/include DESTINATION . ) # Generate version information ################################ include( cmake/GeosxVersion.cmake ) -message( STATUS "Configuring GEOSX version ${GEOSX_VERSION_FULL}" ) +message( STATUS "Configuring GEOSX version ${GEOS_VERSION_FULL}" ) ################################ @@ -127,7 +125,7 @@ if( ENABLE_CUDA ) list( APPEND extraComponentsLinkList cuda ) endif() -if( ENABLE_CUDA_NVTOOLSEXT ) +if( ENABLE_CUDA AND ENABLE_CUDA_NVTOOLSEXT ) list( APPEND extraComponentsLinkList CUDA::nvToolsExt ) endif() @@ -135,15 +133,10 @@ if( ENABLE_HIP ) list( APPEND extraComponentsLinkList blt::hip ) endif() -if ( GEOSX_BUILD_SHARED_LIBS ) - list( APPEND extraComponentsLinkList geosx_core ) -else() - list( APPEND extraComponentsLinkList ${geosx_core_libs} ) -endif() - blt_add_executable( NAME geosx SOURCES main/main.cpp - DEPENDS_ON ${extraComponentsLinkList} + DEPENDS_ON geosx_core + ${extraComponentsLinkList} ${externalComponentsLinkList} ) # Seems to be required on some CMake versions (e.g. 3.16) to get enforce device linking @@ -151,11 +144,6 @@ if( ${ENABLE_HYPRE_DEVICE} STREQUAL "CUDA" ) set_target_properties( geosx PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS TRUE ) endif() -# Removing all transitive link dependencies from geosx_core target to circumvent -# the BLT behavior which imposes all dependencies to be public -#set_target_properties(geosx_core PROPERTIES INTERFACE_LINK_LIBRARIES "") - -target_include_directories( geosx PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) # To change the runtime path during installation set_target_properties( geosx PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib" ) @@ -168,7 +156,7 @@ install( FILES ${CMAKE_INSTALL_PREFIX}/bin/geosx RENAME geos PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) -if( ENABLE_XML_UPDATES AND ENABLE_MPI AND UNIX AND NOT CMAKE_HOST_APPLE AND NOT ENABLE_CUDA AND NOT ENABLE_HIP ) +if( ENABLE_XML_UPDATES AND ENABLE_MPI AND UNIX AND NOT ENABLE_CUDA AND NOT ENABLE_HIP ) set(SCHEMA_DIR ${CMAKE_SOURCE_DIR}/coreComponents/schema) set(SCRIPT_DIR ${CMAKE_SOURCE_DIR}/../scripts) @@ -181,9 +169,9 @@ if( ENABLE_XML_UPDATES AND ENABLE_MPI AND UNIX AND NOT CMAKE_HOST_APPLE AND NOT COMMENT "Generating XML schema" ) - add_custom_target( geosx_update_rst_tables + add_custom_target( geosx_build_datastructure_tables ALL - COMMAND python3 ${SCRIPT_DIR}/SchemaToRSTDocumentation.py ${SCHEMA_DIR} >update_rst_tables.log 2>&1 || (cat update_rst_tables.log && exit 1) + COMMAND python3 ${SCRIPT_DIR}/SchemaToRSTDocumentation.py -s ${SCHEMA_DIR}/schema.xsd -o ${CMAKE_SOURCE_DIR}/docs/sphinx >update_rst_tables.log 2>&1 || (cat update_rst_tables.log && exit 1) WORKING_DIRECTORY ${CMAKE_BINARY_DIR} DEPENDS geosx_generate_schema COMMENT "Generating schema-dependent RST files" @@ -193,20 +181,19 @@ if( ENABLE_XML_UPDATES AND ENABLE_MPI AND UNIX AND NOT CMAKE_HOST_APPLE AND NOT ALL COMMAND bash ${SCRIPT_DIR}/validateXMLFiles.bash -g ${SCHEMA_DIR}/schema.xsd ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/../examples ${CMAKE_SOURCE_DIR}/../inputFiles WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - DEPENDS geosx_update_rst_tables + DEPENDS geosx_generate_schema COMMENT "Validating all XML files in the repository against the schema" ) + if( SPHINX_FOUND ) + blt_add_sphinx_target( geosx_docs ) + add_dependencies( geosx_docs geosx_build_datastructure_tables ) + endif() endif() if( ENABLE_PYGEOSX ) add_subdirectory( pygeosx ) endif() -if( SPHINX_FOUND ) - blt_add_sphinx_target( geosx_docs ) -endif() - - install( DIRECTORY ../examples/ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${CMAKE_PROJECT_NAME}/examples ) @@ -221,7 +208,7 @@ add_custom_target( geosx_generate_install_schema COMMENT "Generating XML schema to install" ) -if( NOT GEOSX_INSTALL_SCHEMA ) +if( NOT GEOS_INSTALL_SCHEMA ) set_target_properties(geosx_generate_install_schema PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1) endif() @@ -232,6 +219,10 @@ install( FILES ${CMAKE_BINARY_DIR}/schema.xsd ################################ # Add python environment setup ################################ +# message(WARNING "Temporarily changing the geosPythonBranch to bugfix/sherman/fixNumpyProd") +# set(GEOS_PYTHON_PACKAGES_BRANCH "bugfix/sherman/fixNumpyProd" CACHE STRING "" FORCE) + + if ( Python3_EXECUTABLE ) message(STATUS "Found python version ${Python3_VERSION}") if (${Python3_VERSION} VERSION_LESS "3.6.0") @@ -261,19 +252,19 @@ if ( Python3_EXECUTABLE ) set(GEOS_PYTHON_PACKAGES_BRANCH "main" CACHE STRING "" FORCE) endif() - set( GEOSX_PYTHON_TOOLS_BINS + set( GEOS_PYTHON_TOOLS_BINS "${CMAKE_BINARY_DIR}/bin/preprocess_xml" "${CMAKE_BINARY_DIR}/bin/format_xml" ) - add_custom_command( OUTPUT ${GEOSX_PYTHON_TOOLS_BINS} + add_custom_command( OUTPUT ${GEOS_PYTHON_TOOLS_BINS} COMMAND bash ${CMAKE_SOURCE_DIR}/../scripts/setupPythonEnvironment.bash -p ${PYTHON_POST_EXECUTABLE} -b ${CMAKE_BINARY_DIR}/bin --python-pkg-branch ${GEOS_PYTHON_PACKAGES_BRANCH} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) add_custom_target( geosx_python_tools - DEPENDS ${GEOSX_PYTHON_TOOLS_BINS} ) + DEPENDS ${GEOS_PYTHON_TOOLS_BINS} ) add_custom_target( geosx_python_tools_clean - COMMAND rm ${GEOSX_PYTHON_TOOLS_BINS} ) + COMMAND rm ${GEOS_PYTHON_TOOLS_BINS} ) add_custom_target( geosx_python_tools_test COMMAND ${CMAKE_BINARY_DIR}/python/geosx/bin/test_geosx_xml_tools diff --git a/src/VERSION b/src/VERSION index cab8585a7df..b4bba825f4a 100644 --- a/src/VERSION +++ b/src/VERSION @@ -1 +1 @@ -VERSION_ID = v0.2.0 +VERSION_ID = v1.1.0 diff --git a/src/cmake/GeosxConfig.cmake b/src/cmake/GeosxConfig.cmake index 237781d89aa..0289a5d209d 100644 --- a/src/cmake/GeosxConfig.cmake +++ b/src/cmake/GeosxConfig.cmake @@ -28,11 +28,11 @@ set( PREPROCESSOR_DEFINES ARRAY_BOUNDS_CHECK ${externalComponentsList} ) foreach( DEP in ${PREPROCESSOR_DEFINES} ) - if( ${DEP}_FOUND OR ENABLE_${DEP} OR GEOSX_ENABLE_${DEP} ) + if( ${DEP}_FOUND OR ENABLE_${DEP} OR GEOS_ENABLE_${DEP} ) set( USE_${DEP} TRUE ) - set( GEOSX_USE_${DEP} TRUE ) set( GEOS_USE_${DEP} TRUE ) - message(STATUS "GEOSX_USE_${DEP} = ${GEOSX_USE_${DEP}}") + set( GEOS_USE_${DEP} TRUE ) + message(STATUS "GEOS_USE_${DEP} = ${GEOS_USE_${DEP}}") endif() endforeach() @@ -40,18 +40,18 @@ set( STRICT_PPD OPENMP ) # only activate these options if they are ENABLED AND FOUND, not if either foreach( DEP in ${STRICT_PPD} ) - if( ${DEP}_FOUND AND ( ENABLE_${DEP} OR GEOSX_ENABLE_${DEP} ) ) + if( ${DEP}_FOUND AND ( ENABLE_${DEP} OR GEOS_ENABLE_${DEP} ) ) set( USE_${DEP} TRUE ) - set( GEOSX_USE_${DEP} TRUE ) set( GEOS_USE_${DEP} TRUE ) - message(STATUS "GEOSX_USE_${DEP} = ${GEOSX_USE_${DEP}}") + set( GEOS_USE_${DEP} TRUE ) + message(STATUS "GEOS_USE_${DEP} = ${GEOS_USE_${DEP}}") endif() endforeach( ) set( GEOS_USE_HYPRE_DEVICE "GEOS_USE_HYPRE_${ENABLE_HYPRE_DEVICE}" ) message( STATUS "GEOS_USE_HYPRE_DEVICE = ${GEOS_USE_HYPRE_DEVICE}") -set( GEOSX_CMAKE_BUILD_TYPE "\"${CMAKE_BUILD_TYPE}\"" ) +set( GEOS_CMAKE_BUILD_TYPE "\"${CMAKE_BUILD_TYPE}\"" ) configure_file( ${CMAKE_SOURCE_DIR}/coreComponents/common/GeosxConfig.hpp.in ${CMAKE_BINARY_DIR}/include/common/GeosxConfig.hpp ) diff --git a/src/cmake/GeosxMacros.cmake b/src/cmake/GeosxMacros.cmake index af5105678ee..d658076cb6a 100644 --- a/src/cmake/GeosxMacros.cmake +++ b/src/cmake/GeosxMacros.cmake @@ -95,3 +95,39 @@ macro( geos_add_test ) COMMAND ${arg_COMMAND} ${ARGN} ) endmacro( geos_add_test ) + + +macro( geos_decorate_link_dependencies ) + + set( options ) + set( singleValueArgs LIST ) + set( multiValueArgs DEPENDENCIES ) + + # Parse the arguments to the macro + cmake_parse_arguments( arg + "${options}" "${singleValueArgs}" "${multiValueArgs}" ${ARGN} ) + + set( staticLibs "" ) + set( otherLibs "" ) + foreach( dep ${arg_DEPENDENCIES} ) + if( NOT TARGET ${dep} ) + message( FATAL_ERROR "Dependency ${dep} not found" ) + endif() + + get_target_property( targetType ${dep} TYPE) + # message( " ${dep} targetType = ${targetType}" ) # debug + + if (targetType STREQUAL STATIC_LIBRARY) + list( APPEND staticLibs ${dep} ) + else() + list( APPEND otherLibs ${dep} ) + endif() + endforeach() + + # message( " staticLibs = ${staticLibs}" ) # debug + # message( " otherLibs = ${otherLibs}" ) # debug + + string (REPLACE ";" "," staticLibsString "${staticLibs}") + set( ${arg_LIST} "$" ${otherLibs} ) + +endmacro( geos_decorate_link_dependencies ) \ No newline at end of file diff --git a/src/cmake/GeosxOptions.cmake b/src/cmake/GeosxOptions.cmake index c0dd7d5075d..468e6490f57 100644 --- a/src/cmake/GeosxOptions.cmake +++ b/src/cmake/GeosxOptions.cmake @@ -4,7 +4,8 @@ message( "CMAKE_SYSTEM_NAME = ${CMAKE_SYSTEM_NAME}" ) message( "CMAKE_HOST_APPLE = ${CMAKE_HOST_APPLE}" ) ### OPTIONS ### -option( GEOS_ENABLE_TESTS "" ON ) +option( GEOS_ENABLE_FPE "Enables floating point exceptions" ON ) +option( GEOS_ENABLE_TESTS "Enables unit tests" ON ) option( ENABLE_CALIPER "Enables Caliper instrumentation" OFF ) option( ENABLE_MATHPRESSO "" ON ) @@ -62,11 +63,11 @@ endif() ### LAI SETUP ### set( supported_LAI Trilinos Hypre Petsc ) -set( GEOSX_LA_INTERFACE "Hypre" CACHE STRING "Linear algebra interface to use in solvers" ) -message( STATUS "GEOSX_LA_INTERFACE = ${GEOSX_LA_INTERFACE}" ) +set( GEOS_LA_INTERFACE "Hypre" CACHE STRING "Linear algebra interface to use in solvers" ) +message( STATUS "GEOS_LA_INTERFACE = ${GEOS_LA_INTERFACE}" ) -if( NOT ( GEOSX_LA_INTERFACE IN_LIST supported_LAI ) ) - message( FATAL_ERROR "GEOSX_LA_INTERFACE must be one of: ${supported_LAI}" ) +if( NOT ( GEOS_LA_INTERFACE IN_LIST supported_LAI ) ) + message( FATAL_ERROR "GEOS_LA_INTERFACE must be one of: ${supported_LAI}" ) endif() ### MPI/OMP/CUDA/HIP SETUP ### @@ -85,24 +86,34 @@ endif() ### BUILD & BLT SETUP ### -option( GEOSX_INSTALL_SCHEMA "Enables schema generation and installation" ON ) +option( GEOS_INSTALL_SCHEMA "Enables schema generation and installation" ON ) -option( GEOSX_BUILD_OBJ_LIBS "Builds coreComponent modules as object libraries" OFF ) +option( GEOS_BUILD_OBJ_LIBS "Builds coreComponent modules as object libraries" OFF ) -option( GEOSX_BUILD_SHARED_LIBS "Builds geosx_core as a shared library " ON ) +option( GEOS_BUILD_SHARED_LIBS "Builds geosx_core as a shared library " ON ) -set( GEOSX_PARALLEL_COMPILE_JOBS "" CACHE STRING "Maximum number of concurrent compilation jobs" ) -if( GEOSX_PARALLEL_COMPILE_JOBS ) - set_property( GLOBAL APPEND PROPERTY JOB_POOLS compile_job_pool=${GEOSX_PARALLEL_COMPILE_JOBS} ) +set( GEOS_PARALLEL_COMPILE_JOBS "" CACHE STRING "Maximum number of concurrent compilation jobs" ) +if( GEOS_PARALLEL_COMPILE_JOBS ) + set_property( GLOBAL APPEND PROPERTY JOB_POOLS compile_job_pool=${GEOS_PARALLEL_COMPILE_JOBS} ) set( CMAKE_JOB_POOL_COMPILE compile_job_pool ) endif() -set( GEOSX_PARALLEL_LINK_JOBS "" CACHE STRING "Maximum number of concurrent link jobs" ) -if( GEOSX_PARALLEL_LINK_JOBS ) - set_property( GLOBAL APPEND PROPERTY JOB_POOLS link_job_pool=${GEOSX_PARALLEL_LINK_JOBS} ) +set( GEOS_PARALLEL_LINK_JOBS "" CACHE STRING "Maximum number of concurrent link jobs" ) +if( GEOS_PARALLEL_LINK_JOBS ) + set_property( GLOBAL APPEND PROPERTY JOB_POOLS link_job_pool=${GEOS_PARALLEL_LINK_JOBS} ) set( CMAKE_JOB_POOL_LINK link_job_pool ) endif() +# Physics packages +option( GEOS_ENABLE_CONTACT "Enables contact physics package" ON ) +option( GEOS_ENABLE_FLUIDFLOW "Enables fluid flow physics package" ON ) +option( GEOS_ENABLE_INDUCEDSEISMICITY "Enables induced seismicity physics package" ON ) +option( GEOS_ENABLE_MULTIPHYSICS "Enables multiphysics physics package" ON ) +option( GEOS_ENABLE_SIMPLEPDE "Enables simple PDE physics package" ON ) +option( GEOS_ENABLE_SOLIDMECHANICS "Enables solid mechanics physics package" ON ) +option( GEOS_ENABLE_SURFACEGENERATION "Enables surface generation physics package" ON ) +option( GEOS_ENABLE_WAVEPROPAGATION "Enables wave propagation physics package" ON ) + #set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE BOOL "" FORCE) #blt_append_custom_compiler_flag(FLAGS_VAR CMAKE_CXX_FLAGS DEFAULT -rdynamic) #set(CMAKE_EXE_LINKER_FLAGS "-rdynamic") @@ -129,7 +140,7 @@ blt_append_custom_compiler_flag( FLAGS_VAR CMAKE_CXX_FLAGS_DEBUG CLANG "-Wno-unused-parameter -Wno-unused-variable -fstandalone-debug" ) -blt_append_custom_compiler_flag( FLAGS_VAR GEOSX_NINJA_FLAGS +blt_append_custom_compiler_flag( FLAGS_VAR GEOS_NINJA_FLAGS DEFAULT " " GNU "-fdiagnostics-color=always" CLANG "-fcolor-diagnostics" @@ -145,67 +156,54 @@ if (ENABLE_GBENCHMARK) endif() if( ${CMAKE_MAKE_PROGRAM} STREQUAL "ninja" OR ${CMAKE_MAKE_PROGRAM} MATCHES ".*/ninja$" ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GEOSX_NINJA_FLAGS}" ) -endif() - - -if( CMAKE_HOST_APPLE ) -# set(GEOSX_LINK_PREPEND_FLAG "-Wl,-force_load" CACHE STRING "") -# set(GEOSX_LINK_POSTPEND_FLAG "" CACHE STRING "") -# elseif( ENABLE_CUDA ) -# set( GEOSX_LINK_PREPEND_FLAG "-Xcompiler \\\\\"-Wl,--whole-archive\\\\\"" CACHE STRING "" ) -# set( GEOSX_LINK_POSTPEND_FLAG "-Xcompiler \\\\\"-Wl,--no-whole-archive\\\\\"" CACHE STRING "" ) -else() - set( GEOSX_LINK_PREPEND_FLAG "-Wl,--whole-archive" CACHE STRING "" ) - set( GEOSX_LINK_POSTPEND_FLAG "-Wl,--no-whole-archive" CACHE STRING "" ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GEOS_NINJA_FLAGS}" ) endif() -set( GEOSX_LOCALINDEX_TYPE "int" CACHE STRING "" ) +set( GEOS_LOCALINDEX_TYPE "int" CACHE STRING "" ) if( ENABLE_HYPRE_MIXINT ) - set( GEOSX_GLOBALINDEX_TYPE "long long int" CACHE STRING "" ) + set( GEOS_GLOBALINDEX_TYPE "long long int" CACHE STRING "" ) else() - set( GEOSX_GLOBALINDEX_TYPE "int" CACHE STRING "" ) + set( GEOS_GLOBALINDEX_TYPE "int" CACHE STRING "" ) endif() -if( GEOSX_LOCALINDEX_TYPE STREQUAL "int" ) - set( GEOSX_LOCALINDEX_TYPE_FLAG "0" CACHE STRING "" FORCE ) -elseif( GEOSX_LOCALINDEX_TYPE STREQUAL "long int" ) - set( GEOSX_LOCALINDEX_TYPE_FLAG "1" CACHE STRING "" FORCE ) -elseif( GEOSX_LOCALINDEX_TYPE STREQUAL "long long int" ) - set( GEOSX_LOCALINDEX_TYPE_FLAG "2" CACHE STRING "" FORCE ) -elseif( GEOSX_LOCALINDEX_TYPE STREQUAL "std::ptrdiff_t" ) - set( GEOSX_LOCALINDEX_TYPE_FLAG "3" CACHE STRING "" FORCE ) +if( GEOS_LOCALINDEX_TYPE STREQUAL "int" ) + set( GEOS_LOCALINDEX_TYPE_FLAG "0" CACHE STRING "" FORCE ) +elseif( GEOS_LOCALINDEX_TYPE STREQUAL "long int" ) + set( GEOS_LOCALINDEX_TYPE_FLAG "1" CACHE STRING "" FORCE ) +elseif( GEOS_LOCALINDEX_TYPE STREQUAL "long long int" ) + set( GEOS_LOCALINDEX_TYPE_FLAG "2" CACHE STRING "" FORCE ) +elseif( GEOS_LOCALINDEX_TYPE STREQUAL "std::ptrdiff_t" ) + set( GEOS_LOCALINDEX_TYPE_FLAG "3" CACHE STRING "" FORCE ) else( TRUE ) - message( FATAL_ERROR "GEOSX_LOCALINDEX_TYPE_FLAG not set for ${GEOSX_LOCALINDEX_TYPE}" ) + message( FATAL_ERROR "GEOS_LOCALINDEX_TYPE_FLAG not set for ${GEOS_LOCALINDEX_TYPE}" ) endif() -if( GEOSX_GLOBALINDEX_TYPE STREQUAL "int" ) - set( GEOSX_GLOBALINDEX_TYPE_FLAG "0" CACHE STRING "" FORCE ) -elseif( GEOSX_GLOBALINDEX_TYPE STREQUAL "long int" ) - set( GEOSX_GLOBALINDEX_TYPE_FLAG "1" CACHE STRING "" FORCE ) -elseif( GEOSX_GLOBALINDEX_TYPE STREQUAL "long long int" ) - set( GEOSX_GLOBALINDEX_TYPE_FLAG "2" CACHE STRING "" FORCE ) +if( GEOS_GLOBALINDEX_TYPE STREQUAL "int" ) + set( GEOS_GLOBALINDEX_TYPE_FLAG "0" CACHE STRING "" FORCE ) +elseif( GEOS_GLOBALINDEX_TYPE STREQUAL "long int" ) + set( GEOS_GLOBALINDEX_TYPE_FLAG "1" CACHE STRING "" FORCE ) +elseif( GEOS_GLOBALINDEX_TYPE STREQUAL "long long int" ) + set( GEOS_GLOBALINDEX_TYPE_FLAG "2" CACHE STRING "" FORCE ) else( TRUE ) - message( FATAL_ERROR "GEOSX_GLOBALINDEX_TYPE_FLAG not set for ${GEOSX_GLOBALINDEX_TYPE}" ) + message( FATAL_ERROR "GEOS_GLOBALINDEX_TYPE_FLAG not set for ${GEOS_GLOBALINDEX_TYPE}" ) endif() -set( GEOSX_BLOCK_SIZE 32 ) +set( GEOS_BLOCK_SIZE 32 ) if( ENABLE_CUDA ) - set( GEOSX_BLOCK_SIZE 32 ) + set( GEOS_BLOCK_SIZE 32 ) endif() if( ENABLE_HIP ) - set( GEOSX_BLOCK_SIZE 64 ) + set( GEOS_BLOCK_SIZE 64 ) endif() -message( "localIndex is an alias for ${GEOSX_LOCALINDEX_TYPE}" ) -message( "globalIndex is an alias for ${GEOSX_GLOBALINDEX_TYPE}" ) -message( "GEOSX_LOCALINDEX_TYPE_FLAG = ${GEOSX_LOCALINDEX_TYPE_FLAG}" ) -message( "GEOSX_GLOBALINDEX_TYPE_FLAG = ${GEOSX_GLOBALINDEX_TYPE_FLAG}" ) +message( "localIndex is an alias for ${GEOS_LOCALINDEX_TYPE}" ) +message( "globalIndex is an alias for ${GEOS_GLOBALINDEX_TYPE}" ) +message( "GEOS_LOCALINDEX_TYPE_FLAG = ${GEOS_LOCALINDEX_TYPE_FLAG}" ) +message( "GEOS_GLOBALINDEX_TYPE_FLAG = ${GEOS_GLOBALINDEX_TYPE_FLAG}" ) message( "CMAKE_CXX_FLAGS = ${CMAKE_CXX_FLAGS}" ) -message( "GEOSX_LINK_PREPEND_FLAG=${GEOSX_LINK_PREPEND_FLAG}" ) -message( "GEOSX_LINK_POSTPEND_FLAG=${GEOSX_LINK_POSTPEND_FLAG}" ) + message( "Leaving GeosxOptions.cmake\n" ) diff --git a/src/cmake/GeosxVersion.cmake b/src/cmake/GeosxVersion.cmake index 5b178cc379b..d34a3391d11 100644 --- a/src/cmake/GeosxVersion.cmake +++ b/src/cmake/GeosxVersion.cmake @@ -19,18 +19,18 @@ endif() # Inputs: # -- SOURCE_DIR # Outputs: -# -- GEOSX_VERSION_FULL -# -- GEOSX_VERSION_LIST -# -- GEOSX_VERSION_MAJOR -# -- GEOSX_VERSION_MINOR -# -- GEOSX_VERSION_PATCH +# -- GEOS_VERSION_FULL +# -- GEOS_VERSION_LIST +# -- GEOS_VERSION_MAJOR +# -- GEOS_VERSION_MINOR +# -- GEOS_VERSION_PATCH macro(geosx_get_file_version) - file ( STRINGS "${SOURCE_DIR}/VERSION" GEOSX_VERSION_FULL ) - string( REGEX REPLACE "VERSION_ID = v" "" GEOSX_VERSION_FULL "${GEOSX_VERSION_FULL}" ) - string( REPLACE "." ";" GEOSX_VERSION_LIST ${GEOSX_VERSION_FULL} ) - list( GET GEOSX_VERSION_LIST 0 GEOSX_VERSION_MAJOR ) - list( GET GEOSX_VERSION_LIST 1 GEOSX_VERSION_MINOR ) - list( GET GEOSX_VERSION_LIST 2 GEOSX_VERSION_PATCH ) + file ( STRINGS "${SOURCE_DIR}/VERSION" GEOS_VERSION_FULL ) + string( REGEX REPLACE "VERSION_ID = v" "" GEOS_VERSION_FULL "${GEOS_VERSION_FULL}" ) + string( REPLACE "." ";" GEOS_VERSION_LIST ${GEOS_VERSION_FULL} ) + list( GET GEOS_VERSION_LIST 0 GEOS_VERSION_MAJOR ) + list( GET GEOS_VERSION_LIST 1 GEOS_VERSION_MINOR ) + list( GET GEOS_VERSION_LIST 2 GEOS_VERSION_PATCH ) endmacro() # Get GEOSX development version from git @@ -39,9 +39,9 @@ endmacro() # -- GIT_FOUND # -- GIT_EXECUTABLE (only when GIT_FOUND=TRUE ) # Outputs (if GIT_FOUND=TRUE and inside git repo): -# -- GEOSX_GIT_BRANCH -# -- GEOSX_GIT_HASH -# -- GEOSX_GIT_TAG +# -- GEOS_GIT_BRANCH +# -- GEOS_GIT_HASH +# -- GEOS_GIT_TAG macro(geosx_get_git_version) if( GIT_FOUND ) # Use BLT Git macros for convenience @@ -49,13 +49,13 @@ macro(geosx_get_git_version) blt_is_git_repo( OUTPUT_STATE is_git_repo SOURCE_DIR ${SOURCE_DIR} ) if( is_git_repo ) - blt_git_branch( BRANCH_NAME GEOSX_GIT_BRANCH + blt_git_branch( BRANCH_NAME GEOS_GIT_BRANCH RETURN_CODE _git_rc SOURCE_DIR ${SOURCE_DIR} ) - blt_git_hashcode( HASHCODE GEOSX_GIT_HASH + blt_git_hashcode( HASHCODE GEOS_GIT_HASH RETURN_CODE _git_rc SOURCE_DIR ${SOURCE_DIR} ) - blt_git_tag( OUTPUT_TAG GEOSX_GIT_TAG + blt_git_tag( OUTPUT_TAG GEOS_GIT_TAG RETURN_CODE _git_rc SOURCE_DIR ${SOURCE_DIR} ) endif() diff --git a/src/cmake/blt b/src/cmake/blt index 5a792c1775e..9ff77344f0b 160000 --- a/src/cmake/blt +++ b/src/cmake/blt @@ -1 +1 @@ -Subproject commit 5a792c1775e7a7628d84dcde31652a689f1df7b5 +Subproject commit 9ff77344f0b2a6ee345e452bddd6bfd46cbbfa35 diff --git a/src/cmake/thirdparty/FindHDF5.cmake b/src/cmake/thirdparty/FindHDF5.cmake deleted file mode 100644 index 32b5c363c2e..00000000000 --- a/src/cmake/thirdparty/FindHDF5.cmake +++ /dev/null @@ -1,27 +0,0 @@ -############################################################################### -# Setup HDF5 -# Wrapper around standard CMake' HDF5 Find Logic. -# - -if(NOT HDF5_DIR) - MESSAGE(FATAL_ERROR "Could not find HDF5. HDF5 support needs explicit HDF5_DIR") -endif() - -# CMake's FindHDF5 module uses the HDF5_ROOT env var -set(HDF5_ROOT ${HDF5_DIR}) -set(ENV{HDF5_ROOT} ${HDF5_ROOT}/bin) - -# Use CMake's FindHDF5 module, which uses hdf5's compiler wrappers to extract -# all the info about the hdf5 install -set( HDF5_USE_STATIC_LIBRARIES FALSE ) - -include(FindHDF5) - -message(STATUS "HDF5_INCLUDE_DIRS: ${HDF5_INCLUDE_DIRS}") -message(STATUS "HDF5_LIBRARIES: ${HDF5_LIBRARIES}") - -# FindHDF5 sets HDF5_DIR to it's installed CMake info if it exists -# we want to keep HDF5_DIR as the root dir of the install to be -# consistent with other packages - -set(HDF5_DIR ${HDF5_ROOT} CACHE PATH "" FORCE) diff --git a/src/cmake/thirdparty/SetupGeosxThirdParty.cmake b/src/cmake/thirdparty/SetupGeosxThirdParty.cmake index e6ce967a316..28549eb8927 100644 --- a/src/cmake/thirdparty/SetupGeosxThirdParty.cmake +++ b/src/cmake/thirdparty/SetupGeosxThirdParty.cmake @@ -1,7 +1,16 @@ #################################### +# # 3rd Party Dependencies +# +# Setup all GEOS TPL +# #################################### + +################################ +# Helper macros & functions +################################ + macro(find_and_import) set(singleValueArgs NAME HEADER) set(multiValueArgs INCLUDE_DIRECTORIES @@ -101,8 +110,22 @@ macro(extract_version_from_header) endmacro( extract_version_from_header) + +macro(mandatory_tpl_doesnt_exist + CURRENT_TPL_NAME + CURRENT_TPL_DIR_VAR) + + message(FATAL_ERROR + "GEOSX requires ${CURRENT_TPL_NAME}, either :\n" + " - Verify that you provided a valid TPL installation directory (GEOS_TPL_DIR = \"${GEOS_TPL_DIR}\"),\n" + " - Or set ${CURRENT_TPL_DIR_VAR} to the ${CURRENT_TPL_NAME} installation directory (${CURRENT_TPL_DIR_VAR} = \"${${CURRENT_TPL_DIR_VAR}}\").\n") + +endmacro(mandatory_tpl_doesnt_exist) + + set(thirdPartyLibs "") + ################################ # BLAS/LAPACK ################################ @@ -184,7 +207,7 @@ if(DEFINED CONDUIT_DIR) set(thirdPartyLibs ${thirdPartyLibs} conduit::conduit) else() - message(FATAL_ERROR "GEOSX requires conduit, set CONDUIT_DIR to the conduit installation directory.") + mandatory_tpl_doesnt_exist("Conduit" CONDUIT_DIR) endif() ################################ @@ -193,29 +216,18 @@ endif() if(DEFINED HDF5_DIR) message(STATUS "HDF5_DIR = ${HDF5_DIR}") - set(HDF5_ROOT ${HDF5_DIR}) - set(HDF5_USE_STATIC_LIBRARIES FALSE) - set(HDF5_NO_FIND_PACKAGE_CONFIG_FILE ON) - include(FindHDF5) - - # On some platforms (Summit) HDF5 lists /usr/include in it's list of include directories. - # When this happens you can get really opaque include errors. - list(REMOVE_ITEM HDF5_INCLUDE_DIRS /usr/include) - - blt_import_library(NAME hdf5 - INCLUDES ${HDF5_INCLUDE_DIRS} - LIBRARIES ${HDF5_LIBRARIES} - TREAT_INCLUDES_AS_SYSTEM ON) + find_package(HDF5 REQUIRED + PATHS ${HDF5_DIR} + NO_DEFAULT_PATH) - file(READ "${HDF5_DIR}/include/H5public.h" header_file ) - string(REGEX MATCH "version: *([0-9]+.[0-9]+.[0-9]+)" _ ${header_file}) - set( HDF5_VERSION "${CMAKE_MATCH_1}" CACHE STRING "" FORCE ) message( " ----> HDF5 version ${HDF5_VERSION}") + blt_convert_to_system_includes(TARGET HDF5::HDF5) + set(ENABLE_HDF5 ON CACHE BOOL "") - set(thirdPartyLibs ${thirdPartyLibs} hdf5) + set(thirdPartyLibs ${thirdPartyLibs} HDF5::HDF5 ) else() - message(FATAL_ERROR "GEOSX requires hdf5, set HDF5_DIR to the hdf5 installation directory.") + mandatory_tpl_doesnt_exist("hdf5" HDF5_DIR) endif() ################################ @@ -229,7 +241,7 @@ if(DEFINED SILO_DIR AND ENABLE_SILO) LIBRARY_DIRECTORIES ${SILO_DIR}/lib HEADER silo.h LIBRARIES siloh5 - DEPENDS hdf5) + DEPENDS HDF5::HDF5 ) set(ENABLE_SILO ON CACHE BOOL "") @@ -259,7 +271,15 @@ if(DEFINED PUGIXML_DIR) set(thirdPartyLibs ${thirdPartyLibs} pugixml) endif() else() - message(FATAL_ERROR "GEOSX requires pugixml, set PUGIXML_DIR to the pugixml installation directory.") + mandatory_tpl_doesnt_exist("pugixml" PUGIXML_DIR) +endif() + +################################ +# CUDA +################################ +if ( ENABLE_CUDA) + find_package(CUDAToolkit REQUIRED) + message( " ----> $CUDAToolkit_VERSION = ${CUDAToolkit_VERSION}") endif() ################################ @@ -291,7 +311,7 @@ if(DEFINED RAJA_DIR) set(ENABLE_RAJA ON CACHE BOOL "") set(thirdPartyLibs ${thirdPartyLibs} RAJA ) else() - message(FATAL_ERROR "GEOSX requires RAJA, set RAJA_DIR to the RAJA installation directory.") + mandatory_tpl_doesnt_exist("RAJA" RAJA_DIR) endif() ################################ @@ -307,6 +327,32 @@ if(DEFINED CAMP_DIR) endif() endif() +################################ +# FMT +################################ +if(DEFINED FMT_DIR) + message(STATUS "FMT_DIR = ${FMT_DIR}") + + find_package(FMT REQUIRED + PATHS ${FMT_DIR} + NO_DEFAULT_PATH) + + message( " ----> fmt_VERSION = ${fmt_VERSION}") + + get_target_property(includeDirs fmt::fmt-header-only INTERFACE_INCLUDE_DIRECTORIES) + + set_property(TARGET fmt::fmt-header-only + APPEND PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES + ${includeDirs}) + + + set(ENABLE_FMT ON CACHE BOOL "") + + set(thirdPartyLibs ${thirdPartyLibs} fmt::fmt-header-only ) +else() + mandatory_tpl_doesnt_exist("{fmt}" FMT_DIR) +endif() + ################################ # Umpire ################################ @@ -322,7 +368,7 @@ if(DEFINED UMPIRE_DIR) set(ENABLE_UMPIRE ON CACHE BOOL "") set(thirdPartyLibs ${thirdPartyLibs} umpire) else() - message(FATAL_ERROR "GEOSX requires Umpire, set UMPIRE_DIR to the Umpire installation directory.") + mandatory_tpl_doesnt_exist("Umpire" UMPIRE_DIR) endif() @@ -345,7 +391,7 @@ if(DEFINED CHAI_DIR) set(ENABLE_CHAI ON CACHE BOOL "") set(thirdPartyLibs ${thirdPartyLibs} chai) else() - message(FATAL_ERROR "GEOSX requires CHAI, set CHAI_DIR to the CHAI installation directory.") + mandatory_tpl_doesnt_exist("CHAI" CHAI_DIR) endif() ################################ @@ -608,41 +654,45 @@ endif() if(DEFINED HYPRE_DIR AND ENABLE_HYPRE) message(STATUS "HYPRE_DIR = ${HYPRE_DIR}") - set( HYPRE_DEPENDS blas lapack umpire) + set( HYPRE_DEPENDS blas lapack umpire ) if( ENABLE_SUPERLU_DIST ) - set( HYPRE_DEPENDS ${HYPRE_DEPENDS} superlu_dist ) + list( APPEND HYPRE_DEPENDS superlu_dist ) endif() if( ${ENABLE_HYPRE_DEVICE} STREQUAL "CUDA" ) - set( EXTRA_LIBS ${CUDA_cusparse_LIBRARY} ${CUDA_cublas_LIBRARY} ${CUDA_curand_LIBRARY} ) + list( APPEND HYPRE_DEPENDS CUDA::cusparse CUDA::cublas CUDA::curand CUDA::cusolver ) + + # Add libnvJitLink when using CUDA >= 12.2.2. Note: requires cmake >= 3.26 + if( CUDAToolkit_VERSION VERSION_GREATER_EQUAL "12.2.2" ) + list( APPEND HYPRE_DEPENDS CUDA::nvJitLink ) + endif() elseif( ${ENABLE_HYPRE_DEVICE} STREQUAL "HIP" ) find_package( rocblas REQUIRED ) find_package( rocsolver REQUIRED ) find_package( rocsparse REQUIRED ) find_package( rocrand REQUIRED ) - set( HYPRE_DEPENDS ${HYPRE_DEPENDS} roc::rocblas roc::rocsparse roc::rocsolver roc::rocrand ) + list( APPEND HYPRE_DEPENDS roc::rocblas roc::rocsparse roc::rocsolver roc::rocrand ) endif( ) - find_and_import(NAME hypre - INCLUDE_DIRECTORIES ${HYPRE_DIR}/include - LIBRARY_DIRECTORIES ${HYPRE_DIR}/lib - HEADER HYPRE.h - LIBRARIES HYPRE - EXTRA_LIBRARIES ${EXTRA_LIBS} - DEPENDS ${HYPRE_DEPENDS}) + find_and_import( NAME hypre + INCLUDE_DIRECTORIES ${HYPRE_DIR}/include + LIBRARY_DIRECTORIES ${HYPRE_DIR}/lib + HEADER HYPRE.h + LIBRARIES HYPRE + DEPENDS ${HYPRE_DEPENDS} ) extract_version_from_header( NAME hypre HEADER "${HYPRE_DIR}/include/HYPRE_config.h" VERSION_STRING "HYPRE_RELEASE_VERSION" ) # Extract some additional information about development version of hypre - file(READ ${HYPRE_DIR}/include/HYPRE_config.h header_file) - if("${header_file}" MATCHES "HYPRE_DEVELOP_STRING *\"([^\"]*)\"") - set(hypre_dev_string "${CMAKE_MATCH_1}") - if("${header_file}" MATCHES "HYPRE_BRANCH_NAME *\"([^\"]*)\"") - set(hypre_dev_branch "${CMAKE_MATCH_1}") + file( READ ${HYPRE_DIR}/include/HYPRE_config.h header_file ) + if( "${header_file}" MATCHES "HYPRE_DEVELOP_STRING *\"([^\"]*)\"" ) + set( hypre_dev_string "${CMAKE_MATCH_1}" ) + if( "${header_file}" MATCHES "HYPRE_BRANCH_NAME *\"([^\"]*)\"" ) + set( hypre_dev_branch "${CMAKE_MATCH_1}" ) endif() - set(hypre_VERSION "${hypre_dev_string} (${hypre_dev_branch})" CACHE STRING "" FORCE) - message(" ----> hypre_VERSION = ${hypre_VERSION}") + set( hypre_VERSION "${hypre_dev_string} (${hypre_dev_branch})" CACHE STRING "" FORCE ) + message( " ----> hypre_VERSION = ${hypre_VERSION}" ) endif() # Prepend Hypre to link flags, fix for Umpire appearing before Hypre on the link line @@ -652,15 +702,15 @@ if(DEFINED HYPRE_DIR AND ENABLE_HYPRE) # if( ENABLE_CUDA AND ( NOT ${ENABLE_HYPRE_DEVICE} STREQUAL "CUDA" ) ) # set(ENABLE_HYPRE OFF CACHE BOOL "" FORCE) - # if( GEOSX_LA_INTERFACE STREQUAL "Hypre") + # if( GEOS_LA_INTERFACE STREQUAL "Hypre") # message( FATAL_ERROR "Hypre LAI selected, but ENABLE_HYPRE_DEVICE not 'CUDA' while ENABLE_CUDA is ON.") # endif() # else() # set(ENABLE_HYPRE ON CACHE BOOL "") # endif() - set(ENABLE_HYPRE ON CACHE BOOL "") - set(thirdPartyLibs ${thirdPartyLibs} hypre ${HYPRE_DEPENDS} ) + set( ENABLE_HYPRE ON CACHE BOOL "" ) + set( thirdPartyLibs ${thirdPartyLibs} hypre ${HYPRE_DEPENDS} ) else() if(ENABLE_HYPRE) message(WARNING "ENABLE_HYPRE is ON but HYPRE_DIR isn't defined.") @@ -676,7 +726,7 @@ endif() if(DEFINED TRILINOS_DIR AND ENABLE_TRILINOS) message(STATUS "TRILINOS_DIR = ${TRILINOS_DIR}") - include(${TRILINOS_DIR}/lib/cmake/Trilinos/TrilinosConfig.cmake) + include(${TRILINOS_DIR}/lib64/cmake/Trilinos/TrilinosConfig.cmake) list(REMOVE_ITEM Trilinos_LIBRARIES "gtest") list(REMOVE_DUPLICATES Trilinos_LIBRARIES) @@ -778,30 +828,6 @@ else() message(STATUS "Not using VTK") endif() -################################ -# FMT -################################ -if(DEFINED FMT_DIR) - message(STATUS "FMT_DIR = ${FMT_DIR}") - - find_package(fmt REQUIRED - PATHS ${FMT_DIR} - NO_DEFAULT_PATH) - - message( " ----> fmt_VERSION = ${fmt_VERSION}") - - get_target_property(includeDirs fmt::fmt INTERFACE_INCLUDE_DIRECTORIES) - - set_property(TARGET fmt::fmt - APPEND PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES - ${includeDirs}) - - set(ENABLE_FMT ON CACHE BOOL "") - - set(thirdPartyLibs ${thirdPartyLibs} fmt::fmt ) -else() - message(FATAL_ERROR "GEOSX requires {fmt}, set FMT_DIR to the {fmt} installation directory.") -endif() ################################ # uncrustify @@ -841,7 +867,7 @@ if( ${CMAKE_VERSION} VERSION_LESS "3.19" ) set( PYTHON_AND_VERSION Python3 ) set( PYTHON_OPTIONAL_COMPONENTS) else() - set( PYTHON_AND_VERSION Python3 3.7.0...3.11.2 ) + set( PYTHON_AND_VERSION Python3 3.6.0...3.12.2 ) set( PYTHON_OPTIONAL_COMPONENTS OPTIONAL_COMPONENTS Development NumPy) endif() if(ENABLE_PYGEOSX) @@ -871,30 +897,12 @@ endif() ################################ # LAI ################################ -string(TOUPPER "${GEOSX_LA_INTERFACE}" upper_LAI) +string(TOUPPER "${GEOS_LA_INTERFACE}" upper_LAI) if(NOT ENABLE_${upper_LAI}) - message(FATAL_ERROR "${GEOSX_LA_INTERFACE} LA interface is selected, but ENABLE_${upper_LAI} is OFF") + message(FATAL_ERROR "${GEOS_LA_INTERFACE} LA interface is selected, but ENABLE_${upper_LAI} is OFF") endif() -option(GEOSX_LA_INTERFACE_${upper_LAI} "${upper_LAI} LA interface is selected" ON) +option(GEOS_LA_INTERFACE_${upper_LAI} "${upper_LAI} LA interface is selected" ON) -################################ -# Fesapi -################################ -# if(DEFINED FESAPI_DIR) -# message(STATUS "FESAPI_DIR = ${FESAPI_DIR}") - -# find_and_import(NAME FesapiCpp -# INCLUDE_DIRECTORIES ${FESAPI_DIR}/include -# LIBRARY_DIRECTORIES ${FESAPI_DIR}/lib -# HEADER fesapi/nsDefinitions.h -# LIBRARIES FesapiCpp -# DEPENDS hdf5) - -# set(FESAPI_DIR ON CACHE BOOL "") -# set(thirdPartyLibs ${thirdPartyLibs} FesapiCpp) -# else() - message(STATUS "Not using Fesapi") -# endif() message(STATUS "thirdPartyLibs = ${thirdPartyLibs}") @@ -902,12 +910,7 @@ message(STATUS "thirdPartyLibs = ${thirdPartyLibs}") # NvToolExt ############################### if ( ENABLE_CUDA AND ENABLE_CUDA_NVTOOLSEXT ) - find_package(CUDAToolkit REQUIRED) - - message( " ----> $CUDAToolkit_VERSION = ${CUDAToolkit_VERSION}") - set(thirdPartyLibs ${thirdPartyLibs} CUDA::nvToolsExt) endif() message(STATUS "thirdPartyLibs = ${thirdPartyLibs}") - diff --git a/src/conf.py b/src/conf.py index 99989855bd3..c7347bd29fb 100644 --- a/src/conf.py +++ b/src/conf.py @@ -18,11 +18,11 @@ # Add python modules to be documented python_root = './coreComponents/python/modules' -python_modules = ('geosx_mesh_tools_package', - 'geosx_xml_tools_package', - 'hdf5_wrapper_package', - 'pygeosx_tools_package', - 'timehistory_package') +python_modules = ('geos-mesh-tools', + 'geos-xml-tools', + 'hdf5-wrapper', + 'pygeos-tools', + 'geos-timehistory') for m in python_modules: sys.path.insert(0, os.path.abspath(os.path.join(python_root, m))) @@ -49,17 +49,24 @@ config_src = os.path.join(docs_path, "GeosxConfig.hpp") config_dst = os.path.join(common_path, "GeosxConfig.hpp") - input_dirs = ["coreComponents/common", - "coreComponents/dataRepository", - "coreComponents/fileIO", - "coreComponents/linearAlgebra", - "coreComponents/mesh", - "coreComponents/managers", - "coreComponents/finiteElement/kernelInterface", - "coreComponents/mesh/MeshFields.hpp", - "coreComponents/physicsSolvers/simplePDE/LaplaceFEMKernels.hpp", - "coreComponents/physicsSolvers/solidMechanics", - "coreComponents/finiteVolume"] + input_dirs = [ + "coreComponents/common", + "coreComponents/dataRepository", + "coreComponents/fileIO", + "coreComponents/linearAlgebra", + "coreComponents/mesh", + "coreComponents/finiteElement/elementFormulations", + "coreComponents/finiteElement/kernelInterface", + "coreComponents/mesh/MeshFields.hpp", + "coreComponents/physicsSolvers", + "coreComponents/finiteVolume", + "coreComponents/functions", + "coreComponents/fieldSpecification", + "coreComponents/discretizationMethods", + "coreComponents/events", + "coreComponents/mainInterface" + ] + # Write correct ReadtheDocs path and input directories shutil.copy(doxyfile_src, doxyfile_dst) @@ -72,16 +79,18 @@ if not os.path.exists(config_dst): os.symlink(config_src, config_dst) + print("********** Running Doxygen in ReadtheDocs **********") # Call doxygen - from subprocess import call - call(['doxygen', doxyfile_dst]) + from subprocess import run + run(['doxygen', doxyfile_dst]) + print("********** Finished Running Doxygen in ReadtheDocs **********") # -- Project information ----------------------------------------------------- -project = u'GEOSX' -copyright = u'2018-2021 Lawrence Livermore National Security, The Board of Trustees of the Leland Stanford Junior University, TotalEnergies, and GEOSX Contributors.' -author = u'GEOSX Contributors' +project = u'GEOS' +copyright = u'2016-2024 Lawrence Livermore National Security LLC, 2018-2024 Total Energies, The Board of Trustees of the Leland Stanford Junior University, 2023-2024 Chevron, 2019- GEOS/GEOSX Contributors' +author = u'GEOS/GEOSX Contributors' # The short X.Y version version = u'' @@ -112,7 +121,7 @@ 'sphinxcontrib.programoutput' ] -plantuml = "/usr/bin/plantuml" +plantuml = "/usr/bin/java -Djava.awt.headless=true -jar /tmp/plantuml.jar" plantuml_output_format = "svg_img" plot_html_show_source_link = True @@ -142,7 +151,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path . -exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store', 'cmake/*'] +exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store', 'cmake/*', '**/blt/**'] todo_include_todos = True @@ -220,8 +229,8 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'GEOSX.tex', u'GEOSX Documentation', - u'Randolph Settgast', 'manual'), + (master_doc, 'GEOS.tex', u'GEOS Documentation', + u'GEOS/GEOSX Developers', 'manual'), ] @@ -230,7 +239,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'geosx', u'GEOSX Documentation', + (master_doc, 'geos', u'GEOS Documentation', [author], 1) ] @@ -241,8 +250,8 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'GEOSX', u'GEOSX Documentation', - author, 'GEOSX', 'One line description of project.', + (master_doc, 'GEOS', u'GEOS Documentation', + author, 'GEOS', 'GEOS simulation framework.', 'Miscellaneous'), ] diff --git a/src/coreComponents/CMakeLists.txt b/src/coreComponents/CMakeLists.txt index 81653fb0b8f..d2286f907da 100644 --- a/src/coreComponents/CMakeLists.txt +++ b/src/coreComponents/CMakeLists.txt @@ -3,19 +3,20 @@ set( subdirs common codingUtilities dataRepository - schema + denseLinearAlgebra functions constitutive + schema + finiteElement mesh - denseLinearAlgebra - linearAlgebra fieldSpecification - finiteElement finiteVolume + linearAlgebra discretizationMethods + events + constitutiveDrivers fileIO physicsSolvers - events mainInterface ) unset( parallelDeps ) @@ -28,7 +29,7 @@ if ( ENABLE_CUDA ) list( APPEND parallelDeps cuda ) endif() -if( ENABLE_CUDA_NVTOOLSEXT ) +if( ENABLE_CUDA AND ENABLE_CUDA_NVTOOLSEXT ) list( APPEND parallelDeps CUDA::nvToolsExt ) endif() @@ -40,7 +41,7 @@ if( ENABLE_MPI ) list( APPEND parallelDeps mpi ) endif() -if ( GEOSX_BUILD_OBJ_LIBS ) +if ( GEOS_BUILD_OBJ_LIBS ) set( LVARRAY_BUILD_OBJ_LIBS TRUE CACHE BOOL "" FORCE ) endif() @@ -56,53 +57,15 @@ foreach( lib ${subdirs} ) endif() endforeach() -# if we're building full static libs and not obj_libs -if( NOT GEOSX_BUILD_SHARED_LIBS ) - set( geosx_core_list "" ) - foreach( lib ${coreLibs} ) - list( APPEND geosx_core_list ${GEOSX_LINK_PREPEND_FLAG} ${lib} ${GEOSX_LINK_POSTPEND_FLAG} ) - endforeach() - set ( geosx_core_libs "${geosx_core_list}" CACHE INTERNAL "" ) -endif( ) - foreach( lib ${subdirs} ) add_subdirectory( ${lib} ) endforeach() -if( GEOSX_BUILD_SHARED_LIBS AND GEOSX_BUILD_OBJ_LIBS ) - message( "Building shared geosx_core library with object coreComponents, executables link to geosx_core" ) - blt_add_library ( NAME geosx_core - SOURCES dummy.cpp - DEPENDS_ON mainInterface physicsSolvers - SHARED TRUE ) - -elseif( GEOSX_BUILD_SHARED_LIBS AND NOT GEOSX_BUILD_OBJ_LIBS ) - message( "Building shared geosx_core library with static coreComponents, executables link to geosx_core" ) - blt_combine_static_libraries( NAME geosx_core - SOURCE_LIBS ${coreLibs} - LIB_TYPE SHARED - LINK_PREPEND ${GEOSX_LINK_PREPEND_FLAG} - LINK_POSTPEND ${GEOSX_LINK_POSTPEND_FLAG} ) - -elseif( NOT GEOSX_BUILD_SHARED_LIBS AND GEOSX_BUILD_OBJ_LIBS ) - message( "Building object coreComponents, executables link to coreComponents" ) +add_library(geosx_core INTERFACE) +if( GEOS_BUILD_SHARED_LIBS) + target_link_libraries(geosx_core INTERFACE mainInterface ) else() - message( "Building static coreComponents, executables link to coreComponents" ) -endif() - -if ( TARGET geosx_core ) - # Seems to be required on some CMake versions (e.g. 3.16) to get enforce device linking - if( ${ENABLE_HYPRE_DEVICE} STREQUAL "CUDA" ) - set_target_properties( geosx_core PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS TRUE ) - endif() - - # To install the library with the runtime path used during the building - set_target_properties( geosx_core PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE ) - - # To install the shared library - install( TARGETS geosx_core LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) - - target_include_directories( geosx_core PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) + target_link_libraries(geosx_core INTERFACE $ ) endif() geosx_add_code_checks( PREFIX coreComponents diff --git a/src/coreComponents/LvArray b/src/coreComponents/LvArray index 1531241583e..00e3ead6706 160000 --- a/src/coreComponents/LvArray +++ b/src/coreComponents/LvArray @@ -1 +1 @@ -Subproject commit 1531241583eebe21cfcdc0facd16a80f1e03c939 +Subproject commit 00e3ead67060d3c3d4b8291d8e4abbf680b87eb3 diff --git a/src/coreComponents/codingUtilities/CMakeLists.txt b/src/coreComponents/codingUtilities/CMakeLists.txt index c51ea1ca849..0fbbae3876a 100644 --- a/src/coreComponents/codingUtilities/CMakeLists.txt +++ b/src/coreComponents/codingUtilities/CMakeLists.txt @@ -1,11 +1,29 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ + Package: codingUtilities + + Contains definition of runtime types. Also contains common traits. +#]] + # # Specify all headers # set( codingUtilities_headers - EnumStrings.hpp + RTTypes.hpp Parsing.hpp SFINAE_Macros.hpp - StringUtilities.hpp UnitTestUtilities.hpp Utilities.hpp traits.hpp @@ -16,15 +34,19 @@ set( codingUtilities_headers # set( codingUtilities_sources Parsing.cpp - StringUtilities.cpp ) + RTTypes.cpp + ) set( dependencyList ${parallelDeps} common fast_float ) +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) blt_add_library( NAME codingUtilities SOURCES ${codingUtilities_sources} HEADERS ${codingUtilities_headers} - DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} + DEPENDS_ON ${decoratedDependencies} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} ) # Avoid compiling with nvcc which sometimes crashes on fast_float @@ -32,6 +54,8 @@ set_source_files_properties( Parsing.cpp PROPERTIES LANGUAGE CXX ) target_include_directories( codingUtilities PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +install( TARGETS codingUtilities LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) + if( GEOS_ENABLE_TESTS ) add_subdirectory(tests) diff --git a/src/coreComponents/codingUtilities/Parsing.cpp b/src/coreComponents/codingUtilities/Parsing.cpp index e483ba2c313..d977ef6831e 100644 --- a/src/coreComponents/codingUtilities/Parsing.cpp +++ b/src/coreComponents/codingUtilities/Parsing.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/codingUtilities/Parsing.hpp b/src/coreComponents/codingUtilities/Parsing.hpp index af36d23a831..ec75cb757f8 100644 --- a/src/coreComponents/codingUtilities/Parsing.hpp +++ b/src/coreComponents/codingUtilities/Parsing.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,6 +21,7 @@ #define GEOS_CODINGUTILITIES_PARSING_HPP_ #include "common/DataTypes.hpp" +#include "common/logger/Logger.hpp" #include diff --git a/src/coreComponents/codingUtilities/RTTypes.cpp b/src/coreComponents/codingUtilities/RTTypes.cpp new file mode 100644 index 00000000000..648f94e6b31 --- /dev/null +++ b/src/coreComponents/codingUtilities/RTTypes.cpp @@ -0,0 +1,230 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file RTTypes.cpp + */ + + +#include "RTTypes.hpp" +#include "LvArray/src/system.hpp" +#include "common/format/StringUtilities.hpp" + +namespace geos +{ + +Regex::Regex( string_view regexStr, string_view formatDescription ): + m_regexStr( regexStr ), + m_formatDescription( formatDescription ) +{} + +void printTypeSummary() +{ + GEOS_LOG_RANK_0( "real64 is alias of " < type_names = + { + {std::type_index( typeid(integer)), "integer"}, + {std::type_index( typeid(real32)), "real32"}, + {std::type_index( typeid(real64)), "real64"}, + {std::type_index( typeid(localIndex)), "localIndex"}, + {std::type_index( typeid(globalIndex)), "globalIndex"}, + {std::type_index( typeid(R1Tensor)), "R1Tensor"}, + {std::type_index( typeid(R1Tensor32)), "R1Tensor32"}, + {std::type_index( typeid(R2SymTensor)), "R2SymTensor"}, + {std::type_index( typeid(integer_array)), "integer_array"}, + {std::type_index( typeid(real32_array)), "real32_array"}, + {std::type_index( typeid(real64_array)), "real64_array"}, + {std::type_index( typeid(localIndex_array)), "localIndex_array"}, + {std::type_index( typeid(globalIndex_array)), "globalIndex_array"}, + {std::type_index( typeid(integer_array2d)), "integer_array2d"}, + {std::type_index( typeid(real32_array2d)), "real32_array2d"}, + {std::type_index( typeid(real64_array2d)), "real64_array2d"}, + {std::type_index( typeid(localIndex_array2d)), "localIndex_array2d"}, + {std::type_index( typeid(globalIndex_array2d)), "globalIndex_array2d"}, + {std::type_index( typeid(integer_array3d)), "integer_array3d"}, + {std::type_index( typeid(real32_array3d)), "real32_array3d"}, + {std::type_index( typeid(real64_array3d)), "real64_array3d"}, + {std::type_index( typeid(localIndex_array3d)), "localIndex_array3d"}, + {std::type_index( typeid(globalIndex_array3d)), "globalIndex_array3d"}, + {std::type_index( typeid(real64_array4d)), "real64_array4d"}, + {std::type_index( typeid(string)), "string"}, + {std::type_index( typeid(Path)), "path"}, + {std::type_index( typeid(string_array)), "string_array"}, + {std::type_index( typeid(path_array)), "path_array"}, + }; + + // If the data type is not defined here, return type_info.name() + auto const iter = type_names.find( key ); + if( iter != type_names.end() ) + { + return iter->second; + } + else + { + return LvArray::system::demangle( key.name()); + } +} + +/** + * @brief Recursive function to build array regexes. + * @param subPattern pattern of the element to surround with braces and separate with commas + * @param dimension 1 = bottom-level, 2 = array1d-level, 3 = array2d-level... + * @param topLevelCall True if this is the first recursive call. + * @return + * + * @note The sub pattern is the base object you are targeting. It can either + * be a simple type or a lower-dimensional array. Sub-elements and + * axes are given as a comma-separated list enclosed in a curly brace. + * For example, a 2D string array would look like: {{"a", "b"}, {"c", "d"}} + */ +string constructArrayRegex( string_view subPattern, integer dimension, bool topLevelCall = true ) +{ + string subPatternStr = dimension > 1 ? + constructArrayRegex( subPattern, dimension-1, false ) : + string( subPattern ); + // Add trailing space if is not already done + if( !stringutilities::endsWith( subPatternStr, "\\s*" ) ) + subPatternStr+="\\s*"; + // Allow the bottom-level to be empty + string const arrayRegex = dimension == 1 ? + "\\{\\s*((" + subPatternStr + ",\\s*)*" + subPatternStr + ")?\\}": + "\\{\\s*(" + subPatternStr + ",\\s*)*" + subPatternStr + "\\}"; + // accept spaces around surrounding braces at the top-level + return topLevelCall ? + "\\s*" + arrayRegex + "\\s*" : + arrayRegex; +} +/** + * @brief function to build array regexes. + * @param subPattern pattern of the element to surround with braces and separate with commas + * @param description description of the subPattern that starts by "Input value must " + * @param dimension 1 = array1d, 2 = array2d... + * @return + */ +Regex constructArrayRegex( string_view subPattern, string_view description, integer dimension ) +{ + std::ostringstream arrayDesc; + + // Adapt the description so the form "Input value must be an int" is transformed to "Input value must be a 1d array. Each value must be an + // int" + { + arrayDesc << "Input value must be a " << dimension << "d array (surrounded by "; + if( dimension > 1 ) + { + arrayDesc << dimension << " levels of "; + } + arrayDesc << "braces and separated by commas). Each value must "; + + // finish by the original description + GEOS_ERROR_IF( !stringutilities::startsWith( description, "Input value must " ), + "Description \"" << description << "\" must start by \"Input value must \" to call constructArrayRegex() on it." ); + arrayDesc << description.substr( description.find( " must " ) ); + } + + return Regex( constructArrayRegex( subPattern, dimension ), + arrayDesc.str() ); +} + +rtTypes::RegexMapType rtTypes::createBasicTypesRegexMap() +{ + // Define the component regexes: + + // Regex to match an unsigned int (123, etc.) + // string_view const ru = "[\\d]+";// unused + + string_view const intDesc = "Input value must be a signed int (eg. -123, 455, +789, etc.)"; + string_view const intRegex = "[+-]?[\\d]+"; + + // Explanation of parts: + // [+-]?[\\d]* matches an optional +/- at the beginning, any numbers preceding the decimal + // ([\\d]\\.?|\\.[\\d]) matches the decimal region of the number (0, 1., 2.3, .4) + // [\\d]* matches any number of numbers following the decimal + // ([eE][-+]?[\\d]+|\\s*) matches an optional scientific notation number + // Note: the xsd regex implementation does not allow an empty branch, so use allow whitespace at the end + string_view const realDesc = "Input value must be a real number (eg. 1, .25, +2.3, -.4, 5.6e7, -8E-9, etc.)"; + string_view const realRegex = "[+-]?[\\d]*([\\d]\\.?|\\.[\\d])[\\d]*([eE][-+]?[\\d]+|\\s*)"; + + string_view const R1Desc = "Input value must be a R1Tensor, an array of 3 real numbers surrounded by braces and separated by commas (eg. \"{ 1, .25, +2.3}\", \"{ -.4, 5.6e7, -8E-9\", etc.) ."; + string const R1Regex = "\\s*\\{\\s*(" + string( realRegex ) + "\\s*,\\s*){2}" + string( realRegex ) + "\\s*\\}\\s*"; + string_view const R2Desc = "Input value must be a R2SymTensor, an array of 6 real numbers surrounded by braces and separated by commas (eg. \"{ 1, .25, +2.3, -.4, 5.6e7, -8E-9\", etc.) ."; + string const R2Regex = "\\s*\\{\\s*(" + string( realRegex ) + "\\s*,\\s*){5}" + string( realRegex ) + "\\s*\\}\\s*"; + + string_view const strDesc = "Input value must be a string that cannot be empty, contain any whitespaces nor the characters , { }"; + string_view const strRegex = "[^,\\{\\}\\s]+\\s*"; + string_view const strEDesc = "Input value must be a string that cannot contain any whitespaces nor the characters , { }"; + string_view const strERegex = "[^,\\{\\}\\s]*\\s*"; + + string_view const pathDesc = "Input value must be a string that cannot be empty, contain any whitespaces nor the characters * ? < > | : \" "; + string_view const pathRegex = "[^*?<>\\|:\";,\\s]+\\s*"; + string_view const pathEDesc = "Input value must be a string that cannot contain any whitespaces nor the characters * ? < > | : \" "; + string_view const pathERegex = "[^*?<>\\|:\";,\\s]*\\s*"; + + string_view const groupNameDesc = "Input value must be a string that cannot be empty and contains only upper/lower letters, digits, and the characters . - _"; + string_view const groupNameRegex = "[a-zA-Z0-9.\\-_]+"; + // to reference groups, we need to support the / for paths, and * [ ] for fnmatch patterns. + string_view const groupNameRefDesc = "Input value must be a string that can contain only upper/lower letters, digits, and the characters . - _ / * [ ]"; + string_view const groupNameRefRegex = "[a-zA-Z0-9.\\-_/*\\[\\]]*"; + + + // Build master list of regexes + RegexMapType regexMap = + { + { "integer", Regex( intRegex, intDesc ) }, + { "localIndex", Regex( intRegex, intDesc ) }, + { "globalIndex", Regex( intRegex, intDesc ) }, + { "real32", Regex( realRegex, realDesc ) }, + { "real64", Regex( realRegex, realDesc ) }, + { "R1Tensor", Regex( R1Regex, R1Desc ) }, + { "R1Tensor32", Regex( R1Regex, R1Desc ) }, + { "R2SymTensor", Regex( R2Regex, R2Desc ) }, + { "integer_array", constructArrayRegex( intRegex, intDesc, 1 ) }, + { "localIndex_array", constructArrayRegex( intRegex, intDesc, 1 ) }, + { "globalIndex_array", constructArrayRegex( intRegex, intDesc, 1 ) }, + { "real32_array", constructArrayRegex( realRegex, realDesc, 1 ) }, + { "real64_array", constructArrayRegex( realRegex, realDesc, 1 ) }, + { "integer_array2d", constructArrayRegex( intRegex, intDesc, 2 ) }, + { "localIndex_array2d", constructArrayRegex( intRegex, intDesc, 2 ) }, + { "globalIndex_array2d", constructArrayRegex( intRegex, intDesc, 2 ) }, + { "real32_array2d", constructArrayRegex( realRegex, realDesc, 2 ) }, + { "real64_array2d", constructArrayRegex( realRegex, realDesc, 2 ) }, + { "integer_array3d", constructArrayRegex( intRegex, intDesc, 3 ) }, + { "localIndex_array3d", constructArrayRegex( intRegex, intDesc, 3 ) }, + { "globalIndex_array3d", constructArrayRegex( intRegex, intDesc, 3 ) }, + { "real32_array3d", constructArrayRegex( realRegex, realDesc, 3 ) }, + { "real64_array3d", constructArrayRegex( realRegex, realDesc, 3 ) }, + { "real64_array4d", constructArrayRegex( realRegex, realDesc, 4 ) }, + { "string", Regex( strERegex, strEDesc ) }, + { "path", Regex( pathERegex, pathEDesc ) }, + { "string_array", constructArrayRegex( strRegex, strDesc, 1 ) }, + { "path_array", constructArrayRegex( pathRegex, pathDesc, 1 ) }, + + { string( CustomTypes::mapPair ), Regex( strERegex, strEDesc ) }, + { string( CustomTypes::plotLevel ), Regex( intRegex, intDesc ) }, + { string( CustomTypes::groupName ), Regex( groupNameRegex, groupNameDesc ) }, + { string( CustomTypes::groupNameRef ), Regex( groupNameRefRegex, groupNameRefDesc ) }, + { string( CustomTypes::groupNameRefArray ), constructArrayRegex( groupNameRefRegex, groupNameRefDesc, 1 ) } + }; + return regexMap; +} + + + +} diff --git a/src/coreComponents/codingUtilities/RTTypes.hpp b/src/coreComponents/codingUtilities/RTTypes.hpp new file mode 100644 index 00000000000..b5327b4fcb6 --- /dev/null +++ b/src/coreComponents/codingUtilities/RTTypes.hpp @@ -0,0 +1,262 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file RTTypes.hpp + * + * This file contains various aliases and functions that provide operations regarding the + * use of the runtime types. + */ + +#ifndef GEOS_CODINGUTILITIES_RTTYPES_HPP +#define GEOS_CODINGUTILITIES_RTTYPES_HPP + +#include "common/DataTypes.hpp" +#include "common/format/EnumStrings.hpp" +#include "common/format/Format.hpp" +#include "common/logger/Logger.hpp" + +namespace geos +{ + +/** + * @brief Perform a type cast of base to derived pointer. + * @tparam NEW_TYPE derived pointer type + * @tparam EXISTING_TYPE base type + * @param val base pointer to cast + * @return pointer cast to derived type or @p nullptr + */ +template< typename NEW_TYPE, typename EXISTING_TYPE > +NEW_TYPE dynamicCast( EXISTING_TYPE * const val ) +{ + static_assert( std::is_pointer< NEW_TYPE >::value, "NEW_TYPE must be a pointer." ); + return dynamic_cast< NEW_TYPE >( val ); +} + +/** + * @brief Perform a type cast of base to derived reference. + * @tparam NEW_TYPE derived reference type + * @tparam EXISTING_TYPE base type + * @param val base reference to cast + * @return reference cast to derived type or @p nullptr + */ +template< typename NEW_TYPE, typename EXISTING_TYPE > +NEW_TYPE dynamicCast( EXISTING_TYPE & val ) +{ + static_assert( std::is_reference< NEW_TYPE >::value, "NEW_TYPE must be a reference." ); + + using POINTER_TO_NEW_TYPE = std::remove_reference_t< NEW_TYPE > *; + POINTER_TO_NEW_TYPE ptr = dynamicCast< POINTER_TO_NEW_TYPE >( &val ); + GEOS_ERROR_IF( ptr == nullptr, "Cast from " << LvArray::system::demangleType( val ) << " to " << + LvArray::system::demangleType< NEW_TYPE >() << " failed." ); + + return *ptr; +} + +/** + * @brief Print a short summary of a few select type aliases. + */ +void printTypeSummary(); + +/** + * @brief The regular expression data for validating inputs. Use rtTypes to get the regex of a + * type, and TypeRegex< T > to define a type regex. + */ +struct Regex +{ + /** + * @brief the regular expression string. + */ + string m_regexStr; + /** + * @brief the description of the expected format of the regular expression. + */ + string m_formatDescription; + /** + * @brief Default constructor + */ + Regex() {} + /** + * @param regexStr the regex string for validation (eg. "[\\d]+") + * @param formatDescription the description of the expected format to be validated (eg. "Input value must be an integer."). + */ + Regex( string_view regexStr, string_view formatDescription ); +}; + +/** + * @brief Extension point for custom types to provide a validation regexp to schema. + * Do not use directly to obtain a type regex, rtTypes::getTypeRegex< T >() should be used instead. + * @tparam T the type for which the regex is defined + * @tparam ENABLE used to conditionally enable partial specializations + * + * Specializations should define the following method: + * \code{cpp} + * static string get(); + * \endcode + */ +template< typename T, typename ENABLE = void > +struct TypeRegex +{ + /** + * @brief Get the type's regex (default implementation returns nothing). + * @return The Regex associated with T. + */ + static Regex get() { return {}; } +}; + +/** + * @brief Static class to manage the type selection of types at runtime and obtain the + * regexes of these types. Typically, these types are 'xsd:simpleType' in the XSD. + */ +class rtTypes +{ +public: + + /** + * @brief the regex map type to store and find the regexes by the associated rtTypeName. + */ + using RegexMapType = std::map< string, Regex >; + + /** + * @brief Custom types are useful to customize the regexes of an existing type. The type name + * can be one of the existing ones, or a totally new one (which can then be used in Wrapper::setRTTypename). + */ + struct CustomTypes + { + /// @cond DO_NOT_DOCUMENT + static constexpr string_view mapPair = "mapPair"; + static constexpr string_view plotLevel = "geos_dataRepository_PlotLevel"; + static constexpr string_view groupName = "groupName"; + static constexpr string_view groupNameRef = "groupNameRef"; + static constexpr string_view groupNameRefArray = "groupNameRef_array"; + /// @endcond + }; + + /** + * @brief Convert a @p std::type_index to a string. + * @param key the std::type_index of the type + * @return a hard coded string that is related to the std::type_index + */ + static string getTypeName( std::type_index const key ); + + /** + * @tparam T type we want the regex + * @return the regex string for the default rtType of T to validate input values to this type. + */ + template< typename T > + static Regex const & getTypeRegex() + { return getTypeRegex< T >( getTypeName( typeid( T ) ) ); } + + /** + * @param typeName The rtType name of the type we want the regex (can be a CustomTypes). + * @tparam T the type we want the regex. If none are available in createBasicTypesRegexMap(), one is + * generated from TypeRegex< T >::get(). + * @return a regex string validating the type T. + */ + template< typename T > + static Regex const & getTypeRegex( string_view typeName ) + { + RegexMapType & map = getTypeRegexMap(); + auto const it = map.find( string( typeName ) ); + if( it != map.end() ) + { + return it->second; + } + else + { + return map.emplace( typeName, TypeRegex< T >::get() ).first->second; + } + } + + /** + * @brief Construct the regexMap for all basic types (TypeRegex< T > extented types are not mentionned) + * @return RegexMapType + */ + static RegexMapType createBasicTypesRegexMap(); + +private: + + /** + * @return A reference to the types regexes map + */ + static RegexMapType & getTypeRegexMap() + { + static RegexMapType m = createBasicTypesRegexMap(); + return m; + } + + /** + * @brief Private constructor because of static class + */ + rtTypes() {} + +}; + +/** + * @brief Utility class for querying type names at runtime. + * @tparam T the target type + * + * This relies on LvArray's demangling facilities and simply + * adds some convenience methods like getting the brief name. + */ +template< typename T > +struct TypeName +{ + /** + * @brief @return Full name of the type. + */ + static string full() + { + return ::LvArray::system::demangle( typeid( T ).name() ); + } + + /** + * @brief @return brief name of the type (ignoring namespaces). + */ + static string brief() + { + string const full_name = full(); + string::size_type const pos = full_name.find_last_of( "::" ); + return ( pos == string::npos ) ? full_name : full_name.substr( pos ); + } +}; + +/** + * @brief Base types TypeRegex specializations + */ +///@{ + +/** + * @brief Specialization of TypeRegex for enumeration types with strings attached (pun intended). + * @tparam ENUM the type of enumeration + */ +template< typename ENUM > +struct TypeRegex< ENUM, std::enable_if_t< internal::HasEnumStrings< ENUM > > > +{ + /** + * @brief @return Regex for validating enumeration inputs for @p ENUM type. + */ + static Regex get() + { + return Regex( EnumStrings< ENUM >::concat( "|" ), + "Input value must be one of { " + EnumStrings< ENUM >::concat( ", " ) + " }." ); + } +}; + +///@} + +} + +#endif /* GEOS_CODINGUTILITIES_RTTYPES_HPP */ diff --git a/src/coreComponents/codingUtilities/SFINAE_Macros.hpp b/src/coreComponents/codingUtilities/SFINAE_Macros.hpp index c1fcb9b4236..83a5f7f8faf 100644 --- a/src/coreComponents/codingUtilities/SFINAE_Macros.hpp +++ b/src/coreComponents/codingUtilities/SFINAE_Macros.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/codingUtilities/StringUtilities.cpp b/src/coreComponents/codingUtilities/StringUtilities.cpp deleted file mode 100644 index b2e19c062c9..00000000000 --- a/src/coreComponents/codingUtilities/StringUtilities.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file StringUtilities.cpp - */ - -#include "StringUtilities.hpp" -#include "limits.h" - -#include -#include -#include - -namespace geos -{ -namespace stringutilities -{ - -string toLower( string const & input ) -{ - string output; - output.resize( input.size() ); - auto const toLowerCase = []( unsigned char c ) - { return std::tolower( c ); }; - std::transform( input.cbegin(), input.cend(), output.begin(), toLowerCase ); - return output; -} - -string_view trim( string_view str, - string_view charsToRemove ) -{ - std::size_t const first = str.find_first_not_of( charsToRemove ); - if( first != string::npos ) - { - std::size_t const last = str.find_last_not_of( charsToRemove ); - return str.substr( first, ( last - first + 1 ) ); - } - return {}; -} -string_view trimSpaces( string_view str ) -{ - return trim( str, " \f\n\r\t\v" ); -} - - -string removeStringAndFollowingContent( string const & str, - string const & strToRemove ) -{ - string newStr = str; - - // check if the line contains the string to remove - std::size_t const pos = newStr.find( strToRemove ); - - if( pos != string::npos ) - { - // remove the character and everything afterwards - newStr = newStr.substr( 0, pos ); - } - return newStr; -} - -// put definition here so we can control the allowable values of T and -// modication of this function triggers a whole code recompile...which -// should be avoided. -template< typename T > -string toMetricPrefixString( T const & value ) -{ - // These are the metric prefixes corrosponding to kilo, mega, giga...etc. - char const prefixes[12] = { 'f', 'p', 'n', 'u', 'm', ' ', 'K', 'M', 'G', 'T', 'P', 'E'}; - string rval; - - int const power = floor( log10( std::abs( (double)value ) ) ); - int const a = floor( power / 3.0 ); - - real64 const scaledValue = value * pow( 10.0, -a * 3 ); - - // format the output of the value to 3 significant digits and append the - // metric prefix. - int const p = 2-std::abs( power - a * 3 ); - char temp[10]; - snprintf( temp, 8, "%5.*f %c", p, scaledValue, prefixes[a+5] ); - rval = temp; - - GEOS_ERROR_IF( rval.empty(), - GEOS_FMT( "The value of {} was not able to be converted with a metric prefix", value ) ); - - - return rval; -} -template string toMetricPrefixString( int const & ); -template string toMetricPrefixString( long int const & ); -template string toMetricPrefixString( long long int const & ); -template string toMetricPrefixString( unsigned long int const & ); -template string toMetricPrefixString( unsigned long long int const & ); -template string toMetricPrefixString( float const & ); -template string toMetricPrefixString( double const & ); - - -} -} diff --git a/src/coreComponents/codingUtilities/StringUtilities.hpp b/src/coreComponents/codingUtilities/StringUtilities.hpp deleted file mode 100644 index db1fac9d409..00000000000 --- a/src/coreComponents/codingUtilities/StringUtilities.hpp +++ /dev/null @@ -1,261 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file StringUtilities.hpp - */ - -#ifndef GEOS_CODINGUTILITIES_STRINGUTILITIES_HPP_ -#define GEOS_CODINGUTILITIES_STRINGUTILITIES_HPP_ - -#include "common/DataTypes.hpp" - -#include -#include - -namespace geos -{ -namespace stringutilities -{ - -/** - * @brief Return a copy of the string in lower case. - * @param input The input string which is not modified. - * @return A new string instance. - */ -string toLower( string const & input ); - -/** - * @brief Join strings or other printable objects with a delimiter. - * @tparam IT type of iterator into the range of objects to join - * @tparam S type of delimiter, usually char, char const * or string - * @param first iterator to start of the range - * @param last iterator past-the-end of the range - * @param delim delimiter used to glue together strings - * @return a string containing input values concatenated with a delimiter - */ -template< typename IT, typename S = char > -string join( IT first, IT last, S const & delim = S() ) -{ - if( first == last ) - { - return {}; - } - std::ostringstream oss; - oss << *first; - while( ++first != last ) - { - oss << delim << *first; - } - return oss.str(); -} - -/** - * @brief Join strings or other printable objects with a delimiter. - * @tparam CONTAINER type of container to join - * @tparam S type of delimiter, usually char, char const * or string - * @param container container to join - * @param delim delimiter used to glue together strings - * @return a string containing input values concatenated with a delimiter - */ -template< typename CONTAINER, typename S = char > -string join( CONTAINER const & cont, S const & delim = S() ) -{ - return join( std::begin( cont ), std::end( cont ), delim ); -} - -/** - * @brief Concatenate variadic arguments into a string with a delimiter. - * @tparam S type of delimiter (printable to std::ostringstream) - * @tparam T type of first argument (printable to std::ostringstream) - * @tparam Ts types of remaining arguments (printable to std::ostringstream) - * @param delim delimiter - * @param v first value - * @param vs remaining values - * @return string containing concatenated printed arguments - */ -template< typename S = char, typename T, typename ... Ts > -string concat( S const & delim, T const & v, Ts const & ... vs ) -{ - std::ostringstream oss; - oss << v; - // Use array initializer and comma trick to get "fold expression" pre C++-17 - using expander = int[]; - (void) expander{ 0, ( void ( oss << delim << vs ), 0) ... }; - return oss.str(); -} - -/** - * @brief Subdivide the string in substrings by the specified delimiters. - * @tparam CONTAINER The templated class of the results container (std::vector by default). - * @param str The string to subdivide. - * @param delimiters String that contains the list of possible delimiters. - * @param treatConsecutiveDelimAsOne If enabled, consecutive delimiters will be treated as one. - * If not enabled, consecutive delimiters will result in empty entries. - * @param preTrimStr If enabled, delimiters at the borders of the string will be ignored. - * If not enabled, those delimiters will result in in empty entries. - * @return The container of the divided substrings. - */ -template< template< class ... > class CONTAINER = std::vector > -CONTAINER< string > tokenize( string const & str, - string const & delimiters, - bool const treatConsecutiveDelimAsOne = true, - bool const preTrimStr = false ) -{ - CONTAINER< string > tokens; - string::size_type tokenBegin, tokenEnd, strEnd; - - if( preTrimStr ) - { - tokenBegin = str.find_first_not_of( delimiters ); - strEnd = str.find_last_not_of( delimiters ) + 1; - } - else - { - tokenBegin = 0; - strEnd = str.size(); - } - - while( ( ( tokenEnd = str.find_first_of( delimiters, tokenBegin ) ) < strEnd ) && tokenBegin < strEnd ) - { - tokens.emplace_back( str.substr( tokenBegin, tokenEnd - tokenBegin ) ); - tokenBegin = !treatConsecutiveDelimAsOne ? tokenEnd + 1 : str.find_first_not_of( delimiters, tokenEnd ); - } - - if( tokenBegin < strEnd ) - { - tokens.emplace_back( str.substr( tokenBegin, strEnd-tokenBegin )); - } - else if( !preTrimStr && str.find_first_of( delimiters, strEnd - 1 ) != string::npos ) - { - tokens.emplace_back( "" ); - } - - return tokens; -} - -/** - * @brief Subdivide the string in substrings by whitespaces separators (see std::isspace()). - * Do not create any empty substrings. - * @tparam CONTAINER The templated class of the results container (std::vector by default). - * @param str The string to subdivide. - * @return CONTAINER< string > The list of the subdivided substrings (std::vector< string > for instance). - */ -template< template< class ... > class CONTAINER = std::vector > -CONTAINER< string > tokenizeBySpaces( string const & str ) -{ - return tokenize< CONTAINER >( str, " \f\n\r\t\v", true, true ); -} - -/** - * @brief Trim the string - * @param[in] str the string to trim - * @param[in] charsToRemove the list of characters to remove - * @return the trimmed string - */ -string_view trim( string_view str, - string_view charsToRemove ); - -/** - * @brief Trim the string so it does not starts nor ends with any whitespaces - * @param[in] str the string to trim - * @return the trimmed string - */ -string_view trimSpaces( string_view str ); - -/** - * @brief Search for a string in the line, and return the line truncated before the string - * @param[in] str the line to truncate - * @param[in] strToRemove the string to search for in the line - * @return the new (truncated) string - */ -string removeStringAndFollowingContent( string const & str, - string const & strToRemove ); - -/** - * @brief Take a string, and return a array1d with the cast values - * @tparam T the type to which the string will be cast - * @param[in] str the string to turn into an array1d - * @return the array1d that stores the cast values - */ -template< typename T > -array1d< T > fromStringToArray( string const & str ) -{ - array1d< T > v; - T sub; - - std::istringstream iss( str ); - while( iss >> sub ) - { - v.emplace_back( sub ); - } - return v; -} - -/** - * @brief Take a numerical value and convert/scale it to a string with a metric - * prefix. i.e. Kilo, Mega, Giga, Tera, Peta, Exa - * - * @tparam T Type of the value to be converted - * @param value The value to be converted - * @return String containging the scaled value. - */ -template< typename T > -string toMetricPrefixString( T const & value ); - -/** - * @brief Compute the length of a constant string at compile-time. - */ -// TODO c++17: this function is to remove in favor of std::string_view -constexpr size_t cstrlen( char const * const str ) -{ - if( str ) - { - char const * ptr = str; - for(; *ptr != '\0'; ++ptr ) - {} - return ptr - str; - } - else - { - return 0; - } -} - -/** - * @return true if the string starts with the prefix. - * @param str The string to compare - * @param prefix A prefix we want to know if the string starts with. - */ -constexpr bool startsWith( std::string_view str, std::string_view prefix ) -{ - return str.size() >= prefix.size() && - str.compare( 0, prefix.size(), prefix ) == 0; -} - -/** - * @return true if the string ends with the suffix. - * @param str The string to compare - * @param suffix A suffix we want to know if the string ends with. - */ -constexpr bool endsWith( std::string_view str, std::string_view suffix ) -{ - return str.size() >= suffix.size() && - str.compare( str.size()-suffix.size(), suffix.size(), suffix ) == 0; -} - -} // namespace stringutilities -} // namespace geos - -#endif /* GEOS_CODINGUTILITIES_STRINGUTILITIES_HPP_ */ diff --git a/src/coreComponents/codingUtilities/UnitTestUtilities.hpp b/src/coreComponents/codingUtilities/UnitTestUtilities.hpp index 3755134d630..6bc2d0ea5b3 100644 --- a/src/coreComponents/codingUtilities/UnitTestUtilities.hpp +++ b/src/coreComponents/codingUtilities/UnitTestUtilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -63,7 +64,7 @@ namespace testing template< typename T > T expected( T expectedSerial, std::initializer_list< T > expectedParallel, - MPI_Comm const & comm = MPI_COMM_GEOSX ) + MPI_Comm const & comm = MPI_COMM_GEOS ) { int const mpiSize = MpiWrapper::commSize( comm ); if( mpiSize == 1 ) @@ -82,8 +83,8 @@ T expected( T expectedSerial, constexpr real64 DEFAULT_ABS_TOL = 1E-12; constexpr real64 DEFAULT_REL_TOL = std::numeric_limits< real64 >::epsilon(); -::testing::AssertionResult checkRelativeErrorFormat( const char *, const char *, const char *, const char *, - real64 const v1, real64 const v2, real64 const relTol, real64 const absTol ) +inline ::testing::AssertionResult checkRelativeErrorFormat( const char *, const char *, const char *, const char *, + real64 const v1, real64 const v2, real64 const relTol, real64 const absTol ) { real64 const delta = std::abs( v1 - v2 ); real64 const value = std::max( std::abs( v1 ), std::abs( v2 ) ); @@ -99,23 +100,23 @@ ::testing::AssertionResult checkRelativeErrorFormat( const char *, const char *, return ::testing::AssertionSuccess(); } -::testing::AssertionResult checkRelativeErrorFormat( char const * a, char const * b, char const * c, - real64 const v1, real64 const v2, real64 const relTol ) +inline ::testing::AssertionResult checkRelativeErrorFormat( char const * a, char const * b, char const * c, + real64 const v1, real64 const v2, real64 const relTol ) { return checkRelativeErrorFormat( a, b, c, "DEFAULT_ABS_TOL", v1, v2, relTol, DEFAULT_ABS_TOL ); } -void checkRelativeError( real64 const v1, real64 const v2, real64 const relTol ) +inline void checkRelativeError( real64 const v1, real64 const v2, real64 const relTol ) { EXPECT_PRED_FORMAT3( checkRelativeErrorFormat, v1, v2, relTol ); } -void checkRelativeError( real64 const v1, real64 const v2, real64 const relTol, real64 const absTol ) +inline void checkRelativeError( real64 const v1, real64 const v2, real64 const relTol, real64 const absTol ) { EXPECT_PRED_FORMAT4( checkRelativeErrorFormat, v1, v2, relTol, absTol ); } -void checkRelativeError( real64 const v1, real64 const v2, real64 const relTol, string const & name ) +inline void checkRelativeError( real64 const v1, real64 const v2, real64 const relTol, string const & name ) { SCOPED_TRACE( name ); EXPECT_PRED_FORMAT3( checkRelativeErrorFormat, v1, v2, relTol ); } -void checkRelativeError( real64 const v1, real64 const v2, real64 const relTol, real64 const absTol, string const & name ) +inline void checkRelativeError( real64 const v1, real64 const v2, real64 const relTol, real64 const absTol, string const & name ) { SCOPED_TRACE( name ); EXPECT_PRED_FORMAT4( checkRelativeErrorFormat, v1, v2, relTol, absTol ); diff --git a/src/coreComponents/codingUtilities/Utilities.hpp b/src/coreComponents/codingUtilities/Utilities.hpp index b6e39ba6667..868d096c28b 100644 --- a/src/coreComponents/codingUtilities/Utilities.hpp +++ b/src/coreComponents/codingUtilities/Utilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,8 @@ #ifndef GEOS_CODINGUTILITIES_UTILITIES_H_ #define GEOS_CODINGUTILITIES_UTILITIES_H_ -#include "codingUtilities/StringUtilities.hpp" +#include "common/format/StringUtilities.hpp" +#include "common/logger/Logger.hpp" #include "common/DataTypes.hpp" #include "LvArray/src/limits.hpp" #include "common/GEOS_RAJA_Interface.hpp" @@ -209,6 +211,31 @@ VAL findOption( mapBase< KEY, VAL, SORTED > const & map, return iter->second; } +namespace +{ + +/** + * @brief Apply functor @p transformer onto the map elements and store the results into a container of type @p C. + * @tparam MAP Type of the considered map. + * @tparam C Type of the container holding the keys. + * @tparam TRANSFORMER Type of the unary functor. + * @param[in] map The map from which keys will be extracted. + * @param transformer Which unary functor to apply to the @p map elements. + * @return The container with the results for the @p transformer application. + */ +template< template< typename ... > class C, typename MAP, typename TRANSFORMER > +auto mapTransformer( MAP const & map, + TRANSFORMER const & transformer ) +{ + using v = std::invoke_result_t< TRANSFORMER, typename MAP::const_reference >; + C< v > result; + auto inserter = std::inserter( result, result.end() ); + std::transform( map.begin(), map.end(), inserter, transformer ); + return result; +} + +} + /** * @brief Extract the keys from the given map. * @tparam MAP Type of the considered map. @@ -219,11 +246,24 @@ VAL findOption( mapBase< KEY, VAL, SORTED > const & map, template< template< typename ... > class C = std::vector, typename MAP > C< typename MAP::key_type > mapKeys( MAP const & map ) { - C< typename MAP::key_type > keys; - auto transformer = []( auto const & p ) { return p.first; }; - auto inserter = std::inserter( keys, keys.end() ); - std::transform( map.begin(), map.end(), inserter, transformer ); - return keys; + auto transformer = []( auto const & p ) -> typename MAP::key_type + { return p.first; }; + return mapTransformer< C >( map, transformer ); +} + +/** + * @brief Extract the values from the given map. + * @tparam MAP Type of the considered map. + * @tparam C Type of the container holding the values. + * @param[in] map The map from which values will be extracted. + * @return The container with the values. + */ +template< template< typename ... > class C = std::vector, typename MAP > +C< typename MAP::mapped_type > mapValues( MAP const & map ) +{ + auto transformer = []( typename MAP::const_reference p ) -> typename MAP::mapped_type + { return p.second; }; + return mapTransformer< C >( map, transformer ); } namespace internal diff --git a/src/coreComponents/codingUtilities/tests/CMakeLists.txt b/src/coreComponents/codingUtilities/tests/CMakeLists.txt index f70776694a0..1fe1863459d 100644 --- a/src/coreComponents/codingUtilities/tests/CMakeLists.txt +++ b/src/coreComponents/codingUtilities/tests/CMakeLists.txt @@ -1,18 +1,21 @@ # Specify list of tests set( testSources testGeosxTraits.cpp - testStringUtilities.cpp - testParsing.cpp ) + testParsing.cpp + testUtilities.cpp ) -set( dependencyList gtest codingUtilities ${parallelDeps} ) +set( dependencyList codingUtilities ${parallelDeps} ) +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) # Add gtest C++ based tests foreach( test ${testSources} ) + get_filename_component( test_name ${test} NAME_WE ) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} ) + DEPENDS_ON ${decoratedDependencies} gtest ) geos_add_test( NAME ${test_name} COMMAND ${test_name} ) diff --git a/src/coreComponents/codingUtilities/tests/testGeosxTraits.cpp b/src/coreComponents/codingUtilities/tests/testGeosxTraits.cpp index dec8e43fa8d..26f37878b4b 100644 --- a/src/coreComponents/codingUtilities/tests/testGeosxTraits.cpp +++ b/src/coreComponents/codingUtilities/tests/testGeosxTraits.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/codingUtilities/tests/testParallelTestUtilities.cpp b/src/coreComponents/codingUtilities/tests/testParallelTestUtilities.cpp index 1276006b8d3..69872e0813a 100644 --- a/src/coreComponents/codingUtilities/tests/testParallelTestUtilities.cpp +++ b/src/coreComponents/codingUtilities/tests/testParallelTestUtilities.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2020- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/codingUtilities/tests/testParsing.cpp b/src/coreComponents/codingUtilities/tests/testParsing.cpp index 3a591cea3ed..63b72772f7f 100644 --- a/src/coreComponents/codingUtilities/tests/testParsing.cpp +++ b/src/coreComponents/codingUtilities/tests/testParsing.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/codingUtilities/tests/testUtilities.cpp b/src/coreComponents/codingUtilities/tests/testUtilities.cpp new file mode 100644 index 00000000000..ee0f3773446 --- /dev/null +++ b/src/coreComponents/codingUtilities/tests/testUtilities.cpp @@ -0,0 +1,36 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "codingUtilities/Utilities.hpp" + +#include + +#include + +using namespace geos; + +TEST( Utilities, MapExtraction ) +{ + std::map< string, int > const m{ + { "k0", 0 }, + { "k1", 1 }, + { "k2", 2 } + }; + + EXPECT_EQ( mapKeys( m ), std::vector< string >( { "k0", "k1", "k2" } ) ); + EXPECT_EQ( mapKeys< std::set >( m ), std::set< string >( { "k0", "k1", "k2" } ) ); + EXPECT_EQ( mapValues( m ), std::vector< int >( { 0, 1, 2 } ) ); + EXPECT_EQ( mapValues< std::set >( m ), std::set< int >( { 0, 1, 2 } ) ); +} diff --git a/src/coreComponents/codingUtilities/traits.hpp b/src/coreComponents/codingUtilities/traits.hpp index 1e05ef8af52..ecf7b4e4dab 100644 --- a/src/coreComponents/codingUtilities/traits.hpp +++ b/src/coreComponents/codingUtilities/traits.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -95,6 +96,14 @@ HAS_MEMBER_FUNCTION( capacity, localIndex, ); */ HAS_MEMBER_FUNCTION_NO_RTYPE( resize, 0 ); +/** + * @brief Defines a static constexpr bool HasMemberFunction_resizeDefault< @p CLASS > + * that is true iff the method @p CLASS ::resizeDefault( int, int, int) exists. + * @tparam CLASS The type to test. + */ +HAS_MEMBER_FUNCTION_NO_RTYPE( resizeDefault, 0, 0 ); + + /** * @brief Defines a static constexpr bool HasMemberFunction_reserve< @p CLASS > * that is true iff the method @p CLASS ::reserve( localIndex ) exists. diff --git a/src/coreComponents/common/BufferAllocator.cpp b/src/coreComponents/common/BufferAllocator.cpp index 898aa82c011..bcee360d14e 100644 --- a/src/coreComponents/common/BufferAllocator.cpp +++ b/src/coreComponents/common/BufferAllocator.cpp @@ -1,7 +1,22 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #include "BufferAllocator.hpp" #include "DataTypes.hpp" -#ifdef GEOSX_USE_CHAI +#ifdef GEOS_USE_CHAI namespace geos { diff --git a/src/coreComponents/common/BufferAllocator.hpp b/src/coreComponents/common/BufferAllocator.hpp index 72ccc92fdc9..dbce67d911c 100644 --- a/src/coreComponents/common/BufferAllocator.hpp +++ b/src/coreComponents/common/BufferAllocator.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,7 +22,7 @@ #include "common/GeosxConfig.hpp" -#ifdef GEOSX_USE_CHAI +#ifdef GEOS_USE_CHAI #include #include diff --git a/src/coreComponents/common/CMakeLists.txt b/src/coreComponents/common/CMakeLists.txt index 5600a8fae85..830be7b7b1f 100644 --- a/src/coreComponents/common/CMakeLists.txt +++ b/src/coreComponents/common/CMakeLists.txt @@ -1,16 +1,45 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: common + +Contains the definition of the basic static types of GEOS. +Also provides commonly used components for such as logging, formatting, memory and wrapper of + dependencies. +#]] + + # # Specify all headers # set( common_headers ${CMAKE_BINARY_DIR}/include/common/GeosxConfig.hpp + format/table/TableLayout.hpp + format/table/TableFormatter.hpp + format/table/TableData.hpp + format/EnumStrings.hpp + format/Format.hpp + format/StringUtilities.hpp + logger/Logger.hpp BufferAllocator.hpp DataLayouts.hpp DataTypes.hpp FieldSpecificationOps.hpp - Format.hpp GEOS_RAJA_Interface.hpp GeosxMacros.hpp - Logger.hpp + MemoryInfos.hpp + logger/Logger.hpp MpiWrapper.hpp Path.hpp Span.hpp @@ -38,9 +67,13 @@ endif( ) # Specify all sources # set( common_sources + format/table/TableLayout.cpp + format/table/TableFormatter.cpp + format/table/TableData.cpp + format/StringUtilities.cpp + logger/Logger.cpp BufferAllocator.cpp - DataTypes.cpp - Logger.cpp + MemoryInfos.cpp MpiWrapper.cpp Path.cpp initializeEnvironment.cpp @@ -57,8 +90,8 @@ if (TARGET conduit) set( dependencyList ${dependencyList} conduit ) endif() -if (TARGET fmt::fmt) - set( dependencyList ${dependencyList} fmt::fmt ) +if (TARGET fmt::fmt-header-only) + set( dependencyList ${dependencyList} fmt::fmt-header-only ) endif() if (TARGET fmt) @@ -97,12 +130,17 @@ blt_add_library( NAME common SOURCES ${common_sources} HEADERS ${common_headers} DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} ) target_include_directories( common PUBLIC ${CMAKE_BINARY_DIR}/include ) target_include_directories( common PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +install( TARGETS common LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) + if( GEOS_ENABLE_TESTS ) add_subdirectory( unitTests ) + add_subdirectory( format/table/unitTests ) + add_subdirectory( format/unitTests ) endif() diff --git a/src/coreComponents/common/DataLayouts.hpp b/src/coreComponents/common/DataLayouts.hpp index 077e5aeb305..e330aa00f1e 100644 --- a/src/coreComponents/common/DataLayouts.hpp +++ b/src/coreComponents/common/DataLayouts.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -102,7 +103,7 @@ static constexpr int ACCELERATION_USD = LvArray::typeManipulation::getStrideOneD namespace particles { -#if defined( GEOSX_USE_CUDA ) +#if defined( GEOS_USE_CUDA ) /// Particle reference position permutation when using cuda. using REFERENCE_POSITION_PERM = RAJA::PERM_JI; @@ -154,16 +155,25 @@ namespace cells /// Cell node map permutation when using cuda. using NODE_MAP_PERMUTATION = RAJA::PERM_JI; +/// Cell strain permutation when using cuda +using STRAIN_PERM = RAJA::PERM_JI; + #else /// Cell node map permutation when not using cuda. using NODE_MAP_PERMUTATION = RAJA::PERM_IJ; +/// Cell strain permutation when not using cuda +using STRAIN_PERM = RAJA::PERM_IJ; + #endif /// Cell node map unit stride dimension. static constexpr int NODE_MAP_USD = LvArray::typeManipulation::getStrideOneDimension( NODE_MAP_PERMUTATION {} ); +/// Cell strain unit stride dimension +static constexpr int STRAIN_USD = LvArray::typeManipulation::getStrideOneDimension( STRAIN_PERM {} ); + } // namespace cells namespace solid diff --git a/src/coreComponents/common/DataTypes.cpp b/src/coreComponents/common/DataTypes.cpp deleted file mode 100644 index f2de87138e6..00000000000 --- a/src/coreComponents/common/DataTypes.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file DataTypes.cpp - */ - - -#include "DataTypes.hpp" -#include "Logger.hpp" -#include "LvArray/src/system.hpp" -#include "codingUtilities/StringUtilities.hpp" - -namespace geos -{ -#ifdef GEOSX_USE_MPI -MPI_Comm MPI_COMM_GEOSX; -#else -int MPI_COMM_GEOSX = 0; -#endif - - -Regex::Regex( string_view regexStr, string_view formatDescription ): - m_regexStr( regexStr ), - m_formatDescription( formatDescription ) -{} - -void printTypeSummary() -{ - GEOS_LOG_RANK_0( "real64 is alias of " < type_names = - { - {std::type_index( typeid(integer)), "integer"}, - {std::type_index( typeid(real32)), "real32"}, - {std::type_index( typeid(real64)), "real64"}, - {std::type_index( typeid(localIndex)), "localIndex"}, - {std::type_index( typeid(globalIndex)), "globalIndex"}, - {std::type_index( typeid(R1Tensor)), "R1Tensor"}, - {std::type_index( typeid(R1Tensor32)), "R1Tensor32"}, - {std::type_index( typeid(R2SymTensor)), "R2SymTensor"}, - {std::type_index( typeid(integer_array)), "integer_array"}, - {std::type_index( typeid(real32_array)), "real32_array"}, - {std::type_index( typeid(real64_array)), "real64_array"}, - {std::type_index( typeid(localIndex_array)), "localIndex_array"}, - {std::type_index( typeid(globalIndex_array)), "globalIndex_array"}, - {std::type_index( typeid(integer_array2d)), "integer_array2d"}, - {std::type_index( typeid(real32_array2d)), "real32_array2d"}, - {std::type_index( typeid(real64_array2d)), "real64_array2d"}, - {std::type_index( typeid(localIndex_array2d)), "localIndex_array2d"}, - {std::type_index( typeid(globalIndex_array2d)), "globalIndex_array2d"}, - {std::type_index( typeid(integer_array3d)), "integer_array3d"}, - {std::type_index( typeid(real32_array3d)), "real32_array3d"}, - {std::type_index( typeid(real64_array3d)), "real64_array3d"}, - {std::type_index( typeid(localIndex_array3d)), "localIndex_array3d"}, - {std::type_index( typeid(globalIndex_array3d)), "globalIndex_array3d"}, - {std::type_index( typeid(real64_array4d)), "real64_array4d"}, - {std::type_index( typeid(string)), "string"}, - {std::type_index( typeid(Path)), "path"}, - {std::type_index( typeid(string_array)), "string_array"}, - {std::type_index( typeid(path_array)), "path_array"}, - }; - - // If the data type is not defined here, return type_info.name() - auto const iter = type_names.find( key ); - if( iter != type_names.end() ) - { - return iter->second; - } - else - { - return LvArray::system::demangle( key.name()); - } -} - -/** - * @brief Recursive function to build array regexes. - * @param subPattern pattern of the element to surround with braces and separate with commas - * @param dimension 1 = bottom-level, 2 = array1d-level, 3 = array2d-level... - * @param topLevelCall True if this is the first recursive call. - * @return - * - * @note The sub pattern is the base object you are targeting. It can either - * be a simple type or a lower-dimensional array. Sub-elements and - * axes are given as a comma-separated list enclosed in a curly brace. - * For example, a 2D string array would look like: {{"a", "b"}, {"c", "d"}} - */ -string constructArrayRegex( string_view subPattern, integer dimension, bool topLevelCall = true ) -{ - string subPatternStr = dimension > 1 ? - constructArrayRegex( subPattern, dimension-1, false ) : - string( subPattern ); - // Add trailing space if is not already done - if( !stringutilities::endsWith( subPatternStr, "\\s*" ) ) - subPatternStr+="\\s*"; - // Allow the bottom-level to be empty - string const arrayRegex = dimension == 1 ? - "\\{\\s*((" + subPatternStr + ",\\s*)*" + subPatternStr + ")?\\}": - "\\{\\s*(" + subPatternStr + ",\\s*)*" + subPatternStr + "\\}"; - // accept spaces around surrounding braces at the top-level - return topLevelCall ? - "\\s*" + arrayRegex + "\\s*" : - arrayRegex; -} -/** - * @brief function to build array regexes. - * @param subPattern pattern of the element to surround with braces and separate with commas - * @param description description of the subPattern that starts by "Input value must " - * @param dimension 1 = array1d, 2 = array2d... - * @return - */ -Regex constructArrayRegex( string_view subPattern, string_view description, integer dimension ) -{ - std::ostringstream arrayDesc; - - // Adapt the description so the form "Input value must be an int" is transformed to "Input value must be a 1d array. Each value must be an - // int" - { - arrayDesc << "Input value must be a " << dimension << "d array (surrounded by "; - if( dimension > 1 ) - { - arrayDesc << dimension << " levels of "; - } - arrayDesc << "braces and separated by commas). Each value must "; - - // finish by the original description - GEOS_ERROR_IF( !stringutilities::startsWith( description, "Input value must " ), - "Description \"" << description << "\" must start by \"Input value must \" to call constructArrayRegex() on it." ); - arrayDesc << description.substr( description.find( " must " ) ); - } - - return Regex( constructArrayRegex( subPattern, dimension ), - arrayDesc.str() ); -} - -rtTypes::RegexMapType rtTypes::createBasicTypesRegexMap() -{ - // Define the component regexes: - - // Regex to match an unsigned int (123, etc.) - // string_view const ru = "[\\d]+";// unused - - string_view const intDesc = "Input value must be a signed int (eg. -123, 455, +789, etc.)"; - string_view const intRegex = "[+-]?[\\d]+"; - - // Explanation of parts: - // [+-]?[\\d]* matches an optional +/- at the beginning, any numbers preceding the decimal - // ([\\d]\\.?|\\.[\\d]) matches the decimal region of the number (0, 1., 2.3, .4) - // [\\d]* matches any number of numbers following the decimal - // ([eE][-+]?[\\d]+|\\s*) matches an optional scientific notation number - // Note: the xsd regex implementation does not allow an empty branch, so use allow whitespace at the end - string_view const realDesc = "Input value must be a real number (eg. 1, .25, +2.3, -.4, 5.6e7, -8E-9, etc.)"; - string_view const realRegex = "[+-]?[\\d]*([\\d]\\.?|\\.[\\d])[\\d]*([eE][-+]?[\\d]+|\\s*)"; - - string_view const R1Desc = "Input value must be a R1Tensor, an array of 3 real numbers surrounded by braces and separated by commas (eg. \"{ 1, .25, +2.3}\", \"{ -.4, 5.6e7, -8E-9\", etc.) ."; - string const R1Regex = "\\s*\\{\\s*(" + string( realRegex ) + "\\s*,\\s*){2}" + string( realRegex ) + "\\s*\\}\\s*"; - string_view const R2Desc = "Input value must be a R2SymTensor, an array of 6 real numbers surrounded by braces and separated by commas (eg. \"{ 1, .25, +2.3, -.4, 5.6e7, -8E-9\", etc.) ."; - string const R2Regex = "\\s*\\{\\s*(" + string( realRegex ) + "\\s*,\\s*){5}" + string( realRegex ) + "\\s*\\}\\s*"; - - string_view const strDesc = "Input value must be a string that cannot be empty, contain any whitespaces nor the characters , { }"; - string_view const strRegex = "[^,\\{\\}\\s]+\\s*"; - string_view const strEDesc = "Input value must be a string that cannot contain any whitespaces nor the characters , { }"; - string_view const strERegex = "[^,\\{\\}\\s]*\\s*"; - - string_view const pathDesc = "Input value must be a string that cannot be empty, contain any whitespaces nor the characters * ? < > | : \" "; - string_view const pathRegex = "[^*?<>\\|:\";,\\s]+\\s*"; - string_view const pathEDesc = "Input value must be a string that cannot contain any whitespaces nor the characters * ? < > | : \" "; - string_view const pathERegex = "[^*?<>\\|:\";,\\s]*\\s*"; - - string_view const groupNameDesc = "Input value must be a string that cannot be empty and contains only upper/lower letters, digits, and the characters . - _"; - string_view const groupNameRegex = "[a-zA-Z0-9.\\-_]+"; - string_view const groupNameRefDesc = "Input value must be a string that can contain only upper/lower letters, digits, and the characters . - _ /"; - string_view const groupNameRefRegex = "[a-zA-Z0-9.\\-_/]*"; - - - // Build master list of regexes - RegexMapType regexMap = - { - { "integer", Regex( intRegex, intDesc ) }, - { "localIndex", Regex( intRegex, intDesc ) }, - { "globalIndex", Regex( intRegex, intDesc ) }, - { "real32", Regex( realRegex, realDesc ) }, - { "real64", Regex( realRegex, realDesc ) }, - { "R1Tensor", Regex( R1Regex, R1Desc ) }, - { "R1Tensor32", Regex( R1Regex, R1Desc ) }, - { "R2SymTensor", Regex( R2Regex, R2Desc ) }, - { "integer_array", constructArrayRegex( intRegex, intDesc, 1 ) }, - { "localIndex_array", constructArrayRegex( intRegex, intDesc, 1 ) }, - { "globalIndex_array", constructArrayRegex( intRegex, intDesc, 1 ) }, - { "real32_array", constructArrayRegex( realRegex, realDesc, 1 ) }, - { "real64_array", constructArrayRegex( realRegex, realDesc, 1 ) }, - { "integer_array2d", constructArrayRegex( intRegex, intDesc, 2 ) }, - { "localIndex_array2d", constructArrayRegex( intRegex, intDesc, 2 ) }, - { "globalIndex_array2d", constructArrayRegex( intRegex, intDesc, 2 ) }, - { "real32_array2d", constructArrayRegex( realRegex, realDesc, 2 ) }, - { "real64_array2d", constructArrayRegex( realRegex, realDesc, 2 ) }, - { "integer_array3d", constructArrayRegex( intRegex, intDesc, 3 ) }, - { "localIndex_array3d", constructArrayRegex( intRegex, intDesc, 3 ) }, - { "globalIndex_array3d", constructArrayRegex( intRegex, intDesc, 3 ) }, - { "real32_array3d", constructArrayRegex( realRegex, realDesc, 3 ) }, - { "real64_array3d", constructArrayRegex( realRegex, realDesc, 3 ) }, - { "real64_array4d", constructArrayRegex( realRegex, realDesc, 4 ) }, - { "string", Regex( strERegex, strEDesc ) }, - { "path", Regex( pathERegex, pathEDesc ) }, - { "string_array", constructArrayRegex( strRegex, strDesc, 1 ) }, - { "path_array", constructArrayRegex( pathRegex, pathDesc, 1 ) }, - - { string( CustomTypes::mapPair ), Regex( strERegex, strEDesc ) }, - { string( CustomTypes::plotLevel ), Regex( intRegex, intDesc ) }, - { string( CustomTypes::groupName ), Regex( groupNameRegex, groupNameDesc ) }, - { string( CustomTypes::groupNameRef ), Regex( groupNameRefRegex, groupNameRefDesc ) }, - { string( CustomTypes::groupNameRefArray ), constructArrayRegex( groupNameRefRegex, groupNameRefDesc, 1 ) } - }; - return regexMap; -} - - - -} diff --git a/src/coreComponents/common/DataTypes.hpp b/src/coreComponents/common/DataTypes.hpp index deba16a2f8a..42c14433f0d 100644 --- a/src/coreComponents/common/DataTypes.hpp +++ b/src/coreComponents/common/DataTypes.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,7 +17,7 @@ * @file DataTypes.hpp * * This file contains various aliases and functions that provide operations regarding the - * use of the data types. + * use of the static types. */ #ifndef GEOS_COMMON_DATATYPES_HPP @@ -28,7 +29,6 @@ #include "BufferAllocator.hpp" #include "DataLayouts.hpp" #include "Tensor.hpp" -#include "Logger.hpp" #include "LvArray/src/Macros.hpp" #include "LvArray/src/Array.hpp" #include "LvArray/src/ArrayOfArrays.hpp" @@ -45,7 +45,7 @@ #include // System includes -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI #include #endif @@ -53,63 +53,23 @@ //#include #include #include +#include #include +#include +#include +#include +#include #include #include -#include -#include #include #include -#include -#include -/** - * top level geosx namespace contains all code that is specific to GEOSX +/* + * top level geos namespace contains all code that is specific to GEOSX */ namespace geos { -/** - * @brief Perform a type cast of base to derived pointer. - * @tparam NEW_TYPE derived pointer type - * @tparam EXISTING_TYPE base type - * @param val base pointer to cast - * @return pointer cast to derived type or @p nullptr - */ -template< typename NEW_TYPE, typename EXISTING_TYPE > -NEW_TYPE dynamicCast( EXISTING_TYPE * const val ) -{ - static_assert( std::is_pointer< NEW_TYPE >::value, "NEW_TYPE must be a pointer." ); - return dynamic_cast< NEW_TYPE >( val ); -} - -/** - * @brief Perform a type cast of base to derived reference. - * @tparam NEW_TYPE derived reference type - * @tparam EXISTING_TYPE base type - * @param val base reference to cast - * @return reference cast to derived type or @p nullptr - */ -template< typename NEW_TYPE, typename EXISTING_TYPE > -NEW_TYPE dynamicCast( EXISTING_TYPE & val ) -{ - static_assert( std::is_reference< NEW_TYPE >::value, "NEW_TYPE must be a reference." ); - - using POINTER_TO_NEW_TYPE = std::remove_reference_t< NEW_TYPE > *; - POINTER_TO_NEW_TYPE ptr = dynamicCast< POINTER_TO_NEW_TYPE >( &val ); - GEOS_ERROR_IF( ptr == nullptr, "Cast from " << LvArray::system::demangleType( val ) << " to " << - LvArray::system::demangleType< NEW_TYPE >() << " failed." ); - - return *ptr; -} - -/// Global MPI communicator used by GEOSX. -#ifdef GEOSX_USE_MPI -extern MPI_Comm MPI_COMM_GEOSX; -#else -extern int MPI_COMM_GEOSX; -#endif - /** * @name Basic data types used in GEOSX. */ @@ -122,10 +82,10 @@ using size_t = std::size_t; using integer = std::int32_t; /// Local index type (for indexing objects within an MPI partition). -using localIndex = GEOSX_LOCALINDEX_TYPE; +using localIndex = GEOS_LOCALINDEX_TYPE; /// Global index type (for indexing objects across MPI partitions). -using globalIndex = GEOSX_GLOBALINDEX_TYPE; +using globalIndex = GEOS_GLOBALINDEX_TYPE; /// String type. using string = std::string; @@ -148,7 +108,7 @@ using real64 = double; /// Type stored in communication buffers. using buffer_unit_type = signed char; -#ifdef GEOSX_USE_CHAI +#ifdef GEOS_USE_CHAI /// Type of storage for communication buffers. using buffer_type = std::vector< buffer_unit_type, BufferAllocator< buffer_unit_type > >; #else @@ -499,177 +459,6 @@ constexpr static auto LOCALINDEX_MAX = std::numeric_limits< localIndex >::max(); /// A global variable for the value of a object that has not been assigned a geos::globalIndex. constexpr static localIndex unmappedLocalIndexValue = -1; - -/** - * @brief Print a short summary of a few select type aliases. - */ -void printTypeSummary(); - -/** - * @brief The regular expression data for validating inputs. Use rtTypes to get the regex of a - * type, and TypeRegex< T > to define a type regex. - */ -struct Regex -{ - /** - * @brief the regular expression string. - */ - string m_regexStr; - /** - * @brief the description of the expected format of the regular expression. - */ - string m_formatDescription; - /** - * @brief Default constructor - */ - Regex() {} - /** - * @param regexStr the regex string for validation (eg. "[\\d]+") - * @param formatDescription the description of the expected format to be validated (eg. "Input value must be an integer."). - */ - Regex( string_view regexStr, string_view formatDescription ); -}; - -/** - * @brief Extension point for custom types to provide a validation regexp to schema. - * Do not use directly to obtain a type regex, rtTypes::getTypeRegex< T >() should be used instead. - * @tparam T the type for which the regex is defined - * @tparam ENABLE used to conditionally enable partial specializations - * - * Specializations should define the following method: - * \code{cpp} - * static string get(); - * \endcode - */ -template< typename T, typename ENABLE = void > -struct TypeRegex -{ - /** - * @brief Get the type's regex (default implementation returns nothing). - * @return The Regex associated with T. - */ - static Regex get() { return {}; } -}; - -/** - * @brief Static class to manage the type selection of types at runtime and obtain the - * regexes of these types. Typically, these types are 'xsd:simpleType' in the XSD. - */ -class rtTypes -{ -public: - - /** - * @brief the regex map type to store and find the regexes by the associated rtTypeName. - */ - using RegexMapType = std::map< string, Regex >; - - /** - * @brief Custom types are useful to customize the regexes of an existing type. The type name - * can be one of the existing ones, or a totally new one (which can then be used in Wrapper::setRTTypename). - */ - struct CustomTypes - { - /// @cond DO_NOT_DOCUMENT - static constexpr string_view mapPair = "mapPair"; - static constexpr string_view plotLevel = "geos_dataRepository_PlotLevel"; - static constexpr string_view groupName = "groupName"; - static constexpr string_view groupNameRef = "groupNameRef"; - static constexpr string_view groupNameRefArray = "groupNameRef_array"; - /// @endcond - }; - - /** - * @brief Convert a @p std::type_index to a string. - * @param key the std::type_index of the type - * @return a hard coded string that is related to the std::type_index - */ - static string getTypeName( std::type_index const key ); - - /** - * @tparam T type we want the regex - * @return the regex string for the default rtType of T to validate input values to this type. - */ - template< typename T > - static Regex const & getTypeRegex() - { return getTypeRegex< T >( getTypeName( typeid( T ) ) ); } - - /** - * @param typeName The rtType name of the type we want the regex (can be a CustomTypes). - * @tparam T the type we want the regex. If none are available in createBasicTypesRegexMap(), one is - * generated from TypeRegex< T >::get(). - * @return a regex string validating the type T. - */ - template< typename T > - static Regex const & getTypeRegex( string_view typeName ) - { - RegexMapType & map = getTypeRegexMap(); - auto const it = map.find( string( typeName ) ); - if( it != map.end() ) - { - return it->second; - } - else - { - return map.emplace( typeName, TypeRegex< T >::get() ).first->second; - } - } - - /** - * @brief Construct the regexMap for all basic types (TypeRegex< T > extented types are not mentionned) - * @return RegexMapType - */ - static RegexMapType createBasicTypesRegexMap(); - -private: - - /** - * @return A reference to the types regexes map - */ - static RegexMapType & getTypeRegexMap() - { - static RegexMapType m = createBasicTypesRegexMap(); - return m; - } - - /** - * @brief Private constructor because of static class - */ - rtTypes() {} - -}; - -/** - * @brief Utility class for querying type names at runtime. - * @tparam T the target type - * - * This relies on LvArray's demangling facilities and simply - * adds some convenience methods like getting the brief name. - */ -template< typename T > -struct TypeName -{ - /** - * @brief @return Full name of the type. - */ - static string full() - { - return ::LvArray::system::demangle( typeid( T ).name() ); - } - - /** - * @brief @return brief name of the type (ignoring namespaces). - */ - static string brief() - { - string const full_name = full(); - string::size_type const pos = full_name.find_last_of( "::" ); - return ( pos == string::npos ) ? full_name : full_name.substr( pos ); - } -}; - -} - - +} /* namespace geos */ #endif /* GEOS_COMMON_DATATYPES_HPP */ diff --git a/src/coreComponents/common/FieldSpecificationOps.hpp b/src/coreComponents/common/FieldSpecificationOps.hpp index 83f21027d6c..d663aae38a7 100644 --- a/src/coreComponents/common/FieldSpecificationOps.hpp +++ b/src/coreComponents/common/FieldSpecificationOps.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/common/FixedSizeDeque.hpp b/src/coreComponents/common/FixedSizeDeque.hpp index ea61af49a44..207d5dc7efb 100644 --- a/src/coreComponents/common/FixedSizeDeque.hpp +++ b/src/coreComponents/common/FixedSizeDeque.hpp @@ -2,22 +2,24 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ + #ifndef FIXEDSIZEDEQUE_HPP #define FIXEDSIZEDEQUE_HPP #include "LvArray/src/Array.hpp" #include "LvArray/src/memcpy.hpp" #include "LvArray/src/ChaiBuffer.hpp" -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" /// Get the positive value of a module b #define POSITIVE_MODULO( a, b ) ( ( ( a ) % ( b ) ) + b ) % ( b ) diff --git a/src/coreComponents/common/FixedSizeDequeWithMutexes.hpp b/src/coreComponents/common/FixedSizeDequeWithMutexes.hpp index e6532dc1392..68d1e9b983b 100644 --- a/src/coreComponents/common/FixedSizeDequeWithMutexes.hpp +++ b/src/coreComponents/common/FixedSizeDequeWithMutexes.hpp @@ -2,15 +2,17 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ + #ifndef FIXEDSIZEDEQUEWITHMUTEXES_HPP #define FIXEDSIZEDEQUEWITHMUTEXES_HPP @@ -50,7 +52,7 @@ class FixedSizeDequeWithMutexes : public FixedSizeDeque< T, INDEX_TYPE > * @param space Space used to store que queue. */ FixedSizeDequeWithMutexes( int maxEntries, int valuesPerEntry, LvArray::MemorySpace space ): FixedSizeDeque< T, INDEX_TYPE >( maxEntries, valuesPerEntry, space, -#ifdef GEOSX_USE_CUDA +#ifdef GEOS_USE_CUDA camp::resources::Resource{ camp::resources::Cuda{} } #else camp::resources::Resource{ camp::resources::Host{} } diff --git a/src/coreComponents/common/Format.hpp b/src/coreComponents/common/Format.hpp deleted file mode 100644 index e2a73a8789c..00000000000 --- a/src/coreComponents/common/Format.hpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -#ifndef GEOS_COMMON_FORMAT_HPP_ -#define GEOS_COMMON_FORMAT_HPP_ - -#include - -#if __cplusplus < 202002L -#define GEOSX_USE_FMT -#endif - -#ifdef GEOSX_USE_FMT -#define FMT_HEADER_ONLY -// Differentiate between standalone fmt path and umpire's fmt path -#include "../include/fmt/core.h" -#include "../include/fmt/chrono.h" -#include "../include/fmt/ranges.h" -#include "../include/fmt/xchar.h" -#define GEOS_FMT_NS fmt -#else // use C++20's -#include -#define GEOS_FMT_NS std -#endif - -#ifdef GEOSX_USE_FMT -/** - * @brief fmtlib formatter for enum classes. - * @tparam T The type of the object being formatted. This should be an - * enum class. - */ -template< typename T > -struct fmt::formatter< T, std::enable_if_t< std::is_enum< T >::value > > -{ - /** - * @brief Parser for the fmtlib formatting library. - * @param ctx The context provided by the fmtlib library, which includes - * the format string. - * @return An iterator pointing to the end of the format string. - */ - template< typename ParseContext > - constexpr auto parse( ParseContext & ctx ) - { - return ctx.end(); - } - - /** - * @brief Formatter for the fmtlib formatting library. - * @param value The enum class object to format. - * @param ctx The context provided by the fmtlib library, which includes - * the output iterator where the formatted string should be written. - * @return An iterator pointing to the end of the formatted string. - */ - template< typename FormatContext > - auto format( const T & value, FormatContext & ctx ) - { - return fmt::format_to( ctx.out(), "{}", static_cast< std::underlying_type_t< T > >( value ) ); - } -}; -#endif - -/** - * @brief Interpolate arguments into a message format string. - * @param msg the message format string, must be a constant expression - */ -#define GEOS_FMT( msg, ... ) GEOS_FMT_NS::format( msg, __VA_ARGS__ ) - -/** - * @brief Interpolate arguments into a message format string and write into an output iterator. - * @param iter the output iterator to write to - * @param size maximum number of characters to write - * @param msg the message format string, must be a constant expression - * @note Ensures the output buffer is zero-terminated (std::format_to_n doesn't) - */ -#define GEOS_FMT_TO( iter, size, msg, ... ) *GEOS_FMT_NS::format_to_n( iter, size - 1, msg, __VA_ARGS__ ).out = '\0' - -// The following workaround is needed to fix compilation with NVCC on some PowerPC machines. -// The issue causes the following assertion error message: -// "Cannot format an argument. To make type T formattable provide a formatter specialization" -// The standard definition of the has_const_formatter check of fmt fails due to a compiler bug, see the issue below: -// https://github.com/fmtlib/fmt/issues/2746 -// The workaround was originally implemented in fmt: -// https://github.com/fmtlib/fmt/commit/70de324aa801eaf52e94c402d526a3849797c620 -// but later removed: -// https://github.com/fmtlib/fmt/commit/466e0650ec2d153d255a40ec230eb77d7f1c3334 -// This workaround bypasse the check for a const formatter whenever the foramt context GEOS_FMT_NS::format_context is used -#ifdef GEOS_USE_FMT_CONST_FORMATTER_WORKAROUND -template< > -constexpr auto GEOS_FMT_NS::detail::has_const_formatter_impl< GEOS_FMT_NS::format_context >( ... ) -> bool -{ - return true; -} -#endif -// End of the workaround for fmt compilation issues - -#endif //GEOS_COMMON_FORMAT_HPP_ diff --git a/src/coreComponents/common/GEOS_RAJA_Interface.hpp b/src/coreComponents/common/GEOS_RAJA_Interface.hpp index 2aad742dc77..d1b2f2e3c8b 100644 --- a/src/coreComponents/common/GEOS_RAJA_Interface.hpp +++ b/src/coreComponents/common/GEOS_RAJA_Interface.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -39,7 +40,7 @@ using serialReduce = RAJA::seq_reduce; using serialStream = RAJA::resources::Host; using serialEvent = RAJA::resources::HostEvent; -#if defined( GEOSX_USE_OPENMP ) +#if defined( GEOS_USE_OPENMP ) auto const parallelHostMemorySpace = hostMemorySpace; @@ -70,10 +71,10 @@ void RAJA_INLINE parallelHostSync() { } #if defined( GEOS_USE_CUDA ) auto const parallelDeviceMemorySpace = LvArray::MemorySpace::cuda; -template< size_t BLOCK_SIZE = GEOSX_BLOCK_SIZE > +template< size_t BLOCK_SIZE = GEOS_BLOCK_SIZE > using parallelDevicePolicy = RAJA::cuda_exec< BLOCK_SIZE >; -template< size_t BLOCK_SIZE = GEOSX_BLOCK_SIZE > +template< size_t BLOCK_SIZE = GEOS_BLOCK_SIZE > using parallelDeviceAsyncPolicy = RAJA::cuda_exec_async< BLOCK_SIZE >; using parallelDeviceStream = RAJA::resources::Cuda; @@ -96,7 +97,7 @@ RAJA_INLINE parallelDeviceEvent forAll( RESOURCE && stream, const localIndex end auto const parallelDeviceMemorySpace = LvArray::MemorySpace::hip; -template< size_t BLOCK_SIZE = GEOSX_BLOCK_SIZE > +template< size_t BLOCK_SIZE = GEOS_BLOCK_SIZE > using parallelDevicePolicy = RAJA::hip_exec< BLOCK_SIZE >; @@ -109,7 +110,7 @@ using parallelDeviceAtomic = RAJA::hip_atomic; void RAJA_INLINE parallelDeviceSync() { RAJA::synchronize< RAJA::hip_synchronize >( ); } // the async dispatch policy caused runtime issues as of rocm@4.5.2, hasn't been checked in rocm@5: -template< size_t BLOCK_SIZE = GEOSX_BLOCK_SIZE > +template< size_t BLOCK_SIZE = GEOS_BLOCK_SIZE > using parallelDeviceAsyncPolicy = parallelDevicePolicy< BLOCK_SIZE >; // RAJA::hip_exec_async< BLOCK_SIZE >; template< typename POLICY, typename RESOURCE, typename LAMBDA > @@ -160,7 +161,7 @@ struct PolicyMap< serialPolicy > using reduce = serialReduce; }; -#if defined(GEOSX_USE_OPENMP) +#if defined(GEOS_USE_OPENMP) template<> struct PolicyMap< RAJA::omp_parallel_for_exec > { @@ -170,8 +171,8 @@ struct PolicyMap< RAJA::omp_parallel_for_exec > #endif #if defined(GEOS_USE_CUDA) -template< typename X, typename Y, size_t BLOCK_SIZE, bool ASYNC > -struct PolicyMap< RAJA::policy::cuda::cuda_exec_explicit< X, Y, BLOCK_SIZE, ASYNC > > +template< typename X, typename Y, typename C, size_t BLOCK_SIZE, bool ASYNC > +struct PolicyMap< RAJA::policy::cuda::cuda_exec_explicit< X, Y, C, BLOCK_SIZE, ASYNC > > { using atomic = RAJA::cuda_atomic; using reduce = RAJA::cuda_reduce; diff --git a/src/coreComponents/common/GeosxConfig.hpp.in b/src/coreComponents/common/GeosxConfig.hpp.in index 4b69fa93652..f09203faf06 100644 --- a/src/coreComponents/common/GeosxConfig.hpp.in +++ b/src/coreComponents/common/GeosxConfig.hpp.in @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + /** * @file GeosxConfig.hpp * @@ -9,28 +24,28 @@ #define GEOS_COMMON_CONFIG_HPP /// Enables floating point exceptions -#cmakedefine GEOSX_USE_FPE +#cmakedefine GEOS_USE_FPE /// Enables bounds check in LvArray classes (CMake option ARRAY_BOUNDS_CHECK) -#cmakedefine GEOSX_USE_ARRAY_BOUNDS_CHECK +#cmakedefine GEOS_USE_ARRAY_BOUNDS_CHECK /// Enables use of Caliper (CMake option ENABLE_CALIPER) -#cmakedefine GEOSX_USE_CALIPER +#cmakedefine GEOS_USE_CALIPER /// Enables use of Caliper (CMake option ENABLE_ADIAK) -#cmakedefine GEOSX_USE_ADIAK +#cmakedefine GEOS_USE_ADIAK /// Enables use of CHAI (CMake option ENABLE_CHAI) -#cmakedefine GEOSX_USE_CHAI +#cmakedefine GEOS_USE_CHAI /// Enables use of Mathpresso library (CMake option ENABLE_MATHPRESSO) -#cmakedefine GEOSX_USE_MATHPRESSO +#cmakedefine GEOS_USE_MATHPRESSO /// Enables use of MPI (CMake option ENABLE_MPI) -#cmakedefine GEOSX_USE_MPI +#cmakedefine GEOS_USE_MPI /// Enables use of OpenMP (CMake option ENABLE_OPENMP) -#cmakedefine GEOSX_USE_OPENMP +#cmakedefine GEOS_USE_OPENMP /// Enables use of CUDA (CMake option ENABLE_CUDA) #cmakedefine GEOS_USE_CUDA @@ -45,28 +60,28 @@ #cmakedefine GEOS_USE_FMT_CONST_FORMATTER_WORKAROUND /// Enables use of PVTPackage (CMake option ENABLE_PVTPackage) -#cmakedefine GEOSX_USE_PVTPackage +#cmakedefine GEOS_USE_PVTPackage /// Enables use of Python (CMake option ENABLE_PYTHON) -#cmakedefine GEOSX_USE_PYGEOSX +#cmakedefine GEOS_USE_PYGEOSX /// Enables use of RAJA (CMake option ENABLE_RAJA) -#cmakedefine GEOSX_USE_RAJA +#cmakedefine GEOS_USE_RAJA /// Enables use of sys/time.h based timers (CMake option ENABLE_TIMERS) -#cmakedefine GEOSX_USE_TIMERS +#cmakedefine GEOS_USE_TIMERS /// Enables use of additional debugging interface for TotalView (Cmake option ENABLE_TOTALVIEW_OUTPUT) -#cmakedefine GEOSX_USE_TOTALVIEW_OUTPUT +#cmakedefine GEOS_USE_TOTALVIEW_OUTPUT /// Enables use of Intel MKL (CMake option ENABLE_MKL) -#cmakedefine GEOSX_USE_MKL +#cmakedefine GEOS_USE_MKL /// Enables use of Trilinos library (CMake option ENABLE_TRILINOS) -#cmakedefine GEOSX_USE_TRILINOS +#cmakedefine GEOS_USE_TRILINOS /// Enables use of Hypre library (CMake option ENABLE_HYPRE) -#cmakedefine GEOSX_USE_HYPRE +#cmakedefine GEOS_USE_HYPRE /// Denotes HYPRE using CPU #define GEOS_USE_HYPRE_CPU 0 @@ -78,46 +93,46 @@ #cmakedefine GEOS_USE_HYPRE_DEVICE @GEOS_USE_HYPRE_DEVICE@ /// Enables use of SuperLU_dist library through HYPRE (CMake option ENABLE_SUPERLU_DIST) -#cmakedefine GEOSX_USE_SUPERLU_DIST +#cmakedefine GEOS_USE_SUPERLU_DIST /// Enables use of PETSc library (CMake option ENABLE_PETSC) -#cmakedefine GEOSX_USE_PETSC +#cmakedefine GEOS_USE_PETSC /// Enables use of Scotch library (CMake option ENABLE_SCOTCH) -#cmakedefine GEOSX_USE_SCOTCH +#cmakedefine GEOS_USE_SCOTCH -/// Choice of global linear algebra interface (CMake option GEOSX_LA_INTERFACE) -#cmakedefine GEOSX_LA_INTERFACE @GEOSX_LA_INTERFACE@ +/// Choice of global linear algebra interface (CMake option GEOS_LA_INTERFACE) +#cmakedefine GEOS_LA_INTERFACE @GEOS_LA_INTERFACE@ /// Macro defined when Trilinos interface is selected -#cmakedefine GEOSX_LA_INTERFACE_TRILINOS +#cmakedefine GEOS_LA_INTERFACE_TRILINOS /// Macro defined when Hypre interface is selected -#cmakedefine GEOSX_LA_INTERFACE_HYPRE +#cmakedefine GEOS_LA_INTERFACE_HYPRE /// Macro defined when PETSc interface is selected -#cmakedefine GEOSX_LA_INTERFACE_PETSC +#cmakedefine GEOS_LA_INTERFACE_PETSC /// Platform-dependent mangling of fortran function names (CMake option FORTRAN_MANGLE_NO_UNDERSCORE) #cmakedefine FORTRAN_MANGLE_NO_UNDERSCORE /// USE OF SEPARATION COEFFICIENT IN FRACTURE FLOW -#cmakedefine GEOSX_USE_SEPARATION_COEFFICIENT +#cmakedefine GEOS_USE_SEPARATION_COEFFICIENT /// CMake option CMAKE_BUILD_TYPE -#cmakedefine GEOSX_CMAKE_BUILD_TYPE @GEOSX_CMAKE_BUILD_TYPE@ +#cmakedefine GEOS_CMAKE_BUILD_TYPE @GEOS_CMAKE_BUILD_TYPE@ /// The type that localIndex will be aliased to. -#define GEOSX_LOCALINDEX_TYPE @GEOSX_LOCALINDEX_TYPE@ +#define GEOS_LOCALINDEX_TYPE @GEOS_LOCALINDEX_TYPE@ /// An integer flag representing the type that localIndex will be aliased to. -#define GEOSX_LOCALINDEX_TYPE_FLAG @GEOSX_LOCALINDEX_TYPE_FLAG@ +#define GEOS_LOCALINDEX_TYPE_FLAG @GEOS_LOCALINDEX_TYPE_FLAG@ /// The type that globalIndex will be aliased to. -#define GEOSX_GLOBALINDEX_TYPE @GEOSX_GLOBALINDEX_TYPE@ +#define GEOS_GLOBALINDEX_TYPE @GEOS_GLOBALINDEX_TYPE@ /// An integer flag representing the type that globalIndex will be aliased to. -#define GEOSX_GLOBALINDEX_TYPE_FLAG @GEOSX_GLOBALINDEX_TYPE_FLAG@ +#define GEOS_GLOBALINDEX_TYPE_FLAG @GEOS_GLOBALINDEX_TYPE_FLAG@ /// The default block size for GEOSX on this platform -#cmakedefine GEOSX_BLOCK_SIZE @GEOSX_BLOCK_SIZE@ +#cmakedefine GEOS_BLOCK_SIZE @GEOS_BLOCK_SIZE@ /// Version information for HDF5 #cmakedefine HDF5_VERSION @HDF5_VERSION@ diff --git a/src/coreComponents/common/GeosxMacros.hpp b/src/coreComponents/common/GeosxMacros.hpp index 357b64bbfdb..bf3ab070948 100644 --- a/src/coreComponents/common/GeosxMacros.hpp +++ b/src/coreComponents/common/GeosxMacros.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -87,7 +88,7 @@ void i_g_n_o_r_e( ARGS const & ... ) {} ///@} -#if defined(GEOSX_USE_OPENMP) +#if defined(GEOS_USE_OPENMP) /// Wrap a pragma clause in the _Pragma statement. We seek to make this include the omp portion of the clause. #define PRAGMA_OMP( clause ) _Pragma( clause ) // #define PRAGMA_OMP( clause ) _Pragma( STRINGIZE( omp clause ) ) diff --git a/src/coreComponents/common/LifoStorage.hpp b/src/coreComponents/common/LifoStorage.hpp index 821d28d4377..a8e68640fc5 100644 --- a/src/coreComponents/common/LifoStorage.hpp +++ b/src/coreComponents/common/LifoStorage.hpp @@ -2,15 +2,17 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ + #ifndef LIFOSTORAGE_HPP #define LIFOSTORAGE_HPP diff --git a/src/coreComponents/common/LifoStorageCommon.hpp b/src/coreComponents/common/LifoStorageCommon.hpp index 615597e089c..3183cde65b8 100644 --- a/src/coreComponents/common/LifoStorageCommon.hpp +++ b/src/coreComponents/common/LifoStorageCommon.hpp @@ -2,15 +2,17 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ + #ifndef LIFOSTORAGECOMMON_HPP #define LIFOSTORAGECOMMON_HPP diff --git a/src/coreComponents/common/LifoStorageCuda.hpp b/src/coreComponents/common/LifoStorageCuda.hpp index 9345db2615d..58016032dcb 100644 --- a/src/coreComponents/common/LifoStorageCuda.hpp +++ b/src/coreComponents/common/LifoStorageCuda.hpp @@ -2,15 +2,17 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ + #ifndef LIFOSTORAGECUDA_HPP #define LIFOSTORAGECUDA_HPP @@ -78,7 +80,7 @@ class LifoStorageCuda : public LifoStorageCommon< T, INDEX_TYPE > if( baseLifo::m_maxNumberOfBuffers - id > (int)m_deviceDeque.capacity() ) { - LIFO_MARK_SCOPE( geosx::lifoStorage::pushAddTasks ); + LIFO_MARK_SCOPE( geos::lifoStorage::pushAddTasks ); // This buffer will go to host memory, and maybe on disk std::packaged_task< void() > task( std::bind( &LifoStorageCuda< T, INDEX_TYPE >::deviceToHost, this, baseLifo::m_bufferToHostCount++ ) ); { @@ -112,7 +114,7 @@ class LifoStorageCuda : public LifoStorageCommon< T, INDEX_TYPE > if( baseLifo::m_bufferToHostCount > 0 ) { - LIFO_MARK_SCOPE( geosx::LifoStorageCuda::popAddTasks ); + LIFO_MARK_SCOPE( geos::LifoStorageCuda::popAddTasks ); // Trigger pull one buffer from host, and maybe from disk std::packaged_task< void() > task( std::bind( &LifoStorageCuda< T, INDEX_TYPE >::hostToDevice, this, --baseLifo::m_bufferToHostCount, id ) ); { @@ -132,8 +134,7 @@ class LifoStorageCuda : public LifoStorageCommon< T, INDEX_TYPE > if( baseLifo::m_bufferCount < baseLifo::m_maxNumberOfBuffers ) { int bufferCount = baseLifo::m_bufferCount; - auto cuda_event = m_popFromDeviceEvents[bufferCount].try_get< camp::resources::CudaEvent >(); - if( cuda_event ) cudaEventSynchronize( cuda_event->getCudaEvent_t() ); + m_popFromDeviceEvents[bufferCount].wait(); } } diff --git a/src/coreComponents/common/LifoStorageHost.hpp b/src/coreComponents/common/LifoStorageHost.hpp index c11999de0cd..348b4a4109c 100644 --- a/src/coreComponents/common/LifoStorageHost.hpp +++ b/src/coreComponents/common/LifoStorageHost.hpp @@ -2,15 +2,17 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ + #ifndef LIFOSTORAGEHOST_HPP #define LIFOSTORAGEHOST_HPP @@ -74,7 +76,7 @@ class LifoStorageHost : public LifoStorageCommon< T, INDEX_TYPE > if( baseLifo::m_maxNumberOfBuffers - pushId > (int)baseLifo::m_hostDeque.capacity() ) { - LIFO_MARK_SCOPE( geosx::lifoStorage::pushAddTasks ); + LIFO_MARK_SCOPE( geos::lifoStorage::pushAddTasks ); // This buffer will go to host memory, and maybe on disk std::packaged_task< void() > t2( std::bind( &LifoStorageHost< T, INDEX_TYPE >::hostToDisk, this, baseLifo::m_bufferToDiskCount++ ) ); { @@ -117,7 +119,7 @@ class LifoStorageHost : public LifoStorageCommon< T, INDEX_TYPE > if( baseLifo::m_bufferToDiskCount > 0 ) { - LIFO_MARK_SCOPE( geosx::LifoStorageHost::popAddTasks ); + LIFO_MARK_SCOPE( geos::LifoStorageHost::popAddTasks ); // Trigger pull one buffer from host, and maybe from disk std::packaged_task< void() > task2( std::bind( &LifoStorageHost< T, INDEX_TYPE >::diskToHost, this, --baseLifo::m_bufferToDiskCount ) ); { diff --git a/src/coreComponents/common/MemoryInfos.cpp b/src/coreComponents/common/MemoryInfos.cpp new file mode 100644 index 00000000000..1e31cdb6bed --- /dev/null +++ b/src/coreComponents/common/MemoryInfos.cpp @@ -0,0 +1,74 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "MemoryInfos.hpp" + +namespace geos +{ +MemoryInfos::MemoryInfos( umpire::MemoryResourceTraits::resource_type resourceType ): + m_totalMemory( 0 ), + m_availableMemory( 0 ), + m_physicalMemoryHandled( 1 ) +{ + switch( resourceType ) + { + case umpire::MemoryResourceTraits::resource_type::host: + case umpire::MemoryResourceTraits::resource_type::pinned: + #if defined( _SC_PHYS_PAGES ) && defined( _SC_PAGESIZE ) + m_totalMemory = sysconf( _SC_PHYS_PAGES ) * sysconf( _SC_PAGESIZE ); + #if defined(_SC_AVPHYS_PAGES) + m_availableMemory = sysconf( _SC_AVPHYS_PAGES ) * sysconf( _SC_PAGESIZE ); + #else + GEOS_WARNING( "Unknown device avaialable memory size getter for this system." ); + m_availableMemory = 0; + #endif + #else + GEOS_WARNING( "Unknown device physical memory size getter for this compiler." ); + m_physicalMemoryHandled = 0; + #endif + break; + case umpire::MemoryResourceTraits::resource_type::device: + case umpire::MemoryResourceTraits::resource_type::device_const: + case umpire::MemoryResourceTraits::resource_type::um: + #if defined( GEOS_USE_CUDA ) + cudaMemGetInfo( &m_availableMemory, &m_totalMemory ); + #else + GEOS_WARNING( "Unknown device physical memory size getter for this compiler." ); + m_physicalMemoryHandled = 0; + #endif + break; + default: + GEOS_WARNING( "Physical memory lookup not implemented" ); + m_physicalMemoryHandled = 0; + break; + } +} + +size_t MemoryInfos::getTotalMemory() const +{ + return m_totalMemory; +} + +size_t MemoryInfos::getAvailableMemory() const +{ + return m_availableMemory; +} + +bool MemoryInfos::isPhysicalMemoryHandled() const +{ + return m_physicalMemoryHandled; +} + +} diff --git a/src/coreComponents/common/MemoryInfos.hpp b/src/coreComponents/common/MemoryInfos.hpp new file mode 100644 index 00000000000..3500093c6de --- /dev/null +++ b/src/coreComponents/common/MemoryInfos.hpp @@ -0,0 +1,73 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#ifndef GEOS_COMMON_MemoryInfos_HPP_ +#define GEOS_COMMON_MemoryInfos_HPP_ + +#include "umpire/util/MemoryResourceTraits.hpp" +#include "common/logger/Logger.hpp" +#include +#include +#if defined( GEOS_USE_CUDA ) +#include +#endif + +namespace geos +{ + +/** + * @class MemoryInfos + * @brief Class to fetch and store memory information for different resource types. + */ +class MemoryInfos +{ +public: + + /** + * @brief Constructor for MemoryInfos. + * @param resourceType The type of memory resource. + */ + MemoryInfos( umpire::MemoryResourceTraits::resource_type resourceType ); + + /** + * @brief Get the total memory available for the resource type. + * @return Total memory in bytes. + */ + size_t getTotalMemory() const; + + /** + * @brief Get the available memory for the resource type. + * @return Available memory in bytes. + */ + size_t getAvailableMemory() const; + + /** + * @brief Check if physical memory is handled. + * @return True if physical memory is handled, false otherwise. + */ + bool isPhysicalMemoryHandled() const; +private: + + ///total memory available. + size_t m_totalMemory; + ///Available memory. + size_t m_availableMemory; + ///Flag indicating if physical memory is handled. + bool m_physicalMemoryHandled; +}; + +} + +#endif diff --git a/src/coreComponents/common/MpiWrapper.cpp b/src/coreComponents/common/MpiWrapper.cpp index e93e0e2c873..f050151a3e4 100644 --- a/src/coreComponents/common/MpiWrapper.cpp +++ b/src/coreComponents/common/MpiWrapper.cpp @@ -2,15 +2,17 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ + /** * @file MpiWrapper.cpp */ @@ -30,16 +32,22 @@ namespace geos { +#ifdef GEOS_USE_MPI +MPI_Comm MPI_COMM_GEOS; +#else +int MPI_COMM_GEOS = 0; +#endif + void MpiWrapper::barrier( MPI_Comm const & MPI_PARAM( comm ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI MPI_Barrier( comm ); #endif } int MpiWrapper::cartCoords( MPI_Comm comm, int rank, int maxdims, int coords[] ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Cart_coords( comm, rank, maxdims, coords ); #else return 0; @@ -49,7 +57,7 @@ int MpiWrapper::cartCoords( MPI_Comm comm, int rank, int maxdims, int coords[] ) int MpiWrapper::cartCreate( MPI_Comm comm_old, int ndims, const int dims[], const int periods[], int reorder, MPI_Comm * comm_cart ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Cart_create( comm_old, ndims, dims, periods, reorder, comm_cart ); #else return 0; @@ -59,7 +67,7 @@ int MpiWrapper::cartCreate( MPI_Comm comm_old, int ndims, const int dims[], cons int MpiWrapper::cartRank( MPI_Comm comm, const int coords[] ) { int rank = 0; -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI MPI_Cart_rank( comm, coords, &rank ); #endif return rank; @@ -67,7 +75,7 @@ int MpiWrapper::cartRank( MPI_Comm comm, const int coords[] ) void MpiWrapper::commFree( MPI_Comm & comm ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI MPI_CHECK_ERROR( MPI_Comm_free( &comm ) ); #else // comm = MPI_COMM_NULL; @@ -77,7 +85,7 @@ void MpiWrapper::commFree( MPI_Comm & comm ) int MpiWrapper::commRank( MPI_Comm const & MPI_PARAM( comm ) ) { int rank = 0; -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI MPI_Comm_rank( comm, &rank ); #endif return rank; @@ -86,7 +94,7 @@ int MpiWrapper::commRank( MPI_Comm const & MPI_PARAM( comm ) ) int MpiWrapper::commSize( MPI_Comm const & MPI_PARAM( comm ) ) { int size = 1; -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI MPI_Comm_size( comm, &size ); #endif return size; @@ -94,7 +102,7 @@ int MpiWrapper::commSize( MPI_Comm const & MPI_PARAM( comm ) ) bool MpiWrapper::commCompare( MPI_Comm const & comm1, MPI_Comm const & comm2 ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI int result; MPI_Comm_compare( comm1, comm2, &result ); return result == MPI_IDENT || result == MPI_CONGRUENT; @@ -105,7 +113,7 @@ bool MpiWrapper::commCompare( MPI_Comm const & comm1, MPI_Comm const & comm2 ) bool MpiWrapper::initialized() { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI int ret = false; MPI_CHECK_ERROR( MPI_Initialized( &ret ) ); return ret; @@ -116,7 +124,7 @@ bool MpiWrapper::initialized() int MpiWrapper::init( int * argc, char * * * argv ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Init( argc, argv ); #else return 0; @@ -125,7 +133,7 @@ int MpiWrapper::init( int * argc, char * * * argv ) void MpiWrapper::finalize() { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI MPI_CHECK_ERROR( MPI_Finalize() ); #endif } @@ -133,7 +141,7 @@ void MpiWrapper::finalize() MPI_Comm MpiWrapper::commDup( MPI_Comm const comm ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI MPI_Comm duplicate; MPI_CHECK_ERROR( MPI_Comm_dup( comm, &duplicate ) ); return duplicate; @@ -144,7 +152,7 @@ MPI_Comm MpiWrapper::commDup( MPI_Comm const comm ) MPI_Comm MpiWrapper::commSplit( MPI_Comm const comm, int color, int key ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI MPI_Comm scomm; MPI_CHECK_ERROR( MPI_Comm_split( comm, color, key, &scomm ) ); return scomm; @@ -155,7 +163,7 @@ MPI_Comm MpiWrapper::commSplit( MPI_Comm const comm, int color, int key ) int MpiWrapper::test( MPI_Request * request, int * flag, MPI_Status * status ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Test( request, flag, status ); #else *flag = 0; @@ -165,7 +173,7 @@ int MpiWrapper::test( MPI_Request * request, int * flag, MPI_Status * status ) int MpiWrapper::testAny( int count, MPI_Request array_of_requests[], int * idx, int * flag, MPI_Status array_of_statuses[] ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Testany( count, array_of_requests, idx, flag, array_of_statuses ); #else *flag = 0; @@ -175,7 +183,7 @@ int MpiWrapper::testAny( int count, MPI_Request array_of_requests[], int * idx, int MpiWrapper::testSome( int count, MPI_Request array_of_requests[], int * outcount, int array_of_indices[], MPI_Status array_of_statuses[] ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Testsome( count, array_of_requests, outcount, array_of_indices, array_of_statuses ); #else *outcount = 0; @@ -185,7 +193,7 @@ int MpiWrapper::testSome( int count, MPI_Request array_of_requests[], int * outc int MpiWrapper::testAll( int count, MPI_Request array_of_requests[], int * flag, MPI_Status array_of_statuses[] ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Testall( count, array_of_requests, flag, array_of_statuses ); #else *flag = 0; @@ -195,7 +203,7 @@ int MpiWrapper::testAll( int count, MPI_Request array_of_requests[], int * flag, int MpiWrapper::check( MPI_Request * request, int * flag, MPI_Status * status ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Request_get_status( *request, flag, status ); #else *flag = 0; @@ -205,7 +213,7 @@ int MpiWrapper::check( MPI_Request * request, int * flag, MPI_Status * status ) int MpiWrapper::checkAny( int count, MPI_Request array_of_requests[], int * idx, int * flag, MPI_Status array_of_statuses[] ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI bool found = false; int flagCache = -1; int rval = MPI_SUCCESS; @@ -237,7 +245,7 @@ int MpiWrapper::checkAny( int count, MPI_Request array_of_requests[], int * idx, int MpiWrapper::checkAll( int count, MPI_Request array_of_requests[], int * flag, MPI_Status array_of_statuses[] ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI // assume all passing, any that don't pass set the flag to false *flag = 1; int rval = MPI_SUCCESS; @@ -264,7 +272,7 @@ int MpiWrapper::checkAll( int count, MPI_Request array_of_requests[], int * flag int MpiWrapper::wait( MPI_Request * request, MPI_Status * status ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Wait( request, status ); #else return 0; @@ -273,7 +281,7 @@ int MpiWrapper::wait( MPI_Request * request, MPI_Status * status ) int MpiWrapper::waitAny( int count, MPI_Request array_of_requests[], int * indx, MPI_Status array_of_statuses[] ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Waitany( count, array_of_requests, indx, array_of_statuses ); #else return 0; @@ -282,7 +290,7 @@ int MpiWrapper::waitAny( int count, MPI_Request array_of_requests[], int * indx, int MpiWrapper::waitSome( int count, MPI_Request array_of_requests[], int * outcount, int array_of_indices[], MPI_Status array_of_statuses[] ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Waitsome( count, array_of_requests, outcount, array_of_indices, array_of_statuses ); #else // *outcount = 0; @@ -292,7 +300,7 @@ int MpiWrapper::waitSome( int count, MPI_Request array_of_requests[], int * outc int MpiWrapper::waitAll( int count, MPI_Request array_of_requests[], MPI_Status array_of_statuses[] ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Waitall( count, array_of_requests, array_of_statuses ); #else return 0; @@ -301,7 +309,7 @@ int MpiWrapper::waitAll( int count, MPI_Request array_of_requests[], MPI_Status double MpiWrapper::wtime( void ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Wtime( ); #else return 0; diff --git a/src/coreComponents/common/MpiWrapper.hpp b/src/coreComponents/common/MpiWrapper.hpp index 10fb0dccde6..22def51e1e8 100644 --- a/src/coreComponents/common/MpiWrapper.hpp +++ b/src/coreComponents/common/MpiWrapper.hpp @@ -2,15 +2,17 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ + /** * @file MpiWrapper.hpp */ @@ -20,9 +22,8 @@ #include "common/DataTypes.hpp" #include "common/Span.hpp" -#include "mesh/ElementType.hpp" -#if defined(GEOSX_USE_MPI) +#if defined(GEOS_USE_MPI) #include #define MPI_PARAM( x ) x #else @@ -97,6 +98,13 @@ struct MPI_Status namespace geos { +/// Global MPI communicator used by GEOSX. +#ifdef GEOS_USE_MPI +extern MPI_Comm MPI_COMM_GEOS; +#else +extern int MPI_COMM_GEOS; +#endif + /** * @struct MpiWrapper * This struct is a wrapper for all mpi.h functions that are used in GEOSX, and provides a collection of @@ -138,7 +146,7 @@ struct MpiWrapper */ ///@{ - static void barrier( MPI_Comm const & MPI_PARAM( comm )=MPI_COMM_GEOSX ); + static void barrier( MPI_Comm const & MPI_PARAM( comm )=MPI_COMM_GEOS ); static int cartCoords( MPI_Comm comm, int rank, int maxdims, int coords[] ); @@ -149,9 +157,9 @@ struct MpiWrapper static void commFree( MPI_Comm & comm ); - static int commRank( MPI_Comm const & MPI_PARAM( comm )=MPI_COMM_GEOSX ); + static int commRank( MPI_Comm const & MPI_PARAM( comm )=MPI_COMM_GEOS ); - static int commSize( MPI_Comm const & MPI_PARAM( comm )=MPI_COMM_GEOSX ); + static int commSize( MPI_Comm const & MPI_PARAM( comm )=MPI_COMM_GEOS ); static bool commCompare( MPI_Comm const & comm1, MPI_Comm const & comm2 ); @@ -277,7 +285,7 @@ struct MpiWrapper std::vector< std::tuple< MPI_Request *, MPI_Status *, std::function< MPI_Request ( int ) > > > const & phases ); ///@} -#if !defined(GEOSX_USE_MPI) +#if !defined(GEOS_USE_MPI) static std::map< int, std::pair< int, void * > > & getTagToPointersMap() { static std::map< int, std::pair< int, void * > > tagToPointers; @@ -336,12 +344,12 @@ struct MpiWrapper * @param[out] allValues The values recived from each rank. */ template< typename T > - static void allGather( T const myValue, array1d< T > & allValues, MPI_Comm comm = MPI_COMM_GEOSX ); + static void allGather( T const myValue, array1d< T > & allValues, MPI_Comm comm = MPI_COMM_GEOS ); template< typename T > static int allGather( arrayView1d< T const > const & sendbuf, array1d< T > & recvbuf, - MPI_Comm comm = MPI_COMM_GEOSX ); + MPI_Comm comm = MPI_COMM_GEOS ); /** * @brief Strongly typed wrapper around MPI_Allreduce. @@ -353,7 +361,7 @@ struct MpiWrapper * @return The return value of the underlying call to MPI_Allreduce(). */ template< typename T > - static int allReduce( T const * sendbuf, T * recvbuf, int count, MPI_Op op, MPI_Comm comm = MPI_COMM_GEOSX ); + static int allReduce( T const * sendbuf, T * recvbuf, int count, MPI_Op op, MPI_Comm comm = MPI_COMM_GEOS ); /** * @brief Convenience wrapper for the MPI_Allreduce function. @@ -364,7 +372,7 @@ struct MpiWrapper * @return The value of reduction across all ranks */ template< typename T > - static T allReduce( T const & value, Reduction const op, MPI_Comm comm = MPI_COMM_GEOSX ); + static T allReduce( T const & value, Reduction const op, MPI_Comm comm = MPI_COMM_GEOS ); /** * @brief Convenience wrapper for the MPI_Allreduce function. Version for sequences. @@ -375,7 +383,7 @@ struct MpiWrapper * @param comm The communicator. */ template< typename T > - static void allReduce( Span< T const > src, Span< T > dst, Reduction const op, MPI_Comm comm = MPI_COMM_GEOSX ); + static void allReduce( Span< T const > src, Span< T > dst, Reduction const op, MPI_Comm comm = MPI_COMM_GEOS ); /** @@ -388,7 +396,7 @@ struct MpiWrapper * @return The return value of the underlying call to MPI_Reduce(). */ template< typename T > - static int reduce( T const * sendbuf, T * recvbuf, int count, MPI_Op op, int root, MPI_Comm comm = MPI_COMM_GEOSX ); + static int reduce( T const * sendbuf, T * recvbuf, int count, MPI_Op op, int root, MPI_Comm comm = MPI_COMM_GEOS ); /** * @brief Convenience wrapper for the MPI_Reduce function. @@ -399,7 +407,7 @@ struct MpiWrapper * @return The value of reduction (only significant at root) */ template< typename T > - static T reduce( T const & value, Reduction const op, int root, MPI_Comm comm = MPI_COMM_GEOSX ); + static T reduce( T const & value, Reduction const op, int root, MPI_Comm comm = MPI_COMM_GEOS ); /** * @brief Convenience wrapper for the MPI_Reduce function. Version for sequences. @@ -410,7 +418,7 @@ struct MpiWrapper * @param comm The communicator. */ template< typename T > - static void reduce( Span< T const > src, Span< T > dst, Reduction const op, int root, MPI_Comm comm = MPI_COMM_GEOSX ); + static void reduce( Span< T const > src, Span< T > dst, Reduction const op, int root, MPI_Comm comm = MPI_COMM_GEOS ); template< typename T > @@ -438,7 +446,7 @@ struct MpiWrapper * @param srcRank The rank that is sending the \p value. */ template< typename T > - static void broadcast( T & value, int srcRank = 0, MPI_Comm comm = MPI_COMM_GEOSX ); + static void broadcast( T & value, int srcRank = 0, MPI_Comm comm = MPI_COMM_GEOS ); /** * @brief Strongly typed wrapper around MPI_Gather(). @@ -548,7 +556,7 @@ struct MpiWrapper * @return a pair where first is the prefix sum, second is the full sum */ template< typename U, typename T > - static U prefixSum( T const value, MPI_Comm comm = MPI_COMM_GEOSX ); + static U prefixSum( T const value, MPI_Comm comm = MPI_COMM_GEOS ); /** * @brief Convenience function for a MPI_Allreduce using a MPI_SUM operation. @@ -556,7 +564,7 @@ struct MpiWrapper * @return The sum of all \p value across the ranks. */ template< typename T > - static T sum( T const & value, MPI_Comm comm = MPI_COMM_GEOSX ); + static T sum( T const & value, MPI_Comm comm = MPI_COMM_GEOS ); /** * @brief Convenience function for a MPI_Allreduce using a MPI_SUM operation. @@ -565,7 +573,7 @@ struct MpiWrapper * @return The sum of all \p value across the ranks. */ template< typename T > - static void sum( Span< T const > src, Span< T > dst, MPI_Comm comm = MPI_COMM_GEOSX ); + static void sum( Span< T const > src, Span< T > dst, MPI_Comm comm = MPI_COMM_GEOS ); /** * @brief Convenience function for a MPI_Allreduce using a MPI_MIN operation. @@ -573,7 +581,7 @@ struct MpiWrapper * @return The minimum of all \p value across the ranks. */ template< typename T > - static T min( T const & value, MPI_Comm comm = MPI_COMM_GEOSX ); + static T min( T const & value, MPI_Comm comm = MPI_COMM_GEOS ); /** * @brief Convenience function for a MPI_Allreduce using a MPI_MIN operation. @@ -582,7 +590,7 @@ struct MpiWrapper * @return The minimum of all \p value across the ranks. */ template< typename T > - static void min( Span< T const > src, Span< T > dst, MPI_Comm comm = MPI_COMM_GEOSX ); + static void min( Span< T const > src, Span< T > dst, MPI_Comm comm = MPI_COMM_GEOS ); /** * @brief Convenience function for a MPI_Allreduce using a MPI_MAX operation. @@ -590,7 +598,7 @@ struct MpiWrapper * @return The maximum of all \p value across the ranks. */ template< typename T > - static T max( T const & value, MPI_Comm comm = MPI_COMM_GEOSX ); + static T max( T const & value, MPI_Comm comm = MPI_COMM_GEOS ); /** * @brief Convenience function for a MPI_Allreduce using a MPI_MAX operation. @@ -599,7 +607,17 @@ struct MpiWrapper * @return The maximum of all \p value across the ranks. */ template< typename T > - static void max( Span< T const > src, Span< T > dst, MPI_Comm comm = MPI_COMM_GEOSX ); + static void max( Span< T const > src, Span< T > dst, MPI_Comm comm = MPI_COMM_GEOS ); + + + /** + * @brief Convenience function for MPI_Gather using a MPI_MAX operation on struct of value and location + * @brief Max is performed on value and location (global index) is returned + * @param[in] struct to send into the max gather. + * @return struct with max val and location + */ + template< typename T > static T maxValLoc( T localValueLocation, MPI_Comm comm = MPI_COMM_GEOS ); + }; namespace internal @@ -675,7 +693,7 @@ int MpiWrapper::allgather( T_SEND const * const sendbuf, int recvcount, MPI_Comm MPI_PARAM( comm ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Allgather( sendbuf, sendcount, internal::getMpiType< T_SEND >(), recvbuf, recvcount, internal::getMpiType< T_RECV >(), comm ); @@ -696,7 +714,7 @@ int MpiWrapper::allgatherv( T_SEND const * const sendbuf, int * displacements, MPI_Comm MPI_PARAM( comm ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Allgatherv( sendbuf, sendcount, internal::getMpiType< T_SEND >(), recvbuf, recvcounts, displacements, internal::getMpiType< T_RECV >(), comm ); @@ -713,7 +731,7 @@ int MpiWrapper::allgatherv( T_SEND const * const sendbuf, template< typename T > void MpiWrapper::allGather( T const myValue, array1d< T > & allValues, MPI_Comm MPI_PARAM( comm ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI int const mpiSize = commSize( comm ); allValues.resize( mpiSize ); @@ -733,7 +751,7 @@ int MpiWrapper::allGather( arrayView1d< T const > const & sendValues, MPI_Comm MPI_PARAM( comm ) ) { int const sendSize = LvArray::integerConversion< int >( sendValues.size() ); -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI int const mpiSize = commSize( comm ); allValues.resize( mpiSize * sendSize ); return MPI_Allgather( sendValues.data(), @@ -761,7 +779,7 @@ int MpiWrapper::allReduce( T const * const sendbuf, MPI_Op const MPI_PARAM( op ), MPI_Comm const MPI_PARAM( comm ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI MPI_Datatype const mpiType = internal::getMpiType< T >(); return MPI_Allreduce( sendbuf == recvbuf ? MPI_IN_PLACE : sendbuf, recvbuf, count, mpiType, op, comm ); #else @@ -781,7 +799,7 @@ int MpiWrapper::reduce( T const * const sendbuf, int root, MPI_Comm const MPI_PARAM( comm ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI MPI_Datatype const mpiType = internal::getMpiType< T >(); return MPI_Reduce( sendbuf == recvbuf ? MPI_IN_PLACE : sendbuf, recvbuf, count, mpiType, op, root, comm ); #else @@ -800,7 +818,7 @@ int MpiWrapper::scan( T const * const sendbuf, MPI_Op MPI_PARAM( op ), MPI_Comm MPI_PARAM( comm ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Scan( sendbuf, recvbuf, count, internal::getMpiType< T >(), op, comm ); #else memcpy( recvbuf, sendbuf, count*sizeof(T) ); @@ -815,7 +833,7 @@ int MpiWrapper::exscan( T const * const MPI_PARAM( sendbuf ), MPI_Op MPI_PARAM( op ), MPI_Comm MPI_PARAM( comm ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Exscan( sendbuf, recvbuf, count, internal::getMpiType< T >(), op, comm ); #else memset( recvbuf, 0, count*sizeof(T) ); @@ -829,7 +847,7 @@ int MpiWrapper::bcast( T * const MPI_PARAM( buffer ), int MPI_PARAM( root ), MPI_Comm MPI_PARAM( comm ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Bcast( buffer, count, internal::getMpiType< T >(), root, comm ); #else return 0; @@ -840,7 +858,7 @@ int MpiWrapper::bcast( T * const MPI_PARAM( buffer ), template< typename T > void MpiWrapper::broadcast( T & MPI_PARAM( value ), int MPI_PARAM( srcRank ), MPI_Comm MPI_PARAM( comm ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI MPI_Bcast( &value, 1, internal::getMpiType< T >(), srcRank, comm ); #endif } @@ -851,7 +869,7 @@ void MpiWrapper::broadcast< string >( string & MPI_PARAM( value ), int MPI_PARAM( srcRank ), MPI_Comm MPI_PARAM( comm ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI int size = LvArray::integerConversion< int >( value.size() ); broadcast( size, srcRank, comm ); value.resize( size ); @@ -867,7 +885,7 @@ int MpiWrapper::gather( TS const * const sendbuf, int MPI_PARAM( root ), MPI_Comm MPI_PARAM( comm ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Gather( sendbuf, sendcount, internal::getMpiType< TS >(), recvbuf, recvcount, internal::getMpiType< TR >(), root, comm ); @@ -891,7 +909,7 @@ int MpiWrapper::gatherv( TS const * const sendbuf, int MPI_PARAM( root ), MPI_Comm MPI_PARAM( comm ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return MPI_Gatherv( sendbuf, sendcount, internal::getMpiType< TS >(), recvbuf, recvcounts, displs, internal::getMpiType< TR >(), root, comm ); @@ -914,7 +932,7 @@ int MpiWrapper::iRecv( T * const buf, MPI_Comm MPI_PARAM( comm ), MPI_Request * MPI_PARAM( request ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI GEOS_ERROR_IF( (*request)!=MPI_REQUEST_NULL, "Attempting to use an MPI_Request that is still in use." ); return MPI_Irecv( buf, count, internal::getMpiType< T >(), source, tag, comm, request ); @@ -944,7 +962,7 @@ int MpiWrapper::recv( array1d< T > & buf, MPI_Comm MPI_PARAM( comm ), MPI_Status * MPI_PARAM( request ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI MPI_Status status; int count; MPI_Probe( source, tag, comm, &status ); @@ -973,7 +991,7 @@ int MpiWrapper::iSend( arrayView1d< T > const & buf, MPI_Comm MPI_PARAM( comm ), MPI_Request * MPI_PARAM( request ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI GEOS_ERROR_IF( (*request)!=MPI_REQUEST_NULL, "Attempting to use an MPI_Request that is still in use." ); return MPI_Isend( reinterpret_cast< void const * >( buf.data() ), @@ -997,7 +1015,7 @@ int MpiWrapper::iSend( T const * const buf, MPI_Comm MPI_PARAM( comm ), MPI_Request * MPI_PARAM( request ) ) { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI GEOS_ERROR_IF( (*request)!=MPI_REQUEST_NULL, "Attempting to use an MPI_Request that is still in use." ); return MPI_Isend( buf, count, internal::getMpiType< T >(), dest, tag, comm, request ); @@ -1026,7 +1044,7 @@ U MpiWrapper::prefixSum( T const value, MPI_Comm comm ) { U localResult; -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI U const convertedValue = value; int const error = MPI_Exscan( &convertedValue, &localResult, 1, internal::getMpiType< U >(), MPI_SUM, comm ); MPI_CHECK_ERROR( error ); @@ -1107,7 +1125,32 @@ void MpiWrapper::reduce( Span< T const > const src, Span< T > const dst, Reducti reduce( src.data(), dst.data(), LvArray::integerConversion< int >( src.size() ), getMpiOp( op ), root, comm ); } +// Mpi helper function to return struct containing the max value and location across ranks +template< typename T > +T MpiWrapper::maxValLoc( T localValueLocation, MPI_Comm comm ) +{ + // Ensure T is trivially copyable + static_assert( std::is_trivially_copyable< T >::value, "maxValLoc requires a trivially copyable type" ); + + // T to have only 2 data members named value and location + static_assert( (sizeof(T::value)+sizeof(T::location)) == sizeof(T) ); + + // Ensure T has value and location members are scalars + static_assert( std::is_scalar_v< decltype(T::value) > || std::is_scalar_v< decltype(T::location) >, "members of struct should be scalar" ); + static_assert( !std::is_pointer_v< decltype(T::value) > && !std::is_pointer_v< decltype(T::location) >, "members of struct should not be pointers" ); + // receive "buffer" + int const numProcs = commSize( comm ); + std::vector< T > recvValLoc( numProcs ); + + MPI_Allgather( &localValueLocation, sizeof(T), MPI_BYTE, recvValLoc.data(), sizeof(T), MPI_BYTE, comm ); + + T maxValLoc= *std::max_element( recvValLoc.begin(), + recvValLoc.end(), + []( auto & lhs, auto & rhs ) -> bool {return lhs.value < rhs.value; } ); + + return maxValLoc; +} } /* namespace geos */ #endif /* GEOS_COMMON_MPIWRAPPER_HPP_ */ diff --git a/src/coreComponents/common/MultiMutexesLock.hpp b/src/coreComponents/common/MultiMutexesLock.hpp index 2bfd9ac83d4..aebd4fa036e 100644 --- a/src/coreComponents/common/MultiMutexesLock.hpp +++ b/src/coreComponents/common/MultiMutexesLock.hpp @@ -2,15 +2,17 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ + #ifndef MULTIMUTEXESLOCK_HPP #define MULTIMUTEXESLOCK_HPP diff --git a/src/coreComponents/common/Path.cpp b/src/coreComponents/common/Path.cpp index 65f11b660e9..30cf6d278e7 100644 --- a/src/coreComponents/common/Path.cpp +++ b/src/coreComponents/common/Path.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -13,7 +14,7 @@ */ #include "Path.hpp" -#include "Logger.hpp" +#include "logger/Logger.hpp" #include #include diff --git a/src/coreComponents/common/Path.hpp b/src/coreComponents/common/Path.hpp index 80c52b9abe1..fe1015d78ff 100644 --- a/src/coreComponents/common/Path.hpp +++ b/src/coreComponents/common/Path.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/common/PhysicsConstants.hpp b/src/coreComponents/common/PhysicsConstants.hpp index 410e45fbc16..69274cf7f91 100644 --- a/src/coreComponents/common/PhysicsConstants.hpp +++ b/src/coreComponents/common/PhysicsConstants.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/common/Span.hpp b/src/coreComponents/common/Span.hpp index ca9330d084a..3fc2185273a 100644 --- a/src/coreComponents/common/Span.hpp +++ b/src/coreComponents/common/Span.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #define GEOS_COMMON_SPAN_HPP #include "codingUtilities/traits.hpp" -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" #include #include diff --git a/src/coreComponents/common/Stopwatch.hpp b/src/coreComponents/common/Stopwatch.hpp index 6fb3c0e23a6..0c6a6fd11a7 100644 --- a/src/coreComponents/common/Stopwatch.hpp +++ b/src/coreComponents/common/Stopwatch.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -89,6 +90,6 @@ class Stopwatch real64 * m_result{}; }; -} // end geosx +} // end geos #endif diff --git a/src/coreComponents/common/Tensor.hpp b/src/coreComponents/common/Tensor.hpp index 9b81af36c01..3af62760530 100644 --- a/src/coreComponents/common/Tensor.hpp +++ b/src/coreComponents/common/Tensor.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/common/Timer.hpp b/src/coreComponents/common/Timer.hpp index 909340b7e5e..ddd5f580119 100644 --- a/src/coreComponents/common/Timer.hpp +++ b/src/coreComponents/common/Timer.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/common/TimingMacros.hpp b/src/coreComponents/common/TimingMacros.hpp index 297aa49f8f1..3d42f1d83b4 100644 --- a/src/coreComponents/common/TimingMacros.hpp +++ b/src/coreComponents/common/TimingMacros.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -40,7 +41,7 @@ namespace timingHelpers } -#if defined( GEOS_USE_CUDA_NVTOOLSEXT ) +#if defined( GEOS_USE_CUDA ) && defined( GEOS_USE_CUDA_NVTOOLSEXT ) #include "nvToolsExt.h" @@ -88,7 +89,7 @@ namespace timingHelpers #endif /* USE_CUDA */ -#ifdef GEOSX_USE_CALIPER +#ifdef GEOS_USE_CALIPER #include #include #include @@ -112,7 +113,7 @@ namespace timingHelpers /// Mark the end of function, only useful when you don't want to or can't mark the whole function. #define GEOS_CALIPER_MARK_FUNCTION_END CALI_MARK_FUNCTION_END -#else // GEOSX_USE_CALIPER +#else // GEOS_USE_CALIPER /// @cond DO_NOT_DOCUMENT #define GEOS_CALIPER_MARK_SCOPE(name) @@ -125,7 +126,7 @@ namespace timingHelpers #define GEOS_CALIPER_MARK_FUNCTION_END /// @endcond -#endif // GEOSX_USE_CALIPER +#endif // GEOS_USE_CALIPER /// Mark scope with both Caliper and NVTX if enabled #define GEOS_MARK_SCOPE(name) GEOS_CALIPER_MARK_SCOPE(name); GEOS_NVTX_MARK_SCOPE(name) @@ -141,7 +142,7 @@ namespace timingHelpers #define GEOS_MARK_END(name) GEOS_CALIPER_MARK_END(name) /// Get current time of day as a floating point number of seconds in a variable @p time. -#ifdef GEOSX_USE_TIMERS +#ifdef GEOS_USE_TIMERS #define GEOS_GET_TIME( time ) \ real64 time; \ do \ diff --git a/src/coreComponents/common/TypeDispatch.hpp b/src/coreComponents/common/TypeDispatch.hpp index c7f30afdf1e..a1881944de2 100644 --- a/src/coreComponents/common/TypeDispatch.hpp +++ b/src/coreComponents/common/TypeDispatch.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -22,6 +23,7 @@ #define GEOS_COMMON_TYPEDISPATCH_HPP #include "common/DataTypes.hpp" +#include "common/logger/Logger.hpp" #include @@ -153,6 +155,12 @@ using Increment = typename IncrementImpl< T, N >::type; } // namespace internal +/** + * @brief Generate a sequence of integers from @p Begin up to (and including) @p End. + */ +template< integer Begin, integer End > +using IntegerSequence = internal::Increment< camp::make_idx_seq_t< End - Begin + 1 >, Begin >; + /** * @brief Construct a list of types. */ @@ -189,10 +197,10 @@ using IntegralTypes = TypeList< integer, localIndex, globalIndex >; using RealTypes = TypeList< real32, real64 >; /** - * @brief Generate a list of types representing array dimensionalities from M up to (and including) @p N. + * @brief Generate a list of types representing array dimensionalities from @p M up to (and including) @p N. */ template< int M, int N > -using DimsRange = camp::as_list< internal::Increment< camp::make_idx_seq_t< N - M + 1 >, M > >; +using DimsRange = camp::as_list< IntegerSequence< M, N > >; /** * @brief Generate a list of types representing array dimensionality exactly @p N. diff --git a/src/coreComponents/common/Units.cpp b/src/coreComponents/common/Units.cpp index ae2b5541a22..e249441f3ff 100644 --- a/src/coreComponents/common/Units.cpp +++ b/src/coreComponents/common/Units.cpp @@ -2,15 +2,17 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ + /** * @file Units.cpp */ @@ -35,8 +37,16 @@ TimeFormatInfo::TimeFormatInfo( double const totalSeconds, int const years, int {} string TimeFormatInfo::toString() const +{ + return GEOS_FMT( "{} ({})", toUnfoldedString(), toSecondsString() ); +} +string TimeFormatInfo::toUnfoldedString() const { std::ostringstream oss; + if( m_totalSeconds < 0.0 ) + { + oss << "-("; + } if( m_years != 0 ) { oss << m_years << "y, " << m_days << "d, "; @@ -45,10 +55,17 @@ string TimeFormatInfo::toString() const { oss << m_days << "d, "; } - oss << GEOS_FMT( "{:0>2}h{:0>2}m{:0>2}s ({} s)", - m_hours, m_minutes, m_seconds, m_totalSeconds ); + oss << GEOS_FMT( "{:0>2}h{:0>2}m{:0>2}s", m_hours, m_minutes, m_seconds ); + if( m_totalSeconds < 0.0 ) + { + oss << ")"; + } return oss.str(); } +string TimeFormatInfo::toSecondsString() const +{ + return GEOS_FMT( "{} s", m_totalSeconds ); +} std::ostream & operator<<( std::ostream & os, TimeFormatInfo const & info ) { @@ -56,32 +73,18 @@ std::ostream & operator<<( std::ostream & os, TimeFormatInfo const & info ) return os; } - -template< typename DURATION > -TimeFormatInfo TimeFormatInfo::fromDuration( DURATION const value ) -{ - using namespace std::chrono; - - auto const totalYears = duration_cast< units::Years >( value ); - auto const daysOut = duration_cast< units::Days >( value - totalYears ); - auto const hoursOut = duration_cast< hours >( value - totalYears - daysOut ); - auto const minutesOut = duration_cast< minutes >( value - totalYears - daysOut - hoursOut ); - auto const secondsOut = duration_cast< seconds >( value - totalYears - daysOut - hoursOut - minutesOut ); - - return TimeFormatInfo( duration< double >( value ).count(), int( totalYears.count() ), - int( daysOut.count() ), int( hoursOut.count() ), - int( minutesOut.count() ), int( secondsOut.count() ) ); -} -// available specializations -template TimeFormatInfo TimeFormatInfo::fromDuration< SystemClock::duration >( SystemClock::duration duration ); - TimeFormatInfo TimeFormatInfo::fromSeconds( double const seconds ) { - int totalYears = int( seconds / YearSeconds ); - int daysOut = int( ( seconds - totalYears * YearSeconds ) / DaySeconds ); - int hoursOut = int( ( seconds - totalYears * YearSeconds - daysOut * DaySeconds ) / HourSeconds ); - int minutesOut = int( ( seconds - totalYears * YearSeconds - daysOut * DaySeconds - hoursOut * HourSeconds ) / MinuteSeconds ); - int secondsOut = int( seconds - totalYears * YearSeconds - daysOut * DaySeconds - hoursOut * HourSeconds - minutesOut * MinuteSeconds ); + double remainingSeconds = seconds < 0.0 ? -seconds : seconds; + int const totalYears = int( remainingSeconds / YearSeconds ); + remainingSeconds -= totalYears * YearSeconds; + int const daysOut = int( remainingSeconds / DaySeconds ); + remainingSeconds -= daysOut * DaySeconds; + int const hoursOut = int( remainingSeconds / HourSeconds ); + remainingSeconds -= hoursOut * HourSeconds; + int const minutesOut = int( remainingSeconds / MinuteSeconds ); + remainingSeconds -= minutesOut * MinuteSeconds; + int const secondsOut = int( remainingSeconds ); return TimeFormatInfo( seconds, totalYears, daysOut, hoursOut, minutesOut, secondsOut ); } diff --git a/src/coreComponents/common/Units.hpp b/src/coreComponents/common/Units.hpp index 43e8fc680e3..8bfdc04ca80 100644 --- a/src/coreComponents/common/Units.hpp +++ b/src/coreComponents/common/Units.hpp @@ -1,11 +1,12 @@ /* - * ------------------------------------------------------------------------------------- + * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,6 +22,7 @@ #include "common/DataTypes.hpp" #include "common/PhysicsConstants.hpp" +#include "common/format/Format.hpp" namespace geos { @@ -82,6 +84,21 @@ enum Unit : integer /// Solubility in g/L Solubility, + + /// Mass in kg + Mass, + + /// Mole in mol + Mole, + + /// Mass rate in kg/s + MassRate, + + /// Mole rate in mol/s + MoleRate, + + /// Transmissibility in m2/s + Transmissibility, }; @@ -93,17 +110,22 @@ constexpr inline std::string_view getDescription( Unit unit ) { switch( unit ) { - default: return "unknown [?]"; - case Dimensionless: return "dimensionless [1]"; - case Pressure: return "pressure [Pa]"; - case Temperature: return "temperature [K]"; - case TemperatureInC: return "temperature [C]"; - case Distance: return "distance [m]"; - case Time: return "time [s]"; - case Viscosity: return "viscosity [Pa*s]"; - case Enthalpy: return "enthalpy [J/kg]"; - case Density: return "density [kg/m3]"; - case Solubility: return "solubility [g/L]"; + default: return "unknown [?]"; + case Dimensionless: return "dimensionless [1]"; + case Pressure: return "pressure [Pa]"; + case Temperature: return "temperature [K]"; + case TemperatureInC: return "temperature [C]"; + case Distance: return "distance [m]"; + case Time: return "time [s]"; + case Viscosity: return "viscosity [Pa*s]"; + case Enthalpy: return "enthalpy [J/kg]"; + case Density: return "density [kg/m3]"; + case Solubility: return "solubility [g/L]"; + case Mass: return "mass [kg]"; + case Mole: return "mole [mol]"; + case MassRate: return "mass rate [kg/s]"; + case MoleRate: return "mole rate [mol/s]"; + case Transmissibility: return "transmissibility [(Pa*s*rm3/s)/Pa]"; } } @@ -115,13 +137,22 @@ constexpr inline std::string_view getSymbol( Unit unit ) { switch( unit ) { - default: return "?"; - case Dimensionless: return "1"; - case Pressure: return "Pa"; - case Temperature: return "K"; - case TemperatureInC: return "C"; - case Distance: return "m"; - case Time: return "s"; + default: return "?"; + case Dimensionless: return "1"; + case Pressure: return "Pa"; + case Temperature: return "K"; + case TemperatureInC: return "C"; + case Distance: return "m"; + case Time: return "s"; + case Viscosity: return "Pa*s"; + case Enthalpy: return "J/kg"; + case Density: return "kg/m3"; + case Solubility: return "g/L"; + case Mass: return "kg"; + case Mole: return "mol"; + case MassRate: return "kg/s"; + case MoleRate: return "mol/s"; + case Transmissibility: return "(Pa*s*rm3/s)/Pa"; } } @@ -136,19 +167,28 @@ inline string formatValue( real64 value, Unit unit ) { switch( unit ) { - default: return GEOS_FMT( "value of {} [?]", value ); - case Dimensionless: return GEOS_FMT( "value of {} [1]", value ); - case Pressure: return GEOS_FMT( "pressure of {} [Pa]", value ); - case Temperature: return GEOS_FMT( "temperature of {} [K]", value ); - case TemperatureInC: return GEOS_FMT( "temperature of {} [K]", convertCToK( value ) ); - case Distance: return GEOS_FMT( "distance of {} [s]", value ); - case Time: return GEOS_FMT( "time of {} [s]", value ); + default: return GEOS_FMT( "value of {} [?]", value ); + case Dimensionless: return GEOS_FMT( "value of {} [1]", value ); + case Pressure: return GEOS_FMT( "pressure of {} [Pa]", value ); + case Temperature: return GEOS_FMT( "temperature of {} [K]", value ); + case TemperatureInC: return GEOS_FMT( "temperature of {} [K]", convertCToK( value ) ); + case Distance: return GEOS_FMT( "distance of {} [s]", value ); + case Time: return GEOS_FMT( "time of {} [s]", value ); + case Viscosity: return GEOS_FMT( "viscosity of {} [Pa*s]", value ); + case Enthalpy: return GEOS_FMT( "enthalpy of {} [J/kg]", value ); + case Density: return GEOS_FMT( "density of {} [kg/m3]", value ); + case Solubility: return GEOS_FMT( "solubility of {} [g/L]", value ); + case Mass: return GEOS_FMT( "mass of {} [kg]", value ); + case Mole: return GEOS_FMT( "mole of {} [mol]", value ); + case MassRate: return GEOS_FMT( "mass rate of {} [kg/s]", value ); + case MoleRate: return GEOS_FMT( "mole rate of {} [mol/s]", value ); + case Transmissibility: return GEOS_FMT( "transmissibility of {} [(Pa*s*rm3/s)/Pa]", value ); } } /// Clock in use in GEOS to manipulate system times. -using SystemClock = std::chrono::system_clock; +using SystemClock = std::chrono::high_resolution_clock; /// One year = 365.2425 days (= 146097 / 400) following the Gregorian calendar and the C++ convention. using YearDaysRatio = std::ratio< 146097, 400 >; @@ -175,18 +215,17 @@ static constexpr double YearSeconds = YearDays * DaySeconds; struct TimeFormatInfo { /// Total time (including the decimal part) this instance represents in seconds - double m_totalSeconds = 0.0; + double const m_totalSeconds = 0.0; /// Number of integral years to show - int m_years = 0; + int const m_years = 0; /// Number of integral days to show - int m_days = 0; + int const m_days = 0; /// Number of integral hours to show - int m_hours = 0; + int const m_hours = 0; /// Number of integral minutes to show - int m_minutes = 0; + int const m_minutes = 0; /// Number of integral seconds to show - int m_seconds = 0; - + int const m_seconds = 0; /** * @brief Construct a TimeFormatInfo from raw data (which must be coherent) @@ -216,11 +255,36 @@ struct TimeFormatInfo friend std::ostream & operator<<( std::ostream & os, TimeFormatInfo const & ctx ); /** - * @return a user friendly string representation of this structure. + * @return a comprehensive string representation of this structure. */ string toString() const; + + /** + * @return a user friendly string representation of this structure (YDHMS format, without subsecond details). + */ + string toUnfoldedString() const; + + /** + * @return a precise string representation of this structure (decimal seconds). + */ + string toSecondsString() const; }; +template< typename DURATION > +TimeFormatInfo TimeFormatInfo::fromDuration( DURATION const value ) +{ + using namespace std::chrono; + + auto const totalYears = duration_cast< units::Years >( value ); + auto const daysOut = duration_cast< units::Days >( value - totalYears ); + auto const hoursOut = duration_cast< hours >( value - totalYears - daysOut ); + auto const minutesOut = duration_cast< minutes >( value - totalYears - daysOut - hoursOut ); + auto const secondsOut = duration_cast< seconds >( value - totalYears - daysOut - hoursOut - minutesOut ); + + return TimeFormatInfo( duration< double >( value ).count(), int( totalYears.count() ), + int( daysOut.count() ), int( hoursOut.count() ), + int( minutesOut.count() ), int( secondsOut.count() ) ); +} } // end namespace units @@ -239,7 +303,7 @@ struct GEOS_FMT_NS::formatter< geos::units::TimeFormatInfo > : GEOS_FMT_NS::form * @param ctx formatting state consisting of the formatting arguments and the output iterator * @return iterator to the output buffer */ - auto format( geos::units::TimeFormatInfo const & durationData, format_context & ctx ) + auto format( geos::units::TimeFormatInfo const & durationData, format_context & ctx ) const { return GEOS_FMT_NS::formatter< std::string >::format( durationData.toString(), ctx ); } diff --git a/src/coreComponents/codingUtilities/EnumStrings.hpp b/src/coreComponents/common/format/EnumStrings.hpp similarity index 83% rename from src/coreComponents/codingUtilities/EnumStrings.hpp rename to src/coreComponents/common/format/EnumStrings.hpp index 8de1f96107c..f5b37de1df1 100644 --- a/src/coreComponents/codingUtilities/EnumStrings.hpp +++ b/src/coreComponents/common/format/EnumStrings.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,13 +22,14 @@ * of these strings, like stream insertion/extraction operators. */ -#ifndef GEOS_CODINGUTILITIES_ENUMSTRINGS_HPP -#define GEOS_CODINGUTILITIES_ENUMSTRINGS_HPP +#ifndef GEOS_COMMON_FORMAT_ENUMSTRINGS_HPP +#define GEOS_COMMON_FORMAT_ENUMSTRINGS_HPP -#include "codingUtilities/StringUtilities.hpp" +#include "common/format/StringUtilities.hpp" +// #include "codingUtilities/RTTypes.hpp" #include "common/DataTypes.hpp" -#include "common/Logger.hpp" -#include "common/Format.hpp" +#include "common/logger/Logger.hpp" +#include "common/format/Format.hpp" #include #include @@ -64,6 +66,15 @@ constexpr int countArgs( ARGS ... ) * may be used to get access to strings at runtime. While not strictly necessary, * it is recommended that macro call immediately follows the enum definition * (or the class definition, if enum is defined inside a class). + * + * enum struct VTKOutputMode + * { + * BINARY, + * ASCII + * }; + * ENUM_STRINGS( VTKOutputMode, + * "binary", + * "ascii" ); */ #define ENUM_STRINGS( ENUM, ... ) \ inline auto const & getEnumStrings( ENUM const ) \ @@ -72,6 +83,11 @@ constexpr int countArgs( ARGS ... ) return ss; \ } \ \ + inline auto const & getEnumTypeNameString( ENUM const ) \ + { \ + return #ENUM; \ + } \ + \ inline std::ostream & operator<<( std::ostream & os, ENUM const e ) \ { \ os << EnumStrings< ENUM >::toString( e ); \ @@ -137,7 +153,7 @@ struct EnumStrings std::size_t size = std::distance( std::begin( strings ), std::end( strings ) ); base_type const index = static_cast< base_type >( e ); GEOS_THROW_IF( index >= LvArray::integerConversion< base_type >( size ), - "Invalid value " << index << " of type " << TypeName< ENUM >::brief() << ". Valid range is 0.." << size - 1, + "Invalid value " << index << " of type " << getEnumTypeNameString( enum_type{} ) << ". Valid range is 0.." << size - 1, InputError ); return strings[ index ]; } @@ -152,7 +168,7 @@ struct EnumStrings auto const & strings = get(); auto const it = std::find( std::begin( strings ), std::end( strings ), s ); GEOS_THROW_IF( it == std::end( strings ), - "Invalid value '" << s << "' of type " << TypeName< enum_type >::brief() << ". Valid options are: " << concat( ", " ), + "Invalid value '" << s << "' of type " << getEnumTypeNameString( enum_type{} ) << ". Valid options are: " << concat( ", " ), InputError ); enum_type const e = static_cast< enum_type >( LvArray::integerConversion< base_type >( std::distance( std::begin( strings ), it ) ) ); return e; @@ -164,23 +180,6 @@ namespace internal IS_VALID_EXPRESSION( HasEnumStrings, ENUM, getEnumStrings( std::declval< ENUM >() ) ); } -/** - * @brief Specialization of TypeRegex for enumeration types with strings attached (pun intended). - * @tparam ENUM the type of enumeration - */ -template< typename ENUM > -struct TypeRegex< ENUM, std::enable_if_t< internal::HasEnumStrings< ENUM > > > -{ - /** - * @brief @return Regex for validating enumeration inputs for @p ENUM type. - */ - static Regex get() - { - return Regex( EnumStrings< ENUM >::concat( "|" ), - "Input value must be one of { " + EnumStrings< ENUM >::concat( ", " ) + "}." ); - } -}; - } // namespace geos // Formatter specialization for enums @@ -207,4 +206,4 @@ struct GEOS_FMT_NS::formatter< Enum, std::enable_if_t< std::is_enum< Enum >::val } }; -#endif //GEOS_CODINGUTILITIES_ENUMSTRINGS_HPP +#endif //GEOS_COMMON_FORMAT_ENUMSTRINGS_HPP diff --git a/src/coreComponents/common/format/Format.hpp b/src/coreComponents/common/format/Format.hpp new file mode 100644 index 00000000000..23f3e3225e3 --- /dev/null +++ b/src/coreComponents/common/format/Format.hpp @@ -0,0 +1,154 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#ifndef GEOS_COMMON_FORMAT_HPP_ +#define GEOS_COMMON_FORMAT_HPP_ + +#include +#include + +#if __cplusplus < 202002L +#define GEOS_USE_FMT +#endif + +#ifdef GEOS_USE_FMT +#ifndef FMT_HEADER_ONLY +#define FMT_HEADER_ONLY +#endif +// Differentiate between standalone fmt path and umpire's fmt path +#include "../include/fmt/core.h" +#include "../include/fmt/chrono.h" +#include "../include/fmt/ranges.h" +#include "../include/fmt/xchar.h" +#define GEOS_FMT_NS fmt +#else // use C++20's +#include +#define GEOS_FMT_NS std +#endif + +#ifdef GEOS_USE_FMT +/** + * @brief fmtlib formatter for enum classes. + * @tparam T The type of the object being formatted. This should be an + * enum class. + */ +template< typename T > +struct fmt::formatter< T, std::enable_if_t< std::is_enum< T >::value > > +{ + /** + * @brief Parser for the fmtlib formatting library. + * @param ctx The context provided by the fmtlib library, which includes + * the format string. + * @return An iterator pointing to the end of the format string. + */ + template< typename ParseContext > + constexpr auto parse( ParseContext & ctx ) + { + return ctx.end(); + } + + /** + * @brief Formatter for the fmtlib formatting library. + * @param value The enum class object to format. + * @param ctx The context provided by the fmtlib library, which includes + * the output iterator where the formatted string should be written. + * @return An iterator pointing to the end of the formatted string. + */ + template< typename FormatContext > + auto format( const T & value, FormatContext & ctx ) const + { + return fmt::format_to( ctx.out(), "{}", static_cast< std::underlying_type_t< T > >( value ) ); + } +}; +#endif + +/** + * @brief Interpolate arguments into a message format string. + * @param msg the message format string, must be a constant expression + */ +#define GEOS_FMT( msg, ... ) GEOS_FMT_NS::format( msg, __VA_ARGS__ ) + +/** + * @brief Interpolate arguments into a message format string and write into an output iterator. + * @param iter the output iterator to write to + * @param size maximum number of characters to write + * @param msg the message format string, must be a constant expression + * @note Ensures the output buffer is zero-terminated (std::format_to_n doesn't) + */ +#define GEOS_FMT_TO( iter, size, msg, ... ) *GEOS_FMT_NS::format_to_n( iter, size - 1, msg, __VA_ARGS__ ).out = '\0' + +/** + * @name Custom formatters + */ +///@{ + +/** + * @brief Format to be able to directly use a std::optional. + * @param T The type of the value contained std::optional and GEOS_FMT_NS::formatter. + */ +template< typename T > +struct GEOS_FMT_NS::formatter< std::optional< T > > : GEOS_FMT_NS::formatter< T > +{ + /** + * @brief Format the std::optional to a string. + * @param opt The std::optional< T > value to format + * @param ctx formatting state consisting of the formatting arguments and the output iterator + * @return return the corresponding value string. If std::optional is empty retun an empty string + */ + auto format( std::optional< T > const & opt, format_context & ctx ) const + { + if( opt ) + { + return GEOS_FMT_NS::formatter< T >::format( *opt, ctx ); + } + return GEOS_FMT_NS::format_to( ctx.out(), "" ); + } +}; + +///@} + +// The following workaround is needed to fix compilation with NVCC on some PowerPC machines. +// The issue causes the following assertion error message: +// "Cannot format an argument. To make type T formattable provide a formatter specialization" +// The standard definition of the has_const_formatter check of fmt fails due to a compiler bug, see the issue below: +// https://github.com/fmtlib/fmt/issues/2746 +// The workaround was originally implemented in fmt: +// https://github.com/fmtlib/fmt/commit/70de324aa801eaf52e94c402d526a3849797c620 +// but later removed: +// https://github.com/fmtlib/fmt/commit/466e0650ec2d153d255a40ec230eb77d7f1c3334 +// This workaround bypasse the check for a const formatter whenever the foramt context GEOS_FMT_NS::format_context is used +#ifdef GEOS_USE_FMT_CONST_FORMATTER_WORKAROUND +template< > +constexpr auto GEOS_FMT_NS::detail::has_const_formatter_impl< GEOS_FMT_NS::format_context >( ... ) -> bool +{ + return true; +} +#endif // End of the workaround for fmt compilation issues + +/** + * Evaluates at compile time if a fmt::formatter exists for a given type + */ +#if __cplusplus < 202002L +template< class T > +static constexpr bool has_formatter_v = fmt::has_formatter< fmt::remove_cvref_t< T >, fmt::format_context >(); +#else +template< typename T > +concept has_formatter_v = requires ( T& v, std::format_context ctx ) +{ + std::formatter< std::remove_cvref_t< T > >().format( v, ctx ); +}; +#endif + +#endif //GEOS_COMMON_FORMAT_HPP_ diff --git a/src/coreComponents/common/format/StringUtilities.cpp b/src/coreComponents/common/format/StringUtilities.cpp new file mode 100644 index 00000000000..004c82276bb --- /dev/null +++ b/src/coreComponents/common/format/StringUtilities.cpp @@ -0,0 +1,143 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StringUtilities.cpp + */ + +#include "StringUtilities.hpp" +#include "common/logger/Logger.hpp" +#include "limits.h" + +#include +#include +#include + +namespace geos +{ +namespace stringutilities +{ + +string toLower( string const & input ) +{ + string output; + output.resize( input.size() ); + auto const toLowerCase = []( unsigned char c ) + { return std::tolower( c ); }; + std::transform( input.cbegin(), input.cend(), output.begin(), toLowerCase ); + return output; +} + +string_view trim( string_view str, + string_view charsToRemove ) +{ + std::size_t const first = str.find_first_not_of( charsToRemove ); + if( first != string::npos ) + { + std::size_t const last = str.find_last_not_of( charsToRemove ); + return str.substr( first, ( last - first + 1 ) ); + } + return {}; +} +string_view trimSpaces( string_view str ) +{ + return trim( str, " \f\n\r\t\v" ); +} + + +string removeStringAndFollowingContent( string_view const str, + string_view const strToRemove ) +{ + string_view newStr = str; + + // check if the line contains the string to remove + std::size_t const pos = newStr.find( strToRemove ); + + if( pos != string::npos ) + { + // remove the character and everything afterwards + newStr = newStr.substr( 0, pos ); + } + return string( newStr ); +} + +// Add comma separators for thousands +template< typename T > +string addCommaSeparators( T const & num ) +{ + static_assert( std::is_integral< T >::value, "addCommaSeparators only supports integral types" ); + + string const numStr = std::to_string( num ); + string result; + + for( std::size_t i = 0; i < numStr.size(); ++i ) + { + result += numStr[i]; + if((numStr.size() - i - 1) % 3 == 0 && i != numStr.size() - 1 ) + { + result += ","; + } + } + return result; +} + +template string addCommaSeparators( int const & num ); +template string addCommaSeparators( long int const & num ); +template string addCommaSeparators( long long int const & num ); + +// put definition here so we can control the allowable values of T and +// modication of this function triggers a whole code recompile...which +// should be avoided. +template< typename T > +string toMetricPrefixString( T const & value ) +{ + if( std::fpclassify( value ) == FP_ZERO ) + { + return " 0.0 "; + } + + // These are the metric prefixes corrosponding to kilo, mega, giga...etc. + char const prefixes[12] = { 'f', 'p', 'n', 'u', 'm', ' ', 'K', 'M', 'G', 'T', 'P', 'E'}; + string rval; + + int const power = floor( log10( std::abs( (double)value ) ) ); + int const a = floor( power / 3.0 ); + + real64 const scaledValue = value * pow( 10.0, -a * 3 ); + + // format the output of the value to 3 significant digits and append the + // metric prefix. + int const p = 2-std::abs( power - a * 3 ); + char temp[10]; + snprintf( temp, 8, "%5.*f %c", p, scaledValue, prefixes[a+5] ); + rval = temp; + + GEOS_ERROR_IF( rval.empty(), + GEOS_FMT( "The value of {} was not able to be converted with a metric prefix", value ) ); + + + return rval; +} +template string toMetricPrefixString( int const & ); +template string toMetricPrefixString( long int const & ); +template string toMetricPrefixString( long long int const & ); +template string toMetricPrefixString( unsigned long int const & ); +template string toMetricPrefixString( unsigned long long int const & ); +template string toMetricPrefixString( float const & ); +template string toMetricPrefixString( double const & ); + + +} +} diff --git a/src/coreComponents/common/format/StringUtilities.hpp b/src/coreComponents/common/format/StringUtilities.hpp new file mode 100644 index 00000000000..79b0333d0a2 --- /dev/null +++ b/src/coreComponents/common/format/StringUtilities.hpp @@ -0,0 +1,336 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StringUtilities.hpp + */ + +#ifndef GEOS_COMMON_FORMAT_STRINGUTILITIES_HPP_ +#define GEOS_COMMON_FORMAT_STRINGUTILITIES_HPP_ + +#include "common/DataTypes.hpp" + +#include +#include + +namespace geos +{ +namespace stringutilities +{ + +/** + * @brief Return a copy of the string in lower case. + * @param input The input string which is not modified. + * @return A new string instance. + */ +string toLower( string const & input ); + +/** + * @brief Join strings or other printable objects with a delimiter. + * @tparam IT type of iterator into the range of objects to join + * @tparam S type of delimiter, usually char, char const * or string + * @param first iterator to start of the range + * @param last iterator past-the-end of the range + * @param delim delimiter used to glue together strings + * @return a string containing input values concatenated with a delimiter + */ +template< typename IT, typename S = char > +string join( IT first, IT last, S const & delim = S() ) +{ + if( first == last ) + { + return {}; + } + std::ostringstream oss; + oss << *first; + while( ++first != last ) + { + oss << delim << *first; + } + return oss.str(); +} + +/** + * @brief Join strings or other printable objects with a delimiter. + * @tparam CONTAINER type of container to join + * @tparam S the type of delimiter, usually char, char const * or string + * @param container the container to join + * @param delim delimiter used to glue together strings + * @return a string containing input values concatenated with a delimiter + */ +template< typename CONTAINER, typename S = char > +string join( CONTAINER const & container, S const & delim = S() ) +{ + return join( std::begin( container ), std::end( container ), delim ); +} + +/** + * @brief Join strings or other printable objects returned by a formatter functor. + * @tparam IT type of iterator into the range of objects to join + * @tparam S type of delimiter, usually char, char const * or string + * @tparam LAMBDA type of formatter functor, usually `[]( auto it ) -> string` + * @param formattingFunc formatter function to get a formattable value from a IT iterator + * @param first iterator to start of the range + * @param last iterator past-the-end of the range + * @param delim delimiter used to glue together strings + * @return a string containing input values concatenated with a delimiter + */ +template< typename IT, typename S, typename LAMBDA > +string joinLamda( IT first, IT last, S const & delim, LAMBDA formattingFunc ) +{ + if( first == last ) + { + return {}; + } + std::ostringstream oss; + oss << formattingFunc( first ); + while( ++first != last ) + { + oss << delim << formattingFunc( first ); + } + return oss.str(); +} + +/** + * @brief Join strings or other printable objects returned by a formatter functor. + * @tparam CONTAINER type of container to join + * @tparam S type of delimiter, usually char, char const * or string + * @tparam LAMBDA type of formatter functor, usually `[]( auto it ) -> string` + * @param formattingFunc formatter function to get a formattable value from an iterator of the container + * @param container container to join + * @param delim delimiter used to glue together strings + * @return a string containing input values concatenated with a delimiter + */ +template< typename CONTAINER, typename S, typename LAMBDA > +string joinLamda( CONTAINER const & container, S const & delim, LAMBDA formattingFunc ) +{ + return joinLamda( std::begin( container ), std::end( container ), delim, formattingFunc ); +} + +/** + * @brief Concatenate variadic arguments into a string with a delimiter. + * @tparam S type of delimiter (printable to std::ostringstream) + * @tparam T type of first argument (printable to std::ostringstream) + * @tparam Ts types of remaining arguments (printable to std::ostringstream) + * @param delim delimiter + * @param v first value + * @param vs remaining values + * @return string containing concatenated printed arguments + */ +template< typename S = char, typename T, typename ... Ts > +string concat( S const & delim, T const & v, Ts const & ... vs ) +{ + std::ostringstream oss; + oss << v; + // Use array initializer and comma trick to get "fold expression" pre C++-17 + using expander = int[]; + (void) expander{ 0, ( void ( oss << delim << vs ), 0) ... }; + return oss.str(); +} + +/** + * @brief Subdivide the string in substrings by the specified delimiters. + * @tparam CONTAINER The templated class of the results container (std::vector by default). + * @param str The string to subdivide. + * @param delimiters String that contains the list of possible delimiters. + * @param treatConsecutiveDelimAsOne If enabled, consecutive delimiters will be treated as one. + * If not enabled, consecutive delimiters will result in empty entries. + * @param preTrimStr If enabled, delimiters at the borders of the string will be ignored. + * If not enabled, those delimiters will result in in empty entries. + * @return The container of the divided substrings. + */ +template< template< class ... > class CONTAINER = std::vector > +CONTAINER< string > tokenize( string const & str, + string const & delimiters, + bool const treatConsecutiveDelimAsOne = true, + bool const preTrimStr = false ) +{ + CONTAINER< string > tokens; + string::size_type tokenBegin, tokenEnd, strEnd; + + if( preTrimStr ) + { + tokenBegin = str.find_first_not_of( delimiters ); + strEnd = str.find_last_not_of( delimiters ) + 1; + } + else + { + tokenBegin = 0; + strEnd = str.size(); + } + + while( ( ( tokenEnd = str.find_first_of( delimiters, tokenBegin ) ) < strEnd ) && tokenBegin < strEnd ) + { + tokens.emplace_back( str.substr( tokenBegin, tokenEnd - tokenBegin ) ); + tokenBegin = !treatConsecutiveDelimAsOne ? tokenEnd + 1 : str.find_first_not_of( delimiters, tokenEnd ); + } + + if( tokenBegin < strEnd ) + { + tokens.emplace_back( str.substr( tokenBegin, strEnd-tokenBegin )); + } + else if( !preTrimStr && str.find_first_of( delimiters, strEnd - 1 ) != string::npos ) + { + tokens.emplace_back( "" ); + } + + return tokens; +} + +/** + * @brief Subdivide the string in substrings by whitespaces separators (see std::isspace()). + * Do not create any empty substrings. + * @tparam CONTAINER The templated class of the results container (std::vector by default). + * @param str The string to subdivide. + * @return CONTAINER< string > The list of the subdivided substrings (std::vector< string > for instance). + */ +template< template< class ... > class CONTAINER = std::vector > +CONTAINER< string > tokenizeBySpaces( string const & str ) +{ + return tokenize< CONTAINER >( str, " \f\n\r\t\v", true, true ); +} + +/** + * @brief Trim the string + * @param[in] str the string to trim + * @param[in] charsToRemove the list of characters to remove + * @return the trimmed string + */ +string_view trim( string_view str, + string_view charsToRemove ); + +/** + * @brief Trim the string so it does not starts nor ends with any whitespaces + * @param[in] str the string to trim + * @return the trimmed string + */ +string_view trimSpaces( string_view str ); + +/** + * @brief Search for a string in the line, and return the line truncated before the string + * @param[in] str the line to truncate + * @param[in] strToRemove the string to search for in the line + * @return the new (truncated) string + */ +string removeStringAndFollowingContent( string_view str, + string_view strToRemove ); + +/** + * @brief Add comma separators to an integral number for readability. + * @tparam T the integral type of the number to format. + * @param[in] num the integral number to format. + * @return a string representation of the number with comma separators. + */ +template< typename T > +string addCommaSeparators( T const & num ); + +/** + * @brief Take a string, and return a array1d with the cast values + * @tparam T the type to which the string will be cast + * @param[in] str the string to turn into an array1d + * @return the array1d that stores the cast values + */ +template< typename T > +array1d< T > fromStringToArray( string const & str ) +{ + array1d< T > v; + T sub; + + std::istringstream iss( str ); + while( iss >> sub ) + { + v.emplace_back( sub ); + } + return v; +} + +/** + * @brief Take a numerical value and convert/scale it to a string with a metric + * prefix. i.e. Kilo, Mega, Giga, Tera, Peta, Exa + * + * @tparam T Type of the value to be converted + * @param value The value to be converted + * @return String containging the scaled value. + */ +template< typename T > +string toMetricPrefixString( T const & value ); + +/** + * @return The length of a constant string computed at compile-time. + * @param str The null-character terminated constant string + * @todo c++17: this function is to remove in favor of std::string_view + */ +constexpr size_t cstrlen( char const * const str ) +{ + if( str ) + { + char const * ptr = str; + for(; *ptr != '\0'; ++ptr ) + {} + return ptr - str; + } + else + { + return 0; + } +} + +/** + * @return true if the string starts with the prefix. + * @param str The string to compare + * @param prefix A prefix we want to know if the string starts with. + */ +constexpr bool startsWith( std::string_view str, std::string_view prefix ) +{ + return str.size() >= prefix.size() && + str.compare( 0, prefix.size(), prefix ) == 0; +} + +/** + * @return true if the string ends with the suffix. + * @param str The string to compare + * @param suffix A suffix we want to know if the string ends with. + */ +constexpr bool endsWith( std::string_view str, std::string_view suffix ) +{ + return str.size() >= suffix.size() && + str.compare( str.size()-suffix.size(), suffix.size(), suffix ) == 0; +} + +/** + * @brief Overloading operator (<<) for std::optional. + * + * This function displays the value contained in a std::optional object if one exists. + * Otherwise, it produces no output. + * + * @tparam T The type of the value contained std::optional. + * @param os An output stream (for example, std::cout). + * @param optValue std::optional value to display. + * @return The output stream + */ +template< typename T > +std::ostream & operator<<( std::ostream & os, std::optional< T > const & optValue ) +{ + if( optValue ) + { + os << optValue.value(); + } + return os; +} + +} // namespace stringutilities +} // namespace geos + +#endif /* GEOS_COMMON_FORMAT_STRINGUTILITIES_HPP_ */ diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp new file mode 100644 index 00000000000..5153bf58752 --- /dev/null +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -0,0 +1,123 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file TableData.cpp + */ + +#include "TableData.hpp" + +namespace geos +{ + +void TableData::addRow( std::vector< string > const & row ) +{ + if( m_rows.size() != 0 && row.size() != m_rows[m_rows.size() - 1].size() ) + { + string msg = "Remarks : some cells may be missing"; + if( std::find( m_errorsMsg.begin(), m_errorsMsg.end(), msg ) == m_errorsMsg.end()) + { + m_errorsMsg.push_back( msg ); + } + } + m_rows.push_back( row ); +} + +void TableData::clear() +{ + m_rows.clear(); + m_errorsMsg.clear(); +} + +std::vector< std::vector< string > > const & TableData::getTableDataRows() const +{ + return m_rows; +} + +std::vector< string > const & TableData::getErrorMsgs() const +{ + return m_errorsMsg; +} + +void TableData2D::collectTableValues( arraySlice1d< real64 const > rowAxisValues, + arraySlice1d< real64 const > columnAxisValues, + arrayView1d< real64 const > values ) +{ + integer const nX = rowAxisValues.size(); + integer const nY = columnAxisValues.size(); + + for( integer i = 0; i < nX; i++ ) + { + for( integer y = 0; y < nY; y++ ) + { + addCell( rowAxisValues[i], columnAxisValues[y], values[ y*nX + i ] ); + } + } +} + +TableData2D::TableDataHolder TableData2D::convertTable2D( arrayView1d< real64 const > const values, + units::Unit const valueUnit, + ArrayOfArraysView< real64 const > const coordinates, + string_view rowAxisDescription, + string_view columnAxisDescription ) +{ + string const rowFmt = GEOS_FMT( "{} = {{}}", rowAxisDescription ); + string const columnFmt = GEOS_FMT( "{} = {{}}", columnAxisDescription ); + + collectTableValues( coordinates[0], coordinates[1], values ); + return buildTableData( string( units::getDescription( valueUnit )), + rowFmt, + columnFmt ); +} + +TableData2D::TableDataHolder TableData2D::buildTableData( string_view targetUnit, + string_view rowFmt, + string_view columnFmt ) const +{ + TableData2D::TableDataHolder tableData1D; + std::vector< size_t > rowsLength; + + tableData1D.headerNames.push_back( string( targetUnit ) ); + + for( auto const & columnValue : m_columnValues ) + { + tableData1D.headerNames.push_back( GEOS_FMT( columnFmt, columnValue ) ); + } + + // insert row value and row cell values + for( auto const & [rowValue, rowMap] : m_data ) + { + std::vector< string > currentRowValues; + currentRowValues.reserve( rowMap.size() ); + currentRowValues.push_back( GEOS_FMT( rowFmt, rowValue ) ); + + std::set< real64 >::const_iterator columnIt = m_columnValues.begin(); + for( auto const & [columnValue, cellValue] : rowMap ) + { + // if a column value(s) is/are missing, insert empty entry(ies) + while( columnValue > *( columnIt++ ) && columnIt != m_columnValues.end() ) + { + currentRowValues.push_back( "" ); + } + currentRowValues.push_back( GEOS_FMT( "{}", cellValue ) ); + } + + tableData1D.tableData.addRow( std::move( currentRowValues ) ); + rowsLength.push_back( currentRowValues.size() ); + } + + return tableData1D; +} +} diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp new file mode 100644 index 00000000000..0842c3a4fbe --- /dev/null +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -0,0 +1,174 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file TableData.hpp + */ + +#ifndef GEOS_COMMON_FORMAT_TABLE_TABLEDATA_HPP +#define GEOS_COMMON_FORMAT_TABLE_TABLEDATA_HPP + +#include "common/Units.hpp" +#include "common/DataTypes.hpp" +#include "common/format/Format.hpp" + +namespace geos +{ + +/** + * @brief Class for managing table data + */ +class TableData +{ +public: + /** + * @brief Add a row to the table. + * The values passed to addRow (can be any type). + * @param args Cell values to be added to the row. + */ + template< typename ... Args > + void addRow( Args const & ... args ); + + /** + * @brief Add a row to the table + * @param row A vector of string representing a row + */ + void addRow( std::vector< string > const & row ); + + /** + * @brief Reset data in the table + */ + void clear(); + + /** + * @return The rows of the table + */ + std::vector< std::vector< string > > const & getTableDataRows() const; + + /** + * @brief Get all error messages + * @return The vector of error messages + */ + std::vector< string > const & getErrorMsgs() const; + +private: + + /// vector containing all rows with cell values + std::vector< std::vector< string > > m_rows; + + /// store error if there are any inconsistencies related to the table + std::vector< string > m_errorsMsg; + +}; + +/** + * @brief Class for managing 2D table m_data + */ +class TableData2D +{ +public: + + /// Type real64 for a row + using RowType = real64; + /// Type real64 for a column + using ColumnType = real64; + + /// Struct containing conversion informations + struct TableDataHolder + { + /// Vector containing all columns names + /// A header value is presented as "pressure [K] = {}" + std::vector< string > headerNames; + /// TableData to be built + TableData tableData; + }; + + /** + * @brief Add a cell to the table. If necessary, create automatically the containing column & row. + * @tparam T The value passed to addCell (can be any type). + * @param value Cell value to be added. + * @param rowValue The value of the row containing the cell. + * @param columnValue The value of the column containing the cell. + */ + template< typename T > + void addCell( RowType rowValue, ColumnType columnValue, T const & value ); + + /** + * @brief Collects all the values needed to build the table + * @param rowAxisValues Vector containing all row axis values + * @param columnAxisValues Vector containing all column axis values + * @param values Vector containing all table values + */ + void collectTableValues( arraySlice1d< real64 const > rowAxisValues, + arraySlice1d< real64 const > columnAxisValues, + arrayView1d< real64 const > values ); + + /** + * @param values Vector containing all table values + * @param valueUnit The table unit value + * @param coordinates Array containing row/column axis values + * @param rowAxisDescription The description for a row unit value + * @param columnAxisDescription The description for a column unit value + * @return A struct containing the tableData converted and all header values ; + */ + TableData2D::TableDataHolder convertTable2D( arrayView1d< real64 const > const values, + units::Unit const valueUnit, + ArrayOfArraysView< real64 const > const coordinates, + string_view rowAxisDescription, + string_view columnAxisDescription ); + + /** + * @return Convert and return a struct containing a 1D Table, the column names list from a TableData2D and any errors related to the table + * @param dataDescription The table dataDescription shown at the top left side + * @param rowFmt The y axis units of the table. + * @param columnFmt The x axis units of the table. + * @note The rows and columns FMT can be customized. The bracket "{}" will be replaced by the axis value. + * By default it displays the axis value. + * I.E to display a customized axis to show the pressures in y axis, a rowFmt value can be : "pressure [K] = {}" + */ + TableDataHolder buildTableData( string_view dataDescription, + string_view rowFmt = "{}", string_view columnFmt = "{}" ) const; + +private: + /// @brief all cell values by their [ row ][ column ] + std::map< RowType, std::map< ColumnType, string > > m_data; + + /// @brief Store all column values when adding cell + std::set< real64 > m_columnValues; +}; + +template< typename ... Args > +void TableData::addRow( Args const &... args ) +{ + std::vector< string > m_cellsValue; + ( [&] { + static_assert( has_formatter_v< decltype(args) >, "Argument passed in addRow cannot be converted to string" ); + string const cellValue = GEOS_FMT( "{}", args ); + m_cellsValue.push_back( cellValue ); + } (), ...); + + addRow( m_cellsValue ); +} + +template< typename T > +void TableData2D::addCell( real64 const rowValue, real64 const columnValue, T const & value ) +{ + static_assert( has_formatter_v< decltype(value) >, "Argument passed in addCell cannot be converted to string" ); + m_columnValues.insert( columnValue ); + m_data[rowValue][columnValue] = GEOS_FMT( "{}", value ); +} + +} +#endif /* GEOS_COMMON_FORMAT_TABLE_TABLEDATA_HPP */ diff --git a/src/coreComponents/common/format/table/TableFormatter.cpp b/src/coreComponents/common/format/table/TableFormatter.cpp new file mode 100644 index 00000000000..7392834e060 --- /dev/null +++ b/src/coreComponents/common/format/table/TableFormatter.cpp @@ -0,0 +1,410 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file TableFormatter.cpp + */ + +#include "TableFormatter.hpp" +#include +#include "common/format/StringUtilities.hpp" +#include "TableFormatter.hpp" +namespace geos +{ + +TableFormatter::TableFormatter( TableLayout const & tableLayout ): + m_tableLayout( tableLayout ) +{} + +/////////////////////////////////////////////////////////////////////// +////// CSV Formatter implementation +/////////////////////////////////////////////////////////////////////// + +TableCSVFormatter::TableCSVFormatter( TableLayout const & tableLayout ): + TableFormatter( tableLayout ) +{ + m_tableLayout = tableLayout; +} + +string TableCSVFormatter::headerToString() const +{ + std::stringstream oss; + static constexpr string_view separator = ","; + + for( std::size_t idxColumn = 0; idxColumn < m_tableLayout.getColumns().size(); ++idxColumn ) + { + oss << m_tableLayout.getColumns()[idxColumn].m_parameter.columnName; + if( idxColumn < m_tableLayout.getColumns().size() - 1 ) + { + oss << separator; + } + } + oss << "\n"; + return oss.str(); +} + +string TableCSVFormatter::dataToString( TableData const & tableData ) const +{ + std::vector< std::vector< string > > const rowsValues = tableData.getTableDataRows(); + std::ostringstream oss; + + for( const auto & row : rowsValues ) + { + oss << stringutilities::join( row.cbegin(), row.cend(), "," ) << "\n"; + } + + return oss.str(); +} + +template<> +string TableCSVFormatter::toString< TableData >( TableData const & tableData ) const +{ + return headerToString() + dataToString( tableData ); +} + +/////////////////////////////////////////////////////////////////////// +////// Log Formatter implementation +/////////////////////////////////////////////////////////////////////// + +/** + * @brief Build cell given an alignment, a value and spaces + * @param alignment The aligment of cell value + * @param value The cell value + * @param spaces The number of spaces in the cell + * @return A formated cell + */ +string buildCell( TableLayout::Alignment const alignment, string_view value, integer const spaces ) +{ + switch( alignment ) + { + case TableLayout::right: return GEOS_FMT( "{:>{}}", value, spaces ); + case TableLayout::left: return GEOS_FMT( "{:<{}}", value, spaces ); + case TableLayout::center: return GEOS_FMT( "{:^{}}", value, spaces ); + default: return GEOS_FMT( "{:>{}}", value, spaces ); + } +} + +/** + * @brief Detect columns who are not displayed from TableLayout and therefore modify columns / tableDataRows vectors + * @param columns Vector built in TableLayout containing all columns with their parameters + * @param tableDataRows Vector built in TableData containing all rows values + */ +void formatColumnsFromLayout( std::vector< TableLayout::Column > & columns, + std::vector< std::vector< string > > & tableDataRows ) +{ + integer idxColumn = 0; + for( auto iterColumn = columns.begin(); iterColumn!=columns.end(); ) + { + if( !iterColumn->m_parameter.enabled ) + { + iterColumn = columns.erase( iterColumn ); + for( auto & row : tableDataRows ) + { + row.erase( row.begin() + idxColumn ); + } + } + else + { + ++iterColumn; + ++idxColumn; + } + } +} + +TableTextFormatter::TableTextFormatter( TableLayout const & tableLayout ): + TableFormatter( tableLayout ) +{} + +void TableTextFormatter::fillTableColumnsFromRows( std::vector< TableLayout::Column > & columns, + std::vector< std::vector< string > > & rows ) const +{ + for( size_t idxRow = 0; idxRow < rows.size(); idxRow++ ) + { + if( rows[idxRow].size() < columns.size() ) + { + rows[idxRow].resize( columns.size(), " " ); + } + + for( size_t idxColumn = 0; idxColumn < columns.size(); idxColumn++ ) + { + if( m_tableLayout.getColumns()[idxColumn].m_parameter.enabled ) + { + columns[idxColumn].m_columnValues.push_back( rows[idxRow][idxColumn] ); + } + } + } +} + +string TableTextFormatter::layoutToString() const +{ + std::ostringstream tableOutput; + string sectionSeparatingLine; + std::vector< TableLayout::Column > columns = m_tableLayout.getColumns(); + + outputLayout( tableOutput, columns, {}, sectionSeparatingLine ); + return tableOutput.str(); +} + +template<> +string TableTextFormatter::toString< TableData >( TableData const & tableData ) const +{ + std::ostringstream tableOutput; + string sectionSeparatingLine; + std::vector< TableLayout::Column > columns = m_tableLayout.getColumns(); + std::vector< std::vector< string > > tableDataRows = tableData.getTableDataRows(); + std::vector< string > const & msgTableError = tableData.getErrorMsgs(); + integer const nbValuesRows = tableDataRows.size(); + + formatColumnsFromLayout( columns, tableDataRows ); + fillTableColumnsFromRows( columns, tableDataRows ); + + outputLayout( tableOutput, columns, msgTableError, sectionSeparatingLine ); + outputSectionRows( columns, sectionSeparatingLine, tableOutput, nbValuesRows, TableLayout::Section::values ); + tableOutput << '\n'; + + return tableOutput.str(); +} + +void TableTextFormatter::outputLayout( std::ostringstream & tableOutput, + std::vector< TableLayout::Column > & columns, + std::vector< string > const & msgTableError, + string & sectionSeparatingLine ) const +{ + string topSeparator; + size_t nbHeaderRows = 0; + std::vector< std::vector< string > > splitHeaders; + string const tableTitle = string( m_tableLayout.getTitle()); + + splitAndSetColumnNames( columns, nbHeaderRows, splitHeaders ); + findAndSetMaxStringSize( columns ); + + computeTableWidth( columns, msgTableError ); + buildTableSeparators( columns, topSeparator, sectionSeparatingLine ); + + tableOutput << '\n'; + outputTopRows( tableOutput, {tableTitle}, topSeparator, TableLayout::Alignment::center ); + outputTopRows( tableOutput, msgTableError, topSeparator, TableLayout::Alignment::left ); + tableOutput << GEOS_FMT( "{}\n", sectionSeparatingLine ); + + outputSectionRows( columns, sectionSeparatingLine, tableOutput, nbHeaderRows, TableLayout::Section::header ); +} + +void TableTextFormatter::splitAndSetColumnNames( std::vector< TableLayout::Column > & columns, + size_t & nbHeaderRows, + std::vector< std::vector< string > > & splitHeaders ) const +{ + + splitHeaders.reserve( columns.size() ); + for( auto const & column : columns ) + { + std::vector< string > splitHeaderParts; + std::istringstream ss( column.m_parameter.columnName ); + string subColumnNames; + + while( getline( ss, subColumnNames, '\n' )) + { + splitHeaderParts.push_back( subColumnNames ); + } + + splitHeaders.push_back( std::move( splitHeaderParts ) ); + } + + nbHeaderRows = std::max_element( splitHeaders.begin(), splitHeaders.end(), + []( auto const & v1, auto const & v2 ) { return v1.size() < v2.size(); } )->size(); + + for( auto & headerParts : splitHeaders ) + { + if( headerParts.size() < nbHeaderRows ) + { + headerParts.resize( nbHeaderRows, " " ); + } + columns[&headerParts - &splitHeaders[0]].m_parameter.splitColumnNameLines = headerParts; + } + +} + +void TableTextFormatter::findAndSetMaxStringSize( std::vector< TableLayout::Column > & columns ) const +{ + for( auto & column : columns ) + { + auto const maxStringSizeHeader = *std::max_element( column.m_parameter.splitColumnNameLines.begin(), + column.m_parameter.splitColumnNameLines.end(), + []( const auto & a, const auto & b ) {return a.size() < b.size();} ); + column.m_maxStringSize = maxStringSizeHeader; + + for( auto const & cell : column.m_columnValues ) + { + if( column.m_maxStringSize.length() < cell.length()) + { + column.m_maxStringSize = cell; + } + } + } +} + +void TableTextFormatter::increaseColumnsSize( std::vector< TableLayout::Column > & columns, + integer const extraCharacters ) const +{ + integer const extraCharactersPerColumn = std::ceil( extraCharacters / columns.size() ); + for( std::size_t idxColumn = 0; idxColumn < columns.size(); ++idxColumn ) + { + integer newMaxStringSize = extraCharactersPerColumn + columns[idxColumn].m_maxStringSize.size(); + if( idxColumn == columns.size() - 1 ) + { + newMaxStringSize += m_tableLayout.getColumnMargin(); + } + + columns[idxColumn].m_maxStringSize = GEOS_FMT( "{:>{}}", + columns[idxColumn].m_maxStringSize, + newMaxStringSize ); + } +} + +void computeTableErrorLength( std::vector< string > const & msgTableError, string::size_type & msgTableErrorLength ) +{ + if( !msgTableError.empty() ) + { + auto maxStringSize = *(std::max_element( msgTableError.begin(), msgTableError.end(), + []( const auto & a, const auto & b ) { + return a.size() < b.size(); + } )); + + msgTableErrorLength += maxStringSize.size() + 1; // max string size + line return at the end + } +} + +void computeTableSectionLength( std::vector< TableLayout::Column > & columns, string::size_type & sectionlineLength ) +{ + sectionlineLength += std::accumulate( columns.begin(), columns.end(), 0, + []( auto sum, const auto & column ) + { return sum + column.m_maxStringSize.length();} ); +} + +void TableTextFormatter::computeTableWidth( std::vector< TableLayout::Column > & columns, + std::vector< string > const & msgTableError ) const +{ + integer const columnMargin = m_tableLayout.getColumnMargin(); + integer const borderMargin = m_tableLayout.getBorderMargin(); + string const tableTitle = string( m_tableLayout.getTitle() ); + + string::size_type sectionLengthWithSpacing = ( ( columns.size() - 1 ) * columnMargin ) + (borderMargin * 2); + string::size_type sectionlineLength = sectionLengthWithSpacing; + string::size_type maxTopLineLength = tableTitle.length(); + string::size_type msgTableErrorLength = borderMargin; + + computeTableErrorLength( msgTableError, msgTableErrorLength ); + computeTableSectionLength( columns, sectionlineLength ); + + maxTopLineLength = std::max( maxTopLineLength, msgTableErrorLength ); + if( sectionlineLength < maxTopLineLength ) + { + integer const extraCharacters = maxTopLineLength - sectionlineLength; + increaseColumnsSize( columns, extraCharacters ); + } +} + + +void TableTextFormatter::buildTableSeparators( std::vector< TableLayout::Column > const & columns, + string & topSeparator, + string & sectionSeparatingLine ) const +{ + { // section separator line + integer const columnMargin = m_tableLayout.getColumnMargin(); + integer const borderMargin = m_tableLayout.getBorderMargin(); + + std::vector< string > maxStringPerColumn; + for( auto const & column : columns ) + { + maxStringPerColumn.push_back( string( column.m_maxStringSize.length(), m_horizontalLine ) ); + } + + string const patternBetweenColumns = GEOS_FMT( "{:-^{}}", m_horizontalLine, columnMargin ); + + std::string const leftBorder = GEOS_FMT( "{}{:-<{}}", m_horizontalLine, "", borderMargin ); + std::string const rightBorder = GEOS_FMT( "{}{:-<{}}", m_horizontalLine, "", borderMargin ); + std::string const columnJoin = stringutilities::join( maxStringPerColumn, patternBetweenColumns ); + + std::ostringstream oss; + oss << leftBorder << columnJoin << rightBorder; + sectionSeparatingLine = oss.str(); + } + + { // top line separator + // -2 because we can have '+' to the extremity of top separator + integer const topSeparatorLength = sectionSeparatingLine.size() - 2; + topSeparator = GEOS_FMT( "{}{:-<{}}{}", m_horizontalLine, "", topSeparatorLength, m_horizontalLine ); + } +} + +void TableTextFormatter::outputTopRows( std::ostringstream & tableOutput, + std::vector< string > const & msg, + string_view topSeparator, + TableLayout::Alignment alignment ) const +{ + if( msg.size() != 0 && msg[0] != "" ) + { + tableOutput << GEOS_FMT( "{}\n", topSeparator ); + for( std::string const & str : msg ) + { + tableOutput << m_verticalLine << string( m_tableLayout.getBorderMargin(), ' ' ); + tableOutput << buildCell( alignment, str, (topSeparator.length() - 6)); + tableOutput << string( m_tableLayout.getBorderMargin(), ' ' ) << "|\n"; + } + } +} + +void TableTextFormatter::outputSectionRows( std::vector< TableLayout::Column > const & columns, + string_view sectionSeparatingLine, + std::ostringstream & tableOutput, + integer const nbRows, + TableLayout::Section const section ) const +{ + integer const columnMargin = m_tableLayout.getColumnMargin(); + integer const borderMargin = m_tableLayout.getBorderMargin(); + + for( integer idxRow = 0; idxRow< nbRows; ++idxRow ) + { + // Append the left border + tableOutput << GEOS_FMT( "{:<{}}", m_verticalLine, 1 + borderMargin ); + for( std::size_t idxColumn = 0; idxColumn < columns.size(); ++idxColumn ) + { + TableLayout::Column const currentColumn = columns[idxColumn]; + auto const & columnContent = section == TableLayout::Section::header ? + columns[idxColumn].m_parameter.splitColumnNameLines : + columns[idxColumn].m_columnValues; + string cell = columnContent.at( idxRow ); + integer const cellSize = currentColumn.m_maxStringSize.length(); + + tableOutput << buildCell( currentColumn.m_parameter.alignment, cell, cellSize ); + + // Add space between column + if( idxColumn < columns.size() - 1 ) + { + tableOutput << GEOS_FMT( "{:^{}}", m_verticalLine, columnMargin ); + } + + } + + // Append right border with line return + tableOutput << GEOS_FMT( "{:>{}}\n", m_verticalLine, borderMargin + 1 ); + } + + if( nbRows != 0 ) + { + tableOutput << GEOS_FMT( "{}\n", sectionSeparatingLine ); + } +} + +} diff --git a/src/coreComponents/common/format/table/TableFormatter.hpp b/src/coreComponents/common/format/table/TableFormatter.hpp new file mode 100644 index 00000000000..26dd2b16ba4 --- /dev/null +++ b/src/coreComponents/common/format/table/TableFormatter.hpp @@ -0,0 +1,259 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file TableFormatter.hpp + */ + +#ifndef GEOS_COMMON_FORMAT_TABLE_TABLEFORMATTER_HPP +#define GEOS_COMMON_FORMAT_TABLE_TABLEFORMATTER_HPP + +#include "TableData.hpp" +#include "TableLayout.hpp" + +namespace geos +{ + +/** + * @brief abstract class for formatting table data + */ +class TableFormatter +{ + +protected: + + /// Layout for a table + TableLayout m_tableLayout; + + TableFormatter() = default; + + /** + * @brief Construct a new Table Formatter from a tableLayout + * @param tableLayout Contain all column names and optionnaly the table title + */ + TableFormatter( TableLayout const & tableLayout ); + + /** + * @brief Destroy the Table Formatter object + */ + virtual ~TableFormatter() = default; +}; + +/** + * @brief class for CSV formatting + */ +class TableCSVFormatter : public TableFormatter +{ +public: + + /** + * @brief Construct a new Table Formatter + */ + TableCSVFormatter(): + TableFormatter( TableLayout() ) + {} + + /** + * @brief Construct a new Table Formatter from a tableLayout + * @param tableLayout Contain all column names and optionnaly the table title + */ + TableCSVFormatter( TableLayout const & tableLayout ); + + /** + * @brief Destroy the TableCSVFormatter object + */ + virtual ~TableCSVFormatter() = default; + + /** + * @return The string with all column names. + */ + string headerToString() const; + + /** + * @brief Convert the table data to a CSV string. + * @param tableData The 1D table data. + * @return The CSV string representation of the table data. + */ + string dataToString( TableData const & tableData ) const; + + /** + * @brief Convert a data source to a CSV string. + * @tparam DATASOURCE The source to convert + * @param tableData The data source to convert + * @return The CSV string representation of a data source. + */ + template< typename DATASOURCE > + string toString( DATASOURCE const & tableData ) const; + +}; + +/** + * @brief Convert the TableData to a CSV string. + * @param tableData The TableData to convert. + * @return The CSV string representation of the TableData. + */ +template<> +string TableCSVFormatter::toString< TableData >( TableData const & tableData ) const; + + +/** + * @brief class for log formatting + */ +class TableTextFormatter : public TableFormatter +{ +public: + + + /** + * @brief Construct a new TableFormatter + */ + TableTextFormatter(): + TableFormatter( TableLayout() ) + {} + + /** + * @brief Construct a new TableFormatter from a tableLayout + * @param tableLayout Contain all column names and optionnaly the table title + */ + TableTextFormatter( TableLayout const & tableLayout ); + + + /** + * @brief Destroy the Table Text Formatter object + */ + virtual ~TableTextFormatter() = default; + + /** + * @return A TableLayout converted into a formatted representation. + */ + string layoutToString() const; + + /** + * @brief Convert a data source to a table string. + * @param tableData The data source to convert. + * @return The table string representation of the TableData. + */ + template< typename DATASOURCE > + string toString( DATASOURCE const & tableData ) const; + +private: + + /// symbol for separator construction + static constexpr char m_verticalLine = '|'; + /// for the extremity of a row + static constexpr char m_horizontalLine = '-'; + + /** + * @brief Fill the vector (m_column) in tableData with values from rows stored in tableData. + * @param columns Vector of columns to be filled. + * @param tableData Vector containing all rows filled with values + */ + void fillTableColumnsFromRows( std::vector< TableLayout::Column > & columns, + std::vector< std::vector< string > > & tableData ) const; + + /** + * @brief Converts a TableLayout into a formatted representation. + * @param tableOutput The output stream + * @param columns The vector containing all table columns + * @param msgTableError A vector containg all error related to the table + * @param sectionSeparatingLine An empty string for building the section separator + */ + void outputLayout( std::ostringstream & tableOutput, + std::vector< TableLayout::Column > & columns, + std::vector< string > const & msgTableError, + string & sectionSeparatingLine ) const; + + /** + * @brief Split all header names by detecting the newline \\n character. and + * set the same vector size for each split header and merge it into columns + * @param columns The vector containg all columns + * @param largestHeaderVectorSize The largest split header vector size + * @param splitHeaders A empty vector who will contain all split header names + */ + void splitAndSetColumnNames( std::vector< TableLayout::Column > & columns, + size_t & largestHeaderVectorSize, + std::vector< std::vector< string > > & splitHeaders ) const; + + /** + * @brief For each column find and set the column's longest string + * @param columns The vector containg all columns + */ + void findAndSetMaxStringSize( std::vector< TableLayout::Column > & columns ) const; + + /** + * @brief recalculate the largest string size for each columns + * @param columns Vector containing all table columns + * @param extraCharacters Extra characters to be added to \p m_maxStringSize of each columns + */ + void increaseColumnsSize( std::vector< TableLayout::Column > & columns, + integer const extraCharacters ) const; + + /** + * @brief Compute the max table line length, taking into account the length of : title, error, columns header and content + * Increase the size of the columns if necessary + * @param columns Vector of column containing containing the largest string for each column + * @param msgTableError Vector containing all error messages + */ + void computeTableWidth( std::vector< TableLayout::Column > & columns, + std::vector< string > const & msgTableError ) const; + + /** + * @brief Build all separators needed from content length contained in the columns vector + * @param columns Vector containing all table columns + * @param topSeparator Top separator to be built + * @param sectionSeparatingLine Line section separator to be built + */ + void buildTableSeparators( std::vector< TableLayout::Column > const & columns, + string & topSeparator, + string & sectionSeparatingLine ) const; + + /** + * @brief Add a row on top of the table + * @param tableOutput The output stream + * @param msg Vector of string(s) to display + * @param topSeparator The top table separator + * @param alignment The aligment for a row + */ + void outputTopRows( std::ostringstream & tableOutput, + std::vector< string > const & msg, + string_view topSeparator, + TableLayout::Alignment alignment ) const; + + /** + * @brief Output a section by specifying it's type ( header or section ) + * @param columns Vector containing all table columns + * @param sectionSeparatingLine Line separator between sections + * @param rows A section row + * @param nbRows Indicates the number of lines in a section + * @param section The section to be built + * @note Add the ending line if there are one or more rows + */ + void outputSectionRows( std::vector< TableLayout::Column > const & columns, + string_view sectionSeparatingLine, + std::ostringstream & rows, + integer const nbRows, + TableLayout::Section const section ) const; +}; + +/** + * @brief Convert a TableData to a table string. + * @param tableData The TableData to convert. + * @return The table string representation of the TableData. + */ +template<> +string TableTextFormatter::toString< TableData >( TableData const & tableData ) const; +} + +#endif /* GEOS_COMMON_FORMAT_TABLE_TABLEFORMATTER_HPP */ diff --git a/src/coreComponents/common/format/table/TableLayout.cpp b/src/coreComponents/common/format/table/TableLayout.cpp new file mode 100644 index 00000000000..7e6b134d606 --- /dev/null +++ b/src/coreComponents/common/format/table/TableLayout.cpp @@ -0,0 +1,79 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file TableData.hpp + */ + +#include "TableLayout.hpp" + +namespace geos +{ + +TableLayout::TableLayout( std::vector< string > const & columnNames, string const & title ): + m_tableTitle( title ) +{ + setMargin( MarginValue::medium ); + m_columns.reserve( columnNames.size() ); + for( auto const & name : columnNames ) + { + m_columns.push_back( {TableLayout::ColumnParam{{name}, Alignment::right, true}, {}, ""} ); + } +} + +TableLayout::TableLayout( std::vector< ColumnParam > const & columnParameters, string const & title ): + m_tableTitle( title ) +{ + setMargin( MarginValue::medium ); + m_columns.reserve( columnParameters.size() ); + for( auto const & param : columnParameters ) + { + m_columns.push_back( { param, {}, ""} ); + } +} + +void TableLayout::setMargin( MarginValue marginValue ) +{ + m_borderMargin = marginValue; + m_columnMargin = integer( marginValue ) * 2 + 1; +} + +std::vector< TableLayout::Column > const & TableLayout::getColumns() const +{ + return m_columns; +} + +string_view TableLayout::getTitle() const +{ + return m_tableTitle; +} + + +integer const & TableLayout::getBorderMargin() const +{ + return m_borderMargin; +} + +integer const & TableLayout::getColumnMargin() const +{ + return m_columnMargin; +} + +integer const & TableLayout::getMarginTitle() const +{ + return m_titleMargin; +} + +} diff --git a/src/coreComponents/common/format/table/TableLayout.hpp b/src/coreComponents/common/format/table/TableLayout.hpp new file mode 100644 index 00000000000..e6f96a878eb --- /dev/null +++ b/src/coreComponents/common/format/table/TableLayout.hpp @@ -0,0 +1,159 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file TableLayout.hpp + */ + +#ifndef GEOS_COMMON_FORMAT_TABLE_TABLELAYOUT_HPP +#define GEOS_COMMON_FORMAT_TABLE_TABLELAYOUT_HPP + +#include "common/DataTypes.hpp" + +namespace geos +{ + +/** + * @brief Class for setup the table layout + */ +class TableLayout +{ + +public: + + /// Type of aligment for a column + enum Alignment { right, left, center }; + + /// Space to apply between all data and border + enum MarginValue : integer + { + tiny = 0, + small = 1, + medium = 2, + large = 3 + }; + + /** + * @brief Enumeration for table sections. + */ + enum Section { header, values }; + + /** + * @brief Structure to set up each colum parameters. + */ + struct ColumnParam + { + /// Name for a column + string columnName; + /// Alignment for a column. By default aligned to the right side + Alignment alignment = Alignment::right; + /// A boolean to display a colummn + bool enabled = true; + /// Vector containing substring column name delimited by "\n" + std::vector< string > splitColumnNameLines; + + /** + * @brief Construct a ColumnParam object with the specified name and alignment. + * @param name The name of the column + * @param align The alignment of the column + */ + ColumnParam( std::string const & name, Alignment align ) + : columnName( name ), alignment( align ) + {} + + /** + * @brief Construct a ColumnParam object with the specified name, alignment, and display flag. + * @param name The name of the column + * @param align The alignment of the column + * @param display Flag indicating whether the column is enabled + */ + ColumnParam( std::string const & name, Alignment align, bool display ) + : columnName( name ), alignment( align ), enabled( display ) + {} + }; + + /** + * @brief Struct for a column. + */ + struct Column + { + /// Structure who contains parameters for a column + ColumnParam m_parameter; + /// A vector containing all column values + std::vector< string > m_columnValues; + /// The largest string in the column + string m_maxStringSize; + }; + + TableLayout() = default; + + /** + * @brief Construct a new Table object, all values in the table are centered by default + * @param columnNames The names of the columns + * @param title The table name + */ + TableLayout( std::vector< string > const & columnNames, string const & title = "" ); + + /** + * @brief Construct a new Table object by specifying value alignment and optionally their displays based to log levels + * level + * @param columnParameters List of structures to set up each colum parameters. + * @param title The table name + */ + TableLayout( std::vector< ColumnParam > const & columnParameters, string const & title = "" ); + + /** + * @return The columns vector + */ + std::vector< Column > const & getColumns() const; + + /** + * @return The table name + */ + string_view getTitle() const; + + /** + * @return The border margin, number of spaces at both left and right table sides + */ + integer const & getBorderMargin() const; + + /** + * @return The column margin, numbers of spaces separating both left and right side from each column content + */ + integer const & getColumnMargin() const; + + /** + * @return The margin title + */ + integer const & getMarginTitle() const; + + /** + * @brief Set the minimal margin width between cell content and borders. + * @param marginValue The margin value + */ + void setMargin( MarginValue marginValue ); + +private: + + std::vector< Column > m_columns; + string m_tableTitle; + integer m_borderMargin; + integer m_columnMargin; + integer m_titleMargin = 2; + +}; +} + +#endif /* GEOS_COMMON_FORMAT_TABLE_TABLELAYOUT_HPP */ diff --git a/src/coreComponents/common/format/table/unitTests/CMakeLists.txt b/src/coreComponents/common/format/table/unitTests/CMakeLists.txt new file mode 100644 index 00000000000..f5a4a358e97 --- /dev/null +++ b/src/coreComponents/common/format/table/unitTests/CMakeLists.txt @@ -0,0 +1,18 @@ +# Specify list of tests +set( gtest_geosx_tests + testTable.cpp ) + +set( dependencyList gtest common ${parallelDeps} ) + +# Add gtest C++ based tests +foreach(test ${gtest_geosx_tests}) + get_filename_component( test_name ${test} NAME_WE ) + blt_add_executable( NAME ${test_name} + SOURCES ${test} + OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} + DEPENDS_ON ${dependencyList} ) + + geos_add_test( NAME ${test_name} + COMMAND ${test_name} ) + +endforeach() diff --git a/src/coreComponents/common/format/table/unitTests/testTable.cpp b/src/coreComponents/common/format/table/unitTests/testTable.cpp new file mode 100644 index 00000000000..0258385b1a1 --- /dev/null +++ b/src/coreComponents/common/format/table/unitTests/testTable.cpp @@ -0,0 +1,333 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// Source includes +#include "common/format/table/TableData.hpp" +#include "common/format/table/TableFormatter.hpp" +#include "common/format/table/TableLayout.hpp" +#include "dataRepository/Group.hpp" +// TPL includes +#include +#include + +using namespace geos; + +TEST( testTable, tableEmptyRow ) +{ + //table with empty row + TableLayout const tableLayout( {"Well\nelement no.\nPV weighted\nbar", + "CordX", + "CoordZ", + "Prev\nelement", + "Next\nelement"}, + "InternalWellGenerator well_injector1" + ); + + TableData tableData; + tableData.addRow( "value1", "[30.21543]", "3.0", 54, 0 ); + tableData.addRow( "", "", "", "", "" ); + tableData.addRow( "Duis fringilla, ligula sed porta fringilla, ligula wisi commodo felis,ut adipiscing felis dui in enim. Suspendisse malesuada ultrices ante", "[30.21543]", "30.45465142", + 787442, 10 ); + + TableTextFormatter const tableText( tableLayout ); + EXPECT_EQ( tableText.toString( + tableData ), + "\n-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n" + "| InternalWellGenerator well_injector1 |\n" + "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n" + "| Well | CordX | CoordZ | Prev | Next |\n" + "| element no. | | | element | element |\n" + "| PV weighted | | | | |\n" + "| bar | | | | |\n" + "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n" + "| value1 | [30.21543] | 3.0 | 54 | 0 |\n" + "| | | | | |\n" + "| Duis fringilla, ligula sed porta fringilla, ligula wisi commodo felis,ut adipiscing felis dui in enim. Suspendisse malesuada ultrices ante | [30.21543] | 30.45465142 | 787442 | 10 |\n" + "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n\n" + ); +} + +TEST( testTable, tableClassic ) +{ + TableLayout const tableLayout( {"Duis fringilla, ligula sed porta fringilla,\nligula wisi commodo felis,ut adipiscing felis dui in enim. Suspendisse malesuada ultrices ante", + "CordX", + "CoordZ", + "Prev\nelement", + "Next\nelement"}, "InternalWellGenerator well_injector1" ); + + TableData tableData; + tableData.addRow( "value1", "[30.21543]", "3.0", 54, 0 ); + tableData.addRow( "", "", "", "", "" ); + tableData.addRow( "value23", "[30.21543]", "30.45465142", 787442, 10 ); + + TableTextFormatter const tableText( tableLayout ); + EXPECT_EQ( tableText.toString( tableData ), + "\n-----------------------------------------------------------------------------------------------------------------------------------------------------------\n" + "| InternalWellGenerator well_injector1 |\n" + "-----------------------------------------------------------------------------------------------------------------------------------------------------------\n" + "| Duis fringilla, ligula sed porta fringilla, | CordX | CoordZ | Prev | Next |\n" + "| ligula wisi commodo felis,ut adipiscing felis dui in enim. Suspendisse malesuada ultrices ante | | | element | element |\n" + "-----------------------------------------------------------------------------------------------------------------------------------------------------------\n" + "| value1 | [30.21543] | 3.0 | 54 | 0 |\n" + "| | | | | |\n" + "| value23 | [30.21543] | 30.45465142 | 787442 | 10 |\n" + "-----------------------------------------------------------------------------------------------------------------------------------------------------------\n\n" + ); +} + +TEST( testTable, tableColumnParamClassic ) +{ + TableLayout const tableLayout( { + TableLayout::ColumnParam{{"Cras egestas"}, TableLayout::Alignment::center}, + TableLayout::ColumnParam{{"CoordX"}, TableLayout::Alignment::left}, + TableLayout::ColumnParam{{"C"}, TableLayout::Alignment::left}, + TableLayout::ColumnParam{{"CoordZ"}, TableLayout::Alignment::left}, + TableLayout::ColumnParam{{"Prev\nelement"}, TableLayout::Alignment::right}, + TableLayout::ColumnParam{{"Next\nelement"}, TableLayout::Alignment::right} + }, "InternalWellGenerator well_injector1" ); + + TableData tableData; + tableData.addRow( "value1", " ", "3.0", 3.0129877, 2.0f, 1 ); + tableData.addRow( "val1", "v", "[3.045,42.02,89.25]", 3.0, 10.0f, 3 ); + + TableTextFormatter const tableText( tableLayout ); + EXPECT_EQ( tableText.toString( tableData ), + "\n-------------------------------------------------------------------------------------------\n" + "| InternalWellGenerator well_injector1 |\n" + "-------------------------------------------------------------------------------------------\n" + "| Cras egestas | CoordX | C | CoordZ | Prev | Next |\n" + "| | | | | element | element |\n" + "-------------------------------------------------------------------------------------------\n" + "| value1 | | 3.0 | 3.0129877 | 2 | 1 |\n" + "| val1 | v | [3.045,42.02,89.25] | 3 | 10 | 3 |\n" + "-------------------------------------------------------------------------------------------\n\n" + ); +} + +TEST( testTable, tableHiddenColumn ) +{ + TableLayout const tableLayout( { + TableLayout::ColumnParam{{"Cras egestas"}, TableLayout::Alignment::center}, + TableLayout::ColumnParam{{"CoordX"}, TableLayout::Alignment::right}, + TableLayout::ColumnParam{{"C"}, TableLayout::Alignment::center}, + TableLayout::ColumnParam{{"CoordZ"}, TableLayout::Alignment::left}, + TableLayout::ColumnParam{{"Prev\nelement"}, TableLayout::Alignment::left, false}, + TableLayout::ColumnParam{{"Next\nelement"}, TableLayout::Alignment::center, false}, + }, "Cras egestas ipsum a nisl. Vivamus variu dolor utsisicdis parturient montes, nascetur ridiculus mus. Duis" ); + + TableData tableData; + tableData.addRow( "value1", " ", "3.0", 3.0129877, 2.0f, 1 ); + tableData.addRow( "val1", "v", "[3.045,42.02,89.25]", 3.0, 10.0f, 3 ); + + TableTextFormatter const tableText( tableLayout ); + EXPECT_EQ( tableText.toString( tableData ), + "\n----------------------------------------------------------------------------------------------------------------\n" + "| Cras egestas ipsum a nisl. Vivamus variu dolor utsisicdis parturient montes, nascetur ridiculus mus. Duis |\n" + "----------------------------------------------------------------------------------------------------------------\n" + "| Cras egestas | CoordX | C | CoordZ |\n" + "----------------------------------------------------------------------------------------------------------------\n" + "| value1 | | 3.0 | 3.0129877 |\n" + "| val1 | v | [3.045,42.02,89.25] | 3 |\n" + "----------------------------------------------------------------------------------------------------------------\n\n" ); +} + +TEST( testTable, tableUniqueColumn ) +{ + TableLayout const tableLayout( { + TableLayout::ColumnParam{{"Cras egestas"}, TableLayout::Alignment::center}, + }, "Cras egestas ipsu a nisl. Vivamus variu dolor utsisicdis parturient montes, nascetur ridiculus mus. Duis" ); + + TableData tableData; + tableData.addRow( "value1" ); + tableData.addRow( "val1" ); + + TableTextFormatter const tableText( tableLayout ); + EXPECT_EQ( tableText.toString( tableData ), + "\n---------------------------------------------------------------------------------------------------------------\n" + "| Cras egestas ipsu a nisl. Vivamus variu dolor utsisicdis parturient montes, nascetur ridiculus mus. Duis |\n" + "---------------------------------------------------------------------------------------------------------------\n" + "| Cras egestas |\n" + "---------------------------------------------------------------------------------------------------------------\n" + "| value1 |\n" + "| val1 |\n" + "---------------------------------------------------------------------------------------------------------------\n\n" ); +} + +TEST( testTable, tableEmptyTitle ) +{ + TableLayout const tableLayout( { + TableLayout::ColumnParam{{"Cras egestas"}, TableLayout::Alignment::center}, + TableLayout::ColumnParam{{"CoordX"}, TableLayout::Alignment::right}, + TableLayout::ColumnParam{{"C"}, TableLayout::Alignment::center}, + TableLayout::ColumnParam{{"CoordZ"}, TableLayout::Alignment::left}, + TableLayout::ColumnParam{{"Prev\nelement"}, TableLayout::Alignment::left}, + TableLayout::ColumnParam{{"Next\nelement"}, TableLayout::Alignment::center}, + } + ); + + TableData tableData; + tableData.addRow( "value1", " ", "3.0", 3.0129877, 2.0f, 1 ); + tableData.addRow( "val1", "v", "[3.045,42.02,89.25]", 3.0, 10.0f, 3 ); + + TableTextFormatter const tableText( tableLayout ); + EXPECT_EQ( tableText.toString( tableData ), + "\n-------------------------------------------------------------------------------------------\n" + "| Cras egestas | CoordX | C | CoordZ | Prev | Next |\n" + "| | | | | element | element |\n" + "-------------------------------------------------------------------------------------------\n" + "| value1 | | 3.0 | 3.0129877 | 2 | 1 |\n" + "| val1 | v | [3.045,42.02,89.25] | 3 | 10 | 3 |\n" + "-------------------------------------------------------------------------------------------\n\n" + ); +} + +TEST( testTable, table2DTable ) +{ + //collect + TableData2D tableData; + + for( real64 p = 10000; p<20000; p+=5000 ) + { + for( real64 t = 400; t>=270; t+=-50.0 ) + { + real64 value = t/p; + tableData.addCell( t, p, value ); + } + } + + //convert + string const rowFmt = GEOS_FMT( "{} = {{}}", "Temperature" ); + string const columnFmt = GEOS_FMT( "{} = {{}}", "Pression" ); + TableData2D::TableDataHolder tableconverted = tableData.buildTableData( "Viscosity kg*s", + rowFmt, + columnFmt ); + + //format + TableLayout const tableLayout( tableconverted.headerNames ); + + //log + TableTextFormatter const tableLog( tableLayout ); + EXPECT_EQ( tableLog.toString( tableconverted.tableData ), + "\n---------------------------------------------------------------------\n" + "| Viscosity kg*s | Pression = 10000 | Pression = 15000 |\n" + "---------------------------------------------------------------------\n" + "| Temperature = 300 | 0.03 | 0.02 |\n" + "| Temperature = 350 | 0.035 | 0.023333333333333334 |\n" + "| Temperature = 400 | 0.04 | 0.02666666666666667 |\n" + "---------------------------------------------------------------------\n\n" + ); +} + + +TEST( testTable, table2DColumnMismatch ) +{ + //test 2D table column mismatch + { + // collect + TableData2D tableData; + + tableData.addCell( 300, 10000, 0.03 ); + tableData.addCell( 300, 15000, 0.02 ); + tableData.addCell( 350, 10000, 0.035 ); + tableData.addCell( 350, 10000, 0.035 ); + tableData.addCell( 400, 10000, 0.04 ); + tableData.addCell( 400, 15000, 0.02666666666666667 ); + + //convert + string const rowFmt = GEOS_FMT( "{} = {{}}", "Temperature" ); + string const columnFmt = GEOS_FMT( "{} = {{}}", "Pression" ); + TableData2D::TableDataHolder tableConverted = tableData.buildTableData( "Viscosity kg*s", + rowFmt, + columnFmt ); + + //format + TableLayout const tableLayout( tableConverted.headerNames ); + + //log + TableTextFormatter const tableLog( tableLayout ); + EXPECT_EQ( tableLog.toString( tableConverted.tableData ), + "\n--------------------------------------------------------------------\n" + "| Remarks : some cells may be missing |\n" + "--------------------------------------------------------------------\n" + "| Viscosity kg*s | Pression = 10000 | Pression = 15000 |\n" + "--------------------------------------------------------------------\n" + "| Temperature = 300 | 0.03 | 0.02 |\n" + "| Temperature = 350 | 0.035 | |\n" + "| Temperature = 400 | 0.04 | 0.02666666666666667 |\n" + "--------------------------------------------------------------------\n\n" + ); + } +} + +TEST( testTable, layoutTable ) +{ + string filename = "fluid1_phaseModel1_PhillipsBrineDensity_table"; + + string log = GEOS_FMT( "The {} PVT table exceeding 500 rows.\nTo visualize the tables, go to the generated csv \n", filename ); + TableLayout const tableLayoutInfos( {TableLayout::ColumnParam{{log}, TableLayout::Alignment::left}}, filename ); + + TableTextFormatter const tableLog( tableLayoutInfos ); + EXPECT_EQ( tableLog.layoutToString(), + "\n-------------------------------------------------------------------------------------\n" + "| fluid1_phaseModel1_PhillipsBrineDensity_table |\n" + "-------------------------------------------------------------------------------------\n" + "| The fluid1_phaseModel1_PhillipsBrineDensity_table PVT table exceeding 500 rows. |\n" + "| To visualize the tables, go to the generated csv |\n" + "-------------------------------------------------------------------------------------\n" + ); +} + +TEST( testTable, tableSetMargin ) +{ + //////////// + //////// If setMargin used elsewhere make it public and remove comments for this test + //////////// + //test with tiny margin + // { + // TableLayout tableLayout( { + // TableLayout::ColumnParam{{"Colonne 1"}, TableLayout::Alignment::center}, + // TableLayout::ColumnParam{{"Colonne 2"}, TableLayout::Alignment::center}, + // TableLayout::ColumnParam{{"Colonne 3"}, TableLayout::Alignment::right}, + // TableLayout::ColumnParam{{"Colonne 4"}, TableLayout::Alignment::right}, + // TableLayout::ColumnParam{{"Prev\nelement"}, TableLayout::Alignment::right}, + // TableLayout::ColumnParam{{"Next\nelement"}, TableLayout::Alignment::right}, + // }, "InternalWellGenerator well_injector1" ); + + // //tableLayout.setMargin( TableLayout::MarginValue::tiny ); + + // TableData tableData; + // tableData.addRow( "value 1", "long value 1", "3.0034", 3.0129877, "" , 1 ); + // tableData.addRow( "value 1", "long value 2", "100.45", 4.0129877, 1 , 2 ); + + // TableTextFormatter const tableText( tableLayout ); + // EXPECT_EQ( tableText.toString( tableData ), +// "\n------------------------------------------------------------\n" +// "| InternalWellGenerator well_injector1 |\n" +// "------------------------------------------------------------\n" +// "|Colonne 1| Colonne 2 |Colonne 3|Colonne 4| Prev| Next|\n" +// "| | | | |element|element|\n" +// "------------------------------------------------------------\n" +// "| value 1 |long value 1| 3.0034|3.0129877| | 1|\n" +// "| value 1 |long value 2| 100.45|4.0129877| 1| 2|\n" +// "------------------------------------------------------------\n\n" +// ); +// } +} + +int main( int argc, char * * argv ) +{ + testing::InitGoogleTest( &argc, argv ); + return RUN_ALL_TESTS(); +} diff --git a/src/coreComponents/common/format/unitTests/CMakeLists.txt b/src/coreComponents/common/format/unitTests/CMakeLists.txt new file mode 100644 index 00000000000..1684cd24bee --- /dev/null +++ b/src/coreComponents/common/format/unitTests/CMakeLists.txt @@ -0,0 +1,19 @@ +# Specify list of tests +set( testSources + testStringUtilities.cpp ) + +set( dependencyList gtest common ${parallelDeps} ) + +# Add gtest C++ based tests +foreach( test ${testSources} ) + + get_filename_component( test_name ${test} NAME_WE ) + blt_add_executable( NAME ${test_name} + SOURCES ${test} + OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} + DEPENDS_ON ${dependencyList} ) + + geos_add_test( NAME ${test_name} + COMMAND ${test_name} ) + +endforeach() diff --git a/src/coreComponents/codingUtilities/tests/testStringUtilities.cpp b/src/coreComponents/common/format/unitTests/testStringUtilities.cpp similarity index 98% rename from src/coreComponents/codingUtilities/tests/testStringUtilities.cpp rename to src/coreComponents/common/format/unitTests/testStringUtilities.cpp index de83594fd94..57dca300d6f 100644 --- a/src/coreComponents/codingUtilities/tests/testStringUtilities.cpp +++ b/src/coreComponents/common/format/unitTests/testStringUtilities.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/common/initializeEnvironment.cpp b/src/coreComponents/common/initializeEnvironment.cpp index 356b4c112f0..179f7ca4279 100644 --- a/src/coreComponents/common/initializeEnvironment.cpp +++ b/src/coreComponents/common/initializeEnvironment.cpp @@ -1,11 +1,12 @@ /* * ------------------------------------------------------------------------------------------------------------ - * SPDX-LiCense-Identifier: LGPL-2.1-only + * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,13 +18,20 @@ #include "TimingMacros.hpp" #include "Path.hpp" #include "LvArray/src/system.hpp" - +#include "common/format/table/TableFormatter.hpp" +#include "common/LifoStorageCommon.hpp" +#include "common/MemoryInfos.hpp" +#include // TPL includes #include +#include +#include +#include "umpire/util/MemoryResourceTraits.hpp" +#include "umpire/util/Platform.hpp" -#if defined( GEOSX_USE_CALIPER ) +#if defined( GEOS_USE_CALIPER ) #include -#if defined( GEOSX_USE_ADIAK ) +#if defined( GEOS_USE_ADIAK ) #include #endif #endif @@ -31,11 +39,11 @@ // System includes #include -#if defined( GEOSX_USE_MKL ) +#if defined( GEOS_USE_MKL ) #include #endif -#if defined( GEOSX_USE_OPENMP ) +#if defined( GEOS_USE_OPENMP ) #include #endif @@ -46,18 +54,16 @@ #if defined( GEOS_USE_HIP ) #include #endif - #include namespace geos { - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void setupLogger() { -#ifdef GEOSX_USE_MPI - logger::InitializeLogger( MPI_COMM_GEOSX ); +#ifdef GEOS_USE_MPI + logger::InitializeLogger( MPI_COMM_GEOS ); #else logger::InitializeLogger(); #endif @@ -74,7 +80,7 @@ void setupLvArray() { LvArray::system::setErrorHandler( []() { - #if defined( GEOSX_USE_MPI ) + #if defined( GEOS_USE_MPI ) int mpi = 0; MPI_Initialized( &mpi ); if( mpi ) @@ -87,17 +93,20 @@ void setupLvArray() LvArray::system::setSignalHandling( []( int const signal ) { LvArray::system::stackTraceHandler( signal, true ); } ); -#if defined(GEOSX_USE_FPE) +#if defined(GEOS_USE_FPE) LvArray::system::setFPE(); #else LvArray::system::disableFloatingPointExceptions( FE_ALL_EXCEPT ); #endif + + /* Disable chai callbacks by default */ + chai::ArrayManager::getInstance()->disableCallbacks(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void setupMKL() { -#ifdef GEOSX_USE_MKL +#ifdef GEOS_USE_MKL GEOS_LOG_RANK_0( "MKL max threads: " << mkl_get_max_threads() ); #endif } @@ -105,7 +114,7 @@ void setupMKL() /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void setupOpenMP() { -#ifdef GEOSX_USE_OPENMP +#ifdef GEOS_USE_OPENMP GEOS_LOG_RANK_0( "Max threads: " << omp_get_max_threads() ); #endif } @@ -118,23 +127,23 @@ void setupMPI( int argc, char * argv[] ) MpiWrapper::init( &argc, &argv ); } - MPI_COMM_GEOSX = MpiWrapper::commDup( MPI_COMM_WORLD ); + MPI_COMM_GEOS = MpiWrapper::commDup( MPI_COMM_WORLD ); - if( MpiWrapper::commRank( MPI_COMM_GEOSX ) == 0 ) + if( MpiWrapper::commRank( MPI_COMM_GEOS ) == 0 ) { // Can't use logging macros prior to logger init - std::cout << "Num ranks: " << MpiWrapper::commSize( MPI_COMM_GEOSX ) << std::endl; + std::cout << "Num ranks: " << MpiWrapper::commSize( MPI_COMM_GEOS ) << std::endl; } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void finalizeMPI() { - MpiWrapper::commFree( MPI_COMM_GEOSX ); + MpiWrapper::commFree( MPI_COMM_GEOS ); MpiWrapper::finalize(); } -#if defined( GEOSX_USE_CALIPER ) +#if defined( GEOS_USE_CALIPER ) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void setupCaliper( cali::ConfigManager & caliperManager, @@ -144,9 +153,9 @@ void setupCaliper( cali::ConfigManager & caliperManager, GEOS_ERROR_IF( caliperManager.error(), "Caliper config error: " << caliperManager.error_msg() ); caliperManager.start(); -#if defined( GEOSX_USE_ADIAK ) -#if defined( GEOSX_USE_MPI ) - adiak::init( &MPI_COMM_GEOSX ); +#if defined( GEOS_USE_ADIAK ) +#if defined( GEOS_USE_MPI ) + adiak::init( &MPI_COMM_GEOS ); #else adiak::init( nullptr ); #endif @@ -166,7 +175,7 @@ void setupCaliper( cali::ConfigManager & caliperManager, adiak::value( "Problem name", commandLineOptions.problemName ); // MPI info -#if defined( GEOSX_USE_MPI ) +#if defined( GEOS_USE_MPI ) adiak::value( "MPI", "On" ); adiak::value( "mpi ranks", MpiWrapper::commSize() ); #else @@ -189,11 +198,11 @@ void setupCaliper( cali::ConfigManager & caliperManager, adiak::value ( "compiler version", "unknown" ); #endif - adiak::value( "build type", GEOSX_CMAKE_BUILD_TYPE ); + adiak::value( "build type", GEOS_CMAKE_BUILD_TYPE ); adiak::value( "compilation date", __DATE__ ); // OpenMP info -#if defined( GEOSX_USE_OPENMP ) +#if defined( GEOS_USE_OPENMP ) std::int64_t const numThreads = omp_get_max_threads(); adiak::value( "OpenMP", "On" ); #else @@ -220,21 +229,21 @@ void setupCaliper( cali::ConfigManager & caliperManager, int hipDriverVersion = 0; #if defined( GESOX_USE_HIP ) adiak::value( "HIP", "On" ) - GEOSX_ERROR_IF_NE( hipSuccess, hipRuntimeGetVersion( &hipRuntimeVersion ) ); - GEOSX_ERROR_IF_NE( hipSuccess, hipDriverGetVersion( &hipDriverVersion ) ); + GEOS_ERROR_IF_NE( hipSuccess, hipRuntimeGetVersion( &hipRuntimeVersion ) ); + GEOS_ERROR_IF_NE( hipSuccess, hipDriverGetVersion( &hipDriverVersion ) ); #else adiak::value( "HIP", "Off" ); #endif adiak::value( "HIP runtime version", hipRuntimeVersion ); adiak::value( "HIP driver version", hipDriverVersion ); -#endif // defined( GEOSX_USE ADIAK ) +#endif // defined( GEOS_USE ADIAK ) } -#endif // defined( GEOSX_USE_CALIPER ) +#endif // defined( GEOS_USE_CALIPER ) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void finalizeCaliper() { -#if defined( GEOSX_USE_CALIPER )and defined( GEOSX_USE_ADIAK ) +#if defined( GEOS_USE_CALIPER )and defined( GEOS_USE_ADIAK ) adiak::fini(); #endif } @@ -248,7 +257,9 @@ void finalizeCaliper() static void addUmpireHighWaterMarks() { umpire::ResourceManager & rm = umpire::ResourceManager::getInstance(); - + integer size; + MPI_Comm_size( MPI_COMM_WORLD, &size ); + size_t nbRank = (std::size_t)size; // Get a list of all the allocators and sort it so that it's in the same order on each rank. std::vector< string > allocatorNames = rm.getAllocatorNames(); std::sort( allocatorNames.begin(), allocatorNames.end() ); @@ -264,9 +275,9 @@ static void addUmpireHighWaterMarks() } // Loop over the allocators. - constexpr int MAX_NAME_LENGTH = 100; - char allocatorNameBuffer[ MAX_NAME_LENGTH + 1 ]; - char allocatorNameMinCharsBuffer[ MAX_NAME_LENGTH + 1 ]; + unsigned MAX_NAME_LENGTH = 100; + + TableData tableData; for( string const & allocatorName : allocatorNames ) { // Skip umpire internal allocators. @@ -274,33 +285,74 @@ static void addUmpireHighWaterMarks() continue; GEOS_ERROR_IF_GT( allocatorName.size(), MAX_NAME_LENGTH ); + string allocatorNameFixedSize = allocatorName; + allocatorNameFixedSize.resize( MAX_NAME_LENGTH, '\0' ); + string allocatorNameMinChars = string( MAX_NAME_LENGTH, '\0' ); - memset( allocatorNameBuffer, '\0', sizeof( allocatorNameBuffer ) ); - memcpy( allocatorNameBuffer, allocatorName.data(), allocatorName.size() ); + // Make sure that each rank is looking at the same allocator. + MpiWrapper::allReduce( allocatorNameFixedSize.c_str(), &allocatorNameMinChars.front(), MAX_NAME_LENGTH, MPI_MIN, MPI_COMM_GEOS ); + if( allocatorNameFixedSize != allocatorNameMinChars ) + { + GEOS_WARNING( "Not all ranks have an allocator named " << allocatorNameFixedSize << ", cannot compute high water mark." ); + continue; + } - memset( allocatorNameMinCharsBuffer, '\0', sizeof( allocatorNameMinCharsBuffer ) ); + umpire::Allocator allocator = rm.getAllocator( allocatorName ); + umpire::strategy::AllocationStrategy const * allocationStrategy = allocator.getAllocationStrategy(); + umpire::MemoryResourceTraits const traits = allocationStrategy->getTraits(); + umpire::MemoryResourceTraits::resource_type resourceType = traits.resource; + MemoryInfos const memInfos( resourceType ); - // Make sure that each rank is looking at the same allocator. - MpiWrapper::allReduce( allocatorNameBuffer, allocatorNameMinCharsBuffer, MAX_NAME_LENGTH, MPI_MIN, MPI_COMM_GEOSX ); - if( strcmp( allocatorNameBuffer, allocatorNameMinCharsBuffer ) != 0 ) + if( !memInfos.isPhysicalMemoryHandled() ) { - GEOS_WARNING( "Not all ranks have an allocator named " << allocatorNameBuffer << ", cannot compute high water mark." ); continue; } // Get the total number of bytes allocated with this allocator across ranks. // This is a little redundant since - std::size_t const mark = rm.getAllocator( allocatorName ).getHighWatermark(); - std::size_t const totalMark = MpiWrapper::sum( mark ); + std::size_t const mark = allocator.getHighWatermark(); + std::size_t const minMark = MpiWrapper::min( mark ); std::size_t const maxMark = MpiWrapper::max( mark ); - GEOS_LOG_RANK_0( "Umpire " << std::setw( 15 ) << allocatorName << " sum across ranks: " << - std::setw( 9 ) << LvArray::system::calculateSize( totalMark ) ); - GEOS_LOG_RANK_0( "Umpire " << std::setw( 15 ) << allocatorName << " rank max: " << - std::setw( 9 ) << LvArray::system::calculateSize( maxMark ) ); + std::size_t const sumMark = MpiWrapper::sum( mark ); + + string percentage; + if( memInfos.getTotalMemory() == 0 ) + { + percentage = 0.0; + GEOS_WARNING( "umpire memory percentage could not be resolved" ); + } + else + { + percentage = GEOS_FMT( "({:.1f}%)", ( 100.0f * (float)mark ) / (float)memInfos.getTotalMemory() ); + } + + string const minMarkValue = GEOS_FMT( "{} {:>8}", + LvArray::system::calculateSize( minMark ), percentage ); + string const maxMarkValue = GEOS_FMT( "{} {:>8}", + LvArray::system::calculateSize( maxMark ), percentage ); + string const avgMarkValue = GEOS_FMT( "{} {:>8}", + LvArray::system::calculateSize( sumMark / nbRank ), percentage ); + string const sumMarkValue = GEOS_FMT( "{} {:>8}", + LvArray::system::calculateSize( sumMark ), percentage ); + + tableData.addRow( allocatorName, + minMarkValue, + maxMarkValue, + avgMarkValue, + sumMarkValue ); pushStatsIntoAdiak( allocatorName + " sum across ranks", mark ); pushStatsIntoAdiak( allocatorName + " rank max", mark ); } + + TableLayout const memoryStatLayout ( {"Umpire Memory Pool\n(reserved / % over total)", + "Min over ranks", + "Max over ranks", + "Avg over ranks", + "Sum over ranks" } ); + TableTextFormatter const memoryStatLog( memoryStatLayout ); + + GEOS_LOG_RANK_0( memoryStatLog.toString( tableData )); } @@ -324,5 +376,4 @@ void cleanupEnvironment() finalizeMPI(); } - } // namespace geos diff --git a/src/coreComponents/common/initializeEnvironment.hpp b/src/coreComponents/common/initializeEnvironment.hpp index 044b1977294..9cd72d023ad 100644 --- a/src/coreComponents/common/initializeEnvironment.hpp +++ b/src/coreComponents/common/initializeEnvironment.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,9 +21,9 @@ #include "MpiWrapper.hpp" // TPL includes -#ifdef GEOSX_USE_CALIPER +#ifdef GEOS_USE_CALIPER -#ifdef GEOSX_USE_ADIAK +#ifdef GEOS_USE_ADIAK #include #endif @@ -146,7 +147,7 @@ void setupEnvironment( int argc, char * argv[] ); */ void cleanupEnvironment(); -#if defined( GEOSX_USE_CALIPER ) +#if defined( GEOS_USE_CALIPER ) /** * @brief Setup Caliper and Adiak. @@ -169,7 +170,7 @@ void setupCaliper( cali::ConfigManager & caliperManager, template< typename T > void pushStatsIntoAdiak( string const & name, T const value ) { -#if defined( GEOSX_USE_CALIPER ) && defined( GEOSX_USE_ADIAK ) && !defined(__APPLE__) +#if defined( GEOS_USE_CALIPER ) && defined( GEOS_USE_ADIAK ) && !defined(__APPLE__) // Apple clang doesn't like adiak. T const total = MpiWrapper::sum( value ); adiak::value( name + " sum", total ); diff --git a/src/coreComponents/common/Logger.cpp b/src/coreComponents/common/logger/Logger.cpp similarity index 89% rename from src/coreComponents/common/Logger.cpp rename to src/coreComponents/common/logger/Logger.cpp index 8b5e410cdf4..0ea4c47a7cb 100644 --- a/src/coreComponents/common/Logger.cpp +++ b/src/coreComponents/common/logger/Logger.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,15 +19,15 @@ // Source includes #include "Logger.hpp" -#include "Path.hpp" -#include "codingUtilities/StringUtilities.hpp" +#include "common/Path.hpp" +#include "common/format/StringUtilities.hpp" namespace geos { /** * @brief Insert an exception message in another one. - * @param originalMsg original exception message (i.e. thrown from LVARRAY_THROW or GEOSX_THROW) + * @param originalMsg original exception message (i.e. thrown from LVARRAY_THROW or GEOS_THROW) * @param msgToInsert message to insert at the top of the originalMsg */ std::string insertExMsg( std::string const & originalMsg, std::string const & msgToInsert ) @@ -75,13 +76,13 @@ int n_ranks = 1; std::ostream * rankStream = nullptr; -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI MPI_Comm comm; #endif } // namespace internal -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI void InitializeLogger( MPI_Comm mpi_comm, const std::string & rankOutputDir ) { diff --git a/src/coreComponents/common/Logger.hpp b/src/coreComponents/common/logger/Logger.hpp similarity index 91% rename from src/coreComponents/common/Logger.hpp rename to src/coreComponents/common/logger/Logger.hpp index f07c5376bd6..0d0cf69c3bf 100644 --- a/src/coreComponents/common/Logger.hpp +++ b/src/coreComponents/common/logger/Logger.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -22,13 +23,13 @@ // Source incldes #include "common/GeosxConfig.hpp" #include "common/GeosxMacros.hpp" -#include "common/Format.hpp" +#include "common/format/Format.hpp" #include "LvArray/src/Macros.hpp" // System includes #include -#if defined(GEOSX_USE_MPI) +#if defined(GEOS_USE_MPI) #include #endif @@ -44,6 +45,25 @@ */ #define GEOS_LOG_VAR( ... ) LVARRAY_LOG_VAR( __VA_ARGS__ ) + +/** + * @brief Conditionally log a message. + * @param EXP an expression that will be evaluated as a predicate + * @param msg a message to log (any expression that can be stream inserted) + */ +#if defined(GEOS_DEVICE_COMPILE) +#define GEOS_LOG_IF( EXP, msg ) +#else +#define GEOS_LOG_IF( EXP, msg ) \ + do { \ + if( EXP ) \ + { \ + std::cout<< msg << std::endl; \ + } \ + } while( false ) +#endif + + /** * @brief Conditionally log a message on screen on rank 0. * @param EXP an expression that will be evaluated as a predicate @@ -59,6 +79,21 @@ } \ } while( false ) +/** + * @brief Conditionally log a message on screen on rank 0 without line breaking. + * @param EXP an expression that will be evaluated as a predicate + * @param msg a message to log (any expression that can be stream inserted) + */ +#define GEOS_LOG_RANK_0_IF_NLR( EXP, msg ) \ + do { \ + if( ::geos::logger::internal::rank == 0 && EXP ) \ + { \ + std::ostringstream oss; \ + oss << msg; \ + std::cout << oss.str(); \ + } \ + } while( false ) + /** * @brief Log a message on screen on rank 0. * @param msg a message to log (any expression that can be stream inserted) @@ -436,13 +471,15 @@ * @brief Output messages based on current Group's log level. * @param[in] minLevel minimum log level * @param[in] msg a message to log (any expression that can be stream inserted) + * @deprecated Will be replaced by GEOS_LOG_LEVEL_INFO */ -#define GEOS_LOG_LEVEL( minLevel, msg ) GEOS_INFO_IF( this->getLogLevel() >= minLevel, msg ); +#define GEOS_LOG_LEVEL( minLevel, msg ) GEOS_LOG_IF( this->getLogLevel() >= minLevel, msg ); /** * @brief Output messages (only on rank 0) based on current Group's log level. * @param[in] minLevel minimum log level * @param[in] msg a message to log (any expression that can be stream inserted) + * @deprecated Will be replaced by GEOS_LOG_LEVEL_INFO_RANK_0 */ #define GEOS_LOG_LEVEL_RANK_0( minLevel, msg ) GEOS_LOG_RANK_0_IF( this->getLogLevel() >= minLevel, msg ) @@ -450,6 +487,7 @@ * @brief Output messages (with one line per rank) based on current Group's log level. * @param[in] minLevel minimum log level * @param[in] msg a message to log (any expression that can be stream inserted) + * @deprecated Will be replaced by GEOS_LOG_LEVEL_INFO_BY_RANK */ #define GEOS_LOG_LEVEL_BY_RANK( minLevel, msg ) GEOS_LOG_RANK_IF( this->getLogLevel() >= minLevel, msg ) @@ -516,6 +554,23 @@ struct SimulationError : public std::runtime_error SimulationError( std::exception const & subException, std::string const & msgToInsert ); }; +/** + * @brief Exception class used to report errors from type conversion + * @todo (ErrorManager EPIC #2940) Consider adding a way to precise custom exception parameters, to add + * expected & encountered typeid for this one (in order to manage the exception output more precisely). + * We could also manage this by having: BadTypeErrorABC <|--- BadTypeError< T > /!\ compilation time + */ +struct BadTypeError : public std::runtime_error +{ + /** + * @brief Constructor + * @param what the error message + */ + BadTypeError( std::string const & what ): + std::runtime_error( what ) + {} +}; + /** * @brief Exception class used for special control flow. */ @@ -536,12 +591,12 @@ extern int n_ranks; extern std::ostream * rankStream; -#if defined(GEOSX_USE_MPI) +#if defined(GEOS_USE_MPI) extern MPI_Comm comm; #endif } // namespace internal -#if defined(GEOSX_USE_MPI) +#if defined(GEOS_USE_MPI) /** * @brief Initialize the logger in a parallel build. * @param comm global MPI communicator diff --git a/src/coreComponents/common/unitTests/CMakeLists.txt b/src/coreComponents/common/unitTests/CMakeLists.txt index 814fd512cec..1a1c94208d5 100644 --- a/src/coreComponents/common/unitTests/CMakeLists.txt +++ b/src/coreComponents/common/unitTests/CMakeLists.txt @@ -11,7 +11,7 @@ if ( ENABLE_CALIPER ) testCaliperSmoke.cpp ) endif() -set( dependencyList ${parallelDeps} common hdf5 gtest ) +set( dependencyList ${parallelDeps} common HDF5::HDF5 gtest ) # Add gtest C++ based tests foreach(test ${gtest_geosx_tests}) diff --git a/src/coreComponents/common/unitTests/testCaliperSmoke.cpp b/src/coreComponents/common/unitTests/testCaliperSmoke.cpp index b2e4e0685a6..7376aeb55c6 100644 --- a/src/coreComponents/common/unitTests/testCaliperSmoke.cpp +++ b/src/coreComponents/common/unitTests/testCaliperSmoke.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2022 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2022 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2022 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/common/unitTests/testDataTypes.cpp b/src/coreComponents/common/unitTests/testDataTypes.cpp index ba76eabbd0b..f83a3f13d5e 100644 --- a/src/coreComponents/common/unitTests/testDataTypes.cpp +++ b/src/coreComponents/common/unitTests/testDataTypes.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/common/unitTests/testFixedSizeDeque.cpp b/src/coreComponents/common/unitTests/testFixedSizeDeque.cpp index 605892b7b54..05293b3fc6c 100644 --- a/src/coreComponents/common/unitTests/testFixedSizeDeque.cpp +++ b/src/coreComponents/common/unitTests/testFixedSizeDeque.cpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #include "common/DataTypes.hpp" #include "common/FixedSizeDeque.hpp" #include "LvArray/src/Array.hpp" diff --git a/src/coreComponents/common/unitTests/testLifoStorage.cpp b/src/coreComponents/common/unitTests/testLifoStorage.cpp index b2dfced38ff..54c5a864bc3 100644 --- a/src/coreComponents/common/unitTests/testLifoStorage.cpp +++ b/src/coreComponents/common/unitTests/testLifoStorage.cpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #include "mainInterface/initialization.hpp" #define LIFO_DISABLE_CALIPER #include "common/LifoStorage.hpp" @@ -29,7 +44,7 @@ template< typename > struct RAJAHelper {}; -using serialPolicy = RAJA::loop_exec; +using serialPolicy = RAJA::seq_exec; template<> struct RAJAHelper< serialPolicy > @@ -58,8 +73,8 @@ struct RAJAHelper< parallelHostPolicy > template< unsigned long THREADS_PER_BLOCK > using devicePolicy = RAJA::cuda_exec< THREADS_PER_BLOCK >; -template< typename X, typename Y, size_t BLOCK_SIZE, bool ASYNC > -struct RAJAHelper< RAJA::policy::cuda::cuda_exec_explicit< X, Y, BLOCK_SIZE, ASYNC > > +template< typename X, typename Y, typename C, size_t BLOCK_SIZE, bool ASYNC > +struct RAJAHelper< RAJA::policy::cuda::cuda_exec_explicit< X, Y, C, BLOCK_SIZE, ASYNC > > { using ReducePolicy = RAJA::cuda_reduce; using AtomicPolicy = RAJA::cuda_atomic; @@ -105,7 +120,7 @@ void testLifoStorageBig( int elemCnt, int numberOfElementsOnDevice, int numberOf array.move( local::RAJAHelper< POLICY >::space ); LifoStorage< float, localIndex > lifo( "lifo", array, numberOfElementsOnDevice, numberOfElementsOnHost, totalNumberOfBuffers ); - for( int j = 0; j < 10; j++ ) + for( int j = 0; j < totalNumberOfBuffers; j++ ) { float * dataPointer = array.data(); @@ -113,7 +128,7 @@ void testLifoStorageBig( int elemCnt, int numberOfElementsOnDevice, int numberOf lifo.push( array ); } - for( int j = 0; j < 10; j++ ) + for( int j = 0; j < totalNumberOfBuffers; j++ ) { lifo.pop( array ); float * dataPointer = array.data(); @@ -153,23 +168,9 @@ void testLifoStorageAsync( int elemCnt, int numberOfElementsOnDevice, int number } -TEST( LifoStorageTest, LifoStorageBufferOnHost ) -{ - testLifoStorage< local::serialPolicy >( 10, 2, 3, 10 ); -} - -TEST( LifoStorageTest, LifoStorageBufferOnHostNoDeviceBuffer ) -{ - testLifoStorage< local::serialPolicy >( 10, 0, 3, 10 ); -} - -TEST( LifoStorageTest, LifoStorageAsyncBufferOnHost ) -{ - testLifoStorageAsync< local::serialPolicy >( 10, 2, 3, 10 ); -} - #ifdef GEOS_USE_CUDA +// running tests on GPUs TEST( LifoStorageTest, LifoStorageBufferOnCUDA ) { testLifoStorage< local::devicePolicy< 32 > >( 10, 2, 3, 10 ); @@ -177,34 +178,57 @@ TEST( LifoStorageTest, LifoStorageBufferOnCUDA ) TEST( LifoStorageTest, LifoStorageBufferOnCUDAlarge ) { - testLifoStorageBig< parallelDevicePolicy< > >( 1000000, 2, 3, 10000 ); + testLifoStorageBig< parallelDevicePolicy< > >( 1000000, 2, 3, 10 ); } TEST( LifoStorageTest, LifoStorageBufferOnCUDAlargeAutoSizeHost ) { - testLifoStorageBig< parallelDevicePolicy< > >( 1000000, 2, -80, 10000 ); + testLifoStorageBig< parallelDevicePolicy< > >( 1000000, 2, -80, 10 ); } TEST( LifoStorageTest, LifoStorageBufferOnCUDAlargeAutoSizeDevice ) { - testLifoStorageBig< parallelDevicePolicy< > >( 1000000, -80, 3, 10000 ); + testLifoStorageBig< parallelDevicePolicy< > >( 1000000, -80, 3, 10 ); } TEST( LifoStorageTest, LifoStorageBufferOnCUDAlargeAutoSizeBoth ) { - testLifoStorageBig< parallelDevicePolicy< > >( 1000000, -80, -80, 10000 ); + testLifoStorageBig< parallelDevicePolicy< > >( 1000000, -80, -80, 10 ); } +// The following test is disabled for now, as it produces a random assertion error +// that affects the current CI (see issue https://github.com/GEOS-DEV/GEOS/issues/3355). +// The error appears randomly on some configurations, and is probably related to the +// size-0 device buffer case that this test covers. This case should not be frequent +// in practise, but the issue should be resolved and the test reactivated as soon as +// a solution is found. +//TEST( LifoStorageTest, LifoStorageBufferOnCUDANoDeviceBuffer ) +//{ +// testLifoStorage< local::devicePolicy< 32 > >( 10, 0, 3, 10 ); +//} -TEST( LifoStorageTest, LifoStorageBufferOnCUDANoDeviceBuffer ) +TEST( LifoStorageTest, LifoStorageAsyncBufferOnCUDA ) { - testLifoStorage< local::devicePolicy< 32 > >( 10, 0, 3, 10 ); + testLifoStorageAsync< local::devicePolicy< 32 > >( 10, 2, 3, 10 ); } -TEST( LifoStorageTest, LifoStorageAsyncBufferOnCUDA ) +#else +// running tests on CPUs +TEST( LifoStorageTest, LifoStorageBufferOnHost ) { - testLifoStorageAsync< local::devicePolicy< 32 > >( 10, 2, 3, 10 ); + testLifoStorage< local::serialPolicy >( 10, 2, 3, 10 ); +} + +TEST( LifoStorageTest, LifoStorageBufferOnHostNoDeviceBuffer ) +{ + testLifoStorage< local::serialPolicy >( 10, 0, 3, 10 ); } + +TEST( LifoStorageTest, LifoStorageAsyncBufferOnHost ) +{ + testLifoStorageAsync< local::serialPolicy >( 10, 2, 3, 10 ); +} + #endif } diff --git a/src/coreComponents/common/unitTests/testTypeDispatch.cpp b/src/coreComponents/common/unitTests/testTypeDispatch.cpp index 837f09b7ce8..c252adb9fc5 100644 --- a/src/coreComponents/common/unitTests/testTypeDispatch.cpp +++ b/src/coreComponents/common/unitTests/testTypeDispatch.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/common/unitTests/testUnits.cpp b/src/coreComponents/common/unitTests/testUnits.cpp index 2ab6ef2cbc3..59651a53588 100644 --- a/src/coreComponents/common/unitTests/testUnits.cpp +++ b/src/coreComponents/common/unitTests/testUnits.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -112,6 +113,26 @@ TEST( Units, SystemDurationFormatTest ) "5500y, 20d, 12h02m25s (173565007345 s)", Years( 5500 ) + Days( 20 ) + hours( 12 ) + seconds( 145 ) ), + DurationCase( + "-(00h00m00s) (-1.11e-07 s)", + -nanoseconds( 111 ) ), + + DurationCase( + "-(00h00m01s) (-1 s)", + -seconds( 1 ) ), + + DurationCase( + "-(00h02m25s) (-145.016 s)", + -seconds( 145 ) - milliseconds( 16 ) ), + + DurationCase( + "-(22h25m45s) (-80745.016 s)", + -hours( 20 ) - minutes( 145 ) - seconds( 45 ) - milliseconds( 16 ) ), + + DurationCase( + "-(5500y, 20d, 12h02m25s) (-173565007345 s)", + -Years( 5500 ) - Days( 20 ) - hours( 12 ) - seconds( 145 ) ), + }; const SystemClock::duration maxDuration = SystemClock::duration::max(); @@ -127,7 +148,7 @@ TEST( Units, SystemDurationFormatTest ) EXPECT_STREQ( durationCase.m_expectedString.c_str(), TimeFormatInfo::fromSeconds( durationCase.m_simDuration ).toString().c_str() ) << errorInfo; - if( durationCase.m_simDuration <= maxSystemTime ) + if( 0.0 < durationCase.m_simDuration && durationCase.m_simDuration <= maxSystemTime ) { EXPECT_STREQ( durationCase.m_expectedString.c_str(), TimeFormatInfo::fromDuration( durationCase.m_systemDuration ).toString().c_str() ) << errorInfo; diff --git a/src/coreComponents/constitutive/CMakeLists.txt b/src/coreComponents/constitutive/CMakeLists.txt index 47e573b6f13..e7f798c3b5f 100644 --- a/src/coreComponents/constitutive/CMakeLists.txt +++ b/src/coreComponents/constitutive/CMakeLists.txt @@ -1,3 +1,22 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: constitutive + +Contains the implementation of constitutive models for fluid and rock properties. +#]] + # # Specify all headers # @@ -17,10 +36,15 @@ set( constitutive_headers capillaryPressure/VanGenuchtenCapillaryPressure.hpp capillaryPressure/capillaryPressureSelector.hpp capillaryPressure/layouts.hpp - contact/ContactBase.hpp - contact/CoulombContact.hpp - contact/ContactSelector.hpp + contact/BartonBandis.hpp + contact/CoulombFriction.hpp + contact/FrictionSelector.hpp + contact/FrictionBase.hpp contact/FrictionlessContact.hpp + contact/HydraulicApertureBase.hpp + contact/HydraulicApertureRelationSelector.hpp + contact/HydraulicApertureTable.hpp + contact/RateAndStateFriction.hpp diffusion/ConstantDiffusion.hpp diffusion/DiffusionBase.hpp diffusion/DiffusionFields.hpp @@ -28,47 +52,59 @@ set( constitutive_headers dispersion/DispersionBase.hpp dispersion/DispersionFields.hpp dispersion/DispersionSelector.hpp - dispersion/LinearIsotropicDispersion.hpp + dispersion/LinearIsotropicDispersion.hpp fluid/multifluid/Layouts.hpp fluid/multifluid/MultiFluidSelector.hpp fluid/multifluid/MultiFluidBase.hpp fluid/multifluid/MultiFluidConstants.hpp fluid/multifluid/MultiFluidUtils.hpp fluid/multifluid/MultiFluidFields.hpp - fluid/multifluid/PVTDriver.hpp - fluid/multifluid/PVTDriverRunTest.hpp fluid/multifluid/blackOil/BlackOilFluidBase.hpp fluid/multifluid/blackOil/BlackOilFluid.hpp fluid/multifluid/blackOil/DeadOilFluid.hpp fluid/multifluid/blackOil/PVTOData.hpp fluid/multifluid/CO2Brine/CO2BrineFluid.hpp fluid/multifluid/CO2Brine/PhaseModel.hpp - fluid/multifluid/CO2Brine/functions/PhillipsBrineDensity.hpp - fluid/multifluid/CO2Brine/functions/PhillipsBrineViscosity.hpp + fluid/multifluid/CO2Brine/functions/BrineEnthalpy.hpp + fluid/multifluid/CO2Brine/functions/CO2Enthalpy.hpp + fluid/multifluid/CO2Brine/functions/CO2EOSSolver.hpp + fluid/multifluid/CO2Brine/functions/CO2Solubility.hpp + fluid/multifluid/CO2Brine/functions/CO2SolubilityDuanSun.hpp + fluid/multifluid/CO2Brine/functions/CO2SolubilitySpycherPruess.hpp fluid/multifluid/CO2Brine/functions/EzrokhiBrineDensity.hpp fluid/multifluid/CO2Brine/functions/EzrokhiBrineViscosity.hpp - fluid/multifluid/CO2Brine/functions/CO2Solubility.hpp fluid/multifluid/CO2Brine/functions/FenghourCO2Viscosity.hpp fluid/multifluid/CO2Brine/functions/FlashModelBase.hpp - fluid/multifluid/CO2Brine/functions/PVTFunctionBase.hpp fluid/multifluid/CO2Brine/functions/NoOpPVTFunction.hpp + fluid/multifluid/CO2Brine/functions/PhillipsBrineDensity.hpp + fluid/multifluid/CO2Brine/functions/PhillipsBrineViscosity.hpp + fluid/multifluid/CO2Brine/functions/PureWaterProperties.hpp + fluid/multifluid/CO2Brine/functions/PVTFunctionBase.hpp fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.hpp fluid/multifluid/CO2Brine/functions/SpanWagnerCO2Density.hpp - fluid/multifluid/CO2Brine/functions/BrineEnthalpy.hpp - fluid/multifluid/CO2Brine/functions/CO2Enthalpy.hpp - fluid/multifluid/CO2Brine/functions/CO2EOSSolver.hpp - fluid/multifluid/CO2Brine/functions/PureWaterProperties.hpp fluid/multifluid/CO2Brine/functions/WaterDensity.hpp - fluid/multifluid/compositional/functions/CompositionalProperties.hpp - fluid/multifluid/compositional/functions/CubicEOSPhaseModel.hpp + fluid/multifluid/compositional/functions/CompositionalProperties.hpp + fluid/multifluid/compositional/functions/CompositionalPropertiesImpl.hpp + fluid/multifluid/compositional/functions/CubicEOSPhaseModel.hpp + fluid/multifluid/compositional/functions/FugacityCalculator.hpp fluid/multifluid/compositional/functions/KValueInitialization.hpp fluid/multifluid/compositional/functions/NegativeTwoPhaseFlash.hpp fluid/multifluid/compositional/functions/RachfordRice.hpp + fluid/multifluid/compositional/functions/StabilityTest.hpp fluid/multifluid/compositional/models/ComponentProperties.hpp fluid/multifluid/compositional/models/CompositionalDensity.hpp fluid/multifluid/compositional/models/ConstantViscosity.hpp + fluid/multifluid/compositional/models/CriticalVolume.hpp + fluid/multifluid/compositional/models/EquationOfState.hpp fluid/multifluid/compositional/models/FunctionBase.hpp + fluid/multifluid/compositional/models/ImmiscibleWaterDensity.hpp + fluid/multifluid/compositional/models/ImmiscibleWaterFlashModel.hpp + fluid/multifluid/compositional/models/ImmiscibleWaterParameters.hpp + fluid/multifluid/compositional/models/ImmiscibleWaterViscosity.hpp + fluid/multifluid/compositional/models/LohrenzBrayClarkViscosity.hpp + fluid/multifluid/compositional/models/LohrenzBrayClarkViscosityImpl.hpp fluid/multifluid/compositional/models/NegativeTwoPhaseFlashModel.hpp + fluid/multifluid/compositional/models/ModelParameters.hpp fluid/multifluid/compositional/models/NullModel.hpp fluid/multifluid/compositional/models/PhaseModel.hpp fluid/multifluid/compositional/CompositionalMultiphaseFluid.hpp @@ -76,8 +112,6 @@ set( constitutive_headers fluid/multifluid/reactive/ReactiveBrineFluid.hpp fluid/multifluid/reactive/ReactiveMultiFluid.hpp fluid/multifluid/reactive/ReactiveMultiFluidFields.hpp - fluid/multifluid/reactive/ReactiveFluidDriver.hpp - fluid/multifluid/reactive/ReactiveFluidSelector.hpp fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.hpp fluid/multifluid/reactive/chemicalReactions/KineticReactions.hpp fluid/multifluid/reactive/chemicalReactions/ReactionsBase.hpp @@ -99,11 +133,10 @@ set( constitutive_headers permeability/ParallelPlatesPermeability.hpp permeability/PermeabilityBase.hpp permeability/PermeabilityFields.hpp + permeability/PressurePermeability.hpp permeability/ProppantPermeability.hpp permeability/SlipDependentPermeability.hpp permeability/WillisRichardsPermeability.hpp - relativePermeability/RelpermDriver.hpp - relativePermeability/RelpermDriverRunTest.hpp relativePermeability/BrooksCoreyBakerRelativePermeability.hpp relativePermeability/BrooksCoreyStone2RelativePermeability.hpp relativePermeability/BrooksCoreyRelativePermeability.hpp @@ -135,7 +168,7 @@ set( constitutive_headers solid/ElasticTransverseIsotropic.hpp solid/ElasticOrthotropic.hpp solid/InvariantDecompositions.hpp - solid/PerfectlyPlastic.hpp + solid/PerfectlyPlastic.hpp solid/PorousSolid.hpp solid/PropertyConversions.hpp solid/SolidBase.hpp @@ -147,7 +180,6 @@ set( constitutive_headers solid/SolidModelDiscretizationOpsTransverseIsotropic.hpp solid/SolidModelDiscretizationOpsOrthotropic.hpp solid/CeramicDamage.hpp - solid/TriaxialDriver.hpp solid/porosity/PorosityFields.hpp solid/porosity/BiotPorosity.hpp solid/porosity/PorosityBase.hpp @@ -159,9 +191,8 @@ set( constitutive_headers thermalConductivity/MultiPhaseThermalConductivityFields.hpp thermalConductivity/MultiPhaseThermalConductivitySelector.hpp thermalConductivity/MultiPhaseVolumeWeightedThermalConductivity.hpp - thermalConductivity/SinglePhaseConstantThermalConductivity.hpp + thermalConductivity/SinglePhaseThermalConductivity.hpp thermalConductivity/SinglePhaseThermalConductivityBase.hpp - thermalConductivity/SinglePhaseThermalConductivityFields.hpp thermalConductivity/SinglePhaseThermalConductivitySelector.hpp thermalConductivity/ThermalConductivityFields.hpp ) @@ -178,30 +209,30 @@ set( constitutive_sources capillaryPressure/TableCapillaryPressure.cpp capillaryPressure/TableCapillaryPressureHelpers.cpp capillaryPressure/VanGenuchtenCapillaryPressure.cpp - contact/ContactBase.cpp - contact/CoulombContact.cpp + contact/BartonBandis.cpp + contact/CoulombFriction.cpp + contact/FrictionBase.cpp contact/FrictionlessContact.cpp + contact/HydraulicApertureBase.cpp + contact/HydraulicApertureTable.cpp + contact/RateAndStateFriction.cpp diffusion/ConstantDiffusion.cpp diffusion/DiffusionBase.cpp dispersion/DispersionBase.cpp dispersion/LinearIsotropicDispersion.cpp fluid/multifluid/MultiFluidBase.cpp - fluid/multifluid/PVTDriver.cpp fluid/multifluid/blackOil/BlackOilFluidBase.cpp fluid/multifluid/blackOil/BlackOilFluid.cpp fluid/multifluid/blackOil/DeadOilFluid.cpp - fluid/multifluid/blackOil/PVTDriverRunTestDeadOilFluid.cpp fluid/multifluid/blackOil/PVTOData.cpp fluid/multifluid/CO2Brine/CO2BrineFluid.cpp - fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsFluid.cpp - fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsThermalFluid.cpp - fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiFluid.cpp - fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiThermalFluid.cpp fluid/multifluid/CO2Brine/functions/PhillipsBrineDensity.cpp fluid/multifluid/CO2Brine/functions/PhillipsBrineViscosity.cpp fluid/multifluid/CO2Brine/functions/EzrokhiBrineDensity.cpp fluid/multifluid/CO2Brine/functions/EzrokhiBrineViscosity.cpp fluid/multifluid/CO2Brine/functions/CO2Solubility.cpp + fluid/multifluid/CO2Brine/functions/CO2SolubilityDuanSun.cpp + fluid/multifluid/CO2Brine/functions/CO2SolubilitySpycherPruess.cpp fluid/multifluid/CO2Brine/functions/FenghourCO2Viscosity.cpp fluid/multifluid/CO2Brine/functions/SpanWagnerCO2Density.cpp fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.cpp @@ -210,16 +241,19 @@ set( constitutive_sources fluid/multifluid/CO2Brine/functions/CO2EOSSolver.cpp fluid/multifluid/CO2Brine/functions/PureWaterProperties.cpp fluid/multifluid/CO2Brine/functions/WaterDensity.cpp - fluid/multifluid/compositional/functions/CompositionalProperties.cpp fluid/multifluid/compositional/models/CompositionalDensity.cpp fluid/multifluid/compositional/models/ConstantViscosity.cpp + fluid/multifluid/compositional/models/CriticalVolume.cpp + fluid/multifluid/compositional/models/ImmiscibleWaterDensity.cpp + fluid/multifluid/compositional/models/ImmiscibleWaterFlashModel.cpp + fluid/multifluid/compositional/models/ImmiscibleWaterParameters.cpp + fluid/multifluid/compositional/models/ImmiscibleWaterViscosity.cpp + fluid/multifluid/compositional/models/LohrenzBrayClarkViscosity.cpp fluid/multifluid/compositional/models/NegativeTwoPhaseFlashModel.cpp fluid/multifluid/compositional/CompositionalMultiphaseFluid.cpp fluid/multifluid/compositional/CompositionalMultiphaseFluidUpdates.cpp - fluid/multifluid/compositional/PVTDriverRunTestCompositionalMultiphaseFluid.cpp fluid/multifluid/reactive/ReactiveBrineFluid.cpp fluid/multifluid/reactive/ReactiveMultiFluid.cpp - fluid/multifluid/reactive/ReactiveFluidDriver.cpp fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.cpp fluid/multifluid/reactive/chemicalReactions/KineticReactions.cpp fluid/multifluid/reactive/chemicalReactions/ReactionsBase.cpp @@ -235,6 +269,7 @@ set( constitutive_sources permeability/ExponentialDecayPermeability.cpp permeability/ParallelPlatesPermeability.cpp permeability/PermeabilityBase.cpp + permeability/PressurePermeability.cpp permeability/ProppantPermeability.cpp permeability/SlipDependentPermeability.cpp permeability/WillisRichardsPermeability.cpp @@ -247,14 +282,6 @@ set( constitutive_sources relativePermeability/TableRelativePermeabilityHysteresis.cpp relativePermeability/VanGenuchtenBakerRelativePermeability.cpp relativePermeability/VanGenuchtenStone2RelativePermeability.cpp - relativePermeability/RelpermDriver.cpp - relativePermeability/RelpermDriverBrooksCoreyBakerRunTest.cpp - relativePermeability/RelpermDriverBrooksCoreyStone2RunTest.cpp - relativePermeability/RelpermDriverBrooksCoreyRunTest.cpp - relativePermeability/RelpermDriverVanGenuchtenBakerRunTest.cpp - relativePermeability/RelpermDriverVanGenuchtenStone2RunTest.cpp - relativePermeability/RelpermDriverTableRelativeRunTest.cpp - relativePermeability/RelpermDriverTableRelativeHysteresisRunTest.cpp solid/CompressibleSolid.cpp solid/CoupledSolidBase.cpp solid/ProppantSolid.cpp @@ -275,7 +302,6 @@ set( constitutive_sources solid/SolidBase.cpp solid/SolidInternalEnergy.cpp solid/CeramicDamage.cpp - solid/TriaxialDriver.cpp solid/porosity/BiotPorosity.cpp solid/porosity/PorosityBase.cpp solid/porosity/PressurePorosity.cpp @@ -283,11 +309,11 @@ set( constitutive_sources thermalConductivity/MultiPhaseConstantThermalConductivity.cpp thermalConductivity/MultiPhaseThermalConductivityBase.cpp thermalConductivity/MultiPhaseVolumeWeightedThermalConductivity.cpp - thermalConductivity/SinglePhaseConstantThermalConductivity.cpp + thermalConductivity/SinglePhaseThermalConductivity.cpp thermalConductivity/SinglePhaseThermalConductivityBase.cpp ) -set( dependencyList ${parallelDeps} events dataRepository functions denseLinearAlgebra ) +set( dependencyList ${parallelDeps} functions denseLinearAlgebra ) if( ENABLE_PVTPackage ) set( constitutive_headers @@ -296,22 +322,29 @@ if( ENABLE_PVTPackage ) set( constitutive_sources ${constitutive_sources} - fluid/multifluid/compositional/CompositionalMultiphaseFluidPVTPackage.cpp ) + fluid/multifluid/compositional/CompositionalMultiphaseFluidPVTPackage.cpp + ) add_subdirectory( PVTPackage ) list( APPEND dependencyList PVTPackage ) endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) + blt_add_library( NAME constitutive SOURCES ${constitutive_sources} HEADERS ${constitutive_headers} - DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} + DEPENDS_ON ${decoratedDependencies} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} ) target_include_directories( constitutive PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +install( TARGETS constitutive LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) + if( GEOS_ENABLE_TESTS ) add_subdirectory( unitTests ) endif( ) diff --git a/src/coreComponents/constitutive/ConstitutiveBase.cpp b/src/coreComponents/constitutive/ConstitutiveBase.cpp index e55cb851a69..03bf6852ecc 100644 --- a/src/coreComponents/constitutive/ConstitutiveBase.cpp +++ b/src/coreComponents/constitutive/ConstitutiveBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -29,7 +30,8 @@ namespace constitutive ConstitutiveBase::ConstitutiveBase( string const & name, Group * const parent ): Group( name, parent ), - m_numQuadraturePoints( 1 ) + m_numQuadraturePoints( 1 ), + m_isClone( false ) { setInputFlags( InputFlags::OPTIONAL_NONUNIQUE ); } @@ -71,6 +73,11 @@ void ConstitutiveBase::allocateConstitutiveData( dataRepository::Group & parent, this->resize( parent.size() ); } +void ConstitutiveBase::setIsClone( bool const newState ) +{ + m_isClone = newState; +} + std::unique_ptr< ConstitutiveBase > ConstitutiveBase::deliverClone( string const & name, Group * const parent ) const @@ -83,6 +90,8 @@ ConstitutiveBase::deliverClone( string const & name, wrapper.copyWrapper( this->getWrapperBase( wrapper.getName() ) ); } ); + newModel->setIsClone( true ); + return newModel; } diff --git a/src/coreComponents/constitutive/ConstitutiveBase.hpp b/src/coreComponents/constitutive/ConstitutiveBase.hpp index b0f9adbf148..12fa1449142 100644 --- a/src/coreComponents/constitutive/ConstitutiveBase.hpp +++ b/src/coreComponents/constitutive/ConstitutiveBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -112,6 +113,11 @@ class ConstitutiveBase : public dataRepository::Group localIndex numQuadraturePoints() const { return m_numQuadraturePoints; } + /** + * @return true if the instance has been produced with deliverClone() + */ + bool isClone() const { return m_isClone; } + virtual std::vector< string > getSubRelationNames() const { return {}; } /** @@ -161,7 +167,16 @@ class ConstitutiveBase : public dataRepository::Group private: + /** + * @brief Set a isClone state boolean + * @param newState The state of the new constitutive model + */ + void setIsClone( bool const newState ); + localIndex m_numQuadraturePoints; + + /// Indicate if this constitutive model a clone + bool m_isClone; }; } diff --git a/src/coreComponents/constitutive/ConstitutiveManager.cpp b/src/coreComponents/constitutive/ConstitutiveManager.cpp index f1e587822ab..3babd88203e 100644 --- a/src/coreComponents/constitutive/ConstitutiveManager.cpp +++ b/src/coreComponents/constitutive/ConstitutiveManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -42,6 +43,7 @@ ConstitutiveManager::~ConstitutiveManager() Group * ConstitutiveManager::createChild( string const & childKey, string const & childName ) { + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) ); std::unique_ptr< ConstitutiveBase > material = ConstitutiveBase::CatalogInterface::factory( childKey, childName, this ); return ®isterGroup< ConstitutiveBase >( childName, std::move( material ) ); } diff --git a/src/coreComponents/constitutive/ConstitutiveManager.hpp b/src/coreComponents/constitutive/ConstitutiveManager.hpp index 85c5da0f143..1ef7f194314 100644 --- a/src/coreComponents/constitutive/ConstitutiveManager.hpp +++ b/src/coreComponents/constitutive/ConstitutiveManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/ConstitutivePassThru.hpp b/src/coreComponents/constitutive/ConstitutivePassThru.hpp index 0f97f509309..ec72812cdb1 100644 --- a/src/coreComponents/constitutive/ConstitutivePassThru.hpp +++ b/src/coreComponents/constitutive/ConstitutivePassThru.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -44,9 +45,12 @@ #include "permeability/CarmanKozenyPermeability.hpp" #include "permeability/ExponentialDecayPermeability.hpp" #include "permeability/ParallelPlatesPermeability.hpp" +#include "permeability/PressurePermeability.hpp" #include "permeability/ProppantPermeability.hpp" #include "permeability/SlipDependentPermeability.hpp" #include "permeability/WillisRichardsPermeability.hpp" +#include "contact/CoulombFriction.hpp" +#include "contact/RateAndStateFriction.hpp" namespace geos @@ -81,6 +85,37 @@ struct ConstitutivePassThru< ElasticIsotropic > } }; +/** + * Specialization for models that derive from FrictionBase. + */ +template<> +struct ConstitutivePassThru< FrictionBase > +{ + template< typename LAMBDA > + static + void execute( ConstitutiveBase & constitutiveRelation, LAMBDA && lambda ) + { + ConstitutivePassThruHandler< CoulombFriction, + RateAndStateFriction >::execute( constitutiveRelation, + std::forward< LAMBDA >( lambda ) ); + } +}; + + +/** + * Specialization for models that derive from CoulombFriction. + */ +template<> +struct ConstitutivePassThru< CoulombFriction > +{ + template< typename LAMBDA > + static + void execute( ConstitutiveBase & constitutiveRelation, LAMBDA && lambda ) + { + ConstitutivePassThruHandler< CoulombFriction >::execute( constitutiveRelation, + std::forward< LAMBDA >( lambda ) ); + } +}; /** * Specialization for models that derive from SolidBase. @@ -296,6 +331,7 @@ struct ConstitutivePassThru< CompressibleSolidBase > CompressibleSolid< PressurePorosity, CarmanKozenyPermeability >, CompressibleSolid< PressurePorosity, ExponentialDecayPermeability >, CompressibleSolid< PressurePorosity, ParallelPlatesPermeability >, + CompressibleSolid< PressurePorosity, PressurePermeability >, CompressibleSolid< PressurePorosity, SlipDependentPermeability >, CompressibleSolid< PressurePorosity, WillisRichardsPermeability > >::execute( constitutiveRelation, @@ -309,6 +345,7 @@ struct ConstitutivePassThru< CompressibleSolidBase > CompressibleSolid< PressurePorosity, CarmanKozenyPermeability >, CompressibleSolid< PressurePorosity, ExponentialDecayPermeability >, CompressibleSolid< PressurePorosity, ParallelPlatesPermeability >, + CompressibleSolid< PressurePorosity, PressurePermeability >, CompressibleSolid< PressurePorosity, SlipDependentPermeability >, CompressibleSolid< PressurePorosity, WillisRichardsPermeability > >::execute( constitutiveRelation, @@ -353,6 +390,7 @@ struct ConstitutivePassThru< CoupledSolidBase > CompressibleSolid< PressurePorosity, CarmanKozenyPermeability >, CompressibleSolid< PressurePorosity, ExponentialDecayPermeability >, CompressibleSolid< PressurePorosity, ParallelPlatesPermeability >, + CompressibleSolid< PressurePorosity, PressurePermeability >, CompressibleSolid< PressurePorosity, SlipDependentPermeability >, CompressibleSolid< PressurePorosity, WillisRichardsPermeability >, PorousSolid< DruckerPragerExtended >, @@ -379,6 +417,7 @@ struct ConstitutivePassThru< CoupledSolidBase > CompressibleSolid< PressurePorosity, CarmanKozenyPermeability >, CompressibleSolid< PressurePorosity, ExponentialDecayPermeability >, CompressibleSolid< PressurePorosity, ParallelPlatesPermeability >, + CompressibleSolid< PressurePorosity, PressurePermeability >, CompressibleSolid< PressurePorosity, SlipDependentPermeability >, CompressibleSolid< PressurePorosity, WillisRichardsPermeability >, PorousSolid< DruckerPragerExtended >, diff --git a/src/coreComponents/constitutive/ConstitutivePassThruHandler.hpp b/src/coreComponents/constitutive/ConstitutivePassThruHandler.hpp index 14013dd6ddb..1597cc65cc4 100644 --- a/src/coreComponents/constitutive/ConstitutivePassThruHandler.hpp +++ b/src/coreComponents/constitutive/ConstitutivePassThruHandler.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,6 +20,7 @@ #define GEOS_CONSTITUTIVEPASSTHRUHANDLER_HPP #include "codingUtilities/traits.hpp" +#include "codingUtilities/RTTypes.hpp" #include "common/DataTypes.hpp" namespace geos diff --git a/src/coreComponents/constitutive/ExponentialRelation.hpp b/src/coreComponents/constitutive/ExponentialRelation.hpp index 398ba112b56..2982b0b8e5f 100644 --- a/src/coreComponents/constitutive/ExponentialRelation.hpp +++ b/src/coreComponents/constitutive/ExponentialRelation.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #define GEOS_CONSITUTIVE_EXPONENTIALRELATION_HPP_ #include "common/DataTypes.hpp" -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include diff --git a/src/coreComponents/constitutive/NullModel.cpp b/src/coreComponents/constitutive/NullModel.cpp index 139715f74e3..9676802af3d 100644 --- a/src/coreComponents/constitutive/NullModel.cpp +++ b/src/coreComponents/constitutive/NullModel.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/NullModel.hpp b/src/coreComponents/constitutive/NullModel.hpp index 962232e00ab..ceddf84a4ac 100644 --- a/src/coreComponents/constitutive/NullModel.hpp +++ b/src/coreComponents/constitutive/NullModel.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/PVTPackage b/src/coreComponents/constitutive/PVTPackage index a92dd22bf4e..374b72962f7 160000 --- a/src/coreComponents/constitutive/PVTPackage +++ b/src/coreComponents/constitutive/PVTPackage @@ -1 +1 @@ -Subproject commit a92dd22bf4e2ddd16d3253613ca40a8fb769827a +Subproject commit 374b72962f7e605e74a1943c541e94d7b3f492a3 diff --git a/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.cpp b/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.cpp index 10518b167d8..16315425bee 100644 --- a/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.cpp +++ b/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -56,9 +57,9 @@ BrooksCoreyCapillaryPressure::BrooksCoreyCapillaryPressure( string const & name, setDescription( "Factor used to scale the phase capillary pressure, defined as: one minus the sum of the phase minimum volume fractions." ); } -void BrooksCoreyCapillaryPressure::postProcessInput() +void BrooksCoreyCapillaryPressure::postInputInitialization() { - CapillaryPressureBase::postProcessInput(); + CapillaryPressureBase::postInputInitialization(); auto const checkInputSize = [&]( auto const & array, auto const & attribute ) { diff --git a/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.hpp b/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.hpp index 2f00ed8d076..c020174dd21 100644 --- a/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.hpp +++ b/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -118,7 +119,7 @@ class BrooksCoreyCapillaryPressure : public CapillaryPressureBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; array1d< real64 > m_phaseMinVolumeFraction; array1d< real64 > m_phaseCapPressureExponentInv; diff --git a/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.cpp b/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.cpp index 22e71e4b4b5..97eb0127978 100644 --- a/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.cpp +++ b/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -48,9 +49,9 @@ CapillaryPressureBase::CapillaryPressureBase( string const & name, } -void CapillaryPressureBase::postProcessInput() +void CapillaryPressureBase::postInputInitialization() { - ConstitutiveBase::postProcessInput(); + ConstitutiveBase::postInputInitialization(); integer const numPhases = numFluidPhases(); GEOS_THROW_IF_LT_MSG( numPhases, 2, diff --git a/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.hpp b/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.hpp index 00c980b3de1..a4c11561d83 100644 --- a/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.hpp +++ b/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -176,7 +177,7 @@ class CapillaryPressureBase : public ConstitutiveBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; // phase names read from input string_array m_phaseNames; diff --git a/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureFields.hpp b/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureFields.hpp index ef5f41b4299..db38eb3fdc1 100644 --- a/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureFields.hpp +++ b/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.cpp b/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.cpp index b0eba72f703..908c42604b4 100644 --- a/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.cpp +++ b/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -120,9 +121,9 @@ JFunctionCapillaryPressure::JFunctionCapillaryPressure( std::string const & name setRestartFlags( RestartFlags::NO_WRITE ); } -void JFunctionCapillaryPressure::postProcessInput() +void JFunctionCapillaryPressure::postInputInitialization() { - CapillaryPressureBase::postProcessInput(); + CapillaryPressureBase::postInputInitialization(); integer const numPhases = m_phaseNames.size(); GEOS_THROW_IF( numPhases != 2 && numPhases != 3, @@ -249,6 +250,7 @@ void JFunctionCapillaryPressure::saveConvergedRockState( arrayView2d< real64 con { permeability = convergedPermeability[ei][0][2]; } + GEOS_ERROR_IF( permeability < LvArray::NumericLimits< real64 >::epsilon, "Zero permeability in J-function capillary pressure" ); // here we compute an average of the porosity over quadrature points // this average is exact for tets, regular pyramids/wedges/hexes, or for VEM diff --git a/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.hpp b/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.hpp index a72a9cf4348..55f099e24fa 100644 --- a/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.hpp +++ b/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,7 +22,7 @@ #include "constitutive/capillaryPressure/CapillaryPressureBase.hpp" -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include "functions/TableFunction.hpp" namespace geos @@ -128,7 +129,7 @@ class JFunctionCapillaryPressure : public CapillaryPressureBase private: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void initializePreSubGroups() override; diff --git a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.cpp b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.cpp index 878ba48e23e..2304238b540 100644 --- a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.cpp +++ b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -67,9 +68,9 @@ TableCapillaryPressure::TableCapillaryPressure( std::string const & name, setRestartFlags( RestartFlags::NO_WRITE ); } -void TableCapillaryPressure::postProcessInput() +void TableCapillaryPressure::postInputInitialization() { - CapillaryPressureBase::postProcessInput(); + CapillaryPressureBase::postInputInitialization(); integer const numPhases = m_phaseNames.size(); GEOS_THROW_IF( numPhases != 2 && numPhases != 3, diff --git a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.hpp b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.hpp index 53eeba07732..739b9993083 100644 --- a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.hpp +++ b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -95,7 +96,7 @@ class TableCapillaryPressure : public CapillaryPressureBase private: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void initializePreSubGroups() override; diff --git a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.cpp b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.cpp index 2f8cbbada24..6e4da85ccba 100644 --- a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.cpp +++ b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.hpp b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.hpp index aeae952cb4f..9e3504b1a8a 100644 --- a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.hpp +++ b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.cpp b/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.cpp index 9aa6213f0ec..31a965992ad 100644 --- a/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.cpp +++ b/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -59,9 +60,9 @@ VanGenuchtenCapillaryPressure::VanGenuchtenCapillaryPressure( string const & nam } -void VanGenuchtenCapillaryPressure::postProcessInput() +void VanGenuchtenCapillaryPressure::postInputInitialization() { - CapillaryPressureBase::postProcessInput(); + CapillaryPressureBase::postInputInitialization(); localIndex const NP = numFluidPhases(); diff --git a/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.hpp b/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.hpp index 9f22ee55f80..14944dd980b 100644 --- a/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.hpp +++ b/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -117,7 +118,7 @@ class VanGenuchtenCapillaryPressure : public CapillaryPressureBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; array1d< real64 > m_phaseMinVolumeFraction; array1d< real64 > m_phaseCapPressureExponentInv; diff --git a/src/coreComponents/constitutive/capillaryPressure/capillaryPressureSelector.hpp b/src/coreComponents/constitutive/capillaryPressure/capillaryPressureSelector.hpp index a38ef270c1c..b164f55aa16 100644 --- a/src/coreComponents/constitutive/capillaryPressure/capillaryPressureSelector.hpp +++ b/src/coreComponents/constitutive/capillaryPressure/capillaryPressureSelector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/capillaryPressure/layouts.hpp b/src/coreComponents/constitutive/capillaryPressure/layouts.hpp index 7459fcdc23f..d4903b67c31 100644 --- a/src/coreComponents/constitutive/capillaryPressure/layouts.hpp +++ b/src/coreComponents/constitutive/capillaryPressure/layouts.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/contact/BartonBandis.cpp b/src/coreComponents/constitutive/contact/BartonBandis.cpp new file mode 100644 index 00000000000..f478c015b28 --- /dev/null +++ b/src/coreComponents/constitutive/contact/BartonBandis.cpp @@ -0,0 +1,51 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file BartonBandis.cpp + */ + + +#include "BartonBandis.hpp" + + +namespace geos +{ + +namespace constitutive +{ + +using namespace dataRepository; + +BartonBandis::BartonBandis( string const & name, Group * const parent ): + HydraulicApertureBase( name, parent ), + m_referenceNormalStress( 0.0 ) +{ + registerWrapper( viewKeyStruct::referenceNormalStressString(), &m_referenceNormalStress ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( " Reference normal stress." ); +} + +BartonBandis::~BartonBandis() +{} + +BartonBandisUpdates BartonBandis::createKernelWrapper() const +{ + return KernelWrapper( m_aperture0, m_referenceNormalStress ); +} + +} /* namespace constitutive */ + +} /* namespace geos */ diff --git a/src/coreComponents/constitutive/contact/BartonBandis.hpp b/src/coreComponents/constitutive/contact/BartonBandis.hpp new file mode 100644 index 00000000000..64f9281924b --- /dev/null +++ b/src/coreComponents/constitutive/contact/BartonBandis.hpp @@ -0,0 +1,144 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file BartonBandis.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_CONTACT_BARTONBANDIS_HPP_ +#define GEOS_CONSTITUTIVE_CONTACT_BARTONBANDIS_HPP_ + +#include "constitutive/contact/HydraulicApertureBase.hpp" +#include "functions/TableFunction.hpp" + +namespace geos +{ + +namespace constitutive +{ + +/** + * @class BartonBandisUpdates + * + * This class is used for in-kernel contact relation updates + */ +class BartonBandisUpdates +{ +public: + + BartonBandisUpdates( real64 const aperture0, + real64 const referenceNormalStress ) + : m_aperture0( aperture0 ), + m_referenceNormalStress( referenceNormalStress ) + {} + + /// Default copy constructor + BartonBandisUpdates( BartonBandisUpdates const & ) = default; + + /// Default move constructor + BartonBandisUpdates( BartonBandisUpdates && ) = default; + + /// Deleted default constructor + BartonBandisUpdates() = default; + + /// Deleted copy assignment operator + BartonBandisUpdates & operator=( BartonBandisUpdates const & ) = delete; + + /// Deleted move assignment operator + BartonBandisUpdates & operator=( BartonBandisUpdates && ) = delete; + + /** + * @brief Evaluate the effective aperture, and its derivative wrt aperture + * @param[in] aperture the model aperture/gap + * @param[out] dHydraulicAperture_dAperture the derivative of the effective aperture wrt aperture + * @return The hydraulic aperture that is always > 0 + */ + GEOS_HOST_DEVICE + real64 computeHydraulicAperture( real64 const aperture, + real64 const normalTraction, + real64 & dHydraulicAperture_aperture, + real64 & dHydraulicAperture_dNormalStress ) const; + +private: + real64 m_aperture0; + + real64 m_referenceNormalStress; +}; + + +/** + * @class BartonBandis + * + * This class serves as the interface for implementing contact enforcement constitutive relations. + * This does not include the actual enforcement algorithm, but only the constitutive relations that + * govern the behavior of the contact. So things like penalty, or friction, or kinematic constraint. + */ +class BartonBandis : public HydraulicApertureBase +{ +public: + + /** + * @brief The standard data repository constructor + * @param name The name of the relation in the data repository + * @param parent The name of the parent Group that holds this relation object. + */ + BartonBandis( string const & name, + Group * const parent ); + + /** + * @brief default destructor + */ + virtual ~BartonBandis() override; + + + /// Type of kernel wrapper for in-kernel update + using KernelWrapper = BartonBandisUpdates; + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelWrapper() const; + +private: + + struct viewKeyStruct : public HydraulicApertureBase::viewKeyStruct + { + /// string/key for reference normal stress + static constexpr char const * referenceNormalStressString() { return "referenceNormalStress"; } + }; + /// Reference normal stress + real64 m_referenceNormalStress; +}; + +GEOS_HOST_DEVICE +GEOS_FORCE_INLINE +real64 BartonBandisUpdates::computeHydraulicAperture( real64 const aperture, + real64 const normalTraction, + real64 & dHydraulicAperture_aperture, + real64 & dHydraulicAperture_dNormalStress ) const +{ + real64 const hydraulicAperture = ( aperture >= 0.0 ) ? (aperture + m_aperture0) : m_aperture0 / ( 1 + 9*normalTraction/m_referenceNormalStress ); + dHydraulicAperture_dNormalStress = ( aperture >= 0.0 ) ? 0.0 : -hydraulicAperture / ( 1 + 9*normalTraction/m_referenceNormalStress ) * 9/m_referenceNormalStress; + dHydraulicAperture_aperture = ( aperture >= 0.0 ) ? 1.0 : 0.0; + + return hydraulicAperture; ///It would be nice to change this to return a tuple. +} + +} /* namespace constitutive */ + +} /* namespace geos */ + +#endif /* GEOS_CONSTITUTIVE_CONTACT_HYDRAULICAPERTURETABLE_HPP_ */ diff --git a/src/coreComponents/constitutive/contact/ContactBase.cpp b/src/coreComponents/constitutive/contact/ContactBase.cpp deleted file mode 100644 index 72523513d2b..00000000000 --- a/src/coreComponents/constitutive/contact/ContactBase.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file ContactBase.cpp - */ - -#include "ContactBase.hpp" -#include "functions/FunctionManager.hpp" -#include "functions/TableFunction.hpp" - -namespace geos -{ - -using namespace dataRepository; - -namespace constitutive -{ - -ContactBase::ContactBase( string const & name, - Group * const parent ): - ConstitutiveBase( name, parent ), - m_apertureTable( nullptr ) -{ - registerWrapper( viewKeyStruct::penaltyStiffnessString(), &m_penaltyStiffness ). - setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Value of the penetration penalty stiffness. Units of Pressure/length" ); - - registerWrapper( viewKeyStruct::shearStiffnessString(), &m_shearStiffness ). - setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Value of the shear elastic stiffness. Units of Pressure/length" ); - - registerWrapper( viewKeyStruct::apertureToleranceString(), &m_apertureTolerance ). - setApplyDefaultValue( 1.0e-9 ). - setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Value to be used to avoid floating point errors in expressions involving aperture. " - "For example in the case of dividing by the actual aperture (not the effective aperture " - "that results from the aperture function) this value may be used to avoid the 1/0 error. " - "Note that this value may have some physical significance in its usage, as it may be used " - "to smooth out highly nonlinear behavior associated with 1/0 in addition to avoiding the " - "1/0 error." ); - - registerWrapper( viewKeyStruct::displacementJumpThresholdString(), &m_displacementJumpThreshold ). - setApplyDefaultValue( std::numeric_limits< real64 >::epsilon() ). - setInputFlag( InputFlags::OPTIONAL ). - setDescription( "A threshold valued to determine whether a fracture is open or not." ); - - - registerWrapper( viewKeyStruct::apertureTableNameString(), &m_apertureTableName ). - setRTTypeName( rtTypes::CustomTypes::groupNameRef ). - setInputFlag( InputFlags::REQUIRED ). - setDescription( "Name of the aperture table" ); -} - -ContactBase::~ContactBase() -{} - - -void ContactBase::postProcessInput() -{ - - GEOS_THROW_IF( m_apertureTableName.empty(), - getFullName() << ": the aperture table name " << m_apertureTableName << " is empty", InputError ); - -} - -void ContactBase::initializePreSubGroups() -{} - - -void ContactBase::allocateConstitutiveData( Group & parent, - localIndex const numConstitutivePointsPerParentIndex ) -{ - ConstitutiveBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex ); - - FunctionManager & functionManager = FunctionManager::getInstance(); - - GEOS_THROW_IF( !functionManager.hasGroup( m_apertureTableName ), - getFullName() << ": the aperture table named " << m_apertureTableName << " could not be found", - InputError ); - - TableFunction & apertureTable = functionManager.getGroup< TableFunction >( m_apertureTableName ); - validateApertureTable( apertureTable ); - - ArrayOfArraysView< real64 > coords = apertureTable.getCoordinates(); - arraySlice1d< real64 const > apertureValues = coords[0]; - array1d< real64 > & hydraulicApertureValues = apertureTable.getValues(); - - localIndex const n = apertureValues.size()-1; - real64 const slope = ( hydraulicApertureValues[n] - hydraulicApertureValues[n-1] ) / ( apertureValues[n] - apertureValues[n-1] ); - real64 const apertureTransition = ( hydraulicApertureValues[n] - slope * apertureValues[n] ) / ( 1.0 - slope ); - - // if the aperture transition is larger than the last coordinates, we enlarge the table - // this check is necessary to ensure that the coordinates are strictly increasing - if( apertureTransition > apertureValues[apertureValues.size()-1] ) - { - GEOS_LOG_RANK_0( GEOS_FMT ( "Adding aperture transition for table {}:", m_apertureTableName ) ); - std::ostringstream s_orig; - for( localIndex i = 0; i < apertureValues.size(); i++ ) - s_orig << "[ " << apertureValues[i] << ", " << hydraulicApertureValues[i] << " ] "; - GEOS_LOG_RANK_0( GEOS_FMT ( " Original table = {}", s_orig.str())); - - coords.emplaceBack( 0, apertureTransition ); - hydraulicApertureValues.emplace_back( apertureTransition ); - // if the aperture transition is larger than 0, we keep enlarging the table - // this check is necessary to ensure that the coordinates are strictly increasing - if( apertureTransition > 0 ) - { - coords.emplaceBack( 0, apertureTransition*10e9 ); - hydraulicApertureValues.emplace_back( apertureTransition*10e9 ); - apertureTable.reInitializeFunction(); - } - - std::ostringstream s_mod; - for( localIndex i = 0; i < apertureValues.size(); i++ ) - s_mod << "[ " << apertureValues[i] << ", " << hydraulicApertureValues[i] << " ] "; - GEOS_LOG_RANK_0( GEOS_FMT ( " Modified table = {}", s_mod.str())); - } - - m_apertureTable = &apertureTable; -} - - -void ContactBase::validateApertureTable( TableFunction const & apertureTable ) const -{ - ArrayOfArraysView< real64 const > const coords = apertureTable.getCoordinates(); - arrayView1d< real64 const > const & hydraulicApertureValues = apertureTable.getValues(); - - GEOS_THROW_IF( coords.size() > 1, - getFullName() << ": Aperture limiter table cannot be greater than a 1D table.", - InputError ); - - arraySlice1d< real64 const > apertureValues = coords[0]; - localIndex const size = apertureValues.size(); - - GEOS_THROW_IF( coords( 0, size-1 ) > 0.0 || coords( 0, size-1 ) < 0.0, - getFullName() << ": Invalid aperture limiter table. Last coordinate must be zero!", - InputError ); - - GEOS_THROW_IF( apertureValues.size() < 2, - getFullName() << ": Invalid aperture limiter table. Must have more than two points specified", - InputError ); - - localIndex const n = apertureValues.size()-1; - real64 const slope = ( hydraulicApertureValues[n] - hydraulicApertureValues[n-1] ) / ( apertureValues[n] - apertureValues[n-1] ); - - GEOS_THROW_IF( slope >= 1.0, - getFullName() << ": Invalid aperture table. The slope of the last two points >= 1 is invalid.", - InputError ); -} - - - -ContactBaseUpdates ContactBase::createKernelWrapper() const -{ - return ContactBaseUpdates( m_penaltyStiffness, - m_shearStiffness, - m_displacementJumpThreshold, - *m_apertureTable ); -} - -} /* end namespace constitutive */ - -} /* end namespace geos */ diff --git a/src/coreComponents/constitutive/contact/ContactBase.hpp b/src/coreComponents/constitutive/contact/ContactBase.hpp deleted file mode 100644 index 98dc22b0af2..00000000000 --- a/src/coreComponents/constitutive/contact/ContactBase.hpp +++ /dev/null @@ -1,268 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file ContactBase.hpp - */ - -#ifndef GEOS_CONSTITUTIVE_CONTACT_CONTACTBASE_HPP_ -#define GEOS_CONSTITUTIVE_CONTACT_CONTACTBASE_HPP_ - -#include "constitutive/ConstitutiveBase.hpp" -#include "functions/TableFunction.hpp" -#include "physicsSolvers/contact/ContactFields.hpp" - - -namespace geos -{ - -namespace constitutive -{ - -/** - * @class ContactBaseUpdates - * - * This class is used for in-kernel contact relation updates - */ -class ContactBaseUpdates -{ -public: - - ContactBaseUpdates( real64 const & penaltyStiffness, - real64 const & shearStiffness, - real64 const & displacementJumpThreshold, - TableFunction const & apertureTable ) - : m_penaltyStiffness( penaltyStiffness ), - m_shearStiffness( shearStiffness ), - m_displacementJumpThreshold( displacementJumpThreshold ), - m_apertureTable( apertureTable.createKernelWrapper() ) - {} - - /// Default copy constructor - ContactBaseUpdates( ContactBaseUpdates const & ) = default; - - /// Default move constructor - ContactBaseUpdates( ContactBaseUpdates && ) = default; - - /// Deleted default constructor - ContactBaseUpdates() = default; - - /// Deleted copy assignment operator - ContactBaseUpdates & operator=( ContactBaseUpdates const & ) = delete; - - /// Deleted move assignment operator - ContactBaseUpdates & operator=( ContactBaseUpdates && ) = delete; - - /** - * @brief Evaluate the effective aperture, and its derivative wrt aperture - * @param[in] aperture the model aperture/gap - * @param[out] dHydraulicAperture_dAperture the derivative of the effective aperture wrt aperture - * @return The hydraulic aperture that is always > 0 - */ - GEOS_HOST_DEVICE - virtual real64 computeHydraulicAperture( real64 const aperture, - real64 & dHydraulicAperture_dAperture ) const; - - - /** - * @brief Evaluate the traction vector and its derivatives wrt to pressure and jump - * @param[in] dispJump the displacement jump - * @param[in] fractureState the fracture state - * @param[out] tractionVector the traction vector - * @param[out] dTractionVector_dJump the derivative of the traction vector wrt displacement jump - */ - GEOS_HOST_DEVICE - inline - virtual void computeTraction( localIndex const k, - arraySlice1d< real64 const > const & oldDispJump, - arraySlice1d< real64 const > const & dispJump, - integer const & fractureState, - arraySlice1d< real64 > const & tractionVector, - arraySlice2d< real64 > const & dTractionVector_dJump ) const - {GEOS_UNUSED_VAR( k, oldDispJump, dispJump, tractionVector, dTractionVector_dJump, fractureState );} - - /** - * @brief Evaluate the traction vector and its derivatives wrt to pressure and jump - * @param[in] dispJump the displacement jump - * @param[in] tractionVector the traction vector - * @param[out] fractureState the fracture state - */ - GEOS_HOST_DEVICE - inline - virtual void updateFractureState( localIndex const k, - arraySlice1d< real64 const > const & dispJump, - arraySlice1d< real64 const > const & tractionVector, - integer & fractureState ) const - { GEOS_UNUSED_VAR( k, dispJump, tractionVector, fractureState ); } - - /** - * @brief Update the traction with the pressure term - * @param[in] pressure the pressure term - * @param[in] isOpen a flag specifying whether the fracture is open or closed - * @param[inout] traction the current tractionVector - * @param[out] dTraction_dPressure the derivative of the fist component of traction wrt pressure - * @return the updated traction - */ - GEOS_HOST_DEVICE - virtual void addPressureToTraction( real64 const & pressure, - arraySlice1d< real64 >const & tractionVector, - real64 & dTraction_dPressure ) const; - - /** - * @brief Evaluate the limit tangential traction norm and return the derivative wrt normal traction - * @param[in] normalTraction the normal traction - * @param[out] dLimitTangentialTractionNorm_dTraction the derivative of the limit tangential traction norm wrt normal traction - * @return the limit tangential traction norm - */ - GEOS_HOST_DEVICE - inline - virtual real64 computeLimitTangentialTractionNorm( real64 const & normalTraction, - real64 & dLimitTangentialTractionNorm_dTraction ) const - { GEOS_UNUSED_VAR( normalTraction, dLimitTangentialTractionNorm_dTraction ); return 0; }; - -protected: - - /// The penalty stiffness - real64 m_penaltyStiffness; - - /// The shear stiffness - real64 m_shearStiffness; - - /// A threshold valued to determine whether a fracture is open or not. - real64 m_displacementJumpThreshold; - - /// The aperture table function wrapper - TableFunction::KernelWrapper m_apertureTable; -}; - - -/** - * @class ContactBase - * - * This class serves as the interface for implementing contact enforcement constitutive relations. - * This does not include the actual enforcement algorithm, but only the constitutive relations that - * govern the behavior of the contact. So things like penalty, or friction, or kinematic constraint. - */ -class ContactBase : public ConstitutiveBase -{ -public: - - /** - * @brief The standard data repository constructor - * @param name The name of the relation in the data repository - * @param parent The name of the parent Group that holds this relation object. - */ - ContactBase( string const & name, - Group * const parent ); - - /** - * @brief default destructor - */ - virtual ~ContactBase() override; - - virtual void allocateConstitutiveData( dataRepository::Group & parent, - localIndex const numConstitutivePointsPerParentIndex ) override; - - /** - * @brief accessor for penalty stiffness - * @return the stiffness - */ - real64 stiffness() const { return m_penaltyStiffness; } - - - /// Type of kernel wrapper for in-kernel update - using KernelWrapper = ContactBaseUpdates; - - /** - * @brief Create an update kernel wrapper. - * @return the wrapper - */ - KernelWrapper createKernelWrapper() const; - - /** - * @struct Structure to hold scoped key names - */ - struct viewKeyStruct : public ConstitutiveBase::viewKeyStruct - { - /// string/key for penalty stiffness - static constexpr char const * penaltyStiffnessString() { return "penaltyStiffness"; } - - /// string/key for shear stiffness - static constexpr char const * shearStiffnessString() { return "shearStiffness"; } - - /// string/key for the displacement jump threshold value - static constexpr char const * displacementJumpThresholdString() { return "displacementJumpThreshold"; } - - /// string/key for aperture tolerance - static constexpr char const * apertureToleranceString() { return "apertureTolerance"; } - - /// string/key for aperture table name - static constexpr char const * apertureTableNameString() { return "apertureTableName"; } - }; - -protected: - virtual void postProcessInput() override; - - virtual void initializePreSubGroups() override; - - /** - * @brief Validate the values provided in the aperture table - * @param[in] apertureTable the effective aperture vs aperture table - */ - void validateApertureTable( TableFunction const & apertureTable ) const; - - - /// The value of penalty to penetration - real64 m_penaltyStiffness; - - /// The value of the shear stiffness - real64 m_shearStiffness; - - /// The aperture tolerance to avoid floating point errors in expressions involving aperture - real64 m_apertureTolerance; - - /// The name of the aperture table, if any - string m_apertureTableName; - - /// A threshold valued to determine whether a fracture is open or not. - real64 m_displacementJumpThreshold; - - /// Pointer to the function that limits the model aperture to a physically admissible value. - TableFunction const * m_apertureTable; -}; - -GEOS_HOST_DEVICE -GEOS_FORCE_INLINE -real64 ContactBaseUpdates::computeHydraulicAperture( real64 const aperture, - real64 & dHydraulicAperture_dAperture ) const -{ - return m_apertureTable.compute( &aperture, &dHydraulicAperture_dAperture ); -} - -GEOS_HOST_DEVICE -GEOS_FORCE_INLINE -void ContactBaseUpdates::addPressureToTraction( real64 const & pressure, - arraySlice1d< real64 > const & tractionVector, - real64 & dTraction_dPressure ) const -{ - tractionVector[0] -= pressure; - dTraction_dPressure = -1.0; -} - - -} /* namespace constitutive */ - -} /* namespace geos */ - -#endif /* GEOS_CONSTITUTIVE_CONTACT_CONTACTBASE_HPP_ */ diff --git a/src/coreComponents/constitutive/contact/ContactSelector.hpp b/src/coreComponents/constitutive/contact/ContactSelector.hpp deleted file mode 100644 index 409928de82c..00000000000 --- a/src/coreComponents/constitutive/contact/ContactSelector.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file ContactSelector.hpp - */ - -#ifndef GEOS_CONSTITUTIVE_CONTACT_CONTACTSELECTOR_HPP_ -#define GEOS_CONSTITUTIVE_CONTACT_CONTACTSELECTOR_HPP_ - -#include "constitutive/ConstitutivePassThruHandler.hpp" -#include "constitutive/contact/CoulombContact.hpp" -#include "constitutive/contact/FrictionlessContact.hpp" - -namespace geos -{ - -namespace constitutive -{ - -template< typename LAMBDA > -void constitutiveUpdatePassThru( ContactBase const & contact, - LAMBDA && lambda ) -{ - ConstitutivePassThruHandler< CoulombContact, - FrictionlessContact >::execute( contact, std::forward< LAMBDA >( lambda ) ); -} - -template< typename LAMBDA > -void constitutiveUpdatePassThru( ContactBase & contact, - LAMBDA && lambda ) -{ - ConstitutivePassThruHandler< CoulombContact, - FrictionlessContact >::execute( contact, std::forward< LAMBDA >( lambda ) ); -} - -} /* namespace constitutive */ - -} /* namespace geos */ - -#endif // GEOS_CONSTITUTIVE_CONTACT_CONTACTSELECTOR_HPP_ diff --git a/src/coreComponents/constitutive/contact/CoulombContact.cpp b/src/coreComponents/constitutive/contact/CoulombContact.cpp deleted file mode 100644 index 49d98a9244e..00000000000 --- a/src/coreComponents/constitutive/contact/CoulombContact.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file CoulombContact.cpp - */ - -#include "CoulombContact.hpp" - -namespace geos -{ - -using namespace dataRepository; - -namespace constitutive -{ - -CoulombContact::CoulombContact( string const & name, Group * const parent ): - ContactBase( name, parent ), - m_cohesion(), - m_frictionCoefficient(), - m_elasticSlip() -{ - registerWrapper( viewKeyStruct::cohesionString(), &m_cohesion ). - setApplyDefaultValue( -1 ). - setInputFlag( InputFlags::REQUIRED ). - setDescription( "Cohesion" ); - - registerWrapper( viewKeyStruct::frictionCoefficientString(), &m_frictionCoefficient ). - setApplyDefaultValue( -1 ). - setInputFlag( InputFlags::REQUIRED ). - setDescription( "Friction coefficient" ); - - registerWrapper( viewKeyStruct::elasticSlipString(), &m_elasticSlip ). - setApplyDefaultValue( 0.0 ). - setDescription( "Elastic Slip" ); - -} - -CoulombContact::~CoulombContact() -{} - -void CoulombContact::postProcessInput() -{ - GEOS_THROW_IF( m_frictionCoefficient < 0.0, - getFullName() << ": The provided friction coefficient is less than zero. Value: " << m_frictionCoefficient, - InputError ); - -} - -void CoulombContact::allocateConstitutiveData( Group & parent, - localIndex const numConstitutivePointsPerParentIndex ) -{ - m_elasticSlip.resize( 0, 2 ); - - ContactBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex ); -} - - -CoulombContactUpdates CoulombContact::createKernelWrapper() const -{ - return CoulombContactUpdates( m_penaltyStiffness, - m_shearStiffness, - m_displacementJumpThreshold, - *m_apertureTable, - m_cohesion, - m_frictionCoefficient, - m_elasticSlip ); -} - -REGISTER_CATALOG_ENTRY( ConstitutiveBase, CoulombContact, string const &, Group * const ) - -} /* namespace constitutive */ - -} /* namespace geos */ diff --git a/src/coreComponents/constitutive/contact/CoulombContact.hpp b/src/coreComponents/constitutive/contact/CoulombContact.hpp deleted file mode 100644 index 1d49dfa9e4e..00000000000 --- a/src/coreComponents/constitutive/contact/CoulombContact.hpp +++ /dev/null @@ -1,327 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file CoulombContact.hpp - */ - -#ifndef GEOS_CONSTITUTIVE_CONTACT_COULOMBCONTACT_HPP_ -#define GEOS_CONSTITUTIVE_CONTACT_COULOMBCONTACT_HPP_ - -#include "ContactBase.hpp" - -namespace geos -{ - -namespace constitutive -{ - -/** - * @class CoulombContactUpdates - * - * This class is used for in-kernel contact relation updates - */ -class CoulombContactUpdates : public ContactBaseUpdates -{ -public: - - CoulombContactUpdates( real64 const & penaltyStiffness, - real64 const & shearStiffness, - real64 const & displacementJumpThreshold, - TableFunction const & apertureTable, - real64 const & cohesion, - real64 const & frictionCoefficient, - arrayView2d< real64 > const & elasticSlip ) - : ContactBaseUpdates( penaltyStiffness, shearStiffness, displacementJumpThreshold, apertureTable ), - m_cohesion( cohesion ), - m_frictionCoefficient( frictionCoefficient ), - m_elasticSlip( elasticSlip ) - {} - - /// Default copy constructor - CoulombContactUpdates( CoulombContactUpdates const & ) = default; - - /// Default move constructor - CoulombContactUpdates( CoulombContactUpdates && ) = default; - - /// Deleted default constructor - CoulombContactUpdates() = delete; - - /// Deleted copy assignment operator - CoulombContactUpdates & operator=( CoulombContactUpdates const & ) = delete; - - /// Deleted move assignment operator - CoulombContactUpdates & operator=( CoulombContactUpdates && ) = delete; - - /** - * @brief Evaluate the limit tangential traction norm and return the derivative wrt normal traction - * @param[in] normalTraction the normal traction - * @param[out] dLimitTangentialTractionNorm_dTraction the derivative of the limit tangential traction norm wrt normal traction - * @return the limit tangential traction norm - */ - GEOS_HOST_DEVICE - inline - virtual real64 computeLimitTangentialTractionNorm( real64 const & normalTraction, - real64 & dLimitTangentialTractionNorm_dTraction ) const override final; - - GEOS_HOST_DEVICE - inline - virtual void computeTraction( localIndex const k, - arraySlice1d< real64 const > const & oldDispJump, - arraySlice1d< real64 const > const & dispJump, - integer const & fractureState, - arraySlice1d< real64 > const & tractionVector, - arraySlice2d< real64 > const & dTractionVector_dJump ) const override final; - - GEOS_HOST_DEVICE - inline - virtual void updateFractureState( localIndex const k, - arraySlice1d< real64 const > const & dispJump, - arraySlice1d< real64 const > const & tractionVector, - integer & fractureState ) const override final; - -private: - - /// The cohesion for each upper level dimension (i.e. cell) of *this - real64 m_cohesion; - - /// The friction coefficient for each upper level dimension (i.e. cell) of *this - real64 m_frictionCoefficient; - - arrayView2d< real64 > m_elasticSlip; -}; - - -/** - * @class CoulombContact - * - * Class to provide a CoulombContact friction model. - */ -class CoulombContact : public ContactBase -{ -public: - - /** - * constructor - * @param[in] name name of the instance in the catalog - * @param[in] parent the group which contains this instance - */ - CoulombContact( string const & name, Group * const parent ); - - /** - * Default Destructor - */ - virtual ~CoulombContact() override; - - /** - * @name Static Factory Catalog members and functions - */ - ///@{ - - /** - * @return A string that is used to register/lookup this class in the registry - */ - static string catalogName() { return "Coulomb"; } - - virtual string getCatalogName() const override { return catalogName(); } - - ///@} - - virtual void allocateConstitutiveData( dataRepository::Group & parent, - localIndex const numConstitutivePointsPerParentIndex ) override final; - - /** - * @brief Const accessor for cohesion - * @return A const reference to arrayView1d containing the - * cohesions (at every element). - */ - real64 const & cohesion() const { return m_cohesion; } - - /** - * @brief Const accessor for friction angle - * @return A const reference to arrayView1d containing the - * friction coefficient (at every element). - */ - real64 const & frictionCoefficient() const { return m_frictionCoefficient; } - - /// Type of kernel wrapper for in-kernel update - using KernelWrapper = CoulombContactUpdates; - - /** - * @brief Create an update kernel wrapper. - * @return the wrapper - */ - KernelWrapper createKernelWrapper() const; - -protected: - - virtual void postProcessInput() override; - -private: - - /// The cohesion for each upper level dimension (i.e. cell) of *this - real64 m_cohesion; - - /// The friction coefficient for each upper level dimension (i.e. cell) of *this - real64 m_frictionCoefficient; - - /// Elastic slip - array2d< real64 > m_elasticSlip; - -/** - * @struct Set of "char const *" and keys for data specified in this class. - */ - struct viewKeyStruct : public ContactBase::viewKeyStruct - { - /// string/key for cohesion - static constexpr char const * cohesionString() { return "cohesion"; } - - /// string/key for friction coefficient - static constexpr char const * frictionCoefficientString() { return "frictionCoefficient"; } - - /// string/key for the elastic slip - static constexpr char const * elasticSlipString() { return "elasticSlip"; } - }; - -}; - - -GEOS_HOST_DEVICE -real64 CoulombContactUpdates::computeLimitTangentialTractionNorm( real64 const & normalTraction, - real64 & dLimitTangentialTractionNorm_dTraction ) const -{ - dLimitTangentialTractionNorm_dTraction = m_frictionCoefficient; - return ( m_cohesion - normalTraction * m_frictionCoefficient ); -} - - -GEOS_HOST_DEVICE -inline void CoulombContactUpdates::computeTraction( localIndex const k, - arraySlice1d< real64 const > const & oldDispJump, - arraySlice1d< real64 const > const & dispJump, - integer const & fractureState, - arraySlice1d< real64 > const & tractionVector, - arraySlice2d< real64 > const & dTractionVector_dJump ) const -{ - - bool const isOpen = fractureState == fields::contact::FractureState::Open; - - // Initialize everyting to 0 - tractionVector[0] = 0.0; - tractionVector[1] = 0.0; - tractionVector[2] = 0.0; - LvArray::forValuesInSlice( dTractionVector_dJump, []( real64 & val ){ val = 0.0; } ); - // If the fracture is open the traction is 0 and so are its derivatives so there is nothing to do - if( !isOpen ) - { - // normal component of the traction - tractionVector[0] = m_penaltyStiffness * dispJump[0]; - // derivative of the normal component w.r.t. to the nomral dispJump - dTractionVector_dJump[0][0] = m_penaltyStiffness; - - // Compute the slip - real64 const slip[2] = { dispJump[1] - oldDispJump[1], - dispJump[2] - oldDispJump[2] }; - - - real64 const tau[2] = { m_shearStiffness * ( slip[0] + m_elasticSlip[k][0] ), - m_shearStiffness * ( slip[1] + m_elasticSlip[k][1] ) }; - - switch( fractureState ) - { - case fields::contact::FractureState::Stick: - { - // Elastic slip case - // Tangential components of the traction are equal to tau - tractionVector[1] = tau[0]; - tractionVector[2] = tau[1]; - - dTractionVector_dJump[1][1] = m_shearStiffness; - dTractionVector_dJump[2][2] = m_shearStiffness; - - // The slip is only elastic: we add the full slip to the elastic one - LvArray::tensorOps::add< 2 >( m_elasticSlip[k], slip ); - - break; - } - case fields::contact::FractureState::Slip: - { - // Plastic slip case - real64 dLimitTau_dNormalTraction; - real64 const limitTau = computeLimitTangentialTractionNorm( tractionVector[0], - dLimitTau_dNormalTraction ); - - real64 const slipNorm = LvArray::tensorOps::l2Norm< 2 >( slip ); - - // Tangential components of the traction computed based on the limitTau - tractionVector[1] = limitTau * slip[0] / slipNorm; - tractionVector[2] = limitTau * slip[1] / slipNorm; - - dTractionVector_dJump[1][0] = m_penaltyStiffness * dLimitTau_dNormalTraction * slip[0] / slipNorm; - dTractionVector_dJump[1][1] = limitTau * pow( slip[1], 2 ) / pow( LvArray::tensorOps::l2NormSquared< 2 >( slip ), 1.5 ); - dTractionVector_dJump[1][2] = limitTau * slip[0] * slip[1] / pow( LvArray::tensorOps::l2NormSquared< 2 >( slip ), 1.5 ); - - dTractionVector_dJump[2][0] = m_penaltyStiffness * dLimitTau_dNormalTraction * slip[1] / slipNorm; - dTractionVector_dJump[2][1] = limitTau * slip[0] * slip[1] / pow( LvArray::tensorOps::l2NormSquared< 2 >( slip ), 1.5 ); - dTractionVector_dJump[2][2] = limitTau * pow( slip[0], 2 ) / pow( LvArray::tensorOps::l2NormSquared< 2 >( slip ), 1.5 ); - - // Compute elastic component of the slip for this case - real64 const plasticSlip[2] = { tractionVector[1] / m_shearStiffness, - tractionVector[2] / m_shearStiffness }; - - LvArray::tensorOps::copy< 2 >( m_elasticSlip[k], slip ); - LvArray::tensorOps::subtract< 2 >( m_elasticSlip[k], plasticSlip ); - - break; - } - } - } -} - -GEOS_HOST_DEVICE -inline void CoulombContactUpdates::updateFractureState( localIndex const k, - arraySlice1d< real64 const > const & dispJump, - arraySlice1d< real64 const > const & tractionVector, - integer & fractureState ) const -{ - using namespace fields::contact; - - if( dispJump[0] > -m_displacementJumpThreshold ) - { - fractureState = FractureState::Open; - m_elasticSlip[k][0] = 0.0; - m_elasticSlip[k][1] = 0.0; - } - else - { - real64 const tau[2] = { tractionVector[1], - tractionVector[2] }; - real64 const tauNorm = LvArray::tensorOps::l2Norm< 2 >( tau ); - - real64 dLimitTau_dNormalTraction; - real64 const limitTau = computeLimitTangentialTractionNorm( tractionVector[0], - dLimitTau_dNormalTraction ); - - // Yield function (not necessary but makes it clearer) - real64 const yield = tauNorm - limitTau; - - fractureState = yield < 0 ? FractureState::Stick : FractureState::Slip; - } -} - -} /* namespace constitutive */ - -} /* namespace geos */ - -#endif /* GEOS_CONSTITUTIVE_CONTACT_COULOMBCONTACT_HPP_ */ diff --git a/src/coreComponents/constitutive/contact/CoulombFriction.cpp b/src/coreComponents/constitutive/contact/CoulombFriction.cpp new file mode 100644 index 00000000000..d59d3d99a45 --- /dev/null +++ b/src/coreComponents/constitutive/contact/CoulombFriction.cpp @@ -0,0 +1,88 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CoulombFriction.cpp + */ + +#include "CoulombFriction.hpp" + +namespace geos +{ + +using namespace dataRepository; + +namespace constitutive +{ + +CoulombFriction::CoulombFriction( string const & name, Group * const parent ): + FrictionBase( name, parent ), + m_cohesion(), + m_frictionCoefficient(), + m_elasticSlip() +{ + registerWrapper( viewKeyStruct::shearStiffnessString(), &m_shearStiffness ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Value of the shear elastic stiffness. Units of Pressure/length" ); + + registerWrapper( viewKeyStruct::cohesionString(), &m_cohesion ). + setApplyDefaultValue( -1 ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Cohesion" ); + + registerWrapper( viewKeyStruct::frictionCoefficientString(), &m_frictionCoefficient ). + setApplyDefaultValue( -1 ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Friction coefficient" ); + + registerWrapper( viewKeyStruct::elasticSlipString(), &m_elasticSlip ). + setApplyDefaultValue( 0.0 ). + setDescription( "Elastic Slip" ); +} + +CoulombFriction::~CoulombFriction() +{} + +void CoulombFriction::postInputInitialization() +{ + GEOS_THROW_IF( m_frictionCoefficient < 0.0, + getFullName() << ": The provided friction coefficient is less than zero. Value: " << m_frictionCoefficient, + InputError ); + +} + +void CoulombFriction::allocateConstitutiveData( Group & parent, + localIndex const numConstitutivePointsPerParentIndex ) +{ + m_elasticSlip.resize( 0, 2 ); + + FrictionBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex ); +} + + +CoulombFrictionUpdates CoulombFriction::createKernelUpdates() const +{ + return CoulombFrictionUpdates( m_displacementJumpThreshold, + m_shearStiffness, + m_cohesion, + m_frictionCoefficient, + m_elasticSlip ); +} + +REGISTER_CATALOG_ENTRY( ConstitutiveBase, CoulombFriction, string const &, Group * const ) + +} /* namespace constitutive */ + +} /* namespace geos */ diff --git a/src/coreComponents/constitutive/contact/CoulombFriction.hpp b/src/coreComponents/constitutive/contact/CoulombFriction.hpp new file mode 100644 index 00000000000..d64453fe31a --- /dev/null +++ b/src/coreComponents/constitutive/contact/CoulombFriction.hpp @@ -0,0 +1,617 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CoulombFriction.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_CONTACT_COULOMBFRICTION_HPP_ +#define GEOS_CONSTITUTIVE_CONTACT_COULOMBFRICTION_HPP_ + +#include "FrictionBase.hpp" + +namespace geos +{ + +namespace constitutive +{ + +/** + * @class CoulombFrictionUpdates + * + * This class is used for in-kernel contact relation updates + */ +class CoulombFrictionUpdates : public FrictionBaseUpdates +{ +public: + CoulombFrictionUpdates( real64 const & displacementJumpThreshold, + real64 const & shearStiffness, + real64 const & cohesion, + real64 const & frictionCoefficient, + arrayView2d< real64 > const & elasticSlip ) + : FrictionBaseUpdates( displacementJumpThreshold ), + m_shearStiffness( shearStiffness ), + m_cohesion( cohesion ), + m_frictionCoefficient( frictionCoefficient ), + m_elasticSlip( elasticSlip ) + {} + + /// Default copy constructor + CoulombFrictionUpdates( CoulombFrictionUpdates const & ) = default; + + /// Default move constructor + CoulombFrictionUpdates( CoulombFrictionUpdates && ) = default; + + /// Deleted default constructor + CoulombFrictionUpdates() = delete; + + /// Deleted copy assignment operator + CoulombFrictionUpdates & operator=( CoulombFrictionUpdates const & ) = delete; + + /// Deleted move assignment operator + CoulombFrictionUpdates & operator=( CoulombFrictionUpdates && ) = delete; + + /** + * @brief Evaluate the limit tangential traction norm and return the derivative wrt normal traction + * @param[in] normalTraction the normal traction + * @param[out] dLimitTangentialTractionNorm_dTraction the derivative of the limit tangential traction norm wrt normal traction + * @return the limit tangential traction norm + */ + GEOS_HOST_DEVICE + inline + virtual real64 computeLimitTangentialTractionNorm( real64 const & normalTraction, + real64 & dLimitTangentialTractionNorm_dTraction ) const override final; + + GEOS_HOST_DEVICE + inline + virtual void computeShearTraction( localIndex const k, + arraySlice1d< real64 const > const & oldDispJump, + arraySlice1d< real64 const > const & dispJump, + integer const & fractureState, + arraySlice1d< real64 > const & tractionVector, + arraySlice2d< real64 > const & dTractionVector_dJump ) const override final; + + GEOS_HOST_DEVICE + inline + virtual void updateFractureState( arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & tractionVector, + integer & fractureState ) const override final; + + GEOS_HOST_DEVICE + inline + virtual void updateElasticSlip( localIndex const k, + arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & oldDispJump, + arraySlice1d< real64 const > const & tractionVector, + integer const & fractureState ) const override final; + + GEOS_HOST_DEVICE + inline + virtual void updateTraction( arraySlice1d< real64 const > const & oldDispJump, + arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & penalty, + arraySlice1d< real64 const > const & traction, + real64 const faceArea, + bool const symmetric, + bool const fixedLimitTau, + real64 const normalTractionTolerance, + real64 const tangentialTractionTolerance, + real64 ( &dTraction_dDispJump )[3][3], + real64 ( &tractionNew )[3], + integer & fractureState ) const override final; + + + GEOS_HOST_DEVICE + inline + virtual void updateTractionOnly( arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & deltaDispJump, + arraySlice1d< real64 const > const & penalty, + arraySlice1d< real64 const > const & traction, + real64 const faceArea, + arraySlice1d< real64 > const & tractionNew ) const override final; + + GEOS_HOST_DEVICE + inline + virtual void constraintCheck( arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & deltaDispJump, + arraySlice1d< real64 > const & tractionVector, + integer const fractureState, + real64 const normalTractionTolerance, + real64 const normalDisplacementTolerance, + real64 const slidingTolerance, + real64 const slidingCheckTolerance, + integer & condConv ) const override final; + +private: + /// The shear stiffness + real64 m_shearStiffness; + + /// The cohesion for each upper level dimension (i.e. cell) of *this + real64 m_cohesion; + + /// The friction coefficient for each upper level dimension (i.e. cell) of *this + real64 m_frictionCoefficient; + + arrayView2d< real64 > m_elasticSlip; +}; + + +/** + * @class CoulombFriction + * + * Class to provide a CoulombFriction friction model. + */ +class CoulombFriction : public FrictionBase +{ +public: + + /** + * constructor + * @param[in] name name of the instance in the catalog + * @param[in] parent the group which contains this instance + */ + CoulombFriction( string const & name, Group * const parent ); + + /** + * Default Destructor + */ + virtual ~CoulombFriction() override; + + static string catalogName() { return "Coulomb"; } + + virtual string getCatalogName() const override { return catalogName(); } + + ///@} + + virtual void allocateConstitutiveData( dataRepository::Group & parent, + localIndex const numConstitutivePointsPerParentIndex ) override final; + + /// Type of kernel wrapper for in-kernel update + using KernelWrapper = CoulombFrictionUpdates; + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelUpdates() const; + +protected: + + virtual void postInputInitialization() override; + +private: + + /// The shear stiffness + real64 m_shearStiffness; + + /// The cohesion for each upper level dimension (i.e. cell) of *this + real64 m_cohesion; + + /// The friction coefficient for each upper level dimension (i.e. cell) of *this + real64 m_frictionCoefficient; + + /// Elastic slip + array2d< real64 > m_elasticSlip; + +/** + * @struct Set of "char const *" and keys for data specified in this class. + */ + struct viewKeyStruct : public FrictionBase::viewKeyStruct + { + /// string/key for shear stiffness + static constexpr char const * shearStiffnessString() { return "shearStiffness"; } + + /// string/key for cohesion + static constexpr char const * cohesionString() { return "cohesion"; } + + /// string/key for friction coefficient + static constexpr char const * frictionCoefficientString() { return "frictionCoefficient"; } + + /// string/key for the elastic slip + static constexpr char const * elasticSlipString() { return "elasticSlip"; } + }; + +}; + + +GEOS_HOST_DEVICE +real64 CoulombFrictionUpdates::computeLimitTangentialTractionNorm( real64 const & normalTraction, + real64 & dLimitTangentialTractionNorm_dTraction ) const +{ + dLimitTangentialTractionNorm_dTraction = -m_frictionCoefficient; + return ( m_cohesion - normalTraction * m_frictionCoefficient ); +} + + +GEOS_HOST_DEVICE +inline void CoulombFrictionUpdates::computeShearTraction( localIndex const k, + arraySlice1d< real64 const > const & oldDispJump, + arraySlice1d< real64 const > const & dispJump, + integer const & fractureState, + arraySlice1d< real64 > const & tractionVector, + arraySlice2d< real64 > const & dTractionVector_dJump ) const +{ + // Compute the slip + real64 const slip[2] = { dispJump[1] - oldDispJump[1], + dispJump[2] - oldDispJump[2] }; + + switch( fractureState ) + { + case fields::contact::FractureState::Stick: + { + // Elastic tangential deformation + + real64 const tau[2] = { m_shearStiffness * ( slip[0] + m_elasticSlip[k][0] ), + m_shearStiffness * ( slip[1] + m_elasticSlip[k][1] ) }; + + // Tangential components of the traction are equal to tau + tractionVector[1] = tau[0]; + tractionVector[2] = tau[1]; + + dTractionVector_dJump[1][1] = m_shearStiffness; + dTractionVector_dJump[2][2] = m_shearStiffness; + + break; + } + case fields::contact::FractureState::Slip: + { + // Plastic tangential deformation + + real64 dLimitTau_dNormalTraction; + real64 const limitTau = computeLimitTangentialTractionNorm( tractionVector[0], + dLimitTau_dNormalTraction ); + + real64 const slipNorm = LvArray::tensorOps::l2Norm< 2 >( slip ); + + // Tangential components of the traction computed based on the limitTau + tractionVector[1] = limitTau * slip[0] / slipNorm; + tractionVector[2] = limitTau * slip[1] / slipNorm; + + dTractionVector_dJump[1][0] = dTractionVector_dJump[0][0] * dLimitTau_dNormalTraction * slip[0] / slipNorm; + dTractionVector_dJump[1][1] = limitTau * pow( slip[1], 2 ) / pow( LvArray::tensorOps::l2NormSquared< 2 >( slip ), 1.5 ); + dTractionVector_dJump[1][2] = -limitTau * slip[0] * slip[1] / pow( LvArray::tensorOps::l2NormSquared< 2 >( slip ), 1.5 ); + + dTractionVector_dJump[2][0] = dTractionVector_dJump[0][0] * dLimitTau_dNormalTraction * slip[1] / slipNorm; + dTractionVector_dJump[2][1] = -limitTau * slip[0] * slip[1] / pow( LvArray::tensorOps::l2NormSquared< 2 >( slip ), 1.5 ); + dTractionVector_dJump[2][2] = limitTau * pow( slip[0], 2 ) / pow( LvArray::tensorOps::l2NormSquared< 2 >( slip ), 1.5 ); + + break; + } + } +} + +GEOS_HOST_DEVICE +inline void CoulombFrictionUpdates::updateFractureState( arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & tractionVector, + integer & fractureState ) const +{ + using namespace fields::contact; + + if( dispJump[0] > -m_displacementJumpThreshold ) + { + fractureState = FractureState::Open; + } + else + { + real64 const tau[2] = { tractionVector[1], + tractionVector[2] }; + real64 const tauNorm = LvArray::tensorOps::l2Norm< 2 >( tau ); + + real64 dLimitTau_dNormalTraction; + real64 const limitTau = computeLimitTangentialTractionNorm( tractionVector[0], + dLimitTau_dNormalTraction ); + + // Yield function (not necessary but makes it clearer) + real64 const yield = tauNorm - limitTau; + + if( yield < 0 ) + { + fractureState = FractureState::Stick; + } + else + { + fractureState = FractureState::Slip; + } + } +} + +GEOS_HOST_DEVICE +inline void CoulombFrictionUpdates::updateElasticSlip( localIndex const k, + arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & oldDispJump, + arraySlice1d< real64 const > const & tractionVector, + integer const & fractureState ) const +{ + using namespace fields::contact; + + if( fractureState == FractureState::Open ) + { + m_elasticSlip[k][0] = 0.0; + m_elasticSlip[k][1] = 0.0; + } + else + { + if( fractureState == FractureState::Stick ) + { + // The slip is only elastic: we add the full slip to the elastic one + real64 const slip[2] = { dispJump[1] - oldDispJump[1], + dispJump[2] - oldDispJump[2] }; + LvArray::tensorOps::add< 2 >( m_elasticSlip[k], slip ); + } + else if( fractureState == FractureState::Slip ) + { + m_elasticSlip[k][0] = tractionVector[1] / m_shearStiffness; + m_elasticSlip[k][1] = tractionVector[2] / m_shearStiffness; + } + } +} + +GEOS_HOST_DEVICE +inline void CoulombFrictionUpdates::updateTraction( arraySlice1d< real64 const > const & oldDispJump, + arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & penalty, + arraySlice1d< real64 const > const & traction, + real64 const faceArea, + bool const symmetric, + bool const fixedLimitTau, + real64 const normalTractionTolerance, + real64 const tangentialTractionTolerance, + real64 ( & dTraction_dDispJump )[3][3], + real64 ( & tractionNew ) [3], + integer & fractureState ) const +{ + + using namespace fields::contact; + + real64 dLimitTangentialTractionNorm_dTraction = 0.0; + real64 limitTau = 0.0; + + // Compute the trial traction + real64 tractionTrial[ 3 ]; + tractionTrial[ 0 ] = traction[0] + penalty[0] * dispJump[0] * faceArea; + tractionTrial[ 1 ] = traction[1] + penalty[1] * (dispJump[1] - oldDispJump[1]) * faceArea; + tractionTrial[ 2 ] = traction[2] + penalty[1] * (dispJump[2] - oldDispJump[2]) * faceArea; + + // Compute tangential trial traction norm + real64 const tau[2] = { tractionTrial[1], + tractionTrial[2] }; + real64 const tractionTrialNorm = LvArray::tensorOps::l2Norm< 2 >( tau ); + + // If normal tangential trial is positive (opening) + fractureState = FractureState::Stick; + if( tractionTrial[ 0 ] > normalTractionTolerance ) + { + tractionNew[0] = 0.0; + dTraction_dDispJump[0][0] = 0.0; + fractureState = FractureState::Open; + } + else + { + tractionNew[0] = tractionTrial[0]; + dTraction_dDispJump[0][0] = -penalty[ 0 ]; + } + + // Compute limit Tau + if( fixedLimitTau ) + { + limitTau = computeLimitTangentialTractionNorm( traction[0], + dLimitTangentialTractionNorm_dTraction ); + } + else + { + limitTau = computeLimitTangentialTractionNorm( tractionNew[0], + dLimitTangentialTractionNorm_dTraction ); + } + + if( tractionTrialNorm <= tangentialTractionTolerance ) + { + // It is needed for the first iteration (both t and u are equal to zero) + dTraction_dDispJump[1][1] = -penalty[1]; + dTraction_dDispJump[2][2] = -penalty[1]; + + tractionNew[1] = tractionTrial[1]; + tractionNew[2] = tractionTrial[2]; + + if( fractureState != FractureState::Open ) + { + fractureState = FractureState::Stick; + } + } + else if( limitTau <= tangentialTractionTolerance ) + { + dTraction_dDispJump[1][1] = 0.0; + dTraction_dDispJump[2][2] = 0.0; + + tractionNew[1] = (fixedLimitTau) ? tractionTrial[1] : 0.0; + tractionNew[2] = (fixedLimitTau) ? tractionTrial[2] : 0.0; + + if( fractureState != FractureState::Open ) + { + fractureState = FractureState::Slip; + } + } + else + { + // Compute psi and dpsi + //real64 const psi = std::tanh( tractionTrialNorm/limitTau ); + //real64 const dpsi = 1.0-std::pow(psi,2); + real64 const psi = ( tractionTrialNorm > limitTau) ? 1.0 : tractionTrialNorm/limitTau; + real64 const dpsi = ( tractionTrialNorm > limitTau) ? 0.0 : 1.0; + + if( fractureState != FractureState::Open ) + { + fractureState = ( tractionTrialNorm > limitTau) ? FractureState::Slip : FractureState::Stick; + } + + // Two symmetric 2x2 matrices + real64 dNormTTdgT[ 3 ]; + dNormTTdgT[ 0 ] = tractionTrial[ 1 ] * tractionTrial[ 1 ]; + dNormTTdgT[ 1 ] = tractionTrial[ 2 ] * tractionTrial[ 2 ]; + dNormTTdgT[ 2 ] = tractionTrial[ 1 ] * tractionTrial[ 2 ]; + + real64 dTdgT[ 3 ]; + dTdgT[ 0 ] = (tractionTrialNorm * tractionTrialNorm - dNormTTdgT[0]); + dTdgT[ 1 ] = (tractionTrialNorm * tractionTrialNorm - dNormTTdgT[1]); + dTdgT[ 2 ] = -dNormTTdgT[2]; + + LvArray::tensorOps::scale< 3 >( dNormTTdgT, 1. / std::pow( tractionTrialNorm, 2 ) ); + LvArray::tensorOps::scale< 3 >( dTdgT, 1. / std::pow( tractionTrialNorm, 3 ) ); + + // Compute dTdDispJump + dTraction_dDispJump[1][1] = -penalty[1] * ( + dpsi * dNormTTdgT[0] + + psi * dTdgT[0] * limitTau ); + dTraction_dDispJump[2][2] = -penalty[1] * ( + dpsi * dNormTTdgT[1] + + psi * dTdgT[1] * limitTau ); + dTraction_dDispJump[1][2] = -penalty[1] * ( + dpsi * dNormTTdgT[2] + + psi * dTdgT[2] * limitTau ); + dTraction_dDispJump[2][1] = dTraction_dDispJump[1][2]; + + if( !symmetric ) + { + // Nonsymetric term + dTraction_dDispJump[1][0] = -dTraction_dDispJump[0][0] * m_frictionCoefficient * + tractionTrial[1] * (psi/tractionTrialNorm - dpsi/limitTau); + dTraction_dDispJump[2][0] = -dTraction_dDispJump[0][0] * m_frictionCoefficient * + tractionTrial[2] * (psi/tractionTrialNorm - dpsi/limitTau); + } + + LvArray::tensorOps::scale< 3 >( tractionTrial, (psi * limitTau)/tractionTrialNorm ); + tractionNew[1] = tractionTrial[1]; + tractionNew[2] = tractionTrial[2]; + } + +} + +GEOS_HOST_DEVICE +inline void CoulombFrictionUpdates::updateTractionOnly( arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & deltaDispJump, + arraySlice1d< real64 const > const & penalty, + arraySlice1d< real64 const > const & traction, + real64 const faceArea, + arraySlice1d< real64 > const & tractionNew ) const +{ + + // TODO: Pass this tol as an argument or define a new class member + real64 const zero = LvArray::NumericLimits< real64 >::epsilon; + + tractionNew[0] = traction[0] + penalty[0] * dispJump[0] * faceArea; + tractionNew[1] = traction[1] + penalty[1] * deltaDispJump[1] * faceArea; + tractionNew[2] = traction[2] + penalty[1] * deltaDispJump[2] * faceArea; + + real64 const tau[2] = { tractionNew[1], + tractionNew[2] }; + real64 const currentTau = LvArray::tensorOps::l2Norm< 2 >( tau ); + + real64 dLimitTangentialTractionNorm_dTraction = 0.0; + real64 const limitTau = computeLimitTangentialTractionNorm( tractionNew[0], + dLimitTangentialTractionNorm_dTraction ); + + // Compute psi + real64 psi; + if( limitTau < zero ) + { + psi = 1.0; + } + else + { + //psi = std::tanh(currentTau / limitTau); + psi = (currentTau > limitTau ) ? 1.0 : currentTau/limitTau; + } + + // Compute the new tangential traction + if( limitTau > zero && currentTau > zero ) + { + tractionNew[1] *= limitTau * psi / currentTau; + tractionNew[2] *= limitTau * psi / currentTau; + } + else + { + tractionNew[1] *= 0.0; + tractionNew[2] *= 0.0; + } +} + +GEOS_HOST_DEVICE +inline void CoulombFrictionUpdates::constraintCheck( arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & deltaDispJump, + arraySlice1d< real64 > const & tractionVector, + integer const fractureState, + real64 const normalTractionTolerance, + real64 const normalDisplacementTolerance, + real64 const slidingTolerance, + real64 const slidingCheckTolerance, + integer & condConv ) const +{ + + using namespace fields::contact; + + // Compute the slip + real64 const deltaDisp[2] = { deltaDispJump[1], + deltaDispJump[2] }; + + real64 const deltaDispNorm = LvArray::tensorOps::l2Norm< 2 >( deltaDisp ); + + // Compute current Tau and limit Tau + real64 const tau[2] = { tractionVector[1], + tractionVector[2] }; + real64 const currentTau = LvArray::tensorOps::l2Norm< 2 >( tau ); + + real64 dLimitTangentialTractionNorm_dTraction = 0.0; + real64 const limitTau = computeLimitTangentialTractionNorm( tractionVector[0], + dLimitTangentialTractionNorm_dTraction ); + + condConv = 0; + // Case 1: if it is open + if( tractionVector[0] >= normalTractionTolerance ) + { + if( fractureState != FractureState::Open ) + { + condConv = 1; + } + tractionVector[0] = 0.0; + tractionVector[1] = 0.0; + tractionVector[2] = 0.0; + } + else + { + // Case 2: compenetration + if(( LvArray::math::abs( dispJump[0] ) > normalDisplacementTolerance ) && + (fractureState != FractureState::Open)) + { + condConv = 2; + } + // Case 3: it is stick and dg is greater than 0 + if( fractureState == FractureState::Stick && + deltaDispNorm > slidingTolerance ) + { + condConv = 3; + } + + // Case 4: the elastic tangential traction is greater than the limit + if( currentTau > (LvArray::math::abs( limitTau ) * (1.0 + slidingCheckTolerance)) ) + { + condConv = 4; + } + } +} + +} /* namespace constitutive */ + +} /* namespace geos */ + +#endif /* GEOS_CONSTITUTIVE_CONTACT_COULOMBFRICTION_HPP_ */ diff --git a/src/coreComponents/constitutive/contact/FrictionBase.cpp b/src/coreComponents/constitutive/contact/FrictionBase.cpp new file mode 100644 index 00000000000..d440e9c53bb --- /dev/null +++ b/src/coreComponents/constitutive/contact/FrictionBase.cpp @@ -0,0 +1,52 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FrictionBase.cpp + */ + +#include "FrictionBase.hpp" +#include "functions/FunctionManager.hpp" +#include "functions/TableFunction.hpp" + +namespace geos +{ + +using namespace dataRepository; + +namespace constitutive +{ + +FrictionBase::FrictionBase( string const & name, + Group * const parent ): + ConstitutiveBase( name, parent ) +{ + registerWrapper( viewKeyStruct::displacementJumpThresholdString(), &m_displacementJumpThreshold ). + setApplyDefaultValue( std::numeric_limits< real64 >::epsilon() ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "A threshold valued to determine whether a fracture is open or not." ); +} + +FrictionBase::~FrictionBase() +{} + +FrictionBaseUpdates FrictionBase::createKernelWrapper() const +{ + return FrictionBaseUpdates( m_displacementJumpThreshold ); +} + +} /* end namespace constitutive */ + +} /* end namespace geos */ diff --git a/src/coreComponents/constitutive/contact/FrictionBase.hpp b/src/coreComponents/constitutive/contact/FrictionBase.hpp new file mode 100644 index 00000000000..d44a9fae7d4 --- /dev/null +++ b/src/coreComponents/constitutive/contact/FrictionBase.hpp @@ -0,0 +1,263 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FrictionBase.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_CONTACT_FRICTIONBASE_HPP_ +#define GEOS_CONSTITUTIVE_CONTACT_FRICTIONBASE_HPP_ + +#include "constitutive/ConstitutiveBase.hpp" +#include "functions/TableFunction.hpp" +#include "physicsSolvers/contact/ContactFields.hpp" + + +namespace geos +{ + +namespace constitutive +{ + +/** + * @class FrictionBaseUpdates + * + * This class is used for in-kernel contact relation updates + */ +class FrictionBaseUpdates +{ +public: + + FrictionBaseUpdates( real64 const & displacementJumpThreshold ) + : m_displacementJumpThreshold( displacementJumpThreshold ) + {} + + /// Default copy constructor + FrictionBaseUpdates( FrictionBaseUpdates const & ) = default; + + /// Default move constructor + FrictionBaseUpdates( FrictionBaseUpdates && ) = default; + + /// Deleted default constructor + FrictionBaseUpdates() = default; + + /// Deleted copy assignment operator + FrictionBaseUpdates & operator=( FrictionBaseUpdates const & ) = delete; + + /// Deleted move assignment operator + FrictionBaseUpdates & operator=( FrictionBaseUpdates && ) = delete; + + /** + * @brief Evaluate the traction vector and its derivatives wrt to pressure and jump + * @param[in] dispJump the displacement jump + * @param[in] fractureState the fracture state + * @param[out] tractionVector the traction vector + * @param[out] dTractionVector_dJump the derivative of the traction vector wrt displacement jump + */ + GEOS_HOST_DEVICE + inline + virtual void computeShearTraction( localIndex const k, + arraySlice1d< real64 const > const & oldDispJump, + arraySlice1d< real64 const > const & dispJump, + integer const & fractureState, + arraySlice1d< real64 > const & tractionVector, + arraySlice2d< real64 > const & dTractionVector_dJump ) const + {GEOS_UNUSED_VAR( k, oldDispJump, dispJump, tractionVector, dTractionVector_dJump, fractureState );} + + /** + * @brief Evaluate the traction vector and its derivatives wrt to pressure and jump + * @param[in] dispJump the displacement jump + * @param[in] tractionVector the traction vector + * @param[out] fractureState the fracture state + */ + GEOS_HOST_DEVICE + inline + virtual void updateFractureState( arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & tractionVector, + integer & fractureState ) const + { GEOS_UNUSED_VAR( dispJump, tractionVector, fractureState ); } + + /** + * @brief Evaluate and store the elastic slip + * @param[in] dispJump the displacement jump + * @param[in] oldDispJump the previous displacement jump + * @param[in] tractionVector the traction vector + * @param[out] fractureState the fracture state + */ + GEOS_HOST_DEVICE + inline + virtual void updateElasticSlip( localIndex const k, + arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & oldDispJump, + arraySlice1d< real64 const > const & tractionVector, + integer const & fractureState ) const + { GEOS_UNUSED_VAR( k, dispJump, oldDispJump, tractionVector, fractureState ); } + + /** + * @brief Update the trial traction vector ( return mapping ) + * @param[in] oldDispJump the displacement jump of the previous time step + * @param[in] dispJump the displacement jump of the current time step + * @param[in] penalty the penalty coefficients + * @param[in] traction the traction vector + * @param[in] symmetric flag to compute only the symmetric part of dTraction_dDispJump + * @param[in] fixedLimitTau flag to keep fixed the tangential stress + * @param[in] normalTractionTolerance normal traction tolerance (if tn > tol => fracture is open) + * @param[in] tangentialTractionTolerance tangential traction tolerance (if tau < tol => tau = 0) + * @param[out] dTraction_dDispJump matrix containing the derivatives of traction over the displacement jump + * @param[out] tractionNew the new traction vector + * @param[out] fractureState the fracture state + */ + GEOS_HOST_DEVICE + inline + virtual void updateTraction( arraySlice1d< real64 const > const & oldDispJump, + arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & penalty, + arraySlice1d< real64 const > const & traction, + real64 const faceArea, + bool const symmetric, + bool const fixedLimitTau, + real64 const normalTractionTolerance, + real64 const tangentialTractionTolerance, + real64 ( & dTraction_dDispJump )[3][3], + real64 ( & tractionNew )[3], + integer & fractureState ) const + { + GEOS_UNUSED_VAR( oldDispJump, dispJump, penalty, traction, faceArea, symmetric, fixedLimitTau, + normalTractionTolerance, tangentialTractionTolerance, + dTraction_dDispJump, tractionNew, fractureState ); + } + + /** + * @brief Update the traction vector only ( return mapping ) + * @param[in] dispJump the displacement jump of the current time step + * @param[in] deltaDispJump the delta displacement jump of the current time step + * @param[in] penalty the penalty coefficients + * @param[in] traction the traction vector + * @param[out] tractionNew the new traction vector + */ + GEOS_HOST_DEVICE + inline + virtual void updateTractionOnly( arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & deltaDispJump, + arraySlice1d< real64 const > const & penalty, + arraySlice1d< real64 const > const & traction, + real64 const faceArea, + arraySlice1d< real64 > const & tractionNew ) const + { GEOS_UNUSED_VAR( dispJump, deltaDispJump, penalty, traction, faceArea, tractionNew ); } + + /** + * @brief Check for the constraint satisfaction + * @param[in] dispJump the displacement jump of the current time step + * @param[in] deltaDispJump the delta displacement jump of the current time step + * @param[in] tractionVector the traction vector + * @param[in] fractureState the fracture check + * @param[in] tolerance the tolerance + * @param[out] condConv flag indicating the result of the check + */ + GEOS_HOST_DEVICE + inline + virtual void constraintCheck( arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & deltaDispJump, + arraySlice1d< real64 > const & tractionVector, + integer const fractureState, + real64 const normalTractionTolerance, + real64 const normalDisplacementTolerance, + real64 const slidingTolerance, + real64 const slidingCheckTolerance, + integer & condConv ) const + { + GEOS_UNUSED_VAR( dispJump, deltaDispJump, tractionVector, fractureState, + normalTractionTolerance, normalDisplacementTolerance, slidingTolerance, + slidingCheckTolerance, condConv ); + } + + /** + * @brief Evaluate the limit tangential traction norm and return the derivative wrt normal traction + * @param[in] normalTraction the normal traction + * @param[out] dLimitTangentialTractionNorm_dTraction the derivative of the limit tangential traction norm wrt normal traction + * @return the limit tangential traction norm + */ + GEOS_HOST_DEVICE + inline + virtual real64 computeLimitTangentialTractionNorm( real64 const & normalTraction, + real64 & dLimitTangentialTractionNorm_dTraction ) const + { + GEOS_UNUSED_VAR( normalTraction ); + dLimitTangentialTractionNorm_dTraction = 0.0; + return 0; + } + +protected: + + /// A threshold valued to determine whether a fracture is open or not. + real64 m_displacementJumpThreshold; + +}; + + +/** + * @class FrictionBase + * + * This class serves as the interface for implementing contact enforcement constitutive relations. + * This does not include the actual enforcement algorithm, but only the constitutive relations that + * govern the behavior of the contact. So things like penalty, or friction, or kinematic constraint. + */ +class FrictionBase : public ConstitutiveBase +{ +public: + + /** + * @brief The standard data repository constructor + * @param name The name of the relation in the data repository + * @param parent The name of the parent Group that holds this relation object. + */ + FrictionBase( string const & name, + Group * const parent ); + + /** + * @brief default destructor + */ + virtual ~FrictionBase() override; + + /// Type of kernel wrapper for in-kernel update + using KernelWrapper = FrictionBaseUpdates; + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelWrapper() const; + + /** + * @struct Structure to hold scoped key names + */ + struct viewKeyStruct : public ConstitutiveBase::viewKeyStruct + { + /// string/key for the displacement jump threshold value + static constexpr char const * displacementJumpThresholdString() { return "displacementJumpThreshold"; } + }; + +protected: + + /// A threshold valued to determine whether a fracture is open or not. + real64 m_displacementJumpThreshold; + +}; + +} /* namespace constitutive */ + +} /* namespace geos */ + +#endif /* GEOS_CONSTITUTIVE_CONTACT_FRICTIONBASE_HPP_ */ diff --git a/src/coreComponents/constitutive/contact/FrictionSelector.hpp b/src/coreComponents/constitutive/contact/FrictionSelector.hpp new file mode 100644 index 00000000000..7ed06f6a797 --- /dev/null +++ b/src/coreComponents/constitutive/contact/FrictionSelector.hpp @@ -0,0 +1,56 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FrictionSelector.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_CONTACT_CONTACTSELECTOR_HPP_ +#define GEOS_CONSTITUTIVE_CONTACT_CONTACTSELECTOR_HPP_ + +#include "constitutive/ConstitutivePassThruHandler.hpp" +#include "constitutive/contact/CoulombFriction.hpp" +#include "constitutive/contact/FrictionlessContact.hpp" +#include "constitutive/contact/RateAndStateFriction.hpp" + +namespace geos +{ + +namespace constitutive +{ + +template< typename LAMBDA > +void constitutiveUpdatePassThru( FrictionBase const & contact, + LAMBDA && lambda ) +{ + ConstitutivePassThruHandler< FrictionlessContact, + CoulombFriction, + RateAndStateFriction >::execute( contact, std::forward< LAMBDA >( lambda ) ); +} + +template< typename LAMBDA > +void constitutiveUpdatePassThru( FrictionBase & contact, + LAMBDA && lambda ) +{ + ConstitutivePassThruHandler< FrictionlessContact, + CoulombFriction, + RateAndStateFriction >::execute( contact, std::forward< LAMBDA >( lambda ) ); +} + +} /* namespace constitutive */ + +} /* namespace geos */ + +#endif // GEOS_CONSTITUTIVE_CONTACT_CONTACTSELECTOR_HPP_ diff --git a/src/coreComponents/constitutive/contact/FrictionlessContact.cpp b/src/coreComponents/constitutive/contact/FrictionlessContact.cpp index 3e16b4e3e77..de63d4d8812 100644 --- a/src/coreComponents/constitutive/contact/FrictionlessContact.cpp +++ b/src/coreComponents/constitutive/contact/FrictionlessContact.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -28,24 +29,15 @@ namespace constitutive FrictionlessContact::FrictionlessContact( string const & name, Group * const parent ): - ContactBase( name, parent ) + FrictionBase( name, parent ) {} FrictionlessContact::~FrictionlessContact() {} -void FrictionlessContact::allocateConstitutiveData( Group & parent, - localIndex const numConstitutivePointsPerParentIndex ) +FrictionlessContactUpdates FrictionlessContact::createKernelUpdates() const { - ContactBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex ); -} - -FrictionlessContactUpdates FrictionlessContact::createKernelWrapper() const -{ - return FrictionlessContactUpdates( m_penaltyStiffness, - m_shearStiffness, - m_displacementJumpThreshold, - *m_apertureTable ); + return FrictionlessContactUpdates( m_displacementJumpThreshold ); } REGISTER_CATALOG_ENTRY( ConstitutiveBase, FrictionlessContact, string const &, Group * const ) diff --git a/src/coreComponents/constitutive/contact/FrictionlessContact.hpp b/src/coreComponents/constitutive/contact/FrictionlessContact.hpp index 62e9a908402..1b17e07dfd7 100644 --- a/src/coreComponents/constitutive/contact/FrictionlessContact.hpp +++ b/src/coreComponents/constitutive/contact/FrictionlessContact.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,7 @@ #ifndef GEOS_CONSTITUTIVE_CONTACT_FRICTIONLESSCONTACT_HPP_ #define GEOS_CONSTITUTIVE_CONTACT_FRICTIONLESSCONTACT_HPP_ -#include "constitutive/contact/ContactBase.hpp" +#include "constitutive/contact/FrictionBase.hpp" namespace geos { @@ -32,15 +33,12 @@ namespace constitutive * * This class is used for in-kernel contact relation updates */ -class FrictionlessContactUpdates : public ContactBaseUpdates +class FrictionlessContactUpdates : public FrictionBaseUpdates { public: - FrictionlessContactUpdates( real64 const & penaltyStiffness, - real64 const & shearStiffness, - real64 const & displacementJumpThreshold, - TableFunction const & apertureTable ) - : ContactBaseUpdates( penaltyStiffness, shearStiffness, displacementJumpThreshold, apertureTable ) + FrictionlessContactUpdates( real64 const & displacementJumpThreshold ) + : FrictionBaseUpdates( displacementJumpThreshold ) {} /// Default copy constructor @@ -60,35 +58,10 @@ class FrictionlessContactUpdates : public ContactBaseUpdates GEOS_HOST_DEVICE inline - virtual void computeTraction( localIndex const k, - arraySlice1d< real64 const > const & oldDispJump, - arraySlice1d< real64 const > const & dispJump, - integer const & fractureState, - arraySlice1d< real64 > const & tractionVector, - arraySlice2d< real64 > const & dTractionVector_dJump ) const override final; - - - GEOS_HOST_DEVICE - inline - virtual void updateFractureState( localIndex const k, - arraySlice1d< real64 const > const & dispJump, + virtual void updateFractureState( arraySlice1d< real64 const > const & dispJump, arraySlice1d< real64 const > const & tractionVector, integer & fractureState ) const override final; - - /** - * @brief Evaluate the limit tangential traction norm and return the derivative wrt normal traction - * @param[in] normalTraction the normal traction - * @param[out] dLimitTangentialTractionNorm_dTraction the derivative of the limit tangential traction norm wrt normal traction - * @return the limit tangential traction norm - */ - GEOS_HOST_DEVICE - inline - virtual real64 computeLimitTangentialTractionNorm( real64 const & normalTraction, - real64 & dLimitTangentialTractionNorm_dTraction ) const override final - { GEOS_UNUSED_VAR( normalTraction, dLimitTangentialTractionNorm_dTraction ); return 0.0; } - -private: }; @@ -99,7 +72,7 @@ class FrictionlessContactUpdates : public ContactBaseUpdates * This does not include the actual enforcement algorithm, but only the constitutive relations that * govern the behavior of the contact. So things like penalty, or friction, or kinematic constraint. */ -class FrictionlessContact : public ContactBase +class FrictionlessContact : public FrictionBase { public: @@ -123,9 +96,6 @@ class FrictionlessContact : public ContactBase virtual string getCatalogName() const override { return catalogName(); } - virtual void allocateConstitutiveData( dataRepository::Group & parent, - localIndex const numConstitutivePointsPerParentIndex ) override; - /// Type of kernel wrapper for in-kernel update using KernelWrapper = FrictionlessContactUpdates; @@ -133,7 +103,7 @@ class FrictionlessContact : public ContactBase * @brief Create an update kernel wrapper. * @return the wrapper */ - KernelWrapper createKernelWrapper() const; + KernelWrapper createKernelUpdates() const; /** * @struct Structure to hold scoped key names @@ -145,33 +115,13 @@ class FrictionlessContact : public ContactBase }; -GEOS_HOST_DEVICE -inline void FrictionlessContactUpdates::computeTraction( localIndex const k, - arraySlice1d< real64 const > const & oldDispJump, - arraySlice1d< real64 const > const & dispJump, - integer const & fractureState, - arraySlice1d< real64 > const & tractionVector, - arraySlice2d< real64 > const & dTractionVector_dJump ) const -{ - GEOS_UNUSED_VAR( k, oldDispJump ); - - bool const isOpen = fractureState == fields::contact::FractureState::Open; - - tractionVector[0] = isOpen ? 0.0 : m_penaltyStiffness * dispJump[0]; - tractionVector[1] = 0.0; - tractionVector[2] = 0.0; - - LvArray::forValuesInSlice( dTractionVector_dJump, []( real64 & val ){ val = 0.0; } ); - dTractionVector_dJump( 0, 0 ) = isOpen ? 0.0 : m_penaltyStiffness; -} GEOS_HOST_DEVICE -inline void FrictionlessContactUpdates::updateFractureState( localIndex const k, - arraySlice1d< real64 const > const & dispJump, +inline void FrictionlessContactUpdates::updateFractureState( arraySlice1d< real64 const > const & dispJump, arraySlice1d< real64 const > const & tractionVector, integer & fractureState ) const { - GEOS_UNUSED_VAR( k, tractionVector ); + GEOS_UNUSED_VAR( tractionVector ); using namespace fields::contact; fractureState = dispJump[0] > m_displacementJumpThreshold ? FractureState::Open : FractureState::Stick; } diff --git a/src/coreComponents/constitutive/contact/HydraulicApertureBase.cpp b/src/coreComponents/constitutive/contact/HydraulicApertureBase.cpp new file mode 100644 index 00000000000..2f5c715453c --- /dev/null +++ b/src/coreComponents/constitutive/contact/HydraulicApertureBase.cpp @@ -0,0 +1,49 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file HydraulicApertureBase.cpp + */ + + +#include "HydraulicApertureBase.hpp" + + +namespace geos +{ + +namespace constitutive +{ + +HydraulicApertureBase::HydraulicApertureBase( string const & name, + Group * const parent ): + ConstitutiveBase( name, parent ), + m_aperture0( 0.0 ) +{ + /// TODO: must become a required parameter. + registerWrapper( viewKeyStruct::apertureZeroString(), &m_aperture0 ). + setInputFlag( dataRepository::InputFlags::OPTIONAL ). + setApplyDefaultValue( 1e-6 ). + setDescription( "Reference hydraulic aperture. It is the aperture at zero normal stress." ); +} + +HydraulicApertureBase::~HydraulicApertureBase() +{} + + + +} /* namespace constitutive */ + +} /* namespace geos */ diff --git a/src/coreComponents/constitutive/contact/HydraulicApertureBase.hpp b/src/coreComponents/constitutive/contact/HydraulicApertureBase.hpp new file mode 100644 index 00000000000..701a20213fc --- /dev/null +++ b/src/coreComponents/constitutive/contact/HydraulicApertureBase.hpp @@ -0,0 +1,74 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file HydraulicApertureBase.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_CONTACT_HYDRAULICAPERTUREBASE_HPP_ +#define GEOS_CONSTITUTIVE_CONTACT_HYDRAULICAPERTUREBASE_HPP_ + +#include "constitutive/ConstitutiveBase.hpp" +#include "functions/TableFunction.hpp" +#include "physicsSolvers/contact/ContactFields.hpp" + + +namespace geos +{ + +namespace constitutive +{ + +/** + * @class HydraulicApertureBase + * + * This class serves as the interface for implementing contact enforcement constitutive relations. + * This does not include the actual enforcement algorithm, but only the constitutive relations that + * govern the behavior of the contact. So things like penalty, or friction, or kinematic constraint. + */ +class HydraulicApertureBase : public ConstitutiveBase +{ +public: + + /** + * @brief The standard data repository constructor + * @param name The name of the relation in the data repository + * @param parent The name of the parent Group that holds this relation object. + */ + HydraulicApertureBase( string const & name, + Group * const parent ); + + /** + * @brief default destructor + */ + virtual ~HydraulicApertureBase() override; + +protected: + + struct viewKeyStruct : public ConstitutiveBase::viewKeyStruct + { + /// string/key for aperture under zero normal stress + static constexpr char const * apertureZeroString() { return "referenceAperture"; } + }; + + /// Reference hydraulic aperture. Aperture at zero normal stress + real64 m_aperture0; /// TODO: this will replace what is currently called defaultAperture. +}; + +} /* namespace constitutive */ + +} /* namespace geos */ + +#endif /* GEOS_CONSTITUTIVE_CONTACT_HYDRAULICAPERTURETABLE_HPP_ */ diff --git a/src/coreComponents/constitutive/contact/HydraulicApertureRelationSelector.hpp b/src/coreComponents/constitutive/contact/HydraulicApertureRelationSelector.hpp new file mode 100644 index 00000000000..f8675f1dc1e --- /dev/null +++ b/src/coreComponents/constitutive/contact/HydraulicApertureRelationSelector.hpp @@ -0,0 +1,53 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FrictionSelector.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_CONTACT_CONTACTSELECTOR_HPP_ +#define GEOS_CONSTITUTIVE_CONTACT_CONTACTSELECTOR_HPP_ + +#include "constitutive/ConstitutivePassThruHandler.hpp" +#include "constitutive/contact/HydraulicApertureTable.hpp" +#include "constitutive/contact/BartonBandis.hpp" + +namespace geos +{ + +namespace constitutive +{ + +template< typename LAMBDA > +void constitutiveUpdatePassThru( HydraulicApertureBase const & contact, + LAMBDA && lambda ) +{ + ConstitutivePassThruHandler< HydraulicApertureTable, + BartonBandis >::execute( contact, std::forward< LAMBDA >( lambda ) ); +} + +template< typename LAMBDA > +void constitutiveUpdatePassThru( HydraulicApertureBase & contact, + LAMBDA && lambda ) +{ + ConstitutivePassThruHandler< HydraulicApertureTable, + BartonBandis >::execute( contact, std::forward< LAMBDA >( lambda ) ); +} + +} /* namespace constitutive */ + +} /* namespace geos */ + +#endif // GEOS_CONSTITUTIVE_CONTACT_CONTACTSELECTOR_HPP_ diff --git a/src/coreComponents/constitutive/contact/HydraulicApertureTable.cpp b/src/coreComponents/constitutive/contact/HydraulicApertureTable.cpp new file mode 100644 index 00000000000..6fe5c08b42f --- /dev/null +++ b/src/coreComponents/constitutive/contact/HydraulicApertureTable.cpp @@ -0,0 +1,159 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file HydraulicApertureTable.cpp + */ + +#include "HydraulicApertureTable.hpp" +#include "functions/FunctionManager.hpp" +#include "functions/TableFunction.hpp" + +namespace geos +{ + +using namespace dataRepository; + +namespace constitutive +{ + +HydraulicApertureTable::HydraulicApertureTable( string const & name, + Group * const parent ): + HydraulicApertureBase( name, parent ), + m_apertureTable( nullptr ) +{ + registerWrapper( viewKeyStruct::apertureToleranceString(), &m_apertureTolerance ). + setApplyDefaultValue( 1.0e-9 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Value to be used to avoid floating point errors in expressions involving aperture. " + "For example in the case of dividing by the actual aperture (not the effective aperture " + "that results from the aperture function) this value may be used to avoid the 1/0 error. " + "Note that this value may have some physical significance in its usage, as it may be used " + "to smooth out highly nonlinear behavior associated with 1/0 in addition to avoiding the " + "1/0 error." ); + + registerWrapper( viewKeyStruct::apertureTableNameString(), &m_apertureTableName ). + setRTTypeName( rtTypes::CustomTypes::groupNameRef ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Name of the aperture table" ); +} + +HydraulicApertureTable::~HydraulicApertureTable() +{} + + + +void HydraulicApertureTable::postInputInitialization() +{ + + GEOS_THROW_IF( m_apertureTableName.empty(), + getFullName() << ": the aperture table name " << m_apertureTableName << " is empty", InputError ); + +} + + +void HydraulicApertureTable::allocateConstitutiveData( Group & parent, + localIndex const numConstitutivePointsPerParentIndex ) +{ + ConstitutiveBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex ); + + FunctionManager & functionManager = FunctionManager::getInstance(); + + GEOS_THROW_IF( !functionManager.hasGroup( m_apertureTableName ), + getFullName() << ": the aperture table named " << m_apertureTableName << " could not be found", + InputError ); + + TableFunction & apertureTable = functionManager.getGroup< TableFunction >( m_apertureTableName ); + validateApertureTable( apertureTable ); + + ArrayOfArraysView< real64 > coords = apertureTable.getCoordinates(); + arraySlice1d< real64 const > apertureValues = coords[0]; + array1d< real64 > & hydraulicApertureValues = apertureTable.getValues(); + + localIndex const n = apertureValues.size()-1; + real64 const slope = ( hydraulicApertureValues[n] - hydraulicApertureValues[n-1] ) / ( apertureValues[n] - apertureValues[n-1] ); + real64 const apertureTransition = ( hydraulicApertureValues[n] - slope * apertureValues[n] ) / ( 1.0 - slope ); + + // if the aperture transition is larger than the last coordinates, we enlarge the table + // this check is necessary to ensure that the coordinates are strictly increasing + if( apertureTransition > apertureValues[apertureValues.size()-1] ) + { + GEOS_LOG_RANK_0( GEOS_FMT ( "Adding aperture transition for table {}:", m_apertureTableName ) ); + std::ostringstream s_orig; + for( localIndex i = 0; i < apertureValues.size(); i++ ) + s_orig << "[ " << apertureValues[i] << ", " << hydraulicApertureValues[i] << " ] "; + GEOS_LOG_RANK_0( GEOS_FMT ( " Original table = {}", s_orig.str())); + + coords.emplaceBack( 0, apertureTransition ); + hydraulicApertureValues.emplace_back( apertureTransition ); + // if the aperture transition is larger than 0, we keep enlarging the table + // this check is necessary to ensure that the coordinates are strictly increasing + if( apertureTransition > 0 ) + { + coords.emplaceBack( 0, apertureTransition*10e9 ); + hydraulicApertureValues.emplace_back( apertureTransition*10e9 ); + apertureTable.reInitializeFunction(); + } + + std::ostringstream s_mod; + for( localIndex i = 0; i < apertureValues.size(); i++ ) + s_mod << "[ " << apertureValues[i] << ", " << hydraulicApertureValues[i] << " ] "; + GEOS_LOG_RANK_0( GEOS_FMT ( " Modified table = {}", s_mod.str())); + } + + m_apertureTable = &apertureTable; +} + + +void HydraulicApertureTable::validateApertureTable( TableFunction const & apertureTable ) const +{ + ArrayOfArraysView< real64 const > const coords = apertureTable.getCoordinates(); + arrayView1d< real64 const > const & hydraulicApertureValues = apertureTable.getValues(); + + GEOS_THROW_IF( coords.size() > 1, + getFullName() << ": Aperture limiter table cannot be greater than a 1D table.", + InputError ); + + arraySlice1d< real64 const > apertureValues = coords[0]; + localIndex const size = apertureValues.size(); + + GEOS_THROW_IF( coords( 0, size-1 ) > 0.0 || coords( 0, size-1 ) < 0.0, + getFullName() << ": Invalid aperture limiter table. Last coordinate must be zero!", + InputError ); + + GEOS_THROW_IF( apertureValues.size() < 2, + getFullName() << ": Invalid aperture limiter table. Must have more than two points specified", + InputError ); + + localIndex const n = apertureValues.size()-1; + real64 const slope = ( hydraulicApertureValues[n] - hydraulicApertureValues[n-1] ) / ( apertureValues[n] - apertureValues[n-1] ); + + GEOS_THROW_IF( slope >= 1.0, + getFullName() << ": Invalid aperture table. The slope of the last two points >= 1 is invalid.", + InputError ); +} + + + +HydraulicApertureTableUpdates HydraulicApertureTable::createKernelWrapper() const +{ + return HydraulicApertureTableUpdates( *m_apertureTable ); +} + +REGISTER_CATALOG_ENTRY( ConstitutiveBase, HydraulicApertureTable, string const &, Group * const ) + +} /* end namespace constitutive */ + +} /* end namespace geos */ diff --git a/src/coreComponents/constitutive/contact/HydraulicApertureTable.hpp b/src/coreComponents/constitutive/contact/HydraulicApertureTable.hpp new file mode 100644 index 00000000000..49aad4568bd --- /dev/null +++ b/src/coreComponents/constitutive/contact/HydraulicApertureTable.hpp @@ -0,0 +1,170 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file HydraulicApertureTable.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_CONTACT_HYDRAULICAPERTURETABLE_HPP_ +#define GEOS_CONSTITUTIVE_CONTACT_HYDRAULICAPERTURETABLE_HPP_ + +#include "constitutive/contact/HydraulicApertureBase.hpp" +#include "functions/TableFunction.hpp" + + +namespace geos +{ + +namespace constitutive +{ + +/** + * @class HydraulicApertureTableUpdates + * + * This class is used for in-kernel contact relation updates + */ +class HydraulicApertureTableUpdates +{ +public: + + HydraulicApertureTableUpdates( TableFunction const & apertureTable ) + : m_apertureTable( apertureTable.createKernelWrapper() ) + {} + + /// Default copy constructor + HydraulicApertureTableUpdates( HydraulicApertureTableUpdates const & ) = default; + + /// Default move constructor + HydraulicApertureTableUpdates( HydraulicApertureTableUpdates && ) = default; + + /// Deleted default constructor + HydraulicApertureTableUpdates() = default; + + /// Deleted copy assignment operator + HydraulicApertureTableUpdates & operator=( HydraulicApertureTableUpdates const & ) = delete; + + /// Deleted move assignment operator + HydraulicApertureTableUpdates & operator=( HydraulicApertureTableUpdates && ) = delete; + + /** + * @brief Evaluate the effective aperture, and its derivative wrt aperture + * @param[in] aperture the model aperture/gap + * @param[out] dHydraulicAperture_dAperture the derivative of the effective aperture wrt aperture + * @return The hydraulic aperture that is always > 0 + */ + GEOS_HOST_DEVICE + real64 computeHydraulicAperture( real64 const aperture, + real64 const normalTraction, + real64 & dHydraulicAperture_daperture, + real64 & dHydraulicAperture_dNormalStress ) const; + +protected: + + /// The aperture table function wrapper + TableFunction::KernelWrapper m_apertureTable; +}; + + +/** + * @class HydraulicApertureTable + * + * This class serves as the interface for implementing contact enforcement constitutive relations. + * This does not include the actual enforcement algorithm, but only the constitutive relations that + * govern the behavior of the contact. So things like penalty, or friction, or kinematic constraint. + */ +class HydraulicApertureTable : public HydraulicApertureBase +{ +public: + + /** + * @brief The standard data repository constructor + * @param name The name of the relation in the data repository + * @param parent The name of the parent Group that holds this relation object. + */ + HydraulicApertureTable( string const & name, + Group * const parent ); + + /** + * @brief default destructor + */ + virtual ~HydraulicApertureTable() override; + + static string catalogName() { return "HydraulicApertureTable"; } + + virtual string getCatalogName() const override { return catalogName(); } + + virtual void allocateConstitutiveData( dataRepository::Group & parent, + localIndex const numConstitutivePointsPerParentIndex ) override final; + + + + /// Type of kernel wrapper for in-kernel update + using KernelWrapper = HydraulicApertureTableUpdates; + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelWrapper() const; + + /** + * @struct Structure to hold scoped key names + */ + struct viewKeyStruct : public ConstitutiveBase::viewKeyStruct + { + /// string/key for aperture tolerance + static constexpr char const * apertureToleranceString() { return "apertureTolerance"; } + + /// string/key for aperture table name + static constexpr char const * apertureTableNameString() { return "apertureTableName"; } + }; + + +protected: + + virtual void postInputInitialization() override; + + /** + * @brief Validate the values provided in the aperture table + * @param[in] apertureTable the effective aperture vs aperture table + */ + void validateApertureTable( TableFunction const & apertureTable ) const; + + /// The aperture tolerance to avoid floating point errors in expressions involving aperture + real64 m_apertureTolerance; + + /// The name of the aperture table, if any + string m_apertureTableName; + + /// Pointer to the function that limits the model aperture to a physically admissible value. + TableFunction const * m_apertureTable; +}; + +GEOS_HOST_DEVICE +GEOS_FORCE_INLINE +real64 HydraulicApertureTableUpdates::computeHydraulicAperture( real64 const aperture, + real64 const normalTraction, + real64 & dHydraulicAperture_dAperture, + real64 & dHydraulicAperture_dNormalStress ) const +{ + GEOS_UNUSED_VAR( normalTraction, dHydraulicAperture_dNormalStress ); + return m_apertureTable.compute( &aperture, &dHydraulicAperture_dAperture ); +} + +} /* namespace constitutive */ + +} /* namespace geos */ + +#endif /* GEOS_CONSTITUTIVE_CONTACT_HYDRAULICAPERTURETABLE_HPP_ */ diff --git a/src/coreComponents/constitutive/contact/RateAndStateFriction.cpp b/src/coreComponents/constitutive/contact/RateAndStateFriction.cpp new file mode 100644 index 00000000000..30d43c9ae7f --- /dev/null +++ b/src/coreComponents/constitutive/contact/RateAndStateFriction.cpp @@ -0,0 +1,116 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file RateAndStateFriction.cpp + */ + +#include "RateAndStateFriction.hpp" + +namespace geos +{ + +using namespace dataRepository; + +namespace constitutive +{ + +RateAndStateFriction::RateAndStateFriction( string const & name, Group * const parent ): + FrictionBase( name, parent ) +{ + registerWrapper( viewKeyStruct::aCoefficientString(), &m_a ). + setDescription( "Rate- and State-dependent friction coefficient a." ); + + registerWrapper( viewKeyStruct::bCoefficientString(), &m_b ). + setDescription( "Rate- and State-dependent friction coefficient b." ); + + registerWrapper( viewKeyStruct::DcCoefficientString(), &m_Dc ). + setDescription( "Rate- and State-dependent friction characteristic length." ); + + registerWrapper( viewKeyStruct::referenceVelocityString(), &m_V0 ). + setDescription( "Rate- and State-dependent friction reference slip rate." ); + + registerWrapper( viewKeyStruct::referenceFrictionCoefficientString(), &m_mu0 ). + setDescription( "Rate- and State-dependent friction reference friction coefficient." ); + + registerWrapper( viewKeyStruct::frictionCoefficientString(), &m_frictionCoefficient ). + setApplyDefaultValue( 0.0 ). + setDescription( "Friction coefficient" ); + + /// Default values + registerWrapper( viewKeyStruct::defaultACoefficientString(), &m_defaultA ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Default value of the Rate- and State-dependent friction coefficient a." ); + + registerWrapper( viewKeyStruct::defaultBCoefficientString(), &m_defaultB ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Default value of the Rate- and State-dependent friction coefficient b." ); + + registerWrapper( viewKeyStruct::defaultDcCoefficientString(), &m_defaultDc ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Default value of the Rate- and State-dependent friction characteristic length." ); + + registerWrapper( viewKeyStruct::defaultReferenceVelocityString(), &m_defaultV0 ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Default value of the Rate- and State-dependent friction reference slip rate." ); + + registerWrapper( viewKeyStruct::defaultReferenceFrictionCoefficientString(), &m_defaultMu0 ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Default value of the Rate- and State-dependent friction reference friction coefficient." ); +} + +RateAndStateFriction::~RateAndStateFriction() +{} + +void RateAndStateFriction::postInputInitialization() +{ + this->getWrapper< array1d< real64 > >( viewKeyStruct::aCoefficientString() ). + setApplyDefaultValue( m_defaultA ); + + this->getWrapper< array1d< real64 > >( viewKeyStruct::bCoefficientString() ). + setApplyDefaultValue( m_defaultB ); + + this->getWrapper< array1d< real64 > >( viewKeyStruct::DcCoefficientString() ). + setApplyDefaultValue( m_defaultDc ); + + this->getWrapper< array1d< real64 > >( viewKeyStruct::referenceVelocityString() ). + setApplyDefaultValue( m_defaultV0 ); + + this->getWrapper< array1d< real64 > >( viewKeyStruct::referenceFrictionCoefficientString() ). + setApplyDefaultValue( m_defaultMu0 ); + + this->getWrapper< array1d< real64 > >( viewKeyStruct::frictionCoefficientString() ). + setApplyDefaultValue( m_defaultMu0 ); +} + +void RateAndStateFriction::allocateConstitutiveData( Group & parent, + localIndex const numConstitutivePointsPerParentIndex ) +{ + FrictionBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex ); +} + +using RateAndStateFrictionUpdates = RateAndStateFriction::KernelWrapper; +RateAndStateFrictionUpdates RateAndStateFriction::createKernelUpdates() const +{ + return RateAndStateFrictionUpdates( m_displacementJumpThreshold, + m_frictionCoefficient, m_a, m_b, + m_Dc, m_V0, m_mu0 ); +} + +REGISTER_CATALOG_ENTRY( ConstitutiveBase, RateAndStateFriction, string const &, Group * const ) + +} /* namespace constitutive */ + +} /* namespace geos */ diff --git a/src/coreComponents/constitutive/contact/RateAndStateFriction.hpp b/src/coreComponents/constitutive/contact/RateAndStateFriction.hpp new file mode 100644 index 00000000000..e05a4089838 --- /dev/null +++ b/src/coreComponents/constitutive/contact/RateAndStateFriction.hpp @@ -0,0 +1,327 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file RateAndStateFriction.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_CONTACT_RATEANDSTATEFRICTION_HPP_ +#define GEOS_CONSTITUTIVE_CONTACT_RATEANDSTATEFRICTION_HPP_ + +#include "FrictionBase.hpp" + +namespace geos +{ + +namespace constitutive +{ + +/** + * @class RateAndStateFrictionUpdates + * + * This class is used for in-kernel contact relation updates + */ + + +/** + * @class RateAndStateFriction + * + * Class to provide a RateAndStateFriction friction model. + */ +class RateAndStateFriction : public FrictionBase +{ +public: + + /** + * constructor + * @param[in] name name of the instance in the catalog + * @param[in] parent the group which contains this instance + */ + RateAndStateFriction( string const & name, Group * const parent ); + + /** + * Default Destructor + */ + virtual ~RateAndStateFriction() override; + + static string catalogName() { return "RateAndStateFriction"; } + + virtual string getCatalogName() const override { return catalogName(); } + + ///@} + + virtual void allocateConstitutiveData( dataRepository::Group & parent, + localIndex const numConstitutivePointsPerParentIndex ) override final; + + class KernelWrapper : public FrictionBaseUpdates + { +public: + KernelWrapper( real64 const displacementJumpThreshold, + arrayView1d< real64 > frictionCoefficient, + arrayView1d< real64 const > a, + arrayView1d< real64 const > b, + arrayView1d< real64 const > Dc, + arrayView1d< real64 const > V0, + arrayView1d< real64 const > mu0 ) + : FrictionBaseUpdates( displacementJumpThreshold ), + m_frictionCoefficient( frictionCoefficient ), + m_a( a ), + m_b( b ), + m_Dc( Dc ), + m_V0( V0 ), + m_mu0( mu0 ) + {} + + /// Default copy constructor + KernelWrapper( KernelWrapper const & ) = default; + + /// Default move constructor + KernelWrapper( KernelWrapper && ) = default; + + /// Deleted default constructor + KernelWrapper() = delete; + + /// Deleted copy assignment operator + KernelWrapper & operator=( KernelWrapper const & ) = delete; + + /// Deleted move assignment operator + KernelWrapper & operator=( KernelWrapper && ) = delete; + + GEOS_HOST_DEVICE + real64 getACoefficient( localIndex const k ) const { return m_a[k]; } + + GEOS_HOST_DEVICE + real64 getBCoefficient( localIndex const k ) const { return m_b[k]; } + + GEOS_HOST_DEVICE + real64 getDcCoefficient( localIndex const k ) const { return m_Dc[k]; } + + GEOS_HOST_DEVICE + inline + virtual void updateFractureState( arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & tractionVector, + integer & fractureState ) const override final; + + GEOS_HOST_DEVICE + inline real64 frictionCoefficient( localIndex const k, + real64 const slipRate, + real64 const stateVariable ) const; + + GEOS_HOST_DEVICE + inline real64 dFrictionCoefficient_dSlipRate( localIndex const k, + real64 const slipRate, + real64 const stateVariable ) const; + + GEOS_HOST_DEVICE + inline real64 dFrictionCoefficient_dStateVariable( localIndex const k, + real64 const slipRate, + real64 const stateVariable ) const; + + GEOS_HOST_DEVICE + inline real64 stateEvolution( localIndex const k, + real64 const slipRate, + real64 const stateVariable ) const; + + GEOS_HOST_DEVICE + inline real64 dStateEvolution_dStateVariable( localIndex const k, + real64 const slipRate, + real64 const stateVariable ) const; + + GEOS_HOST_DEVICE + inline real64 dStateEvolution_dSlipRate( localIndex const k, + real64 const slipRate, + real64 const stateVariable ) const; +private: + /// The friction coefficient + arrayView1d< real64 > m_frictionCoefficient; + + /// Rate and State coefficient a + arrayView1d< real64 const > m_a; + + /// Rate and State coefficient b + arrayView1d< real64 const > m_b; + + /// Rate and State characteristic length + arrayView1d< real64 const > m_Dc; + + /// Rate and State reference velocity + arrayView1d< real64 const > m_V0; + + /// Rate and State reference friction coefficient + arrayView1d< real64 const > m_mu0; + }; + + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelUpdates() const; + +private: + + virtual void postInputInitialization() override; + + /// The friction coefficient for each upper level dimension (i.e. cell) of *this + array1d< real64 > m_frictionCoefficient; + + /// Rate and State coefficient a + array1d< real64 > m_a; + + /// Rate and State coefficient b + array1d< real64 > m_b; + + /// Rate and State characteristic length + array1d< real64 > m_Dc; + + /// Rate and State reference velocity + array1d< real64 > m_V0; + + /// Rate and State reference friction coefficient + array1d< real64 > m_mu0; + + /// Default value of Rate and State coefficient a + real64 m_defaultA; + /// Default value of Rate and State coefficient b + real64 m_defaultB; + + /// Default value of Rate and State characteristic length + real64 m_defaultDc; + + /// Default value of Rate and State reference velocity + real64 m_defaultV0; + + /// Default value of Rate and State reference friction coefficient + real64 m_defaultMu0; + +/** + * @struct Set of "char const *" and keys for data specified in this class. + */ + struct viewKeyStruct : public FrictionBase::viewKeyStruct + { + /// string/key for friction coefficient + static constexpr char const * frictionCoefficientString() { return "frictionCoefficient"; } + /// string/key for Rate and State coefficient a + static constexpr char const * aCoefficientString() { return "a"; } + /// string/key for Rate and State coefficient b + static constexpr char const * bCoefficientString() { return "b"; } + /// string/key for Rate and State characteristic length + static constexpr char const * DcCoefficientString() { return "Dc"; } + /// string/key for reference slip rate + static constexpr char const * referenceVelocityString() { return "referenceVelocity"; } + /// string/key for reference friction coefficient + static constexpr char const * referenceFrictionCoefficientString() { return "referenceFrictionCoefficient"; } + /// string/key for the default value of Rate and State coefficient a + static constexpr char const * defaultACoefficientString() { return "defaultA"; } + /// string/key for the default value of Rate and State coefficient b + static constexpr char const * defaultBCoefficientString() { return "defaultB"; } + /// string/key for the default value of Rate and State characteristic length + static constexpr char const * defaultDcCoefficientString() { return "defaultDc"; } + /// string/key for the default value ofreference slip rate + static constexpr char const * defaultReferenceVelocityString() { return "defaultReferenceVelocity"; } + /// string/key for the default value of reference friction coefficient + static constexpr char const * defaultReferenceFrictionCoefficientString() { return "defaultReferenceFrictionCoefficient"; } + }; + +}; + +GEOS_HOST_DEVICE +inline void RateAndStateFriction::KernelWrapper::updateFractureState( arraySlice1d< real64 const > const & dispJump, + arraySlice1d< real64 const > const & tractionVector, + integer & fractureState ) const +{ + + GEOS_UNUSED_VAR( tractionVector ); + using namespace fields::contact; + + if( dispJump[0] > -m_displacementJumpThreshold ) + { + fractureState = FractureState::Open; + } + else + { + fractureState = FractureState::Slip; + } +} + +GEOS_HOST_DEVICE +inline real64 RateAndStateFriction::KernelWrapper::frictionCoefficient( localIndex const k, + real64 const slipRate, + real64 const stateVariable ) const +{ + + real64 const arg = ( slipRate / (2 * m_V0[k]) ) * LvArray::math::exp( stateVariable / m_a[k] ); + m_frictionCoefficient[k] = m_a[k] * LvArray::math::asinh( arg ); + + return m_frictionCoefficient[k]; +} + +GEOS_HOST_DEVICE +inline real64 RateAndStateFriction::KernelWrapper::dFrictionCoefficient_dSlipRate( localIndex const k, + real64 const slipRate, + real64 const stateVariable ) const +{ + + real64 const arg = ( slipRate / (2 * m_V0[k]) ) * LvArray::math::exp( stateVariable / m_a[k] ); + + return ( m_a[k] * LvArray::math::exp( stateVariable / m_a[k] ) ) / (2 * m_V0[k] * LvArray::math::sqrt( 1 + arg * arg )); +} + +GEOS_HOST_DEVICE +inline real64 RateAndStateFriction::KernelWrapper::dFrictionCoefficient_dStateVariable( localIndex const k, + real64 const slipRate, + real64 const stateVariable ) const +{ + + real64 const arg = ( slipRate / (2 * m_V0[k]) ) * LvArray::math::exp( stateVariable / m_a[k] ); + + return ( slipRate * LvArray::math::exp( stateVariable / m_a[k] ) ) / (2 * m_V0[k] * LvArray::math::sqrt( 1 + arg * arg )); +} + +GEOS_HOST_DEVICE +inline real64 RateAndStateFriction::KernelWrapper::stateEvolution( localIndex const k, + real64 const slipRate, + real64 const stateVariable ) const +{ + real64 const mu = frictionCoefficient( k, slipRate, stateVariable ); + + return -slipRate / m_Dc[k] * (mu - m_mu0[k] + (m_b[k] - m_a[k]) * LvArray::math::log( slipRate / m_V0[k] )); +} + +GEOS_HOST_DEVICE +inline real64 RateAndStateFriction::KernelWrapper::dStateEvolution_dStateVariable( localIndex const k, + real64 const slipRate, + real64 const stateVariable ) const +{ + return -slipRate / m_Dc[k] * dFrictionCoefficient_dStateVariable( k, slipRate, stateVariable ); +} + +GEOS_HOST_DEVICE +inline real64 RateAndStateFriction::KernelWrapper::dStateEvolution_dSlipRate( localIndex const k, + real64 const slipRate, + real64 const stateVariable ) const +{ + real64 const part1 = frictionCoefficient( k, slipRate, stateVariable ) - m_mu0[k] + (m_b[k] - m_a[k]) * LvArray::math::log( slipRate / m_V0[k] ); + + real64 const part2 = dFrictionCoefficient_dSlipRate( k, slipRate, stateVariable ) * slipRate + (m_b[k] - m_a[k]); + + return -1.0 / m_Dc[k] * ( part1 + part2 ); +} + +} /* namespace constitutive */ + +} /* namespace geos */ + +#endif /* GEOS_CONSTITUTIVE_CONTACT_RATEANDSTATEFRICTION_HPP_ */ diff --git a/src/coreComponents/constitutive/contact/deprecated/ApertureTableContact.cpp b/src/coreComponents/constitutive/contact/deprecated/ApertureTableContact.cpp deleted file mode 100644 index 8bcfc1fd689..00000000000 --- a/src/coreComponents/constitutive/contact/deprecated/ApertureTableContact.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file ApertureTableContact.cpp - */ - -#include "../deprecated/ApertureTableContact.hpp" - -#include "functions/FunctionManager.hpp" -#include "functions/TableFunction.hpp" - -namespace geos -{ - -using namespace dataRepository; - -namespace constitutive -{ - -ApertureTableContact::ApertureTableContact( string const & name, - Group * const parent ) - : ContactBase( name, parent ), - m_apertureTolerance( 1.0e-99 ), - m_apertureTable( nullptr ) -{ - registerWrapper( viewKeyStruct::apertureToleranceString(), &m_apertureTolerance ). - setApplyDefaultValue( 1.0e-9 ). - setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Value to be used to avoid floating point errors in expressions involving aperture. " - "For example in the case of dividing by the actual aperture (not the effective aperture " - "that results from the aperture function) this value may be used to avoid the 1/0 error. " - "Note that this value may have some physical significance in its usage, as it may be used " - "to smooth out highly nonlinear behavior associated with 1/0 in addition to avoiding the " - "1/0 error." ); - - registerWrapper( viewKeyStruct::apertureTableNameString(), &m_apertureTableName ). - setRTTypeName( rtTypes::CustomTypes::groupNameRef ). - setInputFlag( InputFlags::REQUIRED ). - setDescription( "Name of the aperture table" ); -} - -ApertureTableContact::~ApertureTableContact() -{} - -void ApertureTableContact::postProcessInput() -{ - FunctionManager const & functionManager = FunctionManager::getInstance(); - - GEOS_THROW_IF( m_apertureTableName.empty(), - getFullName() << ": the aperture table name " << m_apertureTableName << " is empty", - InputError ); - - GEOS_THROW_IF( !functionManager.hasGroup( m_apertureTableName ), - getFullName() << ": the aperture table named " << m_apertureTableName << " could not be found", - InputError ); -} - -void ApertureTableContact::initializePreSubGroups() -{ - FunctionManager & functionManager = FunctionManager::getInstance(); - TableFunction & apertureTable = functionManager.getGroup< TableFunction >( m_apertureTableName ); - validateApertureTable( apertureTable ); - - ArrayOfArraysView< real64 > coords = apertureTable.getCoordinates(); - arraySlice1d< real64 const > apertureValues = coords[0]; - array1d< real64 > & effectiveApertureValues = apertureTable.getValues(); - - localIndex const n = apertureValues.size()-1; - real64 const slope = ( effectiveApertureValues[n] - effectiveApertureValues[n-1] ) / ( apertureValues[n] - apertureValues[n-1] ); - real64 const apertureTransition = ( effectiveApertureValues[n] - slope * apertureValues[n] ) / ( 1.0 - slope ); - - coords.emplaceBack( 0, apertureTransition ); - effectiveApertureValues.emplace_back( apertureTransition ); - coords.emplaceBack( 0, apertureTransition*10e9 ); - effectiveApertureValues.emplace_back( apertureTransition*10e9 ); - apertureTable.reInitializeFunction(); - - m_apertureTable = &apertureTable; -} - -void ApertureTableContact::validateApertureTable( TableFunction const & apertureTable ) const -{ - ArrayOfArraysView< real64 const > const coords = apertureTable.getCoordinates(); - arrayView1d< real64 const > const & effectiveApertureValues = apertureTable.getValues(); - - GEOS_THROW_IF( coords.size() > 1, - getFullName() << ": Aperture limiter table cannot be greater than a 1D table.", - InputError ); - - arraySlice1d< real64 const > apertureValues = coords[0]; - localIndex const size = apertureValues.size(); - - GEOS_THROW_IF( coords( 0, size-1 ) > 0.0 || coords( 0, size-1 ) < 0.0, - getFullName() << ": Invalid aperture limiter table. Last coordinate must be zero!", - InputError ); - - GEOS_THROW_IF( apertureValues.size() < 2, - getFullName() << ": Invalid aperture limiter table. Must have more than two points specified", - InputError ); - - localIndex const n = apertureValues.size()-1; - real64 const slope = ( effectiveApertureValues[n] - effectiveApertureValues[n-1] ) / ( apertureValues[n] - apertureValues[n-1] ); - - GEOS_THROW_IF( slope >= 1.0, - getFullName() << ": Invalid aperture table. The slope of the last two points >= 1 is invalid.", - InputError ); -} - -ApertureTableContactUpdates ApertureTableContact::createKernelWrapper() const -{ - return ApertureTableContactUpdates( m_penaltyStiffness, - *m_apertureTable ); -} - -REGISTER_CATALOG_ENTRY( ConstitutiveBase, ApertureTableContact, string const &, Group * const ) - -} /* namespace constitutive */ - -} /* namespace geos */ diff --git a/src/coreComponents/constitutive/contact/deprecated/ApertureTableContact.hpp b/src/coreComponents/constitutive/contact/deprecated/ApertureTableContact.hpp deleted file mode 100644 index 9ed749274d5..00000000000 --- a/src/coreComponents/constitutive/contact/deprecated/ApertureTableContact.hpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file ApertureTableContact.hpp - */ - -#ifndef GEOS_CONSTITUTIVE_CONTACT_APERTURETABLECONTACT_HPP_ -#define GEOS_CONSTITUTIVE_CONTACT_APERTURETABLECONTACT_HPP_ - -#include "constitutive/contact/ContactBase.hpp" -#include "functions/TableFunction.hpp" - -namespace geos -{ - -namespace constitutive -{ - -/** - * @class ApertureTableContactUpdates - * - * This class is used for in-kernel contact relation updates - */ -class ApertureTableContactUpdates : public ContactBaseUpdates -{ -public: - - ApertureTableContactUpdates( real64 const & penaltyStiffness, - TableFunction const & apertureTable ) - : ContactBaseUpdates( penaltyStiffness ), - m_apertureTable( apertureTable.createKernelWrapper() ) - {} - - /// Default copy constructor - ApertureTableContactUpdates( ApertureTableContactUpdates const & ) = default; - - /// Default move constructor - ApertureTableContactUpdates( ApertureTableContactUpdates && ) = default; - - /// Deleted default constructor - ApertureTableContactUpdates() = delete; - - /// Deleted copy assignment operator - ApertureTableContactUpdates & operator=( ApertureTableContactUpdates const & ) = delete; - - /// Deleted move assignment operator - ApertureTableContactUpdates & operator=( ApertureTableContactUpdates && ) = delete; - - GEOS_HOST_DEVICE - inline - virtual real64 computeEffectiveAperture( real64 const aperture, - real64 & dEffectiveAperture_dAperture ) const; - - GEOS_HOST_DEVICE - inline - virtual void computeTraction( arraySlice1d< real64 const > const & dispJump, - arraySlice1d< real64 > const & tractionVector, - arraySlice2d< real64 > const & dTractionVector_dJump ) const; - - GEOS_HOST_DEVICE - inline - void addPressureToTraction( real64 const & pressure, - bool const isOpen, - arraySlice1d< real64 >const & tractionVector, - real64 & dTraction_dPressure ) const; - -private: - - /// The aperture table function wrapper - TableFunction::KernelWrapper m_apertureTable; - -}; - - -/** - * @class ApertureTableContact - */ -class ApertureTableContact : public ContactBase -{ -public: - - /** - * @brief The standard data repository constructor - * @param name The name of the relation in the data repository - * @param parent The name of the parent Group that holds this relation object. - */ - ApertureTableContact( string const & name, - Group * const parent ); - - /** - * @brief default destructor - */ - virtual ~ApertureTableContact() override; - - /** - * @brief Name that is used to register this a type of "ApertureTableContact" in the object catalog - * @return See description - */ - static string catalogName() { return "Contact"; } - - virtual string getCatalogName() const override { return catalogName(); } - - /** - * @brief accessor for aperture tolerance - * @return the aperture tolerance - */ - real64 apertureTolerance() const { return m_apertureTolerance; } - - /// Type of kernel wrapper for in-kernel update - using KernelWrapper = ApertureTableContactUpdates; - - /** - * @brief Create an update kernel wrapper. - * @return the wrapper - */ - KernelWrapper createKernelWrapper() const; - - /** - * @struct Structure to hold scoped key names - */ - struct viewKeyStruct : public ConstitutiveBase::viewKeyStruct - { - /// string/key for aperture tolerance - static constexpr char const * apertureToleranceString() { return "apertureTolerance"; } - - /// string/key for aperture table name - static constexpr char const * apertureTableNameString() { return "apertureTableName"; } - }; - -protected: - - virtual void postProcessInput() override; - - virtual void initializePreSubGroups() override; - - /** - * @brief Validate the values provided in the aperture table - * @param[in] apertureTable the effective aperture vs aperture table - */ - void validateApertureTable( TableFunction const & apertureTable ) const; - - /// The aperture tolerance to avoid floating point errors in expressions involving aperture - real64 m_apertureTolerance; - - /// The name of the aperture table, if any - string m_apertureTableName; - - /// Pointer to the function that limits the model aperture to a physically admissible value. - TableFunction const * m_apertureTable; - -}; - -GEOS_HOST_DEVICE -real64 ApertureTableContactUpdates::computeEffectiveAperture( real64 const aperture, - real64 & dEffectiveAperture_dAperture ) const -{ - return m_apertureTable.compute( &aperture, &dEffectiveAperture_dAperture ); -} - - -} /* namespace constitutive */ - -} /* namespace geos */ - -#endif /* GEOS_CONSTITUTIVE_CONTACT_APERTURETABLECONTACT_HPP_ */ diff --git a/src/coreComponents/constitutive/diffusion/ConstantDiffusion.cpp b/src/coreComponents/constitutive/diffusion/ConstantDiffusion.cpp index 45128b09e6c..cff80fed216 100644 --- a/src/coreComponents/constitutive/diffusion/ConstantDiffusion.cpp +++ b/src/coreComponents/constitutive/diffusion/ConstantDiffusion.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -59,7 +60,7 @@ void ConstantDiffusion::allocateConstitutiveData( dataRepository::Group & parent } } -void ConstantDiffusion::postProcessInput() +void ConstantDiffusion::postInputInitialization() { GEOS_THROW_IF( m_diffusivityComponents.size() != 3, GEOS_FMT( "{}: the size of the diffusivity must be equal to 3", diff --git a/src/coreComponents/constitutive/diffusion/ConstantDiffusion.hpp b/src/coreComponents/constitutive/diffusion/ConstantDiffusion.hpp index f4ae6c98348..66f586ab637 100644 --- a/src/coreComponents/constitutive/diffusion/ConstantDiffusion.hpp +++ b/src/coreComponents/constitutive/diffusion/ConstantDiffusion.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -95,7 +96,7 @@ class ConstantDiffusion : public DiffusionBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; private: diff --git a/src/coreComponents/constitutive/diffusion/DiffusionBase.cpp b/src/coreComponents/constitutive/diffusion/DiffusionBase.cpp index ae0d0aa7542..491bc987a99 100644 --- a/src/coreComponents/constitutive/diffusion/DiffusionBase.cpp +++ b/src/coreComponents/constitutive/diffusion/DiffusionBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -44,9 +45,9 @@ DiffusionBase::DiffusionBase( string const & name, Group * const parent ) registerField( fields::diffusion::phaseDiffusivityMultiplier{}, &m_phaseDiffusivityMultiplier ); } -void DiffusionBase::postProcessInput() +void DiffusionBase::postInputInitialization() { - ConstitutiveBase::postProcessInput(); + ConstitutiveBase::postInputInitialization(); integer const numPhases = numFluidPhases(); GEOS_THROW_IF_LT_MSG( numPhases, 2, diff --git a/src/coreComponents/constitutive/diffusion/DiffusionBase.hpp b/src/coreComponents/constitutive/diffusion/DiffusionBase.hpp index d6bd8d831de..430d52852f2 100644 --- a/src/coreComponents/constitutive/diffusion/DiffusionBase.hpp +++ b/src/coreComponents/constitutive/diffusion/DiffusionBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -168,7 +169,7 @@ class DiffusionBase : public ConstitutiveBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// phase names read from input string_array m_phaseNames; diff --git a/src/coreComponents/constitutive/diffusion/DiffusionFields.hpp b/src/coreComponents/constitutive/diffusion/DiffusionFields.hpp index 2087f2b8fa6..e570a5584d8 100644 --- a/src/coreComponents/constitutive/diffusion/DiffusionFields.hpp +++ b/src/coreComponents/constitutive/diffusion/DiffusionFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/diffusion/DiffusionSelector.hpp b/src/coreComponents/constitutive/diffusion/DiffusionSelector.hpp index 612bd8ef5ed..40325527e2c 100644 --- a/src/coreComponents/constitutive/diffusion/DiffusionSelector.hpp +++ b/src/coreComponents/constitutive/diffusion/DiffusionSelector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/dispersion/DispersionBase.cpp b/src/coreComponents/constitutive/dispersion/DispersionBase.cpp index e41084afdd2..2789f5a07d9 100644 --- a/src/coreComponents/constitutive/dispersion/DispersionBase.cpp +++ b/src/coreComponents/constitutive/dispersion/DispersionBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -33,9 +34,9 @@ DispersionBase::DispersionBase( string const & name, Group * const parent ) registerField( fields::dispersion::dispersivity{}, &m_dispersivity ); } -void DispersionBase::postProcessInput() +void DispersionBase::postInputInitialization() { - ConstitutiveBase::postProcessInput(); + ConstitutiveBase::postInputInitialization(); m_dispersivity.resize( 0, 0, 3 ); } diff --git a/src/coreComponents/constitutive/dispersion/DispersionBase.hpp b/src/coreComponents/constitutive/dispersion/DispersionBase.hpp index b2d368322f1..4a653aed6e0 100644 --- a/src/coreComponents/constitutive/dispersion/DispersionBase.hpp +++ b/src/coreComponents/constitutive/dispersion/DispersionBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -129,7 +130,7 @@ class DispersionBase : public ConstitutiveBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// cell-wise dispersivity in the subregion /// TODO: support full tensor if linear isotropic diffusion is no longer enough diff --git a/src/coreComponents/constitutive/dispersion/DispersionFields.hpp b/src/coreComponents/constitutive/dispersion/DispersionFields.hpp index 00901dce438..a4be8187737 100644 --- a/src/coreComponents/constitutive/dispersion/DispersionFields.hpp +++ b/src/coreComponents/constitutive/dispersion/DispersionFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/dispersion/DispersionSelector.hpp b/src/coreComponents/constitutive/dispersion/DispersionSelector.hpp index 4372d726a41..c330115a49b 100644 --- a/src/coreComponents/constitutive/dispersion/DispersionSelector.hpp +++ b/src/coreComponents/constitutive/dispersion/DispersionSelector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/dispersion/LinearIsotropicDispersion.cpp b/src/coreComponents/constitutive/dispersion/LinearIsotropicDispersion.cpp index fab77fad476..88e0339f142 100644 --- a/src/coreComponents/constitutive/dispersion/LinearIsotropicDispersion.cpp +++ b/src/coreComponents/constitutive/dispersion/LinearIsotropicDispersion.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -42,7 +43,7 @@ LinearIsotropicDispersion::deliverClone( string const & name, return DispersionBase::deliverClone( name, parent ); } -void LinearIsotropicDispersion::postProcessInput() +void LinearIsotropicDispersion::postInputInitialization() { GEOS_THROW_IF( m_longitudinalDispersivity < 0, GEOS_FMT( "{}: longitudinal dispersivity must be positive", diff --git a/src/coreComponents/constitutive/dispersion/LinearIsotropicDispersion.hpp b/src/coreComponents/constitutive/dispersion/LinearIsotropicDispersion.hpp index 423ab5766fd..de7193694b1 100644 --- a/src/coreComponents/constitutive/dispersion/LinearIsotropicDispersion.hpp +++ b/src/coreComponents/constitutive/dispersion/LinearIsotropicDispersion.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -111,7 +112,7 @@ class LinearIsotropicDispersion : public DispersionBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; private: diff --git a/src/coreComponents/constitutive/docs/BiotPorosity.rst b/src/coreComponents/constitutive/docs/BiotPorosity.rst index dd74e0dbbc5..e1257d14c1e 100644 --- a/src/coreComponents/constitutive/docs/BiotPorosity.rst +++ b/src/coreComponents/constitutive/docs/BiotPorosity.rst @@ -33,7 +33,7 @@ block. The following attributes are supported: -.. include:: /coreComponents/schema/docs/BiotPorosity.rst +.. include:: /docs/sphinx/datastructure/BiotPorosity.rst Example ======================= diff --git a/src/coreComponents/constitutive/docs/BlackOilFluid.rst b/src/coreComponents/constitutive/docs/BlackOilFluid.rst index a7e3fb27e68..106cd122646 100644 --- a/src/coreComponents/constitutive/docs/BlackOilFluid.rst +++ b/src/coreComponents/constitutive/docs/BlackOilFluid.rst @@ -83,7 +83,7 @@ In order to use the model, GEOS must be built with ``-DENABLE_PVTPACKAGE=ON`` (d The following attributes are supported: -.. include:: ../../../coreComponents/schema/docs/BlackOilFluid.rst +.. include:: /docs/sphinx/datastructure/BlackOilFluid.rst Supported phase names are: diff --git a/src/coreComponents/constitutive/docs/BrooksCoreyCapillaryPressure.rst b/src/coreComponents/constitutive/docs/BrooksCoreyCapillaryPressure.rst index e2820290648..e9e5ed043f9 100644 --- a/src/coreComponents/constitutive/docs/BrooksCoreyCapillaryPressure.rst +++ b/src/coreComponents/constitutive/docs/BrooksCoreyCapillaryPressure.rst @@ -47,7 +47,7 @@ node. The following attributes are supported: -.. include:: /coreComponents/schema/docs/BrooksCoreyCapillaryPressure.rst +.. include:: /docs/sphinx/datastructure/BrooksCoreyCapillaryPressure.rst Below are some comments on the model parameters: diff --git a/src/coreComponents/constitutive/docs/BrooksCoreyRelativePermeability.rst b/src/coreComponents/constitutive/docs/BrooksCoreyRelativePermeability.rst index be638c984b1..2ef89a3e981 100644 --- a/src/coreComponents/constitutive/docs/BrooksCoreyRelativePermeability.rst +++ b/src/coreComponents/constitutive/docs/BrooksCoreyRelativePermeability.rst @@ -35,7 +35,7 @@ node. The following attributes are supported: -.. include:: /coreComponents/schema/docs/BrooksCoreyRelativePermeability.rst +.. include:: /docs/sphinx/datastructure/BrooksCoreyRelativePermeability.rst Below are some comments on the model parameters. diff --git a/src/coreComponents/constitutive/docs/CO2BrineFluid.rst b/src/coreComponents/constitutive/docs/CO2BrineFluid.rst index 61ab1782578..2a3e001fc46 100644 --- a/src/coreComponents/constitutive/docs/CO2BrineFluid.rst +++ b/src/coreComponents/constitutive/docs/CO2BrineFluid.rst @@ -244,7 +244,7 @@ The models are represented by ````, `` +References +========== + +- M. L. Michelsen, `The Isothermal Flash Problem. Part I. Stability. + `__, Fluid Phase Equilibria, + vol. 9.1, pp. 1-19, 1982a. + +- M. L. Michelsen, `The Isothermal Flash Problem. Part II. Phase-Split Calculation. + `__, Fluid Phase Equilibria, + vol. 9.1, pp. 21-40, 1982b. .. _Petrowiki: https://petrowiki.spe.org/Phase_behavior_in_reservoir_simulation#Equation-of-state_models diff --git a/src/coreComponents/constitutive/docs/CompressibleSinglePhaseFluid.rst b/src/coreComponents/constitutive/docs/CompressibleSinglePhaseFluid.rst index de00eaa353a..5ff6a6d3d99 100644 --- a/src/coreComponents/constitutive/docs/CompressibleSinglePhaseFluid.rst +++ b/src/coreComponents/constitutive/docs/CompressibleSinglePhaseFluid.rst @@ -36,7 +36,7 @@ The model is represented by ```` node in the input The following attributes are supported: -.. include:: ../../../coreComponents/schema/docs/CompressibleSinglePhaseFluid.rst +.. include:: /docs/sphinx/datastructure/CompressibleSinglePhaseFluid.rst Example ========================= diff --git a/src/coreComponents/constitutive/docs/ConstantPermeability.rst b/src/coreComponents/constitutive/docs/ConstantPermeability.rst index 6c4b065bdfc..84b0d26fe58 100644 --- a/src/coreComponents/constitutive/docs/ConstantPermeability.rst +++ b/src/coreComponents/constitutive/docs/ConstantPermeability.rst @@ -17,7 +17,7 @@ Parameters The following attributes are supported: -.. include:: /coreComponents/schema/docs/ConstantPermeability.rst +.. include:: /docs/sphinx/datastructure/ConstantPermeability.rst Example diff --git a/src/coreComponents/constitutive/docs/Constitutive.rst b/src/coreComponents/constitutive/docs/Constitutive.rst index e6115637721..d1441d78d7b 100644 --- a/src/coreComponents/constitutive/docs/Constitutive.rst +++ b/src/coreComponents/constitutive/docs/Constitutive.rst @@ -18,6 +18,8 @@ These models are grouped together based on their input/output interface. PorosityModels PermeabilityModels PorousSolids + TemperatureDependentSolidVolumetricHeatCapacity + TemperatureDependentThermalConductivity In an input XML file, constitutive models are listed in the ```` block. @@ -49,7 +51,7 @@ A typical ```` and ```` block will look like: diff --git a/src/coreComponents/constitutive/docs/ExponentialDecayPermeability.rst b/src/coreComponents/constitutive/docs/ExponentialDecayPermeability.rst index c5e5889fa42..b2221a83db7 100644 --- a/src/coreComponents/constitutive/docs/ExponentialDecayPermeability.rst +++ b/src/coreComponents/constitutive/docs/ExponentialDecayPermeability.rst @@ -30,7 +30,7 @@ block. The following attributes are supported: -.. include:: /coreComponents/schema/docs/ExponentialDecayPermeability.rst +.. include:: /docs/sphinx/datastructure/ExponentialDecayPermeability.rst Example diff --git a/src/coreComponents/constitutive/docs/FluidModels.rst b/src/coreComponents/constitutive/docs/FluidModels.rst index 3b7beb6c902..445f8a82f0b 100644 --- a/src/coreComponents/constitutive/docs/FluidModels.rst +++ b/src/coreComponents/constitutive/docs/FluidModels.rst @@ -15,6 +15,4 @@ single fluids and fluid mixtures. CompositionalMultiphaseFluid - CO2BrineFluid - - PVTDriver + CO2BrineFluid \ No newline at end of file diff --git a/src/coreComponents/constitutive/docs/KozenyCarmanPermeability.rst b/src/coreComponents/constitutive/docs/KozenyCarmanPermeability.rst index 8365288ce2f..0f315a4ce9f 100644 --- a/src/coreComponents/constitutive/docs/KozenyCarmanPermeability.rst +++ b/src/coreComponents/constitutive/docs/KozenyCarmanPermeability.rst @@ -32,7 +32,7 @@ block. The following attributes are supported: -.. include:: /coreComponents/schema/docs/CarmanKozenyPermeability.rst +.. include:: /docs/sphinx/datastructure/CarmanKozenyPermeability.rst diff --git a/src/coreComponents/constitutive/docs/PVTDriver.rst b/src/coreComponents/constitutive/docs/PVTDriver.rst deleted file mode 100644 index c0b46436a7d..00000000000 --- a/src/coreComponents/constitutive/docs/PVTDriver.rst +++ /dev/null @@ -1,154 +0,0 @@ -PVT Driver -=============== - -.. contents:: Table of Contents - :depth: 3 - -Introduction ------------- - -When calibrating fluid material parameters to experimental or other reference data, it can be a hassle to launch a full flow simulation just to confirm density, viscosity, and other fluid properties are behaving as expected. -Instead, GEOS provides a ``PVTDriver`` allowing the user to test fluid property models for a well defined set of pressure, temperature, and composition conditions. -The driver itself is launched like any other GEOS simulation, but with a particular XML structure: - -.. code-block:: sh - - ./bin/geosx -i myFluidTest.xml - -This driver will work for any multi-phase fluid model (e.g. black-oil, co2-brine, compositional multiphase) enabled within GEOS. - -XML Structure -------------- -A typical XML file to run the driver will have several key elements. -Here, we will walk through an example file included in the source tree at - -.. code-block:: sh - - src/coreComponents/unitTests/constitutiveTests/testPVT_docExample.xml - -The first thing to note is that the XML file structure is identical to a standard GEOS input deck. -In fact, once the constitutive block is calibrated, one could start adding solver and discretization blocks to the same file to create a proper field simulation. -This makes it easy to go back and forth between calibration and simulation. - -The first step is to define a parameterized fluid model to test. -Here, we create a particular type of CO2-Brine mixture: - -.. literalinclude:: ../../unitTests/constitutiveTests/testPVT_docExample.xml - :language: xml - :start-after: - :end-before: - -We also define two time-history functions for the pressure (Pascal units) and temperature (Kelvin units) conditions we want to explore. - -.. literalinclude:: ../../unitTests/constitutiveTests/testPVT_docExample.xml - :language: xml - :start-after: - :end-before: - -Note that the time-axis here is just a pseudo-time, allowing us to `parameterize `_ arbitrarily complicated paths through a (pressure,temperature) diagram. -The actual time values have no impact on the resulting fluid properties. -Here, we fix the temperature at 350K and simply ramp up pressure from 1 MPa to 50 MPa: - -A ``PVTDriver`` is then added as a ``Task``, a particular type of executable event often used for simple actions. - -.. literalinclude:: ../../unitTests/constitutiveTests/testPVT_docExample.xml - :language: xml - :start-after: - :end-before: - -The driver itself takes as input the fluid model, the pressure and temperature control functions, and a "feed composition." -The latter is the mole fraction of each component in the mixture to be tested. -The ``steps`` parameter controls how many steps are taken along the parametric (P,T) path. -Results will be written in a simple ASCII table format (described below) to the file ``output``. -The ``logLevel`` parameter controls the verbosity of log output during execution. - -The driver task is added as a ``SoloEvent`` to the event queue. -This leads to a trivial event queue, since all we do is launch the driver and then quit. - -.. literalinclude:: ../../unitTests/constitutiveTests/testPVT_docExample.xml - :language: xml - :start-after: - :end-before: - -Internally, the driver uses a simple form of time-stepping to advance through the (P,T) steps. -This timestepping is handled independently of the more complicated time-stepping pattern used by physics ``Solvers`` and coordinated by the ``EventManager``. -In particular, in the XML file above, the ``maxTime`` parameter in the ``Events`` block is an event manager control, controlling when/if certain events occur. -Once launched, the PVTDriver internally determines its own max time and timestep size using a combination of the input functions' time coordinates and the requested number of loadsteps. -It is therefore helpful to think of the driver as an instantaneous *event* (from the event manager's point of view), but one which has a separate, internal clock. - -Parameters ----------- -The key XML parameters for the PVTDriver are summarized in the following table: - -.. include:: /coreComponents/schema/docs/PVTDriver.rst - -Output Format -------------- -The ``output`` key is used to identify a file to which the results of the simulation are written. -If this key is omitted, or the user specifies ``output="none"``, file output will be suppressed. -The file is a simple ASCII format with a brief header followed by test data: - -.. code:: sh - - # column 1 = time - # column 2 = pressure - # column 3 = temperature - # column 4 = density - # columns 5-6 = phase fractions - # columns 7-8 = phase densities - # columns 9-10 = phase viscosities - 0.0000e+00 1.0000e+06 3.5000e+02 1.5581e+01 1.0000e+00 4.1138e-11 1.5581e+01 1.0033e+03 1.7476e-05 9.9525e-04 - 2.0408e-02 2.0000e+06 3.5000e+02 3.2165e+01 1.0000e+00 4.1359e-11 3.2165e+01 1.0050e+03 1.7601e-05 9.9525e-04 - 4.0816e-02 3.0000e+06 3.5000e+02 4.9901e+01 1.0000e+00 4.1563e-11 4.9901e+01 1.0066e+03 1.7778e-05 9.9525e-04 - ... - -Note that the number of columns will depend on how many phases and components are present. -In this case, we have a two-phase, two-component mixture. -The total density is reported in column 4, while phase fractions, phase densities, and phase viscosities are reported in subsequent columns. -If the ``outputCompressibility`` flag is activated, an extra column will be added for the total fluid compressibility after the density. -This is defined as :math:`c_t=\frac{1}{\rho_t}\left(\partial{\rho_t}/\partial P\right)` where :math:`\rho_t` is the total density. -The number of columns will also depend on whether the ``outputPhaseComposition`` flag is activated or not. If it is activated, there will be an extra column for the mole fraction of each component in each phase. -The phase order will match the one defined in the input XML (here, the co2-rich phase followed by the water-rich phase). -This file can be readily plotted using any number of plotting tools. Each row corresponds to one timestep of the driver, starting from initial conditions in the first row. - -Unit Testing ------------- - -The development team also uses the PVTDriver to perform unit testing on the various fluid models within GEOS. -The optional argument ``baseline`` can be used to point to a previous output file that has been validated (e.g. against experimental benchmarks or reference codes). -If such a file is specified, the driver will perform a testing run and then compare the new results against the baseline. -In this way, any regressions in the fluid models can be quickly identified. - -Developers of new models are encouraged to add their own baselines to ``src/coreComponents/constitutive/unitTests``. -Adding additional tests is straightforward: - -1. Create a new xml file for your test in ``src/coreComponents/constitutive/unitTests`` or (easier) add extra blocks to the existing XML at ``src/coreComponents/constitutive/unitTests/testPVT.xml``. -For new XMLs, we suggest using the naming convention ``testPVT_myTest.xml``, so that all tests will be grouped together alphabetically. -Set the ``output`` file to ``testPVT_myTest.txt``, and run your test. -Validate the results however is appropriate. -If you have reference data available for this validation, we suggest archiving it in the ``testPVT_data/`` subdirectory, with a description of the source and formatting in the file header. -Several reference datasets are included already as examples. -This directory is also a convenient place to store auxiliary input files like PVT tables. - -2. This output file will now become your new baseline. -Replace the ``output`` key with ``baseline`` so that the driver can read in your file as a baseline for comparison. -Make sure there is no remaining ``output`` key, or set ``output=none``, to suppress further file output. -While you can certainly write a new output for debugging purposes, during our automated unit tests we prefer to suppress file output. -Re-run the driver to confirm that the comparison test passes. - -3. Modify ``src/coreComponents/constitutive/unitTests/CMakeLists.txt`` to enable your new test in the unit test suite. -In particular, you will need to add your new XML file to the existing list in the ``gtest_pvt_xmls`` variable. -Note that if you simply added your test to the existing ``testPVT.xml`` file, no changes are needed. - -.. code:: sh - - set( gtest_pvt_xmls - testPVT.xml - testPVT_myTest.xml - ) - -4. Run ``make`` in your build directory to make sure the CMake syntax is correct - -5. Run ``ctest -V -R PVT`` to run the PVT unit tests. Confirm your test is included and passes properly. - -If you run into troubles, do not hesitate to contact the development team for help. diff --git a/src/coreComponents/constitutive/docs/ParallelPlatesPermeability.rst b/src/coreComponents/constitutive/docs/ParallelPlatesPermeability.rst index 8f53bbb32a8..3169f3d0f84 100644 --- a/src/coreComponents/constitutive/docs/ParallelPlatesPermeability.rst +++ b/src/coreComponents/constitutive/docs/ParallelPlatesPermeability.rst @@ -35,7 +35,7 @@ block. The following attributes are supported: -.. include:: /coreComponents/schema/docs/ParallelPlatesPermeability.rst +.. include:: /docs/sphinx/datastructure/ParallelPlatesPermeability.rst .. _Witherspoon et al.: https://agupubs.onlinelibrary.wiley.com/doi/pdf/10.1029/WR016i006p01016 diff --git a/src/coreComponents/constitutive/docs/PressurePorosity.rst b/src/coreComponents/constitutive/docs/PressurePorosity.rst index 9a6fcb1d365..6659084688b 100644 --- a/src/coreComponents/constitutive/docs/PressurePorosity.rst +++ b/src/coreComponents/constitutive/docs/PressurePorosity.rst @@ -23,7 +23,7 @@ Parameters The following attributes are supported: -.. include:: /coreComponents/schema/docs/PressurePorosity.rst +.. include:: /docs/sphinx/datastructure/PressurePorosity.rst Example ======================= diff --git a/src/coreComponents/constitutive/docs/SlipDependentPermeability.rst b/src/coreComponents/constitutive/docs/SlipDependentPermeability.rst index fb47d4cd597..562728ce046 100644 --- a/src/coreComponents/constitutive/docs/SlipDependentPermeability.rst +++ b/src/coreComponents/constitutive/docs/SlipDependentPermeability.rst @@ -30,7 +30,7 @@ block. The following attributes are supported: -.. include:: /coreComponents/schema/docs/SlipDependentPermeability.rst +.. include:: /docs/sphinx/datastructure/SlipDependentPermeability.rst Example diff --git a/src/coreComponents/constitutive/docs/TableCapillaryPressure.rst b/src/coreComponents/constitutive/docs/TableCapillaryPressure.rst index 64246920f27..e420a43e51b 100644 --- a/src/coreComponents/constitutive/docs/TableCapillaryPressure.rst +++ b/src/coreComponents/constitutive/docs/TableCapillaryPressure.rst @@ -46,7 +46,7 @@ node. The following attributes are supported: -.. include:: /coreComponents/schema/docs/TableCapillaryPressure.rst +.. include:: /docs/sphinx/datastructure/TableCapillaryPressure.rst Below are some comments on the model parameters. diff --git a/src/coreComponents/constitutive/docs/TableRelativePermeability.rst b/src/coreComponents/constitutive/docs/TableRelativePermeability.rst index 1e77bf9c9c6..c7bc8285cfb 100644 --- a/src/coreComponents/constitutive/docs/TableRelativePermeability.rst +++ b/src/coreComponents/constitutive/docs/TableRelativePermeability.rst @@ -28,7 +28,7 @@ node. The following attributes are supported: -.. include:: /coreComponents/schema/docs/TableRelativePermeability.rst +.. include:: /docs/sphinx/datastructure/TableRelativePermeability.rst Below are some comments on the model parameters. diff --git a/src/coreComponents/constitutive/docs/TemperatureDependentSolidVolumetricHeatCapacity.rst b/src/coreComponents/constitutive/docs/TemperatureDependentSolidVolumetricHeatCapacity.rst new file mode 100644 index 00000000000..3ea9510c5d5 --- /dev/null +++ b/src/coreComponents/constitutive/docs/TemperatureDependentSolidVolumetricHeatCapacity.rst @@ -0,0 +1,56 @@ +.. _TemperatureDependentSolidVolumetricHeatCapacity: + + +########################################################## +Temperature-dependent Solid Volumetric Heat Capacity Model +########################################################## + + +Overview +====================== + +In this model, solid volumetric specific heat capacity is assumed to be a linear function of temperature: + +.. math:: + C = C_{0} + \frac{ dC }{ dT } (T - T_{0}) + +where + :math:`C` is the solid volumetric heat capacity at temperature T; + :math:`C_{0}` is the reference solid volumetric heat capacity at the reference temperature; + :math:`T_{0}` is the reference temperature; + :math:`\frac{ dC }{ dT }` is the gradient of the volumetric heat capacity with respect to temperature, which equals to zero for the cases with constant solid volumetric heat capacity; + + + +Parameters +====================== + +The temperature-dependent solid volumetric heat capacity model is called in the +```` block of the input XML file. +This model must be assigned a unique name via the +``name`` attribute. +This name is used to attach the model to regions of the physical +domain via a ``solidInternalEnergyModelName`` attribute in the ```` +block. + +The following attributes are supported: + +.. include:: /docs/sphinx/datastructure/SolidInternalEnergy.rst + + + +Example +======================= + +.. code-block:: xml + + + ... + + ... + diff --git a/src/coreComponents/constitutive/docs/TemperatureDependentThermalConductivity.rst b/src/coreComponents/constitutive/docs/TemperatureDependentThermalConductivity.rst new file mode 100644 index 00000000000..35a047ca0b9 --- /dev/null +++ b/src/coreComponents/constitutive/docs/TemperatureDependentThermalConductivity.rst @@ -0,0 +1,53 @@ +.. _TemperatureDependentThermalConductivity: + + +########################################################## +Temperature-dependent Thermal Conductivity Model +########################################################## + + +Overview +====================== + +In this model, thermal conductivity of porous medium is defined as a linear function of temperature: + +.. math:: + k = k_{0} + \frac{ dk }{ dT } (T - T_{0}) + +where + :math:`k` is the thermal conductivity at temperature T, which is a vector; + :math:`k_{0}` is the reference thermal conductivity at the reference temperature; + :math:`T_{0}` is the reference temperature; + :math:`\frac{ dk }{ dT }` is the gradient of the thermal conductivity with respect to temperature, which equals to zero for the cases with constant thermal conductivity; note that this term is also in vector form, whose components could vary with directions. + + + +Parameters +====================== + +The temperature-dependent thermal conductivity model is called in the +```` block of the input XML file. +This model must be assigned a unique name via the +``name`` attribute. +This name is used to attach the model to CellElementRegion of the physical +domain in the ```` block. + +The following attributes are supported: + +.. include:: /docs/sphinx/datastructure/SinglePhaseThermalConductivity.rst + + +Example +======================= + +.. code-block:: xml + + + ... + + ... + diff --git a/src/coreComponents/constitutive/docs/ThreePhaseRelativePermeability.rst b/src/coreComponents/constitutive/docs/ThreePhaseRelativePermeability.rst index 5aa85ef9b01..4176072e29e 100644 --- a/src/coreComponents/constitutive/docs/ThreePhaseRelativePermeability.rst +++ b/src/coreComponents/constitutive/docs/ThreePhaseRelativePermeability.rst @@ -57,7 +57,7 @@ node. The following attributes are supported: -.. include:: /coreComponents/schema/docs/BrooksCoreyBakerRelativePermeability.rst +.. include:: /docs/sphinx/datastructure/BrooksCoreyBakerRelativePermeability.rst Below are some comments on the model parameters. diff --git a/src/coreComponents/constitutive/docs/VanGenuchtenCapillaryPressure.rst b/src/coreComponents/constitutive/docs/VanGenuchtenCapillaryPressure.rst index 8f1d3fac28b..366fc3d5d97 100644 --- a/src/coreComponents/constitutive/docs/VanGenuchtenCapillaryPressure.rst +++ b/src/coreComponents/constitutive/docs/VanGenuchtenCapillaryPressure.rst @@ -52,7 +52,7 @@ node. The following attributes are supported: -.. include:: /coreComponents/schema/docs/VanGenuchtenCapillaryPressure.rst +.. include:: /docs/sphinx/datastructure/VanGenuchtenCapillaryPressure.rst Below are some comments on the model parameters: diff --git a/src/coreComponents/constitutive/docs/WillisRichardsPermeability.rst b/src/coreComponents/constitutive/docs/WillisRichardsPermeability.rst index f3c02410953..49105b211e7 100644 --- a/src/coreComponents/constitutive/docs/WillisRichardsPermeability.rst +++ b/src/coreComponents/constitutive/docs/WillisRichardsPermeability.rst @@ -41,7 +41,7 @@ block. The following attributes are supported: -.. include:: /coreComponents/schema/docs/WillisRichardsPermeability.rst +.. include:: /docs/sphinx/datastructure/WillisRichardsPermeability.rst Example diff --git a/src/coreComponents/constitutive/docs/constitutiveDeveloperGuide.rst b/src/coreComponents/constitutive/docs/constitutiveDeveloperGuide.rst index 224903eabfc..8f1b7292122 100644 --- a/src/coreComponents/constitutive/docs/constitutiveDeveloperGuide.rst +++ b/src/coreComponents/constitutive/docs/constitutiveDeveloperGuide.rst @@ -88,7 +88,7 @@ dependency of porosity and permeability on the primary unknowns. The base class ``CoupledSolidBase`` implements some basic behaviors and is used to access a generic ``CoupledSolid`` in a physics solver: -.. literalinclude:: /coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp +.. literalinclude:: /coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.hpp :language: c++ :start-after: //START_SPHINX_INCLUDE_COUPLEDSOLID :end-before: //END_SPHINX_INCLUDE_COUPLEDSOLID diff --git a/src/coreComponents/constitutive/docs/solid/DruckerPrager.rst b/src/coreComponents/constitutive/docs/solid/DruckerPrager.rst index 51c52063308..dcb4ccafe49 100644 --- a/src/coreComponents/constitutive/docs/solid/DruckerPrager.rst +++ b/src/coreComponents/constitutive/docs/solid/DruckerPrager.rst @@ -83,7 +83,7 @@ Parameters The following attributes are supported: -.. include:: /coreComponents/schema/docs/DruckerPrager.rst +.. include:: /docs/sphinx/datastructure/DruckerPrager.rst Example ~~~~~~~~~~~~~~~ diff --git a/src/coreComponents/constitutive/docs/solid/ElasticIsotropic.rst b/src/coreComponents/constitutive/docs/solid/ElasticIsotropic.rst index bbd0cc27eb7..92dcf35daed 100644 --- a/src/coreComponents/constitutive/docs/solid/ElasticIsotropic.rst +++ b/src/coreComponents/constitutive/docs/solid/ElasticIsotropic.rst @@ -67,7 +67,7 @@ two will be internally calculated. The "default" keyword in front of certain pr is the default value adopted for a region unless the user separately specifies a heterogeneous field via the ``FieldSpecification`` mechanism. -.. include:: /coreComponents/schema/docs/ElasticIsotropic.rst +.. include:: /docs/sphinx/datastructure/ElasticIsotropic.rst Example ========================= diff --git a/src/coreComponents/constitutive/docs/solid/ElasticOrthotropic.rst b/src/coreComponents/constitutive/docs/solid/ElasticOrthotropic.rst index cf794fb2f0c..483cf8116d2 100644 --- a/src/coreComponents/constitutive/docs/solid/ElasticOrthotropic.rst +++ b/src/coreComponents/constitutive/docs/solid/ElasticOrthotropic.rst @@ -47,7 +47,7 @@ The following attributes are supported. The "default" keyword in front of certa is the default value adopted for a region unless the user separately specifies a heterogeneous field via the ``FieldSpecification`` mechanism. -.. include:: /coreComponents/schema/docs/ElasticOrthotropic.rst +.. include:: /docs/sphinx/datastructure/ElasticOrthotropic.rst Example ========================= diff --git a/src/coreComponents/constitutive/docs/solid/ElasticTransverseIsotropic.rst b/src/coreComponents/constitutive/docs/solid/ElasticTransverseIsotropic.rst index aa0cb479042..8ea11a38cd1 100644 --- a/src/coreComponents/constitutive/docs/solid/ElasticTransverseIsotropic.rst +++ b/src/coreComponents/constitutive/docs/solid/ElasticTransverseIsotropic.rst @@ -47,7 +47,7 @@ The following attributes are supported. The "default" keyword in front of certa is the default value adopted for a region unless the user separately specifies a heterogeneous field via the ``FieldSpecification`` mechanism. -.. include:: /coreComponents/schema/docs/ElasticTransverseIsotropic.rst +.. include:: /docs/sphinx/datastructure/ElasticTransverseIsotropic.rst Example ========================= diff --git a/src/coreComponents/constitutive/docs/solid/SolidModels.rst b/src/coreComponents/constitutive/docs/solid/SolidModels.rst index a62f1ce024e..de494d86bf0 100644 --- a/src/coreComponents/constitutive/docs/solid/SolidModels.rst +++ b/src/coreComponents/constitutive/docs/solid/SolidModels.rst @@ -12,7 +12,6 @@ known models. Theory Voight Plasticity - TriaxialDriver ElasticIsotropic ElasticIsotropicPressureDependent ElasticTransverseIsotropic diff --git a/src/coreComponents/constitutive/docs/solid/TriaxialDriver.rst b/src/coreComponents/constitutive/docs/solid/TriaxialDriver.rst deleted file mode 100644 index 8ddede6ba58..00000000000 --- a/src/coreComponents/constitutive/docs/solid/TriaxialDriver.rst +++ /dev/null @@ -1,142 +0,0 @@ -.. _TriaxialDriver: - - -Triaxial Driver -=============== - -.. contents:: Table of Contents - :depth: 3 - -Introduction ------------- - -When calibrating solid material parameters to experimental data, it can be a hassle to launch a full finite element simulation to mimic experimental loading conditions. Instead, GEOS provides a ``TriaxialDriver`` allowing the user to run loading tests on a single material point. This makes it easy to understand the material response and fit it to lab data. The driver itself is launched like any other GEOS simulation, but with a particular XML structure: - -.. code-block:: sh - - ./bin/geosx -i myTest.xml - - -XML Structure -------------- -A typical XML file to run the triaxial driver will have the following key elements. We present the whole file first, before digging into the individual blocks. - -.. literalinclude:: ../../../unitTests/constitutiveTests/testTriaxial_druckerPragerExtended.xml - :language: xml - -The first thing to note is that the XML structure is identical to a standard GEOS input deck. In fact, once the constitutive block is calibrated, one could start adding solver and discretization blocks to the same file to create a proper field simulation. This makes it easy to go back and forth between calibration and simulation. - -The ``TriaxialDriver`` is added as a ``Task``, a particular type of executable event often used for simple actions. It is added as a ``SoloEvent`` to the event queue. This leads to a trivial event queue, since all we do is launch the driver and then quit. - -Internally, the triaxial driver uses a simple form of time-stepping to advance through the loading steps, allowing for both rate-dependent and rate-independent models to be tested. This timestepping is handled independently from the more complicated time-stepping pattern used by physics ``Solvers`` and coordinated by the ``EventManager``. In particular, in the XML file above, the ``maxTime`` parameter in the ``Events`` block is an event manager control, controlling when/if certain events occur. Once launched, the triaxial driver internally determines its own max time and timestep size using a combination of the strain function's time coordinates and the requested number of loadsteps. It is therefore helpful to think of the driver as an instantaneous *event* (from the event manager's point of view), but one which has a separate, internal clock. - -The key parameters for the TriaxialDriver are: - -.. include:: /coreComponents/schema/docs/TriaxialDriver.rst - -.. note:: - - GEOS uses the *engineering* sign convention where compressive stresses and strains are *negative*. - This is one of the most frequent issues users make when calibrating material parameters, as - stress- and strain-like quantities often need to be negative to make physical sense. You may note in the - XML above, for example, that ``stressFunction`` and ``strainFunction`` have negative values for - a compressive test. - -Test Modes ----------- -The most complicated part of the driver is understanding how the stress and strain functions are applied in different testing modes. The driver mimics laboratory core tests, with loading controlled in the -axial and radial directions. These conditions may be either strain-controlled or stress-controlled, with the user providing time-dependent functions to describe the loading. The following table describes the available test modes in detail: - -+--------------------+-------------------------+--------------------------+---------------------------+ -| **mode** | **axial loading** | **radial loading** | **initial stress** | -+--------------------+-------------------------+--------------------------+---------------------------+ -| ``strainControl`` | axial strain controlled | radial strain controlled | isotropic stress using | -| | with ``axialControl`` | with ``radialControl`` | ``initialStress`` | -+--------------------+-------------------------+--------------------------+---------------------------+ -| ``stressControl`` | axial stress controlled | radial stress controlled | isotropic stress using | -| | with ``axialControl`` | with ``radialControl`` | ``initialStress`` | -+--------------------+-------------------------+--------------------------+---------------------------+ -| ``mixedControl`` | axial strain controlled | radial stress controlled | isotropic stress using | -| | with ``axialControl`` | with ``radialControl`` | ``initialStress`` | -+--------------------+-------------------------+--------------------------+---------------------------+ - -Note that a classical triaxial test can be described using either the ``stressControl`` or ``mixedControl`` mode. We recommend using the ``mixedControl`` mode when possible, because this almost always leads to well-posed loading conditions. In a pure stress controlled test, it is possible for the user to request that the material sustain a load beyond its intrinsic strength envelope, in which case there is no feasible solution and the driver will fail to converge. Imagine, for example, a perfectly plastic material with a yield strength of 10 MPa, but the user attempts to load it to 11 MPa. - -A volumetric test can be created by setting the axial and radial control functions to the same time history function. Similarly, an oedometer test can be created by setting the radial strain to zero. - -The user should be careful to ensure that the initial stress set via the ``initialStress`` value is consistent any applied stresses set through axial or radial loading functions. Otherwise, the material may experience sudden and unexpected deformation at the first timestep because it is not in static equilibrium. - -Output Format -------------- -The ``output`` key is used to identify a file to which the results of the simulation are written. If this key is omitted, or the user specifies ``output="none"``, file output will be suppressed. The file is a simple ASCII format with a brief header followed by test data: - -.. code:: sh - - # column 1 = time - # column 2 = axial_strain - # column 3 = radial_strain_1 - # column 4 = radial_strain_2 - # column 5 = axial_stress - # column 6 = radial_stress_1 - # column 7 = radial_stress_2 - # column 8 = newton_iter - # column 9 = residual_norm - 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 -1.0000e+00 -1.0000e+00 -1.0000e+00 0.0000e+00 0.0000e+00 - 1.6000e-01 -1.6000e-04 4.0000e-05 4.0000e-05 -1.1200e+00 -1.0000e+00 -1.0000e+00 2.0000e+00 0.0000e+00 - 3.2000e-01 -3.2000e-04 8.0000e-05 8.0000e-05 -1.2400e+00 -1.0000e+00 -1.0000e+00 2.0000e+00 0.0000e+00 - ... - -This file can be readily plotted using any number of plotting tools. Each row corresponds to one timestep of the driver, starting from initial conditions in the first row. - -We note that the file contains two columns for radial strain and two columns for radial stress. For an isotropic material, the stresses and strains along the two radial axes will usually be identical. We choose to output this way, however, to accommodate both anisotropic materials and true-triaxial loading conditions. In these cases, the stresses and strains in the radial directions could potentially differ. - -These columns can be added and subtracted to produce other quantities of interest, like mean stress or deviatoric stress. For example, we can plot the output produce stress / strain curves (in this case for a plastic rather than simple elastic material): - -.. figure:: TriaxialDriver.svg - :width: 600px - :align: center - :alt: stress/strain figure - :figclass: align-center - - Stress/strain behavior for a plastic material. - -In this plot, we have reversed the sign convention to be consistent with typical experimental plots. Note also that the ``strainFunction`` includes two unloading cycles, allowing us to observe both plastic loading and elastic unloading. - -Model Convergence ------------------ - -The last two columns of the output file contain information about the convergence behavior of the material driver. In ``triaxial`` mode, the mixed nature of the stress/strain control requires using a Newton solver to converge the solution. This last column reports the number of Newton iterations and final residual norm. Large values here would be indicative of the material model struggling (or failing) to converge. Convergence failures can result from several reasons, including: - -1. Inappropriate material parameter settings -2. Overly large timesteps -3. Infeasible loading conditions (i.e. trying to load a material to a physically-unreachable stress point) -4. Poor model implementation - -We generally spend a lot of time vetting the material model implementations (#4). When you first encounter a problem, it is therefore good to explore the other three scenarios first. If you find something unusual in the model implementation or are just really stuck, please submit an issue on our issue tracker so we can help resolve any bugs. - -Unit Testing ------------- - -The development team also uses the Triaxial Driver to perform unit testing on the various material models within GEOS. The optional argument ``baseline`` can be used to point to a previous output file that has been validated (e.g. against analytical or experimental benchmarks). If such a file is specified, the driver will perform a loading run and then compare the new results against the baseline. In this way, any regressions in the material models can be quickly identified. - -Developers of new models are encouraged to add their own baselines to ``src/coreComponents/constitutive/unitTests``. Adding additional tests is straightforward: - -1. Create a new xml file for your test in ``src/coreComponents/constitutive/unitTests``. There are several examples is this directory already to use as a template. We suggest using the naming convention ``testTriaxial_myTest.xml``, so that all triaxial tests will be grouped together alphabetically. Set the ``output`` file to ``testTriaxial_myTest.txt``, and run your test. Validate the results however is appropriate. - -2. This output file will now become your new baseline. Replace the ``output`` key with ``baseline`` so that the driver can read in your file as a baseline for comparison. Make sure there is no remaining ``output`` key, or set ``output=none``, to suppress further file output. While you can certainly write a new output for debugging purposes, during our automated unit tests we prefer to suppress file output. Re-run the triaxial driver to confirm that the comparison test passes. - -3. Modify ``src/coreComponents/constitutive/unitTests/CMakeLists.txt`` to enable your new test in the unit test suite. In particular, you will need to add your new XML file to the existing list in the ``gtest_triaxial_xmls`` variable: - -.. code:: sh - - set( gtest_triaxial_xmls - testTriaxial_elasticIsotropic.xml - testTriaxial_druckerPragerExtended.xml - testTriaxial_myTest.xml - ) - -4. Run ``make`` in your build directory to make sure the CMake syntax is correct - -5. Run ``ctest -V -R Triax`` to run the triaxial unit tests. Confirm your test is included and passes properly. - -If you run into troubles, do not hesitate to contact the development team for help. diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.cpp index 0a02e19ad51..ee6b5482a92 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,6 +21,7 @@ #include "constitutive/fluid/multifluid/MultiFluidFields.hpp" #include "constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.hpp" #include "common/Units.hpp" +#include "functions/TableFunction.hpp" namespace geos { @@ -101,6 +103,12 @@ CO2BrineFluid( string const & name, Group * const parent ): setRestartFlags( RestartFlags::NO_WRITE ). setDescription( "Names of solubility tables for each phase" ); + this->registerWrapper( viewKeyStruct::writeCSVFlagString(), &m_writeCSV ). + setInputFlag( InputFlags::OPTIONAL ). + setRestartFlags( RestartFlags::NO_WRITE ). + setDescription( "Write PVT tables into a CSV file" ). + setDefaultValue( 0 ); + // if this is a thermal model, we need to make sure that the arrays will be properly displayed and saved to restart if( isThermal() ) { @@ -114,14 +122,6 @@ CO2BrineFluid( string const & name, Group * const parent ): } } -template< typename PHASE1, typename PHASE2, typename FLASH > -bool CO2BrineFluid< PHASE1, PHASE2, FLASH >::isThermal() const -{ - return ( PHASE1::Enthalpy::catalogName() != PVTProps::NoOpPVTFunction::catalogName() && - PHASE2::Enthalpy::catalogName() != PVTProps::NoOpPVTFunction::catalogName() ); -} - - template< typename PHASE1, typename PHASE2, typename FLASH > std::unique_ptr< ConstitutiveBase > CO2BrineFluid< PHASE1, PHASE2, FLASH >:: @@ -162,7 +162,8 @@ void CO2BrineFluid< PHASE1, PHASE2, FLASH >::checkTablesParameters( real64 const m_phase1->enthalpy.checkTablesParameters( pressure, temperatureInCelsius ); } catch( SimulationError const & ex ) { - string const errorMsg = GEOS_FMT( "{}: Table input error for phase no. 1.\n", getDataContext() ); + string const errorMsg = GEOS_FMT( "Table input error for {} phase (in table from \"{}\").\n", + m_phaseNames[m_p1Index], m_phasePVTParaFiles[m_p1Index] ); throw SimulationError( ex, errorMsg ); } @@ -173,7 +174,8 @@ void CO2BrineFluid< PHASE1, PHASE2, FLASH >::checkTablesParameters( real64 const m_phase2->enthalpy.checkTablesParameters( pressure, temperatureInCelsius ); } catch( SimulationError const & ex ) { - string const errorMsg = GEOS_FMT( "{}: Table input error for phase no. 2.\n", getDataContext() ); + string const errorMsg = GEOS_FMT( "Table input error for {} phase (in table from \"{}\").\n", + m_phaseNames[m_p2Index], m_phasePVTParaFiles[m_p2Index] ); throw SimulationError( ex, errorMsg ); } @@ -182,7 +184,8 @@ void CO2BrineFluid< PHASE1, PHASE2, FLASH >::checkTablesParameters( real64 const m_flash->checkTablesParameters( pressure, temperatureInCelsius ); } catch( SimulationError const & ex ) { - string const errorMsg = GEOS_FMT( "{}: Table input error for flash phase.\n", getDataContext() ); + string const errorMsg = GEOS_FMT( "Table input error for flash phase (in table from \"{}\").\n", + m_flashModelParaFile ); throw SimulationError( ex, errorMsg ); } } @@ -191,17 +194,19 @@ void CO2BrineFluid< PHASE1, PHASE2, FLASH >::checkTablesParameters( real64 const template< typename PHASE1, typename PHASE2, typename FLASH > void CO2BrineFluid< PHASE1, PHASE2, FLASH >::initializePreSubGroups() { - GEOS_THROW_IF( this->catalogName() == CO2BrineEzrokhiThermalFluid::catalogName(), +#if defined(GEOS_DEVICE_COMPILE) + GEOS_THROW_IF( this->getCatalogName() == CO2BrineEzrokhiThermalFluid::catalogName(), GEOS_FMT( "The `{}` model is disabled for now. Please use the other thermal CO2-brine model instead: `{}`", CO2BrineEzrokhiThermalFluid::catalogName(), CO2BrinePhillipsThermalFluid::catalogName() ), InputError ); +#endif } template< typename PHASE1, typename PHASE2, typename FLASH > -void CO2BrineFluid< PHASE1, PHASE2, FLASH >::postProcessInput() +void CO2BrineFluid< PHASE1, PHASE2, FLASH >::postInputInitialization() { - MultiFluidBase::postProcessInput(); + MultiFluidBase::postInputInitialization(); GEOS_THROW_IF_NE_MSG( numFluidPhases(), 2, GEOS_FMT( "{}: invalid number of phases", getFullName() ), @@ -230,14 +235,12 @@ void CO2BrineFluid< PHASE1, PHASE2, FLASH >::postProcessInput() string const expectedGasPhaseNames[] = { "CO2", "co2", "gas", "Gas" }; m_p2Index = PVTFunctionHelpers::findName( m_phaseNames, expectedGasPhaseNames, viewKeyStruct::phaseNamesString() ); - createPVTModels(); } template< typename PHASE1, typename PHASE2, typename FLASH > void CO2BrineFluid< PHASE1, PHASE2, FLASH >::createPVTModels() { - // TODO: get rid of these external files and move into XML, this is too error prone // For now, to support the legacy input, we read all the input parameters at once in the arrays below, and then we create the models array1d< array1d< string > > phase1InputParams; @@ -327,10 +330,23 @@ void CO2BrineFluid< PHASE1, PHASE2, FLASH >::createPVTModels() InputError ); // then, we are ready to instantiate the phase models - m_phase1 = std::make_unique< PHASE1 >( getName() + "_phaseModel1", phase1InputParams, m_componentNames, m_componentMolarWeight, - getLogLevel() > 0 && logger::internal::rank==0 ); - m_phase2 = std::make_unique< PHASE2 >( getName() + "_phaseModel2", phase2InputParams, m_componentNames, m_componentMolarWeight, - getLogLevel() > 0 && logger::internal::rank==0 ); + bool const isClone = this->isClone(); + TableFunction::OutputOptions const pvtOutputOpts = { + !isClone && m_writeCSV,// writeCSV + !isClone && (getLogLevel() > 0 && logger::internal::rank==0), // writeInLog + }; + + m_phase1 = std::make_unique< PHASE1 >( getName() + "_phaseModel1", + phase1InputParams, + m_componentNames, + m_componentMolarWeight, + pvtOutputOpts ); + m_phase2 = std::make_unique< PHASE2 >( getName() + "_phaseModel2", + phase2InputParams, + m_componentNames, + m_componentMolarWeight, + pvtOutputOpts ); + // 2) Create the flash model if( !m_flashModelParaFile.empty()) @@ -351,12 +367,16 @@ void CO2BrineFluid< PHASE1, PHASE2, FLASH >::createPVTModels() { if( strs[1] == FLASH::catalogName() ) { + TableFunction::OutputOptions const flashOutputOpts = { + !isClone && m_writeCSV,// writeCSV + !isClone && (getLogLevel() > 0 && logger::internal::rank==0), // writeInLog + }; m_flash = std::make_unique< FLASH >( getName() + '_' + FLASH::catalogName(), strs, m_phaseNames, m_componentNames, m_componentMolarWeight, - getLogLevel() > 0 && logger::internal::rank==0 ); + flashOutputOpts ); } } else @@ -377,9 +397,10 @@ void CO2BrineFluid< PHASE1, PHASE2, FLASH >::createPVTModels() // If 1 table is provided, it is the CO2 solubility table and water vapourisation is zero // If 2 tables are provided, they are the CO2 solubility and water vapourisation tables depending // on how phaseNames is arranged + string const solubilityModel = EnumStrings< CO2Solubility::SolubilityModel >::toString( CO2Solubility::SolubilityModel::Tables ); string_array strs; strs.emplace_back( "FlashModel" ); - strs.emplace_back( "Tables" ); // Marker to indicate that tables are provided + strs.emplace_back( solubilityModel ); // Marker to indicate that tables are provided strs.emplace_back( "" ); // 2 empty strings for the 2 phase tables gas first, then water strs.emplace_back( "" ); if( m_solubilityTables.size() == 2 ) @@ -391,12 +412,18 @@ void CO2BrineFluid< PHASE1, PHASE2, FLASH >::createPVTModels() { strs[2] = m_solubilityTables[0]; } + + TableFunction::OutputOptions const flashOutputOpts = { + !isClone && m_writeCSV,// writeCSV + !isClone && (getLogLevel() >= 0 && logger::internal::rank==0), // writeInLog + }; + m_flash = std::make_unique< FLASH >( getName() + '_' + FLASH::catalogName(), strs, m_phaseNames, m_componentNames, m_componentMolarWeight, - getLogLevel() > 0 && logger::internal::rank==0 ); + flashOutputOpts ); } GEOS_THROW_IF( m_flash == nullptr, diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp index b68851478f2..7b35053a4ab 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,7 @@ #ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_CO2BRINE_CO2BRINEFLUID_HPP_ #define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_CO2BRINE_CO2BRINEFLUID_HPP_ -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "constitutive/fluid/multifluid/MultiFluidUtils.hpp" #include "constitutive/fluid/multifluid/CO2Brine/PhaseModel.hpp" @@ -62,7 +63,19 @@ class CO2BrineFluid : public MultiFluidBase virtual string getCatalogName() const override { return catalogName(); } - virtual bool isThermal() const override; + static constexpr bool isThermalType() + { + return !( std::is_same_v< typename PHASE1::Enthalpy, PVTProps::NoOpPVTFunction > || + std::is_same_v< typename PHASE2::Enthalpy, PVTProps::NoOpPVTFunction > ); + } + + static constexpr integer min_n_components = 2; + static constexpr integer max_n_components = 2; + + virtual bool isThermal() const override + { + return isThermalType(); + } /** * @brief Kernel wrapper class for CO2BrineFluid. @@ -158,16 +171,20 @@ class CO2BrineFluid : public MultiFluidBase static constexpr char const * flashModelParaFileString() { return "flashModelParaFile"; } static constexpr char const * solubilityTablesString() { return "solubilityTableNames"; } static constexpr char const * phasePVTParaFilesString() { return "phasePVTParaFiles"; } + static constexpr char const * writeCSVFlagString() { return "writeCSV"; } }; protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void initializePreSubGroups() override; private: + /** + * @brief Create a PVT Model and output them + */ void createPVTModels(); /// Names of the files defining the viscosity and density models @@ -185,6 +202,8 @@ class CO2BrineFluid : public MultiFluidBase /// Index of the gas phase integer m_p2Index; + /// Output csv file containing informations about PVT + integer m_writeCSV; /// Brine constitutive models std::unique_ptr< PHASE1 > m_phase1; @@ -194,7 +213,6 @@ class CO2BrineFluid : public MultiFluidBase // Flash model std::unique_ptr< FLASH > m_flash; - }; // these aliases are useful in constitutive dispatch @@ -368,7 +386,6 @@ CO2BrineFluid< PHASE1, PHASE2, FLASH >::KernelWrapper:: if( m_isThermal ) { - m_phase1.enthalpy.compute( pressure, temperatureInCelsius, phaseCompFraction.value[ip1].toSliceConst(), phaseCompFraction.derivs[ip1].toSliceConst(), diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiFluid.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiFluid.cpp deleted file mode 100644 index bb19077f9e3..00000000000 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiFluid.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -#include "constitutive/fluid/multifluid/PVTDriverRunTest.hpp" -#include "constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp" - -namespace geos -{ -template void PVTDriver::runTest< constitutive::CO2BrineEzrokhiFluid >( constitutive::CO2BrineEzrokhiFluid &, arrayView2d< real64 > const & ); -} diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiThermalFluid.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiThermalFluid.cpp deleted file mode 100644 index a5d6c9c776e..00000000000 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiThermalFluid.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -#include "constitutive/fluid/multifluid/PVTDriverRunTest.hpp" -#include "constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp" - -namespace geos -{ -template void PVTDriver::runTest< constitutive::CO2BrineEzrokhiThermalFluid >( constitutive::CO2BrineEzrokhiThermalFluid &, arrayView2d< real64 > const & ); -} diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsFluid.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsFluid.cpp deleted file mode 100644 index 6d98a575881..00000000000 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsFluid.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -#include "constitutive/fluid/multifluid/PVTDriverRunTest.hpp" -#include "constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp" - -namespace geos -{ -template void PVTDriver::runTest< constitutive::CO2BrinePhillipsFluid >( constitutive::CO2BrinePhillipsFluid &, arrayView2d< real64 > const & ); -} diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsThermalFluid.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsThermalFluid.cpp deleted file mode 100644 index b8b347702b6..00000000000 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsThermalFluid.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -#include "constitutive/fluid/multifluid/PVTDriverRunTest.hpp" -#include "constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp" - -namespace geos -{ -template void PVTDriver::runTest< constitutive::CO2BrinePhillipsThermalFluid >( constitutive::CO2BrinePhillipsThermalFluid &, arrayView2d< real64 > const & ); -} diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PhaseModel.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PhaseModel.hpp index 9b8d794ee58..d422cc39bd4 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PhaseModel.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/PhaseModel.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,6 +20,8 @@ #ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_CO2BRINE_PHASEMODEL_HPP_ #define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_CO2BRINE_PHASEMODEL_HPP_ +#include "functions/TableFunction.hpp" + namespace geos { @@ -53,27 +56,28 @@ struct PhaseModel * @param[in] inputParams input parameters read from files * @param[in] componentNames names of the components * @param[in] componentMolarWeight molar weights of the components + * @param[in] pvtOutputOpts A structure containing generated table output options */ PhaseModel( string const & phaseModelName, array1d< array1d< string > > const & inputParams, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ) + TableFunction::OutputOptions const pvtOutputOpts ) : density( phaseModelName + "_" + Density::catalogName(), inputParams[InputParamOrder::DENSITY], componentNames, componentMolarWeight, - printTable ), + pvtOutputOpts ), viscosity( phaseModelName + "_" + Viscosity::catalogName(), inputParams[InputParamOrder::VISCOSITY], componentNames, componentMolarWeight, - printTable ), + pvtOutputOpts ), enthalpy( phaseModelName + "_" + Enthalpy::catalogName(), inputParams[InputParamOrder::ENTHALPY], componentNames, componentMolarWeight, - printTable ) + pvtOutputOpts ) {} /// The phase density model diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/BrineEnthalpy.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/BrineEnthalpy.cpp index f7856a1696d..27eb1053d38 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/BrineEnthalpy.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/BrineEnthalpy.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -191,7 +192,7 @@ BrineEnthalpy::BrineEnthalpy( string const & name, string_array const & inputParams, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ): + TableFunction::OutputOptions const pvtOutputOpts ): PVTFunctionBase( name, componentNames, componentMolarWeight ) @@ -204,13 +205,12 @@ BrineEnthalpy::BrineEnthalpy( string const & name, m_CO2EnthalpyTable = makeCO2EnthalpyTable( inputParams, m_functionName, FunctionManager::getInstance() ); m_brineEnthalpyTable = makeBrineEnthalpyTable( inputParams, m_functionName, FunctionManager::getInstance() ); - if( printTable ) - { - m_CO2EnthalpyTable->print( m_CO2EnthalpyTable->getName() ); - m_brineEnthalpyTable->print( m_brineEnthalpyTable->getName() ); - } + + m_CO2EnthalpyTable->outputPVTTableData( pvtOutputOpts ); + m_brineEnthalpyTable->outputPVTTableData( pvtOutputOpts ); } + void BrineEnthalpy::checkTablesParameters( real64 const pressure, real64 const temperature ) const { @@ -232,8 +232,6 @@ BrineEnthalpy::createKernelWrapper() const m_waterIndex ); } -REGISTER_CATALOG_ENTRY( PVTFunctionBase, BrineEnthalpy, string const &, string_array const &, string_array const &, array1d< real64 > const &, bool const ) - } // namespace PVTProps } // namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/BrineEnthalpy.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/BrineEnthalpy.hpp index 1017ed50fea..5231b07740d 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/BrineEnthalpy.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/BrineEnthalpy.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -91,7 +92,7 @@ class BrineEnthalpy : public PVTFunctionBase string_array const & inputParams, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ); + TableFunction::OutputOptions const pvtOutputOpts ); static string catalogName() { return "BrineEnthalpy"; } @@ -143,7 +144,7 @@ void BrineEnthalpyUpdate::compute( real64 const & pressure, arraySlice1d< real64, USD3 > const & dValue, bool useMass ) const { - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; real64 const input[2] = { pressure, temperature }; real64 brineEnthalpy_dTemperature = 0.0; diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2EOSSolver.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2EOSSolver.cpp index 4867a1754c9..1ab2bf40a91 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2EOSSolver.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2EOSSolver.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,6 +20,7 @@ #include "constitutive/fluid/multifluid/CO2Brine/functions/CO2EOSSolver.hpp" #include "common/Units.hpp" +#include "common/logger/Logger.hpp" namespace geos diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2EOSSolver.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2EOSSolver.hpp index 4af2beb32aa..bb5a47ea10a 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2EOSSolver.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2EOSSolver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Enthalpy.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Enthalpy.cpp index da8b829f702..90de88580bf 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Enthalpy.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Enthalpy.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -256,7 +257,7 @@ CO2Enthalpy::CO2Enthalpy( string const & name, string_array const & inputParams, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ): + TableFunction::OutputOptions const pvtOutputOpts ): PVTFunctionBase( name, componentNames, componentMolarWeight ) @@ -265,8 +266,9 @@ CO2Enthalpy::CO2Enthalpy( string const & name, m_CO2Index = PVTFunctionHelpers::findName( componentNames, expectedCO2ComponentNames, "componentNames" ); m_CO2EnthalpyTable = makeCO2EnthalpyTable( inputParams, m_functionName, FunctionManager::getInstance() ); - if( printTable ) - m_CO2EnthalpyTable->print( m_CO2EnthalpyTable->getName() ); + + m_CO2EnthalpyTable->outputPVTTableData( pvtOutputOpts ); + m_CO2EnthalpyTable->outputPVTTableData( pvtOutputOpts ); } @@ -308,8 +310,6 @@ CO2Enthalpy::createKernelWrapper() const m_CO2Index ); } -REGISTER_CATALOG_ENTRY( PVTFunctionBase, CO2Enthalpy, string const &, string_array const &, string_array const &, array1d< real64 > const &, bool const ) - } // namespace PVTProps } // namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Enthalpy.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Enthalpy.hpp index 5ce85a9645d..6cc0852f4ae 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Enthalpy.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Enthalpy.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -79,7 +80,7 @@ class CO2Enthalpy : public PVTFunctionBase string_array const & inputParams, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ); + TableFunction::OutputOptions const pvtOutputOpts ); static string catalogName() { return "CO2Enthalpy"; } @@ -130,7 +131,7 @@ void CO2EnthalpyUpdate::compute( real64 const & pressure, { GEOS_UNUSED_VAR( phaseComposition, dPhaseComposition ); - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; real64 const input[2] = { pressure, temperature }; real64 CO2EnthalpyDeriv[2]{}; diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Solubility.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Solubility.cpp index ce4041bce68..f3946b7bc0d 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Solubility.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Solubility.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,9 +18,8 @@ */ #include "constitutive/fluid/multifluid/CO2Brine/functions/CO2Solubility.hpp" - -#include "constitutive/fluid/multifluid/CO2Brine/functions/CO2EOSSolver.hpp" -#include "constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.hpp" +#include "constitutive/fluid/multifluid/CO2Brine/functions/CO2SolubilitySpycherPruess.hpp" +#include "constitutive/fluid/multifluid/CO2Brine/functions/CO2SolubilityDuanSun.hpp" #include "functions/FunctionManager.hpp" #include "common/Units.hpp" @@ -29,343 +29,199 @@ namespace geos using namespace stringutilities; -namespace constitutive -{ - -namespace PVTProps -{ - namespace { -constexpr real64 P_Pa_f = 1e+5; -constexpr real64 P_c = 73.773 * P_Pa_f; -constexpr real64 T_c = 304.1282; -constexpr real64 Rgas = constants::gasConstant; -constexpr real64 V_c = Rgas*T_c/P_c; - -// these coefficients are in Table (A1) of Duan and Sun (2003) -constexpr real64 acoef[] = -{ 8.99288497e-2, -4.94783127e-1, 4.77922245e-2, 1.03808883e-2, -2.82516861e-2, 9.49887563e-2, 5.20600880e-4, - -2.93540971e-4, -1.77265112e-3, -2.51101973e-5, 8.93353441e-5, 7.88998563e-5, -1.66727022e-2, 1.398, 2.96e-2 }; - -real64 co2EOS( real64 const & T, real64 const & P, real64 const & V_r ) -{ - // reduced pressure - real64 const P_r = P*P_Pa_f/P_c; - // reduced temperature - real64 const T_r = units::convertCToK( T )/T_c; - - // CO2 equation of state - // see equation (A1) in Duan and Sun (2003) - real64 const f_Z = 1.0 - + ( acoef[0] + acoef[1]/(T_r * T_r) + acoef[2]/(T_r * T_r * T_r) )/V_r - + ( acoef[3] + acoef[4]/(T_r * T_r) + acoef[5]/(T_r * T_r * T_r) )/(V_r*V_r) - + ( acoef[6] + acoef[7]/(T_r * T_r) + acoef[8]/(T_r * T_r * T_r) )/(V_r*V_r*V_r*V_r) - + ( acoef[9] + acoef[10]/(T_r * T_r) + acoef[11]/(T_r * T_r * T_r) )/(V_r*V_r*V_r*V_r*V_r) - + acoef[12]/(T_r * T_r * T_r)/(V_r * V_r) * (acoef[13] + acoef[14]/(V_r * V_r)) * exp( -acoef[14]/(V_r * V_r)) - P_r * V_r / T_r; - - return f_Z; -} - -real64 PWater( real64 const & T ) +TableFunction const * makeTable( string const & tableName, + constitutive::PVTProps::PTTableCoordinates const & tableCoords, + array1d< real64 > && values, + FunctionManager & functionManager ) { - // these coefficients are defined in Table (B1) of Duan and Sun (2003) - constexpr real64 ccoef[] = { -38.640844, 5.8948420, 59.876516, 26.654627, 10.637097 }; - - // H2O critical pressure (bars) - real64 const P_c_w = 220.85; - // H2O critical temperature (K) - real64 const T_c_w = 647.29; - real64 const tt = ( units::convertCToK( T )-T_c_w )/T_c_w; - // Empirical model for water pressure of equation (B1) of Duan and Sun (2003) - real64 const x = ( P_c_w*units::convertCToK( T )/T_c_w ) - * (1 - + ccoef[0]*pow( -tt, 1.9 ) - + ccoef[1]*tt - + ccoef[2]*tt*tt - + ccoef[3]*tt*tt*tt - + ccoef[4]*tt*tt*tt*tt); - - return x; -} - -real64 logF( real64 const & T, real64 const & P, real64 const & V_r ) -{ - // reduced pressure - real64 const P_r = P*P_Pa_f/P_c; - // reduced temperature - real64 const T_r = units::convertCToK( T ) / T_c; - real64 const Z = P_r * V_r/T_r; - - // fugacity coefficient of CO2, equation (A6) of Duan and Sun (2003) - real64 const log_f = Z - 1 - log( Z ) + - ( acoef[0] + acoef[1]/T_r/T_r + acoef[2]/T_r/T_r/T_r )/V_r - + ( acoef[3] + acoef[4]/T_r/T_r + acoef[5]/T_r/T_r/T_r )/2.0/V_r/V_r - + ( acoef[6] + acoef[7]/T_r/T_r + acoef[8]/T_r/T_r/T_r )/4.0/V_r/V_r/V_r/V_r - + ( acoef[9] + acoef[10]/T_r/T_r + acoef[11]/T_r/T_r/T_r )/5.0/V_r/V_r/V_r/V_r/V_r - + acoef[12]/2.0/T_r/T_r/T_r/acoef[14] * ( acoef[13] + 1.0 - (acoef[13] + 1.0 + acoef[14]/V_r/V_r) * exp( -acoef[14]/V_r/V_r ) ); - - return log_f; -} - -real64 Par( real64 const & T, real64 const & P, real64 const * cc ) -{ - // "equation for the parameters", see equation (7) of Duan and Sun (2003) - real64 x = cc[0] - + cc[1]*T - + cc[2]/T - + cc[3]*T*T - + cc[4]/(630.0-T) - + cc[5]*P - + cc[6]*P *log( T ) - + cc[7]*P/T - + cc[8]*P/(630.0-T) - + cc[9]*P*P/(630.0-T)/(630.0-T) - + cc[10]*T *log( P ); - - return x; -} - -real64 CO2SolubilityFunction( string const & name, - real64 const & tolerance, - real64 const & T, - real64 const & P, - real64 (* f)( real64 const & x1, real64 const & x2, real64 const & x3 ) ) -{ - // compute the initial guess for Newton's method - real64 const initialReducedVolume = 0.75*Rgas*units::convertCToK( T )/(P*P_Pa_f)*(1/V_c); - - // define the local solver parameters - // for now, this is hard-coded, but we may want to let the user access the parameters at some point - integer const maxNumNewtonIter = 500; - integer const maxNumBacktrackIter = 8; - real64 const maxAbsUpdate = 1e12; - real64 const minAbsDeriv = 0; - real64 const allowedMinValue = 0.05; // value chosen to match previous implementation - real64 const presMultiplierForReporting = 1e5; // this is because P is in hectopascal in this function - - // solve the CO2 equation of state for this pair of (pres, temp) - // return the reduced volume - return CO2EOSSolver::solve( name, - maxNumNewtonIter, - maxNumBacktrackIter, - tolerance, - minAbsDeriv, - maxAbsUpdate, - allowedMinValue, - initialReducedVolume, - T, - P, - presMultiplierForReporting, - f ); + TableFunction * tableFunction = nullptr; + if( functionManager.hasGroup< TableFunction >( tableName ) ) + { + tableFunction = functionManager.getGroupPointer< TableFunction >( tableName ); + } + else + { + tableFunction = dynamicCast< TableFunction * >( functionManager.createChild( "TableFunction", tableName ) ); + tableFunction->setTableCoordinates( tableCoords.getCoords(), { units::Pressure, units::TemperatureInC } ); + tableFunction->setTableValues( values, units::Solubility ); + tableFunction->setInterpolationMethod( TableFunction::InterpolationType::Linear ); + } + tableFunction->initializeFunction(); + return tableFunction; } -void calculateCO2Solubility( string const & functionName, - real64 const & tolerance, - PTTableCoordinates const & tableCoords, - real64 const & salinity, - array1d< real64 > const & values ) +std::pair< TableFunction const *, TableFunction const * > +makeSolubilityTables( string const & functionName, + string_array const & inputParams, + constitutive::PVTProps::CO2Solubility::SolubilityModel const & solubilityModel ) { - // Interaction parameters, see Table 2 of Duan and Sun (2003) - constexpr real64 mu[] = - { 28.9447706, -0.0354581768, -4770.67077, 1.02782768e-5, 33.8126098, 9.04037140e-3, - -1.14934031e-3, -0.307405726, -0.0907301486, 9.32713393e-4, 0 }; - constexpr real64 lambda[] = { -0.411370585, 6.07632013e-4, 97.5347708, 0, 0, 0, 0, -0.0237622469, 0.0170656236, 0, 1.41335834e-5 }; - constexpr real64 zeta[] = { 3.36389723e-4, -1.98298980e-5, 0, 0, 0, 0, 0, 2.12220830e-3, -5.24873303e-3, 0, 0 }; + FunctionManager & functionManager = FunctionManager::getInstance(); + constitutive::PVTProps::PTTableCoordinates tableCoords; - localIndex const nPressures = tableCoords.nPressures(); - localIndex const nTemperatures = tableCoords.nTemperatures(); - - for( localIndex i = 0; i < nPressures; ++i ) + // Check solubility model for explicit table input + if( solubilityModel == constitutive::PVTProps::CO2Solubility::SolubilityModel::Tables ) { - real64 const P = tableCoords.getPressure( i ) / P_Pa_f; - - for( localIndex j = 0; j < nTemperatures; ++j ) + // The default table is a table with all zeros unless the name is explicitly provided + // The pressure and temperature values below will be used only to create the zero table so they + // simply give a range large enough to cover most values. + tableCoords.appendPressure( 1.0e5 ).appendPressure( 1.0e8 ) + .appendTemperature( 0.0 ).appendTemperature( 800.0 ); + + TableFunction const * tables[2] = { nullptr, nullptr }; + for( integer tableIndex : { 0, 1 } ) { - real64 const T = tableCoords.getTemperature( j ); + array1d< real64 > values( 4 ); + values.zero(); - // compute reduced volume by solving the CO2 equation of state - real64 const V_r = CO2SolubilityFunction( functionName, tolerance, T, P, &co2EOS ); - - // compute equation (6) of Duan and Sun (2003) - real64 const logK = Par( units::convertCToK( T ), P, mu ) - - logF( T, P, V_r ) - + 2*Par( units::convertCToK( T ), P, lambda ) * salinity - + Par( units::convertCToK( T ), P, zeta ) * salinity * salinity; - real64 const expLogK = exp( logK ); - - // mole fraction of CO2 in vapor phase, equation (4) of Duan and Sun (2003) - real64 const Pw = PWater( T ); - real64 const y_CO2 = (P - Pw)/P; - values[j*nPressures+i] = y_CO2 * P / expLogK; - - GEOS_WARNING_IF( expLogK <= 1e-10, - GEOS_FMT( "CO2Solubility: exp(logK) = {} is too small (logK = {}, P = {}, T = {}, V_r = {}), resulting solubility value is {}", - expLogK, logK, P, T, V_r, values[j*nPressures+i] )); - - if( values[j*nPressures+i] < 0 ) + string inputTableName = inputParams[2 + tableIndex]; + if( inputTableName.empty() ) + { + inputTableName = GEOS_FMT( "{}_zeroDissolution_table", constitutive::PVTProps::CO2Solubility::catalogName() ); + } + else { - GEOS_LOG_RANK_0( GEOS_FMT( "CO2Solubility: negative solubility value = {}, y_CO2 = {}, P = {}, PWater(T) = {}; corrected to 0", - values[j * nPressures + i], y_CO2, P, Pw ) ); - values[j*nPressures+i] = 0.0; + // If a name is explicitly given, then check that it exists + GEOS_THROW_IF( !functionManager.hasGroup< TableFunction >( inputTableName ), + GEOS_FMT( "{}: Could not find TableFunction with name {}", functionName, inputTableName ), + InputError ); } + tables[tableIndex] = makeTable( inputTableName, tableCoords, std::move ( values ), functionManager ); } + return { tables[0], tables[1] }; } -} - -TableFunction const * getSolubilityTable( string const & tableName, - FunctionManager & functionManager ) -{ - TableFunction * const table = functionManager.getGroupPointer< TableFunction >( tableName ); - table->initializeFunction(); - table->setDimUnits( { units::Pressure, units::TemperatureInC } ); - table->setValueUnits( units::Solubility ); - return table; -} -TableFunction const * makeSolubilityTable( array1d< real64_array > const & coords, - array1d< real64 > const & values, - string const & tableName, - FunctionManager & functionManager ) -{ - TableFunction * const table = dynamicCast< TableFunction * >( functionManager.createChild( "TableFunction", tableName ) ); - table->setTableCoordinates( coords, { units::Pressure, units::TemperatureInC } ); - table->setTableValues( values, units::Solubility ); - table->setInterpolationMethod( TableFunction::InterpolationType::Linear ); - return table; -} + // If the tables have already been created, then simply retrieve them + string const co2TableName = functionName + "_co2Dissolution_table"; + string const h2oTableName = functionName + "_waterVaporization_table"; -TableFunction const * makeZeroTable( string const & tableName, - FunctionManager & functionManager ) -{ - if( functionManager.hasGroup< TableFunction >( tableName ) ) + if( functionManager.hasGroup< TableFunction >( co2TableName ) && functionManager.hasGroup< TableFunction >( h2oTableName )) { - return getSolubilityTable( tableName, functionManager ); + TableFunction const * co2SolubilityTable = functionManager.getGroupPointer< TableFunction >( co2TableName ); + TableFunction const * h2oSolubilityTable = functionManager.getGroupPointer< TableFunction >( h2oTableName ); + return {co2SolubilityTable, h2oSolubilityTable}; } - else - { - array1d< array1d< real64 > > coords( 2 ); - for( integer dim = 0; dim < 2; ++dim ) - { - coords[dim].emplace_back( -1.0e10 ); - coords[dim].emplace_back( 1.0e10 ); - } - array1d< real64 > values( 4 ); - values.zero(); - return makeSolubilityTable( coords, values, tableName, functionManager ); - } -} + // Initialize the (p,T) coordinates + constitutive::PVTProps::PVTFunctionHelpers::initializePropertyTable( inputParams, tableCoords ); -TableFunction const * makeSolubilityTable( string_array const & inputParams, - string const & functionName, - FunctionManager & functionManager ) -{ - // Check the second argument - if( inputParams[1] == "Tables" ) + // Initialize salinity and tolerance + GEOS_THROW_IF_LT_MSG( inputParams.size(), 9, + GEOS_FMT( "{}: insufficient number of model parameters", functionName ), + InputError ); + + real64 tolerance = 1e-9; + real64 salinity = 0.0; + try { - string const inputTableName = inputParams[2]; - if( inputTableName.empty()) - { - return makeZeroTable( GEOS_FMT( "{}_zeroDissolution_table", CO2Solubility::catalogName() ), functionManager ); - } - else + salinity = stod( inputParams[8] ); + if( inputParams.size() >= 10 ) { - GEOS_THROW_IF( !functionManager.hasGroup< TableFunction >( inputTableName ), - GEOS_FMT( "{}: Could not find TableFunction with name {}", functionName, inputTableName ), - InputError ); - return getSolubilityTable( inputTableName, functionManager ); + tolerance = stod( inputParams[9] ); } } + catch( const std::invalid_argument & e ) + { + GEOS_THROW( GEOS_FMT( "{}: invalid model parameter value: {}", functionName, e.what() ), InputError ); + } - string const tableName = functionName + "_co2Dissolution_table"; + integer const nPressures = tableCoords.nPressures(); + integer const nTemperatures = tableCoords.nTemperatures(); - if( functionManager.hasGroup< TableFunction >( tableName ) ) + array1d< real64 > co2Solubility( nPressures * nTemperatures ); + array1d< real64 > h2oSolubility( nPressures * nTemperatures ); + + if( solubilityModel == constitutive::PVTProps::CO2Solubility::SolubilityModel::DuanSun ) { - return getSolubilityTable( tableName, functionManager ); + constitutive::PVTProps::CO2SolubilityDuanSun::populateSolubilityTables( + functionName, + tableCoords, + salinity, + tolerance, + co2Solubility, + h2oSolubility ); } - else + else if( solubilityModel == constitutive::PVTProps::CO2Solubility::SolubilityModel::SpycherPruess ) { - // initialize the (p,T) coordinates - PTTableCoordinates tableCoords; - PVTFunctionHelpers::initializePropertyTable( inputParams, tableCoords ); - - // initialize salinity and tolerance - GEOS_THROW_IF_LT_MSG( inputParams.size(), 9, - GEOS_FMT( "{}: insufficient number of model parameters", functionName ), - InputError ); - - real64 tolerance = 1e-9; - real64 salinity = 0.0; - try + constitutive::PVTProps::CO2SolubilitySpycherPruess::populateSolubilityTables( + functionName, + tableCoords, + salinity, + tolerance, + co2Solubility, + h2oSolubility ); + } + + // Truncate negative solubility and warn + integer constexpr maxBad = 5; // Maximum number of bad values to report + stackArray2d< real64, maxBad *4 > badValues( maxBad, 4 ); + integer badCount = 0; + for( localIndex i = 0; i < nPressures; ++i ) + { + real64 const P = tableCoords.getPressure( i ); + for( localIndex j = 0; j < nTemperatures; ++j ) { - salinity = stod( inputParams[8] ); - if( inputParams.size() >= 10 ) + real64 const T = tableCoords.getTemperature( j ); + if( co2Solubility[j*nPressures+i] < 0.0 || h2oSolubility[j*nPressures+i] < 0.0 ) { - tolerance = stod( inputParams[9] ); + badValues( badCount % maxBad, 0 ) = P; + badValues( badCount % maxBad, 1 ) = T; + badValues( badCount % maxBad, 2 ) = co2Solubility[j*nPressures+i]; + badValues( badCount % maxBad, 3 ) = h2oSolubility[j*nPressures+i]; + ++badCount; + } + if( co2Solubility[j*nPressures+i] < 0.0 ) + { + co2Solubility[j*nPressures+i] = 0.0; + } + if( h2oSolubility[j*nPressures+i] < 0.0 ) + { + h2oSolubility[j*nPressures+i] = 0.0; } } - catch( const std::invalid_argument & e ) - { - GEOS_THROW( GEOS_FMT( "{}: invalid model parameter value: {}", functionName, e.what() ), InputError ); - } - - array1d< real64 > values( tableCoords.nPressures() * tableCoords.nTemperatures() ); - calculateCO2Solubility( functionName, tolerance, tableCoords, salinity, values ); - - return makeSolubilityTable( tableCoords.getCoords(), values, tableName, functionManager ); } -} -TableFunction const * makeVapourisationTable( string_array const & inputParams, - string const & functionName, - FunctionManager & functionManager ) -{ - if( inputParams[1] == "Tables" ) + if( 0 < badCount ) { - string const inputTableName = inputParams[3]; - if( inputTableName.empty()) + std::ostringstream badValueTable; + badValueTable + << std::setw( 15 ) << "Pressure (Pa)" << " " + << std::setw( 15 ) << "Temperature (C)" << " " + << std::setw( 23 ) << "CO2 solubility (mol/kg)" << " " + << std::setw( 23 ) << "H2O solubility (mol/kg)" << " "; + for( integer row = 0; row < LvArray::math::min( maxBad, badCount ); ++row ) { - return makeZeroTable( GEOS_FMT( "{}_zeroDissolution_table", CO2Solubility::catalogName() ), functionManager ); - } - else - { - GEOS_THROW_IF( !functionManager.hasGroup< TableFunction >( inputTableName ), - GEOS_FMT( "{}: Could not find TableFunction with name {}", functionName, inputTableName ), - InputError ); - return getSolubilityTable( inputTableName, functionManager ); + badValueTable + << "\n" + << std::setw( 15 ) << badValues( row, 0 ) << " " + << std::setw( 15 ) << badValues( row, 1 ) << " " + << std::setw( 23 ) << badValues( row, 2 ) << " " + << std::setw( 23 ) << badValues( row, 3 ) << " "; } + GEOS_LOG_RANK_0( GEOS_FMT( "CO2Solubility: {} negative solubility values encountered. These will be truncated to zero.\nCheck out report table with max {} values.\n{}", + badCount, maxBad, badValueTable.str() ) ); } - string const tableName = functionName + "_waterVaporization_table"; - - if( functionManager.hasGroup< TableFunction >( tableName ) ) - { - return getSolubilityTable( tableName, functionManager ); - } - else - { - // initialize the (p,T) coordinates - PTTableCoordinates tableCoords; - PVTFunctionHelpers::initializePropertyTable( inputParams, tableCoords ); - - // Currently initialise to all zeros - array1d< real64 > values( tableCoords.nPressures() * tableCoords.nTemperatures() ); - values.zero(); - - return makeSolubilityTable( tableCoords.getCoords(), values, tableName, functionManager ); - } + TableFunction const * co2SolubilityTable = makeTable( co2TableName, tableCoords, std::move( co2Solubility ), functionManager ); + TableFunction const * h2oSolubilityTable = makeTable( h2oTableName, tableCoords, std::move( h2oSolubility ), functionManager ); + return {co2SolubilityTable, h2oSolubilityTable}; } } // namespace +namespace constitutive +{ +namespace PVTProps +{ + CO2Solubility::CO2Solubility( string const & name, string_array const & inputParams, string_array const & phaseNames, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ): + TableFunction::OutputOptions const pvtOutputOpts ): FlashModelBase( name, componentNames, componentMolarWeight ) @@ -389,13 +245,21 @@ CO2Solubility::CO2Solubility( string const & name, string const expectedWaterPhaseNames[] = { "Water", "water", "Liquid", "liquid" }; m_phaseLiquidIndex = PVTFunctionHelpers::findName( phaseNames, expectedWaterPhaseNames, "phaseNames" ); - m_CO2SolubilityTable = makeSolubilityTable( inputParams, m_modelName, FunctionManager::getInstance() ); - m_WaterVapourisationTable = makeVapourisationTable( inputParams, m_modelName, FunctionManager::getInstance() ); - if( printTable ) + SolubilityModel solubilityModel = SolubilityModel::DuanSun; // Default solubility model + if( inputParams[1] == EnumStrings< SolubilityModel >::toString( SolubilityModel::Tables ) ) { - m_CO2SolubilityTable->print( m_CO2SolubilityTable->getName() ); - m_WaterVapourisationTable->print( m_WaterVapourisationTable->getName() ); + solubilityModel = SolubilityModel::Tables; } + else if( 11 <= inputParams.size() ) + { + solubilityModel = EnumStrings< SolubilityModel >::fromString( inputParams[10] ); + } + + std::tie( m_CO2SolubilityTable, m_WaterVapourisationTable ) = makeSolubilityTables( m_modelName, inputParams, solubilityModel ); + + m_CO2SolubilityTable->outputPVTTableData( pvtOutputOpts ); + m_WaterVapourisationTable->outputPVTTableData( pvtOutputOpts ); + } void CO2Solubility::checkTablesParameters( real64 const pressure, @@ -418,8 +282,6 @@ CO2Solubility::KernelWrapper CO2Solubility::createKernelWrapper() const m_phaseLiquidIndex ); } -REGISTER_CATALOG_ENTRY( FlashModelBase, CO2Solubility, string const &, string_array const &, string_array const &, string_array const &, array1d< real64 > const &, bool const ) - } // end namespace PVTProps } // namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Solubility.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Solubility.hpp index bc0492008fa..9e637b7c9b7 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Solubility.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2Solubility.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,10 +21,10 @@ #define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_CO2BRINE_FUNCTIONS_CO2SOLUBILITY_HPP_ #include "FlashModelBase.hpp" - #include "constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.hpp" #include "constitutive/fluid/multifluid/Layouts.hpp" #include "constitutive/fluid/multifluid/MultiFluidUtils.hpp" +#include "fileIO/Outputs/OutputBase.hpp" #include "functions/TableFunction.hpp" namespace geos @@ -41,8 +42,8 @@ class CO2SolubilityUpdate final : public FlashModelBaseUpdate { public: - using PhaseProp = MultiFluidVar< real64, 3, multifluid::LAYOUT_PHASE, multifluid::LAYOUT_PHASE_DC >; - using PhaseComp = MultiFluidVar< real64, 4, multifluid::LAYOUT_PHASE_COMP, multifluid::LAYOUT_PHASE_COMP_DC >; + using PhaseProp = MultiFluidVar< real64, 3, constitutive::multifluid::LAYOUT_PHASE, constitutive::multifluid::LAYOUT_PHASE_DC >; + using PhaseComp = MultiFluidVar< real64, 4, constitutive::multifluid::LAYOUT_PHASE_COMP, constitutive::multifluid::LAYOUT_PHASE_COMP_DC >; CO2SolubilityUpdate( arrayView1d< real64 const > const & componentMolarWeight, TableFunction const & CO2SolubilityTable, @@ -103,13 +104,20 @@ class CO2SolubilityUpdate final : public FlashModelBaseUpdate class CO2Solubility : public FlashModelBase { public: + enum class SolubilityModel : integer + { + DuanSun, + SpycherPruess, + Tables + }; +public: CO2Solubility( string const & name, string_array const & inputParams, string_array const & phaseNames, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ); + TableFunction::OutputOptions const pvtOutputOpts ); static string catalogName() { return "CO2Solubility"; } @@ -130,7 +138,6 @@ class CO2Solubility : public FlashModelBase KernelWrapper createKernelWrapper() const; private: - /// Table to compute solubility as a function of pressure and temperature TableFunction const * m_CO2SolubilityTable; @@ -160,7 +167,7 @@ CO2SolubilityUpdate::compute( real64 const & pressure, PhaseProp::SliceType const phaseFraction, PhaseComp::SliceType const phaseCompFraction ) const { - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; // Solubility of CO2 is read from the tables in the form of moles of CO2 per kg of water // Solubility of water is read from the tables in the form of moles of water per kg of CO2 @@ -332,6 +339,11 @@ CO2SolubilityUpdate::compute( real64 const & pressure, } } +ENUM_STRINGS( CO2Solubility::SolubilityModel, + "DuanSun", + "SpycherPruess", + "Tables" ); + } // end namespace PVTProps } // end namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2SolubilityDuanSun.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2SolubilityDuanSun.cpp new file mode 100644 index 00000000000..3170912fecc --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2SolubilityDuanSun.cpp @@ -0,0 +1,241 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CO2SolubilityDuanSun.cpp + */ + +#include "constitutive/fluid/multifluid/CO2Brine/functions/CO2SolubilityDuanSun.hpp" +#include "constitutive/fluid/multifluid/CO2Brine/functions/CO2EOSSolver.hpp" + +#include "common/Units.hpp" + +namespace geos +{ +namespace constitutive +{ +namespace PVTProps +{ + +namespace +{ + +inline constexpr real64 P_Pa_f = 1e+5; +inline constexpr real64 P_c = 73.773 * P_Pa_f; +inline constexpr real64 T_c = 304.1282; +inline constexpr real64 Rgas = constants::gasConstant; +inline constexpr real64 V_c = Rgas*T_c/P_c; + +// these coefficients are in Table (A1) of Duan and Sun (2003) +inline constexpr real64 acoef[15] = +{ 8.99288497e-2, -4.94783127e-1, 4.77922245e-2, 1.03808883e-2, -2.82516861e-2, 9.49887563e-2, 5.20600880e-4, + -2.93540971e-4, -1.77265112e-3, -2.51101973e-5, 8.93353441e-5, 7.88998563e-5, -1.66727022e-2, 1.398, 2.96e-2 }; + +real64 co2EOS( real64 const & T, real64 const & P, real64 const & V_r ) +{ + // reduced pressure + real64 const P_r = P*P_Pa_f/P_c; + // reduced temperature + real64 const T_r = units::convertCToK( T )/T_c; + + // CO2 equation of state + // see equation (A1) in Duan and Sun (2003) + real64 const f_Z = 1.0 + + ( acoef[0] + acoef[1]/(T_r * T_r) + acoef[2]/(T_r * T_r * T_r) )/V_r + + ( acoef[3] + acoef[4]/(T_r * T_r) + acoef[5]/(T_r * T_r * T_r) )/(V_r*V_r) + + ( acoef[6] + acoef[7]/(T_r * T_r) + acoef[8]/(T_r * T_r * T_r) )/(V_r*V_r*V_r*V_r) + + ( acoef[9] + acoef[10]/(T_r * T_r) + acoef[11]/(T_r * T_r * T_r) )/(V_r*V_r*V_r*V_r*V_r) + + acoef[12]/(T_r * T_r * T_r)/(V_r * V_r) * (acoef[13] + acoef[14]/(V_r * V_r)) * exp( -acoef[14]/(V_r * V_r)) - P_r * V_r / T_r; + + return f_Z; +} + +real64 PWater( real64 const & T ) +{ + // these coefficients are defined in Table (B1) of Duan and Sun (2003) + static constexpr real64 ccoef[5] = { -38.640844, 5.8948420, 59.876516, 26.654627, 10.637097 }; + + // H2O critical pressure (bars) + real64 const P_c_w = 220.85; + // H2O critical temperature (K) + real64 const T_c_w = 647.29; + real64 const tt = ( units::convertCToK( T )-T_c_w )/T_c_w; + // Empirical model for water pressure of equation (B1) of Duan and Sun (2003) + real64 const x = ( P_c_w*units::convertCToK( T )/T_c_w ) + * (1 + + ccoef[0]*pow( -tt, 1.9 ) + + ccoef[1]*tt + + ccoef[2]*tt*tt + + ccoef[3]*tt*tt*tt + + ccoef[4]*tt*tt*tt*tt); + + return x; +} + +real64 logF( real64 const & T, real64 const & P, real64 const & V_r ) +{ + // reduced pressure + real64 const P_r = P*P_Pa_f/P_c; + // reduced temperature + real64 const T_r = units::convertCToK( T ) / T_c; + real64 const Z = P_r * V_r/T_r; + + real64 const inv_T_r = 1.0/T_r; + real64 const inv_T_r2 = inv_T_r*inv_T_r; + real64 const inv_T_r3 = inv_T_r2*inv_T_r; + real64 const inv_V_r = 1.0/V_r; + real64 const inv_V_r2 = inv_V_r*inv_V_r; + real64 const inv_V_r3 = inv_V_r2*inv_V_r; + real64 const inv_V_r4 = inv_V_r3*inv_V_r; + real64 const inv_V_r5 = inv_V_r4*inv_V_r; + + // fugacity coefficient of CO2, equation (A6) of Duan and Sun (2003) + real64 const log_f = Z - 1 - log( Z ) + + ( acoef[0] + acoef[1]*inv_T_r2 + acoef[2]*inv_T_r3 )*inv_V_r + + ( acoef[3] + acoef[4]*inv_T_r2 + acoef[5]*inv_T_r3 )*0.5*inv_V_r2 + + ( acoef[6] + acoef[7]*inv_T_r2 + acoef[8]*inv_T_r3 )*0.25*inv_V_r4 + + ( acoef[9] + acoef[10]*inv_T_r2 + acoef[11]*inv_T_r3 )*0.2*inv_V_r5 + + acoef[12]*0.5*inv_T_r3/acoef[14] * ( acoef[13] + 1.0 - (acoef[13] + 1.0 + acoef[14]*inv_V_r2) * exp( -acoef[14]*inv_V_r2 ) ); + //This causes a divide by zero FPE when using clang14 on ruby + // real64 const log_f = Z - 1 - log( Z ) + + // ( acoef[0] + acoef[1]/T_r/T_r + acoef[2]/T_r/T_r/T_r )/V_r + // + ( acoef[3] + acoef[4]/T_r/T_r + acoef[5]/T_r/T_r/T_r )/2.0/V_r/V_r + // + ( acoef[6] + acoef[7]/T_r/T_r + acoef[8]/T_r/T_r/T_r )/4.0/V_r/V_r/V_r/V_r + // + ( acoef[9] + acoef[10]/T_r/T_r + acoef[11]/T_r/T_r/T_r )/5.0/V_r/V_r/V_r/V_r/V_r + // + acoef[12]/2.0/T_r/T_r/T_r/acoef[14] * ( acoef[13] + 1.0 - (acoef[13] + 1.0 + acoef[14]/V_r/V_r) * exp( + // -acoef[14]/V_r/V_r ) ); + + + return log_f; +} + +real64 Par( real64 const & T, real64 const & P, real64 const (&cc)[11] ) +{ + // "equation for the parameters", see equation (7) of Duan and Sun (2003) + real64 x = cc[0] + + cc[1]*T + + cc[2]/T + + cc[3]*T*T + + cc[4]/(630.0-T) + + cc[5]*P + + cc[6]*P *log( T ) + + cc[7]*P/T + + cc[8]*P/(630.0-T) + + cc[9]*P*P/(630.0-T)/(630.0-T) + + cc[10]*T *log( P ); + + return x; +} + +real64 CO2SolubilityFunction( string const & name, + real64 const & tolerance, + real64 const & T, + real64 const & P, + real64 (* f)( real64 const & x1, real64 const & x2, real64 const & x3 ) ) +{ + // compute the initial guess for Newton's method + real64 const initialReducedVolume = 0.75*Rgas*units::convertCToK( T )/(P*P_Pa_f)*(1/V_c); + + // define the local solver parameters + // for now, this is hard-coded, but we may want to let the user access the parameters at some point + integer const maxNumNewtonIter = 500; + integer const maxNumBacktrackIter = 8; + real64 const maxAbsUpdate = 1e12; + real64 const minAbsDeriv = 0; + real64 const allowedMinValue = 0.05; // value chosen to match previous implementation + real64 const presMultiplierForReporting = 1e5; // this is because P is in hectopascal in this function + + // solve the CO2 equation of state for this pair of (pres, temp) + // return the reduced volume + return CO2EOSSolver::solve( name, + maxNumNewtonIter, + maxNumBacktrackIter, + tolerance, + minAbsDeriv, + maxAbsUpdate, + allowedMinValue, + initialReducedVolume, + T, + P, + presMultiplierForReporting, + f ); +} + +void calculateCO2Solubility( string const & functionName, + real64 const & tolerance, + PTTableCoordinates const & tableCoords, + real64 const & salinity, + array1d< real64 > const & values ) +{ + // Interaction parameters, see Table 2 of Duan and Sun (2003) + static constexpr real64 mu[11] = + { 28.9447706, -0.0354581768, -4770.67077, 1.02782768e-5, 33.8126098, 9.04037140e-3, + -1.14934031e-3, -0.307405726, -0.0907301486, 9.32713393e-4, 0 }; + static constexpr real64 lambda[11] = { -0.411370585, 6.07632013e-4, 97.5347708, 0, 0, 0, 0, -0.0237622469, 0.0170656236, 0, 1.41335834e-5 }; + static constexpr real64 zeta[11] = { 3.36389723e-4, -1.98298980e-5, 0, 0, 0, 0, 0, 2.12220830e-3, -5.24873303e-3, 0, 0 }; + + localIndex const nPressures = tableCoords.nPressures(); + localIndex const nTemperatures = tableCoords.nTemperatures(); + + for( localIndex i = 0; i < nPressures; ++i ) + { + real64 const P = tableCoords.getPressure( i ) / P_Pa_f; + + for( localIndex j = 0; j < nTemperatures; ++j ) + { + real64 const T = tableCoords.getTemperature( j ); + + // compute reduced volume by solving the CO2 equation of state + real64 const V_r = CO2SolubilityFunction( functionName, tolerance, T, P, &co2EOS ); + + // compute equation (6) of Duan and Sun (2003) + real64 const logK = Par( units::convertCToK( T ), P, mu ) + - logF( T, P, V_r ) + + 2*Par( units::convertCToK( T ), P, lambda ) * salinity + + Par( units::convertCToK( T ), P, zeta ) * salinity * salinity; + real64 const expLogK = exp( logK ); + + // mole fraction of CO2 in vapor phase, equation (4) of Duan and Sun (2003) + real64 const Pw = PWater( T ); + real64 const y_CO2 = (P - Pw)/P; + values[j*nPressures+i] = y_CO2 * P / expLogK; + + GEOS_WARNING_IF( expLogK <= 1e-10, + GEOS_FMT( "CO2Solubility: exp(logK) = {} is too small (logK = {}, P = {}, T = {}, V_r = {}), resulting solubility value is {}", + expLogK, logK, P, T, V_r, values[j*nPressures+i] )); + } + } +} + +} // end namespace + +void CO2SolubilityDuanSun::populateSolubilityTables( string const & functionName, + PTTableCoordinates const & tableCoords, + real64 const & salinity, + real64 const & tolerance, + array1d< real64 > const & co2SolubilityValues, + array1d< real64 > const & h2oSolubilityValues ) +{ + h2oSolubilityValues.zero(); + calculateCO2Solubility( functionName, + tolerance, + tableCoords, + salinity, + co2SolubilityValues ); +} + +} // end namespace PVTProps +} // namespace constitutive +} // end namespace geos diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2SolubilityDuanSun.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2SolubilityDuanSun.hpp new file mode 100644 index 00000000000..92c37932e5d --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2SolubilityDuanSun.hpp @@ -0,0 +1,58 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CO2SolubilityDuanSun.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_CO2BRINE_FUNCTIONS_CO2SOLUBILITYDUANSUN_HPP_ +#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_CO2BRINE_FUNCTIONS_CO2SOLUBILITYDUANSUN_HPP_ + +#include "constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.hpp" + +namespace geos +{ +namespace constitutive +{ +namespace PVTProps +{ + +struct CO2SolubilityDuanSun +{ +/** + * @brief Create CO2 and H2O solubility table based on Duan and Sun (2003) + * @details Each generated table is a 2D table with lookup properties pressure (in Pa) and + * temperature (in degC). The returned CO2 solubility is in mole of CO2 per kg of + * H2O and the returned water vapourisation is in moles of H2O per kg of CO2. + * @param[in] functionName The name of the model + * @param[in] tableCoords The values of pressure and temperature + * @param[in] salinity The salinity of the brine + * @param[in] tolerance Tolerance to be used in solving for the solubility + * @param[out] co2SolubilityValues The CO2 solubility values (mol/kg) at the given pressures and temperatures + * @param[out] h2oSolubilityValues The H2O solubility values (mol/kg) at the given pressures and temperatures + */ + static void populateSolubilityTables( string const & functionName, + PTTableCoordinates const & tableCoords, + real64 const & salinity, + real64 const & tolerance, + array1d< real64 > const & co2SolubilityValues, + array1d< real64 > const & h2oSolubilityValues ); +}; + +} // end namespace PVTProps +} // end namespace constitutive +} // end namespace geos + +#endif //GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_CO2BRINE_FUNCTIONS_CO2SOLUBILITYDUANSUN_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2SolubilitySpycherPruess.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2SolubilitySpycherPruess.cpp new file mode 100644 index 00000000000..4d832d01a27 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2SolubilitySpycherPruess.cpp @@ -0,0 +1,203 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CO2SolubilitySpycherPruess.cpp + */ + +#include "CO2SolubilitySpycherPruess.hpp" +#include "constitutive/fluid/multifluid/CO2Brine/functions/SpanWagnerCO2Density.hpp" +#include "common/Units.hpp" + +namespace geos +{ + +namespace +{ +/** + * Physical constants + * These correlations are developed with units: pressure [bar], volume [cm3], temperature [K]. + * The equilibrium constant correlations (equilibriumConstantCO2 and equilibriumConstantH2O) have a temperature in C + */ +static constexpr real64 P_ref = 1.0; // Reference pressure is 1 bar +static constexpr real64 Pa_2_bar = 1.0e-5; // Conversion factor from Pa to Bar +static constexpr real64 R = 10.0*constants::gasConstant; // Universal gas constant in [bar.cm3/mol.K] +static constexpr real64 molarMassCO2 = 44.01e-3; // Molar mass of CO2 [kg/mol] +static constexpr real64 molarMassH2O = 18.01e-3; // Molar mass of H2O [kg/mol] +static constexpr real64 v_av_H2O = 18.1; // Average partial molar volume of H2O [cm3/mol] +static constexpr real64 v_av_CO2 = 32.6; // Average partial molar volume of CO2 [cm3/mol] + +/** + * @brief Calculate the CO2 equilibrium constant from Spycher et al. (2003) + * @details The correlation parameters are given in Table 2 of Spycher et al. (2003) + * @param[in] T Temperature [C] + */ +real64 equilibriumConstantCO2( real64 const T ) +{ + constexpr real64 c[] = {1.189, 1.304e-2, -5.446e-5}; + real64 const logk0_CO2 = c[0] + T * (c[1] + T * c[2]); + return pow( 10.0, logk0_CO2 ); +} + +/** + * @brief Calculate the H2O equilibrium constant from Spycher et al. (2003) + * @details The correlation parameters are given in Table 2 of Spycher et al. (2003) + * @param[in] T Temperature [C] + */ +real64 equilibriumConstantH2O( real64 const T ) +{ + constexpr real64 c[] = {-2.209, 3.097e-2, -1.098e-4, 2.048e-7}; + real64 const logk0_H2O = c[0] + T * (c[1] + T * (c[2] + T* c[3])); + return pow( 10.0, logk0_H2O ); +} + +/** + * @brief Calculate the fugacity coefficient of CO2 from the RK-EOS + * @param[in] P Pressure [bar] + * @param[in] T Temperature [K] + * @param[in] rhoCO2 Density of CO2 [kg/m3] + * @param[in] salinity Salinity of water + */ +real64 fugacityCoefficientCO2( real64 const P, real64 const T, real64 const rhoCO2, real64 const salinity ) +{ + GEOS_UNUSED_VAR( salinity ); + real64 const V = 1.0e6*molarMassCO2/rhoCO2; // Molar volume [cm3/mol] + + // Mixture parameters from the tuned Redlich-Kwong EOS + // These values are given in Table 1 of Spycher et al. (2003) + real64 const a_CO2 = (7.54e7 - 4.13e4*T); // [bar.cm3.K^(1/2)/mol^2] + real64 constexpr b_CO2 = 27.8; // [cm3/mol] + + real64 const lnPhiCO2 = log( V/(V - b_CO2)) + b_CO2/(V - b_CO2) + - 2*a_CO2/(R*pow( T, 1.5 )*b_CO2)*log((V + b_CO2)/V ) + + a_CO2*b_CO2/(R*pow( T, 1.5 )*b_CO2*b_CO2) * (log((V + b_CO2)/V ) - b_CO2/(V + b_CO2)) + - log( P*V/(R*T)); + return exp( lnPhiCO2 ); +} + +/** + * @brief Calculate the fugacity coefficient of CO2 from the RK-EOS + * @param[in] P Pressure [bar] + * @param[in] T Temperature [K] + * @param[in] rhoCO2 Density of CO2 [kg/m3] + * @param[in] salinity Salinity of water + */ +real64 fugacityCoefficientH2O( real64 const P, real64 const T, real64 const rhoCO2, real64 const salinity ) +{ + GEOS_UNUSED_VAR( salinity ); + real64 const V = 1.0e6*molarMassCO2/rhoCO2; // Molar volume [cm3/mol] + + // Mixture parameters from the tuned Redlich-Kwong EOS + // These values are given in Table 1 of Spycher et al. (2003) + real64 const a_CO2 = (7.54e7 - 4.13e4*T); // [bar.cm3.K^(1/2)/mol^2] + real64 constexpr a_CO2_H2O = 7.89e7; // [bar.cm3.K^(1/2)/mol^2] + real64 constexpr b_CO2 = 27.8; // [cm3/mol] + real64 constexpr b_H2O = 18.18; // [cm3/mol] + + real64 const lnPhiH2O = log( V/(V - b_CO2) ) + b_H2O/(V - b_CO2) + - 2.0 * a_CO2_H2O * log( (V + b_CO2)/V ) / ( R*pow( T, 1.5 )*b_CO2 ) + + a_CO2 * b_H2O / ( R*pow( T, 1.5 )*b_CO2*b_CO2 )*( log( (V + b_CO2)/V ) - b_CO2/(V + b_CO2) ) + - log( P*V/(R*T) ); + return exp( lnPhiH2O ); +} + +/** + * @brief Calculate the parameter A from Eq (11) of Spycher et al. (2003) + * @param[in] P Pressure [Pa] + * @param[in] T Temperature [C] + * @param[in] rhoCO2 CO2 density [kg/m3] + * @param[in] salinity Salinity of the water + */ +real64 computeA( real64 const P, real64 const T, real64 const rhoCO2, real64 const salinity ) +{ + real64 const P_in_bar = P * Pa_2_bar; + real64 const deltaP = P_in_bar - P_ref; + real64 const TinK = units::convertCToK( T ); + real64 const k0_H2O = equilibriumConstantH2O( T ); // K-value for H2O at 1 bar + real64 const phi_H2O = fugacityCoefficientH2O( P_in_bar, TinK, rhoCO2, salinity ); // Fugacity coefficient of H2O for the water-CO2 system + real64 const A = k0_H2O/(phi_H2O*P_in_bar) * exp( deltaP*v_av_H2O/(R*TinK)); + return A; +} + +/** + * @brief Calculate the parameter B from Eq (12) of Spycher et al. (2003) + * @param[in] P Pressure [Pa] + * @param[in] T Temperature [C] + * @param[in] rhoCO2 CO2 density [kg/m3] + * @param[in] salinity Salinity of the water + */ +real64 computeB( real64 const P, real64 const T, real64 const rhoCO2, real64 const salinity ) +{ + real64 const P_in_bar = P * Pa_2_bar; + real64 const deltaP = P_in_bar - P_ref; + real64 const TinK = units::convertCToK( T ); + real64 const k0_CO2 = equilibriumConstantCO2( T ); // K-value for CO2 at 1 bar + real64 const phi_CO2 = fugacityCoefficientCO2( P_in_bar, TinK, rhoCO2, salinity ); // Fugacity coefficient of CO2 for the water-CO2 system + real64 const B = phi_CO2*P_in_bar/(55.508*k0_CO2) * exp( -(deltaP*v_av_CO2)/(R*TinK) ); + return B; +} +} // end namespace + +namespace constitutive +{ +namespace PVTProps +{ +void CO2SolubilitySpycherPruess::populateSolubilityTables( string const & functionName, + PTTableCoordinates const & tableCoords, + real64 const & salinity, + real64 const & tolerance, + array1d< real64 > const & co2SolubilityValues, + array1d< real64 > const & h2oSolubilityValues ) +{ + localIndex const nPressures = tableCoords.nPressures(); + localIndex const nTemperatures = tableCoords.nTemperatures(); + + // Calculate the CO2 density + array1d< real64 > densities( nPressures*nTemperatures ); + SpanWagnerCO2Density::calculateCO2Density( GEOS_FMT( "{}_co2_density", functionName ), + tolerance, + tableCoords, + densities ); + + for( localIndex i = 0; i < nPressures; ++i ) + { + real64 const P = tableCoords.getPressure( i ); + + for( localIndex j = 0; j < nTemperatures; ++j ) + { + real64 const T = tableCoords.getTemperature( j ); + + // Get the CO2 density + real64 const rhoCO2 = densities[j*nPressures+i]; + + // Calculate A and B + real64 const A = computeA( P, T, rhoCO2, salinity ); + real64 const B = computeB( P, T, rhoCO2, salinity ); + + // Calculate the mole fractions + // Eqns (13) and (14) from Spycher et al. (2003) + real64 const y_H2O = (1.0 - B)/(1.0/A - B); + real64 const x_CO2 = B*(1.0 - y_H2O); + + // Calculate the solubility + co2SolubilityValues[j*nPressures+i] = x_CO2/((1.0 - x_CO2)*molarMassH2O); + h2oSolubilityValues[j*nPressures+i] = y_H2O/((1.0 - y_H2O)*molarMassCO2); + } + } +} + +} // end namespace PVTProps +} // namespace constitutive +} // end namespace geos diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2SolubilitySpycherPruess.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2SolubilitySpycherPruess.hpp new file mode 100644 index 00000000000..187ad434fdb --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/CO2SolubilitySpycherPruess.hpp @@ -0,0 +1,60 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CO2SolubilitySpycherPruess.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_CO2BRINE_FUNCTIONS_CO2SOLUBILITYSPYCHERPRUESS_HPP_ +#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_CO2BRINE_FUNCTIONS_CO2SOLUBILITYSPYCHERPRUESS_HPP_ + +#include "constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.hpp" + +namespace geos +{ +namespace constitutive +{ +namespace PVTProps +{ + +struct CO2SolubilitySpycherPruess +{ + +/** + * @brief Create CO2 and H2O solubility table based on Spycher, Pruess, Ennis-King (2003) + * @details Each generated table is a 2D table with lookup properties pressure (in Pa) and + * temperature (in degC). The returned CO2 solubility is in mole of CO2 per kg of + * H2O and the returned water vapourisation is in moles of H2O per kg of CO2. + * @param[in] functionName The name of the model + * @param[in] tableCoords The values of pressure and temperature + * @param[in] salinity The salinity of the brine + * @param[in] tolerance Tolerance to be used in solving for the solubility + * @param[out] co2SolubilityValues The CO2 solubility values (mol/kg) at the given pressures and temperatures + * @param[out] h2oSolubilityValues The H2O solubility values (mol/kg) at the given pressures and temperatures + */ + static void populateSolubilityTables( string const & functionName, + PTTableCoordinates const & tableCoords, + real64 const & salinity, + real64 const & tolerance, + array1d< real64 > const & co2SolubilityValues, + array1d< real64 > const & h2oSolubilityValues ); + +}; + +} // end namespace PVTProps +} // end namespace constitutive +} // end namespace geos + +#endif //GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_CO2BRINE_FUNCTIONS_CO2SOLUBILITYSPYCHERPRUESS_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineDensity.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineDensity.cpp index ec24045a0fa..d35b2c040f5 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineDensity.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineDensity.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -37,7 +38,7 @@ EzrokhiBrineDensity::EzrokhiBrineDensity( string const & name, string_array const & inputPara, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ): + TableFunction::OutputOptions const pvtOutputOpts ): PVTFunctionBase( name, componentNames, componentMolarWeight ) @@ -51,16 +52,14 @@ EzrokhiBrineDensity::EzrokhiBrineDensity( string const & name, makeCoefficients( inputPara ); m_waterSatDensityTable = PureWaterProperties::makeSaturationDensityTable( m_functionName, FunctionManager::getInstance() ); m_waterSatPressureTable = PureWaterProperties::makeSaturationPressureTable( m_functionName, FunctionManager::getInstance() ); - if( printTable ) - { - m_waterSatDensityTable->print( m_waterSatDensityTable->getName() ); - m_waterSatPressureTable->print( m_waterSatPressureTable->getName() ); - } + + m_waterSatPressureTable->outputPVTTableData( pvtOutputOpts ); + m_waterSatDensityTable->outputPVTTableData( pvtOutputOpts ); } void EzrokhiBrineDensity::makeCoefficients( string_array const & inputPara ) { - // compute brine density following Ezrokhi`s method (referenced in Eclipse TD, Aqueous phase properties) + // compute brine density following Ezrokhi`s method // Reference : Zaytsev, I.D. and Aseyev, G.G. Properties of Aqueous Solutions of Electrolytes, Boca Raton, Florida, USA CRC Press (1993). m_waterCompressibility = 4.5e-10; // Pa-1 @@ -102,8 +101,6 @@ EzrokhiBrineDensity::createKernelWrapper() const m_coef2 ); } -REGISTER_CATALOG_ENTRY( PVTFunctionBase, EzrokhiBrineDensity, string const &, string_array const &, string_array const &, array1d< real64 > const &, bool const ) - } // end namespace PVTProps } // namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineDensity.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineDensity.hpp index 0f66d19ba4e..edf0d083335 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineDensity.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineDensity.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -108,7 +109,7 @@ class EzrokhiBrineDensity : public PVTFunctionBase string_array const & inputPara, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ); + TableFunction::OutputOptions const pvtOutputOpts ); virtual ~EzrokhiBrineDensity() override = default; @@ -171,7 +172,8 @@ void EzrokhiBrineDensityUpdate::compute( real64 const & pressure, arraySlice1d< real64, USD3 > const & dValue, bool useMass ) const { - using Deriv = multifluid::DerivativeOffset; + constexpr integer numDof = 4; + using Deriv = constitutive::multifluid::DerivativeOffset; real64 waterSatDensity_dTemperature = 0.0; real64 waterSatPressure_dTemperature = 0.0; @@ -188,32 +190,39 @@ void EzrokhiBrineDensityUpdate::compute( real64 const & pressure, real64 const coefPhaseComposition = m_coef0 + temperature * ( m_coef1 + m_coef2 * temperature ); + real64 const mw_co2 = m_componentMolarWeight[m_CO2Index]; + real64 const mw_h2o = m_componentMolarWeight[m_waterIndex]; + // we have to convert molar component phase fraction (phaseComposition[m_CO2Index]) to mass fraction - real64 const waterMWInv = 1.0 / (phaseComposition[m_CO2Index] * m_componentMolarWeight[m_CO2Index] - + phaseComposition[m_waterIndex] * m_componentMolarWeight[m_waterIndex]); + real64 const waterMWInv = 1.0 / (phaseComposition[m_CO2Index] * mw_co2 + phaseComposition[m_waterIndex] * mw_h2o); + real64 dWaterMWInv[numDof]{}; + for( integer dof = 0; dof < numDof; ++dof ) + { + dWaterMWInv[dof] = -(dPhaseComposition[m_CO2Index][dof] * mw_co2 + dPhaseComposition[m_waterIndex][dof] * mw_h2o)*waterMWInv*waterMWInv; + } - real64 const massPhaseCompositionCO2 = phaseComposition[m_CO2Index] * m_componentMolarWeight[m_CO2Index] * waterMWInv; + real64 const massPhaseCompositionCO2 = phaseComposition[m_CO2Index] * mw_co2 * waterMWInv; real64 const exponent = coefPhaseComposition * massPhaseCompositionCO2; + real64 dExponent[numDof]{}; + for( integer dof = 0; dof < numDof; ++dof ) + { + dExponent[dof] = coefPhaseComposition * mw_co2 * + (dPhaseComposition[m_CO2Index][dof] * waterMWInv + phaseComposition[m_CO2Index] * dWaterMWInv[dof]); + } + dExponent[Deriv::dT] += ( m_coef1 + 2.0 * m_coef2 * temperature) * massPhaseCompositionCO2; - real64 const exponent_dPressure = coefPhaseComposition * dPhaseComposition[m_CO2Index][Deriv::dP]; - real64 const exponent_dTemperature = coefPhaseComposition * dPhaseComposition[m_CO2Index][Deriv::dT] + - ( m_coef1 + 2 * m_coef2 * temperature) * massPhaseCompositionCO2; - // compute only common part of derivatives w.r.t. CO2 and water phase compositions - // later to be multiplied by (phaseComposition[m_waterIndex]) and ( -phaseComposition[m_CO2Index] ) respectively - real64 const exponent_dPhaseComp = coefPhaseComposition * m_componentMolarWeight[m_CO2Index] * m_componentMolarWeight[m_waterIndex] * waterMWInv * waterMWInv; - real64 exponentPowered = pow( 10, exponent ); + real64 exponentPowered = pow( 10.0, exponent ); value = waterDensity * exponentPowered; - real64 const dValueCoef = LvArray::math::log( 10 ) * value; - dValue[Deriv::dP] = dValueCoef * exponent_dPressure + waterDensity_dPressure * exponentPowered; - dValue[Deriv::dT] = dValueCoef * exponent_dTemperature + waterDensity_dTemperature * exponentPowered; + real64 const dValueCoef = LvArray::math::log( 10.0 ) * value; + + dValue[Deriv::dP] = dValueCoef * dExponent[Deriv::dP] + waterDensity_dPressure * exponentPowered; + dValue[Deriv::dT] = dValueCoef * dExponent[Deriv::dT] + waterDensity_dTemperature * exponentPowered; - // here, we multiply common part of derivatives by specific coefficients - real64 const dValue_dPhaseComp = dValueCoef * exponent_dPhaseComp; - dValue[Deriv::dC+m_CO2Index] = dValue_dPhaseComp * phaseComposition[m_waterIndex] * dPhaseComposition[m_CO2Index][Deriv::dC+m_CO2Index]; - dValue[Deriv::dC+m_waterIndex] = dValue_dPhaseComp * ( -phaseComposition[m_CO2Index] ) * dPhaseComposition[m_waterIndex][Deriv::dC+m_waterIndex]; + dValue[Deriv::dC+m_CO2Index] = dValueCoef * dExponent[Deriv::dC+m_CO2Index]; + dValue[Deriv::dC+m_waterIndex] = dValueCoef * dExponent[Deriv::dC+m_waterIndex]; if( !useMass ) { diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineViscosity.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineViscosity.cpp index ec63aa192a9..65976e0d0d9 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineViscosity.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineViscosity.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -37,7 +38,7 @@ EzrokhiBrineViscosity::EzrokhiBrineViscosity( string const & name, string_array const & inputPara, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ): + TableFunction::OutputOptions const pvtOutputOpts ): PVTFunctionBase( name, componentNames, componentMolarWeight ) @@ -50,13 +51,13 @@ EzrokhiBrineViscosity::EzrokhiBrineViscosity( string const & name, makeCoefficients( inputPara ); m_waterViscosityTable = PureWaterProperties::makeSaturationViscosityTable( m_functionName, FunctionManager::getInstance() ); - if( printTable ) - m_waterViscosityTable->print( m_waterViscosityTable->getName() ); + + m_waterViscosityTable->outputPVTTableData( pvtOutputOpts ); } void EzrokhiBrineViscosity::makeCoefficients( string_array const & inputPara ) { - // compute brine viscosity following Ezrokhi`s method (referenced in Eclipse TD, Aqueous phase properties) + // compute brine viscosity following Ezrokhi`s method // Reference : Zaytsev, I.D. and Aseyev, G.G. Properties of Aqueous Solutions of Electrolytes, Boca Raton, Florida, USA CRC Press (1993). GEOS_THROW_IF_LT_MSG( inputPara.size(), 5, GEOS_FMT( "{}: insufficient number of model parameters", m_functionName ), @@ -93,8 +94,6 @@ EzrokhiBrineViscosity::createKernelWrapper() const m_coef2 ); } -REGISTER_CATALOG_ENTRY( PVTFunctionBase, EzrokhiBrineViscosity, string const &, string_array const &, string_array const &, array1d< real64 > const &, bool const ) - } // end namespace PVTProps } // namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineViscosity.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineViscosity.hpp index f007f573f83..bcecc698226 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineViscosity.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/EzrokhiBrineViscosity.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -97,7 +98,7 @@ class EzrokhiBrineViscosity : public PVTFunctionBase string_array const & inputPara, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ); + TableFunction::OutputOptions const pvtOutputOpts ); virtual ~EzrokhiBrineViscosity() override = default; @@ -157,7 +158,7 @@ void EzrokhiBrineViscosityUpdate::compute( real64 const & pressure, { GEOS_UNUSED_VAR( pressure, useMass ); - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; real64 waterVisc_dTemperature = 0.0; real64 const waterVisc = m_waterViscosityTable.compute( &temperature, &waterVisc_dTemperature ); diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/FenghourCO2Viscosity.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/FenghourCO2Viscosity.cpp index 741ab11f3c0..9664a1b3ec4 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/FenghourCO2Viscosity.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/FenghourCO2Viscosity.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -141,14 +142,14 @@ FenghourCO2Viscosity::FenghourCO2Viscosity( string const & name, string_array const & inputParams, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ) + TableFunction::OutputOptions const pvtOutputOpts ) : PVTFunctionBase( name, componentNames, componentMolarWeight ) { m_CO2ViscosityTable = makeViscosityTable( inputParams, m_functionName, FunctionManager::getInstance() ); - if( printTable ) - m_CO2ViscosityTable->print( m_CO2ViscosityTable->getName() ); + + m_CO2ViscosityTable->outputPVTTableData( pvtOutputOpts ); } void FenghourCO2Viscosity::checkTablesParameters( real64 const pressure, @@ -165,8 +166,6 @@ FenghourCO2Viscosity::createKernelWrapper() const *m_CO2ViscosityTable ); } -REGISTER_CATALOG_ENTRY( PVTFunctionBase, FenghourCO2Viscosity, string const &, string_array const &, string_array const &, array1d< real64 > const &, bool const ) - } // end namespace PVTProps } // namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/FenghourCO2Viscosity.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/FenghourCO2Viscosity.hpp index e8205e8745b..889c1e39451 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/FenghourCO2Viscosity.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/FenghourCO2Viscosity.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -75,7 +76,7 @@ class FenghourCO2Viscosity : public PVTFunctionBase string_array const & inputParams, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ); + TableFunction::OutputOptions const pvtOutputOpts ); virtual ~FenghourCO2Viscosity() override = default; @@ -124,7 +125,7 @@ void FenghourCO2ViscosityUpdate::compute( real64 const & pressure, dPhaseComposition, useMass ); - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; real64 const input[2] = { pressure, temperature }; real64 densityDeriv[2]{}; diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/FlashModelBase.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/FlashModelBase.hpp index 314f7498dde..ca568be573c 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/FlashModelBase.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/FlashModelBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -77,19 +78,6 @@ class FlashModelBase virtual ~FlashModelBase() = default; - using CatalogInterface = dataRepository::CatalogInterface< FlashModelBase, - string const &, - string_array const &, - string_array const &, - string_array const &, - array1d< real64 > const &, - bool const >; - static typename CatalogInterface::CatalogType & getCatalog() - { - static CatalogInterface::CatalogType catalog; - return catalog; - } - virtual string getCatalogName() const = 0; /** diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/NoOpPVTFunction.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/NoOpPVTFunction.hpp index 47721c43539..4be877cc7d7 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/NoOpPVTFunction.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/NoOpPVTFunction.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -70,12 +71,12 @@ class NoOpPVTFunction : public PVTFunctionBase string_array const & inputPara, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ) + TableFunction::OutputOptions const pvtOutputOpts ) : PVTFunctionBase( name, componentNames, componentMolarWeight ) { - GEOS_UNUSED_VAR( inputPara, printTable ); + GEOS_UNUSED_VAR( inputPara, pvtOutputOpts ); } virtual ~NoOpPVTFunction() override = default; diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionBase.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionBase.hpp index 7bfea2c71a8..877d097bf47 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionBase.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -112,17 +113,6 @@ class PVTFunctionBase virtual ~PVTFunctionBase() = default; - using CatalogInterface = dataRepository::CatalogInterface< PVTFunctionBase, - string const &, - array1d< string > const &, - array1d< string > const &, - array1d< real64 > const &, - bool const >; - static typename CatalogInterface::CatalogType & getCatalog() - { - static CatalogInterface::CatalogType catalog; - return catalog; - } virtual string getCatalogName() const = 0; diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.cpp index 951fd1c22f6..d38da4703bf 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,7 +17,6 @@ * @file PVTFunctionHelpers.cpp */ -#include "codingUtilities/StringUtilities.hpp" #include "constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.hpp" #include "LvArray/src/sortedArrayManipulation.hpp" @@ -45,7 +45,7 @@ BlackOilTables::readTable( string const & fileName, // Remove whitespace and end-of-line characters, if any str = stringutilities::trim( str, " \r" ); - // Remove # and -- (Eclipse-style) comments + // Remove # and -- comments str = stringutilities::removeStringAndFollowingContent( str, "#" ); str = stringutilities::removeStringAndFollowingContent( str, "--" ); diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.hpp index fd0cc5d2386..91afd9c887d 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,6 +19,8 @@ #include "common/DataTypes.hpp" #include "common/Units.hpp" +#include "common/logger/Logger.hpp" +#include "common/format/StringUtilities.hpp" #ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_CO2BRINE_FUNCTIONS_PVTFUNCTIONHELPERS_HPP_ #define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_CO2BRINE_FUNCTIONS_PVTFUNCTIONHELPERS_HPP_ @@ -122,8 +125,8 @@ class PTTableCoordinates localIndex nPressures() const { return coords[coordType::PRES].size(); } localIndex nTemperatures() const { return coords[coordType::TEMP].size(); } - void appendPressure( const real64 & pres ) { coords[coordType::PRES].emplace_back( pres ); } - void appendTemperature( const real64 & temp ) { coords[coordType::TEMP].emplace_back( temp ); } + PTTableCoordinates & appendPressure( const real64 & pres ) { coords[coordType::PRES].emplace_back( pres ); return *this; } + PTTableCoordinates & appendTemperature( const real64 & temp ) { coords[coordType::TEMP].emplace_back( temp ); return *this; } real64 const & getPressure( localIndex i ) const { return coords[coordType::PRES][i]; } real64 const & getTemperature( localIndex i ) const { return coords[coordType::TEMP][i]; } diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineDensity.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineDensity.cpp index 6f57a276661..de646696998 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineDensity.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineDensity.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -176,7 +177,7 @@ PhillipsBrineDensity::PhillipsBrineDensity( string const & name, string_array const & inputParams, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ): + TableFunction::OutputOptions const pvtOutputOpts ): PVTFunctionBase( name, componentNames, componentMolarWeight ) @@ -188,8 +189,8 @@ PhillipsBrineDensity::PhillipsBrineDensity( string const & name, m_waterIndex = PVTFunctionHelpers::findName( componentNames, expectedWaterComponentNames, "componentNames" ); m_brineDensityTable = makeDensityTable( inputParams, m_functionName, FunctionManager::getInstance() ); - if( printTable ) - m_brineDensityTable->print( m_brineDensityTable->getName() ); + + m_brineDensityTable->outputPVTTableData( pvtOutputOpts ); } PhillipsBrineDensity::KernelWrapper @@ -208,8 +209,6 @@ void PhillipsBrineDensity::checkTablesParameters( real64 const pressure, m_brineDensityTable->checkCoord( temperature, 1 ); } -REGISTER_CATALOG_ENTRY( PVTFunctionBase, PhillipsBrineDensity, string const &, string_array const &, string_array const &, array1d< real64 > const &, bool const ) - } // namespace PVTProps } // namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineDensity.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineDensity.hpp index 85208dd7e70..6a1147d57ee 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineDensity.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineDensity.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -85,7 +86,7 @@ class PhillipsBrineDensity : public PVTFunctionBase string_array const & inputParams, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ); + TableFunction::OutputOptions const pvtOutputOpts ); static string catalogName() { return "PhillipsBrineDensity"; } @@ -135,7 +136,7 @@ void PhillipsBrineDensityUpdate::compute( real64 const & pressure, arraySlice1d< real64, USD3 > const & dValue, bool useMass ) const { - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; // this method implements the method proposed by E. Garcia (2001) diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineViscosity.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineViscosity.cpp index 0c8c8466256..a38a58cc664 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineViscosity.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineViscosity.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -36,15 +37,15 @@ PhillipsBrineViscosity::PhillipsBrineViscosity( string const & name, string_array const & inputPara, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ): + TableFunction::OutputOptions const pvtOutputOpts ): PVTFunctionBase( name, componentNames, componentMolarWeight ) { m_waterViscosityTable = PureWaterProperties::makeSaturationViscosityTable( m_functionName, FunctionManager::getInstance() ); - if( printTable ) - m_waterViscosityTable->print( m_waterViscosityTable->getName() ); makeCoefficients( inputPara ); + + m_waterViscosityTable->outputPVTTableData( pvtOutputOpts ); } void PhillipsBrineViscosity::makeCoefficients( string_array const & inputPara ) @@ -91,8 +92,6 @@ PhillipsBrineViscosity::createKernelWrapper() const m_coef1 ); } -REGISTER_CATALOG_ENTRY( PVTFunctionBase, PhillipsBrineViscosity, string const &, string_array const &, string_array const &, array1d< real64 > const &, bool const ) - } // end namespace PVTProps } // namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineViscosity.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineViscosity.hpp index 8edc4419d64..1f429e5d559 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineViscosity.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineViscosity.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -83,7 +84,7 @@ class PhillipsBrineViscosity : public PVTFunctionBase string_array const & inputPara, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ); + TableFunction::OutputOptions const pvtOutputOpts ); virtual ~PhillipsBrineViscosity() override = default; @@ -139,7 +140,7 @@ void PhillipsBrineViscosityUpdate::compute( real64 const & pressure, dPhaseComposition, useMass ); - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; // compute the viscosity of pure water as a function of temperature real64 dPureWaterVisc_dTemperature; diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PureWaterProperties.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PureWaterProperties.cpp index 5fd11ddc4c0..3d47411ea94 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PureWaterProperties.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PureWaterProperties.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PureWaterProperties.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PureWaterProperties.hpp index fa20fc692bd..15d39c325ef 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PureWaterProperties.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/PureWaterProperties.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/SpanWagnerCO2Density.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/SpanWagnerCO2Density.cpp index 16a4a497ee7..d2922a6a174 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/SpanWagnerCO2Density.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/SpanWagnerCO2Density.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -278,7 +279,7 @@ SpanWagnerCO2Density::SpanWagnerCO2Density( string const & name, string_array const & inputParams, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ): + TableFunction::OutputOptions const pvtOutputOpts ): PVTFunctionBase( name, componentNames, componentMolarWeight ) @@ -287,8 +288,8 @@ SpanWagnerCO2Density::SpanWagnerCO2Density( string const & name, m_CO2Index = PVTFunctionHelpers::findName( componentNames, expectedCO2ComponentNames, "componentNames" ); m_CO2DensityTable = makeDensityTable( inputParams, m_functionName, FunctionManager::getInstance() ); - if( printTable ) - m_CO2DensityTable->print( m_CO2DensityTable->getName() ); + + m_CO2DensityTable->outputPVTTableData( pvtOutputOpts ); } void SpanWagnerCO2Density::checkTablesParameters( real64 const pressure, @@ -306,8 +307,6 @@ SpanWagnerCO2Density::createKernelWrapper() const m_CO2Index ); } -REGISTER_CATALOG_ENTRY( PVTFunctionBase, SpanWagnerCO2Density, string const &, string_array const &, string_array const &, array1d< real64 > const &, bool const ) - } // namespace PVTProps } // namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/SpanWagnerCO2Density.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/SpanWagnerCO2Density.hpp index 181559cd7bd..fcaaff68ca2 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/SpanWagnerCO2Density.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/SpanWagnerCO2Density.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -80,7 +81,7 @@ class SpanWagnerCO2Density : public PVTFunctionBase string_array const & inputParams, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ); + TableFunction::OutputOptions const pvtOutputOpts ); static string catalogName() { return "SpanWagnerCO2Density"; } @@ -134,7 +135,7 @@ void SpanWagnerCO2DensityUpdate::compute( real64 const & pressure, { GEOS_UNUSED_VAR( phaseComposition, dPhaseComposition ); - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; real64 const input[2] = { pressure, temperature }; real64 densityDeriv[2]{}; diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/WaterDensity.cpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/WaterDensity.cpp index 244bdcd73c5..bcfccaf9754 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/WaterDensity.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/WaterDensity.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -36,15 +37,15 @@ WaterDensity::WaterDensity( string const & name, string_array const & inputParams, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ): + TableFunction::OutputOptions const pvtOutputOpts ): PVTFunctionBase( name, componentNames, componentMolarWeight ) { GEOS_UNUSED_VAR( inputParams ); m_waterDensityTable = PureWaterProperties::makeSaturationDensityTable( m_functionName, FunctionManager::getInstance() ); - if( printTable ) - m_waterDensityTable->print( m_waterDensityTable->getName() ); + + m_waterDensityTable->outputPVTTableData( pvtOutputOpts ); } void WaterDensity::checkTablesParameters( real64 const pressure, @@ -61,8 +62,6 @@ WaterDensity::createKernelWrapper() const *m_waterDensityTable ); } -REGISTER_CATALOG_ENTRY( PVTFunctionBase, WaterDensity, string const &, string_array const &, string_array const &, array1d< real64 > const &, bool const ) - } // namespace PVTProps } // namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/WaterDensity.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/WaterDensity.hpp index e1bb09c0276..2787b80f124 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/WaterDensity.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/functions/WaterDensity.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -75,7 +76,7 @@ class WaterDensity : public PVTFunctionBase string_array const & inputParams, string_array const & componentNames, array1d< real64 > const & componentMolarWeight, - bool const printTable ); + TableFunction::OutputOptions const pvtOutputOpts ); static string catalogName() { return "WaterDensity"; } virtual string getCatalogName() const final { return catalogName(); } @@ -117,7 +118,7 @@ void WaterDensityUpdate::compute( real64 const & pressure, { GEOS_UNUSED_VAR( phaseComposition, dPhaseComposition, useMass ); - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; real64 const input[2] = { pressure, temperature }; real64 densityDeriv[2]{}; diff --git a/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp b/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp index 894fa58d041..49a0431a292 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -29,10 +30,23 @@ namespace geos { namespace constitutive { + +namespace singlefluid +{ +struct DerivativeOffset +{ + /// index of derivative wrt pressure + static integer constexpr dP = 0; + /// index of derivative wrt temperature + static integer constexpr dT = 1; + +}; +} namespace multifluid { /// indices of pressure, temperature, and composition derivatives +// Fix me - if the order is changed the code crashes struct DerivativeOffset { /// index of derivative wrt pressure @@ -43,6 +57,33 @@ struct DerivativeOffset static integer constexpr dC = 2; }; +/// indices of pressure, temperature, and composition derivatives +template< integer NC, integer IS_THERMAL > +struct DerivativeOffsetC {}; + +template< integer NC > +struct DerivativeOffsetC< NC, 1 > +{ + /// index of derivative wrt pressure + static integer constexpr dP = 0; + /// index of derivative wrt temperature + static integer constexpr dT = dP + 1; + /// index of first derivative wrt compositions + static integer constexpr dC = dP+2; + /// number of derivatives + static integer constexpr nDer = NC + 2; +}; +template< integer NC > +struct DerivativeOffsetC< NC, 0 > +{ + /// index of derivative wrt pressure + static integer constexpr dP = 0; + /// index of first derivative wrt compositions + static integer constexpr dC = dP+1; + /// number of derivatives + static integer constexpr nDer = NC + 1; +}; + #if defined( GEOS_USE_DEVICE ) /// Constitutive model phase property array layout diff --git a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.cpp b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.cpp index 139e8507a01..506741cf8d4 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -157,9 +158,9 @@ void MultiFluidBase::allocateConstitutiveData( dataRepository::Group & parent, resizeFields( parent.size(), numConstitutivePointsPerParentIndex ); } -void MultiFluidBase::postProcessInput() +void MultiFluidBase::postInputInitialization() { - ConstitutiveBase::postProcessInput(); + ConstitutiveBase::postInputInitialization(); integer const numComp = numFluidComponents(); integer const numPhase = numFluidPhases(); @@ -179,6 +180,12 @@ void MultiFluidBase::postProcessInput() GEOS_THROW_IF_NE_MSG( m_componentMolarWeight.size(), numComp, GEOS_FMT( "{}: invalid number of values in attribute '{}'", getFullName(), viewKeyStruct::componentMolarWeightString() ), InputError ); + for( integer ic = 0; ic < numComp; ++ic ) + { + GEOS_THROW_IF_LT_MSG( m_componentMolarWeight[ic], LvArray::NumericLimits< real64 >::epsilon, + GEOS_FMT( "{}: zero molecular weight found for component {}", getFullName(), m_componentNames[ic] ), + InputError ); + } // call to correctly set member array tertiary sizes on the 'main' material object resizeFields( 0, 0 ); diff --git a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp index a221fa6ed0b..dbddad1cd41 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -56,6 +57,20 @@ class MultiFluidBase : public ConstitutiveBase */ static constexpr integer MAX_NUM_PHASES = MultiFluidConstants::MAX_NUM_PHASES; + /** + * @brief Minimum supported number of fluid components (species) for dispatch + * @note This is the mininum number of components that can be used for dispatch in a kernel launch specific for + * this fluid type. + */ + static constexpr integer min_n_components = 2; + + /** + * @brief Maximum supported number of fluid components (species) for dispatch + * @note This is the maxinum number of components that can be used for dispatch in a kernel launch specific for + * this fluid type. + */ + static constexpr integer max_n_components = 5; + /** * @return number of fluid components (species) in the model */ @@ -113,67 +128,67 @@ class MultiFluidBase : public ConstitutiveBase */ void setMassFlag( bool const flag ) { m_useMass = flag; } - arrayView3d< real64 const, multifluid::USD_PHASE > phaseFraction() const + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > phaseFraction() const { return m_phaseFraction.value; } - arrayView4d< real64 const, multifluid::USD_PHASE_DC > dPhaseFraction() const + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > dPhaseFraction() const { return m_phaseFraction.derivs; } - arrayView3d< real64 const, multifluid::USD_PHASE > phaseDensity() const + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > phaseDensity() const { return m_phaseDensity.value; } - arrayView3d< real64 const, multifluid::USD_PHASE > phaseDensity_n() const + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > phaseDensity_n() const { return m_phaseDensity_n; } - arrayView4d< real64 const, multifluid::USD_PHASE_DC > dPhaseDensity() const + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > dPhaseDensity() const { return m_phaseDensity.derivs; } - arrayView3d< real64 const, multifluid::USD_PHASE > phaseMassDensity() const + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > phaseMassDensity() const { return m_phaseMassDensity.value; } - arrayView4d< real64 const, multifluid::USD_PHASE_DC > dPhaseMassDensity() const + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > dPhaseMassDensity() const { return m_phaseMassDensity.derivs; } - arrayView3d< real64 const, multifluid::USD_PHASE > phaseViscosity() const + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > phaseViscosity() const { return m_phaseViscosity.value; } - arrayView4d< real64 const, multifluid::USD_PHASE_DC > dPhaseViscosity() const + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > dPhaseViscosity() const { return m_phaseViscosity.derivs; } - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > phaseCompFraction() const + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > phaseCompFraction() const { return m_phaseCompFraction.value; } - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > phaseCompFraction_n() const + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > phaseCompFraction_n() const { return m_phaseCompFraction_n; } - arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > dPhaseCompFraction() const + arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > dPhaseCompFraction() const { return m_phaseCompFraction.derivs; } - arrayView2d< real64 const, multifluid::USD_FLUID > totalDensity() const + arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > totalDensity() const { return m_totalDensity.value; } - arrayView2d< real64 const, multifluid::USD_FLUID > totalDensity_n() const + arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > totalDensity_n() const { return m_totalDensity_n; } - arrayView3d< real64 const, multifluid::USD_FLUID_DC > dTotalDensity() const + arrayView3d< real64 const, constitutive::multifluid::USD_FLUID_DC > dTotalDensity() const { return m_totalDensity.derivs; } - arrayView3d< real64 const, multifluid::USD_PHASE > phaseEnthalpy() const + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > phaseEnthalpy() const { return m_phaseEnthalpy.value; } - arrayView3d< real64 const, multifluid::USD_PHASE > phaseEnthalpy_n() const + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > phaseEnthalpy_n() const { return m_phaseEnthalpy_n; } - arrayView4d< real64 const, multifluid::USD_PHASE_DC > dPhaseEnthalpy() const + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > dPhaseEnthalpy() const { return m_phaseEnthalpy.derivs; } - arrayView3d< real64 const, multifluid::USD_PHASE > phaseInternalEnergy() const + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > phaseInternalEnergy() const { return m_phaseInternalEnergy.value; } - arrayView3d< real64 const, multifluid::USD_PHASE > phaseInternalEnergy_n() const + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > phaseInternalEnergy_n() const { return m_phaseInternalEnergy_n; } - arrayView4d< real64 const, multifluid::USD_PHASE_DC > dPhaseInternalEnergy() const + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > dPhaseInternalEnergy() const { return m_phaseInternalEnergy.derivs; } /** @@ -207,9 +222,9 @@ class MultiFluidBase : public ConstitutiveBase public: - using PhaseProp = MultiFluidVar< real64, 3, multifluid::LAYOUT_PHASE, multifluid::LAYOUT_PHASE_DC >; - using PhaseComp = MultiFluidVar< real64, 4, multifluid::LAYOUT_PHASE_COMP, multifluid::LAYOUT_PHASE_COMP_DC >; - using FluidProp = MultiFluidVar< real64, 2, multifluid::LAYOUT_FLUID, multifluid::LAYOUT_FLUID_DC >; + using PhaseProp = MultiFluidVar< real64, 3, constitutive::multifluid::LAYOUT_PHASE, constitutive::multifluid::LAYOUT_PHASE_DC >; + using PhaseComp = MultiFluidVar< real64, 4, constitutive::multifluid::LAYOUT_PHASE_COMP, constitutive::multifluid::LAYOUT_PHASE_COMP_DC >; + using FluidProp = MultiFluidVar< real64, 2, constitutive::multifluid::LAYOUT_FLUID, constitutive::multifluid::LAYOUT_FLUID_DC >; public: class KernelWrapper @@ -256,28 +271,28 @@ class MultiFluidBase : public ConstitutiveBase GEOS_FORCE_INLINE integer numPhases() const { return LvArray::integerConversion< integer >( m_phaseFraction.value.size( 2 ) ); } - GEOS_HOST_DEVICE arrayView3d< real64 const, multifluid::USD_PHASE > phaseFraction() const + GEOS_HOST_DEVICE arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > phaseFraction() const { return m_phaseFraction.value; } - GEOS_HOST_DEVICE arrayView3d< real64 const, multifluid::USD_PHASE > phaseDensity() const + GEOS_HOST_DEVICE arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > phaseDensity() const { return m_phaseDensity.value; } - GEOS_HOST_DEVICE arrayView3d< real64 const, multifluid::USD_PHASE > phaseMassDensity() const + GEOS_HOST_DEVICE arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > phaseMassDensity() const { return m_phaseMassDensity.value; } - GEOS_HOST_DEVICE arrayView3d< real64 const, multifluid::USD_PHASE > phaseViscosity() const + GEOS_HOST_DEVICE arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > phaseViscosity() const { return m_phaseViscosity.value; } - GEOS_HOST_DEVICE arrayView4d< real64 const, multifluid::USD_PHASE_COMP > phaseCompFraction() const + GEOS_HOST_DEVICE arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > phaseCompFraction() const { return m_phaseCompFraction.value; } - GEOS_HOST_DEVICE arrayView2d< real64 const, multifluid::USD_FLUID > totalDensity() const + GEOS_HOST_DEVICE arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > totalDensity() const { return m_totalDensity.value; } - GEOS_HOST_DEVICE arrayView3d< real64 const, multifluid::USD_PHASE > phaseEnthalpy() const + GEOS_HOST_DEVICE arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > phaseEnthalpy() const { return m_phaseEnthalpy.value; } - GEOS_HOST_DEVICE arrayView3d< real64 const, multifluid::USD_PHASE > phaseInternalEnergy() const + GEOS_HOST_DEVICE arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > phaseInternalEnergy() const { return m_phaseInternalEnergy.value; } /** @@ -303,13 +318,13 @@ class MultiFluidBase : public ConstitutiveBase real64 const pressure, real64 const temperature, arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & composition, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const & phaseFraction, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const & phaseDensity, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const & phaseMassDensity, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const & phaseViscosity, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const & phaseEnthalpy, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const & phaseInternalEnergy, - arraySlice2d< real64, multifluid::USD_PHASE_COMP-2 > const & phaseCompFraction, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const & phaseFraction, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const & phaseDensity, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const & phaseMassDensity, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const & phaseViscosity, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const & phaseEnthalpy, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const & phaseInternalEnergy, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_COMP-2 > const & phaseCompFraction, real64 & totalDensity ); protected: @@ -389,8 +404,8 @@ class MultiFluidBase : public ConstitutiveBase template< integer maxNumComp, integer maxNumPhase > GEOS_HOST_DEVICE void convertToMassFractions( real64 const (&phaseMolecularWeight)[maxNumPhase], - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const phaseFrac, - arraySlice2d< real64, multifluid::USD_PHASE_COMP - 2 > const phaseCompFrac ) const; + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const phaseFrac, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_COMP - 2 > const phaseCompFrac ) const; /** * @brief Utility function to convert mole fractions to mass fractions and keep derivatives @@ -417,10 +432,10 @@ class MultiFluidBase : public ConstitutiveBase real64 const (&dPhaseMolecularWeight)[maxNumPhase][maxNumComp+2], PhaseProp::SliceType const phaseFrac, PhaseComp::SliceType const phaseCompFrac, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseDens, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseVisc, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseEnthalpy, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseInternalEnergy ) const; + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseVisc, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseEnthalpy, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseInternalEnergy ) const; /** * @brief Utility function to compute the internal energy from pressure, enthalpy, and density @@ -435,10 +450,10 @@ class MultiFluidBase : public ConstitutiveBase template< integer maxNumComp, integer maxNumPhase > GEOS_HOST_DEVICE void computeInternalEnergy( real64 const & pressure, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const phaseFrac, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const phaseMassDens, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const phaseEnthalpy, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const phaseInternalEnergy ) const; + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const phaseFrac, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const phaseMassDens, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const phaseEnthalpy, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const phaseInternalEnergy ) const; /** * @brief Utility function to compute the internal energy from pressure, enthalpy, and density and keep derivatives @@ -465,8 +480,8 @@ class MultiFluidBase : public ConstitutiveBase */ template< integer maxNumComp, integer maxNumPhase > GEOS_HOST_DEVICE - void computeTotalDensity( arraySlice1d< real64, multifluid::USD_PHASE - 2 > const phaseFrac, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const phaseDens, + void computeTotalDensity( arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const phaseFrac, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const phaseDens, real64 & totalDens ) const; /** @@ -508,7 +523,7 @@ class MultiFluidBase : public ConstitutiveBase real64 totalCompressibility( integer const i, integer const q ) const { real64 const totalFluidDensity = totalDensity()( i, q ); - real64 const dTotalFluidDensity_dP = m_totalDensity.derivs( i, q, multifluid::DerivativeOffset::dP ); + real64 const dTotalFluidDensity_dP = m_totalDensity.derivs( i, q, constitutive::multifluid::DerivativeOffset::dP ); return 0.0 < totalFluidDensity ? dTotalFluidDensity_dP / totalFluidDensity : 0.0; } @@ -585,10 +600,10 @@ class MultiFluidBase : public ConstitutiveBase void computeDerivativesWrtMassFractions( real64 const (&dCompMoleFrac_dCompMassFrac)[maxNumComp][maxNumComp], PhaseProp::SliceType const phaseFrac, PhaseComp::SliceType const phaseCompFrac, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseDens, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseVisc, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseEnthalpy, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseInternalEnergy ) const; + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseVisc, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseEnthalpy, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseInternalEnergy ) const; /** * @brief Main compute function to update properties in a cell with derivatives (used in Newton iterations) @@ -651,7 +666,7 @@ class MultiFluidBase : public ConstitutiveBase */ virtual void resizeFields( localIndex const size, localIndex const numPts ); - virtual void postProcessInput() override; + virtual void postInputInitialization() override; // flag indicating whether input/output component fractions are treated as mass fractions int m_useMass; @@ -678,11 +693,11 @@ class MultiFluidBase : public ConstitutiveBase // backup data - array3d< real64, multifluid::LAYOUT_PHASE > m_phaseDensity_n; - array3d< real64, multifluid::LAYOUT_PHASE > m_phaseEnthalpy_n; - array3d< real64, multifluid::LAYOUT_PHASE > m_phaseInternalEnergy_n; - array4d< real64, multifluid::LAYOUT_PHASE_COMP > m_phaseCompFraction_n; - array2d< real64, multifluid::LAYOUT_FLUID > m_totalDensity_n; + array3d< real64, constitutive::multifluid::LAYOUT_PHASE > m_phaseDensity_n; + array3d< real64, constitutive::multifluid::LAYOUT_PHASE > m_phaseEnthalpy_n; + array3d< real64, constitutive::multifluid::LAYOUT_PHASE > m_phaseInternalEnergy_n; + array4d< real64, constitutive::multifluid::LAYOUT_PHASE_COMP > m_phaseCompFraction_n; + array2d< real64, constitutive::multifluid::LAYOUT_FLUID > m_totalDensity_n; }; @@ -693,13 +708,13 @@ MultiFluidBase::KernelWrapper::computeValues( FLUIDWRAPPER const fluidWrapper, real64 const pressure, real64 const temperature, arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & composition, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const & phaseFraction, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const & phaseDensity, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const & phaseMassDensity, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const & phaseViscosity, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const & phaseEnthalpy, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const & phaseInternalEnergy, - arraySlice2d< real64, multifluid::USD_PHASE_COMP-2 > const & phaseCompFraction, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const & phaseFraction, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const & phaseDensity, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const & phaseMassDensity, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const & phaseViscosity, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const & phaseEnthalpy, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const & phaseInternalEnergy, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_COMP-2 > const & phaseCompFraction, real64 & totalDensity ) { integer constexpr maxNumPhase = MAX_NUM_PHASES; @@ -711,9 +726,9 @@ MultiFluidBase::KernelWrapper::computeValues( FLUIDWRAPPER const fluidWrapper, // Allocate data for derivatives. All properties of the same type will use the same memory // space for the derivatives. The derivatives returned will clearly be garbage but the values // should be correct. - StackArray< real64, 4, maxNumDof * maxNumPhase, multifluid::LAYOUT_PHASE_DC > dPhaseProp( 1, 1, numPhase, numComp+2 ); - StackArray< real64, 5, maxNumDof * maxNumComp * maxNumPhase, multifluid::LAYOUT_PHASE_COMP_DC > dPhaseComp( 1, 1, numPhase, numComp, numComp+2 ); - StackArray< real64, 3, maxNumDof, multifluid::LAYOUT_FLUID_DC > dFluidProp( 1, 1, numComp+2 ); + StackArray< real64, 4, maxNumDof * maxNumPhase, constitutive::multifluid::LAYOUT_PHASE_DC > dPhaseProp( 1, 1, numPhase, numComp+2 ); + StackArray< real64, 5, maxNumDof * maxNumComp * maxNumPhase, constitutive::multifluid::LAYOUT_PHASE_COMP_DC > dPhaseComp( 1, 1, numPhase, numComp, numComp+2 ); + StackArray< real64, 3, maxNumDof, constitutive::multifluid::LAYOUT_FLUID_DC > dFluidProp( 1, 1, numComp+2 ); // Wrap the output in multi variable objects PhaseProp::SliceType phaseFractionWrapper { phaseFraction, dPhaseProp[0][0] }; @@ -768,12 +783,14 @@ MultiFluidBase::KernelWrapper:: real64 totalMolality = 0.0; for( integer ic = 0; ic < numComps; ++ic ) { + // component weight can not be zero, checked in MultiFluidBase::postInputInitialization real64 const mwInv = 1.0 / m_componentMolarWeight[ic]; compMoleFrac[ic] = composition[ic] * mwInv; // this is molality (units of mole/mass) dCompMoleFrac_dCompMassFrac[ic][ic] = mwInv; totalMolality += compMoleFrac[ic]; } + GEOS_ERROR_IF( totalMolality < LvArray::NumericLimits< real64 >::epsilon, "Zero total molality, all component concentrations are equal to zero." ); real64 const totalMolalityInv = 1.0 / totalMolality; for( integer ic = 0; ic < numComps; ++ic ) { @@ -793,8 +810,8 @@ GEOS_FORCE_INLINE void MultiFluidBase::KernelWrapper:: convertToMassFractions( real64 const (&phaseMolecularWeight)[maxNumPhase], - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const phaseFrac, - arraySlice2d< real64, multifluid::USD_PHASE_COMP - 2 > const phaseCompFrac ) const + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const phaseFrac, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_COMP - 2 > const phaseCompFrac ) const { using namespace multifluid; @@ -839,10 +856,10 @@ MultiFluidBase::KernelWrapper:: real64 const (&dPhaseMolecularWeight)[maxNumPhase][maxNumComp+2], PhaseProp::SliceType const phaseFrac, PhaseComp::SliceType const phaseCompFrac, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseDens, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseVisc, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseEnthalpy, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseInternalEnergy ) const + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseVisc, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseEnthalpy, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseInternalEnergy ) const { convertToPhaseMassFractions( phaseMolecularWeight, dPhaseMolecularWeight, @@ -869,7 +886,7 @@ MultiFluidBase::KernelWrapper:: real64 const (&dPhaseMolecularWeight)[maxNumPhase][maxNumDof], PhaseProp::SliceType const phaseFrac ) const { - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; integer const numPhase = numPhases(); integer const numComp = numComponents(); @@ -924,7 +941,7 @@ MultiFluidBase::KernelWrapper:: PhaseProp::SliceType const phaseFrac, PhaseComp::SliceType const phaseCompFrac ) const { - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; integer const numPhase = numPhases(); integer const numComp = numComponents(); @@ -970,12 +987,12 @@ MultiFluidBase::KernelWrapper:: computeDerivativesWrtMassFractions( real64 const (&dCompMoleFrac_dCompMassFrac)[maxNumComp][maxNumComp], PhaseProp::SliceType const phaseFrac, PhaseComp::SliceType const phaseCompFrac, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseDens, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseVisc, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseEnthalpy, - arraySlice2d< real64, multifluid::USD_PHASE_DC - 2 > const dPhaseInternalEnergy ) const + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseVisc, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseEnthalpy, + arraySlice2d< real64, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseInternalEnergy ) const { - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; integer const numPhase = numPhases(); integer const numComp = numComponents(); @@ -1002,10 +1019,10 @@ GEOS_FORCE_INLINE void MultiFluidBase::KernelWrapper:: computeInternalEnergy( real64 const & pressure, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const phaseFrac, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const phaseMassDens, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const phaseEnthalpy, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const phaseInternalEnergy ) const + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const phaseFrac, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const phaseMassDens, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const phaseEnthalpy, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const phaseInternalEnergy ) const { using namespace multifluid; @@ -1047,6 +1064,7 @@ MultiFluidBase::KernelWrapper:: { integer const numPhase = numPhases(); integer const numComp = numComponents(); + integer const numDOF = numComp + 2; for( integer ip = 0; ip < numPhase; ++ip ) { @@ -1059,7 +1077,7 @@ MultiFluidBase::KernelWrapper:: real64 const densInv = 1.0 / phaseMassDens.value[ip]; real64 const densInvSquared = densInv * densInv; phaseInternalEnergy.value[ip] = phaseEnthalpy.value[ip] - pressure * densInv; - for( integer idof = 0; idof < numComp; ++idof ) + for( integer idof = 0; idof < numDOF; ++idof ) { phaseInternalEnergy.derivs[ip][idof] = phaseEnthalpy.derivs[ip][idof] + pressure * phaseMassDens.derivs[ip][idof] * densInvSquared; } @@ -1071,8 +1089,8 @@ template< integer maxNumComp, integer maxNumPhase > GEOS_HOST_DEVICE inline void MultiFluidBase::KernelWrapper:: - computeTotalDensity( arraySlice1d< real64, multifluid::USD_PHASE - 2 > const phaseFrac, - arraySlice1d< real64, multifluid::USD_PHASE - 2 > const phaseDens, + computeTotalDensity( arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const phaseFrac, + arraySlice1d< real64, constitutive::multifluid::USD_PHASE - 2 > const phaseDens, real64 & totalDens ) const { using namespace multifluid; @@ -1103,7 +1121,7 @@ MultiFluidBase::KernelWrapper:: PhaseProp::SliceType const phaseDensity, FluidProp::SliceType const totalDensity ) const { - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; integer const numComp = numComponents(); integer const numPhase = numPhases(); diff --git a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidConstants.hpp b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidConstants.hpp index 4f69f3efa17..1fbd6db0aca 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidConstants.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidConstants.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -49,7 +50,7 @@ struct MultiFluidConstants /** * @brief Max number of SSI iterations */ - static constexpr integer maxSSIIterations = 200; + static constexpr integer maxSSIIterations = 1000; /** * @brief Max number of Newton iterations diff --git a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidFields.hpp b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidFields.hpp index 66ef6fee67f..bc47e09d759 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidFields.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidSelector.hpp b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidSelector.hpp index 6eeb7e4dd79..5636a98d99d 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidSelector.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidSelector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -13,7 +14,7 @@ */ /** - * @file multiFluidSelector.hpp + * @file MultiFluidSelector.hpp */ #ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUIDSELECTOR_HPP_ #define GEOS_CONSTITUTIVE_FLUID_MULTIFLUIDSELECTOR_HPP_ @@ -23,8 +24,8 @@ #include "constitutive/fluid/multifluid/blackOil/BlackOilFluid.hpp" #include "constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp" -#include "common/GeosxConfig.hpp" -#ifdef GEOSX_USE_PVTPackage +#include "common/TypeDispatch.hpp" +#ifdef GEOS_USE_PVTPackage #include "constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidPVTPackage.hpp" #endif #include "constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluid.hpp" @@ -36,43 +37,109 @@ namespace constitutive { template< typename LAMBDA > -void constitutiveUpdatePassThru( MultiFluidBase const & fluid, +void constitutiveUpdatePassThru( constitutive::MultiFluidBase const & fluid, LAMBDA && lambda ) { ConstitutivePassThruHandler< DeadOilFluid, BlackOilFluid, - CompositionalTwoPhasePengRobinsonConstantViscosity, - CompositionalTwoPhaseSoaveRedlichKwongConstantViscosity, -#ifdef GEOSX_USE_PVTPackage +#ifdef GEOS_USE_PVTPackage CompositionalMultiphaseFluidPVTPackage, #endif CO2BrinePhillipsFluid, CO2BrineEzrokhiFluid, - CO2BrinePhillipsThermalFluid -// ,CO2BrineEzrokhiThermalFluid "Uncommenting this will lead to compiler segfault. Need to split compilation -// units for all the options" + CO2BrinePhillipsThermalFluid, +// Including these in a CUDA build will lead to compiler segfault. +// Need to split compilation units for all the options +#if !defined(GEOS_DEVICE_COMPILE) + CO2BrineEzrokhiThermalFluid, + CompositionalTwoPhaseLohrenzBrayClarkViscosity, + CompositionalThreePhaseLohrenzBrayClarkViscosity, +#endif + CompositionalTwoPhaseConstantViscosity >::execute( fluid, std::forward< LAMBDA >( lambda ) ); } template< typename LAMBDA > -void constitutiveUpdatePassThru( MultiFluidBase & fluid, +void constitutiveUpdatePassThru( constitutive::MultiFluidBase & fluid, LAMBDA && lambda ) { ConstitutivePassThruHandler< DeadOilFluid, BlackOilFluid, - CompositionalTwoPhasePengRobinsonConstantViscosity, - CompositionalTwoPhaseSoaveRedlichKwongConstantViscosity, -#ifdef GEOSX_USE_PVTPackage +#ifdef GEOS_USE_PVTPackage CompositionalMultiphaseFluidPVTPackage, #endif CO2BrinePhillipsFluid, CO2BrineEzrokhiFluid, - CO2BrinePhillipsThermalFluid - //,CO2BrineEzrokhiThermalFluid "Uncommenting this will lead to compiler segfault. Need to split compilation -// units for all the options" + CO2BrinePhillipsThermalFluid, +// Including these in a CUDA build will lead to compiler segfault. +// Need to split compilation units for all the options" +#if !defined(GEOS_DEVICE_COMPILE) + CO2BrineEzrokhiThermalFluid, + CompositionalTwoPhaseLohrenzBrayClarkViscosity, + CompositionalThreePhaseLohrenzBrayClarkViscosity, +#endif + CompositionalTwoPhaseConstantViscosity >::execute( fluid, std::forward< LAMBDA >( lambda ) ); } +namespace detail +{ +/** + * @brief Structure to execute a lambda on a fluid model depending on the number of components + * @tparam COMPONENT_LIST Type listing the components to expand over + */ +template< typename COMPONENT_LIST > +struct ComponentSelector; + +template< camp::idx_t ... Is > +struct ComponentSelector< camp::idx_seq< Is ... > > +{ + template< typename FluidType, typename LAMBDA > + static void execute( int numComps, FluidType & fluid, LAMBDA && lambda ) + { +// With gcc8, the fold expression below issues a spurious warning +// warning: suggest parentheses around '&&' within '||' [-Wparentheses] +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94505 +#if (defined(__GNUC__) && (__GNUC__ < 10)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wparentheses" +#endif + + bool const supported = ( ((numComps == Is) && (lambda( fluid, std::integral_constant< integer, Is >() ), true)) || ...); + +#if (defined(__GNUC__) && (__GNUC__ < 10)) +#pragma GCC diagnostic pop +#endif + GEOS_THROW_IF( !supported, + "Unsupported number of components: " << numComps << " for fluid " << FluidType::catalogName(), + InputError ); + } +}; + +} + +template< bool THERMAL = false, typename LAMBDA = NoOpFunc > +void constitutiveComponentUpdatePassThru( constitutive::MultiFluidBase & fluidBase, + integer const numComps, + LAMBDA && lambda ) +{ + constitutiveUpdatePassThru( fluidBase, [&]( auto & fluid ) + { + using FluidType = TYPEOFREF( fluid ); + static_assert( FluidType::min_n_components <= FluidType::max_n_components ); + using Components = typename types::IntegerSequence< FluidType::min_n_components, FluidType::max_n_components >::type; + if constexpr (!THERMAL || FluidType::isThermalType()) + { + detail::ComponentSelector< Components >::execute( numComps, fluid, std::forward< LAMBDA >( lambda )); + } + else + { + GEOS_THROW( "Unsupported thermal call for fluid " << FluidType::catalogName(), + InputError ); + } + } ); +} + } // namespace constitutive } // namespace geos diff --git a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidUtils.hpp b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidUtils.hpp index 6f3db3ca97f..900561fa5e9 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidUtils.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidUtils.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -63,6 +64,8 @@ struct MultiFluidVarSlice internal::ArraySliceOrRef< T, DIM, USD > value; /// variable value internal::ArraySliceOrRef< T, DIM + 1, USD_DC > derivs; /// derivative w.r.t. pressure, temperature, compositions + + using ValueType = internal::ArraySliceOrRef< T, DIM, USD >; }; /** @@ -87,13 +90,15 @@ struct MultiFluidVarView ArrayView< T, NDIM + 1, USD_DC > const & derivsSrc ): value( valueSrc ), derivs( derivsSrc ) - {}; + {} ArrayView< T, NDIM, USD > value; ///< View into property values ArrayView< T, NDIM + 1, USD_DC > derivs; ///< View into property derivatives w.r.t. pressure, temperature, compositions using SliceType = MultiFluidVarSlice< T, NDIM - 2, USD - 2, USD_DC - 2 >; + using ValueType = ArrayView< T, NDIM, USD >; + GEOS_HOST_DEVICE SliceType operator()( localIndex const k, localIndex const q ) const { @@ -119,6 +124,12 @@ struct MultiFluidVar using SliceType = typename ViewType::SliceType; using SliceTypeConst = typename ViewTypeConst::SliceType; + using ValueType = Array< real64, NDIM, PERM >; + template< int MAXSIZE > + using StackValueType = StackArray< real64, NDIM, MAXSIZE, PERM >; + using ViewValueType = typename ViewType::ValueType; + using SliceValueType = typename SliceType::ValueType; + ViewType toView() { return { value.toView(), derivs.toView() }; diff --git a/src/coreComponents/constitutive/fluid/multifluid/PVTDriverRunTest.hpp b/src/coreComponents/constitutive/fluid/multifluid/PVTDriverRunTest.hpp deleted file mode 100644 index da522d27913..00000000000 --- a/src/coreComponents/constitutive/fluid/multifluid/PVTDriverRunTest.hpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file PVTDriverRunTest.hpp - */ - -#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_PVTDRIVERRUNTEST_HPP_ -#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_PVTDRIVERRUNTEST_HPP_ - -#include "PVTDriver.hpp" -#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" - -namespace geos -{ - -template< typename FLUID_TYPE > -void PVTDriver::runTest( FLUID_TYPE & fluid, arrayView2d< real64 > const & table ) -{ - // get number of phases and components - - integer const numComponents = fluid.numFluidComponents(); - integer const numPhases = fluid.numFluidPhases(); - - // prefer output in mass - - fluid.setMassFlag( true ); - - // create kernel wrapper - - typename FLUID_TYPE::KernelWrapper const kernelWrapper = fluid.createKernelWrapper(); - - // set composition to user specified feed - // it is more convenient to provide input in molar, so perform molar to mass conversion here - - GEOS_ASSERT_EQ( numComponents, m_feed.size() ); - array2d< real64, compflow::LAYOUT_COMP > const compositionValues( 1, numComponents ); - - real64 sum = 0.0; - for( integer i = 0; i < numComponents; ++i ) - { - compositionValues[0][i] = m_feed[i] * fluid.componentMolarWeights()[i]; - sum += compositionValues[0][i]; - } - for( integer i = 0; i < numComponents; ++i ) - { - compositionValues[0][i] /= sum; - } - - arrayView2d< real64 const, compflow::USD_COMP > const composition = compositionValues; - - // perform fluid update using table (P,T) and save resulting total density, etc. - // note: column indexing should be kept consistent with output file header below. - - integer const numSteps = m_numSteps; - integer const outputCompressibility = m_outputCompressibility; - integer const outputPhaseComposition = m_outputPhaseComposition; - using ExecPolicy = typename FLUID_TYPE::exec_policy; - forAll< ExecPolicy >( composition.size( 0 ), - [ outputCompressibility, outputPhaseComposition, numPhases, numComponents, numSteps, kernelWrapper, - table, composition] - GEOS_HOST_DEVICE ( localIndex const i ) - { - // Index for start of phase properties - integer const PHASE = outputCompressibility != 0 ? TEMP + 3 : TEMP + 2; - - // Temporary space for phase mole fractions - stackArray1d< real64, constitutive::MultiFluidBase::MAX_NUM_COMPONENTS > phaseComposition( numComponents ); - - for( integer n = 0; n <= numSteps; ++n ) - { - kernelWrapper.update( i, 0, table( n, PRES ), table( n, TEMP ), composition[i] ); - table( n, TEMP + 1 ) = kernelWrapper.totalDensity()( i, 0 ); - - if( outputCompressibility != 0 ) - { - table( n, TEMP + 2 ) = kernelWrapper.totalCompressibility( i, 0 ); - } - - for( integer p = 0; p < numPhases; ++p ) - { - table( n, PHASE + p ) = kernelWrapper.phaseFraction()( i, 0, p ); - table( n, PHASE + p + numPhases ) = kernelWrapper.phaseDensity()( i, 0, p ); - table( n, PHASE + p + 2 * numPhases ) = kernelWrapper.phaseViscosity()( i, 0, p ); - } - if( outputPhaseComposition != 0 ) - { - for( integer p = 0; p < numPhases; ++p ) - { - integer const compStartIndex = PHASE + 3 * numPhases + p * numComponents; - - kernelWrapper.phaseCompMoleFraction( i, 0, p, phaseComposition ); - for( integer ic = 0; ic < numComponents; ++ic ) - { - table( n, compStartIndex + ic ) = phaseComposition[ic]; - } - } - } - } - } ); - -} - -} - -#endif /* GEOS_CONSTITUTIVE_PVTDRIVERRUNTEST_HPP_ */ diff --git a/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluid.cpp b/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluid.cpp index 87b7475167f..a1e44064dd1 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluid.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluid.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -37,9 +38,9 @@ BlackOilFluid::BlackOilFluid( string const & name, .setRestartFlags( RestartFlags::NO_WRITE ); } -void BlackOilFluid::postProcessInput() +void BlackOilFluid::postInputInitialization() { - BlackOilFluidBase::postProcessInput(); + BlackOilFluidBase::postInputInitialization(); GEOS_THROW_IF_NE_MSG( numFluidPhases(), 3, GEOS_FMT( "{}: this model only supports three-phase flow", getFullName() ), @@ -48,7 +49,7 @@ void BlackOilFluid::postProcessInput() void BlackOilFluid::readInputDataFromTableFunctions() { - GEOS_THROW( GEOS_FMT( "{}: this option is not implemented yet, please provide PVT files in standard Eclipse format", getFullName() ), + GEOS_THROW( GEOS_FMT( "{}: this option is not implemented yet, please provide PVT files in standard text format", getFullName() ), InputError ); } diff --git a/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluid.hpp b/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluid.hpp index 52716ec7a4e..444330af0b0 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluid.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -51,6 +52,11 @@ class BlackOilFluid : public BlackOilFluidBase virtual string getCatalogName() const override { return catalogName(); } + static constexpr bool isThermalType(){ return false; } + + static constexpr integer min_n_components = 3; + static constexpr integer max_n_components = 3; + /** * @brief Kernel wrapper class for BlackOilFluid * This kernel can be called on the GPU @@ -136,7 +142,7 @@ class BlackOilFluid : public BlackOilFluidBase void computeDensitiesViscosities( bool const needDerivs, real64 const pressure, real64 const composition[NC_BO], - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & phaseFrac, + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const & phaseFrac, PhaseProp::SliceType const & phaseDens, PhaseProp::SliceType const & phaseMassDens, PhaseProp::SliceType const & phaseVisc, @@ -247,7 +253,7 @@ class BlackOilFluid : public BlackOilFluidBase real64 const dBo_dPres, real64 const dBo_dComp[HNC_BO], real64 & dens, - arraySlice1d< real64, multifluid::USD_PHASE_DC - 3 > const & dDens ) const; + arraySlice1d< real64, constitutive::multifluid::USD_PHASE_DC - 3 > const & dDens ) const; /// Data needed to update the oil phase properties PVTOData::KernelWrapper m_PVTOView; @@ -261,7 +267,7 @@ class BlackOilFluid : public BlackOilFluidBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; private: @@ -270,7 +276,7 @@ class BlackOilFluid : public BlackOilFluidBase virtual void readInputDataFromPVTFiles() override; /** - * @brief Read all the PVT table provided by the user in Eclipse format + * @brief Read all the PVT table provided by the user in text format * @param[in] oilTable the oil table data read from file * @param[in] oilSurfaceMassDensity the oil phase surface mass density * @param[in] oilSurfaceMolecularWeight the oil phase surface molecular weight @@ -409,7 +415,7 @@ BlackOilFluid::KernelWrapper:: PhaseProp::SliceType const & phaseFraction, PhaseComp::SliceType const & phaseCompFraction ) const { - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; using PT = BlackOilFluid::PhaseType; integer const ipOil = m_phaseOrder[PT::OIL]; @@ -557,14 +563,14 @@ BlackOilFluid::KernelWrapper:: computeDensitiesViscosities( bool const needDerivs, real64 const pressure, real64 const composition[NC_BO], - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & phaseFrac, + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const & phaseFrac, PhaseProp::SliceType const & phaseDens, PhaseProp::SliceType const & phaseMassDens, PhaseProp::SliceType const & phaseVisc, real64 phaseMolecularWeight[NP_BO], real64 dPhaseMolecularWeight[NP_BO][NC_BO+2] ) const { - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; using PT = BlackOilFluid::PhaseType; integer const ipOil = m_phaseOrder[PT::OIL]; @@ -899,9 +905,9 @@ BlackOilFluid::KernelWrapper:: real64 const dBo_dPres, real64 const dBo_dComp[HNC_BO], real64 & dens, - arraySlice1d< real64, multifluid::USD_PHASE_DC - 3 > const & dDens ) const + arraySlice1d< real64, constitutive::multifluid::USD_PHASE_DC - 3 > const & dDens ) const { - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; using PT = BlackOilFluid::PhaseType; real64 const oilDens = (useMass)? m_PVTOView.m_surfaceMassDensity[PT::OIL]: diff --git a/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluidBase.cpp b/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluidBase.cpp index dd25bff6eb9..45e40461025 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluidBase.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluidBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -160,11 +161,11 @@ integer BlackOilFluidBase::getWaterPhaseIndex() const return PVTProps::PVTFunctionHelpers::findName( m_phaseNames, expectedWaterPhaseNames, viewKeyStruct::phaseNamesString() ); } -void BlackOilFluidBase::postProcessInput() +void BlackOilFluidBase::postInputInitialization() { m_componentNames = m_phaseNames; - MultiFluidBase::postProcessInput(); + MultiFluidBase::postInputInitialization(); m_phaseTypes.resize( numFluidPhases() ); m_phaseOrder.resizeDefault( MAX_NUM_PHASES, -1 ); @@ -186,6 +187,13 @@ void BlackOilFluidBase::postProcessInput() m_phaseOrder[m_phaseTypes[ip]] = ip; } + // Number of components should be at least equal to number of phases + GEOS_THROW_IF_LT_MSG( numFluidComponents(), numFluidPhases(), + GEOS_FMT( "{}: {} number of components ({}) must be at least number of phases ({})", + getFullName(), viewKeyStruct::componentNamesString(), + numFluidComponents(), numFluidPhases() ), + InputError ); + auto const checkInputSize = [&]( auto const & array, auto const & attribute ) { GEOS_THROW_IF_NE_MSG( array.size(), m_phaseNames.size(), diff --git a/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluidBase.hpp b/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluidBase.hpp index 30e25c4e1cd..a5f4f9b7569 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluidBase.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluidBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -128,7 +129,7 @@ class BlackOilFluidBase : public MultiFluidBase virtual integer getWaterPhaseIndex() const override final; - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void initializePostSubGroups() override; @@ -143,7 +144,7 @@ class BlackOilFluidBase : public MultiFluidBase virtual void readInputDataFromTableFunctions() = 0; /** - * @brief Read all the PVT table provided by the user in Eclipse format + * @brief Read all the PVT table provided by the user in text format */ virtual void readInputDataFromPVTFiles() = 0; diff --git a/src/coreComponents/constitutive/fluid/multifluid/blackOil/DeadOilFluid.cpp b/src/coreComponents/constitutive/fluid/multifluid/blackOil/DeadOilFluid.cpp index 6973c413204..ef8888c16d1 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/blackOil/DeadOilFluid.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/blackOil/DeadOilFluid.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -32,6 +33,16 @@ DeadOilFluid::DeadOilFluid( string const & name, BlackOilFluidBase( name, parent ) {} +void DeadOilFluid::postInputInitialization() +{ + BlackOilFluidBase::postInputInitialization(); + + integer const numComps = numFluidComponents(); + GEOS_THROW_IF( numComps != 2 && numComps != 3, + GEOS_FMT( "{}: this model only supports 2 or 3 components", getFullName() ), + InputError ); +} + void DeadOilFluid::readInputDataFromPVTFiles() { GEOS_THROW_IF_NE_MSG( m_tableFiles.size(), numFluidPhases(), diff --git a/src/coreComponents/constitutive/fluid/multifluid/blackOil/DeadOilFluid.hpp b/src/coreComponents/constitutive/fluid/multifluid/blackOil/DeadOilFluid.hpp index c651f9baf5e..0b87bbd7d6a 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/blackOil/DeadOilFluid.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/blackOil/DeadOilFluid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -37,6 +38,11 @@ class DeadOilFluid : public BlackOilFluidBase virtual string getCatalogName() const override { return catalogName(); } + static constexpr bool isThermalType(){ return false; } + + static constexpr integer min_n_components = 2; + static constexpr integer max_n_components = 3; + /** * @brief Kernel wrapper class for DeadOilFluid * This kernel can be called on the GPU @@ -130,6 +136,10 @@ class DeadOilFluid : public BlackOilFluidBase */ KernelWrapper createKernelWrapper(); +protected: + + virtual void postInputInitialization() override; + private: /** @@ -138,7 +148,7 @@ class DeadOilFluid : public BlackOilFluidBase virtual void readInputDataFromTableFunctions() override; /** - * @brief Read all the PVT table provided by the user in Eclipse format + * @brief Read all the PVT table provided by the user in text format */ virtual void readInputDataFromPVTFiles() override; @@ -151,7 +161,7 @@ DeadOilFluid::KernelWrapper:: computeDensities( real64 const pressure, PhaseProp::SliceType const & phaseMassDens ) const { - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; LvArray::forValuesInSlice( phaseMassDens.derivs, []( real64 & val ){ val = 0.0; } ); @@ -197,7 +207,7 @@ DeadOilFluid::KernelWrapper:: computeViscosities( real64 const pressure, PhaseProp::SliceType const & phaseVisc ) const { - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; LvArray::forValuesInSlice( phaseVisc.derivs, []( real64 & val ){ val = 0.0; } ); @@ -245,7 +255,7 @@ DeadOilFluid::KernelWrapper:: { GEOS_UNUSED_VAR( temperature, phaseEnthalpy, phaseInternalEnergy ); - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; integer const nComps = numComponents(); integer const nPhases = numPhases(); diff --git a/src/coreComponents/constitutive/fluid/multifluid/blackOil/PVTDriverRunTestDeadOilFluid.cpp b/src/coreComponents/constitutive/fluid/multifluid/blackOil/PVTDriverRunTestDeadOilFluid.cpp deleted file mode 100644 index e6bf84094f9..00000000000 --- a/src/coreComponents/constitutive/fluid/multifluid/blackOil/PVTDriverRunTestDeadOilFluid.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/* - * PVTDriverRunTestDeadOilFluid.cpp - */ - -#include "constitutive/fluid/multifluid/PVTDriverRunTest.hpp" -#include "constitutive/fluid/multifluid/blackOil/DeadOilFluid.hpp" -#include "constitutive/fluid/multifluid/blackOil/BlackOilFluid.hpp" - - -namespace geos -{ -template void PVTDriver::runTest< constitutive::DeadOilFluid >( constitutive::DeadOilFluid &, arrayView2d< real64 > const & ); -template void PVTDriver::runTest< constitutive::BlackOilFluid >( constitutive::BlackOilFluid &, arrayView2d< real64 > const & ); -} diff --git a/src/coreComponents/constitutive/fluid/multifluid/blackOil/PVTOData.cpp b/src/coreComponents/constitutive/fluid/multifluid/blackOil/PVTOData.cpp index 8436f16bef8..a8d96c41d82 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/blackOil/PVTOData.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/blackOil/PVTOData.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/multifluid/blackOil/PVTOData.hpp b/src/coreComponents/constitutive/fluid/multifluid/blackOil/PVTOData.hpp index f2c8442a944..d73bfb702e7 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/blackOil/PVTOData.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/blackOil/PVTOData.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluid.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluid.cpp index 9f9ec01ffbb..493c92db612 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluid.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluid.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,78 +20,104 @@ #include "CompositionalMultiphaseFluid.hpp" #include "constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" #include "codingUtilities/Utilities.hpp" +#include "common/format/StringUtilities.hpp" namespace geos { +namespace fields +{ +namespace multifluid +{ +DECLARE_FIELD( kValues, + "kValues", + array4dLayoutPhaseComp, + 0, + NOPLOT, + WRITE_AND_READ, + "Phase equilibrium ratios" ); +} +} + namespace constitutive { template< typename FLASH, typename PHASE1, typename PHASE2, typename PHASE3 > CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >:: CompositionalMultiphaseFluid( string const & name, Group * const parent ) - : MultiFluidBase( name, parent ) + : MultiFluidBase( name, parent ), + m_componentProperties( std::make_unique< compositional::ComponentProperties >( m_componentNames, m_componentMolarWeight ) ), + m_parameters( createModelParameters() ) { using InputFlags = dataRepository::InputFlags; + using RestartFlags = dataRepository::RestartFlags; getWrapperBase( viewKeyStruct::componentNamesString() ).setInputFlag( InputFlags::REQUIRED ); getWrapperBase( viewKeyStruct::componentMolarWeightString() ).setInputFlag( InputFlags::REQUIRED ); getWrapperBase( viewKeyStruct::phaseNamesString() ).setInputFlag( InputFlags::REQUIRED ); - registerWrapper( viewKeyStruct::componentCriticalPressureString(), &m_componentCriticalPressure ). + registerWrapper( viewKeyStruct::componentCriticalPressureString(), &m_componentProperties->m_componentCriticalPressure ). setInputFlag( InputFlags::REQUIRED ). setDescription( "Component critical pressures" ); - registerWrapper( viewKeyStruct::componentCriticalTemperatureString(), &m_componentCriticalTemperature ). + registerWrapper( viewKeyStruct::componentCriticalTemperatureString(), &m_componentProperties->m_componentCriticalTemperature ). setInputFlag( InputFlags::REQUIRED ). setDescription( "Component critical temperatures" ); - registerWrapper( viewKeyStruct::componentCriticalVolumeString(), &m_componentCriticalVolume ). - setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Component critical volumnes" ); - - registerWrapper( viewKeyStruct::componentAcentricFactorString(), &m_componentAcentricFactor ). + registerWrapper( viewKeyStruct::componentAcentricFactorString(), &m_componentProperties->m_componentAcentricFactor ). setInputFlag( InputFlags::REQUIRED ). setDescription( "Component acentric factors" ); - registerWrapper( viewKeyStruct::componentVolumeShiftString(), &m_componentVolumeShift ). + registerWrapper( viewKeyStruct::componentVolumeShiftString(), &m_componentProperties->m_componentVolumeShift ). setInputFlag( InputFlags::OPTIONAL ). setDescription( "Component volume shifts" ); - registerWrapper( viewKeyStruct::componentBinaryCoeffString(), &m_componentBinaryCoeff ). + registerWrapper( viewKeyStruct::componentBinaryCoeffString(), &m_componentProperties->m_componentBinaryCoeff ). setInputFlag( InputFlags::OPTIONAL ). setDescription( "Table of binary interaction coefficients" ); + + registerField( fields::multifluid::kValues{}, &m_kValues ); + + // Link parameters specific to each model + m_parameters->registerParameters( this ); + + // Register extra wrappers to enable auto-cloning + registerWrapper( "phaseOrder", &m_phaseOrder ) + .setSizedFromParent( 0 ) + .setRestartFlags( RestartFlags::NO_WRITE ); } template< typename FLASH, typename PHASE1, typename PHASE2, typename PHASE3 > integer CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::getWaterPhaseIndex() const { - string const expectedWaterPhaseNames[] = { "water" }; - return PVTProps::PVTFunctionHelpers::findName( m_phaseNames, expectedWaterPhaseNames, viewKeyStruct::phaseNamesString() ); -} - -// Naming conventions -namespace compositional -{ -template< int NP > struct PhaseName {}; -template<> struct PhaseName< 2 > { static constexpr char const * catalogName() { return "TwoPhase"; } }; -template<> struct PhaseName< 3 > { static constexpr char const * catalogName() { return "ThreePhase"; } }; + integer const aqueous = static_cast< integer >(PhaseType::AQUEOUS); + return m_phaseOrder.size() > aqueous ? m_phaseOrder[aqueous] : -1; } template< typename FLASH, typename PHASE1, typename PHASE2, typename PHASE3 > string CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::catalogName() { - return GEOS_FMT( "Compositonal{}Fluid{}{}", - compositional::PhaseName< FLASH::KernelWrapper::getNumberOfPhases() >::catalogName(), + return GEOS_FMT( "Compositional{}Fluid{}", FLASH::catalogName(), PHASE1::Viscosity::catalogName() ); } template< typename FLASH, typename PHASE1, typename PHASE2, typename PHASE3 > -void CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::postProcessInput() +void CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::allocateConstitutiveData( dataRepository::Group & parent, + localIndex const numConstitutivePointsPerParentIndex ) +{ + MultiFluidBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex ); + + // Zero k-Values to force initialisation with Wilson k-Values + m_kValues.zero(); +} + +template< typename FLASH, typename PHASE1, typename PHASE2, typename PHASE3 > +void CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::postInputInitialization() { - MultiFluidBase::postProcessInput(); + MultiFluidBase::postInputInitialization(); integer const NC = numFluidComponents(); integer const NP = numFluidPhases(); @@ -107,32 +134,56 @@ void CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::postProcessI InputError ); }; - checkInputSize( m_componentCriticalPressure, NC, viewKeyStruct::componentCriticalPressureString() ); - checkInputSize( m_componentCriticalTemperature, NC, viewKeyStruct::componentCriticalTemperatureString() ); - checkInputSize( m_componentAcentricFactor, NC, viewKeyStruct::componentAcentricFactorString() ); + checkInputSize( m_componentProperties->m_componentCriticalPressure, NC, viewKeyStruct::componentCriticalPressureString() ); + checkInputSize( m_componentProperties->m_componentCriticalTemperature, NC, viewKeyStruct::componentCriticalTemperatureString() ); + checkInputSize( m_componentProperties->m_componentAcentricFactor, NC, viewKeyStruct::componentAcentricFactorString() ); - if( m_componentCriticalVolume.empty() ) + if( m_componentProperties->m_componentVolumeShift.empty() ) { - m_componentCriticalVolume.resize( NC ); - calculateCriticalVolume( m_componentCriticalPressure, - m_componentCriticalTemperature, - m_componentCriticalVolume ); + m_componentProperties->m_componentVolumeShift.resize( NC ); + m_componentProperties->m_componentVolumeShift.zero(); } - checkInputSize( m_componentCriticalVolume, NC, viewKeyStruct::componentCriticalVolumeString() ); + checkInputSize( m_componentProperties->m_componentVolumeShift, NC, viewKeyStruct::componentVolumeShiftString() ); - if( m_componentVolumeShift.empty() ) + array2d< real64 > & componentBinaryCoeff = m_componentProperties->m_componentBinaryCoeff; + if( componentBinaryCoeff.empty() ) { - m_componentVolumeShift.resize( NC ); - m_componentVolumeShift.zero(); + componentBinaryCoeff.resize( NC, NC ); + componentBinaryCoeff.zero(); } - checkInputSize( m_componentVolumeShift, NC, viewKeyStruct::componentVolumeShiftString() ); + checkInputSize( componentBinaryCoeff, NC * NC, viewKeyStruct::componentBinaryCoeffString() ); - if( m_componentBinaryCoeff.empty() ) + // Binary interaction coefficients should be symmetric and have zero diagonal + GEOS_THROW_IF_NE_MSG( componentBinaryCoeff.size( 0 ), NC, + GEOS_FMT( "{}: invalid number of values in attribute '{}'", getFullName(), viewKeyStruct::componentBinaryCoeffString() ), + InputError ); + GEOS_THROW_IF_NE_MSG( componentBinaryCoeff.size( 1 ), NC, + GEOS_FMT( "{}: invalid number of values in attribute '{}'", getFullName(), viewKeyStruct::componentBinaryCoeffString() ), + InputError ); + for( integer ic = 0; ic < NC; ++ic ) { - m_componentBinaryCoeff.resize( NC, NC ); - m_componentBinaryCoeff.zero(); + GEOS_THROW_IF_GT_MSG( LvArray::math::abs( componentBinaryCoeff( ic, ic )), MultiFluidConstants::epsilon, + GEOS_FMT( "{}: {} entry at ({},{}) is {}: should be zero", getFullName(), viewKeyStruct::componentBinaryCoeffString(), + ic, ic, componentBinaryCoeff( ic, ic ) ), + InputError ); + for( integer jc = ic + 1; jc < NC; ++jc ) + { + real64 const difference = LvArray::math::abs( componentBinaryCoeff( ic, jc )-componentBinaryCoeff( jc, ic )); + GEOS_THROW_IF_GT_MSG( difference, MultiFluidConstants::epsilon, + GEOS_FMT( "{}: {} entry at ({},{}) is {} and is different from entry at ({},{}) which is {}", + getFullName(), viewKeyStruct::componentBinaryCoeffString(), + ic, jc, componentBinaryCoeff( ic, jc ), jc, ic, componentBinaryCoeff( jc, ic ) ), + InputError ); + } } - checkInputSize( m_componentBinaryCoeff, NC * NC, viewKeyStruct::componentBinaryCoeffString() ); + + // Determine the phase ordering + m_phaseOrder.resize( 3 ); + m_phaseOrder[PhaseType::LIQUID] = findPhaseIndex( "oil,liq,liquid" ); + m_phaseOrder[PhaseType::VAPOUR] = findPhaseIndex( "gas,vap,vapor,vapour" ); + m_phaseOrder[PhaseType::AQUEOUS] = findPhaseIndex( "wat,water,aqueous" ); + + m_parameters->postInputInitialization( this, *m_componentProperties ); } template< typename FLASH, typename PHASE1, typename PHASE2, typename PHASE3 > @@ -144,12 +195,22 @@ void CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::initializePo createModels(); } +template< typename FLASH, typename PHASE1, typename PHASE2, typename PHASE3 > +void CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::resizeFields( localIndex const size, localIndex const numPts ) +{ + MultiFluidBase::resizeFields( size, numPts ); + + m_kValues.resize( size, numPts, numFluidPhases()-1, numFluidComponents() ); +} + template< typename FLASH, typename PHASE1, typename PHASE2, typename PHASE3 > std::unique_ptr< ConstitutiveBase > CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::deliverClone( string const & name, Group * const parent ) const { std::unique_ptr< ConstitutiveBase > clone = MultiFluidBase::deliverClone( name, parent ); + CompositionalMultiphaseFluid & newFluid = dynamicCast< CompositionalMultiphaseFluid & >( *clone ); + newFluid.createModels(); return clone; } @@ -157,12 +218,12 @@ template< typename FLASH, typename PHASE1, typename PHASE2, typename PHASE3 > typename CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::KernelWrapper CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::createKernelWrapper() { - //auto phaseModels = std::make_tuple((m_phases)...); return KernelWrapper( *m_componentProperties, *m_flash, *m_phase1, *m_phase2, *m_phase3, + m_phaseOrder.toViewConst(), m_componentMolarWeight, m_useMass, m_phaseFraction.toView(), @@ -172,66 +233,90 @@ CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::createKernelWrapp m_phaseEnthalpy.toView(), m_phaseInternalEnergy.toView(), m_phaseCompFraction.toView(), - m_totalDensity.toView() ); + m_totalDensity.toView(), + m_kValues.toView() ); } // Create the fluid models template< typename FLASH, typename PHASE1, typename PHASE2, typename PHASE3 > void CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::createModels() { - m_componentProperties = std::make_unique< compositional::ComponentProperties >( - m_componentNames, - m_componentMolarWeight, - m_componentCriticalPressure, - m_componentCriticalTemperature, - m_componentCriticalVolume, - m_componentAcentricFactor, - m_componentVolumeShift, - m_componentBinaryCoeff ); - m_flash = std::make_unique< FLASH >( getName() + '_' + FLASH::catalogName(), - *m_componentProperties ); + *m_componentProperties, + *m_parameters ); m_phase1 = std::make_unique< PHASE1 >( GEOS_FMT( "{}_PhaseModel1", getName() ), - *m_componentProperties ); + *m_componentProperties, + 0, + *m_parameters ); m_phase2 = std::make_unique< PHASE2 >( GEOS_FMT( "{}_PhaseModel2", getName() ), - *m_componentProperties ); + *m_componentProperties, + 1, + *m_parameters ); m_phase3 = std::make_unique< PHASE3 >( GEOS_FMT( "{}_PhaseModel3", getName() ), - *m_componentProperties ); + *m_componentProperties, + 2, + *m_parameters ); } template< typename FLASH, typename PHASE1, typename PHASE2, typename PHASE3 > -void CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::calculateCriticalVolume( - arrayView1d< const real64 > const criticalPressure, - arrayView1d< const real64 > const criticalTemperature, - arrayView1d< real64 > const criticalVolume ) const +integer CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::findPhaseIndex( string names ) const { - integer const numComponents = criticalPressure.size( 0 ); - for( integer ic=0; ic +std::unique_ptr< compositional::ModelParameters > +CompositionalMultiphaseFluid< FLASH, PHASE1, PHASE2, PHASE3 >::createModelParameters() +{ + std::unique_ptr< compositional::ModelParameters > parameters; + parameters = FLASH::createParameters( std::move( parameters )); + parameters = PHASE1::createParameters( std::move( parameters )); + parameters = PHASE2::createParameters( std::move( parameters )); + parameters = PHASE3::createParameters( std::move( parameters )); + return parameters; } // Explicit instantiation of the model template. template class CompositionalMultiphaseFluid< - compositional::NegativeTwoPhaseFlashPRPR, + compositional::NegativeTwoPhaseFlashModel, compositional::PhaseModel< compositional::CompositionalDensity, compositional::ConstantViscosity, compositional::NullModel >, compositional::PhaseModel< compositional::CompositionalDensity, compositional::ConstantViscosity, compositional::NullModel > >; template class CompositionalMultiphaseFluid< - compositional::NegativeTwoPhaseFlashSRKSRK, - compositional::PhaseModel< compositional::CompositionalDensity, compositional::ConstantViscosity, compositional::NullModel >, - compositional::PhaseModel< compositional::CompositionalDensity, compositional::ConstantViscosity, compositional::NullModel > >; + compositional::NegativeTwoPhaseFlashModel, + compositional::PhaseModel< compositional::CompositionalDensity, compositional::LohrenzBrayClarkViscosity, compositional::NullModel >, + compositional::PhaseModel< compositional::CompositionalDensity, compositional::LohrenzBrayClarkViscosity, compositional::NullModel > >; +template class CompositionalMultiphaseFluid< + compositional::ImmiscibleWaterFlashModel, + compositional::PhaseModel< compositional::CompositionalDensity, compositional::LohrenzBrayClarkViscosity, compositional::NullModel >, + compositional::PhaseModel< compositional::CompositionalDensity, compositional::LohrenzBrayClarkViscosity, compositional::NullModel >, + compositional::PhaseModel< compositional::ImmiscibleWaterDensity, compositional::ImmiscibleWaterViscosity, compositional::NullModel > >; + +REGISTER_CATALOG_ENTRY( ConstitutiveBase, + CompositionalTwoPhaseConstantViscosity, + string const &, + dataRepository::Group * const ) REGISTER_CATALOG_ENTRY( ConstitutiveBase, - CompositionalTwoPhasePengRobinsonConstantViscosity, + CompositionalTwoPhaseLohrenzBrayClarkViscosity, string const &, dataRepository::Group * const ) REGISTER_CATALOG_ENTRY( ConstitutiveBase, - CompositionalTwoPhaseSoaveRedlichKwongConstantViscosity, + CompositionalThreePhaseLohrenzBrayClarkViscosity, string const &, dataRepository::Group * const ) diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluid.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluid.hpp index 2f2ddf4a790..e4bb5789175 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluid.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -22,13 +23,15 @@ #include "constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidUpdates.hpp" #include "constitutive/fluid/multifluid/compositional/models/ConstantViscosity.hpp" #include "constitutive/fluid/multifluid/compositional/models/CompositionalDensity.hpp" +#include "constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterDensity.hpp" +#include "constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterFlashModel.hpp" +#include "constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterViscosity.hpp" +#include "constitutive/fluid/multifluid/compositional/models/LohrenzBrayClarkViscosity.hpp" #include "constitutive/fluid/multifluid/compositional/models/NegativeTwoPhaseFlashModel.hpp" +#include "constitutive/fluid/multifluid/compositional/models/ModelParameters.hpp" #include "constitutive/fluid/multifluid/compositional/models/NullModel.hpp" #include "constitutive/fluid/multifluid/compositional/models/PhaseModel.hpp" -#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" -#include "constitutive/fluid/multifluid/MultiFluidUtils.hpp" - namespace geos { namespace constitutive @@ -68,6 +71,8 @@ class CompositionalMultiphaseFluid : public MultiFluidBase virtual string getCatalogName() const override { return catalogName(); } + static constexpr bool isThermalType(){ return false; } + // TODO: This method should be implemented if an incorrect extrapolation of the pressure and temperature is encountered in the kernel /** * @copydoc MultiFluidBase::checkTablesParameters( real64 pressure, real64 temperature ) @@ -77,13 +82,15 @@ class CompositionalMultiphaseFluid : public MultiFluidBase GEOS_UNUSED_VAR( pressure, temperature ); } + virtual void allocateConstitutiveData( dataRepository::Group & parent, + localIndex const numConstitutivePointsPerParentIndex ) override; + virtual integer getWaterPhaseIndex() const override final; struct viewKeyStruct : MultiFluidBase::viewKeyStruct { static constexpr char const * componentCriticalPressureString() { return "componentCriticalPressure"; } static constexpr char const * componentCriticalTemperatureString() { return "componentCriticalTemperature"; } - static constexpr char const * componentCriticalVolumeString() { return "componentCriticalVolume"; } static constexpr char const * componentAcentricFactorString() { return "componentAcentricFactor"; } static constexpr char const * componentVolumeShiftString() { return "componentVolumeShift"; } static constexpr char const * componentBinaryCoeffString() { return "componentBinaryCoeff"; } @@ -100,53 +107,61 @@ class CompositionalMultiphaseFluid : public MultiFluidBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void initializePostSubGroups() override; -private: - /** - * @brief Estimate critical volumes using Ihmels' (2010) correlation - * @details reference: http://dx.doi.org/10.1021/je100167w - * @param[in] criticalPressure The component critical pressures - * @param[in] criticalTemperature The component critical temperatures - * @param[in] criticalVolume The component critical volumes - */ - void calculateCriticalVolume( arrayView1d< const real64 > const criticalPressure, - arrayView1d< const real64 > const criticalTemperature, - arrayView1d< real64 > const criticalVolume ) const; + virtual void resizeFields( localIndex const size, localIndex const numPts ) override; + + enum PhaseType : integer + { + LIQUID = 0, + VAPOUR = 1, + AQUEOUS = 2, + }; private: // Create the fluid models void createModels(); + integer findPhaseIndex( string names ) const; + + static std::unique_ptr< compositional::ModelParameters > createModelParameters(); + // Flash model std::unique_ptr< FLASH > m_flash{}; + // Phase ordering + array1d< integer > m_phaseOrder; + // Phase models - std::unique_ptr< PHASE1 > m_phase1; - std::unique_ptr< PHASE2 > m_phase2; - std::unique_ptr< PHASE3 > m_phase3; + std::unique_ptr< PHASE1 > m_phase1{}; + std::unique_ptr< PHASE2 > m_phase2{}; + std::unique_ptr< PHASE3 > m_phase3{}; + // Standard EOS component input std::unique_ptr< compositional::ComponentProperties > m_componentProperties{}; - // standard EOS component input - array1d< real64 > m_componentCriticalPressure; - array1d< real64 > m_componentCriticalTemperature; - array1d< real64 > m_componentCriticalVolume; - array1d< real64 > m_componentAcentricFactor; - array1d< real64 > m_componentVolumeShift; - array2d< real64 > m_componentBinaryCoeff; + // Extra parameters specific to this model + std::unique_ptr< compositional::ModelParameters > m_parameters{}; + + // backup data + PhaseComp::ValueType m_kValues; }; -using CompositionalTwoPhasePengRobinsonConstantViscosity = CompositionalMultiphaseFluid< - compositional::NegativeTwoPhaseFlashPRPR, - compositional::PhaseModel< compositional::CompositionalDensity, compositional::ConstantViscosity, compositional::NullModel >, - compositional::PhaseModel< compositional::CompositionalDensity, compositional::ConstantViscosity, compositional::NullModel > >; -using CompositionalTwoPhaseSoaveRedlichKwongConstantViscosity = CompositionalMultiphaseFluid< - compositional::NegativeTwoPhaseFlashSRKSRK, +using CompositionalTwoPhaseConstantViscosity = CompositionalMultiphaseFluid< + compositional::NegativeTwoPhaseFlashModel, compositional::PhaseModel< compositional::CompositionalDensity, compositional::ConstantViscosity, compositional::NullModel >, compositional::PhaseModel< compositional::CompositionalDensity, compositional::ConstantViscosity, compositional::NullModel > >; +using CompositionalTwoPhaseLohrenzBrayClarkViscosity = CompositionalMultiphaseFluid< + compositional::NegativeTwoPhaseFlashModel, + compositional::PhaseModel< compositional::CompositionalDensity, compositional::LohrenzBrayClarkViscosity, compositional::NullModel >, + compositional::PhaseModel< compositional::CompositionalDensity, compositional::LohrenzBrayClarkViscosity, compositional::NullModel > >; +using CompositionalThreePhaseLohrenzBrayClarkViscosity = CompositionalMultiphaseFluid< + compositional::ImmiscibleWaterFlashModel, + compositional::PhaseModel< compositional::CompositionalDensity, compositional::LohrenzBrayClarkViscosity, compositional::NullModel >, + compositional::PhaseModel< compositional::CompositionalDensity, compositional::LohrenzBrayClarkViscosity, compositional::NullModel >, + compositional::PhaseModel< compositional::ImmiscibleWaterDensity, compositional::ImmiscibleWaterViscosity, compositional::NullModel > >; } /* namespace constitutive */ diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidPVTPackage.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidPVTPackage.cpp index 2a6faab23b4..9aea320884d 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidPVTPackage.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidPVTPackage.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -45,6 +46,10 @@ CompositionalMultiphaseFluidPVTPackage::CompositionalMultiphaseFluidPVTPackage( setInputFlag( InputFlags::REQUIRED ). setDescription( "List of equation of state types for each phase" ); + registerWrapper( viewKeyStruct::constantPhaseViscosityString(), &m_constantPhaseViscosity ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Viscosity for each phase" ); + registerWrapper( viewKeyStruct::componentCriticalPressureString(), &m_componentCriticalPressure ). setInputFlag( InputFlags::REQUIRED ). setDescription( "Component critical pressures" ); @@ -72,9 +77,9 @@ integer CompositionalMultiphaseFluidPVTPackage::getWaterPhaseIndex() const return PVTProps::PVTFunctionHelpers::findName( m_phaseNames, expectedWaterPhaseNames, viewKeyStruct::phaseNamesString() ); } -void CompositionalMultiphaseFluidPVTPackage::postProcessInput() +void CompositionalMultiphaseFluidPVTPackage::postInputInitialization() { - MultiFluidBase::postProcessInput(); + MultiFluidBase::postInputInitialization(); auto const getPVTPackagePhaseType = [&]( string const & phaseName ) { @@ -104,7 +109,16 @@ void CompositionalMultiphaseFluidPVTPackage::postProcessInput() checkInputSize( m_componentCriticalPressure, NC, viewKeyStruct::componentCriticalPressureString() ); checkInputSize( m_componentCriticalTemperature, NC, viewKeyStruct::componentCriticalTemperatureString() ); checkInputSize( m_componentAcentricFactor, NC, viewKeyStruct::componentAcentricFactorString() ); - checkInputSize( m_equationsOfState, NP, viewKeyStruct::equationsOfStateString() ); + + if( m_constantPhaseViscosity.empty() ) + { + m_constantPhaseViscosity.resize( NP ); + for( integer ip = 0; ip < NP; ++ip ) + { + m_constantPhaseViscosity[ip] = 0.001; // Default value = 1 cP + } + } + checkInputSize( m_constantPhaseViscosity, NP, viewKeyStruct::constantPhaseViscosityString() ); if( m_componentVolumeShift.empty() ) { @@ -167,6 +181,7 @@ CompositionalMultiphaseFluidPVTPackage::deliverClone( string const & name, CompositionalMultiphaseFluidPVTPackage::KernelWrapper:: KernelWrapper( pvt::MultiphaseSystem & fluid, arrayView1d< pvt::PHASE_TYPE > const & phaseTypes, + arrayView1d< geos::real64 const > const & constantPhaseViscosity, arrayView1d< geos::real64 const > const & componentMolarWeight, bool useMass, PhaseProp::ViewType phaseFraction, @@ -188,7 +203,8 @@ CompositionalMultiphaseFluidPVTPackage::KernelWrapper:: std::move( phaseCompFraction ), std::move( totalDensity ) ), m_fluid( fluid ), - m_phaseTypes( phaseTypes ) + m_phaseTypes( phaseTypes ), + m_constantPhaseViscosity( constantPhaseViscosity ) {} CompositionalMultiphaseFluidPVTPackage::KernelWrapper @@ -196,6 +212,7 @@ CompositionalMultiphaseFluidPVTPackage::createKernelWrapper() { return KernelWrapper( *m_fluid, m_phaseTypes, + m_constantPhaseViscosity, m_componentMolarWeight, m_useMass, m_phaseFraction.toView(), diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidPVTPackage.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidPVTPackage.hpp index 1be5e7ccd4a..1b5d9b6db4a 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidPVTPackage.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidPVTPackage.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -45,6 +46,8 @@ class CompositionalMultiphaseFluidPVTPackage : public MultiFluidBase virtual string getCatalogName() const override { return catalogName(); } + static constexpr bool isThermalType(){ return false; } + // TODO: This method should be implemented if an incorrect extrapolation of the pressure and temperature is encountered in the kernel /** * @copydoc MultiFluidBase::checkTablesParameters( real64 pressure, real64 temperature ) @@ -64,6 +67,7 @@ class CompositionalMultiphaseFluidPVTPackage : public MultiFluidBase static constexpr char const * componentAcentricFactorString() { return "componentAcentricFactor"; } static constexpr char const * componentVolumeShiftString() { return "componentVolumeShift"; } static constexpr char const * componentBinaryCoeffString() { return "componentBinaryCoeff"; } + static constexpr char const * constantPhaseViscosityString() { return "constantPhaseViscosity"; } }; /** @@ -98,6 +102,7 @@ class CompositionalMultiphaseFluidPVTPackage : public MultiFluidBase KernelWrapper( pvt::MultiphaseSystem & fluid, arrayView1d< pvt::PHASE_TYPE > const & phaseTypes, + arrayView1d< real64 const > const & constantPhaseViscosity, arrayView1d< real64 const > const & componentMolarWeight, bool const useMass, PhaseProp::ViewType phaseFraction, @@ -112,6 +117,7 @@ class CompositionalMultiphaseFluidPVTPackage : public MultiFluidBase pvt::MultiphaseSystem & m_fluid; arrayView1d< pvt::PHASE_TYPE > m_phaseTypes; + arrayView1d< real64 const > m_constantPhaseViscosity; }; /** @@ -122,7 +128,7 @@ class CompositionalMultiphaseFluidPVTPackage : public MultiFluidBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void initializePostSubGroups() override; @@ -139,6 +145,9 @@ class CompositionalMultiphaseFluidPVTPackage : public MultiFluidBase // names of equations of state to use for each phase string_array m_equationsOfState; + // Phase viscosity + array1d< real64 > m_constantPhaseViscosity; + // standard EOS component input array1d< real64 > m_componentCriticalPressure; array1d< real64 > m_componentCriticalTemperature; @@ -179,7 +188,7 @@ CompositionalMultiphaseFluidPVTPackage::KernelWrapper:: GEOS_UNUSED_VAR( totalDensity ); #else - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; integer constexpr maxNumComp = MultiFluidBase::MAX_NUM_COMPONENTS; integer constexpr maxNumPhase = MultiFluidBase::MAX_NUM_PHASES; @@ -239,7 +248,7 @@ CompositionalMultiphaseFluidPVTPackage::KernelWrapper:: phaseMassDensity.derivs[ip][Deriv::dT] = massDens.dT; // TODO - phaseViscosity.value[ip] = 0.001; + phaseViscosity.value[ip] = m_constantPhaseViscosity[ip]; phaseViscosity.derivs[ip][Deriv::dP] = 0.0; phaseViscosity.derivs[ip][Deriv::dT] = 0.0; diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidUpdates.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidUpdates.cpp index 8c4007e1660..299dd2eb111 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidUpdates.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidUpdates.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidUpdates.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidUpdates.hpp index 3ccefa5bb16..ee3b4ee1dd0 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidUpdates.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidUpdates.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -45,6 +46,7 @@ class CompositionalMultiphaseFluidUpdates final : public MultiFluidBase::KernelW PHASE1 const & phase1, PHASE2 const & phase2, PHASE3 const & phase3, + arrayView1d< integer const > const & phaseOrder, arrayView1d< real64 const > const & componentMolarWeight, bool const useMass, MultiFluidBase::PhaseProp::ViewType phaseFrac, @@ -54,7 +56,8 @@ class CompositionalMultiphaseFluidUpdates final : public MultiFluidBase::KernelW MultiFluidBase::PhaseProp::ViewType phaseEnthalpy, MultiFluidBase::PhaseProp::ViewType phaseInternalEnergy, MultiFluidBase::PhaseComp::ViewType phaseCompFrac, - MultiFluidBase::FluidProp::ViewType totalDensity ); + MultiFluidBase::FluidProp::ViewType totalDensity, + MultiFluidBase::PhaseComp::ViewValueType kValues ); GEOS_HOST_DEVICE virtual void compute( real64 const pressure, @@ -76,6 +79,43 @@ class CompositionalMultiphaseFluidUpdates final : public MultiFluidBase::KernelW real64 const temperature, arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & composition ) const override; +protected: + GEOS_HOST_DEVICE + void compute( real64 const pressure, + real64 const temperature, + arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & composition, + MultiFluidBase::PhaseProp::SliceType const phaseFrac, + MultiFluidBase::PhaseProp::SliceType const phaseDens, + MultiFluidBase::PhaseProp::SliceType const phaseMassDensity, + MultiFluidBase::PhaseProp::SliceType const phaseVisc, + MultiFluidBase::PhaseProp::SliceType const phaseEnthalpy, + MultiFluidBase::PhaseProp::SliceType const phaseInternalEnergy, + MultiFluidBase::PhaseComp::SliceType const phaseCompFrac, + MultiFluidBase::FluidProp::SliceType const totalDensity, + MultiFluidBase::PhaseComp::SliceType::ValueType const & kValues ) const; + + /** + * @brief Convert derivatives from phase mole fraction to total mole fraction + * @details Given property derivatives @c dProperty where composition derivatives are with + * respect to a phase compositions, this will transform that properties so that + * they the composition derivatives are with respect to total composition. The derivatives + * of the phase composition should be provided in @c dPhaseComposition. + * @param[in] numComps The number of components + * @param[in] dPhaseComposition Derivatives of the phase composition + * @param[in,out] dProperty The derivatives of the property + * @param[in] workSpace Temporary workspace + */ + template< int USD1, int USD2 > + GEOS_HOST_DEVICE + static void convertDerivativesToTotalMoleFraction( integer const numComps, + arraySlice2d< real64 const, USD1 > const & dPhaseComposition, + arraySlice1d< real64, USD2 > const & dProperty, + arraySlice1d< real64 > const & workSpace ); + + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + static void setZero( real64 & val ){ val = 0.0; } + private: // The component properties compositional::ComponentProperties::KernelWrapper m_componentProperties; @@ -83,10 +123,16 @@ class CompositionalMultiphaseFluidUpdates final : public MultiFluidBase::KernelW // Flash kernel wrapper typename FLASH::KernelWrapper m_flash; + // The ordering of phases + arrayView1d< integer const > const m_phaseOrder; + // Phase model kernel wrappers typename PHASE1::KernelWrapper m_phase1; typename PHASE2::KernelWrapper m_phase2; typename PHASE3::KernelWrapper m_phase3; + + // Backup variables + MultiFluidBase::PhaseComp::ViewValueType m_kValues; }; template< typename FLASH, typename PHASE1, typename PHASE2, typename PHASE3 > @@ -96,6 +142,7 @@ CompositionalMultiphaseFluidUpdates( compositional::ComponentProperties const & PHASE1 const & phase1, PHASE2 const & phase2, PHASE3 const & phase3, + arrayView1d< integer const > const & phaseOrder, arrayView1d< real64 const > const & componentMolarWeight, bool const useMass, MultiFluidBase::PhaseProp::ViewType phaseFrac, @@ -105,7 +152,8 @@ CompositionalMultiphaseFluidUpdates( compositional::ComponentProperties const & MultiFluidBase::PhaseProp::ViewType phaseEnthalpy, MultiFluidBase::PhaseProp::ViewType phaseInternalEnergy, MultiFluidBase::PhaseComp::ViewType phaseCompFrac, - MultiFluidBase::FluidProp::ViewType totalDensity ): + MultiFluidBase::FluidProp::ViewType totalDensity, + MultiFluidBase::PhaseComp::ViewValueType kValues ): MultiFluidBase::KernelWrapper( componentMolarWeight, useMass, std::move( phaseFrac ), @@ -118,9 +166,11 @@ CompositionalMultiphaseFluidUpdates( compositional::ComponentProperties const & std::move( totalDensity ) ), m_componentProperties( componentProperties.createKernelWrapper() ), m_flash( flash.createKernelWrapper() ), + m_phaseOrder( phaseOrder ), m_phase1( phase1.createKernelWrapper() ), m_phase2( phase2.createKernelWrapper() ), - m_phase3( phase3.createKernelWrapper() ) + m_phase3( phase3.createKernelWrapper() ), + m_kValues( kValues ) {} template< typename FLASH, typename PHASE1, typename PHASE2, typename PHASE3 > @@ -140,14 +190,50 @@ CompositionalMultiphaseFluidUpdates< FLASH, PHASE1, PHASE2, PHASE3 >::compute( MultiFluidBase::PhaseComp::SliceType const phaseCompFrac, MultiFluidBase::FluidProp::SliceType const totalDensity ) const { - GEOS_UNUSED_VAR( phaseEnthalpy, phaseInternalEnergy ); + integer constexpr maxNumComp = MultiFluidBase::MAX_NUM_COMPONENTS; + integer constexpr maxNumPhase = MultiFluidBase::MAX_NUM_PHASES - 1; + MultiFluidBase::PhaseComp::StackValueType< maxNumPhase *maxNumComp > kValues( 1, 1, numPhases() - 1, numComponents() ); - using Deriv = multifluid::DerivativeOffset; + LvArray::forValuesInSlice( kValues[0][0], setZero ); // Force initialisation of k-Values + + compute( pressure, + temperature, + composition, + phaseFrac, + phaseDens, + phaseMassDensity, + phaseVisc, + phaseEnthalpy, + phaseInternalEnergy, + phaseCompFrac, + totalDensity, + kValues[0][0] ); +} +template< typename FLASH, typename PHASE1, typename PHASE2, typename PHASE3 > +GEOS_HOST_DEVICE +GEOS_FORCE_INLINE +void +CompositionalMultiphaseFluidUpdates< FLASH, PHASE1, PHASE2, PHASE3 >::compute( + real64 const pressure, + real64 const temperature, + arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & composition, + MultiFluidBase::PhaseProp::SliceType const phaseFrac, + MultiFluidBase::PhaseProp::SliceType const phaseDens, + MultiFluidBase::PhaseProp::SliceType const phaseMassDensity, + MultiFluidBase::PhaseProp::SliceType const phaseVisc, + MultiFluidBase::PhaseProp::SliceType const phaseEnthalpy, + MultiFluidBase::PhaseProp::SliceType const phaseInternalEnergy, + MultiFluidBase::PhaseComp::SliceType const phaseCompFrac, + MultiFluidBase::FluidProp::SliceType const totalDensity, + MultiFluidBase::PhaseComp::SliceType::ValueType const & kValues ) const +{ integer constexpr maxNumComp = MultiFluidBase::MAX_NUM_COMPONENTS; + integer constexpr maxNumDof = MultiFluidBase::MAX_NUM_COMPONENTS + 2; integer constexpr maxNumPhase = MultiFluidBase::MAX_NUM_PHASES; integer const numComp = numComponents(); integer const numPhase = numPhases(); + integer const numDof = numComp + 2; // 1. Convert input mass fractions to mole fractions and keep derivatives @@ -174,6 +260,7 @@ CompositionalMultiphaseFluidUpdates< FLASH, PHASE1, PHASE2, PHASE3 >::compute( pressure, temperature, compMoleFrac.toSliceConst(), + kValues, phaseFrac, phaseCompFrac ); @@ -181,34 +268,31 @@ CompositionalMultiphaseFluidUpdates< FLASH, PHASE1, PHASE2, PHASE3 >::compute( m_phase1.density.compute( m_componentProperties, pressure, temperature, - phaseCompFrac.value[0].toSliceConst(), - phaseCompFrac.derivs[0].toSliceConst(), - phaseDens.value[0], - phaseDens.derivs[0], - phaseMassDensity.value[0], - phaseMassDensity.derivs[0], + phaseCompFrac.value[m_phaseOrder[0]].toSliceConst(), + phaseDens.value[m_phaseOrder[0]], + phaseDens.derivs[m_phaseOrder[0]], + phaseMassDensity.value[m_phaseOrder[0]], + phaseMassDensity.derivs[m_phaseOrder[0]], m_useMass ); m_phase2.density.compute( m_componentProperties, pressure, temperature, - phaseCompFrac.value[1].toSliceConst(), - phaseCompFrac.derivs[1].toSliceConst(), - phaseDens.value[1], - phaseDens.derivs[1], - phaseMassDensity.value[1], - phaseMassDensity.derivs[1], + phaseCompFrac.value[m_phaseOrder[1]].toSliceConst(), + phaseDens.value[m_phaseOrder[1]], + phaseDens.derivs[m_phaseOrder[1]], + phaseMassDensity.value[m_phaseOrder[1]], + phaseMassDensity.derivs[m_phaseOrder[1]], m_useMass ); if constexpr (2 < FLASH::KernelWrapper::getNumberOfPhases()) { m_phase3.density.compute( m_componentProperties, pressure, temperature, - phaseCompFrac.value[2].toSliceConst(), - phaseCompFrac.derivs[2].toSliceConst(), - phaseDens.value[2], - phaseDens.derivs[2], - phaseMassDensity.value[2], - phaseMassDensity.derivs[2], + phaseCompFrac.value[m_phaseOrder[2]].toSliceConst(), + phaseDens.value[m_phaseOrder[2]], + phaseDens.derivs[m_phaseOrder[2]], + phaseMassDensity.value[m_phaseOrder[2]], + phaseMassDensity.derivs[m_phaseOrder[2]], m_useMass ); } @@ -216,54 +300,80 @@ CompositionalMultiphaseFluidUpdates< FLASH, PHASE1, PHASE2, PHASE3 >::compute( m_phase1.viscosity.compute( m_componentProperties, pressure, temperature, - phaseCompFrac.value[0].toSliceConst(), - phaseCompFrac.derivs[0].toSliceConst(), - phaseMassDensity.value[0], - phaseMassDensity.derivs[0].toSliceConst(), - phaseVisc.value[0], - phaseVisc.derivs[0], + phaseCompFrac.value[m_phaseOrder[0]].toSliceConst(), + phaseMassDensity.value[m_phaseOrder[0]], + phaseMassDensity.derivs[m_phaseOrder[0]].toSliceConst(), + phaseVisc.value[m_phaseOrder[0]], + phaseVisc.derivs[m_phaseOrder[0]], m_useMass ); m_phase2.viscosity.compute( m_componentProperties, pressure, temperature, - phaseCompFrac.value[1].toSliceConst(), - phaseCompFrac.derivs[1].toSliceConst(), - phaseMassDensity.value[1], - phaseMassDensity.derivs[1].toSliceConst(), - phaseVisc.value[1], - phaseVisc.derivs[1], + phaseCompFrac.value[m_phaseOrder[1]].toSliceConst(), + phaseMassDensity.value[m_phaseOrder[1]], + phaseMassDensity.derivs[m_phaseOrder[1]].toSliceConst(), + phaseVisc.value[m_phaseOrder[1]], + phaseVisc.derivs[m_phaseOrder[1]], m_useMass ); if constexpr (2 < FLASH::KernelWrapper::getNumberOfPhases()) { m_phase3.viscosity.compute( m_componentProperties, pressure, temperature, - phaseCompFrac.value[2].toSliceConst(), - phaseCompFrac.derivs[2].toSliceConst(), - phaseMassDensity.value[2], - phaseMassDensity.derivs[2].toSliceConst(), - phaseVisc.value[2], - phaseVisc.derivs[2], + phaseCompFrac.value[m_phaseOrder[2]].toSliceConst(), + phaseMassDensity.value[m_phaseOrder[2]], + phaseMassDensity.derivs[m_phaseOrder[2]].toSliceConst(), + phaseVisc.value[m_phaseOrder[2]], + phaseVisc.derivs[m_phaseOrder[2]], m_useMass ); } - // 5. if mass variables used instead of molar, perform the conversion + // 5. Convert derivatives from phase composition to total composition + stackArray1d< real64, maxNumDof > workSpace( numDof ); + for( integer ip = 0; ip < FLASH::KernelWrapper::getNumberOfPhases(); ++ip ) + { + convertDerivativesToTotalMoleFraction( numComp, + phaseCompFrac.derivs[ip].toSliceConst(), + phaseDens.derivs[ip], + workSpace ); + convertDerivativesToTotalMoleFraction( numComp, + phaseCompFrac.derivs[ip].toSliceConst(), + phaseMassDensity.derivs[ip], + workSpace ); + convertDerivativesToTotalMoleFraction( numComp, + phaseCompFrac.derivs[ip].toSliceConst(), + phaseVisc.derivs[ip], + workSpace ); + } + + // 6. if mass variables used instead of molar, perform the conversion if( m_useMass ) { real64 phaseMolecularWeight[maxNumPhase]{}; real64 dPhaseMolecularWeight[maxNumPhase][maxNumComp+2]{}; + arrayView1d< real64 const > const & componentMolarWeight = m_componentProperties.m_componentMolarWeight; + for( integer ip = 0; ip < numPhase; ++ip ) { - phaseMolecularWeight[ip] = 1.0; - dPhaseMolecularWeight[ip][Deriv::dP] = 0.0; - dPhaseMolecularWeight[ip][Deriv::dT] = 0.0; + phaseMolecularWeight[ip] = 0.0; + for( integer kc = 0; kc < numDof; ++kc ) + { + dPhaseMolecularWeight[ip][kc] = 0.0; + } + + auto const & phaseComposition = phaseCompFrac.value[ip].toSliceConst(); + auto const & dPhaseComposition = phaseCompFrac.derivs[ip].toSliceConst(); + for( integer ic = 0; ic < numComp; ++ic ) { - dPhaseMolecularWeight[ip][Deriv::dC+ic] = 0.0; + phaseMolecularWeight[ip] += phaseComposition[ic] * componentMolarWeight[ic]; + for( integer kc = 0; kc < numDof; ++kc ) + { + dPhaseMolecularWeight[ip][kc] += dPhaseComposition( ic, kc ) * componentMolarWeight[ic]; + } } } - convertToMassFractions( dCompMoleFrac_dCompMassFrac, phaseMolecularWeight, dPhaseMolecularWeight, @@ -275,7 +385,7 @@ CompositionalMultiphaseFluidUpdates< FLASH, PHASE1, PHASE2, PHASE3 >::compute( phaseInternalEnergy.derivs ); } - // 6. Compute total fluid mass/molar density and derivatives + // 7. Compute total fluid mass/molar density and derivatives computeTotalDensity( phaseFrac, phaseDens, @@ -303,7 +413,37 @@ update( localIndex const k, m_phaseEnthalpy( k, q ), m_phaseInternalEnergy( k, q ), m_phaseCompFraction( k, q ), - m_totalDensity( k, q ) ); + m_totalDensity( k, q ), + m_kValues[k][q] ); +} + +template< typename FLASH, typename PHASE1, typename PHASE2, typename PHASE3 > +template< int USD1, int USD2 > +GEOS_HOST_DEVICE +void +CompositionalMultiphaseFluidUpdates< FLASH, PHASE1, PHASE2, PHASE3 >:: +convertDerivativesToTotalMoleFraction( integer const numComps, + arraySlice2d< real64 const, USD1 > const & dPhaseComposition, + arraySlice1d< real64, USD2 > const & dProperty, + arraySlice1d< real64 > const & workSpace ) +{ + using Deriv = constitutive::multifluid::DerivativeOffset; + integer const numDofs = numComps + 2; + for( integer kc = 0; kc < numDofs; ++kc ) + { + workSpace[kc] = dProperty[kc]; + } + for( integer ic = 0; ic < numComps; ++ic ) + { + dProperty[Deriv::dC+ic] = 0.0; + } + for( integer kc = 0; kc < numDofs; ++kc ) + { + for( integer ic = 0; ic < numComps; ++ic ) + { + dProperty[kc] += (dPhaseComposition( ic, kc ) * workSpace[Deriv::dC+ic]); + } + } } } /* namespace constitutive */ diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/PVTDriverRunTestCompositionalMultiphaseFluid.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/PVTDriverRunTestCompositionalMultiphaseFluid.cpp deleted file mode 100644 index d1c69c43ca1..00000000000 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/PVTDriverRunTestCompositionalMultiphaseFluid.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/* - * PVTDriverRunTestCompositionalMultiphaseFluid.cpp - */ - -#include "constitutive/fluid/multifluid/PVTDriverRunTest.hpp" -#ifdef GEOSX_USE_PVTPackage -#include "constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidPVTPackage.hpp" -#endif -#include "constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluid.hpp" - -namespace geos -{ -#ifdef GEOSX_USE_PVTPackage -template void PVTDriver::runTest< constitutive::CompositionalMultiphaseFluidPVTPackage >( constitutive::CompositionalMultiphaseFluidPVTPackage &, arrayView2d< real64 > const & ); -#endif -template void PVTDriver::runTest< constitutive::CompositionalTwoPhasePengRobinsonConstantViscosity >( - constitutive::CompositionalTwoPhasePengRobinsonConstantViscosity &, arrayView2d< real64 > const & ); -template void PVTDriver::runTest< constitutive::CompositionalTwoPhaseSoaveRedlichKwongConstantViscosity >( - constitutive::CompositionalTwoPhaseSoaveRedlichKwongConstantViscosity &, arrayView2d< real64 > const & ); -} diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/CompositionalProperties.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/CompositionalProperties.cpp deleted file mode 100644 index 165801fa177..00000000000 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/CompositionalProperties.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file CompositionalProperties.hpp - */ - -#include "CompositionalProperties.hpp" -#include "constitutive/fluid/multifluid/MultiFluidConstants.hpp" - -namespace geos -{ - -namespace constitutive -{ - -namespace compositional -{ - -/* - * Calculate the molar volume and apply the Peneloux shift parameters. The parameters should be in - * dimensional form. - * Peneloux, A et al. 1982. Fluid phase equilibria, 8(1):7–23. - * https://doi.org/10.1016/0378-3812(82)80002-2 - */ -GEOS_HOST_DEVICE -void CompositionalProperties::computeMolarDensity( integer const numComps, - real64 const pressure, - real64 const temperature, - arraySlice1d< real64 const > const & composition, - arraySlice1d< real64 const > const & volumeShift, - real64 const compressibilityFactor, - real64 & molarDensity ) -{ - - real64 vEos = constants::gasConstant * temperature * compressibilityFactor / pressure; - real64 vCorrected = vEos; - - for( integer ic = 0; ic < numComps; ++ic ) - { - vCorrected += composition[ic] * volumeShift[ic]; - } - - if( MultiFluidConstants::epsilon < vCorrected ) - { - molarDensity = 1.0 / vCorrected; - } - else - { - molarDensity = 0.0; - } -} - -GEOS_HOST_DEVICE -void CompositionalProperties::computeMolarDensity( integer const numComps, - real64 const pressure, - real64 const temperature, - arraySlice1d< real64 const > const & GEOS_UNUSED_PARAM ( composition ), - arraySlice1d< real64 const > const & volumeShift, - real64 const compressibilityFactor, - real64 const dCompressibilityFactor_dp, - real64 const dCompressibilityFactor_dt, - arraySlice1d< real64 const > const & dCompressibilityFactor_dz, - real64 const molarDensity, - real64 & dMolarDensity_dp, - real64 & dMolarDensity_dt, - arraySlice1d< real64 > const & dMolarDensity_dz ) -{ - if( molarDensity < MultiFluidConstants::epsilon ) - { - dMolarDensity_dp = 0.0; - dMolarDensity_dt = 0.0; - for( integer ic = 0; ic < numComps; ++ic ) - { - dMolarDensity_dz[ic] = 0.0; - } - return; - } - - real64 dvCorrected_dx = 0.0; - - // Pressure derivative - dvCorrected_dx = constants::gasConstant * temperature * (dCompressibilityFactor_dp - compressibilityFactor / pressure) / pressure; - dMolarDensity_dp = -molarDensity * molarDensity * dvCorrected_dx; - - // Temperature derivative - dvCorrected_dx = constants::gasConstant * (temperature * dCompressibilityFactor_dt + compressibilityFactor) / pressure; - dMolarDensity_dt = -molarDensity * molarDensity * dvCorrected_dx; - - // Composition derivative - for( integer ic = 0; ic < numComps; ++ic ) - { - dvCorrected_dx = constants::gasConstant * temperature * dCompressibilityFactor_dz[ic] / pressure + volumeShift[ic]; - dMolarDensity_dz[ic] = -molarDensity * molarDensity * dvCorrected_dx; - } -} - -GEOS_HOST_DEVICE -void CompositionalProperties::computeMassDensity( integer const numComps, - arraySlice1d< real64 const > const & composition, - arraySlice1d< real64 const > const & molecularWeight, - real64 const molarDensity, - real64 & massDensity ) -{ - massDensity = 0.0; - for( integer ic = 0; ic < numComps; ++ic ) - { - massDensity += molecularWeight[ic] * composition[ic] * molarDensity; - } -} - -GEOS_HOST_DEVICE -void CompositionalProperties::computeMassDensity( integer const numComps, - arraySlice1d< real64 const > const & molecularWeight, - real64 const molarDensity, - real64 const dMolarDensity_dp, - real64 const dMolarDensity_dt, - arraySlice1d< real64 const > const dMolarDensity_dz, - real64 const massDensity, - real64 & dMassDensity_dp, - real64 & dMassDensity_dt, - arraySlice1d< real64 > const & dMassDensity_dz ) -{ - // Pressure derivative - dMassDensity_dp = massDensity * dMolarDensity_dp / molarDensity; - - // Temperature derivative - dMassDensity_dt = massDensity * dMolarDensity_dt / molarDensity; - - // Composition derivative - for( integer ic = 0; ic < numComps; ++ic ) - { - dMassDensity_dz[ic] = massDensity * dMolarDensity_dz[ic] / molarDensity + molecularWeight[ic] * molarDensity; - } -} - -} // namespace compositional - -} // namespace constitutive - -} // namespace geos diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/CompositionalProperties.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/CompositionalProperties.hpp index 84f886df626..c0bfac86dda 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/CompositionalProperties.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/CompositionalProperties.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,6 +21,7 @@ #define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_FUNCTIONS_COMPOSITIONALPROPERTIES_HPP_ #include "common/DataTypes.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" namespace geos { @@ -32,97 +34,51 @@ namespace compositional struct CompositionalProperties { + using Deriv = geos::constitutive::multifluid::DerivativeOffset; public: /** - * @brief Compute the molar density of a mixture from the composition and the compressibility factor + * @brief Compute the molar density and derivatives * @param[in] numComps number of components * @param[in] pressure pressure * @param[in] temperature temperature * @param[in] composition composition of the mixture * @param[in] volumeShift dimensional volume shift parameters * @param[in] compressibilityFactor compressibility factor (z-factor) + * @param[in] compressibilityFactorDerivs derivatives of the compressibility factor (z-factor) * @param[out] molarDensity the calculated molar density - * @note The volume shifts can result in a negative molar density which will be truncated to zero + * @param[out] molarDensityDerivs derivatives of the molar density */ + template< integer USD1, integer USD2 > GEOS_HOST_DEVICE static void computeMolarDensity( integer const numComps, real64 const pressure, real64 const temperature, - arraySlice1d< real64 const > const & composition, + arraySlice1d< real64 const, USD1 > const & composition, arraySlice1d< real64 const > const & volumeShift, real64 const compressibilityFactor, - real64 & molarDensity ); + arraySlice1d< real64 const > const & compressibilityFactorDerivs, + real64 & molarDensity, + arraySlice1d< real64, USD2 > const & molarDensityDerivs ); /** - * @brief Compute the molar density derivatives - * @param[in] numComps number of components - * @param[in] pressure pressure - * @param[in] temperature temperature - * @param[in] composition composition of the mixture - * @param[in] volumeShift dimensional volume shift parameters - * @param[in] compressibilityFactor compressibility factor (z-factor) - * @param[in] dCompressibilityFactor_dp derivative of the compressibility factor (z-factor) wrt pressure - * @param[in] dCompressibilityFactor_dp derivative of the compressibility factor (z-factor) wrt temperature - * @param[in] dCompressibilityFactor_dz derivative of the compressibility factor (z-factor) wrt composition - * @param[in] molarDensity the calculated molar density - * @param[out] dMolarDensity_dp derivative of the molar density wrt pressure - * @param[out] dMolarDensity_dt derivative of the molar density wrt temperature - * @param[out] dMolarDensity_dz derivative of the molar density wrt composition - */ - GEOS_HOST_DEVICE - static void computeMolarDensity( integer const numComps, - real64 const pressure, - real64 const temperature, - arraySlice1d< real64 const > const & composition, - arraySlice1d< real64 const > const & volumeShift, - real64 const compressibilityFactor, - real64 const dCompressibilityFactor_dp, - real64 const dCompressibilityFactor_dt, - arraySlice1d< real64 const > const & dCompressibilityFactor_dz, - real64 const molarDensity, - real64 & dMolarDensity_dp, - real64 & dMolarDensity_dt, - arraySlice1d< real64 > const & dMolarDensity_dz ); - - /** - * @brief Compute the mass density of a mixture from the composition and the molar density + * @brief Compute the mass density and derivatives * @param[in] numComps number of components * @param[in] composition composition of the mixture * @param[in] molecularWeight the component molecular weights * @param[in] molarDensity the mixture molar density - * @param[out] massDensity the calculated mass density + * @param[in] molarDensityDerivs derivatives of the molar density + * @param[out] massDensity mass density + * @param[out] massDensityDerivs derivatives of the mass density */ + template< integer USD1, integer USD2 > GEOS_HOST_DEVICE static void computeMassDensity( integer const numComps, - arraySlice1d< real64 const > const & composition, + arraySlice1d< real64 const, USD1 > const & composition, arraySlice1d< real64 const > const & molecularWeight, real64 const molarDensity, - real64 & massDensity ); - - /** - * @brief Compute the mass density derivatives - * @param[in] numComps number of components - * @param[in] molecularWeight the component molecular weights - * @param[in] molarDensity the mixture molar density - * @param[in] dMolarDensity_dp derivative of the molar density wrt pressure - * @param[in] dMolarDensity_dt derivative of the molar density wrt temperature - * @param[in] dMolarDensity_dz derivative of the molar density wrt composition - * @param[in] massDensity mass density - * @param[out] dMassDensity_dp derivative of the mass density wrt pressure - * @param[out] dMassDensity_dt derivative of the mass density wrt temperature - * @param[out] dMassDensity_dz derivative of the mass density wrt composition - */ - GEOS_HOST_DEVICE - static void computeMassDensity( integer const numComps, - arraySlice1d< real64 const > const & molecularWeight, - real64 const molarDensity, - real64 const dMolarDensity_dp, - real64 const dMolarDensity_dt, - arraySlice1d< real64 const > const dMolarDensity_dz, - real64 const massDensity, - real64 & dMassDensity_dp, - real64 & dMassDensity_dt, - arraySlice1d< real64 > const & dMassDensity_dz ); + arraySlice1d< real64 const, USD2 > const & molarDensityDerivs, + real64 & massDensity, + arraySlice1d< real64, USD2 > const & massDensityDerivs ); }; } //namespace compositional @@ -131,4 +87,7 @@ struct CompositionalProperties } // namespace geos +// Implementation +#include "CompositionalPropertiesImpl.hpp" + #endif //GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_FUNCTIONS_COMPOSITIONALPROPERTIES_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/CompositionalPropertiesImpl.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/CompositionalPropertiesImpl.hpp new file mode 100644 index 00000000000..9c6a39b30b3 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/CompositionalPropertiesImpl.hpp @@ -0,0 +1,137 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CompositionalPropertiesImpl.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_FUNCTIONS_COMPOSITIONALPROPERTIESIMPL_HPP_ +#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_FUNCTIONS_COMPOSITIONALPROPERTIESIMPL_HPP_ + +#include "CompositionalProperties.hpp" +#include "constitutive/fluid/multifluid/MultiFluidConstants.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +/* + * Calculate the molar volume and apply the Peneloux shift parameters. The parameters should be in + * dimensional form. + * Peneloux, A et al. 1982. Fluid phase equilibria, 8(1):7–23. + * https://doi.org/10.1016/0378-3812(82)80002-2 + */ +template< integer USD1, integer USD2 > +GEOS_HOST_DEVICE +void CompositionalProperties::computeMolarDensity( integer const numComps, + real64 const pressure, + real64 const temperature, + arraySlice1d< real64 const, USD1 > const & composition, + arraySlice1d< real64 const > const & volumeShift, + real64 const compressibilityFactor, + arraySlice1d< real64 const > const & compressibilityFactorDerivs, + real64 & molarDensity, + arraySlice1d< real64, USD2 > const & molarDensityDerivs ) +{ + real64 vEos = constants::gasConstant * temperature * compressibilityFactor / pressure; + real64 vCorrected = vEos; + + for( integer ic = 0; ic < numComps; ++ic ) + { + vCorrected -= composition[ic] * volumeShift[ic]; + } + + if( MultiFluidConstants::epsilon < vCorrected ) + { + molarDensity = 1.0 / vCorrected; + } + else + { + molarDensity = 0.0; + auto const setZero = []( real64 & val ){ val = 0.0; }; + LvArray::forValuesInSlice( molarDensityDerivs, setZero ); + return; + } + + real64 dvCorrected_dx = 0.0; + + // Pressure derivative + dvCorrected_dx = constants::gasConstant * temperature * (compressibilityFactorDerivs[Deriv::dP] - compressibilityFactor / pressure) / pressure; + molarDensityDerivs[Deriv::dP] = -molarDensity * molarDensity * dvCorrected_dx; + + // Temperature derivative + dvCorrected_dx = constants::gasConstant * (temperature * compressibilityFactorDerivs[Deriv::dT] + compressibilityFactor) / pressure; + molarDensityDerivs[Deriv::dT] = -molarDensity * molarDensity * dvCorrected_dx; + + // Composition derivative + for( integer ic = 0; ic < numComps; ++ic ) + { + integer const kc = Deriv::dC + ic; + dvCorrected_dx = constants::gasConstant * temperature * compressibilityFactorDerivs[kc] / pressure - volumeShift[ic]; + molarDensityDerivs[kc] = -molarDensity * molarDensity * dvCorrected_dx; + } +} + +template< integer USD1, integer USD2 > +GEOS_HOST_DEVICE +void CompositionalProperties::computeMassDensity( integer const numComps, + arraySlice1d< real64 const, USD1 > const & composition, + arraySlice1d< real64 const > const & molecularWeight, + real64 const molarDensity, + arraySlice1d< real64 const, USD2 > const & molarDensityDerivs, + real64 & massDensity, + arraySlice1d< real64, USD2 > const & massDensityDerivs ) +{ + massDensity = 0.0; + for( integer ic = 0; ic < numComps; ++ic ) + { + massDensity += molecularWeight[ic] * composition[ic] * molarDensity; + } + + if( massDensity < MultiFluidConstants::epsilon ) + { + auto const setZero = []( real64 & val ){ val = 0.0; }; + LvArray::forValuesInSlice( massDensityDerivs, setZero ); + return; + } + + real64 const oneOverMolarDensity = 1.0 / molarDensity; + + // Pressure and temperature derivatives + for( integer const kc : {Deriv::dP, Deriv::dT} ) + { + massDensityDerivs[kc] = massDensity * molarDensityDerivs[kc] * oneOverMolarDensity; + } + + // Composition derivative + for( integer ic = 0; ic < numComps; ++ic ) + { + integer const kc = Deriv::dC + ic; + massDensityDerivs[kc] = massDensity * molarDensityDerivs[kc] * oneOverMolarDensity + molecularWeight[ic] * molarDensity; + } +} + +} // namespace compositional + +} // namespace constitutive + +} // namespace geos + +#endif //GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_FUNCTIONS_COMPOSITIONALPROPERTIESIMPL_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/CubicEOSPhaseModel.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/CubicEOSPhaseModel.hpp index 8adfa65457e..faa8d4496bd 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/CubicEOSPhaseModel.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/CubicEOSPhaseModel.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,9 @@ #define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_FUNCTIONS_CUBICEOSPHASEMODEL_HPP_ #include "common/DataTypes.hpp" +#include "common/logger/Logger.hpp" #include "constitutive/fluid/multifluid/MultiFluidConstants.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" #include "constitutive/fluid/multifluid/compositional/models/ComponentProperties.hpp" namespace geos @@ -73,6 +76,7 @@ struct SoaveRedlichKwongEOS template< typename EOS_TYPE > struct CubicEOSPhaseModel { + using Deriv = geos::constitutive::multifluid::DerivativeOffset; public: /** * @brief Generate a catalog name @@ -89,15 +93,121 @@ struct CubicEOSPhaseModel * @param[in] componentProperties The compositional component properties * @param[out] logFugacityCoefficients log of the fugacity coefficients */ + template< integer USD > GEOS_HOST_DEVICE GEOS_FORCE_INLINE static void computeLogFugacityCoefficients( integer const numComps, real64 const & pressure, real64 const & temperature, - arrayView1d< real64 const > const composition, + arraySlice1d< real64 const, USD > const & composition, ComponentProperties::KernelWrapper const & componentProperties, - arraySlice1d< real64 > const logFugacityCoefficients ); + arraySlice1d< real64 > const & logFugacityCoefficients ); + + /** + * @brief Secondary entry point of the cubic EOS model + * @details Computes the derivatives of the logarithm of the fugacity coefficients + * @param[in] numComps number of components + * @param[in] pressure pressure + * @param[in] temperature temperature + * @param[in] composition composition of the phase + * @param[in] componentProperties The compositional component properties + * @param[in] logFugacityCoefficients log of the fugacity coefficients + * @param[out] logFugacityCoefficientDerivs derivatives of the log of the fugacity coefficients + */ + template< integer USD > + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + static void + computeLogFugacityCoefficients( integer const numComps, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const, USD > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + arraySlice1d< real64 const > const & logFugacityCoefficients, + arraySlice2d< real64 > const & logFugacityCoefficientDerivs ); + + /** + * @brief Compute compressibility factor for the cubic EOS model + * @details Computes the compressibility factor (z-factor) for the cubic EOS model including derivatives + * @param[in] numComps number of components + * @param[in] pressure pressure + * @param[in] temperature temperature + * @param[in] composition composition of the phase + * @param[in] componentProperties The compositional component properties + * @param[out] compressibilityFactor the current compressibility factor + * @param[out] compressibilityFactorDerivs derivatives of the compressibility factor + */ + template< integer USD > + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + static void + computeCompressibilityFactor( integer const numComps, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const, USD > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + real64 & compressibilityFactor, + arraySlice1d< real64 > const & compressibilityFactorDerivs ); + + /** + * @brief Calculate the dimensional volume shift + * @details Computes the dimensional form of the volume shifts given the user defined non-dimensional form. + * @param[in] numComps The number of components + * @param[in] componentProperties The compositional model properties + * @param[out] dimensionalVolumeShift The calculated dimensional volume shifts + */ + GEOS_FORCE_INLINE + static void calculateDimensionalVolumeShift( ComponentProperties const & componentProperties, + arraySlice1d< real64 > const & dimensionalVolumeShift ); + + /** + * @brief Calculate the pure coefficients + * @details Computes the pure coefficients + * @param[in] ic Component index + * @param[in] pressure pressure + * @param[in] temperature temperature + * @param[in] componentProperties The compositional component properties + * @param[out] aCoefficient pure coefficient (A) + * @param[out] bCoefficient pure coefficient (B) + */ + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + static void + computePureCoefficients( integer const ic, + real64 const & pressure, + real64 const & temperature, + ComponentProperties::KernelWrapper const & componentProperties, + real64 & aCoefficient, + real64 & bCoefficient ); + + /** + * @brief Calculate the pure coefficients derivatives + * @details Computes the pure coefficients derivatives + * @param[in] ic Component index + * @param[in] pressure pressure + * @param[in] temperature temperature + * @param[in] componentProperties The compositional component properties + * @param[out] aCoefficient pure coefficient (A) + * @param[out] bCoefficient pure coefficient (B) + * @param[out] daCoefficient_dp pure coefficient (A) derivative w.r.t. pressure + * @param[out] dbCoefficient_dp pure coefficient (B) derivative w.r.t. pressure + * @param[out] daCoefficient_dt pure coefficient (A) derivative w.r.t. temperature + * @param[out] dbCoefficient_dt pure coefficient (B) derivative w.r.t. temperature + */ + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + static void + computePureCoefficients( integer const ic, + real64 const & pressure, + real64 const & temperature, + ComponentProperties::KernelWrapper const & componentProperties, + real64 & aCoefficient, + real64 & bCoefficient, + real64 & daCoefficient_dp, + real64 & dbCoefficient_dp, + real64 & daCoefficient_dt, + real64 & dbCoefficient_dt ); /** * @brief Compute the mixture coefficients using pressure, temperature, composition and input @@ -111,16 +221,17 @@ struct CubicEOSPhaseModel * @param[out] aMixtureCoefficient mixture coefficient (A) * @param[out] bMixtureCoefficient mixture coefficient (B) */ + template< integer USD > GEOS_HOST_DEVICE GEOS_FORCE_INLINE static void computeMixtureCoefficients( integer const numComps, real64 const & pressure, real64 const & temperature, - arrayView1d< real64 const > const composition, + arraySlice1d< real64 const, USD > const & composition, ComponentProperties::KernelWrapper const & componentProperties, - arraySlice1d< real64 > const aPureCoefficient, - arraySlice1d< real64 > const bPureCoefficient, + arraySlice1d< real64 > const & aPureCoefficient, + arraySlice1d< real64 > const & bPureCoefficient, real64 & aMixtureCoefficient, real64 & bMixtureCoefficient ); @@ -135,32 +246,25 @@ struct CubicEOSPhaseModel * @param[in] bPureCoefficient pure coefficient (B) * @param[in] aMixtureCoefficient mixture coefficient (A) * @param[in] bMixtureCoefficient mixture coefficient (B) - * @param[out] daMixtureCoefficient_dp derivative of mixture coefficient (A) wrt pressure - * @param[out] dbMixtureCoefficient_dp derivative of mixture coefficient (B) wrt pressure - * @param[out] daMixtureCoefficient_dt derivative of mixture coefficient (A) wrt temperature - * @param[out] dbMixtureCoefficient_dt derivative of mixture coefficient (B) wrt temperature - * @param[out] daMixtureCoefficient_dz derivative of mixture coefficient (A) wrt composition - * @param[out] dbMixtureCoefficient_dz derivative of mixture coefficient (B) wrt composition + * @param[out] aMixtureCoefficientDerivs derivatives of mixture coefficient (A) + * @param[out] bMixtureCoefficientDerivs derivatives of mixture coefficient (B) * @note Assumes that pressure and temperature are strictly positive */ + template< integer USD > GEOS_HOST_DEVICE GEOS_FORCE_INLINE static void computeMixtureCoefficients( integer const numComps, real64 const & pressure, real64 const & temperature, - arrayView1d< real64 const > const composition, + arraySlice1d< real64 const, USD > const & composition, ComponentProperties::KernelWrapper const & componentProperties, - arraySlice1d< real64 const > const aPureCoefficient, - arraySlice1d< real64 const > const bPureCoefficient, + arraySlice1d< real64 const > const & aPureCoefficient, + arraySlice1d< real64 const > const & bPureCoefficient, real64 const aMixtureCoefficient, real64 const bMixtureCoefficient, - real64 & daMixtureCoefficient_dp, - real64 & dbMixtureCoefficient_dp, - real64 & daMixtureCoefficient_dt, - real64 & dbMixtureCoefficient_dt, - arraySlice1d< real64 > const daMixtureCoefficient_dz, - arraySlice1d< real64 > const dbMixtureCoefficient_dz ); + arraySlice1d< real64 > const & aMixtureCoefficientDerivs, + arraySlice1d< real64 > const & bMixtureCoefficientDerivs ); /** * @brief Compute the compressibility factor using compositions, BICs, and mixture coefficients @@ -173,14 +277,15 @@ struct CubicEOSPhaseModel * @param[in] bMixtureCoefficient mixture coefficient (B) * @param[out] compressibilityFactor compressibility factor */ + template< integer USD > GEOS_HOST_DEVICE GEOS_FORCE_INLINE static void computeCompressibilityFactor( integer const numComps, - arrayView1d< real64 const > const composition, - arrayView2d< real64 const > const & binaryInteractionCoefficients, - arraySlice1d< real64 const > const aPureCoefficient, - arraySlice1d< real64 const > const bPureCoefficient, + arraySlice1d< real64 const, USD > const & composition, + arraySlice2d< real64 const > const & binaryInteractionCoefficients, + arraySlice1d< real64 const > const & aPureCoefficient, + arraySlice1d< real64 const > const & bPureCoefficient, real64 const & aMixtureCoefficient, real64 const & bMixtureCoefficient, real64 & compressibilityFactor ); @@ -191,15 +296,9 @@ struct CubicEOSPhaseModel * @param[in] aMixtureCoefficient mixture coefficient (A) * @param[in] bMixtureCoefficient mixture coefficient (B) * @param[in] compressibilityFactor the current compressibility factor - * @param[in] daMixtureCoefficient_dp derivative of mixture coefficient (A) wrt pressure - * @param[in] dbMixtureCoefficient_dp derivative of mixture coefficient (B) wrt pressure - * @param[in] daMixtureCoefficient_dt derivative of mixture coefficient (A) wrt temperature - * @param[in] dbMixtureCoefficient_dt derivative of mixture coefficient (B) wrt temperature - * @param[in] daMixtureCoefficient_dz derivative of mixture coefficient (A) wrt composition - * @param[in] dbMixtureCoefficient_dz derivative of mixture coefficient (B) wrt composition - * @param[out] dCompressibilityFactor_dp derivative of the compressibility factor wrt pressure - * @param[out] dCompressibilityFactor_dt derivative of the compressibility factor wrt temperature - * @param[out] dCompressibilityFactor_dz derivative of the compressibility factor wrt composition + * @param[in] aMixtureCoefficientDerivs derivatives of mixture coefficient (A) + * @param[in] bMixtureCoefficientDerivs derivatives of mixture coefficient (B) + * @param[out] compressibilityFactorDerivs derivatives of the compressibility factor * @note Assumes that pressure and temperature are strictly positive */ GEOS_HOST_DEVICE @@ -209,15 +308,9 @@ struct CubicEOSPhaseModel real64 const & aMixtureCoefficient, real64 const & bMixtureCoefficient, real64 const & compressibilityFactor, - real64 const & daMixtureCoefficient_dp, - real64 const & dbMixtureCoefficient_dp, - real64 const & daMixtureCoefficient_dt, - real64 const & dbMixtureCoefficient_dt, - arraySlice1d< real64 const > const daMixtureCoefficient_dz, - arraySlice1d< real64 const > const dbMixtureCoefficient_dz, - real64 & dCompressibilityFactor_dp, - real64 & dCompressibilityFactor_dt, - arraySlice1d< real64 > const dCompressibilityFactor_dz ); + arraySlice1d< real64 const > const & aMixtureCoefficientDerivs, + arraySlice1d< real64 const > const & bMixtureCoefficientDerivs, + arraySlice1d< real64 > const & compressibilityFactorDerivs ); /** * @brief Compute the log of the fugacity coefficients using compositions, BICs, compressibility factor and mixture coefficients @@ -231,18 +324,19 @@ struct CubicEOSPhaseModel * @param[in] bMixtureCoefficient mixture coefficient (B) * @param[out] logFugacityCoefficients log of the fugacity coefficients */ + template< integer USD > GEOS_HOST_DEVICE GEOS_FORCE_INLINE static void computeLogFugacityCoefficients( integer const numComps, - arrayView1d< real64 const > const composition, - arrayView2d< real64 const > const & binaryInteractionCoefficients, + arraySlice1d< real64 const, USD > const & composition, + arraySlice2d< real64 const > const & binaryInteractionCoefficients, real64 const & compressibilityFactor, - arraySlice1d< real64 const > const aPureCoefficient, - arraySlice1d< real64 const > const bPureCoefficient, + arraySlice1d< real64 const > const & aPureCoefficient, + arraySlice1d< real64 const > const & bPureCoefficient, real64 const & aMixtureCoefficient, real64 const & bMixtureCoefficient, - arraySlice1d< real64 > const logFugacityCoefficients ); + arraySlice1d< real64 > const & logFugacityCoefficients ); /** * @brief Helper functions solving a cubic equation using trigonometry @@ -267,15 +361,16 @@ struct CubicEOSPhaseModel }; template< typename EOS_TYPE > +template< integer USD > GEOS_HOST_DEVICE void CubicEOSPhaseModel< EOS_TYPE >:: computeLogFugacityCoefficients( integer const numComps, real64 const & pressure, real64 const & temperature, - arrayView1d< real64 const > const composition, + arraySlice1d< real64 const, USD > const & composition, ComponentProperties::KernelWrapper const & componentProperties, - arraySlice1d< real64 > const logFugacityCoefficients ) + arraySlice1d< real64 > const & logFugacityCoefficients ) { // step 0: allocate the stack memory needed for the update stackArray1d< real64, MultiFluidConstants::MAX_NUM_COMPONENTS > aPureCoefficient( numComps ); @@ -284,7 +379,7 @@ computeLogFugacityCoefficients( integer const numComps, real64 bMixtureCoefficient = 0.0; real64 compressibilityFactor = 0.0; - arrayView2d< real64 const > const & binaryInteractionCoefficients = componentProperties.m_componentBinaryCoeff; + arraySlice2d< real64 const > const & binaryInteractionCoefficients = componentProperties.m_componentBinaryCoeff; // step 1: compute the mixture coefficients aPureCoefficient, bPureCoefficient, aMixtureCoefficient, bMixtureCoefficient computeMixtureCoefficients( numComps, // number of components @@ -319,33 +414,335 @@ computeLogFugacityCoefficients( integer const numComps, logFugacityCoefficients ); // output } +template< typename EOS_TYPE > +template< integer USD > +GEOS_HOST_DEVICE +void +CubicEOSPhaseModel< EOS_TYPE >:: +computeLogFugacityCoefficients( integer const numComps, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const, USD > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + arraySlice1d< real64 const > const & logFugacityCoefficients, + arraySlice2d< real64 > const & logFugacityCoefficientDerivs ) +{ + integer constexpr numMaxComps = MultiFluidConstants::MAX_NUM_COMPONENTS; + integer constexpr numMaxDofs = MultiFluidConstants::MAX_NUM_COMPONENTS + 2; + integer const numDofs = 2 + numComps; + + GEOS_UNUSED_VAR( logFugacityCoefficients ); + + stackArray1d< real64, numMaxComps > aPureCoefficient( numComps ); + stackArray1d< real64, numMaxComps > bPureCoefficient( numComps ); + stackArray2d< real64, 2*numMaxComps > aPureCoefficientDerivs( numComps, 2 ); + stackArray2d< real64, 2*numMaxComps > bPureCoefficientDerivs( numComps, 2 ); + real64 aMixtureCoefficient = 0.0; + real64 bMixtureCoefficient = 0.0; + real64 compressibilityFactor = 0.0; + stackArray1d< real64, numMaxDofs > aMixtureCoefficientDerivs( numDofs ); + stackArray1d< real64, numMaxDofs > bMixtureCoefficientDerivs( numDofs ); + stackArray1d< real64, numMaxDofs > compressibilityFactorDerivs( numDofs ); + + arraySlice2d< real64 const > const & binaryInteractionCoefficients = componentProperties.m_componentBinaryCoeff; + + // 1.1: Compute the pure and mixture coefficients + computeMixtureCoefficients( numComps, // number of components + pressure, // cell input + temperature, + composition, + componentProperties, // user input, + aPureCoefficient, // output + bPureCoefficient, + aMixtureCoefficient, + bMixtureCoefficient ); + + // 1.2: Compute pure coefficient derivatives + for( integer ic = 0; ic < numComps; ++ic ) + { + computePureCoefficients( ic, + pressure, + temperature, + componentProperties, + aPureCoefficient[ic], + bPureCoefficient[ic], + aPureCoefficientDerivs( ic, Deriv::dP ), + bPureCoefficientDerivs( ic, Deriv::dP ), + aPureCoefficientDerivs( ic, Deriv::dT ), + bPureCoefficientDerivs( ic, Deriv::dT )); + } + + // 1.3: Compute mixture coefficient derivatives + computeMixtureCoefficients( numComps, + pressure, + temperature, + composition, + componentProperties, + aPureCoefficient, + bPureCoefficient, + aMixtureCoefficient, + bMixtureCoefficient, + aMixtureCoefficientDerivs, + bMixtureCoefficientDerivs ); + + // 2.1: Update the compressibility factor + computeCompressibilityFactor( numComps, // number of components + composition, // cell input + binaryInteractionCoefficients, // user input + aPureCoefficient, // computed by computeMixtureCoefficients + bPureCoefficient, + aMixtureCoefficient, + bMixtureCoefficient, + compressibilityFactor ); // output + // 2.2: Update the compressibility factor derivatives + computeCompressibilityFactor( numComps, + aMixtureCoefficient, + bMixtureCoefficient, + compressibilityFactor, + aMixtureCoefficientDerivs, + bMixtureCoefficientDerivs, + compressibilityFactorDerivs ); + + // 3. Calculate derivatives of the logarithm of the fugacity coefficients + stackArray1d< real64, numMaxComps > ki( numComps ); + stackArray2d< real64, numMaxComps * numMaxDofs > dki( numComps, numDofs ); + + // ki + for( integer ic = 0; ic < numComps; ++ic ) + { + ki[ic] = 0.0; + dki( ic, Deriv::dP ) = 0.0; + dki( ic, Deriv::dT ) = 0.0; + for( integer jc = 0; jc < numComps; ++jc ) + { + real64 const aCoeffI = sqrt( aPureCoefficient[ic] ); + real64 const aCoeffJ = sqrt( aPureCoefficient[jc] ); + real64 const kij = ( 1.0 - binaryInteractionCoefficients( ic, jc ) ) * aCoeffI * aCoeffJ; + ki[ic] += composition[jc] * kij; + dki( ic, Deriv::dC + jc ) = kij; + dki( ic, Deriv::dP ) += 0.5 * composition[jc] * kij * ( aPureCoefficientDerivs( ic, Deriv::dP )/aPureCoefficient[ic] + aPureCoefficientDerivs( jc, Deriv::dP )/aPureCoefficient[jc] ); + dki( ic, Deriv::dT ) += 0.5 * composition[jc] * kij * ( aPureCoefficientDerivs( ic, Deriv::dT )/aPureCoefficient[ic] + aPureCoefficientDerivs( jc, Deriv::dT )/aPureCoefficient[jc] ); + } + } + + auto const calculateDerivatives = [&]( integer const kc ){ + real64 const E = log( compressibilityFactor + EOS_TYPE::delta1 * bMixtureCoefficient ) + - log( compressibilityFactor + EOS_TYPE::delta2 * bMixtureCoefficient ); + + real64 const dE_dX = (compressibilityFactorDerivs[kc] + EOS_TYPE::delta1*bMixtureCoefficientDerivs[kc])/( compressibilityFactor + EOS_TYPE::delta1 * bMixtureCoefficient ) + -(compressibilityFactorDerivs[kc] + EOS_TYPE::delta2*bMixtureCoefficientDerivs[kc])/( compressibilityFactor + EOS_TYPE::delta2 * bMixtureCoefficient ); + + //real64 const F = log( compressibilityFactor - bMixtureCoefficient ); + real64 const dF_dX = (compressibilityFactorDerivs[kc] - bMixtureCoefficientDerivs[kc])/(compressibilityFactor - bMixtureCoefficient); + + real64 const G = 1.0 / ( ( EOS_TYPE::delta1 - EOS_TYPE::delta2 ) * bMixtureCoefficient ); + real64 const dG_dX = -G * bMixtureCoefficientDerivs[kc] / bMixtureCoefficient; + + real64 const A = aMixtureCoefficient; + real64 const dA_dX = aMixtureCoefficientDerivs[kc]; + + for( integer ic = 0; ic < numComps; ++ic ) + { + real64 const B = bPureCoefficient[ic] / bMixtureCoefficient; + real64 dB_dX = -B*bMixtureCoefficientDerivs[kc] / bMixtureCoefficient; + if( kc < Deriv::dC ) + { + dB_dX += bPureCoefficientDerivs( ic, kc ) / bMixtureCoefficient; + } + + // lnPhi = ( compressibilityFactor - 1 ) * B - F - G * ( 2 * ki[ic] - A * B ) * E; + logFugacityCoefficientDerivs( ic, kc ) = + compressibilityFactorDerivs[kc]*B + ( compressibilityFactor - 1 ) * dB_dX + - dF_dX + - dG_dX * ( 2 * ki[ic] - A * B ) * E + - G * ( 2 * dki( ic, kc ) - dA_dX * B - A * dB_dX ) * E + - G * ( 2 * ki[ic] - A * B ) * dE_dX; + } + }; + + calculateDerivatives( Deriv::dP ); + calculateDerivatives( Deriv::dT ); + + for( integer jc = 0; jc < numComps; ++jc ) + { + calculateDerivatives( Deriv::dC+jc ); + } +} + +template< typename EOS_TYPE > +template< integer USD > +GEOS_HOST_DEVICE +void +CubicEOSPhaseModel< EOS_TYPE >:: +computeCompressibilityFactor( integer const numComps, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const, USD > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + real64 & compressibilityFactor, + arraySlice1d< real64 > const & compressibilityFactorDerivs ) +{ + // step 0: allocate the stack memory needed for the update + integer constexpr numMaxComps = MultiFluidConstants::MAX_NUM_COMPONENTS; + integer constexpr numMaxDofs = MultiFluidConstants::MAX_NUM_COMPONENTS + 2; + integer const numDofs = 2 + numComps; + + stackArray1d< real64, numMaxComps > aPureCoefficient( numComps ); + stackArray1d< real64, numMaxComps > bPureCoefficient( numComps ); + real64 aMixtureCoefficient = 0.0; + real64 bMixtureCoefficient = 0.0; + stackArray1d< real64, numMaxDofs > aMixtureCoefficientDerivs( numDofs ); + stackArray1d< real64, numMaxDofs > bMixtureCoefficientDerivs( numDofs ); + + arraySlice2d< real64 const > const & binaryInteractionCoefficients = componentProperties.m_componentBinaryCoeff; + + // step 1: compute the mixture coefficients aPureCoefficient, bPureCoefficient, aMixtureCoefficient, bMixtureCoefficient + // 1.1: Compute the pure and mixture coefficients + computeMixtureCoefficients( numComps, // number of components + pressure, // cell input + temperature, + composition, + componentProperties, // user input, + aPureCoefficient, // output + bPureCoefficient, + aMixtureCoefficient, + bMixtureCoefficient ); + + // 1.2: Compute mixture coefficient derivatives + computeMixtureCoefficients( numComps, + pressure, + temperature, + composition, + componentProperties, + aPureCoefficient, + bPureCoefficient, + aMixtureCoefficient, + bMixtureCoefficient, + aMixtureCoefficientDerivs, + bMixtureCoefficientDerivs ); + + // 2.1: Update the compressibility factor + computeCompressibilityFactor( numComps, // number of components + composition, // cell input + binaryInteractionCoefficients, // user input + aPureCoefficient, // computed by computeMixtureCoefficients + bPureCoefficient, + aMixtureCoefficient, + bMixtureCoefficient, + compressibilityFactor ); // output + + // 2.2: Update the compressibility factor derivatives + computeCompressibilityFactor( numComps, + aMixtureCoefficient, + bMixtureCoefficient, + compressibilityFactor, + aMixtureCoefficientDerivs, + bMixtureCoefficientDerivs, + compressibilityFactorDerivs ); +} + +template< typename EOS_TYPE > +void +CubicEOSPhaseModel< EOS_TYPE >:: +calculateDimensionalVolumeShift( ComponentProperties const & componentProperties, + arraySlice1d< real64 > const & dimensionalVolumeShift ) +{ + integer const numComps = componentProperties.getNumberOfComponents(); + for( integer ic = 0; ic < numComps; ++ic ) + { + real64 const Vs = componentProperties.getComponentVolumeShift()[ic]; + real64 const Pc = componentProperties.getComponentCriticalPressure()[ic]; + real64 const Tc = componentProperties.getComponentCriticalTemperature()[ic]; + real64 constexpr omegaB = EOS_TYPE::omegaB; + dimensionalVolumeShift[ic] = constants::gasConstant * Vs * omegaB * Tc / Pc; + } +} + template< typename EOS_TYPE > GEOS_HOST_DEVICE void CubicEOSPhaseModel< EOS_TYPE >:: +computePureCoefficients( integer const ic, + real64 const & pressure, + real64 const & temperature, + ComponentProperties::KernelWrapper const & componentProperties, + real64 & aCoefficient, + real64 & bCoefficient ) +{ + real64 daCoefficient_dp = 0.0; + real64 dbCoefficient_dp = 0.0; + real64 daCoefficient_dt = 0.0; + real64 dbCoefficient_dt = 0.0; + computePureCoefficients( ic, + pressure, + temperature, + componentProperties, + aCoefficient, + bCoefficient, + daCoefficient_dp, + dbCoefficient_dp, + daCoefficient_dt, + dbCoefficient_dt ); +} + + +template< typename EOS_TYPE > +GEOS_HOST_DEVICE +void +CubicEOSPhaseModel< EOS_TYPE >:: +computePureCoefficients( integer const ic, + real64 const & pressure, + real64 const & temperature, + ComponentProperties::KernelWrapper const & componentProperties, + real64 & aCoefficient, + real64 & bCoefficient, + real64 & daCoefficient_dp, + real64 & dbCoefficient_dp, + real64 & daCoefficient_dt, + real64 & dbCoefficient_dt ) +{ + arraySlice1d< real64 const > const & criticalPressure = componentProperties.m_componentCriticalPressure; + arraySlice1d< real64 const > const & criticalTemperature = componentProperties.m_componentCriticalTemperature; + arraySlice1d< real64 const > const & acentricFactor = componentProperties.m_componentAcentricFactor; + + real64 const m = EOS_TYPE::evaluate( acentricFactor[ic] ); + real64 const pr = pressure / criticalPressure[ic]; + real64 const tr = temperature / criticalTemperature[ic]; + + real64 const sqrtTr = sqrt( tr ); + real64 const mt = 1.0 + m * (1.0 - sqrtTr); + + aCoefficient = EOS_TYPE::omegaA * pr / (tr*tr) * mt * mt; + bCoefficient = EOS_TYPE::omegaB * pr / tr; + + daCoefficient_dp = aCoefficient / pressure; + dbCoefficient_dp = bCoefficient / pressure; + + daCoefficient_dt = -aCoefficient * (2.0/temperature + m/(mt * sqrtTr * criticalTemperature[ic])); + dbCoefficient_dt = -bCoefficient / temperature; +} + +template< typename EOS_TYPE > +template< integer USD > +GEOS_HOST_DEVICE +void +CubicEOSPhaseModel< EOS_TYPE >:: computeMixtureCoefficients( integer const numComps, real64 const & pressure, real64 const & temperature, - arrayView1d< real64 const > const composition, + arraySlice1d< real64 const, USD > const & composition, ComponentProperties::KernelWrapper const & componentProperties, - arraySlice1d< real64 > const aPureCoefficient, - arraySlice1d< real64 > const bPureCoefficient, + arraySlice1d< real64 > const & aPureCoefficient, + arraySlice1d< real64 > const & bPureCoefficient, real64 & aMixtureCoefficient, real64 & bMixtureCoefficient ) { - arrayView1d< real64 const > const & criticalPressure = componentProperties.m_componentCriticalPressure; - arrayView1d< real64 const > const & criticalTemperature = componentProperties.m_componentCriticalTemperature; - arrayView1d< real64 const > const & acentricFactor = componentProperties.m_componentAcentricFactor; - arrayView2d< real64 const > const & binaryInteractionCoefficients = componentProperties.m_componentBinaryCoeff; + arraySlice2d< real64 const > const & binaryInteractionCoefficients = componentProperties.m_componentBinaryCoeff; // mixture coefficients for( integer ic = 0; ic < numComps; ++ic ) { - real64 const m = EOS_TYPE::evaluate( acentricFactor[ic] ); - real64 const pr = pressure / criticalPressure[ic]; - real64 const tr = temperature / criticalTemperature[ic]; - aPureCoefficient[ic] = EOS_TYPE::omegaA * pr / (tr*tr) * pow( 1.0 + m * ( 1.0 - sqrt( tr ) ), 2.0 ); - bPureCoefficient[ic] = EOS_TYPE::omegaB * pr / tr; + computePureCoefficients( ic, pressure, temperature, componentProperties, aPureCoefficient[ic], bPureCoefficient[ic] ); } aMixtureCoefficient = 0.0; @@ -354,89 +751,85 @@ computeMixtureCoefficients( integer const numComps, { for( integer jc = 0; jc < numComps; ++jc ) { - aMixtureCoefficient += ( composition[ic] * composition[jc] * ( 1.0 - binaryInteractionCoefficients( ic, jc ) ) * sqrt( aPureCoefficient[ic] * aPureCoefficient[jc] ) ); + aMixtureCoefficient += composition[ic] * composition[jc] * ( 1.0 - binaryInteractionCoefficients( ic, jc ) ) * sqrt( aPureCoefficient[ic] * aPureCoefficient[jc] ); } bMixtureCoefficient += composition[ic] * bPureCoefficient[ic]; } } template< typename EOS_TYPE > +template< integer USD > GEOS_HOST_DEVICE void CubicEOSPhaseModel< EOS_TYPE >:: computeMixtureCoefficients( integer const numComps, real64 const & pressure, real64 const & temperature, - arrayView1d< real64 const > const composition, + arraySlice1d< real64 const, USD > const & composition, ComponentProperties::KernelWrapper const & componentProperties, - arraySlice1d< real64 const > const aPureCoefficient, - arraySlice1d< real64 const > const bPureCoefficient, + arraySlice1d< real64 const > const & aPureCoefficient, + arraySlice1d< real64 const > const & bPureCoefficient, real64 const aMixtureCoefficient, real64 const bMixtureCoefficient, - real64 & daMixtureCoefficient_dp, - real64 & dbMixtureCoefficient_dp, - real64 & daMixtureCoefficient_dt, - real64 & dbMixtureCoefficient_dt, - arraySlice1d< real64 > const daMixtureCoefficient_dz, - arraySlice1d< real64 > const dbMixtureCoefficient_dz ) + arraySlice1d< real64 > const & aMixtureCoefficientDerivs, + arraySlice1d< real64 > const & bMixtureCoefficientDerivs ) { - arrayView1d< real64 const > const & criticalTemperature = componentProperties.m_componentCriticalTemperature; - arrayView1d< real64 const > const & acentricFactor = componentProperties.m_componentAcentricFactor; - arrayView2d< real64 const > const & binaryInteractionCoefficients = componentProperties.m_componentBinaryCoeff; - - stackArray1d< real64, MultiFluidConstants::MAX_NUM_COMPONENTS > daPureCoefficient_dx( numComps ); + arraySlice2d< real64 const > const & binaryInteractionCoefficients = componentProperties.m_componentBinaryCoeff; // Calculate pressure derivatives - daMixtureCoefficient_dp = aMixtureCoefficient / pressure; - dbMixtureCoefficient_dp = bMixtureCoefficient / pressure; + aMixtureCoefficientDerivs[Deriv::dP] = aMixtureCoefficient / pressure; + bMixtureCoefficientDerivs[Deriv::dP] = bMixtureCoefficient / pressure; // Calculate temperature derivatives + real64 aCoefficient = 0.0; + real64 bCoefficient = 0.0; + real64 dummy = 0.0; + stackArray1d< real64, MultiFluidConstants::MAX_NUM_COMPONENTS > daPureCoefficient_dt( numComps ); for( integer ic = 0; ic < numComps; ++ic ) { - real64 const m = EOS_TYPE::evaluate( acentricFactor[ic] ); - real64 const sqrtTr = sqrt( temperature / criticalTemperature[ic] ); - real64 const mt = 1.0 + m * (1.0 - sqrtTr); - daPureCoefficient_dx[ic] = -aPureCoefficient[ic] * (2.0/temperature + m/(mt*sqrtTr*criticalTemperature[ic])); + computePureCoefficients( ic, pressure, temperature, componentProperties, + aCoefficient, bCoefficient, dummy, dummy, daPureCoefficient_dt[ic], dummy ); } - daMixtureCoefficient_dt = 0.0; - dbMixtureCoefficient_dt = -bMixtureCoefficient / temperature; + aMixtureCoefficientDerivs[Deriv::dT] = 0.0; + bMixtureCoefficientDerivs[Deriv::dT] = -bMixtureCoefficient / temperature; for( integer ic = 0; ic < numComps; ++ic ) { for( integer jc = 0; jc < numComps; ++jc ) { real64 const coeff = composition[ic] * composition[jc] * ( 1.0 - binaryInteractionCoefficients( ic, jc ) ) / sqrt( aPureCoefficient[ic] * aPureCoefficient[jc] ); - daMixtureCoefficient_dt += 0.5 * coeff * (daPureCoefficient_dx[ic]*aPureCoefficient[jc] + daPureCoefficient_dx[jc]*aPureCoefficient[ic]); + aMixtureCoefficientDerivs[Deriv::dT] += 0.5 * coeff * (daPureCoefficient_dt[ic]*aPureCoefficient[jc] + daPureCoefficient_dt[jc]*aPureCoefficient[ic]); } } // Calculate composition derivatives for( integer ic = 0; ic < numComps; ++ic ) { - daMixtureCoefficient_dz[ic] = 0.0; - dbMixtureCoefficient_dz[ic] = 0.0; + aMixtureCoefficientDerivs[Deriv::dC+ic] = 0.0; + bMixtureCoefficientDerivs[Deriv::dC+ic] = 0.0; } for( integer ic = 0; ic < numComps; ++ic ) { for( integer jc = 0; jc < numComps; ++jc ) { real64 const coeff = ( 1.0 - binaryInteractionCoefficients( ic, jc ) ) * sqrt( aPureCoefficient[ic] * aPureCoefficient[jc] ); - daMixtureCoefficient_dz[ic] += coeff * composition[jc]; - daMixtureCoefficient_dz[jc] += coeff * composition[ic]; + aMixtureCoefficientDerivs[Deriv::dC+ic] += coeff * composition[jc]; + aMixtureCoefficientDerivs[Deriv::dC+jc] += coeff * composition[ic]; } - dbMixtureCoefficient_dz[ic] = bPureCoefficient[ic]; + bMixtureCoefficientDerivs[Deriv::dC+ic] = bPureCoefficient[ic]; } } template< typename EOS_TYPE > +template< integer USD > GEOS_HOST_DEVICE void CubicEOSPhaseModel< EOS_TYPE >:: computeCompressibilityFactor( integer const numComps, - arrayView1d< real64 const > const composition, - arrayView2d< real64 const > const & binaryInteractionCoefficients, - arraySlice1d< real64 const > const aPureCoefficient, - arraySlice1d< real64 const > const bPureCoefficient, + arraySlice1d< real64 const, USD > const & composition, + arraySlice2d< real64 const > const & binaryInteractionCoefficients, + arraySlice1d< real64 const > const & aPureCoefficient, + arraySlice1d< real64 const > const & bPureCoefficient, real64 const & aMixtureCoefficient, real64 const & bMixtureCoefficient, real64 & compressibilityFactor ) @@ -505,80 +898,61 @@ computeCompressibilityFactor( integer const numComps, real64 const & aMixtureCoefficient, real64 const & bMixtureCoefficient, real64 const & compressibilityFactor, - real64 const & daMixtureCoefficient_dp, - real64 const & dbMixtureCoefficient_dp, - real64 const & daMixtureCoefficient_dt, - real64 const & dbMixtureCoefficient_dt, - arraySlice1d< real64 const > const daMixtureCoefficient_dz, - arraySlice1d< real64 const > const dbMixtureCoefficient_dz, - real64 & dcompressibilityFactor_dp, - real64 & dcompressibilityFactor_dt, - arraySlice1d< real64 > const dcompressibilityFactor_dz ) + arraySlice1d< real64 const > const & aMixtureCoefficientDerivs, + arraySlice1d< real64 const > const & bMixtureCoefficientDerivs, + arraySlice1d< real64 > const & compressibilityFactorDerivs ) { - // a Z3 + b Z2 + cZ + d = 0 - // Derivatives for a,b,c,d - // dadx is zero; - real64 dbdx = 0.0; - real64 dcdx = 0.0; - real64 dddx = 0.0; - - constexpr real64 d1pd2 = EOS_TYPE::delta1 + EOS_TYPE::delta2; - constexpr real64 d1xd2 = EOS_TYPE::delta1 * EOS_TYPE::delta2; + real64 constexpr d1pd2 = EOS_TYPE::delta1 + EOS_TYPE::delta2; + real64 constexpr d1xd2 = EOS_TYPE::delta1 * EOS_TYPE::delta2; - constexpr real64 a = 1.0; + real64 constexpr a = 1.0; real64 const b = ( d1pd2 - 1.0 ) * bMixtureCoefficient - 1.0; real64 const c = aMixtureCoefficient + d1xd2 * bMixtureCoefficient * bMixtureCoefficient - d1pd2 * bMixtureCoefficient * ( bMixtureCoefficient + 1.0 ); // Implicit differentiation scale real64 const denominator = (3.0*a*compressibilityFactor + 2.0*b)*compressibilityFactor + c; - constexpr real64 epsilon = MultiFluidConstants::epsilon; - real64 const scalingFactor = fabs( denominator ) < epsilon ? 0.0 : -1.0 / denominator; - - // Pressure derivatives - dbdx = ( d1pd2 - 1.0 ) * dbMixtureCoefficient_dp; - dcdx = daMixtureCoefficient_dp + (2.0*(d1xd2-d1pd2)*bMixtureCoefficient-d1pd2)*dbMixtureCoefficient_dp; - dddx = -(aMixtureCoefficient*dbMixtureCoefficient_dp + daMixtureCoefficient_dp*bMixtureCoefficient - + d1xd2*((3.0*bMixtureCoefficient+2.0)*bMixtureCoefficient*dbMixtureCoefficient_dp)); - dcompressibilityFactor_dp = (((dbdx*compressibilityFactor) + dcdx)*compressibilityFactor + dddx) * scalingFactor; - - // Temperature derivatives - dbdx = ( d1pd2 - 1.0 ) * dbMixtureCoefficient_dt; - dcdx = daMixtureCoefficient_dt + (2.0*(d1xd2-d1pd2)*bMixtureCoefficient-d1pd2)*dbMixtureCoefficient_dt; - dddx = -(aMixtureCoefficient*dbMixtureCoefficient_dt + daMixtureCoefficient_dt*bMixtureCoefficient - + d1xd2*((3.0*bMixtureCoefficient+2.0)*bMixtureCoefficient*dbMixtureCoefficient_dt)); - dcompressibilityFactor_dt = (((dbdx*compressibilityFactor) + dcdx)*compressibilityFactor + dddx) * scalingFactor; - - // Composition derivatives - for( integer ic = 0; ic < numComps; ++ic ) + real64 const scalingFactor = LvArray::math::abs( denominator ) < MultiFluidConstants::epsilon ? 0.0 : -1.0 / denominator; + + integer const numDofs = numComps + 2; + + for( integer kc = 0; kc < numDofs; ++kc ) { - dbdx = ( d1pd2 - 1.0 ) * dbMixtureCoefficient_dz[ic]; - dcdx = daMixtureCoefficient_dz[ic] + (2.0*(d1xd2-d1pd2)*bMixtureCoefficient-d1pd2)*dbMixtureCoefficient_dz[ic]; - dddx = -(aMixtureCoefficient*dbMixtureCoefficient_dz[ic] + daMixtureCoefficient_dz[ic]*bMixtureCoefficient - + d1xd2*((3.0*bMixtureCoefficient+2.0)*bMixtureCoefficient*dbMixtureCoefficient_dz[ic])); - dcompressibilityFactor_dz[ic] = (((dbdx*compressibilityFactor) + dcdx)*compressibilityFactor + dddx) * scalingFactor; + // Given derivative of the mixture parameters a and b w.r.t. variable X, calculate the derivative of the + // compressibility factor (z-factor) w.r.t. X + real64 const da_dX = aMixtureCoefficientDerivs[kc]; + real64 const db_dX = bMixtureCoefficientDerivs[kc]; + // a Z3 + b Z2 + cZ + d = 0 + // Derivatives for a,b,c,d + real64 const dbdx = ( d1pd2 - 1.0 ) * db_dX; + real64 const dcdx = da_dX + ( 2.0*(d1xd2-d1pd2) * bMixtureCoefficient - d1pd2 )*db_dX; + real64 const dddx = -(aMixtureCoefficient*db_dX + da_dX*bMixtureCoefficient + + d1xd2*((3.0*bMixtureCoefficient+2.0)*bMixtureCoefficient*db_dX)); + compressibilityFactorDerivs[kc] = (((dbdx*compressibilityFactor) + dcdx)*compressibilityFactor + dddx) * scalingFactor; } } template< typename EOS_TYPE > +template< integer USD > GEOS_HOST_DEVICE void CubicEOSPhaseModel< EOS_TYPE >:: computeLogFugacityCoefficients( integer const numComps, - arrayView1d< real64 const > const composition, - arrayView2d< real64 const > const & binaryInteractionCoefficients, + arraySlice1d< real64 const, USD > const & composition, + arraySlice2d< real64 const > const & binaryInteractionCoefficients, real64 const & compressibilityFactor, - arraySlice1d< real64 const > const aPureCoefficient, - arraySlice1d< real64 const > const bPureCoefficient, + arraySlice1d< real64 const > const & aPureCoefficient, + arraySlice1d< real64 const > const & bPureCoefficient, real64 const & aMixtureCoefficient, real64 const & bMixtureCoefficient, - arraySlice1d< real64 > const logFugacityCoefficients ) + arraySlice1d< real64 > const & logFugacityCoefficients ) { stackArray1d< real64, MultiFluidConstants::MAX_NUM_COMPONENTS > ki( numComps ); // ki for( integer ic = 0; ic < numComps; ++ic ) { + ki[ic] = 0.0; for( integer jc = 0; jc < numComps; ++jc ) { ki[ic] += composition[jc] * ( 1.0 - binaryInteractionCoefficients( ic, jc ) ) * sqrt( aPureCoefficient[ic] * aPureCoefficient[jc] ); @@ -586,9 +960,13 @@ computeLogFugacityCoefficients( integer const numComps, } // E - real64 const E = log( ( compressibilityFactor + EOS_TYPE::delta1 * bMixtureCoefficient ) - / ( compressibilityFactor + EOS_TYPE::delta2 * bMixtureCoefficient ) ); - real64 const F = log( compressibilityFactor - bMixtureCoefficient ); + real64 const expE = ( compressibilityFactor + EOS_TYPE::delta1 * bMixtureCoefficient ) / + ( compressibilityFactor + EOS_TYPE::delta2 * bMixtureCoefficient ); + real64 const expF = compressibilityFactor - bMixtureCoefficient; + GEOS_ERROR_IF( expE < MultiFluidConstants::epsilon || expF < MultiFluidConstants::epsilon, + GEOS_FMT( "Cubic EOS failed with exp(E)={} and exp(F)={}", expE, expF )); + real64 const E = log( expE ); + real64 const F = log( expF ); real64 const G = 1.0 / ( ( EOS_TYPE::delta1 - EOS_TYPE::delta2 ) * bMixtureCoefficient ); real64 const A = aMixtureCoefficient; @@ -644,6 +1022,9 @@ solveCubicPolynomial( real64 const & m3, } } +using CubicEOSPR = CubicEOSPhaseModel< PengRobinsonEOS >; +using CubicEOSSRK = CubicEOSPhaseModel< SoaveRedlichKwongEOS >; + } // namespace compositional } // namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/FugacityCalculator.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/FugacityCalculator.hpp new file mode 100644 index 00000000000..2fa6af3a6fd --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/FugacityCalculator.hpp @@ -0,0 +1,155 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FugacityCalculator.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_FUNCTIONS_FUGACITYCALCULATOR_HPP_ +#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_FUNCTIONS_FUGACITYCALCULATOR_HPP_ + +#include "constitutive/fluid/multifluid/compositional/models/ComponentProperties.hpp" +#include "constitutive/fluid/multifluid/compositional/models/EquationOfState.hpp" +#include "constitutive/fluid/multifluid/compositional/functions/CubicEOSPhaseModel.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +struct FugacityCalculator +{ + /** + * @brief Calculate the log fugacity for a phase + * @param[in] numComps number of components + * @param[in] pressure pressure + * @param[in] temperature temperature + * @param[in] composition composition of the phase + * @param[in] componentProperties The compositional component properties + * @param[in] equationOfState The equation of state + * @param[out] logFugacity the calculated log fugacity + */ + template< int USD > + GEOS_HOST_DEVICE + static void computeLogFugacity( integer const numComps, + real64 const pressure, + real64 const temperature, + arraySlice1d< real64 const, USD > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + EquationOfStateType const equationOfState, + arraySlice1d< real64 > const & logFugacity ); + + /** + * @brief Calculate the derivatives for the log fugacity for a phase + * @param[in] numComps number of components + * @param[in] pressure pressure + * @param[in] temperature temperature + * @param[in] composition composition of the phase + * @param[in] componentProperties The compositional component properties + * @param[in] equationOfState The equation of state + * @param[in] logFugacity the calculated log fugacity + * @param[out] logFugacityDerivs the calculated derivatives of the log fugacity + */ + template< int USD1, int USD2 > + GEOS_HOST_DEVICE + static void computeLogFugacityDerivatives( integer const numComps, + real64 const pressure, + real64 const temperature, + arraySlice1d< real64 const, USD1 > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + EquationOfStateType const equationOfState, + arraySlice1d< real64 const > const & logFugacity, + arraySlice2d< real64, USD2 > const & logFugacityDerivs ); +}; + +template< int USD > +GEOS_HOST_DEVICE +void FugacityCalculator::computeLogFugacity( integer const numComps, + real64 const pressure, + real64 const temperature, + arraySlice1d< real64 const, USD > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + EquationOfStateType const equationOfState, + arraySlice1d< real64 > const & logFugacity ) +{ + if( equationOfState == EquationOfStateType::PengRobinson ) + { + CubicEOSPhaseModel< PengRobinsonEOS >:: + computeLogFugacityCoefficients( numComps, + pressure, + temperature, + composition, + componentProperties, + logFugacity ); + } + else if( equationOfState == EquationOfStateType::SoaveRedlichKwong ) + { + CubicEOSPhaseModel< SoaveRedlichKwongEOS >:: + computeLogFugacityCoefficients( numComps, + pressure, + temperature, + composition, + componentProperties, + logFugacity ); + } +} + +template< int USD1, int USD2 > +GEOS_HOST_DEVICE +void FugacityCalculator::computeLogFugacityDerivatives( integer const numComps, + real64 const pressure, + real64 const temperature, + arraySlice1d< real64 const, USD1 > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + EquationOfStateType const equationOfState, + arraySlice1d< real64 const > const & logFugacity, + arraySlice2d< real64, USD2 > const & logFugacityDerivs ) +{ + if( equationOfState == EquationOfStateType::PengRobinson ) + { + CubicEOSPhaseModel< PengRobinsonEOS >:: + computeLogFugacityCoefficients( numComps, + pressure, + temperature, + composition, + componentProperties, + logFugacity, + logFugacityDerivs ); + } + else if( equationOfState == EquationOfStateType::SoaveRedlichKwong ) + { + CubicEOSPhaseModel< SoaveRedlichKwongEOS >:: + computeLogFugacityCoefficients( numComps, + pressure, + temperature, + composition, + componentProperties, + logFugacity, + logFugacityDerivs ); + } +} + +} // namespace compositional + +} // namespace constitutive + +} // namespace geos + + +#endif //GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_FUNCTIONS_FUGACITYCALCULATOR_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/KValueInitialization.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/KValueInitialization.hpp index 0ef7352233e..f19219aeb94 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/KValueInitialization.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/KValueInitialization.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -42,6 +43,7 @@ struct KValueInitialization * @param[in] componentProperties The compositional component properties * @param[out] kValues the calculated k-values **/ + template< integer USD > GEOS_HOST_DEVICE GEOS_FORCE_INLINE static void @@ -49,7 +51,7 @@ struct KValueInitialization real64 const pressure, real64 const temperature, ComponentProperties::KernelWrapper const & componentProperties, - arraySlice1d< real64 > const kValues ) + arraySlice1d< real64, USD > const & kValues ) { arrayView1d< real64 const > const & criticalPressure = componentProperties.m_componentCriticalPressure; arrayView1d< real64 const > const & criticalTemperature = componentProperties.m_componentCriticalTemperature; diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/NegativeTwoPhaseFlash.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/NegativeTwoPhaseFlash.hpp index 7cd8e9508cf..2af75b9b4b9 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/NegativeTwoPhaseFlash.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/NegativeTwoPhaseFlash.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,23 +20,25 @@ #ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_FUNCTIONS_NEGATIVETWOPHASEFLASH_HPP_ #define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_FUNCTIONS_NEGATIVETWOPHASEFLASH_HPP_ -#include "common/DataTypes.hpp" #include "RachfordRice.hpp" #include "KValueInitialization.hpp" +#include "FugacityCalculator.hpp" #include "constitutive/fluid/multifluid/MultiFluidConstants.hpp" #include "constitutive/fluid/multifluid/compositional/models/ComponentProperties.hpp" +#include "denseLinearAlgebra/interfaces/blaslapack/BlasLapackLA.hpp" namespace geos { namespace constitutive { - namespace compositional { struct NegativeTwoPhaseFlash { + using Deriv = constitutive::multifluid::DerivativeOffset; + public: /** * @brief Perform negative two-phase EOS flash @@ -44,153 +47,502 @@ struct NegativeTwoPhaseFlash * @param[in] temperature temperature * @param[in] composition composition of the mixture * @param[in] componentProperties The compositional component properties + * @param[in] liquidEos The equation of state for the liquid phase + * @param[in] vapourEos The equation of state for the vapour phase + * @param[in/out] kValues The phase equilibrium ratios * @param[out] vapourPhaseMoleFraction the calculated vapour (gas) mole fraction * @param[out] liquidComposition the calculated liquid phase composition * @param[out] vapourComposition the calculated vapour phase composition * @return an indicator of success of the flash */ - template< typename EOS_TYPE_LIQUID, typename EOS_TYPE_VAPOUR > + template< int USD1, int USD2 > GEOS_HOST_DEVICE static bool compute( integer const numComps, real64 const pressure, real64 const temperature, - arrayView1d< real64 const > const composition, + arraySlice1d< real64 const > const & composition, ComponentProperties::KernelWrapper const & componentProperties, + EquationOfStateType const liquidEos, + EquationOfStateType const vapourEos, + arraySlice2d< real64, USD1 > const & kValues, real64 & vapourPhaseMoleFraction, - arrayView1d< real64 > const liquidComposition, - arrayView1d< real64 > const vapourComposition ) - { - constexpr integer maxNumComps = MultiFluidConstants::MAX_NUM_COMPONENTS; - stackArray1d< real64, maxNumComps > logLiquidFugacity( numComps ); - stackArray1d< real64, maxNumComps > logVapourFugacity( numComps ); - stackArray1d< real64, maxNumComps > kVapourLiquid( numComps ); - stackArray1d< real64, maxNumComps > fugacityRatios( numComps ); - stackArray1d< integer, maxNumComps > presentComponentIds( numComps ); + arraySlice1d< real64, USD2 > const & liquidComposition, + arraySlice1d< real64, USD2 > const & vapourComposition ); - // Initialise compositions to feed composition - for( integer ic = 0; ic < numComps; ++ic ) - { - liquidComposition[ic] = composition[ic]; - vapourComposition[ic] = composition[ic]; - } + /** + * @brief Calculate derivatives from the two-phase negative flash + * @param[in] numComps number of components + * @param[in] pressure pressure + * @param[in] temperature temperature + * @param[in] composition composition of the mixture + * @param[in] componentProperties The compositional component properties + * @param[in] liquidEos The equation of state for the liquid phase + * @param[in] vapourEos The equation of state for the vapour phase + * @param[in] vapourFraction the calculated vapour (gas) mole fraction + * @param[in] liquidComposition the calculated liquid phase composition + * @param[in] vapourComposition the calculated vapour phase composition + * @param[out] vapourFractionDerivs derivatives of the calculated vapour (gas) mole fraction + * @param[out] liquidCompositionDerivs derivatives of the calculated liquid phase composition + * @param[out] vapourCompositionDerivs derivatives of the calculated vapour phase composition + */ + template< integer USD1, integer USD2, integer USD3 > + GEOS_HOST_DEVICE + static void computeDerivatives( integer const numComps, + real64 const pressure, + real64 const temperature, + arraySlice1d< real64 const > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + EquationOfStateType const liquidEos, + EquationOfStateType const vapourEos, + real64 const & vapourFraction, + arraySlice1d< real64 const, USD1 > const & liquidComposition, + arraySlice1d< real64 const, USD1 > const & vapourComposition, + arraySlice1d< real64, USD2 > const & vapourFractionDerivs, + arraySlice2d< real64, USD3 > const & liquidCompositionDerivs, + arraySlice2d< real64, USD3 > const & vapourCompositionDerivs ); +private: + /** + * @brief Calculate which components are present. + * @details Creates a list of indices whose components have non-zero mole fraction. + * @param[in] numComps number of components + * @param[in] composition the composition of the fluid + * @param[out] presentComponents the list of present components + * @return the number of present components + */ + template< typename ARRAY > + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + static integer calculatePresentComponents( integer const numComps, + arraySlice1d< real64 const > const & composition, + ARRAY & presentComponents ) + { // Check for machine-zero feed values integer presentCount = 0; for( integer ic = 0; ic < numComps; ++ic ) { - if( MultiFluidConstants::epsilon < composition[ic] ) + if( MultiFluidConstants::minForSpeciesPresence < composition[ic] ) { - presentComponentIds[presentCount++] = ic; + presentComponents[presentCount++] = ic; } } - presentComponentIds.resize( presentCount ); + presentComponents.resize( presentCount ); + return presentCount; + } + /** + * @brief Normalise a composition in place to ensure that the components add up to unity + * @param[in] numComps number of components + * @param[in/out] composition composition to be normalized + * @return the sum of the given values + */ + template< integer USD > + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + static real64 normalizeComposition( integer const numComps, + arraySlice1d< real64, USD > const & composition ) + { + real64 totalMoles = 0.0; + for( integer ic = 0; ic < numComps; ++ic ) + { + totalMoles += composition[ic]; + } + real64 const oneOverTotalMoles = 1.0 / (totalMoles + MultiFluidConstants::epsilon); + for( integer ic = 0; ic < numComps; ++ic ) + { + composition[ic] *= oneOverTotalMoles; + } + return totalMoles; + } + + /** + * @brief Calculate the logarithms of the fugacity ratios + * @param[in] numComps number of components + * @param[in] pressure pressure + * @param[in] temperature temperature + * @param[in] composition composition of the mixture + * @param[in] componentProperties The compositional component properties + * @param[in] liquidEos The equation of state for the liquid phase + * @param[in] vapourEos The equation of state for the vapour phase + * @param[in] kValues The k-values + * @param[in] presentComponents The indices of the present components + * @param[out] vapourPhaseMoleFraction the calculated vapour (gas) mole fraction + * @param[out] liquidComposition the calculated liquid phase composition + * @param[out] vapourComposition the calculated vapour phase composition + * @param[out] logLiquidFugacity the calculated log fugacity ratios for the liquid phase + * @param[out] logVapourFugacity the calculated log fugacity ratios for the vapour phase + * @param[out] fugacityRatios the fugacity rations + * @return The error + */ + template< integer USD1, integer USD2 > + GEOS_HOST_DEVICE + static real64 computeFugacityRatio( + integer const numComps, + real64 const pressure, + real64 const temperature, + arraySlice1d< real64 const > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + EquationOfStateType const liquidEos, + EquationOfStateType const vapourEos, + arraySlice1d< real64 const, USD1 > const & kValues, + arraySlice1d< integer const > const & presentComponents, + real64 & vapourPhaseMoleFraction, + arraySlice1d< real64, USD2 > const & liquidComposition, + arraySlice1d< real64, USD2 > const & vapourComposition, + arraySlice1d< real64 > const & logLiquidFugacity, + arraySlice1d< real64 > const & logVapourFugacity, + arraySlice1d< real64 > const & fugacityRatios ); + + /** + * @brief Solve the lineat system for the derivatives of the flash + * @param[in/out] A the coefficient matrix. Destroyed after call + * @param[in/out] X the rhs and solution + * @return @c true if the problem is well solved @c false otherwise + */ + template< int USD > + GEOS_HOST_DEVICE + static bool solveLinearSystem( arraySlice2d< real64, USD > const & A, + arraySlice2d< real64, USD > const & X ) + { +#if defined(GEOS_DEVICE_COMPILE) + GEOS_UNUSED_VAR( A ); + GEOS_UNUSED_VAR( X ); + return false; +#else + BlasLapackLA::solveLinearSystem( A, X ); + return true; +#endif + } + +}; + +template< int USD1, int USD2 > +GEOS_HOST_DEVICE +bool NegativeTwoPhaseFlash::compute( integer const numComps, + real64 const pressure, + real64 const temperature, + arraySlice1d< real64 const > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + EquationOfStateType const liquidEos, + EquationOfStateType const vapourEos, + arraySlice2d< real64, USD1 > const & kValues, + real64 & vapourPhaseMoleFraction, + arraySlice1d< real64, USD2 > const & liquidComposition, + arraySlice1d< real64, USD2 > const & vapourComposition ) +{ + constexpr integer maxNumComps = MultiFluidConstants::MAX_NUM_COMPONENTS; + stackArray1d< real64, maxNumComps > logLiquidFugacity( numComps ); + stackArray1d< real64, maxNumComps > logVapourFugacity( numComps ); + stackArray1d< real64, maxNumComps > fugacityRatios( numComps ); + stackArray1d< integer, maxNumComps > componentIndices( numComps ); + auto const & kVapourLiquid = kValues[0]; + + calculatePresentComponents( numComps, composition, componentIndices ); + + // Initialise compositions to feed composition + for( integer ic = 0; ic < numComps; ++ic ) + { + liquidComposition[ic] = composition[ic]; + vapourComposition[ic] = composition[ic]; + } + + // Check if k-Values need to be initialised + bool needInitialisation = true; + for( integer ic = 0; ic < numComps; ++ic ) + { + if( kVapourLiquid[ic] < MultiFluidConstants::epsilon ) + { + needInitialisation = true; + break; + } + } + + if( needInitialisation ) + { KValueInitialization::computeWilsonGasLiquidKvalue( numComps, pressure, temperature, componentProperties, kVapourLiquid ); + } + + auto const presentComponents = componentIndices.toSliceConst(); + + bool converged = false; + for( localIndex iterationCount = 0; iterationCount < MultiFluidConstants::maxSSIIterations; ++iterationCount ) + { + real64 const error = computeFugacityRatio( numComps, + pressure, + temperature, + composition, + componentProperties, + liquidEos, + vapourEos, + kVapourLiquid.toSliceConst(), + presentComponents, + vapourPhaseMoleFraction, + liquidComposition, + vapourComposition, + logLiquidFugacity.toSlice(), + logVapourFugacity.toSlice(), + fugacityRatios.toSlice() ); - bool converged = false; - for( localIndex iterationCount = 0; iterationCount < MultiFluidConstants::maxSSIIterations; ++iterationCount ) + // Compute fugacity ratios and check convergence + converged = (error < MultiFluidConstants::fugacityTolerance); + + if( converged ) { - // Solve Rachford-Rice Equation - vapourPhaseMoleFraction = RachfordRice::solve( kVapourLiquid, composition, presentComponentIds ); + break; + } - // Assign phase compositions - for( integer const ic : presentComponentIds ) - { - liquidComposition[ic] = composition[ic] / ( 1.0 + vapourPhaseMoleFraction * ( kVapourLiquid[ic] - 1.0 ) ); - vapourComposition[ic] = kVapourLiquid[ic] * liquidComposition[ic]; - } + // Update K-values + for( integer ic = 0; ic < numComps; ++ic ) + { + kVapourLiquid[ic] *= exp( fugacityRatios[ic] ); + } + } - normalizeComposition( numComps, liquidComposition ); - normalizeComposition( numComps, vapourComposition ); + // Retrieve physical bounds from negative flash values + if( vapourPhaseMoleFraction < MultiFluidConstants::epsilon ) + { + vapourPhaseMoleFraction = 0.0; + for( integer ic = 0; ic < numComps; ++ic ) + { + liquidComposition[ic] = composition[ic]; + vapourComposition[ic] = composition[ic]; + } + } + else if( 1.0 - vapourPhaseMoleFraction < MultiFluidConstants::epsilon ) + { + vapourPhaseMoleFraction = 1.0; + for( integer ic = 0; ic < numComps; ++ic ) + { + liquidComposition[ic] = composition[ic]; + vapourComposition[ic] = composition[ic]; + } + } - // Compute the phase fugacities - EOS_TYPE_LIQUID::computeLogFugacityCoefficients( numComps, + return converged; +} + +template< integer USD1, integer USD2, integer USD3 > +GEOS_HOST_DEVICE +void NegativeTwoPhaseFlash::computeDerivatives( + integer const numComps, + real64 const pressure, + real64 const temperature, + arraySlice1d< real64 const > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + EquationOfStateType const liquidEos, + EquationOfStateType const vapourEos, + real64 const & vapourFraction, + arraySlice1d< real64 const, USD1 > const & liquidComposition, + arraySlice1d< real64 const, USD1 > const & vapourComposition, + arraySlice1d< real64, USD2 > const & vapourFractionDerivs, + arraySlice2d< real64, USD3 > const & liquidCompositionDerivs, + arraySlice2d< real64, USD3 > const & vapourCompositionDerivs ) +{ + constexpr integer maxNumComps = MultiFluidConstants::MAX_NUM_COMPONENTS; + constexpr integer maxNumDofs = MultiFluidConstants::MAX_NUM_COMPONENTS + 2; + + integer const numDofs = numComps + 2; + + auto const setZero = []( real64 & val ) { val = 0.0; }; + LvArray::forValuesInSlice( vapourFractionDerivs, setZero ); + LvArray::forValuesInSlice( liquidCompositionDerivs, setZero ); + LvArray::forValuesInSlice( vapourCompositionDerivs, setZero ); + + // Check if we are single or 2-phase + if( vapourFraction < MultiFluidConstants::epsilon ) + { + for( integer ic = 0; ic < numComps; ++ic ) + { + liquidCompositionDerivs( ic, Deriv::dC + ic ) = 1.0; + vapourCompositionDerivs( ic, Deriv::dC + ic ) = 1.0; + } + } + else if( 1.0 - vapourFraction < MultiFluidConstants::epsilon ) + { + for( integer ic = 0; ic < numComps; ++ic ) + { + liquidCompositionDerivs( ic, Deriv::dC + ic ) = 1.0; + vapourCompositionDerivs( ic, Deriv::dC + ic ) = 1.0; + } + } + else + { + // Calculate the liquid and vapour fugacities and derivatives + stackArray1d< real64, maxNumComps > logLiquidFugacity( numComps ); + stackArray1d< real64, maxNumComps > logVapourFugacity( numComps ); + stackArray2d< real64, maxNumComps * maxNumDofs > logLiquidFugacityDerivs( numComps, numDofs ); + stackArray2d< real64, maxNumComps * maxNumDofs > logVapourFugacityDerivs( numComps, numDofs ); + + FugacityCalculator::computeLogFugacity( numComps, + pressure, + temperature, + liquidComposition, + componentProperties, + liquidEos, + logLiquidFugacity ); + FugacityCalculator::computeLogFugacity( numComps, + pressure, + temperature, + vapourComposition, + componentProperties, + vapourEos, + logVapourFugacity ); + + FugacityCalculator::computeLogFugacityDerivatives( numComps, pressure, temperature, liquidComposition, componentProperties, - logLiquidFugacity ); - EOS_TYPE_VAPOUR::computeLogFugacityCoefficients( numComps, + liquidEos, + logLiquidFugacity.toSliceConst(), + logLiquidFugacityDerivs.toSlice() ); + FugacityCalculator::computeLogFugacityDerivatives( numComps, pressure, temperature, vapourComposition, componentProperties, - logVapourFugacity ); + vapourEos, + logVapourFugacity.toSliceConst(), + logVapourFugacityDerivs.toSlice() ); - // Compute fugacity ratios and check convergence - converged = true; + constexpr integer maxNumVals = 2*MultiFluidConstants::MAX_NUM_COMPONENTS+1; + integer const numVals = 2*numComps; + StackArray< real64, 2, maxNumVals * maxNumVals, MatrixLayout::COL_MAJOR_PERM > A( numVals + 1, numVals + 1 ); + StackArray< real64, 2, maxNumVals * maxNumVals, MatrixLayout::COL_MAJOR_PERM > X( numVals + 1, numVals + 1 ); - for( integer const ic : presentComponentIds ) - { - fugacityRatios[ic] = exp( logLiquidFugacity[ic] - logVapourFugacity[ic] ) * liquidComposition[ic] / vapourComposition[ic]; - if( MultiFluidConstants::fugacityTolerance < fabs( fugacityRatios[ic] - 1.0 ) ) - { - converged = false; - } - } + LvArray::forValuesInSlice( A.toSlice(), setZero ); + LvArray::forValuesInSlice( X.toSlice(), setZero ); - if( converged ) - { - break; - } + for( integer ic = 0; ic < numComps; ++ic ) + { + integer const xi = ic; + integer const yi = ic + numComps; + integer const vi = numVals; + + integer e = ic; + A( e, xi ) = 1.0 - vapourFraction; + A( e, yi ) = vapourFraction; + A( e, vi ) = vapourComposition[ic] - liquidComposition[ic]; - // Update K-values - for( integer const ic : presentComponentIds ) + e = ic + numComps; + real64 const phiL = exp( logLiquidFugacity( ic ) ); + real64 const phiV = exp( logVapourFugacity( ic ) ); + for( integer jc = 0; jc < numComps; ++jc ) { - kVapourLiquid[ic] *= fugacityRatios[ic]; + integer const xj = jc; + integer const yj = jc + numComps; + real64 const dPhiLdx = logLiquidFugacityDerivs( ic, Deriv::dC+jc ); + real64 const dPhiVdy = logVapourFugacityDerivs( ic, Deriv::dC+jc ); + A( e, xj ) = liquidComposition[ic] * phiL * dPhiLdx; + A( e, yj ) = -vapourComposition[ic] * phiV * dPhiVdy; } + A( e, xi ) += phiL; + A( e, yi ) -= phiV; + + e = numVals; + A( e, xi ) = -1.0; + A( e, yi ) = 1.0; + } + + // Pressure and temperature derivatives + for( integer ic = 0; ic < numComps; ++ic ) + { + real64 const phiL = -liquidComposition[ic] * exp( logLiquidFugacity( ic ) ); + real64 const phiV = vapourComposition[ic] * exp( logVapourFugacity( ic ) ); + X( ic + numComps, Deriv::dP ) = phiL * logLiquidFugacityDerivs( ic, Deriv::dP ) + + phiV * logVapourFugacityDerivs( ic, Deriv::dP ); + X( ic + numComps, Deriv::dT ) = phiL * logLiquidFugacityDerivs( ic, Deriv::dT ) + + phiV * logVapourFugacityDerivs( ic, Deriv::dT ); } - // Retrieve physical bounds from negative flash values - if( vapourPhaseMoleFraction <= 0.0 ) + // Composition derivatives + for( integer kc = 0; kc < numComps; ++kc ) { - vapourPhaseMoleFraction = 0.0; + integer const idof = Deriv::dC + kc; + for( integer ic = 0; ic < numComps; ++ic ) { - liquidComposition[ic] = composition[ic]; + X( ic, idof ) = -composition[ic]; } + X( kc, idof ) += 1.0; } - else if( 1.0 <= vapourPhaseMoleFraction ) + + // Solve linear system + solveLinearSystem( A.toSlice(), X.toSlice() ); + + // Fill in the derivatives + for( integer idof = 0; idof < numDofs; ++idof ) { - vapourPhaseMoleFraction = 1.0; for( integer ic = 0; ic < numComps; ++ic ) { - vapourComposition[ic] = composition[ic]; + liquidCompositionDerivs( ic, idof ) = X( ic, idof ); + vapourCompositionDerivs( ic, idof ) = X( ic + numComps, idof ); } + vapourFractionDerivs( idof ) = X( numVals, idof ); } + } +} + +template< integer USD1, integer USD2 > +GEOS_HOST_DEVICE +real64 NegativeTwoPhaseFlash::computeFugacityRatio( + integer const numComps, + real64 const pressure, + real64 const temperature, + arraySlice1d< real64 const > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + EquationOfStateType const liquidEos, + EquationOfStateType const vapourEos, + arraySlice1d< real64 const, USD1 > const & kValues, + arraySlice1d< integer const > const & presentComponents, + real64 & vapourPhaseMoleFraction, + arraySlice1d< real64, USD2 > const & liquidComposition, + arraySlice1d< real64, USD2 > const & vapourComposition, + arraySlice1d< real64 > const & logLiquidFugacity, + arraySlice1d< real64 > const & logVapourFugacity, + arraySlice1d< real64 > const & fugacityRatios ) +{ + // Solve Rachford-Rice Equation + vapourPhaseMoleFraction = RachfordRice::solve( kValues, composition, presentComponents ); - return converged; + // Assign phase compositions + for( integer ic = 0; ic < numComps; ++ic ) + { + liquidComposition[ic] = composition[ic] / ( 1.0 + vapourPhaseMoleFraction * ( kValues[ic] - 1.0 ) ); + vapourComposition[ic] = kValues[ic] * liquidComposition[ic]; } -private: - /** - * @brief Normalise a composition in place to ensure that the components add up to unity - * @param[in] numComps number of components - * @param[in/out] composition composition to be normalized - * @return the sum of the given values - */ - GEOS_HOST_DEVICE - GEOS_FORCE_INLINE - static real64 normalizeComposition( integer const numComps, - arraySlice1d< real64 > const composition ) + normalizeComposition( numComps, liquidComposition ); + normalizeComposition( numComps, vapourComposition ); + + FugacityCalculator::computeLogFugacity( numComps, + pressure, + temperature, + liquidComposition.toSliceConst(), + componentProperties, + liquidEos, + logLiquidFugacity ); + FugacityCalculator::computeLogFugacity( numComps, + pressure, + temperature, + vapourComposition.toSliceConst(), + componentProperties, + vapourEos, + logVapourFugacity ); + + // Compute fugacity ratios and calculate the error + real64 error = 0.0; + for( integer const ic : presentComponents ) { - real64 totalMoles = 0.0; - for( integer ic = 0; ic < numComps; ++ic ) - { - totalMoles += composition[ic]; - } - real64 const oneOverTotalMoles = 1.0 / (totalMoles + MultiFluidConstants::epsilon); - for( integer ic = 0; ic < numComps; ++ic ) - { - composition[ic] *= oneOverTotalMoles; - } - return totalMoles; + fugacityRatios[ic] = ( logLiquidFugacity[ic] - logVapourFugacity[ic] ) + log( liquidComposition[ic] ) - log( vapourComposition[ic] ); + error += (fugacityRatios[ic]*fugacityRatios[ic]); } -}; + return LvArray::math::sqrt( error ); +} } // namespace compositional diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/RachfordRice.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/RachfordRice.hpp index af7c05bb428..4b997c2c45b 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/RachfordRice.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/RachfordRice.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,6 +22,7 @@ #include "common/DataTypes.hpp" #include "constitutive/fluid/multifluid/MultiFluidConstants.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" namespace geos { @@ -44,36 +46,24 @@ struct RachfordRice /** * @brief Function solving the Rachford-Rice equation - * @input[in] kValues the array fo K-values + * @input[in] kValues the array of K-values * @input[in] feed the component fractions * @input[in] presentComponentIds the indices of components with a non-zero fractions * @return the gas mole fraction **/ + template< integer USD1, integer USD2 > GEOS_HOST_DEVICE real64 static - solve( arraySlice1d< real64 const > const kValues, - arraySlice1d< real64 const > const feed, - arraySlice1d< integer const > const presentComponentIds ) + solve( arraySlice1d< real64 const, USD2 > const & kValues, + arraySlice1d< real64 const, USD1 > const & feed, + arraySlice1d< integer const > const & presentComponentIds ) { real64 gasPhaseMoleFraction = 0; // min and max Kvalues for non-zero composition - real64 maxK = 0.0; - real64 minK = 1 / epsilon; - - for( integer i = 0; i < presentComponentIds.size(); ++i ) - { - integer const ic = presentComponentIds[i]; - if( kValues[ic] > maxK ) - { - maxK = kValues[ic]; - } - if( kValues[ic] < minK ) - { - minK = kValues[ic]; - } - } + real64 minK, maxK; + findKValueRange( kValues, presentComponentIds, minK, maxK ); // check for trivial solutions. // this corresponds to bad Kvalues @@ -179,12 +169,13 @@ struct RachfordRice * @input[in] x the value at which the Rachford-Rice function is evaluated * @return the value of the Rachford-Rice function at x **/ + template< integer USD1, integer USD2 > GEOS_HOST_DEVICE real64 static - evaluate( arraySlice1d< real64 const > const kValues, - arraySlice1d< real64 const > const feed, - arraySlice1d< integer const > const presentComponentIds, + evaluate( arraySlice1d< real64 const, USD2 > const & kValues, + arraySlice1d< real64 const, USD1 > const & feed, + arraySlice1d< integer const > const & presentComponentIds, real64 const & x ) { real64 value = 0.0; @@ -205,12 +196,13 @@ struct RachfordRice * @input[in] x the value at which the derivative of the Rachford-Rice function is evaluated * @return the value of the derivative of the Rachford-Rice function at x **/ + template< integer USD1, integer USD2 > GEOS_HOST_DEVICE real64 static - evaluateDerivative( arraySlice1d< real64 const > const kValues, - arraySlice1d< real64 const > const feed, - arraySlice1d< integer const > const presentComponentIds, + evaluateDerivative( arraySlice1d< real64 const, USD2 > const & kValues, + arraySlice1d< real64 const, USD1 > const & feed, + arraySlice1d< integer const > const & presentComponentIds, real64 const & x ) { real64 value = 0.0; @@ -224,6 +216,38 @@ struct RachfordRice return value; } + /** + * @brief Calculate the minimum and maximum k-value + * @input[in] kValues the array fo K-values + * @input[in] presentComponentIds the indices of components with a non-zero fractions + * @input[out] minK the minimum k-value for non-zero components + * @input[out] maxK the maximum k-value for non-zero components + **/ + template< integer USD > + GEOS_FORCE_INLINE + GEOS_HOST_DEVICE + void + static + findKValueRange( arraySlice1d< real64 const, USD > const & kValues, + arraySlice1d< integer const > const & presentComponentIds, + real64 & minK, + real64 & maxK ) + { + minK = 1.0 / epsilon; + maxK = 0.0; + for( integer const ic : presentComponentIds ) + { + if( kValues[ic] > maxK ) + { + maxK = kValues[ic]; + } + if( kValues[ic] < minK ) + { + minK = kValues[ic]; + } + } + } + }; } // namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/StabilityTest.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/StabilityTest.hpp new file mode 100644 index 00000000000..2317bcfd342 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/functions/StabilityTest.hpp @@ -0,0 +1,227 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StabilityTest.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_FUNCTIONS_STABILITYTEST_HPP_ +#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_FUNCTIONS_STABILITYTEST_HPP_ + +#include "KValueInitialization.hpp" +#include "FugacityCalculator.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "constitutive/fluid/multifluid/MultiFluidConstants.hpp" +#include "constitutive/fluid/multifluid/compositional/models/ComponentProperties.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +struct StabilityTest +{ +private: + static constexpr integer maxNumComps = MultiFluidConstants::MAX_NUM_COMPONENTS; +public: + /** + * @brief Perform a two-phase stability test + * @param[in] numComps number of components + * @param[in] pressure pressure + * @param[in] temperature temperature + * @param[in] composition composition of the mixture + * @param[in] componentProperties The compositional component properties + * @param[in] equationOfState The equation of state + * @param[out] tangentPlaneDistance the minimum tangent plane distance (TPD) + * @param[out] kValues the k-values estimated from the stationary points + * @return a flag indicating that 2 stationary points have been found + */ + template< integer USD1, integer USD2 > + GEOS_HOST_DEVICE + static bool compute( integer const numComps, + real64 const pressure, + real64 const temperature, + arraySlice1d< real64 const, USD1 > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + EquationOfStateType const & equationOfState, + real64 & tangentPlaneDistance, + arraySlice1d< real64, USD2 > const & kValues ) + { + constexpr integer numTrials = 2; // Trial compositions + stackArray2d< real64, 4*maxNumComps > workSpace( 4, numComps ); + arraySlice1d< real64 > logFugacity = workSpace[0]; + arraySlice1d< real64 > normalizedComposition = workSpace[1]; + arraySlice1d< real64 > logTrialComposition = workSpace[2]; + arraySlice1d< real64 > hyperplane = workSpace[3]; // h-parameter + stackArray1d< integer, maxNumComps > availableComponents( numComps ); + + calculatePresentComponents( numComps, composition, availableComponents ); + auto const presentComponents = availableComponents.toSliceConst(); + + LvArray::forValuesInSlice( workSpace.toSlice(), []( real64 & a ){ a = 0.0; } ); + + // Calculate the hyperplane parameter + // h_i = log( z_i ) + log( phi_i ) + FugacityCalculator::computeLogFugacity( numComps, + pressure, + temperature, + composition, + componentProperties, + equationOfState, + logFugacity ); + for( integer const ic : presentComponents ) + { + hyperplane[ic] = LvArray::math::log( composition[ic] ) + logFugacity[ic]; + } + + // Initialise the trial compositions using Wilson k-Values + KValueInitialization::computeWilsonGasLiquidKvalue( numComps, + pressure, + temperature, + componentProperties, + kValues ); + + tangentPlaneDistance = LvArray::NumericLimits< real64 >::max; + for( integer trialIndex = 0; trialIndex < numTrials; ++trialIndex ) + { + // Initialise next sample + real64 const alpha = static_cast< real64 >(trialIndex)/(numTrials-1); + for( integer const ic : presentComponents ) + { + normalizedComposition[ic] = composition[ic]*(alpha * kValues[ic] + (1.0 - alpha) / kValues[ic]); + logTrialComposition[ic] = LvArray::math::log( normalizedComposition[ic] ); + } + + for( localIndex iterationCount = 0; iterationCount < MultiFluidConstants::maxSSIIterations; ++iterationCount ) + { + // Normalise the composition and calculate the fugacity + real64 const totalMoles = normalizeComposition( numComps, normalizedComposition ); + FugacityCalculator::computeLogFugacity( numComps, + pressure, + temperature, + normalizedComposition.toSliceConst(), + componentProperties, + equationOfState, + logFugacity ); + + // Calculate the TPD + real64 tpd = 0.0; + for( integer const ic : presentComponents ) + { + tpd += composition[ic] + totalMoles * normalizedComposition[ic] * (logTrialComposition[ic] + logFugacity[ic] - hyperplane[ic] - 1.0); + } + if( tpd < tangentPlaneDistance ) + { + tangentPlaneDistance = tpd; + } + if( tangentPlaneDistance < -MultiFluidConstants::fugacityTolerance ) + { + break; + } + + // Check stationarity + real64 error = 0.0; + for( integer const ic : presentComponents ) + { + real64 const dG = logTrialComposition[ic] + logFugacity[ic] - hyperplane[ic]; + error += (dG*dG); + } + error = LvArray::math::sqrt( error ); + if( error < MultiFluidConstants::fugacityTolerance ) + { + break; + } + + // Update to next step + for( integer const ic : presentComponents ) + { + logTrialComposition[ic] = hyperplane[ic] - logFugacity[ic]; + normalizedComposition[ic] = LvArray::math::exp( logTrialComposition[ic] ); + } + } + if( tangentPlaneDistance < -MultiFluidConstants::fugacityTolerance ) + { + break; + } + } + return true; + } + +private: + /** + * @brief Calculate which components are present. + * @details Creates a list of indices whose components have non-zero mole fraction. + * @param[in] numComps number of components + * @param[in] composition the composition of the fluid + * @param[out] presentComponents the list of present components + * @return the number of present components + */ + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + static integer calculatePresentComponents( integer const numComps, + arraySlice1d< real64 const > const & composition, + stackArray1d< integer, maxNumComps > & presentComponents ) + { + // Check for machine-zero feed values + integer presentCount = 0; + for( integer ic = 0; ic < numComps; ++ic ) + { + if( MultiFluidConstants::epsilon < composition[ic] ) + { + presentComponents[presentCount++] = ic; + } + } + presentComponents.resize( presentCount ); + return presentCount; + } + + /** + * @brief Normalise a composition in place to ensure that the components add up to unity + * @param[in] numComps number of components + * @param[in/out] composition composition to be normalized + * @return the sum of the given values + */ + template< integer USD > + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + static real64 normalizeComposition( integer const numComps, + arraySlice1d< real64, USD > const & composition ) + { + real64 totalMoles = 0.0; + for( integer ic = 0; ic < numComps; ++ic ) + { + totalMoles += composition[ic]; + } + GEOS_ASSERT( MultiFluidConstants::epsilon < totalMoles ); + real64 const oneOverTotalMoles = 1.0 / totalMoles; + for( integer ic = 0; ic < numComps; ++ic ) + { + composition[ic] *= oneOverTotalMoles; + } + return totalMoles; + } +}; + +} // namespace compositional + +} // namespace constitutive + +} // namespace geos + +#endif //GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_FUNCTIONS_STABILITYTEST_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ComponentProperties.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ComponentProperties.hpp index 2dec4ae3c57..e4a99359228 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ComponentProperties.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ComponentProperties.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -37,21 +38,9 @@ class ComponentProperties final { public: ComponentProperties( string_array const & componentNames, - array1d< real64 > const & componentMolarWeight, - array1d< real64 > const & componentCriticalPressure, - array1d< real64 > const & componentCriticalTemperature, - array1d< real64 > const & componentCriticalVolume, - array1d< real64 > const & componentAcentricFactor, - array1d< real64 > const & componentVolumeShift, - array2d< real64 > const & componentBinaryCoeff ): + array1d< real64 > const & componentMolarWeight ): m_componentNames ( componentNames ), - m_componentMolarWeight ( componentMolarWeight ), - m_componentCriticalPressure ( componentCriticalPressure ), - m_componentCriticalTemperature( componentCriticalTemperature ), - m_componentCriticalVolume( componentCriticalVolume ), - m_componentAcentricFactor( componentAcentricFactor ), - m_componentVolumeShift( componentVolumeShift ), - m_componentBinaryCoeff( componentBinaryCoeff ) + m_componentMolarWeight ( componentMolarWeight ) {} ~ComponentProperties() = default; @@ -64,19 +53,27 @@ class ComponentProperties final */ integer getNumberOfComponents() const { return m_componentNames.size(); } + /** + * Data accessors + */ + arrayView1d< string > const & getComponentName() const { return m_componentNames; } + arrayView1d< real64 > const & getComponentMolarWeight() const { return m_componentMolarWeight; } + arrayView1d< real64 > const & getComponentCriticalPressure() const { return m_componentCriticalPressure; } + arrayView1d< real64 > const & getComponentCriticalTemperature() const { return m_componentCriticalTemperature; } + arrayView1d< real64 > const & getComponentAcentricFactor() const { return m_componentAcentricFactor; } + arrayView1d< real64 > const & getComponentVolumeShift() const { return m_componentVolumeShift; } + struct KernelWrapper { KernelWrapper( arrayView1d< real64 const > const & componentMolarWeight, arrayView1d< real64 const > const & componentCriticalPressure, arrayView1d< real64 const > const & componentCriticalTemperature, - arrayView1d< real64 const > const & componentCriticalVolume, arrayView1d< real64 const > const & componentAcentricFactor, arrayView1d< real64 const > const & componentVolumeShift, arrayView2d< real64 const > const & componentBinaryCoeff ): m_componentMolarWeight ( componentMolarWeight ), m_componentCriticalPressure ( componentCriticalPressure ), m_componentCriticalTemperature( componentCriticalTemperature ), - m_componentCriticalVolume( componentCriticalVolume ), m_componentAcentricFactor( componentAcentricFactor ), m_componentVolumeShift( componentVolumeShift ), m_componentBinaryCoeff( componentBinaryCoeff ) @@ -94,7 +91,6 @@ class ComponentProperties final m_componentMolarWeight.move( space, touch ); m_componentCriticalPressure.move( space, touch ); m_componentCriticalTemperature.move( space, touch ); - m_componentCriticalVolume.move( space, touch ); m_componentAcentricFactor.move( space, touch ); m_componentVolumeShift.move( space, touch ); m_componentBinaryCoeff.move( space, touch ); @@ -104,7 +100,6 @@ class ComponentProperties final arrayView1d< real64 const > m_componentMolarWeight; arrayView1d< real64 const > m_componentCriticalPressure; arrayView1d< real64 const > m_componentCriticalTemperature; - arrayView1d< real64 const > m_componentCriticalVolume; arrayView1d< real64 const > m_componentAcentricFactor; arrayView1d< real64 const > m_componentVolumeShift; arrayView2d< real64 const > m_componentBinaryCoeff; @@ -119,22 +114,20 @@ class ComponentProperties final return KernelWrapper( m_componentMolarWeight, m_componentCriticalPressure, m_componentCriticalTemperature, - m_componentCriticalVolume, m_componentAcentricFactor, m_componentVolumeShift, m_componentBinaryCoeff ); } -private: +public: // Standard compositional input string_array const & m_componentNames; array1d< real64 > const & m_componentMolarWeight; - array1d< real64 > const & m_componentCriticalPressure; - array1d< real64 > const & m_componentCriticalTemperature; - array1d< real64 > const & m_componentCriticalVolume; - array1d< real64 > const & m_componentAcentricFactor; - array1d< real64 > const & m_componentVolumeShift; - array2d< real64 > const & m_componentBinaryCoeff; + array1d< real64 > m_componentCriticalPressure; + array1d< real64 > m_componentCriticalTemperature; + array1d< real64 > m_componentAcentricFactor; + array1d< real64 > m_componentVolumeShift; + array2d< real64 > m_componentBinaryCoeff; }; } // namespace compositional diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/CompositionalDensity.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/CompositionalDensity.cpp index 50a35083871..99802799c43 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/CompositionalDensity.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/CompositionalDensity.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -26,19 +27,52 @@ namespace constitutive namespace compositional { - CompositionalDensity::CompositionalDensity( string const & name, - ComponentProperties const & componentProperties ): - FunctionBase( name, componentProperties ) -{} + ComponentProperties const & componentProperties, + integer const phaseIndex, + ModelParameters const & modelParameters ) + : FunctionBase( name, componentProperties ) +{ + EquationOfState const * equationOfState = modelParameters.get< EquationOfState >(); + string const eosName = equationOfState->m_equationsOfStateNames[phaseIndex]; + m_equationOfState = EnumStrings< EquationOfStateType >::fromString( eosName ); + + // Calculate the dimensional volume shift + m_componentDimensionalVolumeShift.resize( componentProperties.getNumberOfComponents()); + calculateDimensionalVolumeShift( componentProperties, + m_equationOfState, + m_componentDimensionalVolumeShift ); +} CompositionalDensity::KernelWrapper CompositionalDensity::createKernelWrapper() const { - return KernelWrapper(); + return KernelWrapper( m_componentDimensionalVolumeShift, m_equationOfState ); +} + +std::unique_ptr< ModelParameters > +CompositionalDensity::createParameters( std::unique_ptr< ModelParameters > parameters ) +{ + return EquationOfState::create( std::move( parameters ) ); +} + +void CompositionalDensity::calculateDimensionalVolumeShift( ComponentProperties const & componentProperties, + EquationOfStateType const & equationOfState, + arraySlice1d< real64 > componentDimensionalVolumeShift ) +{ + if( equationOfState == EquationOfStateType::PengRobinson ) + { + CubicEOSPhaseModel< PengRobinsonEOS >::calculateDimensionalVolumeShift( componentProperties, + componentDimensionalVolumeShift ); + } + else if( equationOfState == EquationOfStateType::SoaveRedlichKwong ) + { + CubicEOSPhaseModel< SoaveRedlichKwongEOS >::calculateDimensionalVolumeShift( componentProperties, + componentDimensionalVolumeShift ); + } } -} // namespace PVTProps +} // namespace compositional } // namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/CompositionalDensity.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/CompositionalDensity.hpp index 9a7fcf557a1..beb58c14fb2 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/CompositionalDensity.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/CompositionalDensity.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,8 +21,12 @@ #define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_COMPOSITIONALDENSITY_HPP_ #include "FunctionBase.hpp" +#include "EquationOfState.hpp" #include "constitutive/fluid/multifluid/MultiFluidUtils.hpp" +#include "constitutive/fluid/multifluid/MultiFluidConstants.hpp" +#include "constitutive/fluid/multifluid/compositional/functions/CompositionalProperties.hpp" +#include "constitutive/fluid/multifluid/compositional/functions/CubicEOSPhaseModel.hpp" namespace geos { @@ -35,37 +40,48 @@ namespace compositional class CompositionalDensityUpdate final : public FunctionBaseUpdate { public: - CompositionalDensityUpdate() = default; + CompositionalDensityUpdate( arrayView1d< real64 const > const & volumeShift, + EquationOfStateType const equationOfState ) + : m_componentDimensionalVolumeShift( volumeShift ), + m_equationOfState( equationOfState ) + {} - template< int USD1 > + template< integer USD1, integer USD2 > GEOS_HOST_DEVICE void compute( ComponentProperties::KernelWrapper const & componentProperties, real64 const & pressure, real64 const & temperature, arraySlice1d< real64 const, USD1 > const & phaseComposition, real64 & molarDensity, + arraySlice1d< real64, USD2 > const & dMolarDensity, real64 & massDensity, + arraySlice1d< real64, USD2 > const & dMassDensity, bool useMass ) const; - template< int USD1, int USD2, int USD3 > +private: + template< integer USD > GEOS_HOST_DEVICE - void compute( ComponentProperties::KernelWrapper const & componentProperties, - real64 const & pressure, - real64 const & temperature, - arraySlice1d< real64 const, USD1 > const & phaseComposition, - arraySlice2d< real64 const, USD2 > const & dPhaseComposition, - real64 & molarDensity, - arraySlice1d< real64, USD3 > const & dMolarDensity, - real64 & massDensity, - arraySlice1d< real64, USD3 > const & dMassDensity, - bool useMass ) const; + void computeCompressibilityFactor( integer const numComps, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const, USD > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + EquationOfStateType const equationOfState, + real64 & compressibilityFactor, + arraySlice1d< real64 > const & compressibilityFactorDerivs ) const; + +private: + arrayView1d< real64 const > m_componentDimensionalVolumeShift; + EquationOfStateType const m_equationOfState; }; class CompositionalDensity : public FunctionBase { public: CompositionalDensity( string const & name, - ComponentProperties const & componentProperties ); + ComponentProperties const & componentProperties, + integer const phaseIndex, + ModelParameters const & modelParameters ); static string catalogName() { return "CompositionalDensity"; } @@ -82,46 +98,102 @@ class CompositionalDensity : public FunctionBase * @return the wrapper */ KernelWrapper createKernelWrapper() const; + + // Create parameters unique to this model + static std::unique_ptr< ModelParameters > createParameters( std::unique_ptr< ModelParameters > parameters ); + +private: + static void calculateDimensionalVolumeShift( ComponentProperties const & componentProperties, + EquationOfStateType const & equationOfState, + arraySlice1d< real64 > componentDimensionalVolumeShift ); + +private: + array1d< real64 > m_componentDimensionalVolumeShift; + EquationOfStateType m_equationOfState; }; -template< int USD1 > +template< integer USD1, integer USD2 > GEOS_HOST_DEVICE -void CompositionalDensityUpdate::compute( ComponentProperties::KernelWrapper const & componentProperties, - real64 const & pressure, - real64 const & temperature, - arraySlice1d< real64 const, USD1 > const & phaseComposition, - real64 & molarDensity, - real64 & massDensity, - bool useMass ) const +void CompositionalDensityUpdate::compute( + ComponentProperties::KernelWrapper const & componentProperties, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const, USD1 > const & phaseComposition, + real64 & molarDensity, + arraySlice1d< real64, USD2 > const & dMolarDensity, + real64 & massDensity, + arraySlice1d< real64, USD2 > const & dMassDensity, + bool useMass ) const { - GEOS_UNUSED_VAR( componentProperties, pressure, temperature, useMass ); - GEOS_UNUSED_VAR( phaseComposition ); - - massDensity = 1000.0; - molarDensity = massDensity/40.0; + GEOS_UNUSED_VAR( useMass ); + + integer const numComps = componentProperties.m_componentMolarWeight.size(); + integer const numDofs = 2 + numComps; + + real64 compressibilityFactor = 0.0; + stackArray1d< real64, 2+MultiFluidConstants::MAX_NUM_COMPONENTS > tempDerivs( numDofs ); + + computeCompressibilityFactor( numComps, + pressure, + temperature, + phaseComposition, + componentProperties, + m_equationOfState, + compressibilityFactor, + tempDerivs.toSlice() ); + + CompositionalProperties::computeMolarDensity( numComps, + pressure, + temperature, + phaseComposition, + m_componentDimensionalVolumeShift.toSliceConst(), + compressibilityFactor, + tempDerivs.toSlice(), + molarDensity, + dMolarDensity ); + + CompositionalProperties::computeMassDensity( numComps, + phaseComposition, + componentProperties.m_componentMolarWeight.toSliceConst(), + molarDensity, + dMolarDensity.toSliceConst(), + massDensity, + dMassDensity ); } -template< int USD1, int USD2, int USD3 > +template< integer USD > GEOS_HOST_DEVICE -void CompositionalDensityUpdate::compute( ComponentProperties::KernelWrapper const & componentProperties, - real64 const & pressure, - real64 const & temperature, - arraySlice1d< real64 const, USD1 > const & phaseComposition, - arraySlice2d< real64 const, USD2 > const & dPhaseComposition, - real64 & molarDensity, - arraySlice1d< real64, USD3 > const & dMolarDensity, - real64 & massDensity, - arraySlice1d< real64, USD3 > const & dMassDensity, - bool useMass ) const +void CompositionalDensityUpdate::computeCompressibilityFactor( integer const numComps, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const, USD > const & composition, + ComponentProperties::KernelWrapper const & componentProperties, + EquationOfStateType const equationOfState, + real64 & compressibilityFactor, + arraySlice1d< real64 > const & compressibilityFactorDerivs ) const { - GEOS_UNUSED_VAR( componentProperties, pressure, temperature, useMass ); - GEOS_UNUSED_VAR( phaseComposition, dPhaseComposition ); - - massDensity = 1000.0; - molarDensity = massDensity/40.0; - - LvArray::forValuesInSlice( dMolarDensity, setZero ); - LvArray::forValuesInSlice( dMassDensity, setZero ); + if( equationOfState == EquationOfStateType::PengRobinson ) + { + CubicEOSPhaseModel< PengRobinsonEOS >:: + computeCompressibilityFactor( numComps, + pressure, + temperature, + composition, + componentProperties, + compressibilityFactor, + compressibilityFactorDerivs ); + } + else if( equationOfState == EquationOfStateType::SoaveRedlichKwong ) + { + CubicEOSPhaseModel< SoaveRedlichKwongEOS >:: + computeCompressibilityFactor( numComps, + pressure, + temperature, + composition, + componentProperties, + compressibilityFactor, + compressibilityFactorDerivs ); + } } } // end namespace compositional diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ConstantViscosity.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ConstantViscosity.cpp index 6ee6094aa06..a3239a34f21 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ConstantViscosity.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ConstantViscosity.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,6 +18,7 @@ */ #include "ConstantViscosity.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" namespace geos { @@ -28,14 +30,65 @@ namespace compositional { ConstantViscosity::ConstantViscosity( string const & name, - ComponentProperties const & componentProperties ): + ComponentProperties const & componentProperties, + integer const phaseIndex, + ModelParameters const & modelParameters ): FunctionBase( name, componentProperties ) +{ + Parameters const * parameters = modelParameters.get< Parameters >(); + m_constantPhaseViscosity = parameters->m_constantPhaseViscosity[phaseIndex]; +} + +ConstantViscosityUpdate::ConstantViscosityUpdate( real64 const constantPhaseViscosity ): + m_constantPhaseViscosity( constantPhaseViscosity ) {} ConstantViscosity::KernelWrapper ConstantViscosity::createKernelWrapper() const { - return KernelWrapper( ); + return KernelWrapper( m_constantPhaseViscosity ); +} + +std::unique_ptr< ModelParameters > +ConstantViscosity::createParameters( std::unique_ptr< ModelParameters > parameters ) +{ + if( parameters && parameters->get< Parameters >() != nullptr ) + { + return parameters; + } + return std::make_unique< Parameters >( std::move( parameters ) ); +} + +ConstantViscosity::Parameters::Parameters( std::unique_ptr< ModelParameters > parameters ): + ModelParameters( std::move( parameters ) ) +{} + +void ConstantViscosity::Parameters::registerParametersImpl( MultiFluidBase * fluid ) +{ + fluid->registerWrapper( viewKeyStruct::constantPhaseViscosityString(), &m_constantPhaseViscosity ). + setInputFlag( dataRepository::InputFlags::OPTIONAL ). + setDescription( "Constant phase viscosity" ); +} + +void ConstantViscosity::Parameters::postInputInitializationImpl( MultiFluidBase const * fluid, + ComponentProperties const & componentProperties ) +{ + GEOS_UNUSED_VAR( componentProperties ); + + integer const numPhase = fluid->numFluidPhases(); + + if( m_constantPhaseViscosity.empty() ) + { + m_constantPhaseViscosity.resize( numPhase ); + for( integer ip = 0; ip < numPhase; ++ip ) + { + m_constantPhaseViscosity[ip] = ConstantViscosity::defaultViscosity; + } + } + GEOS_THROW_IF_NE_MSG( m_constantPhaseViscosity.size(), numPhase, + GEOS_FMT( "{}: invalid number of values in attribute '{}'", fluid->getFullName(), + viewKeyStruct::constantPhaseViscosityString() ), + InputError ); } } // end namespace compositional diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ConstantViscosity.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ConstantViscosity.hpp index 45a38d28a11..cee73c0ae1c 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ConstantViscosity.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ConstantViscosity.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -33,37 +34,33 @@ namespace compositional class ConstantViscosityUpdate final : public FunctionBaseUpdate { public: - ConstantViscosityUpdate() = default; + explicit ConstantViscosityUpdate( real64 const constantPhaseViscosity ); - template< int USD1 > + template< integer USD1, integer USD2 > GEOS_HOST_DEVICE void compute( ComponentProperties::KernelWrapper const & componentProperties, real64 const & pressure, real64 const & temperature, arraySlice1d< real64 const, USD1 > const & phaseComposition, real64 const & density, + arraySlice1d< real64 const, USD2 > const & dDensity, real64 & viscosity, + arraySlice1d< real64, USD2 > const & dViscosity, bool useMass ) const; - template< int USD1, int USD2, int USD3 > - GEOS_HOST_DEVICE - void compute( ComponentProperties::KernelWrapper const & componentProperties, - real64 const & pressure, - real64 const & temperature, - arraySlice1d< real64 const, USD1 > const & phaseComposition, - arraySlice2d< real64 const, USD2 > const & dPhaseComposition, - real64 const & density, - arraySlice1d< real64 const, USD3 > const & dDensity, - real64 & viscosity, - arraySlice1d< real64, USD3 > const & dViscosity, - bool useMass ) const; +private: + real64 const m_constantPhaseViscosity; }; class ConstantViscosity : public FunctionBase { +public: + static constexpr real64 defaultViscosity = 0.001; public: ConstantViscosity( string const & name, - ComponentProperties const & componentProperties ); + ComponentProperties const & componentProperties, + integer const phaseIndex, + ModelParameters const & modelParameters ); static string catalogName() { return ""; } @@ -80,45 +77,51 @@ class ConstantViscosity : public FunctionBase * @return the wrapper */ KernelWrapper createKernelWrapper() const; -}; -template< int USD1 > -GEOS_HOST_DEVICE -GEOS_FORCE_INLINE -void ConstantViscosityUpdate::compute( ComponentProperties::KernelWrapper const & componentProperties, - real64 const & pressure, - real64 const & temperature, - arraySlice1d< real64 const, USD1 > const & phaseComposition, - real64 const & density, - real64 & viscosity, - bool useMass ) const -{ - GEOS_UNUSED_VAR( componentProperties, pressure, temperature, useMass ); - GEOS_UNUSED_VAR( phaseComposition ); - GEOS_UNUSED_VAR( density ); + // Parameters for constant viscosity model + class Parameters : public ModelParameters + { +public: + Parameters( std::unique_ptr< ModelParameters > parameters ); + ~Parameters() override = default; - viscosity = 0.001; -} + array1d< real64 > m_constantPhaseViscosity; + +private: + void registerParametersImpl( MultiFluidBase * fluid ) override; + void postInputInitializationImpl( MultiFluidBase const * fluid, ComponentProperties const & componentProperties ) override; + + struct viewKeyStruct + { + static constexpr char const * constantPhaseViscosityString() { return "constantPhaseViscosity"; } + }; + }; + + // Create parameters unique to this model + static std::unique_ptr< ModelParameters > createParameters( std::unique_ptr< ModelParameters > parameters ); -template< int USD1, int USD2, int USD3 > +private: + real64 m_constantPhaseViscosity{defaultViscosity}; +}; + +template< integer USD1, integer USD2 > GEOS_HOST_DEVICE GEOS_FORCE_INLINE void ConstantViscosityUpdate::compute( ComponentProperties::KernelWrapper const & componentProperties, real64 const & pressure, real64 const & temperature, arraySlice1d< real64 const, USD1 > const & phaseComposition, - arraySlice2d< real64 const, USD2 > const & dPhaseComposition, real64 const & density, - arraySlice1d< real64 const, USD3 > const & dDensity, + arraySlice1d< real64 const, USD2 > const & dDensity, real64 & viscosity, - arraySlice1d< real64, USD3 > const & dViscosity, + arraySlice1d< real64, USD2 > const & dViscosity, bool useMass ) const { GEOS_UNUSED_VAR( componentProperties, pressure, temperature, useMass ); - GEOS_UNUSED_VAR( phaseComposition, dPhaseComposition ); + GEOS_UNUSED_VAR( phaseComposition ); GEOS_UNUSED_VAR( density, dDensity ); - viscosity = 0.001; + viscosity = m_constantPhaseViscosity; LvArray::forValuesInSlice( dViscosity, setZero ); } diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/CriticalVolume.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/CriticalVolume.cpp new file mode 100644 index 00000000000..95d147af02f --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/CriticalVolume.cpp @@ -0,0 +1,93 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CriticalVolume.cpp + */ + +#include "CriticalVolume.hpp" +#include "ComponentProperties.hpp" + +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +CriticalVolume::CriticalVolume( std::unique_ptr< ModelParameters > parameters ): + ModelParameters( std::move( parameters ) ) +{} + +std::unique_ptr< ModelParameters > CriticalVolume::create( std::unique_ptr< ModelParameters > parameters ) +{ + if( parameters && parameters->get< CriticalVolume >() != nullptr ) + { + return parameters; + } + return std::make_unique< CriticalVolume >( std::move( parameters ) ); +} + +void CriticalVolume::registerParametersImpl( MultiFluidBase * fluid ) +{ + fluid->registerWrapper( viewKeyStruct::componentCriticalVolumeString(), &m_componentCriticalVolume ). + setInputFlag( dataRepository::InputFlags::OPTIONAL ). + setDescription( "Component critical volumes" ); +} + +void CriticalVolume::postInputInitializationImpl( MultiFluidBase const * fluid, + ComponentProperties const & componentProperties ) +{ + integer const numComponents = fluid->numFluidComponents(); + + if( m_componentCriticalVolume.empty() ) + { + m_componentCriticalVolume.resize( numComponents ); + + arrayView1d< real64 > const & componentCriticalPressure = componentProperties.getComponentCriticalPressure(); + arrayView1d< real64 > const & componentCriticalTemperature = componentProperties.getComponentCriticalTemperature(); + + calculateCriticalVolume( numComponents, + componentCriticalPressure, + componentCriticalTemperature, + m_componentCriticalVolume ); + } + + GEOS_THROW_IF_NE_MSG( m_componentCriticalVolume.size(), numComponents, + GEOS_FMT( "{}: invalid number of values in attribute '{}'", fluid->getFullName(), + viewKeyStruct::componentCriticalVolumeString() ), + InputError ); +} + +void CriticalVolume::calculateCriticalVolume( integer const numComponents, + arrayView1d< const real64 > const criticalPressure, + arrayView1d< const real64 > const criticalTemperature, + arrayView1d< real64 > const criticalVolume ) +{ + for( integer ic=0; ic parameters ); + ~CriticalVolume() override = default; + + static std::unique_ptr< ModelParameters > create( std::unique_ptr< ModelParameters > parameters ); + + array1d< real64 > m_componentCriticalVolume; + +protected: + void registerParametersImpl( MultiFluidBase * fluid ) override; + + void postInputInitializationImpl( MultiFluidBase const * fluid, ComponentProperties const & componentProperties ) override; + + struct viewKeyStruct + { + static constexpr char const * componentCriticalVolumeString() { return "componentCriticalVolume"; } + }; + + /** + * @brief Estimate critical volumes using Ihmels' (2010) correlation + * @details reference: http://dx.doi.org/10.1021/je100167w + * @param[in] numComponents The number of components + * @param[in] criticalPressure The component critical pressures + * @param[in] criticalTemperature The component critical temperatures + * @param[in] criticalVolume The component critical volumes + */ + static void calculateCriticalVolume( integer const numComponents, + arrayView1d< const real64 > const criticalPressure, + arrayView1d< const real64 > const criticalTemperature, + arrayView1d< real64 > const criticalVolume ); +}; + +} // end namespace compositional + +} // end namespace constitutive + +} // end namespace geos + +#endif //GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_CRITICALVOLUME_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/EquationOfState.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/EquationOfState.hpp new file mode 100644 index 00000000000..b27dd249318 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/EquationOfState.hpp @@ -0,0 +1,106 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file EquationOfState.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_EQUATIONOFSTATE_HPP_ +#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_EQUATIONOFSTATE_HPP_ + +#include "ModelParameters.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "dataRepository/InputFlags.hpp" +#include "common/format/EnumStrings.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +enum class EquationOfStateType : integer +{ + PengRobinson, + SoaveRedlichKwong +}; + +ENUM_STRINGS( EquationOfStateType, + "pr", + "srk" ); + +class EquationOfState : public ModelParameters +{ +public: + EquationOfState( std::unique_ptr< ModelParameters > parameters ): + ModelParameters( std::move( parameters ) ) + {} + + ~EquationOfState() override = default; + + static std::unique_ptr< ModelParameters > create( std::unique_ptr< ModelParameters > parameters ) + { + if( parameters && parameters->get< EquationOfState >() != nullptr ) + { + return parameters; + } + return std::make_unique< EquationOfState >( std::move( parameters ) ); + } + + struct viewKeyStruct + { + static constexpr char const * equationsOfStateString() { return "equationsOfState"; } + }; + + string_array m_equationsOfStateNames; + +protected: + void registerParametersImpl( MultiFluidBase * fluid ) override + { + fluid->registerWrapper( viewKeyStruct::equationsOfStateString(), &m_equationsOfStateNames ). + setInputFlag( dataRepository::InputFlags::REQUIRED ). + setDescription( "List of equation of state types for each phase. Valid options:\n* " + + EnumStrings< EquationOfStateType >::concat( "\n* " ) ); + } + + void postInputInitializationImpl( MultiFluidBase const * fluid, ComponentProperties const & componentProperties ) override + { + GEOS_UNUSED_VAR( componentProperties ); + + integer const numPhase = fluid->numFluidPhases(); + + GEOS_THROW_IF_NE_MSG( m_equationsOfStateNames.size(), numPhase, + GEOS_FMT( "{}: invalid number of values in attribute '{}'", fluid->getFullName(), + viewKeyStruct::equationsOfStateString() ), + InputError ); + + // If any value is invalid conversion will throw + for( string const & eos : m_equationsOfStateNames ) + { + EnumStrings< EquationOfStateType >::fromString( eos ); + } + } +}; + +} // end namespace compositional + +} // end namespace constitutive + +} // end namespace geos + +#endif //GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_EQUATIONOFSTATE_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/FunctionBase.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/FunctionBase.hpp index 3ccb6c97f8a..2bb0299e24c 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/FunctionBase.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/FunctionBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,9 +20,8 @@ #ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_FUNCTIONBASE_HPP_ #define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_FUNCTIONBASE_HPP_ -#include "dataRepository/ObjectCatalog.hpp" - #include "ComponentProperties.hpp" +#include "ModelParameters.hpp" namespace geos { @@ -83,6 +83,12 @@ class FunctionBase virtual FunctionType functionType() const = 0; + // Create parameters unique to this model + static std::unique_ptr< ModelParameters > createParameters( std::unique_ptr< ModelParameters > parameters ) + { + return parameters; + } + protected: /// Name of the PVT function string m_functionName; diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterDensity.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterDensity.cpp new file mode 100644 index 00000000000..22bb8d40b9d --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterDensity.cpp @@ -0,0 +1,82 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ImmiscibleWaterDensity.cpp + */ + +#include "ImmiscibleWaterDensity.hpp" +#include "ImmiscibleWaterParameters.hpp" +#include "dataRepository/InputFlags.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +ImmiscibleWaterDensityUpdate::ImmiscibleWaterDensityUpdate( real64 const waterMolecularWeight, + real64 const referencePressure, + real64 const referenceTemperature, + real64 const density, + real64 const compressibility, + real64 const expansionCoefficient ): + m_waterMolecularWeight( waterMolecularWeight ), + m_referencePressure( referencePressure ), + m_referenceTemperature( referenceTemperature ), + m_density( density ), + m_compressibility( compressibility ), + m_expansionCoefficient( expansionCoefficient ) +{} + +ImmiscibleWaterDensity::ImmiscibleWaterDensity( string const & name, + ComponentProperties const & componentProperties, + integer const phaseIndex, + ModelParameters const & modelParameters ): + FunctionBase( name, componentProperties ), + m_parameters( modelParameters ) +{ + GEOS_UNUSED_VAR( phaseIndex ); + integer const h2oIndex = ImmiscibleWaterParameters::getWaterComponentIndex( componentProperties ); + GEOS_THROW_IF_LT_MSG( h2oIndex, 0, "Water component not found", InputError ); + m_waterMolecularWeight = componentProperties.getComponentMolarWeight()[h2oIndex]; +} + +ImmiscibleWaterDensity::KernelWrapper +ImmiscibleWaterDensity::createKernelWrapper() const +{ + ImmiscibleWaterParameters const * waterParameters = m_parameters.get< ImmiscibleWaterParameters >(); + return KernelWrapper( m_waterMolecularWeight, + waterParameters->m_waterReferencePressure, + waterParameters->m_waterReferenceTemperature, + waterParameters->m_waterDensity, + waterParameters->m_waterCompressibility, + waterParameters->m_waterExpansionCoefficient ); +} + +std::unique_ptr< ModelParameters > +ImmiscibleWaterDensity::createParameters( std::unique_ptr< ModelParameters > parameters ) +{ + return ImmiscibleWaterParameters::create( std::move( parameters ) ); +} + +} // namespace compositional + +} // namespace constitutive + +} // namespace geos diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterDensity.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterDensity.hpp new file mode 100644 index 00000000000..8afadca5bbf --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterDensity.hpp @@ -0,0 +1,140 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ImmiscibleWaterDensity.cpp + */ + +#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_IMMISCIBLEWATERDENSITY_HPP_ +#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_IMMISCIBLEWATERDENSITY_HPP_ + +#include "FunctionBase.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +class ImmiscibleWaterDensityUpdate final : public FunctionBaseUpdate +{ + using Deriv = geos::constitutive::multifluid::DerivativeOffset; +public: + ImmiscibleWaterDensityUpdate( real64 const waterMolecularWeight, + real64 const referencePressure, + real64 const referenceTemperature, + real64 const density, + real64 const compressibility, + real64 const expansionCoefficient ); + + template< integer USD1, integer USD2 > + GEOS_HOST_DEVICE + void compute( ComponentProperties::KernelWrapper const & componentProperties, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const, USD1 > const & phaseComposition, + real64 & molarDensity, + arraySlice1d< real64, USD2 > const & dMolarDensity, + real64 & massDensity, + arraySlice1d< real64, USD2 > const & dMassDensity, + bool useMass ) const; + +private: + real64 const m_waterMolecularWeight; + real64 const m_referencePressure; + real64 const m_referenceTemperature; + real64 const m_density; + real64 const m_compressibility; + real64 const m_expansionCoefficient; +}; + +class ImmiscibleWaterDensity : public FunctionBase +{ +public: + ImmiscibleWaterDensity( string const & name, + ComponentProperties const & componentProperties, + integer const phaseIndex, + ModelParameters const & modelParameters ); + + static string catalogName() { return "ImmiscibleWaterDensity"; } + + virtual FunctionType functionType() const override + { + return FunctionType::DENSITY; + } + + /// Type of kernel wrapper for in-kernel update + using KernelWrapper = ImmiscibleWaterDensityUpdate; + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelWrapper() const; + + // Create parameters unique to this model + static std::unique_ptr< ModelParameters > createParameters( std::unique_ptr< ModelParameters > parameters ); + +private: + ModelParameters const & m_parameters; + real64 m_waterMolecularWeight{0.0}; +}; + +template< integer USD1, integer USD2 > +GEOS_HOST_DEVICE +void ImmiscibleWaterDensityUpdate::compute( + ComponentProperties::KernelWrapper const & componentProperties, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const, USD1 > const & phaseComposition, + real64 & molarDensity, + arraySlice1d< real64, USD2 > const & dMolarDensity, + real64 & massDensity, + arraySlice1d< real64, USD2 > const & dMassDensity, + bool useMass ) const +{ + GEOS_UNUSED_VAR( componentProperties ); + GEOS_UNUSED_VAR( phaseComposition ); + GEOS_UNUSED_VAR( useMass ); + + LvArray::forValuesInSlice( dMolarDensity, setZero ); + LvArray::forValuesInSlice( dMassDensity, setZero ); + + real64 const density = m_density * + LvArray::math::exp( m_compressibility * (pressure - m_referencePressure) ) * + LvArray::math::exp( -m_expansionCoefficient * (temperature - m_referenceTemperature) ); + real64 const dDensity_dp = m_compressibility * density; + real64 const dDensity_dT = -m_expansionCoefficient * density; + + massDensity = density; + dMassDensity[Deriv::dP] = dDensity_dp; + dMassDensity[Deriv::dT] = dDensity_dT; + + molarDensity = density / m_waterMolecularWeight; + dMolarDensity[Deriv::dP] = dDensity_dp / m_waterMolecularWeight; + dMolarDensity[Deriv::dT] = dDensity_dT / m_waterMolecularWeight; +} + +} // end namespace compositional + +} // end namespace constitutive + +} // end namespace geos + +#endif //GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_IMMISCIBLEWATERDENSITY_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterFlashModel.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterFlashModel.cpp new file mode 100644 index 00000000000..d095bcf0df8 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterFlashModel.cpp @@ -0,0 +1,104 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ImmiscibleWaterFlashModel.cpp + */ + +#include "ImmiscibleWaterFlashModel.hpp" +#include "ImmiscibleWaterParameters.hpp" +#include "EquationOfState.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +// Naming conventions +string ImmiscibleWaterFlashModel::catalogName() +{ + return "ThreePhase"; +} + +ImmiscibleWaterFlashModel::ImmiscibleWaterFlashModel( string const & name, + ComponentProperties const & componentProperties, + ModelParameters const & modelParameters ): + FunctionBase( name, componentProperties ), + m_parameters( modelParameters ) +{ + m_waterComponentIndex = ImmiscibleWaterParameters::getWaterComponentIndex( componentProperties ); +} + +ImmiscibleWaterFlashModel::KernelWrapper +ImmiscibleWaterFlashModel::createKernelWrapper() const +{ + constexpr integer liquidIndex = 0; + constexpr integer vapourIndex = 1; + constexpr integer aqueousIndex = 2; + EquationOfState const * equationOfState = m_parameters.get< EquationOfState >(); + EquationOfStateType const liquidEos = EnumStrings< EquationOfStateType >::fromString( equationOfState->m_equationsOfStateNames[liquidIndex] ); + EquationOfStateType const vapourEos = EnumStrings< EquationOfStateType >::fromString( equationOfState->m_equationsOfStateNames[vapourIndex] ); + + array1d< real64 > componentCriticalVolume( m_componentProperties.getNumberOfComponents()); + + return KernelWrapper( m_componentProperties.getNumberOfComponents(), + liquidIndex, + vapourIndex, + aqueousIndex, + m_waterComponentIndex, + liquidEos, + vapourEos, + componentCriticalVolume ); +} + +ImmiscibleWaterFlashModelUpdate::ImmiscibleWaterFlashModelUpdate( + integer const numComponents, + integer const liquidIndex, + integer const vapourIndex, + integer const aqueousIndex, + integer const waterComponentIndex, + EquationOfStateType const liquidEos, + EquationOfStateType const vapourEos, + arrayView1d< real64 const > const componentCriticalVolume ): + m_twoPhaseModel( numComponents, + liquidIndex, + vapourIndex, + liquidEos, + vapourEos, + componentCriticalVolume ), + m_numComponents( numComponents ), + m_liquidIndex( liquidIndex ), + m_vapourIndex( vapourIndex ), + m_aquoesIndex( aqueousIndex ), + m_waterComponentIndex( waterComponentIndex ) +{} + +std::unique_ptr< ModelParameters > +ImmiscibleWaterFlashModel::createParameters( std::unique_ptr< ModelParameters > parameters ) +{ + auto params = NegativeTwoPhaseFlashModel::createParameters( std::move( parameters ) ); + params = ImmiscibleWaterParameters::create( std::move( params ) ); + return params; +} + +} // end namespace compositional + +} // namespace constitutive + +} // end namespace geos diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterFlashModel.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterFlashModel.hpp new file mode 100644 index 00000000000..d154b45d97f --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterFlashModel.hpp @@ -0,0 +1,212 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ImmiscibleWaterFlashModel.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_IMMISCIBLEWATERFLASHMODEL_HPP_ +#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_IMMISCIBLEWATERFLASHMODEL_HPP_ + +#include "FunctionBase.hpp" +#include "EquationOfState.hpp" + +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "constitutive/fluid/multifluid/MultiFluidUtils.hpp" +#include "NegativeTwoPhaseFlashModel.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +class ModelParameters; + +class ImmiscibleWaterFlashModelUpdate final : public FunctionBaseUpdate +{ +private: + static constexpr integer maxNumComps = MultiFluidConstants::MAX_NUM_COMPONENTS; +public: + + using PhaseProp = NegativeTwoPhaseFlashModelUpdate::PhaseProp; + using PhaseComp = NegativeTwoPhaseFlashModelUpdate::PhaseComp; + using Deriv = multifluid::DerivativeOffset; + + ImmiscibleWaterFlashModelUpdate( integer const numComponents, + integer const liquidIndex, + integer const vapourIndex, + integer const aqueousIndex, + integer const waterComponentIndex, + EquationOfStateType const liquidEos, + EquationOfStateType const vapourEos, + arrayView1d< real64 const > const componentCriticalVolume ); + + // Mark as a 3-phase flash + GEOS_HOST_DEVICE + static constexpr integer getNumberOfPhases() { return 3; } + + template< int USD1, int USD2 > + GEOS_HOST_DEVICE + void compute( ComponentProperties::KernelWrapper const & componentProperties, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const, USD1 > const & compFraction, + arraySlice2d< real64, USD2 > const & kValues, + PhaseProp::SliceType const phaseFraction, + PhaseComp::SliceType const phaseCompFraction ) const; + +private: + template< int USD > + GEOS_FORCE_INLINE + GEOS_HOST_DEVICE + void convertCompositionDerivatives( real64 const hcMoleFraction, + arraySlice1d< real64 const > const & composition, + arraySlice1d< real64, USD > const & derivatives ) const + { + real64 dvdzi = 0.0; + for( integer ic = 0; ic < m_numComponents; ++ic ) + { + dvdzi += derivatives[Deriv::dC+ic] * composition[ic]; + } + for( integer ic = 0; ic < m_numComponents; ++ic ) + { + derivatives[Deriv::dC+ic] /= hcMoleFraction; + } + derivatives[Deriv::dC+m_waterComponentIndex] = dvdzi / hcMoleFraction; + } + +private: + NegativeTwoPhaseFlashModel::KernelWrapper const m_twoPhaseModel; + integer const m_numComponents; + integer const m_liquidIndex; + integer const m_vapourIndex; + integer const m_aquoesIndex; + integer const m_waterComponentIndex; +}; + +class ImmiscibleWaterFlashModel : public FunctionBase +{ +public: + ImmiscibleWaterFlashModel( string const & name, + ComponentProperties const & componentProperties, + ModelParameters const & modelParameters ); + + static string catalogName(); + + FunctionType functionType() const override + { + return FunctionType::FLASH; + } + + /// Type of kernel wrapper for in-kernel update + using KernelWrapper = ImmiscibleWaterFlashModelUpdate; + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelWrapper() const; + + // Create parameters unique to this model + static std::unique_ptr< ModelParameters > createParameters( std::unique_ptr< ModelParameters > parameters ); + +private: + ModelParameters const & m_parameters; + integer m_waterComponentIndex{-1}; +}; + +template< int USD1, int USD2 > +GEOS_HOST_DEVICE +void ImmiscibleWaterFlashModelUpdate::compute( ComponentProperties::KernelWrapper const & componentProperties, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const, USD1 > const & compFraction, + arraySlice2d< real64, USD2 > const & kValues, + PhaseProp::SliceType const phaseFraction, + PhaseComp::SliceType const phaseCompFraction ) const +{ + LvArray::forValuesInSlice( phaseFraction.value, setZero ); + LvArray::forValuesInSlice( phaseFraction.derivs, setZero ); + LvArray::forValuesInSlice( phaseCompFraction.value, setZero ); + LvArray::forValuesInSlice( phaseCompFraction.derivs, setZero ); + + // Water phase + phaseFraction.value[m_aquoesIndex] = compFraction[m_waterComponentIndex]; + phaseFraction.derivs( m_aquoesIndex, Deriv::dC + m_waterComponentIndex ) = 1.0; + phaseCompFraction.value( m_aquoesIndex, m_waterComponentIndex ) = 1.0; + + // Total hydrocarbon mole fraction + real64 const z_hc = 1.0 - compFraction[m_waterComponentIndex]; + + if( z_hc < MultiFluidConstants::minForSpeciesPresence ) + { + // Single phase water + real64 const constantComposition = 1.0 / (m_numComponents - 1); + for( integer ic = 0; ic < m_numComponents; ++ic ) + { + phaseCompFraction.value( m_liquidIndex, ic ) = constantComposition; + phaseCompFraction.value( m_vapourIndex, ic ) = constantComposition; + } + phaseCompFraction.value( m_liquidIndex, m_waterComponentIndex ) = 0.0; + phaseCompFraction.value( m_vapourIndex, m_waterComponentIndex ) = 0.0; + } + else + { + // Hydrocarbon phases + + // Calculate normalised hyrdocarbon composition + stackArray1d< real64, maxNumComps > composition( m_numComponents ); + for( integer ic = 0; ic < m_numComponents; ++ic ) + { + composition[ic] = compFraction[ic] / z_hc; + } + composition[m_waterComponentIndex] = 0.0; + + // Perform negative two-phase flash + m_twoPhaseModel.compute( componentProperties, + pressure, + temperature, + composition.toSliceConst(), + kValues, + phaseFraction, + phaseCompFraction ); + + for( integer const phaseIndex : {m_liquidIndex, m_vapourIndex} ) + { + real64 const v = phaseFraction.value[phaseIndex]; + phaseFraction.value[phaseIndex] *= z_hc; + LvArray::forValuesInSlice( phaseFraction.derivs[phaseIndex], [&]( real64 & a ){ a *= z_hc; } ); + convertCompositionDerivatives( z_hc, composition.toSliceConst(), phaseFraction.derivs[phaseIndex] ); + phaseFraction.derivs( phaseIndex, Deriv::dC+m_waterComponentIndex ) = -v; + + for( integer ic = 0; ic < m_numComponents; ++ic ) + { + convertCompositionDerivatives( z_hc, composition.toSliceConst(), phaseCompFraction.derivs[phaseIndex][ic] ); + } + } + } +} + +} // end namespace compositional + +} // end namespace constitutive + +} // end namespace geos + +#endif //GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_IMMISCIBLEWATERFLASHMODEL_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterParameters.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterParameters.cpp new file mode 100644 index 00000000000..217b5ad54ae --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterParameters.cpp @@ -0,0 +1,141 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ImmiscibleWaterParameters.cpp + */ + +#include "ImmiscibleWaterParameters.hpp" +#include "ComponentProperties.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "dataRepository/InputFlags.hpp" +#include "common/format/StringUtilities.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +ImmiscibleWaterParameters::ImmiscibleWaterParameters( std::unique_ptr< ModelParameters > parameters ): + ModelParameters( std::move( parameters ) ) +{} + +std::unique_ptr< ModelParameters > +ImmiscibleWaterParameters::create( std::unique_ptr< ModelParameters > parameters ) +{ + if( parameters && parameters->get< ImmiscibleWaterParameters >() != nullptr ) + { + return parameters; + } + return std::make_unique< ImmiscibleWaterParameters >( std::move( parameters ) ); +} + +integer ImmiscibleWaterParameters::getWaterComponentIndex( ComponentProperties const & componentProperties ) +{ + auto componentNames = componentProperties.getComponentName(); + integer const numComps = componentNames.size(); + for( integer ic = 0; ic < numComps; ++ic ) + { + string const compName = stringutilities::toLower( componentNames[ic] ); + if( compName == waterComponentName ) + { + return ic; + } + } + return -1; +} + +void ImmiscibleWaterParameters::registerParametersImpl( MultiFluidBase * fluid ) +{ + fluid->registerWrapper( viewKeyStruct::waterReferencePressureString(), &m_waterReferencePressure ). + setInputFlag( dataRepository::InputFlags::REQUIRED ). + setDescription( "The reference pressure for water density and viscosity" ); + + fluid->registerWrapper( viewKeyStruct::waterReferenceTemperatureString(), &m_waterReferenceTemperature ). + setInputFlag( dataRepository::InputFlags::OPTIONAL ). + setDefaultValue( m_waterReferenceTemperature ). + setDescription( "The reference temperature for water density and viscosity" ); + + fluid->registerWrapper( viewKeyStruct::waterDensityString(), &m_waterDensity ). + setInputFlag( dataRepository::InputFlags::REQUIRED ). + setDescription( "The water density at the reference pressure and temperature" ); + + fluid->registerWrapper( viewKeyStruct::waterViscosityString(), &m_waterViscosity ). + setInputFlag( dataRepository::InputFlags::REQUIRED ). + setDescription( "The water viscosity at the reference pressure and temperature" ); + + fluid->registerWrapper( viewKeyStruct::waterCompressibilityString(), &m_waterCompressibility ). + setInputFlag( dataRepository::InputFlags::REQUIRED ). + setDescription( "The compressibility of water" ); + + fluid->registerWrapper( viewKeyStruct::waterViscosityCompressibilityString(), &m_waterViscosityCompressibility ). + setInputFlag( dataRepository::InputFlags::OPTIONAL ). + setDefaultValue( m_waterViscosityCompressibility ). + setDescription( "The compressibility (normalized derivative with respect to pressure) of the water viscosity" ); + + fluid->registerWrapper( viewKeyStruct::waterExpansionCoefficientString(), &m_waterExpansionCoefficient ). + setInputFlag( dataRepository::InputFlags::OPTIONAL ). + setDefaultValue( m_waterExpansionCoefficient ). + setDescription( "The volumetric coefficient of thermal expansion of water" ); + + fluid->registerWrapper( viewKeyStruct::waterViscosityExpansionCoefficientString(), &m_waterViscosityExpansionCoefficient ). + setInputFlag( dataRepository::InputFlags::OPTIONAL ). + setDefaultValue( m_waterViscosityExpansionCoefficient ). + setDescription( "The coefficient of thermal expansion (normalized derivative with respect to temperature) of water viscosity" ); +} + +void ImmiscibleWaterParameters::postInputInitializationImpl( MultiFluidBase const * fluid, + ComponentProperties const & componentProperties ) +{ + integer const waterIndex = fluid->getWaterPhaseIndex(); + GEOS_THROW_IF_LT_MSG( waterIndex, 0, + GEOS_FMT( "{}: water phase not found '{}'", fluid->getFullName(), + MultiFluidBase::viewKeyStruct::phaseNamesString() ), + InputError ); + + integer const h2oIndex = getWaterComponentIndex( componentProperties ); + GEOS_THROW_IF_LT_MSG( h2oIndex, 0, + GEOS_FMT( "{}: water component not found '{}'", fluid->getFullName(), + MultiFluidBase::viewKeyStruct::componentNamesString() ), + InputError ); + + // Pretty much everything should be positive + auto const checkLowerBound = [&]( real64 const & value, real64 const & bound, string const & attribute ) + { + GEOS_THROW_IF_LT_MSG( value, bound, + GEOS_FMT( "{}: invalid number of value in attribute '{}'. Should be greater than {}", + fluid->getFullName(), bound, attribute ), + InputError ); + }; + + real64 constexpr epsilon = MultiFluidConstants::epsilon; + + checkLowerBound( m_waterDensity, epsilon, viewKeyStruct::waterDensityString()); + checkLowerBound( m_waterViscosity, epsilon, viewKeyStruct::waterViscosityString()); + checkLowerBound( m_waterCompressibility, 0.0, viewKeyStruct::waterCompressibilityString()); + checkLowerBound( m_waterViscosityCompressibility, 0.0, viewKeyStruct::waterViscosityCompressibilityString()); + checkLowerBound( m_waterExpansionCoefficient, 0.0, viewKeyStruct::waterExpansionCoefficientString()); + checkLowerBound( m_waterViscosityExpansionCoefficient, 0.0, viewKeyStruct::waterViscosityExpansionCoefficientString()); +} + +} // end namespace compositional + +} // end namespace constitutive + +} // end namespace geos diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterParameters.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterParameters.hpp new file mode 100644 index 00000000000..76242ba5ed4 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterParameters.hpp @@ -0,0 +1,80 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ImmiscibleWaterParameters.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_IMMISCIBLEWATERPARAMETERS_HPP_ +#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_IMMISCIBLEWATERPARAMETERS_HPP_ + +#include "ModelParameters.hpp" +#include "common/DataTypes.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +class ImmiscibleWaterParameters : public ModelParameters +{ + static constexpr char const * waterComponentName = "h2o"; + +public: + ImmiscibleWaterParameters( std::unique_ptr< ModelParameters > parameters ); + ~ImmiscibleWaterParameters() override = default; + + static std::unique_ptr< ModelParameters > create( std::unique_ptr< ModelParameters > parameters ); + + static integer getWaterComponentIndex( ComponentProperties const & componentProperties ); + + struct viewKeyStruct + { + static constexpr char const * waterReferencePressureString() { return "waterReferencePressure"; } + static constexpr char const * waterReferenceTemperatureString() { return "waterReferenceTemperature"; } + static constexpr char const * waterDensityString() { return "waterDensity"; } + static constexpr char const * waterViscosityString() { return "waterViscosity"; } + static constexpr char const * waterCompressibilityString() { return "waterCompressibility"; } + static constexpr char const * waterViscosityCompressibilityString() { return "waterViscosityCompressibility"; } + static constexpr char const * waterExpansionCoefficientString() { return "waterExpansionCoefficient"; } + static constexpr char const * waterViscosityExpansionCoefficientString() { return "waterViscosityExpansionCoefficient"; } + }; + + real64 m_waterReferencePressure; + real64 m_waterReferenceTemperature{293.15}; + real64 m_waterDensity; + real64 m_waterViscosity; + real64 m_waterCompressibility; + real64 m_waterViscosityCompressibility{0.0}; + real64 m_waterExpansionCoefficient{0.0}; + real64 m_waterViscosityExpansionCoefficient{0.0}; + +protected: + void registerParametersImpl( MultiFluidBase * fluid ) override; + + void postInputInitializationImpl( MultiFluidBase const * fluid, ComponentProperties const & componentProperties ) override; +}; + +} // end namespace compositional + +} // end namespace constitutive + +} // end namespace geos + +#endif //GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_IMMISCIBLEWATERPARAMETERS_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterViscosity.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterViscosity.cpp new file mode 100644 index 00000000000..37d070a1a46 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterViscosity.cpp @@ -0,0 +1,75 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ImmiscibleWaterViscosity.cpp + */ + +#include "ImmiscibleWaterViscosity.hpp" +#include "ImmiscibleWaterParameters.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +ImmiscibleWaterViscosityUpdate::ImmiscibleWaterViscosityUpdate( real64 const referencePressure, + real64 const referenceTemperature, + real64 const viscosity, + real64 const compressibility, + real64 const expansionCoefficient ): + m_referencePressure( referencePressure ), + m_referenceTemperature( referenceTemperature ), + m_viscosity( viscosity ), + m_compressibility( compressibility ), + m_expansionCoefficient( expansionCoefficient ) +{} + +ImmiscibleWaterViscosity::ImmiscibleWaterViscosity( string const & name, + ComponentProperties const & componentProperties, + integer const phaseIndex, + ModelParameters const & modelParameters ): + FunctionBase( name, componentProperties ), + m_parameters( modelParameters ) +{ + GEOS_UNUSED_VAR( phaseIndex ); +} + +ImmiscibleWaterViscosity::KernelWrapper +ImmiscibleWaterViscosity::createKernelWrapper() const +{ + ImmiscibleWaterParameters const * waterParameters = m_parameters.get< ImmiscibleWaterParameters >(); + return KernelWrapper( waterParameters->m_waterReferencePressure, + waterParameters->m_waterReferenceTemperature, + waterParameters->m_waterViscosity, + waterParameters->m_waterViscosityCompressibility, + waterParameters->m_waterViscosityExpansionCoefficient ); +} + +std::unique_ptr< ModelParameters > +ImmiscibleWaterViscosity::createParameters( std::unique_ptr< ModelParameters > parameters ) +{ + return ImmiscibleWaterParameters::create( std::move( parameters ) ); +} + +} // namespace compositional + +} // namespace constitutive + +} // end namespace geos diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterViscosity.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterViscosity.hpp new file mode 100644 index 00000000000..453589962e4 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterViscosity.hpp @@ -0,0 +1,130 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ImmiscibleWaterViscosity.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_IMMISCIBLEWATERVISCOSITY_HPP_ +#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_IMMISCIBLEWATERVISCOSITY_HPP_ + +#include "FunctionBase.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +class ImmiscibleWaterViscosityUpdate final : public FunctionBaseUpdate +{ + using Deriv = geos::constitutive::multifluid::DerivativeOffset; +public: + ImmiscibleWaterViscosityUpdate( real64 const referencePressure, + real64 const referenceTemperature, + real64 const viscosity, + real64 const compressibility, + real64 const expansionCoefficient ); + + template< integer USD1, integer USD2 > + GEOS_HOST_DEVICE + void compute( ComponentProperties::KernelWrapper const & componentProperties, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const, USD1 > const & phaseComposition, + real64 const & density, + arraySlice1d< real64 const, USD2 > const & dDensity, + real64 & viscosity, + arraySlice1d< real64, USD2 > const & dViscosity, + bool useMass ) const; + +private: + real64 const m_referencePressure; + real64 const m_referenceTemperature; + real64 const m_viscosity; + real64 const m_compressibility; + real64 const m_expansionCoefficient; +}; + +class ImmiscibleWaterViscosity : public FunctionBase +{ +public: + ImmiscibleWaterViscosity( string const & name, + ComponentProperties const & componentProperties, + integer const phaseIndex, + ModelParameters const & modelParameters ); + + static string catalogName() { return ""; } + + FunctionType functionType() const override + { + return FunctionType::VISCOSITY; + } + + /// Type of kernel wrapper for in-kernel update + using KernelWrapper = ImmiscibleWaterViscosityUpdate; + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelWrapper() const; + + // Create parameters unique to this model + static std::unique_ptr< ModelParameters > createParameters( std::unique_ptr< ModelParameters > parameters ); + +private: + ModelParameters const & m_parameters; +}; + +template< integer USD1, integer USD2 > +GEOS_HOST_DEVICE +GEOS_FORCE_INLINE +void ImmiscibleWaterViscosityUpdate::compute( ComponentProperties::KernelWrapper const & componentProperties, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const, USD1 > const & phaseComposition, + real64 const & density, + arraySlice1d< real64 const, USD2 > const & dDensity, + real64 & viscosity, + arraySlice1d< real64, USD2 > const & dViscosity, + bool useMass ) const +{ + GEOS_UNUSED_VAR( componentProperties ); + GEOS_UNUSED_VAR( phaseComposition ); + GEOS_UNUSED_VAR( density ); + GEOS_UNUSED_VAR( dDensity ); + GEOS_UNUSED_VAR( useMass ); + + LvArray::forValuesInSlice( dViscosity, setZero ); + + viscosity = m_viscosity * + LvArray::math::exp( m_compressibility * (pressure - m_referencePressure) ) * + LvArray::math::exp( -m_expansionCoefficient * (temperature - m_referenceTemperature) ); + dViscosity[Deriv::dP] = m_compressibility * viscosity; + dViscosity[Deriv::dT] = -m_expansionCoefficient * viscosity; +} + +} // end namespace compositional + +} // end namespace constitutive + +} // end namespace geos + +#endif //GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_IMMISCIBLEWATERVISCOSITY_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/LohrenzBrayClarkViscosity.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/LohrenzBrayClarkViscosity.cpp new file mode 100644 index 00000000000..fc06c82a949 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/LohrenzBrayClarkViscosity.cpp @@ -0,0 +1,98 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file LohrenzBrayClarkViscosity.cpp + */ + +#include "LohrenzBrayClarkViscosity.hpp" +#include "CriticalVolume.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "constitutive/fluid/multifluid/MultiFluidConstants.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +LohrenzBrayClarkViscosityUpdate::LohrenzBrayClarkViscosityUpdate( MixingType const mixing_type, + arrayView1d< real64 const > const & componentCriticalVolume ) + : m_mixing_type( mixing_type ), + m_componentCriticalVolume( componentCriticalVolume ) +{} + +LohrenzBrayClarkViscosity::LohrenzBrayClarkViscosity( string const & name, + ComponentProperties const & componentProperties, + integer const phaseIndex, + ModelParameters const & modelParameters ): + FunctionBase( name, componentProperties ), + m_parameters( modelParameters ) +{ + GEOS_UNUSED_VAR( phaseIndex ); +} + +LohrenzBrayClarkViscosity::KernelWrapper +LohrenzBrayClarkViscosity::createKernelWrapper() const +{ + Parameters const * parameters = m_parameters.get< Parameters >(); + CriticalVolume const * criticalVolume = m_parameters.get< CriticalVolume >(); + auto const mixingType = EnumStrings< LohrenzBrayClarkViscosityUpdate::MixingType >::fromString( parameters->m_componentMixingType ); + return KernelWrapper( mixingType, criticalVolume->m_componentCriticalVolume ); +} + +std::unique_ptr< ModelParameters > +LohrenzBrayClarkViscosity::createParameters( std::unique_ptr< ModelParameters > parameters ) +{ + if( parameters && parameters->get< Parameters >() != nullptr ) + { + return parameters; + } + return std::make_unique< Parameters >( CriticalVolume::create( std::move( parameters )) ); +} + +LohrenzBrayClarkViscosity::Parameters::Parameters( std::unique_ptr< ModelParameters > parameters ): + ModelParameters( std::move( parameters ) ) +{ + constexpr LohrenzBrayClarkViscosityUpdate::MixingType defaultMixing = LohrenzBrayClarkViscosityUpdate::MixingType::HERNING_ZIPPERER; + m_componentMixingType = EnumStrings< LohrenzBrayClarkViscosityUpdate::MixingType >::toString( defaultMixing ); +} + +void LohrenzBrayClarkViscosity::Parameters::registerParametersImpl( MultiFluidBase * fluid ) +{ + fluid->registerWrapper( viewKeyStruct::componentMixingTypeString(), &m_componentMixingType ). + setInputFlag( dataRepository::InputFlags::OPTIONAL ). + setApplyDefaultValue( m_componentMixingType ). + setDescription( "Viscosity mixing rule to be used for Lohrenz-Bray-Clark computation. Valid options:\n* " + + EnumStrings< LohrenzBrayClarkViscosityUpdate::MixingType >::concat( "\n* " ) ); +} + +void LohrenzBrayClarkViscosity::Parameters::postInputInitializationImpl( MultiFluidBase const * fluid, + ComponentProperties const & componentProperties ) +{ + GEOS_UNUSED_VAR( fluid, componentProperties ); + // If the value is invalid, this will throw + EnumStrings< LohrenzBrayClarkViscosityUpdate::MixingType >::fromString( m_componentMixingType ); +} + +} // end namespace compositional + +} // namespace constitutive + +} // end namespace geos diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/LohrenzBrayClarkViscosity.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/LohrenzBrayClarkViscosity.hpp new file mode 100644 index 00000000000..bf9a47c70f0 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/LohrenzBrayClarkViscosity.hpp @@ -0,0 +1,334 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file LohrenzBrayClarkViscosity.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_LOHRENZBRAYCLARKVISCOSITY_HPP_ +#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_LOHRENZBRAYCLARKVISCOSITY_HPP_ + +#include "FunctionBase.hpp" + +#include "common/format/EnumStrings.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +class ModelParameters; + +class LohrenzBrayClarkViscosityUpdate final : public FunctionBaseUpdate +{ +public: +/** + * @brief Mixing types for phase viscosity + */ + enum class MixingType : integer + { + HERNING_ZIPPERER, + WILKE, + BROKAW + }; + +public: + LohrenzBrayClarkViscosityUpdate( MixingType const mixing_type, + arrayView1d< real64 const > const & componentCriticalVolume ); + + template< integer USD1, integer USD2 > + GEOS_HOST_DEVICE + void compute( ComponentProperties::KernelWrapper const & componentProperties, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const, USD1 > const & phaseComposition, + real64 const & density, + arraySlice1d< real64 const, USD2 > const & dDensity, + real64 & viscosity, + arraySlice1d< real64, USD2 > const & dViscosity, + bool useMass ) const; + + GEOS_HOST_DEVICE + void setMixingType( MixingType const mixing_type ) + { + m_mixing_type = mixing_type; + } + +private: + /** + * @brief Estimate pure component properties at dilute-gas conditions + * @details This estimates pure component properties at dilute-gas conditions (pressure near atmospheric) using + * Stiel and Thodos [1961] correlation: https://doi.org/10.1002/aic.690070416 + * Dilute viscosity is solely temperature dependent + * Units are converted so componentViscosity is in centipoise to match original reference + * @param[in] numComponents The number of components + * @param[in] componentProperties Physical properties of the components + * @param[in] temperature The temperature + * @param[out] componentDiluteViscosity The compoment dilute viscosity + * @param[out] dComponentDiluteViscosity_dTemperature The derivatives of compoment dilute viscosity w.r.t. temperature + */ + GEOS_HOST_DEVICE + void computeComponentDiluteViscosity_StielThodos( integer const numComponents, + ComponentProperties::KernelWrapper const & componentProperties, + real64 const temperature, + arraySlice1d< real64 > const componentDiluteViscosity, + arraySlice1d< real64 > const dComponentDiluteViscosity_dTemperature ) const + { + for( integer ic = 0; ic < numComponents; ++ic ) + { + real64 const criticalPressure = componentProperties.m_componentCriticalPressure[ic]; + real64 const criticalTemperature = componentProperties.m_componentCriticalTemperature[ic]; + real64 const molarWeight = componentProperties.m_componentMolarWeight[ic]; + + real64 reducedTemperature = temperature / criticalTemperature; + real64 inverseComponentChi = 0.0; + real64 discardDerivative = 0.0; + inverseChiParameter( criticalPressure, criticalTemperature, molarWeight, inverseComponentChi, + discardDerivative, discardDerivative, discardDerivative ); + + if( molarWeight < 2.1e-3 ) // hydrogen correlation, Stiel & Thodos, 1961, Eq. 12 + { + componentDiluteViscosity[ic] = 90.71e-5 * pow( 0.1375*temperature - 1.67, 0.625 ); + dComponentDiluteViscosity_dTemperature[ic] = 90.71e-5 * 0.625 * 0.1375 * pow( 0.1375*temperature - 1.67, -0.375 ); + } + else if( reducedTemperature <= 1.5 ) // nonpolar gas correlation at low temp, Eq. 9 + { + componentDiluteViscosity[ic] = 34e-5 * pow( reducedTemperature, 0.94 ) * inverseComponentChi; + dComponentDiluteViscosity_dTemperature[ic] = 34e-5 * 0.94 * pow( reducedTemperature, -0.06 ) * inverseComponentChi / criticalTemperature; + } + else // nonpolar gas correlation at high temp, Eq. 10 + { + componentDiluteViscosity[ic] = 17.78e-5 * pow( 4.58*reducedTemperature-1.67, 0.625 ) * inverseComponentChi; + dComponentDiluteViscosity_dTemperature[ic] = 17.78e-5 * 4.58 * 0.625 * pow( 4.58*reducedTemperature-1.67, -0.375 ) * inverseComponentChi / criticalTemperature; + } + } + } + + /** + * @brief Estimate phase viscosity at dilute-gas conditions using Herning and Zipperer [1936] + * @details This estimates the phase viscosity properties at dilute-gas conditions (pressure near atmospheric) using + * Herning and Zipperer [1936] mixing rule. + * Herning, F. and Zipperer, L,: “Calculation of the Viscosity of Technical Gas Mixtures from the + * Viscosity of Individual Gases, german”, Gas u. Wasserfach (1936) 79, No. 49, 69. + * @param[in] numComponents The number of components + * @param[in] componentProperties Physical properties of the components + * @param[in] temperature The temperature + * @param[in] phaseComposition The composition of the phase + * @param[in] componentDiluteViscosity The compoment dilute viscosity + * @param[in] dComponentDiluteViscosity_dTemperature The derivatives of compoment dilute viscosity w.r.t. temperature + * @param[out] phaseViscosity The phase viscosity + * @param[out] dPhaseViscosity The phase viscosity derivatives + */ + template< integer USD1, integer USD2 > + GEOS_HOST_DEVICE + void computePhaseDiluteViscosity_HerningZipperer( integer const numComponents, + ComponentProperties::KernelWrapper const & componentProperties, + real64 const temperature, + arraySlice1d< real64 const, USD1 > const & phaseComposition, + arraySlice1d< real64 const > const & componentDiluteViscosity, + arraySlice1d< real64 const > const & dComponentDiluteViscosity_dTemperature, + real64 & phaseViscosity, + arraySlice1d< real64, USD2 > const & dPhaseViscosity ) const; + + /** + * @brief Estimate phase viscosity at dilute-gas conditions using Wilke [1950] + * @details This estimates the phase viscosity properties at dilute-gas conditions (pressure near atmospheric) using + * Wilke [1950] mixing rule. https://doi.org/10.1063/1.1747673 + * @param[in] numComponents The number of components + * @param[in] componentProperties Physical properties of the components + * @param[in] temperature The temperature + * @param[in] phaseComposition The composition of the phase + * @param[in] componentDiluteViscosity The compoment dilute viscosity + * @param[in] dComponentDiluteViscosity_dTemperature The derivatives of compoment dilute viscosity w.r.t. temperature + * @param[out] phaseViscosity The phase viscosity + * @param[out] dPhaseViscosity The phase viscosity derivatives + */ + template< integer USD1, integer USD2 > + GEOS_HOST_DEVICE + void computePhaseDiluteViscosity_Wilke( integer const numComponents, + ComponentProperties::KernelWrapper const & componentProperties, + real64 const temperature, + arraySlice1d< real64 const, USD1 > const & phaseComposition, + arraySlice1d< real64 const > const & componentDiluteViscosity, + arraySlice1d< real64 const > const & dComponentDiluteViscosity_dTemperature, + real64 & phaseViscosity, + arraySlice1d< real64, USD2 > const & dPhaseViscosity ) const; + + /** + * @brief Estimate phase viscosity at dilute-gas conditions using Brokaw[1968] + * @details This estimates the phase viscosity properties at dilute-gas conditions (pressure near atmospheric) using + * Brokaw[1968] mixing rule. + * Brokaw, R. S. (1968). Viscosity of Gas Mixtures. United States: National Aeronautics and Space Administration. + * @param[in] numComponents The number of components + * @param[in] componentProperties Physical properties of the components + * @param[in] temperature The temperature + * @param[in] phaseComposition The composition of the phase + * @param[in] componentDiluteViscosity The compoment dilute viscosity + * @param[in] dComponentDiluteViscosity_dTemperature The derivatives of compoment dilute viscosity w.r.t. temperature + * @param[out] phaseViscosity The phase viscosity + * @param[out] dPhaseViscosity The phase viscosity derivatives + */ + template< integer USD1, integer USD2 > + GEOS_HOST_DEVICE + void computePhaseDiluteViscosity_Brokaw( integer const numComponents, + ComponentProperties::KernelWrapper const & componentProperties, + real64 const temperature, + arraySlice1d< real64 const, USD1 > const & phaseComposition, + arraySlice1d< real64 const > const & componentDiluteViscosity, + arraySlice1d< real64 const > const & dComponentDiluteViscosity_dTemperature, + real64 & phaseViscosity, + arraySlice1d< real64, USD2 > const & dPhaseViscosity ) const; + + /** + * @brief Estimates phase viscosity using Lohrenz, Bray & Clark [1964] + * @details This estimates the phase viscosity at given (P,T) conditions using the Lohrenz, Bray & Clark [1964] correlation. + * This is an additional term added to the dilute gas estimate. + * https://doi.org/10.2118/915-PA + * @param[in] numComponents The number of components + * @param[in] componentProperties Physical properties of the components + * @param[in] phaseComposition The composition of the phase + * @param[in] phaseDensity The phase density + * @param[in] dPhaseDensity The derivatives of the phase density + * @param[out] phaseViscosity The phase viscosity + * @param[out] dPhaseViscosity The phase viscosity derivatives + */ + template< integer USD1, integer USD2 > + GEOS_HOST_DEVICE + void computePhaseViscosity_LohrenzBrayClark( integer const numComponents, + ComponentProperties::KernelWrapper const & componentProperties, + arraySlice1d< real64 const, USD1 > const & phaseComposition, + real64 const phaseDensity, + arraySlice1d< real64 const, USD2 > const & dPhaseDensity, + real64 & phaseViscosity, + arraySlice1d< real64, USD2 > const & dPhaseViscosity ) const; + + /** + * @brief Computes inverse chi parameter + * @details Computes "1/chi" parameter (inverse of the viscosity-reducing parameter) from [ST 1961, LBC 1964]. + * Using units of (K, atm, amu). + * @param[in] criticalPressure The component critical pressure + * @param[in] criticalTemperature The component critical temperature + * @param[in] molarWeight The component molar weight + * @param[out] value The inverse chi parameter + * @param[out] derivP Derivative of the inverse chi parameter w.r.t. pressure + * @param[out] derivT Derivative of the inverse chi parameter w.r.t. temperature + * @param[out] derivM Derivative of the inverse chi parameter w.r.t. molar weight + */ + GEOS_HOST_DEVICE + void inverseChiParameter( real64 const criticalPressure, + real64 const criticalTemperature, + real64 const molarWeight, + real64 & value, + real64 & derivP, + real64 & derivT, + real64 & derivM ) const + { + real64 T = pow( criticalTemperature, 1.0/6.0 ); + real64 dT = (1.0/6.0) * pow( criticalTemperature, -5.0/6.0 ); + + real64 constexpr sqrt1000 = 31.6227766017; // note: kg/mol to atomic mass units + real64 M = sqrt1000 * sqrt( molarWeight ); + real64 dM = 0.5 * sqrt1000 / sqrt( molarWeight ); + + real64 P = pow( criticalPressure / PA_TO_ATM, 2.0/3.0 ); // note: pascal to atm conversion + real64 dP = pow( PA_TO_ATM, -2.0/3.0 ) * pow( criticalPressure, -1.0/3.0 ) * 2.0/3.0; + + value = M*P/T; + derivP = M*dP/T; + derivT = -M*P*dT/(T*T); + derivM = dM*P/T; + } + +private: + MixingType m_mixing_type; + arrayView1d< real64 const > m_componentCriticalVolume; + +private: + // Conversion factor from cP to Pa.s + static constexpr real64 CP_TO_PAS = 1.0e-3; + // Conversion from Pa to atm + static constexpr real64 PA_TO_ATM = 1.01325e+5; +}; + +class LohrenzBrayClarkViscosity : public FunctionBase +{ +public: + LohrenzBrayClarkViscosity( string const & name, + ComponentProperties const & componentProperties, + integer const phaseIndex, + ModelParameters const & modelParameters ); + + static string catalogName() { return "LohrenzBrayClark"; } + + FunctionType functionType() const override + { + return FunctionType::VISCOSITY; + } + + /// Type of kernel wrapper for in-kernel update + using KernelWrapper = LohrenzBrayClarkViscosityUpdate; + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelWrapper() const; + + // Parameters for the LBC viscosity model + class Parameters : public ModelParameters + { +public: + Parameters( std::unique_ptr< ModelParameters > parameters ); + ~Parameters() override = default; + + string m_componentMixingType; + +private: + void registerParametersImpl( MultiFluidBase * fluid ) override; + void postInputInitializationImpl( MultiFluidBase const * fluid, ComponentProperties const & componentProperties ) override; + + struct viewKeyStruct + { + static constexpr char const * componentMixingTypeString() { return "viscosityMixingRule"; } + }; + }; + + // Create parameters unique to this model + static std::unique_ptr< ModelParameters > createParameters( std::unique_ptr< ModelParameters > parameters ); + +private: + ModelParameters const & m_parameters; +}; + +/// Declare strings associated with enumeration values. +ENUM_STRINGS( LohrenzBrayClarkViscosityUpdate::MixingType, + "HerningZipperer", + "Wilke", + "Brokaw" ); + +} // end namespace compositional + +} // end namespace constitutive + +} // end namespace geos + +// Implementation +#include "LohrenzBrayClarkViscosityImpl.hpp" + +#endif //GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_LOHRENZBRAYCLARKVISCOSITY_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/LohrenzBrayClarkViscosityImpl.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/LohrenzBrayClarkViscosityImpl.hpp new file mode 100644 index 00000000000..590da10921d --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/LohrenzBrayClarkViscosityImpl.hpp @@ -0,0 +1,409 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file LohrenzBrayClarkViscosityImpl.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_LOHRENZBRAYCLARKVISCOSITYIMPL_HPP_ +#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_LOHRENZBRAYCLARKVISCOSITYIMPL_HPP_ + +#include "LohrenzBrayClarkViscosity.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "constitutive/fluid/multifluid/MultiFluidConstants.hpp" + +namespace geos +{ + +namespace constitutive +{ + +namespace compositional +{ + +template< integer USD1, integer USD2 > +GEOS_HOST_DEVICE +void LohrenzBrayClarkViscosityUpdate::compute( ComponentProperties::KernelWrapper const & componentProperties, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const, USD1 > const & phaseComposition, + real64 const & density, + arraySlice1d< real64 const, USD2 > const & dDensity, + real64 & viscosity, + arraySlice1d< real64, USD2 > const & dViscosity, + bool useMass ) const +{ + GEOS_UNUSED_VAR( pressure ); // No-direct pressure dependence (instead through density) + GEOS_UNUSED_VAR( useMass ); + + integer constexpr maxNumComps = MultiFluidConstants::MAX_NUM_COMPONENTS; + integer constexpr maxNumDofs = MultiFluidConstants::MAX_NUM_COMPONENTS + 2; + integer const numComponents = componentProperties.m_componentMolarWeight.size(); + integer const numDofs = numComponents + 2; + + // Space for temporary variable derivatives + stackArray1d< real64, maxNumDofs > tempDerivs( numDofs ); + + // Estimate pure component properties at dilute-gas conditions (pressure near atmospheric) using + // Stiel and Thodos [1961] correlation: https://doi.org/10.1002/aic.690070416 + // Dilute viscosity is solely temperature dependent + // Units are converted so componentViscosity is in centipoise to match original reference + + stackArray1d< real64, maxNumComps > componentDiluteViscosity( numComponents ); + + computeComponentDiluteViscosity_StielThodos( numComponents, + componentProperties, + temperature, + componentDiluteViscosity, + tempDerivs ); + + // Estimate phase viscosity (in cp) at dilute gas conditions using either + // the Herning and Zipperer [1936], Wilke [1950], or Brokaw[1968] mixture rule. + // The classic LBC model uses Herning-Zipperer, but the other two may be more accurate. + + if( m_mixing_type == MixingType::HERNING_ZIPPERER ) + { + computePhaseDiluteViscosity_HerningZipperer( numComponents, + componentProperties, + temperature, + phaseComposition, + componentDiluteViscosity, + tempDerivs, + viscosity, + dViscosity ); + } + else if( m_mixing_type == MixingType::WILKE ) + { + computePhaseDiluteViscosity_Wilke( numComponents, + componentProperties, + temperature, + phaseComposition, + componentDiluteViscosity, + tempDerivs, + viscosity, + dViscosity ); + } + else if( m_mixing_type == MixingType::BROKAW ) + { + computePhaseDiluteViscosity_Brokaw( numComponents, + componentProperties, + temperature, + phaseComposition, + componentDiluteViscosity, + tempDerivs, + viscosity, + dViscosity ); + } + + // Estimate phase viscosity at given (P,T) conditions using LBC [1964] correlation. + // This is an additional term added to the dilute gas estimate above. + computePhaseViscosity_LohrenzBrayClark( numComponents, + componentProperties, + phaseComposition, + density, + dDensity, + viscosity, + dViscosity ); + + // Scale centipoise to pascal.seconds + viscosity *= CP_TO_PAS; + for( integer kc = 0; kc < numDofs; ++kc ) + { + dViscosity[kc] *= CP_TO_PAS; + } +} + +template< integer USD1, integer USD2 > +GEOS_HOST_DEVICE +void LohrenzBrayClarkViscosityUpdate::computePhaseDiluteViscosity_HerningZipperer( integer const numComponents, + ComponentProperties::KernelWrapper const & componentProperties, + real64 const temperature, + arraySlice1d< real64 const, USD1 > const & phaseComposition, + arraySlice1d< real64 const > const & componentDiluteViscosity, + arraySlice1d< real64 const > const & dComponentDiluteViscosity_dTemperature, + real64 & phaseViscosity, + arraySlice1d< real64, USD2 > const & dPhaseViscosity ) const +{ + using Deriv = constitutive::multifluid::DerivativeOffset; + GEOS_UNUSED_VAR( temperature ); + + real64 A = 0.0; + real64 dA_dT = 0.0; + real64 B = 0.0; + + for( integer ic = 0; ic < numComponents; ++ic ) + { + real64 const sqrtMolarWeight = sqrt( componentProperties.m_componentMolarWeight[ic] ); + A += phaseComposition[ic] * sqrtMolarWeight * componentDiluteViscosity[ic]; + B += phaseComposition[ic] * sqrtMolarWeight; + dA_dT += phaseComposition[ic] * sqrtMolarWeight * dComponentDiluteViscosity_dTemperature[ic]; + } + + phaseViscosity = A/B; + dPhaseViscosity[Deriv::dP] = 0.0; + dPhaseViscosity[Deriv::dT] = dA_dT/B; + + for( integer ic = 0; ic < numComponents; ++ic ) + { + real64 const sqrtMolarWeight = sqrt( componentProperties.m_componentMolarWeight[ic] ); + real64 const dA_dxi = sqrtMolarWeight * componentDiluteViscosity[ic]; + real64 const dB_dxi = sqrtMolarWeight; + dPhaseViscosity[Deriv::dC+ic] = dA_dxi / B - A * dB_dxi / (B * B); + } +} + +template< integer USD1, integer USD2 > +GEOS_HOST_DEVICE +void LohrenzBrayClarkViscosityUpdate::computePhaseDiluteViscosity_Wilke( integer const numComponents, + ComponentProperties::KernelWrapper const & componentProperties, + real64 const temperature, + arraySlice1d< real64 const, USD1 > const & phaseComposition, + arraySlice1d< real64 const > const & componentDiluteViscosity, + arraySlice1d< real64 const > const & dComponentDiluteViscosity_dTemperature, + real64 & phaseViscosity, + arraySlice1d< real64, USD2 > const & dPhaseViscosity ) const +{ + using Deriv = constitutive::multifluid::DerivativeOffset; + GEOS_UNUSED_VAR( temperature ); + + // compute the "phi" interaction matrix (and its temperature derivatives) + integer constexpr maxNumComps = MultiFluidConstants::MAX_NUM_COMPONENTS; + stackArray2d< real64, maxNumComps *maxNumComps > phi( numComponents, numComponents ); + stackArray2d< real64, maxNumComps *maxNumComps > dPhi_dT( numComponents, numComponents ); + + LvArray::forValuesInSlice( phi.toSlice(), setZero ); + LvArray::forValuesInSlice( dPhi_dT.toSlice(), setZero ); + + for( integer ic = 0; ic < numComponents; ++ic ) + { + for( integer jc = 0; jc < numComponents; ++jc ) + { + real64 const mw_i = componentProperties.m_componentMolarWeight[ic]; + real64 const mw_j = componentProperties.m_componentMolarWeight[jc]; + + real64 const weightRatio = mw_i / mw_j; + + real64 const invVisc_j = 1.0 / componentDiluteViscosity[jc]; + real64 const viscosityRatio = componentDiluteViscosity[ic] * invVisc_j; + + real64 const dViscosityRatio_dT = dComponentDiluteViscosity_dTemperature[ic] * invVisc_j + - componentDiluteViscosity[ic] * dComponentDiluteViscosity_dTemperature[jc] * invVisc_j * invVisc_j; + + real64 const A = 1.0 + sqrt( viscosityRatio )*pow( weightRatio, -0.25 ); + real64 const dA_dT = 0.5*pow( weightRatio, -0.25 )/sqrt( viscosityRatio )*dViscosityRatio_dT; + + real64 const B = A*A; + real64 const dB_dT = 2.0*A*dA_dT; + real64 const C = sqrt( 8.0 )*sqrt( 1.0 + weightRatio ); + + phi( ic, jc ) = B/C; + dPhi_dT( ic, jc ) = dB_dT/C; + } + } + + // compute phase viscosity via Wilke mixing rule + + phaseViscosity = 0; + LvArray::forValuesInSlice( dPhaseViscosity, setZero ); + + for( integer ic = 0; ic < numComponents; ++ic ) + { + real64 A = 0; + real64 dA_dT = 0; + + for( integer jc = 0; jc < numComponents; ++jc ) + { + A += phi( ic, jc )*phaseComposition[jc]; + dA_dT += dPhi_dT( ic, jc )*phaseComposition[jc]; + } + + phaseViscosity += phaseComposition[ic] * componentDiluteViscosity[ic] / A; + dPhaseViscosity[Deriv::dT] += phaseComposition[ic] * dComponentDiluteViscosity_dTemperature[ic] / A + - phaseComposition[ic] * componentDiluteViscosity[ic] / (A*A) * dA_dT; + + dPhaseViscosity[Deriv::dC+ic] += componentDiluteViscosity[ic] / A; + + // the following is some tricky loop merging. the derivatives for other components "jc" will depend on the value of A + // computed above for component "ic", so we add these entries for other derivatives immediately. + + for( integer jc = 0; jc < numComponents; ++jc ) + { + dPhaseViscosity[Deriv::dC+jc] -= phaseComposition[ic] * componentDiluteViscosity[ic] / (A*A) * phi( ic, jc ); + } + } +} + +template< integer USD1, integer USD2 > +GEOS_HOST_DEVICE +void LohrenzBrayClarkViscosityUpdate::computePhaseDiluteViscosity_Brokaw( integer const numComponents, + ComponentProperties::KernelWrapper const & componentProperties, + real64 const temperature, + arraySlice1d< real64 const, USD1 > const & phaseComposition, + arraySlice1d< real64 const > const & componentDiluteViscosity, + arraySlice1d< real64 const > const & dComponentDiluteViscosity_dTemperature, + real64 & phaseViscosity, + arraySlice1d< real64, USD2 > const & dPhaseViscosity ) const +{ + using Deriv = constitutive::multifluid::DerivativeOffset; + GEOS_UNUSED_VAR( temperature ); + + // Compute the "phi" interaction matrix (constant, as only function of molecular weights) + integer constexpr maxNumComps = MultiFluidConstants::MAX_NUM_COMPONENTS; + stackArray2d< real64, maxNumComps *maxNumComps > phi( numComponents, numComponents ); + + LvArray::forValuesInSlice( phi.toSlice(), setZero ); + + for( integer ic = 0; ic < numComponents; ++ic ) + { + for( integer jc = 0; jc < ic; ++jc ) + { + real64 const mw_i = componentProperties.m_componentMolarWeight[ic]; + real64 const mw_j = componentProperties.m_componentMolarWeight[jc]; + real64 const A = mw_i / mw_j; + real64 const B = pow( 4.0*mw_i*mw_j/((mw_i+mw_j)*(mw_i+mw_j)), 0.25 ); + real64 const A45 = pow( A, 0.45 ); + + phi( ic, jc ) = B/sqrt( A ) * (1.0 + (A-A45)/(2.0 + 2.0*A + B*(1+A45) / (1+B))); + phi( jc, ic ) = phi( ic, jc ); + } + phi( ic, ic ) = 1.0; + } + + phaseViscosity = 0.0; + LvArray::forValuesInSlice( dPhaseViscosity, setZero ); + + for( integer ic = 0; ic < numComponents; ++ic ) + { + real64 A = 0; + real64 dA_dT = 0; + + for( integer jc = 0; jc < numComponents; ++jc ) + { + real64 const aij = phi( ic, jc )*phaseComposition[jc] / sqrt( componentDiluteViscosity[jc] ); + A += aij; + dA_dT -= 0.5*aij*dComponentDiluteViscosity_dTemperature[jc] / componentDiluteViscosity[jc]; + } + + real64 const sqrtComponentDiluteViscosity = sqrt( componentDiluteViscosity[ic] ); + phaseViscosity += phaseComposition[ic] * sqrtComponentDiluteViscosity / A; + + dPhaseViscosity[Deriv::dT] += 0.5*phaseComposition[ic] / sqrtComponentDiluteViscosity * dComponentDiluteViscosity_dTemperature[ic] / A + - phaseComposition[ic] * sqrtComponentDiluteViscosity / (A*A) * dA_dT; + + dPhaseViscosity[Deriv::dC+ic] += sqrtComponentDiluteViscosity / A; + + // the following is some tricky loop merging. the derivatives for other components "jc" will depend on the value of A + // computed above for component "ic", so we add these entries for other derivatives immediately. + + for( integer jc = 0; jc < numComponents; ++jc ) + { + dPhaseViscosity[Deriv::dC+jc] -= phaseComposition[ic] * phi( ic, jc ) * sqrt( componentDiluteViscosity[ic]/componentDiluteViscosity[jc] ) / (A*A); + } + } +} + +template< integer USD1, integer USD2 > +GEOS_HOST_DEVICE +void LohrenzBrayClarkViscosityUpdate::computePhaseViscosity_LohrenzBrayClark( integer const numComponents, + ComponentProperties::KernelWrapper const & componentProperties, + arraySlice1d< real64 const, USD1 > const & phaseComposition, + real64 const phaseDensity, + arraySlice1d< real64 const, USD2 > const & dPhaseDensity, + real64 & phaseViscosity, + arraySlice1d< real64, USD2 > const & dPhaseViscosity ) const +{ + using Deriv = constitutive::multifluid::DerivativeOffset; + // Compute phase pseudo properties via Kay's mixing rule + real64 phaseCriticalPressure = 0.0; + real64 phaseCriticalTemperature = 0.0; + real64 phaseCriticalVolume = 0.0; + real64 phaseMolarWeight = 0.0; + + auto const & criticalPressure = componentProperties.m_componentCriticalPressure; + auto const & criticalTemperature = componentProperties.m_componentCriticalTemperature; + auto const & criticalVolume = m_componentCriticalVolume; + auto const & molarWeight = componentProperties.m_componentMolarWeight; + + for( integer ic = 0; ic < numComponents; ++ic ) + { + phaseCriticalPressure += phaseComposition[ic] * criticalPressure[ic]; + phaseCriticalTemperature += phaseComposition[ic] * criticalTemperature[ic]; + phaseCriticalVolume += phaseComposition[ic] * criticalVolume[ic]; + phaseMolarWeight += phaseComposition[ic] * molarWeight[ic]; + } + + // Compute LBC polynomial + + real64 reducedDensity = phaseDensity * phaseCriticalVolume / phaseMolarWeight; + real64 inversePhaseChi, dInversePhaseChi_dPc, dInversePhaseChi_dTc, dInversePhaseChi_dMw; + + inverseChiParameter( phaseCriticalPressure, + phaseCriticalTemperature, + phaseMolarWeight, + inversePhaseChi, + dInversePhaseChi_dPc, + dInversePhaseChi_dTc, + dInversePhaseChi_dMw ); + + real64 polynomialOne = 0.1023000 + + 0.0233640*reducedDensity + + 0.0585330*pow( reducedDensity, 2 ) + - 0.0407580*pow( reducedDensity, 3 ) + + 0.0093324*pow( reducedDensity, 4 ); + + real64 polynomialTwo = pow( polynomialOne, 4.0 ) - 1.0e-4; + + // add polynomial contribution to dilute term to get final phase viscosity + + phaseViscosity += polynomialTwo * inversePhaseChi; + + // get derivatives, noting phaseDensity is a function of (pressure, temperature, composition) + // and inversePhaseChi is a function of composition. + // these derivatives are *added* to the ones already present from the dilute terms above. + + real64 dPolynomialOne_dReducedDensity = 0.0233640 + + 0.1170660*reducedDensity + - 0.1222740*pow( reducedDensity, 2 ) + + 0.0373296*pow( reducedDensity, 3 ); + real64 dPolynomialTwo_dReducedDensity = 4.0 * pow( polynomialOne, 3.0 ) * dPolynomialOne_dReducedDensity; + + real64 dViscosity_dDensity = dPolynomialTwo_dReducedDensity * inversePhaseChi * phaseCriticalVolume / phaseMolarWeight; + real64 dViscosity_dCriticalRatio = dPolynomialTwo_dReducedDensity * inversePhaseChi * phaseDensity; + + real64 dViscosity_dPc = polynomialTwo * dInversePhaseChi_dPc; + real64 dViscosity_dTc = polynomialTwo * dInversePhaseChi_dTc; + real64 dViscosity_dMw = polynomialTwo * dInversePhaseChi_dMw - dViscosity_dCriticalRatio * phaseCriticalVolume / pow( phaseMolarWeight, 2 ); + real64 dViscosity_dVc = dViscosity_dCriticalRatio / phaseMolarWeight; + + dPhaseViscosity[Deriv::dP] += dViscosity_dDensity * dPhaseDensity[Deriv::dP]; + dPhaseViscosity[Deriv::dT] += dViscosity_dDensity * dPhaseDensity[Deriv::dT]; + + for( integer ic = 0; ic < numComponents; ++ic ) + { + dPhaseViscosity[Deriv::dC+ic] += dViscosity_dDensity * dPhaseDensity[Deriv::dC+ic] + + dViscosity_dPc * criticalPressure[ic] + + dViscosity_dTc * criticalTemperature[ic] + + dViscosity_dMw * molarWeight[ic] + + dViscosity_dVc * criticalVolume[ic]; + } +} + +} // end namespace compositional + +} // namespace constitutive + +} // end namespace geos + +#endif //GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_LOHRENZBRAYCLARKVISCOSITYIMPL_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ModelParameters.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ModelParameters.hpp new file mode 100644 index 00000000000..3cc6f0a4333 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/ModelParameters.hpp @@ -0,0 +1,96 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ModelParameters.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_MODELPARAMETERS_HPP_ +#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_MODELPARAMETERS_HPP_ + +#include +#include "common/GeosxMacros.hpp" + +namespace geos +{ + +namespace constitutive +{ + +class MultiFluidBase; + +namespace compositional +{ + +class ComponentProperties; + +class ModelParameters +{ +public: + ModelParameters( std::unique_ptr< ModelParameters > parameters = nullptr ): baseParameters( std::move( parameters ) ) {} + virtual ~ModelParameters() = default; + + void registerParameters( MultiFluidBase * fluid ) + { + registerParametersImpl( fluid ); + if( baseParameters ) + { + baseParameters->registerParameters( fluid ); + } + } + + void postInputInitialization( MultiFluidBase const * fluid, ComponentProperties const & componentProperties ) + { + postInputInitializationImpl( fluid, componentProperties ); + if( baseParameters ) + { + baseParameters->postInputInitialization( fluid, componentProperties ); + } + } + + template< typename PARAMETERS > + PARAMETERS const * get() const + { + PARAMETERS const * parameters = dynamic_cast< PARAMETERS const * >(this); + if( parameters == nullptr && baseParameters ) + { + return baseParameters->get< PARAMETERS >(); + } + return parameters; + } + +private: + virtual void registerParametersImpl( MultiFluidBase * fluid ) + { + GEOS_UNUSED_VAR( fluid ); + } + + virtual void postInputInitializationImpl( MultiFluidBase const * fluid, ComponentProperties const & componentProperties ) + { + GEOS_UNUSED_VAR( fluid ); + GEOS_UNUSED_VAR( componentProperties ); + } + +private: + std::unique_ptr< ModelParameters > baseParameters{}; +}; + +} // end namespace compositional + +} // end namespace constitutive + +} // end namespace geos + +#endif //GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_MODELPARAMETERS_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/NegativeTwoPhaseFlashModel.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/NegativeTwoPhaseFlashModel.cpp index 48048202020..16a39c39e23 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/NegativeTwoPhaseFlashModel.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/NegativeTwoPhaseFlashModel.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,6 +18,8 @@ */ #include "NegativeTwoPhaseFlashModel.hpp" +#include "EquationOfState.hpp" +#include "CriticalVolume.hpp" namespace geos { @@ -28,35 +31,59 @@ namespace compositional { // Naming conventions -template< typename EOS_TYPE_LIQUID, typename EOS_TYPE_VAPOUR > -string NegativeTwoPhaseFlashModel< EOS_TYPE_LIQUID, EOS_TYPE_VAPOUR >::catalogName() +string NegativeTwoPhaseFlashModel::catalogName() { - return EOS_TYPE_LIQUID::catalogName(); + return "TwoPhase"; } -template< typename EOS_TYPE_LIQUID, typename EOS_TYPE_VAPOUR > -NegativeTwoPhaseFlashModel< EOS_TYPE_LIQUID, EOS_TYPE_VAPOUR >:: -NegativeTwoPhaseFlashModel( string const & name, - ComponentProperties const & componentProperties ): - FunctionBase( name, componentProperties ) +NegativeTwoPhaseFlashModel::NegativeTwoPhaseFlashModel( string const & name, + ComponentProperties const & componentProperties, + ModelParameters const & modelParameters ): + FunctionBase( name, componentProperties ), + m_parameters( modelParameters ) {} -template< typename EOS_TYPE_LIQUID, typename EOS_TYPE_VAPOUR > -typename NegativeTwoPhaseFlashModel< EOS_TYPE_LIQUID, EOS_TYPE_VAPOUR >::KernelWrapper -NegativeTwoPhaseFlashModel< EOS_TYPE_LIQUID, EOS_TYPE_VAPOUR >::createKernelWrapper() const +NegativeTwoPhaseFlashModel::KernelWrapper +NegativeTwoPhaseFlashModel::createKernelWrapper() const { - return KernelWrapper( m_componentProperties.getNumberOfComponents() ); + constexpr integer liquidIndex = 0; + constexpr integer vapourIndex = 1; + EquationOfState const * equationOfState = m_parameters.get< EquationOfState >(); + EquationOfStateType const liquidEos = EnumStrings< EquationOfStateType >::fromString( equationOfState->m_equationsOfStateNames[liquidIndex] ); + EquationOfStateType const vapourEos = EnumStrings< EquationOfStateType >::fromString( equationOfState->m_equationsOfStateNames[vapourIndex] ); + + CriticalVolume const * criticalVolume = m_parameters.get< CriticalVolume >(); + + return KernelWrapper( m_componentProperties.getNumberOfComponents(), + liquidIndex, + vapourIndex, + liquidEos, + vapourEos, + criticalVolume->m_componentCriticalVolume ); } -template< typename EOS_TYPE_LIQUID, typename EOS_TYPE_VAPOUR > -NegativeTwoPhaseFlashModelUpdate< EOS_TYPE_LIQUID, EOS_TYPE_VAPOUR >:: -NegativeTwoPhaseFlashModelUpdate( integer const numComponents ): - m_numComponents( numComponents ) +NegativeTwoPhaseFlashModelUpdate::NegativeTwoPhaseFlashModelUpdate( + integer const numComponents, + integer const liquidIndex, + integer const vapourIndex, + EquationOfStateType const liquidEos, + EquationOfStateType const vapourEos, + arrayView1d< real64 const > const componentCriticalVolume ): + m_numComponents( numComponents ), + m_liquidIndex( liquidIndex ), + m_vapourIndex( vapourIndex ), + m_liquidEos( liquidEos ), + m_vapourEos( vapourEos ), + m_componentCriticalVolume( componentCriticalVolume ) {} -// Explicit instantiation of the model template. -template class NegativeTwoPhaseFlashModel< CubicEOSPhaseModel< PengRobinsonEOS >, CubicEOSPhaseModel< PengRobinsonEOS > >; -template class NegativeTwoPhaseFlashModel< CubicEOSPhaseModel< SoaveRedlichKwongEOS >, CubicEOSPhaseModel< SoaveRedlichKwongEOS > >; +std::unique_ptr< ModelParameters > +NegativeTwoPhaseFlashModel::createParameters( std::unique_ptr< ModelParameters > parameters ) +{ + std::unique_ptr< ModelParameters > params = EquationOfState::create( std::move( parameters ) ); + params = CriticalVolume::create( std::move( params ) ); + return params; +} } // end namespace compositional diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/NegativeTwoPhaseFlashModel.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/NegativeTwoPhaseFlashModel.hpp index e9d6d17ef6c..d55d3df6656 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/NegativeTwoPhaseFlashModel.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/NegativeTwoPhaseFlashModel.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,10 +21,12 @@ #define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_COMPOSITIONAL_MODELS_NEGATIVETWOPHASEFLASHMODEL_HPP_ #include "FunctionBase.hpp" +#include "EquationOfState.hpp" #include "constitutive/fluid/multifluid/Layouts.hpp" #include "constitutive/fluid/multifluid/MultiFluidUtils.hpp" -#include "constitutive/fluid/multifluid/compositional/functions/CubicEOSPhaseModel.hpp" +#include "constitutive/fluid/multifluid/compositional/functions/StabilityTest.hpp" +#include "constitutive/fluid/multifluid/compositional/functions/NegativeTwoPhaseFlash.hpp" namespace geos { @@ -34,76 +37,158 @@ namespace constitutive namespace compositional { -template< typename EOS_TYPE_LIQUID, typename EOS_TYPE_VAPOUR > +class ModelParameters; + class NegativeTwoPhaseFlashModelUpdate final : public FunctionBaseUpdate { public: + using PhaseProp = MultiFluidVar< real64, 3, constitutive::multifluid::LAYOUT_PHASE, constitutive::multifluid::LAYOUT_PHASE_DC >; + using PhaseComp = MultiFluidVar< real64, 4, constitutive::multifluid::LAYOUT_PHASE_COMP, constitutive::multifluid::LAYOUT_PHASE_COMP_DC >; + using Deriv = constitutive::multifluid::DerivativeOffset; - using PhaseProp = MultiFluidVar< real64, 3, multifluid::LAYOUT_PHASE, multifluid::LAYOUT_PHASE_DC >; - using PhaseComp = MultiFluidVar< real64, 4, multifluid::LAYOUT_PHASE_COMP, multifluid::LAYOUT_PHASE_COMP_DC >; + static constexpr real64 stabilityTolerance = MultiFluidConstants::fugacityTolerance; - explicit NegativeTwoPhaseFlashModelUpdate( integer const numComponents ); + NegativeTwoPhaseFlashModelUpdate( integer const numComponents, + integer const liquidIndex, + integer const vapourIndex, + EquationOfStateType const liquidEos, + EquationOfStateType const vapourEos, + arrayView1d< real64 const > const componentCriticalVolume ); // Mark as a 2-phase flash GEOS_HOST_DEVICE static constexpr integer getNumberOfPhases() { return 2; } - template< int USD1, int USD2, int USD3 > + template< int USD1, int USD2 > GEOS_HOST_DEVICE void compute( ComponentProperties::KernelWrapper const & componentProperties, real64 const & pressure, real64 const & temperature, arraySlice1d< real64 const, USD1 > const & compFraction, - arraySlice1d< real64, USD2 > const & phaseFraction, - arraySlice2d< real64, USD3 > const & phaseCompFraction ) const + arraySlice2d< real64, USD2 > const & kValues, + PhaseProp::SliceType const phaseFraction, + PhaseComp::SliceType const phaseCompFraction ) const { - GEOS_UNUSED_VAR( componentProperties, pressure, temperature ); - // TODO: Constant values for now. To be linked with the static function call - phaseFraction[m_liquidIndex] = 0.5; - phaseFraction[m_vapourIndex] = 0.5; - for( integer ic = 0; ic < m_numComponents; ++ic ) + integer const numDofs = 2 + m_numComponents; + + // Perform stability test to check that we have 2 phases + real64 tangentPlaneDistance = 0.0; + bool const stabilityStatus = StabilityTest::compute( m_numComponents, + pressure, + temperature, + compFraction, + componentProperties, + m_liquidEos, + tangentPlaneDistance, + kValues[0] ); + GEOS_ERROR_IF( !stabilityStatus, + GEOS_FMT( "Stability test failed at pressure {:.5e} and temperature {:.3f}", pressure, temperature )); + + if( tangentPlaneDistance < -stabilityTolerance ) { - phaseCompFraction[m_liquidIndex][ic] = compFraction[ic]; - phaseCompFraction[m_vapourIndex][ic] = compFraction[ic]; + // Unstable mixture + // Iterative solve to converge flash + bool const flashStatus = NegativeTwoPhaseFlash::compute( m_numComponents, + pressure, + temperature, + compFraction, + componentProperties, + m_liquidEos, + m_vapourEos, + kValues, + phaseFraction.value[m_vapourIndex], + phaseCompFraction.value[m_liquidIndex], + phaseCompFraction.value[m_vapourIndex] ); + + GEOS_ERROR_IF( !flashStatus, + GEOS_FMT( "Negative two phase flash failed to converge at pressure {:.5e} and temperature {:.3f}", + pressure, temperature )); + + // Calculate derivatives + NegativeTwoPhaseFlash::computeDerivatives( m_numComponents, + pressure, + temperature, + compFraction, + componentProperties, + m_liquidEos, + m_vapourEos, + phaseFraction.value[m_vapourIndex], + phaseCompFraction.value[m_liquidIndex].toSliceConst(), + phaseCompFraction.value[m_vapourIndex].toSliceConst(), + phaseFraction.derivs[m_vapourIndex], + phaseCompFraction.derivs[m_liquidIndex], + phaseCompFraction.derivs[m_vapourIndex] ); + } + else + { + // Stable mixture - simply label + calculateLiCorrelation( componentProperties, + temperature, + compFraction, + phaseFraction.value[m_vapourIndex] ); + + LvArray::forValuesInSlice( phaseFraction.derivs[m_vapourIndex], setZero ); + LvArray::forValuesInSlice( phaseCompFraction.derivs[m_liquidIndex], setZero ); + LvArray::forValuesInSlice( phaseCompFraction.derivs[m_vapourIndex], setZero ); + for( integer ic = 0; ic < m_numComponents; ++ic ) + { + phaseCompFraction.value( m_vapourIndex, ic ) = compFraction[ic]; + phaseCompFraction.value( m_liquidIndex, ic ) = compFraction[ic]; + phaseCompFraction.derivs( m_vapourIndex, ic, Deriv::dC + ic ) = 1.0; + phaseCompFraction.derivs( m_liquidIndex, ic, Deriv::dC + ic ) = 1.0; + } + } + + // Complete by calculating liquid phase fraction + phaseFraction.value[m_liquidIndex] = 1.0 - phaseFraction.value[m_vapourIndex]; + for( integer ic = 0; ic < numDofs; ic++ ) + { + phaseFraction.derivs[m_liquidIndex][ic] = -phaseFraction.derivs[m_vapourIndex][ic]; } } - template< int USD1 > + template< int USD > GEOS_HOST_DEVICE - void compute( ComponentProperties::KernelWrapper const & componentProperties, - real64 const & pressure, - real64 const & temperature, - arraySlice1d< real64 const, USD1 > const & compFraction, - PhaseProp::SliceType const phaseFraction, - PhaseComp::SliceType const phaseCompFraction ) const + void calculateLiCorrelation( ComponentProperties::KernelWrapper const & componentProperties, + real64 const & temperature, + arraySlice1d< real64 const, USD > const & composition, + real64 & vapourFraction ) const { - GEOS_UNUSED_VAR( componentProperties, pressure, temperature ); - - // TODO: Constant values for now. To be linked with the static function call - phaseFraction.value[m_liquidIndex] = 0.5; - phaseFraction.value[m_vapourIndex] = 0.5; + real64 sumVz = 0.0; + real64 sumVzt = 0.0; + arrayView1d< real64 const > const & criticalTemperature = componentProperties.m_componentCriticalTemperature; for( integer ic = 0; ic < m_numComponents; ++ic ) { - phaseCompFraction.value[m_liquidIndex][ic] = compFraction[ic]; - phaseCompFraction.value[m_vapourIndex][ic] = compFraction[ic]; + real64 const Vz = m_componentCriticalVolume[ic] * composition[ic]; + sumVz += Vz; + sumVzt += Vz * criticalTemperature[ic]; + } + real64 const pseudoCritTemperature = sumVzt / sumVz; + if( pseudoCritTemperature < temperature ) + { + vapourFraction = 1.0; + } + else + { + vapourFraction = 0.0; } - - LvArray::forValuesInSlice( phaseFraction.derivs, setZero ); - LvArray::forValuesInSlice( phaseCompFraction.derivs, setZero ); } private: integer const m_numComponents; - integer const m_liquidIndex{0}; - integer const m_vapourIndex{1}; + integer const m_liquidIndex; + integer const m_vapourIndex; + EquationOfStateType const m_liquidEos; + EquationOfStateType const m_vapourEos; + arrayView1d< real64 const > const m_componentCriticalVolume; }; -template< typename EOS_TYPE_LIQUID, typename EOS_TYPE_VAPOUR > class NegativeTwoPhaseFlashModel : public FunctionBase { public: NegativeTwoPhaseFlashModel( string const & name, - ComponentProperties const & componentProperties ); + ComponentProperties const & componentProperties, + ModelParameters const & modelParameters ); static string catalogName(); @@ -113,21 +198,20 @@ class NegativeTwoPhaseFlashModel : public FunctionBase } /// Type of kernel wrapper for in-kernel update - using KernelWrapper = NegativeTwoPhaseFlashModelUpdate< EOS_TYPE_LIQUID, EOS_TYPE_VAPOUR >; + using KernelWrapper = NegativeTwoPhaseFlashModelUpdate; /** * @brief Create an update kernel wrapper. * @return the wrapper */ KernelWrapper createKernelWrapper() const; -}; -using NegativeTwoPhaseFlashPRPR = NegativeTwoPhaseFlashModel< - CubicEOSPhaseModel< PengRobinsonEOS >, - CubicEOSPhaseModel< PengRobinsonEOS > >; -using NegativeTwoPhaseFlashSRKSRK = NegativeTwoPhaseFlashModel< - CubicEOSPhaseModel< SoaveRedlichKwongEOS >, - CubicEOSPhaseModel< SoaveRedlichKwongEOS > >; + // Create parameters unique to this model + static std::unique_ptr< ModelParameters > createParameters( std::unique_ptr< ModelParameters > parameters ); + +private: + ModelParameters const & m_parameters; +}; } // end namespace compositional diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/NullModel.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/NullModel.hpp index 00eae8f5948..dd10f7caef5 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/NullModel.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/NullModel.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -35,18 +36,6 @@ class NullModelUpdate final : public FunctionBaseUpdate public: NullModelUpdate() = default; - template< int USD1 > - GEOS_HOST_DEVICE - void compute( ComponentProperties::KernelWrapper const & componentProperties, - real64 const & pressure, - real64 const & temperature, - arraySlice1d< real64 const, USD1 > const & phaseComposition, - real64 & value, - bool useMass ) const - { - GEOS_UNUSED_VAR( componentProperties, pressure, temperature, phaseComposition, value, useMass ); - } - template< int USD1, int USD2, int USD3 > GEOS_HOST_DEVICE void compute( ComponentProperties::KernelWrapper const & componentProperties, @@ -71,9 +60,21 @@ class NullModel : public FunctionBase public: NullModel( string const & name, - ComponentProperties const & componentProperties ): + ComponentProperties const & componentProperties, + integer const phaseIndex, + ModelParameters const & modelParameters ): + FunctionBase( name, componentProperties ) + { + GEOS_UNUSED_VAR( phaseIndex, modelParameters ); + } + + NullModel( string const & name, + ComponentProperties const & componentProperties, + ModelParameters const & modelParameters ): FunctionBase( name, componentProperties ) - {} + { + GEOS_UNUSED_VAR( modelParameters ); + } virtual ~NullModel() override = default; diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/PhaseModel.hpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/PhaseModel.hpp index 638b6f9a8eb..c99b723c0b0 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/models/PhaseModel.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/models/PhaseModel.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -30,6 +31,8 @@ namespace constitutive namespace compositional { +class ModelParameters; + /** * @brief Struct storing the submodels describing the fluid phase behavior. * @tparam DENSITY Class describing the density model @@ -51,13 +54,21 @@ struct PhaseModel * @param[in] componentProperties EOS parameters for components */ PhaseModel( string const & phaseModelName, - ComponentProperties const & componentProperties ): + ComponentProperties const & componentProperties, + integer const phaseIndex, + ModelParameters const & modelParameters ): density( phaseModelName + "_" + Density::catalogName(), - componentProperties ), + componentProperties, + phaseIndex, + modelParameters ), viscosity( phaseModelName + "_" + Viscosity::catalogName(), - componentProperties ), + componentProperties, + phaseIndex, + modelParameters ), enthalpy( phaseModelName + "_" + Enthalpy::catalogName(), - componentProperties ) + componentProperties, + phaseIndex, + modelParameters ) {} /// The phase density model @@ -122,6 +133,17 @@ struct PhaseModel viscosity, enthalpy ); } + + // Create parameters unique to this model + static std::unique_ptr< ModelParameters > createParameters( std::unique_ptr< ModelParameters > parameters ) + { + std::unique_ptr< ModelParameters > phaseParameters = std::move( parameters ); + phaseParameters = Density::createParameters( std::move( phaseParameters ) ); + phaseParameters = Viscosity::createParameters( std::move( phaseParameters ) ); + phaseParameters = Enthalpy::createParameters( std::move( phaseParameters ) ); + return phaseParameters; + } + }; // A no-op phase model diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveBrineFluid.cpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveBrineFluid.cpp index f118a6a6819..7451008cd6c 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveBrineFluid.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveBrineFluid.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,6 +20,7 @@ #include "constitutive/fluid/multifluid/MultiFluidFields.hpp" #include "constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.hpp" +#include "constitutive/ConstitutiveManager.hpp" #include "common/Units.hpp" namespace geos @@ -68,6 +70,12 @@ ReactiveBrineFluid( string const & name, Group * const parent ): setRestartFlags( RestartFlags::NO_WRITE ). setDescription( "Names of the files defining the parameters of the viscosity and density models" ); + this->registerWrapper( viewKeyStruct::writeCSVFlagString(), &m_writeCSV ). + setApplyDefaultValue( 0 ). + setInputFlag( InputFlags::OPTIONAL ). + setRestartFlags( RestartFlags::NO_WRITE ). + setDescription( "Write PVT tables into a CSV file" ); + // if this is a thermal model, we need to make sure that the arrays will be properly displayed and saved to restart if( isThermal() ) { @@ -93,6 +101,7 @@ std::unique_ptr< ConstitutiveBase > ReactiveBrineFluid< PHASE > :: deliverClone( string const & name, Group * const parent ) const { + std::unique_ptr< ConstitutiveBase > clone = ReactiveMultiFluid::deliverClone( name, parent ); ReactiveBrineFluid & newConstitutiveRelation = dynamicCast< ReactiveBrineFluid & >( *clone ); @@ -111,9 +120,9 @@ integer ReactiveBrineFluid< PHASE > ::getWaterPhaseIndex() const template< typename PHASE > -void ReactiveBrineFluid< PHASE > ::postProcessInput() +void ReactiveBrineFluid< PHASE > ::postInputInitialization() { - ReactiveMultiFluid::postProcessInput(); + ReactiveMultiFluid::postInputInitialization(); GEOS_THROW_IF_NE_MSG( numFluidPhases(), 1, GEOS_FMT( "{}: invalid number of phases", getFullName() ), @@ -128,7 +137,6 @@ void ReactiveBrineFluid< PHASE > ::postProcessInput() template< typename PHASE > void ReactiveBrineFluid< PHASE > ::createPVTModels() { - // TODO: get rid of these external files and move into XML, this is too error prone // For now, to support the legacy input, we read all the input parameters at once in the arrays below, and then we create the models array1d< array1d< string > > phase1InputParams; @@ -192,9 +200,15 @@ void ReactiveBrineFluid< PHASE > ::createPVTModels() GEOS_FMT( "{}: PVT model {} not found in input files", getFullName(), PHASE::Enthalpy::catalogName() ), InputError ); + bool const isClone = this->isClone(); + TableFunction::OutputOptions const pvtOutputOpts = { + !isClone && m_writeCSV,// writeCSV + !isClone && (getLogLevel() >= 0 && logger::internal::rank==0), // writeInLog + }; + // then, we are ready to instantiate the phase models m_phase = std::make_unique< PHASE >( getName() + "_phaseModel1", phase1InputParams, m_componentNames, m_componentMolarWeight, - getLogLevel() > 0 && logger::internal::rank==0 ); + pvtOutputOpts ); } template< typename PHASE > @@ -214,7 +228,8 @@ void ReactiveBrineFluid< PHASE >::checkTablesParameters( real64 const pressure, m_phase->enthalpy.checkTablesParameters( pressure, temperatureInCelsius ); } catch( SimulationError const & ex ) { - string const errorMsg = GEOS_FMT( "{}: Table input error.\n", getDataContext() ); + string const errorMsg = GEOS_FMT( "Table input error (in table from {}).\n", + stringutilities::join( m_phasePVTParaFiles ) ); throw SimulationError( ex, errorMsg ); } } diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveBrineFluid.hpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveBrineFluid.hpp index 0be8a28c8c9..f1d88712b00 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveBrineFluid.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveBrineFluid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,7 @@ #ifndef GEOS_CONSTITUTIVE_FLUID_REACTIVEBRINEFLUID_HPP_ #define GEOS_CONSTITUTIVE_FLUID_REACTIVEBRINEFLUID_HPP_ -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include "constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.hpp" #include "constitutive/fluid/multifluid/MultiFluidUtils.hpp" #include "constitutive/fluid/multifluid/CO2Brine/PhaseModel.hpp" @@ -151,19 +152,26 @@ class ReactiveBrineFluid : public ReactiveMultiFluid struct viewKeyStruct : ReactiveMultiFluid::viewKeyStruct { static constexpr char const * phasePVTParaFilesString() { return "phasePVTParaFiles"; } + static constexpr char const * writeCSVFlagString() { return "writeCSV"; } }; protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; private: + /** + * @brief Create a PVT Model and output them + */ void createPVTModels(); /// Names of the files defining the viscosity and density models path_array m_phasePVTParaFiles; + /// Output csv file containing informations about PVT + integer m_writeCSV; + /// Brine constitutive models std::unique_ptr< PHASE > m_phase; diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveFluidSelector.hpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveFluidSelector.hpp index 6d69b0805f1..03439e9629b 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveFluidSelector.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveFluidSelector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.cpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.cpp index 669cfe5e84d..09ac848a16a 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -59,9 +60,9 @@ std::unique_ptr< ConstitutiveBase > ReactiveMultiFluid:: return clone; } -void ReactiveMultiFluid::postProcessInput() +void ReactiveMultiFluid::postInputInitialization() { - MultiFluidBase::postProcessInput(); + MultiFluidBase::postInputInitialization(); GEOS_THROW_IF_NE_MSG( numFluidPhases(), 1, GEOS_FMT( "{}: invalid number of phases", getFullName() ), diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.hpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.hpp index 959fdf35282..71ebd796571 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_REACTIVE_REACTIVEMULTIFLUID_HPP_ -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.hpp" #include "constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.hpp" @@ -171,7 +172,7 @@ class ReactiveMultiFluid : public MultiFluidBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; void createChemicalReactions(); @@ -188,13 +189,13 @@ class ReactiveMultiFluid : public MultiFluidBase std::unique_ptr< chemicalReactions::KineticReactions > m_kineticReactions; - array2d< real64, multifluid::LAYOUT_FLUID > m_primarySpeciesConcentration; + array2d< real64, constitutive::multifluid::LAYOUT_FLUID > m_primarySpeciesConcentration; - array2d< real64, multifluid::LAYOUT_FLUID > m_secondarySpeciesConcentration; + array2d< real64, constitutive::multifluid::LAYOUT_FLUID > m_secondarySpeciesConcentration; - array2d< real64, multifluid::LAYOUT_FLUID > m_primarySpeciesTotalConcentration; + array2d< real64, constitutive::multifluid::LAYOUT_FLUID > m_primarySpeciesTotalConcentration; - array2d< real64, multifluid::LAYOUT_FLUID > m_kineticReactionRates; + array2d< real64, constitutive::multifluid::LAYOUT_FLUID > m_kineticReactionRates; }; inline void diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluidFields.hpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluidFields.hpp index 8531ecb7383..d3a3a77f967 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluidFields.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluidFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.cpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.cpp index 4cc3eef7114..8ae3e0c8ee2 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.hpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.hpp index 08cd8287776..e3908d4df7d 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.cpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.cpp index fa2c6643bd1..5009c9fbeae 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.hpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.hpp index 9b470dff5c0..7c2ff5bf64a 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/ReactionsBase.cpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/ReactionsBase.cpp index bc9c3f4ccee..df579b3587e 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/ReactionsBase.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/ReactionsBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/ReactionsBase.hpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/ReactionsBase.hpp index c7c78367b77..8b3e01b335f 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/ReactionsBase.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/ReactionsBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/singlefluid/CompressibleSinglePhaseFluid.cpp b/src/coreComponents/constitutive/fluid/singlefluid/CompressibleSinglePhaseFluid.cpp index 6c896110e64..76646b5222a 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/CompressibleSinglePhaseFluid.cpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/CompressibleSinglePhaseFluid.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -92,9 +93,9 @@ void CompressibleSinglePhaseFluid::allocateConstitutiveData( dataRepository::Gro m_viscosity.setValues< serialPolicy >( m_referenceViscosity ); } -void CompressibleSinglePhaseFluid::postProcessInput() +void CompressibleSinglePhaseFluid::postInputInitialization() { - SingleFluidBase::postProcessInput(); + SingleFluidBase::postInputInitialization(); auto const checkNonnegative = [&]( real64 const value, auto const & attribute ) { diff --git a/src/coreComponents/constitutive/fluid/singlefluid/CompressibleSinglePhaseFluid.hpp b/src/coreComponents/constitutive/fluid/singlefluid/CompressibleSinglePhaseFluid.hpp index 7758989391d..b28f2109a21 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/CompressibleSinglePhaseFluid.hpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/CompressibleSinglePhaseFluid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -181,7 +182,7 @@ class CompressibleSinglePhaseFluid : public SingleFluidBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// default density value real64 m_defaultDensity; diff --git a/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluid.cpp b/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluid.cpp index ee186e16c4f..adf166a4540 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluid.cpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluid.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -79,9 +80,9 @@ ParticleFluid::ParticleFluid( string const & name, Group * const parent ): ParticleFluid::~ParticleFluid() = default; -void ParticleFluid::postProcessInput() +void ParticleFluid::postInputInitialization() { - ParticleFluidBase::postProcessInput(); + ParticleFluidBase::postInputInitialization(); GEOS_ERROR_IF( m_proppantDensity < 500.0, "Invalid proppantDensity in ParticleFluid " diff --git a/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluid.hpp b/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluid.hpp index 609b6a47d10..a6a724f0933 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluid.hpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,7 @@ #ifndef GEOS_CONSTITUTIVE_FLUID_SINGLEFLUID_PARTICLEFLUID_HPP_ #define GEOS_CONSTITUTIVE_FLUID_SINGLEFLUID_PARTICLEFLUID_HPP_ -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include "constitutive/fluid/singlefluid/ParticleFluidBase.hpp" namespace geos @@ -225,7 +226,7 @@ class ParticleFluid : public ParticleFluidBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; private: diff --git a/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidBase.cpp b/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidBase.cpp index eb77cbc78ad..d4faa0d8a20 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidBase.cpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -54,9 +55,9 @@ ParticleFluidBase::ParticleFluidBase( string const & name, Group * const parent ParticleFluidBase::~ParticleFluidBase() = default; -void ParticleFluidBase::postProcessInput() +void ParticleFluidBase::postInputInitialization() { - ConstitutiveBase::postProcessInput(); + ConstitutiveBase::postInputInitialization(); } void ParticleFluidBase::allocateConstitutiveData( Group & parent, diff --git a/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidBase.hpp b/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidBase.hpp index c027b4110cd..9960b7376ee 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidBase.hpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -160,7 +161,7 @@ class ParticleFluidBase : public ConstitutiveBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; array1d< real64 > m_settlingFactor; array1d< real64 > m_dSettlingFactor_dPressure; diff --git a/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidFields.hpp b/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidFields.hpp index 7eab5fa5ed8..30b10912683 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidFields.hpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidSelector.hpp b/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidSelector.hpp index 8fd597199f3..f0033da5c48 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidSelector.hpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/ParticleFluidSelector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/singlefluid/ProppantSlurryFluid.cpp b/src/coreComponents/constitutive/fluid/singlefluid/ProppantSlurryFluid.cpp index 713a0f04b45..95c4d0a8fb0 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/ProppantSlurryFluid.cpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/ProppantSlurryFluid.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -73,9 +74,9 @@ void ProppantSlurryFluid::allocateConstitutiveData( dataRepository::Group & pare } -void ProppantSlurryFluid::postProcessInput() +void ProppantSlurryFluid::postInputInitialization() { - SlurryFluidBase::postProcessInput(); + SlurryFluidBase::postInputInitialization(); GEOS_ERROR_IF_LT_MSG( m_compressibility, 0.0, getFullName() << ": invalid value of " << viewKeyStruct::compressibilityString() ); diff --git a/src/coreComponents/constitutive/fluid/singlefluid/ProppantSlurryFluid.hpp b/src/coreComponents/constitutive/fluid/singlefluid/ProppantSlurryFluid.hpp index 2637c19adb2..eb8809bac58 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/ProppantSlurryFluid.hpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/ProppantSlurryFluid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -334,7 +335,7 @@ class ProppantSlurryFluid : public SlurryFluidBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; private: diff --git a/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.cpp b/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.cpp index 0f7f6a5cc1c..b5a91dfdb58 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.cpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -51,9 +52,9 @@ SingleFluidBase::SingleFluidBase( string const & name, Group * const parent ) } -void SingleFluidBase::postProcessInput() +void SingleFluidBase::postInputInitialization() { - ConstitutiveBase::postProcessInput(); + ConstitutiveBase::postInputInitialization(); // for fracture elements, set the default value getField< fields::singlefluid::density_n >(). diff --git a/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp b/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp index 2f04795b81c..d94b98672e5 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -275,9 +276,17 @@ class SingleFluidBase : public ConstitutiveBase virtual real64 defaultDensity() const = 0; virtual real64 defaultViscosity() const = 0; +/** + * @brief Get the thermal flag. + * @return boolean value indicating whether the model can be used to assemble the energy balance equation or not + * @detail if isThermal is true, the constitutive model compute the enthalpy and internal energy of the phase. + * This can be used to check the compatibility of the constitutive model with the solver + */ + virtual bool isThermal() const { return false; } + protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; //START_SPHINX_INCLUDE_00 array2d< real64 > m_density; diff --git a/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidFields.hpp b/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidFields.hpp index 0f15bb504d2..8714083accd 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidFields.hpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidSelector.hpp b/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidSelector.hpp index d71dc3641f4..be6560c6c21 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidSelector.hpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidSelector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidBase.cpp b/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidBase.cpp index 1c4b6199357..11a49d4da84 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidBase.cpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -81,9 +82,9 @@ SlurryFluidBase::SlurryFluidBase( string const & name, Group * const parent ): SlurryFluidBase::~SlurryFluidBase() = default; -void SlurryFluidBase::postProcessInput() +void SlurryFluidBase::postInputInitialization() { - SingleFluidBase::postProcessInput(); + SingleFluidBase::postInputInitialization(); localIndex const NC = numFluidComponents(); diff --git a/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidBase.hpp b/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidBase.hpp index 24e0efc989f..94a101b32e3 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidBase.hpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -305,7 +306,7 @@ class SlurryFluidBase : public SingleFluidBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; string_array m_componentNames; diff --git a/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidFields.hpp b/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidFields.hpp index b3ccad93a01..55bd3b82b6f 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidFields.hpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidSelector.hpp b/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidSelector.hpp index 864b1540368..53b341c95fb 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidSelector.hpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/SlurryFluidSelector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/fluid/singlefluid/ThermalCompressibleSinglePhaseFluid.cpp b/src/coreComponents/constitutive/fluid/singlefluid/ThermalCompressibleSinglePhaseFluid.cpp index 96ffa8bf5f7..af28e00814a 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/ThermalCompressibleSinglePhaseFluid.cpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/ThermalCompressibleSinglePhaseFluid.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -71,9 +72,9 @@ void ThermalCompressibleSinglePhaseFluid::allocateConstitutiveData( dataReposito m_internalEnergy.setValues< serialPolicy >( m_referenceInternalEnergy ); } -void ThermalCompressibleSinglePhaseFluid::postProcessInput() +void ThermalCompressibleSinglePhaseFluid::postInputInitialization() { - CompressibleSinglePhaseFluid::postProcessInput(); + CompressibleSinglePhaseFluid::postInputInitialization(); auto const checkNonnegative = [&]( real64 const value, auto const & attribute ) { diff --git a/src/coreComponents/constitutive/fluid/singlefluid/ThermalCompressibleSinglePhaseFluid.hpp b/src/coreComponents/constitutive/fluid/singlefluid/ThermalCompressibleSinglePhaseFluid.hpp index e20130bf9fb..af79dd929c1 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/ThermalCompressibleSinglePhaseFluid.hpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/ThermalCompressibleSinglePhaseFluid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -248,7 +249,7 @@ class ThermalCompressibleSinglePhaseFluid : public CompressibleSinglePhaseFluid protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; private: diff --git a/src/coreComponents/constitutive/permeability/CarmanKozenyPermeability.cpp b/src/coreComponents/constitutive/permeability/CarmanKozenyPermeability.cpp index 511402d34db..f57f52ffd77 100644 --- a/src/coreComponents/constitutive/permeability/CarmanKozenyPermeability.cpp +++ b/src/coreComponents/constitutive/permeability/CarmanKozenyPermeability.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/permeability/CarmanKozenyPermeability.hpp b/src/coreComponents/constitutive/permeability/CarmanKozenyPermeability.hpp index 56518a12e4a..2d7605b4871 100644 --- a/src/coreComponents/constitutive/permeability/CarmanKozenyPermeability.hpp +++ b/src/coreComponents/constitutive/permeability/CarmanKozenyPermeability.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -50,10 +51,13 @@ class CarmanKozenyPermeabilityUpdate : public PermeabilityBaseUpdate arraySlice1d< real64 > const & dPerm_dPorosity ) const; GEOS_HOST_DEVICE - virtual void updateFromPorosity( localIndex const k, - localIndex const q, - real64 const & porosity ) const override + virtual void updateFromPressureAndPorosity( localIndex const k, + localIndex const q, + real64 const & pressure, + real64 const & porosity ) const override { + GEOS_UNUSED_VAR( pressure ); + compute( porosity, m_permeability[k][q], m_dPerm_dPorosity[k][q] ); diff --git a/src/coreComponents/constitutive/permeability/ConstantPermeability.cpp b/src/coreComponents/constitutive/permeability/ConstantPermeability.cpp index f6c8ec0dc67..eecbc1c6645 100644 --- a/src/coreComponents/constitutive/permeability/ConstantPermeability.cpp +++ b/src/coreComponents/constitutive/permeability/ConstantPermeability.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -87,7 +88,7 @@ void ConstantPermeability::initializeState() const } ); } -void ConstantPermeability::postProcessInput() +void ConstantPermeability::postInputInitialization() {} REGISTER_CATALOG_ENTRY( ConstitutiveBase, ConstantPermeability, string const &, Group * const ) diff --git a/src/coreComponents/constitutive/permeability/ConstantPermeability.hpp b/src/coreComponents/constitutive/permeability/ConstantPermeability.hpp index 51a7206d152..4357ea50b5d 100644 --- a/src/coreComponents/constitutive/permeability/ConstantPermeability.hpp +++ b/src/coreComponents/constitutive/permeability/ConstantPermeability.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -80,7 +81,7 @@ class ConstantPermeability : public PermeabilityBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; private: diff --git a/src/coreComponents/constitutive/permeability/ExponentialDecayPermeability.cpp b/src/coreComponents/constitutive/permeability/ExponentialDecayPermeability.cpp index 3a6fb77d9a6..4ac85ac4d9a 100644 --- a/src/coreComponents/constitutive/permeability/ExponentialDecayPermeability.cpp +++ b/src/coreComponents/constitutive/permeability/ExponentialDecayPermeability.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/permeability/ExponentialDecayPermeability.hpp b/src/coreComponents/constitutive/permeability/ExponentialDecayPermeability.hpp index 5f7e7cc0589..c8d39b0bfcf 100644 --- a/src/coreComponents/constitutive/permeability/ExponentialDecayPermeability.hpp +++ b/src/coreComponents/constitutive/permeability/ExponentialDecayPermeability.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/permeability/ParallelPlatesPermeability.cpp b/src/coreComponents/constitutive/permeability/ParallelPlatesPermeability.cpp index ca57f7d4863..379a584bbd0 100644 --- a/src/coreComponents/constitutive/permeability/ParallelPlatesPermeability.cpp +++ b/src/coreComponents/constitutive/permeability/ParallelPlatesPermeability.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/permeability/ParallelPlatesPermeability.hpp b/src/coreComponents/constitutive/permeability/ParallelPlatesPermeability.hpp index 5a3c01af8f1..6977221fbfd 100644 --- a/src/coreComponents/constitutive/permeability/ParallelPlatesPermeability.hpp +++ b/src/coreComponents/constitutive/permeability/ParallelPlatesPermeability.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/permeability/PermeabilityBase.cpp b/src/coreComponents/constitutive/permeability/PermeabilityBase.cpp index b023e926115..0086cf6dc13 100644 --- a/src/coreComponents/constitutive/permeability/PermeabilityBase.cpp +++ b/src/coreComponents/constitutive/permeability/PermeabilityBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -68,6 +69,5 @@ void PermeabilityBase::allocateConstitutiveData( dataRepository::Group & parent, ConstitutiveBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex ); } -REGISTER_CATALOG_ENTRY( ConstitutiveBase, PermeabilityBase, string const &, Group * const ) } } /* namespace geos */ diff --git a/src/coreComponents/constitutive/permeability/PermeabilityBase.hpp b/src/coreComponents/constitutive/permeability/PermeabilityBase.hpp index ee7c661d600..d983bcf8d8e 100644 --- a/src/coreComponents/constitutive/permeability/PermeabilityBase.hpp +++ b/src/coreComponents/constitutive/permeability/PermeabilityBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -47,11 +48,12 @@ class PermeabilityBaseUpdate localIndex numGauss() const { return m_permeability.size( 1 ); } GEOS_HOST_DEVICE - virtual void updateFromPorosity( localIndex const k, - localIndex const q, - real64 const & porosity ) const + virtual void updateFromPressureAndPorosity( localIndex const k, + localIndex const q, + real64 const & pressure, + real64 const & porosity ) const { - GEOS_UNUSED_VAR( k, q, porosity ); + GEOS_UNUSED_VAR( k, q, pressure, porosity ); } GEOS_HOST_DEVICE @@ -113,10 +115,6 @@ class PermeabilityBase : public ConstitutiveBase virtual void allocateConstitutiveData( dataRepository::Group & parent, localIndex const numConstitutivePointsPerParentIndex ) override; - static string catalogName() { return "PermeabilityBase"; } - - virtual string getCatalogName() const override { return catalogName(); } - /** * @brief Const/non-mutable accessor for permeability. * @return Accessor diff --git a/src/coreComponents/constitutive/permeability/PermeabilityFields.hpp b/src/coreComponents/constitutive/permeability/PermeabilityFields.hpp index 45bc12ca6fe..e1a48f17618 100644 --- a/src/coreComponents/constitutive/permeability/PermeabilityFields.hpp +++ b/src/coreComponents/constitutive/permeability/PermeabilityFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/permeability/PressurePermeability.cpp b/src/coreComponents/constitutive/permeability/PressurePermeability.cpp new file mode 100644 index 00000000000..abcb8cde307 --- /dev/null +++ b/src/coreComponents/constitutive/permeability/PressurePermeability.cpp @@ -0,0 +1,128 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PressurePermeability.cpp + */ + +#include "PressurePermeability.hpp" + +namespace geos +{ + +using namespace dataRepository; + +namespace constitutive +{ + + +PressurePermeability::PressurePermeability( string const & name, Group * const parent ): + PermeabilityBase( name, parent ) +{ + registerWrapper( viewKeyStruct::referencePermeabilityComponentsString(), &m_referencePermeabilityComponents ). + setInputFlag( InputFlags::REQUIRED ). + setRestartFlags( RestartFlags::NO_WRITE ). + setDescription( "Reference xx, yy and zz components of a diagonal permeability tensor." ); + + registerWrapper( viewKeyStruct::pressureDependenceConstantsString(), &m_pressureDependenceConstants ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Pressure dependence coefficients for each permeability component." ); + + registerWrapper( viewKeyStruct::referencePressureString(), &m_referencePressure ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Reference pressure for the pressure permeability model" ); + + registerWrapper( viewKeyStruct::referencePermeabilityString(), &m_referencePermeability ). + setApplyDefaultValue( 0.0 ). + setPlotLevel( PlotLevel::LEVEL_0 ). + setDescription( "Reference permeability field" ); + + registerWrapper( viewKeyStruct::maxPermeabilityString(), &m_maxPermeability ). + setApplyDefaultValue( 1.0 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Max. permeability can be reached." ); + + registerWrapper( viewKeyStruct::pressureModelTypeString(), &m_presModelType ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( PressureModelType::Hyperbolic ). + setDescription( "Type of the pressure dependence model. " ); +} + +std::unique_ptr< ConstitutiveBase > +PressurePermeability::deliverClone( string const & name, + Group * const parent ) const +{ + return PermeabilityBase::deliverClone( name, parent ); +} + +void PressurePermeability::postInputInitialization() +{ + for( localIndex i=0; i < 3; i++ ) + { + GEOS_ERROR_IF( fabs( m_pressureDependenceConstants[i] ) < 1e-15 && m_presModelType == PressureModelType::Hyperbolic, + getDataContext() << ": the pressure dependent constant at component " << i << " is too close to zero, which is not allowed for the hyperbolic model." ); + } +} + +void PressurePermeability::allocateConstitutiveData( dataRepository::Group & parent, + localIndex const numConstitutivePointsPerParentIndex ) +{ + m_referencePermeability.resize( 0, 1, 3 ); + + PermeabilityBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex ); + + integer const numQuad = 1; // NOTE: enforcing 1 quadrature point + + for( localIndex ei = 0; ei < parent.size(); ++ei ) + { + for( localIndex q = 0; q < numQuad; ++q ) + { + m_referencePermeability[ei][q][0] = m_referencePermeabilityComponents[0]; + m_referencePermeability[ei][q][1] = m_referencePermeabilityComponents[1]; + m_referencePermeability[ei][q][2] = m_referencePermeabilityComponents[2]; + } + } +} + +void PressurePermeability::initializeState() const +{ + localIndex const numE = m_permeability.size( 0 ); + integer constexpr numQuad = 1; // NOTE: enforcing 1 quadrature point + + auto permView = m_permeability.toView(); + real64 const permComponents[3] = { m_referencePermeabilityComponents[0], + m_referencePermeabilityComponents[1], + m_referencePermeabilityComponents[2] }; + + forAll< parallelDevicePolicy<> >( numE, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + for( localIndex q = 0; q < numQuad; ++q ) + { + for( integer dim=0; dim < 3; ++dim ) + { + // The default value is -1 so if it still -1 it needs to be set to something physical + if( permView[ei][q][dim] < 0 ) + { + permView[ei][q][dim] = permComponents[dim]; + } + } + } + } ); +} + +REGISTER_CATALOG_ENTRY( ConstitutiveBase, PressurePermeability, string const &, Group * const ) + +} +} /* namespace geos */ diff --git a/src/coreComponents/constitutive/permeability/PressurePermeability.hpp b/src/coreComponents/constitutive/permeability/PressurePermeability.hpp new file mode 100644 index 00000000000..df517530771 --- /dev/null +++ b/src/coreComponents/constitutive/permeability/PressurePermeability.hpp @@ -0,0 +1,252 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PressurePermeability.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_PERMEABILITY_PRESSUREPERMEABILITY_HPP_ +#define GEOS_CONSTITUTIVE_PERMEABILITY_PRESSUREPERMEABILITY_HPP_ + +#include "constitutive/permeability/PermeabilityBase.hpp" + + +namespace geos +{ +namespace constitutive +{ + +enum class PressureModelType : integer +{ + Exponential, + Hyperbolic +}; + +ENUM_STRINGS( PressureModelType, + "Exponential", + "Hyperbolic" ); + +class PressurePermeabilityUpdate : public PermeabilityBaseUpdate +{ +public: + + PressurePermeabilityUpdate( PressureModelType const & presModelType, + R1Tensor const pressureDependenceConstants, + real64 const & referencePressure, + real64 const & maxPermeability, + arrayView3d< real64 > const & referencePermeability, + arrayView3d< real64 > const & permeability, + arrayView3d< real64 > const & dPerm_dPressure ) + : PermeabilityBaseUpdate( permeability, dPerm_dPressure ), + m_presModelType( presModelType ), + m_pressureDependenceConstants( pressureDependenceConstants ), + m_referencePressure( referencePressure ), + m_maxPermeability( maxPermeability ), + m_referencePermeability( referencePermeability ) + {} + + GEOS_HOST_DEVICE + void compute( real64 const & deltaPressure, + R1Tensor const pressureDependenceConstants, + real64 const (&referencePermeability)[3], + arraySlice1d< real64 > const & permeability, + arraySlice1d< real64 > const & dPerm_dPressure ) const; + + GEOS_HOST_DEVICE + void compute( real64 const & deltaPressure, + R1Tensor const pressureDependenceConstants, + real64 const (&referencePermeability)[3], + real64 const maxPermeability, + arraySlice1d< real64 > const & permeability, + arraySlice1d< real64 > const & dPerm_dPressure ) const; + + GEOS_HOST_DEVICE + virtual void updateFromPressureAndPorosity( localIndex const k, + localIndex const q, + real64 const & pressure, + real64 const & porosity ) const override + { + GEOS_UNUSED_VAR( q, porosity ); + + real64 const deltaPressure = pressure - m_referencePressure; + + real64 referencePermeability[3]; + + referencePermeability[0] = m_referencePermeability[k][0][0]; + referencePermeability[1] = m_referencePermeability[k][0][1]; + referencePermeability[2] = m_referencePermeability[k][0][2]; + + switch( m_presModelType ) + { + case PressureModelType::Exponential: + { + compute( deltaPressure, + m_pressureDependenceConstants, + referencePermeability, + m_permeability[k][0], + m_dPerm_dPressure[k][0] ); + + break; + } + case PressureModelType::Hyperbolic: + { + compute( deltaPressure, + m_pressureDependenceConstants, + referencePermeability, + m_maxPermeability, + m_permeability[k][0], + m_dPerm_dPressure[k][0] ); + + break; + } + default: + { + GEOS_ERROR( "PressureModelType is invalid! It should be either Exponential or Hyperbolic" ); + } + } + } + +private: + + /// Pressure dependence model type + PressureModelType m_presModelType; + + /// Pressure dependent coefficients for each permeability component + R1Tensor m_pressureDependenceConstants; + + /// Reference pressure in the model + real64 const m_referencePressure; + + /// Maximum permeability + real64 const m_maxPermeability; + + arrayView3d< real64 > m_referencePermeability; + +}; + + +class PressurePermeability : public PermeabilityBase +{ +public: + + PressurePermeability( string const & name, Group * const parent ); + + std::unique_ptr< ConstitutiveBase > deliverClone( string const & name, + Group * const parent ) const override; + + virtual void allocateConstitutiveData( dataRepository::Group & parent, + localIndex const numConstitutivePointsPerParentIndex ) override; + + static string catalogName() { return "PressurePermeability"; } + + virtual string getCatalogName() const override { return catalogName(); } + + /// Type of kernel wrapper for in-kernel update + using KernelWrapper = PressurePermeabilityUpdate; + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelWrapper() const + { + return KernelWrapper( m_presModelType, + m_pressureDependenceConstants, + m_referencePressure, + m_maxPermeability, + m_referencePermeability, + m_permeability, + m_dPerm_dPressure ); + } + + struct viewKeyStruct : public PermeabilityBase::viewKeyStruct + { + static constexpr char const * referencePermeabilityComponentsString() { return "referencePermeabilityComponents"; } + static constexpr char const * pressureDependenceConstantsString() { return "pressureDependenceConstants"; } + static constexpr char const * referencePressureString() { return "referencePressure"; } + static constexpr char const * referencePermeabilityString() { return "referencePermeability"; } + static constexpr char const * maxPermeabilityString() { return "maxPermeability"; } + static constexpr char const * pressureModelTypeString() { return "pressureModelType"; } + } viewKeys; + + virtual void initializeState() const override final; + +protected: + + virtual void postInputInitialization() override; + +private: + + /// Permeability components at the reference pressure + R1Tensor m_referencePermeabilityComponents; + + /// Pressure dependent coefficients for each permeability component + R1Tensor m_pressureDependenceConstants; + + /// Reference pressure in the model + real64 m_referencePressure; + + /// Maximum permeability + real64 m_maxPermeability; + + array3d< real64 > m_referencePermeability; + + /// Pressure dependence model type + PressureModelType m_presModelType; + +}; + +GEOS_HOST_DEVICE +GEOS_FORCE_INLINE +void PressurePermeabilityUpdate::compute( real64 const & deltaPressure, + R1Tensor const pressureDependenceConstants, + real64 const (&referencePermeability)[3], + arraySlice1d< real64 > const & permeability, + arraySlice1d< real64 > const & dPerm_dPressure ) const +{ + for( localIndex i=0; i < permeability.size(); i++ ) + { + real64 const perm = referencePermeability[i] * exp( pressureDependenceConstants[i] * deltaPressure ); + + permeability[i] = perm; + dPerm_dPressure[i] = perm * pressureDependenceConstants[i]; + } +} + +GEOS_HOST_DEVICE +GEOS_FORCE_INLINE +void PressurePermeabilityUpdate::compute( real64 const & deltaPressure, + R1Tensor const pressureDependenceConstants, + real64 const (&referencePermeability)[3], + real64 const maxPermeability, + arraySlice1d< real64 > const & permeability, + arraySlice1d< real64 > const & dPerm_dPressure ) const +{ + for( localIndex i=0; i < permeability.size(); i++ ) + { + real64 const pressureOffSet = log( maxPermeability/referencePermeability[i] - 1 )/pressureDependenceConstants[i]; + + real64 const perm = maxPermeability/( 1 + exp( -pressureDependenceConstants[i]*( deltaPressure - pressureOffSet ) ) ); + permeability[i] = perm; + dPerm_dPressure[i] = perm*perm/maxPermeability*pressureDependenceConstants[i]*exp( -pressureDependenceConstants[i]*deltaPressure ); + } +} + +}/* namespace constitutive */ + +} /* namespace geos */ + + +#endif //GEOS_CONSTITUTIVE_PERMEABILITY_PRESSUREPERMEABILITY_HPP_ diff --git a/src/coreComponents/constitutive/permeability/ProppantPermeability.cpp b/src/coreComponents/constitutive/permeability/ProppantPermeability.cpp index 77a8b1eb49f..201afe3fd63 100644 --- a/src/coreComponents/constitutive/permeability/ProppantPermeability.cpp +++ b/src/coreComponents/constitutive/permeability/ProppantPermeability.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -60,7 +61,7 @@ ProppantPermeability::deliverClone( string const & name, return ConstitutiveBase::deliverClone( name, parent ); } -void ProppantPermeability::postProcessInput() +void ProppantPermeability::postInputInitialization() { real64 const oneMinusMaxConcentration = ( 1.0 - m_maxProppantConcentration ); m_proppantPackPermeability = m_proppantDiameter * m_proppantDiameter / 180.0; diff --git a/src/coreComponents/constitutive/permeability/ProppantPermeability.hpp b/src/coreComponents/constitutive/permeability/ProppantPermeability.hpp index f1e8e85b596..73b54febf02 100644 --- a/src/coreComponents/constitutive/permeability/ProppantPermeability.hpp +++ b/src/coreComponents/constitutive/permeability/ProppantPermeability.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -152,7 +153,7 @@ class ProppantPermeability : public PermeabilityBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; private: diff --git a/src/coreComponents/constitutive/permeability/SlipDependentPermeability.cpp b/src/coreComponents/constitutive/permeability/SlipDependentPermeability.cpp index 7873db48ef7..63d17baa9e5 100644 --- a/src/coreComponents/constitutive/permeability/SlipDependentPermeability.cpp +++ b/src/coreComponents/constitutive/permeability/SlipDependentPermeability.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/permeability/SlipDependentPermeability.hpp b/src/coreComponents/constitutive/permeability/SlipDependentPermeability.hpp index 9c6d6a325a8..2c883115fa9 100644 --- a/src/coreComponents/constitutive/permeability/SlipDependentPermeability.hpp +++ b/src/coreComponents/constitutive/permeability/SlipDependentPermeability.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/permeability/WillisRichardsPermeability.cpp b/src/coreComponents/constitutive/permeability/WillisRichardsPermeability.cpp index 7edcbc1b550..b57ae9b5086 100644 --- a/src/coreComponents/constitutive/permeability/WillisRichardsPermeability.cpp +++ b/src/coreComponents/constitutive/permeability/WillisRichardsPermeability.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/permeability/WillisRichardsPermeability.hpp b/src/coreComponents/constitutive/permeability/WillisRichardsPermeability.hpp index f92ea293117..400e8f8356c 100644 --- a/src/coreComponents/constitutive/permeability/WillisRichardsPermeability.hpp +++ b/src/coreComponents/constitutive/permeability/WillisRichardsPermeability.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyBakerRelativePermeability.cpp b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyBakerRelativePermeability.cpp index 8dc5da9a18b..bb8ad661a74 100644 --- a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyBakerRelativePermeability.cpp +++ b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyBakerRelativePermeability.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -65,9 +66,9 @@ BrooksCoreyBakerRelativePermeability::BrooksCoreyBakerRelativePermeability( stri } -void BrooksCoreyBakerRelativePermeability::postProcessInput() +void BrooksCoreyBakerRelativePermeability::postInputInitialization() { - RelativePermeabilityBase::postProcessInput(); + RelativePermeabilityBase::postInputInitialization(); GEOS_THROW_IF( m_phaseOrder[PhaseType::OIL] < 0, GEOS_FMT( "{}: reference oil phase has not been defined and must be included in model", getFullName() ), diff --git a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyBakerRelativePermeability.hpp b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyBakerRelativePermeability.hpp index a2c748bacb5..f1d80333f86 100644 --- a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyBakerRelativePermeability.hpp +++ b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyBakerRelativePermeability.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -39,9 +40,9 @@ class BrooksCoreyBakerRelativePermeabilityUpdate final : public RelativePermeabi real64 const volFracScale, arrayView1d< integer const > const & phaseTypes, arrayView1d< integer const > const & phaseOrder, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseRelPerm, - arrayView4d< real64, relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseTrappedVolFrac ) + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseRelPerm, + arrayView4d< real64, constitutive::relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseTrappedVolFrac ) : RelativePermeabilityBaseUpdate( phaseTypes, phaseOrder, phaseRelPerm, @@ -57,9 +58,9 @@ class BrooksCoreyBakerRelativePermeabilityUpdate final : public RelativePermeabi GEOS_HOST_DEVICE void compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; GEOS_HOST_DEVICE virtual void update( localIndex const k, @@ -85,7 +86,7 @@ class BrooksCoreyBakerRelativePermeabilityUpdate final : public RelativePermeabi * @param[in] maxValue the endpoint relative permeability value * * This function evaluates the relperm function and its derivative at a given phase saturation - * Reference: Eclipse technical description and Petrowiki + * Reference: Petrowiki */ GEOS_HOST_DEVICE GEOS_FORCE_INLINE @@ -143,7 +144,7 @@ class BrooksCoreyBakerRelativePermeability : public RelativePermeabilityBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; array1d< real64 > m_phaseMinVolumeFraction; @@ -163,9 +164,9 @@ GEOS_HOST_DEVICE inline void BrooksCoreyBakerRelativePermeabilityUpdate:: compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const { LvArray::forValuesInSlice( dPhaseRelPerm_dPhaseVolFrac, []( real64 & val ){ val = 0.0; } ); diff --git a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyRelativePermeability.cpp b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyRelativePermeability.cpp index 30f2a310abd..2c64e5de56c 100644 --- a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyRelativePermeability.cpp +++ b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyRelativePermeability.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -56,9 +57,9 @@ BrooksCoreyRelativePermeability::BrooksCoreyRelativePermeability( string const & } -void BrooksCoreyRelativePermeability::postProcessInput() +void BrooksCoreyRelativePermeability::postInputInitialization() { - RelativePermeabilityBase::postProcessInput(); + RelativePermeabilityBase::postInputInitialization(); auto const checkInputSize = [&]( auto const & array, auto const & attribute ) { diff --git a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyRelativePermeability.hpp b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyRelativePermeability.hpp index 5e8890f32f5..4518603dc3e 100644 --- a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyRelativePermeability.hpp +++ b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyRelativePermeability.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -36,9 +37,9 @@ class BrooksCoreyRelativePermeabilityUpdate final : public RelativePermeabilityB real64 const volFracScale, arrayView1d< integer const > const & phaseTypes, arrayView1d< integer const > const & phaseOrder, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseRelPerm, - arrayView4d< real64, relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseTrappedVolFrac ) + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseRelPerm, + arrayView4d< real64, constitutive::relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseTrappedVolFrac ) : RelativePermeabilityBaseUpdate( phaseTypes, phaseOrder, phaseRelPerm, @@ -52,9 +53,9 @@ class BrooksCoreyRelativePermeabilityUpdate final : public RelativePermeabilityB GEOS_HOST_DEVICE void compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; GEOS_HOST_DEVICE virtual void update( localIndex const k, @@ -109,7 +110,7 @@ class BrooksCoreyRelativePermeability : public RelativePermeabilityBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; //START_SPHINX_INCLUDE_02 array1d< real64 > m_phaseMinVolumeFraction; @@ -124,9 +125,9 @@ GEOS_HOST_DEVICE inline void BrooksCoreyRelativePermeabilityUpdate:: compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const { LvArray::forValuesInSlice( dPhaseRelPerm_dPhaseVolFrac, []( real64 & val ){ val = 0.0; } ); diff --git a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyStone2RelativePermeability.cpp b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyStone2RelativePermeability.cpp index 2ab7a3ff330..8eb25929ddb 100644 --- a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyStone2RelativePermeability.cpp +++ b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyStone2RelativePermeability.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -65,9 +66,9 @@ BrooksCoreyStone2RelativePermeability::BrooksCoreyStone2RelativePermeability( st } -void BrooksCoreyStone2RelativePermeability::postProcessInput() +void BrooksCoreyStone2RelativePermeability::postInputInitialization() { - RelativePermeabilityBase::postProcessInput(); + RelativePermeabilityBase::postInputInitialization(); GEOS_THROW_IF( m_phaseOrder[PhaseType::OIL] < 0, GEOS_FMT( "{}: reference oil phase has not been defined and must be included in model", getFullName() ), diff --git a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyStone2RelativePermeability.hpp b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyStone2RelativePermeability.hpp index df5b11d80a6..7cb1a097537 100644 --- a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyStone2RelativePermeability.hpp +++ b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyStone2RelativePermeability.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -39,9 +40,9 @@ class BrooksCoreyStone2RelativePermeabilityUpdate final : public RelativePermeab real64 const volFracScale, arrayView1d< integer const > const & phaseTypes, arrayView1d< integer const > const & phaseOrder, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseRelPerm, - arrayView4d< real64, relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseTrappedVolFrac ) + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseRelPerm, + arrayView4d< real64, constitutive::relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseTrappedVolFrac ) : RelativePermeabilityBaseUpdate( phaseTypes, phaseOrder, phaseRelPerm, @@ -57,9 +58,9 @@ class BrooksCoreyStone2RelativePermeabilityUpdate final : public RelativePermeab GEOS_HOST_DEVICE void compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; GEOS_HOST_DEVICE virtual void update( localIndex const k, @@ -85,7 +86,7 @@ class BrooksCoreyStone2RelativePermeabilityUpdate final : public RelativePermeab * @param[in] maxValue the endpoint relative permeability value * * This function evaluates the relperm function and its derivative at a given phase saturation - * Reference: Eclipse technical description and Petrowiki + * Reference: Petrowiki */ GEOS_HOST_DEVICE inline @@ -141,7 +142,7 @@ class BrooksCoreyStone2RelativePermeability : public RelativePermeabilityBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; array1d< real64 > m_phaseMinVolumeFraction; @@ -161,9 +162,9 @@ GEOS_HOST_DEVICE inline void BrooksCoreyStone2RelativePermeabilityUpdate:: compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const { LvArray::forValuesInSlice( dPhaseRelPerm_dPhaseVolFrac, []( real64 & val ){ val = 0.0; } ); diff --git a/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.cpp b/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.cpp index d72ce6443b6..1376c0a6b6a 100644 --- a/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.cpp +++ b/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -50,9 +51,9 @@ RelativePermeabilityBase::RelativePermeabilityBase( string const & name, Group * } -void RelativePermeabilityBase::postProcessInput() +void RelativePermeabilityBase::postInputInitialization() { - ConstitutiveBase::postProcessInput(); + ConstitutiveBase::postInputInitialization(); integer const numPhases = numFluidPhases(); GEOS_THROW_IF_LT_MSG( numPhases, 2, diff --git a/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.hpp b/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.hpp index e0315f8afa3..9fac61f555e 100644 --- a/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.hpp +++ b/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -23,7 +24,7 @@ #include "constitutive/ConstitutiveBase.hpp" #include "constitutive/relativePermeability/layouts.hpp" #include "common/GEOS_RAJA_Interface.hpp" -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" namespace geos { @@ -57,7 +58,7 @@ class RelativePermeabilityBaseUpdate */ GEOS_HOST_DEVICE - arrayView3d< real64 const, relperm::USD_RELPERM > relperm() const + arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > relperm() const { return m_phaseRelPerm; } /** @@ -86,9 +87,9 @@ class RelativePermeabilityBaseUpdate RelativePermeabilityBaseUpdate( arrayView1d< integer const > const & phaseTypes, arrayView1d< integer const > const & phaseOrder, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseRelPerm, - arrayView4d< real64, relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseTrappedVolFrac ) + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseRelPerm, + arrayView4d< real64, constitutive::relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseTrappedVolFrac ) : m_phaseTypes( phaseTypes ), m_phaseOrder( phaseOrder ), m_phaseRelPerm( phaseRelPerm ), @@ -98,10 +99,10 @@ class RelativePermeabilityBaseUpdate arrayView1d< integer const > m_phaseTypes; arrayView1d< integer const > m_phaseOrder; - arrayView3d< real64, relperm::USD_RELPERM > m_phaseRelPerm; - arrayView4d< real64, relperm::USD_RELPERM_DS > m_dPhaseRelPerm_dPhaseVolFrac; + arrayView3d< real64, constitutive::relperm::USD_RELPERM > m_phaseRelPerm; + arrayView4d< real64, constitutive::relperm::USD_RELPERM_DS > m_dPhaseRelPerm_dPhaseVolFrac; - arrayView3d< real64, relperm::USD_RELPERM > m_phaseTrappedVolFrac; + arrayView3d< real64, constitutive::relperm::USD_RELPERM > m_phaseTrappedVolFrac; private: GEOS_HOST_DEVICE @@ -156,10 +157,10 @@ class RelativePermeabilityBase : public ConstitutiveBase arrayView1d< string const > phaseNames() const { return m_phaseNames; } - arrayView3d< real64 const, relperm::USD_RELPERM > phaseTrappedVolFraction() const { return m_phaseTrappedVolFrac; } + arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > phaseTrappedVolFraction() const { return m_phaseTrappedVolFrac; } - arrayView3d< real64 const, relperm::USD_RELPERM > phaseRelPerm() const { return m_phaseRelPerm; } - arrayView4d< real64 const, relperm::USD_RELPERM_DS > dPhaseRelPerm_dPhaseVolFraction() const { return m_dPhaseRelPerm_dPhaseVolFrac; } + arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > phaseRelPerm() const { return m_phaseRelPerm; } + arrayView4d< real64 const, constitutive::relperm::USD_RELPERM_DS > dPhaseRelPerm_dPhaseVolFraction() const { return m_dPhaseRelPerm_dPhaseVolFrac; } arrayView1d< integer const > getPhaseOrder() const { return m_phaseOrder; } virtual arrayView1d< real64 const > getPhaseMinVolumeFraction() const = 0; @@ -200,7 +201,7 @@ class RelativePermeabilityBase : public ConstitutiveBase */ virtual void resizeFields( localIndex const size, localIndex const numPts ); - virtual void postProcessInput() override; + virtual void postInputInitialization() override; // phase names read from input string_array m_phaseNames; @@ -212,10 +213,10 @@ class RelativePermeabilityBase : public ConstitutiveBase protected: // output quantities - array3d< real64, relperm::LAYOUT_RELPERM > m_phaseRelPerm; - array3d< real64, relperm::LAYOUT_RELPERM > m_phaseRelPerm_n; - array4d< real64, relperm::LAYOUT_RELPERM_DS > m_dPhaseRelPerm_dPhaseVolFrac; - array3d< real64, relperm::LAYOUT_RELPERM > m_phaseTrappedVolFrac; + array3d< real64, constitutive::relperm::LAYOUT_RELPERM > m_phaseRelPerm; + array3d< real64, constitutive::relperm::LAYOUT_RELPERM > m_phaseRelPerm_n; + array4d< real64, constitutive::relperm::LAYOUT_RELPERM_DS > m_dPhaseRelPerm_dPhaseVolFrac; + array3d< real64, constitutive::relperm::LAYOUT_RELPERM > m_phaseTrappedVolFrac; }; diff --git a/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityFields.hpp b/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityFields.hpp index edaf4a48a5c..06f4cf37ec8 100644 --- a/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityFields.hpp +++ b/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityInterpolators.hpp b/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityInterpolators.hpp index 9db8b526d05..7f44d468490 100644 --- a/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityInterpolators.hpp +++ b/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityInterpolators.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -45,8 +46,8 @@ struct Baker * @param[in] dGoRelPerm_dOilVolFrac * * This function interpolates the two-phase relperms to compute the three-phase relperm - * The interpolation is based on the modified Baker method, also used as default in Eclipse - * Reference: Eclipse technical description and PetroWiki + * The interpolation is based on the modified Baker method + * Reference: PetroWiki */ GEOS_HOST_DEVICE GEOS_FORCE_INLINE @@ -59,7 +60,7 @@ struct Baker real64 const & goRelPerm, real64 const & dGoRelPerm_dOilVolFrac, real64 & threePhaseRelPerm, - arraySlice1d< real64, relperm::USD_RELPERM_DS - 3 > const & dThreePhaseRelPerm_dVolFrac ) + arraySlice1d< real64, constitutive::relperm::USD_RELPERM_DS - 3 > const & dThreePhaseRelPerm_dVolFrac ) { using PT = RelativePermeabilityBase::PhaseType; integer const ipWater = phaseOrder[PT::WATER]; @@ -130,7 +131,6 @@ struct Stone2 * * This function interpolates the two-phase relperms to compute the three-phase relperm * The interpolation is based on the modified Stone 2 method - * Reference: Eclipse technical description */ GEOS_HOST_DEVICE GEOS_FORCE_INLINE @@ -147,7 +147,7 @@ struct Stone2 real64 const & gRelPerm, real64 const & dGRelPerm_dGasVolFrac, real64 & threePhaseRelPerm, - arraySlice1d< real64, relperm::USD_RELPERM_DS - 3 > const & dThreePhaseRelPerm_dVolFrac ) + arraySlice1d< real64, constitutive::relperm::USD_RELPERM_DS - 3 > const & dThreePhaseRelPerm_dVolFrac ) { using PT = RelativePermeabilityBase::PhaseType; diff --git a/src/coreComponents/constitutive/relativePermeability/RelativePermeabilitySelector.hpp b/src/coreComponents/constitutive/relativePermeability/RelativePermeabilitySelector.hpp index 3663125c744..ee20a4c4f6e 100644 --- a/src/coreComponents/constitutive/relativePermeability/RelativePermeabilitySelector.hpp +++ b/src/coreComponents/constitutive/relativePermeability/RelativePermeabilitySelector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -50,7 +51,7 @@ void constitutiveUpdatePassThru( RelativePermeabilityBase const & relPerm, BrooksCoreyBakerRelativePermeability, BrooksCoreyStone2RelativePermeability, TableRelativePermeability, - TableRelativePermeabilityHysteresis, + constitutive::TableRelativePermeabilityHysteresis, VanGenuchtenBakerRelativePermeability, VanGenuchtenStone2RelativePermeability >::execute( relPerm, std::forward< LAMBDA >( lambda ) ); } @@ -63,7 +64,7 @@ void constitutiveUpdatePassThru( RelativePermeabilityBase & relPerm, BrooksCoreyBakerRelativePermeability, BrooksCoreyStone2RelativePermeability, TableRelativePermeability, - TableRelativePermeabilityHysteresis, + constitutive::TableRelativePermeabilityHysteresis, VanGenuchtenBakerRelativePermeability, VanGenuchtenStone2RelativePermeability >::execute( relPerm, std::forward< LAMBDA >( lambda ) ); } diff --git a/src/coreComponents/constitutive/relativePermeability/RelpermDriverBrooksCoreyBakerRunTest.cpp b/src/coreComponents/constitutive/relativePermeability/RelpermDriverBrooksCoreyBakerRunTest.cpp deleted file mode 100644 index 02bc968c4f8..00000000000 --- a/src/coreComponents/constitutive/relativePermeability/RelpermDriverBrooksCoreyBakerRunTest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -#include "RelpermDriverRunTest.hpp" -#include "BrooksCoreyBakerRelativePermeability.hpp" - - -namespace geos -{ -template void RelpermDriver::runTest< geos::constitutive::BrooksCoreyBakerRelativePermeability >( geos::constitutive::BrooksCoreyBakerRelativePermeability &, arrayView2d< real64 > const & ); -} diff --git a/src/coreComponents/constitutive/relativePermeability/RelpermDriverBrooksCoreyRunTest.cpp b/src/coreComponents/constitutive/relativePermeability/RelpermDriverBrooksCoreyRunTest.cpp deleted file mode 100644 index 74a4c4e0e4c..00000000000 --- a/src/coreComponents/constitutive/relativePermeability/RelpermDriverBrooksCoreyRunTest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -#include "RelpermDriverRunTest.hpp" -#include "BrooksCoreyRelativePermeability.hpp" - - -namespace geos -{ -template void RelpermDriver::runTest< geos::constitutive::BrooksCoreyRelativePermeability >( geos::constitutive::BrooksCoreyRelativePermeability &, arrayView2d< real64 > const & ); -} diff --git a/src/coreComponents/constitutive/relativePermeability/RelpermDriverBrooksCoreyStone2RunTest.cpp b/src/coreComponents/constitutive/relativePermeability/RelpermDriverBrooksCoreyStone2RunTest.cpp deleted file mode 100644 index 38cbc3e527e..00000000000 --- a/src/coreComponents/constitutive/relativePermeability/RelpermDriverBrooksCoreyStone2RunTest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -#include "RelpermDriverRunTest.hpp" -#include "BrooksCoreyStone2RelativePermeability.hpp" - - -namespace geos -{ -template void RelpermDriver::runTest< geos::constitutive::BrooksCoreyStone2RelativePermeability >( geos::constitutive::BrooksCoreyStone2RelativePermeability &, arrayView2d< real64 > const & ); -} diff --git a/src/coreComponents/constitutive/relativePermeability/RelpermDriverTableRelativeHysteresisRunTest.cpp b/src/coreComponents/constitutive/relativePermeability/RelpermDriverTableRelativeHysteresisRunTest.cpp deleted file mode 100644 index 674eab909f8..00000000000 --- a/src/coreComponents/constitutive/relativePermeability/RelpermDriverTableRelativeHysteresisRunTest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -#include "RelpermDriverRunTest.hpp" -#include "TableRelativePermeabilityHysteresis.hpp" - - -namespace geos -{ -template void RelpermDriver::runTest< geos::constitutive::TableRelativePermeabilityHysteresis >( geos::constitutive::TableRelativePermeabilityHysteresis &, arrayView2d< real64 > const & ); -} diff --git a/src/coreComponents/constitutive/relativePermeability/RelpermDriverTableRelativeRunTest.cpp b/src/coreComponents/constitutive/relativePermeability/RelpermDriverTableRelativeRunTest.cpp deleted file mode 100644 index 6ad567b039b..00000000000 --- a/src/coreComponents/constitutive/relativePermeability/RelpermDriverTableRelativeRunTest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -#include "RelpermDriverRunTest.hpp" -#include "TableRelativePermeability.hpp" - - -namespace geos -{ -template void RelpermDriver::runTest< geos::constitutive::TableRelativePermeability >( geos::constitutive::TableRelativePermeability &, arrayView2d< real64 > const & ); -} diff --git a/src/coreComponents/constitutive/relativePermeability/RelpermDriverVanGenuchtenBakerRunTest.cpp b/src/coreComponents/constitutive/relativePermeability/RelpermDriverVanGenuchtenBakerRunTest.cpp deleted file mode 100644 index 361be63b991..00000000000 --- a/src/coreComponents/constitutive/relativePermeability/RelpermDriverVanGenuchtenBakerRunTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ -#include "RelpermDriverRunTest.hpp" -#include "VanGenuchtenBakerRelativePermeability.hpp" - - -namespace geos -{ -template void RelpermDriver::runTest< geos::constitutive::VanGenuchtenBakerRelativePermeability >( geos::constitutive::VanGenuchtenBakerRelativePermeability &, arrayView2d< real64 > const & ); -} diff --git a/src/coreComponents/constitutive/relativePermeability/RelpermDriverVanGenuchtenStone2RunTest.cpp b/src/coreComponents/constitutive/relativePermeability/RelpermDriverVanGenuchtenStone2RunTest.cpp deleted file mode 100644 index a9bd123e879..00000000000 --- a/src/coreComponents/constitutive/relativePermeability/RelpermDriverVanGenuchtenStone2RunTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ -#include "RelpermDriverRunTest.hpp" -#include "VanGenuchtenStone2RelativePermeability.hpp" - - -namespace geos -{ -template void RelpermDriver::runTest< geos::constitutive::VanGenuchtenStone2RelativePermeability >( geos::constitutive::VanGenuchtenStone2RelativePermeability &, arrayView2d< real64 > const & ); -} diff --git a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeability.cpp b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeability.cpp index 74a2dba31af..cd88449a1b1 100644 --- a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeability.cpp +++ b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeability.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -84,9 +85,9 @@ TableRelativePermeability::TableRelativePermeability( std::string const & name, "Valid options \n* " + EnumStrings< ThreePhaseInterpolator >::concat( "\n* " ) ); } -void TableRelativePermeability::postProcessInput() +void TableRelativePermeability::postInputInitialization() { - RelativePermeabilityBase::postProcessInput(); + RelativePermeabilityBase::postInputInitialization(); integer const numPhases = m_phaseNames.size(); GEOS_THROW_IF( numPhases != 2 && numPhases != 3, diff --git a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeability.hpp b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeability.hpp index e0dbf5a59e4..363cea73608 100644 --- a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeability.hpp +++ b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeability.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -72,31 +73,31 @@ class TableRelativePermeability : public RelativePermeabilityBase arrayView1d< integer const > const & phaseTypes, arrayView1d< integer const > const & phaseOrder, ThreePhaseInterpolator const & threePhaseInterpolator, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseRelPerm, - arrayView4d< real64, relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseTrappedVolFrac ); + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseRelPerm, + arrayView4d< real64, constitutive::relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseTrappedVolFrac ); GEOS_HOST_DEVICE void computeTwoPhase( integer const ipWetting, integer const ipNonWetting, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; GEOS_HOST_DEVICE void computeThreePhase( integer const ipWetting, integer const ipInter, integer const ipNonWetting, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; GEOS_HOST_DEVICE void compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; GEOS_HOST_DEVICE virtual void update( localIndex const k, @@ -145,7 +146,7 @@ class TableRelativePermeability : public RelativePermeabilityBase private: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void initializePreSubGroups() override; @@ -189,8 +190,8 @@ TableRelativePermeability::KernelWrapper:: computeTwoPhase( integer const ipWetting, integer const ipNonWetting, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const { using TPT = TableRelativePermeability::TwoPhasePairPhaseType; @@ -215,8 +216,8 @@ TableRelativePermeability::KernelWrapper:: integer const ipInter, integer const ipNonWetting, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const { real64 interRelPerm_wi = 0; // oil rel perm using two-phase gas-oil data real64 dInterRelPerm_wi_dInterVolFrac = 0; // derivative w.r.t to So @@ -294,9 +295,9 @@ GEOS_HOST_DEVICE inline void TableRelativePermeability::KernelWrapper:: compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const { LvArray::forValuesInSlice( dPhaseRelPerm_dPhaseVolFrac, []( real64 & val ){ val = 0.0; } ); diff --git a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHelpers.cpp b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHelpers.cpp index ea15c74924e..0edd1537af7 100644 --- a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHelpers.cpp +++ b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHelpers.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHelpers.hpp b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHelpers.hpp index 1b6ca0123b8..275949a41ff 100644 --- a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHelpers.hpp +++ b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHelpers.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.cpp b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.cpp index 79ae8653649..44ce342cd09 100644 --- a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.cpp +++ b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,7 +22,6 @@ #include "constitutive/relativePermeability/RelativePermeabilityFields.hpp" #include "constitutive/relativePermeability/TableRelativePermeabilityHelpers.hpp" #include "functions/FunctionManager.hpp" -#include "constitutive/relativePermeability/RelpermDriver.hpp" namespace geos { @@ -161,9 +161,9 @@ TableRelativePermeabilityHysteresis::TableRelativePermeabilityHysteresis( std::s } -void TableRelativePermeabilityHysteresis::postProcessInput() +void TableRelativePermeabilityHysteresis::postInputInitialization() { - RelativePermeabilityBase::postProcessInput(); + RelativePermeabilityBase::postInputInitialization(); using IPT = TableRelativePermeabilityHysteresis::ImbibitionPhasePairPhaseType; @@ -488,7 +488,7 @@ void TableRelativePermeabilityHysteresis::computeLandCoefficient() ipNonWetting = m_phaseOrder[PhaseType::GAS]; } - // Note: for simplicity, the notations are taken from IX documentation (although this breaks our phaseVolFrac naming convention) + // Note: for simplicity, the notations are taken reservoir simulation literature (although this breaks our phaseVolFrac naming convention) // Step 1: Land parameter for the wetting phase diff --git a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.hpp b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.hpp index b4275a01594..f5390ff7034 100644 --- a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.hpp +++ b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -134,9 +135,9 @@ class TableRelativePermeabilityHysteresis : public RelativePermeabilityBase real64 const & waterOilRelPermMaxValue, arrayView2d< real64 const, compflow::USD_PHASE > const & phaseMinHistoricalVolFraction, arrayView2d< real64 const, compflow::USD_PHASE > const & phaseMaxHistoricalVolFraction, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseTrappedVolFrac, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseRelPerm, - arrayView4d< real64, relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac ); + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseTrappedVolFrac, + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseRelPerm, + arrayView4d< real64, constitutive::relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac ); /** * @brief Function updating the relperm (and derivative) for a phase using the drainage table @@ -255,10 +256,10 @@ class TableRelativePermeabilityHysteresis : public RelativePermeabilityBase arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMaxHistoricalVolFraction, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMinHistoricalVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, arraySlice2d< real64, - relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; + constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; /** * @brief Function updating all the phase relperms (and derivatives) for three-phase flow @@ -280,10 +281,10 @@ class TableRelativePermeabilityHysteresis : public RelativePermeabilityBase arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMaxHistoricalVolFraction, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMinHistoricalVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, arraySlice2d< real64, - relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; + constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; /** * @brief Main function updating all the phase relperms (and derivatives) @@ -297,9 +298,9 @@ class TableRelativePermeabilityHysteresis : public RelativePermeabilityBase void compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMaxHistoricalVolFraction, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMinHistoricalVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; GEOS_HOST_DEVICE virtual void update( localIndex const k, @@ -447,7 +448,7 @@ class TableRelativePermeabilityHysteresis : public RelativePermeabilityBase private: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void initializePreSubGroups() override; @@ -567,7 +568,7 @@ class TableRelativePermeabilityHysteresis : public RelativePermeabilityBase /// Max krwo value (unique as krwo and krgo are considred non hysteretical in our implementation) real64 m_waterOilMaxRelPerm; - /// enum class to dispatch interpolator (Baker/Eclipse,StoneII) + /// enum class to dispatch interpolator (Baker,StoneII) ThreePhaseInterpolator m_threePhaseInterpolator; }; @@ -710,11 +711,11 @@ TableRelativePermeabilityHysteresis::KernelWrapper:: real64 & phaseRelPerm, real64 & dPhaseRelPerm_dPhaseVolFrac ) const { - // note: for simplicity, the notations are taken from IX documentation (although this breaks our phaseVolFrac naming convention) + // note: for simplicity, the notations are taken from reservoir simulation literature (although this breaks our phaseVolFrac naming + // convention) // Step 1: for a given value of the max historical saturation, Shy, compute the trapped critical saturation, Scrt, - // using Land's method. The calculation includes the modifications from Jerauld. This is equation 2.162 from - // the IX technical description. + // using Land's method. The calculation includes the modifications from Jerauld. real64 const S = phaseVolFraction; real64 const Scri = imbibitionPhaseMinVolFraction; real64 const Scrd = drainagePhaseMinVolFraction; @@ -743,9 +744,8 @@ TableRelativePermeabilityHysteresis::KernelWrapper:: else { // Step 2: compute the normalized saturation, S_norm, at which the imbibition relperm curve will be evaluated. - // This is equation 2.166 from the IX technical description. real64 const ratio = ( Smx - Scri ) / ( Shy - Scrt ); - real64 const Snorm = Scri + ( S - Scrt ) * ratio; // normalized saturation from equation 2.166 + real64 const Snorm = Scri + ( S - Scrt ) * ratio; // normalized saturation real64 const dSnorm_dS = ratio; // Step 3: evaluate the imbibition relperm, kri(Snorm), at the normalized saturation, Snorm. @@ -760,7 +760,6 @@ TableRelativePermeabilityHysteresis::KernelWrapper:: real64 const krdAtSmx = drainageRelPermEndPoint; // Step 6: apply the formula blending drainage and imbibition relperms from the Killough model. - // This equation 2.165 from the IX technical description. real64 const drainageRelPermRatio = krdAtShy / krdAtSmx; phaseRelPerm = kriAtSnorm * drainageRelPermRatio; dPhaseRelPerm_dPhaseVolFrac = dkriAtSnorm_dS * drainageRelPermRatio; @@ -779,12 +778,12 @@ TableRelativePermeabilityHysteresis::KernelWrapper:: arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMaxHistoricalVolFraction, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMinHistoricalVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const { - using TPT = TableRelativePermeabilityHysteresis::TwoPhasePairPhaseType; - using IPT = TableRelativePermeabilityHysteresis::ImbibitionPhasePairPhaseType; + using TPT = constitutive::TableRelativePermeabilityHysteresis::TwoPhasePairPhaseType; + using IPT = constitutive::TableRelativePermeabilityHysteresis::ImbibitionPhasePairPhaseType; // ---------- wetting rel perm if( !m_phaseHasHysteresis[IPT::WETTING] || @@ -869,17 +868,17 @@ TableRelativePermeabilityHysteresis::KernelWrapper:: arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMaxHistoricalVolFraction, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMinHistoricalVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const { real64 interRelPerm_wi = 0; // oil rel perm using two-phase gas-oil data real64 dInterRelPerm_wi_dInterVolFrac = 0; // derivative w.r.t to So real64 interRelPerm_nwi = 0; // oil rel perm using two-phase gas-oil data real64 dInterRelPerm_nwi_dInterVolFrac = 0; // derivative w.r.t to So - using TPT = TableRelativePermeabilityHysteresis::ThreePhasePairPhaseType; - using IPT = TableRelativePermeabilityHysteresis::ImbibitionPhasePairPhaseType; + using TPT = constitutive::TableRelativePermeabilityHysteresis::ThreePhasePairPhaseType; + using IPT = constitutive::TableRelativePermeabilityHysteresis::ImbibitionPhasePairPhaseType; // 1) Wetting and intermediate phase relative permeabilities using two-phase wetting-intermediate data @@ -1012,9 +1011,9 @@ TableRelativePermeabilityHysteresis::KernelWrapper:: compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMaxHistoricalVolFraction, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMinHistoricalVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const { LvArray::forValuesInSlice( dPhaseRelPerm_dPhaseVolFrac, []( real64 & val ) { val = 0.0; } ); diff --git a/src/coreComponents/constitutive/relativePermeability/VanGenuchtenBakerRelativePermeability.cpp b/src/coreComponents/constitutive/relativePermeability/VanGenuchtenBakerRelativePermeability.cpp index ba5b2fb2e97..12823c81163 100644 --- a/src/coreComponents/constitutive/relativePermeability/VanGenuchtenBakerRelativePermeability.cpp +++ b/src/coreComponents/constitutive/relativePermeability/VanGenuchtenBakerRelativePermeability.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -67,9 +68,9 @@ VanGenuchtenBakerRelativePermeability::VanGenuchtenBakerRelativePermeability( st } -void VanGenuchtenBakerRelativePermeability::postProcessInput() +void VanGenuchtenBakerRelativePermeability::postInputInitialization() { - RelativePermeabilityBase::postProcessInput(); + RelativePermeabilityBase::postInputInitialization(); GEOS_THROW_IF( m_phaseOrder[PhaseType::OIL] < 0, GEOS_FMT( "{}: reference oil phase has not been defined and must be included in model", getFullName() ), diff --git a/src/coreComponents/constitutive/relativePermeability/VanGenuchtenBakerRelativePermeability.hpp b/src/coreComponents/constitutive/relativePermeability/VanGenuchtenBakerRelativePermeability.hpp index c38ce75a230..dae8a72c3c7 100644 --- a/src/coreComponents/constitutive/relativePermeability/VanGenuchtenBakerRelativePermeability.hpp +++ b/src/coreComponents/constitutive/relativePermeability/VanGenuchtenBakerRelativePermeability.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -39,9 +40,9 @@ class VanGenuchtenBakerRelativePermeabilityUpdate final : public RelativePermeab real64 const volFracScale, arrayView1d< integer const > const & phaseTypes, arrayView1d< integer const > const & phaseOrder, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseRelPerm, - arrayView4d< real64, relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseTrappedVolFrac ) + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseRelPerm, + arrayView4d< real64, constitutive::relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseTrappedVolFrac ) : RelativePermeabilityBaseUpdate( phaseTypes, phaseOrder, phaseRelPerm, @@ -57,9 +58,9 @@ class VanGenuchtenBakerRelativePermeabilityUpdate final : public RelativePermeab GEOS_HOST_DEVICE void compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; GEOS_HOST_DEVICE virtual void update( localIndex const k, @@ -86,7 +87,7 @@ class VanGenuchtenBakerRelativePermeabilityUpdate final : public RelativePermeab * @return (void) * * This function evaluates the relperm function and its derivative at a given phase saturation - * Reference: Eclipse technical description and Petrowiki + * Reference: Petrowiki */ GEOS_HOST_DEVICE GEOS_FORCE_INLINE @@ -141,7 +142,7 @@ class VanGenuchtenBakerRelativePermeability : public RelativePermeabilityBase arrayView1d< real64 const > getPhaseMinVolumeFraction() const override { return m_phaseMinVolumeFraction; }; protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; array1d< real64 > m_phaseMinVolumeFraction; @@ -161,9 +162,9 @@ GEOS_HOST_DEVICE inline void VanGenuchtenBakerRelativePermeabilityUpdate:: compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const { LvArray::forValuesInSlice( dPhaseRelPerm_dPhaseVolFrac, []( real64 & val ){ val = 0.0; } ); diff --git a/src/coreComponents/constitutive/relativePermeability/VanGenuchtenStone2RelativePermeability.cpp b/src/coreComponents/constitutive/relativePermeability/VanGenuchtenStone2RelativePermeability.cpp index 020e9c24a9e..dbb0ee05f0e 100644 --- a/src/coreComponents/constitutive/relativePermeability/VanGenuchtenStone2RelativePermeability.cpp +++ b/src/coreComponents/constitutive/relativePermeability/VanGenuchtenStone2RelativePermeability.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -67,9 +68,9 @@ VanGenuchtenStone2RelativePermeability::VanGenuchtenStone2RelativePermeability( } -void VanGenuchtenStone2RelativePermeability::postProcessInput() +void VanGenuchtenStone2RelativePermeability::postInputInitialization() { - RelativePermeabilityBase::postProcessInput(); + RelativePermeabilityBase::postInputInitialization(); GEOS_THROW_IF( m_phaseOrder[PhaseType::OIL] < 0, GEOS_FMT( "{}: reference oil phase has not been defined and must be included in model", getFullName() ), diff --git a/src/coreComponents/constitutive/relativePermeability/VanGenuchtenStone2RelativePermeability.hpp b/src/coreComponents/constitutive/relativePermeability/VanGenuchtenStone2RelativePermeability.hpp index 3e93a8264e5..8a9c6db6217 100644 --- a/src/coreComponents/constitutive/relativePermeability/VanGenuchtenStone2RelativePermeability.hpp +++ b/src/coreComponents/constitutive/relativePermeability/VanGenuchtenStone2RelativePermeability.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -39,9 +40,9 @@ class VanGenuchtenStone2RelativePermeabilityUpdate final : public RelativePermea real64 const volFracScale, arrayView1d< integer const > const & phaseTypes, arrayView1d< integer const > const & phaseOrder, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseRelPerm, - arrayView4d< real64, relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, - arrayView3d< real64, relperm::USD_RELPERM > const & phaseTrappedVolFrac ) + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseRelPerm, + arrayView4d< real64, constitutive::relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, + arrayView3d< real64, constitutive::relperm::USD_RELPERM > const & phaseTrappedVolFrac ) : RelativePermeabilityBaseUpdate( phaseTypes, phaseOrder, phaseRelPerm, @@ -57,9 +58,9 @@ class VanGenuchtenStone2RelativePermeabilityUpdate final : public RelativePermea GEOS_HOST_DEVICE void compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const; GEOS_HOST_DEVICE virtual void update( localIndex const k, @@ -86,7 +87,7 @@ class VanGenuchtenStone2RelativePermeabilityUpdate final : public RelativePermea * @return (void) * * This function evaluates the relperm function and its derivative at a given phase saturation - * Reference: Eclipse technical description and Petrowiki + * Reference: Petrowiki */ GEOS_HOST_DEVICE inline @@ -142,7 +143,7 @@ class VanGenuchtenStone2RelativePermeability : public RelativePermeabilityBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; array1d< real64 > m_phaseMinVolumeFraction; @@ -162,9 +163,9 @@ GEOS_HOST_DEVICE inline void VanGenuchtenStone2RelativePermeabilityUpdate:: compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, - arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseRelPerm, - arraySlice2d< real64, relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac, + arraySlice1d< real64, constitutive::relperm::USD_RELPERM - 2 > const & phaseRelPerm, + arraySlice2d< real64, constitutive::relperm::USD_RELPERM_DS - 2 > const & dPhaseRelPerm_dPhaseVolFrac ) const { LvArray::forValuesInSlice( dPhaseRelPerm_dPhaseVolFrac, []( real64 & val ){ val = 0.0; } ); diff --git a/src/coreComponents/constitutive/relativePermeability/layouts.hpp b/src/coreComponents/constitutive/relativePermeability/layouts.hpp index 26313873498..9343a7a36a6 100644 --- a/src/coreComponents/constitutive/relativePermeability/layouts.hpp +++ b/src/coreComponents/constitutive/relativePermeability/layouts.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/solid/CeramicDamage.cpp b/src/coreComponents/constitutive/solid/CeramicDamage.cpp index 592fd05ab35..389cf93a711 100644 --- a/src/coreComponents/constitutive/solid/CeramicDamage.cpp +++ b/src/coreComponents/constitutive/solid/CeramicDamage.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -83,9 +84,9 @@ void CeramicDamage::allocateConstitutiveData( dataRepository::Group & parent, } -void CeramicDamage::postProcessInput() +void CeramicDamage::postInputInitialization() { - ElasticIsotropic::postProcessInput(); + ElasticIsotropic::postInputInitialization(); GEOS_THROW_IF( m_tensileStrength < 0.0, "Tensile strength must be a positive number.", InputError ); GEOS_THROW_IF( m_compressiveStrength < m_tensileStrength, "Compressive strength must be greater than tensile strength.", InputError ); diff --git a/src/coreComponents/constitutive/solid/CeramicDamage.hpp b/src/coreComponents/constitutive/solid/CeramicDamage.hpp index 3ff7d16e0a1..1575fe84fac 100644 --- a/src/coreComponents/constitutive/solid/CeramicDamage.hpp +++ b/src/coreComponents/constitutive/solid/CeramicDamage.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -29,8 +30,8 @@ * integrated and tracked by this model. */ -#ifndef GEOSX_CONSTITUTIVE_SOLID_KINEMATICDAMAGE_HPP -#define GEOSX_CONSTITUTIVE_SOLID_KINEMATICDAMAGE_HPP +#ifndef GEOS_CONSTITUTIVE_SOLID_KINEMATICDAMAGE_HPP +#define GEOS_CONSTITUTIVE_SOLID_KINEMATICDAMAGE_HPP #include "ElasticIsotropic.hpp" #include "InvariantDecompositions.hpp" @@ -525,7 +526,7 @@ class CeramicDamage : public ElasticIsotropic protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// State variable: The damage values for each quadrature point array2d< real64 > m_damage; @@ -553,4 +554,4 @@ class CeramicDamage : public ElasticIsotropic } /* namespace geos */ -#endif /* GEOSX_CONSTITUTIVE_SOLID_KINEMATICDAMAGE_HPP_ */ +#endif /* GEOS_CONSTITUTIVE_SOLID_KINEMATICDAMAGE_HPP_ */ diff --git a/src/coreComponents/constitutive/solid/CompressibleSolid.cpp b/src/coreComponents/constitutive/solid/CompressibleSolid.cpp index 49043f3c980..a0e5609b618 100644 --- a/src/coreComponents/constitutive/solid/CompressibleSolid.cpp +++ b/src/coreComponents/constitutive/solid/CompressibleSolid.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -23,6 +24,7 @@ #include "constitutive/permeability/CarmanKozenyPermeability.hpp" #include "constitutive/permeability/ExponentialDecayPermeability.hpp" #include "constitutive/permeability/ParallelPlatesPermeability.hpp" +#include "constitutive/permeability/PressurePermeability.hpp" #include "constitutive/permeability/SlipDependentPermeability.hpp" #include "constitutive/permeability/WillisRichardsPermeability.hpp" @@ -47,6 +49,7 @@ CompressibleSolid< PORO_TYPE, PERM_TYPE >::~CompressibleSolid() = default; // Register all CompressibleSolid model types. typedef CompressibleSolid< PressurePorosity, ConstantPermeability > CompressibleRockConstant; typedef CompressibleSolid< PressurePorosity, CarmanKozenyPermeability > CompressibleRockCK; +typedef CompressibleSolid< PressurePorosity, PressurePermeability > CompressibleRockPressurePerm; typedef CompressibleSolid< PressurePorosity, ExponentialDecayPermeability > FaultED; typedef CompressibleSolid< PressurePorosity, ParallelPlatesPermeability > FractureRock; typedef CompressibleSolid< PressurePorosity, SlipDependentPermeability > Fault; @@ -54,6 +57,7 @@ typedef CompressibleSolid< PressurePorosity, WillisRichardsPermeability > FaultW REGISTER_CATALOG_ENTRY( ConstitutiveBase, CompressibleRockConstant, string const &, Group * const ) REGISTER_CATALOG_ENTRY( ConstitutiveBase, CompressibleRockCK, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( ConstitutiveBase, CompressibleRockPressurePerm, string const &, Group * const ) REGISTER_CATALOG_ENTRY( ConstitutiveBase, FractureRock, string const &, Group * const ) REGISTER_CATALOG_ENTRY( ConstitutiveBase, FaultED, string const &, Group * const ) REGISTER_CATALOG_ENTRY( ConstitutiveBase, Fault, string const &, Group * const ) diff --git a/src/coreComponents/constitutive/solid/CompressibleSolid.hpp b/src/coreComponents/constitutive/solid/CompressibleSolid.hpp index db93d4a14a8..83e0690e9a4 100644 --- a/src/coreComponents/constitutive/solid/CompressibleSolid.hpp +++ b/src/coreComponents/constitutive/solid/CompressibleSolid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -54,17 +55,15 @@ class CompressibleSolidUpdates : public CoupledSolidUpdates< NullModel, PORO_TYP virtual void updateStateFromPressureAndTemperature( localIndex const k, localIndex const q, real64 const & pressure, - real64 const & pressure_n, - real64 const & pressure_k, + real64 const & GEOS_UNUSED_PARAM( pressure_k ), + real64 const & GEOS_UNUSED_PARAM( pressure_n ), real64 const & temperature, - real64 const & temperature_k, - real64 const & temperature_n ) const override final + real64 const & GEOS_UNUSED_PARAM( temperature_k ), + real64 const & GEOS_UNUSED_PARAM( temperature_n ) ) const override final { - m_porosityUpdate.updateFromPressureAndTemperature( k, q, - pressure, pressure_k, pressure_n, - temperature, temperature_k, temperature_n ); + m_porosityUpdate.updateFromPressureAndTemperature( k, q, pressure, temperature ); real64 const porosity = m_porosityUpdate.getPorosity( k, q ); - m_permUpdate.updateFromPorosity( k, q, porosity ); + m_permUpdate.updateFromPressureAndPorosity( k, q, pressure, porosity ); } GEOS_HOST_DEVICE @@ -74,15 +73,9 @@ class CompressibleSolidUpdates : public CoupledSolidUpdates< NullModel, PORO_TYP real64 const & oldHydraulicAperture, real64 const & newHydraulicAperture ) const { - real64 const pressure_k = 0; - real64 const pressure_n = 0; real64 const temperature = 0; - real64 const temperature_k = 0; - real64 const temperature_n = 0; real64 const dHydraulicAperture_dNormalJump = 1.0; - m_porosityUpdate.updateFromPressureAndTemperature( k, q, - pressure, pressure_k, pressure_n, - temperature, temperature_k, temperature_n ); + m_porosityUpdate.updateFromPressureAndTemperature( k, q, pressure, temperature ); m_permUpdate.updateFromAperture( k, q, oldHydraulicAperture, newHydraulicAperture, dHydraulicAperture_dNormalJump ); } @@ -96,7 +89,7 @@ class CompressibleSolidUpdates : public CoupledSolidUpdates< NullModel, PORO_TYP real64 const ( &dispJump )[3], real64 const ( &traction )[3] ) const { - m_porosityUpdate.updateFromPressureAndTemperature( k, q, pressure, 0.0, 0.0, 0.0, 0.0, 0.0 ); + m_porosityUpdate.updateFromPressureAndTemperature( k, q, pressure, 0.0 ); m_permUpdate.updateFromApertureAndShearDisplacement( k, q, oldHydraulicAperture, newHydraulicAperture, dHydraulicAperture_dNormalJump, pressure, dispJump, traction ); } diff --git a/src/coreComponents/constitutive/solid/CoupledSolid.hpp b/src/coreComponents/constitutive/solid/CoupledSolid.hpp index e871f07e219..2c2e508e12a 100644 --- a/src/coreComponents/constitutive/solid/CoupledSolid.hpp +++ b/src/coreComponents/constitutive/solid/CoupledSolid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/solid/CoupledSolidBase.cpp b/src/coreComponents/constitutive/solid/CoupledSolidBase.cpp index a0f970711dd..14c7a2fcc0b 100644 --- a/src/coreComponents/constitutive/solid/CoupledSolidBase.cpp +++ b/src/coreComponents/constitutive/solid/CoupledSolidBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/solid/CoupledSolidBase.hpp b/src/coreComponents/constitutive/solid/CoupledSolidBase.hpp index 35306907a4e..c91395707f1 100644 --- a/src/coreComponents/constitutive/solid/CoupledSolidBase.hpp +++ b/src/coreComponents/constitutive/solid/CoupledSolidBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -169,6 +170,14 @@ class CoupledSolidBase : public ConstitutiveBase return getBaseSolidModel().getDensity(); } + /* + * @brief get the current solid effective stress + * return a constant arrayView3d to effective stress in Voigt form + */ + arrayView3d< real64 const, solid::STRESS_USD > const getEffectiveStress() const + { + return getBaseSolidModel().getStress(); + } /* * @brief get the current biot coefficient @@ -202,7 +211,7 @@ class CoupledSolidBase : public ConstitutiveBase /** * @brief initialize the constitutive models fields. */ - void initializeState() const + virtual void initializeState() const { getBasePorosityModel().initializeState(); getBasePermModel().initializeState(); diff --git a/src/coreComponents/constitutive/solid/Damage.cpp b/src/coreComponents/constitutive/solid/Damage.cpp index 4812112f17c..6515fe4990d 100644 --- a/src/coreComponents/constitutive/solid/Damage.cpp +++ b/src/coreComponents/constitutive/solid/Damage.cpp @@ -1,12 +1,12 @@ - /* * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -97,9 +97,9 @@ Damage< BASE >::Damage( string const & name, Group * const parent ): template< typename BASE > -void Damage< BASE >::postProcessInput() +void Damage< BASE >::postInputInitialization() { - BASE::postProcessInput(); + BASE::postInputInitialization(); GEOS_ERROR_IF( m_extDrivingForceFlag != 0 && m_extDrivingForceFlag!= 1, BASE::getDataContext() << ": invalid external driving force flag option - must" diff --git a/src/coreComponents/constitutive/solid/Damage.hpp b/src/coreComponents/constitutive/solid/Damage.hpp index 6ad834d7205..5c2cc22488e 100644 --- a/src/coreComponents/constitutive/solid/Damage.hpp +++ b/src/coreComponents/constitutive/solid/Damage.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -281,7 +282,7 @@ class Damage : public BASE static string catalogName() { return string( "Damage" ) + BASE::m_catalogNameString; } virtual string getCatalogName() const override { return catalogName(); } - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void allocateConstitutiveData( dataRepository::Group & parent, localIndex const numConstitutivePointsPerParentIndex ) override; diff --git a/src/coreComponents/constitutive/solid/DamageSpectral.cpp b/src/coreComponents/constitutive/solid/DamageSpectral.cpp index f53a857f170..68e67cd0fb6 100644 --- a/src/coreComponents/constitutive/solid/DamageSpectral.cpp +++ b/src/coreComponents/constitutive/solid/DamageSpectral.cpp @@ -1,12 +1,12 @@ - /* * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/solid/DamageSpectral.hpp b/src/coreComponents/constitutive/solid/DamageSpectral.hpp index 2f919ac0580..5ad79b47567 100644 --- a/src/coreComponents/constitutive/solid/DamageSpectral.hpp +++ b/src/coreComponents/constitutive/solid/DamageSpectral.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -28,8 +29,6 @@ #define QUADRATIC_DISSIPATION 0 -using namespace LvArray; - namespace geos { namespace constitutive diff --git a/src/coreComponents/constitutive/solid/DamageSpectralUtilities.hpp b/src/coreComponents/constitutive/solid/DamageSpectralUtilities.hpp index d7859a0ac57..1706ded507a 100644 --- a/src/coreComponents/constitutive/solid/DamageSpectralUtilities.hpp +++ b/src/coreComponents/constitutive/solid/DamageSpectralUtilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -25,11 +26,15 @@ #ifndef GEOS_CONSTITUTIVE_SOLID_DAMAGESPECTRALUTILITIES_HPP_ #define GEOS_CONSTITUTIVE_SOLID_DAMAGESPECTRALUTILITIES_HPP_ + #include #include #include #include "LvArray/src/output.hpp" #include "LvArray/src/tensorOps.hpp" +#include "common/DataTypes.hpp" +#include "common/logger/Logger.hpp" + namespace geos { @@ -413,6 +418,6 @@ void getTestStress( real64 (& strain)[6], real64 (& stress)[6] ) LvArray::tensorOps::scaledAdd< 6 >( stress, positiveStress, damageFactor ); } -} //namespacegeosx +} //namespacegeos #endif /* GEOS_CONSTITUTIVE_SOLID_DAMAGESPECTRALUTILITIES_HPP_ */ diff --git a/src/coreComponents/constitutive/solid/DamageVolDev.cpp b/src/coreComponents/constitutive/solid/DamageVolDev.cpp index 23035f85f21..0bacfa2a8dd 100644 --- a/src/coreComponents/constitutive/solid/DamageVolDev.cpp +++ b/src/coreComponents/constitutive/solid/DamageVolDev.cpp @@ -1,12 +1,12 @@ - /* * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/solid/DamageVolDev.hpp b/src/coreComponents/constitutive/solid/DamageVolDev.hpp index 3639b2ccc1f..914a5d2cc4e 100644 --- a/src/coreComponents/constitutive/solid/DamageVolDev.hpp +++ b/src/coreComponents/constitutive/solid/DamageVolDev.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/solid/DelftEgg.cpp b/src/coreComponents/constitutive/solid/DelftEgg.cpp index 695e6cad813..cd45347cb72 100644 --- a/src/coreComponents/constitutive/solid/DelftEgg.cpp +++ b/src/coreComponents/constitutive/solid/DelftEgg.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -108,9 +109,9 @@ void DelftEgg::allocateConstitutiveData( Group & parent, } -void DelftEgg::postProcessInput() +void DelftEgg::postInputInitialization() { - ElasticIsotropic::postProcessInput(); + ElasticIsotropic::postInputInitialization(); GEOS_THROW_IF( m_defaultCslSlope <= 0, getFullName() << ": Non-positive slope of critical state line detected", InputError ); diff --git a/src/coreComponents/constitutive/solid/DelftEgg.hpp b/src/coreComponents/constitutive/solid/DelftEgg.hpp index 8a318c16b83..5789b46178c 100644 --- a/src/coreComponents/constitutive/solid/DelftEgg.hpp +++ b/src/coreComponents/constitutive/solid/DelftEgg.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -583,7 +584,7 @@ class DelftEgg : public ElasticIsotropic protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// Material parameter: The default value of the recompression index real64 m_defaultRecompressionIndex; diff --git a/src/coreComponents/constitutive/solid/Deprecated/PoreVolumeCompressibleSolid.cpp b/src/coreComponents/constitutive/solid/Deprecated/PoreVolumeCompressibleSolid.cpp index 5c87d625358..6952ec194cf 100644 --- a/src/coreComponents/constitutive/solid/Deprecated/PoreVolumeCompressibleSolid.cpp +++ b/src/coreComponents/constitutive/solid/Deprecated/PoreVolumeCompressibleSolid.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -72,7 +73,7 @@ void PoreVolumeCompressibleSolid::allocateConstitutiveData( dataRepository::Grou m_poreVolumeMultiplier.setValues< serialPolicy >( 1.0 ); } -void PoreVolumeCompressibleSolid::postProcessInput() +void PoreVolumeCompressibleSolid::postInputInitialization() { if( m_compressibility < 0.0 ) { diff --git a/src/coreComponents/constitutive/solid/Deprecated/PoreVolumeCompressibleSolid.hpp b/src/coreComponents/constitutive/solid/Deprecated/PoreVolumeCompressibleSolid.hpp index fc1af76b002..fa60f97d4ab 100644 --- a/src/coreComponents/constitutive/solid/Deprecated/PoreVolumeCompressibleSolid.hpp +++ b/src/coreComponents/constitutive/solid/Deprecated/PoreVolumeCompressibleSolid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -61,7 +62,7 @@ class PoreVolumeCompressibleSolid : public ConstitutiveBase }; protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; private: diff --git a/src/coreComponents/constitutive/solid/Deprecated/PoroElastic.cpp b/src/coreComponents/constitutive/solid/Deprecated/PoroElastic.cpp index edb54dbfff1..688140ec100 100644 --- a/src/coreComponents/constitutive/solid/Deprecated/PoroElastic.cpp +++ b/src/coreComponents/constitutive/solid/Deprecated/PoroElastic.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -73,9 +74,9 @@ PoroElastic< BASE >::~PoroElastic() {} template< typename BASE > -void PoroElastic< BASE >::postProcessInput() +void PoroElastic< BASE >::postInputInitialization() { - BASE::postProcessInput(); + BASE::postInputInitialization(); m_poreVolumeRelation.setCoefficients( m_referencePressure, 1.0, m_compressibility ); } diff --git a/src/coreComponents/constitutive/solid/Deprecated/PoroElastic.hpp b/src/coreComponents/constitutive/solid/Deprecated/PoroElastic.hpp index 2ea0eb55029..9d3c1e9a359 100644 --- a/src/coreComponents/constitutive/solid/Deprecated/PoroElastic.hpp +++ b/src/coreComponents/constitutive/solid/Deprecated/PoroElastic.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -121,7 +122,7 @@ class PoroElastic : public BASE virtual string getCatalogName() const override { return catalogName(); } /// Post-process XML input - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /** * @brief Deliver a clone of this object diff --git a/src/coreComponents/constitutive/solid/DruckerPrager.cpp b/src/coreComponents/constitutive/solid/DruckerPrager.cpp index 37d67fd8be4..cfdbfb05253 100644 --- a/src/coreComponents/constitutive/solid/DruckerPrager.cpp +++ b/src/coreComponents/constitutive/solid/DruckerPrager.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -97,9 +98,9 @@ void DruckerPrager::allocateConstitutiveData( dataRepository::Group & parent, } -void DruckerPrager::postProcessInput() +void DruckerPrager::postInputInitialization() { - ElasticIsotropic::postProcessInput(); + ElasticIsotropic::postInputInitialization(); GEOS_THROW_IF( m_defaultCohesion < 0, getFullName() << ": Negative cohesion value detected", InputError ); diff --git a/src/coreComponents/constitutive/solid/DruckerPrager.hpp b/src/coreComponents/constitutive/solid/DruckerPrager.hpp index de29b6a4298..f741f60166d 100644 --- a/src/coreComponents/constitutive/solid/DruckerPrager.hpp +++ b/src/coreComponents/constitutive/solid/DruckerPrager.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -465,7 +466,7 @@ class DruckerPrager : public ElasticIsotropic protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// Material parameter: The default value of yield surface slope real64 m_defaultFrictionAngle; diff --git a/src/coreComponents/constitutive/solid/DruckerPragerExtended.cpp b/src/coreComponents/constitutive/solid/DruckerPragerExtended.cpp index 90e260f77bc..2158e78f3a0 100644 --- a/src/coreComponents/constitutive/solid/DruckerPragerExtended.cpp +++ b/src/coreComponents/constitutive/solid/DruckerPragerExtended.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -113,9 +114,9 @@ void DruckerPragerExtended::allocateConstitutiveData( dataRepository::Group & pa } -void DruckerPragerExtended::postProcessInput() +void DruckerPragerExtended::postInputInitialization() { - ElasticIsotropic::postProcessInput(); + ElasticIsotropic::postInputInitialization(); GEOS_THROW_IF( m_defaultCohesion < 0, getFullName() << ": Negative cohesion value detected", InputError ); diff --git a/src/coreComponents/constitutive/solid/DruckerPragerExtended.hpp b/src/coreComponents/constitutive/solid/DruckerPragerExtended.hpp index 2e3c33cff29..20869d79e66 100644 --- a/src/coreComponents/constitutive/solid/DruckerPragerExtended.hpp +++ b/src/coreComponents/constitutive/solid/DruckerPragerExtended.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -504,7 +505,7 @@ class DruckerPragerExtended : public ElasticIsotropic protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// Material parameter: The default value of the initial yield surface slope real64 m_defaultInitialFrictionAngle; diff --git a/src/coreComponents/constitutive/solid/DuvautLionsSolid.cpp b/src/coreComponents/constitutive/solid/DuvautLionsSolid.cpp index c7e67141dee..4e3e128adee 100644 --- a/src/coreComponents/constitutive/solid/DuvautLionsSolid.cpp +++ b/src/coreComponents/constitutive/solid/DuvautLionsSolid.cpp @@ -1,12 +1,12 @@ - /* * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -44,9 +44,9 @@ DuvautLionsSolid< BASE >::DuvautLionsSolid( string const & name, Group * const p template< typename BASE > -void DuvautLionsSolid< BASE >::postProcessInput() +void DuvautLionsSolid< BASE >::postInputInitialization() { - BASE::postProcessInput(); + BASE::postInputInitialization(); } template< typename BASE > diff --git a/src/coreComponents/constitutive/solid/DuvautLionsSolid.hpp b/src/coreComponents/constitutive/solid/DuvautLionsSolid.hpp index 04091d1790d..8c3bd5d849c 100644 --- a/src/coreComponents/constitutive/solid/DuvautLionsSolid.hpp +++ b/src/coreComponents/constitutive/solid/DuvautLionsSolid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -160,7 +161,7 @@ class DuvautLionsSolid : public BASE real64 relaxationTime() const { return m_relaxationTime; } - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void allocateConstitutiveData( dataRepository::Group & parent, localIndex const numConstitutivePointsPerParentIndex ) override; diff --git a/src/coreComponents/constitutive/solid/ElasticIsotropic.cpp b/src/coreComponents/constitutive/solid/ElasticIsotropic.cpp index 46d9ce7212e..773087398a4 100644 --- a/src/coreComponents/constitutive/solid/ElasticIsotropic.cpp +++ b/src/coreComponents/constitutive/solid/ElasticIsotropic.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -63,11 +64,11 @@ ElasticIsotropic::ElasticIsotropic( string const & name, Group * const parent ): ElasticIsotropic::~ElasticIsotropic() {} -void ElasticIsotropic::postProcessInput() +void ElasticIsotropic::postInputInitialization() { // check what constants the user actually input, and do conversions as needed - SolidBase::postProcessInput(); + SolidBase::postInputInitialization(); real64 & nu = getReference< real64 >( viewKeyStruct::defaultPoissonRatioString() ); real64 & E = getReference< real64 >( viewKeyStruct::defaultYoungModulusString() ); diff --git a/src/coreComponents/constitutive/solid/ElasticIsotropic.hpp b/src/coreComponents/constitutive/solid/ElasticIsotropic.hpp index 26d076ca949..bed64cb6e6a 100644 --- a/src/coreComponents/constitutive/solid/ElasticIsotropic.hpp +++ b/src/coreComponents/constitutive/solid/ElasticIsotropic.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -544,7 +545,7 @@ class ElasticIsotropic : public SolidBase protected: /// Post-process XML data - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// The default value of the bulk modulus for any new allocations. real64 m_defaultBulkModulus; diff --git a/src/coreComponents/constitutive/solid/ElasticIsotropicPressureDependent.cpp b/src/coreComponents/constitutive/solid/ElasticIsotropicPressureDependent.cpp index 3e1c565983c..95172384a19 100644 --- a/src/coreComponents/constitutive/solid/ElasticIsotropicPressureDependent.cpp +++ b/src/coreComponents/constitutive/solid/ElasticIsotropicPressureDependent.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -77,11 +78,11 @@ ElasticIsotropicPressureDependent::~ElasticIsotropicPressureDependent() {} -void ElasticIsotropicPressureDependent::postProcessInput() +void ElasticIsotropicPressureDependent::postInputInitialization() { // check what constants the user actually input, and do conversions as needed - SolidBase::postProcessInput(); + SolidBase::postInputInitialization(); real64 & G = m_defaultShearModulus; real64 & Cr = m_defaultRecompressionIndex; diff --git a/src/coreComponents/constitutive/solid/ElasticIsotropicPressureDependent.hpp b/src/coreComponents/constitutive/solid/ElasticIsotropicPressureDependent.hpp index 823e44e8609..4181e8e2013 100644 --- a/src/coreComponents/constitutive/solid/ElasticIsotropicPressureDependent.hpp +++ b/src/coreComponents/constitutive/solid/ElasticIsotropicPressureDependent.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 Total, S.A - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -565,7 +566,7 @@ class ElasticIsotropicPressureDependent : public SolidBase protected: /// Post-process XML data - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// The default value of the bulk modulus for any new allocations. real64 m_defaultRefPressure; diff --git a/src/coreComponents/constitutive/solid/ElasticOrthotropic.cpp b/src/coreComponents/constitutive/solid/ElasticOrthotropic.cpp index 93c748e3361..7c707d690cc 100644 --- a/src/coreComponents/constitutive/solid/ElasticOrthotropic.cpp +++ b/src/coreComponents/constitutive/solid/ElasticOrthotropic.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -175,9 +176,9 @@ ElasticOrthotropic::ElasticOrthotropic( string const & name, Group * const paren ElasticOrthotropic::~ElasticOrthotropic() {} -void ElasticOrthotropic::postProcessInput() +void ElasticOrthotropic::postInputInitialization() { - SolidBase::postProcessInput(); + SolidBase::postInputInitialization(); real64 & c11 = getReference< real64 >( viewKeyStruct::defaultC11String() ); real64 & c12 = getReference< real64 >( viewKeyStruct::defaultC12String() ); diff --git a/src/coreComponents/constitutive/solid/ElasticOrthotropic.hpp b/src/coreComponents/constitutive/solid/ElasticOrthotropic.hpp index 56731703729..4445b88cc12 100644 --- a/src/coreComponents/constitutive/solid/ElasticOrthotropic.hpp +++ b/src/coreComponents/constitutive/solid/ElasticOrthotropic.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -729,7 +730,7 @@ class ElasticOrthotropic : public SolidBase } protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// The default value of the Young's modulus E1 for any new /// allocations. diff --git a/src/coreComponents/constitutive/solid/ElasticTransverseIsotropic.cpp b/src/coreComponents/constitutive/solid/ElasticTransverseIsotropic.cpp index 55982285a85..9cad0340f36 100644 --- a/src/coreComponents/constitutive/solid/ElasticTransverseIsotropic.cpp +++ b/src/coreComponents/constitutive/solid/ElasticTransverseIsotropic.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -112,9 +113,9 @@ ElasticTransverseIsotropic::ElasticTransverseIsotropic( string const & name, Gro ElasticTransverseIsotropic::~ElasticTransverseIsotropic() {} -void ElasticTransverseIsotropic::postProcessInput() +void ElasticTransverseIsotropic::postInputInitialization() { - SolidBase::postProcessInput(); + SolidBase::postInputInitialization(); real64 & c11 = getReference< real64 >( viewKeyStruct::defaultC11String() ); real64 & c13 = getReference< real64 >( viewKeyStruct::defaultC13String() ); diff --git a/src/coreComponents/constitutive/solid/ElasticTransverseIsotropic.hpp b/src/coreComponents/constitutive/solid/ElasticTransverseIsotropic.hpp index de8833cbcb0..f2c86d4439a 100644 --- a/src/coreComponents/constitutive/solid/ElasticTransverseIsotropic.hpp +++ b/src/coreComponents/constitutive/solid/ElasticTransverseIsotropic.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -574,7 +575,7 @@ class ElasticTransverseIsotropic : public SolidBase } protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// The default value of the transverse Young's modulus for any new /// allocations. diff --git a/src/coreComponents/constitutive/solid/InvariantDecompositions.hpp b/src/coreComponents/constitutive/solid/InvariantDecompositions.hpp index 6e578c9f83c..588d3e69f33 100644 --- a/src/coreComponents/constitutive/solid/InvariantDecompositions.hpp +++ b/src/coreComponents/constitutive/solid/InvariantDecompositions.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/constitutive/solid/ModifiedCamClay.cpp b/src/coreComponents/constitutive/solid/ModifiedCamClay.cpp index 8f7ff754a4e..6d0e8f401d6 100644 --- a/src/coreComponents/constitutive/solid/ModifiedCamClay.cpp +++ b/src/coreComponents/constitutive/solid/ModifiedCamClay.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -86,9 +87,9 @@ void ModifiedCamClay::allocateConstitutiveData( dataRepository::Group & parent, } -void ModifiedCamClay::postProcessInput() +void ModifiedCamClay::postInputInitialization() { - ElasticIsotropicPressureDependent::postProcessInput(); + ElasticIsotropicPressureDependent::postInputInitialization(); GEOS_THROW_IF( m_defaultCslSlope <= 0, getFullName() << ": Non-positive slope of critical state line detected", InputError ); diff --git a/src/coreComponents/constitutive/solid/ModifiedCamClay.hpp b/src/coreComponents/constitutive/solid/ModifiedCamClay.hpp index 9657578e84a..4377571e603 100644 --- a/src/coreComponents/constitutive/solid/ModifiedCamClay.hpp +++ b/src/coreComponents/constitutive/solid/ModifiedCamClay.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -588,7 +589,7 @@ class ModifiedCamClay : public ElasticIsotropicPressureDependent protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// Material parameter: The default value of the virgin compression index real64 m_defaultVirginCompressionIndex; diff --git a/src/coreComponents/constitutive/solid/PerfectlyPlastic.cpp b/src/coreComponents/constitutive/solid/PerfectlyPlastic.cpp index f6ff767c937..a1d39db1f50 100644 --- a/src/coreComponents/constitutive/solid/PerfectlyPlastic.cpp +++ b/src/coreComponents/constitutive/solid/PerfectlyPlastic.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -53,9 +54,9 @@ void PerfectlyPlastic::allocateConstitutiveData( dataRepository::Group & parent, } -void PerfectlyPlastic::postProcessInput() +void PerfectlyPlastic::postInputInitialization() { - ElasticIsotropic::postProcessInput(); + ElasticIsotropic::postInputInitialization(); GEOS_THROW_IF( m_defaultYieldStress < 0.0, "Negative yield stress detected", InputError ); diff --git a/src/coreComponents/constitutive/solid/PerfectlyPlastic.hpp b/src/coreComponents/constitutive/solid/PerfectlyPlastic.hpp index 5732d9a440d..d1faf2ff686 100644 --- a/src/coreComponents/constitutive/solid/PerfectlyPlastic.hpp +++ b/src/coreComponents/constitutive/solid/PerfectlyPlastic.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -16,8 +17,8 @@ * @file PerfectlyPlastic.hpp */ -#ifndef GEOSX_CONSTITUTIVE_SOLID_PERFECTLYPLASTIC_HPP -#define GEOSX_CONSTITUTIVE_SOLID_PERFECTLYPLASTIC_HPP +#ifndef GEOS_CONSTITUTIVE_SOLID_PERFECTLYPLASTIC_HPP +#define GEOS_CONSTITUTIVE_SOLID_PERFECTLYPLASTIC_HPP #include "ElasticIsotropic.hpp" #include "InvariantDecompositions.hpp" @@ -324,7 +325,7 @@ class PerfectlyPlastic : public ElasticIsotropic protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// Material parameter: The default value of yield stress real64 m_defaultYieldStress; @@ -337,4 +338,4 @@ class PerfectlyPlastic : public ElasticIsotropic } /* namespace geos */ -#endif /* GEOSX_CONSTITUTIVE_SOLID_PERFECTLYPLASTIC_HPP_ */ +#endif /* GEOS_CONSTITUTIVE_SOLID_PERFECTLYPLASTIC_HPP_ */ diff --git a/src/coreComponents/constitutive/solid/PorousSolid.cpp b/src/coreComponents/constitutive/solid/PorousSolid.cpp index ed9cadb7bca..9514e505fe2 100644 --- a/src/coreComponents/constitutive/solid/PorousSolid.cpp +++ b/src/coreComponents/constitutive/solid/PorousSolid.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -46,6 +47,12 @@ PorousSolid< SOLID_TYPE >::PorousSolid( string const & name, Group * const paren template< typename SOLID_TYPE > PorousSolid< SOLID_TYPE >::~PorousSolid() = default; +template< typename SOLID_TYPE > +void PorousSolid< SOLID_TYPE >::initializeState() const +{ + CoupledSolid< SOLID_TYPE, BiotPorosity, ConstantPermeability >::initializeState(); +} + // Register all PorousSolid model types. typedef PorousSolid< ElasticIsotropic > PorousElasticIsotropic; typedef PorousSolid< ElasticTransverseIsotropic > PorousElasticTransverseIsotropic; diff --git a/src/coreComponents/constitutive/solid/PorousSolid.hpp b/src/coreComponents/constitutive/solid/PorousSolid.hpp index 67a16bef411..b4a9429eb43 100644 --- a/src/coreComponents/constitutive/solid/PorousSolid.hpp +++ b/src/coreComponents/constitutive/solid/PorousSolid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -62,19 +63,19 @@ class PorousSolidUpdates : public CoupledSolidUpdates< SOLID_TYPE, BiotPorosity, real64 const & temperature_k, real64 const & temperature_n ) const override final { - updateBiotCoefficientAndAssignBulkModulus( k ); + updateBiotCoefficientAndAssignModuli( k ); - m_porosityUpdate.updateFromPressureAndTemperature( k, q, - pressure, pressure_k, pressure_n, - temperature, temperature_k, temperature_n ); + m_porosityUpdate.updateFixedStress( k, q, + pressure, pressure_k, pressure_n, + temperature, temperature_k, temperature_n ); } GEOS_HOST_DEVICE void smallStrainUpdatePoromechanics( localIndex const k, localIndex const q, - real64 const & pressure_n, - real64 const & pressure, real64 const & timeIncrement, + real64 const & pressure, + real64 const & pressure_n, real64 const & temperature, real64 const & deltaTemperatureFromLastStep, real64 const ( &strainIncrement )[6], @@ -82,6 +83,7 @@ class PorousSolidUpdates : public CoupledSolidUpdates< SOLID_TYPE, BiotPorosity, real64 ( & dTotalStress_dPressure )[6], real64 ( & dTotalStress_dTemperature )[6], DiscretizationOps & stiffness, + integer const performStressInitialization, real64 & porosity, real64 & porosity_n, real64 & dPorosity_dVolStrain, @@ -92,8 +94,8 @@ class PorousSolidUpdates : public CoupledSolidUpdates< SOLID_TYPE, BiotPorosity, // Compute total stress increment and its derivative computeTotalStress( k, q, - pressure, timeIncrement, + pressure, temperature, strainIncrement, totalStress, @@ -116,18 +118,27 @@ class PorousSolidUpdates : public CoupledSolidUpdates< SOLID_TYPE, BiotPorosity, dPorosity_dPressure, dPorosity_dTemperature ); + // skip porosity update when doing poromechanics initialization + if( performStressInitialization ) + { + porosity = porosityInit; + dPorosity_dVolStrain = 0.0; + dPorosity_dPressure = 0.0; + dPorosity_dTemperature = 0.0; + } + // Save the derivative of solid density wrt pressure for the computation of the body force - dSolidDensity_dPressure = m_porosityUpdate.dGrainDensity_dPressure(); + dSolidDensity_dPressure = m_porosityUpdate.dGrainDensity_dPressure( k ); } GEOS_HOST_DEVICE void smallStrainUpdatePoromechanicsFixedStress( localIndex const k, localIndex const q, - real64 const & pressure_n, - real64 const & pressure, real64 const & timeIncrement, - real64 const & temperature_n, + real64 const & pressure, + real64 const & pressure_n, real64 const & temperature, + real64 const & temperature_n, real64 const ( &strainIncrement )[6], real64 ( & totalStress )[6], DiscretizationOps & stiffness ) const @@ -138,8 +149,8 @@ class PorousSolidUpdates : public CoupledSolidUpdates< SOLID_TYPE, BiotPorosity, // Compute total stress increment and its derivative computeTotalStress( k, q, - pressure, timeIncrement, + pressure, temperature, strainIncrement, totalStress, @@ -148,7 +159,6 @@ class PorousSolidUpdates : public CoupledSolidUpdates< SOLID_TYPE, BiotPorosity, stiffness ); // Compute total stress increment for the porosity update - GEOS_UNUSED_VAR( pressure_n, temperature_n ); real64 const bulkModulus = m_solidUpdate.getBulkModulus( k ); real64 const meanEffectiveStressIncrement = bulkModulus * ( strainIncrement[0] + strainIncrement[1] + strainIncrement[2] ); real64 const biotCoefficient = m_porosityUpdate.getBiotCoefficient( k ); @@ -211,12 +221,13 @@ class PorousSolidUpdates : public CoupledSolidUpdates< SOLID_TYPE, BiotPorosity, GEOS_HOST_DEVICE inline - void updateBiotCoefficientAndAssignBulkModulus( localIndex const k ) const + void updateBiotCoefficientAndAssignModuli( localIndex const k ) const { // This call is not general like this. real64 const bulkModulus = m_solidUpdate.getBulkModulus( k ); + real64 const shearModulus = m_solidUpdate.getShearModulus( k ); - m_porosityUpdate.updateBiotCoefficientAndAssignBulkModulus( k, bulkModulus ); + m_porosityUpdate.updateBiotCoefficientAndAssignModuli( k, bulkModulus, shearModulus ); } GEOS_HOST_DEVICE @@ -258,8 +269,8 @@ class PorousSolidUpdates : public CoupledSolidUpdates< SOLID_TYPE, BiotPorosity, inline void computeTotalStress( localIndex const k, localIndex const q, - real64 const & pressure, real64 const & timeIncrement, + real64 const & pressure, real64 const & temperature, real64 const ( &strainIncrement )[6], real64 ( & totalStress )[6], @@ -267,6 +278,8 @@ class PorousSolidUpdates : public CoupledSolidUpdates< SOLID_TYPE, BiotPorosity, real64 ( & dTotalStress_dTemperature )[6], DiscretizationOps & stiffness ) const { + updateBiotCoefficientAndAssignModuli( k ); + // Compute total stress increment and its derivative w.r.t. pressure m_solidUpdate.smallStrainUpdate( k, q, @@ -275,8 +288,6 @@ class PorousSolidUpdates : public CoupledSolidUpdates< SOLID_TYPE, BiotPorosity, totalStress, // first effective stress increment accumulated stiffness ); - updateBiotCoefficientAndAssignBulkModulus( k ); - // Add the contributions of pressure and temperature to the total stress real64 const biotCoefficient = m_porosityUpdate.getBiotCoefficient( k ); real64 const thermalExpansionCoefficient = m_solidUpdate.getThermalExpansionCoefficient( k ); @@ -357,6 +368,11 @@ class PorousSolid : public CoupledSolid< SOLID_TYPE, BiotPorosity, ConstantPerme getPermModel() ); } + /** + * @brief initialize the constitutive models fields. + */ + virtual void initializeState() const override final; + /** * @brief Const/non-mutable accessor for density * @return Accessor diff --git a/src/coreComponents/constitutive/solid/PropertyConversions.hpp b/src/coreComponents/constitutive/solid/PropertyConversions.hpp index 02be2f01bc0..169e70c9ed5 100644 --- a/src/coreComponents/constitutive/solid/PropertyConversions.hpp +++ b/src/coreComponents/constitutive/solid/PropertyConversions.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/constitutive/solid/ProppantSolid.cpp b/src/coreComponents/constitutive/solid/ProppantSolid.cpp index 8a1905da4d2..db1d67d2aac 100644 --- a/src/coreComponents/constitutive/solid/ProppantSolid.cpp +++ b/src/coreComponents/constitutive/solid/ProppantSolid.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/solid/ProppantSolid.hpp b/src/coreComponents/constitutive/solid/ProppantSolid.hpp index 345cd0a6b03..084689a7c73 100644 --- a/src/coreComponents/constitutive/solid/ProppantSolid.hpp +++ b/src/coreComponents/constitutive/solid/ProppantSolid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/solid/SolidBase.cpp b/src/coreComponents/constitutive/solid/SolidBase.cpp index b213b037996..f22cec62d93 100644 --- a/src/coreComponents/constitutive/solid/SolidBase.cpp +++ b/src/coreComponents/constitutive/solid/SolidBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -69,7 +70,7 @@ SolidBase::~SolidBase() {} -void SolidBase::postProcessInput() +void SolidBase::postInputInitialization() { this->getWrapper< array2d< real64 > >( viewKeyStruct::densityString() ). setApplyDefaultValue( m_defaultDensity ); diff --git a/src/coreComponents/constitutive/solid/SolidBase.hpp b/src/coreComponents/constitutive/solid/SolidBase.hpp index 6e8f6264817..24b05eea71a 100644 --- a/src/coreComponents/constitutive/solid/SolidBase.hpp +++ b/src/coreComponents/constitutive/solid/SolidBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -677,7 +678,7 @@ class SolidBase : public constitutive::ConstitutiveBase protected: /// Post-process XML input - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// The current stress at a quadrature point (i.e. at timestep n, global newton iteration k) array3d< real64, solid::STRESS_PERMUTATION > m_newStress; @@ -699,10 +700,6 @@ class SolidBase : public constitutive::ConstitutiveBase /// Flag to disable inelasticity (plasticity, damage, etc.) bool m_disableInelasticity = false; - - /// band-aid fix...going to have to remove this after we clean up - /// initialization for constitutive models. - bool m_postProcessed = false; }; } // namespace constitutive diff --git a/src/coreComponents/constitutive/solid/SolidInternalEnergy.cpp b/src/coreComponents/constitutive/solid/SolidInternalEnergy.cpp index 1928050957d..6f78fd8c78b 100644 --- a/src/coreComponents/constitutive/solid/SolidInternalEnergy.cpp +++ b/src/coreComponents/constitutive/solid/SolidInternalEnergy.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -30,7 +31,8 @@ SolidInternalEnergy::SolidInternalEnergy( string const & name, Group * const par ConstitutiveBase( name, parent ), m_internalEnergy(), m_dInternalEnergy_dTemperature(), - m_volumetricHeatCapacity(), + m_referenceVolumetricHeatCapacity(), + m_dVolumetricHeatCapacity_dTemperature(), m_referenceTemperature(), m_referenceInternalEnergy() { @@ -47,9 +49,14 @@ SolidInternalEnergy::SolidInternalEnergy( string const & name, Group * const par setApplyDefaultValue( 0.0 ). setDescription( "Derivative of the solid internal energy w.r.t. temperature [J/(m^3.K)]" ); - registerWrapper( viewKeyStruct::volumetricHeatCapacityString(), &m_volumetricHeatCapacity ). + registerWrapper( viewKeyStruct::referenceVolumetricHeatCapacityString(), &m_referenceVolumetricHeatCapacity ). setInputFlag( InputFlags::REQUIRED ). - setDescription( "Solid volumetric heat capacity [J/(kg.K)]" ); + setDescription( "Reference solid volumetric heat capacity [J/(kg.K)]" ); + + registerWrapper( viewKeyStruct::dVolumetricHeatCapacity_dTemperatureString(), &m_dVolumetricHeatCapacity_dTemperature ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( 0.0 ). + setDescription( "Derivative of the solid volumetric heat capacity w.r.t. temperature [J/(m^3.K^2)]" ); registerWrapper( viewKeyStruct::referenceTemperatureString(), &m_referenceTemperature ). setInputFlag( InputFlags::REQUIRED ). diff --git a/src/coreComponents/constitutive/solid/SolidInternalEnergy.hpp b/src/coreComponents/constitutive/solid/SolidInternalEnergy.hpp index cd2efaa4024..20dcdf52abb 100644 --- a/src/coreComponents/constitutive/solid/SolidInternalEnergy.hpp +++ b/src/coreComponents/constitutive/solid/SolidInternalEnergy.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -35,12 +36,14 @@ class SolidInternalEnergyUpdates SolidInternalEnergyUpdates( arrayView2d< real64 > const & internalEnergy, arrayView2d< real64 > const & dInternalEnergy_dTemperature, - real64 const & volumetricHeatCapacity, + real64 const & referenceVolumetricHeatCapacity, + real64 const & dVolumetricHeatCapacity_dTemperature, real64 const & referenceTemperature, real64 const & referenceInternalEnergy ): m_internalEnergy( internalEnergy ), m_dInternalEnergy_dTemperature( dInternalEnergy_dTemperature ), - m_volumetricHeatCapacity( volumetricHeatCapacity ), + m_referenceVolumetricHeatCapacity( referenceVolumetricHeatCapacity ), + m_dVolumetricHeatCapacity_dTemperature( dVolumetricHeatCapacity_dTemperature ), m_referenceTemperature( referenceTemperature ), m_referenceInternalEnergy( referenceInternalEnergy ) {} @@ -59,8 +62,10 @@ class SolidInternalEnergyUpdates real64 & internalEnergy, real64 & dInternalEnergy_dTemperature ) const { - internalEnergy = m_referenceInternalEnergy + m_volumetricHeatCapacity * ( temperature - m_referenceTemperature ); - dInternalEnergy_dTemperature = m_volumetricHeatCapacity; + real64 volumetricHeatCapacity = m_referenceVolumetricHeatCapacity + m_dVolumetricHeatCapacity_dTemperature * ( temperature - m_referenceTemperature ); + + internalEnergy = m_referenceInternalEnergy + volumetricHeatCapacity * ( temperature - m_referenceTemperature ); + dInternalEnergy_dTemperature = volumetricHeatCapacity + m_dVolumetricHeatCapacity_dTemperature * ( temperature - m_referenceTemperature ); } private: @@ -71,13 +76,16 @@ class SolidInternalEnergyUpdates /// Derivative of the solid internal energy w.r.t. the temperature arrayView2d< real64 > m_dInternalEnergy_dTemperature; - /// Solid volumetric heat capacity - real64 m_volumetricHeatCapacity; + /// Solid volumetric heat capacity at the reference tempearture + real64 m_referenceVolumetricHeatCapacity; + + /// Derivative of the solid volumetric heat capacity w.r.t. the temperature + real64 m_dVolumetricHeatCapacity_dTemperature; /// Reference temperature real64 m_referenceTemperature; - /// Reference internal energy + /// Internal energy at the reference temperature real64 m_referenceInternalEnergy; }; @@ -99,7 +107,8 @@ class SolidInternalEnergy : public ConstitutiveBase static constexpr char const * internalEnergyString() { return "internalEnergy"; } static constexpr char const * oldInternalEnergyString() { return "internalEnergy_n"; } static constexpr char const * dInternalEnergy_dTemperatureString() { return "dInternalEnergy_dTemperature"; } - static constexpr char const * volumetricHeatCapacityString() { return "volumetricHeatCapacity"; } + static constexpr char const * referenceVolumetricHeatCapacityString() { return "referenceVolumetricHeatCapacity"; } + static constexpr char const * dVolumetricHeatCapacity_dTemperatureString() { return "dVolumetricHeatCapacity_dTemperature"; } static constexpr char const * referenceTemperatureString() { return "referenceTemperature"; } static constexpr char const * referenceInternalEnergyString() { return "referenceInternalEnergy"; } } viewKeys; @@ -114,7 +123,8 @@ class SolidInternalEnergy : public ConstitutiveBase { return KernelWrapper( m_internalEnergy, m_dInternalEnergy_dTemperature, - m_volumetricHeatCapacity, + m_referenceVolumetricHeatCapacity, + m_dVolumetricHeatCapacity_dTemperature, m_referenceTemperature, m_referenceInternalEnergy ); } @@ -152,8 +162,11 @@ class SolidInternalEnergy : public ConstitutiveBase /// Derivative of the solid internal energy w.r.t. the temperature array2d< real64 > m_dInternalEnergy_dTemperature; - /// Solid volumetric heat capacity - real64 m_volumetricHeatCapacity; + /// Solid volumetric heat capacity at the reference temperature + real64 m_referenceVolumetricHeatCapacity; + + /// Derivative of the solid volumetric heat capacity w.r.t. the temperature + real64 m_dVolumetricHeatCapacity_dTemperature; /// Reference temperature real64 m_referenceTemperature; diff --git a/src/coreComponents/constitutive/solid/SolidModelDiscretizationOps.hpp b/src/coreComponents/constitutive/solid/SolidModelDiscretizationOps.hpp index 3a889e5aa48..2e196534bf6 100644 --- a/src/coreComponents/constitutive/solid/SolidModelDiscretizationOps.hpp +++ b/src/coreComponents/constitutive/solid/SolidModelDiscretizationOps.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsFullyAnisotroipic.hpp b/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsFullyAnisotroipic.hpp index 05121655899..6eefc6d686f 100644 --- a/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsFullyAnisotroipic.hpp +++ b/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsFullyAnisotroipic.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsIsotropic.hpp b/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsIsotropic.hpp index 16c5f7d0253..78172ee75f9 100644 --- a/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsIsotropic.hpp +++ b/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsIsotropic.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsOrthotropic.hpp b/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsOrthotropic.hpp index 7929df465de..a16fdb8fb23 100644 --- a/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsOrthotropic.hpp +++ b/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsOrthotropic.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsTransverseIsotropic.hpp b/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsTransverseIsotropic.hpp index f9a3eb655d7..9cf78b133de 100644 --- a/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsTransverseIsotropic.hpp +++ b/src/coreComponents/constitutive/solid/SolidModelDiscretizationOpsTransverseIsotropic.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/constitutive/solid/SolidUtilities.hpp b/src/coreComponents/constitutive/solid/SolidUtilities.hpp index c7b79e8d121..337b7f30509 100644 --- a/src/coreComponents/constitutive/solid/SolidUtilities.hpp +++ b/src/coreComponents/constitutive/solid/SolidUtilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/solid/porosity/BiotPorosity.cpp b/src/coreComponents/constitutive/solid/porosity/BiotPorosity.cpp index 1494de982b9..37454064d27 100644 --- a/src/coreComponents/constitutive/solid/porosity/BiotPorosity.cpp +++ b/src/coreComponents/constitutive/solid/porosity/BiotPorosity.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,6 +19,7 @@ #include "BiotPorosity.hpp" #include "PorosityFields.hpp" +#include "constitutive/solid/SolidBase.hpp" namespace geos { @@ -31,8 +33,9 @@ namespace constitutive BiotPorosity::BiotPorosity( string const & name, Group * const parent ): PorosityBase( name, parent ) { - registerWrapper( viewKeyStruct::grainBulkModulusString(), &m_grainBulkModulus ). + registerWrapper( viewKeyStruct::defaultGrainBulkModulusString(), &m_defaultGrainBulkModulus ). setInputFlag( InputFlags::REQUIRED ). + setApplyDefaultValue( -1.0 ). setDescription( "Grain bulk modulus" ); registerWrapper( viewKeyStruct::defaultThermalExpansionCoefficientString(), &m_defaultThermalExpansionCoefficient ). @@ -40,9 +43,18 @@ BiotPorosity::BiotPorosity( string const & name, Group * const parent ): setInputFlag( InputFlags::OPTIONAL ). setDescription( "Default thermal expansion coefficient" ); + registerWrapper( viewKeyStruct::useUniaxialFixedStressString(), &m_useUniaxialFixedStress ). + setApplyDefaultValue( 0 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Flag enabling uniaxial approximation in fixed stress update" ); + registerField( fields::porosity::biotCoefficient{}, &m_biotCoefficient ). - setApplyDefaultValue( 1.0 ); // this is useful for sequential simulations, for the first flow solve - // ultimately, we want to be able to load the biotCoefficient from input directly, and this won't be necessary anymore + setApplyDefaultValue( 1.0 ). + setDescription( "Biot coefficient" ); + + registerField( fields::porosity::grainBulkModulus{}, &m_grainBulkModulus ). + setApplyDefaultValue( -1.0 ). + setDescription( "Grain Bulk modulus." ); registerField( fields::porosity::thermalExpansionCoefficient{}, &m_thermalExpansionCoefficient ); @@ -53,6 +65,10 @@ BiotPorosity::BiotPorosity( string const & name, Group * const parent ): registerWrapper( viewKeyStruct::solidBulkModulusString(), &m_bulkModulus ). setApplyDefaultValue( 1e-6 ). setDescription( "Solid bulk modulus" ); + + registerWrapper( viewKeyStruct::solidShearModulusString(), &m_shearModulus ). + setApplyDefaultValue( 1e-6 ). + setDescription( "Solid shear modulus" ); } void BiotPorosity::allocateConstitutiveData( dataRepository::Group & parent, @@ -63,12 +79,16 @@ void BiotPorosity::allocateConstitutiveData( dataRepository::Group & parent, m_meanTotalStressIncrement_k.resize( 0, numConstitutivePointsPerParentIndex ); } -void BiotPorosity::postProcessInput() +void BiotPorosity::postInputInitialization() { - PorosityBase::postProcessInput(); + PorosityBase::postInputInitialization(); getWrapper< array1d< real64 > >( fields::porosity::thermalExpansionCoefficient::key() ). setApplyDefaultValue( m_defaultThermalExpansionCoefficient ); + + // set results as array default values + getWrapper< array1d< real64 > >( fields::porosity::grainBulkModulus::key() ). + setApplyDefaultValue( m_defaultGrainBulkModulus ); } void BiotPorosity::initializeState() const diff --git a/src/coreComponents/constitutive/solid/porosity/BiotPorosity.hpp b/src/coreComponents/constitutive/solid/porosity/BiotPorosity.hpp index 918efea6b67..8ea2df08b22 100644 --- a/src/coreComponents/constitutive/solid/porosity/BiotPorosity.hpp +++ b/src/coreComponents/constitutive/solid/porosity/BiotPorosity.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -55,28 +56,32 @@ class BiotPorosityUpdates : public PorosityBaseUpdates arrayView2d< real64 > const & meanTotalStressIncrement_k, arrayView1d< real64 > const & averageMeanTotalStressIncrement_k, arrayView1d< real64 > const & bulkModulus, - real64 const & grainBulkModulus ): PorosityBaseUpdates( newPorosity, - porosity_n, - dPorosity_dPressure, - dPorosity_dTemperature, - initialPorosity, - referencePorosity ), + arrayView1d< real64 > const & shearModulus, + arrayView1d< real64 > const & grainBulkModulus, + integer const useUniaxialFixedStress ): PorosityBaseUpdates( newPorosity, + porosity_n, + dPorosity_dPressure, + dPorosity_dTemperature, + initialPorosity, + referencePorosity ), m_grainBulkModulus( grainBulkModulus ), m_thermalExpansionCoefficient( thermalExpansionCoefficient ), m_biotCoefficient( biotCoefficient ), m_bulkModulus( bulkModulus ), + m_shearModulus( shearModulus ), m_meanTotalStressIncrement_k( meanTotalStressIncrement_k ), - m_averageMeanTotalStressIncrement_k( averageMeanTotalStressIncrement_k ) + m_averageMeanTotalStressIncrement_k( averageMeanTotalStressIncrement_k ), + m_useUniaxialFixedStress( useUniaxialFixedStress ) {} GEOS_HOST_DEVICE real64 getBiotCoefficient( localIndex const k ) const { return m_biotCoefficient[k]; } GEOS_HOST_DEVICE - real64 getGrainBulkModulus() const { return m_grainBulkModulus; } + real64 getGrainBulkModulus( localIndex const k ) const { return m_grainBulkModulus[k]; } GEOS_HOST_DEVICE - real64 dGrainDensity_dPressure() const { return 1.0 / m_grainBulkModulus; } + real64 dGrainDensity_dPressure( localIndex const k ) const { return 1.0 / m_grainBulkModulus[k]; } GEOS_HOST_DEVICE void updateFromPressureTemperatureAndStrain( localIndex const k, @@ -88,7 +93,7 @@ class BiotPorosityUpdates : public PorosityBaseUpdates real64 & dPorosity_dPressure, real64 & dPorosity_dTemperature ) const { - real64 const biotSkeletonModulusInverse = (m_biotCoefficient[k] - m_referencePorosity[k]) / m_grainBulkModulus; + real64 const biotSkeletonModulusInverse = (m_biotCoefficient[k] - m_referencePorosity[k]) / m_grainBulkModulus[k]; real64 const porosityThermalExpansion = 3 * m_thermalExpansionCoefficient[k] * ( m_biotCoefficient[k] - m_referencePorosity[k] ); real64 const porosity = m_porosity_n[k][q] @@ -100,75 +105,90 @@ class BiotPorosityUpdates : public PorosityBaseUpdates dPorosity_dPressure = biotSkeletonModulusInverse; dPorosity_dTemperature = -porosityThermalExpansion; - savePorosity( k, q, porosity, biotSkeletonModulusInverse ); + savePorosity( k, q, porosity, dPorosity_dPressure, dPorosity_dTemperature ); } GEOS_HOST_DEVICE - void computePorosity( real64 const & deltaPressureFromBeginningOfTimeStep, - real64 const & deltaTemperatureFromBeginningOfTimeStep, - real64 const & porosity_n, - real64 const & referencePorosity, - real64 & porosity, - real64 & dPorosity_dPressure, - real64 & dPorosity_dTemperature, - real64 const & biotCoefficient, - real64 const & thermalExpansionCoefficient, - real64 const & averageMeanTotalStressIncrement_k, - real64 const & bulkModulus ) const + void computePorosityFixedStress( real64 const & pressure, + real64 const & pressure_k, + real64 const & pressure_n, + real64 const & temperature, + real64 const & temperature_k, + real64 const & temperature_n, + real64 const & porosity_n, + real64 const & referencePorosity, + real64 & porosity, + real64 & dPorosity_dPressure, + real64 & dPorosity_dTemperature, + real64 const & biotCoefficient, + real64 const & thermalExpansionCoefficient, + real64 const & averageMeanTotalStressIncrement_k, + real64 const & bulkModulus, + real64 const & fixedStressModulus, + real64 const & grainBulkModulus ) const { - real64 const biotSkeletonModulusInverse = (biotCoefficient - referencePorosity) / m_grainBulkModulus; + real64 const biotSkeletonModulusInverse = (biotCoefficient - referencePorosity) / grainBulkModulus; real64 const porosityThermalExpansion = 3 * thermalExpansionCoefficient * ( biotCoefficient - referencePorosity ); - real64 const fixedStressPressureCoefficient = biotCoefficient * biotCoefficient / bulkModulus; - real64 const fixedStressTemperatureCoefficient = 3 * biotCoefficient * thermalExpansionCoefficient; + real64 const pressureCoefficient = biotCoefficient * biotCoefficient / bulkModulus; + real64 const temperatureCoefficient = 3 * biotCoefficient * thermalExpansionCoefficient; // total stress formulation for porosity update porosity = porosity_n - + biotCoefficient * averageMeanTotalStressIncrement_k / bulkModulus // change due to stress increment (at the previous - // sequential iteration) - + biotSkeletonModulusInverse * deltaPressureFromBeginningOfTimeStep // change due to pressure increment - - porosityThermalExpansion * deltaTemperatureFromBeginningOfTimeStep; // change due to temperature increment + // change due to stress increment + + biotCoefficient * averageMeanTotalStressIncrement_k / bulkModulus + // change due to pressure increment + + biotSkeletonModulusInverse * ( pressure - pressure_n ) + pressureCoefficient * ( pressure_k - pressure_n ) + // change due to temperature increment + - porosityThermalExpansion * ( temperature - temperature_n ) + temperatureCoefficient * ( temperature_k - temperature_n ); dPorosity_dPressure = biotSkeletonModulusInverse; dPorosity_dTemperature = -porosityThermalExpansion; // Fixed-stress part - porosity += fixedStressPressureCoefficient * deltaPressureFromBeginningOfTimeStep // fixed-stress pressure term - + fixedStressTemperatureCoefficient * deltaTemperatureFromBeginningOfTimeStep; // fixed-stress temperature term + real64 const fixedStressPressureCoefficient = biotCoefficient * biotCoefficient / fixedStressModulus; + real64 const fixedStressTemperatureCoefficient = 3 * biotCoefficient * thermalExpansionCoefficient * bulkModulus / fixedStressModulus; + porosity += fixedStressPressureCoefficient * ( pressure - pressure_k ) // fixed-stress pressure term + + fixedStressTemperatureCoefficient * ( temperature - temperature_k ); // fixed-stress temperature term dPorosity_dPressure += fixedStressPressureCoefficient; dPorosity_dTemperature += fixedStressTemperatureCoefficient; } + // this function is used in flow solver + // it uses average stress increment (element-based) GEOS_HOST_DEVICE - virtual void updateFromPressureAndTemperature( localIndex const k, - localIndex const q, - real64 const & pressure, // current - real64 const & GEOS_UNUSED_PARAM( pressure_k ), // last iteration (for sequential) - real64 const & pressure_n, // last time step - real64 const & temperature, - real64 const & GEOS_UNUSED_PARAM( temperature_k ), - real64 const & temperature_n ) const override final + virtual void updateFixedStress( localIndex const k, + localIndex const q, + real64 const & pressure, + real64 const & pressure_k, + real64 const & pressure_n, + real64 const & temperature, + real64 const & temperature_k, + real64 const & temperature_n ) const { - real64 const deltaPressureFromBeginningOfTimeStep = pressure - pressure_n; - real64 const deltaTemperatureFromBeginningOfTimeStep = temperature - temperature_n; - - computePorosity( deltaPressureFromBeginningOfTimeStep, - deltaTemperatureFromBeginningOfTimeStep, - m_porosity_n[k][q], - m_referencePorosity[k], - m_newPorosity[k][q], - m_dPorosity_dPressure[k][q], - m_dPorosity_dTemperature[k][q], - m_biotCoefficient[k], - m_thermalExpansionCoefficient[k], - m_averageMeanTotalStressIncrement_k[k], - m_bulkModulus[k] ); + real64 const fixedStressModulus = m_useUniaxialFixedStress ? (m_bulkModulus[k] + 4 * m_shearModulus[k] / 3) : m_bulkModulus[k]; + + computePorosityFixedStress( pressure, pressure_k, pressure_n, + temperature, temperature_k, temperature_n, + m_porosity_n[k][q], + m_referencePorosity[k], + m_newPorosity[k][q], + m_dPorosity_dPressure[k][q], + m_dPorosity_dTemperature[k][q], + m_biotCoefficient[k], + m_thermalExpansionCoefficient[k], + m_averageMeanTotalStressIncrement_k[k], + m_bulkModulus[k], + fixedStressModulus, + m_grainBulkModulus[k] ); } GEOS_HOST_DEVICE - void updateBiotCoefficientAndAssignBulkModulus( localIndex const k, - real64 const bulkModulus ) const + void updateBiotCoefficientAndAssignModuli( localIndex const k, + real64 const bulkModulus, real64 const shearModulus ) const { m_bulkModulus[k] = bulkModulus; - m_biotCoefficient[k] = 1 - bulkModulus / m_grainBulkModulus; + m_shearModulus[k] = shearModulus; + + m_biotCoefficient[k] = 1.0 - bulkModulus / m_grainBulkModulus[k]; } GEOS_HOST_DEVICE @@ -182,7 +202,7 @@ class BiotPorosityUpdates : public PorosityBaseUpdates protected: /// Grain bulk modulus (read from XML) - real64 const m_grainBulkModulus; + arrayView1d< real64 > const m_grainBulkModulus; /// View on the thermal expansion coefficients (read from XML) arrayView1d< real64 const > const m_thermalExpansionCoefficient; @@ -193,12 +213,17 @@ class BiotPorosityUpdates : public PorosityBaseUpdates /// View on the bulk modulus (updated by PorousSolid) arrayView1d< real64 > const m_bulkModulus; + /// View on the shear modulus (updated by PorousSolid) + arrayView1d< real64 > const m_shearModulus; + /// View on the mean total stress increment at quadrature points (updated by PorousSolid) arrayView2d< real64 > const m_meanTotalStressIncrement_k; /// View on the average mean total stress increment arrayView1d< real64 > const m_averageMeanTotalStressIncrement_k; + /// Flag enabling uniaxial approximation in fixed stress update + integer m_useUniaxialFixedStress; }; class BiotPorosity : public PorosityBase @@ -215,7 +240,7 @@ class BiotPorosity : public PorosityBase struct viewKeyStruct : public PorosityBase::viewKeyStruct { - static constexpr char const *grainBulkModulusString() { return "grainBulkModulus"; } + static constexpr char const *defaultGrainBulkModulusString() { return "defaultGrainBulkModulus"; } static constexpr char const *meanTotalStressIncrementString() { return "meanTotalStressIncrement"; } @@ -223,7 +248,13 @@ class BiotPorosity : public PorosityBase static constexpr char const *solidBulkModulusString() { return "solidBulkModulus"; } + static constexpr char const *solidShearModulusString() { return "solidShearModulus"; } + static constexpr char const *defaultThermalExpansionCoefficientString() { return "defaultPorosityTEC"; } + + static constexpr char const *useUniaxialFixedStressString() { return "useUniaxialFixedStress"; } + + static constexpr char const *defaultBiotCoefficientString() { return "defaultBiotCoefficient"; } } viewKeys; virtual void initializeState() const override final; @@ -273,11 +304,13 @@ class BiotPorosity : public PorosityBase m_meanTotalStressIncrement_k, m_averageMeanTotalStressIncrement_k, m_bulkModulus, - m_grainBulkModulus ); + m_shearModulus, + m_grainBulkModulus, + m_useUniaxialFixedStress ); } protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// Default thermal expansion coefficients (read from XML) @@ -286,12 +319,18 @@ class BiotPorosity : public PorosityBase /// Thermal expansion coefficients (read from XML) array1d< real64 > m_thermalExpansionCoefficient; + /// Default value of the Biot coefficient (read from XML) + real64 m_defaultBiotCoefficient; + /// Biot coefficients (update in the update class, not read in input) array1d< real64 > m_biotCoefficient; /// Bulk modulus (updated in the update class, not read in input) array1d< real64 > m_bulkModulus; + /// Shear modulus (updated in the update class, not read in input) + array1d< real64 > m_shearModulus; + /// Mean total stress increment (updated in the update class, not read in input) array2d< real64 > m_meanTotalStressIncrement_k; @@ -299,7 +338,13 @@ class BiotPorosity : public PorosityBase array1d< real64 > m_averageMeanTotalStressIncrement_k; /// Grain bulk modulus (read from XML) - real64 m_grainBulkModulus; + real64 m_defaultGrainBulkModulus; + + /// Grain bulk modulus (can be specified in XML) + array1d< real64 > m_grainBulkModulus; + + /// Flag enabling uniaxial approximation in fixed stress update + integer m_useUniaxialFixedStress; }; } /* namespace constitutive */ diff --git a/src/coreComponents/constitutive/solid/porosity/PorosityBase.cpp b/src/coreComponents/constitutive/solid/porosity/PorosityBase.cpp index 7bd1990640d..8b354eaebcc 100644 --- a/src/coreComponents/constitutive/solid/porosity/PorosityBase.cpp +++ b/src/coreComponents/constitutive/solid/porosity/PorosityBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -67,7 +68,7 @@ void PorosityBase::allocateConstitutiveData( dataRepository::Group & parent, ConstitutiveBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex ); } -void PorosityBase::postProcessInput() +void PorosityBase::postInputInitialization() { getField< fields::porosity::referencePorosity >(). setApplyDefaultValue( m_defaultReferencePorosity ); diff --git a/src/coreComponents/constitutive/solid/porosity/PorosityBase.hpp b/src/coreComponents/constitutive/solid/porosity/PorosityBase.hpp index 4485e30c089..72cffcf623f 100644 --- a/src/coreComponents/constitutive/solid/porosity/PorosityBase.hpp +++ b/src/coreComponents/constitutive/solid/porosity/PorosityBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -58,27 +59,6 @@ class PorosityBaseUpdates m_referencePorosity ( referencePorosity ) {} - /** - * @brief Helper to save point stress back to m_newPorosity array - * - * This is mostly defined for improving code readability. - * - * @param[in] k Element index. - * @param[in] q Quadrature point index. - * @param[in] porosity porosity to be saved to m_newPorosity[k][q] - * @param[in] dPorosity_dPressure porosity derivative w.r.t pressure to be saved to m_dPorosity_dPressure[k][q] - */ - GEOS_HOST_DEVICE - inline - void savePorosity( localIndex const k, - localIndex const q, - real64 const & porosity, - real64 const & dPorosity_dPressure ) const - { - m_newPorosity[k][q] = porosity; - m_dPorosity_dPressure[k][q] = dPorosity_dPressure; - } - /** * @brief Helper to save porosity back to m_newPorosity array * @@ -128,20 +108,6 @@ class PorosityBaseUpdates return m_initialPorosity[k][q]; } - GEOS_HOST_DEVICE - virtual void updateFromPressureAndTemperature( localIndex const k, - localIndex const q, - real64 const & pressure, - real64 const & pressure_k, - real64 const & pressure_n, - real64 const & temperature, - real64 const & temperature_k, - real64 const & temperature_n ) const - { - GEOS_UNUSED_VAR( k, q, pressure, pressure_k, pressure_n, temperature, temperature_k, temperature_n ); - GEOS_ERROR( "updateFromPressureAndTemperature is not implemented for porosityBase." ); - } - protected: /// New value of porosity @@ -172,10 +138,6 @@ class PorosityBase : public ConstitutiveBase virtual void allocateConstitutiveData( dataRepository::Group & parent, localIndex const numConstitutivePointsPerParentIndex ) override; - static string catalogName() { return "PorosityBase"; } - - virtual string getCatalogName() const override { return catalogName(); } - struct viewKeyStruct : public ConstitutiveBase::viewKeyStruct { static constexpr char const * defaultReferencePorosityString() { return "defaultReferencePorosity"; } @@ -289,17 +251,6 @@ class PorosityBase : public ConstitutiveBase return out.toView(); } - GEOS_HOST_DEVICE - inline - void savePorosity( localIndex const k, - localIndex const q, - real64 const & porosity, - real64 const & dPorosity_dPressure ) const - { - m_newPorosity[k][q] = porosity; - m_dPorosity_dPressure[k][q] = dPorosity_dPressure; - } - using KernelWrapper = PorosityBaseUpdates; /** @@ -318,7 +269,7 @@ class PorosityBase : public ConstitutiveBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; array2d< real64 > m_newPorosity; diff --git a/src/coreComponents/constitutive/solid/porosity/PorosityFields.hpp b/src/coreComponents/constitutive/solid/porosity/PorosityFields.hpp index f36a43b440f..60b90dcbff1 100644 --- a/src/coreComponents/constitutive/solid/porosity/PorosityFields.hpp +++ b/src/coreComponents/constitutive/solid/porosity/PorosityFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -82,7 +83,7 @@ DECLARE_FIELD( biotCoefficient, "biotCoefficient", array1d< real64 >, 0, - NOPLOT, + LEVEL_0, WRITE_AND_READ, "Biot coefficient" ); @@ -110,6 +111,14 @@ DECLARE_FIELD( averageMeanTotalStressIncrement_k, NO_WRITE, "Mean total stress increment averaged over quadrature points at the previous sequential iteration" ); +DECLARE_FIELD( grainBulkModulus, + "grainBulkModulus", + array1d< real64 >, + 0, + LEVEL_0, + WRITE_AND_READ, + "Biot coefficient" ); + } diff --git a/src/coreComponents/constitutive/solid/porosity/PressurePorosity.cpp b/src/coreComponents/constitutive/solid/porosity/PressurePorosity.cpp index 18cc9d31a08..cf62672c08d 100644 --- a/src/coreComponents/constitutive/solid/porosity/PressurePorosity.cpp +++ b/src/coreComponents/constitutive/solid/porosity/PressurePorosity.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -46,9 +47,9 @@ void PressurePorosity::allocateConstitutiveData( dataRepository::Group & parent, PorosityBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex ); } -void PressurePorosity::postProcessInput() +void PressurePorosity::postInputInitialization() { - PorosityBase::postProcessInput(); + PorosityBase::postInputInitialization(); // TODO valdate input } diff --git a/src/coreComponents/constitutive/solid/porosity/PressurePorosity.hpp b/src/coreComponents/constitutive/solid/porosity/PressurePorosity.hpp index 584f69ce3e7..37228c53c65 100644 --- a/src/coreComponents/constitutive/solid/porosity/PressurePorosity.hpp +++ b/src/coreComponents/constitutive/solid/porosity/PressurePorosity.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -67,14 +68,10 @@ class PressurePorosityUpdates : public PorosityBaseUpdates } GEOS_HOST_DEVICE - virtual void updateFromPressureAndTemperature( localIndex const k, - localIndex const q, - real64 const & pressure, - real64 const & GEOS_UNUSED_PARAM( pressure_k ), - real64 const & GEOS_UNUSED_PARAM( pressure_n ), - real64 const & temperature, - real64 const & GEOS_UNUSED_PARAM( temperature_k ), - real64 const & GEOS_UNUSED_PARAM( temperature_n ) ) const override final + void updateFromPressureAndTemperature( localIndex const k, + localIndex const q, + real64 const & pressure, + real64 const & temperature ) const { computePorosity( pressure, temperature, @@ -132,7 +129,7 @@ class PressurePorosity : public PorosityBase private: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; real64 m_referencePressure; diff --git a/src/coreComponents/constitutive/solid/porosity/ProppantPorosity.cpp b/src/coreComponents/constitutive/solid/porosity/ProppantPorosity.cpp index 367f3987b04..fb27663d63d 100644 --- a/src/coreComponents/constitutive/solid/porosity/ProppantPorosity.cpp +++ b/src/coreComponents/constitutive/solid/porosity/ProppantPorosity.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -51,7 +52,7 @@ void ProppantPorosity::allocateConstitutiveData( dataRepository::Group & parent, PorosityBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex ); } -void ProppantPorosity::postProcessInput() +void ProppantPorosity::postInputInitialization() { getField< fields::porosity::referencePorosity >(). setApplyDefaultValue( m_defaultReferencePorosity ); diff --git a/src/coreComponents/constitutive/solid/porosity/ProppantPorosity.hpp b/src/coreComponents/constitutive/solid/porosity/ProppantPorosity.hpp index ef271b87883..45a23163aec 100644 --- a/src/coreComponents/constitutive/solid/porosity/ProppantPorosity.hpp +++ b/src/coreComponents/constitutive/solid/porosity/ProppantPorosity.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -110,7 +111,7 @@ class ProppantPorosity : public PorosityBase private: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; real64 m_maxProppantConcentration; diff --git a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseConstantThermalConductivity.cpp b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseConstantThermalConductivity.cpp index ae739db7160..3ca4d0ba26a 100644 --- a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseConstantThermalConductivity.cpp +++ b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseConstantThermalConductivity.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -59,7 +60,7 @@ void MultiPhaseConstantThermalConductivity::allocateConstitutiveData( dataReposi } } -void MultiPhaseConstantThermalConductivity::postProcessInput() +void MultiPhaseConstantThermalConductivity::postInputInitialization() { GEOS_THROW_IF( m_thermalConductivityComponents[0] < 0 || m_thermalConductivityComponents[1] < 0 || diff --git a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseConstantThermalConductivity.hpp b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseConstantThermalConductivity.hpp index b95625ac8d4..8d9edf7bd91 100644 --- a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseConstantThermalConductivity.hpp +++ b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseConstantThermalConductivity.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -98,7 +99,7 @@ class MultiPhaseConstantThermalConductivity : public MultiPhaseThermalConductivi protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; private: diff --git a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivityBase.cpp b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivityBase.cpp index 9b46ce43008..8e74a96e8ed 100644 --- a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivityBase.cpp +++ b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivityBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -40,9 +41,9 @@ MultiPhaseThermalConductivityBase::MultiPhaseThermalConductivityBase( string con registerField( fields::thermalconductivity::dEffectiveConductivity_dPhaseVolFraction{}, &m_dEffectiveConductivity_dPhaseVolFrac ); } -void MultiPhaseThermalConductivityBase::postProcessInput() +void MultiPhaseThermalConductivityBase::postInputInitialization() { - ConstitutiveBase::postProcessInput(); + ConstitutiveBase::postInputInitialization(); integer const numPhases = numFluidPhases(); GEOS_THROW_IF_LT_MSG( numPhases, 2, diff --git a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivityBase.hpp b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivityBase.hpp index c29f7bac2ba..be06063814b 100644 --- a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivityBase.hpp +++ b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivityBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -175,7 +176,7 @@ class MultiPhaseThermalConductivityBase : public ConstitutiveBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// phase names read from input string_array m_phaseNames; diff --git a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivityFields.hpp b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivityFields.hpp index eeec60a2797..335ba640bb1 100644 --- a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivityFields.hpp +++ b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivityFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivitySelector.hpp b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivitySelector.hpp index 98dbfb63bae..fdb89e7ba00 100644 --- a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivitySelector.hpp +++ b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseThermalConductivitySelector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseVolumeWeightedThermalConductivity.cpp b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseVolumeWeightedThermalConductivity.cpp index 5d8f996c0b5..f72e78bfdb3 100644 --- a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseVolumeWeightedThermalConductivity.cpp +++ b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseVolumeWeightedThermalConductivity.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -71,7 +72,7 @@ void MultiPhaseVolumeWeightedThermalConductivity::allocateConstitutiveData( data } } -void MultiPhaseVolumeWeightedThermalConductivity::postProcessInput() +void MultiPhaseVolumeWeightedThermalConductivity::postInputInitialization() { GEOS_THROW_IF( m_rockThermalConductivityComponents[0] <= 0 || m_rockThermalConductivityComponents[1] <= 0 || diff --git a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseVolumeWeightedThermalConductivity.hpp b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseVolumeWeightedThermalConductivity.hpp index e1000cd6bc6..ad1c4b37680 100644 --- a/src/coreComponents/constitutive/thermalConductivity/MultiPhaseVolumeWeightedThermalConductivity.hpp +++ b/src/coreComponents/constitutive/thermalConductivity/MultiPhaseVolumeWeightedThermalConductivity.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -160,7 +161,7 @@ class MultiPhaseVolumeWeightedThermalConductivity : public MultiPhaseThermalCond protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; private: diff --git a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseConstantThermalConductivity.cpp b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseConstantThermalConductivity.cpp deleted file mode 100644 index 0cd9199bb37..00000000000 --- a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseConstantThermalConductivity.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file SinglePhaseConstantThermalConductivity.cpp - */ - -#include "SinglePhaseConstantThermalConductivity.hpp" - -namespace geos -{ - -using namespace dataRepository; - -namespace constitutive -{ - -SinglePhaseConstantThermalConductivity::SinglePhaseConstantThermalConductivity( string const & name, Group * const parent ): - SinglePhaseThermalConductivityBase( name, parent ) -{ - registerWrapper( viewKeyStruct::thermalConductivityComponentsString(), &m_thermalConductivityComponents ). - setInputFlag( InputFlags::REQUIRED ). - setRestartFlags( RestartFlags::NO_WRITE ). - setDescription( "xx, yy, and zz components of a diagonal thermal conductivity tensor [J/(s.m.K)]" ); -} - -std::unique_ptr< ConstitutiveBase > -SinglePhaseConstantThermalConductivity::deliverClone( string const & name, - Group * const parent ) const -{ - return SinglePhaseThermalConductivityBase::deliverClone( name, parent ); -} - -void SinglePhaseConstantThermalConductivity::initializeRockFluidState( arrayView2d< real64 const > const & initialPorosity ) const -{ - for( localIndex ei = 0; ei < initialPorosity.size( 0 ); ++ei ) - { - // NOTE: enforcing 1 quadrature point - for( localIndex q = 0; q < 1; ++q ) - { - m_effectiveConductivity[ei][q][0] = m_thermalConductivityComponents[0]; - m_effectiveConductivity[ei][q][1] = m_thermalConductivityComponents[1]; - m_effectiveConductivity[ei][q][2] = m_thermalConductivityComponents[2]; - } - } -} - -void SinglePhaseConstantThermalConductivity::update( arrayView2d< real64 const > const & initialPorosity ) const -{ - real64 thermalConductivityComponents[3]; - for( int i = 0; i<3; ++i ) - { - thermalConductivityComponents[i] = m_thermalConductivityComponents[i]; - } - arrayView3d< real64 > const effectiveConductivity = m_effectiveConductivity; - - forAll< parallelDevicePolicy<> >( initialPorosity.size( 0 ), [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - // NOTE: enforcing 1 quadrature point - for( localIndex q = 0; q < 1; ++q ) - { - effectiveConductivity[ei][q][0] = thermalConductivityComponents[0]; - effectiveConductivity[ei][q][1] = thermalConductivityComponents[1]; - effectiveConductivity[ei][q][2] = thermalConductivityComponents[2]; - } - } ); -} - -void SinglePhaseConstantThermalConductivity::allocateConstitutiveData( dataRepository::Group & parent, - localIndex const numConstitutivePointsPerParentIndex ) -{ - SinglePhaseThermalConductivityBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex ); -} - -void SinglePhaseConstantThermalConductivity::postProcessInput() -{ - GEOS_THROW_IF( m_thermalConductivityComponents[0] <= 0 || - m_thermalConductivityComponents[1] <= 0 || - m_thermalConductivityComponents[2] <= 0, - GEOS_FMT( "{}: the components of the thermal conductivity tensor must be strictly positive", - getFullName() ), - InputError ); -} - -REGISTER_CATALOG_ENTRY( ConstitutiveBase, SinglePhaseConstantThermalConductivity, string const &, Group * const ) - -} // namespace constitutive - -} // namespace geos diff --git a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseConstantThermalConductivity.hpp b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseConstantThermalConductivity.hpp deleted file mode 100644 index ae343d61ed7..00000000000 --- a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseConstantThermalConductivity.hpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file SinglePhaseConstantThermalConductivity.hpp - */ - -#ifndef GEOS_CONSTITUTIVE_SINGLEPHASE_THERMALCONDUCTIVITY_CONSTANTTHERMALCONDUCTIVITY_HPP_ -#define GEOS_CONSTITUTIVE_SINGLEPHASE_THERMALCONDUCTIVITY_CONSTANTTHERMALCONDUCTIVITY_HPP_ - -#include "constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.hpp" - - -namespace geos -{ -namespace constitutive -{ - -/** - * @brief The update class for constant thermal conductivity (does not do anything) - */ -class SinglePhaseConstantThermalConductivityUpdate : public SinglePhaseThermalConductivityBaseUpdate -{ -public: - - /** - * @brief Constructor for the class performing the thermal conductivity updates - * @param effectiveConductivity the array of cell-wise effective conductivities in the subregion - * the subregion - */ - SinglePhaseConstantThermalConductivityUpdate( arrayView3d< real64 > const & effectiveConductivity ) - : SinglePhaseThermalConductivityBaseUpdate( effectiveConductivity ) - {} - - GEOS_HOST_DEVICE - virtual void update( localIndex const k, - localIndex const q, - real64 const & laggedPorosity ) const override - { GEOS_UNUSED_VAR( k, q, laggedPorosity ); } - -}; - -/** - * @brief The class for constant thermal conductivity - */ -class SinglePhaseConstantThermalConductivity : public SinglePhaseThermalConductivityBase -{ -public: - - /** - * @brief Constructor for the class storing constant conductivity - * @param[in] name the name of the class - * @param[in] parent pointer to the parent Group - */ - SinglePhaseConstantThermalConductivity( string const & name, Group * const parent ); - - std::unique_ptr< ConstitutiveBase > deliverClone( string const & name, - Group * const parent ) const override; - - virtual void allocateConstitutiveData( dataRepository::Group & parent, - localIndex const numConstitutivePointsPerParentIndex ) override; - - static string catalogName() { return "SinglePhaseConstantThermalConductivity"; } - - virtual string getCatalogName() const override { return catalogName(); } - - - virtual void initializeRockFluidState( arrayView2d< real64 const > const & initialPorosity ) const override final; - - virtual void update( arrayView2d< real64 const > const & porosity ) const override final; - - - /// Type of kernel wrapper for in-kernel update - using KernelWrapper = SinglePhaseConstantThermalConductivityUpdate; - - /** - * @brief Create an update kernel wrapper. - * @return the wrapper - */ - KernelWrapper createKernelWrapper() const - { - return KernelWrapper( m_effectiveConductivity ); - } - - struct viewKeyStruct : public SinglePhaseThermalConductivityBase::viewKeyStruct - { - static constexpr char const * thermalConductivityComponentsString() { return "thermalConductivityComponents"; } - } viewKeys; - -protected: - - virtual void postProcessInput() override; - -private: - - /// default thermal conductivity in the subRegion - R1Tensor m_thermalConductivityComponents; - -}; - -} // namespace constitutive - -} // namespace geos - - -#endif //GEOS_CONSTITUTIVE_SINGLEPHASE_THERMALCONDUCTIVITY_CONSTANTTHERMALCONDUCTIVITY_HPP_ diff --git a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivity.cpp b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivity.cpp new file mode 100644 index 00000000000..51a8082165e --- /dev/null +++ b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivity.cpp @@ -0,0 +1,134 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SinglePhaseThermalConductivity.cpp + */ + +#include "SinglePhaseThermalConductivity.hpp" + +namespace geos +{ + +using namespace dataRepository; + +namespace constitutive +{ + +SinglePhaseThermalConductivity::SinglePhaseThermalConductivity( string const & name, Group * const parent ): + SinglePhaseThermalConductivityBase( name, parent ) +{ + registerWrapper( viewKeyStruct::defaultThermalConductivityComponentsString(), &m_defaultThermalConductivityComponents ). + setInputFlag( InputFlags::REQUIRED ). + setRestartFlags( RestartFlags::NO_WRITE ). + setDescription( "xx, yy, and zz diagonal components of the default thermal conductivity tensor [J/(s.m.K)]" ); + + registerWrapper( viewKeyStruct::thermalConductivityGradientComponentsString(), &m_thermalConductivityGradientComponents ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( {0.0, 0.0, 0.0} ). + setDescription( "xx, yy, and zz diagonal components of the thermal conductivity gradient tensor w.r.t. temperature [J/(s.m.K^2)]" ); + + registerWrapper( viewKeyStruct::referenceTemperatureString(), &m_referenceTemperature ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( 0.0 ). + setDescription( "The reference temperature at which the conductivity components are equal to the default values" ); +} + +std::unique_ptr< ConstitutiveBase > +SinglePhaseThermalConductivity::deliverClone( string const & name, + Group * const parent ) const +{ + return SinglePhaseThermalConductivityBase::deliverClone( name, parent ); +} + +void SinglePhaseThermalConductivity::initializeRockFluidState( arrayView2d< real64 const > const & initialPorosity ) const +{ + arrayView3d< real64 > dEffectiveConductivity_dT = m_dEffectiveConductivity_dT.toView(); + arrayView3d< real64 > effectiveConductivity = m_effectiveConductivity.toView(); + R1Tensor const defaultThermalConductivityComponents = m_defaultThermalConductivityComponents; + R1Tensor const thermalConductivityGradientComponents = m_thermalConductivityGradientComponents; + + forAll< parallelDevicePolicy<> >( initialPorosity.size( 0 ), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + // NOTE: enforcing 1 quadrature point + for( localIndex q = 0; q < 1; ++q ) + { + effectiveConductivity[ei][q][0] = defaultThermalConductivityComponents[0]; + effectiveConductivity[ei][q][1] = defaultThermalConductivityComponents[1]; + effectiveConductivity[ei][q][2] = defaultThermalConductivityComponents[2]; + + dEffectiveConductivity_dT[ei][q][0] = thermalConductivityGradientComponents[0]; + dEffectiveConductivity_dT[ei][q][1] = thermalConductivityGradientComponents[1]; + dEffectiveConductivity_dT[ei][q][2] = thermalConductivityGradientComponents[2]; + } + } ); +} + +void SinglePhaseThermalConductivity::updateFromTemperature( arrayView1d< real64 const > const & temperature ) const +{ + arrayView3d< real64 > dEffectiveConductivity_dT = m_dEffectiveConductivity_dT.toView(); + arrayView3d< real64 > effectiveConductivity = m_effectiveConductivity.toView(); + R1Tensor const defaultThermalConductivityComponents = m_defaultThermalConductivityComponents; + R1Tensor const thermalConductivityGradientComponents = m_thermalConductivityGradientComponents; + real64 const referenceTemperature = m_referenceTemperature; + + forAll< parallelDevicePolicy<> >( temperature.size( 0 ), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + for( localIndex q = 0; q < 1; ++q ) + { + + real64 const deltaTemperature = temperature[ei] - referenceTemperature; + + effectiveConductivity[ei][q][0] = defaultThermalConductivityComponents[0] + thermalConductivityGradientComponents[0] * deltaTemperature; + effectiveConductivity[ei][q][1] = defaultThermalConductivityComponents[1] + thermalConductivityGradientComponents[1] * deltaTemperature; + effectiveConductivity[ei][q][2] = defaultThermalConductivityComponents[2] + thermalConductivityGradientComponents[2] * deltaTemperature; + + for( localIndex i=0; i<=2; i++ ) + { + if( effectiveConductivity[ei][q][i] <1e-2 ) + { + effectiveConductivity[ei][q][i] = 1e-2; // W/m/K To avoid negative conductivity + } + } + + dEffectiveConductivity_dT[ei][q][0] = thermalConductivityGradientComponents[0]; + dEffectiveConductivity_dT[ei][q][1] = thermalConductivityGradientComponents[1]; + dEffectiveConductivity_dT[ei][q][2] = thermalConductivityGradientComponents[2]; + } + } ); +} + +void SinglePhaseThermalConductivity::allocateConstitutiveData( dataRepository::Group & parent, + localIndex const numConstitutivePointsPerParentIndex ) +{ + SinglePhaseThermalConductivityBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex ); +} + +void SinglePhaseThermalConductivity::postInputInitialization() +{ + GEOS_THROW_IF( m_defaultThermalConductivityComponents[0] <= 0 || + m_defaultThermalConductivityComponents[1] <= 0 || + m_defaultThermalConductivityComponents[2] <= 0, + GEOS_FMT( "{}: the components of the default thermal conductivity tensor must be strictly positive", + getFullName() ), + InputError ); + +} + +REGISTER_CATALOG_ENTRY( ConstitutiveBase, SinglePhaseThermalConductivity, string const &, Group * const ) + +} // namespace constitutive + +} // namespace geos diff --git a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivity.hpp b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivity.hpp new file mode 100644 index 00000000000..e19319c841b --- /dev/null +++ b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivity.hpp @@ -0,0 +1,127 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SinglePhaseThermalConductivity.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_SINGLEPHASE_THERMALCONDUCTIVITY_THERMALCONDUCTIVITY_HPP_ +#define GEOS_CONSTITUTIVE_SINGLEPHASE_THERMALCONDUCTIVITY_THERMALCONDUCTIVITY_HPP_ + +#include "constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.hpp" + + +namespace geos +{ +namespace constitutive +{ + +/** + * @brief The update class for constant thermal conductivity (does not do anything) + */ +class SinglePhaseThermalConductivityUpdate : public SinglePhaseThermalConductivityBaseUpdate +{ +public: + + /** + * @brief Constructor for the class performing the thermal conductivity updates + * @param effectiveConductivity the array of cell-wise effective conductivities in the subregion + * the subregion + */ + SinglePhaseThermalConductivityUpdate( arrayView3d< real64 > const & effectiveConductivity, + arrayView3d< real64 > const & dEffectiveConductivity_dT ) + : SinglePhaseThermalConductivityBaseUpdate( effectiveConductivity, + dEffectiveConductivity_dT ) + {} + + GEOS_HOST_DEVICE + virtual void update( localIndex const k, + localIndex const q, + real64 const & laggedPorosity ) const override + { GEOS_UNUSED_VAR( k, q, laggedPorosity ); } + +}; + +/** + * @brief The class for constant thermal conductivity + */ +class SinglePhaseThermalConductivity : public SinglePhaseThermalConductivityBase +{ +public: + + /** + * @brief Constructor for the class storing constant conductivity + * @param[in] name the name of the class + * @param[in] parent pointer to the parent Group + */ + SinglePhaseThermalConductivity( string const & name, Group * const parent ); + + std::unique_ptr< ConstitutiveBase > deliverClone( string const & name, + Group * const parent ) const override; + + virtual void allocateConstitutiveData( dataRepository::Group & parent, + localIndex const numConstitutivePointsPerParentIndex ) override; + + static string catalogName() { return "SinglePhaseThermalConductivity"; } + + virtual string getCatalogName() const override { return catalogName(); } + + virtual void initializeRockFluidState( arrayView2d< real64 const > const & initialPorosity ) const override final; + + virtual void updateFromTemperature( arrayView1d< real64 const > const & temperature ) const override final; + + /// Type of kernel wrapper for in-kernel update + using KernelWrapper = SinglePhaseThermalConductivityUpdate; + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelWrapper() const + { + return KernelWrapper( m_effectiveConductivity, + m_dEffectiveConductivity_dT ); + } + + struct viewKeyStruct : public SinglePhaseThermalConductivityBase::viewKeyStruct + { + static constexpr char const * defaultThermalConductivityComponentsString() { return "defaultThermalConductivityComponents"; } + static constexpr char const * thermalConductivityGradientComponentsString() { return "thermalConductivityGradientComponents"; } + static constexpr char const * referenceTemperatureString() { return "referenceTemperature"; } + } viewKeys; + +protected: + + virtual void postInputInitialization() override; + +private: + + /// Default thermal conductivity components in the subRegion + R1Tensor m_defaultThermalConductivityComponents; + + /// Thermal conductivity gradient components in the subRegion + R1Tensor m_thermalConductivityGradientComponents; + + /// Reference temperature + real64 m_referenceTemperature; + +}; + +} // namespace constitutive + +} // namespace geos + + +#endif //GEOS_CONSTITUTIVE_SINGLEPHASE_THERMALCONDUCTIVITY_CONSTANTTHERMALCONDUCTIVITY_HPP_ diff --git a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.cpp b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.cpp index 7bd134e0256..c0a4b0a47ed 100644 --- a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.cpp +++ b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,7 +19,6 @@ #include "SinglePhaseThermalConductivityBase.hpp" #include "ThermalConductivityFields.hpp" -#include "SinglePhaseThermalConductivityFields.hpp" namespace geos { @@ -32,13 +32,15 @@ SinglePhaseThermalConductivityBase::SinglePhaseThermalConductivityBase( string c : ConstitutiveBase( name, parent ) { registerField( fields::thermalconductivity::effectiveConductivity{}, &m_effectiveConductivity ); + registerField( fields::thermalconductivity::dEffectiveConductivity_dT{}, &m_dEffectiveConductivity_dT ); } -void SinglePhaseThermalConductivityBase::postProcessInput() +void SinglePhaseThermalConductivityBase::postInputInitialization() { - ConstitutiveBase::postProcessInput(); + ConstitutiveBase::postInputInitialization(); m_effectiveConductivity.resize( 0, 0, 3 ); + m_dEffectiveConductivity_dT.resize( 0, 0, 3 ); } void SinglePhaseThermalConductivityBase::allocateConstitutiveData( dataRepository::Group & parent, @@ -46,6 +48,7 @@ void SinglePhaseThermalConductivityBase::allocateConstitutiveData( dataRepositor { // NOTE: enforcing 1 quadrature point m_effectiveConductivity.resize( 0, 1, 3 ); + m_dEffectiveConductivity_dT.resize( 0, 1, 3 ); ConstitutiveBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex ); } diff --git a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.hpp b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.hpp index 612f05623c2..fd51086b7fa 100644 --- a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.hpp +++ b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -55,16 +56,18 @@ class SinglePhaseThermalConductivityBaseUpdate /** * @brief Constructor for the class performing the thermal conductivity updates * @param effectiveConductivity the array of cell-wise effective conductivities in the subregion - * @param dEffectiveConductivity_dPhaseVolFrac the array of cell-wise derivatives of effective conductivities wrt phase vol fractions in - * the subregion */ - SinglePhaseThermalConductivityBaseUpdate( arrayView3d< real64 > const & effectiveConductivity ) - : m_effectiveConductivity( effectiveConductivity ) + SinglePhaseThermalConductivityBaseUpdate( arrayView3d< real64 > const & effectiveConductivity, + arrayView3d< real64 > const & dEffectiveConductivity_dT ) + : m_effectiveConductivity( effectiveConductivity ), + m_dEffectiveConductivity_dT( dEffectiveConductivity_dT ) {} /// View on the cell-wise effective conductivities arrayView3d< real64 > m_effectiveConductivity; + /// View on the derivative of effective conductivities w.r.t. temperature + arrayView3d< real64 > m_dEffectiveConductivity_dT; private: /** @@ -124,12 +127,25 @@ class SinglePhaseThermalConductivityBase : public ConstitutiveBase virtual void update( arrayView2d< real64 const > const & porosity ) const { GEOS_UNUSED_VAR( porosity ); } + /** + * @brief Update the thermal conductivity state + * @param[in] temperature the temperature field + */ + virtual void updateFromTemperature( arrayView1d< real64 const > const & temperature ) const + { GEOS_UNUSED_VAR( temperature ); } + /** * @brief Getter for the effective conductivities in the subRegion * @return an arrayView of effective conductivities */ arrayView3d< real64 const > effectiveConductivity() const { return m_effectiveConductivity; } + /** + * @brief Getter for the derivative of effective conductivities in the subRegion w.r.t. temperature + * @return an arrayView of derivative of effective conductivities w.r.t. temperature + */ + arrayView3d< real64 const > dEffectiveConductivity_dT() const { return m_dEffectiveConductivity_dT; } + private: /** @@ -141,11 +157,13 @@ class SinglePhaseThermalConductivityBase : public ConstitutiveBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// cell-wise effective conductivities in the subregion array3d< real64 > m_effectiveConductivity; + /// Derivative of effective conductivities w.r.t. temperature + array3d< real64 > m_dEffectiveConductivity_dT; }; } // namespace constitutive diff --git a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityFields.hpp b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityFields.hpp deleted file mode 100644 index e996e05b5b0..00000000000 --- a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityFields.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file SinglePhaseThermalConductivityFields.hpp - */ - -#ifndef GEOS_CONSTITUTIVE_SINGLEPHASE_THERMALCONDUCTIVITY_THERMALCONDUCTIVITYFIELDS_HPP_ -#define GEOS_CONSTITUTIVE_SINGLEPHASE_THERMALCONDUCTIVITY_THERMALCONDUCTIVITYFIELDS_HPP_ - -#include "constitutive/relativePermeability/layouts.hpp" -#include "mesh/MeshFields.hpp" - -namespace geos -{ - -namespace fields -{ - -namespace thermalconductivity -{ - -DECLARE_FIELD( dEffectiveConductivity_dPorosity, - "dEffectiveConductivity_dPorosity", - array3d< real64 >, - 0, - NOPLOT, - NO_WRITE, - "Derivative of effective conductivity with respect to porosity" ); - -} - -} - -} - -#endif // GEOS_CONSTITUTIVE_SINGLEPHASE_THERMALCONDUCTIVITY_THERMALCONDUCTIVITYFIELDS_HPP_ diff --git a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivitySelector.hpp b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivitySelector.hpp index 4373503be8c..445d6f58c13 100644 --- a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivitySelector.hpp +++ b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivitySelector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #define GEOS_CONSTITUTIVE_SINGLEPHASE_THERMALCONDUCTIVITY_THERMALCONDUCTIVITYSELECTOR_HPP #include "constitutive/ConstitutivePassThruHandler.hpp" -#include "constitutive/thermalConductivity/SinglePhaseConstantThermalConductivity.hpp" +#include "constitutive/thermalConductivity/SinglePhaseThermalConductivity.hpp" namespace geos { @@ -32,14 +33,14 @@ template< typename LAMBDA > void constitutiveUpdatePassThru( SinglePhaseThermalConductivityBase const & thermalConductivity, LAMBDA && lambda ) { - ConstitutivePassThruHandler< SinglePhaseConstantThermalConductivity >::execute( thermalConductivity, std::forward< LAMBDA >( lambda ) ); + ConstitutivePassThruHandler< SinglePhaseThermalConductivity >::execute( thermalConductivity, std::forward< LAMBDA >( lambda ) ); } template< typename LAMBDA > void constitutiveUpdatePassThru( SinglePhaseThermalConductivityBase & thermalConductivity, LAMBDA && lambda ) { - ConstitutivePassThruHandler< SinglePhaseConstantThermalConductivity >::execute( thermalConductivity, std::forward< LAMBDA >( lambda ) ); + ConstitutivePassThruHandler< SinglePhaseThermalConductivity >::execute( thermalConductivity, std::forward< LAMBDA >( lambda ) ); } } // namespace constitutive diff --git a/src/coreComponents/constitutive/thermalConductivity/ThermalConductivityFields.hpp b/src/coreComponents/constitutive/thermalConductivity/ThermalConductivityFields.hpp index 661a3ad7f37..64ff08e9a70 100644 --- a/src/coreComponents/constitutive/thermalConductivity/ThermalConductivityFields.hpp +++ b/src/coreComponents/constitutive/thermalConductivity/ThermalConductivityFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -39,6 +40,14 @@ DECLARE_FIELD( effectiveConductivity, WRITE_AND_READ, "Effective conductivity" ); +DECLARE_FIELD( dEffectiveConductivity_dT, + "dEffectiveConductivity_dT", + array3d< real64 >, + 0, + LEVEL_3, + WRITE_AND_READ, + "Derivative of effective conductivity w.r.t. temperature" ); + DECLARE_FIELD( rockThermalConductivity, "rockThermalConductivity", array3d< real64 >, diff --git a/src/coreComponents/constitutive/unitTests/CMakeLists.txt b/src/coreComponents/constitutive/unitTests/CMakeLists.txt index add6c460a3f..aa095d493c8 100644 --- a/src/coreComponents/constitutive/unitTests/CMakeLists.txt +++ b/src/coreComponents/constitutive/unitTests/CMakeLists.txt @@ -1,20 +1,28 @@ # Specify list of tests set( gtest_geosx_tests + testCompositionalDensity.cpp testCompositionalProperties.cpp + testCubicEOS.cpp testDamageUtilities.cpp testDruckerPrager.cpp testElasticIsotropic.cpp testKValueInitialization.cpp + testImmiscibleWaterFlashModel.cpp + testImmiscibleWaterProperties.cpp + testLohrenzBrayClarkViscosity.cpp testModifiedCamClay.cpp + testMultiFluidSelector.cpp testNegativeTwoPhaseFlash.cpp + testNegativeTwoPhaseFlash9Comp.cpp testParticleFluidEnums.cpp testPropertyConversions.cpp - testCubicEOS.cpp + testStabilityTest2Comp.cpp + testStabilityTest9Comp.cpp testRachfordRice.cpp ) set( dependencyList gtest blas lapack constitutive ${parallelDeps} ) -if( ENABLE_CUDA_NVTOOLSEXT ) +if( ENABLE_CUDA AND ENABLE_CUDA_NVTOOLSEXT ) list( APPEND dependencyList CUDA::nvToolsExt ) endif() diff --git a/src/coreComponents/constitutive/unitTests/TestFluid.hpp b/src/coreComponents/constitutive/unitTests/TestFluid.hpp index e9f2f1fbf76..4728b19aaff 100644 --- a/src/coreComponents/constitutive/unitTests/TestFluid.hpp +++ b/src/coreComponents/constitutive/unitTests/TestFluid.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -44,12 +45,12 @@ struct Fluid static constexpr integer C8 = 9; static constexpr integer C10 = 10; - static constexpr integer Pc = 0; - static constexpr integer Tc = 1; - static constexpr integer Vc = 2; - static constexpr integer Ac = 3; - static constexpr integer Mw = 4; - static constexpr integer Vs = 5; + static constexpr integer Pc = 0; // Critical pressure + static constexpr integer Tc = 1; // Critical temperature + static constexpr integer Vc = 2; // Critical colume + static constexpr integer Ac = 3; // Accentric factor + static constexpr integer Mw = 4; // Molecular weight + static constexpr integer Vs = 5; // Volume shift static std::array< real64, 66 > data; }; @@ -66,6 +67,15 @@ class TestFluid static std::unique_ptr< TestFluid< NC > > create( std::array< integer, NC > const & components ) { std::unique_ptr< TestFluid< NC > > testFluid( new TestFluid() ); + const std::unordered_map< integer, string > componentNames = { + {Fluid::H2O, "H2O"}, {Fluid::CO2, "CO2"}, {Fluid::N2, "N2"}, {Fluid::H2S, "H2S"}, + {Fluid::C1, "CH4"}, {Fluid::C2, "C2H6"}, {Fluid::C3, "C3H8"}, {Fluid::C4, "C4H10"}, + {Fluid::C5, "C5H12"}, {Fluid::C8, "C8H18"}, {Fluid::C10, "C10+"}, + }; + for( integer const ic : components ) + { + testFluid->componentNames.emplace_back( componentNames.at( ic ) ); + } createArray( testFluid->criticalPressure, components, Fluid::Pc, Fluid::data ); createArray( testFluid->criticalTemperature, components, Fluid::Tc, Fluid::data ); createArray( testFluid->criticalVolume, components, Fluid::Vc, Fluid::data ); @@ -76,21 +86,54 @@ class TestFluid return testFluid; } - constitutive::compositional::ComponentProperties::KernelWrapper createKernelWrapper() const + template< typename LIST > + void setBinaryCoefficients( LIST const & bics ) { - return constitutive::compositional::ComponentProperties::KernelWrapper( - molecularWeight, - criticalPressure, - criticalTemperature, - criticalVolume, - acentricFactor, - volumeShift, - binaryCoeff ); + auto bic = bics.begin(); + for( int i = 0; i < NC; ++i ) + { + for( int j = 0; j < i; ++j ) + { + binaryCoeff( i, j ) = *bic++; + binaryCoeff( j, i ) = binaryCoeff( i, j ); + } + binaryCoeff( i, i ) = 0.0; + } + } + + constitutive::compositional::ComponentProperties & getComponentProperties() + { + if( !m_component_properties ) + { + m_component_properties = std::make_unique< constitutive::compositional::ComponentProperties >( + componentNames, + molecularWeight ); + createArray( m_component_properties->m_componentCriticalPressure, criticalPressure ); + createArray( m_component_properties->m_componentCriticalTemperature, criticalTemperature ); + createArray( m_component_properties->m_componentAcentricFactor, acentricFactor ); + createArray( m_component_properties->m_componentVolumeShift, volumeShift ); + m_component_properties->m_componentBinaryCoeff.resize( NC, NC ); + for( integer ic = 0; ic < NC; ++ic ) + { + for( integer jc = 0; jc < NC; ++jc ) + { + m_component_properties->m_componentBinaryCoeff( ic, jc ) = binaryCoeff( ic, jc ); + } + } + } + return *m_component_properties; + } + + constitutive::compositional::ComponentProperties::KernelWrapper createKernelWrapper() + { + return getComponentProperties().createKernelWrapper(); } private: TestFluid() = default; +public: + string_array componentNames; array1d< real64 > criticalPressure; array1d< real64 > criticalTemperature; array1d< real64 > criticalVolume; @@ -99,6 +142,9 @@ class TestFluid array1d< real64 > volumeShift; array2d< real64 > binaryCoeff; +private: + std::unique_ptr< constitutive::compositional::ComponentProperties > m_component_properties{}; + private: template< typename ARRAY, typename LIST, typename DATAARRAY > static void createArray( ARRAY & array, LIST const & indices, integer const row, DATAARRAY const & data ) @@ -117,6 +163,15 @@ class TestFluid array.emplace_back( value ); } } + template< typename ARRAY, typename LIST > + static void populateArray( ARRAY & array, LIST const & data ) + { + integer i = 0; + for( auto const value : data ) + { + array[i++] = value; + } + } }; std::array< real64, 66 > Fluid::data = { @@ -133,8 +188,8 @@ std::array< real64, 66 > Fluid::data = { 3.4400e-01, 2.3900e-01, 4.0000e-02, 9.4200e-02, -2.1900e-01, 9.9500e-02, 1.5230e-01, 1.8440e-01, 1.1400e-02, 4.4300e-01, 8.1600e-01, // -- Mw - 1.8015e+01, 4.4010e+01, 2.8013e+01, 3.4100e+01, 1.6043e+01, 3.0070e+01, - 4.4097e+01, 5.8124e+01, 7.2151e+01, 1.1423e+02, 1.4228e+02, + 1.8015e-02, 4.4010e-02, 2.8013e-02, 3.4100e-02, 1.6043e-02, 3.0070e-02, + 4.4097e-02, 5.8124e-02, 7.2151e-02, 1.1423e-01, 1.4228e-01, // -- Vs 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, diff --git a/src/coreComponents/constitutive/unitTests/TestFluidUtilities.hpp b/src/coreComponents/constitutive/unitTests/TestFluidUtilities.hpp index ec2cea463ca..c3d13fc6ed8 100644 --- a/src/coreComponents/constitutive/unitTests/TestFluidUtilities.hpp +++ b/src/coreComponents/constitutive/unitTests/TestFluidUtilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -59,6 +60,59 @@ void testNumericalDerivative( real64 const x, real64 const dx, real64 const deri checkRelativeError( derivative, rightDerivative, relTolerance, absTolerance, "Right derivative" ); } +/** + * @brief Tests a multi-valued function against a derivative + * @details Will calculate the left-sided and the right-sided numerical derivatives of a function + * and compare this against a analytically calculated values provided. + * @tparam numValues the number of values that the function returns + * @tparam FUNCTION the type of function (typically a lambda) + * @param x The value at which the function should be evaluated + * @param dx The value to use to perturb @c x in the calculation of the numerical derivatives + * @param derivatives The values of the analytically calculated derivatives to use for comparison + * @param function The function which is being tested. This should be a function that takes 2 parameters. + * The first is the value at which the function is being evaluated (x) and the second is an array + * of size @c numValues which is the result of the execution of the function. + * @param absTolerance The absolute tolerance to use for the comparison + * @param relTolerance The relative tolerance to use for the comparison + */ +template< integer numValues, typename FUNCTION > +void testNumericalDerivative( real64 const x, + real64 const dx, + arraySlice1d< real64 const > const & derivatives, + FUNCTION && function, + real64 const absTolerance = absTol, + real64 const relTolerance = relTol ) +{ + stackArray1d< real64, numValues > leftValues( numValues ); + stackArray1d< real64, numValues > centreValues( numValues ); + stackArray1d< real64, numValues > rightValues( numValues ); + function( x-dx, leftValues ); + function( x, centreValues ); + function( x+dx, rightValues ); + + // Use the same space to calculate the left-sided and right sided derivatives + for( integer i = 0; i < numValues; ++i ) + { + // Choose from the left, central and right derivatives, the one that's nearest the analytical value + real64 minError = LvArray::NumericLimits< real64 >::max; + real64 selectedDerivative = 0.0; + for( real64 const distance : {centreValues[i] - leftValues[i], + rightValues[i] - centreValues[i], + 0.5*(rightValues[i] - leftValues[i])} ) + { + real64 const deriv = distance / dx; + real64 const error = LvArray::math::abs( deriv - derivatives[i] ); + if( error < minError ) + { + minError = error; + selectedDerivative = deriv; + } + } + checkRelativeError( derivatives[i], selectedDerivative, relTolerance, absTolerance, + GEOS_FMT( "Numerical derivative for component {}", i ) ); + } +} + }// namespace internal }// namespace testing diff --git a/src/coreComponents/constitutive/unitTests/testCompositionalDensity.cpp b/src/coreComponents/constitutive/unitTests/testCompositionalDensity.cpp new file mode 100644 index 00000000000..2a5c25759a9 --- /dev/null +++ b/src/coreComponents/constitutive/unitTests/testCompositionalDensity.cpp @@ -0,0 +1,265 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// Source includes +#include "codingUtilities/UnitTestUtilities.hpp" +#include "constitutive/fluid/multifluid/compositional/models/CompositionalDensity.hpp" +#include "TestFluid.hpp" +#include "TestFluidUtilities.hpp" + +using namespace geos::constitutive::compositional; + +namespace geos +{ +namespace testing +{ + +template< int NC > +using DensityData = std::tuple< + real64 const, // pressure + real64 const, // temperature + Feed< NC > const, // phase composition + real64 const, // expected molar density + real64 const // expected mass density + >; + +template< int NC > +struct FluidData {}; + +template<> +struct FluidData< 9 > +{ + static std::unique_ptr< TestFluid< 9 > > createFluid() + { + auto fluid = TestFluid< 9 >::create( {Fluid::H2O, Fluid::CO2, Fluid::N2, Fluid::C5, Fluid::C2, Fluid::C3, Fluid::C4, Fluid::C5, Fluid::C10} ); + const std::array< real64 const, 36 > bics = { + 0.01, 0, 0.003732, 0, 0.01, 0, 0, 0.01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0.01, 0, 0.028, 0.01, 0.01, 0, 0, 0.01, 0, 0.04532, 0.01, 0.01, 0, 0, 0 + }; + fluid->setBinaryCoefficients( bics ); + return fluid; + } +}; + +template< int NC, EquationOfStateType EOS_TYPE > +class CompositionalDensityTestFixture : public ::testing::TestWithParam< DensityData< NC > > +{ + static constexpr real64 relTol = 1.0e-5; + static constexpr real64 absTol = 1.0e-7; + static constexpr int numComps = NC; + static constexpr int numDofs = NC + 2; + using Deriv = geos::constitutive::multifluid::DerivativeOffset; +public: + CompositionalDensityTestFixture() + : m_fluid( FluidData< NC >::createFluid() ) + { + ComponentProperties const & componentProperties = this->m_fluid->getComponentProperties(); + m_parameters = CompositionalDensity::createParameters( std::make_unique< ModelParameters >() ); + + auto equationOfState = const_cast< EquationOfState * >(m_parameters->get< EquationOfState >()); + string const eosName = EnumStrings< EquationOfStateType >::toString( EOS_TYPE ); + equationOfState->m_equationsOfStateNames.emplace_back( eosName ); + + m_density = std::make_unique< CompositionalDensity >( "PhaseDensity", componentProperties, 0, *m_parameters ); + } + + ~CompositionalDensityTestFixture() = default; + + void testDensityValues( DensityData< NC > const & data ) + { + real64 const pressure = std::get< 0 >( data ); + real64 const temperature = std::get< 1 >( data ); + stackArray1d< real64, numComps > phaseComposition; + TestFluid< NC >::createArray( phaseComposition, std::get< 2 >( data )); + real64 const expectedMolarDensity = std::get< 3 >( data ); + real64 const expectedMassDensity = std::get< 4 >( data ); + + auto componentProperties = m_fluid->createKernelWrapper(); + auto kernelWrapper = this->m_density->createKernelWrapper(); + + real64 molarDensity = 0.0; + real64 massDensity = 0.0; + stackArray1d< real64, numDofs > tempDerivs( numDofs ); + + kernelWrapper.compute( componentProperties, + pressure, + temperature, + phaseComposition.toSliceConst(), + molarDensity, + tempDerivs.toSlice(), + massDensity, + tempDerivs.toSlice(), + false ); + + checkRelativeError( molarDensity, expectedMolarDensity, relTol, absTol ); + checkRelativeError( massDensity, expectedMassDensity, relTol, absTol ); + } + + void testDensityDerivatives( DensityData< NC > const & data ) + { + real64 const pressure = std::get< 0 >( data ); + real64 const temperature = std::get< 1 >( data ); + stackArray1d< real64, numComps > phaseComposition; + TestFluid< NC >::createArray( phaseComposition, std::get< 2 >( data )); + + auto componentProperties = m_fluid->createKernelWrapper(); + auto kernelWrapper = m_density->createKernelWrapper(); + + real64 molarDensity = 0.0; + real64 massDensity = 0.0; + stackArray1d< real64, numDofs > molarDensityDerivs( numDofs ); + stackArray1d< real64, numDofs > massDensityDerivs( numDofs ); + + kernelWrapper.compute( componentProperties, + pressure, + temperature, + phaseComposition.toSliceConst(), + molarDensity, + molarDensityDerivs.toSlice(), + massDensity, + massDensityDerivs.toSlice(), + false ); + + auto calculateDensity = [&]( real64 const p, real64 const t, auto const & zmf ) -> std::pair< real64, real64 > { + real64 densityMolar = 0.0; + real64 densityMass = 0.0; + stackArray1d< real64, numDofs > tempDerivs( numDofs ); + kernelWrapper.compute( componentProperties, p, t, + zmf.toSliceConst(), + densityMolar, + tempDerivs.toSlice(), + densityMass, + tempDerivs.toSlice(), + false ); + return {densityMolar, densityMass}; + }; + + // Compare against numerical derivatives + // -- Pressure derivative + real64 const dp = 1.0e-4 * pressure; + internal::testNumericalDerivative( + pressure, dp, molarDensityDerivs[Deriv::dP], + [&]( real64 const p ) -> real64 { + return calculateDensity( p, temperature, phaseComposition ).first; + } ); + internal::testNumericalDerivative( + pressure, dp, massDensityDerivs[Deriv::dP], + [&]( real64 const p ) -> real64 { + return calculateDensity( p, temperature, phaseComposition ).second; + } ); + + // -- Temperature derivative + real64 const dT = 1.0e-6 * temperature; + internal::testNumericalDerivative( + temperature, dT, molarDensityDerivs[Deriv::dT], + [&]( real64 const t ) -> real64 { + return calculateDensity( pressure, t, phaseComposition ).first; + } ); + internal::testNumericalDerivative( + temperature, dT, massDensityDerivs[Deriv::dT], + [&]( real64 const t ) -> real64 { + return calculateDensity( pressure, t, phaseComposition ).second; + } ); + + // -- Composition derivatives derivative + real64 const dz = 1.0e-7; + for( integer ic = 0; ic < numComps; ++ic ) + { + internal::testNumericalDerivative( + 0.0, dz, molarDensityDerivs[Deriv::dC + ic], + [&]( real64 const z ) -> real64 { + stackArray1d< real64, numComps > zmf( numComps ); + for( integer jc = 0; jc < numComps; ++jc ) + { + zmf[jc] = phaseComposition[jc]; + } + zmf[ic] += z; + return calculateDensity( pressure, temperature, zmf ).first; + } ); + internal::testNumericalDerivative( + 0.0, dz, massDensityDerivs[Deriv::dC + ic], + [&]( real64 const z ) -> real64 { + stackArray1d< real64, numComps > zmf( numComps ); + for( integer jc = 0; jc < numComps; ++jc ) + { + zmf[jc] = phaseComposition[jc]; + } + zmf[ic] += z; + return calculateDensity( pressure, temperature, zmf ).second; + } ); + } + } + +protected: + std::unique_ptr< CompositionalDensity > m_density{}; + std::unique_ptr< TestFluid< NC > > m_fluid{}; + std::unique_ptr< ModelParameters > m_parameters{}; +}; + +using PengRobinson = CompositionalDensityTestFixture< 9, EquationOfStateType::PengRobinson >; +using SoaveRedlichKwong = CompositionalDensityTestFixture< 9, EquationOfStateType::SoaveRedlichKwong >; + +TEST_P( PengRobinson, testDensityDerivatives ) +{ + testDensityDerivatives( GetParam() ); +} + +TEST_P( SoaveRedlichKwong, testDensityDerivatives ) +{ + testDensityDerivatives( GetParam() ); +} + +/* UNCRUSTIFY-OFF */ + +INSTANTIATE_TEST_SUITE_P( + CompositionalDensityTest, PengRobinson, + ::testing::ValuesIn( { + DensityData< 9 >{1.839590e+06, 2.971500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 8.355571e+03, 4.559906e+02 }, + DensityData< 9 >{1.839590e+06, 2.971500e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 7.703898e+02, 2.691914e+01 }, + DensityData< 9 >{1.839590e+06, 2.971500e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 8.337694e+03, 4.567935e+02 }, + DensityData< 9 >{1.839590e+06, 3.630000e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 9.073321e+02, 4.951606e+01 }, + DensityData< 9 >{1.839590e+06, 3.630000e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 6.178234e+02, 2.158813e+01 }, + DensityData< 9 >{1.839590e+06, 3.630000e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 9.197865e+02, 5.039192e+01 }, + DensityData< 9 >{1.839590e+08, 2.971500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1.095078e+04, 5.976195e+02 }, + DensityData< 9 >{1.839590e+08, 2.971500e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 2.480270e+04, 8.666618e+02 }, + DensityData< 9 >{1.839590e+08, 2.971500e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 1.087917e+04, 5.960323e+02 }, + DensityData< 9 >{1.839590e+08, 3.630000e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1.065128e+04, 5.812747e+02 }, + DensityData< 9 >{1.839590e+08, 3.630000e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 2.305823e+04, 8.057060e+02 }, + DensityData< 9 >{1.839590e+08, 3.630000e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 1.058381e+04, 5.798506e+02 } + } ) + ); +INSTANTIATE_TEST_SUITE_P( + CompositionalDensityTest, SoaveRedlichKwong, + ::testing::ValuesIn( { + DensityData< 9 >{1.839590e+06, 2.971500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 7.433979e+03, 4.056963e+02 }, + DensityData< 9 >{1.839590e+06, 2.971500e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 7.629968e+02, 2.666082e+01 }, + DensityData< 9 >{1.839590e+06, 2.971500e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 7.416959e+03, 4.063495e+02 }, + DensityData< 9 >{1.839590e+06, 3.630000e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 8.919848e+02, 4.867851e+01 }, + DensityData< 9 >{1.839590e+06, 3.630000e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 6.133569e+02, 2.143206e+01 }, + DensityData< 9 >{1.839590e+06, 3.630000e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 9.045641e+02, 4.955794e+01 }, + DensityData< 9 >{1.839590e+08, 2.971500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 9.868675e+03, 5.385656e+02 }, + DensityData< 9 >{1.839590e+08, 2.971500e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 2.257420e+04, 7.887929e+02 }, + DensityData< 9 >{1.839590e+08, 2.971500e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 9.803814e+03, 5.371171e+02 }, + DensityData< 9 >{1.839590e+08, 3.630000e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 9.615674e+03, 5.247585e+02 }, + DensityData< 9 >{1.839590e+08, 3.630000e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 2.109248e+04, 7.370183e+02 }, + DensityData< 9 >{1.839590e+08, 3.630000e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 9.554300e+03, 5.234471e+02 } + } ) + ); + +/* UNCRUSTIFY-ON */ + +} // testing + +} // geos diff --git a/src/coreComponents/constitutive/unitTests/testCompositionalProperties.cpp b/src/coreComponents/constitutive/unitTests/testCompositionalProperties.cpp index c41428ed2da..910fd96059c 100644 --- a/src/coreComponents/constitutive/unitTests/testCompositionalProperties.cpp +++ b/src/coreComponents/constitutive/unitTests/testCompositionalProperties.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -51,6 +52,8 @@ class CompositionalPropertiesTestDataTestFixture : public ::testing::TestWithPar { public: static constexpr integer numComps = NC; + static constexpr integer numDof = NC + 2; + using Deriv = geos::constitutive::multifluid::DerivativeOffset; public: CompositionalPropertiesTestDataTestFixture() : m_fluid( createFluid< NC >() ) @@ -65,7 +68,7 @@ class CompositionalPropertiesTestDataTestFixture : public ::testing::TestWithPar real64 const molarDensity = computeMolarDensity( pressure, temperature, - composition ); + composition.toSliceConst() ); checkRelativeError( molarDensity, expectedMolarDensity, internal::relTol, internal::absTol ); } @@ -76,23 +79,19 @@ class CompositionalPropertiesTestDataTestFixture : public ::testing::TestWithPar const auto [pressure, temperature, composition] = getInputData( data ); real64 molarDensity = 0.0; - real64 dMolarDensity_dp = 0.0; - real64 dMolarDensity_dt = 0.0; - array1d< real64 > dMolarDensity_dz( numComps ); + stackArray1d< real64, numDof > molarDensityDerivs( numDof ); computeMolarDensity( pressure, temperature, - composition, + composition.toSliceConst(), molarDensity, - dMolarDensity_dp, - dMolarDensity_dt, - dMolarDensity_dz ); + molarDensityDerivs.toSlice() ); // Compare against numerical derivatives // -- Pressure derivative real64 const dp = 1.0e-4 * pressure; internal::testNumericalDerivative( - pressure, dp, dMolarDensity_dp, + pressure, dp, molarDensityDerivs[Deriv::dP], [this, & t=temperature, & zmf=composition]( real64 const p ) -> real64 { return computeMolarDensity( p, t, zmf ); } ); @@ -100,7 +99,7 @@ class CompositionalPropertiesTestDataTestFixture : public ::testing::TestWithPar // -- Temperature derivative real64 const dT = 1.0e-6 * temperature; internal::testNumericalDerivative( - temperature, dT, dMolarDensity_dt, + temperature, dT, molarDensityDerivs[Deriv::dT], [this, & p=pressure, & zmf=composition]( real64 const t ) -> real64 { return computeMolarDensity( p, t, zmf ); } ); @@ -110,7 +109,7 @@ class CompositionalPropertiesTestDataTestFixture : public ::testing::TestWithPar for( integer ic = 0; ic < numComps; ++ic ) { internal::testNumericalDerivative( - 0.0, dz, dMolarDensity_dz[ic], + 0.0, dz, molarDensityDerivs[Deriv::dC + ic], [this, & p=pressure, & t=temperature, zmf=composition, ic]( real64 const z ) -> real64 { zmf[ic] += z; real64 const density = computeMolarDensity( p, t, zmf ); @@ -139,23 +138,19 @@ class CompositionalPropertiesTestDataTestFixture : public ::testing::TestWithPar const auto [pressure, temperature, composition] = getInputData( data ); real64 massDensity = 0.0; - real64 dMassDensity_dp = 0.0; - real64 dMassDensity_dt = 0.0; - array1d< real64 > dMassDensity_dz( numComps ); + array1d< real64 > massDensityDerivs( numDof ); computeMassDensity( pressure, temperature, composition, massDensity, - dMassDensity_dp, - dMassDensity_dt, - dMassDensity_dz ); + massDensityDerivs ); // Compare against numerical derivatives // -- Pressure derivative real64 const dp = 1.0e-4 * pressure; internal::testNumericalDerivative( - pressure, dp, dMassDensity_dp, + pressure, dp, massDensityDerivs[Deriv::dP], [this, & t=temperature, & zmf=composition]( real64 const p ) -> real64 { return computeMassDensity( p, t, zmf ); } ); @@ -163,7 +158,7 @@ class CompositionalPropertiesTestDataTestFixture : public ::testing::TestWithPar // -- Temperature derivative real64 const dT = 1.0e-6 * temperature; internal::testNumericalDerivative( - temperature, dT, dMassDensity_dt, + temperature, dT, massDensityDerivs[Deriv::dT], [this, & p=pressure, & zmf=composition]( real64 const t ) -> real64 { return computeMassDensity( p, t, zmf ); } ); @@ -173,11 +168,12 @@ class CompositionalPropertiesTestDataTestFixture : public ::testing::TestWithPar for( integer ic = 0; ic < numComps; ++ic ) { internal::testNumericalDerivative( - 0.0, dz, dMassDensity_dz[ic], + 0.0, dz, massDensityDerivs[Deriv::dC + ic], [this, & p=pressure, & t=temperature, & zmf=composition, ic]( real64 const z ) -> real64 { + real64 const z0 = zmf[ic]; zmf[ic] += z; real64 const density = computeMassDensity( p, t, zmf ); - zmf[ic] -= z; + zmf[ic] = z0; return density; } ); } @@ -195,64 +191,26 @@ class CompositionalPropertiesTestDataTestFixture : public ::testing::TestWithPar } real64 computeMolarDensity( real64 const pressure, real64 const temperature, - arrayView1d< real64 const > const & composition ) const + arraySlice1d< real64 const > const & composition ) const { - auto const componentProperties = this->m_fluid->createKernelWrapper(); - auto const binaryInteractionCoefficients = componentProperties.m_componentBinaryCoeff; - auto const volumeShift = componentProperties.m_componentVolumeShift; - - real64 compressibilityFactor = 0.0; real64 molarDensity = 0.0; - array1d< real64 > aPureCoefficient( numComps ); - array1d< real64 > bPureCoefficient( numComps ); - real64 aMixtureCoefficient = 0.0; - real64 bMixtureCoefficient = 0.0; - - CubicEOSPhaseModel< EOS_TYPE >:: - computeMixtureCoefficients( numComps, - pressure, - temperature, - composition, - componentProperties, - aPureCoefficient, - bPureCoefficient, - aMixtureCoefficient, - bMixtureCoefficient ); - - CubicEOSPhaseModel< EOS_TYPE >:: - computeCompressibilityFactor( numComps, - composition, - binaryInteractionCoefficients, - aPureCoefficient, - bPureCoefficient, - aMixtureCoefficient, - bMixtureCoefficient, - compressibilityFactor ); - - CompositionalProperties::computeMolarDensity( numComps, - pressure, - temperature, - composition, - volumeShift, - compressibilityFactor, - molarDensity ); + stackArray1d< real64, numDof > molarDensityDerivs( numDof ); + computeMolarDensity( pressure, temperature, composition, molarDensity, molarDensityDerivs.toSlice() ); return molarDensity; } void computeMolarDensity( real64 const pressure, real64 const temperature, - arrayView1d< real64 const > const & composition, + arraySlice1d< real64 const > const & composition, real64 & molarDensity, - real64 & dMolarDensity_dp, - real64 & dMolarDensity_dt, - arraySlice1d< real64 > const dMolarDensity_dz ) const + arraySlice1d< real64 > const molarDensityDerivs ) const { auto const componentProperties = this->m_fluid->createKernelWrapper(); auto const binaryInteractionCoefficients = componentProperties.m_componentBinaryCoeff; auto const volumeShift = componentProperties.m_componentVolumeShift; real64 compressibilityFactor = 0.0; - array1d< real64 > aPureCoefficient( numComps ); - array1d< real64 > bPureCoefficient( numComps ); + stackArray1d< real64, numComps > aPureCoefficient( numComps ); + stackArray1d< real64, numComps > bPureCoefficient( numComps ); real64 aMixtureCoefficient = 0.0; real64 bMixtureCoefficient = 0.0; @@ -262,17 +220,13 @@ class CompositionalPropertiesTestDataTestFixture : public ::testing::TestWithPar temperature, composition, componentProperties, - aPureCoefficient, - bPureCoefficient, + aPureCoefficient.toSlice(), + bPureCoefficient.toSlice(), aMixtureCoefficient, bMixtureCoefficient ); - real64 daMixtureCoefficient_dp = 0.0; - real64 dbMixtureCoefficient_dp = 0.0; - real64 daMixtureCoefficient_dt = 0.0; - real64 dbMixtureCoefficient_dt = 0.0; - array1d< real64 > daMixtureCoefficient_dz( numComps ); - array1d< real64 > dbMixtureCoefficient_dz( numComps ); + stackArray1d< real64, numDof > aMixtureCoefficientDerivs( numDof ); + stackArray1d< real64, numDof > bMixtureCoefficientDerivs( numDof ); CubicEOSPhaseModel< EOS_TYPE >:: computeMixtureCoefficients( numComps, @@ -280,54 +234,33 @@ class CompositionalPropertiesTestDataTestFixture : public ::testing::TestWithPar temperature, composition, componentProperties, - aPureCoefficient, - bPureCoefficient, + aPureCoefficient.toSliceConst(), + bPureCoefficient.toSliceConst(), aMixtureCoefficient, bMixtureCoefficient, - daMixtureCoefficient_dp, - dbMixtureCoefficient_dp, - daMixtureCoefficient_dt, - dbMixtureCoefficient_dt, - daMixtureCoefficient_dz, - dbMixtureCoefficient_dz ); + aMixtureCoefficientDerivs.toSlice(), + bMixtureCoefficientDerivs.toSlice() ); CubicEOSPhaseModel< EOS_TYPE >:: computeCompressibilityFactor( numComps, composition, binaryInteractionCoefficients, - aPureCoefficient, - bPureCoefficient, + aPureCoefficient.toSliceConst(), + bPureCoefficient.toSliceConst(), aMixtureCoefficient, bMixtureCoefficient, compressibilityFactor ); - real64 dCompressibilityFactor_dp = 0.0; - real64 dCompressibilityFactor_dt = 0.0; - array1d< real64 > dCompressibilityFactor_dz( numComps ); + stackArray1d< real64, numDof > compressibilityFactorDerivs( numDof ); CubicEOSPhaseModel< EOS_TYPE >:: computeCompressibilityFactor( numComps, aMixtureCoefficient, bMixtureCoefficient, compressibilityFactor, - daMixtureCoefficient_dp, - dbMixtureCoefficient_dp, - daMixtureCoefficient_dt, - dbMixtureCoefficient_dt, - daMixtureCoefficient_dz, - dbMixtureCoefficient_dz, - dCompressibilityFactor_dp, - dCompressibilityFactor_dt, - dCompressibilityFactor_dz ); - - CompositionalProperties:: - computeMolarDensity( numComps, - pressure, - temperature, - composition, - volumeShift, - compressibilityFactor, - molarDensity ); + aMixtureCoefficientDerivs.toSliceConst(), + bMixtureCoefficientDerivs.toSliceConst(), + compressibilityFactorDerivs.toSlice() ); CompositionalProperties:: computeMolarDensity( numComps, @@ -336,66 +269,44 @@ class CompositionalPropertiesTestDataTestFixture : public ::testing::TestWithPar composition, volumeShift, compressibilityFactor, - dCompressibilityFactor_dp, - dCompressibilityFactor_dt, - dCompressibilityFactor_dz, + compressibilityFactorDerivs.toSliceConst(), molarDensity, - dMolarDensity_dp, - dMolarDensity_dt, - dMolarDensity_dz ); + molarDensityDerivs ); } real64 computeMassDensity( real64 const pressure, real64 const temperature, - arrayView1d< real64 const > const & composition ) const + arraySlice1d< real64 const > const & composition ) const { - auto const componentProperties = this->m_fluid->createKernelWrapper(); - auto const molecularWeight = componentProperties.m_componentMolarWeight; - - real64 const molarDensity = computeMolarDensity( pressure, temperature, composition ); real64 massDensity = 0.0; - CompositionalProperties:: - computeMassDensity( numComps, - composition, - molecularWeight, - molarDensity, - massDensity ); + stackArray1d< real64, numDof > massDensityDerivs( numDof ); + computeMassDensity( pressure, temperature, composition, massDensity, massDensityDerivs.toSlice() ); return massDensity; } void computeMassDensity( real64 const pressure, real64 const temperature, - arrayView1d< real64 const > const & composition, + arraySlice1d< real64 const > const & composition, real64 & massDensity, - real64 & dMassDensity_dp, - real64 & dMassDensity_dt, - arraySlice1d< real64 > const dMassDensity_dz ) const + arraySlice1d< real64 > const massDensityDerivs ) const { auto const componentProperties = this->m_fluid->createKernelWrapper(); auto const molecularWeight = componentProperties.m_componentMolarWeight; - massDensity = computeMassDensity( pressure, temperature, composition ); - real64 molarDensity = 0.0; - real64 dMolarDensity_dp = 0.0; - real64 dMolarDensity_dt = 0.0; - array1d< real64 > dMolarDensity_dz( numComps ); + stackArray1d< real64, numDof > molarDensityDerivs( numDof ); + computeMolarDensity( pressure, temperature, composition, molarDensity, - dMolarDensity_dp, - dMolarDensity_dt, - dMolarDensity_dz ); + molarDensityDerivs.toSlice() ); CompositionalProperties:: computeMassDensity( numComps, + composition, molecularWeight, molarDensity, - dMolarDensity_dp, - dMolarDensity_dt, - dMolarDensity_dz, + molarDensityDerivs.toSliceConst(), massDensity, - dMassDensity_dp, - dMassDensity_dt, - dMassDensity_dz ); + massDensityDerivs ); } protected: @@ -430,72 +341,72 @@ template<> std::vector< CompositionalPropertiesTestData< 4 > > generateTestData< PengRobinsonEOS, 4 >() { return { - { 1.000000e+05, 2.771500e+02, { 0.000000, 0.495099, 0.495118, 0.009783 }, 3.733061e+03, 1.271768e+02, 4.747588e+05 }, - { 1.000000e+05, 2.771500e+02, { 0.000652, 0.128231, 0.128281, 0.742836 }, 1.119134e+04, 4.630013e+01, 5.181608e+05 }, - { 1.000000e+05, 2.771500e+02, { 0.855328, 0.000205, 0.000000, 0.144467 }, 4.348717e+01, 2.658628e+01, 1.156162e+03 }, - { 1.000000e+05, 2.886500e+02, { 0.000507, 0.112984, 0.113029, 0.773480 }, 1.214893e+04, 4.293636e+01, 5.216311e+05 }, - { 1.000000e+05, 2.886500e+02, { 0.777870, 0.000520, 0.000000, 0.221610 }, 4.177763e+01, 2.584219e+01, 1.079625e+03 }, - { 1.000000e+05, 2.886500e+02, { 0.985235, 0.000000, 0.000000, 0.014765 }, 4.169466e+01, 2.786538e+01, 1.161838e+03 }, - { 1.000000e+05, 2.981500e+02, { 0.653033, 0.000901, 0.000000, 0.346066 }, 4.049414e+01, 2.463074e+01, 9.974005e+02 }, - { 1.000000e+05, 2.981500e+02, { 0.000506, 0.143046, 0.143326, 0.713122 }, 1.013248e+04, 4.959370e+01, 5.025071e+05 }, - { 1.000000e+05, 2.981500e+02, { 0.582848, 0.000748, 0.000000, 0.416404 }, 4.053125e+01, 2.391430e+01, 9.692764e+02 }, - { 1.000000e+05, 2.981500e+02, { 0.972848, 0.000000, 0.000000, 0.027152 }, 4.036515e+01, 2.774153e+01, 1.119791e+03 }, - { 1.000000e+05, 3.331500e+02, { 0.000000, 0.477146, 0.477164, 0.045691 }, 3.754190e+03, 1.232183e+02, 4.625850e+05 }, - { 1.000000e+05, 3.331500e+02, { 0.210877, 0.008984, 0.000001, 0.780137 }, 3.640845e+01, 2.098792e+01, 7.641376e+02 }, - { 1.000000e+05, 3.331500e+02, { 0.818043, 0.000000, 0.000000, 0.181957 }, 3.614852e+01, 2.619379e+01, 9.468669e+02 }, - { 1.000000e+05, 3.721500e+02, { 0.000000, 0.104818, 0.104822, 0.790360 }, 3.312721e+01, 4.112577e+01, 1.362382e+03 }, - { 1.000000e+05, 3.721500e+02, { 0.000117, 0.356347, 0.549688, 0.093848 }, 3.581375e+03, 1.206090e+02, 4.319462e+05 }, - { 1.013250e+05, 2.771500e+02, { 0.000000, 0.495099, 0.495118, 0.009783 }, 3.733064e+03, 1.271768e+02, 4.747592e+05 }, - { 1.013250e+05, 2.886500e+02, { 0.000516, 0.112950, 0.112994, 0.773540 }, 1.215157e+04, 4.292888e+01, 5.216533e+05 }, - { 1.013250e+05, 2.886500e+02, { 0.780815, 0.000514, 0.000000, 0.218672 }, 4.233123e+01, 2.587101e+01, 1.095152e+03 }, - { 1.013250e+05, 2.886500e+02, { 0.000599, 0.132633, 0.132752, 0.734016 }, 1.081051e+04, 4.727865e+01, 5.111063e+05 }, - { 1.013250e+05, 2.886500e+02, { 0.743752, 0.000426, 0.000000, 0.255823 }, 4.234963e+01, 2.549200e+01, 1.079576e+03 }, - { 1.013250e+05, 2.981500e+02, { 0.000448, 0.114592, 0.114680, 0.770280 }, 1.192251e+04, 4.329570e+01, 5.161936e+05 }, - { 1.013250e+05, 2.981500e+02, { 0.657746, 0.000890, 0.000000, 0.341364 }, 4.103031e+01, 2.467683e+01, 1.012498e+03 }, - { 1.013250e+05, 2.981500e+02, { 0.000516, 0.142463, 0.142736, 0.714285 }, 1.016359e+04, 4.946432e+01, 5.027349e+05 }, - { 1.013250e+05, 3.331500e+02, { 0.000000, 0.477146, 0.477164, 0.045690 }, 3.754193e+03, 1.232184e+02, 4.625856e+05 }, - { 1.013250e+05, 3.331500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.593026e+04, 1.801500e+01, 8.274336e+05 }, - { 1.013250e+05, 3.331500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.593025e+04, 1.801500e+01, 8.274336e+05 }, - { 1.013250e+05, 3.331500e+02, { 0.820407, 0.000000, 0.000000, 0.179593 }, 3.662747e+01, 2.621743e+01, 9.602781e+02 }, - { 1.013250e+05, 3.721500e+02, { 0.080408, 0.000000, 0.000000, 0.919592 }, 3.299996e+01, 1.881892e+01, 6.210236e+02 }, - { 5.000000e+06, 2.771500e+02, { 0.000000, 0.495216, 0.495235, 0.009549 }, 3.742134e+03, 1.272026e+02, 4.760091e+05 }, - { 5.000000e+06, 2.771500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.772799e+04, 1.801500e+01, 8.598197e+05 }, - { 5.000000e+06, 2.771500e+02, { 0.029212, 0.107914, 0.107918, 0.754956 }, 1.264269e+04, 4.210047e+01, 5.322630e+05 }, - { 5.000000e+06, 2.886500e+02, { 0.000000, 0.493093, 0.493111, 0.013796 }, 3.739164e+03, 1.267344e+02, 4.738808e+05 }, - { 5.000000e+06, 2.886500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.739475e+04, 1.801500e+01, 8.538165e+05 }, - { 5.000000e+06, 2.886500e+02, { 0.999549, 0.000000, 0.000000, 0.000451 }, 2.122222e+03, 2.800849e+01, 5.944023e+04 }, - { 5.000000e+06, 2.981500e+02, { 0.000000, 0.490855, 0.490873, 0.018272 }, 3.739300e+03, 1.262410e+02, 4.720529e+05 }, - { 5.000000e+06, 2.981500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.710908e+04, 1.801500e+01, 8.486701e+05 }, - { 5.000000e+06, 2.981500e+02, { 0.030096, 0.107834, 0.107839, 0.754231 }, 1.241638e+04, 4.209177e+01, 5.226274e+05 }, - { 5.000000e+06, 3.331500e+02, { 0.031858, 0.107709, 0.107720, 0.752713 }, 1.198645e+04, 4.208259e+01, 5.044209e+05 }, - { 5.000000e+06, 3.331500e+02, { 0.964491, 0.000264, 0.000000, 0.035245 }, 1.824920e+03, 2.768343e+01, 5.052004e+04 }, - { 5.000000e+06, 3.331500e+02, { 0.035989, 0.120533, 0.120574, 0.722904 }, 1.106526e+04, 4.495504e+01, 4.974394e+05 }, - { 5.000000e+06, 3.331500e+02, { 0.961874, 0.000247, 0.000000, 0.037879 }, 1.826197e+03, 2.765560e+01, 5.050457e+04 }, - { 5.000000e+06, 3.721500e+02, { 0.037408, 0.121753, 0.121923, 0.718916 }, 1.046451e+04, 4.525417e+01, 4.735627e+05 }, - { 5.000000e+06, 3.721500e+02, { 0.889694, 0.001014, 0.000003, 0.109288 }, 1.643713e+03, 2.700817e+01, 4.439368e+04 }, - { 1.000000e+07, 2.771500e+02, { 0.000004, 0.000000, 0.000000, 0.999996 }, 4.775121e+04, 1.801504e+01, 8.602398e+05 }, - { 1.000000e+07, 2.771500e+02, { 0.999835, 0.000000, 0.000000, 0.000165 }, 4.468580e+03, 2.801135e+01, 1.251710e+05 }, - { 1.000000e+07, 2.886500e+02, { 0.000000, 0.493260, 0.493279, 0.013460 }, 3.748279e+03, 1.267714e+02, 4.751745e+05 }, - { 1.000000e+07, 2.886500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.742059e+04, 1.801500e+01, 8.542819e+05 }, - { 1.000000e+07, 2.886500e+02, { 0.055934, 0.104932, 0.104936, 0.734198 }, 1.273695e+04, 4.171005e+01, 5.312588e+05 }, - { 1.000000e+07, 2.981500e+02, { 0.000000, 0.491084, 0.491102, 0.017814 }, 3.748930e+03, 1.262914e+02, 4.734578e+05 }, - { 1.000000e+07, 2.981500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.713720e+04, 1.801500e+01, 8.491766e+05 }, - { 1.000000e+07, 2.981500e+02, { 0.056951, 0.104818, 0.104822, 0.733409 }, 1.263544e+04, 4.169517e+01, 5.268366e+05 }, - { 1.000000e+07, 2.981500e+02, { 0.065451, 0.116299, 0.116311, 0.701940 }, 1.172878e+04, 4.431245e+01, 5.197309e+05 }, - { 1.000000e+07, 2.981500e+02, { 0.991760, 0.000074, 0.000000, 0.008166 }, 4.103168e+03, 2.793775e+01, 1.146333e+05 }, - { 1.000000e+07, 3.331500e+02, { 0.000000, 0.478424, 0.478442, 0.043135 }, 3.777896e+03, 1.235001e+02, 4.665706e+05 }, - { 1.000000e+07, 3.331500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.600669e+04, 1.801500e+01, 8.288105e+05 }, - { 1.000000e+07, 3.331500e+02, { 0.996818, 0.000000, 0.000000, 0.003182 }, 3.589847e+03, 2.798118e+01, 1.004482e+05 }, - { 1.000000e+07, 3.721500e+02, { 0.000000, 0.453197, 0.453215, 0.093588 }, 3.878777e+03, 1.179381e+02, 4.574555e+05 }, - { 1.000000e+08, 2.771500e+02, { 0.000000, 0.496608, 0.496627, 0.006766 }, 3.834889e+03, 1.275094e+02, 4.889844e+05 }, - { 1.000000e+08, 2.886500e+02, { 0.156951, 0.104818, 0.104822, 0.633409 }, 1.310108e+04, 4.269497e+01, 5.593502e+05 }, - { 1.000000e+08, 2.886500e+02, { 0.000031, 0.000000, 0.000000, 0.999969 }, 4.783830e+04, 1.801531e+01, 8.618217e+05 }, - { 1.000000e+08, 2.886500e+02, { 0.999447, 0.000000, 0.000000, 0.000553 }, 2.330195e+04, 2.800748e+01, 6.526287e+05 }, - { 1.000000e+08, 2.981500e+02, { 0.000000, 0.493623, 0.493642, 0.012735 }, 3.840586e+03, 1.268513e+02, 4.871835e+05 }, - { 1.000000e+08, 3.331500e+02, { 0.010000, 0.000000, 0.000000, 0.990000 }, 4.638822e+04, 1.811498e+01, 8.403216e+05 }, - { 1.000000e+08, 3.721500e+02, { 0.156951, 0.104818, 0.104822, 0.633409 }, 1.247160e+04, 4.269497e+01, 5.324747e+05 }, - { 1.000000e+08, 3.721500e+02, { 0.000671, 0.000000, 0.000000, 0.999329 }, 4.538427e+04, 1.802171e+01, 8.179019e+05 }, - { 1.000000e+08, 3.721500e+02, { 0.991955, 0.000000, 0.000000, 0.008045 }, 1.979639e+04, 2.793257e+01, 5.529641e+05 } + { 1.000000e+05, 2.771500e+02, { 0.000000, 0.495099, 0.495118, 0.009783 }, 3.733061e+03, 1.271768e+02, 4.747588e+02 }, + { 1.000000e+05, 2.771500e+02, { 0.000652, 0.128231, 0.128281, 0.742836 }, 1.119134e+04, 4.630013e+01, 5.181608e+02 }, + { 1.000000e+05, 2.771500e+02, { 0.855328, 0.000205, 0.000000, 0.144467 }, 4.348717e+01, 2.658628e+01, 1.156162e+00 }, + { 1.000000e+05, 2.886500e+02, { 0.000507, 0.112984, 0.113029, 0.773480 }, 1.214893e+04, 4.293636e+01, 5.216311e+02 }, + { 1.000000e+05, 2.886500e+02, { 0.777870, 0.000520, 0.000000, 0.221610 }, 4.177763e+01, 2.584219e+01, 1.079625e+00 }, + { 1.000000e+05, 2.886500e+02, { 0.985235, 0.000000, 0.000000, 0.014765 }, 4.169466e+01, 2.786538e+01, 1.161838e+00 }, + { 1.000000e+05, 2.981500e+02, { 0.653033, 0.000901, 0.000000, 0.346066 }, 4.049414e+01, 2.463074e+01, 9.974005e-01 }, + { 1.000000e+05, 2.981500e+02, { 0.000506, 0.143046, 0.143326, 0.713122 }, 1.013248e+04, 4.959370e+01, 5.025071e+02 }, + { 1.000000e+05, 2.981500e+02, { 0.582848, 0.000748, 0.000000, 0.416404 }, 4.053125e+01, 2.391430e+01, 9.692764e-01 }, + { 1.000000e+05, 2.981500e+02, { 0.972848, 0.000000, 0.000000, 0.027152 }, 4.036515e+01, 2.774153e+01, 1.119791e+00 }, + { 1.000000e+05, 3.331500e+02, { 0.000000, 0.477146, 0.477164, 0.045691 }, 3.754190e+03, 1.232183e+02, 4.625850e+02 }, + { 1.000000e+05, 3.331500e+02, { 0.210877, 0.008984, 0.000001, 0.780137 }, 3.640845e+01, 2.098792e+01, 7.641376e-01 }, + { 1.000000e+05, 3.331500e+02, { 0.818043, 0.000000, 0.000000, 0.181957 }, 3.614852e+01, 2.619379e+01, 9.468669e-01 }, + { 1.000000e+05, 3.721500e+02, { 0.000000, 0.104818, 0.104822, 0.790360 }, 3.312721e+01, 4.112577e+01, 1.362382e+00 }, + { 1.000000e+05, 3.721500e+02, { 0.000117, 0.356347, 0.549688, 0.093848 }, 3.581375e+03, 1.206090e+02, 4.319462e+02 }, + { 1.013250e+05, 2.771500e+02, { 0.000000, 0.495099, 0.495118, 0.009783 }, 3.733064e+03, 1.271768e+02, 4.747592e+02 }, + { 1.013250e+05, 2.886500e+02, { 0.000516, 0.112950, 0.112994, 0.773540 }, 1.215157e+04, 4.292888e+01, 5.216533e+02 }, + { 1.013250e+05, 2.886500e+02, { 0.780815, 0.000514, 0.000000, 0.218672 }, 4.233123e+01, 2.587101e+01, 1.095152e+00 }, + { 1.013250e+05, 2.886500e+02, { 0.000599, 0.132633, 0.132752, 0.734016 }, 1.081051e+04, 4.727865e+01, 5.111063e+02 }, + { 1.013250e+05, 2.886500e+02, { 0.743752, 0.000426, 0.000000, 0.255823 }, 4.234963e+01, 2.549200e+01, 1.079576e+00 }, + { 1.013250e+05, 2.981500e+02, { 0.000448, 0.114592, 0.114680, 0.770280 }, 1.192251e+04, 4.329570e+01, 5.161936e+02 }, + { 1.013250e+05, 2.981500e+02, { 0.657746, 0.000890, 0.000000, 0.341364 }, 4.103031e+01, 2.467683e+01, 1.012498e+00 }, + { 1.013250e+05, 2.981500e+02, { 0.000516, 0.142463, 0.142736, 0.714285 }, 1.016359e+04, 4.946432e+01, 5.027349e+02 }, + { 1.013250e+05, 3.331500e+02, { 0.000000, 0.477146, 0.477164, 0.045690 }, 3.754193e+03, 1.232184e+02, 4.625856e+02 }, + { 1.013250e+05, 3.331500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.593026e+04, 1.801500e+01, 8.274336e+02 }, + { 1.013250e+05, 3.331500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.593025e+04, 1.801500e+01, 8.274336e+02 }, + { 1.013250e+05, 3.331500e+02, { 0.820407, 0.000000, 0.000000, 0.179593 }, 3.662747e+01, 2.621743e+01, 9.602781e-01 }, + { 1.013250e+05, 3.721500e+02, { 0.080408, 0.000000, 0.000000, 0.919592 }, 3.299996e+01, 1.881892e+01, 6.210236e-01 }, + { 5.000000e+06, 2.771500e+02, { 0.000000, 0.495216, 0.495235, 0.009549 }, 3.742134e+03, 1.272026e+02, 4.760091e+02 }, + { 5.000000e+06, 2.771500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.772799e+04, 1.801500e+01, 8.598197e+02 }, + { 5.000000e+06, 2.771500e+02, { 0.029212, 0.107914, 0.107918, 0.754956 }, 1.264269e+04, 4.210047e+01, 5.322630e+02 }, + { 5.000000e+06, 2.886500e+02, { 0.000000, 0.493093, 0.493111, 0.013796 }, 3.739164e+03, 1.267344e+02, 4.738808e+02 }, + { 5.000000e+06, 2.886500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.739475e+04, 1.801500e+01, 8.538165e+02 }, + { 5.000000e+06, 2.886500e+02, { 0.999549, 0.000000, 0.000000, 0.000451 }, 2.122222e+03, 2.800849e+01, 5.944023e+01 }, + { 5.000000e+06, 2.981500e+02, { 0.000000, 0.490855, 0.490873, 0.018272 }, 3.739300e+03, 1.262410e+02, 4.720529e+02 }, + { 5.000000e+06, 2.981500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.710908e+04, 1.801500e+01, 8.486701e+02 }, + { 5.000000e+06, 2.981500e+02, { 0.030096, 0.107834, 0.107839, 0.754231 }, 1.241638e+04, 4.209177e+01, 5.226274e+02 }, + { 5.000000e+06, 3.331500e+02, { 0.031858, 0.107709, 0.107720, 0.752713 }, 1.198645e+04, 4.208259e+01, 5.044209e+02 }, + { 5.000000e+06, 3.331500e+02, { 0.964491, 0.000264, 0.000000, 0.035245 }, 1.824920e+03, 2.768343e+01, 5.052004e+01 }, + { 5.000000e+06, 3.331500e+02, { 0.035989, 0.120533, 0.120574, 0.722904 }, 1.106526e+04, 4.495504e+01, 4.974394e+02 }, + { 5.000000e+06, 3.331500e+02, { 0.961874, 0.000247, 0.000000, 0.037879 }, 1.826197e+03, 2.765560e+01, 5.050457e+01 }, + { 5.000000e+06, 3.721500e+02, { 0.037408, 0.121753, 0.121923, 0.718916 }, 1.046451e+04, 4.525417e+01, 4.735627e+02 }, + { 5.000000e+06, 3.721500e+02, { 0.889694, 0.001014, 0.000003, 0.109288 }, 1.643713e+03, 2.700817e+01, 4.439368e+01 }, + { 1.000000e+07, 2.771500e+02, { 0.000004, 0.000000, 0.000000, 0.999996 }, 4.775121e+04, 1.801504e+01, 8.602398e+02 }, + { 1.000000e+07, 2.771500e+02, { 0.999835, 0.000000, 0.000000, 0.000165 }, 4.468580e+03, 2.801135e+01, 1.251710e+02 }, + { 1.000000e+07, 2.886500e+02, { 0.000000, 0.493260, 0.493279, 0.013460 }, 3.748279e+03, 1.267714e+02, 4.751745e+02 }, + { 1.000000e+07, 2.886500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.742059e+04, 1.801500e+01, 8.542819e+02 }, + { 1.000000e+07, 2.886500e+02, { 0.055934, 0.104932, 0.104936, 0.734198 }, 1.273695e+04, 4.171005e+01, 5.312588e+02 }, + { 1.000000e+07, 2.981500e+02, { 0.000000, 0.491084, 0.491102, 0.017814 }, 3.748930e+03, 1.262914e+02, 4.734578e+02 }, + { 1.000000e+07, 2.981500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.713720e+04, 1.801500e+01, 8.491766e+02 }, + { 1.000000e+07, 2.981500e+02, { 0.056951, 0.104818, 0.104822, 0.733409 }, 1.263544e+04, 4.169517e+01, 5.268366e+02 }, + { 1.000000e+07, 2.981500e+02, { 0.065451, 0.116299, 0.116311, 0.701940 }, 1.172878e+04, 4.431245e+01, 5.197309e+02 }, + { 1.000000e+07, 2.981500e+02, { 0.991760, 0.000074, 0.000000, 0.008166 }, 4.103168e+03, 2.793775e+01, 1.146333e+02 }, + { 1.000000e+07, 3.331500e+02, { 0.000000, 0.478424, 0.478442, 0.043135 }, 3.777896e+03, 1.235001e+02, 4.665706e+02 }, + { 1.000000e+07, 3.331500e+02, { 0.000000, 0.000000, 0.000000, 1.000000 }, 4.600669e+04, 1.801500e+01, 8.288105e+02 }, + { 1.000000e+07, 3.331500e+02, { 0.996818, 0.000000, 0.000000, 0.003182 }, 3.589847e+03, 2.798118e+01, 1.004482e+02 }, + { 1.000000e+07, 3.721500e+02, { 0.000000, 0.453197, 0.453215, 0.093588 }, 3.878777e+03, 1.179381e+02, 4.574555e+02 }, + { 1.000000e+08, 2.771500e+02, { 0.000000, 0.496608, 0.496627, 0.006766 }, 3.834889e+03, 1.275094e+02, 4.889844e+02 }, + { 1.000000e+08, 2.886500e+02, { 0.156951, 0.104818, 0.104822, 0.633409 }, 1.310108e+04, 4.269497e+01, 5.593502e+02 }, + { 1.000000e+08, 2.886500e+02, { 0.000031, 0.000000, 0.000000, 0.999969 }, 4.783830e+04, 1.801531e+01, 8.618217e+02 }, + { 1.000000e+08, 2.886500e+02, { 0.999447, 0.000000, 0.000000, 0.000553 }, 2.330195e+04, 2.800748e+01, 6.526287e+02 }, + { 1.000000e+08, 2.981500e+02, { 0.000000, 0.493623, 0.493642, 0.012735 }, 3.840586e+03, 1.268513e+02, 4.871835e+02 }, + { 1.000000e+08, 3.331500e+02, { 0.010000, 0.000000, 0.000000, 0.990000 }, 4.638822e+04, 1.811498e+01, 8.403216e+02 }, + { 1.000000e+08, 3.721500e+02, { 0.156951, 0.104818, 0.104822, 0.633409 }, 1.247160e+04, 4.269497e+01, 5.324747e+02 }, + { 1.000000e+08, 3.721500e+02, { 0.000671, 0.000000, 0.000000, 0.999329 }, 4.538427e+04, 1.802171e+01, 8.179019e+02 }, + { 1.000000e+08, 3.721500e+02, { 0.991955, 0.000000, 0.000000, 0.008045 }, 1.979639e+04, 2.793257e+01, 5.529641e+02 } }; } diff --git a/src/coreComponents/constitutive/unitTests/testCubicEOS.cpp b/src/coreComponents/constitutive/unitTests/testCubicEOS.cpp index e453e225787..7ca010ba8e5 100644 --- a/src/coreComponents/constitutive/unitTests/testCubicEOS.cpp +++ b/src/coreComponents/constitutive/unitTests/testCubicEOS.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -53,9 +54,9 @@ TEST( CubicEOSTest, testCubicEOSTwoComponentsSRK ) CubicEOSPhaseModel< SoaveRedlichKwongEOS >:: computeLogFugacityCoefficients( numComps, - pressure, temperature, composition, + pressure, temperature, composition.toSliceConst(), componentProperties, - logFugacityCoefficients ); + logFugacityCoefficients.toSlice() ); checkRelativeError( logFugacityCoefficients[0], expectedLogFugacityCoefficients[0], relTol ); checkRelativeError( logFugacityCoefficients[1], expectedLogFugacityCoefficients[1], relTol ); @@ -72,9 +73,9 @@ TEST( CubicEOSTest, testCubicEOSTwoComponentsSRK ) CubicEOSPhaseModel< SoaveRedlichKwongEOS >:: computeLogFugacityCoefficients( numComps, - pressure, temperature, composition, + pressure, temperature, composition.toSliceConst(), componentProperties, - logFugacityCoefficients ); + logFugacityCoefficients.toSlice() ); checkRelativeError( logFugacityCoefficients[0], expectedLogFugacityCoefficients[0], relTol ); checkRelativeError( logFugacityCoefficients[1], expectedLogFugacityCoefficients[1], relTol ); @@ -91,9 +92,9 @@ TEST( CubicEOSTest, testCubicEOSTwoComponentsSRK ) CubicEOSPhaseModel< SoaveRedlichKwongEOS >:: computeLogFugacityCoefficients( numComps, - pressure, temperature, composition, + pressure, temperature, composition.toSliceConst(), componentProperties, - logFugacityCoefficients ); + logFugacityCoefficients.toSlice() ); checkRelativeError( logFugacityCoefficients[0], expectedLogFugacityCoefficients[0], relTol ); checkRelativeError( logFugacityCoefficients[1], expectedLogFugacityCoefficients[1], relTol ); @@ -110,9 +111,9 @@ TEST( CubicEOSTest, testCubicEOSTwoComponentsSRK ) CubicEOSPhaseModel< SoaveRedlichKwongEOS >:: computeLogFugacityCoefficients( numComps, - pressure, temperature, composition, + pressure, temperature, composition.toSliceConst(), componentProperties, - logFugacityCoefficients ); + logFugacityCoefficients.toSlice() ); checkRelativeError( logFugacityCoefficients[0], expectedLogFugacityCoefficients[0], relTol ); checkRelativeError( logFugacityCoefficients[1], expectedLogFugacityCoefficients[1], relTol ); @@ -149,9 +150,9 @@ TEST( CubicEOSTest, testCubicEOSFourComponentsPR ) CubicEOSPhaseModel< PengRobinsonEOS >:: computeLogFugacityCoefficients( numComps, - pressure, temperature, composition, + pressure, temperature, composition.toSliceConst(), componentProperties, - logFugacityCoefficients ); + logFugacityCoefficients.toSlice() ); checkRelativeError( logFugacityCoefficients[0], expectedLogFugacityCoefficients[0], relTol ); checkRelativeError( logFugacityCoefficients[1], expectedLogFugacityCoefficients[1], relTol ); @@ -174,9 +175,9 @@ TEST( CubicEOSTest, testCubicEOSFourComponentsPR ) CubicEOSPhaseModel< PengRobinsonEOS >:: computeLogFugacityCoefficients( numComps, - pressure, temperature, composition, + pressure, temperature, composition.toSliceConst(), componentProperties, - logFugacityCoefficients ); + logFugacityCoefficients.toSlice() ); checkRelativeError( logFugacityCoefficients[0], expectedLogFugacityCoefficients[0], relTol ); checkRelativeError( logFugacityCoefficients[1], expectedLogFugacityCoefficients[1], relTol ); @@ -199,9 +200,9 @@ TEST( CubicEOSTest, testCubicEOSFourComponentsPR ) CubicEOSPhaseModel< PengRobinsonEOS >:: computeLogFugacityCoefficients( numComps, - pressure, temperature, composition, + pressure, temperature, composition.toSliceConst(), componentProperties, - logFugacityCoefficients ); + logFugacityCoefficients.toSlice() ); checkRelativeError( logFugacityCoefficients[0], expectedLogFugacityCoefficients[0], relTol ); checkRelativeError( logFugacityCoefficients[1], expectedLogFugacityCoefficients[1], relTol ); @@ -240,9 +241,9 @@ TEST( CubicEOSTest, testCubicEOSFourComponentsSRK ) CubicEOSPhaseModel< SoaveRedlichKwongEOS >:: computeLogFugacityCoefficients( numComps, - pressure, temperature, composition, + pressure, temperature, composition.toSliceConst(), componentProperties, - logFugacityCoefficients ); + logFugacityCoefficients.toSlice() ); checkRelativeError( logFugacityCoefficients[0], expectedLogFugacityCoefficients[0], relTol ); checkRelativeError( logFugacityCoefficients[1], expectedLogFugacityCoefficients[1], relTol ); @@ -265,9 +266,9 @@ TEST( CubicEOSTest, testCubicEOSFourComponentsSRK ) CubicEOSPhaseModel< SoaveRedlichKwongEOS >:: computeLogFugacityCoefficients( numComps, - pressure, temperature, composition, + pressure, temperature, composition.toSliceConst(), componentProperties, - logFugacityCoefficients ); + logFugacityCoefficients.toSlice() ); checkRelativeError( logFugacityCoefficients[0], expectedLogFugacityCoefficients[0], relTol ); checkRelativeError( logFugacityCoefficients[1], expectedLogFugacityCoefficients[1], relTol ); @@ -290,15 +291,14 @@ TEST( CubicEOSTest, testCubicEOSFourComponentsSRK ) CubicEOSPhaseModel< SoaveRedlichKwongEOS >:: computeLogFugacityCoefficients( numComps, - pressure, temperature, composition, + pressure, temperature, composition.toSliceConst(), componentProperties, - logFugacityCoefficients ); + logFugacityCoefficients.toSlice() ); checkRelativeError( logFugacityCoefficients[0], expectedLogFugacityCoefficients[0], relTol ); checkRelativeError( logFugacityCoefficients[1], expectedLogFugacityCoefficients[1], relTol ); checkRelativeError( logFugacityCoefficients[2], expectedLogFugacityCoefficients[2], relTol ); checkRelativeError( logFugacityCoefficients[3], expectedLogFugacityCoefficients[3], relTol ); - } // ----------------------------------------------------------------- @@ -352,6 +352,8 @@ class DerivativeTestFixture : public ::testing::TestWithParam< TestData< NC > > { public: static constexpr integer numComps = NC; + static constexpr integer numDof = NC + 2; + using Deriv = geos::constitutive::multifluid::DerivativeOffset; using ParamType = std::tuple< real64 const, real64 const, Feed< NC > const >; public: DerivativeTestFixture(); @@ -384,23 +386,21 @@ class MixCoeffDerivativeTestFixture : public DerivativeTestFixture< EOS, NC > { public: using DerivativeTestFixture< EOS, NC >::numComps; + using DerivativeTestFixture< EOS, NC >::numDof; + using Deriv = typename DerivativeTestFixture< EOS, NC >::Deriv; using ParamType = typename DerivativeTestFixture< EOS, NC >::ParamType; public: void testNumericalDerivatives( ParamType const & testData ) const { auto componentProperties = this->m_fluid->createKernelWrapper(); - array1d< real64 > aPureCoefficient( numComps ); - array1d< real64 > bPureCoefficient( numComps ); + stackArray1d< real64, numComps > aPureCoefficient( numComps ); + stackArray1d< real64, numComps > bPureCoefficient( numComps ); - real64 daMixtureCoefficient_dp = 0.0; - real64 dbMixtureCoefficient_dp = 0.0; - real64 daMixtureCoefficient_dt = 0.0; - real64 dbMixtureCoefficient_dt = 0.0; - array1d< real64 > daMixtureCoefficient_dz( numComps ); - array1d< real64 > dbMixtureCoefficient_dz( numComps ); + stackArray1d< real64, numDof > aMixtureCoefficientDerivs( numDof ); + stackArray1d< real64, numDof > bMixtureCoefficientDerivs( numDof ); - array1d< real64 > composition; + stackArray1d< real64, numComps > composition; real64 const pressure = std::get< 0 >( testData ); real64 const temperature = std::get< 1 >( testData ); TestFluid< NC >::createArray( composition, std::get< 2 >( testData )); @@ -410,10 +410,10 @@ class MixCoeffDerivativeTestFixture : public DerivativeTestFixture< EOS, NC > real64 b = 0.0; CubicEOSPhaseModel< EOS >::computeMixtureCoefficients( numComps, - p, t, zmf, + p, t, zmf.toSliceConst(), componentProperties, - aPureCoefficient, - bPureCoefficient, + aPureCoefficient.toSlice(), + bPureCoefficient.toSlice(), a, b ); return {a, b}; @@ -427,29 +427,25 @@ class MixCoeffDerivativeTestFixture : public DerivativeTestFixture< EOS, NC > numComps, pressure, temperature, - composition, + composition.toSliceConst(), componentProperties, - aPureCoefficient, - bPureCoefficient, + aPureCoefficient.toSlice(), + bPureCoefficient.toSlice(), aMixtureCoefficient, bMixtureCoefficient, - daMixtureCoefficient_dp, - dbMixtureCoefficient_dp, - daMixtureCoefficient_dt, - dbMixtureCoefficient_dt, - daMixtureCoefficient_dz, - dbMixtureCoefficient_dz ); + aMixtureCoefficientDerivs.toSlice(), + bMixtureCoefficientDerivs.toSlice() ); // Compare against numerical derivatives // -- Pressure derivative real64 const dp = 1.0e-4 * pressure; geos::testing::internal::testNumericalDerivative( - pressure, dp, daMixtureCoefficient_dp, + pressure, dp, aMixtureCoefficientDerivs[Deriv::dP], [&]( real64 const p ) -> real64 { return computeCoefficients( p, temperature, composition ).first; } ); geos::testing::internal::testNumericalDerivative( - pressure, dp, dbMixtureCoefficient_dp, + pressure, dp, bMixtureCoefficientDerivs[Deriv::dP], [&]( real64 const p ) -> real64 { return computeCoefficients( p, temperature, composition ).second; } ); @@ -457,12 +453,12 @@ class MixCoeffDerivativeTestFixture : public DerivativeTestFixture< EOS, NC > // -- Temperature derivative real64 const dT = 1.0e-6 * temperature; geos::testing::internal::testNumericalDerivative( - temperature, dT, daMixtureCoefficient_dt, + temperature, dT, aMixtureCoefficientDerivs[Deriv::dT], [&]( real64 const t ) -> real64 { return computeCoefficients( pressure, t, composition ).first; } ); geos::testing::internal::testNumericalDerivative( - temperature, dT, dbMixtureCoefficient_dt, + temperature, dT, bMixtureCoefficientDerivs[Deriv::dT], [&]( real64 const t ) -> real64 { return computeCoefficients( pressure, t, composition ).second; } ); @@ -478,12 +474,12 @@ class MixCoeffDerivativeTestFixture : public DerivativeTestFixture< EOS, NC > return coefficients; }; geos::testing::internal::testNumericalDerivative( - 0.0, dz, daMixtureCoefficient_dz[ic], + 0.0, dz, aMixtureCoefficientDerivs[Deriv::dC+ic], [&]( real64 const z ) -> real64 { return computeComponentCoefficients( z ).first; } ); geos::testing::internal::testNumericalDerivative( - 0.0, dz, dbMixtureCoefficient_dz[ic], + 0.0, dz, bMixtureCoefficientDerivs[Deriv::dC+ic], [&]( real64 const z ) -> real64 { return computeComponentCoefficients( z ).second; } ); @@ -543,6 +539,8 @@ class CompressibilityDerivativeTestFixture : public DerivativeTestFixture< EOS, { public: using DerivativeTestFixture< EOS, NC >::numComps; + using DerivativeTestFixture< EOS, NC >::numDof; + using Deriv = typename DerivativeTestFixture< EOS, NC >::Deriv; using ParamType = typename DerivativeTestFixture< EOS, NC >::ParamType; public: void testNumericalDerivatives( ParamType const & testData ) const @@ -550,22 +548,16 @@ class CompressibilityDerivativeTestFixture : public DerivativeTestFixture< EOS, auto const componentProperties = this->m_fluid->createKernelWrapper(); auto const binaryInteractionCoefficients = componentProperties.m_componentBinaryCoeff; - array1d< real64 > aPureCoefficient( numComps ); - array1d< real64 > bPureCoefficient( numComps ); + stackArray1d< real64, numComps > aPureCoefficient( numComps ); + stackArray1d< real64, numComps > bPureCoefficient( numComps ); real64 aMixtureCoefficient = 0.0; real64 bMixtureCoefficient = 0.0; - real64 daMixtureCoefficient_dp = 0.0; - real64 dbMixtureCoefficient_dp = 0.0; - real64 daMixtureCoefficient_dt = 0.0; - real64 dbMixtureCoefficient_dt = 0.0; - array1d< real64 > daMixtureCoefficient_dz( numComps ); - array1d< real64 > dbMixtureCoefficient_dz( numComps ); - - real64 dCompressibilityFactor_dp = 0.0; - real64 dCompressibilityFactor_dt = 0.0; - array1d< real64 > dCompressibilityFactor_dz( numComps ); - - array1d< real64 > composition; + stackArray1d< real64, numDof > aMixtureCoefficientDerivs( numDof ); + stackArray1d< real64, numDof > bMixtureCoefficientDerivs( numDof ); + + stackArray1d< real64, numDof > compressibilityFactorDerivs( numDof ); + + stackArray1d< real64, numComps > composition; real64 const pressure = std::get< 0 >( testData ); real64 const temperature = std::get< 1 >( testData ); TestFluid< NC >::createArray( composition, std::get< 2 >( testData )); @@ -574,18 +566,18 @@ class CompressibilityDerivativeTestFixture : public DerivativeTestFixture< EOS, real64 z = 0.0; CubicEOSPhaseModel< EOS >::computeMixtureCoefficients( numComps, - p, t, zmf, + p, t, zmf.toSliceConst(), componentProperties, - aPureCoefficient, - bPureCoefficient, + aPureCoefficient.toSlice(), + bPureCoefficient.toSlice(), aMixtureCoefficient, bMixtureCoefficient ); CubicEOSPhaseModel< EOS >::computeCompressibilityFactor( numComps, - zmf, + zmf.toSliceConst(), binaryInteractionCoefficients, - aPureCoefficient, - bPureCoefficient, + aPureCoefficient.toSliceConst(), + bPureCoefficient.toSliceConst(), aMixtureCoefficient, bMixtureCoefficient, z ); @@ -600,38 +592,28 @@ class CompressibilityDerivativeTestFixture : public DerivativeTestFixture< EOS, numComps, pressure, temperature, - composition, + composition.toSliceConst(), componentProperties, - aPureCoefficient, - bPureCoefficient, + aPureCoefficient.toSliceConst(), + bPureCoefficient.toSliceConst(), aMixtureCoefficient, bMixtureCoefficient, - daMixtureCoefficient_dp, - dbMixtureCoefficient_dp, - daMixtureCoefficient_dt, - dbMixtureCoefficient_dt, - daMixtureCoefficient_dz, - dbMixtureCoefficient_dz ); + aMixtureCoefficientDerivs.toSlice(), + bMixtureCoefficientDerivs.toSlice() ); CubicEOSPhaseModel< EOS >::computeCompressibilityFactor( numComps, aMixtureCoefficient, bMixtureCoefficient, compressibilityFactor, - daMixtureCoefficient_dp, - dbMixtureCoefficient_dp, - daMixtureCoefficient_dt, - dbMixtureCoefficient_dt, - daMixtureCoefficient_dz, - dbMixtureCoefficient_dz, - dCompressibilityFactor_dp, - dCompressibilityFactor_dt, - dCompressibilityFactor_dz ); + aMixtureCoefficientDerivs.toSliceConst(), + bMixtureCoefficientDerivs.toSliceConst(), + compressibilityFactorDerivs.toSlice() ); // Compare against numerical derivatives // -- Pressure derivative real64 const dp = 1.0e-4 * pressure; geos::testing::internal::testNumericalDerivative( - pressure, dp, dCompressibilityFactor_dp, + pressure, dp, compressibilityFactorDerivs[Deriv::dP], [&]( real64 const p ) -> real64 { return computeCompressibilityFactor( p, temperature, composition ); } ); @@ -639,7 +621,7 @@ class CompressibilityDerivativeTestFixture : public DerivativeTestFixture< EOS, // -- Temperature derivative real64 const dT = 1.0e-6 * temperature; geos::testing::internal::testNumericalDerivative( - temperature, dT, dCompressibilityFactor_dt, + temperature, dT, compressibilityFactorDerivs[Deriv::dT], [&]( real64 const t ) -> real64 { return computeCompressibilityFactor( pressure, t, composition ); } ); @@ -649,7 +631,7 @@ class CompressibilityDerivativeTestFixture : public DerivativeTestFixture< EOS, for( integer ic = 0; ic < numComps; ++ic ) { geos::testing::internal::testNumericalDerivative( - 0.0, dz, dCompressibilityFactor_dz[ic], + 0.0, dz, compressibilityFactorDerivs[Deriv::dC+ic], [&]( real64 const z ) -> real64 { composition[ic] += z; real64 const compressibility = computeCompressibilityFactor( pressure, temperature, composition ); @@ -705,3 +687,140 @@ INSTANTIATE_TEST_SUITE_P( CompressibilityDerivativeSRK4TestFixture, ::testing::ValuesIn( generateTestData< 4 >()) ); + +template< typename EOS, int NC > +class FugacityDerivativeTestFixture : public DerivativeTestFixture< EOS, NC > +{ +public: + using DerivativeTestFixture< EOS, NC >::numComps; + using DerivativeTestFixture< EOS, NC >::numDof; + using Deriv = typename DerivativeTestFixture< EOS, NC >::Deriv; + using ParamType = typename DerivativeTestFixture< EOS, NC >::ParamType; +public: + void testNumericalDerivatives( ParamType const & testData ) const + { + auto const componentProperties = this->m_fluid->createKernelWrapper(); + + stackArray1d< real64, numComps > logFugacityCoefficients( numComps ); + stackArray2d< real64, numComps *numDof > logFugacityCoefficientDerivs( numComps, numDof ); + + stackArray1d< real64, numComps > composition; + real64 const pressure = std::get< 0 >( testData ); + real64 const temperature = std::get< 1 >( testData ); + TestFluid< NC >::createArray( composition, std::get< 2 >( testData )); + + auto const calculateLogFugacityCoefficients = [&]( integer const ic, real64 const p, real64 const t, auto const & zmf ) -> real64 { + stackArray1d< real64, numComps > displacedLogFugacityCoefficients( numComps ); + CubicEOSPhaseModel< EOS >::computeLogFugacityCoefficients( numComps, + p, + t, + zmf.toSliceConst(), + componentProperties, + displacedLogFugacityCoefficients.toSlice() ); + return displacedLogFugacityCoefficients[ic]; + }; + + // Calculate values + CubicEOSPhaseModel< EOS >::computeLogFugacityCoefficients( numComps, + pressure, + temperature, + composition.toSliceConst(), + componentProperties, + logFugacityCoefficients.toSlice() ); + + // Calculate derivatives + CubicEOSPhaseModel< EOS >::computeLogFugacityCoefficients( numComps, + pressure, + temperature, + composition.toSliceConst(), + componentProperties, + logFugacityCoefficients.toSliceConst(), + logFugacityCoefficientDerivs.toSlice() ); + + // Compare against numerical derivatives + // -- Pressure derivative + real64 const dp = 1.0e-4 * pressure; + for( integer ic = 0; ic < numComps; ++ic ) + { + geos::testing::internal::testNumericalDerivative( + pressure, dp, logFugacityCoefficientDerivs( ic, Deriv::dP ), + [&]( real64 const p ) -> real64 { + return calculateLogFugacityCoefficients( ic, p, temperature, composition ); + } ); + } + + // -- Temperature derivative + real64 const dT = 1.0e-6 * temperature; + for( integer ic = 0; ic < numComps; ++ic ) + { + geos::testing::internal::testNumericalDerivative( + temperature, dT, logFugacityCoefficientDerivs( ic, Deriv::dT ), + [&]( real64 const t ) -> real64 { + return calculateLogFugacityCoefficients( ic, pressure, t, composition ); + } ); + } + + // -- Composition derivatives + real64 const dz = 1.0e-7; + for( integer ic = 0; ic < numComps; ++ic ) + { + for( integer jc = 0; jc < numComps; ++jc ) + { + geos::testing::internal::testNumericalDerivative( + 0.0, dz, logFugacityCoefficientDerivs( ic, Deriv::dC + jc ), + [&]( real64 const z ) -> real64 { + composition[jc] += z; + real64 const logFugacityCoefficient = calculateLogFugacityCoefficients( ic, pressure, temperature, composition ); + composition[jc] -= z; + return logFugacityCoefficient; + }, 1.0e-6 ); + } + } + } +}; + +using FugacityDerivativePR2TestFixture = FugacityDerivativeTestFixture< PengRobinsonEOS, 2 >; +using FugacityDerivativePR4TestFixture = FugacityDerivativeTestFixture< PengRobinsonEOS, 4 >; +using FugacityDerivativeSRK2TestFixture = FugacityDerivativeTestFixture< SoaveRedlichKwongEOS, 2 >; +using FugacityDerivativeSRK4TestFixture = FugacityDerivativeTestFixture< SoaveRedlichKwongEOS, 4 >; + +TEST_P( FugacityDerivativePR2TestFixture, testNumericalDerivatives ) +{ + testNumericalDerivatives( GetParam() ); +} +TEST_P( FugacityDerivativePR4TestFixture, testNumericalDerivatives ) +{ + testNumericalDerivatives( GetParam() ); +} +TEST_P( FugacityDerivativeSRK2TestFixture, testNumericalDerivatives ) +{ + testNumericalDerivatives( GetParam() ); +} +TEST_P( FugacityDerivativeSRK4TestFixture, testNumericalDerivatives ) +{ + testNumericalDerivatives( GetParam() ); +} + +// 2-component fluid test +INSTANTIATE_TEST_SUITE_P( + CubicEOSTest, + FugacityDerivativePR2TestFixture, + ::testing::ValuesIn( generateTestData< 2 >()) + ); +INSTANTIATE_TEST_SUITE_P( + CubicEOSTest, + FugacityDerivativeSRK2TestFixture, + ::testing::ValuesIn( generateTestData< 2 >()) + ); + +// 4-component fluid test +INSTANTIATE_TEST_SUITE_P( + CubicEOSTest, + FugacityDerivativePR4TestFixture, + ::testing::ValuesIn( generateTestData< 4 >()) + ); +INSTANTIATE_TEST_SUITE_P( + CubicEOSTest, + FugacityDerivativeSRK4TestFixture, + ::testing::ValuesIn( generateTestData< 4 >()) + ); diff --git a/src/coreComponents/constitutive/unitTests/testDamageUtilities.cpp b/src/coreComponents/constitutive/unitTests/testDamageUtilities.cpp index 4e955ca3d7d..c6c676469be 100644 --- a/src/coreComponents/constitutive/unitTests/testDamageUtilities.cpp +++ b/src/coreComponents/constitutive/unitTests/testDamageUtilities.cpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #include #include #include diff --git a/src/coreComponents/constitutive/unitTests/testDruckerPrager.cpp b/src/coreComponents/constitutive/unitTests/testDruckerPrager.cpp index bf2e24ef63d..69ced2da66c 100644 --- a/src/coreComponents/constitutive/unitTests/testDruckerPrager.cpp +++ b/src/coreComponents/constitutive/unitTests/testDruckerPrager.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -82,7 +83,7 @@ void testDruckerPragerDriver() xmlWrapper::xmlNode xmlConstitutiveNode = xmlDocument.getChild( "Constitutive" ); constitutiveManager.processInputFileRecursive( xmlDocument, xmlConstitutiveNode ); - constitutiveManager.postProcessInputRecursive(); + constitutiveManager.postInputInitializationRecursive(); localIndex constexpr numElem = 2; localIndex constexpr numQuad = 4; @@ -198,7 +199,7 @@ void testDruckerPragerExtendedDriver() xmlWrapper::xmlNode xmlConstitutiveNode = xmlDocument.getChild( "Constitutive" ); constitutiveManager.processInputFileRecursive( xmlDocument, xmlConstitutiveNode ); - constitutiveManager.postProcessInputRecursive(); + constitutiveManager.postInputInitializationRecursive(); localIndex constexpr numElem = 2; localIndex constexpr numQuad = 4; diff --git a/src/coreComponents/constitutive/unitTests/testElasticIsotropic.cpp b/src/coreComponents/constitutive/unitTests/testElasticIsotropic.cpp index 5592872d7e1..64ecf8d41f2 100644 --- a/src/coreComponents/constitutive/unitTests/testElasticIsotropic.cpp +++ b/src/coreComponents/constitutive/unitTests/testElasticIsotropic.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -81,7 +82,7 @@ TEST( ElasticIsotropicTests, testStateUpdatePoint ) xmlWrapper::xmlNode xmlConstitutiveNode = xmlDocument.getChild( "Constitutive" ); constitutiveManager.processInputFileRecursive( xmlDocument, xmlConstitutiveNode ); - constitutiveManager.postProcessInputRecursive(); + constitutiveManager.postInputInitializationRecursive(); dataRepository::Group disc( "discretization", &rootGroup ); disc.resize( 2 ); diff --git a/src/coreComponents/constitutive/unitTests/testImmiscibleWaterFlashModel.cpp b/src/coreComponents/constitutive/unitTests/testImmiscibleWaterFlashModel.cpp new file mode 100644 index 00000000000..9f0c5fefe50 --- /dev/null +++ b/src/coreComponents/constitutive/unitTests/testImmiscibleWaterFlashModel.cpp @@ -0,0 +1,376 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// Source includes +#include "codingUtilities/UnitTestUtilities.hpp" +#include "constitutive/fluid/multifluid/MultiFluidUtils.hpp" +#include "constitutive/fluid/multifluid/compositional/models/EquationOfState.hpp" +#include "constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterFlashModel.hpp" +#include "TestFluid.hpp" +#include "TestFluidUtilities.hpp" + +using namespace geos::constitutive; +using namespace geos::constitutive::compositional; + +namespace geos +{ +namespace testing +{ + +constexpr integer numTestComps = 3; + +template< integer NC > +using FlashData = std::tuple< + real64 const, // pressure + real64 const, // temperature + Feed< NC > const, // phase composition + real64 const, // expected liquid fraction + real64 const, // expected vapour fraction + real64 const, // expected aqueous fraction + Feed< numTestComps > const, // expected liquid mole fractions + Feed< numTestComps > const, // expected vapour mole fractions + Feed< numTestComps > const // expected aqueous mole fractions + >; + +template< integer NC > +struct FluidData {}; + +template<> +struct FluidData< 3 > +{ + static constexpr integer testComponents[numTestComps] = {0, 1, 2}; + static std::unique_ptr< TestFluid< 3 > > createFluid() + { + auto fluid = TestFluid< 3 >::create( {Fluid::C1, Fluid::C10, Fluid::H2O} ); + const std::array< real64 const, 3 > bics = { 0.25, 0.0, 0.0 }; + fluid->setBinaryCoefficients( bics ); + return fluid; + } +}; + +template<> +struct FluidData< 9 > +{ + static constexpr integer testComponents[numTestComps] = {0, 2, 8}; + static std::unique_ptr< TestFluid< 9 > > createFluid() + { + auto fluid = TestFluid< 9 >::create( {Fluid::H2O, Fluid::CO2, Fluid::N2, Fluid::C5, Fluid::C2, Fluid::C3, Fluid::C4, Fluid::C5, Fluid::C10} ); + const std::array< real64 const, 36 > bics = { + 0.01, 0, 0.003732, 0, 0.01, 0, 0, 0.01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0.01, 0, 0.028, 0.01, 0.01, 0, 0, 0.01, 0, 0.04532, 0.01, 0.01, 0, 0, 0 + }; + fluid->setBinaryCoefficients( bics ); + return fluid; + } +}; + +template< integer NC > +class ImmiscibleWaterFlashModelTestFixture : public ::testing::TestWithParam< FlashData< NC > > +{ + static constexpr real64 relTol = 1.0e-5; + static constexpr real64 absTol = 1.0e-7; + static constexpr integer numPhases = 3; + static constexpr integer numComps = NC; + static constexpr integer numDofs = NC + 2; + using Deriv = geos::constitutive::multifluid::DerivativeOffset; + using PhasePropSlice = ImmiscibleWaterFlashModelUpdate::PhaseProp::SliceType; + using PhaseCompSlice = ImmiscibleWaterFlashModelUpdate::PhaseComp::SliceType; + +public: + ImmiscibleWaterFlashModelTestFixture() + : m_fluid( FluidData< NC >::createFluid() ) + { + ComponentProperties const & componentProperties = this->m_fluid->getComponentProperties(); + + m_parameters = ImmiscibleWaterFlashModel::createParameters( std::move( m_parameters ) ); + + auto * equationOfState = const_cast< EquationOfState * >(m_parameters->get< EquationOfState >()); + string const eosName = EnumStrings< EquationOfStateType >::toString( EquationOfStateType::PengRobinson ); + equationOfState->m_equationsOfStateNames.emplace_back( eosName ); + equationOfState->m_equationsOfStateNames.emplace_back( eosName ); + equationOfState->m_equationsOfStateNames.emplace_back( eosName ); + + m_flash = std::make_unique< ImmiscibleWaterFlashModel >( "FlashModel", componentProperties, *m_parameters ); + } + + ~ImmiscibleWaterFlashModelTestFixture() = default; + + void testFlash( FlashData< NC > const & data ) + { + real64 const pressure = std::get< 0 >( data ); + real64 const temperature = std::get< 1 >( data ); + stackArray1d< real64, numComps > composition; + TestFluid< NC >::createArray( composition, std::get< 2 >( data )); + + real64 const expectedPhaseFraction[numPhases] = {std::get< 3 >( data ), std::get< 4 >( data ), std::get< 5 >( data )}; + Feed< numTestComps > const expectedPhaseComponentFraction[numPhases] = {std::get< 6 >( data ), std::get< 7 >( data ), std::get< 8 >( data ) }; + + stackArray2d< real64, (numPhases-1)*numComps > kValues( numPhases-1, numComps ); + LvArray::forValuesInSlice( kValues.toSlice(), []( real64 & v ){ v = 0.0; } ); + + StackArray< real64, 3, numPhases, multifluid::LAYOUT_PHASE > phaseFractionData( 1, 1, numPhases ); + StackArray< real64, 4, numPhases *numDofs, multifluid::LAYOUT_PHASE_DC > dPhaseFractionData( 1, 1, numPhases, numDofs ); + StackArray< real64, 4, numPhases *numComps, multifluid::LAYOUT_PHASE_COMP > phaseComponentFractionData( 1, 1, numPhases, numComps ); + StackArray< real64, 5, numPhases *numComps *numDofs, multifluid::LAYOUT_PHASE_COMP_DC > dPhaseComponentFractionData( 1, 1, numPhases, numComps, numDofs ); + + auto phaseFraction = phaseFractionData[0][0]; + auto dPhaseFraction = dPhaseFractionData[0][0]; + auto phaseComponentFraction = phaseComponentFractionData[0][0]; + auto dPhaseComponentFraction = dPhaseComponentFractionData[0][0]; + + auto componentProperties = m_fluid->createKernelWrapper(); + auto flashKernelWrapper = m_flash->createKernelWrapper(); + + flashKernelWrapper.compute( componentProperties, + pressure, + temperature, + composition.toSliceConst(), + kValues.toSlice(), + PhasePropSlice( phaseFraction, dPhaseFraction ), + PhaseCompSlice( phaseComponentFraction, dPhaseComponentFraction ) ); + + for( integer ip = 0; ip < numPhases; ip++ ) + { + checkRelativeError( phaseFraction[ip], expectedPhaseFraction[ip], relTol, absTol ); + for( integer i = 0; i < numTestComps; ++i ) + { + integer const ic = FluidData< numComps >::testComponents[i]; + checkRelativeError( phaseComponentFraction[ip][ic], expectedPhaseComponentFraction[ip][i], relTol, absTol ); + } + } + } + + void testFlashDerivatives( FlashData< NC > const & data ) + { + // Number of output values from each flash calculation + constexpr integer numValues = numPhases * (1 + numComps); + + real64 const pressure = std::get< 0 >( data ); + real64 const temperature = std::get< 1 >( data ); + stackArray1d< real64, numComps > composition; + TestFluid< NC >::createArray( composition, std::get< 2 >( data )); + + stackArray2d< real64, (numPhases-1)*numComps > kValues( numPhases-1, numComps ); + LvArray::forValuesInSlice( kValues.toSlice(), []( real64 & v ){ v = 0.0; } ); + + StackArray< real64, 3, numPhases, multifluid::LAYOUT_PHASE > phaseFractionData( 1, 1, numPhases ); + StackArray< real64, 4, numPhases *numDofs, multifluid::LAYOUT_PHASE_DC > dPhaseFractionData( 1, 1, numPhases, numDofs ); + StackArray< real64, 4, numPhases *numComps, multifluid::LAYOUT_PHASE_COMP > phaseComponentFractionData( 1, 1, numPhases, numComps ); + StackArray< real64, 5, numPhases *numComps *numDofs, multifluid::LAYOUT_PHASE_COMP_DC > dPhaseComponentFractionData( 1, 1, numPhases, numComps, numDofs ); + + auto phaseFraction = phaseFractionData[0][0]; + auto dPhaseFraction = dPhaseFractionData[0][0]; + auto phaseComponentFraction = phaseComponentFractionData[0][0]; + auto dPhaseComponentFraction = dPhaseComponentFractionData[0][0]; + + stackArray1d< real64, numValues > derivatives( numValues ); + + auto componentProperties = m_fluid->createKernelWrapper(); + auto flashKernelWrapper = m_flash->createKernelWrapper(); + + flashKernelWrapper.compute( componentProperties, + pressure, + temperature, + composition.toSliceConst(), + kValues.toSlice(), + PhasePropSlice( phaseFraction, dPhaseFraction ), + PhaseCompSlice( phaseComponentFraction, dPhaseComponentFraction ) ); + + // Combine derivatives into a single output + auto const concatDerivatives = []( integer const kc, auto & derivs, auto const & phaseFractionDerivs, auto const & phaseComponentFractionDerivs ){ + integer j = 0; + for( integer ip = 0; ip < numPhases; ++ip ) + { + derivs[j++] = phaseFractionDerivs( ip, kc ); + for( integer ic = 0; ic < numComps; ++ic ) + { + derivs[j++] = phaseComponentFractionDerivs( ip, ic, kc ); + } + } + }; + + auto const evaluateFlash = [&]( real64 const p, real64 const t, auto const & zmf, auto & values ){ + StackArray< real64, 3, numPhases, multifluid::LAYOUT_PHASE > displacedPhaseFractionData( 1, 1, numPhases ); + StackArray< real64, 4, numPhases *numDofs, multifluid::LAYOUT_PHASE_DC > displacedPhaseFractionDerivsData( 1, 1, numPhases, numDofs ); + StackArray< real64, 4, numPhases *numComps, multifluid::LAYOUT_PHASE_COMP > displacedPhaseComponentFractionData( 1, 1, numPhases, numComps ); + StackArray< real64, 5, numPhases *numComps *numDofs, multifluid::LAYOUT_PHASE_COMP_DC > displacedPhaseComponentFractionDerivsData( 1, 1, numPhases, numComps, numDofs ); + + auto displacedPhaseFraction = displacedPhaseFractionData[0][0]; + auto displacedPhaseFractionDerivs = displacedPhaseFractionDerivsData[0][0]; + auto displacedPhaseComponentFraction = displacedPhaseComponentFractionData[0][0]; + auto displacedPhaseComponentFractionDerivs = displacedPhaseComponentFractionDerivsData[0][0]; + + flashKernelWrapper.compute( componentProperties, + p, + t, + zmf, + kValues.toSlice(), + PhasePropSlice( displacedPhaseFraction, displacedPhaseFractionDerivs ), + PhaseCompSlice( displacedPhaseComponentFraction, displacedPhaseComponentFractionDerivs ) ); + integer j = 0; + for( integer ip = 0; ip < numPhases; ++ip ) + { + values[j++] = displacedPhaseFraction[ip]; + for( integer ic = 0; ic < numComps; ++ic ) + { + values[j++] = displacedPhaseComponentFraction( ip, ic ); + } + } + }; + + // Test against numerically calculated values + // --- Pressure derivatives --- + concatDerivatives( Deriv::dP, derivatives, dPhaseFraction, dPhaseComponentFraction ); + real64 const dp = 1.0e-4 * pressure; + geos::testing::internal::testNumericalDerivative< numValues >( + pressure, dp, derivatives, + [&]( real64 const p, auto & values ) { + evaluateFlash( p, temperature, composition.toSliceConst(), values ); + } ); + + // -- Temperature derivative + concatDerivatives( Deriv::dT, derivatives, dPhaseFraction, dPhaseComponentFraction ); + real64 const dT = 1.0e-6 * temperature; + geos::testing::internal::testNumericalDerivative< numValues >( + temperature, dT, derivatives, + [&]( real64 const t, auto & values ) { + evaluateFlash( pressure, t, composition.toSliceConst(), values ); + } ); + + // -- Composition derivatives derivative + real64 const dz = 1.0e-7; + for( integer const ic : FluidData< numComps >::testComponents ) + { + real64 sumZ = 0.0; + for( integer jc = 0; jc < numComps; ++jc ) + { + sumZ += composition[jc]; + } + sumZ -= composition[ic]; + if( sumZ < absTol ) + { + continue; + } + concatDerivatives( Deriv::dC+ic, derivatives, dPhaseFraction, dPhaseComponentFraction ); + geos::testing::internal::testNumericalDerivative< numValues >( + 0.0, dz, derivatives, + [&]( real64 const z, auto & values ) { + stackArray1d< real64, numComps > zmf( numComps ); + for( integer jc = 0; jc < numComps; ++jc ) + { + zmf[jc] = composition[jc]; + } + zmf[ic] += z; + evaluateFlash( pressure, temperature, zmf.toSliceConst(), values ); + } ); + } + } + +protected: + std::unique_ptr< TestFluid< NC > > m_fluid{}; + std::unique_ptr< ImmiscibleWaterFlashModel > m_flash{}; + std::unique_ptr< ModelParameters > m_parameters{}; +}; + +using ImmiscibleWaterFlashModel3 = ImmiscibleWaterFlashModelTestFixture< 3 >; +using ImmiscibleWaterFlashModel9 = ImmiscibleWaterFlashModelTestFixture< 9 >; + +TEST_P( ImmiscibleWaterFlashModel3, testFlash ) +{ + testFlash( GetParam() ); +} +TEST_P( ImmiscibleWaterFlashModel3, testFlashDerivatives ) +{ + testFlashDerivatives( GetParam() ); +} + +TEST_P( ImmiscibleWaterFlashModel9, testFlash ) +{ + testFlash( GetParam() ); +} +TEST_P( ImmiscibleWaterFlashModel9, testFlashDerivatives ) +{ + testFlashDerivatives( GetParam() ); +} + +//------------------------------------------------------------------------------- +// Data +//------------------------------------------------------------------------------- +/* UNCRUSTIFY-OFF */ + +INSTANTIATE_TEST_SUITE_P( + ImmiscibleWaterFlashModel, ImmiscibleWaterFlashModel3, + ::testing::Values( + FlashData<3>{1.0e+05, 293.15, {0.000000, 0.000000, 1.000000}, 0.000000, 0.000000, 1.000000, {0.500000, 0.500000, 0.000000}, {0.500000, 0.500000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+06, 293.15, {0.000000, 0.000000, 1.000000}, 0.000000, 0.000000, 1.000000, {0.500000, 0.500000, 0.000000}, {0.500000, 0.500000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+07, 293.15, {0.000000, 0.000000, 1.000000}, 0.000000, 0.000000, 1.000000, {0.500000, 0.500000, 0.000000}, {0.500000, 0.500000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+05, 313.15, {0.000000, 0.000000, 1.000000}, 0.000000, 0.000000, 1.000000, {0.500000, 0.500000, 0.000000}, {0.500000, 0.500000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+06, 313.15, {0.000000, 0.000000, 1.000000}, 0.000000, 0.000000, 1.000000, {0.500000, 0.500000, 0.000000}, {0.500000, 0.500000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+07, 313.15, {0.000000, 0.000000, 1.000000}, 0.000000, 0.000000, 1.000000, {0.500000, 0.500000, 0.000000}, {0.500000, 0.500000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+05, 353.15, {0.000000, 0.000000, 1.000000}, 0.000000, 0.000000, 1.000000, {0.500000, 0.500000, 0.000000}, {0.500000, 0.500000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+06, 353.15, {0.000000, 0.000000, 1.000000}, 0.000000, 0.000000, 1.000000, {0.500000, 0.500000, 0.000000}, {0.500000, 0.500000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+07, 353.15, {0.000000, 0.000000, 1.000000}, 0.000000, 0.000000, 1.000000, {0.500000, 0.500000, 0.000000}, {0.500000, 0.500000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+05, 293.15, {0.300000, 0.300000, 0.400000}, 0.300217, 0.299783, 0.400000, {0.000723, 0.999277, 0.000000}, {1.000000, 0.000000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+06, 293.15, {0.300000, 0.300000, 0.400000}, 0.302162, 0.297838, 0.400000, {0.007157, 0.992843, 0.000000}, {1.000000, 0.000000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+07, 293.15, {0.300000, 0.300000, 0.400000}, 0.320811, 0.279189, 0.400000, {0.064871, 0.935129, 0.000000}, {1.000000, 0.000000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+05, 313.15, {0.300000, 0.300000, 0.400000}, 0.300236, 0.299764, 0.400000, {0.000787, 0.999213, 0.000000}, {1.000000, 0.000000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+06, 313.15, {0.300000, 0.300000, 0.400000}, 0.302354, 0.297646, 0.400000, {0.007785, 0.992215, 0.000000}, {1.000000, 0.000000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+07, 313.15, {0.300000, 0.300000, 0.400000}, 0.322797, 0.277203, 0.400000, {0.070623, 0.929377, 0.000000}, {1.000000, 0.000000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+05, 353.15, {0.300000, 0.300000, 0.400000}, 0.300271, 0.299729, 0.400000, {0.000919, 0.999081, 0.000000}, {0.999982, 0.000018, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+06, 353.15, {0.300000, 0.300000, 0.400000}, 0.302753, 0.297247, 0.400000, {0.009094, 0.990906, 0.000000}, {0.999998, 0.000002, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+07, 353.15, {0.300000, 0.300000, 0.400000}, 0.326941, 0.273059, 0.400000, {0.082404, 0.917596, 0.000000}, {0.999999, 0.000001, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+05, 293.15, {0.200000, 0.800000, 0.000000}, 0.800579, 0.199421, 0.000000, {0.000723, 0.999277, 0.000000}, {1.000000, 0.000000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+06, 293.15, {0.200000, 0.800000, 0.000000}, 0.805767, 0.194233, 0.000000, {0.007157, 0.992843, 0.000000}, {1.000000, 0.000000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+07, 293.15, {0.200000, 0.800000, 0.000000}, 0.855497, 0.144503, 0.000000, {0.064871, 0.935129, 0.000000}, {1.000000, 0.000000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+05, 313.15, {0.200000, 0.800000, 0.000000}, 0.800630, 0.199370, 0.000000, {0.000787, 0.999213, 0.000000}, {1.000000, 0.000000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+06, 313.15, {0.200000, 0.800000, 0.000000}, 0.806277, 0.193723, 0.000000, {0.007785, 0.992215, 0.000000}, {1.000000, 0.000000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+07, 313.15, {0.200000, 0.800000, 0.000000}, 0.860791, 0.139209, 0.000000, {0.070623, 0.929377, 0.000000}, {1.000000, 0.000000, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+05, 353.15, {0.200000, 0.800000, 0.000000}, 0.800732, 0.199268, 0.000000, {0.000919, 0.999081, 0.000000}, {0.999982, 0.000018, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+06, 353.15, {0.200000, 0.800000, 0.000000}, 0.807341, 0.192659, 0.000000, {0.009094, 0.990906, 0.000000}, {0.999998, 0.000002, 0.000000}, {0.000000, 0.000000, 1.000000}}, + FlashData<3>{1.0e+07, 353.15, {0.200000, 0.800000, 0.000000}, 0.871843, 0.128157, 0.000000, {0.082404, 0.917596, 0.000000}, {0.999999, 0.000001, 0.000000}, {0.000000, 0.000000, 1.000000}} + ) +); + +INSTANTIATE_TEST_SUITE_P( + ImmiscibleWaterFlashModel, ImmiscibleWaterFlashModel9, + ::testing::Values( + FlashData<9>{1.0e+06, 293.15, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 0.198828, 0.792172, 0.009000, {0.000000, 0.011551, 0.850986}, {0.000000, 0.672081, 0.000000}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+07, 293.15, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 0.307007, 0.683993, 0.009000, {0.000000, 0.111647, 0.551128}, {0.000000, 0.731621, 0.000000}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+08, 293.15, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 0.991000, 0.000000, 0.009000, {0.000000, 0.539556, 0.170737}, {0.000000, 0.539556, 0.170737}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+06, 313.15, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 0.190493, 0.800507, 0.009000, {0.000000, 0.010985, 0.888223}, {0.000000, 0.665337, 0.000000}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+07, 313.15, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 0.288620, 0.702380, 0.009000, {0.000000, 0.106713, 0.586237}, {0.000000, 0.717418, 0.000001}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+08, 313.15, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 0.991000, 0.000000, 0.009000, {0.000000, 0.539556, 0.170737}, {0.000000, 0.539556, 0.170737}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+06, 353.15, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 0.181787, 0.809213, 0.009000, {0.000000, 0.010453, 0.930750}, {0.000000, 0.658417, 0.000003}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+07, 353.15, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 0.261660, 0.729340, 0.009000, {0.000000, 0.101277, 0.646622}, {0.000000, 0.696794, 0.000007}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+08, 353.15, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 0.947424, 0.043576, 0.009000, {0.000000, 0.529993, 0.178339}, {0.000000, 0.747468, 0.005438}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+06, 293.15, {0.400000, 0.001820, 0.323730, 0.069380, 0.053220, 0.027610, 0.012650, 0.009140, 0.102450}, 0.120388, 0.479612, 0.400000, {0.000000, 0.011551, 0.850996}, {0.000000, 0.672084, 0.000000}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+07, 293.15, {0.400000, 0.001820, 0.323730, 0.069380, 0.053220, 0.027610, 0.012650, 0.009140, 0.102450}, 0.185888, 0.414112, 0.400000, {0.000000, 0.111648, 0.551139}, {0.000000, 0.731628, 0.000000}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+08, 293.15, {0.400000, 0.001820, 0.323730, 0.069380, 0.053220, 0.027610, 0.012650, 0.009140, 0.102450}, 0.600000, 0.000000, 0.400000, {0.000000, 0.539550, 0.170750}, {0.000000, 0.539550, 0.170750}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+06, 313.15, {0.400000, 0.001820, 0.323730, 0.069380, 0.053220, 0.027610, 0.012650, 0.009140, 0.102450}, 0.115342, 0.484658, 0.400000, {0.000000, 0.010985, 0.888229}, {0.000000, 0.665341, 0.000000}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+07, 313.15, {0.400000, 0.001820, 0.323730, 0.069380, 0.053220, 0.027610, 0.012650, 0.009140, 0.102450}, 0.174755, 0.425245, 0.400000, {0.000000, 0.106714, 0.586247}, {0.000000, 0.717425, 0.000001}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+08, 313.15, {0.400000, 0.001820, 0.323730, 0.069380, 0.053220, 0.027610, 0.012650, 0.009140, 0.102450}, 0.600000, 0.000000, 0.400000, {0.000000, 0.539550, 0.170750}, {0.000000, 0.539550, 0.170750}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+06, 353.15, {0.400000, 0.001820, 0.323730, 0.069380, 0.053220, 0.027610, 0.012650, 0.009140, 0.102450}, 0.110071, 0.489929, 0.400000, {0.000000, 0.010453, 0.930753}, {0.000000, 0.658421, 0.000003}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+07, 353.15, {0.400000, 0.001820, 0.323730, 0.069380, 0.053220, 0.027610, 0.012650, 0.009140, 0.102450}, 0.158432, 0.441568, 0.400000, {0.000000, 0.101278, 0.646630}, {0.000000, 0.696800, 0.000007}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+08, 353.15, {0.400000, 0.001820, 0.323730, 0.069380, 0.053220, 0.027610, 0.012650, 0.009140, 0.102450}, 0.573644, 0.026356, 0.400000, {0.000000, 0.529997, 0.178345}, {0.000000, 0.747479, 0.005437}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+06, 313.15, {1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000}, 0.000000, 0.000000, 1.000000, {0.000000, 0.125000, 0.125000}, {0.000000, 0.125000, 0.125000}, {1.000000, 0.000000, 0.000000}}, + FlashData<9>{1.0e+08, 353.15, {1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000}, 0.000000, 0.000000, 1.000000, {0.000000, 0.125000, 0.125000}, {0.000000, 0.125000, 0.125000}, {1.000000, 0.000000, 0.000000}} + ) +); + +/* UNCRUSTIFY-ON */ + +} // testing + +} // geos diff --git a/src/coreComponents/constitutive/unitTests/testImmiscibleWaterProperties.cpp b/src/coreComponents/constitutive/unitTests/testImmiscibleWaterProperties.cpp new file mode 100644 index 00000000000..d1a6e998b79 --- /dev/null +++ b/src/coreComponents/constitutive/unitTests/testImmiscibleWaterProperties.cpp @@ -0,0 +1,285 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// Source includes +#include "codingUtilities/UnitTestUtilities.hpp" +#include "constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterParameters.hpp" +#include "constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterDensity.hpp" +#include "constitutive/fluid/multifluid/compositional/models/ImmiscibleWaterViscosity.hpp" +#include "TestFluid.hpp" +#include "TestFluidUtilities.hpp" + +using namespace geos::constitutive::compositional; + +namespace geos +{ +namespace testing +{ + +template< int NC > +using TestData = std::tuple< + real64 const, // pressure + real64 const, // temperature + Feed< NC > const, // phase composition + real64 const, // expected molar density + real64 const, // expected mass density + real64 const // expected viscosity + >; + +template< int NC > +struct FluidData {}; + +template<> +struct FluidData< 3 > +{ + static std::unique_ptr< TestFluid< 3 > > createFluid() + { + auto fluid = TestFluid< 3 >::create( {Fluid::C1, Fluid::C10, Fluid::H2O} ); + std::array< real64, 3 > const bics = {0.25, 0.0, 0.0}; + fluid->setBinaryCoefficients( bics ); + return fluid; + } +}; + +template< int NC > +class ImmiscibleWaterPropertiesTestFixture : public ::testing::TestWithParam< TestData< NC > > +{ + static constexpr real64 relTol = 1.0e-5; + static constexpr real64 absTol = 1.0e-7; + static constexpr int numComps = NC; + static constexpr int numDofs = NC + 2; + using Deriv = geos::constitutive::multifluid::DerivativeOffset; +public: + ImmiscibleWaterPropertiesTestFixture() + : m_fluid( FluidData< NC >::createFluid() ) + { + ComponentProperties const & componentProperties = this->m_fluid->getComponentProperties(); + + m_parameters = ImmiscibleWaterDensity::createParameters( std::make_unique< ModelParameters >() ); + m_parameters = ImmiscibleWaterViscosity::createParameters( std::move( m_parameters ) ); + + auto * waterParameters = const_cast< ImmiscibleWaterParameters * >(m_parameters->get< ImmiscibleWaterParameters >()); + waterParameters->m_waterReferencePressure = 215.0e5; + waterParameters->m_waterDensity = 1020.0; + waterParameters->m_waterCompressibility = 4.1483E-10; + waterParameters->m_waterViscosityCompressibility = 2.0E-11; + waterParameters->m_waterViscosity = 0.32929e-3; + + m_density = std::make_unique< ImmiscibleWaterDensity >( "PhaseDensity", componentProperties, 0, *m_parameters ); + m_viscosity = std::make_unique< ImmiscibleWaterViscosity >( "PhaseViscosity", componentProperties, 0, *m_parameters ); + } + + ~ImmiscibleWaterPropertiesTestFixture() = default; + + void testProperties( TestData< NC > const & data ) + { + real64 const pressure = std::get< 0 >( data ); + real64 const temperature = std::get< 1 >( data ); + stackArray1d< real64, numComps > phaseComposition; + TestFluid< NC >::createArray( phaseComposition, std::get< 2 >( data )); + real64 const expectedMolarDensity = std::get< 3 >( data ); + real64 const expectedMassDensity = std::get< 4 >( data ); + real64 const expectedViscosity = std::get< 5 >( data ); + + real64 molarDensity = 0.0; + real64 massDensity = 0.0; + real64 viscosity = 0.0; + stackArray1d< real64, numDofs > tempDerivs( numDofs ); + + auto componentProperties = m_fluid->createKernelWrapper(); + auto densityKernelWrapper = m_density->createKernelWrapper(); + auto viscosityKernelWrapper = m_viscosity->createKernelWrapper(); + + densityKernelWrapper.compute( componentProperties, + pressure, + temperature, + phaseComposition.toSliceConst(), + molarDensity, + tempDerivs.toSlice(), + massDensity, + tempDerivs.toSlice(), + false ); + + viscosityKernelWrapper.compute( componentProperties, + pressure, + temperature, + phaseComposition.toSliceConst(), + massDensity, + tempDerivs.toSliceConst(), + viscosity, + tempDerivs.toSlice(), + false ); + + checkRelativeError( molarDensity, expectedMolarDensity, relTol, absTol ); + checkRelativeError( massDensity, expectedMassDensity, relTol, absTol ); + checkRelativeError( viscosity, expectedViscosity, relTol, absTol ); + } + + void testPropertyDerivatives( TestData< NC > const & data ) + { + real64 const pressure = std::get< 0 >( data ); + real64 const temperature = std::get< 1 >( data ); + stackArray1d< real64, numComps > phaseComposition; + TestFluid< NC >::createArray( phaseComposition, std::get< 2 >( data )); + + auto componentProperties = m_fluid->createKernelWrapper(); + auto densityKernelWrapper = m_density->createKernelWrapper(); + auto viscosityKernelWrapper = m_viscosity->createKernelWrapper(); + + real64 molarDensity = 0.0; + real64 massDensity = 0.0; + real64 viscosity = 0.0; + stackArray1d< real64, numDofs > molarDensityDerivs( numDofs ); + stackArray1d< real64, numDofs > massDensityDerivs( numDofs ); + stackArray1d< real64, numDofs > viscosityDerivs( numDofs ); + stackArray1d< real64, 3 > derivatives( 3 ); + + densityKernelWrapper.compute( componentProperties, + pressure, + temperature, + phaseComposition.toSliceConst(), + molarDensity, + molarDensityDerivs.toSlice(), + massDensity, + massDensityDerivs.toSlice(), + false ); + + viscosityKernelWrapper.compute( componentProperties, + pressure, + temperature, + phaseComposition.toSliceConst(), + massDensity, + massDensityDerivs.toSliceConst(), + viscosity, + viscosityDerivs.toSlice(), + false ); + + // Viscosity values are very small so we will inflate the values to avoid false positives due + // to the absolute value check + real64 constexpr viscosityScale = 1.0e6; + + auto calculateProperties = [&]( real64 const p, real64 const t, auto const & zmf, auto & values ) { + stackArray1d< real64, numDofs > tempDerivs( numDofs ); + densityKernelWrapper.compute( componentProperties, p, t, zmf.toSliceConst(), + values[0], tempDerivs.toSlice(), values[1], tempDerivs.toSlice(), false ); + viscosityKernelWrapper.compute( componentProperties, p, t, zmf.toSliceConst(), + values[1], tempDerivs.toSliceConst(), values[2], tempDerivs.toSlice(), false ); + values[2] *= viscosityScale; + }; + + auto concatDerivatives = [&]( int idof ){ + derivatives[0] = molarDensityDerivs[idof]; + derivatives[1] = massDensityDerivs[idof]; + derivatives[2] = viscosityScale * viscosityDerivs[idof]; + }; + + // Compare against numerical derivatives + // -- Pressure derivative + concatDerivatives( Deriv::dP ); + real64 const dp = 1.0e-4 * pressure; + internal::testNumericalDerivative< 3 >( pressure, dp, derivatives.toSliceConst(), + [&]( real64 const p, auto & values ) { + calculateProperties( p, temperature, phaseComposition, values ); + }, absTol, relTol ); + + // -- Temperature derivative + concatDerivatives( Deriv::dT ); + real64 const dT = 1.0e-6 * temperature; + internal::testNumericalDerivative< 3 >( temperature, dT, derivatives.toSliceConst(), + [&]( real64 const t, auto & values ) { + calculateProperties( pressure, t, phaseComposition, values ); + }, absTol, relTol ); + + // -- Composition derivatives derivative + real64 const dz = 1.0e-7; + for( integer ic = 0; ic < NC; ++ic ) + { + concatDerivatives( Deriv::dC+ic ); + internal::testNumericalDerivative< 3 >( 0.0, dz, derivatives.toSliceConst(), + [&]( real64 const z, auto & values ) { + stackArray1d< real64, numComps > zmf( numComps ); + for( integer jc = 0; jc < numComps; ++jc ) + { + zmf[jc] = phaseComposition[jc]; + } + zmf[ic] += z; + calculateProperties( pressure, temperature, zmf, values ); + }, absTol, relTol ); + } + } + +protected: + std::unique_ptr< TestFluid< NC > > m_fluid{}; + std::unique_ptr< ImmiscibleWaterDensity > m_density{}; + std::unique_ptr< ImmiscibleWaterViscosity > m_viscosity{}; + std::unique_ptr< ModelParameters > m_parameters{}; +}; + +using ImmiscibleWaterProperties3 = ImmiscibleWaterPropertiesTestFixture< 3 >; + +TEST_P( ImmiscibleWaterProperties3, testProperties ) +{ + testProperties( GetParam() ); +} + +TEST_P( ImmiscibleWaterProperties3, testPropertyDerivatives ) +{ + testPropertyDerivatives( GetParam() ); +} + +//------------------------------------------------------------------------------- +// Data +//------------------------------------------------------------------------------- + +/* UNCRUSTIFY-OFF */ + +INSTANTIATE_TEST_SUITE_P( + ImmiscibleWaterProperties, ImmiscibleWaterProperties3, + ::testing::Values( + TestData< 3 >( 2.0e+06, 293.15, { 0.30, 0.30, 0.40 }, 5.616333e+04, 1.011782e+03, 3.291616e-04 ), + TestData< 3 >( 1.5e+07, 293.15, { 0.30, 0.30, 0.40 }, 5.646702e+04, 1.017253e+03, 3.292472e-04 ), + TestData< 3 >( 6.0e+07, 293.15, { 0.30, 0.30, 0.40 }, 5.753101e+04, 1.036421e+03, 3.295437e-04 ), + TestData< 3 >( 2.0e+06, 353.15, { 0.30, 0.30, 0.40 }, 5.616333e+04, 1.011782e+03, 3.291616e-04 ), + TestData< 3 >( 1.5e+07, 353.15, { 0.30, 0.30, 0.40 }, 5.646702e+04, 1.017253e+03, 3.292472e-04 ), + TestData< 3 >( 6.0e+07, 353.15, { 0.30, 0.30, 0.40 }, 5.753101e+04, 1.036421e+03, 3.295437e-04 ), + TestData< 3 >( 2.0e+06, 573.15, { 0.30, 0.30, 0.40 }, 5.616333e+04, 1.011782e+03, 3.291616e-04 ), + TestData< 3 >( 1.5e+07, 573.15, { 0.30, 0.30, 0.40 }, 5.646702e+04, 1.017253e+03, 3.292472e-04 ), + TestData< 3 >( 6.0e+07, 573.15, { 0.30, 0.30, 0.40 }, 5.753101e+04, 1.036421e+03, 3.295437e-04 ), + TestData< 3 >( 2.0e+06, 293.15, { 0.00, 0.00, 1.00 }, 5.616333e+04, 1.011782e+03, 3.291616e-04 ), + TestData< 3 >( 1.5e+07, 293.15, { 0.00, 0.00, 1.00 }, 5.646702e+04, 1.017253e+03, 3.292472e-04 ), + TestData< 3 >( 6.0e+07, 293.15, { 0.00, 0.00, 1.00 }, 5.753101e+04, 1.036421e+03, 3.295437e-04 ), + TestData< 3 >( 2.0e+06, 353.15, { 0.00, 0.00, 1.00 }, 5.616333e+04, 1.011782e+03, 3.291616e-04 ), + TestData< 3 >( 1.5e+07, 353.15, { 0.00, 0.00, 1.00 }, 5.646702e+04, 1.017253e+03, 3.292472e-04 ), + TestData< 3 >( 6.0e+07, 353.15, { 0.00, 0.00, 1.00 }, 5.753101e+04, 1.036421e+03, 3.295437e-04 ), + TestData< 3 >( 2.0e+06, 573.15, { 0.00, 0.00, 1.00 }, 5.616333e+04, 1.011782e+03, 3.291616e-04 ), + TestData< 3 >( 1.5e+07, 573.15, { 0.00, 0.00, 1.00 }, 5.646702e+04, 1.017253e+03, 3.292472e-04 ), + TestData< 3 >( 6.0e+07, 573.15, { 0.00, 0.00, 1.00 }, 5.753101e+04, 1.036421e+03, 3.295437e-04 ), + TestData< 3 >( 2.0e+06, 293.15, { 0.20, 0.80, 0.00 }, 5.616333e+04, 1.011782e+03, 3.291616e-04 ), + TestData< 3 >( 1.5e+07, 293.15, { 0.20, 0.80, 0.00 }, 5.646702e+04, 1.017253e+03, 3.292472e-04 ), + TestData< 3 >( 6.0e+07, 293.15, { 0.20, 0.80, 0.00 }, 5.753101e+04, 1.036421e+03, 3.295437e-04 ), + TestData< 3 >( 2.0e+06, 353.15, { 0.20, 0.80, 0.00 }, 5.616333e+04, 1.011782e+03, 3.291616e-04 ), + TestData< 3 >( 1.5e+07, 353.15, { 0.20, 0.80, 0.00 }, 5.646702e+04, 1.017253e+03, 3.292472e-04 ), + TestData< 3 >( 6.0e+07, 353.15, { 0.20, 0.80, 0.00 }, 5.753101e+04, 1.036421e+03, 3.295437e-04 ), + TestData< 3 >( 2.0e+06, 573.15, { 0.20, 0.80, 0.00 }, 5.616333e+04, 1.011782e+03, 3.291616e-04 ), + TestData< 3 >( 1.5e+07, 573.15, { 0.20, 0.80, 0.00 }, 5.646702e+04, 1.017253e+03, 3.292472e-04 ), + TestData< 3 >( 6.0e+07, 573.15, { 0.20, 0.80, 0.00 }, 5.753101e+04, 1.036421e+03, 3.295437e-04 ) + ) +); + +/* UNCRUSTIFY-ON */ + +} // testing + +} // geos diff --git a/src/coreComponents/constitutive/unitTests/testKValueInitialization.cpp b/src/coreComponents/constitutive/unitTests/testKValueInitialization.cpp index de5548fd714..ac0d01dcd35 100644 --- a/src/coreComponents/constitutive/unitTests/testKValueInitialization.cpp +++ b/src/coreComponents/constitutive/unitTests/testKValueInitialization.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -56,13 +57,13 @@ class WilsonKValueInitializationTestFixture : integer const compIndex = std::get< 2 >( GetParam() ); real64 const expectedKValue = std::get< 3 >( GetParam() ); - array1d< real64 > kValues( numComps ); + stackArray1d< real64, NC > kValues( numComps ); KValueInitialization::computeWilsonGasLiquidKvalue( numComps, pressure, temperature, createKernelWrapper(), - kValues ); + kValues.toSlice() ); ASSERT_EQ( kValues.size(), NC ); checkRelativeError( expectedKValue, kValues[compIndex], relTol ); @@ -83,7 +84,6 @@ class WilsonKValueInitializationTestFixture : discarded, criticalPressure, criticalTemperature, - discarded, acentricFactor, discarded, discarded2d ); diff --git a/src/coreComponents/constitutive/unitTests/testLohrenzBrayClarkViscosity.cpp b/src/coreComponents/constitutive/unitTests/testLohrenzBrayClarkViscosity.cpp new file mode 100644 index 00000000000..3adeab00ab1 --- /dev/null +++ b/src/coreComponents/constitutive/unitTests/testLohrenzBrayClarkViscosity.cpp @@ -0,0 +1,291 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// Source includes +#include "codingUtilities/UnitTestUtilities.hpp" +#include "constitutive/fluid/multifluid/compositional/models/CompositionalDensity.hpp" +#include "constitutive/fluid/multifluid/compositional/models/CriticalVolume.hpp" +#include "constitutive/fluid/multifluid/compositional/models/LohrenzBrayClarkViscosity.hpp" +#include "TestFluid.hpp" +#include "TestFluidUtilities.hpp" + +using namespace geos::constitutive::compositional; + +namespace geos +{ +namespace testing +{ + +template< int NC > +using ViscosityData = std::tuple< + integer const, // Mixing type + real64 const, // pressure + real64 const, // temperature + Feed< NC > const, // phase composition + real64 const // expected viscosity + >; + +template< int NC > +struct FluidData {}; + +template<> +struct FluidData< 9 > +{ + static std::unique_ptr< TestFluid< 9 > > createFluid() + { + auto fluid = TestFluid< 9 >::create( {Fluid::H2O, Fluid::CO2, Fluid::N2, Fluid::C5, Fluid::C2, Fluid::C3, Fluid::C4, Fluid::C5, Fluid::C10} ); + const std::array< real64 const, 36 > bics = { + 0.01, 0, 0.003732, 0, 0.01, 0, 0, 0.01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0.01, 0, 0.028, 0.01, 0.01, 0, 0, 0.01, 0, 0.04532, 0.01, 0.01, 0, 0, 0 + }; + fluid->setBinaryCoefficients( bics ); + return fluid; + } +}; + +template< int NC > +class LohrenzBrayClarkViscosityTestFixture : public ::testing::TestWithParam< ViscosityData< NC > > +{ + static constexpr real64 relTol = 1.0e-5; + static constexpr real64 absTol = 1.0e-7; + static constexpr int numComps = NC; + static constexpr int numDofs = NC + 2; + using Deriv = geos::constitutive::multifluid::DerivativeOffset; +public: + LohrenzBrayClarkViscosityTestFixture() + : m_fluid( FluidData< NC >::createFluid() ) + { + ComponentProperties const & componentProperties = this->m_fluid->getComponentProperties(); + + m_parameters = CompositionalDensity::createParameters( std::make_unique< ModelParameters >() ); + m_parameters = LohrenzBrayClarkViscosity::createParameters( std::move( m_parameters ) ); + + auto * parameters = const_cast< CriticalVolume * >(m_parameters->get< CriticalVolume >()); + parameters->m_componentCriticalVolume.resize( NC ); + TestFluid< 9 >::populateArray( parameters->m_componentCriticalVolume, this->m_fluid->criticalVolume ); + + auto * equationOfState = const_cast< EquationOfState * >(m_parameters->get< EquationOfState >()); + string const eosName = EnumStrings< EquationOfStateType >::toString( EquationOfStateType::PengRobinson ); + equationOfState->m_equationsOfStateNames.emplace_back( eosName ); + + m_density = std::make_unique< CompositionalDensity >( "PhaseDensity", componentProperties, 0, *m_parameters ); + m_viscosity = std::make_unique< LohrenzBrayClarkViscosity >( "PhaseViscosity", componentProperties, 0, *m_parameters ); + } + + ~LohrenzBrayClarkViscosityTestFixture() = default; + + void testViscosity( ViscosityData< NC > const & data ) + { + auto const mixing_type = static_cast< LohrenzBrayClarkViscosityUpdate::MixingType >(std::get< 0 >( data )); + real64 const pressure = std::get< 1 >( data ); + real64 const temperature = std::get< 2 >( data ); + stackArray1d< real64, numComps > phaseComposition; + TestFluid< NC >::createArray( phaseComposition, std::get< 3 >( data )); + real64 const expectedViscosity = std::get< 4 >( data ); + + real64 molarDensity = 0.0; + real64 massDensity = 0.0; + real64 viscosity = 0.0; + stackArray1d< real64, numDofs > tempDerivs( numDofs ); + + auto componentProperties = m_fluid->createKernelWrapper(); + auto densityKernelWrapper = m_density->createKernelWrapper(); + auto viscosityKernelWrapper = m_viscosity->createKernelWrapper(); + + viscosityKernelWrapper.setMixingType( mixing_type ); + + densityKernelWrapper.compute( componentProperties, + pressure, + temperature, + phaseComposition.toSliceConst(), + molarDensity, + tempDerivs.toSlice(), + massDensity, + tempDerivs.toSlice(), + false ); + + viscosityKernelWrapper.compute( componentProperties, + pressure, + temperature, + phaseComposition.toSliceConst(), + massDensity, + tempDerivs.toSliceConst(), + viscosity, + tempDerivs.toSlice(), + false ); + + checkRelativeError( viscosity, expectedViscosity, relTol, absTol ); + } + + void testViscosityDerivatives( ViscosityData< NC > const & data ) + { + auto const mixing_type = static_cast< LohrenzBrayClarkViscosityUpdate::MixingType >(std::get< 0 >( data )); + real64 const pressure = std::get< 1 >( data ); + real64 const temperature = std::get< 2 >( data ); + stackArray1d< real64, numComps > phaseComposition; + TestFluid< NC >::createArray( phaseComposition, std::get< 3 >( data )); + + auto componentProperties = m_fluid->createKernelWrapper(); + auto densityKernelWrapper = m_density->createKernelWrapper(); + auto viscosityKernelWrapper = m_viscosity->createKernelWrapper(); + + viscosityKernelWrapper.setMixingType( mixing_type ); + + real64 molarDensity = 0.0; + real64 massDensity = 0.0; + real64 viscosity = 0.0; + stackArray1d< real64, numDofs > molarDensityDerivs( numDofs ); + stackArray1d< real64, numDofs > massDensityDerivs( numDofs ); + stackArray1d< real64, numDofs > viscosityDerivs( numDofs ); + + densityKernelWrapper.compute( componentProperties, + pressure, + temperature, + phaseComposition.toSliceConst(), + molarDensity, + molarDensityDerivs.toSlice(), + massDensity, + massDensityDerivs.toSlice(), + false ); + + viscosityKernelWrapper.compute( componentProperties, + pressure, + temperature, + phaseComposition.toSliceConst(), + massDensity, + massDensityDerivs.toSliceConst(), + viscosity, + viscosityDerivs.toSlice(), + false ); + + auto calculateViscosity = [&]( real64 const p, real64 const t, auto const & zmf ) -> real64 { + real64 densityMolar = 0.0; + real64 densityMass = 0.0; + real64 phaseViscosity = 0.0; + stackArray1d< real64, numDofs > tempDerivs( numDofs ); + densityKernelWrapper.compute( componentProperties, p, t, zmf.toSliceConst(), + densityMolar, tempDerivs.toSlice(), densityMass, tempDerivs.toSlice(), false ); + viscosityKernelWrapper.compute( componentProperties, p, t, zmf.toSliceConst(), + densityMass, tempDerivs.toSliceConst(), phaseViscosity, tempDerivs.toSlice(), false ); + return phaseViscosity; + }; + + // Viscosity values are very small so we will inflate the values to avoid false positives due + // to the absolute value check + real64 constexpr scale = 1.0e6; + + // Compare against numerical derivatives + // -- Pressure derivative + real64 const dp = 1.0e-4 * pressure; + internal::testNumericalDerivative( + pressure, dp, scale*viscosityDerivs[Deriv::dP], + [&]( real64 const p ) -> real64 { + return scale*calculateViscosity( p, temperature, phaseComposition ); + } ); + + // -- Temperature derivative + real64 const dT = 1.0e-6 * temperature; + internal::testNumericalDerivative( + temperature, dT, scale*viscosityDerivs[Deriv::dT], + [&]( real64 const t ) -> real64 { + return scale*calculateViscosity( pressure, t, phaseComposition ); + } ); + + // -- Composition derivatives derivative + real64 const dz = 1.0e-7; + for( integer ic = 0; ic < 1; ++ic ) + { + internal::testNumericalDerivative( + 0.0, dz, scale*viscosityDerivs[Deriv::dC + ic], + [&]( real64 const z ) -> real64 { + stackArray1d< real64, numComps > zmf( numComps ); + for( integer jc = 0; jc < numComps; ++jc ) + { + zmf[jc] = phaseComposition[jc]; + } + zmf[ic] += z; + return scale*calculateViscosity( pressure, temperature, zmf ); + } ); + } + } + +protected: + std::unique_ptr< TestFluid< NC > > m_fluid{}; + std::unique_ptr< CompositionalDensity > m_density{}; + std::unique_ptr< LohrenzBrayClarkViscosity > m_viscosity{}; + std::unique_ptr< ModelParameters > m_parameters{}; +}; + +using LohrenzBrayClarkViscosity9 = LohrenzBrayClarkViscosityTestFixture< 9 >; + +TEST_P( LohrenzBrayClarkViscosity9, testViscosity ) +{ + testViscosity( GetParam() ); +} + +TEST_P( LohrenzBrayClarkViscosity9, testViscosityDerivatives ) +{ + testViscosityDerivatives( GetParam() ); +} + +//------------------------------------------------------------------------------- +// Data +//------------------------------------------------------------------------------- +INSTANTIATE_TEST_SUITE_P( + LohrenzBrayClarkViscosity, + LohrenzBrayClarkViscosity9, + ::testing::ValuesIn( { + ViscosityData< 9 >{ 0, 1.839590e+06, 2.971500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1.041140e-04 }, + ViscosityData< 9 >{ 1, 1.839590e+06, 2.971500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1.001152e-04 }, + ViscosityData< 9 >{ 2, 1.839590e+06, 2.971500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1.064158e-04 }, + ViscosityData< 9 >{ 0, 1.839590e+06, 2.971500e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 1.761220e-05 }, + ViscosityData< 9 >{ 1, 1.839590e+06, 2.971500e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 1.659626e-05 }, + ViscosityData< 9 >{ 2, 1.839590e+06, 2.971500e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 1.844604e-05 }, + ViscosityData< 9 >{ 0, 1.839590e+06, 2.971500e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 1.062011e-04 }, + ViscosityData< 9 >{ 1, 1.839590e+06, 2.971500e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 1.021978e-04 }, + ViscosityData< 9 >{ 2, 1.839590e+06, 2.971500e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 1.085108e-04 }, + ViscosityData< 9 >{ 0, 1.839590e+06, 3.630000e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1.681288e-05 }, + ViscosityData< 9 >{ 1, 1.839590e+06, 3.630000e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1.230528e-05 }, + ViscosityData< 9 >{ 2, 1.839590e+06, 3.630000e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1.959149e-05 }, + ViscosityData< 9 >{ 0, 1.839590e+06, 3.630000e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 2.033595e-05 }, + ViscosityData< 9 >{ 1, 1.839590e+06, 3.630000e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 1.923634e-05 }, + ViscosityData< 9 >{ 2, 1.839590e+06, 3.630000e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 2.133312e-05 }, + ViscosityData< 9 >{ 0, 1.839590e+06, 3.630000e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 1.681118e-05 }, + ViscosityData< 9 >{ 1, 1.839590e+06, 3.630000e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 1.229779e-05 }, + ViscosityData< 9 >{ 2, 1.839590e+06, 3.630000e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 1.959939e-05 }, + ViscosityData< 9 >{ 0, 1.839590e+08, 2.971500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 6.123583e-04 }, + ViscosityData< 9 >{ 1, 1.839590e+08, 2.971500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 6.083595e-04 }, + ViscosityData< 9 >{ 2, 1.839590e+08, 2.971500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 6.146601e-04 }, + ViscosityData< 9 >{ 0, 1.839590e+08, 2.971500e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 1.451048e-04 }, + ViscosityData< 9 >{ 1, 1.839590e+08, 2.971500e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 1.440889e-04 }, + ViscosityData< 9 >{ 2, 1.839590e+08, 2.971500e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 1.459387e-04 }, + ViscosityData< 9 >{ 0, 1.839590e+08, 2.971500e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 6.170310e-04 }, + ViscosityData< 9 >{ 1, 1.839590e+08, 2.971500e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 6.130277e-04 }, + ViscosityData< 9 >{ 2, 1.839590e+08, 2.971500e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 6.193407e-04 }, + ViscosityData< 9 >{ 0, 1.839590e+08, 3.630000e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 4.720985e-04 }, + ViscosityData< 9 >{ 1, 1.839590e+08, 3.630000e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 4.675909e-04 }, + ViscosityData< 9 >{ 2, 1.839590e+08, 3.630000e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 4.748771e-04 }, + ViscosityData< 9 >{ 0, 1.839590e+08, 3.630000e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 1.078437e-04 }, + ViscosityData< 9 >{ 1, 1.839590e+08, 3.630000e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 1.067441e-04 }, + ViscosityData< 9 >{ 2, 1.839590e+08, 3.630000e+02, {0.008260, 0.005440, 0.770320, 0.104560, 0.061770, 0.024590, 0.008840, 0.004720, 0.011490}, 1.088409e-04 }, + ViscosityData< 9 >{ 0, 1.839590e+08, 3.630000e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 4.763030e-04 }, + ViscosityData< 9 >{ 1, 1.839590e+08, 3.630000e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 4.717896e-04 }, + ViscosityData< 9 >{ 2, 1.839590e+08, 3.630000e+02, {0.008990, 0.002990, 0.532810, 0.114470, 0.087910, 0.045660, 0.020950, 0.015160, 0.171070}, 4.790912e-04 } + } ) + ); + +} // testing + +} // geos diff --git a/src/coreComponents/constitutive/unitTests/testModifiedCamClay.cpp b/src/coreComponents/constitutive/unitTests/testModifiedCamClay.cpp index 253971bccd1..6cfbb6791d8 100644 --- a/src/coreComponents/constitutive/unitTests/testModifiedCamClay.cpp +++ b/src/coreComponents/constitutive/unitTests/testModifiedCamClay.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 Total, S.A - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -96,7 +97,7 @@ void testModifiedCamClayDriver() xmlWrapper::xmlNode xmlConstitutiveNode = xmlDocument.getChild( "Constitutive" ); constitutiveManager.processInputFileRecursive( xmlDocument, xmlConstitutiveNode ); - constitutiveManager.postProcessInputRecursive(); + constitutiveManager.postInputInitializationRecursive(); localIndex constexpr numElem = 2; localIndex constexpr numQuad = 4; diff --git a/src/coreComponents/constitutive/unitTests/testMultiFluidSelector.cpp b/src/coreComponents/constitutive/unitTests/testMultiFluidSelector.cpp new file mode 100644 index 00000000000..55a045b5be9 --- /dev/null +++ b/src/coreComponents/constitutive/unitTests/testMultiFluidSelector.cpp @@ -0,0 +1,159 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// Source includes +#include "codingUtilities/UnitTestUtilities.hpp" +#include "constitutive/fluid/multifluid/MultiFluidSelector.hpp" + +using namespace geos; +using namespace geos::testing; +using namespace geos::constitutive; + +template< typename FluidType > +class MultiFluidSelectorTest : public ::testing::Test +{ +public: + MultiFluidSelectorTest(): + m_node(), + m_parent( "parent", m_node ) + { + m_model = &m_parent.registerGroup< FluidType >( "fluid" ); + } + ~MultiFluidSelectorTest() override = default; + + MultiFluidBase & getFluid() const { return *m_model; } + +protected: + conduit::Node m_node; + dataRepository::Group m_parent; + FluidType * m_model{}; +}; + +using MultiFluidSelectorTestDeadOilFluid = MultiFluidSelectorTest< DeadOilFluid >; +using MultiFluidSelectorTestCO2BrinePhillipsThermalFluid = MultiFluidSelectorTest< CO2BrinePhillipsThermalFluid >; +using MultiFluidSelectorTestCompositionalTwoPhaseConstantViscosity = MultiFluidSelectorTest< CompositionalTwoPhaseConstantViscosity >; + +TEST_F( MultiFluidSelectorTestDeadOilFluid, testValidComponents ) +{ + bool isExecuted = false; + constitutiveComponentUpdatePassThru( getFluid(), 2, [&]( auto &, auto NC ) + { + integer constexpr numComps = NC(); + EXPECT_EQ( numComps, 2 ); + isExecuted = true; + } ); + EXPECT_TRUE( isExecuted ); + + isExecuted = false; + constitutiveComponentUpdatePassThru( getFluid(), 3, [&]( auto &, auto NC ) + { + integer constexpr numComps = NC(); + EXPECT_EQ( numComps, 3 ); + isExecuted = true; + } ); + EXPECT_TRUE( isExecuted ); +} + +TEST_F( MultiFluidSelectorTestDeadOilFluid, testInvalidComponents ) +{ + EXPECT_THROW( constitutiveComponentUpdatePassThru( getFluid(), 1, []( auto &, auto ) + { + FAIL(); // Shouldn't be called + } ), InputError ); + + EXPECT_THROW( constitutiveComponentUpdatePassThru( getFluid(), 4, []( auto &, auto ) + { + FAIL(); // Shouldn't be called + } ), InputError ); +} + +TEST_F( MultiFluidSelectorTestDeadOilFluid, testThermal ) +{ + EXPECT_THROW( constitutiveComponentUpdatePassThru< true >( getFluid(), 2, []( auto &, auto ) + { + FAIL(); // Shouldn't be called + } ), InputError ); +} + +TEST_F( MultiFluidSelectorTestCO2BrinePhillipsThermalFluid, testValidComponents ) +{ + bool isExecuted = false; + constitutiveComponentUpdatePassThru( getFluid(), 2, [&]( auto &, auto NC ) + { + integer constexpr numComps = NC(); + EXPECT_EQ( numComps, 2 ); + isExecuted = true; + } ); + EXPECT_TRUE( isExecuted ); +} + +TEST_F( MultiFluidSelectorTestCO2BrinePhillipsThermalFluid, testInvalidComponents ) +{ + EXPECT_THROW( constitutiveComponentUpdatePassThru( getFluid(), 1, []( auto &, auto ) + { + FAIL(); // Shouldn't be called + } ), InputError ); + + EXPECT_THROW( constitutiveComponentUpdatePassThru( getFluid(), 3, []( auto &, auto ) + { + FAIL(); // Shouldn't be called + } ), InputError ); +} + +TEST_F( MultiFluidSelectorTestCO2BrinePhillipsThermalFluid, testThermal ) +{ + bool isExecuted = false; + constitutiveComponentUpdatePassThru< true >( getFluid(), 2, [&]( auto &, auto ) + { + isExecuted = true; + } ); + EXPECT_TRUE( isExecuted ); +} + +TEST_F( MultiFluidSelectorTestCompositionalTwoPhaseConstantViscosity, testValidComponents ) +{ + for( integer nc = 2; nc <= 5; nc++ ) + { + bool isExecuted = false; + constitutiveComponentUpdatePassThru( getFluid(), nc, [&]( auto &, auto NC ) + { + integer constexpr numComps = NC(); + EXPECT_EQ( numComps, nc ); + isExecuted = true; + } ); + EXPECT_TRUE( isExecuted ); + } +} + +TEST_F( MultiFluidSelectorTestCompositionalTwoPhaseConstantViscosity, testInvalidComponents ) +{ + EXPECT_THROW( constitutiveComponentUpdatePassThru( getFluid(), 1, []( auto &, auto ) + { + FAIL(); // Shouldn't be called + } ), InputError ); + + EXPECT_THROW( constitutiveComponentUpdatePassThru( getFluid(), 6, []( auto &, auto ) + { + FAIL(); // Shouldn't be called + } ), InputError ); +} + +TEST_F( MultiFluidSelectorTestCompositionalTwoPhaseConstantViscosity, testThermal ) +{ + EXPECT_THROW( constitutiveComponentUpdatePassThru< true >( getFluid(), 2, [&]( auto &, auto ) + { + FAIL(); // Shouldn't be called + } ), InputError ); +} diff --git a/src/coreComponents/constitutive/unitTests/testNegativeTwoPhaseFlash.cpp b/src/coreComponents/constitutive/unitTests/testNegativeTwoPhaseFlash.cpp index bfc074c578d..d27bc16d58c 100644 --- a/src/coreComponents/constitutive/unitTests/testNegativeTwoPhaseFlash.cpp +++ b/src/coreComponents/constitutive/unitTests/testNegativeTwoPhaseFlash.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,6 +18,7 @@ #include "constitutive/fluid/multifluid/compositional/functions/NegativeTwoPhaseFlash.hpp" #include "constitutive/fluid/multifluid/compositional/functions/CubicEOSPhaseModel.hpp" #include "TestFluid.hpp" +#include "TestFluidUtilities.hpp" using namespace geos::constitutive::compositional; @@ -58,12 +60,14 @@ using FlashData = std::tuple< Feed< NC > const // expected vapour composition >; -template< int NC, typename EOS_TYPE > +template< int NC, EquationOfStateType EOS_TYPE > class NegativeTwoPhaseFlashTestFixture : public ::testing::TestWithParam< FlashData< NC > > { static constexpr real64 relTol = 1.0e-5; static constexpr real64 absTol = 1.0e-7; static constexpr int numComps = NC; + static constexpr int numDofs = NC + 2; + using Deriv = geos::constitutive::multifluid::DerivativeOffset; public: NegativeTwoPhaseFlashTestFixture() : m_fluid( FluidData< NC >::createFluid() ) @@ -77,30 +81,35 @@ class NegativeTwoPhaseFlashTestFixture : public ::testing::TestWithParam< Flash real64 const pressure = std::get< 0 >( data ); real64 const temperature = std::get< 1 >( data ); - array1d< real64 > composition; + stackArray1d< real64, numComps > composition; TestFluid< NC >::createArray( composition, std::get< 2 >( data )); bool const expectedStatus = std::get< 3 >( data ); real64 const expectedVapourFraction = std::get< 4 >( data ); - stackArray1d< real64, NC > expectedLiquidComposition; + stackArray1d< real64, numComps > expectedLiquidComposition; TestFluid< NC >::createArray( expectedLiquidComposition, std::get< 5 >( data )); - stackArray1d< real64, NC > expectedVapourComposition; + stackArray1d< real64, numComps > expectedVapourComposition; TestFluid< NC >::createArray( expectedVapourComposition, std::get< 6 >( data )); real64 vapourFraction = -1.0; - array1d< real64 > liquidComposition( numComps ); - array1d< real64 > vapourComposition( numComps ); + stackArray1d< real64, numComps > liquidComposition( numComps ); + stackArray1d< real64, numComps > vapourComposition( numComps ); + stackArray2d< real64, numComps > kValues( 1, numComps ); + kValues.zero(); - bool status = NegativeTwoPhaseFlash::compute< EOS_TYPE, EOS_TYPE >( + bool status = NegativeTwoPhaseFlash::compute( numComps, pressure, temperature, - composition, + composition.toSliceConst(), componentProperties, + EOS_TYPE, + EOS_TYPE, + kValues.toSlice(), vapourFraction, - liquidComposition, - vapourComposition ); + liquidComposition.toSlice(), + vapourComposition.toSlice() ); // Check the flash success result ASSERT_EQ( expectedStatus, status ); @@ -132,14 +141,140 @@ class NegativeTwoPhaseFlashTestFixture : public ::testing::TestWithParam< Flash } } + void testFlashDerivatives( FlashData< NC > const & data ) + { + // Number of output values from each flash calculation + constexpr integer numValues = 1 + 2*numComps; + + auto componentProperties = this->m_fluid->createKernelWrapper(); + + bool const expectedStatus = std::get< 3 >( data ); + if( !expectedStatus ) return; + + real64 const pressure = std::get< 0 >( data ); + real64 const temperature = std::get< 1 >( data ); + stackArray1d< real64, numComps > composition; + TestFluid< NC >::createArray( composition, std::get< 2 >( data )); + + real64 vapourFraction = -1.0; + stackArray1d< real64, numComps > liquidComposition( numComps ); + stackArray1d< real64, numComps > vapourComposition( numComps ); + stackArray2d< real64, numComps > kValues( 1, numComps ); + kValues.zero(); + + stackArray1d< real64, numDofs > vapourFractionDerivs( numDofs ); + stackArray2d< real64, numComps * numDofs > liquidCompositionDerivs( numComps, numDofs ); + stackArray2d< real64, numComps * numDofs > vapourCompositionDerivs( numComps, numDofs ); + stackArray1d< real64, numValues > derivatives( numValues ); + + // Combine values and derivatives into a single output + auto const concatDerivatives = []( integer const kc, auto & derivs, auto const & v, auto const & xmf, auto const & ymf ){ + derivs[0] = v[kc]; + for( integer ic = 0; ic < numComps; ++ic ) + { + derivs[1+ic] = xmf( ic, kc ); + derivs[1+ic+numComps] = ymf( ic, kc ); + } + }; + std::cout << std::scientific << std::setprecision( 8 ); + + auto const evaluateFlash = [&]( real64 const p, real64 const t, auto const & zmf, auto & values ){ + stackArray1d< real64, numComps > displacedLiquidComposition( numComps ); + stackArray1d< real64, numComps > displacedVapourComposition( numComps ); + kValues.zero(); + + NegativeTwoPhaseFlash::compute( + numComps, + p, + t, + zmf.toSliceConst(), + componentProperties, + EOS_TYPE, + EOS_TYPE, + kValues.toSlice(), + values[0], + displacedLiquidComposition.toSlice(), + displacedVapourComposition.toSlice() ); + for( integer ic = 0; ic < numComps; ++ic ) + { + values[1+ic] = displacedLiquidComposition[ic]; + values[1+ic+numComps] = displacedVapourComposition[ic]; + } + }; + + NegativeTwoPhaseFlash::compute( + numComps, + pressure, + temperature, + composition.toSliceConst(), + componentProperties, + EOS_TYPE, + EOS_TYPE, + kValues.toSlice(), + vapourFraction, + liquidComposition.toSlice(), + vapourComposition.toSlice() ); + + NegativeTwoPhaseFlash::computeDerivatives( + numComps, + pressure, + temperature, + composition.toSliceConst(), + componentProperties, + EOS_TYPE, + EOS_TYPE, + vapourFraction, + liquidComposition.toSliceConst(), + vapourComposition.toSliceConst(), + vapourFractionDerivs.toSlice(), + liquidCompositionDerivs.toSlice(), + vapourCompositionDerivs.toSlice() ); + + // Test against numerically calculated values + // --- Pressure derivatives --- + concatDerivatives( Deriv::dP, derivatives, vapourFractionDerivs, liquidCompositionDerivs, vapourCompositionDerivs ); + real64 const dp = 1.0e-4 * pressure; + geos::testing::internal::testNumericalDerivative< numValues >( + pressure, dp, derivatives, + [&]( real64 const p, auto & values ) { + evaluateFlash( p, temperature, composition, values ); + } ); + + // --- Temperature derivatives --- + concatDerivatives( Deriv::dT, derivatives, vapourFractionDerivs, liquidCompositionDerivs, vapourCompositionDerivs ); + real64 const dT = 1.0e-6 * temperature; + geos::testing::internal::testNumericalDerivative< numValues >( + temperature, dT, derivatives, + [&]( real64 const t, auto & values ) { + evaluateFlash( pressure, t, composition, values ); + } ); + + // --- Composition derivatives --- + real64 constexpr dz = 1.0e-7; + for( integer jc = 0; jc < numComps; ++jc ) + { + if( composition[jc] < 1.0e-6 ) continue; + integer const kc = Deriv::dC + jc; + concatDerivatives( kc, derivatives, vapourFractionDerivs, liquidCompositionDerivs, vapourCompositionDerivs ); + geos::testing::internal::testNumericalDerivative< numValues >( + 0.0, dz, derivatives, + [&]( real64 const z, auto & values ) { + real64 const originalFraction = composition[jc]; + composition[jc] += z; + evaluateFlash( pressure, temperature, composition, values ); + composition[jc] = originalFraction; + }, relTol, absTol ); + } + } + protected: std::unique_ptr< TestFluid< NC > > m_fluid{}; }; -using NegativeTwoPhaseFlash2CompPR = NegativeTwoPhaseFlashTestFixture< 2, CubicEOSPhaseModel< PengRobinsonEOS > >; -using NegativeTwoPhaseFlash2CompSRK = NegativeTwoPhaseFlashTestFixture< 2, CubicEOSPhaseModel< SoaveRedlichKwongEOS > >; -using NegativeTwoPhaseFlash4CompPR = NegativeTwoPhaseFlashTestFixture< 4, CubicEOSPhaseModel< PengRobinsonEOS > >; -using NegativeTwoPhaseFlash4CompSRK = NegativeTwoPhaseFlashTestFixture< 4, CubicEOSPhaseModel< SoaveRedlichKwongEOS > >; +using NegativeTwoPhaseFlash2CompPR = NegativeTwoPhaseFlashTestFixture< 2, EquationOfStateType::PengRobinson >; +using NegativeTwoPhaseFlash2CompSRK = NegativeTwoPhaseFlashTestFixture< 2, EquationOfStateType::SoaveRedlichKwong >; +using NegativeTwoPhaseFlash4CompPR = NegativeTwoPhaseFlashTestFixture< 4, EquationOfStateType::PengRobinson >; +using NegativeTwoPhaseFlash4CompSRK = NegativeTwoPhaseFlashTestFixture< 4, EquationOfStateType::SoaveRedlichKwong >; TEST_P( NegativeTwoPhaseFlash2CompPR, testNegativeFlash ) { @@ -161,6 +296,26 @@ TEST_P( NegativeTwoPhaseFlash4CompSRK, testNegativeFlash ) testFlash( GetParam() ); } +TEST_P( NegativeTwoPhaseFlash2CompPR, testNegativeFlashDerivatives ) +{ + testFlashDerivatives( GetParam() ); +} + +TEST_P( NegativeTwoPhaseFlash2CompSRK, testNegativeFlashDerivatives ) +{ + testFlashDerivatives( GetParam() ); +} + +TEST_P( NegativeTwoPhaseFlash4CompPR, testNegativeFlashDerivatives ) +{ + testFlashDerivatives( GetParam() ); +} + +TEST_P( NegativeTwoPhaseFlash4CompSRK, testNegativeFlashDerivatives ) +{ + testFlashDerivatives( GetParam() ); +} + //------------------------------------------------------------------------------- // Data generated by PVTPackage //------------------------------------------------------------------------------- @@ -210,10 +365,10 @@ INSTANTIATE_TEST_SUITE_P( FlashData< 2 >( 1.013250e+05, 1.231500e+02, { 0.50000000, 0.50000000 }, true, 0.44681454, { 0.90248098, 0.09751902 }, { 0.00170237, 0.99829763 } ), FlashData< 2 >( 1.013250e+05, 1.231500e+02, { 0.90000000, 0.10000000 }, true, 0.00275426, { 0.90248098, 0.09751902 }, { 0.00170237, 0.99829763 } ), FlashData< 2 >( 1.000000e+06, 1.231500e+02, { 0.10000000, 0.90000000 }, true, 0.00000000, { 0.10000000, 0.90000000 }, { 0.10000000, 0.90000000 } ), - FlashData< 2 >( 1.000000e+06, 1.231500e+02, { 0.50000000, 0.50000000 }, false, 0.00000000, { 0.50000000, 0.50000000 }, { 0.49950202, 0.50049798 } ), + FlashData< 2 >( 1.000000e+06, 1.231500e+02, { 0.50000000, 0.50000000 }, true, 0.00000000, { 0.50000000, 0.50000000 }, { 0.49950202, 0.50049798 } ), FlashData< 2 >( 1.000000e+06, 1.231500e+02, { 0.90000000, 0.10000000 }, true, 0.00000000, { 0.90000000, 0.10000000 }, { 0.90000000, 0.10000000 } ), FlashData< 2 >( 5.000000e+06, 1.231500e+02, { 0.75000000, 0.25000000 }, true, 0.00000000, { 0.75000000, 0.25000000 }, { 0.74999999, 0.25000001 } ), - FlashData< 2 >( 5.000000e+06, 1.231500e+02, { 0.50000000, 0.50000000 }, false, 0.00000000, { 0.50000000, 0.50000000 }, { 0.49979984, 0.50020016 } ), + FlashData< 2 >( 5.000000e+06, 1.231500e+02, { 0.50000000, 0.50000000 }, true, 0.00000000, { 0.50000000, 0.50000000 }, { 0.49979984, 0.50020016 } ), FlashData< 2 >( 5.000000e+06, 1.231500e+02, { 0.90000000, 0.10000000 }, true, 0.00000000, { 0.90000000, 0.10000000 }, { 0.90000000, 0.10000000 } ), FlashData< 2 >( 1.000000e+08, 1.231500e+02, { 0.90000000, 0.10000000 }, true, 0.00000000, { 0.90000000, 0.10000000 }, { 0.90000000, 0.10000000 } ), FlashData< 2 >( 1.000000e+05, 1.931500e+02, { 0.10000000, 0.90000000 }, true, 1.00000000, { 0.10000000, 0.90000000 }, { 0.10000000, 0.90000000 } ), @@ -316,13 +471,13 @@ INSTANTIATE_TEST_SUITE_P( { 0.59975210, 0.00000000, 0.00078842, 0.39945949 } ), FlashData< 4 >( 1.000000e+07, 4.731500e+02, { 0.01000000, 0.00000000, 0.00000000, 0.99000000 }, true, 0.01121076, { 0.00102378, 0.00000000, 0.00000000, 0.99897622 }, { 0.80170284, 0.00000000, 0.00000000, 0.19829716 } ), - FlashData< 4 >( 1.000000e+08, 4.731500e+02, { 0.05695100, 0.10481800, 0.10482200, 0.73340900 }, false, 0.00000000, { 0.05695100, 0.10481800, 0.10482200, 0.73340900 }, + FlashData< 4 >( 1.000000e+08, 4.731500e+02, { 0.05695100, 0.10481800, 0.10482200, 0.73340900 }, true, 0.00000000, { 0.05695100, 0.10481800, 0.10482200, 0.73340900 }, { 0.72438623, 0.02564505, 0.01665696, 0.23331176 } ), - FlashData< 4 >( 1.000000e+08, 4.731500e+02, { 0.15695100, 0.10481800, 0.10482200, 0.63340900 }, false, 0.00000000, { 0.15695100, 0.10481800, 0.10482200, 0.63340900 }, + FlashData< 4 >( 1.000000e+08, 4.731500e+02, { 0.15695100, 0.10481800, 0.10482200, 0.63340900 }, true, 0.00000000, { 0.15695100, 0.10481800, 0.10482200, 0.63340900 }, { 0.73612750, 0.02738195, 0.01777184, 0.21871871 } ), FlashData< 4 >( 1.000000e+08, 4.731500e+02, { 0.00000000, 0.10481800, 0.10482200, 0.79036000 }, true, 0.72801768, { 0.00000000, 0.38538472, 0.38540005, 0.22921523 }, { 0.00000000, 0.00000023, 0.00000000, 0.99999977 } ), - FlashData< 4 >( 1.000000e+08, 4.731500e+02, { 0.10481800, 0.00000000, 0.10482200, 0.79036000 }, false, 0.00000000, { 0.10481800, 0.00000000, 0.10482200, 0.79036000 }, + FlashData< 4 >( 1.000000e+08, 4.731500e+02, { 0.10481800, 0.00000000, 0.10482200, 0.79036000 }, true, 0.00000000, { 0.10481800, 0.00000000, 0.10482200, 0.79036000 }, { 0.74504275, 0.00000000, 0.01613702, 0.23882023 } ) ) ); diff --git a/src/coreComponents/constitutive/unitTests/testNegativeTwoPhaseFlash9Comp.cpp b/src/coreComponents/constitutive/unitTests/testNegativeTwoPhaseFlash9Comp.cpp new file mode 100644 index 00000000000..49c494e9dd3 --- /dev/null +++ b/src/coreComponents/constitutive/unitTests/testNegativeTwoPhaseFlash9Comp.cpp @@ -0,0 +1,547 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// Source includes +#include "codingUtilities/UnitTestUtilities.hpp" +#include "constitutive/fluid/multifluid/compositional/functions/NegativeTwoPhaseFlash.hpp" +#include "constitutive/fluid/multifluid/compositional/functions/CubicEOSPhaseModel.hpp" +#include "TestFluid.hpp" +#include "TestFluidUtilities.hpp" + +using namespace geos::constitutive::compositional; + +namespace geos +{ +namespace testing +{ + +static constexpr integer numComps = 9; + +using FlashData = std::tuple< + real64 const, // pressure + real64 const, // temperature + Feed< numComps > const, // total composition + int, // expected flash status (success (1)/failure (0)) + real64 const, // expected vapour fraction + Feed< 2 > const, // expected liquid composition (2 selected components) + Feed< 2 > const // expected vapour composition (2 selected components) + >; + +template< EquationOfStateType EOS_TYPE > +class NegativeTwoPhaseFlashTest9CompFixture : public ::testing::TestWithParam< FlashData > +{ + static constexpr real64 relTol = 1.0e-5; + static constexpr real64 absTol = 1.0e-7; + static constexpr int numDofs = numComps + 2; + // Selected components for test + static constexpr int comp0 = 0; + static constexpr int comp1 = numComps-1; + using Deriv = geos::constitutive::multifluid::DerivativeOffset; +public: + NegativeTwoPhaseFlashTest9CompFixture() + : m_fluid( createFluid() ) + {} + + ~NegativeTwoPhaseFlashTest9CompFixture() = default; + + void testFlash( FlashData const & data ) + { + auto componentProperties = this->m_fluid->createKernelWrapper(); + + real64 const pressure = std::get< 0 >( data ); + real64 const temperature = std::get< 1 >( data ); + stackArray1d< real64, numComps > composition; + TestFluid< numComps >::createArray( composition, std::get< 2 >( data )); + + bool const expectedStatus = std::get< 3 >( data ); + real64 const expectedVapourFraction = std::get< 4 >( data ); + + stackArray1d< real64, numComps > expectedLiquidComposition; + stackArray1d< real64, numComps > expectedVapourComposition; + TestFluid< numComps >::createArray( expectedLiquidComposition, std::get< 5 >( data )); + TestFluid< numComps >::createArray( expectedVapourComposition, std::get< 6 >( data )); + + real64 vapourFraction = -1.0; + stackArray1d< real64, numComps > liquidComposition( numComps ); + stackArray1d< real64, numComps > vapourComposition( numComps ); + stackArray2d< real64, numComps > kValues( 1, numComps ); + kValues.zero(); + + bool status = NegativeTwoPhaseFlash::compute( + numComps, + pressure, + temperature, + composition.toSliceConst(), + componentProperties, + EOS_TYPE, + EOS_TYPE, + kValues.toSlice(), + vapourFraction, + liquidComposition.toSlice(), + vapourComposition.toSlice() ); + + // Check the flash success result + ASSERT_EQ( expectedStatus, status ); + + if( !expectedStatus ) + { + return; + } + + // Check the vaopur fraction + checkRelativeError( expectedVapourFraction, vapourFraction, relTol, absTol ); + + // Check liquid composition + if( expectedVapourFraction < 1.0 - absTol ) + { + checkRelativeError( expectedLiquidComposition[0], liquidComposition[comp0], relTol, absTol ); + checkRelativeError( expectedLiquidComposition[1], liquidComposition[comp1], relTol, absTol ); + } + + // Check vapour composition + if( absTol < expectedVapourFraction ) + { + checkRelativeError( expectedVapourComposition[0], vapourComposition[comp0], relTol, absTol ); + checkRelativeError( expectedVapourComposition[1], vapourComposition[comp1], relTol, absTol ); + } + } + + void testFlashDerivatives( FlashData const & data ) + { + // Number of output values from each flash calculation + constexpr integer numValues = 1 + 2*numComps; + + auto componentProperties = this->m_fluid->createKernelWrapper(); + + bool const expectedStatus = std::get< 3 >( data ); + if( !expectedStatus ) return; + + real64 const pressure = std::get< 0 >( data ); + real64 const temperature = std::get< 1 >( data ); + stackArray1d< real64, numComps > composition; + TestFluid< numComps >::createArray( composition, std::get< 2 >( data )); + + real64 vapourFraction = -1.0; + stackArray1d< real64, numComps > liquidComposition( numComps ); + stackArray1d< real64, numComps > vapourComposition( numComps ); + stackArray2d< real64, numComps > kValues( 1, numComps ); + kValues.zero(); + + stackArray1d< real64, numDofs > vapourFractionDerivs( numDofs ); + stackArray2d< real64, numComps * numDofs > liquidCompositionDerivs( numComps, numDofs ); + stackArray2d< real64, numComps * numDofs > vapourCompositionDerivs( numComps, numDofs ); + stackArray1d< real64, numValues > derivatives( numValues ); + + // Combine values and derivatives into a single output + auto const concatDerivatives = []( integer const kc, auto & derivs, auto const & v, auto const & xmf, auto const & ymf ){ + derivs[0] = v[kc]; + for( integer ic = 0; ic < numComps; ++ic ) + { + derivs[1+ic] = xmf( ic, kc ); + derivs[1+ic+numComps] = ymf( ic, kc ); + } + }; + + auto const evaluateFlash = [&]( real64 const p, real64 const t, auto const & zmf, auto & values ){ + stackArray1d< real64, numComps > displacedLiquidComposition( numComps ); + stackArray1d< real64, numComps > displacedVapourComposition( numComps ); + + NegativeTwoPhaseFlash::compute( + numComps, + p, + t, + zmf.toSliceConst(), + componentProperties, + EOS_TYPE, + EOS_TYPE, + kValues.toSlice(), + values[0], + displacedLiquidComposition.toSlice(), + displacedVapourComposition.toSlice() ); + for( integer ic = 0; ic < numComps; ++ic ) + { + values[1+ic] = displacedLiquidComposition[ic]; + values[1+ic+numComps] = displacedVapourComposition[ic]; + } + }; + + NegativeTwoPhaseFlash::compute( + numComps, + pressure, + temperature, + composition.toSliceConst(), + componentProperties, + EOS_TYPE, + EOS_TYPE, + kValues.toSlice(), + vapourFraction, + liquidComposition.toSlice(), + vapourComposition.toSlice() ); + + NegativeTwoPhaseFlash::computeDerivatives( + numComps, + pressure, + temperature, + composition.toSliceConst(), + componentProperties, + EOS_TYPE, + EOS_TYPE, + vapourFraction, + liquidComposition.toSliceConst(), + vapourComposition.toSliceConst(), + vapourFractionDerivs.toSlice(), + liquidCompositionDerivs.toSlice(), + vapourCompositionDerivs.toSlice() ); + + // Test against numerically calculated values + // --- Pressure derivatives --- + concatDerivatives( Deriv::dP, derivatives, vapourFractionDerivs, liquidCompositionDerivs, vapourCompositionDerivs ); + real64 const dp = 1.0e-4 * pressure; + geos::testing::internal::testNumericalDerivative< numValues >( + pressure, dp, derivatives, + [&]( real64 const p, auto & values ) { + evaluateFlash( p, temperature, composition, values ); + } ); + + // --- Temperature derivatives --- + concatDerivatives( Deriv::dT, derivatives, vapourFractionDerivs, liquidCompositionDerivs, vapourCompositionDerivs ); + real64 const dT = 1.0e-6 * temperature; + geos::testing::internal::testNumericalDerivative< numValues >( + temperature, dT, derivatives, + [&]( real64 const t, auto & values ) { + evaluateFlash( pressure, t, composition, values ); + } ); + + // --- Composition derivatives --- + real64 constexpr dz = 1.0e-7; + for( integer jc = 0; jc < numComps; ++jc ) + { + if( composition[jc] < 1.0e-6 ) continue; + integer const kc = Deriv::dC + jc; + concatDerivatives( kc, derivatives, vapourFractionDerivs, liquidCompositionDerivs, vapourCompositionDerivs ); + geos::testing::internal::testNumericalDerivative< numValues >( + 0.0, dz, derivatives, + [&]( real64 const z, auto & values ) { + real64 const originalFraction = composition[jc]; + composition[jc] += z; + evaluateFlash( pressure, temperature, composition, values ); + composition[jc] = originalFraction; + }, 10*relTol, 10*absTol ); + } + } + +protected: + std::unique_ptr< TestFluid< numComps > > m_fluid{}; +private: + static std::unique_ptr< TestFluid< numComps > > createFluid(); +}; + +template< EquationOfStateType EOS_TYPE > +std::unique_ptr< TestFluid< numComps > > NegativeTwoPhaseFlashTest9CompFixture< EOS_TYPE >::createFluid() +{ + std::unique_ptr< TestFluid< numComps > > fluid = TestFluid< numComps >::create( {0, 0, 0, 0, 0, 0, 0, 0, 0} ); + // Manually populate + TestFluid< numComps >::populateArray( fluid->criticalPressure, Feed< 9 >{73.8659e5, 33.9439e5, 46.0421e5, 48.8387e5, 42.4552e5, 37.47e5, 33.5892e5, 30.1037e5, 20.549e5} ); + TestFluid< numComps >::populateArray( fluid->criticalTemperature, Feed< 9 >{304.7, 126.2, 190.6, 305.43, 369.8, 419.5, 465.9, 507.5, 678.8} ); + TestFluid< numComps >::populateArray( fluid->criticalVolume, Feed< 9 >{9.3999e-05, 9.0001e-05, 9.7999e-05, 1.4800e-04, 2.0000e-04, 2.5800e-04, 3.1000e-04, 3.5100e-04, 6.8243e-04} ); + TestFluid< numComps >::populateArray( fluid->acentricFactor, Feed< 9 >{0.225, 0.04, 0.013, 0.0986, 0.1524, 0.1956, 0.2413, 0.299, 0.5618} ); + TestFluid< numComps >::populateArray( fluid->molecularWeight, Feed< 9 >{44.01e-3, 28.01e-3, 16.04e-3, 30.07e-3, 44.1e-3, 58.12e-3, 72.15e-3, 84e-3, 173e-3} ); + TestFluid< numComps >::populateArray( fluid->volumeShift, Feed< 9 >{ -0.04958, -0.136012, -0.1486264, -0.10863408, -0.08349872, -0.06331568, -0.04196464, -0.0150072, 0.0000 } ); + fluid->setBinaryCoefficients( Feed< 36 >{ + 1.0000e-02, + 0.0000e+00, 3.7320e-03, + 0.0000e+00, 1.0000e-02, 0.0000e+00, + 0.0000e+00, 1.0000e-02, 0.0000e+00, 0.0000e+00, + 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, + 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, + 1.0000e-02, 0.0000e+00, 2.8000e-02, 1.0000e-02, 1.0000e-02, 0.0000e+00, 0.0000e+00, + 1.0000e-02, 0.0000e+00, 4.5320e-02, 1.0000e-02, 1.0000e-02, 0.0000e+00, 0.0000e+00, 0.0000e+00 + } ); + return fluid; +} + +using PengRobinson = NegativeTwoPhaseFlashTest9CompFixture< EquationOfStateType::PengRobinson >; +using SoaveRedlichKwong = NegativeTwoPhaseFlashTest9CompFixture< EquationOfStateType::SoaveRedlichKwong >; + +TEST_P( PengRobinson, testNegativeFlash ) +{ + testFlash( GetParam() ); +} + +TEST_P( PengRobinson, testNegativeFlashDerivatives ) +{ + testFlashDerivatives( GetParam() ); +} + +TEST_P( SoaveRedlichKwong, testNegativeFlash ) +{ + testFlash( GetParam() ); +} + +TEST_P( SoaveRedlichKwong, testNegativeFlashDerivatives ) +{ + testFlashDerivatives( GetParam() ); +} + +//------------------------------------------------------------------------------- +// Data +//------------------------------------------------------------------------------- + +/* UNCRUSTIFY-OFF */ + +INSTANTIATE_TEST_SUITE_P( + NegativeTwoPhaseFlash, PengRobinson, + ::testing::Values( + FlashData( 1.000000e+05, 2.781500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+05, 2.781500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.798353, {0.000363, 0.839010}, {0.011181, 0.000020} ), + FlashData( 1.000000e+05, 2.781500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998685, {0.000228, 0.938644}, {0.007035, 0.000022} ), + FlashData( 1.013250e+05, 2.781500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.013250e+05, 2.781500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.798070, {0.000368, 0.837836}, {0.011184, 0.000020} ), + FlashData( 1.013250e+05, 2.781500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998684, {0.000231, 0.937856}, {0.007035, 0.000022} ), + FlashData( 1.000000e+06, 2.781500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+06, 2.781500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.700780, {0.003486, 0.565464}, {0.011355, 0.000003} ), + FlashData( 1.000000e+06, 2.781500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.997643, {0.002159, 0.531971}, {0.007037, 0.000002} ), + FlashData( 1.000000e+07, 2.781500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+07, 2.781500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.349114, {0.010010, 0.259905}, {0.007116, 0.000090} ), + FlashData( 1.000000e+07, 2.781500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.991703, {0.009755, 0.140969}, {0.007003, 0.000087} ), + FlashData( 1.500000e+07, 2.781500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.500000e+07, 2.781500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.176058, {0.009422, 0.205086}, {0.007026, 0.001256} ), + FlashData( 1.500000e+07, 2.781500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.009422, 0.205089}, {0.007026, 0.001256} ), + FlashData( 5.000000e+07, 2.781500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+08, 2.781500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.000000e+05, 2.886500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.001168, {0.000348, 0.839991}, {0.013059, 0.000053} ), + FlashData( 1.000000e+05, 2.886500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.805671, {0.000295, 0.870461}, {0.011100, 0.000055} ), + FlashData( 1.000000e+05, 2.886500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998750, {0.000187, 0.957531}, {0.007035, 0.000059} ), + FlashData( 1.013250e+05, 2.886500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.001057, {0.000350, 0.839898}, {0.012947, 0.000052} ), + FlashData( 1.013250e+05, 2.886500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.805431, {0.000299, 0.869390}, {0.011102, 0.000054} ), + FlashData( 1.013250e+05, 2.886500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998749, {0.000189, 0.956982}, {0.007035, 0.000058} ), + FlashData( 1.000000e+06, 2.886500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+06, 2.886500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.719045, {0.002880, 0.602213}, {0.011391, 0.000007} ), + FlashData( 1.000000e+06, 2.886500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998097, {0.001770, 0.656139}, {0.007036, 0.000007} ), + FlashData( 1.000000e+07, 2.886500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+07, 2.886500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.391974, {0.009806, 0.278198}, {0.007750, 0.000123} ), + FlashData( 1.000000e+07, 2.886500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.994318, {0.008887, 0.201207}, {0.007015, 0.000113} ), + FlashData( 1.500000e+07, 2.886500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.500000e+07, 2.886500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.231493, {0.009474, 0.219807}, {0.007427, 0.001195} ), + FlashData( 1.500000e+07, 2.886500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.999406, {0.009004, 0.228228}, {0.007025, 0.001121} ), + FlashData( 5.000000e+07, 2.886500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+05, 2.981500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.002535, {0.000327, 0.841142}, {0.014448, 0.000119} ), + FlashData( 1.000000e+05, 2.981500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.811028, {0.000249, 0.894832}, {0.011039, 0.000125} ), + FlashData( 1.000000e+05, 2.981500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998841, {0.000158, 0.968326}, {0.007034, 0.000134} ), + FlashData( 1.013250e+05, 2.981500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.002401, {0.000329, 0.841029}, {0.014353, 0.000118} ), + FlashData( 1.013250e+05, 2.981500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.810823, {0.000253, 0.893869}, {0.011041, 0.000124} ), + FlashData( 1.013250e+05, 2.981500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998839, {0.000161, 0.967914}, {0.007034, 0.000132} ), + FlashData( 1.000000e+06, 2.981500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+06, 2.981500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.733594, {0.002451, 0.635078}, {0.011378, 0.000016} ), + FlashData( 1.000000e+06, 2.981500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998313, {0.001505, 0.734457}, {0.007035, 0.000017} ), + FlashData( 1.000000e+07, 2.981500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+07, 2.981500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.426139, {0.009539, 0.294719}, {0.008274, 0.000169} ), + FlashData( 1.000000e+07, 2.981500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.995698, {0.008127, 0.256601}, {0.007021, 0.000153} ), + FlashData( 1.500000e+07, 2.981500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.500000e+07, 2.981500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.275063, {0.009454, 0.232929}, {0.007803, 0.001242} ), + FlashData( 1.500000e+07, 2.981500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.999403, {0.008577, 0.252667}, {0.007025, 0.001106} ), + FlashData( 5.000000e+07, 2.981500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+05, 3.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.009514, {0.000227, 0.847062}, {0.014475, 0.000776} ), + FlashData( 1.000000e+05, 3.231500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.820830, {0.000171, 0.940506}, {0.010927, 0.000840} ), + FlashData( 1.000000e+05, 3.231500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.999605, {0.000110, 0.982954}, {0.007029, 0.000869} ), + FlashData( 1.013250e+05, 3.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.009213, {0.000231, 0.846804}, {0.014528, 0.000766} ), + FlashData( 1.013250e+05, 3.231500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.820694, {0.000173, 0.939845}, {0.010929, 0.000829} ), + FlashData( 1.013250e+05, 3.231500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.999594, {0.000111, 0.982731}, {0.007029, 0.000858} ), + FlashData( 1.000000e+06, 3.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+06, 3.231500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.763803, {0.001692, 0.716010}, {0.011260, 0.000105} ), + FlashData( 1.000000e+06, 3.231500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998655, {0.001048, 0.848573}, {0.007034, 0.000115} ), + FlashData( 1.000000e+07, 3.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+07, 3.231500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.500392, {0.008630, 0.338259}, {0.009369, 0.000406} ), + FlashData( 1.000000e+07, 3.231500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.997667, {0.006476, 0.384497}, {0.007027, 0.000360} ), + FlashData( 1.500000e+07, 3.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.500000e+07, 3.231500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.367748, {0.009160, 0.266615}, {0.008725, 0.001720} ), + FlashData( 1.500000e+07, 3.231500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 5.000000e+07, 3.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+05, 3.531500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.031155, {0.000097, 0.865831}, {0.008647, 0.004929} ), + FlashData( 1.000000e+05, 3.531500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.829852, {0.000120, 0.968392}, {0.010821, 0.005338} ), + FlashData( 1.000000e+05, 3.531500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.013250e+05, 3.531500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.030488, {0.000099, 0.865241}, {0.008755, 0.004866} ), + FlashData( 1.013250e+05, 3.531500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.829724, {0.000121, 0.968002}, {0.010822, 0.005269} ), + FlashData( 1.013250e+05, 3.531500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.000000e+06, 3.531500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+06, 3.531500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.787992, {0.001191, 0.795638}, {0.011101, 0.000658} ), + FlashData( 1.000000e+06, 3.531500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.999382, {0.000748, 0.906103}, {0.007030, 0.000696} ), + FlashData( 1.000000e+07, 3.531500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+07, 3.531500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.567463, {0.007479, 0.389712}, {0.010159, 0.001120} ), + FlashData( 1.000000e+07, 3.531500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.999429, {0.005131, 0.493383}, {0.007027, 0.000975} ), + FlashData( 1.500000e+07, 3.531500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.500000e+07, 3.531500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.449715, {0.008545, 0.304966}, {0.009556, 0.003072} ), + FlashData( 1.500000e+07, 3.531500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.000000e+05, 3.731500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.053370, {0.000054, 0.885524}, {0.005836, 0.013991} ), + FlashData( 1.000000e+05, 3.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.839835, {0.000099, 0.977972}, {0.010698, 0.014959} ), + FlashData( 1.000000e+05, 3.731500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.013250e+05, 3.731500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.052543, {0.000056, 0.884773}, {0.005903, 0.013808} ), + FlashData( 1.013250e+05, 3.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.839621, {0.000100, 0.977689}, {0.010700, 0.014767} ), + FlashData( 1.013250e+05, 3.731500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.000000e+06, 3.731500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+06, 3.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.799362, {0.000988, 0.836026}, {0.011011, 0.001828} ), + FlashData( 1.000000e+06, 3.731500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.000000e+07, 3.731500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+07, 3.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.602229, {0.006805, 0.422215}, {0.010450, 0.002084} ), + FlashData( 1.000000e+07, 3.731500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.500000e+07, 3.731500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.500000e+07, 3.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.492074, {0.008098, 0.328602}, {0.009931, 0.004663} ), + FlashData( 1.500000e+07, 3.731500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.000000e+05, 3.931500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.078426, {0.000034, 0.907428}, {0.004230, 0.035040} ), + FlashData( 1.000000e+05, 3.931500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.860286, {0.000083, 0.983960}, {0.010448, 0.036880} ), + FlashData( 1.000000e+05, 3.931500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.013250e+05, 3.931500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.077531, {0.000035, 0.906620}, {0.004269, 0.034580} ), + FlashData( 1.013250e+05, 3.931500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.859825, {0.000084, 0.983745}, {0.010454, 0.036407} ), + FlashData( 1.000000e+06, 3.931500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+06, 3.931500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.808966, {0.000846, 0.866838}, {0.010926, 0.004456} ), + FlashData( 1.000000e+07, 3.931500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.630979, {0.006236, 0.452193}, {0.010617, 0.003695} ), + FlashData( 1.500000e+07, 3.931500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.527277, {0.007678, 0.350047}, {0.010185, 0.007065} ), + FlashData( 1.500000e+07, 3.931500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 5.000000e+07, 3.931500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.013250e+05, 5.231500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.000000e+06, 5.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.013401, {0.000295, 0.847670}, {0.005333, 0.201455} ), + FlashData( 1.000000e+06, 5.231500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 1.000000, {0.009000, 0.169200}, {0.009000, 0.169200} ), + FlashData( 1.000000e+07, 5.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+07, 5.231500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.783614, {0.004654, 0.554668}, {0.010200, 0.062757} ), + FlashData( 1.500000e+07, 5.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.500000e+07, 5.231500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.717160, {0.006496, 0.400841}, {0.009988, 0.077843} ), + FlashData( 1.013250e+05, 5.731500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.000000e+06, 5.731500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.166124, {0.000103, 0.906268}, {0.001666, 0.501402} ), + FlashData( 1.000000e+07, 5.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.947056, {0.004797, 0.541766}, {0.009235, 0.148372} ), + FlashData( 8.000000e+07, 8.731500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 8.000000e+07, 8.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 1.000000, {0.009000, 0.169200}, {0.009000, 0.169200} ), + FlashData( 8.000000e+07, 8.731500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.000000e+08, 8.731500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+08, 8.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 1.000000, {0.009000, 0.169200}, {0.009000, 0.169200} ), + FlashData( 1.000000e+08, 8.731500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ) + ) + ); + +INSTANTIATE_TEST_SUITE_P( + NegativeTwoPhaseFlash, SoaveRedlichKwong, + ::testing::Values( + FlashData( 1.000000e+05, 2.781500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000197, {0.000361, 0.839175}, {0.010852, 0.000016} ), + FlashData( 1.000000e+05, 2.781500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.798097, {0.000372, 0.837963}, {0.011183, 0.000016} ), + FlashData( 1.000000e+05, 2.781500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998678, {0.000233, 0.937435}, {0.007035, 0.000017} ), + FlashData( 1.013250e+05, 2.781500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000102, {0.000362, 0.839096}, {0.010741, 0.000015} ), + FlashData( 1.013250e+05, 2.781500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.797815, {0.000377, 0.836797}, {0.011185, 0.000015} ), + FlashData( 1.013250e+05, 2.781500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998677, {0.000236, 0.936631}, {0.007035, 0.000017} ), + FlashData( 1.000000e+06, 2.781500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+06, 2.781500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.701296, {0.003551, 0.566442}, {0.011321, 0.000002} ), + FlashData( 1.000000e+06, 2.781500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.997601, {0.002208, 0.522879}, {0.007038, 0.000002} ), + FlashData( 1.000000e+07, 2.781500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+07, 2.781500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.355337, {0.010126, 0.262428}, {0.006957, 0.000064} ), + FlashData( 1.000000e+07, 2.781500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.990607, {0.010007, 0.127315}, {0.006998, 0.000061} ), + FlashData( 1.500000e+07, 2.781500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.500000e+07, 2.781500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.189968, {0.009500, 0.208646}, {0.006869, 0.001001} ), + FlashData( 1.500000e+07, 2.781500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998881, {0.009683, 0.203759}, {0.007023, 0.001029} ), + FlashData( 1.000000e+05, 2.886500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.001347, {0.000346, 0.840142}, {0.012715, 0.000042} ), + FlashData( 1.000000e+05, 2.886500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.805502, {0.000302, 0.869750}, {0.011100, 0.000044} ), + FlashData( 1.000000e+05, 2.886500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998737, {0.000191, 0.957109}, {0.007035, 0.000047} ), + FlashData( 1.013250e+05, 2.886500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.001238, {0.000348, 0.840050}, {0.012604, 0.000042} ), + FlashData( 1.013250e+05, 2.886500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.805263, {0.000306, 0.868685}, {0.011102, 0.000043} ), + FlashData( 1.013250e+05, 2.886500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998736, {0.000193, 0.956554}, {0.007035, 0.000047} ), + FlashData( 1.000000e+06, 2.886500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+06, 2.886500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.719517, {0.002933, 0.603231}, {0.011365, 0.000006} ), + FlashData( 1.000000e+06, 2.886500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998081, {0.001810, 0.651470}, {0.007036, 0.000006} ), + FlashData( 1.000000e+07, 2.886500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+07, 2.886500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.396003, {0.009922, 0.280076}, {0.007594, 0.000088} ), + FlashData( 1.000000e+07, 2.886500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.993728, {0.009141, 0.187545}, {0.007013, 0.000080} ), + FlashData( 1.500000e+07, 2.886500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.500000e+07, 2.886500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.240606, {0.009550, 0.222512}, {0.007264, 0.000938} ), + FlashData( 1.500000e+07, 2.886500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998414, {0.009259, 0.224729}, {0.007022, 0.000901} ), + FlashData( 5.000000e+07, 2.886500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+05, 2.981500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.002711, {0.000326, 0.841291}, {0.014087, 0.000098} ), + FlashData( 1.000000e+05, 2.981500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.810920, {0.000255, 0.894421}, {0.011039, 0.000103} ), + FlashData( 1.000000e+05, 2.981500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998816, {0.000162, 0.968232}, {0.007034, 0.000110} ), + FlashData( 1.013250e+05, 2.981500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.002578, {0.000328, 0.841178}, {0.013993, 0.000096} ), + FlashData( 1.013250e+05, 2.981500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.810716, {0.000258, 0.893460}, {0.011041, 0.000101} ), + FlashData( 1.013250e+05, 2.981500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998814, {0.000164, 0.967820}, {0.007034, 0.000108} ), + FlashData( 1.000000e+06, 2.981500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+06, 2.981500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.734036, {0.002496, 0.636140}, {0.011357, 0.000013} ), + FlashData( 1.000000e+06, 2.981500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998304, {0.001539, 0.732405}, {0.007035, 0.000014} ), + FlashData( 1.000000e+07, 2.981500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+07, 2.981500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.428647, {0.009656, 0.296047}, {0.008126, 0.000123} ), + FlashData( 1.000000e+07, 2.981500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.995306, {0.008367, 0.244161}, {0.007020, 0.000110} ), + FlashData( 1.500000e+07, 2.981500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.500000e+07, 2.981500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.280995, {0.009532, 0.234947}, {0.007638, 0.000967} ), + FlashData( 1.500000e+07, 2.981500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998466, {0.008825, 0.247830}, {0.007023, 0.000877} ), + FlashData( 5.000000e+07, 2.981500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+05, 3.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.009799, {0.000227, 0.847306}, {0.014141, 0.000671} ), + FlashData( 1.000000e+05, 3.231500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.820760, {0.000174, 0.940659}, {0.010927, 0.000727} ), + FlashData( 1.000000e+05, 3.231500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.999486, {0.000112, 0.983094}, {0.007030, 0.000751} ), + FlashData( 1.013250e+05, 3.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.009494, {0.000230, 0.847045}, {0.014191, 0.000663} ), + FlashData( 1.013250e+05, 3.231500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.820626, {0.000176, 0.940001}, {0.010929, 0.000717} ), + FlashData( 1.013250e+05, 3.231500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.999476, {0.000113, 0.982873}, {0.007030, 0.000741} ), + FlashData( 1.000000e+06, 3.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+06, 3.231500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.764168, {0.001724, 0.717170}, {0.011245, 0.000089} ), + FlashData( 1.000000e+06, 3.231500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.998636, {0.001071, 0.849075}, {0.007034, 0.000098} ), + FlashData( 1.000000e+07, 3.231500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.500247, {0.008751, 0.338258}, {0.009248, 0.000309} ), + FlashData( 1.000000e+07, 3.231500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.997385, {0.006666, 0.376212}, {0.007027, 0.000273} ), + FlashData( 1.500000e+07, 3.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.500000e+07, 3.231500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.368341, {0.009249, 0.267083}, {0.008574, 0.001342} ), + FlashData( 1.500000e+07, 3.231500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.999515, {0.007646, 0.315975}, {0.007026, 0.001103} ), + FlashData( 1.000000e+05, 3.531500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.031804, {0.000097, 0.866423}, {0.008470, 0.004481} ), + FlashData( 1.000000e+05, 3.531500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.829483, {0.000122, 0.968691}, {0.010825, 0.004849} ), + FlashData( 1.000000e+05, 3.531500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.013250e+05, 3.531500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.031134, {0.000099, 0.865829}, {0.008574, 0.004423} ), + FlashData( 1.013250e+05, 3.531500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.829361, {0.000124, 0.968304}, {0.010826, 0.004786} ), + FlashData( 1.013250e+05, 3.531500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.000000e+06, 3.531500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+06, 3.531500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.788230, {0.001216, 0.796793}, {0.011091, 0.000588} ), + FlashData( 1.000000e+06, 3.531500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.999299, {0.000766, 0.906819}, {0.007030, 0.000621} ), + FlashData( 1.000000e+07, 3.531500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+07, 3.531500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.565606, {0.007602, 0.388344}, {0.010074, 0.000894} ), + FlashData( 1.000000e+07, 3.531500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 0.999017, {0.005276, 0.488289}, {0.007028, 0.000777} ), + FlashData( 1.500000e+07, 3.531500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.500000e+07, 3.531500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.446859, {0.008647, 0.303916}, {0.009437, 0.002442} ), + FlashData( 1.500000e+07, 3.531500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.000000e+05, 3.731500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.054177, {0.000055, 0.886321}, {0.005743, 0.013044} ), + FlashData( 1.000000e+05, 3.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.838983, {0.000101, 0.978218}, {0.010708, 0.013933} ), + FlashData( 1.000000e+05, 3.731500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.013250e+05, 3.731500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.053352, {0.000056, 0.885570}, {0.005808, 0.012873} ), + FlashData( 1.013250e+05, 3.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.838780, {0.000102, 0.977938}, {0.010710, 0.013754} ), + FlashData( 1.000000e+06, 3.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.799463, {0.001011, 0.837056}, {0.011004, 0.001676} ), + FlashData( 1.000000e+07, 3.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.599654, {0.006926, 0.420077}, {0.010385, 0.001707} ), + FlashData( 1.500000e+07, 3.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.487747, {0.008205, 0.326722}, {0.009835, 0.003763} ), + FlashData( 1.000000e+05, 3.931500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.079189, {0.000034, 0.908297}, {0.004184, 0.033343} ), + FlashData( 1.000000e+05, 3.931500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.858658, {0.000085, 0.984127}, {0.010467, 0.035057} ), + FlashData( 1.013250e+05, 3.931500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.078302, {0.000035, 0.907492}, {0.004221, 0.032904} ), + FlashData( 1.013250e+05, 3.931500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.858220, {0.000086, 0.983915}, {0.010473, 0.034607} ), + FlashData( 1.013250e+05, 3.931500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ), + FlashData( 1.000000e+06, 3.931500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+06, 3.931500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.808878, {0.000868, 0.867643}, {0.010922, 0.004171} ), + FlashData( 1.000000e+07, 3.931500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.627809, {0.006355, 0.449384}, {0.010568, 0.003096} ), + FlashData( 1.500000e+07, 3.931500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.521757, {0.007786, 0.347485}, {0.010113, 0.005784} ), + FlashData( 1.000000e+06, 5.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.013083, {0.000299, 0.847460}, {0.005181, 0.201586} ), + FlashData( 1.000000e+07, 5.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+07, 5.231500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.771605, {0.004757, 0.549320}, {0.010256, 0.056684} ), + FlashData( 1.500000e+07, 5.231500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.500000e+07, 5.231500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.692342, {0.006548, 0.399534}, {0.010089, 0.066846} ), + FlashData( 1.000000e+06, 5.731500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.168528, {0.000106, 0.906625}, {0.001631, 0.505413} ), + FlashData( 1.000000e+07, 5.731500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+07, 5.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.914262, {0.004869, 0.538035}, {0.009387, 0.134611} ), + FlashData( 1.500000e+07, 5.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 0.986509, {0.007097, 0.343039}, {0.009026, 0.166823} ), + FlashData( 1.000000e+08, 8.731500e+02, {0.000363, 0.000007, 0.003471, 0.006007, 0.018423, 0.034034, 0.042565, 0.056120, 0.839010}, 1, 0.000000, {0.000363, 0.839010}, {0.000363, 0.839010} ), + FlashData( 1.000000e+08, 8.731500e+02, {0.009000, 0.003000, 0.534700, 0.114600, 0.087900, 0.045600, 0.020900, 0.015100, 0.169200}, 1, 1.000000, {0.009000, 0.169200}, {0.009000, 0.169200} ), + FlashData( 1.000000e+08, 8.731500e+02, {0.007026, 0.006161, 0.827761, 0.091046, 0.045353, 0.015026, 0.004474, 0.001898, 0.001256}, 1, 1.000000, {0.007026, 0.001256}, {0.007026, 0.001256} ) + ) + ); + +/* UNCRUSTIFY-ON */ + +} // testing + +} // geos diff --git a/src/coreComponents/constitutive/unitTests/testParticleFluidEnums.cpp b/src/coreComponents/constitutive/unitTests/testParticleFluidEnums.cpp index 629646c45e0..bd9dd97d83c 100644 --- a/src/coreComponents/constitutive/unitTests/testParticleFluidEnums.cpp +++ b/src/coreComponents/constitutive/unitTests/testParticleFluidEnums.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2020- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/constitutive/unitTests/testPropertyConversions.cpp b/src/coreComponents/constitutive/unitTests/testPropertyConversions.cpp index 1f5447e66f3..4c21a7759b4 100644 --- a/src/coreComponents/constitutive/unitTests/testPropertyConversions.cpp +++ b/src/coreComponents/constitutive/unitTests/testPropertyConversions.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/constitutive/unitTests/testRachfordRice.cpp b/src/coreComponents/constitutive/unitTests/testRachfordRice.cpp index 0b7f3230735..a8ce4fc2f1a 100644 --- a/src/coreComponents/constitutive/unitTests/testRachfordRice.cpp +++ b/src/coreComponents/constitutive/unitTests/testRachfordRice.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/constitutive/unitTests/testStabilityTest2Comp.cpp b/src/coreComponents/constitutive/unitTests/testStabilityTest2Comp.cpp new file mode 100644 index 00000000000..b967f9ba83d --- /dev/null +++ b/src/coreComponents/constitutive/unitTests/testStabilityTest2Comp.cpp @@ -0,0 +1,144 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// Source includes +#include "codingUtilities/UnitTestUtilities.hpp" +#include "constitutive/fluid/multifluid/MultiFluidConstants.hpp" +#include "constitutive/fluid/multifluid/compositional/functions/StabilityTest.hpp" +#include "constitutive/fluid/multifluid/compositional/functions/NegativeTwoPhaseFlash.hpp" +#include "constitutive/fluid/multifluid/compositional/functions/CubicEOSPhaseModel.hpp" +#include "TestFluid.hpp" +#include "TestFluidUtilities.hpp" + +using namespace geos::constitutive; +using namespace geos::constitutive::compositional; + +namespace geos +{ +namespace testing +{ + +static constexpr integer numComps = 2; + +using StabilityData = std::tuple< + real64 const, // pressure + real64 const, // temperature + real64 const, // CH4 mole fraction + real64 const // expected tangent plane distance + >; + +template< EquationOfStateType EOS_TYPE > +class StabilityTestTest2CompFixture : public ::testing::TestWithParam< StabilityData > +{ + static constexpr real64 relTol = 1.0e-5; + static constexpr real64 absTol = 1.0e-7; + +public: + StabilityTestTest2CompFixture() + : m_fluid( createFluid() ) + {} + + ~StabilityTestTest2CompFixture() = default; + + void testStability( StabilityData const & data ) + { + auto componentProperties = this->m_fluid->createKernelWrapper(); + + real64 const pressure = std::get< 0 >( data ); + real64 const temperature = std::get< 1 >( data ); + real64 const zCH4 = std::get< 2 >( data ); + real64 const expectedTangentPlaneDistance = std::get< 3 >( data ); + + stackArray1d< real64, numComps > composition( numComps ); + composition[0] = zCH4; + composition[1] = 1.0 - zCH4; + + real64 tangentPlaneDistance = LvArray::NumericLimits< real64 >::max; + stackArray1d< real64, numComps > kValues( numComps ); + + bool const stabilityStatus = StabilityTest::compute( numComps, + pressure, + temperature, + composition.toSliceConst(), + componentProperties, + EOS_TYPE, + tangentPlaneDistance, + kValues.toSlice() ); + + // Expect this to succeed + ASSERT_EQ( stabilityStatus, true ); + + // Check the tanget plane distance + checkRelativeError( expectedTangentPlaneDistance, tangentPlaneDistance, relTol, absTol ); + } + +protected: + std::unique_ptr< TestFluid< numComps > > m_fluid{}; + +private: + static std::unique_ptr< TestFluid< numComps > > createFluid() + { + std::unique_ptr< TestFluid< numComps > > fluid = TestFluid< numComps >::create( {Fluid::C1, Fluid::C3} ); + fluid->setBinaryCoefficients( Feed< 1 >{ 0.1 } ); + return fluid; + } +}; + +using PengRobinson = StabilityTestTest2CompFixture< EquationOfStateType::PengRobinson >; +using SoaveRedlichKwong = StabilityTestTest2CompFixture< EquationOfStateType::SoaveRedlichKwong >; +TEST_P( PengRobinson, testStabilityTest ) +{ + testStability( GetParam() ); +} +TEST_P( SoaveRedlichKwong, testStabilityTest ) +{ + testStability( GetParam() ); +} + +//------------------------------------------------------------------------------- +// Data +//------------------------------------------------------------------------------- + +/* UNCRUSTIFY-OFF */ + +INSTANTIATE_TEST_SUITE_P( + StabilityTest, PengRobinson, + ::testing::Values( + StabilityData{ 1.00000e+06, 297.15, 0.2, 1.1102230e-16 }, + StabilityData{ 1.00000e+06, 353.15, 0.2, -2.2204460e-16 }, + StabilityData{ 5.00000e+06, 297.15, 0.2, -1.0160710e+00 }, + StabilityData{ 5.00000e+06, 353.15, 0.2, -1.4627298e-03 }, + StabilityData{ 2.00000e+07, 297.15, 0.2, -3.3306691e-16 }, + StabilityData{ 2.00000e+07, 353.15, 0.2, -6.6613381e-16 } + ) +); + +INSTANTIATE_TEST_SUITE_P( + StabilityTest, SoaveRedlichKwong, + ::testing::Values( + StabilityData{ 1.00000e+06, 297.15, 0.2, -2.2204460e-16 }, + StabilityData{ 1.00000e+06, 353.15, 0.2, -3.3306691e-16 }, + StabilityData{ 5.00000e+06, 297.15, 0.2, -1.0780446e+00 }, + StabilityData{ 5.00000e+06, 353.15, 0.2, -3.1421339e-03 }, + StabilityData{ 2.00000e+07, 297.15, 0.2, -2.4424907e-15 }, + StabilityData{ 2.00000e+07, 353.15, 0.2, -7.7715612e-16 } + ) +); + +/* UNCRUSTIFY-ON */ + +} // testing + +} // geos diff --git a/src/coreComponents/constitutive/unitTests/testStabilityTest9Comp.cpp b/src/coreComponents/constitutive/unitTests/testStabilityTest9Comp.cpp new file mode 100644 index 00000000000..c3c8a479ae2 --- /dev/null +++ b/src/coreComponents/constitutive/unitTests/testStabilityTest9Comp.cpp @@ -0,0 +1,635 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// Source includes +#include "codingUtilities/UnitTestUtilities.hpp" +#include "constitutive/fluid/multifluid/MultiFluidConstants.hpp" +#include "constitutive/fluid/multifluid/compositional/functions/StabilityTest.hpp" +#include "constitutive/fluid/multifluid/compositional/functions/NegativeTwoPhaseFlash.hpp" +#include "TestFluid.hpp" +#include "TestFluidUtilities.hpp" + +using namespace geos::constitutive; +using namespace geos::constitutive::compositional; + +namespace geos +{ +namespace testing +{ + +static constexpr integer numComps = 9; + +using FlashData = std::tuple< + real64 const, // pressure + real64 const, // temperature + Feed< numComps > const, // total composition + real64 const // expected tangent plane distance + >; + +template< EquationOfStateType EOS_TYPE > +class StabilityTestTest9CompFixture : public ::testing::TestWithParam< FlashData > +{ + static constexpr real64 relTol = 1.0e-5; + static constexpr real64 absTol = 1.0e-7; + static constexpr real64 tpdTol = MultiFluidConstants::fugacityTolerance; +public: + StabilityTestTest9CompFixture() + : m_fluid( createFluid() ) + {} + + ~StabilityTestTest9CompFixture() = default; + + void testStability( FlashData const & data ) + { + auto componentProperties = this->m_fluid->createKernelWrapper(); + + real64 const pressure = std::get< 0 >( data ); + real64 const temperature = std::get< 1 >( data ); + stackArray1d< real64, numComps > composition; + TestFluid< numComps >::createArray( composition, std::get< 2 >( data )); + + real64 const expectedTangentPlaneDistance = std::get< 3 >( data ); + + real64 tangentPlaneDistance = LvArray::NumericLimits< real64 >::max; + stackArray1d< real64, numComps > kValues( numComps ); + + bool const stabilityStatus = StabilityTest::compute( numComps, + pressure, + temperature, + composition.toSliceConst(), + componentProperties, + EOS_TYPE, + tangentPlaneDistance, + kValues.toSlice() ); + + // Expect this to succeed + ASSERT_EQ( stabilityStatus, true ); + + // Check the tanget plane distance + checkRelativeError( expectedTangentPlaneDistance, tangentPlaneDistance, relTol, absTol ); + } + + void testFlash( FlashData const & data ) + { + auto componentProperties = this->m_fluid->createKernelWrapper(); + + real64 const pressure = std::get< 0 >( data ); + real64 const temperature = std::get< 1 >( data ); + stackArray1d< real64, numComps > composition; + TestFluid< numComps >::createArray( composition, std::get< 2 >( data )); + + real64 tangentPlaneDistance = LvArray::NumericLimits< real64 >::max; + stackArray2d< real64, numComps > kValues( 1, numComps ); + + StabilityTest::compute( numComps, + pressure, + temperature, + composition.toSliceConst(), + componentProperties, + EOS_TYPE, + tangentPlaneDistance, + kValues[0] ); + + // Now perform the nagative flash + real64 vapourFraction = -1.0; + stackArray1d< real64, numComps > liquidComposition( numComps ); + stackArray1d< real64, numComps > vapourComposition( numComps ); + + bool const status = NegativeTwoPhaseFlash::compute( + numComps, + pressure, + temperature, + composition.toSliceConst(), + componentProperties, + EOS_TYPE, + EOS_TYPE, + kValues.toSlice(), + vapourFraction, + liquidComposition.toSlice(), + vapourComposition.toSlice() ); + + // Expect this to succeed + ASSERT_EQ( status, true ); + + constexpr real64 epsilon = MultiFluidConstants::epsilon; + real64 const V = vapourFraction; + real64 const L = 1.0 - V; + + // Check stability vs flash + if( tangentPlaneDistance < -tpdTol ) + { + // Unstable mixture: both L and V should be positive + ASSERT_GT( V, epsilon ); + ASSERT_GT( L, epsilon ); + } + else + { + // Stable mixture: one of L or V should be zero + ASSERT_TRUE( V < epsilon || L < epsilon ); + } + } + +protected: + std::unique_ptr< TestFluid< numComps > > m_fluid{}; +private: + static std::unique_ptr< TestFluid< numComps > > createFluid(); +}; + +template< EquationOfStateType EOS_TYPE > +std::unique_ptr< TestFluid< numComps > > StabilityTestTest9CompFixture< EOS_TYPE >::createFluid() +{ + std::unique_ptr< TestFluid< numComps > > fluid = TestFluid< numComps >::create( {0, 0, 0, 0, 0, 0, 0, 0, 0} ); + // Manually populate + TestFluid< numComps >::populateArray( fluid->criticalPressure, Feed< 9 >{73.8659e5, 33.9439e5, 46.0421e5, 48.8387e5, 42.4552e5, 37.47e5, 33.5892e5, 30.1037e5, 20.549e5} ); + TestFluid< numComps >::populateArray( fluid->criticalTemperature, Feed< 9 >{304.7, 126.2, 190.6, 305.43, 369.8, 419.5, 465.9, 507.5, 678.8} ); + TestFluid< numComps >::populateArray( fluid->criticalVolume, Feed< 9 >{9.3999e-05, 9.0001e-05, 9.7999e-05, 1.4800e-04, 2.0000e-04, 2.5800e-04, 3.1000e-04, 3.5100e-04, 6.8243e-04} ); + TestFluid< numComps >::populateArray( fluid->acentricFactor, Feed< 9 >{0.225, 0.04, 0.013, 0.0986, 0.1524, 0.1956, 0.2413, 0.299, 0.5618} ); + TestFluid< numComps >::populateArray( fluid->molecularWeight, Feed< 9 >{44.01e-3, 28.01e-3, 16.04e-3, 30.07e-3, 44.1e-3, 58.12e-3, 72.15e-3, 84e-3, 173e-3} ); + TestFluid< numComps >::populateArray( fluid->volumeShift, Feed< 9 >{ -0.04958, -0.136012, -0.1486264, -0.10863408, -0.08349872, -0.06331568, -0.04196464, -0.0150072, 0.0000 } ); + fluid->setBinaryCoefficients( Feed< 36 >{ + 1.0000e-02, + 0.0000e+00, 3.7320e-03, + 0.0000e+00, 1.0000e-02, 0.0000e+00, + 0.0000e+00, 1.0000e-02, 0.0000e+00, 0.0000e+00, + 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, + 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, + 1.0000e-02, 0.0000e+00, 2.8000e-02, 1.0000e-02, 1.0000e-02, 0.0000e+00, 0.0000e+00, + 1.0000e-02, 0.0000e+00, 4.5320e-02, 1.0000e-02, 1.0000e-02, 0.0000e+00, 0.0000e+00, 0.0000e+00 + } ); + return fluid; +} + +using PengRobinson = StabilityTestTest9CompFixture< EquationOfStateType::PengRobinson >; +using SoaveRedlichKwong = StabilityTestTest9CompFixture< EquationOfStateType::SoaveRedlichKwong >; +TEST_P( PengRobinson, testStabilityTest ) +{ + testStability( GetParam() ); +} +TEST_P( SoaveRedlichKwong, testStabilityTest ) +{ + testStability( GetParam() ); +} +TEST_P( PengRobinson, testStabilityWithFlash ) +{ + testFlash( GetParam() ); +} +TEST_P( SoaveRedlichKwong, testStabilityWithFlash ) +{ + testFlash( GetParam() ); +} + +//------------------------------------------------------------------------------- +// Data +//------------------------------------------------------------------------------- + +/* UNCRUSTIFY-OFF */ + +INSTANTIATE_TEST_SUITE_P( + StabilityTest, PengRobinson, + ::testing::Values( + FlashData(1.0e+05, 2.8815e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.654557e+03), + FlashData(1.0e+05, 2.9715e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -8.451746e+02), + FlashData(1.0e+05, 3.5315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.648191e+01), + FlashData(1.0e+05, 3.9315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -3.373702e+00), + FlashData(1.0e+05, 5.7315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.862294e-16), + FlashData(1.0e+06, 2.8815e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -6.805742e-04), + FlashData(1.0e+06, 2.9715e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.731794e-03), + FlashData(1.0e+06, 3.5315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.307138e+02), + FlashData(1.0e+06, 3.9315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.249650e+01), + FlashData(1.0e+06, 5.7315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.695692e-16), + FlashData(5.0e+06, 2.8815e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -7.864345e-06), + FlashData(5.0e+06, 2.9715e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -9.661303e-05), + FlashData(5.0e+06, 3.5315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -7.751816e-02), + FlashData(5.0e+06, 3.9315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.922828e+00), + FlashData(5.0e+06, 5.7315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -3.133069e-03), + FlashData(1.0e+07, 2.8815e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.468194e-01), + FlashData(1.0e+07, 2.9715e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.220020e-01), + FlashData(1.0e+07, 3.5315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -6.940155e-03), + FlashData(1.0e+07, 3.9315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -6.633758e-02), + FlashData(1.0e+07, 5.7315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -9.432557e-03), + FlashData(5.0e+07, 2.8815e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.555613e-15), + FlashData(5.0e+07, 2.9715e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -9.189698e-16), + FlashData(5.0e+07, 3.5315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -5.824334e-16), + FlashData(5.0e+07, 3.9315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -3.014082e-16), + FlashData(5.0e+07, 5.7315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -7.242471e-16), + FlashData(1.0e+08, 2.8815e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.409965e-15), + FlashData(1.0e+08, 2.9715e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.459838e-15), + FlashData(1.0e+08, 3.5315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.031795e-15), + FlashData(1.0e+08, 3.9315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -4.224052e-16), + FlashData(1.0e+08, 5.7315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.127570e-17), + FlashData(1.0e+05, 2.8815e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.654444e+03), + FlashData(1.0e+05, 2.9715e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -8.451167e+02), + FlashData(1.0e+05, 3.5315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.648008e+01), + FlashData(1.0e+05, 3.9315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -3.373450e+00), + FlashData(1.0e+05, 5.7315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.353084e-16), + FlashData(1.0e+06, 2.8815e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -5.937707e-04), + FlashData(1.0e+06, 2.9715e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.529252e-03), + FlashData(1.0e+06, 3.5315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.304552e+02), + FlashData(1.0e+06, 3.9315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.246200e+01), + FlashData(1.0e+06, 5.7315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.498002e-16), + FlashData(5.0e+06, 2.8815e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.584882e-05), + FlashData(5.0e+06, 2.9715e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -5.710689e-05), + FlashData(5.0e+06, 3.5315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -7.513597e-02), + FlashData(5.0e+06, 3.9315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.846606e+00), + FlashData(5.0e+06, 5.7315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.388927e-03), + FlashData(1.0e+07, 2.8815e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.436556e-01), + FlashData(1.0e+07, 2.9715e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.200479e-01), + FlashData(1.0e+07, 3.5315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -6.516862e-03), + FlashData(1.0e+07, 3.9315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -6.407883e-02), + FlashData(1.0e+07, 5.7315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -8.400914e-03), + FlashData(5.0e+07, 2.8815e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -3.453834e-15), + FlashData(5.0e+07, 2.9715e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, 1.543904e-16), + FlashData(5.0e+07, 3.5315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.550044e-16), + FlashData(5.0e+07, 3.9315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.092077e-15), + FlashData(5.0e+07, 5.7315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.786765e-16), + FlashData(1.0e+08, 2.8815e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -4.206704e-15), + FlashData(1.0e+08, 2.9715e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.204834e-15), + FlashData(1.0e+08, 3.5315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, 4.354156e-16), + FlashData(1.0e+08, 3.9315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.236059e-15), + FlashData(1.0e+08, 5.7315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -6.765422e-17), + FlashData(1.0e+05, 2.8815e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+05, 2.9715e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+05, 3.5315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+05, 3.9315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+05, 5.7315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+06, 2.8815e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+06, 2.9715e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+06, 3.5315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+06, 3.9315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+06, 5.7315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+06, 2.8815e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+06, 2.9715e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+06, 3.5315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+06, 3.9315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+06, 5.7315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+07, 2.8815e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+07, 2.9715e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+07, 3.5315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+07, 3.9315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+07, 5.7315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+07, 2.8815e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+07, 2.9715e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+07, 3.5315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+07, 3.9315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+07, 5.7315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+08, 2.8815e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+08, 2.9715e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+08, 3.5315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+08, 3.9315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+08, 5.7315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+05, 2.8815e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+05, 2.9715e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+05, 3.5315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+05, 3.9315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+05, 5.7315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+06, 2.8815e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+06, 2.9715e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+06, 3.5315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+06, 3.9315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+06, 5.7315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+06, 2.8815e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+06, 2.9715e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+06, 3.5315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+06, 3.9315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+06, 5.7315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+07, 2.8815e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+07, 2.9715e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+07, 3.5315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+07, 3.9315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+07, 5.7315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+07, 2.8815e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+07, 2.9715e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+07, 3.5315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+07, 3.9315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+07, 5.7315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+08, 2.8815e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+08, 2.9715e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+08, 3.5315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+08, 3.9315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+08, 5.7315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+05, 2.8815e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -5.551115e-17), + FlashData(1.0e+05, 2.9715e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+05, 3.5315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+05, 3.9315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -5.551115e-17), + FlashData(1.0e+05, 5.7315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -5.551115e-17), + FlashData(1.0e+06, 2.8815e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 1.110223e-16), + FlashData(1.0e+06, 2.9715e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110223e-16), + FlashData(1.0e+06, 3.5315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.775558e-16), + FlashData(1.0e+06, 3.9315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -4.996004e-16), + FlashData(1.0e+06, 5.7315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 5.551115e-17), + FlashData(5.0e+06, 2.8815e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.775558e-16), + FlashData(5.0e+06, 2.9715e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110223e-16), + FlashData(5.0e+06, 3.5315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -3.330669e-16), + FlashData(5.0e+06, 3.9315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 1.110223e-16), + FlashData(5.0e+06, 5.7315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.665335e-16), + FlashData(1.0e+07, 2.8815e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.665335e-16), + FlashData(1.0e+07, 2.9715e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -4.996004e-16), + FlashData(1.0e+07, 3.5315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 5.551115e-17), + FlashData(1.0e+07, 3.9315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 1.110223e-16), + FlashData(1.0e+07, 5.7315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 5.551115e-17), + FlashData(5.0e+07, 2.8815e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.165734e-15), + FlashData(5.0e+07, 2.9715e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 5.551115e-17), + FlashData(5.0e+07, 3.5315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 1.110223e-16), + FlashData(5.0e+07, 3.9315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 5.551115e-17), + FlashData(5.0e+07, 5.7315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.665335e-16), + FlashData(1.0e+08, 2.8815e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.054712e-15), + FlashData(1.0e+08, 2.9715e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 1.665335e-16), + FlashData(1.0e+08, 3.5315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 5.551115e-16), + FlashData(1.0e+08, 3.9315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 5.551115e-17), + FlashData(1.0e+08, 5.7315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.665335e-16), + FlashData(1.0e+05, 2.8815e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.574938e+01), + FlashData(1.0e+05, 2.9715e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.788764e+01), + FlashData(1.0e+05, 3.5315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.980440e+01), + FlashData(1.0e+05, 3.9315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.152737e+01), + FlashData(1.0e+05, 5.7315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, 5.551115e-17), + FlashData(1.0e+06, 2.8815e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -8.611610e-01), + FlashData(1.0e+06, 2.9715e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.103151e+00), + FlashData(1.0e+06, 3.5315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.526750e+00), + FlashData(1.0e+06, 3.9315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -4.845663e+00), + FlashData(1.0e+06, 5.7315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -5.551115e-17), + FlashData(5.0e+06, 2.8815e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, 0.000000e+00), + FlashData(5.0e+06, 2.9715e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -4.996004e-16), + FlashData(5.0e+06, 3.5315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -9.882069e-02), + FlashData(5.0e+06, 3.9315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -4.113572e-01), + FlashData(5.0e+06, 5.7315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -6.662307e-02), + FlashData(1.0e+07, 2.8815e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -2.609024e-15), + FlashData(1.0e+07, 2.9715e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -2.831069e-15), + FlashData(1.0e+07, 3.5315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, 8.881784e-16), + FlashData(1.0e+07, 3.9315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.776357e-15), + FlashData(1.0e+07, 5.7315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -3.536058e-02), + FlashData(5.0e+07, 2.8815e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, 1.665335e-16), + FlashData(5.0e+07, 2.9715e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, 9.436896e-16), + FlashData(5.0e+07, 3.5315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -2.609024e-15), + FlashData(5.0e+07, 3.9315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -5.551115e-17), + FlashData(5.0e+07, 5.7315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -4.440892e-16), + FlashData(1.0e+08, 2.8815e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, 1.831868e-15), + FlashData(1.0e+08, 2.9715e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -3.608225e-15), + FlashData(1.0e+08, 3.5315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -4.440892e-16), + FlashData(1.0e+08, 3.9315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, 2.164935e-15), + FlashData(1.0e+08, 5.7315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -9.992007e-16), + FlashData(1.0e+05, 2.8815e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110206e-16), + FlashData(1.0e+05, 2.9715e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110206e-16), + FlashData(1.0e+05, 3.5315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 3.388132e-21), + FlashData(1.0e+05, 3.9315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 3.388132e-21), + FlashData(1.0e+05, 5.7315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110189e-16), + FlashData(1.0e+06, 2.8815e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.098348e-16), + FlashData(1.0e+06, 2.9715e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.103430e-16), + FlashData(1.0e+06, 3.5315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 1.694066e-21), + FlashData(1.0e+06, 3.9315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -3.330449e-16), + FlashData(1.0e+06, 5.7315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110223e-16), + FlashData(5.0e+06, 2.8815e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110189e-16), + FlashData(5.0e+06, 2.9715e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -3.254148e-16), + FlashData(5.0e+06, 3.5315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.218888e-16), + FlashData(5.0e+06, 3.9315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.220412e-16), + FlashData(5.0e+06, 5.7315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110189e-16), + FlashData(1.0e+07, 2.8815e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -3.259383e-17), + FlashData(1.0e+07, 2.9715e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 2.032879e-20), + FlashData(1.0e+07, 3.5315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110189e-16), + FlashData(1.0e+07, 3.9315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 1.694066e-21), + FlashData(1.0e+07, 5.7315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.220429e-16), + FlashData(5.0e+07, 2.8815e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.220599e-16), + FlashData(5.0e+07, 2.9715e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -8.266076e-16), + FlashData(5.0e+07, 3.5315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 2.220463e-16), + FlashData(5.0e+07, 3.9315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -4.440858e-16), + FlashData(5.0e+07, 5.7315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.111900e-16), + FlashData(1.0e+08, 2.8815e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 2.220463e-16), + FlashData(1.0e+08, 2.9715e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -4.925937e-16), + FlashData(1.0e+08, 3.5315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -3.198447e-16), + FlashData(1.0e+08, 3.9315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.541336e-16), + FlashData(1.0e+08, 5.7315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.223851e-16) + ) +); + +INSTANTIATE_TEST_SUITE_P( + StabilityTest, SoaveRedlichKwong, + ::testing::Values( + FlashData(1.0e+05, 2.8815e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.814994e+03), + FlashData(1.0e+05, 2.9715e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -9.241583e+02), + FlashData(1.0e+05, 3.5315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.828694e+01), + FlashData(1.0e+05, 3.9315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -3.557644e+00), + FlashData(1.0e+05, 5.7315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.736526e-16), + FlashData(1.0e+06, 2.8815e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.257797e-03), + FlashData(1.0e+06, 2.9715e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -3.641615e-03), + FlashData(1.0e+06, 3.5315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.511074e+02), + FlashData(1.0e+06, 3.9315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.482449e+01), + FlashData(1.0e+06, 5.7315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.509209e-16), + FlashData(5.0e+06, 2.8815e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.708694e-05), + FlashData(5.0e+06, 2.9715e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.932987e-04), + FlashData(5.0e+06, 3.5315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -6.840385e-02), + FlashData(5.0e+06, 3.9315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.584587e+00), + FlashData(5.0e+06, 5.7315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.029479e-02), + FlashData(1.0e+07, 2.8815e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.674182e-01), + FlashData(1.0e+07, 2.9715e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.444982e-01), + FlashData(1.0e+07, 3.5315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -5.201703e-03), + FlashData(1.0e+07, 3.9315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -5.402326e-02), + FlashData(1.0e+07, 5.7315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.715992e-02), + FlashData(5.0e+07, 2.8815e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.502339e-15), + FlashData(5.0e+07, 2.9715e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -8.907805e-16), + FlashData(5.0e+07, 3.5315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -6.071532e-16), + FlashData(5.0e+07, 3.9315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -9.840219e-16), + FlashData(5.0e+07, 5.7315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -6.379446e-16), + FlashData(1.0e+08, 2.8815e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.673141e-15), + FlashData(1.0e+08, 2.9715e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -8.729996e-16), + FlashData(1.0e+08, 3.5315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, 5.551115e-17), + FlashData(1.0e+08, 3.9315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, 6.977925e-16), + FlashData(1.0e+08, 5.7315e+02, {0.00900, 0.00300, 0.53470, 0.11460, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.179612e-15), + FlashData(1.0e+05, 2.8815e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.814881e+03), + FlashData(1.0e+05, 2.9715e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -9.241007e+02), + FlashData(1.0e+05, 3.5315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.828513e+01), + FlashData(1.0e+05, 3.9315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -3.557396e+00), + FlashData(1.0e+05, 5.7315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.769418e-16), + FlashData(1.0e+06, 2.8815e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.170713e-03), + FlashData(1.0e+06, 2.9715e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -3.444682e-03), + FlashData(1.0e+06, 3.5315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.508509e+02), + FlashData(1.0e+06, 3.9315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.479052e+01), + FlashData(1.0e+06, 5.7315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.179612e-16), + FlashData(5.0e+06, 2.8815e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.705802e-05), + FlashData(5.0e+06, 2.9715e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.542653e-04), + FlashData(5.0e+06, 3.5315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -6.637320e-02), + FlashData(5.0e+06, 3.9315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.515601e+00), + FlashData(5.0e+06, 5.7315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.953021e-02), + FlashData(1.0e+07, 2.8815e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.633584e-01), + FlashData(1.0e+07, 2.9715e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.416234e-01), + FlashData(1.0e+07, 3.5315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -4.840113e-03), + FlashData(1.0e+07, 3.9315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -5.210515e-02), + FlashData(1.0e+07, 5.7315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.603198e-02), + FlashData(5.0e+07, 2.8815e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -2.909131e-15), + FlashData(5.0e+07, 2.9715e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.826664e-15), + FlashData(5.0e+07, 3.5315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, 3.972517e-16), + FlashData(5.0e+07, 3.9315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -8.812395e-16), + FlashData(5.0e+07, 5.7315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -6.002143e-16), + FlashData(1.0e+08, 2.8815e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -3.093012e-15), + FlashData(1.0e+08, 2.9715e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -1.975850e-15), + FlashData(1.0e+08, 3.5315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, 9.055257e-16), + FlashData(1.0e+08, 3.9315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, 8.396062e-16), + FlashData(1.0e+08, 5.7315e+02, {0.00000, 0.00000, 0.53770, 0.12360, 0.08790, 0.04560, 0.02090, 0.01510, 0.16920}, -4.961309e-16), + FlashData(1.0e+05, 2.8815e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+05, 2.9715e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+05, 3.5315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+05, 3.9315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+05, 5.7315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+06, 2.8815e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+06, 2.9715e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+06, 3.5315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+06, 3.9315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+06, 5.7315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+06, 2.8815e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+06, 2.9715e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+06, 3.5315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+06, 3.9315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+06, 5.7315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+07, 2.8815e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+07, 2.9715e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+07, 3.5315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+07, 3.9315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+07, 5.7315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+07, 2.8815e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+07, 2.9715e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+07, 3.5315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+07, 3.9315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+07, 5.7315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+08, 2.8815e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+08, 2.9715e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+08, 3.5315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+08, 3.9315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+08, 5.7315e+02, {1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+05, 2.8815e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+05, 2.9715e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+05, 3.5315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+05, 3.9315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+05, 5.7315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+06, 2.8815e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+06, 2.9715e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+06, 3.5315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+06, 3.9315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+06, 5.7315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+06, 2.8815e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+06, 2.9715e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+06, 3.5315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+06, 3.9315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+06, 5.7315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+07, 2.8815e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+07, 2.9715e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+07, 3.5315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+07, 3.9315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+07, 5.7315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+07, 2.8815e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+07, 2.9715e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+07, 3.5315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+07, 3.9315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(5.0e+07, 5.7315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+08, 2.8815e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+08, 2.9715e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+08, 3.5315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+08, 3.9315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+08, 5.7315e+02, {0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000}, 0.000000e+00), + FlashData(1.0e+05, 2.8815e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 5.551115e-17), + FlashData(1.0e+05, 2.9715e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 2.775558e-16), + FlashData(1.0e+05, 3.5315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -5.551115e-17), + FlashData(1.0e+05, 3.9315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.775558e-16), + FlashData(1.0e+05, 5.7315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+06, 2.8815e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(1.0e+06, 2.9715e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 1.665335e-16), + FlashData(1.0e+06, 3.5315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -5.551115e-17), + FlashData(1.0e+06, 3.9315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.665335e-16), + FlashData(1.0e+06, 5.7315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 5.551115e-17), + FlashData(5.0e+06, 2.8815e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.775558e-16), + FlashData(5.0e+06, 2.9715e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+06, 3.5315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -4.440892e-16), + FlashData(5.0e+06, 3.9315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 0.000000e+00), + FlashData(5.0e+06, 5.7315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.220446e-16), + FlashData(1.0e+07, 2.8815e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -6.106227e-16), + FlashData(1.0e+07, 2.9715e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -3.885781e-16), + FlashData(1.0e+07, 3.5315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.665335e-16), + FlashData(1.0e+07, 3.9315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -3.885781e-16), + FlashData(1.0e+07, 5.7315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -5.551115e-17), + FlashData(5.0e+07, 2.8815e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -6.106227e-16), + FlashData(5.0e+07, 2.9715e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -9.436896e-16), + FlashData(5.0e+07, 3.5315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -3.885781e-16), + FlashData(5.0e+07, 3.9315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.665335e-16), + FlashData(5.0e+07, 5.7315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -5.551115e-17), + FlashData(1.0e+08, 2.8815e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 5.551115e-17), + FlashData(1.0e+08, 2.9715e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -5.551115e-16), + FlashData(1.0e+08, 3.5315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -9.436896e-16), + FlashData(1.0e+08, 3.9315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110223e-16), + FlashData(1.0e+08, 5.7315e+02, {0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.665335e-16), + FlashData(1.0e+05, 2.8815e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.547585e+01), + FlashData(1.0e+05, 2.9715e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.757647e+01), + FlashData(1.0e+05, 3.5315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.891242e+01), + FlashData(1.0e+05, 3.9315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.206762e+01), + FlashData(1.0e+05, 5.7315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -2.220446e-16), + FlashData(1.0e+06, 2.8815e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -8.275766e-01), + FlashData(1.0e+06, 2.9715e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.064839e+00), + FlashData(1.0e+06, 3.5315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.425766e+00), + FlashData(1.0e+06, 3.9315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -4.771453e+00), + FlashData(1.0e+06, 5.7315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -3.330669e-16), + FlashData(5.0e+06, 2.8815e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -4.052314e-15), + FlashData(5.0e+06, 2.9715e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, 1.554312e-15), + FlashData(5.0e+06, 3.5315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -8.067042e-02), + FlashData(5.0e+06, 3.9315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -3.893771e-01), + FlashData(5.0e+06, 5.7315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -4.938871e-02), + FlashData(1.0e+07, 2.8815e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -3.552714e-15), + FlashData(1.0e+07, 2.9715e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, 1.831868e-15), + FlashData(1.0e+07, 3.5315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -4.440892e-16), + FlashData(1.0e+07, 3.9315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.110223e-16), + FlashData(1.0e+07, 5.7315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -3.809697e-02), + FlashData(5.0e+07, 2.8815e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.498801e-15), + FlashData(5.0e+07, 2.9715e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, 3.608225e-15), + FlashData(5.0e+07, 3.5315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, 3.053113e-15), + FlashData(5.0e+07, 3.9315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.609823e-15), + FlashData(5.0e+07, 5.7315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -5.551115e-17), + FlashData(1.0e+08, 2.8815e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.276756e-15), + FlashData(1.0e+08, 2.9715e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -2.886580e-15), + FlashData(1.0e+08, 3.5315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -8.326673e-16), + FlashData(1.0e+08, 3.9315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -1.720846e-15), + FlashData(1.0e+08, 5.7315e+02, {0.50000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.50000}, -4.440892e-16), + FlashData(1.0e+05, 2.8815e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.220395e-16), + FlashData(1.0e+05, 2.9715e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110071e-16), + FlashData(1.0e+05, 3.5315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110206e-16), + FlashData(1.0e+05, 3.9315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110189e-16), + FlashData(1.0e+05, 5.7315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110189e-16), + FlashData(1.0e+06, 2.8815e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.206961e-16), + FlashData(1.0e+06, 2.9715e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.108224e-16), + FlashData(1.0e+06, 3.5315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110240e-16), + FlashData(1.0e+06, 3.9315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -8.470329e-21), + FlashData(1.0e+06, 5.7315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110223e-16), + FlashData(5.0e+06, 2.8815e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.706067e-16), + FlashData(5.0e+06, 2.9715e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110189e-16), + FlashData(5.0e+06, 3.5315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110206e-16), + FlashData(5.0e+06, 3.9315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.113577e-16), + FlashData(5.0e+06, 5.7315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 3.388132e-21), + FlashData(1.0e+07, 2.8815e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.220412e-16), + FlashData(1.0e+07, 2.9715e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 1.694066e-21), + FlashData(1.0e+07, 3.5315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110189e-16), + FlashData(1.0e+07, 3.9315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.192985e-16), + FlashData(1.0e+07, 5.7315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.220429e-16), + FlashData(5.0e+07, 2.8815e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.220243e-16), + FlashData(5.0e+07, 2.9715e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.524659e-20), + FlashData(5.0e+07, 3.5315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110206e-16), + FlashData(5.0e+07, 3.9315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.220260e-16), + FlashData(5.0e+07, 5.7315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.108190e-16), + FlashData(1.0e+08, 2.8815e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -6.661135e-16), + FlashData(1.0e+08, 2.9715e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.110375e-16), + FlashData(1.0e+08, 3.5315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -2.995007e-16), + FlashData(1.0e+08, 3.9315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, 1.110240e-16), + FlashData(1.0e+08, 5.7315e+02, {0.00001, 0.00000, 0.99999, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000}, -1.105768e-16) + ) +); + +/* UNCRUSTIFY-ON */ + +} // testing + +} // geos diff --git a/src/coreComponents/constitutive/unitTests/testTriaxial.cpp b/src/coreComponents/constitutive/unitTests/testTriaxial.cpp index 22aa43009b3..b9de06affcd 100644 --- a/src/coreComponents/constitutive/unitTests/testTriaxial.cpp +++ b/src/coreComponents/constitutive/unitTests/testTriaxial.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 Total, S.A - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/constitutiveDrivers/CMakeLists.txt b/src/coreComponents/constitutiveDrivers/CMakeLists.txt new file mode 100644 index 00000000000..36dad24e0d4 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/CMakeLists.txt @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: constitutiveDrivers + +Contains fluid and rock constitutive model tests to calibrate constitutive model parameters to + experimental data. +#]] + +# +# Specify all headers +# +set( constitutiveDrivers_headers + fluid/multiFluid/PVTDriver.hpp + fluid/multiFluid/PVTDriverRunTest.hpp + fluid/multiFluid/reactive/ReactiveFluidDriver.hpp + relativePermeability/RelpermDriver.hpp + relativePermeability/RelpermDriverRunTest.hpp + solid/TriaxialDriver.hpp + ) +# +# Specify all sources +# +set( constitutiveDrivers_sources + fluid/multiFluid/PVTDriver.cpp + fluid/multiFluid/blackOil/PVTDriverRunTestDeadOilFluid.cpp + fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsFluid.cpp + fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsThermalFluid.cpp + fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiFluid.cpp + fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiThermalFluid.cpp + fluid/multiFluid/compositional/PVTDriverRunTestCompositionalThreePhaseLohrenzBrayClarkViscosity.cpp + fluid/multiFluid/compositional/PVTDriverRunTestCompositionalTwoPhaseConstantViscosity.cpp + fluid/multiFluid/compositional/PVTDriverRunTestCompositionalTwoPhaseLohrenzBrayClarkViscosity.cpp + fluid/multiFluid/reactive/ReactiveFluidDriver.cpp + relativePermeability/RelpermDriver.cpp + relativePermeability/RelpermDriverBrooksCoreyBakerRunTest.cpp + relativePermeability/RelpermDriverBrooksCoreyStone2RunTest.cpp + relativePermeability/RelpermDriverBrooksCoreyRunTest.cpp + relativePermeability/RelpermDriverVanGenuchtenBakerRunTest.cpp + relativePermeability/RelpermDriverVanGenuchtenStone2RunTest.cpp + relativePermeability/RelpermDriverTableRelativeRunTest.cpp + relativePermeability/RelpermDriverTableRelativeHysteresisRunTest.cpp + solid/TriaxialDriver.cpp + ) + +set( dependencyList ${parallelDeps} constitutive events ) + +if( ENABLE_PVTPackage ) + set( constitutiveDrivers_sources + ${constitutiveDrivers_sources} + fluid/multiFluid/compositional/PVTDriverRunTestCompositionalMultiphaseFluid.cpp + ) +endif() + +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) + +blt_add_library( NAME constitutiveDrivers + SOURCES ${constitutiveDrivers_sources} + HEADERS ${constitutiveDrivers_headers} + DEPENDS_ON ${decoratedDependencies} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} + ) + +target_include_directories( constitutiveDrivers PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +install( TARGETS constitutiveDrivers LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) diff --git a/src/coreComponents/constitutiveDrivers/docs/ConstitutiveDrivers.rst b/src/coreComponents/constitutiveDrivers/docs/ConstitutiveDrivers.rst new file mode 100644 index 00000000000..8ad6a17ca83 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/docs/ConstitutiveDrivers.rst @@ -0,0 +1,13 @@ +.. _ConstitutiveDrivers: + +Constitutive Drivers +============================================ +To test and calibrate constitutive models, GEOS provides a set of drivers that can be used to run simulations with specific input parameters. +These drivers are designed to facilitate the exploration of various constitutive behaviors and to validate the models against known benchmarks. + +.. toctree:: + :maxdepth: 1 + + PVTDriver + + TriaxialDriver diff --git a/src/coreComponents/constitutiveDrivers/docs/PVTDriver.rst b/src/coreComponents/constitutiveDrivers/docs/PVTDriver.rst new file mode 100644 index 00000000000..eaa849ea060 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/docs/PVTDriver.rst @@ -0,0 +1,155 @@ +PVT Driver +=============== + +.. contents:: Table of Contents + :depth: 3 + +Introduction +------------ + +When calibrating fluid material parameters to experimental or other reference data, it can be a hassle to launch a full flow simulation just to confirm density, viscosity, and other fluid properties are behaving as expected. +Instead, GEOS provides a ``PVTDriver`` allowing the user to test fluid property models for a well defined set of pressure, temperature, and composition conditions. +The driver itself is launched like any other GEOS simulation, but with a particular XML structure: + +.. code-block:: sh + + ./bin/geosx -i myFluidTest.xml + +This driver will work for any multi-phase fluid model (e.g. black-oil, co2-brine, compositional multiphase) enabled within GEOS. + +XML Structure +------------- +A typical XML file to run the driver will have several key elements. +Here, we will walk through an example file included in the source tree at + +.. code-block:: sh + + src/coreComponents/unitTests/constitutiveTests/testPVT_docExample.xml + +The first thing to note is that the XML file structure is identical to a standard GEOS input deck. +In fact, once the constitutive block is calibrated, one could start adding solver and discretization blocks to the same file to create a proper field simulation. +This makes it easy to go back and forth between calibration and simulation. + +The first step is to define a parameterized fluid model to test. +Here, we create a particular type of CO2-Brine mixture: + +.. literalinclude:: ../../unitTests/constitutiveTests/testPVT_docExample.xml + :language: xml + :start-after: + :end-before: + +We also define two time-history functions for the pressure (Pascal units) and temperature (Kelvin units) conditions we want to explore. + +.. literalinclude:: ../../unitTests/constitutiveTests/testPVT_docExample.xml + :language: xml + :start-after: + :end-before: + +Note that the time-axis here is just a pseudo-time, allowing us to `parameterize `_ arbitrarily complicated paths through a (pressure,temperature) diagram. +The actual time values have no impact on the resulting fluid properties. +Here, we fix the temperature at 350K and simply ramp up pressure from 1 MPa to 50 MPa: + +A ``PVTDriver`` is then added as a ``Task``, a particular type of executable event often used for simple actions. + +.. literalinclude:: ../../unitTests/constitutiveTests/testPVT_docExample.xml + :language: xml + :start-after: + :end-before: + +The driver itself takes as input the fluid model, the pressure and temperature control functions, and a "feed composition." +The latter is the mole fraction of each component in the mixture to be tested. +The ``steps`` parameter controls how many steps are taken along the parametric (P,T) path. +Results will be written in a simple ASCII table format (described below) to the file ``output``. +The ``logLevel`` parameter controls the verbosity of log output during execution. + +The driver task is added as a ``SoloEvent`` to the event queue. +This leads to a trivial event queue, since all we do is launch the driver and then quit. + +.. literalinclude:: ../../unitTests/constitutiveTests/testPVT_docExample.xml + :language: xml + :start-after: + :end-before: + +Internally, the driver uses a simple form of time-stepping to advance through the (P,T) steps. +This timestepping is handled independently of the more complicated time-stepping pattern used by physics ``Solvers`` and coordinated by the ``EventManager``. +In particular, in the XML file above, the ``maxTime`` parameter in the ``Events`` block is an event manager control, controlling when/if certain events occur. +Once launched, the PVTDriver internally determines its own max time and timestep size using a combination of the input functions' time coordinates and the requested number of loadsteps. +It is therefore helpful to think of the driver as an instantaneous *event* (from the event manager's point of view), but one which has a separate, internal clock. + +Parameters +---------- +The key XML parameters for the PVTDriver are summarized in the following table: + +.. include:: /docs/sphinx/datastructure/PVTDriver.rst + +Output Format +------------- +The ``output`` key is used to identify a file to which the results of the simulation are written. +If this key is omitted, or the user specifies ``output="none"``, file output will be suppressed. +The file is a simple ASCII format with a brief header followed by test data: + +.. code:: sh + + # column 1 = time + # column 2 = pressure + # column 3 = temperature + # column 4 = density + # columns 5-6 = phase fractions + # columns 7-8 = phase densities + # columns 9-10 = phase viscosities + 0.0000e+00 1.0000e+06 3.5000e+02 1.5581e+01 1.0000e+00 4.1138e-11 1.5581e+01 1.0033e+03 1.7476e-05 9.9525e-04 + 2.0408e-02 2.0000e+06 3.5000e+02 3.2165e+01 1.0000e+00 4.1359e-11 3.2165e+01 1.0050e+03 1.7601e-05 9.9525e-04 + 4.0816e-02 3.0000e+06 3.5000e+02 4.9901e+01 1.0000e+00 4.1563e-11 4.9901e+01 1.0066e+03 1.7778e-05 9.9525e-04 + ... + +Note that the number of columns will depend on how many phases and components are present. +In this case, we have a two-phase, two-component mixture. +The total density is reported in column 4, while phase fractions, phase densities, and phase viscosities are reported in subsequent columns. +If the ``outputCompressibility`` flag is activated, an extra column will be added for the total fluid compressibility after the density. +This is defined as :math:`c_t=\frac{1}{\rho_t}\left(\partial{\rho_t}/\partial P\right)` where :math:`\rho_t` is the total density. +If the ``outputMassDensity`` flag is activated, extra columns will be added for the mass density of each phase. +The number of columns will also depend on whether the ``outputPhaseComposition`` flag is activated or not. If it is activated, there will be an extra column for the mole fraction of each component in each phase. +The phase order will match the one defined in the input XML (here, the co2-rich phase followed by the water-rich phase). +This file can be readily plotted using any number of plotting tools. Each row corresponds to one timestep of the driver, starting from initial conditions in the first row. + +Unit Testing +------------ + +The development team also uses the PVTDriver to perform unit testing on the various fluid models within GEOS. +The optional argument ``baseline`` can be used to point to a previous output file that has been validated (e.g. against experimental benchmarks or reference codes). +If such a file is specified, the driver will perform a testing run and then compare the new results against the baseline. +In this way, any regressions in the fluid models can be quickly identified. + +Developers of new models are encouraged to add their own baselines to ``src/coreComponents/constitutive/unitTests``. +Adding additional tests is straightforward: + +1. Create a new xml file for your test in ``src/coreComponents/constitutive/unitTests`` or (easier) add extra blocks to the existing XML at ``src/coreComponents/constitutive/unitTests/testPVT.xml``. +For new XMLs, we suggest using the naming convention ``testPVT_myTest.xml``, so that all tests will be grouped together alphabetically. +Set the ``output`` file to ``testPVT_myTest.txt``, and run your test. +Validate the results however is appropriate. +If you have reference data available for this validation, we suggest archiving it in the ``testPVT_data/`` subdirectory, with a description of the source and formatting in the file header. +Several reference datasets are included already as examples. +This directory is also a convenient place to store auxiliary input files like PVT tables. + +2. This output file will now become your new baseline. +Replace the ``output`` key with ``baseline`` so that the driver can read in your file as a baseline for comparison. +Make sure there is no remaining ``output`` key, or set ``output=none``, to suppress further file output. +While you can certainly write a new output for debugging purposes, during our automated unit tests we prefer to suppress file output. +Re-run the driver to confirm that the comparison test passes. + +3. Modify ``src/coreComponents/constitutive/unitTests/CMakeLists.txt`` to enable your new test in the unit test suite. +In particular, you will need to add your new XML file to the existing list in the ``gtest_pvt_xmls`` variable. +Note that if you simply added your test to the existing ``testPVT.xml`` file, no changes are needed. + +.. code:: sh + + set( gtest_pvt_xmls + testPVT.xml + testPVT_myTest.xml + ) + +4. Run ``make`` in your build directory to make sure the CMake syntax is correct + +5. Run ``ctest -V -R PVT`` to run the PVT unit tests. Confirm your test is included and passes properly. + +If you run into troubles, do not hesitate to contact the development team for help. diff --git a/src/coreComponents/constitutiveDrivers/docs/TriaxialDriver.rst b/src/coreComponents/constitutiveDrivers/docs/TriaxialDriver.rst new file mode 100644 index 00000000000..ced93bc86f7 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/docs/TriaxialDriver.rst @@ -0,0 +1,142 @@ +.. _TriaxialDriver: + + +Triaxial Driver +=============== + +.. contents:: Table of Contents + :depth: 3 + +Introduction +------------ + +When calibrating solid material parameters to experimental data, it can be a hassle to launch a full finite element simulation to mimic experimental loading conditions. Instead, GEOS provides a ``TriaxialDriver`` allowing the user to run loading tests on a single material point. This makes it easy to understand the material response and fit it to lab data. The driver itself is launched like any other GEOS simulation, but with a particular XML structure: + +.. code-block:: sh + + ./bin/geosx -i myTest.xml + + +XML Structure +------------- +A typical XML file to run the triaxial driver will have the following key elements. We present the whole file first, before digging into the individual blocks. + +.. literalinclude:: ../../unitTests/constitutiveTests/testTriaxial_druckerPragerExtended.xml + :language: xml + +The first thing to note is that the XML structure is identical to a standard GEOS input deck. In fact, once the constitutive block is calibrated, one could start adding solver and discretization blocks to the same file to create a proper field simulation. This makes it easy to go back and forth between calibration and simulation. + +The ``TriaxialDriver`` is added as a ``Task``, a particular type of executable event often used for simple actions. It is added as a ``SoloEvent`` to the event queue. This leads to a trivial event queue, since all we do is launch the driver and then quit. + +Internally, the triaxial driver uses a simple form of time-stepping to advance through the loading steps, allowing for both rate-dependent and rate-independent models to be tested. This timestepping is handled independently from the more complicated time-stepping pattern used by physics ``Solvers`` and coordinated by the ``EventManager``. In particular, in the XML file above, the ``maxTime`` parameter in the ``Events`` block is an event manager control, controlling when/if certain events occur. Once launched, the triaxial driver internally determines its own max time and timestep size using a combination of the strain function's time coordinates and the requested number of loadsteps. It is therefore helpful to think of the driver as an instantaneous *event* (from the event manager's point of view), but one which has a separate, internal clock. + +The key parameters for the TriaxialDriver are: + +.. include:: /docs/sphinx/datastructure/TriaxialDriver.rst + +.. note:: + + GEOS uses the *engineering* sign convention where compressive stresses and strains are *negative*. + This is one of the most frequent issues users make when calibrating material parameters, as + stress- and strain-like quantities often need to be negative to make physical sense. You may note in the + XML above, for example, that ``stressFunction`` and ``strainFunction`` have negative values for + a compressive test. + +Test Modes +---------- +The most complicated part of the driver is understanding how the stress and strain functions are applied in different testing modes. The driver mimics laboratory core tests, with loading controlled in the +axial and radial directions. These conditions may be either strain-controlled or stress-controlled, with the user providing time-dependent functions to describe the loading. The following table describes the available test modes in detail: + ++--------------------+-------------------------+--------------------------+---------------------------+ +| **mode** | **axial loading** | **radial loading** | **initial stress** | ++--------------------+-------------------------+--------------------------+---------------------------+ +| ``strainControl`` | axial strain controlled | radial strain controlled | isotropic stress using | +| | with ``axialControl`` | with ``radialControl`` | ``initialStress`` | ++--------------------+-------------------------+--------------------------+---------------------------+ +| ``stressControl`` | axial stress controlled | radial stress controlled | isotropic stress using | +| | with ``axialControl`` | with ``radialControl`` | ``initialStress`` | ++--------------------+-------------------------+--------------------------+---------------------------+ +| ``mixedControl`` | axial strain controlled | radial stress controlled | isotropic stress using | +| | with ``axialControl`` | with ``radialControl`` | ``initialStress`` | ++--------------------+-------------------------+--------------------------+---------------------------+ + +Note that a classical triaxial test can be described using either the ``stressControl`` or ``mixedControl`` mode. We recommend using the ``mixedControl`` mode when possible, because this almost always leads to well-posed loading conditions. In a pure stress controlled test, it is possible for the user to request that the material sustain a load beyond its intrinsic strength envelope, in which case there is no feasible solution and the driver will fail to converge. Imagine, for example, a perfectly plastic material with a yield strength of 10 MPa, but the user attempts to load it to 11 MPa. + +A volumetric test can be created by setting the axial and radial control functions to the same time history function. Similarly, an oedometer test can be created by setting the radial strain to zero. + +The user should be careful to ensure that the initial stress set via the ``initialStress`` value is consistent any applied stresses set through axial or radial loading functions. Otherwise, the material may experience sudden and unexpected deformation at the first timestep because it is not in static equilibrium. + +Output Format +------------- +The ``output`` key is used to identify a file to which the results of the simulation are written. If this key is omitted, or the user specifies ``output="none"``, file output will be suppressed. The file is a simple ASCII format with a brief header followed by test data: + +.. code:: sh + + # column 1 = time + # column 2 = axial_strain + # column 3 = radial_strain_1 + # column 4 = radial_strain_2 + # column 5 = axial_stress + # column 6 = radial_stress_1 + # column 7 = radial_stress_2 + # column 8 = newton_iter + # column 9 = residual_norm + 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 -1.0000e+00 -1.0000e+00 -1.0000e+00 0.0000e+00 0.0000e+00 + 1.6000e-01 -1.6000e-04 4.0000e-05 4.0000e-05 -1.1200e+00 -1.0000e+00 -1.0000e+00 2.0000e+00 0.0000e+00 + 3.2000e-01 -3.2000e-04 8.0000e-05 8.0000e-05 -1.2400e+00 -1.0000e+00 -1.0000e+00 2.0000e+00 0.0000e+00 + ... + +This file can be readily plotted using any number of plotting tools. Each row corresponds to one timestep of the driver, starting from initial conditions in the first row. + +We note that the file contains two columns for radial strain and two columns for radial stress. For an isotropic material, the stresses and strains along the two radial axes will usually be identical. We choose to output this way, however, to accommodate both anisotropic materials and true-triaxial loading conditions. In these cases, the stresses and strains in the radial directions could potentially differ. + +These columns can be added and subtracted to produce other quantities of interest, like mean stress or deviatoric stress. For example, we can plot the output produce stress / strain curves (in this case for a plastic rather than simple elastic material): + +.. figure:: TriaxialDriver.svg + :width: 600px + :align: center + :alt: stress/strain figure + :figclass: align-center + + Stress/strain behavior for a plastic material. + +In this plot, we have reversed the sign convention to be consistent with typical experimental plots. Note also that the ``strainFunction`` includes two unloading cycles, allowing us to observe both plastic loading and elastic unloading. + +Model Convergence +----------------- + +The last two columns of the output file contain information about the convergence behavior of the material driver. In ``triaxial`` mode, the mixed nature of the stress/strain control requires using a Newton solver to converge the solution. This last column reports the number of Newton iterations and final residual norm. Large values here would be indicative of the material model struggling (or failing) to converge. Convergence failures can result from several reasons, including: + +1. Inappropriate material parameter settings +2. Overly large timesteps +3. Infeasible loading conditions (i.e. trying to load a material to a physically-unreachable stress point) +4. Poor model implementation + +We generally spend a lot of time vetting the material model implementations (#4). When you first encounter a problem, it is therefore good to explore the other three scenarios first. If you find something unusual in the model implementation or are just really stuck, please submit an issue on our issue tracker so we can help resolve any bugs. + +Unit Testing +------------ + +The development team also uses the Triaxial Driver to perform unit testing on the various material models within GEOS. The optional argument ``baseline`` can be used to point to a previous output file that has been validated (e.g. against analytical or experimental benchmarks). If such a file is specified, the driver will perform a loading run and then compare the new results against the baseline. In this way, any regressions in the material models can be quickly identified. + +Developers of new models are encouraged to add their own baselines to ``src/coreComponents/constitutive/unitTests``. Adding additional tests is straightforward: + +1. Create a new xml file for your test in ``src/coreComponents/constitutive/unitTests``. There are several examples is this directory already to use as a template. We suggest using the naming convention ``testTriaxial_myTest.xml``, so that all triaxial tests will be grouped together alphabetically. Set the ``output`` file to ``testTriaxial_myTest.txt``, and run your test. Validate the results however is appropriate. + +2. This output file will now become your new baseline. Replace the ``output`` key with ``baseline`` so that the driver can read in your file as a baseline for comparison. Make sure there is no remaining ``output`` key, or set ``output=none``, to suppress further file output. While you can certainly write a new output for debugging purposes, during our automated unit tests we prefer to suppress file output. Re-run the triaxial driver to confirm that the comparison test passes. + +3. Modify ``src/coreComponents/constitutive/unitTests/CMakeLists.txt`` to enable your new test in the unit test suite. In particular, you will need to add your new XML file to the existing list in the ``gtest_triaxial_xmls`` variable: + +.. code:: sh + + set( gtest_triaxial_xmls + testTriaxial_elasticIsotropic.xml + testTriaxial_druckerPragerExtended.xml + testTriaxial_myTest.xml + ) + +4. Run ``make`` in your build directory to make sure the CMake syntax is correct + +5. Run ``ctest -V -R Triax`` to run the triaxial unit tests. Confirm your test is included and passes properly. + +If you run into troubles, do not hesitate to contact the development team for help. diff --git a/src/coreComponents/constitutive/docs/solid/TriaxialDriver.svg b/src/coreComponents/constitutiveDrivers/docs/TriaxialDriver.svg similarity index 100% rename from src/coreComponents/constitutive/docs/solid/TriaxialDriver.svg rename to src/coreComponents/constitutiveDrivers/docs/TriaxialDriver.svg diff --git a/src/coreComponents/constitutiveDrivers/fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiFluid.cpp b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiFluid.cpp new file mode 100644 index 00000000000..3d5d5d46ea4 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiFluid.cpp @@ -0,0 +1,22 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "constitutiveDrivers/fluid/multiFluid/PVTDriverRunTest.hpp" +#include "constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp" + +namespace geos +{ +template void PVTDriver::runTest< constitutive::CO2BrineEzrokhiFluid >( constitutive::CO2BrineEzrokhiFluid &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutiveDrivers/fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiThermalFluid.cpp b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiThermalFluid.cpp new file mode 100644 index 00000000000..e5d457ca9f7 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrineEzrokhiThermalFluid.cpp @@ -0,0 +1,22 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "constitutiveDrivers/fluid/multiFluid/PVTDriverRunTest.hpp" +#include "constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp" + +namespace geos +{ +template void PVTDriver::runTest< constitutive::CO2BrineEzrokhiThermalFluid >( constitutive::CO2BrineEzrokhiThermalFluid &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutiveDrivers/fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsFluid.cpp b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsFluid.cpp new file mode 100644 index 00000000000..8815bc53000 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsFluid.cpp @@ -0,0 +1,22 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "constitutiveDrivers/fluid/multiFluid/PVTDriverRunTest.hpp" +#include "constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp" + +namespace geos +{ +template void PVTDriver::runTest< constitutive::CO2BrinePhillipsFluid >( constitutive::CO2BrinePhillipsFluid &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutiveDrivers/fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsThermalFluid.cpp b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsThermalFluid.cpp new file mode 100644 index 00000000000..0839e37d65b --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/CO2Brine/PVTDriverRunTestCO2BrinePhillipsThermalFluid.cpp @@ -0,0 +1,22 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "constitutiveDrivers/fluid/multiFluid/PVTDriverRunTest.hpp" +#include "constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp" + +namespace geos +{ +template void PVTDriver::runTest< constitutive::CO2BrinePhillipsThermalFluid >( constitutive::CO2BrinePhillipsThermalFluid &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutive/fluid/multifluid/PVTDriver.cpp b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/PVTDriver.cpp similarity index 88% rename from src/coreComponents/constitutive/fluid/multifluid/PVTDriver.cpp rename to src/coreComponents/constitutiveDrivers/fluid/multiFluid/PVTDriver.cpp index ebee0639d42..56cece6e149 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/PVTDriver.cpp +++ b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/PVTDriver.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -23,10 +24,10 @@ #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "constitutive/fluid/multifluid/MultiFluidSelector.hpp" #include "constitutive/fluid/multifluid/MultiFluidConstants.hpp" -#include "fileIO/Outputs/OutputBase.hpp" +//#include "fileIO/Outputs/OutputBase.hpp" #include "functions/FunctionManager.hpp" #include "functions/TableFunction.hpp" -#include "codingUtilities/StringUtilities.hpp" +#include "common/format/StringUtilities.hpp" #include @@ -61,6 +62,11 @@ PVTDriver::PVTDriver( const string & name, setInputFlag( InputFlags::REQUIRED ). setDescription( "Function controlling temperature time history" ); + registerWrapper( viewKeyStruct::outputMassDensityString(), &m_outputMassDensity ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( 0 ). + setDescription( "Flag to indicate that the mass density of each phase should be output" ); + registerWrapper( viewKeyStruct::outputCompressibilityString(), &m_outputCompressibility ). setInputFlag( InputFlags::OPTIONAL ). setApplyDefaultValue( 0 ). @@ -87,9 +93,13 @@ PVTDriver::PVTDriver( const string & name, setDescription( "Baseline file" ); } -void PVTDriver::postProcessInput() +void PVTDriver::postInputInitialization() { // Validate some inputs + GEOS_ERROR_IF( m_outputMassDensity != 0 && m_outputMassDensity != 1, + getWrapperDataContext( viewKeyStruct::outputMassDensityString() ) << + ": option can be either 0 (false) or 1 (true)" ); + GEOS_ERROR_IF( m_outputCompressibility != 0 && m_outputCompressibility != 1, getWrapperDataContext( viewKeyStruct::outputCompressibilityString() ) << ": option can be either 0 (false) or 1 (true)" ); @@ -112,6 +122,12 @@ void PVTDriver::postProcessInput() // Default column order = time, pressure, temp, totalDensity, phaseFraction_{1:NP}, phaseDensity_{1:NP}, phaseViscosity_{1:NP} integer numCols = 3*m_numPhases+4; + // If the mass density is requested then add NP columns + if( m_outputMassDensity != 0 ) + { + numCols += m_numPhases; + } + // If the total compressibility is requested then add a column if( m_outputCompressibility != 0 ) { @@ -185,6 +201,7 @@ bool PVTDriver::execute( real64 const GEOS_UNUSED_PARAM( time_n ), GEOS_LOG_RANK_0( " Steps .................. " << m_numSteps ); GEOS_LOG_RANK_0( " Output ................. " << m_outputFile ); GEOS_LOG_RANK_0( " Baseline ............... " << m_baselineFile ); + GEOS_LOG_RANK_0( " Output Mass Density .... " << m_outputMassDensity ); GEOS_LOG_RANK_0( " Output Compressibility . " << m_outputCompressibility ); GEOS_LOG_RANK_0( " Output Phase Comp. ..... " << m_outputPhaseComposition ); } @@ -248,6 +265,11 @@ void PVTDriver::outputResults() columnIndex += m_numPhases; fprintf( fp, "# columns %d-%d = phase densities\n", columnIndex+1, columnIndex + m_numPhases ); columnIndex += m_numPhases; + if( m_outputMassDensity != 0 ) + { + fprintf( fp, "# columns %d-%d = phase mass densities\n", columnIndex+1, columnIndex + m_numPhases ); + columnIndex += m_numPhases; + } fprintf( fp, "# columns %d-%d = phase viscosities\n", columnIndex+1, columnIndex + m_numPhases ); columnIndex += m_numPhases; @@ -288,6 +310,10 @@ void PVTDriver::compareWithBaseline() { headerRows++; } + if( m_outputMassDensity ) + { + headerRows++; + } if( m_outputPhaseComposition ) { headerRows += getFluid().numFluidPhases(); @@ -314,9 +340,9 @@ void PVTDriver::compareWithBaseline() real64 const error = fabs( m_table[row][col]-value ) / ( fabs( value )+1 ); GEOS_THROW_IF( error > MultiFluidConstants::baselineTolerance, - "Results do not match baseline at data row " << row+1 - << " (row " << row+headerRows << " with header)" - << " and column " << col+1, std::runtime_error ); + GEOS_FMT( "Results do not match baseline ({} vs {}) at data row {} (row {} with header) and column {}", + m_table[row][col], value, row+1, row+headerRows, col+1 ), + std::runtime_error ); } } diff --git a/src/coreComponents/constitutive/fluid/multifluid/PVTDriver.hpp b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/PVTDriver.hpp similarity index 88% rename from src/coreComponents/constitutive/fluid/multifluid/PVTDriver.hpp rename to src/coreComponents/constitutiveDrivers/fluid/multiFluid/PVTDriver.hpp index ed1c763571c..bae4e9827c9 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/PVTDriver.hpp +++ b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/PVTDriver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -44,7 +45,7 @@ class PVTDriver : public TaskBase static string catalogName() { return "PVTDriver"; } - void postProcessInput() override; + void postInputInitialization() override; virtual bool execute( real64 const GEOS_UNUSED_PARAM( time_n ), real64 const GEOS_UNUSED_PARAM( dt ), @@ -90,6 +91,7 @@ class PVTDriver : public TaskBase constexpr static char const * outputString() { return "output"; } constexpr static char const * baselineString() { return "baseline"; } constexpr static char const * feedString() { return "feedComposition"; } + constexpr static char const * outputMassDensityString() { return "outputMassDensity"; } constexpr static char const * outputCompressibilityString() { return "outputCompressibility"; } constexpr static char const * outputPhaseCompositionString() { return "outputPhaseComposition"; } }; @@ -102,6 +104,7 @@ class PVTDriver : public TaskBase string m_pressureFunctionName; ///< Time-dependent function controlling pressure string m_temperatureFunctionName; ///< Time-dependent function controlling temperature string m_outputFile; ///< Output file (optional, no output if not specified) + integer m_outputMassDensity{0}; ///< Flag to indicate that the mass density of each phase should be output integer m_outputCompressibility{0}; ///< Flag to indicate that the total compressibility should be output integer m_outputPhaseComposition{0}; ///< Flag to indicate that phase compositions should be output diff --git a/src/coreComponents/constitutiveDrivers/fluid/multiFluid/PVTDriverRunTest.hpp b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/PVTDriverRunTest.hpp new file mode 100644 index 00000000000..6b763d25134 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/PVTDriverRunTest.hpp @@ -0,0 +1,131 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PVTDriverRunTest.hpp + */ + +#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_PVTDRIVERRUNTEST_HPP_ +#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_PVTDRIVERRUNTEST_HPP_ + +#include "PVTDriver.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" + +namespace geos +{ + +template< typename FLUID_TYPE > +void PVTDriver::runTest( FLUID_TYPE & fluid, arrayView2d< real64 > const & table ) +{ + // get number of phases and components + + integer const numComponents = fluid.numFluidComponents(); + integer const numPhases = fluid.numFluidPhases(); + + // prefer output in mass + + fluid.setMassFlag( true ); + + // create kernel wrapper + + typename FLUID_TYPE::KernelWrapper const kernelWrapper = fluid.createKernelWrapper(); + + // set composition to user specified feed + // it is more convenient to provide input in molar, so perform molar to mass conversion here + + GEOS_ASSERT_EQ( numComponents, m_feed.size() ); + array2d< real64, compflow::LAYOUT_COMP > const compositionValues( 1, numComponents ); + + real64 sum = 0.0; + for( integer i = 0; i < numComponents; ++i ) + { + compositionValues[0][i] = m_feed[i] * fluid.componentMolarWeights()[i]; + sum += compositionValues[0][i]; + } + for( integer i = 0; i < numComponents; ++i ) + { + compositionValues[0][i] /= sum; + } + + arrayView2d< real64 const, compflow::USD_COMP > const composition = compositionValues; + + // perform fluid update using table (P,T) and save resulting total density, etc. + // note: column indexing should be kept consistent with output file header below. + + bool const outputMassDensity = (m_outputMassDensity != 0); + bool const outputCompressibility = (m_outputCompressibility != 0); + bool const outputPhaseComposition = (m_outputPhaseComposition != 0); + + integer const numSteps = m_numSteps; + using ExecPolicy = typename FLUID_TYPE::exec_policy; + forAll< ExecPolicy >( composition.size( 0 ), + [outputMassDensity, outputCompressibility, outputPhaseComposition, + numPhases, numComponents, numSteps, kernelWrapper, + table, composition] + GEOS_HOST_DEVICE ( localIndex const i ) + { + // Index for start of phase properties + integer const PHASE_FRACTION = outputCompressibility ? TEMP + 3 : TEMP + 2; + integer const PHASE_DENSITY = PHASE_FRACTION + numPhases; + integer const PHASE_VISCOSITY = outputMassDensity ? PHASE_DENSITY + 2*numPhases : PHASE_DENSITY + numPhases; + integer const PHASE_COMP = PHASE_VISCOSITY + numPhases; + + // Temporary space for phase mole fractions + stackArray1d< real64, constitutive::MultiFluidBase::MAX_NUM_COMPONENTS > phaseComposition( numComponents ); + + for( integer n = 0; n <= numSteps; ++n ) + { + kernelWrapper.update( i, 0, table( n, PRES ), table( n, TEMP ), composition[i] ); + table( n, TEMP + 1 ) = kernelWrapper.totalDensity()( i, 0 ); + + if( outputCompressibility ) + { + table( n, TEMP + 2 ) = kernelWrapper.totalCompressibility( i, 0 ); + } + + for( integer p = 0; p < numPhases; ++p ) + { + table( n, PHASE_FRACTION + p ) = kernelWrapper.phaseFraction()( i, 0, p ); + table( n, PHASE_DENSITY + p ) = kernelWrapper.phaseDensity()( i, 0, p ); + table( n, PHASE_VISCOSITY + p ) = kernelWrapper.phaseViscosity()( i, 0, p ); + } + if( outputMassDensity ) + { + for( integer p = 0; p < numPhases; ++p ) + { + table( n, PHASE_DENSITY + numPhases + p ) = kernelWrapper.phaseMassDensity()( i, 0, p ); + } + } + if( outputPhaseComposition ) + { + for( integer p = 0; p < numPhases; ++p ) + { + integer const compStartIndex = PHASE_COMP + p * numComponents; + + kernelWrapper.phaseCompMoleFraction( i, 0, p, phaseComposition ); + for( integer ic = 0; ic < numComponents; ++ic ) + { + table( n, compStartIndex + ic ) = phaseComposition[ic]; + } + } + } + } + } ); + +} + +} + +#endif /* GEOS_CONSTITUTIVE_PVTDRIVERRUNTEST_HPP_ */ diff --git a/src/coreComponents/constitutiveDrivers/fluid/multiFluid/blackOil/PVTDriverRunTestDeadOilFluid.cpp b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/blackOil/PVTDriverRunTestDeadOilFluid.cpp new file mode 100644 index 00000000000..1b5bbf0e469 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/blackOil/PVTDriverRunTestDeadOilFluid.cpp @@ -0,0 +1,29 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/* + * PVTDriverRunTestDeadOilFluid.cpp + */ + +#include "constitutiveDrivers/fluid/multiFluid/PVTDriverRunTest.hpp" +#include "constitutive/fluid/multifluid/blackOil/DeadOilFluid.hpp" +#include "constitutive/fluid/multifluid/blackOil/BlackOilFluid.hpp" + + +namespace geos +{ +template void PVTDriver::runTest< constitutive::DeadOilFluid >( constitutive::DeadOilFluid &, arrayView2d< real64 > const & ); +template void PVTDriver::runTest< constitutive::BlackOilFluid >( constitutive::BlackOilFluid &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutiveDrivers/fluid/multiFluid/compositional/PVTDriverRunTestCompositionalMultiphaseFluid.cpp b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/compositional/PVTDriverRunTestCompositionalMultiphaseFluid.cpp new file mode 100644 index 00000000000..6506255acce --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/compositional/PVTDriverRunTestCompositionalMultiphaseFluid.cpp @@ -0,0 +1,26 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/* + * PVTDriverRunTestCompositionalMultiphaseFluid.cpp + */ + +#include "constitutiveDrivers/fluid/multiFluid/PVTDriverRunTest.hpp" +#include "constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluidPVTPackage.hpp" + +namespace geos +{ +template void PVTDriver::runTest< constitutive::CompositionalMultiphaseFluidPVTPackage >( constitutive::CompositionalMultiphaseFluidPVTPackage &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutiveDrivers/fluid/multiFluid/compositional/PVTDriverRunTestCompositionalThreePhaseLohrenzBrayClarkViscosity.cpp b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/compositional/PVTDriverRunTestCompositionalThreePhaseLohrenzBrayClarkViscosity.cpp new file mode 100644 index 00000000000..38299b6c451 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/compositional/PVTDriverRunTestCompositionalThreePhaseLohrenzBrayClarkViscosity.cpp @@ -0,0 +1,27 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/* + * PVTDriverRunTestCompositionalThreePhaseLohrenzBrayClarkViscosity.cpp + */ + +#include "constitutiveDrivers/fluid/multiFluid/PVTDriverRunTest.hpp" +#include "constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluid.hpp" + +namespace geos +{ +template void PVTDriver::runTest< constitutive::CompositionalThreePhaseLohrenzBrayClarkViscosity >( + constitutive::CompositionalThreePhaseLohrenzBrayClarkViscosity &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutiveDrivers/fluid/multiFluid/compositional/PVTDriverRunTestCompositionalTwoPhaseConstantViscosity.cpp b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/compositional/PVTDriverRunTestCompositionalTwoPhaseConstantViscosity.cpp new file mode 100644 index 00000000000..7404cb9d035 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/compositional/PVTDriverRunTestCompositionalTwoPhaseConstantViscosity.cpp @@ -0,0 +1,27 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/* + * PVTDriverRunTestCompositionalTwoPhaseConstantViscosity.cpp + */ + +#include "constitutiveDrivers/fluid/multiFluid/PVTDriverRunTest.hpp" +#include "constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluid.hpp" + +namespace geos +{ +template void PVTDriver::runTest< constitutive::CompositionalTwoPhaseConstantViscosity >( + constitutive::CompositionalTwoPhaseConstantViscosity &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutiveDrivers/fluid/multiFluid/compositional/PVTDriverRunTestCompositionalTwoPhaseLohrenzBrayClarkViscosity.cpp b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/compositional/PVTDriverRunTestCompositionalTwoPhaseLohrenzBrayClarkViscosity.cpp new file mode 100644 index 00000000000..f97b8526705 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/compositional/PVTDriverRunTestCompositionalTwoPhaseLohrenzBrayClarkViscosity.cpp @@ -0,0 +1,27 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/* + * PVTDriverRunTestCompositionalTwoPhaseLohrenzBrayClarkViscosity.cpp + */ + +#include "constitutiveDrivers/fluid/multiFluid/PVTDriverRunTest.hpp" +#include "constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluid.hpp" + +namespace geos +{ +template void PVTDriver::runTest< constitutive::CompositionalTwoPhaseLohrenzBrayClarkViscosity >( + constitutive::CompositionalTwoPhaseLohrenzBrayClarkViscosity &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveFluidDriver.cpp b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/reactive/ReactiveFluidDriver.cpp similarity index 97% rename from src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveFluidDriver.cpp rename to src/coreComponents/constitutiveDrivers/fluid/multiFluid/reactive/ReactiveFluidDriver.cpp index e0e826b0f2e..1d0259bcd5c 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveFluidDriver.cpp +++ b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/reactive/ReactiveFluidDriver.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,7 +18,6 @@ */ #include "ReactiveFluidDriver.hpp" -#include "fileIO/Outputs/OutputBase.hpp" #include "constitutive/fluid/multifluid/CO2Brine/functions/PureWaterProperties.hpp" #include "functions/TableFunction.hpp" #include "functions/FunctionManager.hpp" @@ -73,7 +73,7 @@ ReactiveFluidDriver::~ReactiveFluidDriver() {} -void ReactiveFluidDriver::postProcessInput() +void ReactiveFluidDriver::postInputInitialization() { // get number of phases and components diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveFluidDriver.hpp b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/reactive/ReactiveFluidDriver.hpp similarity index 88% rename from src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveFluidDriver.hpp rename to src/coreComponents/constitutiveDrivers/fluid/multiFluid/reactive/ReactiveFluidDriver.hpp index 9982c4db8a1..170f761c704 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveFluidDriver.hpp +++ b/src/coreComponents/constitutiveDrivers/fluid/multiFluid/reactive/ReactiveFluidDriver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -31,8 +32,6 @@ namespace geos { -using namespace constitutive; - /** * @class ReactiveFluidDriver * @@ -49,7 +48,7 @@ class ReactiveFluidDriver : public TaskBase static string catalogName() { return "ReactiveFluidDriver"; } - void postProcessInput() override; + void postInputInitialization() override; virtual bool execute( real64 const GEOS_UNUSED_PARAM( time_n ), real64 const GEOS_UNUSED_PARAM( dt ), @@ -113,7 +112,8 @@ class ReactiveFluidDriver : public TaskBase enum columnKeys { TIME, PRES, TEMP }; ///< Enumeration of "input" column keys for readability - static constexpr real64 m_baselineTol = MultiFluidConstants::baselineTolerance; ///< Comparison tolerance for baseline results + static constexpr real64 m_baselineTol = constitutive::MultiFluidConstants::baselineTolerance; ///< Comparison tolerance for baseline + ///< results }; } /* namespace geos */ diff --git a/src/coreComponents/constitutive/relativePermeability/RelpermDriver.cpp b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriver.cpp similarity index 97% rename from src/coreComponents/constitutive/relativePermeability/RelpermDriver.cpp rename to src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriver.cpp index 0689c2b86d8..06085a50861 100644 --- a/src/coreComponents/constitutive/relativePermeability/RelpermDriver.cpp +++ b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriver.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -86,7 +87,7 @@ void RelpermDriver::outputResults() } -void RelpermDriver::postProcessInput() +void RelpermDriver::postInputInitialization() { constitutive::ConstitutiveManager & constitutiveManager = this->getGroupByPath< constitutive::ConstitutiveManager >( "/Problem/domain/Constitutive" ); diff --git a/src/coreComponents/constitutive/relativePermeability/RelpermDriver.hpp b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriver.hpp similarity index 92% rename from src/coreComponents/constitutive/relativePermeability/RelpermDriver.hpp rename to src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriver.hpp index cbfa1dc4361..426c66bf130 100644 --- a/src/coreComponents/constitutive/relativePermeability/RelpermDriver.hpp +++ b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -31,7 +32,7 @@ class RelpermDriver : public TaskBase static string catalogName() { return "RelpermDriver"; } - void postProcessInput() override; + void postInputInitialization() override; virtual bool execute( real64 const GEOS_UNUSED_PARAM( time_n ), real64 const GEOS_UNUSED_PARAM( dt ), diff --git a/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverBrooksCoreyBakerRunTest.cpp b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverBrooksCoreyBakerRunTest.cpp new file mode 100644 index 00000000000..4fc2d6a03d5 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverBrooksCoreyBakerRunTest.cpp @@ -0,0 +1,23 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "RelpermDriverRunTest.hpp" +#include "constitutive/relativePermeability/BrooksCoreyBakerRelativePermeability.hpp" + + +namespace geos +{ +template void RelpermDriver::runTest< geos::constitutive::BrooksCoreyBakerRelativePermeability >( geos::constitutive::BrooksCoreyBakerRelativePermeability &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverBrooksCoreyRunTest.cpp b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverBrooksCoreyRunTest.cpp new file mode 100644 index 00000000000..a2b0db0fb93 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverBrooksCoreyRunTest.cpp @@ -0,0 +1,23 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "RelpermDriverRunTest.hpp" +#include "constitutive/relativePermeability/BrooksCoreyRelativePermeability.hpp" + + +namespace geos +{ +template void RelpermDriver::runTest< geos::constitutive::BrooksCoreyRelativePermeability >( geos::constitutive::BrooksCoreyRelativePermeability &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverBrooksCoreyStone2RunTest.cpp b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverBrooksCoreyStone2RunTest.cpp new file mode 100644 index 00000000000..12c68c39cf2 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverBrooksCoreyStone2RunTest.cpp @@ -0,0 +1,23 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "RelpermDriverRunTest.hpp" +#include "constitutive/relativePermeability/BrooksCoreyStone2RelativePermeability.hpp" + + +namespace geos +{ +template void RelpermDriver::runTest< geos::constitutive::BrooksCoreyStone2RelativePermeability >( geos::constitutive::BrooksCoreyStone2RelativePermeability &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutive/relativePermeability/RelpermDriverRunTest.hpp b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverRunTest.hpp similarity index 87% rename from src/coreComponents/constitutive/relativePermeability/RelpermDriverRunTest.hpp rename to src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverRunTest.hpp index 38a9b67fc3f..4ae09f0c00c 100644 --- a/src/coreComponents/constitutive/relativePermeability/RelpermDriverRunTest.hpp +++ b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverRunTest.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -15,19 +16,18 @@ #ifndef GEOS_RELPERMDRIVERRUNTEST_HPP_ #define GEOS_RELPERMDRIVERRUNTEST_HPP_ -#include "constitutive/relativePermeability/RelpermDriver.hpp" +#include "constitutiveDrivers/relativePermeability/RelpermDriver.hpp" #include "constitutive/relativePermeability/RelativePermeabilityFields.hpp" -#include "layouts.hpp" +#include "constitutive/relativePermeability/layouts.hpp" namespace geos { -using namespace constitutive; - //specific to Hysteresis template< typename RELPERM_TYPE > -std::enable_if_t< std::is_same< TableRelativePermeabilityHysteresis, RELPERM_TYPE >::value, void > +std::enable_if_t< std::is_same< constitutive::TableRelativePermeabilityHysteresis, + RELPERM_TYPE >::value, void > RelpermDriver::runTest( RELPERM_TYPE & relperm, const arrayView2d< real64 > & table ) { @@ -36,7 +36,7 @@ RelpermDriver::runTest( RELPERM_TYPE & relperm, // create kernel wrapper - typename TableRelativePermeabilityHysteresis::KernelWrapper const kernelWrapper = relperm.createKernelWrapper(); + typename constitutive::TableRelativePermeabilityHysteresis::KernelWrapper const kernelWrapper = relperm.createKernelWrapper(); // set saturation to user specified feed // it is more convenient to provide input in molar, so perform molar to mass conversion here @@ -90,15 +90,15 @@ RelpermDriver::runTest( RELPERM_TYPE & relperm, arrayView2d< real64 const, compflow::USD_PHASE > const saturation = saturationValues.toViewConst(); - auto const & phaseHasHysteresis = relperm.template getReference< array1d< integer > >( TableRelativePermeabilityHysteresis::viewKeyStruct::phaseHasHysteresisString()); + auto const & phaseHasHysteresis = relperm.template getReference< array1d< integer > >( constitutive::TableRelativePermeabilityHysteresis::viewKeyStruct::phaseHasHysteresisString()); arrayView2d< real64, compflow::USD_PHASE > phaseMaxHistoricalVolFraction = relperm.template getField< fields::relperm::phaseMaxHistoricalVolFraction >().reference(); arrayView2d< real64, compflow::USD_PHASE > phaseMinHistoricalVolFraction = relperm.template getField< fields::relperm::phaseMinHistoricalVolFraction >().reference(); arrayView1d< real64 > const drainagePhaseMinVolFraction = relperm.template getReference< array1d< real64 > >( - TableRelativePermeabilityHysteresis::viewKeyStruct::drainagePhaseMinVolumeFractionString()); + constitutive::TableRelativePermeabilityHysteresis::viewKeyStruct::drainagePhaseMinVolumeFractionString()); arrayView1d< real64 > const drainagePhaseMaxVolFraction = relperm.template getReference< array1d< real64 > >( - TableRelativePermeabilityHysteresis::viewKeyStruct::drainagePhaseMaxVolumeFractionString()); + constitutive::TableRelativePermeabilityHysteresis::viewKeyStruct::drainagePhaseMaxVolumeFractionString()); //setting for drainage { @@ -164,7 +164,7 @@ RelpermDriver::runTest( RELPERM_TYPE & relperm, } template< typename RELPERM_TYPE > -std::enable_if_t< !std::is_same< TableRelativePermeabilityHysteresis, RELPERM_TYPE >::value, void > +std::enable_if_t< !std::is_same< constitutive::TableRelativePermeabilityHysteresis, RELPERM_TYPE >::value, void > RelpermDriver::runTest( RELPERM_TYPE & relperm, const arrayView2d< real64 > & table ) { diff --git a/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverTableRelativeHysteresisRunTest.cpp b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverTableRelativeHysteresisRunTest.cpp new file mode 100644 index 00000000000..4ed6420b673 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverTableRelativeHysteresisRunTest.cpp @@ -0,0 +1,23 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "RelpermDriverRunTest.hpp" +#include "constitutive/relativePermeability/TableRelativePermeabilityHysteresis.hpp" + + +namespace geos +{ +template void RelpermDriver::runTest< geos::constitutive::TableRelativePermeabilityHysteresis >( geos::constitutive::TableRelativePermeabilityHysteresis &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverTableRelativeRunTest.cpp b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverTableRelativeRunTest.cpp new file mode 100644 index 00000000000..e5c8a240853 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverTableRelativeRunTest.cpp @@ -0,0 +1,23 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "RelpermDriverRunTest.hpp" +#include "constitutive/relativePermeability/TableRelativePermeability.hpp" + + +namespace geos +{ +template void RelpermDriver::runTest< geos::constitutive::TableRelativePermeability >( geos::constitutive::TableRelativePermeability &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverVanGenuchtenBakerRunTest.cpp b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverVanGenuchtenBakerRunTest.cpp new file mode 100644 index 00000000000..7f441eb5130 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverVanGenuchtenBakerRunTest.cpp @@ -0,0 +1,23 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "RelpermDriverRunTest.hpp" +#include "constitutive/relativePermeability/VanGenuchtenBakerRelativePermeability.hpp" + + +namespace geos +{ +template void RelpermDriver::runTest< geos::constitutive::VanGenuchtenBakerRelativePermeability >( geos::constitutive::VanGenuchtenBakerRelativePermeability &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverVanGenuchtenStone2RunTest.cpp b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverVanGenuchtenStone2RunTest.cpp new file mode 100644 index 00000000000..53b39539a5d --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverVanGenuchtenStone2RunTest.cpp @@ -0,0 +1,23 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "RelpermDriverRunTest.hpp" +#include "constitutive/relativePermeability/VanGenuchtenStone2RelativePermeability.hpp" + + +namespace geos +{ +template void RelpermDriver::runTest< geos::constitutive::VanGenuchtenStone2RelativePermeability >( geos::constitutive::VanGenuchtenStone2RelativePermeability &, arrayView2d< real64 > const & ); +} diff --git a/src/coreComponents/constitutive/solid/TriaxialDriver.cpp b/src/coreComponents/constitutiveDrivers/solid/TriaxialDriver.cpp similarity index 98% rename from src/coreComponents/constitutive/solid/TriaxialDriver.cpp rename to src/coreComponents/constitutiveDrivers/solid/TriaxialDriver.cpp index 4a02fe0e9d7..6dbd8bb13c3 100644 --- a/src/coreComponents/constitutive/solid/TriaxialDriver.cpp +++ b/src/coreComponents/constitutiveDrivers/solid/TriaxialDriver.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,7 +18,6 @@ */ #include "TriaxialDriver.hpp" -#include "fileIO/Outputs/OutputBase.hpp" namespace geos { @@ -74,7 +74,7 @@ TriaxialDriver::~TriaxialDriver() {} -void TriaxialDriver::postProcessInput() +void TriaxialDriver::postInputInitialization() { // initialize table functions diff --git a/src/coreComponents/constitutive/solid/TriaxialDriver.hpp b/src/coreComponents/constitutiveDrivers/solid/TriaxialDriver.hpp similarity index 94% rename from src/coreComponents/constitutive/solid/TriaxialDriver.hpp rename to src/coreComponents/constitutiveDrivers/solid/TriaxialDriver.hpp index ac41efae878..1147e52b0b7 100644 --- a/src/coreComponents/constitutive/solid/TriaxialDriver.hpp +++ b/src/coreComponents/constitutiveDrivers/solid/TriaxialDriver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -31,8 +32,6 @@ namespace geos { -using namespace constitutive; - /** * @class TriaxialDriver * @@ -57,7 +56,7 @@ class TriaxialDriver : public TaskBase static string catalogName() { return "TriaxialDriver"; } - void postProcessInput() override; + void postInputInitialization() override; virtual bool execute( real64 const GEOS_UNUSED_PARAM( time_n ), real64 const GEOS_UNUSED_PARAM( dt ), diff --git a/src/coreComponents/dataRepository/BufferOps.hpp b/src/coreComponents/dataRepository/BufferOps.hpp index 041b97cc687..1601dae424c 100644 --- a/src/coreComponents/dataRepository/BufferOps.hpp +++ b/src/coreComponents/dataRepository/BufferOps.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,6 +19,7 @@ #define GEOS_DATAREPOSITORY_BUFFEROPS_HPP_ #include "common/DataTypes.hpp" +#include "common/logger/Logger.hpp" #include "codingUtilities/Utilities.hpp" #include "codingUtilities/traits.hpp" #include "LvArray/src/limits.hpp" @@ -625,7 +627,7 @@ PackSize( VARPACK && ... pack ) return Pack< false >( junk, pack ... ); } -#ifdef GEOSX_USE_ARRAY_BOUNDS_CHECK +#ifdef GEOS_USE_ARRAY_BOUNDS_CHECK //------------------------------------------------------------------------------ template< bool DO_PACKING, typename T, typename T_INDICES > typename std::enable_if< !is_packable_by_index< T > && @@ -662,7 +664,7 @@ Unpack( buffer_unit_type const * & buffer, arraySlice1d< INDEX_TYPE > const & indices, INDEX_TYPE & length ); -#endif /* GEOSX_USE_ARRAY_BOUNDS_CHECK */ +#endif /* GEOS_USE_ARRAY_BOUNDS_CHECK */ } /* namespace bufferOps */ } /* namespace geos */ diff --git a/src/coreComponents/dataRepository/BufferOpsDevice.cpp b/src/coreComponents/dataRepository/BufferOpsDevice.cpp index 91c40a67bb7..ada2da9b8a9 100644 --- a/src/coreComponents/dataRepository/BufferOpsDevice.cpp +++ b/src/coreComponents/dataRepository/BufferOpsDevice.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -87,15 +88,16 @@ template< bool DO_PACKING, typename T, int NDIM, int USD > typename std::enable_if< can_memcpy< T >, localIndex >::type PackDataDevice( buffer_unit_type * & buffer, ArrayView< T const, NDIM, USD > const & var, - parallelDeviceEvents & events ) + parallelDeviceEvents & GEOS_UNUSED_PARAM( events ) ) { if( DO_PACKING ) { - parallelDeviceStream stream; - events.emplace_back( forAll< parallelDeviceAsyncPolicy<> >( stream, var.size(), [=] GEOS_DEVICE ( localIndex ii ) +// parallelDeviceStream stream; +// events.emplace_back( forAll< parallelDeviceAsyncPolicy<> >( stream, var.size(), [=] GEOS_DEVICE ( localIndex ii ) + forAll< parallelDevicePolicy<> >( var.size(), [=] GEOS_DEVICE ( localIndex ii ) { reinterpret_cast< std::remove_const_t< T > * >( buffer )[ ii ] = var.data()[ ii ]; - } ) ); + } ); } localIndex packedSize = var.size() * sizeof(T); if( DO_PACKING ) @@ -121,13 +123,14 @@ template< typename T, int NDIM, int USD > typename std::enable_if< can_memcpy< T >, localIndex >::type UnpackDataDevice( buffer_unit_type const * & buffer, ArrayView< T, NDIM, USD > const & var, - parallelDeviceEvents & events ) + parallelDeviceEvents & GEOS_UNUSED_PARAM( events ) ) { - parallelDeviceStream stream; - events.emplace_back( forAll< parallelDeviceAsyncPolicy<> >( stream, var.size(), [=] GEOS_DEVICE ( localIndex ii ) + // parallelDeviceStream stream; + // events.emplace_back( forAll< parallelDeviceAsyncPolicy<> >( stream, var.size(), [=] GEOS_DEVICE ( localIndex ii ) + forAll< parallelDevicePolicy<> >( var.size(), [=] GEOS_DEVICE ( localIndex ii ) { var.data()[ ii ] = reinterpret_cast< const T * >( buffer )[ ii ]; - } ) ); + } ); localIndex packedSize = var.size() * sizeof(T); buffer += var.size() * sizeof(T); return packedSize; diff --git a/src/coreComponents/dataRepository/BufferOpsDevice.hpp b/src/coreComponents/dataRepository/BufferOpsDevice.hpp index 8d647ca8322..5bef77f360b 100644 --- a/src/coreComponents/dataRepository/BufferOpsDevice.hpp +++ b/src/coreComponents/dataRepository/BufferOpsDevice.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/BufferOps_inline.hpp b/src/coreComponents/dataRepository/BufferOps_inline.hpp index f1f0553823b..8792e9a153e 100644 --- a/src/coreComponents/dataRepository/BufferOps_inline.hpp +++ b/src/coreComponents/dataRepository/BufferOps_inline.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -642,7 +643,7 @@ localIndex Unpack( buffer_unit_type const * & buffer, return sizeOfUnpackedChars; } -#ifdef GEOSX_USE_ARRAY_BOUNDS_CHECK +#ifdef GEOS_USE_ARRAY_BOUNDS_CHECK template< bool DO_PACKING, typename T, typename INDEX_TYPE > typename std::enable_if< !std::is_trivial< T >::value, localIndex >::type @@ -741,7 +742,7 @@ Unpack( buffer_unit_type const * & buffer, return sizeOfUnpackedChars; } -#endif /* GEOSX_USE_ARRAY_BOUNDS_CHECK */ +#endif /* GEOS_USE_ARRAY_BOUNDS_CHECK */ template< bool DO_PACKING, int USD > localIndex Pack( buffer_unit_type * & buffer, @@ -1526,7 +1527,10 @@ Unpack( buffer_unit_type const * & buffer, relatedObjectGlobalToLocalMap, clearFlag ); - unmappedGlobalIndices[li].insert( unmappedIndices.data(), unmappedIndices.size() ); + if( unmappedIndices.size() > 0 ) + { + unmappedGlobalIndices[li].insert( unmappedIndices.data(), unmappedIndices.size() ); + } } return sizeOfUnpackedChars; } @@ -1643,7 +1647,10 @@ Unpack( buffer_unit_type const * & buffer, // insert unknown global indices related to the local index into an additional mapping to resolve externally unmapped.resize( LvArray::sortedArrayManipulation::makeSortedUnique( unmapped.begin(), unmapped.end() ) ); - unmappedGlobalIndices[li].insert( unmapped.begin(), unmapped.end() ); + if( unmapped.size() > 0 ) + { + unmappedGlobalIndices[li].insert( unmapped.begin(), unmapped.end() ); + } } // If there were element lists that didn't fit in the map, rebuild the whole thing @@ -1761,7 +1768,11 @@ Pack( buffer_unit_type * & buffer, arraySlice1d< globalIndex const > const & relatedObjectLocalToGlobalMap ) { localIndex sizeOfPackedChars = 0; - array1d< globalIndex > junk; + array1d< globalIndex > invalidGlobalIndices( var.size( 1 ) ); + for( localIndex a=0; a( buffer, indices.size() ); for( localIndex a=0; a const & unmappedGI = iterUnmappedGI==unmappedGlobalIndices.end() ? - junk : + invalidGlobalIndices : iterUnmappedGI->second; sizeOfPackedChars += Pack< DO_PACKING >( buffer, diff --git a/src/coreComponents/dataRepository/CMakeLists.txt b/src/coreComponents/dataRepository/CMakeLists.txt index 1b882eb42e5..8d0fc0e09ce 100644 --- a/src/coreComponents/dataRepository/CMakeLists.txt +++ b/src/coreComponents/dataRepository/CMakeLists.txt @@ -1,4 +1,26 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: dataRepository + +Provides the building blocks for the data structure of GEOS objects. +Also contains a wrapper to process entries from an xml file into data types. +#]] + +# # Specify all headers +# set( dataRepository_headers BufferOps.hpp BufferOpsDevice.hpp @@ -11,6 +33,8 @@ set( dataRepository_headers InputFlags.hpp KeyIndexT.hpp KeyNames.hpp + LogLevelsInfo.hpp + LogLevelsRegistry.hpp MappedVector.hpp ObjectCatalog.hpp ReferenceWrapper.hpp @@ -24,7 +48,9 @@ set( dataRepository_headers GroupContext.hpp WrapperContext.hpp ) +# # Specify all sources +# set( dataRepository_sources BufferOpsDevice.cpp ConduitRestart.cpp @@ -35,6 +61,7 @@ set( dataRepository_sources xmlWrapper.cpp DataContext.cpp GroupContext.cpp + LogLevelsRegistry.cpp WrapperContext.cpp ) set( dependencyList ${parallelDeps} codingUtilities ) @@ -50,14 +77,19 @@ if( ENABLE_PYGEOSX ) list( APPEND dependencyList Python3::Python pylvarray ) endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) blt_add_library( NAME dataRepository SOURCES ${dataRepository_sources} HEADERS ${dataRepository_headers} - DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} ) + DEPENDS_ON ${decoratedDependencies} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} + ) target_include_directories( dataRepository PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +install( TARGETS dataRepository LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) if( GEOS_ENABLE_TESTS ) diff --git a/src/coreComponents/dataRepository/ConduitRestart.cpp b/src/coreComponents/dataRepository/ConduitRestart.cpp index c569afd80cd..10e3c4e58f2 100644 --- a/src/coreComponents/dataRepository/ConduitRestart.cpp +++ b/src/coreComponents/dataRepository/ConduitRestart.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -51,7 +52,7 @@ string writeRootFile( conduit::Node & root, string const & rootPath ) conduit::relay::io::save( root, completeRootPath + ".root", "hdf5" ); } - MpiWrapper::barrier( MPI_COMM_GEOSX ); + MpiWrapper::barrier( MPI_COMM_GEOS ); return GEOS_FMT( "{}/rank_{:07}.hdf5", completeRootPath.data(), MpiWrapper::commRank() ); } diff --git a/src/coreComponents/dataRepository/ConduitRestart.hpp b/src/coreComponents/dataRepository/ConduitRestart.hpp index feb6ab216ca..68cf0766e0a 100644 --- a/src/coreComponents/dataRepository/ConduitRestart.hpp +++ b/src/coreComponents/dataRepository/ConduitRestart.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/DataContext.cpp b/src/coreComponents/dataRepository/DataContext.cpp index 8ddf77b3e94..87e9f791750 100644 --- a/src/coreComponents/dataRepository/DataContext.cpp +++ b/src/coreComponents/dataRepository/DataContext.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/DataContext.hpp b/src/coreComponents/dataRepository/DataContext.hpp index 6b30face341..46daeb38506 100644 --- a/src/coreComponents/dataRepository/DataContext.hpp +++ b/src/coreComponents/dataRepository/DataContext.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,9 +21,9 @@ #define GEOS_DATAREPOSITORY_DATACONTEXT_HPP_ #include "common/DataTypes.hpp" -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" #include "xmlWrapper.hpp" -#include "common/Format.hpp" +#include "common/format/Format.hpp" namespace geos { @@ -217,7 +218,7 @@ struct GEOS_FMT_NS::formatter< geos::dataRepository::DataContext > : GEOS_FMT_NS * @param ctx formatting state consisting of the formatting arguments and the output iterator * @return iterator to the output buffer */ - auto format( geos::dataRepository::DataContext const & dataContext, format_context & ctx ) + auto format( geos::dataRepository::DataContext const & dataContext, format_context & ctx ) const { return GEOS_FMT_NS::formatter< std::string >::format( dataContext.toString(), ctx ); } diff --git a/src/coreComponents/dataRepository/DefaultValue.hpp b/src/coreComponents/dataRepository/DefaultValue.hpp index c0d94c182c0..4212244aa72 100644 --- a/src/coreComponents/dataRepository/DefaultValue.hpp +++ b/src/coreComponents/dataRepository/DefaultValue.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/ExecutableGroup.cpp b/src/coreComponents/dataRepository/ExecutableGroup.cpp index 22658578d44..b268730af7e 100644 --- a/src/coreComponents/dataRepository/ExecutableGroup.cpp +++ b/src/coreComponents/dataRepository/ExecutableGroup.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/ExecutableGroup.hpp b/src/coreComponents/dataRepository/ExecutableGroup.hpp index 69fa86db55b..b1751f3e1f0 100644 --- a/src/coreComponents/dataRepository/ExecutableGroup.hpp +++ b/src/coreComponents/dataRepository/ExecutableGroup.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,7 @@ #ifndef GEOS_DATAREPOSITORY_EXECUTABLEGROUP_HPP_ #define GEOS_DATAREPOSITORY_EXECUTABLEGROUP_HPP_ -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include "common/DataTypes.hpp" #include "Group.hpp" diff --git a/src/coreComponents/dataRepository/Group.cpp b/src/coreComponents/dataRepository/Group.cpp index 5be399e8449..440178c2a7d 100644 --- a/src/coreComponents/dataRepository/Group.cpp +++ b/src/coreComponents/dataRepository/Group.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -15,11 +16,11 @@ // Source includes #include "Group.hpp" #include "ConduitRestart.hpp" -#include "codingUtilities/StringUtilities.hpp" +#include "common/format/StringUtilities.hpp" #include "codingUtilities/Utilities.hpp" #include "common/TimingMacros.hpp" #include "GroupContext.hpp" -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) #include "python/PyGroupType.hpp" #endif @@ -49,6 +50,7 @@ Group::Group( string const & name, m_restart_flags( RestartFlags::WRITE_AND_READ ), m_input_flags( InputFlags::INVALID ), m_conduitNode( rootNode[ name ] ), + m_logLevelsRegistry( std::make_unique< LogLevelsRegistry >() ), m_dataContext( std::make_unique< GroupContext >( *this ) ) {} @@ -79,7 +81,6 @@ void Group::deregisterWrapper( string const & name ) m_conduitNode.remove( name ); } - void Group::resize( indexType const newSize ) { forWrappers( [newSize] ( WrapperBase & wrapper ) @@ -242,17 +243,16 @@ void Group::processInputFile( xmlWrapper::xmlNode const & targetNode, } } -void Group::postProcessInputRecursive() +void Group::postInputInitializationRecursive() { + m_logLevelsRegistry = nullptr; for( auto const & subGroupIter : m_subGroups ) { - subGroupIter.second->postProcessInputRecursive(); + subGroupIter.second->postInputInitializationRecursive(); } - postProcessInput(); + postInputInitialization(); } - - void Group::registerDataOnMeshRecursive( Group & meshBodies ) { registerDataOnMesh( meshBodies ); @@ -262,7 +262,6 @@ void Group::registerDataOnMeshRecursive( Group & meshBodies ) } } - Group * Group::createChild( string const & childKey, string const & childName ) { GEOS_ERROR_IF( !(CatalogInterface::hasKeyName( childKey )), @@ -272,7 +271,6 @@ Group * Group::createChild( string const & childKey, string const & childName ) CatalogInterface::factory( childKey, childName, this ) ); } - void Group::printDataHierarchy( integer const indent ) const { GEOS_LOG( string( indent, '\t' ) << getName() << " : " << LvArray::system::demangleType( *this ) ); @@ -644,9 +642,8 @@ void Group::postRestartInitializationRecursive() void Group::enableLogLevelInput() { - string const logLevelString = "logLevel"; - - registerWrapper( logLevelString, &m_logLevel ). + // TODO : Improve the Log Level description to clearly assign a usecase per log level (incoming PR). + registerWrapper( viewKeyStruct::logLevelString(), &m_logLevel ). setApplyDefaultValue( 0 ). setInputFlag( InputFlags::OPTIONAL ). setDescription( "Log level" ); @@ -710,7 +707,7 @@ localIndex Group::getSubGroupIndex( keyType const & key ) const return getSubGroups().getIndex( key ); } -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) PyTypeObject * Group::getPythonType() const { return geos::python::getPyGroupType(); } #endif diff --git a/src/coreComponents/dataRepository/Group.hpp b/src/coreComponents/dataRepository/Group.hpp index 6192f3cddab..a9925c49c77 100644 --- a/src/coreComponents/dataRepository/Group.hpp +++ b/src/coreComponents/dataRepository/Group.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -26,6 +27,8 @@ #include "RestartFlags.hpp" #include "Wrapper.hpp" #include "xmlWrapper.hpp" +#include "LogLevelsInfo.hpp" +#include "LogLevelsRegistry.hpp" #include @@ -142,7 +145,7 @@ class Group using CatalogInterface = dataRepository::CatalogInterface< Group, string const &, Group * const >; /** - * @brief Get the singleton catalog for this class. + * @brief Get the singleton catalog for this Group. * @return reference to the catalog object */ static CatalogInterface::CatalogType & getCatalog(); @@ -337,8 +340,12 @@ class Group "Group " << getDataContext() << " has no child named " << key << std::endl << dumpSubGroupsNames(), std::domain_error ); - - return dynamicCast< T & >( *child ); + T * const castedChild = dynamicCast< T * >( child ); + GEOS_THROW_IF( castedChild == nullptr, + GEOS_FMT( "{} was expected to be a '{}'.", + child->getDataContext(), LvArray::system::demangleType< T >() ), + BadTypeError ); + return *castedChild; } /** @@ -352,8 +359,12 @@ class Group "Group " << getDataContext() << " has no child named " << key << std::endl << dumpSubGroupsNames(), std::domain_error ); - - return dynamicCast< T const & >( *child ); + T const * const castedChild = dynamicCast< T const * >( child ); + GEOS_THROW_IF( castedChild == nullptr, + GEOS_FMT( "{} was expected to be a '{}'.", + child->getDataContext(), LvArray::system::demangleType< T >() ), + BadTypeError ); + return *castedChild; } /** @@ -446,7 +457,6 @@ class Group { using T = std::conditional_t< std::is_const< CONTAINERTYPE >::value, CASTTYPE const, CASTTYPE >; T * const castedContainer = dynamic_cast< T * >( &container ); - if( castedContainer != nullptr ) { lambda( *castedContainer ); @@ -587,6 +597,7 @@ class Group void forSubGroups( LOOKUP_CONTAINER const & subGroupKeys, LAMBDA && lambda ) { localIndex counter = 0; + for( auto const & subgroup : subGroupKeys ) { applyLambdaToContainer< GROUPTYPE, GROUPTYPES... >( getGroup( subgroup ), [&]( auto & castedSubGroup ) @@ -779,10 +790,10 @@ class Group xmlWrapper::xmlNodePos const & nodePos ); /** - * @brief Recursively call postProcessInput() to apply post processing after + * @brief Recursively call postInputInitialization() to apply post processing after * reading input values. */ - void postProcessInputRecursive(); + void postInputInitializationRecursive(); ///@} @@ -854,6 +865,16 @@ class Group ///@} //END_SPHINX_INCLUDE_REGISTER_WRAPPER + /** + * @brief Append a levelCondition and a log description to the description of the wrapped object given a log info struct. + * Must be called in constructor. + * @tparam LOG_LEVEL_INFO The log documentation to add. + * @return void if the trait is verified. + */ + template< typename LOG_LEVEL_INFO > + std::enable_if_t< geos::is_log_level_info< LOG_LEVEL_INFO >, void > + addLogLevel(); + /** * @name Schema generation methods */ @@ -1414,6 +1435,15 @@ class Group */ void setInputFlags( InputFlags flags ) { m_input_flags = flags; } + /** + * @brief Structure to hold scoped key names + */ + struct viewKeyStruct + { + /// @return String for the logLevel wrapper + static constexpr char const * logLevelString() { return "logLevel"; } + }; + ///@} /** @@ -1460,7 +1490,9 @@ class Group */ void loadFromConduit(); - /// Enable verbosity input for object + /** + * @deprecated will be remove and replace by addLogLevel + */ void enableLogLevelInput(); /** @@ -1482,7 +1514,7 @@ class Group * @brief Return PyGroup type. * @return Return PyGroup type. */ -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) virtual PyTypeObject * getPythonType() const; #endif @@ -1500,7 +1532,7 @@ class Group * This function provides capability to post process input values prior to * any other initialization operations. */ - virtual void postProcessInput() {} + virtual void postInputInitialization() {} /** * @brief Called by Initialize() prior to initializing sub-Groups. @@ -1597,6 +1629,8 @@ class Group /// Verbosity flag for group logs integer m_logLevel; + + //END_SPHINX_INCLUDE_02 /// Restart flag for this group... and subsequently all wrappers in this group. @@ -1608,6 +1642,9 @@ class Group /// Reference to the conduit::Node that mirrors this group conduit::Node & m_conduitNode; + // Keep track of log levels & descriptions + std::unique_ptr< LogLevelsRegistry > m_logLevelsRegistry; + /// A DataContext object used to provide contextual information on this Group, /// if it is created from an input XML file, the line or offset in that file. std::unique_ptr< DataContext > m_dataContext; @@ -1694,6 +1731,24 @@ Wrapper< T > & Group::registerWrapper( string const & name, return rval; } +template< typename LOG_LEVEL_INFO > +std::enable_if_t< geos::is_log_level_info< LOG_LEVEL_INFO >, void > +Group::addLogLevel() +{ + GEOS_ERROR_IF( m_logLevelsRegistry == nullptr, "You cannot call addLogLevel after schema generation" ); + + Wrapper< integer > * wrapper = getWrapperPointer< integer >( viewKeyStruct::logLevelString() ); + if( wrapper == nullptr ) + { + wrapper = ®isterWrapper( viewKeyStruct::logLevelString(), &m_logLevel ); + wrapper->setApplyDefaultValue( 0 ); + wrapper->setInputFlag( InputFlags::OPTIONAL ); + } + m_logLevelsRegistry->addEntry( LOG_LEVEL_INFO::getMinLogLevel(), + LOG_LEVEL_INFO::getDescription() ); + wrapper->setDescription( m_logLevelsRegistry->buildLogLevelDescription()); +} + } /* end namespace dataRepository */ } /* end namespace geos */ diff --git a/src/coreComponents/dataRepository/GroupContext.cpp b/src/coreComponents/dataRepository/GroupContext.cpp index 3f63d2d92aa..d21771cfbdb 100644 --- a/src/coreComponents/dataRepository/GroupContext.cpp +++ b/src/coreComponents/dataRepository/GroupContext.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/GroupContext.hpp b/src/coreComponents/dataRepository/GroupContext.hpp index 327f00f5251..476540f98eb 100644 --- a/src/coreComponents/dataRepository/GroupContext.hpp +++ b/src/coreComponents/dataRepository/GroupContext.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/HistoryDataSpec.hpp b/src/coreComponents/dataRepository/HistoryDataSpec.hpp index 098f5c24fce..f1d083f1d2a 100644 --- a/src/coreComponents/dataRepository/HistoryDataSpec.hpp +++ b/src/coreComponents/dataRepository/HistoryDataSpec.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -21,6 +22,7 @@ #include "codingUtilities/traits.hpp" #include "common/DataTypes.hpp" +#include "common/logger/Logger.hpp" #include "LvArray/src/Array.hpp" namespace geos diff --git a/src/coreComponents/dataRepository/InputFlags.hpp b/src/coreComponents/dataRepository/InputFlags.hpp index c48d0162c65..4390eec54b0 100644 --- a/src/coreComponents/dataRepository/InputFlags.hpp +++ b/src/coreComponents/dataRepository/InputFlags.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #define GEOS_DATAREPOSITORY_INPUTFLAGS_HPP_ #include "common/DataTypes.hpp" -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" namespace geos { diff --git a/src/coreComponents/dataRepository/KeyIndexT.hpp b/src/coreComponents/dataRepository/KeyIndexT.hpp index 6d56de608af..2812bc1ca8f 100644 --- a/src/coreComponents/dataRepository/KeyIndexT.hpp +++ b/src/coreComponents/dataRepository/KeyIndexT.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/KeyNames.hpp b/src/coreComponents/dataRepository/KeyNames.hpp index 082b6db81fc..4c46b69a266 100644 --- a/src/coreComponents/dataRepository/KeyNames.hpp +++ b/src/coreComponents/dataRepository/KeyNames.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/LogLevelsInfo.hpp b/src/coreComponents/dataRepository/LogLevelsInfo.hpp new file mode 100644 index 00000000000..7e50ece2eb4 --- /dev/null +++ b/src/coreComponents/dataRepository/LogLevelsInfo.hpp @@ -0,0 +1,91 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file LogLevelsInfo.hpp + * This file contains log level information infrastructure and the mecanism to ensure LOG_LEVEL_INFO structure is valid + */ +#ifndef GEOS_COMMON_LOGLEVELSINFO_HPP +#define GEOS_COMMON_LOGLEVELSINFO_HPP + +#include "common/DataTypes.hpp" +#include "common/format/Format.hpp" + +namespace geos +{ + +/** + * @brief Trait used to check whether a LOG_LEVEL_INFO structure is valid. + * @tparam LOG_LEVEL_INFO The log level structure to check. + * + * A log level structure must have this following + * struct LogName + * { + * static constexpr int getMinLogLevel() { return 1; } + * static constexpr std::string_view getDescription() { return "Log level description"; } + * }; + */ +template< typename LOG_LEVEL_INFO > +static constexpr bool is_log_level_info = + std::is_same_v< integer, decltype(LOG_LEVEL_INFO::getMinLogLevel()) > && + std::is_same_v< std::string_view, decltype(LOG_LEVEL_INFO::getDescription()) >; + +/** + * @brief Verify if a log level is active + * @tparam LOG_LEVEL_INFO The structure containing log level information. + * @param level Log level to be checked. + * @return `true` if the log level is active, `false` otherwise. + * @pre `LOG_LEVEL_INFO` must satisfy `logInfo::is_log_level_info`. + * + */ +template< typename LOG_LEVEL_INFO > +std::enable_if_t< is_log_level_info< LOG_LEVEL_INFO >, bool > +isLogLevelActive( integer level ) +{ + return level >= LOG_LEVEL_INFO::getMinLogLevel(); +} + +/** ThOSE 3 macros would replace the ones in Logger.hpp */ +/** + * @brief Output messages based on current Group's log level. + * @param[in] logInfoStruct Strut containing log level desscription + * @param[in] msg a message to log (any expression that can be stream inserted) + */ +#define GEOS_LOG_LEVEL_INFO( logInfoStruct, msg ) GEOS_LOG_IF( isLogLevelActive< logInfoStruct >( this->getLogLevel() ), msg ); + +/** + * @brief Output messages (only on rank 0) based on current Group's log level. + * @param[in] logInfoStruct Strut containing log level desscription + * @param[in] msg a message to log (any expression that can be stream inserted) + */ +#define GEOS_LOG_LEVEL_INFO_RANK_0( logInfoStruct, msg ) GEOS_LOG_RANK_0_IF( isLogLevelActive< logInfoStruct >( this->getLogLevel() ), msg ); + +/** + * @brief Output messages (with one line per rank) based on current Group's log level. + * @param[in] logInfoStruct Strut containing log level desscription + * @param[in] msg a message to log (any expression that can be stream inserted) + */ +#define GEOS_LOG_LEVEL_INFO_BY_RANK( logInfoStruct, msg ) GEOS_LOG_RANK_IF( isLogLevelActive< logInfoStruct >( this->getLogLevel() ), msg ); + +/** + * @brief Output messages (only on rank 0) based on current Group's log level without the line return. + * @param[in] logInfoStruct Strut containing log level desscription + * @param[in] msg a message to log (any expression that can be stream inserted) + */ +#define GEOS_LOG_LEVEL_INFO_RANK_0_NLR( logInfoStruct, msg ) GEOS_LOG_RANK_0_IF_NLR( isLogLevelActive< logInfoStruct >( this->getLogLevel() ), msg ); + +} + +#endif // GEOS_COMMON_LOGLEVELSINFO_HPP diff --git a/src/coreComponents/dataRepository/LogLevelsRegistry.cpp b/src/coreComponents/dataRepository/LogLevelsRegistry.cpp new file mode 100644 index 00000000000..3f81ef9e285 --- /dev/null +++ b/src/coreComponents/dataRepository/LogLevelsRegistry.cpp @@ -0,0 +1,44 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "LogLevelsRegistry.hpp" + +namespace geos +{ + +void LogLevelsRegistry::addEntry( integer condition, std::string_view description ) +{ + m_logLevelsDescriptions[condition].push_back( string( description ) ); +} + +string LogLevelsRegistry::buildLogLevelDescription() const +{ + std::ostringstream description; + description << "Sets the level of information to write in the standard output (the console typically).\n" + "Level 0 outputs no specific information for this solver. Higher levels require more outputs."; + for( auto const & [logLevel, logDescriptions] : m_logLevelsDescriptions ) + { + description << GEOS_FMT( "\n{}\n", logLevel ); + for( size_t idxDesc = 0; idxDesc < logDescriptions.size(); idxDesc++ ) + { + description << " - " << logDescriptions[idxDesc]; + if( idxDesc != logDescriptions.size() - 1 ) + description << '\n'; + } + } + return description.str(); +} + +} diff --git a/src/coreComponents/dataRepository/LogLevelsRegistry.hpp b/src/coreComponents/dataRepository/LogLevelsRegistry.hpp new file mode 100644 index 00000000000..d96f9a79d4e --- /dev/null +++ b/src/coreComponents/dataRepository/LogLevelsRegistry.hpp @@ -0,0 +1,61 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file LogLevelsRegistry.hpp + */ + +#ifndef GEOS_COMMON_LOGLEVELSREGISTRY_HPP +#define GEOS_COMMON_LOGLEVELSREGISTRY_HPP + +#include "common/DataTypes.hpp" +#include "common/format/Format.hpp" + +namespace geos +{ + +/** + * @brief Keep track of log level documention for a group + */ +class LogLevelsRegistry +{ +public: + + /** + * @brief Add a log description for a wrapper + * @param level The minimum log level + * @param description The description for the log level + */ + void addEntry( integer level, std::string_view description ); + + /** + * @brief Construct the log level string description for a wrapper + * @return The log level string description + */ + string buildLogLevelDescription() const; + +private: + + /** + * @brief Map for building the log level string for each wrapper. + * key : a logLevel condition, values : a set of description for a corresponding loglevel. + */ + std::map< integer, std::vector< std::string > > m_logLevelsDescriptions; + +}; + +} + +#endif diff --git a/src/coreComponents/dataRepository/MappedVector.hpp b/src/coreComponents/dataRepository/MappedVector.hpp index 0de9284e815..59f7967d991 100644 --- a/src/coreComponents/dataRepository/MappedVector.hpp +++ b/src/coreComponents/dataRepository/MappedVector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -22,7 +23,7 @@ // Source includes #include "KeyIndexT.hpp" #include "common/GeosxMacros.hpp" -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" #include "LvArray/src/limits.hpp" // System includes diff --git a/src/coreComponents/dataRepository/ObjectCatalog.hpp b/src/coreComponents/dataRepository/ObjectCatalog.hpp index bc74ffd9b72..dbf089033a6 100644 --- a/src/coreComponents/dataRepository/ObjectCatalog.hpp +++ b/src/coreComponents/dataRepository/ObjectCatalog.hpp @@ -1,19 +1,21 @@ -#ifndef GEOS_DATAREPOSITORY_OBJECTCATALOG_HPP_ -#define GEOS_DATAREPOSITORY_OBJECTCATALOG_HPP_ /* * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ +#ifndef GEOS_DATAREPOSITORY_OBJECTCATALOG_HPP_ +#define GEOS_DATAREPOSITORY_OBJECTCATALOG_HPP_ + /** * @file ObjectCatalog.hpp * The ObjectCatalog acts as a statically initialized factory. It functions in @@ -25,8 +27,8 @@ * of a */ -#include "common/Logger.hpp" -#include "codingUtilities/StringUtilities.hpp" +#include "common/logger/Logger.hpp" +#include "common/format/StringUtilities.hpp" #include "LvArray/src/system.hpp" #include diff --git a/src/coreComponents/dataRepository/ReferenceWrapper.hpp b/src/coreComponents/dataRepository/ReferenceWrapper.hpp index 76fedb42f2a..6fb666b3e9f 100644 --- a/src/coreComponents/dataRepository/ReferenceWrapper.hpp +++ b/src/coreComponents/dataRepository/ReferenceWrapper.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/RestartFlags.hpp b/src/coreComponents/dataRepository/RestartFlags.hpp index caea13b7c5b..f6fc765d94a 100644 --- a/src/coreComponents/dataRepository/RestartFlags.hpp +++ b/src/coreComponents/dataRepository/RestartFlags.hpp @@ -2,23 +2,26 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ -#ifndef GEOS_DATAREPOSITORY_RESTARTFLAGS_HPP_ -#define GEOS_DATAREPOSITORY_RESTARTFLAGS_HPP_ - /** * @file RestartFlags.hpp */ +#ifndef GEOS_DATAREPOSITORY_RESTARTFLAGS_HPP_ +#define GEOS_DATAREPOSITORY_RESTARTFLAGS_HPP_ + +#include "common/logger/Logger.hpp" + namespace geos { namespace dataRepository diff --git a/src/coreComponents/dataRepository/Utilities.cpp b/src/coreComponents/dataRepository/Utilities.cpp index 2794be33c2f..03be7e7f721 100644 --- a/src/coreComponents/dataRepository/Utilities.cpp +++ b/src/coreComponents/dataRepository/Utilities.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -76,7 +77,7 @@ void printMemoryAllocation( Group const & group, integer const indent, real64 co globalAllocations.data(), numValues, 0, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); // reduce data across ranks (min, max, sum) if( MpiWrapper::commRank()==0 ) diff --git a/src/coreComponents/dataRepository/Utilities.hpp b/src/coreComponents/dataRepository/Utilities.hpp index bb7bdc766b9..93a2084d15e 100644 --- a/src/coreComponents/dataRepository/Utilities.hpp +++ b/src/coreComponents/dataRepository/Utilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/Wrapper.hpp b/src/coreComponents/dataRepository/Wrapper.hpp index 404225490af..344806e5362 100644 --- a/src/coreComponents/dataRepository/Wrapper.hpp +++ b/src/coreComponents/dataRepository/Wrapper.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -410,7 +411,7 @@ class Wrapper final : public WrapperBase virtual void resize( localIndex const newSize ) override { wrapperHelpers::move( *m_data, hostMemorySpace, true ); - wrapperHelpers::resizeDefault( reference(), newSize, m_default ); + wrapperHelpers::resizeDefault( reference(), newSize, m_default, this->getName() ); } /// @cond DO_NOT_DOCUMENT @@ -893,6 +894,15 @@ class Wrapper final : public WrapperBase return *this; } + /** + * @copydoc WrapperBase::appendDescription(string const &) + */ + Wrapper< T > & appendDescription( string const & description ) + { + WrapperBase::appendDescription( description ); + return *this; + } + /** * @copydoc WrapperBase::setRegisteringObjects(string const &) */ @@ -931,7 +941,7 @@ class Wrapper final : public WrapperBase // void tvTemplateInstantiation(); #endif -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) virtual PyObject * createPythonObject( ) override { return wrapperHelpers::createPythonObject( reference() ); } #endif diff --git a/src/coreComponents/dataRepository/WrapperBase.cpp b/src/coreComponents/dataRepository/WrapperBase.cpp index d1d660754d0..306878ab9e6 100644 --- a/src/coreComponents/dataRepository/WrapperBase.cpp +++ b/src/coreComponents/dataRepository/WrapperBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/WrapperBase.hpp b/src/coreComponents/dataRepository/WrapperBase.hpp index 542863e03b9..36b74c84971 100644 --- a/src/coreComponents/dataRepository/WrapperBase.hpp +++ b/src/coreComponents/dataRepository/WrapperBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -26,7 +27,7 @@ #include "HistoryDataSpec.hpp" #include "DataContext.hpp" -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) #include "LvArray/src/python/python.hpp" #endif @@ -508,6 +509,17 @@ class WrapperBase return *this; } + /** + * @brief Add up more text to the existing description string of the wrapper. + * @param description the description to add to the end of the previous one. + * @return a pointer to this wrapper + */ + WrapperBase & appendDescription( string const & description ) + { + m_description += description; + return *this; + } + /** * @brief Get the description string of the wrapper. * @return this wrapper's description string @@ -642,7 +654,7 @@ class WrapperBase // static int TV_ttf_display_type( const WrapperBase * wrapper); #endif -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) /** * @brief Return a Python object representing the wrapped object. * @return A Python object representing the wrapped object. diff --git a/src/coreComponents/dataRepository/WrapperContext.cpp b/src/coreComponents/dataRepository/WrapperContext.cpp index b9aa00ff731..92f52ba8708 100644 --- a/src/coreComponents/dataRepository/WrapperContext.cpp +++ b/src/coreComponents/dataRepository/WrapperContext.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/WrapperContext.hpp b/src/coreComponents/dataRepository/WrapperContext.hpp index d948a0334b9..78fd48fb6f1 100644 --- a/src/coreComponents/dataRepository/WrapperContext.hpp +++ b/src/coreComponents/dataRepository/WrapperContext.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/docs/Group.rst b/src/coreComponents/dataRepository/docs/Group.rst index 39547980be3..370ac8937b9 100644 --- a/src/coreComponents/dataRepository/docs/Group.rst +++ b/src/coreComponents/dataRepository/docs/Group.rst @@ -119,3 +119,9 @@ Looping Interface :language: c++ :start-after: //START_SPHINX_INCLUDE_LOOP_INTERFACE :end-before: //END_SPHINX_INCLUDE_LOOP_INTERFACE + + +Doxygen API documentation +------------------------- + +`Group API <../../../doxygen_output/html/classgeos_1_1data_repository_1_1_group.html>`_ diff --git a/src/coreComponents/dataRepository/docs/MappedVector.rst b/src/coreComponents/dataRepository/docs/MappedVector.rst index 260c448d376..22cb211d39b 100644 --- a/src/coreComponents/dataRepository/docs/MappedVector.rst +++ b/src/coreComponents/dataRepository/docs/MappedVector.rst @@ -41,7 +41,7 @@ Element access In addition to these, an STL-conformant iterator interface is available via ``begin()`` and ``end()`` methods. The type iterated over is a key-pointer pair (provided as `value_type` alias). -API documentation ------------------ +Doxygen API documentation +------------------------- -`MappedVector <../../../doxygen_output/html/classgeos_1_1_mapped_vector.html>`_ +`MappedVector API <../../../doxygen_output/html/classgeos_1_1_mapped_vector.html>`_ diff --git a/src/coreComponents/dataRepository/docs/Wrapper.rst b/src/coreComponents/dataRepository/docs/Wrapper.rst index 27f4b8815d9..e7f44040f38 100644 --- a/src/coreComponents/dataRepository/docs/Wrapper.rst +++ b/src/coreComponents/dataRepository/docs/Wrapper.rst @@ -124,7 +124,7 @@ The type ``DefaultValue`` is used to store the default value for the wrapper. ``DefaultValue`` is actually not a type but an alias for another internal struct. As such, it cannot currently be specialized for a user's custom type. -API documentation ------------------ +Doxygen API documentation +------------------------- -`Wrapper <../../../doxygen_output/html/classgeos_1_1data_repository_1_1_wrapper.html>`_ +`Wrapper API <../../../doxygen_output/html/classgeos_1_1data_repository_1_1_wrapper.html>`_ diff --git a/src/coreComponents/dataRepository/docs/dataRepository.rst b/src/coreComponents/dataRepository/docs/dataRepository.rst index 16b82289bba..221cb8823cf 100644 --- a/src/coreComponents/dataRepository/docs/dataRepository.rst +++ b/src/coreComponents/dataRepository/docs/dataRepository.rst @@ -6,14 +6,16 @@ Data Repository The GEOS "Data Repository" is intended to provide the building blocks for the code structure within GEOS. The "Data Repository" provides a general capability to store arbitrary data and objects in a hierarchical -structure, similar to a standard file system. +structure, similar to a standard file system. The "Wrapper" object is a generic container for any object, +and provides a standard interface for accessing an object and performing standard operations. +The "Group" object is a container for "Wrapper" and other "Group" objects. -The components/classes of the data structure that a developer will require some knowledge of are: +The components/classes of the data structure that a developer should have some knowledge of are: .. toctree:: :maxdepth: 2 - /coreComponents/dataRepository/docs/MappedVector /coreComponents/dataRepository/docs/Group /coreComponents/dataRepository/docs/Wrapper /coreComponents/dataRepository/docs/ObjectCatalog + /coreComponents/dataRepository/docs/MappedVector diff --git a/src/coreComponents/dataRepository/python/PyGroup.cpp b/src/coreComponents/dataRepository/python/PyGroup.cpp index aa84c8e4019..9fa25b2db3c 100644 --- a/src/coreComponents/dataRepository/python/PyGroup.cpp +++ b/src/coreComponents/dataRepository/python/PyGroup.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/dataRepository/python/PyGroup.hpp b/src/coreComponents/dataRepository/python/PyGroup.hpp index f93efe62800..80af2282c50 100644 --- a/src/coreComponents/dataRepository/python/PyGroup.hpp +++ b/src/coreComponents/dataRepository/python/PyGroup.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/dataRepository/python/PyGroupType.hpp b/src/coreComponents/dataRepository/python/PyGroupType.hpp index b620ed71673..df0879ae86e 100644 --- a/src/coreComponents/dataRepository/python/PyGroupType.hpp +++ b/src/coreComponents/dataRepository/python/PyGroupType.hpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #ifndef GEOS_PYTHON_PYGROUPTYPE_HPP_ #define GEOS_PYTHON_PYGROUPTYPE_HPP_ diff --git a/src/coreComponents/dataRepository/python/PyWrapper.cpp b/src/coreComponents/dataRepository/python/PyWrapper.cpp index d6537e095b7..68b620986c7 100644 --- a/src/coreComponents/dataRepository/python/PyWrapper.cpp +++ b/src/coreComponents/dataRepository/python/PyWrapper.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/dataRepository/python/PyWrapper.hpp b/src/coreComponents/dataRepository/python/PyWrapper.hpp index 2e9dc9bdb8c..c059459e397 100644 --- a/src/coreComponents/dataRepository/python/PyWrapper.hpp +++ b/src/coreComponents/dataRepository/python/PyWrapper.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/dataRepository/unitTests/CMakeLists.txt b/src/coreComponents/dataRepository/unitTests/CMakeLists.txt index 14386e0b842..b55a26c7460 100644 --- a/src/coreComponents/dataRepository/unitTests/CMakeLists.txt +++ b/src/coreComponents/dataRepository/unitTests/CMakeLists.txt @@ -1,13 +1,14 @@ # Specify list of tests set( dataRepository_tests testDefaultValue.cpp + testPacking.cpp testWrapper.cpp testXmlWrapper.cpp testBufferOps.cpp ) set( dependencyList ${parallelDeps} gtest dataRepository ) -if( ENABLE_CUDA_NVTOOLSEXT ) +if( ENABLE_CUDA AND ENABLE_CUDA_NVTOOLSEXT ) list( APPEND dependencyList CUDA::nvToolsExt ) endif() diff --git a/src/coreComponents/dataRepository/unitTests/testBufferOps.cpp b/src/coreComponents/dataRepository/unitTests/testBufferOps.cpp index f84b83bc709..bc7fb8357b1 100644 --- a/src/coreComponents/dataRepository/unitTests/testBufferOps.cpp +++ b/src/coreComponents/dataRepository/unitTests/testBufferOps.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/unitTests/testDefaultValue.cpp b/src/coreComponents/dataRepository/unitTests/testDefaultValue.cpp index 345a6da8b2e..eef51a81bf8 100644 --- a/src/coreComponents/dataRepository/unitTests/testDefaultValue.cpp +++ b/src/coreComponents/dataRepository/unitTests/testDefaultValue.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/unitTests/dataRepositoryTests/testPacking.cpp b/src/coreComponents/dataRepository/unitTests/testPacking.cpp similarity index 78% rename from src/coreComponents/unitTests/dataRepositoryTests/testPacking.cpp rename to src/coreComponents/dataRepository/unitTests/testPacking.cpp index 1173a76d4d3..32b31f7c1b6 100644 --- a/src/coreComponents/unitTests/dataRepositoryTests/testPacking.cpp +++ b/src/coreComponents/dataRepository/unitTests/testPacking.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,13 +18,11 @@ #include "LvArray/src/Array.hpp" #include "dataRepository/BufferOps.hpp" #include "dataRepository/BufferOpsDevice.hpp" -#include "mainInterface/initialization.hpp" -#include "mesh/mpiCommunications/CommunicationTools.hpp" - #include "dataRepository/wrapperHelpers.hpp" #include #include +#include using namespace geos; @@ -116,6 +115,32 @@ TEST( testPacking, testTensorPacking ) EXPECT_TRUE( tns[0][ii] = unp[0][ii] ); } +// void printArray( arrayView1d< R1Tensor const > const & arr, +// arrayView1d< R1Tensor const > const & unpackArray ) +// { +// printf( "arr.size() = %d\n", arr.size() ); +// printf( "unpackArray.size() = %d\n", unpackArray.size() ); + +// for( localIndex ii = 0; ii < unpackArray.size(); ++ii ) +// { +// if( !( arr[ii] == unpackArray[ii] ) ) +// { +// printf( "arr[%d] = ( %f, %f, %f )\n", ii, arr[ii][0], arr[ii][1], arr[ii][2] ); +// printf( "unPackarray[%d] = ( %f, %f, %f ) : ", ii, unpackArray[ii][0], unpackArray[ii][1], unpackArray[ii][2] ); + +// forAll< geos::parallelDevicePolicy<1> >( 1, [=] GEOS_DEVICE ( localIndex ) +// { +// printf( "( %f, %f, %f ) : ", unpackArray[ii][0], unpackArray[ii][1], unpackArray[ii][2] ); +// } ); + +// forAll< serialPolicy >( 1, [=]( localIndex ) +// { +// printf( "( %f, %f, %f )\n", unpackArray[ii][0], unpackArray[ii][1], unpackArray[ii][2] ); +// } ); +// } +// } +// } + TEST( testPacking, testPackingDevice ) { std::srand( std::time( nullptr )); @@ -134,15 +159,32 @@ TEST( testPacking, testPackingDevice ) buffer_type buf( calc_size ); buffer_unit_type * buffer = &buf[0]; bufferOps::PackDevice< true >( buffer, veloc.toViewConst(), packEvents ); - waitAllDeviceEvents( packEvents ); + // waitAllDeviceEvents( packEvents ); + + // R1Tensor const * const castedBuffer = reinterpret_cast< R1Tensor const * >( &buf[16] ); + // for( localIndex ii = 0; ii < size; ++ii ) + // { + // printf( " %d = ( %f, %f, %f ) != ( %f, %f, %f )\n", ii, veloc[ii][0], veloc[ii][1], veloc[ii][2], castedBuffer[ii][0], + // castedBuffer[ii][1], castedBuffer[ii][2] ); + // } buffer_unit_type const * cbuffer = &buf[0]; parallelDeviceEvents unpackEvents; bufferOps::UnpackDevice( cbuffer, unpacked.toView(), unpackEvents ); waitAllDeviceEvents( unpackEvents ); unpacked.move( hostMemorySpace ); + +// printArray( veloc, unpacked.toViewConst() ); + for( localIndex ii = 0; ii < size; ++ii ) + { EXPECT_EQ( veloc[ii], unpacked[ii] ); +// if( !(veloc[ii] == unpacked[ii]) ) +// { +// printf( " veloc[%d] = ( %f, %f, %f )\n", ii, veloc[ii][0], veloc[ii][1], veloc[ii][2] ); +// printf( " unpacked[%d] = ( %f, %f, %f )\n", ii, unpacked[ii][0], unpacked[ii][1], unpacked[ii][2] ); +// } + } } TEST( testPacking, testPackingDeviceHelper ) @@ -221,8 +263,6 @@ TEST( testPacking, testPackByIndexDevice ) int main( int ac, char * av[] ) { ::testing::InitGoogleTest( &ac, av ); - geos::basicSetup( ac, av ); int const result = RUN_ALL_TESTS(); - geos::basicCleanup(); return result; } diff --git a/src/coreComponents/dataRepository/unitTests/testReferenceWrapper.cpp b/src/coreComponents/dataRepository/unitTests/testReferenceWrapper.cpp index 451ce094d49..1a7979cf541 100644 --- a/src/coreComponents/dataRepository/unitTests/testReferenceWrapper.cpp +++ b/src/coreComponents/dataRepository/unitTests/testReferenceWrapper.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/unitTests/testWrapper.cpp b/src/coreComponents/dataRepository/unitTests/testWrapper.cpp index 517615afe2d..d04fd2b5440 100644 --- a/src/coreComponents/dataRepository/unitTests/testWrapper.cpp +++ b/src/coreComponents/dataRepository/unitTests/testWrapper.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/dataRepository/unitTests/testXmlWrapper.cpp b/src/coreComponents/dataRepository/unitTests/testXmlWrapper.cpp index 87ac3a888d6..fba0eec3ab4 100644 --- a/src/coreComponents/dataRepository/unitTests/testXmlWrapper.cpp +++ b/src/coreComponents/dataRepository/unitTests/testXmlWrapper.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -15,6 +16,7 @@ #include #include "dataRepository/xmlWrapper.hpp" +#include "common/format/EnumStrings.hpp" using namespace geos; @@ -327,6 +329,32 @@ INSTANTIATE_TEST_SUITE_P( std::make_tuple( "1 2", 0, true ))); +enum class TestEnum { None, Default, Value, Value2 }; +ENUM_STRINGS( TestEnum, "None", "Default", "Value", "Value2" ); + +class enumAttributeTestFixture : public AttributeReadTestFixture< TestEnum > {}; + +TEST_P( enumAttributeTestFixture, testParsing ) +{ + testParams = GetParam(); + this->test(); +} + +INSTANTIATE_TEST_SUITE_P( + enumAttributeTests, + enumAttributeTestFixture, + ::testing::Values( std::make_tuple( "None", TestEnum::None, false ), + std::make_tuple( "Default", TestEnum::Default, false ), + std::make_tuple( "Value", TestEnum::Value, false ), + std::make_tuple( "Value2", TestEnum::Value2, false ), + std::make_tuple( "0", TestEnum( 0 ), true ), + std::make_tuple( "4.", TestEnum( 0 ), true ), + std::make_tuple( "alpha", TestEnum( 0 ), true ), + std::make_tuple( "Val", TestEnum( 0 ), true ), + std::make_tuple( "Def ault", TestEnum( 0 ), true ), + std::make_tuple( "None123", TestEnum( 0 ), true ) ) ); + + TEST( testXmlWrapper, testGroupNamesFormats ) { struct GroupNameTest diff --git a/src/coreComponents/dataRepository/wrapperHelpers.hpp b/src/coreComponents/dataRepository/wrapperHelpers.hpp index b5a0c385050..7b66b1b2178 100644 --- a/src/coreComponents/dataRepository/wrapperHelpers.hpp +++ b/src/coreComponents/dataRepository/wrapperHelpers.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -32,8 +33,9 @@ #include "common/GeosxMacros.hpp" #include "common/Span.hpp" #include "codingUtilities/traits.hpp" +#include "LvArray/src/system.hpp" -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) #include "LvArray/src/python/python.hpp" #endif @@ -187,18 +189,40 @@ resize( T & GEOS_UNUSED_PARAM( value ), localIndex const GEOS_UNUSED_PARAM( newSize ) ) {} - -template< typename T, int NDIM, typename PERMUTATION > -inline std::enable_if_t< DefaultValue< Array< T, NDIM, PERMUTATION > >::has_default_value > -resizeDefault( Array< T, NDIM, PERMUTATION > & value, +template< typename T > +inline std::enable_if_t< traits::HasMemberFunction_resizeDefault< T > && + DefaultValue< T >::has_default_value > +resizeDefault( T & value, localIndex const newSize, - DefaultValue< Array< T, NDIM, PERMUTATION > > const & defaultValue ) + DefaultValue< T > const & defaultValue, + string const & ) { value.resizeDefault( newSize, defaultValue.value ); } template< typename T > -inline void -resizeDefault( T & value, localIndex const newSize, DefaultValue< T > const & GEOS_UNUSED_PARAM( defaultValue ) ) -{ resize( value, newSize ); } +inline std::enable_if_t< !( traits::HasMemberFunction_resizeDefault< T > && + DefaultValue< T >::has_default_value ) > +resizeDefault( T & value, + localIndex const newSize, + DefaultValue< T > const & GEOS_UNUSED_PARAM( defaultValue ), + string const & name ) +{ +#if !defined(NDEBUG) + GEOS_LOG_RANK_0( GEOS_FMT( "Warning: For Wrapper<{}>::name() = {}:\n" + " wrapperHelpers::resizeDefault<{}>() called, but the SFINAE filter failed:\n" + " traits::HasMemberFunction_resizeDefault< {} > = {}\n " + " DefaultValue< {} >::has_default_value = {}", + LvArray::system::demangleType< T >(), + name, + LvArray::system::demangleType< T >(), + LvArray::system::demangleType< T >(), + traits::HasMemberFunction_resizeDefault< T >, + LvArray::system::demangleType< T >(), + DefaultValue< T >::has_default_value ) ); +#else + GEOS_UNUSED_VAR( name ); +#endif + resize( value, newSize ); +} template< typename T, int NDIM, typename PERMUTATION > @@ -489,6 +513,133 @@ pullDataFromConduitNode( Array< T, NDIM, PERMUTATION > & var, std::memcpy( var.data(), valuesNode.data_ptr(), numBytesFromArray ); } + + +template< typename T, typename INDEX_TYPE > +std::enable_if_t< bufferOps::can_memcpy< T > > +pushDataToConduitNode( ArrayOfArrays< T, INDEX_TYPE > const & var2, + conduit::Node & node ) +{ + ArrayOfArraysView< T const, INDEX_TYPE > const & var = var2.toViewConst(); + internal::logOutputType( LvArray::system::demangleType( var ), "Output array via external pointer: " ); + + // ArrayOfArrays::m_numArrays + INDEX_TYPE const numArrays = var.size(); + conduit::DataType const numArraysType( conduitTypeInfo< INDEX_TYPE >::id, 1 ); + node[ "__numberOfArrays__" ].set( numArraysType, const_cast< void * >( static_cast< void const * >(&numArrays) ) ); + + // ArrayOfArrays::m_offsets + INDEX_TYPE const * const offsets = var.getOffsets(); + conduit::DataType const offsetsType( conduitTypeInfo< INDEX_TYPE >::id, numArrays+1 ); + node[ "__offsets__" ].set_external( offsetsType, const_cast< void * >( static_cast< void const * >( offsets ) ) ); + + // ArrayOfArrays::m_sizes + INDEX_TYPE const * const sizes = var.getSizes(); + conduit::DataType const sizesType( conduitTypeInfo< INDEX_TYPE >::id, numArrays ); + node[ "__sizes__" ].set_external( sizesType, const_cast< void * >( static_cast< void const * >( sizes ) ) ); + + // **** WARNING: alters the uninitialized values in the ArrayOfArrays **** + T * const values = const_cast< T * >(var.getValues()); + for( INDEX_TYPE i = 0; i < numArrays; ++i ) + { + INDEX_TYPE const curOffset = offsets[ i ]; + INDEX_TYPE const nextOffset = offsets[ i + 1 ]; + for( INDEX_TYPE j = curOffset + var.sizeOfArray( i ); j < nextOffset; ++j ) + { + if constexpr ( std::is_arithmetic< T >::value ) + { + values[ j ] = 0; + } + else + { + values[ j ] = T(); + } + } + } + + constexpr int conduitTypeID = conduitTypeInfo< T >::id; + constexpr int sizeofConduitType = conduitTypeInfo< T >::sizeOfConduitType; + conduit::DataType const dtype( conduitTypeID, offsets[numArrays] * sizeof( T ) / sizeofConduitType ); + + // Push the data into conduit + node[ "__values__" ].set_external( dtype, values ); +} + +template< typename T, typename INDEX_TYPE > +std::enable_if_t< bufferOps::can_memcpy< T > > +pullDataFromConduitNode( ArrayOfArrays< T, INDEX_TYPE > & var, + conduit::Node const & node ) +{ + + // numArrays node + conduit::Node const & numArraysNode = node.fetch_existing( "__numberOfArrays__" ); + INDEX_TYPE const * const numArrays = numArraysNode.value(); + + // offsets node + conduit::Node const & offsetsNode = node.fetch_existing( "__offsets__" ); + conduit::DataType const & offsetsDataType = offsetsNode.dtype(); + INDEX_TYPE const * const offsets = offsetsNode.value(); + INDEX_TYPE const sizeOffsets = offsetsDataType.number_of_elements(); + + // sizes node + conduit::Node const & sizesNode = node.fetch_existing( "__sizes__" ); + conduit::DataType const & sizesDataType = sizesNode.dtype(); + INDEX_TYPE const * const sizes = sizesNode.value(); + INDEX_TYPE const sizeSizes = sizesDataType.number_of_elements(); + + // Check that the numArrays, sizes and offsets are consistent. + GEOS_ERROR_IF_NE( *numArrays, sizeSizes ); + GEOS_ERROR_IF_NE( *numArrays+1, sizeOffsets ); + + // values node + conduit::Node const & valuesNode = node.fetch_existing( "__values__" ); + conduit::DataType const & valuesDataType = valuesNode.dtype(); + const INDEX_TYPE valuesSize = valuesDataType.number_of_elements(); + + // should preallocate var.m_values with estimated sizes + INDEX_TYPE const arraySizeEstimate = (*numArrays)==0 ? 0 : valuesSize / (*numArrays); + var.resize( *numArrays, arraySizeEstimate ); + var.reserveValues( valuesSize ); + + // correctly set the sizes and capacities of each sub-array + localIndex allocatedSize = 0; + for( INDEX_TYPE i = 0; i < *numArrays; ++i ) + { + INDEX_TYPE const arrayAllocation = offsets[i+1] - offsets[i]; + var.setCapacityOfArray( i, arrayAllocation ); + var.resizeArray( i, sizes[ i ] ); + allocatedSize += arrayAllocation; + } + + // make sure that the allocated size is the same as the number of values read + GEOS_ERROR_IF_NE( valuesSize, allocatedSize ); + + // make sure the allocatedSize is consistent wit the last offset + GEOS_ERROR_IF_NE( allocatedSize, offsets[sizeOffsets-1] ); + + // get a view because the ArrayOfArraysView data accessors are protected + ArrayOfArraysView< T const, INDEX_TYPE > const & varView = var.toViewConst(); + INDEX_TYPE const * const varOffsets = varView.getOffsets(); + INDEX_TYPE const * const varSizes = varView.getSizes(); + + // check that the offsets that are read are the same as the ones that were allocated + GEOS_ERROR_IF_NE( varOffsets[0], offsets[0] ); + + // check each subarray has the identical capacity and size + for( INDEX_TYPE i = 0; i<*numArrays; ++i ) + { + GEOS_ERROR_IF_NE( varOffsets[i+1], offsets[i+1] ); + GEOS_ERROR_IF_NE( varSizes[i], sizes[i] ); + } + + // copy the values + localIndex numBytesFromArray = allocatedSize * sizeof( T ); + GEOS_ERROR_IF_NE( numBytesFromArray, valuesDataType.strided_bytes() ); + std::memcpy( const_cast< T * >(varView.getValues()), valuesNode.data_ptr(), numBytesFromArray ); +} + + + template< typename T > void pushDataToConduitNode( InterObjectRelation< T > const & var, conduit::Node & node ) @@ -825,7 +976,7 @@ UnpackDataByIndexDevice( buffer_unit_type const * &, T const &, IDX &, parallelD return 0; } -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) template< typename T > inline std::enable_if_t< LvArray::python::CanCreate< T >, PyObject * > diff --git a/src/coreComponents/dataRepository/xmlWrapper.cpp b/src/coreComponents/dataRepository/xmlWrapper.cpp index 29f80e4bf43..e0ada302c49 100644 --- a/src/coreComponents/dataRepository/xmlWrapper.cpp +++ b/src/coreComponents/dataRepository/xmlWrapper.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #include "xmlWrapper.hpp" -#include "codingUtilities/StringUtilities.hpp" +#include "common/format/StringUtilities.hpp" #include "common/MpiWrapper.hpp" #include "dataRepository/KeyNames.hpp" @@ -34,8 +35,8 @@ namespace xmlWrapper void validateString( string const & value, Regex const & regex ) { std::smatch m; - bool inputValidated = std::regex_search( value, m, std::regex( regex.m_regexStr ) ); - if( !inputValidated || m.length() != ptrdiff_t( value.length() ) ) + bool inputValidated = std::regex_match( value, m, std::regex( regex.m_regexStr ) ); + if( !inputValidated ) { ptrdiff_t errorId = ( m.size()>0 && m.position( 0 )==0 ) ? m.length() : 0; GEOS_THROW( GEOS_FMT( "Input string validation failed at:\n" @@ -170,7 +171,7 @@ void xmlDocument::addIncludedXML( xmlNode & targetNode, int const level ) return isAbsolutePath( fileName ) ? fileName : joinPath( splitPath( currentFilePath ).first, fileName ); }(); - GEOS_LOG_RANK_0( "Included additionnal XML file: " << getAbsolutePath( includedFilePath ) ); + GEOS_LOG_RANK_0( "Included additional XML file: " << getAbsolutePath( includedFilePath ) ); xmlDocument includedXmlDocument; xmlResult const result = includedXmlDocument.loadFile( includedFilePath, hasNodeFileInfo() ); diff --git a/src/coreComponents/dataRepository/xmlWrapper.hpp b/src/coreComponents/dataRepository/xmlWrapper.hpp index 1e5961c1ae5..71890a2a21f 100644 --- a/src/coreComponents/dataRepository/xmlWrapper.hpp +++ b/src/coreComponents/dataRepository/xmlWrapper.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -25,7 +26,8 @@ #include "common/GEOS_RAJA_Interface.hpp" #include "LvArray/src/output.hpp" #include "LvArray/src/input.hpp" -#include "codingUtilities/StringUtilities.hpp" +#include "common/format/StringUtilities.hpp" +#include "codingUtilities/RTTypes.hpp" // TPL includes #include diff --git a/src/coreComponents/denseLinearAlgebra/CMakeLists.txt b/src/coreComponents/denseLinearAlgebra/CMakeLists.txt index 3edb50f95d5..c91c99e352f 100644 --- a/src/coreComponents/denseLinearAlgebra/CMakeLists.txt +++ b/src/coreComponents/denseLinearAlgebra/CMakeLists.txt @@ -1,23 +1,54 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: denseLinearAlgebra + +Contains dense linear algebra functions and interfaces to BLAS and LAPACK packages. +#]] + +# # Specify all headers +# set( denseLinearAlgebra_headers common/layouts.hpp + denseLASolvers.hpp interfaces/blaslapack/BlasLapackFunctions.h interfaces/blaslapack/BlasLapackLA.hpp ) +# # Specify all sources +# set( denseLinearAlgebra_sources interfaces/blaslapack/BlasLapackLA.cpp ) set( dependencyList codingUtilities blas lapack ${parallelDeps} ) +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) + blt_add_library( NAME denseLinearAlgebra SOURCES ${denseLinearAlgebra_sources} HEADERS ${denseLinearAlgebra_headers} - DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} ) + DEPENDS_ON ${decoratedDependencies} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} + ) target_include_directories( denseLinearAlgebra PUBLIC ${CMAKE_CURRENT_LIST_DIR} ) +install( TARGETS denseLinearAlgebra LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) + if( GEOS_ENABLE_TESTS ) add_subdirectory( unitTests ) endif( ) diff --git a/src/coreComponents/denseLinearAlgebra/common/layouts.hpp b/src/coreComponents/denseLinearAlgebra/common/layouts.hpp index 193a9183b78..77bf184d868 100644 --- a/src/coreComponents/denseLinearAlgebra/common/layouts.hpp +++ b/src/coreComponents/denseLinearAlgebra/common/layouts.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/denseLinearAlgebra/denseLASolvers.hpp b/src/coreComponents/denseLinearAlgebra/denseLASolvers.hpp new file mode 100644 index 00000000000..976b6df848d --- /dev/null +++ b/src/coreComponents/denseLinearAlgebra/denseLASolvers.hpp @@ -0,0 +1,319 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file denseLASolvers.hpp + */ +#ifndef GEOS_DENSELINEARALGEBRA_DENSELASOLVERS_HPP_ +#define GEOS_DENSELINEARALGEBRA_DENSELASOLVERS_HPP_ + +#include "common/DataTypes.hpp" +#include "denseLinearAlgebra/common/layouts.hpp" +#include "LvArray/src/tensorOps.hpp" +#include "common/logger/Logger.hpp" + +#include + +namespace geos +{ + +namespace denseLinearAlgebra +{ + +namespace details +{ + +constexpr real64 singularMatrixTolerance = 1e2*LvArray::NumericLimits< real64 >::epsilon; + +/** + * @brief Solves a 2x2 linear system A * x = b. + * + * This function solves a linear system of the form A * x = b, where A is a 2x2 matrix, + * b is a 2x1 vector, and x is the solution vector. The function checks the sizes + * of the inputs to ensure they conform to the expected dimensions. It also checks that + * the determinant of matrix A is not near zero to avoid solving a singular system. + * + * @tparam MATRIX_TYPE The type of the matrix A. Must support indexing with `A[i][j]`. + * @tparam RHS_TYPE The type of the right-hand side vector b. Must support indexing with `b[i]`. + * @tparam SOL_TYPE The type of the solution vector x. Must support indexing with `x[i]`. + * + * @param[in] A The 2x2 matrix representing the system of equations. Must have size 2x2. + * @param[in] b The 2-element vector representing the right-hand side of the equation. + * @param[out] x The 2-element vector that will store the solution to the system. + * @return bool that sepcifies whether the solve succeeded (1) or not (0). + */ +template< typename MATRIX_TYPE, + typename RHS_TYPE, + typename SOL_TYPE > +GEOS_HOST_DEVICE +inline +bool solveTwoByTwoSystem( MATRIX_TYPE const & A, RHS_TYPE const & b, SOL_TYPE && x ) +{ + LvArray::tensorOps::internal::checkSizes< 2, 2 >( A ); + LvArray::tensorOps::internal::checkSizes< 2 >( b ); + LvArray::tensorOps::internal::checkSizes< 2 >( x ); + + real64 const detA = LvArray::tensorOps::determinant< 2 >( A ); + + if( LvArray::math::abs( detA ) < singularMatrixTolerance ) + return false; + + real64 const invA = 1.0 / detA; + + x[0] = ( A[1][1] * b[0] - A[0][1] * b[1] ) * invA; + x[1] = ( A[0][0] * b[1] - A[1][0] * b[0] ) * invA; + + return true; +} + +/** + * @brief Solves a 3x3 linear system A * x = b. + * + * This function solves a linear system of the form A * x = b, where A is a 3x3 matrix, + * b is a 3x1 vector, and x is the solution vector. The function checks the sizes + * of the inputs to ensure they conform to the expected dimensions. It also checks that + * the determinant of matrix A is not near zero to avoid solving a singular system. + * + * @tparam MATRIX_TYPE The type of the matrix A. Must support indexing with `A[i][j]`. + * @tparam RHS_TYPE The type of the right-hand side vector b. Must support indexing with `b[i]`. + * @tparam SOL_TYPE The type of the solution vector x. Must support indexing with `x[i]`. + * + * @param[in] A The 3x3 matrix representing the system of equations. Must have size 3x3. + * @param[in] b The 3-element vector representing the right-hand side of the equation. + * @param[out] x The 3-element vector that will store the solution to the system. + * @return bool that sepcifies whether the solve succeeded (1) or not (0). + */ +template< typename MATRIX_TYPE, + typename RHS_TYPE, + typename SOL_TYPE > +GEOS_HOST_DEVICE +inline +bool solveThreeByThreeSystem( MATRIX_TYPE const & A, RHS_TYPE const & b, SOL_TYPE && x ) +{ + LvArray::tensorOps::internal::checkSizes< 3, 3 >( A ); + LvArray::tensorOps::internal::checkSizes< 3 >( b ); + LvArray::tensorOps::internal::checkSizes< 3 >( x ); + + real64 const detA = LvArray::tensorOps::determinant< 3 >( A ); + + if( LvArray::math::abs( detA ) < singularMatrixTolerance ) + return false; + + real64 const invA = 1.0 / detA; + + real64 const detX0 = b[0] * ( A[1][1] * A[2][2] - A[2][1] * A[1][2] ) - + b[1] * ( A[0][1] * A[2][2] - A[0][2] * A[2][1] ) + + b[2] * ( A[0][1] * A[1][2] - A[0][2] * A[1][1] ); + + real64 const detX1 = A[0][0] * ( b[1] * A[2][2] - b[2] * A[1][2] ) - + A[1][0] * ( b[0] * A[2][2] - b[2] * A[0][2] ) + + A[2][0] * ( b[0] * A[1][2] - b[1] * A[0][2] ); + + real64 const detX2 = A[0][0] * ( A[1][1] * b[2] - A[2][1] * b[1] ) - + A[1][0] * ( A[0][1] * b[2] - A[2][1] * b[0] ) + + A[2][0] * ( A[0][1] * b[1] - A[1][1] * b[0] ); + + x[0] = detX0 * invA; + x[1] = detX1 * invA; + x[2] = detX2 * invA; + + return true; +} + +/** + * @brief Solves a linear system where the matrix is upper triangular using back substitution. + * + * This function solves the linear system `Ax = b`, where `A` is an upper triangular matrix, using + * back substitution. The solution `x` is computed and stored in the provided output vector. + * + * @tparam N The size of the square matrix `A`. + * @tparam MATRIX_TYPE The type of the matrix `A`. + * @tparam RHS_TYPE The type of the right-hand side vector `b`. + * @tparam SOL_TYPE The type of the solution vector `x`. + * @param[in] A The upper triangular matrix representing the coefficients of the system. + * @param[in] b The right-hand side vector. It is used to compute the solution. + * @param[out] x The solution vector. The result of solving the system `Ax = b` using back substitution. + */ +template< std::ptrdiff_t N, + typename MATRIX_TYPE, + typename RHS_TYPE, + typename SOL_TYPE > +GEOS_HOST_DEVICE +inline +void solveUpperTriangularSystem( MATRIX_TYPE const & A, RHS_TYPE const & b, SOL_TYPE && x ) +{ + for( std::ptrdiff_t i = N - 1; i >= 0; --i ) + { + real64 sum = b[i]; + for( std::ptrdiff_t j = i + 1; j < N; ++j ) + { + sum -= A[i][j] * x[j]; + } + x[i] = sum / A[i][i]; + } +} + +/** + * @brief Solves a linear system using Gaussian elimination. + * + * This function performs Gaussian elimination on the given matrix `A` and right-hand side vector `b`. + * It transforms the matrix `A` boolo an upper triangular matrix and then solves for the solution `x` + * using back substitution. + * + * @tparam N The size of the square matrix `A`. + * @tparam MATRIX_TYPE The type of the matrix `A`. + * @tparam RHS_TYPE The type of the right-hand side vector `b`. + * @tparam SOL_TYPE The type of the solution vector `x`. + * @param[in,out] A The matrix to be transformed boolo an upper triangular matrix. Modified in place. + * @param[in,out] b The right-hand side vector. Modified in place to reflect the transformed system. + * @param[out] x The solution vector. The result of solving the system `Ax = b`. + * @return bool that sepcifies whether the solve succeeded (1) or not (0). + */ +template< std::ptrdiff_t N, + typename MATRIX_TYPE, + typename RHS_TYPE, + typename SOL_TYPE > +GEOS_HOST_DEVICE +inline +bool solveGaussianElimination( MATRIX_TYPE & A, RHS_TYPE & b, SOL_TYPE && x ) +{ + static_assert( N > 0, "N must be greater than 0." ); + LvArray::tensorOps::internal::checkSizes< N, N >( A ); + LvArray::tensorOps::internal::checkSizes< N >( b ); + LvArray::tensorOps::internal::checkSizes< N >( x ); + + // Step 1: Transform boolo an upper triangular matrix + + // 1.a. Find the pivot + for( std::ptrdiff_t i = 0; i < N; ++i ) + { + std::ptrdiff_t max_row = i; + for( std::ptrdiff_t k = i + 1; k < N; ++k ) + { + if( LvArray::math::abs( A[k][i] ) > LvArray::math::abs( A[max_row][i] )) + { + max_row = k; + } + } + + // 1.b. Swap rows + for( std::ptrdiff_t k = i; k < N; ++k ) + { + // std::swap( A[i][k], A[max_row][k] ); + real64 const temp = A[max_row][k]; + A[max_row][k] = A[i][k]; + A[i][k] = temp; + } + // std::swap( b[i], b[max_row] ); cannot be done on device + real64 const temp = b[i]; + b[i] = b[max_row]; + b[max_row] = temp; + + + if( LvArray::math::abs( A[i][i] ) < singularMatrixTolerance ) + return false; + + // 1.c Eliminate entries below the pivot + for( std::ptrdiff_t k = i + 1; k < N; ++k ) + { + real64 const scaling = A[k][i] / A[i][i]; + for( std::ptrdiff_t j = i; j < N; ++j ) + { + A[k][j] -= scaling * A[i][j]; + } + b[k] -= scaling * b[i]; + } + } + + // Step 2: Backward substitution + solveUpperTriangularSystem< N >( A, b, std::forward< SOL_TYPE >( x ) ); + + return true; +} + +} // details namespace + +/** + * @brief Solves a linear system using the most appropriate method based on the size of the system. + * + * This function determines the appropriate method for solving a linear system `Ax = b` based on + * the size of the matrix `A`. For 2x2 and 3x3 systems, specialized solvers are used. For larger systems, + * Gaussian elimination is employed. The matrix and the rhs are modified by the function. + * + * @tparam N The size of the square matrix `A`. + * @tparam MATRIX_TYPE The type of the matrix `A`. + * @tparam RHS_TYPE The type of the right-hand side vector `b`. + * @tparam SOL_TYPE The type of the solution vector `x`. + * @tparam MODIFY_MATRIX boolean flag indicating whether the input matrix `A` and vector `b` should be modified. + * If `1`, the matrix `A` and vector `b` are modified in place. If `0`, copies of + * `A` and `b` are made, and the original data is left unchanged. + * @param[in] A The matrix representing the coefficients of the system. + * @param[in] b The right-hand side vector. + * @param[out] x The solution vector. The result of solving the system `Ax = b`. + * @return bool that sepcifies whether the solve succeeded (1) or not (0). + */ +template< std::ptrdiff_t N, + typename MATRIX_TYPE, + typename RHS_TYPE, + typename SOL_TYPE, + bool MODIFY_MATRIX = 1 > +GEOS_HOST_DEVICE +inline +bool solve( MATRIX_TYPE & A, RHS_TYPE & b, SOL_TYPE && x ) +{ + static_assert( N > 0, "N must be greater than 0." ); + static_assert( N < 10, "N cannot be larger than 9" ); + LvArray::tensorOps::internal::checkSizes< N, N >( A ); + LvArray::tensorOps::internal::checkSizes< N >( b ); + LvArray::tensorOps::internal::checkSizes< N >( x ); + + if constexpr ( N == 2 ) + { + return details::solveTwoByTwoSystem( A, b, std::forward< SOL_TYPE >( x ) ); + } + else if constexpr ( N == 3 ) + { + return details::solveThreeByThreeSystem( A, b, std::forward< SOL_TYPE >( x ) ); + } + else + { + if constexpr ( MODIFY_MATRIX ) + { + return details::solveGaussianElimination< N >( A, b, std::forward< SOL_TYPE >( x ) ); + } + else + { + real64 A_copy[N][N]{}; + real64 b_copy[N]{}; + + for( std::ptrdiff_t i=0; i < N; ++i ) + { + b_copy[i] = b[i]; + for( std::ptrdiff_t j=0; j < N; ++j ) + { + A_copy[i][j] = A[i][j]; + } + } + return details::solveGaussianElimination< N >( A_copy, b_copy, std::forward< SOL_TYPE >( x ) ); + } + } +} + +} // denseLinearAlgebra + +} // geos + + +#endif /*GEOS_DENSELINEARALGEBRA_DENSELASOLVERS_HPP_*/ diff --git a/src/coreComponents/denseLinearAlgebra/interfaces/blaslapack/BlasLapackFunctions.h b/src/coreComponents/denseLinearAlgebra/interfaces/blaslapack/BlasLapackFunctions.h index 5f61325f69c..47600b5b100 100644 --- a/src/coreComponents/denseLinearAlgebra/interfaces/blaslapack/BlasLapackFunctions.h +++ b/src/coreComponents/denseLinearAlgebra/interfaces/blaslapack/BlasLapackFunctions.h @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -162,6 +163,19 @@ void GEOS_dgetrs( char const * TRANS, int const * LDB, int * INFO ); +#define GEOS_dgels FORTRAN_MANGLE( dgels ) +void GEOS_dgels( char const * TRANS, + int const * M, + int const * N, + int const * NRHS, + double * A, + int const * LDA, + double * B, + int const * LDB, + double * WORK, + int const * LWORK, + int * INFO ); + } #endif diff --git a/src/coreComponents/denseLinearAlgebra/interfaces/blaslapack/BlasLapackLA.cpp b/src/coreComponents/denseLinearAlgebra/interfaces/blaslapack/BlasLapackLA.cpp index 31fb564cf89..2642d481a4d 100644 --- a/src/coreComponents/denseLinearAlgebra/interfaces/blaslapack/BlasLapackLA.cpp +++ b/src/coreComponents/denseLinearAlgebra/interfaces/blaslapack/BlasLapackLA.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -22,9 +23,11 @@ // BLAS and LAPACK function declaration #include "denseLinearAlgebra/interfaces/blaslapack/BlasLapackFunctions.h" +#include "common/logger/Logger.hpp" + #include -// Put everything under the geosx namespace. +// Put everything under the geos namespace. namespace geos { @@ -349,6 +352,181 @@ void matrixInverse( arraySlice2d< real64 const, USD > const & A, matrixInverse( A, Ainv, detA ); } +template< int USD > +void matrixLeastSquaresSolutionSolve( arraySlice2d< real64, USD > const & A, + arraySlice1d< real64 > const & B, + arraySlice1d< real64 > const & X ) +{ + GEOS_ASSERT_MSG( A.size( 1 ) == X.size() && A.size( 0 ) == B.size(), + "Matrix, unknown vector and rhs vector not compatible" ); + + GEOS_ASSERT_MSG( X.size() <= B.size(), + "Matrix, unknown vector and rhs vector not compatible" ); + + int const M = LvArray::integerConversion< int >( A.size( 0 ) ); + int const N = LvArray::integerConversion< int >( A.size( 1 ) ); + int const NRHS = 1; + + int const LWORK = N + N; + array1d< double > WORK( LWORK ); + + int INFO = 0; + + GEOS_dgels( "N", &M, &N, &NRHS, A.dataIfContiguous(), &M, B.dataIfContiguous(), &M, WORK.data(), &LWORK, &INFO ); + + for( int i = 0; i < N; ++i ) + { + X[i] = B[i]; + } + + GEOS_ERROR_IF( INFO != 0, "The algorithm computing matrix linear system failed to converge." ); +} + +template< int USD1, int USD2 > +GEOS_FORCE_INLINE +void matrixCopy( int const N, + int const M, + arraySlice2d< real64, USD1 > const & A, + arraySlice2d< real64, USD2 > const & B ) +{ + for( int i = 0; i < N; i++ ) + { + for( int j = 0; j < M; j++ ) + { + B( i, j ) = A( i, j ); + } + } +} + +template< int USD > +GEOS_FORCE_INLINE +void matrixTranspose( int const N, + arraySlice2d< real64, USD > const & A ) +{ + for( int i = 0; i < N; i++ ) + { + for( int j = i+1; j < N; j++ ) + { + std::swap( A( i, j ), A( j, i ) ); + } + } +} + +template< typename T, int USD > +void solveLinearSystem( arraySlice2d< T, USD > const & A, + arraySlice2d< real64 const, USD > const & B, + arraySlice2d< real64, USD > const & X ) +{ + // --- Check that source matrix is square + int const N = LvArray::integerConversion< int >( A.size( 0 ) ); + GEOS_ASSERT_MSG( N > 0 && + N == A.size( 1 ), + "Matrix must be square" ); + + // --- Check that rhs B has appropriate dimensions + GEOS_ASSERT_MSG( B.size( 0 ) == N, + "right-hand-side matrix has wrong dimensions" ); + int const M = LvArray::integerConversion< int >( B.size( 1 ) ); + + // --- Check that solution X has appropriate dimensions + GEOS_ASSERT_MSG( X.size( 0 ) == N && + X.size( 1 ) == M, + "solution matrix has wrong dimensions" ); + + // --- Check that everything is contiguous + GEOS_ASSERT_MSG( A.isContiguous(), "Matrix is not contiguous" ); + GEOS_ASSERT_MSG( B.isContiguous(), "right-hand-side matrix is not contiguous" ); + GEOS_ASSERT_MSG( X.isContiguous(), "solution matrix is not contiguous" ); + + real64 * matrixData = nullptr; + array2d< real64 > LU; // Space for LU-factors + if constexpr ( !std::is_const< T >::value ) + { + matrixData = A.dataIfContiguous(); + } + else + { + LU.resize( N, N ); + matrixData = LU.data(); + // Direct copy here ignoring permutation + int const INCX = 1; + int const INCY = 1; + int const K = LvArray::integerConversion< int >( A.size( ) ); + GEOS_dcopy( &K, A.dataIfContiguous(), &INCX, matrixData, &INCY ); + } + + array1d< int > IPIV( N ); + int INFO; + char const TRANS = (USD == MatrixLayout::ROW_MAJOR) ? 'T' : 'N'; + + GEOS_dgetrf( &N, &N, matrixData, &N, IPIV.data(), &INFO ); + + GEOS_ASSERT_MSG( INFO == 0, "LAPACK dgetrf error code: " << INFO ); + + if constexpr ( std::is_const< T >::value ) + { + int const INCX = 1; + int const INCY = 1; + int const K = LvArray::integerConversion< int >( B.size( ) ); + GEOS_dcopy( &K, B.dataIfContiguous(), &INCX, X.dataIfContiguous(), &INCY ); + } + + // For row-major form, we need to reorder into col-major form + // This might require an extra allocation + real64 * solutionData = X.dataIfContiguous(); + array2d< real64, MatrixLayout::COL_MAJOR_PERM > X0; + if constexpr ( USD == MatrixLayout::ROW_MAJOR ) + { + if( 1 < M && M == N ) + { + // Square case: swap in place + matrixTranspose( N, X ); + } + else if( 1 < M ) + { + X0.resize( N, M ); + matrixCopy( N, M, X, X0.toSlice() ); + solutionData = X0.data(); + } + } + + GEOS_dgetrs( &TRANS, &N, &M, matrixData, &N, IPIV.data(), solutionData, &N, &INFO ); + + GEOS_ASSERT_MSG( INFO == 0, "LAPACK dgetrs error code: " << INFO ); + + if constexpr ( USD == MatrixLayout::ROW_MAJOR ) + { + if( 1 < M && M == N ) + { + // Square case: swap in place + matrixTranspose( N, X ); + } + else if( 1 < M ) + { + matrixCopy( N, M, X0.toSlice(), X ); + } + } +} + +template< typename T, int USD > +void solveLinearSystem( arraySlice2d< T, USD > const & A, + arraySlice1d< real64 const > const & b, + arraySlice1d< real64 > const & x ) +{ + // --- Check that b and x have the same size + int const N = LvArray::integerConversion< int >( b.size( 0 ) ); + GEOS_ASSERT_MSG( 0 < N && x.size() == N, + "right-hand-side and/or solution has wrong dimensions" ); + + // Create 2d slices + int const dims[2] = {N, 1}; + int const strides[2] = {1, 1}; + arraySlice2d< real64 const, USD > B( b.dataIfContiguous(), dims, strides ); + arraySlice2d< real64, USD > X( x.dataIfContiguous(), dims, strides ); + + solveLinearSystem( A, B, X ); +} + } // namespace detail real64 BlasLapackLA::determinant( arraySlice2d< real64 const, MatrixLayout::ROW_MAJOR > const & A ) @@ -855,51 +1033,65 @@ void BlasLapackLA::matrixEigenvalues( MatRowMajor< real64 const > const & A, matrixEigenvalues( AT.toSliceConst(), lambda ); } -void BlasLapackLA::solveLinearSystem( MatColMajor< real64 const > const & A, - arraySlice1d< real64 const > const & rhs, - arraySlice1d< real64 > const & solution ) +void BlasLapackLA::solveLinearSystem( MatRowMajor< real64 const > const & A, + Vec< real64 const > const & rhs, + Vec< real64 > const & solution ) { - // --- Check that source matrix is square - int const NN = LvArray::integerConversion< int >( A.size( 0 )); - GEOS_ASSERT_MSG( NN > 0 && - NN == A.size( 1 ), - "Matrix must be square" ); - - // --- Check that rhs and solution have appropriate dimension - GEOS_ASSERT_MSG( rhs.size( 0 ) == NN, - "right-hand-side vector has wrong dimensions" ); - - GEOS_ASSERT_MSG( solution.size( 0 ) == NN, - "solution vector has wrong dimensions" ); + detail::solveLinearSystem( A, rhs, solution ); +} - array1d< int > IPIV; - IPIV.resize( NN ); - int const NRHS = 1; // we only allow for 1 rhs vector. - int INFO; +void BlasLapackLA::solveLinearSystem( MatColMajor< real64 const > const & A, + Vec< real64 const > const & rhs, + Vec< real64 > const & solution ) +{ + detail::solveLinearSystem( A, rhs, solution ); +} - // make a copy of A, since dgeev destroys contents - array2d< real64, MatrixLayout::COL_MAJOR_PERM > ACOPY( A.size( 0 ), A.size( 1 ) ); - BlasLapackLA::matrixCopy( A, ACOPY ); +void BlasLapackLA::solveLinearSystem( MatRowMajor< real64 > const & A, + Vec< real64 > const & rhs ) +{ + detail::solveLinearSystem( A, rhs.toSliceConst(), rhs ); +} - // copy the rhs in the solution vector - BlasLapackLA::vectorCopy( rhs, solution ); +void BlasLapackLA::solveLinearSystem( MatColMajor< real64 > const & A, + Vec< real64 > const & rhs ) +{ + detail::solveLinearSystem( A, rhs.toSliceConst(), rhs ); +} - GEOS_dgetrf( &NN, &NN, ACOPY.data(), &NN, IPIV.data(), &INFO ); +void BlasLapackLA::solveLinearSystem( MatRowMajor< real64 const > const & A, + MatRowMajor< real64 const > const & rhs, + MatRowMajor< real64 > const & solution ) +{ + detail::solveLinearSystem( A, rhs, solution ); +} - GEOS_ASSERT_MSG( INFO == 0, "LAPACK dgetrf error code: " << INFO ); +void BlasLapackLA::solveLinearSystem( MatColMajor< real64 const > const & A, + MatColMajor< real64 const > const & rhs, + MatColMajor< real64 > const & solution ) +{ + detail::solveLinearSystem( A, rhs, solution ); +} - GEOS_dgetrs( "N", &NN, &NRHS, ACOPY.data(), &NN, IPIV.data(), solution.dataIfContiguous(), &NN, &INFO ); +void BlasLapackLA::solveLinearSystem( MatRowMajor< real64 > const & A, + MatRowMajor< real64 > const & rhs ) +{ + detail::solveLinearSystem( A, rhs.toSliceConst(), rhs ); +} - GEOS_ASSERT_MSG( INFO == 0, "LAPACK dgetrs error code: " << INFO ); +void BlasLapackLA::solveLinearSystem( MatColMajor< real64 > const & A, + MatColMajor< real64 > const & rhs ) +{ + detail::solveLinearSystem( A, rhs.toSliceConst(), rhs ); } -void BlasLapackLA::solveLinearSystem( MatRowMajor< real64 const > const & A, - arraySlice1d< real64 const > const & rhs, - arraySlice1d< real64 > const & solution ) +void BlasLapackLA::matrixLeastSquaresSolutionSolve( arraySlice2d< real64 const, MatrixLayout::ROW_MAJOR > const & A, + arraySlice1d< real64 const > const & B, + arraySlice1d< real64 > const & X ) { array2d< real64, MatrixLayout::COL_MAJOR_PERM > AT( A.size( 0 ), A.size( 1 ) ); - // convert A to a column major format + // convert A to a row major format for( int i = 0; i < A.size( 0 ); ++i ) { for( int j = 0; j < A.size( 1 ); ++j ) @@ -908,9 +1100,22 @@ void BlasLapackLA::solveLinearSystem( MatRowMajor< real64 const > const & A, } } - solveLinearSystem( AT.toSliceConst(), rhs, solution ); + matrixLeastSquaresSolutionSolve( AT.toSliceConst(), B, X ); } +void BlasLapackLA::matrixLeastSquaresSolutionSolve( arraySlice2d< real64 const, MatrixLayout::COL_MAJOR > const & A, + arraySlice1d< real64 const > const & B, + arraySlice1d< real64 > const & X ) +{ + // make a copy of A, since dgels modifies the components in A + array2d< real64, MatrixLayout::COL_MAJOR_PERM > ACOPY( A.size( 0 ), A.size( 1 ) ); + BlasLapackLA::matrixCopy( A, ACOPY ); + + // make a copy of B, since dgels modifies the components in B + array1d< real64 > BCOPY( B.size() ); + BlasLapackLA::vectorCopy( B, BCOPY ); + detail::matrixLeastSquaresSolutionSolve( ACOPY.toSlice(), BCOPY.toSlice(), X ); +} -} // end geosx namespace +} // end geos namespace diff --git a/src/coreComponents/denseLinearAlgebra/interfaces/blaslapack/BlasLapackLA.hpp b/src/coreComponents/denseLinearAlgebra/interfaces/blaslapack/BlasLapackLA.hpp index dbf7eec9f6e..ffacecc65de 100644 --- a/src/coreComponents/denseLinearAlgebra/interfaces/blaslapack/BlasLapackLA.hpp +++ b/src/coreComponents/denseLinearAlgebra/interfaces/blaslapack/BlasLapackLA.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -30,6 +31,7 @@ namespace geos * \class BlasLapackLA * \brief This class contains a collection of BLAS and LAPACK linear * algebra operations for GEOSX array1d and array2d + * \warning These methods are currently not supported on GPUs */ struct BlasLapackLA { @@ -454,18 +456,88 @@ struct BlasLapackLA * @param [in] rhs GEOSX array1d. * @param [out] solution GEOSX array1d. */ + static void solveLinearSystem( MatColMajor< real64 const > const & A, + Vec< real64 const > const & rhs, + Vec< real64 > const & solution ); + + /** + * @copydoc solveLinearSystem( MatColMajor const &, Vec< real64 const > const &, Vec< real64 const > const & ) + */ static void solveLinearSystem( MatRowMajor< real64 const > const & A, Vec< real64 const > const & rhs, Vec< real64 > const & solution ); /** - * @copydoc solveLinearSystem( MatRowMajor const &, Vec< real64 const > const &, Vec< real64 const > const & ) + * @brief Solves the linear system ; + * \p A \p solution = \p rhs. + * + * @details The method is intended for the solution of a small dense linear system. + * This solves the system in-place without allocating extra memory for the matrix or the solution. This means + * that at on exit the matrix is modified replaced by the LU factors and the right hand side vector is + * replaced by the solution. + * It employs lapack method dgetr. * - * @note this function first applies a matrix permutation and then calls the row major version of the function. + * @param [in/out] A GEOSX array2d. The matrix. On exit this will be replaced by the factorisation of A + * @param [in/out] rhs GEOSX array1d. The right hand side. On exit this will be the solution + */ + static void solveLinearSystem( MatColMajor< real64 > const & A, + Vec< real64 > const & rhs ); + + /** + * @copydoc solveLinearSystem( MatColMajor< real64 > const &, Vec< real64 > const & ) + */ + static void solveLinearSystem( MatRowMajor< real64 > const & A, + Vec< real64 > const & rhs ); + + /** + * @brief Solves the linear system ; + * \p A \p solution = \p rhs. + * + * @details The method is intended for the solution of a small dense linear system in which A is an NxN matrix, the + * right-hand-side and the solution are matrices of size NxM. + * It employs lapack method dgetr. + * + * @param [in] A GEOSX array2d. + * @param [in] rhs GEOSX array2d. + * @param [out] solution GEOSX array2d. */ static void solveLinearSystem( MatColMajor< real64 const > const & A, - Vec< real64 const > const & rhs, - Vec< real64 > const & solution ); + MatColMajor< real64 const > const & rhs, + MatColMajor< real64 > const & solution ); + + /** + * @copydoc solveLinearSystem( MatColMajor< real64 const > const &, MatColMajor< real64 const > const &, MatColMajor< const > const & ) + * + * @note this function will allocate space to reorder the solution into column major form. + */ + static void solveLinearSystem( MatRowMajor< real64 const > const & A, + MatRowMajor< real64 const > const & rhs, + MatRowMajor< real64 > const & solution ); + + /** + * @brief Solves the linear system ; + * \p A \p solution = \p rhs. + * + * @details The method is intended for the solution of a small dense linear system in which A is an NxN matrix, the + * right-hand-side and the solution are matrices of size NxM. + * This solves the system in-place without allocating extra memory for the matrix or the solution. This means + * that at on exit the matrix is modified replaced by the LU factors and the right hand side vector is + * replaced by the solution. + * It employs lapack method dgetr. + * + * @param [in/out] A GEOSX array2d. The matrix. On exit this will be replaced by the factorisation of A + * @param [in/out] rhs GEOSX array1d. The right hand side. On exit this will be the solution + */ + static void solveLinearSystem( MatColMajor< real64 > const & A, + MatColMajor< real64 > const & rhs ); + + /** + * @copydoc solveLinearSystem( MatColMajor< real64 > const &, MatRowMajor< real64 > const & ) + * + * @note this function will allocate space to reorder the solution into column major form. + */ + static void solveLinearSystem( MatRowMajor< real64 > const & A, + MatRowMajor< real64 > const & rhs ); /** * @brief Vector copy; @@ -596,6 +668,23 @@ struct BlasLapackLA static void matrixEigenvalues( MatColMajor< real64 const > const & A, Vec< std::complex< real64 > > const & lambda ); + /** + * @brief Computes the least squares solution of B - AX + * + * @param [in] A GEOSX array2d. + * @param [in] B GEOSX array1d. + * @param [out] X GEOSX array1d. + */ + static void matrixLeastSquaresSolutionSolve( MatRowMajor< real64 const > const & A, + Vec< real64 const > const & B, + Vec< real64 > const & X ); + + /** + * @copydoc matrixLeastSquaresSolutionSolve + */ + static void matrixLeastSquaresSolutionSolve( MatColMajor< real64 const > const & A, + Vec< real64 const > const & B, + Vec< real64 > const & X ); }; } diff --git a/src/coreComponents/denseLinearAlgebra/unitTests/CMakeLists.txt b/src/coreComponents/denseLinearAlgebra/unitTests/CMakeLists.txt index 1b7d0eefb3d..5334abc1acb 100644 --- a/src/coreComponents/denseLinearAlgebra/unitTests/CMakeLists.txt +++ b/src/coreComponents/denseLinearAlgebra/unitTests/CMakeLists.txt @@ -1,5 +1,7 @@ set( serial_tests - testBlasLapack.cpp ) + testBlasLapack.cpp + testSolveLinearSystem.cpp + testDenseLASolvers.cpp ) set( dependencyList gtest denseLinearAlgebra ) diff --git a/src/coreComponents/denseLinearAlgebra/unitTests/testBlasLapack.cpp b/src/coreComponents/denseLinearAlgebra/unitTests/testBlasLapack.cpp index 8198473c2fc..b3b8046b0f9 100644 --- a/src/coreComponents/denseLinearAlgebra/unitTests/testBlasLapack.cpp +++ b/src/coreComponents/denseLinearAlgebra/unitTests/testBlasLapack.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -1139,6 +1140,47 @@ void matrix_svd_test() } } +template< typename LAI > +void matrix_linear_system_least_square_solve_test() +{ + INDEX_TYPE M = 3; + INDEX_TYPE N = 2; + + array2d< real64 > A( M, N ); + array1d< real64 > B( M ); + array1d< real64 > X( N ); + + array1d< real64 > vecResult( N ); + + // Assign component values to A + A( 0, 0 ) = 0.0; + A( 0, 1 ) = 1.0; + A( 1, 0 ) = 1.0; + A( 1, 1 ) = 1.0; + A( 2, 0 ) = 2.0; + A( 2, 1 ) = 1.0; + + // Assign component values to B + B( 0 ) = 6.0; + B( 1 ) = 0.0; + B( 2 ) = 0.0; + + // Compute X + LAI::matrixLeastSquaresSolutionSolve( A, B, X ); + + // Assign component values to the reference solution + vecResult( 0 ) = -3.0; + vecResult( 1 ) = 5.0; + + // Check + for( INDEX_TYPE i = 0; i < N; ++i ) + { + EXPECT_NEAR( vecResult( i ), + X( i ), + machinePrecision ); + } +} + TEST( Array1D, vectorNorm1 ) { vector_norm1_test< BlasLapackLA >(); @@ -1264,6 +1306,12 @@ TEST( DenseLAInterface, matrixSVD ) matrix_svd_test< BlasLapackLA >(); } +TEST( Array2D, matrixLinearSystemSolve ) +{ + matrix_linear_system_least_square_solve_test< BlasLapackLA >(); +} + + int main( int argc, char * * argv ) { ::testing::InitGoogleTest( &argc, argv ); diff --git a/src/coreComponents/denseLinearAlgebra/unitTests/testDenseLASolvers.cpp b/src/coreComponents/denseLinearAlgebra/unitTests/testDenseLASolvers.cpp new file mode 100644 index 00000000000..cbeda07ea64 --- /dev/null +++ b/src/coreComponents/denseLinearAlgebra/unitTests/testDenseLASolvers.cpp @@ -0,0 +1,219 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "denseLinearAlgebra/denseLASolvers.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "testUtils.hpp" + +// TPL includes +#include + +#include + +namespace geos +{ +namespace denseLinearAlgebra +{ +namespace testing +{ + +constexpr real64 machinePrecision = 1.0e3 * LvArray::NumericLimits< real64 >::epsilon; + +template< std::ptrdiff_t N > +class LinearSystem +{ +public: + real64 matrix[N][N]{}; + real64 solution[N]{}; + real64 rhs[N]{}; +}; + +template< std::ptrdiff_t N > +class InvertibleLinearSystem : public LinearSystem< N > +{ +public: + using LinearSystem< N >::matrix; + using LinearSystem< N >::solution; + using LinearSystem< N >::rhs; + + InvertibleLinearSystem( short int seed ) + { + std::mt19937 generator( seed ); + std::uniform_real_distribution< real64 > distribution( -10.0, 10.0 ); + std::uniform_real_distribution< real64 > perturbation( -20.0, 20.0 ); + for( ptrdiff_t i=0; i +class SingularLinearSystem : public LinearSystem< N > +{ +public: + using LinearSystem< N >::matrix; + using LinearSystem< N >::solution; + using LinearSystem< N >::rhs; + + SingularLinearSystem( short int seed ) + { + std::mt19937 generator( seed ); + std::uniform_real_distribution< real64 > distribution( -10.0, 10.0 ); + for( ptrdiff_t i=0; i +class DenseLinearSolverTest : public ::testing::Test +{ +public: + + static constexpr std::ptrdiff_t size = N::value; + + DenseLinearSolverTest() = default; + ~DenseLinearSolverTest() override = default; + + void test_solve() + { + InvertibleLinearSystem< size > LS( 2024 ); + + // GEOS_UNUSED_VAR(LS); + + forAll< parallelDevicePolicy<> >( 1, [=] GEOS_HOST_DEVICE ( int ) + { + real64 sol[size]{}; + real64 matrix[size][size]{}; + real64 rhs[size]{}; + + LvArray::tensorOps::copy< size, size >( matrix, LS.matrix ); + LvArray::tensorOps::copy< size >( rhs, LS.rhs ); + bool const success = denseLinearAlgebra::solve< size >( matrix, rhs, sol ); + + PORTABLE_EXPECT_TRUE( success ); + + for( std::ptrdiff_t i = 0; i < size; ++i ) + { + PORTABLE_EXPECT_NEAR( sol[i], + LS.solution[i], + machinePrecision ); + } + } ); + } + void test_singularSystem() + { + SingularLinearSystem< size > LS( 2024 ); + + forAll< parallelDevicePolicy<> >( 1, [=] GEOS_HOST_DEVICE ( int ) + { + + real64 sol[size]{}; + real64 matrix[size][size]{}; + real64 rhs[size]{}; + + LvArray::tensorOps::copy< size, size >( matrix, LS.matrix ); + LvArray::tensorOps::copy< size >( rhs, LS.rhs ); + bool const success = denseLinearAlgebra::solve< size >( matrix, rhs, sol ); + + PORTABLE_EXPECT_FALSE( success ); + } ); + } + +}; + +using Dimensions = ::testing::Types< std::integral_constant< std::ptrdiff_t, 2 >, + std::integral_constant< std::ptrdiff_t, 3 >, + std::integral_constant< std::ptrdiff_t, 4 >, + std::integral_constant< std::ptrdiff_t, 5 >, + std::integral_constant< std::ptrdiff_t, 6 >, + std::integral_constant< std::ptrdiff_t, 7 >, + std::integral_constant< std::ptrdiff_t, 8 >, + std::integral_constant< std::ptrdiff_t, 9 > >; + + +class NameGenerator +{ +public: + template< typename T > + static std::string GetName( int ) + { + if constexpr (T::value == 2) return "TwoByTwo"; + if constexpr (T::value == 3) return "ThreeByThree"; + if constexpr (T::value == 4) return "FourByFour"; + if constexpr (T::value == 5) return "FiveByFive"; + if constexpr (T::value == 6) return "SixBySix"; + if constexpr (T::value == 7) return "SevenBySeven"; + if constexpr (T::value == 8) return "EightByEight"; + if constexpr (T::value == 9) return "NineByNine"; + } +}; + +TYPED_TEST_SUITE( DenseLinearSolverTest, Dimensions, NameGenerator ); + +TYPED_TEST( DenseLinearSolverTest, testDenseLA ) +{ + this->test_solve(); + this->test_singularSystem(); +} + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + int const result = RUN_ALL_TESTS(); + return result; +} + +} // testing + +} // denseLinearAlgebra + +} // namespace geos diff --git a/src/coreComponents/denseLinearAlgebra/unitTests/testSolveLinearSystem.cpp b/src/coreComponents/denseLinearAlgebra/unitTests/testSolveLinearSystem.cpp new file mode 100644 index 00000000000..605a3e16ea6 --- /dev/null +++ b/src/coreComponents/denseLinearAlgebra/unitTests/testSolveLinearSystem.cpp @@ -0,0 +1,457 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file testSolveLinearSystem.cpp + */ + +// Source includes +#include "denseLinearAlgebra/interfaces/blaslapack/BlasLapackLA.hpp" +#include "common/logger/Logger.hpp" + +#include "gtest/gtest.h" + +using namespace geos; + +constexpr int MAX_SIZE = 20; +constexpr real64 machinePrecision = 1.0e2 * LvArray::NumericLimits< real64 >::epsilon; + +// Test matrices +enum TestMatrixType +{ + LAPLACE, + SAMPLING, + GRCAR +}; + +template< TestMatrixType MATRIX_TYPE > +struct TestMatrix {}; + +template<> +struct TestMatrix< TestMatrixType::LAPLACE > +{ + template< int USD > + static void create( arraySlice2d< real64, USD > const & A ) + { + int const N = LvArray::integerConversion< int >( A.size( 0 ) ); + GEOS_ASSERT( 2 <= N ); + LvArray::forValuesInSlice( A, []( real64 & a ){ a = 0.0; } ); + for( int i = 0; i < N-1; i++ ) + { + A( i+1, i ) = -1.0; + A( i+1, i+1 ) = 2.0; + A( i, i+1 ) = -1.0; + } + A( 0, 0 ) = 2.0; + } +}; + +template<> +struct TestMatrix< TestMatrixType::SAMPLING > +{ + template< int USD > + static void create( arraySlice2d< real64, USD > const & A ) + { + int const N = LvArray::integerConversion< int >( A.size( 0 ) ); + GEOS_ASSERT( 2 <= N ); + + real64 minajj = LvArray::NumericLimits< real64 >::max; + for( int j = 1; j <= N; j++ ) + { + real64 ajj = 0.0; + for( int i = 1; i <= N; i++ ) + { + if( i != j ) + { + A( i-1, j-1 ) = static_cast< real64 >(i)/static_cast< real64 >(i-j); + ajj += A( i-1, j-1 ); + } + } + A( j-1, j-1 ) = ajj; + minajj = LvArray::math::min( ajj, minajj ); + } + for( int j = 0; j < N; j++ ) + { + A( j, j ) -= minajj; + } + } +}; + +template<> +struct TestMatrix< TestMatrixType::GRCAR > +{ + template< int USD > + static void create( arraySlice2d< real64, USD > const & A ) + { + int const N = LvArray::integerConversion< int >( A.size( 0 ) ); + GEOS_ASSERT( 4 < N ); + LvArray::forValuesInSlice( A, []( real64 & a ){ a = 0.0; } ); + for( int i = 0; i < N-1; i++ ) + { + A( i+1, i ) = -1.0; + } + for( int c = 0; c < 4; c++ ) + { + for( int i = 0; i < N-c; i++ ) + { + A( i, i+c ) = 1.0; + } + } + } +}; + +// Randomly reorder a matrix +template< int USD > +void random_permutation( arraySlice2d< real64, USD > const & A ) +{ + int const N = LvArray::integerConversion< int >( A.size( 0 ) ); + GEOS_ASSERT( 2 <= N ); + + StackArray< real64, 1, MAX_SIZE > ordering( N ); + BlasLapackLA::vectorRand( ordering.toSlice() ); + + for( int j = 0; j < N; j++ ) + { + int const i = static_cast< int >(ordering[j]*N); + if( i != j ) + { + for( int k = 0; k < N; ++k ) + { + std::swap( A( i, k ), A( j, k )); + } + } + } +} + +// Local naive matrix-vector multiply +template< int USD > +void matrix_vector_multiply( arraySlice2d< real64 const, USD > const & A, + arraySlice1d< real64 const > const & x, + arraySlice1d< real64 > const & b ) +{ + int const N = LvArray::integerConversion< int >( A.size( 0 ) ); + for( int i = 0; i < N; ++i ) + { + real64 bi = 0.0; + for( int j = 0; j < N; ++j ) + { + bi += A( i, j )*x( j ); + } + b( i ) = bi; + } +} + +// Local naive matrix-matrix multiply +template< int USD > +void matrix_matrix_multiply( arraySlice2d< real64 const, USD > const & A, + arraySlice2d< real64 const, USD > const & X, + arraySlice2d< real64, USD > const & B ) +{ + int const K = LvArray::integerConversion< int >( A.size( 1 ) ); + int const M = LvArray::integerConversion< int >( X.size( 0 ) ); + int const N = LvArray::integerConversion< int >( X.size( 1 ) ); + for( int i = 0; i < M; ++i ) + { + for( int j = 0; j < N; ++j ) + { + real64 bij = 0.0; + for( int k = 0; k < K; ++k ) + { + bij += A( i, k )*X( k, j ); + } + B( i, j ) = bij; + } + } +} + +template< typename MatrixType > +struct ArrayType {}; + +template<> +struct ArrayType< Array< real64, 2, MatrixLayout::COL_MAJOR_PERM > > +{ + using type = Array< real64, 1 >; +}; +template<> +struct ArrayType< Array< real64, 2, MatrixLayout::ROW_MAJOR_PERM > > +{ + using type = Array< real64, 1 >; +}; +template<> +struct ArrayType< StackArray< real64, 2, MAX_SIZE *MAX_SIZE, MatrixLayout::COL_MAJOR_PERM > > +{ + using type = StackArray< real64, 1, MAX_SIZE >; +}; +template<> +struct ArrayType< StackArray< real64, 2, MAX_SIZE *MAX_SIZE, MatrixLayout::ROW_MAJOR_PERM > > +{ + using type = StackArray< real64, 1, MAX_SIZE >; +}; + +template< typename MatrixType > +class LinearSolveFixture : public ::testing::Test +{ +public: + using VectorType = typename ArrayType< MatrixType >::type; +public: + LinearSolveFixture() = default; + ~LinearSolveFixture() override = default; + + template< TestMatrixType TEST_MATRIX, int N > + void test_matrix_vector_solve() const + { + static_assert( 1 < N && N <= MAX_SIZE ); + + MatrixType A( N, N ); + TestMatrix< TEST_MATRIX >::create( A.toSlice() ); + random_permutation( A.toSlice() ); + + VectorType b ( N ); + VectorType x ( N ); + VectorType x0 ( N ); + + // Save selected values of A to check later + real64 const a00 = A( 0, 0 ); + real64 const a01 = A( 0, 1 ); + real64 const a10 = A( N-1, N-2 ); + real64 const a11 = A( N-1, N-1 ); + + // Create actual solution + LvArray::forValuesInSlice( x0.toSlice(), []( real64 & a ){ a = 1.0; } ); + + // Multiply to get rhs + matrix_vector_multiply( A.toSliceConst(), x0.toSliceConst(), b.toSlice() ); + + // Save selected values of b to check later + real64 const b0 = b( 0 ); + real64 const b1 = b( N-1 ); + + // Solve + BlasLapackLA::solveLinearSystem( A.toSliceConst(), b.toSliceConst(), x.toSlice() ); + + // Check solution + for( int i = 0; i < N; ++i ) + { + EXPECT_NEAR( x( i ), x0( i ), machinePrecision ); + } + + // Check that we have not destroyed A + EXPECT_NEAR( A( 0, 0 ), a00, machinePrecision ); + EXPECT_NEAR( A( 0, 1 ), a01, machinePrecision ); + EXPECT_NEAR( A( N-1, N-2 ), a10, machinePrecision ); + EXPECT_NEAR( A( N-1, N-1 ), a11, machinePrecision ); + + // Check that we have not destroyed b + EXPECT_NEAR( b( 0 ), b0, machinePrecision ); + EXPECT_NEAR( b( N-1 ), b1, machinePrecision ); + } + + template< TestMatrixType TEST_MATRIX, int N > + void test_matrix_vector_solve_inplace( ) const + { + static_assert( 1 < N && N <= MAX_SIZE ); + + MatrixType A( N, N ); + TestMatrix< TEST_MATRIX >::create( A.toSlice() ); + random_permutation( A.toSlice() ); + + VectorType x ( N ); + VectorType x0 ( N ); + + // Create actual solution + LvArray::forValuesInSlice( x0.toSlice(), []( real64 & a ){ a = 1.0; } ); + + // Multiply to get rhs + matrix_vector_multiply( A.toSliceConst(), x0.toSliceConst(), x.toSlice() ); + + // Solve + BlasLapackLA::solveLinearSystem( A, x.toSlice() ); + + // Check in place + for( int i = 0; i < N; ++i ) + { + EXPECT_NEAR( x( i ), x0( i ), machinePrecision ); + } + } + + template< TestMatrixType TEST_MATRIX, int N, int M > + void test_matrix_matrix_solve( ) const + { + static_assert( 1 < N && N <= MAX_SIZE ); + static_assert( 1 <= M && M <= MAX_SIZE ); + + MatrixType A ( N, N ); + TestMatrix< TEST_MATRIX >::create( A.toSlice() ); + random_permutation( A.toSlice() ); + + MatrixType B ( N, M ); + MatrixType X ( N, M ); + MatrixType X0 ( N, M ); + + real64 const a00 = A( 0, 0 ); + real64 const a01 = A( 0, 1 ); + real64 const a10 = A( N-1, N-2 ); + real64 const a11 = A( N-1, N-1 ); + + // Create actual solution + // Populate matrix with random coefficients + BlasLapackLA::matrixRand( X0, + BlasLapackLA::RandomNumberDistribution::UNIFORM_m1p1 ); + + // Multiply to get rhs + matrix_matrix_multiply( A.toSliceConst(), X0.toSliceConst(), B.toSlice() ); + + // Save selected values of B to check later + real64 const b00 = B( 0, 0 ); + real64 const b01 = B( N-1, M-1 ); + + // Solve + BlasLapackLA::solveLinearSystem( A.toSliceConst(), B.toSliceConst(), X.toSlice() ); + + // Check + for( int i = 0; i < N; ++i ) + { + for( int j = 0; j < M; ++j ) + { + EXPECT_NEAR( X( i, j ), X0( i, j ), machinePrecision ); + } + } + + // Check that we have not destroyed A + EXPECT_NEAR( A( 0, 0 ), a00, machinePrecision ); + EXPECT_NEAR( A( 0, 1 ), a01, machinePrecision ); + EXPECT_NEAR( A( N-1, N-2 ), a10, machinePrecision ); + EXPECT_NEAR( A( N-1, N-1 ), a11, machinePrecision ); + + // Check that we have not destroyed b + EXPECT_NEAR( B( 0, 0 ), b00, machinePrecision ); + EXPECT_NEAR( B( N-1, M-1 ), b01, machinePrecision ); + } + + template< TestMatrixType TEST_MATRIX, int N, int M > + void test_matrix_matrix_solve_inplace( ) const + { + static_assert( 1 < N && N <= MAX_SIZE ); + static_assert( 1 <= M && M <= MAX_SIZE ); + + MatrixType A ( N, N ); + TestMatrix< TEST_MATRIX >::create( A.toSlice() ); + random_permutation( A.toSlice() ); + + MatrixType X ( N, M ); + MatrixType X0 ( N, M ); + + // Create actual solution + // Populate matrix with random coefficients + BlasLapackLA::matrixRand( X0, + BlasLapackLA::RandomNumberDistribution::UNIFORM_m1p1 ); + + // Multiply to get rhs + matrix_matrix_multiply( A.toSliceConst(), X0.toSliceConst(), X.toSlice() ); + + // Solve + BlasLapackLA::solveLinearSystem( A.toSlice(), X.toSlice() ); + + // Check + for( int i = 0; i < N; ++i ) + { + for( int j = 0; j < M; ++j ) + { + EXPECT_NEAR( X( i, j ), X0( i, j ), machinePrecision ); + } + } + } +}; + +using LinearSolveTypes = ::testing::Types< + Array< real64, 2, MatrixLayout::COL_MAJOR_PERM >, + Array< real64, 2, MatrixLayout::ROW_MAJOR_PERM >, + StackArray< real64, 2, MAX_SIZE *MAX_SIZE, MatrixLayout::COL_MAJOR_PERM >, + StackArray< real64, 2, MAX_SIZE *MAX_SIZE, MatrixLayout::ROW_MAJOR_PERM > >; + +class NameGenerator +{ +public: + template< typename T > + static std::string GetName( int ) + { + if constexpr (std::is_same_v< T, Array< real64, 2, MatrixLayout::COL_MAJOR_PERM > >) return "col-major-heap-array"; + if constexpr (std::is_same_v< T, Array< real64, 2, MatrixLayout::ROW_MAJOR_PERM > >) return "row-major-heap-array"; + if constexpr (std::is_same_v< T, StackArray< real64, 2, MAX_SIZE *MAX_SIZE, MatrixLayout::COL_MAJOR_PERM > >) return "col-major-stack-array"; + if constexpr (std::is_same_v< T, StackArray< real64, 2, MAX_SIZE *MAX_SIZE, MatrixLayout::ROW_MAJOR_PERM > >) return "row-major-stack-array"; + } +}; + +TYPED_TEST_SUITE( LinearSolveFixture, LinearSolveTypes, NameGenerator ); + +TYPED_TEST( LinearSolveFixture, matrix_vector_solve_laplace ) +{ + this->template test_matrix_vector_solve< TestMatrixType::LAPLACE, 5 >(); + this->template test_matrix_vector_solve_inplace< TestMatrixType::LAPLACE, 5 >(); + this->template test_matrix_vector_solve< TestMatrixType::LAPLACE, 12 >(); + this->template test_matrix_vector_solve_inplace< TestMatrixType::LAPLACE, 12 >(); +} + +TYPED_TEST( LinearSolveFixture, matrix_vector_solve_grcar ) +{ + this->template test_matrix_vector_solve< TestMatrixType::GRCAR, 6 >(); + this->template test_matrix_vector_solve_inplace< TestMatrixType::GRCAR, 6 >(); + this->template test_matrix_vector_solve< TestMatrixType::GRCAR, 10 >(); + this->template test_matrix_vector_solve_inplace< TestMatrixType::GRCAR, 10 >(); +} + +TYPED_TEST( LinearSolveFixture, matrix_vector_solve_sampling ) +{ + this->template test_matrix_vector_solve< TestMatrixType::SAMPLING, 3 >(); + this->template test_matrix_vector_solve_inplace< TestMatrixType::SAMPLING, 3 >(); + this->template test_matrix_vector_solve< TestMatrixType::SAMPLING, 20 >(); + this->template test_matrix_vector_solve_inplace< TestMatrixType::SAMPLING, 20 >(); +} + +TYPED_TEST( LinearSolveFixture, matrix_matrix_solve_laplace ) +{ + this->template test_matrix_matrix_solve< TestMatrixType::LAPLACE, 5, 1 >(); + this->template test_matrix_matrix_solve_inplace< TestMatrixType::LAPLACE, 5, 1 >(); + this->template test_matrix_matrix_solve< TestMatrixType::LAPLACE, 5, 3 >(); + this->template test_matrix_matrix_solve_inplace< TestMatrixType::LAPLACE, 5, 3 >(); + this->template test_matrix_matrix_solve< TestMatrixType::LAPLACE, 5, 5 >(); + this->template test_matrix_matrix_solve_inplace< TestMatrixType::LAPLACE, 5, 5 >(); + this->template test_matrix_matrix_solve< TestMatrixType::LAPLACE, 5, 12 >(); + this->template test_matrix_matrix_solve_inplace< TestMatrixType::LAPLACE, 5, 12 >(); +} + +TYPED_TEST( LinearSolveFixture, matrix_matrix_solve_grcar ) +{ + this->template test_matrix_matrix_solve< TestMatrixType::GRCAR, 5, 1 >(); + this->template test_matrix_matrix_solve_inplace< TestMatrixType::GRCAR, 5, 1 >(); + this->template test_matrix_matrix_solve< TestMatrixType::GRCAR, 5, 3 >(); + this->template test_matrix_matrix_solve_inplace< TestMatrixType::GRCAR, 5, 3 >(); + this->template test_matrix_matrix_solve< TestMatrixType::GRCAR, 5, 5 >(); + this->template test_matrix_matrix_solve_inplace< TestMatrixType::GRCAR, 5, 5 >(); + this->template test_matrix_matrix_solve< TestMatrixType::GRCAR, 5, 12 >(); + this->template test_matrix_matrix_solve_inplace< TestMatrixType::GRCAR, 5, 12 >(); +} + +TYPED_TEST( LinearSolveFixture, matrix_matrix_solve_sampling ) +{ + this->template test_matrix_matrix_solve< TestMatrixType::SAMPLING, 5, 1 >(); + this->template test_matrix_matrix_solve_inplace< TestMatrixType::SAMPLING, 5, 1 >(); + this->template test_matrix_matrix_solve< TestMatrixType::SAMPLING, 12, 3 >(); + this->template test_matrix_matrix_solve_inplace< TestMatrixType::SAMPLING, 5, 3 >(); + this->template test_matrix_matrix_solve< TestMatrixType::SAMPLING, 5, 5 >(); + this->template test_matrix_matrix_solve_inplace< TestMatrixType::SAMPLING, 5, 5 >(); + this->template test_matrix_matrix_solve< TestMatrixType::SAMPLING, 5, 12 >(); + this->template test_matrix_matrix_solve_inplace< TestMatrixType::SAMPLING, 5, 12 >(); +} diff --git a/src/coreComponents/denseLinearAlgebra/unitTests/testUtils.hpp b/src/coreComponents/denseLinearAlgebra/unitTests/testUtils.hpp new file mode 100644 index 00000000000..17f093a569b --- /dev/null +++ b/src/coreComponents/denseLinearAlgebra/unitTests/testUtils.hpp @@ -0,0 +1,34 @@ + +#include "common/GeosxMacros.hpp" + +// TPL includes +#include + + +namespace geos +{ +namespace denseLinearAlgebra +{ +namespace testing +{ + + +#if defined(GEOS_DEVICE_COMPILE) +#define PORTABLE_EXPECT_EQ( L, R ) GEOS_ERROR_IF_NE( L, R ) +#define PORTABLE_EXPECT_NEAR( L, R, EPSILON ) LVARRAY_ERROR_IF_GE_MSG( LvArray::math::abs( ( L ) -( R ) ), EPSILON, \ + STRINGIZE( L ) " = " << ( L ) << "\n" << STRINGIZE( R ) " = " << ( R ) ); +#define PORTABLE_EXPECT_TRUE( value ) GEOS_ERROR_IF( !value, "should be true" ) +#define PORTABLE_EXPECT_FALSE( value ) GEOS_ERROR_IF( value, "should be false" ) +#else +#define PORTABLE_EXPECT_EQ( L, R ) EXPECT_EQ( L, R ) +#define PORTABLE_EXPECT_NEAR( L, R, EPSILON ) EXPECT_LE( LvArray::math::abs( ( L ) -( R ) ), EPSILON ) << \ + STRINGIZE( L ) " = " << ( L ) << "\n" << STRINGIZE( R ) " = " << ( R ); +#define PORTABLE_EXPECT_TRUE( value ) EXPECT_TRUE( value ) +#define PORTABLE_EXPECT_FALSE( value ) EXPECT_FALSE( value ) +#endif + +} //namespace testing + +} // namespace denseLinearAlgebra + +} // namespace geos diff --git a/src/coreComponents/discretizationMethods/CMakeLists.txt b/src/coreComponents/discretizationMethods/CMakeLists.txt index e038df90710..176924f5c41 100644 --- a/src/coreComponents/discretizationMethods/CMakeLists.txt +++ b/src/coreComponents/discretizationMethods/CMakeLists.txt @@ -1,3 +1,22 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: discretizationMethods + +Gives access to the discretization methods and their components for applications to the mesh. +#]] + # # Specify all headers # @@ -13,12 +32,17 @@ set( dependencyList ${parallelDeps} finiteVolume ) set( mainInterface_sources NumericalMethodsManager.cpp ) +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) + blt_add_library( NAME discretizationMethods SOURCES ${mainInterface_sources} HEADERS ${mainInterface_headers} - DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} + DEPENDS_ON ${decoratedDependencies} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} ) target_include_directories( discretizationMethods PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +install( TARGETS discretizationMethods LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) diff --git a/src/coreComponents/discretizationMethods/NumericalMethodsManager.cpp b/src/coreComponents/discretizationMethods/NumericalMethodsManager.cpp index 3de9232d7f0..6e4fb3c5cf5 100644 --- a/src/coreComponents/discretizationMethods/NumericalMethodsManager.cpp +++ b/src/coreComponents/discretizationMethods/NumericalMethodsManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/discretizationMethods/NumericalMethodsManager.hpp b/src/coreComponents/discretizationMethods/NumericalMethodsManager.hpp index 7022ea36110..503647f206a 100644 --- a/src/coreComponents/discretizationMethods/NumericalMethodsManager.hpp +++ b/src/coreComponents/discretizationMethods/NumericalMethodsManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/discretizationMethods/docs/NumericalMethodsManager.rst b/src/coreComponents/discretizationMethods/docs/NumericalMethodsManager.rst index ff8e3d19238..312b3acba67 100644 --- a/src/coreComponents/discretizationMethods/docs/NumericalMethodsManager.rst +++ b/src/coreComponents/discretizationMethods/docs/NumericalMethodsManager.rst @@ -5,7 +5,7 @@ Numerical Methods This section describes the specification of numerical methods used by solvers. -.. include:: /coreComponents/schema/docs/NumericalMethods.rst +.. include:: /docs/sphinx/datastructure/NumericalMethods.rst .. include:: /coreComponents/finiteElement/docs/FiniteElement.rst.txt diff --git a/src/coreComponents/dummy.cpp b/src/coreComponents/dummy.cpp index abf992adfe6..44722daa7d7 100644 --- a/src/coreComponents/dummy.cpp +++ b/src/coreComponents/dummy.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/events/CMakeLists.txt b/src/coreComponents/events/CMakeLists.txt index 8e87a2f62c6..a8e2e2ba714 100644 --- a/src/coreComponents/events/CMakeLists.txt +++ b/src/coreComponents/events/CMakeLists.txt @@ -1,3 +1,23 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: events + +Contains GEOS event types. +Manages the events and tasks. +#]] + # # Specify all headers # @@ -24,14 +44,19 @@ set( events_sources tasks/TasksManager.cpp ) -set( dependencyList ${parallelDeps} common fileIO dataRepository ) +set( dependencyList ${parallelDeps} functions ) + +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) blt_add_library( NAME events SOURCES ${events_sources} HEADERS ${events_headers} - DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} + DEPENDS_ON ${decoratedDependencies} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} ) target_include_directories( events PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +install( TARGETS events LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) diff --git a/src/coreComponents/events/EventBase.cpp b/src/coreComponents/events/EventBase.cpp index 93059a355a4..6212dc89d61 100644 --- a/src/coreComponents/events/EventBase.cpp +++ b/src/coreComponents/events/EventBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -121,7 +122,7 @@ EventBase::CatalogInterface::CatalogType & EventBase::getCatalog() Group * EventBase::createChild( string const & childKey, string const & childName ) { - GEOS_LOG_RANK_0( "Adding Event: " << childKey << ", " << childName ); + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) ); std::unique_ptr< EventBase > event = EventBase::CatalogInterface::factory( childKey, childName, this ); return &this->registerGroup< EventBase >( childName, std::move( event ) ); } diff --git a/src/coreComponents/events/EventBase.hpp b/src/coreComponents/events/EventBase.hpp index 99aa5b3cfbb..c3e4920b188 100644 --- a/src/coreComponents/events/EventBase.hpp +++ b/src/coreComponents/events/EventBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -44,12 +45,6 @@ class EventBase : public ExecutableGroup /// Destructor virtual ~EventBase() override; - /** - * @brief Catalog name interface. - * @return This type's catalog name. - **/ - static string catalogName() { return "EventBase"; } - /** * @brief If the event forecast is equal to 1, then signal the targets to prepare for execution * during the next cycle. @@ -162,7 +157,7 @@ class EventBase : public ExecutableGroup /** * @brief Helper function to validate the consistency of the event input - * @note We cannot use postProcessInput here because we can perform the validation only after the m_target pointer is set + * @note We cannot use postInputInitialization here because we can perform the validation only after the m_target pointer is set */ virtual void validate() const {}; @@ -175,7 +170,7 @@ class EventBase : public ExecutableGroup /** * @brief Update the event progress for the event/sub-events. * @note This method is used to determine how to handle the timestamp for an event - * @note If the event occurs after anything targeting a SolverBase object, then + * @note If the event occurs after anything targeting a PhysicsSolverBase object, then * set the m_isPostSolverEvent flag. If set, then the time passed to the target * will be time + dt. * @param eventCounters The event count for each event/sub-event. diff --git a/src/coreComponents/events/EventManager.cpp b/src/coreComponents/events/EventManager.cpp index 3ebb6c2af44..69c3a46dd95 100644 --- a/src/coreComponents/events/EventManager.cpp +++ b/src/coreComponents/events/EventManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #include "common/TimingMacros.hpp" #include "events/EventBase.hpp" -#include "mesh/mpiCommunications/CommunicationTools.hpp" +#include "common/MpiWrapper.hpp" #include "common/Units.hpp" namespace geos @@ -53,14 +54,14 @@ EventManager::EventManager( string const & name, setDescription( "Start simulation time for the global event loop." ); registerWrapper( viewKeyStruct::maxTimeString(), &m_maxTime ). - setApplyDefaultValue( std::numeric_limits< real64 >::max()). + setApplyDefaultValue( 10000 * units::YearSeconds ). // 10000 years setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Maximum simulation time for the global event loop." ); + setDescription( "Maximum simulation time for the global event loop. Disabled by default." ); registerWrapper( viewKeyStruct::maxCycleString(), &m_maxCycle ). - setApplyDefaultValue( std::numeric_limits< integer >::max()). + setApplyDefaultValue( std::numeric_limits< integer >::max() ). setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Maximum simulation cycle for the global event loop." ); + setDescription( "Maximum simulation cycle for the global event loop. Disabled by default." ); registerWrapper( viewKeyStruct::timeString(), &m_time ). setRestartFlags( RestartFlags::WRITE_AND_READ ). @@ -92,7 +93,7 @@ EventManager::~EventManager() Group * EventManager::createChild( string const & childKey, string const & childName ) { - GEOS_LOG_RANK_0( "Adding Event: " << childKey << ", " << childName ); + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) ); std::unique_ptr< EventBase > event = EventBase::CatalogInterface::factory( childKey, childName, this ); return &this->registerGroup< EventBase >( childName, std::move( event ) ); } @@ -162,10 +163,10 @@ bool EventManager::run( DomainPartition & domain ) } m_currentSubEvent = 0; -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI // Find the min dt across processes real64 dt_global; - MPI_Allreduce( &m_dt, &dt_global, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_GEOSX ); + MPI_Allreduce( &m_dt, &dt_global, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_GEOS ); m_dt = dt_global; #endif } @@ -226,24 +227,43 @@ bool EventManager::run( DomainPartition & domain ) void EventManager::outputTime() const { + const bool isTimeLimited = m_maxTime < std::numeric_limits< real64 >::max(); + const bool isCycleLimited = m_maxCycle < std::numeric_limits< integer >::max(); + units::TimeFormatInfo const timeInfo = units::TimeFormatInfo::fromSeconds( m_time ); + units::TimeFormatInfo const maxTimeInfo = units::TimeFormatInfo::fromSeconds( m_maxTime ); + + const auto timeCompletionUnfoldedString = [&]() -> std::string { + return GEOS_FMT( " out of {} ({:.0f}% completed)", + maxTimeInfo.toUnfoldedString(), + 100.0 * (m_time - m_minTime) / ( m_maxTime - m_minTime ) ); + }; + const auto timeCompletionSecondsString = [&]() -> std::string { + return GEOS_FMT( " / {}", maxTimeInfo.toSecondsString() ); + }; + const auto cycleCompletionString = [&]() -> std::string { + return GEOS_FMT( " out of {} ({:.0f}% completed)", + m_maxCycle, ( 100.0 * m_cycle ) / m_maxCycle ); + }; + // The formating here is a work in progress. - GEOS_LOG_RANK_0( GEOS_FMT( "\n" - "------------------- TIMESTEP START -------------------\n" - " - Time: {}\n" - " - Delta Time: {}\n" - " - Cycle: {}\n" - "------------------------------------------------------\n\n", - units::TimeFormatInfo::fromSeconds( m_time ), - units::TimeFormatInfo::fromSeconds( m_dt ), - m_cycle )); + GEOS_LOG_RANK_0( "\n------------------------- TIMESTEP START -------------------------" ); + GEOS_LOG_RANK_0( GEOS_FMT( " - Time: {}{}", + timeInfo.toUnfoldedString(), + isTimeLimited ? timeCompletionUnfoldedString() : "" ) ); + GEOS_LOG_RANK_0( GEOS_FMT( " ({}{})", + timeInfo.toSecondsString(), + isTimeLimited ? timeCompletionSecondsString() : "" ) ); + GEOS_LOG_RANK_0( GEOS_FMT( " - Delta Time: {}", units::TimeFormatInfo::fromSeconds( m_dt ) ) ); + GEOS_LOG_RANK_0( GEOS_FMT( " - Cycle: {}{}", + m_cycle, + isCycleLimited ? cycleCompletionString() : "" ) ); + GEOS_LOG_RANK_0( "--------------------------------------------------------------------\n" ); // We are keeping the old outputs to keep compatibility with current log reading scripts. if( m_timeOutputFormat==TimeOutputFormat::full ) { - units::TimeFormatInfo info = units::TimeFormatInfo::fromSeconds( m_time ); - GEOS_LOG_RANK_0( GEOS_FMT( "Time: {} years, {} days, {} hrs, {} min, {} s, dt: {} s, Cycle: {}\n", - info.m_years, info.m_days, info.m_hours, info.m_minutes, info.m_seconds, m_dt, m_cycle ) ); + timeInfo.m_years, timeInfo.m_days, timeInfo.m_hours, timeInfo.m_minutes, timeInfo.m_seconds, m_dt, m_cycle ) ); } else if( m_timeOutputFormat==TimeOutputFormat::years ) { diff --git a/src/coreComponents/events/EventManager.hpp b/src/coreComponents/events/EventManager.hpp index c839346d19a..b86f48b8518 100644 --- a/src/coreComponents/events/EventManager.hpp +++ b/src/coreComponents/events/EventManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/events/HaltEvent.cpp b/src/coreComponents/events/HaltEvent.cpp index a604b59c159..93cc9d2d581 100644 --- a/src/coreComponents/events/HaltEvent.cpp +++ b/src/coreComponents/events/HaltEvent.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -65,7 +66,7 @@ void HaltEvent::estimateEventTiming( real64 const GEOS_UNUSED_PARAM( time ), // The timing for the ranks may differ slightly, so synchronize // TODO: Only do the communication when you are close to the end? -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI integer forecast_global; MPI_Allreduce( &forecast, &forecast_global, 1, MPI_INT, MPI_MIN, MPI_COMM_WORLD ); forecast = forecast_global; diff --git a/src/coreComponents/events/HaltEvent.hpp b/src/coreComponents/events/HaltEvent.hpp index b9c05281ac3..68501ea47b2 100644 --- a/src/coreComponents/events/HaltEvent.hpp +++ b/src/coreComponents/events/HaltEvent.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/events/PeriodicEvent.cpp b/src/coreComponents/events/PeriodicEvent.cpp index 69261113cea..e26ea889137 100644 --- a/src/coreComponents/events/PeriodicEvent.cpp +++ b/src/coreComponents/events/PeriodicEvent.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,7 +19,7 @@ #include "PeriodicEvent.hpp" -#include "common/Format.hpp" +#include "common/format/Format.hpp" #include "functions/FunctionManager.hpp" namespace geos @@ -171,10 +172,30 @@ void PeriodicEvent::checkOptionalFunctionThreshold( real64 const time, // Because the function applied to an object may differ by rank, synchronize // (Note: this shouldn't occur very often, since it is only called if the base forecast <= 0) -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI real64 result_global; - MPI_Allreduce( &result, &result_global, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD ); - result = result_global; + switch( m_functionStatOption ) + { + case 0: + { + MPI_Allreduce( &result, &result_global, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD ); + result = result_global; + break; + } + case 1: + { + int nprocs; + MPI_Comm_size( MPI_COMM_WORLD, &nprocs ); + MPI_Allreduce( &result, &result_global, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); + result = result_global / nprocs; + break; + } + case 2: + { + MPI_Allreduce( &result, &result_global, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD ); + result = result_global; + } + } #endif } diff --git a/src/coreComponents/events/PeriodicEvent.hpp b/src/coreComponents/events/PeriodicEvent.hpp index e6db372eb35..9c2cf943c87 100644 --- a/src/coreComponents/events/PeriodicEvent.hpp +++ b/src/coreComponents/events/PeriodicEvent.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/events/SoloEvent.cpp b/src/coreComponents/events/SoloEvent.cpp index 3894ff6447f..89d8b2edd23 100644 --- a/src/coreComponents/events/SoloEvent.cpp +++ b/src/coreComponents/events/SoloEvent.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/events/SoloEvent.hpp b/src/coreComponents/events/SoloEvent.hpp index b636df1eba6..d905e07e479 100644 --- a/src/coreComponents/events/SoloEvent.hpp +++ b/src/coreComponents/events/SoloEvent.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/events/docs/EventManager.rst b/src/coreComponents/events/docs/EventManager.rst index 76c94493feb..8fe6ace3bb8 100644 --- a/src/coreComponents/events/docs/EventManager.rst +++ b/src/coreComponents/events/docs/EventManager.rst @@ -52,8 +52,8 @@ Event ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The children of the Event block define the events that may execute during a simulation. These may be of type ``HaltEvent``, ``PeriodicEvent``, or ``SoloEvent``. The exit criteria for the global event loop are defined by the attributes ``maxTime`` and ``maxCycle`` (which by default are set to their max values). If the optional logLevel flag is set, the EventManager will report additional information with regards to timestep requests and event forecasts for its children. -.. include:: ../../../coreComponents/schema/docs/Events.rst - +.. include:: /docs/sphinx/datastructure/Events.rst + :start-line: 3 PeriodicEvent ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -67,21 +67,22 @@ By default, a PeriodicEvent will execute throughout the entire simulation. This The timestep request event is typically determined via its target. However, this value can be overridden by setting the ``forceDt`` or ``maxEventDt`` attributes. -.. include:: ../../../coreComponents/schema/docs/PeriodicEvent.rst - +.. include:: /docs/sphinx/datastructure/PeriodicEvent.rst + :start-line: 3 SoloEvent ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This type of event will execute once once the event loop reaches a certain cycle (targetCycle) or time (targetTime). Similar to the PeriodicEvent type, this event will modify its timestep requests so that a cycle occurs at the exact time requested (this can be turned off by specifying targetExactTimestep="0"). The forecast calculations follow an similar approach to the PeriodicEvent type. -.. include:: ../../../coreComponents/schema/docs/SoloEvent.rst - +.. include:: /docs/sphinx/datastructure/SoloEvent.rst + :start-line: 3 HaltEvent ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This event type is designed to track the wall clock. When the time exceeds the value specified via maxRunTime, the event will trigger and set a flag that instructs the main EventManager loop to cleanly exit at the end of the current cycle. The event for cast for this event type is given by: ``forecast = (maxRuntime - (currentTime - startTime)) / realDt`` -.. include:: ../../../coreComponents/schema/docs/HaltEvent.rst +.. include:: /docs/sphinx/datastructure/HaltEvent.rst + :start-line: 3 diff --git a/src/coreComponents/events/docs/TasksManager.rst b/src/coreComponents/events/docs/TasksManager.rst index c0e5740b483..49ca88b6dc6 100644 --- a/src/coreComponents/events/docs/TasksManager.rst +++ b/src/coreComponents/events/docs/TasksManager.rst @@ -21,13 +21,15 @@ Task *************************** The children of the Tasks block define different Tasks to be triggered by events specified in the :ref:`EventManager` during the execution of the simulation. At present the only supported task is the ``PackCollection`` used to collect time history data for output by a TimeHistory output. -.. include:: ../../../coreComponents/schema/docs/Tasks.rst - +.. include:: /docs/sphinx/datastructure/Tasks.rst + :start-line: 3 + PackCollection *************************** The ``PackCollection`` Task is used to collect time history information from fields. Either the entire field or specified named sets of indices in the field can be collected. -.. include:: ../../../coreComponents/schema/docs/PackCollection.rst +.. include:: /docs/sphinx/datastructure/PackCollection.rst + :start-line: 3 Note: The time history information collected via this task is buffered internally until it is output by a linked TimeHistory Output. diff --git a/src/coreComponents/events/tasks/TaskBase.cpp b/src/coreComponents/events/tasks/TaskBase.cpp index 5819a0c70f4..6020534f189 100644 --- a/src/coreComponents/events/tasks/TaskBase.cpp +++ b/src/coreComponents/events/tasks/TaskBase.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -39,7 +40,7 @@ TaskBase::CatalogInterface::CatalogType & TaskBase::getCatalog() return catalog; } -void TaskBase::postProcessInput() +void TaskBase::postInputInitialization() { } } /* namespace */ diff --git a/src/coreComponents/events/tasks/TaskBase.hpp b/src/coreComponents/events/tasks/TaskBase.hpp index 94293fa2896..dfe0393fe86 100644 --- a/src/coreComponents/events/tasks/TaskBase.hpp +++ b/src/coreComponents/events/tasks/TaskBase.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -39,12 +40,6 @@ class TaskBase : public ExecutableGroup Group * const parent ); virtual ~TaskBase( ) override; - /** - * @brief Catalog name interface - * @return This type's catalog name - */ - static string catalogName() { return "TaskBase"; } - /// The catalog interface type for TaskBase using CatalogInterface = dataRepository::CatalogInterface< TaskBase, string const &, Group * const >; /** @@ -71,8 +66,8 @@ class TaskBase : public ExecutableGroup return false; } - /// @copydoc geos::dataRepository::Group::postProcessInput( ) - void postProcessInput() override; + /// @copydoc geos::dataRepository::Group::postInputInitialization( ) + void postInputInitialization() override; }; } /* namespace */ diff --git a/src/coreComponents/events/tasks/TasksManager.cpp b/src/coreComponents/events/tasks/TasksManager.cpp index 133e5bc9987..9f95aefb2ac 100644 --- a/src/coreComponents/events/tasks/TasksManager.cpp +++ b/src/coreComponents/events/tasks/TasksManager.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -37,6 +38,7 @@ TasksManager::~TasksManager() Group * TasksManager::createChild( string const & childKey, string const & childName ) { + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) ); std::unique_ptr< TaskBase > task = TaskBase::CatalogInterface::factory( childKey, childName, this ); return &this->registerGroup< TaskBase >( childName, std::move( task ) ); } diff --git a/src/coreComponents/events/tasks/TasksManager.hpp b/src/coreComponents/events/tasks/TasksManager.hpp index d47237b40cc..852e0fd8cf4 100644 --- a/src/coreComponents/events/tasks/TasksManager.hpp +++ b/src/coreComponents/events/tasks/TasksManager.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/fieldSpecification/AquiferBoundaryCondition.cpp b/src/coreComponents/fieldSpecification/AquiferBoundaryCondition.cpp index f74b40c75a5..061cfc344b9 100644 --- a/src/coreComponents/fieldSpecification/AquiferBoundaryCondition.cpp +++ b/src/coreComponents/fieldSpecification/AquiferBoundaryCondition.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,8 +19,6 @@ #include "AquiferBoundaryCondition.hpp" -#include "mesh/DomainPartition.hpp" - namespace geos { @@ -113,7 +112,7 @@ AquiferBoundaryCondition::AquiferBoundaryCondition( string const & name, Group * } -void AquiferBoundaryCondition::postProcessInput() +void AquiferBoundaryCondition::postInputInitialization() { GEOS_THROW_IF_LE_MSG( m_permeability, 0.0, getCatalogName() << " " << getDataContext() << @@ -164,7 +163,7 @@ void AquiferBoundaryCondition::postProcessInput() void AquiferBoundaryCondition::setupDefaultPressureInfluenceFunction() { - // default table; see Eclipse or Intersect documentation + // default table array1d< array1d< real64 > > dimensionlessTime; dimensionlessTime.resize( 1 ); @@ -282,14 +281,13 @@ void AquiferBoundaryCondition::setGravityVector( R1Tensor const & gravityVector void AquiferBoundaryCondition::computeTimeConstant() { - // equation 5.3 of the Eclipse TD m_timeConstant = m_viscosity * m_porosity * m_totalCompressibility * m_innerRadius * m_innerRadius; m_timeConstant /= m_permeability; } void AquiferBoundaryCondition::computeInfluxConstant() { - // equation 5.4 of the Eclipse TD, including the constant 6.283 of the Carter-Tracy model + // 6.283 is the constant of the Carter-Tracy model m_influxConstant = 6.283 * m_thickness * ( m_angle / 360.0 ) * m_porosity * m_totalCompressibility * m_innerRadius * m_innerRadius; } diff --git a/src/coreComponents/fieldSpecification/AquiferBoundaryCondition.hpp b/src/coreComponents/fieldSpecification/AquiferBoundaryCondition.hpp index 0ecf1dc2793..4b27724fefe 100644 --- a/src/coreComponents/fieldSpecification/AquiferBoundaryCondition.hpp +++ b/src/coreComponents/fieldSpecification/AquiferBoundaryCondition.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -117,7 +118,7 @@ class AquiferBoundaryCondition : public FieldSpecificationBase }; - /// @copydoc FieldSpecificationBase(string const &, Group *) + /// @copydoc FieldSpecificationBase(string const &, dataRepository::Group *) AquiferBoundaryCondition( string const & name, Group * parent ); /// deleted default constructor @@ -264,7 +265,7 @@ class AquiferBoundaryCondition : public FieldSpecificationBase protected: - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; private: @@ -356,7 +357,7 @@ AquiferBoundaryCondition::KernelWrapper:: real64 const & areaFraction, real64 & dAquiferVolFlux_dPres ) const { - // compute the dimensionless time (equation 5.5 of the Eclipse TD) + // compute the dimensionless time real64 const dimensionlessTimeAtBeginningOfStep = timeAtBeginningOfStep / m_timeConstant; real64 const dimensionlessTimeAtEndOfStep = ( timeAtBeginningOfStep + dt ) / m_timeConstant; @@ -367,15 +368,15 @@ AquiferBoundaryCondition::KernelWrapper:: // compute the potential difference between the reservoir (old pressure) and the aquifer real64 const potDiff = m_initialPressure - reservoirPressure_n - m_density * ( m_gravCoef - reservoirGravCoef ); - // compute the a (equation 5.8 of the Eclipse TD) + // compute the a real64 const timeConstantInv = 1.0 / m_timeConstant; real64 const denom = presInfluence - dimensionlessTimeAtBeginningOfStep * dPresInfluence_dTime; real64 const a = timeConstantInv * ( m_influxConstant * potDiff - m_cumulativeFlux * dPresInfluence_dTime ) / denom; - // compute the b (equation 5.9 of the Eclipse TD) + // compute the b real64 const b = timeConstantInv * m_influxConstant / denom; - // compute the average inflow rate Q (equation 5.7 of the Eclipse TD) + // compute the average inflow rate Q real64 const aquiferVolFlux = areaFraction * ( a - b * ( reservoirPressure - reservoirPressure_n ) ); dAquiferVolFlux_dPres = -areaFraction * b; diff --git a/src/coreComponents/fieldSpecification/CMakeLists.txt b/src/coreComponents/fieldSpecification/CMakeLists.txt index 10ad2e8ec1a..0b6ff6691e6 100644 --- a/src/coreComponents/fieldSpecification/CMakeLists.txt +++ b/src/coreComponents/fieldSpecification/CMakeLists.txt @@ -1,3 +1,24 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: fieldSpecification + +Contains: + - field specification objects definition. + - an interface to manage these objects. +#]] + # # Specify all headers # @@ -26,14 +47,19 @@ set( fieldSpecification_sources PerfectlyMatchedLayer.cpp ) -set( dependencyList ${parallelDeps} functions linearAlgebra ) +set( dependencyList ${parallelDeps} mesh ) + +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) blt_add_library( NAME fieldSpecification SOURCES ${fieldSpecification_sources} HEADERS ${fieldSpecification_headers} - DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} + DEPENDS_ON ${decoratedDependencies} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} ) target_include_directories( fieldSpecification PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +install( TARGETS fieldSpecification LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) diff --git a/src/coreComponents/fieldSpecification/DirichletBoundaryCondition.cpp b/src/coreComponents/fieldSpecification/DirichletBoundaryCondition.cpp index 81fd8b4f32c..19a62d921dd 100644 --- a/src/coreComponents/fieldSpecification/DirichletBoundaryCondition.cpp +++ b/src/coreComponents/fieldSpecification/DirichletBoundaryCondition.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/fieldSpecification/DirichletBoundaryCondition.hpp b/src/coreComponents/fieldSpecification/DirichletBoundaryCondition.hpp index b838fcaa171..553ac23e7dc 100644 --- a/src/coreComponents/fieldSpecification/DirichletBoundaryCondition.hpp +++ b/src/coreComponents/fieldSpecification/DirichletBoundaryCondition.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/fieldSpecification/EquilibriumInitialCondition.cpp b/src/coreComponents/fieldSpecification/EquilibriumInitialCondition.cpp index f5df02ff47c..c355f36d927 100644 --- a/src/coreComponents/fieldSpecification/EquilibriumInitialCondition.cpp +++ b/src/coreComponents/fieldSpecification/EquilibriumInitialCondition.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -89,7 +90,7 @@ EquilibriumInitialCondition::EquilibriumInitialCondition( string const & name, G addSetName( "all" ); } -void EquilibriumInitialCondition::postProcessInput() +void EquilibriumInitialCondition::postInputInitialization() { GEOS_THROW_IF( ( m_temperatureVsElevationTableName.empty() != m_componentFractionVsElevationTableNames.empty() ), diff --git a/src/coreComponents/fieldSpecification/EquilibriumInitialCondition.hpp b/src/coreComponents/fieldSpecification/EquilibriumInitialCondition.hpp index ea6834362b4..fe29ce2fc40 100644 --- a/src/coreComponents/fieldSpecification/EquilibriumInitialCondition.hpp +++ b/src/coreComponents/fieldSpecification/EquilibriumInitialCondition.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -33,7 +34,7 @@ class EquilibriumInitialCondition : public FieldSpecificationBase { public: - /// @copydoc FieldSpecificationBase(string const &, Group *) + /// @copydoc FieldSpecificationBase(string const &, dataRepository::Group *) EquilibriumInitialCondition( string const & name, Group * parent ); /// deleted default constructor @@ -162,7 +163,7 @@ class EquilibriumInitialCondition : public FieldSpecificationBase protected: - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; virtual void initializePreSubGroups() override final; diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp index 09f92109054..693ecc2f4aa 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,8 +17,6 @@ #include "common/MpiWrapper.hpp" #include "fieldSpecification/FieldSpecificationManager.hpp" -#include "mesh/DomainPartition.hpp" - namespace geos { diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp index 49a49f0a081..cdce71bc664 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -25,7 +26,6 @@ #include "codingUtilities/Utilities.hpp" #include "dataRepository/Group.hpp" #include "functions/FunctionBase.hpp" -#include "linearAlgebra/interfaces/InterfaceTypes.hpp" #include "common/FieldSpecificationOps.hpp" #include "mesh/ObjectManagerBase.hpp" #include "mesh/MeshObjectPath.hpp" diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationManager.cpp b/src/coreComponents/fieldSpecification/FieldSpecificationManager.cpp index f1b8d2df8d1..155596304d6 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationManager.cpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -14,7 +15,7 @@ #include "FieldSpecificationManager.hpp" -#include "codingUtilities/StringUtilities.hpp" +#include "common/format/StringUtilities.hpp" #include "constitutive/ConstitutiveManager.hpp" namespace geos @@ -50,6 +51,7 @@ FieldSpecificationManager & FieldSpecificationManager::getInstance() Group * FieldSpecificationManager::createChild( string const & childKey, string const & childName ) { + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) ); std::unique_ptr< FieldSpecificationBase > bc = FieldSpecificationBase::CatalogInterface::factory( childKey, childName, this ); return &this->registerGroup( childName, std::move( bc ) ); } diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationManager.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationManager.hpp index 65f95ec70ce..be7f8ffec7b 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationManager.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,11 +22,9 @@ #include "FieldSpecificationBase.hpp" -#include "codingUtilities/StringUtilities.hpp" +#include "common/format/StringUtilities.hpp" #include "common/DataTypes.hpp" #include "common/TimingMacros.hpp" -#include "mesh/ObjectManagerBase.hpp" -#include "mesh/DomainPartition.hpp" namespace geos { diff --git a/src/coreComponents/fieldSpecification/PerfectlyMatchedLayer.cpp b/src/coreComponents/fieldSpecification/PerfectlyMatchedLayer.cpp index bdc50920a25..c2d7317cec0 100644 --- a/src/coreComponents/fieldSpecification/PerfectlyMatchedLayer.cpp +++ b/src/coreComponents/fieldSpecification/PerfectlyMatchedLayer.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -75,7 +76,7 @@ PerfectlyMatchedLayer::PerfectlyMatchedLayer( string const & name, Group * const } -void PerfectlyMatchedLayer::postProcessInput() +void PerfectlyMatchedLayer::postInputInitialization() { GEOS_THROW_IF( (m_xMax[0]( FieldSpecificationBase::viewKeyStruct::fieldNameString() ). setInputFlag( InputFlags::FALSE ); setFieldName( catalogName() ); + + getWrapper< string >( FieldSpecificationBase::viewKeyStruct::functionNameString() ). + setDescription( GEOS_FMT( "Name of a function that specifies the variation of the production rate variations of this {}." + "Multiplied by {}. If no function is provided, a constant value of 1 is used." + "The producted fluid rate unit is in kg by default, or in mole if the flow solver has a {} of 0.", + catalogName(), + FieldSpecificationBase::viewKeyStruct::scaleString(), + CompositionalMultiphaseBase::viewKeyStruct::useMassFlagString() ) ); + + getWrapper< real64 >( FieldSpecificationBase::viewKeyStruct::scaleString() ). + setDescription( GEOS_FMT( "Multiplier of the {0} value. If no {0} is provided, this value is used directly.", + FieldSpecificationBase::viewKeyStruct::functionNameString() ) ); } REGISTER_CATALOG_ENTRY( FieldSpecificationBase, SourceFluxBoundaryCondition, string const &, Group * const ) diff --git a/src/coreComponents/fieldSpecification/SourceFluxBoundaryCondition.hpp b/src/coreComponents/fieldSpecification/SourceFluxBoundaryCondition.hpp index 804b14f8559..2ee5e258bef 100644 --- a/src/coreComponents/fieldSpecification/SourceFluxBoundaryCondition.hpp +++ b/src/coreComponents/fieldSpecification/SourceFluxBoundaryCondition.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/fieldSpecification/TractionBoundaryCondition.cpp b/src/coreComponents/fieldSpecification/TractionBoundaryCondition.cpp index 5bf74b2d2da..4d924a8a41a 100644 --- a/src/coreComponents/fieldSpecification/TractionBoundaryCondition.cpp +++ b/src/coreComponents/fieldSpecification/TractionBoundaryCondition.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -60,7 +61,7 @@ TractionBoundaryCondition::TractionBoundaryCondition( string const & name, Group } -void TractionBoundaryCondition::postProcessInput() +void TractionBoundaryCondition::postInputInitialization() { if( m_tractionType == TractionType::vector ) { diff --git a/src/coreComponents/fieldSpecification/TractionBoundaryCondition.hpp b/src/coreComponents/fieldSpecification/TractionBoundaryCondition.hpp index b689bd8a672..03c67657393 100644 --- a/src/coreComponents/fieldSpecification/TractionBoundaryCondition.hpp +++ b/src/coreComponents/fieldSpecification/TractionBoundaryCondition.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -35,7 +36,7 @@ class TableFunction; class TractionBoundaryCondition : public FieldSpecificationBase { public: - /// @copydoc FieldSpecificationBase(string const &, Group *) + /// @copydoc FieldSpecificationBase(string const &, dataRepository::Group *) TractionBoundaryCondition( string const & name, Group * parent ); /// deleted default constructor @@ -108,7 +109,7 @@ class TractionBoundaryCondition : public FieldSpecificationBase protected: - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; virtual void initializePreSubGroups() override final; diff --git a/src/coreComponents/fieldSpecification/docs/AquiferBoundaryCondition.rst b/src/coreComponents/fieldSpecification/docs/AquiferBoundaryCondition.rst index 86e22f1349b..fff21095fe4 100644 --- a/src/coreComponents/fieldSpecification/docs/AquiferBoundaryCondition.rst +++ b/src/coreComponents/fieldSpecification/docs/AquiferBoundaryCondition.rst @@ -156,7 +156,7 @@ The main Carter-Tracy parameters and the expected units are listed below: The full list of parameters is provided below: -.. include:: /coreComponents/schema/docs/Aquifer.rst +.. include:: /docs/sphinx/datastructure/Aquifer.rst Examples =============== diff --git a/src/coreComponents/fieldSpecification/docs/EquilibriumInitialCondition.rst b/src/coreComponents/fieldSpecification/docs/EquilibriumInitialCondition.rst index a3489725b82..3967e4d5831 100644 --- a/src/coreComponents/fieldSpecification/docs/EquilibriumInitialCondition.rst +++ b/src/coreComponents/fieldSpecification/docs/EquilibriumInitialCondition.rst @@ -58,7 +58,7 @@ These parameters are used with the fluid density model (depending for compositio The full list of parameters is provided below: -.. include:: /coreComponents/schema/docs/HydrostaticEquilibrium.rst +.. include:: /docs/sphinx/datastructure/HydrostaticEquilibrium.rst Examples diff --git a/src/coreComponents/fileIO/CMakeLists.txt b/src/coreComponents/fileIO/CMakeLists.txt index c479846cc79..a53eda4945c 100644 --- a/src/coreComponents/fileIO/CMakeLists.txt +++ b/src/coreComponents/fileIO/CMakeLists.txt @@ -1,4 +1,27 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: fileIO + +Contains: + - I/O interfaces for the packing components and supported outputs and their python wrappers. + - a coupler for data exchange with CHOMBO. +#]] + +# # Specify all headers +# set( fileIO_headers Outputs/BlueprintOutput.hpp Outputs/OutputBase.hpp @@ -14,7 +37,9 @@ set( fileIO_headers timeHistory/HDFHistoryIO.hpp timeHistory/HistoryCollection.hpp ) +# # Specify all sources +# set( fileIO_sources Outputs/BlueprintOutput.cpp Outputs/OutputBase.cpp @@ -28,7 +53,7 @@ set( fileIO_sources timeHistory/PackCollection.cpp timeHistory/HDFHistoryIO.cpp ) -set( dependencyList ${parallelDeps} mesh constitutive hdf5 ) +set( dependencyList ${parallelDeps} events mesh HDF5::HDF5 ) if( ENABLE_PYGEOSX ) list( APPEND fileIO_headers python/PyHistoryCollectionType.hpp @@ -44,17 +69,17 @@ endif() if( ENABLE_MPI ) add_subdirectory( coupling/hdf5_interface ) - list( APPEND dependencyList mpi hdf5_interface ) + list( APPEND dependencyList mpi hdf5_interface HDF5::HDF5 ) list( APPEND fileIO_headers coupling/ChomboCoupler.hpp Outputs/ChomboIO.hpp ) list( APPEND fileIO_sources coupling/ChomboCoupler.cpp Outputs/ChomboIO.cpp ) endif() if( ENABLE_SILO ) - list( APPEND dependencyList silo ) - list( APPEND fileIO_headers - silo/SiloFile.hpp + list( APPEND dependencyList silo HDF5::HDF5) + list( APPEND fileIO_headers + silo/SiloFile.hpp Outputs/SiloOutput.hpp ) - list( APPEND fileIO_sources + list( APPEND fileIO_sources silo/SiloFile.cpp Outputs/SiloOutput.cpp ) endif( ) @@ -75,17 +100,25 @@ if( ENABLE_VTK ) list( APPEND dependencyList VTK::IOLegacy VTK::IOXML ) endif() -if( ENABLE_CUDA_NVTOOLSEXT ) +if( ENABLE_CUDA AND ENABLE_CUDA_NVTOOLSEXT ) list( APPEND dependencyList CUDA::nvToolsExt ) endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) + blt_add_library( NAME fileIO SOURCES ${fileIO_sources} HEADERS ${fileIO_headers} - DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} ) + DEPENDS_ON ${decoratedDependencies} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} + ) target_include_directories( fileIO PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +install( TARGETS fileIO LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) + + diff --git a/src/coreComponents/fileIO/Outputs/BlueprintOutput.cpp b/src/coreComponents/fileIO/Outputs/BlueprintOutput.cpp index fce0d9f4eab..55bf84e79ba 100644 --- a/src/coreComponents/fileIO/Outputs/BlueprintOutput.cpp +++ b/src/coreComponents/fileIO/Outputs/BlueprintOutput.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -128,53 +129,57 @@ BlueprintOutput::BlueprintOutput( string const & name, } /////////////////////////////////////////////////////////////////////////////////////////////////// -bool BlueprintOutput::execute( real64 const time, - real64 const, - integer const cycle, - integer const, - real64 const, +bool BlueprintOutput::execute( real64 const time_n, + real64 const GEOS_UNUSED_PARAM( dt ), + integer const cycleNumber, + integer const GEOS_UNUSED_PARAM( eventCounter ), + real64 const GEOS_UNUSED_PARAM( eventProgress ), DomainPartition & domain ) { GEOS_MARK_FUNCTION; - MeshLevel const & meshLevel = domain.getMeshBody( 0 ).getBaseDiscretization(); + { + Timer timer( m_outputTimer ); - conduit::Node meshRoot; - conduit::Node & mesh = meshRoot[ "mesh" ]; - conduit::Node & coordset = mesh[ "coordsets/nodes" ]; - conduit::Node & topologies = mesh[ "topologies" ]; + MeshLevel const & meshLevel = domain.getMeshBody( 0 ).getBaseDiscretization(); - mesh[ "state/time" ] = time; - mesh[ "state/cycle" ] = cycle; + conduit::Node meshRoot; + conduit::Node & mesh = meshRoot[ "mesh" ]; + conduit::Node & coordset = mesh[ "coordsets/nodes" ]; + conduit::Node & topologies = mesh[ "topologies" ]; - addNodalData( meshLevel.getNodeManager(), coordset, topologies, mesh[ "fields" ] ); + mesh[ "state/time" ] = time_n; + mesh[ "state/cycle" ] = cycleNumber; - dataRepository::Group averagedElementData( "averagedElementData", this ); - addElementData( meshLevel.getElemManager(), coordset, topologies, mesh[ "fields" ], averagedElementData ); + addNodalData( meshLevel.getNodeManager(), coordset, topologies, mesh[ "fields" ] ); - /// The Blueprint will complain if the fields node is present but empty. - if( mesh[ "fields" ].number_of_children() == 0 ) - { - mesh.remove( "fields" ); - } + dataRepository::Group averagedElementData( "averagedElementData", this ); + addElementData( meshLevel.getElemManager(), coordset, topologies, mesh[ "fields" ], averagedElementData ); + + /// The Blueprint will complain if the fields node is present but empty. + if( mesh[ "fields" ].number_of_children() == 0 ) + { + mesh.remove( "fields" ); + } - /// Verify that the mesh conforms to the Blueprint. - conduit::Node info; - GEOS_ASSERT_MSG( conduit::blueprint::verify( "mesh", meshRoot, info ), info.to_json() ); + /// Verify that the mesh conforms to the Blueprint. + conduit::Node info; + GEOS_ASSERT_MSG( conduit::blueprint::verify( "mesh", meshRoot, info ), info.to_json() ); - /// Generate the Blueprint index. - conduit::Node fileRoot; - conduit::Node & index = fileRoot[ "blueprint_index/mesh" ]; - conduit::blueprint::mesh::generate_index( mesh, "mesh", MpiWrapper::commSize(), index ); + /// Generate the Blueprint index. + conduit::Node fileRoot; + conduit::Node & index = fileRoot[ "blueprint_index/mesh" ]; + conduit::blueprint::mesh::generate_index( mesh, "mesh", MpiWrapper::commSize(), index ); - /// Verify that the index conforms to the Blueprint. - info.reset(); - GEOS_ASSERT_MSG( conduit::blueprint::mesh::index::verify( index, info ), info.to_json() ); + /// Verify that the index conforms to the Blueprint. + info.reset(); + GEOS_ASSERT_MSG( conduit::blueprint::mesh::index::verify( index, info ), info.to_json() ); - /// Write out the root index file, then write out the mesh. - string const completePath = GEOS_FMT( "{}/blueprintFiles/cycle_{:07}", OutputBase::getOutputDirectory(), cycle ); - string const filePathForRank = dataRepository::writeRootFile( fileRoot, completePath ); - conduit::relay::io::save( meshRoot, filePathForRank, "hdf5" ); + /// Write out the root index file, then write out the mesh. + string const completePath = GEOS_FMT( "{}/blueprintFiles/cycle_{:07}", OutputBase::getOutputDirectory(), cycleNumber ); + string const filePathForRank = dataRepository::writeRootFile( fileRoot, completePath ); + conduit::relay::io::save( meshRoot, filePathForRank, "hdf5" ); + } return false; } @@ -306,7 +311,19 @@ void BlueprintOutput::writeOutConstitutiveData( dataRepository::Group const & co } ); } +namespace logInfo +{ +struct BlueprintOutputTimer : public OutputTimerBase +{ + std::string_view getDescription() const override { return "Blueprint output timing"; } +}; +} +logInfo::OutputTimerBase const & BlueprintOutput::getTimerCategory() const +{ + static logInfo::BlueprintOutputTimer timer; + return timer; +} REGISTER_CATALOG_ENTRY( OutputBase, BlueprintOutput, string const &, dataRepository::Group * const ) diff --git a/src/coreComponents/fileIO/Outputs/BlueprintOutput.hpp b/src/coreComponents/fileIO/Outputs/BlueprintOutput.hpp index 4c4a26c52fd..7ba575f967d 100644 --- a/src/coreComponents/fileIO/Outputs/BlueprintOutput.hpp +++ b/src/coreComponents/fileIO/Outputs/BlueprintOutput.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -35,6 +36,12 @@ class ElementRegionManager; */ class BlueprintOutput : public OutputBase { +protected: + /** + * @copydoc OutputBase::getTimerCategory + */ + logInfo::OutputTimerBase const & getTimerCategory() const override; + public: /** diff --git a/src/coreComponents/fileIO/Outputs/ChomboIO.cpp b/src/coreComponents/fileIO/Outputs/ChomboIO.cpp index ffabfe63b05..ea2a16da38e 100644 --- a/src/coreComponents/fileIO/Outputs/ChomboIO.cpp +++ b/src/coreComponents/fileIO/Outputs/ChomboIO.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -29,6 +30,20 @@ namespace geos using namespace dataRepository; +namespace logInfo +{ +struct ChomboOutputTimer : public OutputTimerBase +{ + std::string_view getDescription() const override { return "Chombo output timing"; } +}; +} + +logInfo::OutputTimerBase const & ChomboIO::getTimerCategory() const +{ + static logInfo::ChomboOutputTimer timer; + return timer; +} + ChomboIO::ChomboIO( string const & name, Group * const parent ): OutputBase( name, parent ), m_coupler( nullptr ), @@ -40,7 +55,7 @@ ChomboIO::ChomboIO( string const & name, Group * const parent ): { registerWrapper( viewKeyStruct::outputPathString(), &m_outputPath ). setInputFlag( InputFlags::REQUIRED ). - setDescription( "Path at which the geosx to chombo file will be written." ); + setDescription( "Path at which the geos to chombo file will be written." ); registerWrapper( viewKeyStruct::beginCycleString(), &m_beginCycle ). setInputFlag( InputFlags::REQUIRED ). @@ -49,17 +64,17 @@ ChomboIO::ChomboIO( string const & name, Group * const parent ): registerWrapper( viewKeyStruct::inputPathString(), &m_inputPath ). setInputFlag( InputFlags::OPTIONAL ). setDefaultValue( "/INVALID_INPUT_PATH" ). - setDescription( "Path at which the chombo to geosx file will be written." ); + setDescription( "Path at which the chombo to geos file will be written." ); registerWrapper( viewKeyStruct::waitForInputString(), &m_waitForInput ). setInputFlag( InputFlags::REQUIRED ). setDefaultValue( 0 ). - setDescription( "True iff geosx should wait for chombo to write out a file. When true the inputPath must be set." ); + setDescription( "True iff geos should wait for chombo to write out a file. When true the inputPath must be set." ); registerWrapper( viewKeyStruct::useChomboPressuresString(), &m_useChomboPressures ). setInputFlag( InputFlags::OPTIONAL ). setDefaultValue( 0 ). - setDescription( "True iff geosx should use the pressures chombo writes out." ); + setDescription( "True iff geos should use the pressures chombo writes out." ); } ChomboIO::~ChomboIO() @@ -87,7 +102,7 @@ bool ChomboIO::execute( real64 const GEOS_UNUSED_PARAM( time_n ), GEOS_LOG_LEVEL_RANK_0( 1, "Initializing chombo coupling" ); - m_coupler = new ChomboCoupler( MPI_COMM_GEOSX, m_outputPath, m_inputPath, domain.getMeshBody( 0 ).getBaseDiscretization() ); + m_coupler = new ChomboCoupler( MPI_COMM_GEOS, m_outputPath, m_inputPath, domain.getMeshBody( 0 ).getBaseDiscretization() ); } diff --git a/src/coreComponents/fileIO/Outputs/ChomboIO.hpp b/src/coreComponents/fileIO/Outputs/ChomboIO.hpp index 8af35769f34..ea6defc059a 100644 --- a/src/coreComponents/fileIO/Outputs/ChomboIO.hpp +++ b/src/coreComponents/fileIO/Outputs/ChomboIO.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -88,6 +89,12 @@ class ChomboIO final : public OutputBase } viewKeys; /// @endcond +protected: + /** + * @copydoc OutputBase::getTimerCategory + */ + logInfo::OutputTimerBase const & getTimerCategory() const override; + private: ChomboCoupler * m_coupler; string m_outputPath; diff --git a/src/coreComponents/fileIO/Outputs/OutputBase.cpp b/src/coreComponents/fileIO/Outputs/OutputBase.cpp index 59b3cbb4398..64b93e51635 100644 --- a/src/coreComponents/fileIO/Outputs/OutputBase.cpp +++ b/src/coreComponents/fileIO/Outputs/OutputBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,18 +19,17 @@ #include "OutputBase.hpp" #include "common/MpiWrapper.hpp" +#include "functions/FunctionBase.hpp" namespace geos { -string OutputBase::m_outputDirectory; -string OutputBase::m_fileNameRoot; - using namespace dataRepository; OutputBase::OutputBase( string const & name, Group * const parent ): ExecutableGroup( name, parent ), + m_outputTimer(), m_childDirectory(), m_parallelThreads( 1 ) { @@ -44,6 +44,8 @@ OutputBase::OutputBase( string const & name, setInputFlag( InputFlags::OPTIONAL ). setDescription( "Number of plot files." ); + // Add the Timers log level + addLogLevel< logInfo::OutputTimers >(); } OutputBase::~OutputBase() @@ -63,14 +65,33 @@ void OutputBase::initializePreSubGroups() // SetupDirectoryStructure(); } + + +string const & OutputBase::getOutputDirectory() +{ + static string m_outputDirectory; + return m_outputDirectory; +} + void OutputBase::setOutputDirectory( string const & outputDir ) { - m_outputDirectory = outputDir; + string & outputDirectory = const_cast< string & >( getOutputDirectory() ); + outputDirectory = outputDir; + FunctionBase::setOutputDirectory( outputDirectory ); +} + + + +string const & OutputBase::getFileNameRoot() +{ + static string m_fileNameRoot; + return m_fileNameRoot; } void OutputBase::setFileNameRoot( string const & root ) { - m_fileNameRoot = root; + string & fileRootName = const_cast< string & >( getFileNameRoot() ); + fileRootName = root; } @@ -78,7 +99,7 @@ void OutputBase::setupDirectoryStructure() { string childDirectory = m_childDirectory; - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); if( rank == 0 ) { if( !childDirectory.empty()) @@ -88,5 +109,23 @@ void OutputBase::setupDirectoryStructure() } } +void OutputBase::cleanup( real64 const GEOS_UNUSED_PARAM( time_n ), + integer const GEOS_UNUSED_PARAM( cycleNumber ), + integer const GEOS_UNUSED_PARAM( eventCounter ), + real64 const GEOS_UNUSED_PARAM( eventProgress ), + DomainPartition & GEOS_UNUSED_PARAM( domain ) ) +{ + // Report timing statistics + real64 const time = std::chrono::duration< double >( m_outputTimer ).count(); + real64 const minTime = MpiWrapper::min( time ); + real64 const maxTime = MpiWrapper::max( time ); + if( maxTime > 0 ) + { + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::OutputTimers, + GEOS_FMT( "{}: file writing time = {} s (min), {} s (max)", + getName(), minTime, maxTime ) ); + } +} + } /* namespace geos */ diff --git a/src/coreComponents/fileIO/Outputs/OutputBase.hpp b/src/coreComponents/fileIO/Outputs/OutputBase.hpp index 4d41cd8b820..01dad62582f 100644 --- a/src/coreComponents/fileIO/Outputs/OutputBase.hpp +++ b/src/coreComponents/fileIO/Outputs/OutputBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,11 +21,50 @@ #include "dataRepository/Group.hpp" #include "dataRepository/ExecutableGroup.hpp" - +#include "dataRepository/LogLevelsInfo.hpp" // For logInfo namespace +#include "common/Timer.hpp" namespace geos { +namespace logInfo +{ +/** + * @brief Base timer category for output operations + * @details Provides configuration for logging output operation timing information + */ +struct OutputTimers +{ + /** + * @brief Get the description of this timer + * @return String view containing the timer description + */ + static std::string_view getDescription() { return "Output timing information"; } + + /** + * @brief Get the minimum log level for this timer + * @return Integer representing the minimum log level + */ + static constexpr int getMinLogLevel() { return 1; } +}; + +/** + * @brief Base interface for specific output type timers + * @details Each output type (VTK, Silo, etc.) implements this interface to provide + * its own timing category. This is used in conjunction with OutputTimers: + * - OutputTimerBase: For polymorphic behavior in derived output classes + * - OutputTimers: For the general output timing logging infrastructure + */ +struct OutputTimerBase +{ + /** + * @brief Get the description of this timer + * @return String view containing the timer description + */ + virtual std::string_view getDescription() const = 0; +}; +} + /** * @class OutputBase * @@ -39,12 +79,6 @@ class OutputBase : public ExecutableGroup /// Destructor virtual ~OutputBase() override; - /** - * @brief Catalog name interface. - * @return This type's catalog name. - **/ - static string catalogName() { return "OutputBase"; } - /** * @brief Setter for the output directory * @param outputDir The output directory @@ -55,7 +89,7 @@ class OutputBase : public ExecutableGroup * @brief Getter for the output directory * @return The output directory **/ - static string getOutputDirectory() {return m_outputDirectory;} + static string const & getOutputDirectory(); /** * @brief Setter for the file name root @@ -67,7 +101,7 @@ class OutputBase : public ExecutableGroup * @brief Getter for the file name root * @return The file name root **/ - static string getFileNameRoot() { return m_fileNameRoot; } + static string const & getFileNameRoot(); /// Method for setting up output directories. virtual void setupDirectoryStructure(); @@ -97,6 +131,8 @@ class OutputBase : public ExecutableGroup **/ integer parallelThreads() const { return m_parallelThreads; } + + protected: /** * @brief Do initialization prior to calling initialization operations @@ -105,13 +141,26 @@ class OutputBase : public ExecutableGroup **/ virtual void initializePreSubGroups() override; + /// Timer used to track duration of file writing operations for this specific output type + std::chrono::system_clock::duration m_outputTimer; + + /** + * @brief Get the timer category for this output type + * @return Reference to the output timer base for timing statistics + */ + virtual logInfo::OutputTimerBase const & getTimerCategory() const = 0; + + /// @copydoc geos::ExecutableGroup::cleanup + virtual void cleanup( real64 const time_n, + integer const cycleNumber, + integer const eventCounter, + real64 const eventProgress, + DomainPartition & domain ) override; + private: string m_childDirectory; integer m_parallelThreads; - static string m_outputDirectory; - static string m_fileNameRoot; - }; diff --git a/src/coreComponents/fileIO/Outputs/OutputManager.cpp b/src/coreComponents/fileIO/Outputs/OutputManager.cpp index bc3fd08d32d..42ea71af77a 100644 --- a/src/coreComponents/fileIO/Outputs/OutputManager.cpp +++ b/src/coreComponents/fileIO/Outputs/OutputManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -38,7 +39,7 @@ OutputManager::~OutputManager() Group * OutputManager::createChild( string const & childKey, string const & childName ) { - GEOS_LOG_RANK_0( "Adding Output: " << childKey << ", " << childName ); + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) ); std::unique_ptr< OutputBase > output = OutputBase::CatalogInterface::factory( childKey, childName, this ); return &this->registerGroup< OutputBase >( childName, std::move( output ) ); } diff --git a/src/coreComponents/fileIO/Outputs/OutputManager.hpp b/src/coreComponents/fileIO/Outputs/OutputManager.hpp index da03cc8037c..38a68c06568 100644 --- a/src/coreComponents/fileIO/Outputs/OutputManager.hpp +++ b/src/coreComponents/fileIO/Outputs/OutputManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/fileIO/Outputs/OutputUtilities.cpp b/src/coreComponents/fileIO/Outputs/OutputUtilities.cpp index 96dfea5eea9..a3731f88c78 100644 --- a/src/coreComponents/fileIO/Outputs/OutputUtilities.cpp +++ b/src/coreComponents/fileIO/Outputs/OutputUtilities.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,7 +19,7 @@ #include "OutputUtilities.hpp" -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" #include "mesh/ElementRegionManager.hpp" #include "mesh/NodeManager.hpp" diff --git a/src/coreComponents/fileIO/Outputs/OutputUtilities.hpp b/src/coreComponents/fileIO/Outputs/OutputUtilities.hpp index 118ef469f94..1cfd7f0deba 100644 --- a/src/coreComponents/fileIO/Outputs/OutputUtilities.hpp +++ b/src/coreComponents/fileIO/Outputs/OutputUtilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/fileIO/Outputs/PythonOutput.cpp b/src/coreComponents/fileIO/Outputs/PythonOutput.cpp index 2e3775823c7..3ef3adf4d46 100644 --- a/src/coreComponents/fileIO/Outputs/PythonOutput.cpp +++ b/src/coreComponents/fileIO/Outputs/PythonOutput.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -17,6 +18,20 @@ namespace geos { +namespace logInfo +{ +struct PythonOutputTimer : public OutputTimerBase +{ + std::string_view getDescription() const override { return "Python output timing"; } +}; +} + +logInfo::OutputTimerBase const & PythonOutput::getTimerCategory() const +{ + static logInfo::PythonOutputTimer timer; + return timer; +} + REGISTER_CATALOG_ENTRY( OutputBase, PythonOutput, string const &, dataRepository::Group * const ) } // namespace geos diff --git a/src/coreComponents/fileIO/Outputs/PythonOutput.hpp b/src/coreComponents/fileIO/Outputs/PythonOutput.hpp index 880deb331ce..eabcea33fbe 100644 --- a/src/coreComponents/fileIO/Outputs/PythonOutput.hpp +++ b/src/coreComponents/fileIO/Outputs/PythonOutput.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -74,6 +75,9 @@ class PythonOutput : public OutputBase GEOS_UNUSED_VAR( domain ); return true; } + +protected: + logInfo::OutputTimerBase const & getTimerCategory() const override; }; diff --git a/src/coreComponents/fileIO/Outputs/RestartOutput.cpp b/src/coreComponents/fileIO/Outputs/RestartOutput.cpp index 3fa21e052d3..b8f8e5b9f0c 100644 --- a/src/coreComponents/fileIO/Outputs/RestartOutput.cpp +++ b/src/coreComponents/fileIO/Outputs/RestartOutput.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -23,6 +24,14 @@ namespace geos using namespace dataRepository; +namespace logInfo +{ +struct RestartOutputTimer : public OutputTimerBase +{ + std::string_view getDescription() const override { return "Restart output timing"; } +}; +} + RestartOutput::RestartOutput( string const & name, Group * const parent ): OutputBase( name, parent ) @@ -40,19 +49,24 @@ bool RestartOutput::execute( real64 const GEOS_UNUSED_PARAM( time_n ), { GEOS_MARK_FUNCTION; - Group & rootGroup = this->getGroupByPath( "/Problem" ); + { + Timer timer( m_outputTimer ); - // Ignoring the eventProgress indicator for now to be compliant with the integrated test repo - // integer const eventProgressPercent = static_cast(eventProgress * 100.0); - string const fileName = GEOS_FMT( "{}_restart_{:09}", getFileNameRoot(), cycleNumber ); - - rootGroup.prepareToWrite(); - writeTree( joinPath( OutputBase::getOutputDirectory(), fileName ), *(rootGroup.getConduitNode().parent()) ); - rootGroup.finishWriting(); + Group & rootGroup = this->getGroupByPath( "/Problem" ); + string const fileName = GEOS_FMT( "{}_restart_{:09}", getFileNameRoot(), cycleNumber ); + rootGroup.prepareToWrite(); + writeTree( joinPath( OutputBase::getOutputDirectory(), fileName ), *(rootGroup.getConduitNode().parent()) ); + rootGroup.finishWriting(); + } return false; } +logInfo::OutputTimerBase const & RestartOutput::getTimerCategory() const +{ + static logInfo::RestartOutputTimer timer; + return timer; +} REGISTER_CATALOG_ENTRY( OutputBase, RestartOutput, string const &, Group * const ) } /* namespace geos */ diff --git a/src/coreComponents/fileIO/Outputs/RestartOutput.hpp b/src/coreComponents/fileIO/Outputs/RestartOutput.hpp index e925f10c763..09e336a50fe 100644 --- a/src/coreComponents/fileIO/Outputs/RestartOutput.hpp +++ b/src/coreComponents/fileIO/Outputs/RestartOutput.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -77,6 +78,12 @@ class RestartOutput : public OutputBase dataRepository::ViewKey writeFEMFaces = { "writeFEMFaces" }; } viewKeys; /// @endcond + +protected: + /** + * @copydoc OutputBase::getTimerCategory + */ + logInfo::OutputTimerBase const & getTimerCategory() const override; }; diff --git a/src/coreComponents/fileIO/Outputs/SiloOutput.cpp b/src/coreComponents/fileIO/Outputs/SiloOutput.cpp index 2e1fbe74421..6d372b59e04 100644 --- a/src/coreComponents/fileIO/Outputs/SiloOutput.cpp +++ b/src/coreComponents/fileIO/Outputs/SiloOutput.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -27,6 +28,20 @@ namespace geos using namespace dataRepository; +namespace logInfo +{ +struct SiloOutputTimer : public OutputTimerBase +{ + std::string_view getDescription() const override { return "Silo output timing"; } +}; +} + +logInfo::OutputTimerBase const & SiloOutput::getTimerCategory() const +{ + static logInfo::SiloOutputTimer timer; + return timer; +} + SiloOutput::SiloOutput( string const & name, Group * const parent ): OutputBase( name, parent ), @@ -85,7 +100,7 @@ SiloOutput::SiloOutput( string const & name, SiloOutput::~SiloOutput() {} -void SiloOutput::postProcessInput() +void SiloOutput::postInputInitialization() { string const fieldNamesString = viewKeysStruct::fieldNames; string const onlyPlotSpecifiedFieldNamesString = viewKeysStruct::onlyPlotSpecifiedFieldNames; @@ -121,31 +136,35 @@ bool SiloOutput::execute( real64 const time_n, { GEOS_MARK_FUNCTION; - SiloFile silo; - - int const size = MpiWrapper::commSize( MPI_COMM_GEOSX ); - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); - MpiWrapper::barrier( MPI_COMM_GEOSX ); - - integer const numFiles = parallelThreads() == 0 ? size : parallelThreads(); - - // TODO set this during initialization - // silo.setOutputDirectory( getGlobalState().getCommandLineOptions().outputDirectory ), - silo.setOutputDirectory( getOutputDirectory() ), - silo.setPlotLevel( m_plotLevel ); - silo.setWriteEdgeMesh( m_writeEdgeMesh ); - silo.setWriteFaceMesh( m_writeFaceMesh ); - silo.setWriteCellElementMesh( m_writeCellElementMesh ); - silo.setWriteFaceElementMesh( m_writeFaceElementMesh ); - silo.setOnlyPlotSpecifiedFieldNamesFlag( m_onlyPlotSpecifiedFieldNames ); - silo.setFieldNames( m_fieldNames.toViewConst() ); - silo.setPlotFileRoot( m_plotFileRoot ); - silo.initialize( numFiles ); - silo.waitForBatonWrite( rank, cycleNumber, eventCounter, false ); - silo.writeDomainPartition( domain, cycleNumber, time_n + dt * eventProgress, 0 ); - silo.handOffBaton(); - silo.clearEmptiesFromMultiObjects( cycleNumber ); - silo.finish(); + { + Timer timer( m_outputTimer ); + + SiloFile silo; + + int const size = MpiWrapper::commSize( MPI_COMM_GEOS ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); + MpiWrapper::barrier( MPI_COMM_GEOS ); + + integer const numFiles = parallelThreads() == 0 ? size : parallelThreads(); + + // TODO set this during initialization + // silo.setOutputDirectory( getGlobalState().getCommandLineOptions().outputDirectory ), + silo.setOutputDirectory( getOutputDirectory() ), + silo.setPlotLevel( m_plotLevel ); + silo.setWriteEdgeMesh( m_writeEdgeMesh ); + silo.setWriteFaceMesh( m_writeFaceMesh ); + silo.setWriteCellElementMesh( m_writeCellElementMesh ); + silo.setWriteFaceElementMesh( m_writeFaceElementMesh ); + silo.setOnlyPlotSpecifiedFieldNamesFlag( m_onlyPlotSpecifiedFieldNames ); + silo.setFieldNames( m_fieldNames.toViewConst() ); + silo.setPlotFileRoot( m_plotFileRoot ); + silo.initialize( numFiles ); + silo.waitForBatonWrite( rank, cycleNumber, eventCounter, false ); + silo.writeDomainPartition( domain, cycleNumber, time_n + dt * eventProgress, 0 ); + silo.handOffBaton(); + silo.clearEmptiesFromMultiObjects( cycleNumber ); + silo.finish(); + } return false; } diff --git a/src/coreComponents/fileIO/Outputs/SiloOutput.hpp b/src/coreComponents/fileIO/Outputs/SiloOutput.hpp index b57ee2f01cf..0780ef7bb22 100644 --- a/src/coreComponents/fileIO/Outputs/SiloOutput.hpp +++ b/src/coreComponents/fileIO/Outputs/SiloOutput.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -84,9 +85,15 @@ class SiloOutput : public OutputBase } siloOutputViewKeys; /// @endcond +protected: + /** + * @copydoc OutputBase::getTimerCategory + */ + logInfo::OutputTimerBase const & getTimerCategory() const override; + private: - void postProcessInput() override; + void postInputInitialization() override; string m_plotFileRoot; integer m_writeEdgeMesh; diff --git a/src/coreComponents/fileIO/Outputs/TimeHistoryOutput.cpp b/src/coreComponents/fileIO/Outputs/TimeHistoryOutput.cpp index ebf215e17ce..c54f416dd92 100644 --- a/src/coreComponents/fileIO/Outputs/TimeHistoryOutput.cpp +++ b/src/coreComponents/fileIO/Outputs/TimeHistoryOutput.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -16,12 +17,28 @@ #include "fileIO/timeHistory/HDFFile.hpp" -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) #include "fileIO/python/PyHistoryOutputType.hpp" #endif namespace geos { +using namespace dataRepository; + +namespace logInfo +{ +struct TimeHistoryOutputTimer : public OutputTimerBase +{ + std::string_view getDescription() const override { return "Time history output timing"; } +}; +} + +logInfo::OutputTimerBase const & TimeHistoryOutput::getTimerCategory() const +{ + static logInfo::TimeHistoryOutputTimer timer; + return timer; +} + TimeHistoryOutput::TimeHistoryOutput( string const & name, Group * const parent ): OutputBase( name, parent ), @@ -31,6 +48,8 @@ TimeHistoryOutput::TimeHistoryOutput( string const & name, m_recordCount( 0 ), m_io( ) { + enableLogLevelInput(); + registerWrapper( viewKeys::timeHistoryOutputTargetString(), &m_collectorPaths ). setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ). setInputFlag( InputFlags::REQUIRED ). @@ -61,8 +80,6 @@ TimeHistoryOutput::TimeHistoryOutput( string const & name, void TimeHistoryOutput::initCollectorParallel( DomainPartition const & domain, HistoryCollection & collector ) { - GEOS_ASSERT( m_io.empty() ); - bool const freshInit = ( m_recordCount == 0 ); string const outputDirectory = getOutputDirectory(); @@ -80,6 +97,7 @@ void TimeHistoryOutput::initCollectorParallel( DomainPartition const & domain, H } m_io.emplace_back( std::make_unique< HDFHistoryIO >( outputFile, static_cast( m_useMPIO ), metadata, m_recordCount ) ); + m_io.back()->setLogLevel( this->getLogLevel() ); hc.registerBufferProvider( collectorIdx, [this, idx = m_io.size() - 1]( localIndex count ) { m_io[idx]->updateCollectingCount( count ); @@ -89,12 +107,13 @@ void TimeHistoryOutput::initCollectorParallel( DomainPartition const & domain, H } }; - // FIXME Why stop (pseudo) recursion at one single level? registerBufferCalls( collector ); + MpiWrapper::barrier( MPI_COMM_GEOS ); for( localIndex metaIdx = 0; metaIdx < collector.numMetaDataCollectors(); ++metaIdx ) { registerBufferCalls( collector.getMetaDataCollector( metaIdx ), collector.getTargetName() + " " ); + MpiWrapper::barrier( MPI_COMM_GEOS ); } // Do the time output last so its at the end of the m_io list, since writes are parallel @@ -105,12 +124,13 @@ void TimeHistoryOutput::initCollectorParallel( DomainPartition const & domain, H { HistoryMetadata timeMetadata = collector.getTimeMetaData(); m_io.emplace_back( std::make_unique< HDFHistoryIO >( outputFile, static_cast( m_useMPIO ), timeMetadata, m_recordCount, 1, 2, MPI_COMM_SELF ) ); + m_io.back()->setLogLevel( this->getLogLevel() ); // We copy the back `idx` not to rely on possible future appends to `m_io`. collector.registerTimeBufferProvider( [this, idx = m_io.size() - 1]() { return m_io[idx]->getBufferHead(); } ); m_io.back()->init( !freshInit ); } - MpiWrapper::barrier( MPI_COMM_GEOSX ); + MpiWrapper::barrier( MPI_COMM_GEOS ); } void TimeHistoryOutput::initializePostInitialConditionsPostSubGroups() @@ -118,16 +138,17 @@ void TimeHistoryOutput::initializePostInitialConditionsPostSubGroups() { // check whether to truncate or append to the file up front so we don't have to bother during later accesses string const outputDirectory = getOutputDirectory(); - if( MpiWrapper::commRank( MPI_COMM_GEOSX ) == 0 ) + if( MpiWrapper::commRank( MPI_COMM_GEOS ) == 0 ) { makeDirsForPath( outputDirectory ); } - MpiWrapper::barrier( MPI_COMM_GEOSX ); + MpiWrapper::barrier( MPI_COMM_GEOS ); string const outputFile = joinPath( outputDirectory, m_filename ); - HDFFile( outputFile, (m_recordCount == 0), static_cast(m_useMPIO), MPI_COMM_GEOSX ); + HDFFile( outputFile, (m_recordCount == 0), static_cast(m_useMPIO), MPI_COMM_GEOS ); } DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); + GEOS_LOG_LEVEL_BY_RANK( 3, GEOS_FMT( "TimeHistory: '{}' initializing data collectors.", this->getName() ) ); for( auto collectorPath : m_collectorPaths ) { try @@ -164,12 +185,18 @@ bool TimeHistoryOutput::execute( real64 const GEOS_UNUSED_PARAM( time_n ), DomainPartition & GEOS_UNUSED_PARAM( domain ) ) { GEOS_MARK_FUNCTION; - localIndex newBuffered = m_io.front()->getBufferedCount( ); - for( auto & th_io : m_io ) + { - th_io->write( ); + Timer timer( m_outputTimer ); + + localIndex newBuffered = m_io.front()->getBufferedCount( ); + for( auto & th_io : m_io ) + { + th_io->write( ); + } + m_recordCount += newBuffered; } - m_recordCount += newBuffered; + return false; } @@ -180,6 +207,7 @@ void TimeHistoryOutput::cleanup( real64 const time_n, DomainPartition & domain ) { execute( time_n, 0.0, cycleNumber, eventCounter, eventProgress, domain ); + MpiWrapper::barrier( MPI_COMM_GEOS ); // remove any unused trailing space reserved to write additional histories for( auto & th_io : m_io ) { @@ -187,7 +215,7 @@ void TimeHistoryOutput::cleanup( real64 const time_n, } } -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) PyTypeObject * TimeHistoryOutput::getPythonType() const { return python::getPyHistoryOutputType(); } #endif diff --git a/src/coreComponents/fileIO/Outputs/TimeHistoryOutput.hpp b/src/coreComponents/fileIO/Outputs/TimeHistoryOutput.hpp index 364a510a44d..e3f5a954eda 100644 --- a/src/coreComponents/fileIO/Outputs/TimeHistoryOutput.hpp +++ b/src/coreComponents/fileIO/Outputs/TimeHistoryOutput.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -111,10 +112,16 @@ class TimeHistoryOutput : public OutputBase * @brief Return PyHistoryOutput type. * @return Return PyHistoryOutput type. */ -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) virtual PyTypeObject * getPythonType() const override; #endif +protected: + /** + * @copydoc OutputBase::getTimerCategory + */ + logInfo::OutputTimerBase const & getTimerCategory() const override; + private: /** diff --git a/src/coreComponents/fileIO/Outputs/VTKOutput.cpp b/src/coreComponents/fileIO/Outputs/VTKOutput.cpp index b9b6256bc1a..01168c319fe 100644 --- a/src/coreComponents/fileIO/Outputs/VTKOutput.cpp +++ b/src/coreComponents/fileIO/Outputs/VTKOutput.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,9 +18,9 @@ */ #include "VTKOutput.hpp" +#include "common/MpiWrapper.hpp" - -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) #include "fileIO/python/PyVTKOutputType.hpp" #endif @@ -28,6 +29,20 @@ namespace geos using namespace dataRepository; +namespace logInfo +{ +struct VTKOutputTimer : public OutputTimerBase +{ + std::string_view getDescription() const override { return "VTK output timing"; } +}; +} + +logInfo::OutputTimerBase const & VTKOutput::getTimerCategory() const +{ + static logInfo::VTKOutputTimer timer; + return timer; +} + VTKOutput::VTKOutput( string const & name, Group * const parent ): OutputBase( name, parent ), @@ -55,11 +70,21 @@ VTKOutput::VTKOutput( string const & name, setInputFlag( InputFlags::OPTIONAL ). setDescription( "Level detail plot. Only fields with lower of equal plot level will be output." ); + registerWrapper( viewKeysStruct::numberOfTargetProcesses, &m_numberOfTargetProcesses ). + setApplyDefaultValue( MpiWrapper::commSize() ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Number of output aggregate files to be written." ); + registerWrapper( viewKeysStruct::writeGhostCells, &m_writeGhostCells ). setApplyDefaultValue( 0 ). setInputFlag( InputFlags::OPTIONAL ). setDescription( "Should the vtk files contain the ghost cells or not." ); + registerWrapper( viewKeysStruct::writeFaceElementsAs3D, &m_writeFaceElementsAs3D ). + setApplyDefaultValue( 0 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Should the face elements be written as 3d volumes or not." ); + registerWrapper( viewKeysStruct::onlyPlotSpecifiedFieldNames, &m_onlyPlotSpecifiedFieldNames ). setApplyDefaultValue( 0 ). setInputFlag( InputFlags::OPTIONAL ). @@ -69,7 +94,7 @@ VTKOutput::VTKOutput( string const & name, registerWrapper( viewKeysStruct::fieldNames, &m_fieldNames ). setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ). setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Names of the fields to output. If this attribute is specified, GEOSX outputs all the fields specified by the user, regardless of their `plotLevel`" ); + setDescription( "Names of the fields to output. If this attribute is specified, GEOS outputs all the fields specified by the user, regardless of their `plotLevel`" ); registerWrapper( viewKeysStruct::levelNames, &m_levelNames ). setInputFlag( InputFlags::OPTIONAL ). @@ -89,13 +114,21 @@ VTKOutput::VTKOutput( string const & name, VTKOutput::~VTKOutput() {} -void VTKOutput::postProcessInput() +void VTKOutput::postInputInitialization() { m_writer.setOutputLocation( getOutputDirectory(), m_plotFileRoot ); m_writer.setFieldNames( m_fieldNames.toViewConst() ); m_writer.setLevelNames( m_levelNames.toViewConst() ); m_writer.setOnlyPlotSpecifiedFieldNamesFlag( m_onlyPlotSpecifiedFieldNames ); + GEOS_ERROR_IF_LT_MSG( m_numberOfTargetProcesses, 1, + GEOS_FMT( "{}: processes count cannot be less than 1.", + getWrapperDataContext( viewKeysStruct::numberOfTargetProcesses ) ) ); + GEOS_ERROR_IF_GT_MSG( m_numberOfTargetProcesses, MpiWrapper::commSize(), + GEOS_FMT( "{}: processes count cannot exceed the launched ranks count.", + getWrapperDataContext( viewKeysStruct::numberOfTargetProcesses ) ) ); + m_writer.setNumberOfTargetProcesses( m_numberOfTargetProcesses ); + string const fieldNamesString = viewKeysStruct::fieldNames; string const onlyPlotSpecifiedFieldNamesString = viewKeysStruct::onlyPlotSpecifiedFieldNames; @@ -116,6 +149,9 @@ void VTKOutput::postProcessInput() "{} `{}`: found {} fields to plot in `{}`, in addition to all fields with `plotLevel` smaller or equal to {}.", catalogName(), getDataContext(), std::to_string( m_fieldNames.size() ), fieldNamesString, m_plotLevel ) ); + + GEOS_ERROR_IF( m_writeFaceElementsAs3D, GEOS_FMT( "{} `{}`: 3D vtk plot of faceElements is not yet supported.", + catalogName(), getDataContext() ) ); } @@ -137,18 +173,25 @@ bool VTKOutput::execute( real64 const time_n, real64 const GEOS_UNUSED_PARAM ( eventProgress ), DomainPartition & domain ) { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: writing {} at time {} s (cycle number {})", getName(), m_fieldNames, time_n + dt, cycleNumber )); + GEOS_MARK_FUNCTION; + + GEOS_LOG_LEVEL_RANK_0( 2, GEOS_FMT( "{}: writing {} at time {} s (cycle number {})", getName(), m_fieldNames, time_n + dt, cycleNumber )); + + { + Timer timer( m_outputTimer ); - m_writer.setWriteGhostCells( m_writeGhostCells ); - m_writer.setOutputMode( m_writeBinaryData ); - m_writer.setOutputRegionType( m_outputRegionType ); - m_writer.setPlotLevel( m_plotLevel ); - m_writer.write( time_n, cycleNumber, domain ); + m_writer.setWriteGhostCells( m_writeGhostCells ); + m_writer.setWriteFaceElementsAs3D ( m_writeFaceElementsAs3D ); + m_writer.setOutputMode( m_writeBinaryData ); + m_writer.setOutputRegionType( m_outputRegionType ); + m_writer.setPlotLevel( m_plotLevel ); + m_writer.write( time_n, cycleNumber, domain ); + } return false; } -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) PyTypeObject * VTKOutput::getPythonType() const { return python::getPyVTKOutputType(); diff --git a/src/coreComponents/fileIO/Outputs/VTKOutput.hpp b/src/coreComponents/fileIO/Outputs/VTKOutput.hpp index c87b92a0513..d4112de73b3 100644 --- a/src/coreComponents/fileIO/Outputs/VTKOutput.hpp +++ b/src/coreComponents/fileIO/Outputs/VTKOutput.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -45,7 +46,7 @@ class VTKOutput : public OutputBase */ static string catalogName() { return "VTK"; } - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /** * @brief Set the plotFileRoot name for the output @@ -76,6 +77,9 @@ class VTKOutput : public OutputBase DomainPartition & domain ) override { execute( time_n, 0, cycleNumber, eventCounter, eventProgress, domain ); + + // Call parent class cleanup to get the timing statistics + OutputBase::cleanup( time_n, cycleNumber, eventCounter, eventProgress, domain ); } /** @@ -89,12 +93,14 @@ class VTKOutput : public OutputBase static constexpr auto plotFileRoot = "plotFileRoot"; static constexpr auto writeFEMFaces = "writeFEMFaces"; static constexpr auto writeGhostCells = "writeGhostCells"; + static constexpr auto writeFaceElementsAs3D = "writeFaceElementsAs3D"; static constexpr auto plotLevel = "plotLevel"; static constexpr auto binaryString = "format"; static constexpr auto outputRegionTypeString = "outputRegionType"; static constexpr auto onlyPlotSpecifiedFieldNames = "onlyPlotSpecifiedFieldNames"; static constexpr auto fieldNames = "fieldNames"; static constexpr auto levelNames = "levelNames"; + static constexpr auto numberOfTargetProcesses = "numberOfTargetProcesses"; } vtkOutputViewKeys; /// @endcond @@ -102,19 +108,31 @@ class VTKOutput : public OutputBase * @brief Return PyVTKOutput type. * @return Return PyVTKOutput type. */ -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) virtual PyTypeObject * getPythonType() const override; #endif +protected: + /** + * @copydoc OutputBase::getTimerCategory + */ + logInfo::OutputTimerBase const & getTimerCategory() const override; + private: string m_plotFileRoot; integer m_writeFaceMesh; integer m_plotLevel; + /// Aggregate output data to be written + integer m_numberOfTargetProcesses; + /// Should the vtk files contain the ghost cells or not. integer m_writeGhostCells; + /// Should the face elements be written as 3d volumes or not. + integer m_writeFaceElementsAs3D; + /// flag to decide whether we only plot the specified field names integer m_onlyPlotSpecifiedFieldNames; diff --git a/src/coreComponents/fileIO/coupling/ChomboCoupler.cpp b/src/coreComponents/fileIO/coupling/ChomboCoupler.cpp index c4eabd3aa55..75ebd8f7015 100644 --- a/src/coreComponents/fileIO/coupling/ChomboCoupler.cpp +++ b/src/coreComponents/fileIO/coupling/ChomboCoupler.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/fileIO/coupling/ChomboCoupler.hpp b/src/coreComponents/fileIO/coupling/ChomboCoupler.hpp index 68087f8f4fa..a2d839576da 100644 --- a/src/coreComponents/fileIO/coupling/ChomboCoupler.hpp +++ b/src/coreComponents/fileIO/coupling/ChomboCoupler.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/fileIO/coupling/hdf5_interface b/src/coreComponents/fileIO/coupling/hdf5_interface index 7ee534586a6..9bf87ec0a5d 160000 --- a/src/coreComponents/fileIO/coupling/hdf5_interface +++ b/src/coreComponents/fileIO/coupling/hdf5_interface @@ -1 +1 @@ -Subproject commit 7ee534586a6ea995532eb4e3cfc7da4e5ccff64a +Subproject commit 9bf87ec0a5d532e65a7e3828bd9968cd4380301c diff --git a/src/coreComponents/fileIO/doc/Outputs.rst b/src/coreComponents/fileIO/doc/Outputs.rst index d46204a92e0..b8d91d92fed 100644 --- a/src/coreComponents/fileIO/doc/Outputs.rst +++ b/src/coreComponents/fileIO/doc/Outputs.rst @@ -28,7 +28,7 @@ The SILO output is defined through the ```` XML node (subnode of ```` XML node (subnode of `` The parameter options are listed in the following table: -.. include:: /coreComponents/schema/docs/VTK.rst +.. include:: /docs/sphinx/datastructure/VTK.rst TimeHistory Output ================== @@ -59,7 +59,7 @@ The TimeHistory output is defined through the ```` XML node (subnod The parameter options are listed in the following table: -.. include:: /coreComponents/schema/docs/TimeHistory.rst +.. include:: /docs/sphinx/datastructure/TimeHistory.rst In order to properly collect and output time history information the following steps must be accomplished: diff --git a/src/coreComponents/fileIO/python/PyHistoryCollection.cpp b/src/coreComponents/fileIO/python/PyHistoryCollection.cpp index 67a467bbb46..5f65e62966a 100644 --- a/src/coreComponents/fileIO/python/PyHistoryCollection.cpp +++ b/src/coreComponents/fileIO/python/PyHistoryCollection.cpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #define PY_SSIZE_T_CLEAN #include diff --git a/src/coreComponents/fileIO/python/PyHistoryCollectionType.hpp b/src/coreComponents/fileIO/python/PyHistoryCollectionType.hpp index a028282d6a0..5e7af98e496 100644 --- a/src/coreComponents/fileIO/python/PyHistoryCollectionType.hpp +++ b/src/coreComponents/fileIO/python/PyHistoryCollectionType.hpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #ifndef GEOS_PYTHON_PYHISTORYCOLLECTIONTYPE_HPP_ #define GEOS_PYTHON_PYHISTORYCOLLECTIONTYPE_HPP_ diff --git a/src/coreComponents/fileIO/python/PyHistoryOutput.cpp b/src/coreComponents/fileIO/python/PyHistoryOutput.cpp index 06c1bbbf167..5da919b192a 100644 --- a/src/coreComponents/fileIO/python/PyHistoryOutput.cpp +++ b/src/coreComponents/fileIO/python/PyHistoryOutput.cpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #define PY_SSIZE_T_CLEAN #include diff --git a/src/coreComponents/fileIO/python/PyHistoryOutputType.hpp b/src/coreComponents/fileIO/python/PyHistoryOutputType.hpp index 39f67d8fa44..ac8f382d4dc 100644 --- a/src/coreComponents/fileIO/python/PyHistoryOutputType.hpp +++ b/src/coreComponents/fileIO/python/PyHistoryOutputType.hpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #ifndef GEOS_PYTHON_PYHISTORYOUTPUTTYPE_HPP_ #define GEOS_PYTHON_PYHISTORYOUTPUTTYPE_HPP_ diff --git a/src/coreComponents/fileIO/python/PyVTKOutput.cpp b/src/coreComponents/fileIO/python/PyVTKOutput.cpp index 4bc148a5ae6..496fe116348 100644 --- a/src/coreComponents/fileIO/python/PyVTKOutput.cpp +++ b/src/coreComponents/fileIO/python/PyVTKOutput.cpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #define PY_SSIZE_T_CLEAN #include @@ -118,7 +133,7 @@ static PyObject * setOutputDir( PyVTKOutput * self, PyObject * args ) try { self->group->setOutputDirectory( path ); - self->group->postProcessInput(); + self->group->postInputInitialization(); } catch( std::out_of_range const & e ) { @@ -154,7 +169,7 @@ static PyObject * setOutputFileRootName( PyVTKOutput * self, PyObject * args ) try { self->group->setPlotFileRoot( filename ); - self->group->postProcessInput(); + self->group->postInputInitialization(); } catch( std::out_of_range const & e ) { diff --git a/src/coreComponents/fileIO/python/PyVTKOutputType.hpp b/src/coreComponents/fileIO/python/PyVTKOutputType.hpp index cc008817a42..4c58691e990 100644 --- a/src/coreComponents/fileIO/python/PyVTKOutputType.hpp +++ b/src/coreComponents/fileIO/python/PyVTKOutputType.hpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #ifndef GEOS_PYTHON_PYVTKOUTPUTTYPE_HPP_ #define GEOS_PYTHON_PYVTKOUTPUTTYPE_HPP_ diff --git a/src/coreComponents/fileIO/silo/SiloFile.cpp b/src/coreComponents/fileIO/silo/SiloFile.cpp index 85d6eb85542..7c5b6b1fa17 100644 --- a/src/coreComponents/fileIO/silo/SiloFile.cpp +++ b/src/coreComponents/fileIO/silo/SiloFile.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -24,13 +25,13 @@ #include "codingUtilities/Utilities.hpp" #include "common/DataTypes.hpp" -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" #include "common/MpiWrapper.hpp" #include "common/TypeDispatch.hpp" #include "constitutive/ConstitutiveManager.hpp" #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" -#include "constitutive/contact/ContactBase.hpp" +#include "constitutive/contact/FrictionBase.hpp" #include "constitutive/NullModel.hpp" #include "fileIO/Outputs/OutputUtilities.hpp" #include "mesh/DomainPartition.hpp" @@ -46,7 +47,7 @@ -#if !defined(GEOSX_USE_MPI) +#if !defined(GEOS_USE_MPI) int MPI_Comm_size( MPI_Comm, int * size ) { *size=1; return 0; } int MPI_Comm_rank( MPI_Comm, int * rank ) { *rank=1; return 0; } @@ -281,8 +282,8 @@ void SiloFile::makeSiloDirectories() { int rank=0; -#ifdef GEOSX_USE_MPI - MPI_Comm_rank( MPI_COMM_GEOSX, &rank ); +#ifdef GEOS_USE_MPI + MPI_Comm_rank( MPI_COMM_GEOS, &rank ); #endif if( rank==0 ) @@ -298,18 +299,18 @@ void SiloFile::initialize( int const MPI_PARAM( numGroups ) ) { makeSiloDirectories(); -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI // Ensure all procs agree on numGroups, driver and file_ext m_numGroups = numGroups; #else m_numGroups = 1; #endif - MpiWrapper::bcast( &m_numGroups, 1, 0, MPI_COMM_GEOSX ); -// MPI_Bcast( const_cast(&m_driver), 1, MPI_INT, 0, MPI_COMM_GEOSX); + MpiWrapper::bcast( &m_numGroups, 1, 0, MPI_COMM_GEOS ); +// MPI_Bcast( const_cast(&m_driver), 1, MPI_INT, 0, MPI_COMM_GEOS); // Initialize PMPIO, pass a pointer to the driver type as the user data. m_baton = PMPIO_Init( m_numGroups, PMPIO_WRITE, - MPI_COMM_GEOSX, + MPI_COMM_GEOS, 1, PMPIO_DefaultCreate, PMPIO_DefaultOpen, @@ -346,8 +347,8 @@ void SiloFile::waitForBatonWrite( int const domainNumber, { int rank = 0; -#ifdef GEOSX_USE_MPI - MPI_Comm_rank( MPI_COMM_GEOSX, &rank ); +#ifdef GEOS_USE_MPI + MPI_Comm_rank( MPI_COMM_GEOS, &rank ); #endif int const groupRank = PMPIO_GroupRank( m_baton, rank ); @@ -380,8 +381,8 @@ void SiloFile::waitForBaton( int const domainNumber, string const & restartFileN { int rank = 0; -#ifdef GEOSX_USE_MPI - MPI_Comm_rank( MPI_COMM_GEOSX, &rank ); +#ifdef GEOS_USE_MPI + MPI_Comm_rank( MPI_COMM_GEOS, &rank ); #endif int const groupRank = PMPIO_GroupRank( m_baton, rank ); @@ -414,8 +415,8 @@ void SiloFile::handOffBaton() PMPIO_HandOffBaton( m_baton, m_dbFilePtr ); int rank = 0; -#ifdef GEOSX_USE_MPI - MPI_Comm_rank( MPI_COMM_GEOSX, &rank ); +#ifdef GEOS_USE_MPI + MPI_Comm_rank( MPI_COMM_GEOS, &rank ); #endif if( rank==0 ) { @@ -576,8 +577,8 @@ void SiloFile::writeMeshObject( string const & meshName, // write multimesh object int rank = 0; -#ifdef GEOSX_USE_MPI - MPI_Comm_rank( MPI_COMM_GEOSX, &rank ); +#ifdef GEOS_USE_MPI + MPI_Comm_rank( MPI_COMM_GEOS, &rank ); #endif if( rank == 0 ) { @@ -651,8 +652,8 @@ void SiloFile::writeBeamMesh( string const & meshName, //----write multimesh object { int rank = 0; - #ifdef GEOSX_USE_MPI - MPI_Comm_rank( MPI_COMM_GEOSX, &rank ); + #ifdef GEOS_USE_MPI + MPI_Comm_rank( MPI_COMM_GEOS, &rank ); #endif if( rank == 0 ) { @@ -684,8 +685,8 @@ void SiloFile::writePointMesh( string const & meshName, //----write multimesh object { int rank = 0; - #ifdef GEOSX_USE_MPI - MPI_Comm_rank( MPI_COMM_GEOSX, &rank ); + #ifdef GEOS_USE_MPI + MPI_Comm_rank( MPI_COMM_GEOS, &rank ); #endif if( rank == 0 ) { @@ -812,13 +813,13 @@ void SiloFile::writeMaterialMapsFullStorage( ElementRegionBase const & elemRegio } // write multimesh object int rank = 0; - #ifdef GEOSX_USE_MPI - MPI_Comm_rank( MPI_COMM_GEOSX, &rank ); + #ifdef GEOS_USE_MPI + MPI_Comm_rank( MPI_COMM_GEOS, &rank ); #endif if( rank == 0 ) { - int const size = MpiWrapper::commSize( MPI_COMM_GEOSX ); + int const size = MpiWrapper::commSize( MPI_COMM_GEOS ); array1d< string > vBlockNames( size ); std::vector< char * > BlockNames( size ); @@ -982,8 +983,8 @@ void SiloFile::writeMaterialVarDefinition( string const & subDir, void SiloFile::clearEmptiesFromMultiObjects( int const cycleNum ) { - int const size = MpiWrapper::commSize( MPI_COMM_GEOSX ); - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int const size = MpiWrapper::commSize( MPI_COMM_GEOS ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); string sendbufferVars; string sendbufferMesh; @@ -1014,7 +1015,7 @@ void SiloFile::clearEmptiesFromMultiObjects( int const cycleNum ) integer_array rcounts( size ); integer_array displs( size ); - MpiWrapper::gather( &sizeOfSendBufferVars, 1, rcounts.data(), 1, 0, MPI_COMM_GEOSX ); + MpiWrapper::gather( &sizeOfSendBufferVars, 1, rcounts.data(), 1, 0, MPI_COMM_GEOS ); int sizeOfReceiveBuffer = 0; displs[0] = 0; @@ -1031,10 +1032,10 @@ void SiloFile::clearEmptiesFromMultiObjects( int const cycleNum ) rcounts.data(), displs.data(), 0, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); - MpiWrapper::gather( &sizeOfSendBufferMesh, 1, rcounts.data(), 1, 0, MPI_COMM_GEOSX ); + MpiWrapper::gather( &sizeOfSendBufferMesh, 1, rcounts.data(), 1, 0, MPI_COMM_GEOS ); int sizeOfReceiveBufferMesh = 0; displs[0] = 0; @@ -1051,7 +1052,7 @@ void SiloFile::clearEmptiesFromMultiObjects( int const cycleNum ) rcounts.data(), displs.data(), 0, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); @@ -1467,7 +1468,7 @@ void SiloFile::writeElementMesh( ElementRegionBase const & elementRegion, localIndex const numFluids = regionFluidMaterialList.size(); string_array - fractureContactMaterialList = elementRegion.getConstitutiveNames< constitutive::ContactBase >(); + fractureContactMaterialList = elementRegion.getConstitutiveNames< constitutive::FrictionBase >(); localIndex const numContacts = fractureContactMaterialList.size(); @@ -1969,7 +1970,7 @@ void SiloFile::writePolygonMeshObject( const string & meshName, // write multimesh object int rank = 0; -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI MPI_Comm_rank( MPI_COMM_WORLD, &rank ); #endif if( rank == 0 ) @@ -2110,8 +2111,8 @@ void SiloFile::writeMultiXXXX( const DBObjectType type, (void)centering; int size = 1; -#ifdef GEOSX_USE_MPI - MPI_Comm_size( MPI_COMM_GEOSX, &size ); +#ifdef GEOS_USE_MPI + MPI_Comm_size( MPI_COMM_GEOS, &size ); #endif string_array vBlockNames( size ); @@ -2258,8 +2259,8 @@ void SiloFile::writeDataField( string const & meshName, // write multimesh object int rank = 0; -#ifdef GEOSX_USE_MPI - MPI_Comm_rank( MPI_COMM_GEOSX, &rank ); +#ifdef GEOS_USE_MPI + MPI_Comm_rank( MPI_COMM_GEOS, &rank ); #endif if( rank == 0 ) { @@ -2527,8 +2528,8 @@ void SiloFile::writeDataField( string const & meshName, // write multimesh object int rank = 0; -#ifdef GEOSX_USE_MPI - MPI_Comm_rank( MPI_COMM_GEOSX, &rank ); +#ifdef GEOS_USE_MPI + MPI_Comm_rank( MPI_COMM_GEOS, &rank ); #endif if( rank == 0 ) { @@ -2815,8 +2816,8 @@ void SiloFile::writeMaterialDataField( string const & meshName, // write multimesh object int rank = 0; -#ifdef GEOSX_USE_MPI - MPI_Comm_rank( MPI_COMM_GEOSX, &rank ); +#ifdef GEOS_USE_MPI + MPI_Comm_rank( MPI_COMM_GEOS, &rank ); #endif if( rank == 0 ) { @@ -3126,7 +3127,7 @@ void SiloFile::writeStressVarDefinition( string const & MatDir ) void SiloFile::writeVectorVarDefinition( string const & fieldName, string const & subDirectory ) { - if( MpiWrapper::commRank( MPI_COMM_GEOSX ) == 0 ) + if( MpiWrapper::commRank( MPI_COMM_GEOS ) == 0 ) { DBSetDir( m_dbBaseFilePtr, subDirectory.c_str() ); DBtoc * const siloTOC = DBGetToc ( m_dbBaseFilePtr ); diff --git a/src/coreComponents/fileIO/silo/SiloFile.hpp b/src/coreComponents/fileIO/silo/SiloFile.hpp index 827cb809511..e05904b6acd 100644 --- a/src/coreComponents/fileIO/silo/SiloFile.hpp +++ b/src/coreComponents/fileIO/silo/SiloFile.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -121,7 +122,7 @@ class SiloFile */ void makeSubDirectory( string const & subdir, string const & rootdir ) { - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); // char dirname[100]; if( rank == 0 ) diff --git a/src/coreComponents/fileIO/timeHistory/BufferedHistoryIO.hpp b/src/coreComponents/fileIO/timeHistory/BufferedHistoryIO.hpp index e324803f463..a54b81790b9 100644 --- a/src/coreComponents/fileIO/timeHistory/BufferedHistoryIO.hpp +++ b/src/coreComponents/fileIO/timeHistory/BufferedHistoryIO.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -72,6 +73,23 @@ class BufferedHistoryIO * is a shortcut that should eventually be fixed by keeping this information in the HDF5 buffer. */ virtual localIndex getBufferedCount() = 0; + + /** + * @brief Get the log-level for BufferedHistoryIO classes + * @return the current log-level + */ + int getLogLevel() const { return m_logLevel; } + + /** + * @brief Set the log-level for BufferedHistoryIO classes + * @param[in] logLevel the log-level to set + */ + void setLogLevel( int logLevel ) { m_logLevel = logLevel; } + +private: + + /// the log-level + int m_logLevel = 0; }; } diff --git a/src/coreComponents/fileIO/timeHistory/HDFFile.cpp b/src/coreComponents/fileIO/timeHistory/HDFFile.cpp index 26cb8cd650b..b88767d6ecc 100644 --- a/src/coreComponents/fileIO/timeHistory/HDFFile.cpp +++ b/src/coreComponents/fileIO/timeHistory/HDFFile.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2020- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -34,6 +35,8 @@ HDFFile::HDFFile( string const & fnm, bool deleteExisting, bool parallelAccess, { m_faplId = H5Pcreate( H5P_FILE_ACCESS ); H5Pset_fapl_mpio( m_faplId, m_comm, MPI_INFO_NULL ); + H5Pset_all_coll_metadata_ops( m_faplId, 1 ); + H5Pset_coll_metadata_write( m_faplId, 1 ); m_filename = fnm + ".hdf5"; } else @@ -72,6 +75,7 @@ HDFFile::~HDFFile() { if( m_mpioFapl ) { +// H5Fflush( m_fileId, H5F_SCOPE_GLOBAL ); H5Pclose( m_faplId ); } H5Fclose( m_fileId ); diff --git a/src/coreComponents/fileIO/timeHistory/HDFFile.hpp b/src/coreComponents/fileIO/timeHistory/HDFFile.hpp index 161db0246b0..f2ab6358099 100644 --- a/src/coreComponents/fileIO/timeHistory/HDFFile.hpp +++ b/src/coreComponents/fileIO/timeHistory/HDFFile.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2020- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/fileIO/timeHistory/HDFHistoryIO.cpp b/src/coreComponents/fileIO/timeHistory/HDFHistoryIO.cpp index 649b4c43c00..7cb271a3889 100644 --- a/src/coreComponents/fileIO/timeHistory/HDFHistoryIO.cpp +++ b/src/coreComponents/fileIO/timeHistory/HDFHistoryIO.cpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #include "HDFHistoryIO.hpp" #include "HDFFile.hpp" @@ -204,43 +219,49 @@ void HDFHistoryIO::init( bool existsOkay ) if( subcomm != MPI_COMM_NULL ) { - std::vector< hsize_t > historyFileDims( m_rank+1 ); - historyFileDims[0] = LvArray::integerConversion< hsize_t >( m_writeLimit ); - - std::vector< hsize_t > dimChunks( m_rank+1 ); - dimChunks[0] = 1; - - for( hsize_t dd = 1; dd < m_rank+1; ++dd ) - { - // hdf5 doesn't like chunk size 0, hence the subcomm - dimChunks[dd] = m_dims[dd-1]; - historyFileDims[dd] = m_dims[dd-1]; - } - dimChunks[1] = m_chunkSize; - historyFileDims[1] = LvArray::integerConversion< hsize_t >( m_globalIdxCount ); - + GEOS_LOG_LEVEL_BY_RANK( 3, GEOS_FMT( "TimeHistory: opening file {}.", m_filename ) ); HDFFile target( m_filename, false, m_useMPIO, m_useMPIO ? subcomm : m_comm ); + GEOS_LOG_LEVEL_BY_RANK( 3, GEOS_FMT( "TimeHistory: opened file {}.", m_filename ) ); + bool inTarget = target.hasDataset( m_name ); if( !inTarget ) { - hid_t dcplId = 0; + std::vector< hsize_t > historyFileDims( m_rank+1 ); + historyFileDims[0] = LvArray::integerConversion< hsize_t >( m_writeLimit ); + std::vector< hsize_t > dimChunks( m_rank+1 ); + dimChunks[0] = 1; + for( hsize_t dd = 1; dd < m_rank+1; ++dd ) + { + // hdf5 doesn't like chunk size 0, hence the subcomm + dimChunks[dd] = m_dims[dd-1]; + historyFileDims[dd] = m_dims[dd-1]; + } + dimChunks[1] = m_chunkSize; + historyFileDims[1] = LvArray::integerConversion< hsize_t >( m_globalIdxCount ); std::vector< hsize_t > maxFileDims( historyFileDims ); // chunking is required to create an extensible dataset dcplId = H5Pcreate( H5P_DATASET_CREATE ); herr_t err = H5Pset_chunk( dcplId, m_rank + 1, &dimChunks[0] ); GEOS_ERROR_IF( err < 0, "H5Pset_chunk failed."); + maxFileDims[0] = H5S_UNLIMITED; maxFileDims[1] = H5S_UNLIMITED; hid_t space = H5Screate_simple( m_rank+1, &historyFileDims[0], &maxFileDims[0] ); hid_t dataset = H5Dcreate( target, m_name.c_str(), m_hdfType, space, H5P_DEFAULT, dcplId, H5P_DEFAULT ); + GEOS_LOG_LEVEL_BY_RANK( 3, GEOS_FMT( "TimeHistory: {}, created hdf5 dataset {}.", m_filename, m_name ) ); H5Dclose( dataset ); H5Sclose( space ); + H5Pclose( dcplId ); } else if( existsOkay ) { updateDatasetExtent( m_writeLimit ); } - GEOS_ERROR_IF( inTarget && !existsOkay, "Dataset (" + m_name + ") already exists in output file: " + m_filename ); + else + { + GEOS_ERROR( "Dataset (" + m_name + ") already exists in output file: " + m_filename ); + } + GEOS_LOG_LEVEL_BY_RANK( 3, GEOS_FMT( "TimeHistory: closed file {}.", m_filename ) ); } } @@ -274,7 +295,14 @@ void HDFHistoryIO::write() if( m_subcomm != MPI_COMM_NULL ) { + GEOS_LOG_LEVEL_BY_RANK( 3, GEOS_FMT( "TimeHistory: opening file {}.", m_filename ) ); HDFFile target( m_filename, false, m_useMPIO, m_useMPIO ? m_subcomm : m_comm ); + GEOS_LOG_LEVEL_BY_RANK( 3, GEOS_FMT( "TimeHistory: opened file {}.", m_filename ) ); + + if( !target.hasDataset( m_name ) ) + { + GEOS_ERROR( "Attempted to write to a non-existent dataset: " + m_name ); + } hid_t dataset = H5Dopen( target, m_name.c_str(), H5P_DEFAULT ); hid_t filespace = H5Dget_space( dataset ); @@ -296,8 +324,21 @@ void HDFHistoryIO::write() hid_t fileHyperslab = filespace; herr_t err = H5Sselect_hyperslab( fileHyperslab, H5S_SELECT_SET, &fileOffset[0], nullptr, &bufferedCounts[0], nullptr ); GEOS_ERROR_IF( err < 0, "H5Sselect_hyperslab failed."); - err = H5Dwrite( dataset, m_hdfType, memspace, fileHyperslab, H5P_DEFAULT, dataBuffer ); + if( m_useMPIO ) + { + hid_t dxplId = H5Pcreate( H5P_DATASET_XFER ); + H5Pset_dxpl_mpio( dxplId, H5FD_MPIO_COLLECTIVE ); + err = H5Dwrite( dataset, m_hdfType, memspace, fileHyperslab, dxplId, dataBuffer ); + } + else + { + err = H5Dwrite( dataset, m_hdfType, memspace, fileHyperslab, H5P_DEFAULT, dataBuffer ); + } GEOS_ERROR_IF( err < 0, "H5Dwrite failed."); + + GEOS_LOG_LEVEL_BY_RANK( 3, GEOS_FMT( "TimeHistory: wrote row {} of dataset '{}'.", m_writeHead, m_name ) ); + H5Pclose( dxplId ); + // forward the data buffer pointer to the start of the next row if( dataBuffer ) { @@ -316,14 +357,14 @@ void HDFHistoryIO::write() GEOS_ERROR_IF( err < 0, "H5Sclose failed." ); err = H5Dclose( dataset ); GEOS_ERROR_IF( err < 0, "H5Dclose failed." ); - } - + GEOS_LOG_LEVEL_BY_RANK( 3, GEOS_FMT( "TimeHistory: closing file {}.", m_filename ) ); } m_writeHead++; } } m_sizeChanged = false; m_localIdxCounts_buffered.clear( ); emptyBuffer( ); + MpiWrapper::barrier( m_comm ); } void HDFHistoryIO::compressInFile() @@ -363,6 +404,7 @@ void HDFHistoryIO::updateDatasetExtent( hsize_t rowLimit ) err = H5Dclose( dataset ); GEOS_ERROR_IF( err < 0, "H5Dclose failed." ); } + MpiWrapper::barrier( m_comm ); } size_t HDFHistoryIO::getRowBytes() diff --git a/src/coreComponents/fileIO/timeHistory/HDFHistoryIO.hpp b/src/coreComponents/fileIO/timeHistory/HDFHistoryIO.hpp index ddb6109393a..79f459ab9e3 100644 --- a/src/coreComponents/fileIO/timeHistory/HDFHistoryIO.hpp +++ b/src/coreComponents/fileIO/timeHistory/HDFHistoryIO.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -19,6 +20,7 @@ #include "dataRepository/HistoryDataSpec.hpp" #include "BufferedHistoryIO.hpp" #include "common/DataTypes.hpp" +#include "common/MpiWrapper.hpp" #include @@ -53,7 +55,7 @@ class HDFHistoryIO : public BufferedHistoryIO localIndex writeHead = 0, localIndex initAlloc = 1, localIndex overallocMultiple = 2, - MPI_Comm comm = MPI_COMM_GEOSX ); + MPI_Comm comm = MPI_COMM_GEOS ); /** * @brief Constructor @@ -70,7 +72,7 @@ class HDFHistoryIO : public BufferedHistoryIO localIndex writeHead = 0, localIndex initAlloc = 1, localIndex overallocMultiple = 2, - MPI_Comm comm = MPI_COMM_GEOSX ): + MPI_Comm comm = MPI_COMM_GEOS ): HDFHistoryIO( filename, useMPIO, spec.getRank(), diff --git a/src/coreComponents/fileIO/timeHistory/HistoryCollection.hpp b/src/coreComponents/fileIO/timeHistory/HistoryCollection.hpp index 8119db9051b..de2a68f3ac7 100644 --- a/src/coreComponents/fileIO/timeHistory/HistoryCollection.hpp +++ b/src/coreComponents/fileIO/timeHistory/HistoryCollection.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -25,8 +26,6 @@ namespace geos { -using namespace dataRepository; - /** * @class HistoryCollection * diff --git a/src/coreComponents/fileIO/timeHistory/HistoryCollectionBase.cpp b/src/coreComponents/fileIO/timeHistory/HistoryCollectionBase.cpp index c5ad121dcc5..3fc95d6c825 100644 --- a/src/coreComponents/fileIO/timeHistory/HistoryCollectionBase.cpp +++ b/src/coreComponents/fileIO/timeHistory/HistoryCollectionBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2020- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/fileIO/timeHistory/HistoryCollectionBase.hpp b/src/coreComponents/fileIO/timeHistory/HistoryCollectionBase.hpp index b38fc9c4f10..ef30cf21b55 100644 --- a/src/coreComponents/fileIO/timeHistory/HistoryCollectionBase.hpp +++ b/src/coreComponents/fileIO/timeHistory/HistoryCollectionBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2020- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,7 +18,7 @@ #include "HistoryCollection.hpp" -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) #include "fileIO/python/PyHistoryCollectionType.hpp" #endif @@ -60,7 +61,7 @@ class HistoryCollectionBase : public HistoryCollection HistoryCollection & getMetaDataCollector( localIndex metaIdx ) override; -#if defined(GEOSX_USE_PYGEOSX) +#if defined(GEOS_USE_PYGEOSX) /** * @brief Return PyHistoryCollection type. * @return Return PyHistoryCollection type. diff --git a/src/coreComponents/fileIO/timeHistory/PackCollection.cpp b/src/coreComponents/fileIO/timeHistory/PackCollection.cpp index 971765e0505..746d26ce24b 100644 --- a/src/coreComponents/fileIO/timeHistory/PackCollection.cpp +++ b/src/coreComponents/fileIO/timeHistory/PackCollection.cpp @@ -1,7 +1,25 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #include "PackCollection.hpp" namespace geos { + +using namespace dataRepository; + PackCollection::PackCollection ( string const & name, Group * parent ) : HistoryCollectionBase( name, parent ) , m_setsIndices( ) @@ -57,6 +75,7 @@ void PackCollection::initializePostSubGroups( ) { // coord meta collectors should have m_disableCoordCollection == true to avoid // infinite recursive init calls here + // (side note: should we create a m_isMetaCollector field to prevent any confusion?) metaCollector->initializePostSubGroups(); } m_initialized = true; @@ -240,7 +259,7 @@ localIndex PackCollection::numMetaDataCollectors() const void PackCollection::buildMetaDataCollectors() { - if( !m_disableCoordCollection ) + if( !m_disableCoordCollection && m_targetIsMeshObject ) { char const * coordField = nullptr; if( m_objectPath.find( "nodeManager" ) != string::npos ) diff --git a/src/coreComponents/fileIO/timeHistory/PackCollection.hpp b/src/coreComponents/fileIO/timeHistory/PackCollection.hpp index 03f3a0cee8a..468bc5ecb62 100644 --- a/src/coreComponents/fileIO/timeHistory/PackCollection.hpp +++ b/src/coreComponents/fileIO/timeHistory/PackCollection.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/fileIO/vtk/VTKPVDWriter.cpp b/src/coreComponents/fileIO/vtk/VTKPVDWriter.cpp index a98d2391735..f928e64097c 100644 --- a/src/coreComponents/fileIO/vtk/VTKPVDWriter.cpp +++ b/src/coreComponents/fileIO/vtk/VTKPVDWriter.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/fileIO/vtk/VTKPVDWriter.hpp b/src/coreComponents/fileIO/vtk/VTKPVDWriter.hpp index b70910af08b..756a6fa03df 100644 --- a/src/coreComponents/fileIO/vtk/VTKPVDWriter.hpp +++ b/src/coreComponents/fileIO/vtk/VTKPVDWriter.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/fileIO/vtk/VTKPolyDataWriterInterface.cpp b/src/coreComponents/fileIO/vtk/VTKPolyDataWriterInterface.cpp index fce83637687..fbd36b2b166 100644 --- a/src/coreComponents/fileIO/vtk/VTKPolyDataWriterInterface.cpp +++ b/src/coreComponents/fileIO/vtk/VTKPolyDataWriterInterface.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -15,7 +16,7 @@ // Source includes #include "VTKPolyDataWriterInterface.hpp" -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" #include "common/TypeDispatch.hpp" #include "dataRepository/Group.hpp" #include "mesh/DomainPartition.hpp" @@ -32,11 +33,14 @@ #include #include #include - +#include // System includes #include #include +#include "mesh/generators/VTKUtilities.hpp" + + namespace geos { @@ -54,7 +58,8 @@ VTKPolyDataWriterInterface::VTKPolyDataWriterInterface( string name ): m_requireFieldRegistrationCheck( true ), m_previousCycle( -1 ), m_outputMode( VTKOutputMode::BINARY ), - m_outputRegionType( VTKRegionTypes::ALL ) + m_outputRegionType( VTKRegionTypes::ALL ), + m_writeFaceElementsAs3D( false ) {} static int @@ -121,11 +126,11 @@ getVtkToGeosxNodeOrdering( ParticleType const particleType ) /** * @brief Provide the local list of nodes or face streams for the corresponding VTK element * - * @param elementType geosx element type + * @param elementType geos element type * @return list of nodes or face streams * - * For geosx element with existing standard VTK element the corresponding list of nodes is provided. - * For Prism7+, the geosx element is converted to VTK_POLYHEDRON. The vtkUnstructuredGrid + * For geos element with existing standard VTK element the corresponding list of nodes is provided. + * For Prism7+, the geos element is converted to VTK_POLYHEDRON. The vtkUnstructuredGrid * stores polyhedron cells as face streams of the following format: * [numberOfCellFaces, * (numberOfPointsOfFace0, pointId0, pointId1, ... ), @@ -143,7 +148,7 @@ static std::vector< int > getVtkConnectivity( ElementType const elementType, loc case ElementType::Vertex: return { 0 }; case ElementType::Line: return { 0, 1 }; case ElementType::Triangle: return { 0, 1, 2 }; - case ElementType::Quadrilateral: return { 0, 1, 3, 2 }; + case ElementType::Quadrilateral: return { 0, 1, 2, 3 }; case ElementType::Polygon: return { }; // TODO case ElementType::Tetrahedron: return { 0, 1, 2, 3 }; case ElementType::Pyramid: return { 0, 1, 3, 2, 4 }; @@ -337,23 +342,28 @@ getWell( WellElementSubRegion const & subRegion, * @brief Gets the cell connectivities and the vertices coordinates as VTK objects for a specific FaceElementSubRegion. * @param[in] subRegion the FaceElementSubRegion to be output * @param[in] nodeManager the NodeManager associated with the DomainPartition being written. + * @param[in] faceManager the faceManager associated with the DomainPartition being written. * @return a pair containing a VTKPoints (with the information on the vertices and their coordinates) * and a VTKCellArray (with the cell connectivities). */ static ElementData getSurface( FaceElementSubRegion const & subRegion, - NodeManager const & nodeManager ) + NodeManager const & nodeManager, + FaceManager const & faceManager, + bool const writeFaceElementsAs3D ) { // Get unique node set composing the surface + auto & elemToFaces = subRegion.faceList(); auto & elemToNodes = subRegion.nodeList(); + auto & faceToNodes = faceManager.nodeList(); auto cellArray = vtkSmartPointer< vtkCellArray >::New(); cellArray->SetNumberOfCells( subRegion.size() ); std::vector< int > cellTypes; cellTypes.reserve( subRegion.size() ); - std::unordered_map< localIndex, localIndex > geosx2VTKIndexing; - geosx2VTKIndexing.reserve( subRegion.size() * subRegion.numNodesPerElement() ); + std::unordered_map< localIndex, localIndex > geos2VTKIndexing; + geos2VTKIndexing.reserve( subRegion.size() * subRegion.numNodesPerElement() ); localIndex nodeIndexInVTK = 0; // FaceElementSubRegion being heterogeneous, the size of the connectivity vector may vary for each element. // In order not to allocate a new vector every time, we combine the usage of `clear` and `push_back`. @@ -361,14 +371,15 @@ getSurface( FaceElementSubRegion const & subRegion, for( localIndex ei = 0; ei < subRegion.size(); ei++ ) { - auto const & nodes = elemToNodes[ei]; + // we use the nodes of face 0 + auto const & nodes = !writeFaceElementsAs3D ? faceToNodes[elemToFaces( ei, 0 )] : elemToNodes[ei]; auto const numNodes = nodes.size(); ElementType const elementType = subRegion.getElementType( ei ); std::vector< int > vtkOrdering; - if( elementType == ElementType::Polygon ) + if( elementType == ElementType::Polygon || writeFaceElementsAs3D ) { - vtkOrdering.resize( nodes.size() ); + vtkOrdering.resize( numNodes ); std::iota( vtkOrdering.begin(), vtkOrdering.end(), 0 ); } else @@ -377,12 +388,17 @@ getSurface( FaceElementSubRegion const & subRegion, } connectivity.clear(); - for( int const & ordering: vtkOrdering ) + for( int const & ordering : vtkOrdering ) { - auto const & VTKIndexPos = geosx2VTKIndexing.find( nodes[ordering] ); - if( VTKIndexPos == geosx2VTKIndexing.end() ) + auto const & VTKIndexPos = geos2VTKIndexing.find( nodes[ordering] ); + if( VTKIndexPos == geos2VTKIndexing.end() ) { - connectivity.push_back( geosx2VTKIndexing[nodes[ordering]] = nodeIndexInVTK++ ); + /// If the node is not found in the geos2VTKIndexing map: + /// 1. we assign the current value of nodeIndexInVTK to this node in the map (geos2VTKIndexing[nodes[ordering]] = + /// nodeIndexInVTK++). + /// 2. we increment nodeIndexInVTK to ensure the next new node gets a unique index. + /// 3. we add this new VTK node index to the connectivity vector (connectivity.push_back). + connectivity.push_back( geos2VTKIndexing[nodes[ordering]] = nodeIndexInVTK++ ); } else { @@ -395,10 +411,10 @@ getSurface( FaceElementSubRegion const & subRegion, } auto points = vtkSmartPointer< vtkPoints >::New(); - points->SetNumberOfPoints( geosx2VTKIndexing.size() ); + points->SetNumberOfPoints( geos2VTKIndexing.size() ); arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const referencePosition = nodeManager.referencePosition(); - for( auto nodeIndex: geosx2VTKIndexing ) + for( auto nodeIndex: geos2VTKIndexing ) { auto point = referencePosition[nodeIndex.first]; points->SetPoint( nodeIndex.second, point[0], point[1], point[2] ); @@ -535,7 +551,7 @@ getVtkCells( CellElementRegion const & region, std::vector< int > const vtkOrdering = getVtkConnectivity( subRegion.getElementType(), subRegionNumNodes ); localIndex const numVtkData = vtkOrdering.size(); - // For all geosx element, the corresponding VTK data are copied in "connectivity". + // For all geos element, the corresponding VTK data are copied in "connectivity". // Local nodes are mapped to global indices. Any negative value in "vtkOrdering" // corresponds to the number of faces or the number of nodes per faces, and they // are copied as positive values. @@ -1028,7 +1044,7 @@ void VTKPolyDataWriterInterface::writeElementFields( ElementRegionBase const & r void VTKPolyDataWriterInterface::writeCellElementRegions( real64 const time, ElementRegionManager const & elemManager, NodeManager const & nodeManager, - string const & path ) const + string const & path ) { elemManager.forElementRegions< CellElementRegion >( [&]( CellElementRegion const & region ) { @@ -1042,15 +1058,13 @@ void VTKPolyDataWriterInterface::writeCellElementRegions( real64 const time, writeTimestamp( ug.GetPointer(), time ); writeElementFields( region, ug->GetCellData() ); writeNodeFields( nodeManager, VTKCells.nodes, ug->GetPointData() ); - - string const regionDir = joinPath( path, region.getName() ); - writeUnstructuredGrid( regionDir, ug.GetPointer() ); + writeUnstructuredGrid( path, region, ug.GetPointer() ); } ); } void VTKPolyDataWriterInterface::writeParticleRegions( real64 const time, ParticleManager const & particleManager, - string const & path ) const + string const & path ) { particleManager.forParticleRegions< ParticleRegion >( [&]( ParticleRegion const & region ) { @@ -1064,15 +1078,14 @@ void VTKPolyDataWriterInterface::writeParticleRegions( real64 const time, writeTimestamp( ug.GetPointer(), time ); writeParticleFields( region, ug->GetCellData() ); - string const regionDir = joinPath( path, region.getName() ); - writeUnstructuredGrid( regionDir, ug.GetPointer() ); + writeUnstructuredGrid( path, region, ug.GetPointer() ); } ); } void VTKPolyDataWriterInterface::writeWellElementRegions( real64 const time, ElementRegionManager const & elemManager, NodeManager const & nodeManager, - string const & path ) const + string const & path ) { elemManager.forElementRegions< WellElementRegion >( [&]( WellElementRegion const & region ) { @@ -1085,9 +1098,7 @@ void VTKPolyDataWriterInterface::writeWellElementRegions( real64 const time, writeTimestamp( ug.GetPointer(), time ); writeElementFields( region, ug->GetCellData() ); - - string const regionDir = joinPath( path, region.getName() ); - writeUnstructuredGrid( regionDir, ug.GetPointer() ); + writeUnstructuredGrid( path, region, ug.GetPointer() ); } ); } @@ -1095,7 +1106,8 @@ void VTKPolyDataWriterInterface::writeSurfaceElementRegions( real64 const time, ElementRegionManager const & elemManager, NodeManager const & nodeManager, EmbeddedSurfaceNodeManager const & embSurfNodeManager, - string const & path ) const + FaceManager const & faceManager, + string const & path ) { elemManager.forElementRegions< SurfaceElementRegion >( [&]( SurfaceElementRegion const & region ) { @@ -1112,7 +1124,7 @@ void VTKPolyDataWriterInterface::writeSurfaceElementRegions( real64 const time, case SurfaceElementRegion::SurfaceSubRegionType::faceElement: { auto const & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); - return getSurface( subRegion, nodeManager ); + return getSurface( subRegion, nodeManager, faceManager, m_writeFaceElementsAs3D ); } default: { @@ -1126,9 +1138,7 @@ void VTKPolyDataWriterInterface::writeSurfaceElementRegions( real64 const time, writeTimestamp( ug.GetPointer(), time ); writeElementFields( region, ug->GetCellData() ); - - string const regionDir = joinPath( path, region.getName() ); - writeUnstructuredGrid( regionDir, ug.GetPointer() ); + writeUnstructuredGrid( path, region, ug.GetPointer() ); } ); } @@ -1174,13 +1184,11 @@ void VTKPolyDataWriterInterface::writeVtmFile( integer const cycle, string const meshPath = joinPath( getCycleSubFolder( cycle ), meshBodyName, meshLevelName ); - int const mpiSize = MpiWrapper::commSize(); - auto addElementRegion = [&]( ElementRegionBase const & region ) { std::vector< string > const blockPath{ meshBody.getName(), meshLevel.getName(), region.getCatalogName(), region.getName() }; string const regionPath = joinPath( meshPath, region.getName() ); - for( int i = 0; i < mpiSize; i++ ) + for( const auto & i : m_targetProcessesId.at( region.getName()) ) { string const dataSetName = getRankFileName( i ); string const dataSetFile = joinPath( regionPath, dataSetName + ".vtu" ); @@ -1193,7 +1201,7 @@ void VTKPolyDataWriterInterface::writeVtmFile( integer const cycle, string const & regionName = region.getName(); std::vector< string > const blockPath{ meshBodyName, meshLevelName, region.getCatalogName(), regionName }; string const regionPath = joinPath( meshPath, regionName ); - for( int i = 0; i < mpiSize; i++ ) + for( const auto & i : m_targetProcessesId.at( region.getName()) ) { string const dataSetName = getRankFileName( i ); string const dataSetFile = joinPath( regionPath, dataSetName + ".vtu" ); @@ -1242,8 +1250,11 @@ int toVtkOutputMode( VTKOutputMode const mode ) } void VTKPolyDataWriterInterface::writeUnstructuredGrid( string const & path, - vtkUnstructuredGrid * ug ) const + ObjectManagerBase const & region, + vtkUnstructuredGrid * ug ) { + string const regionDir = joinPath( path, region.getName() ); + vtkSmartPointer< vtkAlgorithm > filter; // If we want to get rid of the ghost ranks, we use the appropriate `vtkThreshold` filter. @@ -1265,15 +1276,51 @@ void VTKPolyDataWriterInterface::writeUnstructuredGrid( string const & path, } filter->SetInputDataObject( ug ); - filter->Update(); - - makeDirectory( path ); - string const vtuFilePath = joinPath( path, getRankFileName( MpiWrapper::commRank() ) + ".vtu" ); - auto const vtuWriter = vtkSmartPointer< vtkXMLUnstructuredGridWriter >::New(); - vtuWriter->SetInputData( filter->GetOutputDataObject( 0 ) ); - vtuWriter->SetFileName( vtuFilePath.c_str() ); - vtuWriter->SetDataMode( toVtkOutputMode( m_outputMode ) ); - vtuWriter->Write(); + + vtkSmartPointer< vtkMultiProcessController > controller = vtk::getController(); + vtkMultiProcessController::SetGlobalController( controller ); + + // In case of m_numberOfTargetProcesses == GetNumberOfProcesses the filter returns a shallow copy + // The behavior is the same as previously in this case. The rank number is computed instead of implicitly written + vtkNew< vtkAggregateDataSetFilter > aggregate; + aggregate->SetInputConnection( filter->GetOutputPort()); + aggregate->SetNumberOfTargetProcesses( m_numberOfTargetProcesses ); + aggregate->SetMergePoints( false ); + aggregate->Update(); + + int localCommRank = -1; + if( vtkDataSet::SafeDownCast( aggregate->GetOutput())->GetNumberOfPoints() != 0 ) + { + localCommRank = MpiWrapper::commRank(); + makeDirectory( regionDir ); + string const vtuFilePath = joinPath( regionDir, getRankFileName( localCommRank ) + ".vtu" ); + auto const vtuWriter = vtkSmartPointer< vtkXMLUnstructuredGridWriter >::New(); + vtuWriter->SetInputData( aggregate->GetOutput() ); + vtuWriter->SetFileName( vtuFilePath.c_str() ); + vtuWriter->SetDataMode( toVtkOutputMode( m_outputMode ) ); + vtuWriter->Write(); + } + + const int size = MpiWrapper::commSize( MPI_COMM_GEOS ); + std::vector< int > globalValues( size ); + + // Everything is done on rank 0 + MpiWrapper::gather( &localCommRank, + 1, + globalValues.data(), + 1, + 0, + MPI_COMM_GEOS ); + + if( MpiWrapper::commRank() == 0 ) + { + // any rank that does not hold data will not participate in the output + globalValues.erase( std::remove_if( globalValues.begin(), + globalValues.end(), + []( int x ) { return x == -1; } ), + globalValues.end()); + m_targetProcessesId[region.getName()] = globalValues; + } } void VTKPolyDataWriterInterface::write( real64 const time, @@ -1292,7 +1339,7 @@ void VTKPolyDataWriterInterface::write( real64 const time, { makeDirsForPath( stepSubDirFull ); } - MpiWrapper::barrier( MPI_COMM_GEOSX ); + MpiWrapper::barrier( MPI_COMM_GEOS ); // loop over all mesh levels and mesh bodies domain.forMeshBodies( [&]( MeshBody const & meshBody ) @@ -1314,6 +1361,7 @@ void VTKPolyDataWriterInterface::write( real64 const time, ElementRegionManager const & elemManager = meshLevel.getElemManager(); ParticleManager const & particleManager = meshLevel.getParticleManager(); NodeManager const & nodeManager = meshLevel.getNodeManager(); + FaceManager const & faceManager = meshLevel.getFaceManager(); EmbeddedSurfaceNodeManager const & embSurfNodeManager = meshLevel.getEmbSurfNodeManager(); string const & meshBodyName = meshBody.getName(); @@ -1339,7 +1387,7 @@ void VTKPolyDataWriterInterface::write( real64 const time, } if( m_outputRegionType == VTKRegionTypes::SURFACE || m_outputRegionType == VTKRegionTypes::ALL ) { - writeSurfaceElementRegions( time, elemManager, nodeManager, embSurfNodeManager, meshDir ); + writeSurfaceElementRegions( time, elemManager, nodeManager, embSurfNodeManager, faceManager, meshDir ); } if( m_outputRegionType == VTKRegionTypes::PARTICLE || m_outputRegionType == VTKRegionTypes::ALL ) { diff --git a/src/coreComponents/fileIO/vtk/VTKPolyDataWriterInterface.hpp b/src/coreComponents/fileIO/vtk/VTKPolyDataWriterInterface.hpp index 1baa383407c..c44ca64347d 100644 --- a/src/coreComponents/fileIO/vtk/VTKPolyDataWriterInterface.hpp +++ b/src/coreComponents/fileIO/vtk/VTKPolyDataWriterInterface.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,11 +17,12 @@ #define GEOS_FILEIO_VTK_VTKPOLYDATAWRITERINTERFACE_HPP_ #include "common/DataTypes.hpp" +#include "mesh/ObjectManagerBase.hpp" #include "dataRepository/WrapperBase.hpp" #include "dataRepository/Wrapper.hpp" #include "fileIO/vtk/VTKPVDWriter.hpp" #include "fileIO/vtk/VTKVTMWriter.hpp" -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" class vtkUnstructuredGrid; class vtkPointData; @@ -36,6 +38,7 @@ class EmbeddedSurfaceNodeManager; class ElementRegionManager; class NodeManager; class ParticleManager; +class FaceManager; namespace vtk { @@ -89,6 +92,15 @@ class VTKPolyDataWriterInterface m_writeGhostCells = writeGhostCells; } + /** + * @brief Defines whether in the vtk output facelements should be 2D or 3D + * @param writeFaceElementsAs3D The boolean flag. + */ + void setWriteFaceElementsAs3D( bool writeFaceElementsAs3D ) + { + m_writeFaceElementsAs3D = writeFaceElementsAs3D; + } + /** * @brief Sets the plot level * @details All fields have an associated plot level. If it is <= to \p plotLevel, @@ -156,6 +168,14 @@ class VTKPolyDataWriterInterface { m_levelNames.insert( levelNames.begin(), levelNames.end() ); } + /** + * @brief Set the Number Of Target Processes + * @param[in] numberOfTargetProcesses the number of processes + */ + void setNumberOfTargetProcesses( integer const numberOfTargetProcesses ) + { + m_numberOfTargetProcesses = numberOfTargetProcesses; + } /** * @brief Main method of this class. Write all the files for one time step. @@ -199,7 +219,7 @@ class VTKPolyDataWriterInterface void clearData(); -private: +protected: /** * @brief Check if plotting is enabled for this field @@ -212,58 +232,63 @@ class VTKPolyDataWriterInterface * @brief Writes the files for all the CellElementRegions. * @details There will be one file written per CellElementRegion and per rank. * @param[in] time the time-step - * @param[in] cycle the current cycle number * @param[in] elemManager the ElementRegionManager containing the CellElementRegions to be output * @param[in] nodeManager the NodeManager containing the nodes of the domain to be output - * @param[in] meshLevelName the name of the MeshLevel containing the nodes and elements to be output - * @param[in] meshBodyName the name of the MeshBody containing the nodes and elements to be output + * @param[in] path the path to the file to output */ void writeCellElementRegions( real64 time, ElementRegionManager const & elemManager, NodeManager const & nodeManager, - string const & path ) const; - - void writeParticleRegions( real64 const time, - ParticleManager const & particleManager, - string const & path ) const; + string const & path ); /** * @brief Writes the files containing the well representation * @details There will be one file written per WellElementRegion and per rank * @param[in] time the time-step - * @param[in] cycle the current cycle number * @param[in] elemManager the ElementRegionManager containing the WellElementRegions to be output * @param[in] nodeManager the NodeManager containing the nodes of the domain to be output + * @param[in] path The path to the file to output */ void writeWellElementRegions( real64 time, ElementRegionManager const & elemManager, NodeManager const & nodeManager, - string const & path ) const; + string const & path ); + + /** + * @brief Writes the files containing the particle representation + * @details There will be one file written per ParticleRegion and per rank + * @param[in] time the time-step + * @param[in] particleManager the ParticleManager containing the ParticleRegions to be output + * @param[in] path the root path where the mesh will be written + */ + void writeParticleRegions( real64 const time, + ParticleManager const & particleManager, + string const & path ); /** * @brief Writes the files containing the faces elements * @details There will be one file written per FaceElementRegion and per rank * @param[in] time the time-step - * @param[in] cycle the current cycle number * @param[in] elemManager the ElementRegionManager containing the FaceElementRegions to be output * @param[in] nodeManager the NodeManager containing the nodes of the domain to be output - * @param[in] meshLevelName the name of the MeshLevel containing the nodes and elements to be output - * @param[in] meshBodyName the name of the MeshBody containing the nodes and elements to be output + * @param[in] embSurfNodeManager the embedded surface node Manager. + * @param[in] faceManager the faceManager. + * @param[in] path the path to the output file. */ void writeSurfaceElementRegions( real64 time, ElementRegionManager const & elemManager, NodeManager const & nodeManager, EmbeddedSurfaceNodeManager const & embSurfNodeManager, - string const & path ) const; + FaceManager const & faceManager, + string const & path ); /** * @brief Writes a VTM file for the time-step \p time. * @details a VTM file is a VTK Multiblock file. It contains relative path to different files organized in blocks. * @param[in] cycle the current cycle number - * @param[in] elemManager the ElementRegionManager containing all the regions to be output and referred to in the VTM file + * @param[in] domain the DomainPartition containing all the regions to be output and referred to in the VTM file * @param[in] vtmWriter a writer specialized for the VTM file format */ - void writeVtmFile( integer const cycle, DomainPartition const & domain, VTKVTMWriter const & vtmWriter ) const; @@ -285,6 +310,11 @@ class VTKPolyDataWriterInterface void writeElementFields( ElementRegionBase const & subRegion, vtkCellData * cellData ) const; + /** + * @brief Writes all the fields associated to the elements of \p region if their plotlevel is <= m_plotLevel + * @param[in] region ParticleRegion being written + * @param[in] cellData a VTK object containing all the fields associated with the elements + */ void writeParticleFields( ParticleRegionBase const & region, vtkCellData * cellData ) const; @@ -293,13 +323,15 @@ class VTKPolyDataWriterInterface * @details The unstructured grid is the last element in the hierarchy of the output, * it contains the cells connectivities and the vertices coordinates as long as the * data fields associated with it - * @param[in] ug a VTK SmartPointer to the VTK unstructured grid. * @param[in] path directory path for the grid file + * @param[in] region ElementRegionBase beeing written + * @param[in] ug a VTK SmartPointer to the VTK unstructured grid. */ void writeUnstructuredGrid( string const & path, - vtkUnstructuredGrid * ug ) const; + ObjectManagerBase const & region, + vtkUnstructuredGrid * ug ); -private: +protected: /// Output directory name string m_outputDir; @@ -337,6 +369,15 @@ class VTKPolyDataWriterInterface /// Region output type, could be CELL, WELL, SURFACE, or ALL VTKRegionTypes m_outputRegionType; + + /// Defines whether to plot a faceElement as a 3D volumetric element or not. + bool m_writeFaceElementsAs3D; + + /// Number of target processes to aggregate the data to be written + integer m_numberOfTargetProcesses; + + /// Map a region name to the array of ranks outputed for it + std::map< string, std::vector< integer > > m_targetProcessesId; }; } // namespace vtk diff --git a/src/coreComponents/fileIO/vtk/VTKVTMWriter.cpp b/src/coreComponents/fileIO/vtk/VTKVTMWriter.cpp index b37ad3d79e1..2f4bfe41c1b 100644 --- a/src/coreComponents/fileIO/vtk/VTKVTMWriter.cpp +++ b/src/coreComponents/fileIO/vtk/VTKVTMWriter.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/fileIO/vtk/VTKVTMWriter.hpp b/src/coreComponents/fileIO/vtk/VTKVTMWriter.hpp index 3eede3f1cfe..45a8d52dea7 100644 --- a/src/coreComponents/fileIO/vtk/VTKVTMWriter.hpp +++ b/src/coreComponents/fileIO/vtk/VTKVTMWriter.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/BilinearFormUtilities.hpp b/src/coreComponents/finiteElement/BilinearFormUtilities.hpp index a236b4a54df..a268c2db764 100644 --- a/src/coreComponents/finiteElement/BilinearFormUtilities.hpp +++ b/src/coreComponents/finiteElement/BilinearFormUtilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/CMakeLists.txt b/src/coreComponents/finiteElement/CMakeLists.txt index d8ade51e37e..1fd77c86b1a 100644 --- a/src/coreComponents/finiteElement/CMakeLists.txt +++ b/src/coreComponents/finiteElement/CMakeLists.txt @@ -1,3 +1,22 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: finiteElement + +Contains the interface and implementation of finite element formulations. +#]] + # # Specify all headers # @@ -22,6 +41,7 @@ set( finiteElement_headers elementFormulations/LagrangeBasis2.hpp elementFormulations/LagrangeBasis3GL.hpp elementFormulations/LagrangeBasis5GL.hpp + kernelInterface/InterfaceKernelBase.hpp kernelInterface/ImplicitKernelBase.hpp kernelInterface/KernelBase.hpp kernelInterface/SparsityKernelBase.hpp @@ -41,15 +61,20 @@ set( finiteElement_sources set( dependencyList ${parallelDeps} dataRepository ) +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) + blt_add_library( NAME finiteElement SOURCES ${finiteElement_sources} HEADERS ${finiteElement_headers} - DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} + DEPENDS_ON ${decoratedDependencies} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} ) target_include_directories( finiteElement PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +install( TARGETS finiteElement LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) if( GEOS_ENABLE_TESTS ) add_subdirectory( unitTests ) diff --git a/src/coreComponents/finiteElement/ElementLibrary_depricated/SpecializedFormulations/UniformStrainHexahedron.cpp b/src/coreComponents/finiteElement/ElementLibrary_depricated/SpecializedFormulations/UniformStrainHexahedron.cpp index d73f4719752..31f6c6504e7 100644 --- a/src/coreComponents/finiteElement/ElementLibrary_depricated/SpecializedFormulations/UniformStrainHexahedron.cpp +++ b/src/coreComponents/finiteElement/ElementLibrary_depricated/SpecializedFormulations/UniformStrainHexahedron.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/ElementLibrary_depricated/SpecializedFormulations/UniformStrainHexahedron.h b/src/coreComponents/finiteElement/ElementLibrary_depricated/SpecializedFormulations/UniformStrainHexahedron.h index 9c38cde0d64..ea634ecf95e 100644 --- a/src/coreComponents/finiteElement/ElementLibrary_depricated/SpecializedFormulations/UniformStrainHexahedron.h +++ b/src/coreComponents/finiteElement/ElementLibrary_depricated/SpecializedFormulations/UniformStrainHexahedron.h @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/FiniteElementDiscretization.cpp b/src/coreComponents/finiteElement/FiniteElementDiscretization.cpp index bb9da889c27..85f18da5efe 100644 --- a/src/coreComponents/finiteElement/FiniteElementDiscretization.cpp +++ b/src/coreComponents/finiteElement/FiniteElementDiscretization.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -54,7 +55,7 @@ FiniteElementDiscretization::~FiniteElementDiscretization() {} -void FiniteElementDiscretization::postProcessInput() +void FiniteElementDiscretization::postInputInitialization() { GEOS_ERROR_IF( m_useVem < 0 || m_useVem > 1, getDataContext() << ": The flag useVirtualElements can be either 0 or 1" ); diff --git a/src/coreComponents/finiteElement/FiniteElementDiscretization.hpp b/src/coreComponents/finiteElement/FiniteElementDiscretization.hpp index 0d129a5da71..0ee428550a9 100644 --- a/src/coreComponents/finiteElement/FiniteElementDiscretization.hpp +++ b/src/coreComponents/finiteElement/FiniteElementDiscretization.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -107,7 +108,7 @@ class FiniteElementDiscretization : public dataRepository::Group /// Optional parameter indicating if the class should use Virtual Elements. int m_useVem; - void postProcessInput() override final; + void postInputInitialization() override final; }; diff --git a/src/coreComponents/finiteElement/FiniteElementDiscretizationManager.cpp b/src/coreComponents/finiteElement/FiniteElementDiscretizationManager.cpp index 413670a3c27..8bd43f0cdaf 100644 --- a/src/coreComponents/finiteElement/FiniteElementDiscretizationManager.cpp +++ b/src/coreComponents/finiteElement/FiniteElementDiscretizationManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -39,6 +40,7 @@ FiniteElementDiscretizationManager::~FiniteElementDiscretizationManager() Group * FiniteElementDiscretizationManager::createChild( string const & childKey, string const & childName ) { // These objects should probably not be registered on managed group... + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) ); std::unique_ptr< Group > fem = Group::CatalogInterface::factory( childKey, childName, this ); return &this->registerGroup( childName, std::move( fem ) ); } diff --git a/src/coreComponents/finiteElement/FiniteElementDiscretizationManager.hpp b/src/coreComponents/finiteElement/FiniteElementDiscretizationManager.hpp index 1d25381b478..e82a8b99244 100644 --- a/src/coreComponents/finiteElement/FiniteElementDiscretizationManager.hpp +++ b/src/coreComponents/finiteElement/FiniteElementDiscretizationManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/FiniteElementDispatch.hpp b/src/coreComponents/finiteElement/FiniteElementDispatch.hpp index 01ac7d1f49d..5db1789d6e8 100644 --- a/src/coreComponents/finiteElement/FiniteElementDispatch.hpp +++ b/src/coreComponents/finiteElement/FiniteElementDispatch.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -45,7 +46,7 @@ finiteElement::Q4_Hexahedron_Lagrange_GaussLobatto, \ finiteElement::Q5_Hexahedron_Lagrange_GaussLobatto -#if defined( GEOSX_DISPATCH_VEM ) +#if defined( GEOS_DISPATCH_VEM ) #define VEM_1_TYPES \ finiteElement::H1_Tetrahedron_VEM_Gauss1, \ @@ -86,9 +87,11 @@ #define FE_TYPES_2D \ - finiteElement::H1_QuadrilateralFace_Lagrange1_GaussLegendre2 \ + finiteElement::H1_QuadrilateralFace_Lagrange1_GaussLegendre2, \ finiteElement::H1_TriangleFace_Lagrange1_Gauss1 +#define BASE_FE_TYPES_2D FE_TYPES_2D + namespace geos { namespace finiteElement diff --git a/src/coreComponents/finiteElement/Kinematics.h b/src/coreComponents/finiteElement/Kinematics.h index 688aaccf5e7..9cc8bed31cd 100644 --- a/src/coreComponents/finiteElement/Kinematics.h +++ b/src/coreComponents/finiteElement/Kinematics.h @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/LinearFormUtilities.hpp b/src/coreComponents/finiteElement/LinearFormUtilities.hpp index 2b6475743cf..678725c1ad6 100644 --- a/src/coreComponents/finiteElement/LinearFormUtilities.hpp +++ b/src/coreComponents/finiteElement/LinearFormUtilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/PDEUtilities.hpp b/src/coreComponents/finiteElement/PDEUtilities.hpp index 716e31b89e2..a7f958ae17f 100644 --- a/src/coreComponents/finiteElement/PDEUtilities.hpp +++ b/src/coreComponents/finiteElement/PDEUtilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,7 @@ #ifndef GEOS_FINITEELEMENT_PDEUTILITIES_HPP_ #define GEOS_FINITEELEMENT_PDEUTILITIES_HPP_ -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" namespace geos { diff --git a/src/coreComponents/finiteElement/elementFormulations/ConformingVirtualElementOrder1.hpp b/src/coreComponents/finiteElement/elementFormulations/ConformingVirtualElementOrder1.hpp index eea219c69b9..3486004d766 100644 --- a/src/coreComponents/finiteElement/elementFormulations/ConformingVirtualElementOrder1.hpp +++ b/src/coreComponents/finiteElement/elementFormulations/ConformingVirtualElementOrder1.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -62,7 +63,9 @@ class ConformingVirtualElementOrder1 final : public FiniteElementBase ConformingVirtualElementOrder1() = default; - virtual ~ConformingVirtualElementOrder1() = default; + GEOS_HOST_DEVICE + virtual ~ConformingVirtualElementOrder1() override + {} /** * @struct StackVariables diff --git a/src/coreComponents/finiteElement/elementFormulations/ConformingVirtualElementOrder1_impl.hpp b/src/coreComponents/finiteElement/elementFormulations/ConformingVirtualElementOrder1_impl.hpp index 1f02b577f1e..932603a3b9c 100644 --- a/src/coreComponents/finiteElement/elementFormulations/ConformingVirtualElementOrder1_impl.hpp +++ b/src/coreComponents/finiteElement/elementFormulations/ConformingVirtualElementOrder1_impl.hpp @@ -2,15 +2,17 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ + /** * @file ConformingVirtualElementOrder1_impl.hpp */ diff --git a/src/coreComponents/finiteElement/elementFormulations/FiniteElementBase.hpp b/src/coreComponents/finiteElement/elementFormulations/FiniteElementBase.hpp index de0d1e45155..10f246bd49a 100644 --- a/src/coreComponents/finiteElement/elementFormulations/FiniteElementBase.hpp +++ b/src/coreComponents/finiteElement/elementFormulations/FiniteElementBase.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -56,6 +57,7 @@ class FiniteElementBase * @brief Copy Constructor * @param source The object to copy. */ + GEOS_HOST_DEVICE FiniteElementBase( FiniteElementBase const & source ): #ifdef CALC_FEM_SHAPE_IN_KERNEL m_viewGradN(), @@ -86,7 +88,9 @@ class FiniteElementBase /** * @brief Destructor */ - virtual ~FiniteElementBase() = default; + GEOS_HOST_DEVICE + virtual ~FiniteElementBase() + {} /** * @struct StackVariables diff --git a/src/coreComponents/finiteElement/elementFormulations/H1_Hexahedron_Lagrange1_GaussLegendre2.hpp b/src/coreComponents/finiteElement/elementFormulations/H1_Hexahedron_Lagrange1_GaussLegendre2.hpp index fe93d494822..0b164a174c2 100644 --- a/src/coreComponents/finiteElement/elementFormulations/H1_Hexahedron_Lagrange1_GaussLegendre2.hpp +++ b/src/coreComponents/finiteElement/elementFormulations/H1_Hexahedron_Lagrange1_GaussLegendre2.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -75,6 +76,10 @@ class H1_Hexahedron_Lagrange1_GaussLegendre2 final : public FiniteElementBase public: /// The number of nodes/support points per element. constexpr static localIndex numNodes = LagrangeBasis1::TensorProduct3D::numSupportPoints; + + /// The number of faces/support points for bubble functions per element. + constexpr static localIndex numFaces = LagrangeBasis1::TensorProduct3D::numSupportFaces; + /// The maximum number of support points per element. constexpr static localIndex maxSupportPoints = numNodes; @@ -88,6 +93,7 @@ class H1_Hexahedron_Lagrange1_GaussLegendre2 final : public FiniteElementBase USING_FINITEELEMENTBASE /** @endcond Doxygen_Suppress */ + GEOS_HOST_DEVICE virtual ~H1_Hexahedron_Lagrange1_GaussLegendre2() override {} @@ -209,6 +215,42 @@ class H1_Hexahedron_Lagrange1_GaussLegendre2 final : public FiniteElementBase return calcN( q, N ); } + /** + * @brief Calculate face bubble functions values for each face at a + * given point in the parent space. + * @param pointCoord coordinates of the given point. + * @param N An array to pass back the shape function values for each support + * face. + */ + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + static void calcFaceBubbleN( real64 const (&pointCoord)[3], + real64 (& N)[numFaces] ) + { + LagrangeBasis1::TensorProduct3D::valueFaceBubble( pointCoord, N ); + } + + /** + * @brief Calculate face bubble functions values for each face at a + * quadrature point. + * @param q Index of the quadrature point. + * @param N An array to pass back the shape function values for each support + * point. + */ + GEOS_HOST_DEVICE + inline + static void calcFaceBubbleN( localIndex const q, + real64 (& N)[numFaces] ) + { + int qa, qb, qc; + LagrangeBasis1::TensorProduct3D::multiIndex( q, qa, qb, qc ); + real64 const qCoords[3] = { quadratureFactor * LagrangeBasis1::parentSupportCoord( qa ), + quadratureFactor * LagrangeBasis1::parentSupportCoord( qb ), + quadratureFactor * LagrangeBasis1::parentSupportCoord( qc ) }; + + calcFaceBubbleN( qCoords, N ); + } + /** * @brief Calculate the shape functions derivatives wrt the physical * coordinates. @@ -240,6 +282,20 @@ class H1_Hexahedron_Lagrange1_GaussLegendre2 final : public FiniteElementBase StackVariables const & stack, real64 ( &gradN )[numNodes][3] ); + /** + * @brief Calculate the bubble function derivatives wrt the physical + * coordinates. + * @param q Index of the quadrature point. + * @param X Array containing the coordinates of the support points. + * @param gradN Array to contain the shape bubble function derivatives for all + * support points at the coordinates of the quadrature point @p q. + * @return The determinant of the parent/physical transformation matrix. + */ + GEOS_HOST_DEVICE + static real64 calcGradFaceBubbleN( localIndex const q, + real64 const (&X)[numNodes][3], + real64 ( &gradN )[numFaces][3] ); + /** * @brief Calculate the integration weights for a quadrature point. * @param q Index of the quadrature point. @@ -573,6 +629,41 @@ real64 H1_Hexahedron_Lagrange1_GaussLegendre2:: return calcGradN( q, X, gradN ); } +GEOS_HOST_DEVICE +inline +real64 +H1_Hexahedron_Lagrange1_GaussLegendre2::calcGradFaceBubbleN( localIndex const q, + real64 const (&X)[numNodes][3], + real64 (& gradN)[numFaces][3] ) +{ + real64 J[3][3] = {{0}}; + + + int qa, qb, qc; + LagrangeBasis1::TensorProduct3D::multiIndex( q, qa, qb, qc ); + + jacobianTransformation( qa, qb, qc, X, J ); + + real64 const detJ = LvArray::tensorOps::invert< 3 >( J ); + + real64 dNdXi[numFaces][3] = {{0}}; + + real64 const qCoords[3] = { quadratureFactor * LagrangeBasis1::parentSupportCoord( qa ), + quadratureFactor * LagrangeBasis1::parentSupportCoord( qb ), + quadratureFactor * LagrangeBasis1::parentSupportCoord( qc ) }; + + LagrangeBasis1::TensorProduct3D::gradientFaceBubble( qCoords, dNdXi ); + + for( int fi=0; fi +GEOS_HOST_DEVICE +GEOS_FORCE_INLINE +real64 +Qk_Hexahedron_Lagrange_GaussLobatto< GL_BASIS >::calcGradNWithCorners( localIndex const q, + real64 const (&X)[8][3], + real64 (& gradN)[numNodes][3] ) +{ + int qa, qb, qc; + GL_BASIS::TensorProduct3D::multiIndex( q, qa, qb, qc ); + + real64 J[3][3] = {{0}}; + + jacobianTransformation( qa, qb, qc, X, J ); + + real64 const detJ = LvArray::tensorOps::invert< 3 >( J ); + + applyTransformationToParentGradients( q, J, gradN ); + + return detJ; +} +//************************************************************************************************* +template< typename GL_BASIS > +GEOS_HOST_DEVICE +GEOS_FORCE_INLINE +real64 +Qk_Hexahedron_Lagrange_GaussLobatto< GL_BASIS >::calcGradNWithCorners( real64 const (&coords)[3], + real64 const (&X)[8][3], + real64 (& gradN)[numNodes][3] ) +{ + real64 J[3][3] = {{0}}; + + jacobianTransformationWithCorners( coords, X, J ); + + real64 const detJ = LvArray::tensorOps::invert< 3 >( J ); + + applyTransformationToParentGradients( coords, J, gradN ); + + return detJ; +} +template< typename GL_BASIS > +GEOS_HOST_DEVICE +GEOS_FORCE_INLINE +real64 Qk_Hexahedron_Lagrange_GaussLobatto< GL_BASIS >:: +calcGradNWithCorners( localIndex const q, + real64 const (&X)[8][3], + StackVariables const & GEOS_UNUSED_PARAM( stack ), + real64 ( & gradN )[numNodes][3] ) +{ + return calcGradN( q, X, gradN ); +} //************************************************************************************************* #if __GNUC__ #pragma GCC diagnostic push @@ -982,6 +1094,37 @@ jacobianTransformation( real64 const (&coords)[3], }, X, J ); } +template< typename GL_BASIS > +GEOS_HOST_DEVICE +GEOS_FORCE_INLINE +void +Qk_Hexahedron_Lagrange_GaussLobatto< GL_BASIS >:: +jacobianTransformationWithCorners( real64 const (&coords)[3], + real64 const (&X)[8][3], + real64 ( & J )[3][3] ) +{ + supportLoop( coords, [] GEOS_HOST_DEVICE ( real64 const (&dNdXi)[3], + int const nodeIndex, + real64 const (&X)[8][3], + real64 (& J)[3][3] ) + { + int qa, qb, qc; + GL_BASIS::TensorProduct3D::multiIndex( nodeIndex, qa, qb, qc ); + real64 Xnode[3]; + real64 alpha = ( GL_BASIS::parentSupportCoord( qa ) + 1.0 ) / 2.0; + real64 beta = ( GL_BASIS::parentSupportCoord( qb ) + 1.0 ) / 2.0; + real64 gamma = ( GL_BASIS::parentSupportCoord( qc ) + 1.0 ) / 2.0; + trilinearInterp( alpha, beta, gamma, X, Xnode ); + for( int i = 0; i < 3; ++i ) + { + for( int j = 0; j < 3; ++j ) + { + J[i][j] = J[i][j] + dNdXi[ j ] * Xnode[i]; + } + } + }, X, J ); +} + template< typename GL_BASIS > GEOS_HOST_DEVICE GEOS_FORCE_INLINE diff --git a/src/coreComponents/finiteElement/kernelInterface/ImplicitKernelBase.hpp b/src/coreComponents/finiteElement/kernelInterface/ImplicitKernelBase.hpp index 681ec678ecb..8e86d076e68 100644 --- a/src/coreComponents/finiteElement/kernelInterface/ImplicitKernelBase.hpp +++ b/src/coreComponents/finiteElement/kernelInterface/ImplicitKernelBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/kernelInterface/InterfaceKernelBase.hpp b/src/coreComponents/finiteElement/kernelInterface/InterfaceKernelBase.hpp new file mode 100644 index 00000000000..5315b8451ae --- /dev/null +++ b/src/coreComponents/finiteElement/kernelInterface/InterfaceKernelBase.hpp @@ -0,0 +1,306 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file InterfaceKernelBase.hpp + */ + +#ifndef GEOS_FINITEELEMENT_INTERFACEKERNELBASE_HPP_ +#define GEOS_FINITEELEMENT_INTERFACEKERNELBASE_HPP_ + +#include "ImplicitKernelBase.hpp" + +/** + * @brief This macro allows solvers to select a subset of FE_TYPES_2D on which the dispatch is done. + * If none are selected, by default all the BASE_FE_TYPES_2D apply. + */ +#ifndef SELECTED_FE_TYPES_2D +#define SELECTED_FE_TYPES_2D BASE_FE_TYPES_2D +#endif + +namespace geos +{ + +/** + * @namespace finiteElement Contains the finite element implementation. + */ +namespace finiteElement +{ + +/** + * @class InterfaceKernelBase + * @brief Define the base class for interface finite element kernels. + * (2D finite elements belong to FaceElementSubRegion). + * @tparam CONSTITUTIVE_TYPE The type of constitutive model present in the + * FaceElementSubRegion. + * @tparam FE_TYPE The type of finite element. + * @tparam NUM_DOF_PER_TEST_SP The number of DOF per test support point. + * @tparam NUM_DOF_PER_TRIAL_SP The number of DOF per trial support point. + * + */ + +template< typename CONSTITUTIVE_TYPE, + typename FE_TYPE, + int NUM_DOF_PER_TEST_SP, + int NUM_DOF_PER_TRIAL_SP > +class InterfaceKernelBase : public ImplicitKernelBase< FaceElementSubRegion, + CONSTITUTIVE_TYPE, + FE_TYPE, + NUM_DOF_PER_TEST_SP, + NUM_DOF_PER_TRIAL_SP > +{ +public: + + /// Alias for the base class, i.e., geos::finiteElement::ImplicitKernelBase) + using Base = ImplicitKernelBase< FaceElementSubRegion, + CONSTITUTIVE_TYPE, + FE_TYPE, + NUM_DOF_PER_TEST_SP, + NUM_DOF_PER_TRIAL_SP >; + + using Base::m_dofNumber; + using Base::m_dofRankOffset; + using Base::m_matrix; + + /** + * @brief Constructor + * @copydoc geos::finiteElement::ImplicitKernelBase::ImplicitKernelBase + */ + InterfaceKernelBase( NodeManager const & nodeManager, + EdgeManager const & edgeManager, + FaceManager const & faceManager, + localIndex const targetRegionIndex, + FaceElementSubRegion & elementSubRegion, + FE_TYPE const & finiteElementSpace, + CONSTITUTIVE_TYPE & inputConstitutiveType, + arrayView1d< globalIndex const > const inputDofNumber, + globalIndex const rankOffset, + CRSMatrixView< real64, globalIndex const > const inputMatrix, + arrayView1d< real64 > const inputRhs, + real64 const inputDt ): + Base( nodeManager, + edgeManager, + faceManager, + targetRegionIndex, + elementSubRegion, + finiteElementSpace, + inputConstitutiveType, + inputDofNumber, + rankOffset, + inputMatrix, + inputRhs, + inputDt ) + {} + + //*************************************************************************** + /** + * @copydoc finiteElement::KernelBase::StackVariables + */ + struct StackVariables + {}; + +}; + +/** + * @class InterfaceKernelFactory + * @brief Used to forward arguments to a class that implements the InterfaceKernelBase interface. + * @tparam KERNEL_TYPE The template class to construct, should implement the InterfaceKernelBase interface. + * @tparam ARGS The arguments used to construct a @p KERNEL_TYPE in addition to the standard arguments. + */ +template< template< typename CONSTITUTIVE_TYPE, + typename FE_TYPE > class KERNEL_TYPE, + typename ... ARGS > +class InterfaceKernelFactory +{ +public: + + /** + * @brief Initialize the factory. + * @param args The arguments used to construct a @p KERNEL_TYPE in addition to the standard arguments. + */ + InterfaceKernelFactory( ARGS ... args ): + m_args( args ... ) + {} + + /** + * @brief Create a new kernel with the given standard arguments. + * @tparam CONSTITUTIVE_TYPE The type of @p inputConstitutiveType. + * @tparam FE_TYPE The type of @p finiteElementSpace. + * @param nodeManager The node manager. + * @param edgeManager The edge manager. + * @param faceManager The face manager. + * @param targetRegionIndex The target region index. + * @param elementSubRegion The subregion to execute on. + * @param finiteElementSpace The finite element space. + * @param inputConstitutiveType The constitutive relation. + * @return A new kernel constructed with the given arguments and @c ARGS. + */ + template< typename CONSTITUTIVE_TYPE, typename FE_TYPE > + KERNEL_TYPE< CONSTITUTIVE_TYPE, FE_TYPE > createKernel( + NodeManager & nodeManager, + EdgeManager const & edgeManager, + FaceManager const & faceManager, + localIndex const targetRegionIndex, + FaceElementSubRegion & elementSubRegion, + FE_TYPE const & finiteElementSpace, + CONSTITUTIVE_TYPE & inputConstitutiveType ) + { + camp::tuple< NodeManager &, + EdgeManager const &, + FaceManager const &, + localIndex const, + FaceElementSubRegion &, + FE_TYPE const &, + CONSTITUTIVE_TYPE & > standardArgs { nodeManager, + edgeManager, + faceManager, + targetRegionIndex, + elementSubRegion, + finiteElementSpace, + inputConstitutiveType }; + + auto allArgs = camp::tuple_cat_pair( standardArgs, m_args ); + return camp::make_from_tuple< KERNEL_TYPE< CONSTITUTIVE_TYPE, FE_TYPE > >( allArgs ); + + } + +private: + /// The arguments to append to the standard kernel constructor arguments. + camp::tuple< ARGS ... > m_args; +}; + +//***************************************************************************** + +//START_interfaceBasedKernelApplication +/** + * @brief Performs a loop over FaceElementSubRegion and calls a kernel launch + * with compile time knowledge of sub-loop bounds such as number of nodes and + * quadrature points per element. + * @tparam POLICY The RAJA launch policy to pass to the kernel launch. + * @tparam CONSTITUTIVE_BASE The common base class for constitutive pass-thru/dispatch which gives the kernel + * launch compile time knowledge of the constitutive model. + * @tparam KERNEL_FACTORY The type of @p interfaceKernelFactory, typically an instantiation of @c InterfaceKernelFactory, and + * must adhere to that interface. + * @param mesh The MeshLevel object. + * @param targetRegionName The names of the target regions to apply the @p KERNEL_TEMPLATE. + * @param faceElementList List of element of the same type belongs to FaceElementSubRegion. + * @param subRegionFE Finite element object. + * @param constitutiveStringName Key string used to retrieve the constitutive model. + * @param interfaceKernelFactory The object used to construct the kernel. + * @return The maximum contribution to the residual, which may be used to scale the residual. + * + * @details Loops over all regions Applies/Launches a kernel specified by the @p KERNEL_TEMPLATE through + * #::geos::finiteElement::KernelBase::kernelLaunch(). + */ +template< typename POLICY, + typename CONSTITUTIVE_BASE, + typename KERNEL_FACTORY > +static +real64 interfaceBasedKernelApplication( MeshLevel & mesh, + string const & targetRegionName, + arrayView1d< localIndex const > const & faceElementList, + FiniteElementBase const & subRegionFE, + string const & constitutiveStringName, + KERNEL_FACTORY & interfaceKernelFactory ) +{ + GEOS_MARK_FUNCTION; + + + // save the maximum residual contribution for scaling residuals for convergence criteria. + real64 maxResidualContribution = 0; + + NodeManager & nodeManager = mesh.getNodeManager(); + EdgeManager & edgeManager = mesh.getEdgeManager(); + FaceManager & faceManager = mesh.getFaceManager(); + ElementRegionManager & elementManager = mesh.getElemManager(); + + SurfaceElementRegion & region = elementManager.getRegion< SurfaceElementRegion >( targetRegionName ); + FaceElementSubRegion & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); + localIndex const targetRegionIndex = 0; + + // Get the constitutive model...and allocate a null constitutive model if required. + constitutive::ConstitutiveBase * constitutiveRelation = nullptr; + constitutive::NullModel * nullConstitutiveModel = nullptr; + if( subRegion.template hasWrapper< string >( constitutiveStringName ) ) + { + string const & constitutiveName = subRegion.template getReference< string >( constitutiveStringName ); + constitutiveRelation = &subRegion.template getConstitutiveModel( constitutiveName ); + } + else + { + nullConstitutiveModel = &subRegion.template registerGroup< constitutive::NullModel >( "nullModelGroup" ); + constitutiveRelation = nullConstitutiveModel; + } + + localIndex const numElems = faceElementList.size(); + + // Call the constitutive dispatch which converts the type of constitutive model into a compile time constant. + constitutive::ConstitutivePassThru< CONSTITUTIVE_BASE >::execute( *constitutiveRelation, + [&maxResidualContribution, + &nodeManager, + &edgeManager, + &faceManager, + targetRegionIndex, + &interfaceKernelFactory, + &subRegion, + &subRegionFE, + numElems] + ( auto & castedConstitutiveRelation ) + { + + finiteElement::FiniteElementDispatchHandler< SELECTED_FE_TYPES_2D >::dispatch2D( subRegionFE, + [&maxResidualContribution, + &nodeManager, + &edgeManager, + &faceManager, + targetRegionIndex, + &interfaceKernelFactory, + &subRegion, + numElems, + &castedConstitutiveRelation] ( auto const finiteElement ) + + { + auto kernel = interfaceKernelFactory.createKernel( nodeManager, + edgeManager, + faceManager, + targetRegionIndex, + subRegion, + finiteElement, + castedConstitutiveRelation ); + + using KERNEL_TYPE = decltype( kernel ); + + // Call the kernelLaunch function, and store the maximum contribution to the residual. + maxResidualContribution = + std::max( maxResidualContribution, + KERNEL_TYPE::template kernelLaunch< POLICY, KERNEL_TYPE >( numElems, kernel ) ); + + } ); + } ); + + // Remove the null constitutive model (not required, but cleaner) + if( nullConstitutiveModel ) + { + subRegion.deregisterGroup( "nullModelGroup" ); + } + + return maxResidualContribution; +} +//END_interfaceBasedKernelApplication + +} // namespace finiteElement +} // namespace geos + +#endif /* GEOS_FINITEELEMENT_INTERFACEKERNELBASE_HPP_ */ diff --git a/src/coreComponents/finiteElement/kernelInterface/KernelBase.hpp b/src/coreComponents/finiteElement/kernelInterface/KernelBase.hpp index ac5068fb0fe..d759430485b 100644 --- a/src/coreComponents/finiteElement/kernelInterface/KernelBase.hpp +++ b/src/coreComponents/finiteElement/kernelInterface/KernelBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -264,7 +265,7 @@ class KernelBase /// The finite element space/discretization object for the element type in /// the SUBREGION_TYPE. - FE_TYPE const & m_finiteElementSpace; + FE_TYPE const m_finiteElementSpace; }; /** diff --git a/src/coreComponents/finiteElement/kernelInterface/SparsityKernelBase.hpp b/src/coreComponents/finiteElement/kernelInterface/SparsityKernelBase.hpp index a107ff4f38f..cc1abe0e1f5 100644 --- a/src/coreComponents/finiteElement/kernelInterface/SparsityKernelBase.hpp +++ b/src/coreComponents/finiteElement/kernelInterface/SparsityKernelBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/unitTests/CMakeLists.txt b/src/coreComponents/finiteElement/unitTests/CMakeLists.txt index a8f044271be..0360038c17f 100644 --- a/src/coreComponents/finiteElement/unitTests/CMakeLists.txt +++ b/src/coreComponents/finiteElement/unitTests/CMakeLists.txt @@ -12,7 +12,7 @@ set(testSources set( dependencyList gtest finiteElement ${parallelDeps} ) -if( ENABLE_CUDA_NVTOOLSEXT ) +if( ENABLE_CUDA AND ENABLE_CUDA_NVTOOLSEXT ) list( APPEND dependencyList CUDA::nvToolsExt ) endif() diff --git a/src/coreComponents/finiteElement/unitTests/testFiniteElementBase.cpp b/src/coreComponents/finiteElement/unitTests/testFiniteElementBase.cpp index 835d8778f6c..b6e3c1f4610 100644 --- a/src/coreComponents/finiteElement/unitTests/testFiniteElementBase.cpp +++ b/src/coreComponents/finiteElement/unitTests/testFiniteElementBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/unitTests/testFiniteElementHelpers.hpp b/src/coreComponents/finiteElement/unitTests/testFiniteElementHelpers.hpp index 3148edb9f14..d59d26bc794 100644 --- a/src/coreComponents/finiteElement/unitTests/testFiniteElementHelpers.hpp +++ b/src/coreComponents/finiteElement/unitTests/testFiniteElementHelpers.hpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #ifndef GEOS_FINITEELEMENT_UNITTESTS_TESTFINITEELEMENTHELPERS_HPP_ #define GEOS_FINITEELEMENT_UNITTESTS_TESTFINITEELEMENTHELPERS_HPP_ diff --git a/src/coreComponents/finiteElement/unitTests/testH1_Hexahedron_Lagrange1_GaussLegendre2.cpp b/src/coreComponents/finiteElement/unitTests/testH1_Hexahedron_Lagrange1_GaussLegendre2.cpp index 2a73fc1b357..f84126503f2 100644 --- a/src/coreComponents/finiteElement/unitTests/testH1_Hexahedron_Lagrange1_GaussLegendre2.cpp +++ b/src/coreComponents/finiteElement/unitTests/testH1_Hexahedron_Lagrange1_GaussLegendre2.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/unitTests/testH1_Pyramid_Lagrange1_Gauss5.cpp b/src/coreComponents/finiteElement/unitTests/testH1_Pyramid_Lagrange1_Gauss5.cpp index fa0acd770a3..2b0226a1521 100644 --- a/src/coreComponents/finiteElement/unitTests/testH1_Pyramid_Lagrange1_Gauss5.cpp +++ b/src/coreComponents/finiteElement/unitTests/testH1_Pyramid_Lagrange1_Gauss5.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/unitTests/testH1_QuadrilateralFace_Lagrange1_GaussLegendre2.cpp b/src/coreComponents/finiteElement/unitTests/testH1_QuadrilateralFace_Lagrange1_GaussLegendre2.cpp index 7a48db8231c..327b7a51a75 100644 --- a/src/coreComponents/finiteElement/unitTests/testH1_QuadrilateralFace_Lagrange1_GaussLegendre2.cpp +++ b/src/coreComponents/finiteElement/unitTests/testH1_QuadrilateralFace_Lagrange1_GaussLegendre2.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/unitTests/testH1_Tetrahedron_Lagrange1_Gauss1.cpp b/src/coreComponents/finiteElement/unitTests/testH1_Tetrahedron_Lagrange1_Gauss1.cpp index 1d6302f5526..6ff8c6ee6ec 100644 --- a/src/coreComponents/finiteElement/unitTests/testH1_Tetrahedron_Lagrange1_Gauss1.cpp +++ b/src/coreComponents/finiteElement/unitTests/testH1_Tetrahedron_Lagrange1_Gauss1.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/unitTests/testH1_TriangleFace_Lagrange1_Gauss1.cpp b/src/coreComponents/finiteElement/unitTests/testH1_TriangleFace_Lagrange1_Gauss1.cpp index e4c038fa08d..058e20d2db2 100644 --- a/src/coreComponents/finiteElement/unitTests/testH1_TriangleFace_Lagrange1_Gauss1.cpp +++ b/src/coreComponents/finiteElement/unitTests/testH1_TriangleFace_Lagrange1_Gauss1.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/unitTests/testH1_Wedge_Lagrange1_Gauss6.cpp b/src/coreComponents/finiteElement/unitTests/testH1_Wedge_Lagrange1_Gauss6.cpp index dfcb9373c08..7951af09a7b 100644 --- a/src/coreComponents/finiteElement/unitTests/testH1_Wedge_Lagrange1_Gauss6.cpp +++ b/src/coreComponents/finiteElement/unitTests/testH1_Wedge_Lagrange1_Gauss6.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/unitTests/testQ3_Hexahedron_Lagrange_GaussLobatto.cpp b/src/coreComponents/finiteElement/unitTests/testQ3_Hexahedron_Lagrange_GaussLobatto.cpp index 6d353392f52..b204cc9baa9 100644 --- a/src/coreComponents/finiteElement/unitTests/testQ3_Hexahedron_Lagrange_GaussLobatto.cpp +++ b/src/coreComponents/finiteElement/unitTests/testQ3_Hexahedron_Lagrange_GaussLobatto.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteElement/unitTests/testQ5_Hexahedron_Lagrange_GaussLobatto.cpp b/src/coreComponents/finiteElement/unitTests/testQ5_Hexahedron_Lagrange_GaussLobatto.cpp index c78f7714db0..2e74a035da0 100644 --- a/src/coreComponents/finiteElement/unitTests/testQ5_Hexahedron_Lagrange_GaussLobatto.cpp +++ b/src/coreComponents/finiteElement/unitTests/testQ5_Hexahedron_Lagrange_GaussLobatto.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/BoundaryStencil.cpp b/src/coreComponents/finiteVolume/BoundaryStencil.cpp index 913a57704be..d2bb993141b 100644 --- a/src/coreComponents/finiteVolume/BoundaryStencil.cpp +++ b/src/coreComponents/finiteVolume/BoundaryStencil.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/BoundaryStencil.hpp b/src/coreComponents/finiteVolume/BoundaryStencil.hpp index 2b27d35872c..137bd6692a9 100644 --- a/src/coreComponents/finiteVolume/BoundaryStencil.hpp +++ b/src/coreComponents/finiteVolume/BoundaryStencil.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/CMakeLists.txt b/src/coreComponents/finiteVolume/CMakeLists.txt index 9fc47c9411b..77aa9112334 100644 --- a/src/coreComponents/finiteVolume/CMakeLists.txt +++ b/src/coreComponents/finiteVolume/CMakeLists.txt @@ -1,3 +1,23 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: finiteVolume + +Implementation and access to finite volume method. The main data structures of this package are + the stencils: connection values at the interfaces of the volume elements. +#]] + # # Specify all headers # @@ -40,14 +60,19 @@ set( finiteVolume_sources HybridMimeticDiscretization.cpp ) -set( dependencyList ${parallelDeps} mesh codingUtilities fieldSpecification ) +set( dependencyList ${parallelDeps} mesh fieldSpecification ) + +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) blt_add_library( NAME finiteVolume SOURCES ${finiteVolume_sources} HEADERS ${finiteVolume_headers} - DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} + DEPENDS_ON ${decoratedDependencies} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} ) target_include_directories( finiteVolume PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +install( TARGETS finiteVolume LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) diff --git a/src/coreComponents/finiteVolume/CellElementStencilMPFA.cpp b/src/coreComponents/finiteVolume/CellElementStencilMPFA.cpp index 9ed1ef71bbc..1f9556667fc 100644 --- a/src/coreComponents/finiteVolume/CellElementStencilMPFA.cpp +++ b/src/coreComponents/finiteVolume/CellElementStencilMPFA.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/CellElementStencilMPFA.hpp b/src/coreComponents/finiteVolume/CellElementStencilMPFA.hpp index 35afb9c0c80..296db38ad8d 100644 --- a/src/coreComponents/finiteVolume/CellElementStencilMPFA.hpp +++ b/src/coreComponents/finiteVolume/CellElementStencilMPFA.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/CellElementStencilTPFA.cpp b/src/coreComponents/finiteVolume/CellElementStencilTPFA.cpp index 6cdc2bb7065..d95969e7a48 100644 --- a/src/coreComponents/finiteVolume/CellElementStencilTPFA.cpp +++ b/src/coreComponents/finiteVolume/CellElementStencilTPFA.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/CellElementStencilTPFA.hpp b/src/coreComponents/finiteVolume/CellElementStencilTPFA.hpp index 0de8fcf2a6f..88fa3bb2b27 100644 --- a/src/coreComponents/finiteVolume/CellElementStencilTPFA.hpp +++ b/src/coreComponents/finiteVolume/CellElementStencilTPFA.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -219,9 +220,8 @@ CellElementStencilTPFAWrapper:: real64 (& weight)[1][2], real64 (& dWeight_dVar )[1][2] ) const { - GEOS_UNUSED_VAR( dCoeff_dVar ); - real64 halfWeight[2]; + real64 dHalfWeight_dVar[2]; // real64 const tolerance = 1e-30 * lengthTolerance; // TODO: choice of constant based on physics? @@ -232,6 +232,7 @@ CellElementStencilTPFAWrapper:: localIndex const ei = m_elementIndices[iconn][i]; halfWeight[i] = m_weights[iconn][i]; + dHalfWeight_dVar[i] = m_weights[iconn][i]; // Proper computation real64 faceNormal[3]; @@ -242,8 +243,11 @@ CellElementStencilTPFAWrapper:: } real64 faceConormal[3]; + real64 dFaceConormal_dVar[3]; LvArray::tensorOps::hadamardProduct< 3 >( faceConormal, coefficient[er][esr][ei][0], faceNormal ); + LvArray::tensorOps::hadamardProduct< 3 >( dFaceConormal_dVar, dCoeff_dVar[er][esr][ei][0], faceNormal ); halfWeight[i] *= LvArray::tensorOps::AiBi< 3 >( m_cellToFaceVec[iconn][i], faceConormal ); + dHalfWeight_dVar[i] *= LvArray::tensorOps::AiBi< 3 >( m_cellToFaceVec[iconn][i], dFaceConormal_dVar ); // correct negative weight issue arising from non-K-orthogonal grids if( halfWeight[i] < 0.0 ) @@ -251,8 +255,13 @@ CellElementStencilTPFAWrapper:: LvArray::tensorOps::hadamardProduct< 3 >( faceConormal, coefficient[er][esr][ei][0], m_cellToFaceVec[iconn][i] ); + LvArray::tensorOps::hadamardProduct< 3 >( dFaceConormal_dVar, + dCoeff_dVar[er][esr][ei][0], + m_cellToFaceVec[iconn][i] ); halfWeight[i] = m_weights[iconn][i]; + dHalfWeight_dVar[i] = m_weights[iconn][i]; halfWeight[i] *= LvArray::tensorOps::AiBi< 3 >( m_cellToFaceVec[iconn][i], faceConormal ); + dHalfWeight_dVar[i] *= LvArray::tensorOps::AiBi< 3 >( m_cellToFaceVec[iconn][i], dFaceConormal_dVar ); } } @@ -263,16 +272,25 @@ CellElementStencilTPFAWrapper:: real64 const harmonicWeight = sum > 0 ? product / sum : 0.0; real64 const arithmeticWeight = sum / 2; + real64 dHarmonicWeight_dVar[2]; + real64 dArithmeticWeight_dVar[2]; + + dHarmonicWeight_dVar[0] = sum > 0 ? (dHalfWeight_dVar[0]*sum*halfWeight[1] - dHalfWeight_dVar[0]*halfWeight[0]*halfWeight[1]) / ( sum*sum ) : 0.0; + dHarmonicWeight_dVar[1] = sum > 0 ? (dHalfWeight_dVar[1]*sum*halfWeight[0] - dHalfWeight_dVar[1]*halfWeight[1]*halfWeight[0]) / ( sum*sum ) : 0.0; + + dArithmeticWeight_dVar[0] = dHalfWeight_dVar[0] / 2; + dArithmeticWeight_dVar[1] = dHalfWeight_dVar[1] / 2; + real64 const meanPermCoeff = 1.0; //TODO make it a member if it is really necessary real64 const value = meanPermCoeff * harmonicWeight + (1 - meanPermCoeff) * arithmeticWeight; for( localIndex ke = 0; ke < 2; ++ke ) { weight[0][ke] = m_transMultiplier[iconn] * value * (ke == 0 ? 1 : -1); - } - dWeight_dVar[0][0] = 0.0; - dWeight_dVar[0][1] = 0.0; + real64 const dValue_dVar = meanPermCoeff * dHarmonicWeight_dVar[ke] + (1 - meanPermCoeff) * dArithmeticWeight_dVar[ke]; + dWeight_dVar[0][ke] = m_transMultiplier[iconn] * dValue_dVar; + } } GEOS_HOST_DEVICE diff --git a/src/coreComponents/finiteVolume/EmbeddedSurfaceToCellStencil.cpp b/src/coreComponents/finiteVolume/EmbeddedSurfaceToCellStencil.cpp index 6a2d4e3abb4..3fe641696e1 100644 --- a/src/coreComponents/finiteVolume/EmbeddedSurfaceToCellStencil.cpp +++ b/src/coreComponents/finiteVolume/EmbeddedSurfaceToCellStencil.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/EmbeddedSurfaceToCellStencil.hpp b/src/coreComponents/finiteVolume/EmbeddedSurfaceToCellStencil.hpp index d110ef18081..7f9c1562366 100644 --- a/src/coreComponents/finiteVolume/EmbeddedSurfaceToCellStencil.hpp +++ b/src/coreComponents/finiteVolume/EmbeddedSurfaceToCellStencil.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/FaceElementToCellStencil.cpp b/src/coreComponents/finiteVolume/FaceElementToCellStencil.cpp index d4af43bf652..df56d0db33e 100644 --- a/src/coreComponents/finiteVolume/FaceElementToCellStencil.cpp +++ b/src/coreComponents/finiteVolume/FaceElementToCellStencil.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/FaceElementToCellStencil.hpp b/src/coreComponents/finiteVolume/FaceElementToCellStencil.hpp index bd212d5607f..3b970bd8b2b 100644 --- a/src/coreComponents/finiteVolume/FaceElementToCellStencil.hpp +++ b/src/coreComponents/finiteVolume/FaceElementToCellStencil.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/FiniteVolumeManager.cpp b/src/coreComponents/finiteVolume/FiniteVolumeManager.cpp index 89289e5f32b..500d1da5ecf 100644 --- a/src/coreComponents/finiteVolume/FiniteVolumeManager.cpp +++ b/src/coreComponents/finiteVolume/FiniteVolumeManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -41,6 +42,7 @@ FiniteVolumeManager::~FiniteVolumeManager() Group * FiniteVolumeManager::createChild( string const & childKey, string const & childName ) { + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) ); if( childKey == HybridMimeticDiscretization::catalogName() ) { std::unique_ptr< HybridMimeticDiscretization > hm = std::make_unique< HybridMimeticDiscretization >( childName, this ); diff --git a/src/coreComponents/finiteVolume/FiniteVolumeManager.hpp b/src/coreComponents/finiteVolume/FiniteVolumeManager.hpp index 2fe3be2527d..82e2e638854 100644 --- a/src/coreComponents/finiteVolume/FiniteVolumeManager.hpp +++ b/src/coreComponents/finiteVolume/FiniteVolumeManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/FluxApproximationBase.cpp b/src/coreComponents/finiteVolume/FluxApproximationBase.cpp index 05f0b2dbddd..36b61678f39 100644 --- a/src/coreComponents/finiteVolume/FluxApproximationBase.cpp +++ b/src/coreComponents/finiteVolume/FluxApproximationBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -59,10 +60,6 @@ FluxApproximationBase::FluxApproximationBase( string const & name, Group * const setDescription( "Type of upwinding scheme. " "Valid options:\n* " + EnumStrings< UpwindingScheme >::concat( "\n* " ) ); -// registerWrapper( viewKeyStruct::epsC1PPUString(), &m_upwindingParams.epsC1PPU ). -// setApplyDefaultValue( 1e-10 ). -// setInputFlag( InputFlags::OPTIONAL ). -// setDescription( "Tolerance for C1-PPU smoothing" ); } FluxApproximationBase::CatalogInterface::CatalogType & diff --git a/src/coreComponents/finiteVolume/FluxApproximationBase.hpp b/src/coreComponents/finiteVolume/FluxApproximationBase.hpp index a26320b39c3..fafce71f6ff 100644 --- a/src/coreComponents/finiteVolume/FluxApproximationBase.hpp +++ b/src/coreComponents/finiteVolume/FluxApproximationBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -38,6 +39,7 @@ enum class UpwindingScheme : integer { PPU, ///< PPU upwinding C1PPU, ///< C1-PPU upwinding from https://doi.org/10.1016/j.advwatres.2017.07.028 + IHU ///< IHU as in https://link.springer.com/content/pdf/10.1007/s10596-019-09835-6.pdf }; /** @@ -45,7 +47,8 @@ enum class UpwindingScheme : integer */ ENUM_STRINGS( UpwindingScheme, "PPU", - "C1PPU" ); + "C1PPU", + "IHU" ); /** * @struct UpwindingParameters @@ -54,7 +57,7 @@ ENUM_STRINGS( UpwindingScheme, */ struct UpwindingParameters { - /// PPU or C1-PPU + /// PPU or C1-PPU or IHU UpwindingScheme upwindingScheme; /// C1-PPU smoothing tolerance @@ -130,11 +133,9 @@ class FluxApproximationBase : public dataRepository::Group * @brief Add a new fracture stencil. * @param[in,out] mesh the mesh on which to add the fracture stencil * @param[in] faceElementRegionName the face element region name - * @param[in] initFields if true initialize physical fields, like pressure */ virtual void addToFractureStencil( MeshLevel & mesh, - string const & faceElementRegionName, - bool const initFields ) const = 0; + string const & faceElementRegionName ) const = 0; /** * @brief Add a new embedded fracture stencil. diff --git a/src/coreComponents/finiteVolume/HybridMimeticDiscretization.cpp b/src/coreComponents/finiteVolume/HybridMimeticDiscretization.cpp index 35d2149a50a..f9740cbb547 100644 --- a/src/coreComponents/finiteVolume/HybridMimeticDiscretization.cpp +++ b/src/coreComponents/finiteVolume/HybridMimeticDiscretization.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/HybridMimeticDiscretization.hpp b/src/coreComponents/finiteVolume/HybridMimeticDiscretization.hpp index 3aa80049dd1..c5bad903c66 100644 --- a/src/coreComponents/finiteVolume/HybridMimeticDiscretization.hpp +++ b/src/coreComponents/finiteVolume/HybridMimeticDiscretization.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/MimeticInnerProductDispatch.hpp b/src/coreComponents/finiteVolume/MimeticInnerProductDispatch.hpp index 136637b7534..d9362edd0a3 100644 --- a/src/coreComponents/finiteVolume/MimeticInnerProductDispatch.hpp +++ b/src/coreComponents/finiteVolume/MimeticInnerProductDispatch.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/ProjectionEDFMHelper.cpp b/src/coreComponents/finiteVolume/ProjectionEDFMHelper.cpp index c9e9769125b..ed477300ff0 100644 --- a/src/coreComponents/finiteVolume/ProjectionEDFMHelper.cpp +++ b/src/coreComponents/finiteVolume/ProjectionEDFMHelper.cpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #include "ProjectionEDFMHelper.hpp" #include "mesh/MeshLevel.hpp" #include "finiteVolume/CellElementStencilTPFA.hpp" diff --git a/src/coreComponents/finiteVolume/ProjectionEDFMHelper.hpp b/src/coreComponents/finiteVolume/ProjectionEDFMHelper.hpp index 54c72bfb18c..ac044dcf10c 100644 --- a/src/coreComponents/finiteVolume/ProjectionEDFMHelper.hpp +++ b/src/coreComponents/finiteVolume/ProjectionEDFMHelper.hpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #ifndef GEOS_FINITEVOLUME_PROJECTIONEDFMHELPER_HPP_ #define GEOS_FINITEVOLUME_PROJECTIONEDFMHELPER_HPP_ diff --git a/src/coreComponents/finiteVolume/StencilBase.hpp b/src/coreComponents/finiteVolume/StencilBase.hpp index 7113f1d148e..cf6fb20eebe 100644 --- a/src/coreComponents/finiteVolume/StencilBase.hpp +++ b/src/coreComponents/finiteVolume/StencilBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -13,7 +14,7 @@ */ /** - * @file CellElementStencilTPFA.hpp + * @file StencilBase.hpp */ #ifndef GEOS_FINITEVOLUME_STENCILBASE_HPP_ diff --git a/src/coreComponents/finiteVolume/SurfaceElementStencil.cpp b/src/coreComponents/finiteVolume/SurfaceElementStencil.cpp index 8b3d3c56be2..2a030dff1eb 100644 --- a/src/coreComponents/finiteVolume/SurfaceElementStencil.cpp +++ b/src/coreComponents/finiteVolume/SurfaceElementStencil.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/SurfaceElementStencil.hpp b/src/coreComponents/finiteVolume/SurfaceElementStencil.hpp index 62f07d7dc51..69b2a85c08a 100644 --- a/src/coreComponents/finiteVolume/SurfaceElementStencil.hpp +++ b/src/coreComponents/finiteVolume/SurfaceElementStencil.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -24,25 +25,6 @@ namespace geos { -/// @cond DO_NOT_DOCUMENT -// TODO remove! This option allows for the creation of new mass inside a newly -// created FaceElement. The new mass will be equal to: -// creationMass = defaultDensity * defaultAperture * faceArea. -// If 0, then the beginning of step density is artificially set to zero...which -// may cause some newton convergence problems. -#define ALLOW_CREATION_MASS 1 - - -// TODO remove! This option sets the pressure in a newly created FaceElement to -// be the lowest value of all attached non-new FaceElements. -#define SET_CREATION_PRESSURE 1 - -// TODO remove! This option sets the nodal displacements attached a newly -// created FaceElement to some scalar fraction of the aperture of the -// lowest attached non-new FaceElements. -#define SET_CREATION_DISPLACEMENT 0 -/// @endcond - /** * @brief Describes properties of SurfaceElementStencil. * diff --git a/src/coreComponents/finiteVolume/TwoPointFluxApproximation.cpp b/src/coreComponents/finiteVolume/TwoPointFluxApproximation.cpp index 8e96749683a..25c128770fa 100644 --- a/src/coreComponents/finiteVolume/TwoPointFluxApproximation.cpp +++ b/src/coreComponents/finiteVolume/TwoPointFluxApproximation.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -282,11 +283,6 @@ void TwoPointFluxApproximation::addFractureFractureConnectionsDFM( MeshLevel & m hydraulicAperture, fractureRegionIndex, elemGhostRank, -#if SET_CREATION_DISPLACEMENT==1 - faceToNodesMap, - totalDisplacement, - aperture, -#endif &fractureStencil] ( localIndex const k ) { @@ -365,237 +361,6 @@ void TwoPointFluxApproximation::addFractureFractureConnectionsDFM( MeshLevel & m } ); } -void TwoPointFluxApproximation::initNewFractureFieldsDFM( MeshLevel & mesh, - string const & faceElementRegionName ) const -{ - // TODO Note that all of this initialization should be performed elsewhere. - // This is just here because it was convenient, but it is not appropriate - // to have physics based initialization in the flux approximator. - -#if !defined(SET_CREATION_DISPLACEMENT) - static_assert( true, "must have SET_CREATION_DISPLACEMENT defined" ); -#endif - -#if !defined(ALLOW_CREATION_MASS) - static_assert( true, "must have ALLOW_CREATION_MASS defined" ); -#endif - -#if !defined(SET_CREATION_PRESSURE) - static_assert( true, "must have SET_CREATION_PRESSURE defined" ); -#endif - - ElementRegionManager & elemManager = mesh.getElemManager(); - ElementRegionManager::ElementViewAccessor< arrayView1d< integer const > > const elemGhostRank = - elemManager.constructArrayViewAccessor< integer, 1 >( ObjectManagerBase::viewKeyStruct::ghostRankString() ); - - SurfaceElementRegion & fractureRegion = elemManager.getRegion< SurfaceElementRegion >( faceElementRegionName ); - localIndex const fractureRegionIndex = fractureRegion.getIndexInParent(); - FaceElementSubRegion & fractureSubRegion = fractureRegion.getUniqueSubRegion< FaceElementSubRegion >(); - ArrayOfArraysView< localIndex const > const & fractureConnectorsToFaceElements = fractureSubRegion.m_2dFaceTo2dElems.toViewConst(); -#if SET_CREATION_DISPLACEMENT==1 - NodeManager & nodeManager = mesh.getNodeManager(); - FaceManager const & faceManager = mesh.getFaceManager(); - ArrayOfArraysView< localIndex const > const & faceToNodesMap = faceManager.nodeList(); - FaceElementSubRegion::FaceMapType const & faceMap = fractureSubRegion.faceList(); - array2dLayoutIncrDisplacementConst const incrementalDisplacement = - nodeManager.getField< fields::solidMechanics::incrementalDisplacement >(); - array2dLayoutTotalDisplacementConst const totalDisplacement = - nodeManager.getField< fields::solidMechanics::totalDisplacement >(); - arrayView1d< real64 > const aperture = fractureSubRegion.getReference< array1d< real64 > >( "elementAperture" ); -#endif - -#ifdef GEOSX_USE_SEPARATION_COEFFICIENT - arrayView1d< real64 > const apertureF = fractureSubRegion.getReference< array1d< real64 > >( "apertureAtFailure" ); -#endif - -#if ALLOW_CREATION_MASS==0 - arrayView1d< real64 > const dens = fractureSubRegion.getReference< array1d< real64 > >( "density_n" ); -#endif - -#if SET_CREATION_PRESSURE==1 - arrayView1d< real64 > const fluidPressure_n = fractureSubRegion.getField< fields::flow::pressure_n >(); - arrayView1d< real64 > const fluidPressure = fractureSubRegion.getField< fields::flow::pressure >(); - // Set the new face elements to some unphysical numbers to make sure they get set by the following routines. - SortedArrayView< localIndex const > const newFaceElements = fractureSubRegion.m_newFaceElements.toViewConst(); - - forAll< serialPolicy >( fractureSubRegion.m_newFaceElements.size(), [=]( localIndex const k ) - { - localIndex const kfe = newFaceElements[k]; - fluidPressure[kfe] = 1.0e99; -#ifdef GEOSX_USE_SEPARATION_COEFFICIENT - apertureF[kfe] = aperture[kfe]; -#endif -#if SET_CREATION_DISPLACEMENT==1 - aperture[kfe] = 1.0e99; -#endif - } ); - -#endif // SET_CREATION_PRESSURE - - SortedArray< localIndex > allNewElems; - allNewElems.insert( fractureSubRegion.m_newFaceElements.begin(), - fractureSubRegion.m_newFaceElements.end() ); - SortedArrayView< localIndex const > const recalculateFractureConnectorEdges = fractureSubRegion.m_recalculateConnectionsFor2dFaces.toViewConst(); - - // add new connectors/connections between face elements to the fracture stencil - forAll< serialPolicy >( recalculateFractureConnectorEdges.size(), - [ &allNewElems, - recalculateFractureConnectorEdges, - fractureConnectorsToFaceElements, - fractureRegionIndex, - elemGhostRank, - fluidPressure, - fluidPressure_n, -#if SET_CREATION_DISPLACEMENT==1 - faceToNodesMap, - totalDisplacement, - aperture, -#endif - &fractureSubRegion - ] - ( localIndex const k ) - { - localIndex const fci = recalculateFractureConnectorEdges[k]; - localIndex const numElems = fractureConnectorsToFaceElements.sizeOfArray( fci ); -#if SET_CREATION_PRESSURE==1 - real64 initialPressure = 1.0e99; -#endif -#if SET_CREATION_DISPLACEMENT==1 - real64 initialAperture = 1.0e99; -#endif - SortedArray< localIndex > newElems; - bool containsLocalElement = false; - - // loop over all face elements attached to the connector and add them to the stencil - for( localIndex kfe=0; kfe( totalDisplacement[node0] ) ) > 1.0e-99 && - LvArray::math::abs( LvArray::tensorOps::l2Norm< 3 >( totalDisplacement[node1] ) ) > 1.0e-99 ) - { - zeroDisp = false; - } - } - if( zeroDisp ) - { - aperture[newElemIndex] = 0; - } -#endif - } - } ); - - SortedArray< localIndex > touchedNodes; - forAll< serialPolicy >( allNewElems.size(), - [ &allNewElems - , fluidPressure - , fluidPressure_n -#if SET_CREATION_DISPLACEMENT==1 - , aperture - , faceMap - , faceNormal - , faceToNodesMap - , &touchedNodes - , incrementalDisplacement - , totalDisplacement - , this -#endif - ]( localIndex const k ) - { - localIndex const newElemIndex = allNewElems[k]; - // if the value of pressure was not set, then set it to zero and punt. - if( fluidPressure[newElemIndex] > 1.0e98 ) - { - fluidPressure[newElemIndex] = 0.0; - } - fluidPressure_n[newElemIndex] = fluidPressure[newElemIndex]; -#if ALLOW_CREATION_MASS==0 - // set the initial density of the face element to 0 to enforce mass conservation ( i.e. no creation of mass) - dens[newElemIndex] = 0.0; -#endif -#if SET_CREATION_DISPLACEMENT==1 - // If the aperture has been set, then we can set the estimate of displacements. - if( aperture[newElemIndex] < 1e98 ) - { - localIndex const faceIndex0 = faceMap( newElemIndex, 0 ); - localIndex const faceIndex1 = faceMap( newElemIndex, 1 ); - - real64 newDisp[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3( faceNormal[ faceIndex0 ] ); - LvArray::tensorOps::scale< 3 >( newDisp, -aperture[newElemIndex] ); - localIndex const numNodesPerFace = faceToNodesMap.sizeOfArray( faceIndex0 ); - for( localIndex a=0; a( incrementalDisplacement[node0], newDisp ); - LvArray::tensorOps::add< 3 >( totalDisplacement[node0], newDisp ); - LvArray::tensorOps::subtract< 3 >( incrementalDisplacement[node1], newDisp ); - LvArray::tensorOps::subtract< 3 >( totalDisplacement[node1], newDisp ); - } - } - } - if( this->getLogLevel() > 1 ) - { - printf( "New elem index, init aper, init press = %4ld, %4.2e, %4.2e \n", - newElemIndex, - aperture[newElemIndex], - fluidPressure[newElemIndex] ); - } -#endif - } ); -} - void TwoPointFluxApproximation::cleanMatrixMatrixConnectionsDFM( MeshLevel & mesh, string const & faceElementRegionName ) const { @@ -619,6 +384,7 @@ void TwoPointFluxApproximation::cleanMatrixMatrixConnectionsDFM( MeshLevel & mes // This is there to shut off previously connected cells // that are not connected anymore due to dynamic fracturing. cellStencil.zero( faceMap[kfe][0] ); + cellStencil.zero( faceMap[kfe][1] ); } ); } @@ -653,14 +419,14 @@ void TwoPointFluxApproximation::addFractureMatrixConnectionsDFM( MeshLevel & mes SurfaceElementRegion & fractureRegion = elemManager.getRegion< SurfaceElementRegion >( faceElementRegionName ); localIndex const fractureRegionIndex = fractureRegion.getIndexInParent(); FaceElementSubRegion & fractureSubRegion = fractureRegion.getUniqueSubRegion< FaceElementSubRegion >(); - OrderedVariableToManyElementRelation const & elems2dToElems3d = fractureSubRegion.getToCellRelation(); + FixedToManyElementRelation const & elems2dToElems3d = fractureSubRegion.getToCellRelation(); SortedArrayView< localIndex const > const new2dElems = fractureSubRegion.m_newFaceElements.toViewConst(); FaceElementSubRegion::FaceMapType const & faceMap = fractureSubRegion.faceList(); - ArrayOfArraysView< localIndex const > elemRegionList = elems2dToElems3d.m_toElementRegion.toViewConst(); - ArrayOfArraysView< localIndex const > elemSubRegionList = elems2dToElems3d.m_toElementSubRegion.toViewConst(); - ArrayOfArraysView< localIndex const > elemList = elems2dToElems3d.m_toElementIndex.toViewConst(); + arrayView2d< localIndex const > const elemRegionList = elems2dToElems3d.m_toElementRegion.toViewConst(); + arrayView2d< localIndex const > const elemSubRegionList = elems2dToElems3d.m_toElementSubRegion.toViewConst(); + arrayView2d< localIndex const > const elemList = elems2dToElems3d.m_toElementIndex.toViewConst(); // reserve memory for the connections of this region if( cellStencil.size() != 0 ) @@ -682,7 +448,6 @@ void TwoPointFluxApproximation::addFractureMatrixConnectionsDFM( MeshLevel & mes forAll< serialPolicy >( new2dElems.size(), [ new2dElems, - &elems2dToElems3d, &faceToCellStencil, &faceMap, elemRegionList, @@ -700,7 +465,7 @@ void TwoPointFluxApproximation::addFractureMatrixConnectionsDFM( MeshLevel & mes { localIndex const kfe = new2dElems[k]; { - localIndex const numElems = elems2dToElems3d.m_toElementSubRegion.sizeOfArray( kfe ); + localIndex const numElems = 2; GEOS_ERROR_IF( numElems > maxElems, "Max stencil size exceeded by fracture-cell connector " << kfe ); @@ -761,17 +526,11 @@ void TwoPointFluxApproximation::addFractureMatrixConnectionsDFM( MeshLevel & mes } void TwoPointFluxApproximation::addToFractureStencil( MeshLevel & mesh, - string const & faceElementRegionName, - bool const initFields ) const + string const & faceElementRegionName ) const { this->addFractureFractureConnectionsDFM( mesh, faceElementRegionName ); this->cleanMatrixMatrixConnectionsDFM( mesh, faceElementRegionName ); this->addFractureMatrixConnectionsDFM( mesh, faceElementRegionName ); - - if( initFields ) - { - this->initNewFractureFieldsDFM( mesh, faceElementRegionName ); - } } void TwoPointFluxApproximation::addFractureMatrixConnectionsEDFM( MeshLevel & mesh, @@ -832,7 +591,7 @@ void TwoPointFluxApproximation::addFractureMatrixConnectionsEDFM( MeshLevel & me stencilCellsRegionIndex[1] = fractureRegionIndex; stencilCellsSubRegionIndex[1] = 0; stencilCellsIndex[1] = kes; - stencilWeights[1] = 4. * faceArea[fractureRegionIndex] / hydraulicAperture[fractureRegionIndex][0][kes]; + stencilWeights[1] = 4. * faceArea[kes] / hydraulicAperture[fractureRegionIndex][0][kes]; edfmStencil.add( 2, stencilCellsRegionIndex.data(), @@ -1196,7 +955,7 @@ void TwoPointFluxApproximation::computeAquiferStencil( DomainPartition & domain, globalSumFaceAreas.data(), localSumFaceAreas.size(), MpiWrapper::getMpiOp( MpiWrapper::Reduction::Sum ), - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); // Step 3: compute the face area fraction for each connection, and insert into boundary stencil diff --git a/src/coreComponents/finiteVolume/TwoPointFluxApproximation.hpp b/src/coreComponents/finiteVolume/TwoPointFluxApproximation.hpp index 8820dd4a388..53be3ad3e04 100644 --- a/src/coreComponents/finiteVolume/TwoPointFluxApproximation.hpp +++ b/src/coreComponents/finiteVolume/TwoPointFluxApproximation.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -73,8 +74,7 @@ class TwoPointFluxApproximation : public FluxApproximationBase virtual void registerFractureStencil( Group & stencilGroup ) const override; virtual void addToFractureStencil( MeshLevel & mesh, - string const & faceElementRegionName, - bool const initFields ) const override; + string const & faceElementRegionName ) const override; virtual void registerBoundaryStencil( Group & stencilGroup, string const & setName ) const override; diff --git a/src/coreComponents/finiteVolume/docs/StencilModel.plantuml b/src/coreComponents/finiteVolume/docs/StencilModel.plantuml new file mode 100644 index 00000000000..fa7b49c49b4 --- /dev/null +++ b/src/coreComponents/finiteVolume/docs/StencilModel.plantuml @@ -0,0 +1,362 @@ +@startuml StencilModel + +' left to right direction + +skinparam classAttributeIconSize 0 +skinparam groupInheritance 0 + + + + +' ############################# +' # external classes +' ############################# +class array2d +hide array2d + + + +' ############################# +' # Stencil traits templates +' ############################# + + +package "Stencil traits" <> { + class StencilTraits << template >> { + CONTAINER : class + MAX_NUM_POINTS_IN_FLUX : localIndex + MAX_STENCIL_SIZE : localIndex + MAX_NUM_CONNECTIONS : localIndex + } + + map TwoPointStencilTraits { + CONTAINER => array2d + MAX_NUM_POINTS_IN_FLUX => 2 + MAX_STENCIL_SIZE => 2 + MAX_NUM_CONNECTIONS => 1 + } + map CellElementStencilMPFATraits { + CONTAINER => ArrayOfArrays + MAX_NUM_POINTS_IN_FLUX => 2 + MAX_STENCIL_SIZE => 18 + MAX_NUM_CONNECTIONS => 1 + } + map SurfaceElementStencilTraits { + CONTAINER => ArrayOfArrays + MAX_NUM_POINTS_IN_FLUX => 6 + MAX_STENCIL_SIZE => 6 + MAX_NUM_CONNECTIONS => 15 + } + + StencilTraits <|--u TwoPointStencilTraits : << template instance >> + StencilTraits <|--u CellElementStencilMPFATraits : << template instance >> + StencilTraits <|--u SurfaceElementStencilTraits : << template instance >> +} + + +' ############################# +' # Stencil classes +' ############################# +class StencilBase< TRAITS > { + - m_elementRegionIndices : IndexContainerView + - m_elementSubRegionIndices : IndexContainerView + - m_elementIndices : IndexContainerView + - m_weights : WeightContainerView + - m_connectorIndices + + getElementRegionIndices() : IndexContainerView + getElementSubRegionIndices() : IndexContainerView + getElementIndices() : IndexContainerView + getWeights() : WeightContainerView + + {abstract} reserve() : void + {abstract} add(N, elemRegionIds[N], elemSubRegionIds[N], elemIds[N], weights[N], connIndex) : void + {abstract} move() : void + {abstract} zero() : bool + {abstract} size() : localIndex + setName() : void +} +note right : Provides management of the interior stencil points +StencilTraits <|-d- StencilBase : TRAITS : StencilTraits + + +class CellElementStencilTPFA { + createKernelWrapper() : CellElementStencilTPFAWrapper + addVectors( transMultipler, geomStabilizationCoef faceNormal[3], cellToFace[2][3] ) +} +note left : Provides management of the interior stencil points when using Two-Point flux approximation. +StencilBase <|-- CellElementStencilTPFA : << TRAITS : TwoPointStencilTraits >> + + +class BoundaryStencil { + createKernelWrapper() : BoundaryStencilWrapper + addVectors( transMultipler, faceNormal[3], cellToFace[2][3] ) +} +note right : Provides management of the boundary stencil points(stencils used to prescribe boundary conditions on domain boundaries, i.e. faces) +StencilBase <|-- BoundaryStencil : << TRAITS : TwoPointStencilTraits >> + + +class CellElementStencilMPFA { +} +note right : Provides management of the interior stencil points when using a Multi-point flux approximation. +StencilBase <|-- CellElementStencilMPFA : << TRAITS : CellElementStencilMPFATraits >> + + +class FaceElementToCellStencil { + createKernelWrapper() : FaceElementToCellStencilWrapper + addVectors( transMultipler, faceNormal[3], cellToFace[2][3] ) +} +note right : Provides management of the interior stencil points for a face elements when using Two-Point flux approximation. +StencilBase <|-- FaceElementToCellStencil : << TRAITS : TwoPointStencilTraits >> + + +class EmbeddedSurfaceToCellStencil { + createKernelWrapper() : EmbeddedSurfaceToCellStencilWrapper +} +note right : Provides management of the interior stencil points for a face elements when using Two-Point flux approximation. +StencilBase <|-- EmbeddedSurfaceToCellStencil : << TRAITS : TwoPointStencilTraits >> + + +class SurfaceElementStencil { + createKernelWrapper() : SurfaceElementStencilWrapper +} +note right : Provides management of the interior stencil points for a face elements when using Two-Point flux approximation. +StencilBase <|-- SurfaceElementStencil : << TRAITS : SurfaceElementStencilTraits >> + + +CellElementStencilTPFA -[hidden]u- BoundaryStencil +BoundaryStencil -[hidden]u- CellElementStencilMPFA +CellElementStencilMPFA -[hidden]u- FaceElementToCellStencil +FaceElementToCellStencil -[hidden]u- EmbeddedSurfaceToCellStencil +EmbeddedSurfaceToCellStencil -[hidden]u- SurfaceElementStencil + + +' ############################# +' # Stencil Wrapper classes +' ############################# +class StencilWrapperBase< TRAITS > { + - m_elementRegionIndices : IndexContainerView + - m_elementSubRegionIndices : IndexContainerView + - m_elementIndices : IndexContainerView + - m_weights : WeightContainerView + + getElementRegionIndices() : IndexContainerView + getElementSubRegionIndices() : IndexContainerView + getElementIndices() : IndexContainerView + getWeights() : WeightContainerView + + void {abstract} computeWeights(iconn, coefficient, weight) +} +note right of StencilWrapperBase + Class to provide access to the computation of stencil weights that may be called from a kernel function. +end note +note left of StencilWrapperBase::"computeWeights(iconn, coefficient, weight, [...])" + Present in the inheriting classes with different signatures. + Compute transmissibility for the "iconn" cell-cell connection taking the "coefficient" (= permeability) and the stencil value into account to compute "weight": + transmissibility = stencilWeight * permeability +end note +StencilTraits <|-d- StencilWrapperBase : TRAITS : StencilTraits + + +class BoundaryStencilWrapper { + - m_faceNormal : arrayView2D< real64 > + - m_cellToFaceVec : arrayView2D< real64 > + - m_weightMultiplier : arrayView2D< real64 > + + void computeWeights( iconn, coefficient, &weight, ... ) +} +note right : Provides access to the boundary stencil that may be called from a kernel function. +StencilWrapperBase <|-- BoundaryStencilWrapper : << TRAITS : TwoPointStencilTraits >> + + +class CellElementStencilTPFAWrapper { + m_faceNormal : arrayView2d< real64 > + m_cellToFaceVec : arrayView3d< real64 > + m_transMultiplier : arrayView1d< real64 > + m_geometricStabilizationCoef : arrayView1d< real64 > + + void computeWeights( iconn, coefficient, &weight[1][2], ... ) +} +note right : Provides access to the cellElement stencil that may be called from a kernel function. +StencilWrapperBase <|-- CellElementStencilTPFAWrapper : << TRAITS : TwoPointStencilTraits >> + + +class FaceElementToCellStencilWrapper { + m_faceNormal : arrayView2d< real64 > + m_cellToFaceVec : arrayView3d< real64 > + m_transMultiplier : arrayView1d< real64 > + + void computeWeights( iconn, coefficient, &weight[1][2], ... ) +} +note right : Provides access to the FaceElementToCellStencil that may be called from a kernel function. +StencilWrapperBase <|-- FaceElementToCellStencilWrapper : << TRAITS : TwoPointStencilTraits >> + + +class SurfaceElementStencilWrapper { + m_cellCenterToEdgeCenters ArrayOfArraysView + m_meanPermCoefficient real64 + + void computeWeights( iconn, coefficient, &weight[1][2], ... ) +} +note right : Provides access to the SurfaceElementStencil that may be called from a kernel function. +StencilWrapperBase <|-- SurfaceElementStencilWrapper : << TRAITS : SurfaceElementStencilTraits >> + + +class EmbeddedSurfaceToCellStencilWrapper { + void computeWeights( iconn, coefficient, &weight[1][2], ... ) +} +note right : Provide access to the EmbeddedSurfaceToCellStencil that may be called from a kernel function. +StencilWrapperBase <|-- EmbeddedSurfaceToCellStencilWrapper : << TRAITS : TwoPointStencilTraits >> + + +BoundaryStencilWrapper -[hidden]down- CellElementStencilTPFAWrapper +CellElementStencilTPFAWrapper -[hidden]down- FaceElementToCellStencilWrapper +FaceElementToCellStencilWrapper -[hidden]down- SurfaceElementStencilWrapper +SurfaceElementStencilWrapper -[hidden]down- EmbeddedSurfaceToCellStencilWrapper + + +' ############################# +' # Physics solver classes +' ############################# + + +class SinglePhaseFVM { + assembleFluxTerms( dt, domain ) +} + +package singlePhaseFVMKernels { + + class FaceBasedAssemblyKernelBase { + - m_rankOffset : globalIndex + - m_dt : real64 + - m_permeability : arrayView3d< real64 > + - m_pres : arrayView1d< real64 > + - m_dens : arrayView2d< real64 > + - ... + } + + class FaceBasedAssemblyKernel< STENCIL_WRAPPER > { + {static} launch(int numConnections, FaceBasedAssemblyKernel kernel) + setup(localIndex iconn, StackVariables & stack) + computeFlux(localIndex iconn, StackVariables & stack) + complete(localIndex iconn, StackVariables & stack) + } + note left: Define the interface for the assembly kernel in charge of flux terms (there are more classes of this type) + note right of FaceBasedAssemblyKernel::launch + Performs the kernel launch: setup(), computeFlux(), complete() + end note + note right of FaceBasedAssemblyKernel::computeFlux + Compute the local flux contributions. + - Depends on StencilWrapperBase::computeWeights() to compute the transmissibility for the current timestep (because permeability can change) + end note + FaceBasedAssemblyKernelBase <|-- FaceBasedAssemblyKernel + FaceBasedAssemblyKernel *-- StencilWrapperBase : contains a << STENCIL_WRAPPER : StencilWrapperBase >> + + class StackVariables { + - stencilSize : localIndex + - numFluxElems : localIndex + - transmissibility : real64[][2] + - dTrans_dPres : real64[][2] + - dofColIndices : stackArray1d< globalIndex > + - localFlux : stackArray1d< real64 > + - localFluxJacobian : stackArray2d< real64 > + } + FaceBasedAssemblyKernel ..> StackVariables : depends on + + class FaceBasedAssemblyKernelFactory< STENCIL_WRAPPER > { + {static} createAndLaunch([...], STENCIL_WRAPPER stencilWrapper, [...]) + } + note right of FaceBasedAssemblyKernelFactory::createAndLaunch + Create and call a FaceBasedAssemblyKernel after the StencilWrapperBase + end note + FaceBasedAssemblyKernelFactory ..> FaceBasedAssemblyKernel : creates a + FaceBasedAssemblyKernelFactory ..> StencilWrapperBase : depends on << STENCIL_WRAPPER : StencilWrapperBase >> + SinglePhaseFVM::assembleFluxTerms ..> FaceBasedAssemblyKernelFactory : launches + +} +note top of singlePhaseFVMKernels: Namespace that groups device kernel classes for the SinglePhaseFVM physics solver + + +' ############################# +' # FIELDS +' ############################# + + +package fields { + +' class ghostRank +' class elementVolume + + package permeability { + class permeability + class permeabilityMultiplier +' class dPerm_dPressure + } + note "constitutive/permeability/PermeabilityFields.hpp" as permeabilityN + permeabilityN .. permeability + + package flow { + class pressure +' class initialPressure +' class deltaPressure + class temperature +' class netToGross +' class deltaVolume +' class gravityCoefficient + + class transMultiplier + note right of transMultiplier : Permeability multiplier in transmissibility calculation + } + note "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" as flowN + flowN .. flow +} +note top of fields : mesh/MeshFields.hpp + + +' ############################# +' # Flux classes +' ############################# + + +class FluxApproximationBase { + initializePostInitialConditionsPreSubGroups() + {abstract} computeCellStencil( mesh ) + {abstract} computeBoundaryStencil( mesh ) + {abstract} computeAquiferStencil( domain, mesh ) + [...] +} +note top of FluxApproximationBase + Base class for various flux approximation classes. + Stores the main and boundary stencils, construction is implemented in derived classes. +end note +note right of FluxApproximationBase::initializePostInitialConditionsPreSubGroups + Call : + - computeCellStencil() + - computeBoundaryStencil() + - computeAquiferStencil() +end note +note right of FluxApproximationBase::computeCellStencil + Compute the "Main stencil" **(=CellElementStencilXPFA)** for cell-cell fluxes. +end note +note right of FluxApproximationBase::computeBoundaryStencil + Boundary stencils are for Dirichlet boundary conditions +end note +note right of FluxApproximationBase::computeAquiferStencil + Called for each "Aquifer" +end note + +class TwoPointFluxApproximation { + computeCellStencil( mesh ) + computeBoundaryStencil( mesh ) + computeAquiferStencil( domain, mesh ) + [...] +} +FluxApproximationBase <|-- TwoPointFluxApproximation : creates a +CellElementStencilTPFA <..r... TwoPointFluxApproximation::computeCellStencil : computeCellStencil()\nwrites in + + +@enduml \ No newline at end of file diff --git a/src/coreComponents/finiteVolume/mimeticInnerProducts/BdVLMInnerProduct.hpp b/src/coreComponents/finiteVolume/mimeticInnerProducts/BdVLMInnerProduct.hpp index 5315503aef3..5bde9c3a3c3 100644 --- a/src/coreComponents/finiteVolume/mimeticInnerProducts/BdVLMInnerProduct.hpp +++ b/src/coreComponents/finiteVolume/mimeticInnerProducts/BdVLMInnerProduct.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/mimeticInnerProducts/MimeticInnerProductBase.hpp b/src/coreComponents/finiteVolume/mimeticInnerProducts/MimeticInnerProductBase.hpp index ac2971725d6..2c905c1713a 100644 --- a/src/coreComponents/finiteVolume/mimeticInnerProducts/MimeticInnerProductBase.hpp +++ b/src/coreComponents/finiteVolume/mimeticInnerProducts/MimeticInnerProductBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/mimeticInnerProducts/MimeticInnerProductHelpers.hpp b/src/coreComponents/finiteVolume/mimeticInnerProducts/MimeticInnerProductHelpers.hpp index 527bd134136..7eb8f5558c6 100644 --- a/src/coreComponents/finiteVolume/mimeticInnerProducts/MimeticInnerProductHelpers.hpp +++ b/src/coreComponents/finiteVolume/mimeticInnerProducts/MimeticInnerProductHelpers.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/mimeticInnerProducts/QuasiRTInnerProduct.hpp b/src/coreComponents/finiteVolume/mimeticInnerProducts/QuasiRTInnerProduct.hpp index 4987e0d768f..e125659ec8e 100644 --- a/src/coreComponents/finiteVolume/mimeticInnerProducts/QuasiRTInnerProduct.hpp +++ b/src/coreComponents/finiteVolume/mimeticInnerProducts/QuasiRTInnerProduct.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/mimeticInnerProducts/QuasiTPFAInnerProduct.hpp b/src/coreComponents/finiteVolume/mimeticInnerProducts/QuasiTPFAInnerProduct.hpp index 701529a924c..4f481e7181b 100644 --- a/src/coreComponents/finiteVolume/mimeticInnerProducts/QuasiTPFAInnerProduct.hpp +++ b/src/coreComponents/finiteVolume/mimeticInnerProducts/QuasiTPFAInnerProduct.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/mimeticInnerProducts/SimpleInnerProduct.hpp b/src/coreComponents/finiteVolume/mimeticInnerProducts/SimpleInnerProduct.hpp index 8b6c8089ab1..da7f4b2b330 100644 --- a/src/coreComponents/finiteVolume/mimeticInnerProducts/SimpleInnerProduct.hpp +++ b/src/coreComponents/finiteVolume/mimeticInnerProducts/SimpleInnerProduct.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/finiteVolume/mimeticInnerProducts/TPFAInnerProduct.hpp b/src/coreComponents/finiteVolume/mimeticInnerProducts/TPFAInnerProduct.hpp index d15dab34478..dde1042e41b 100644 --- a/src/coreComponents/finiteVolume/mimeticInnerProducts/TPFAInnerProduct.hpp +++ b/src/coreComponents/finiteVolume/mimeticInnerProducts/TPFAInnerProduct.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/functions/CMakeLists.txt b/src/coreComponents/functions/CMakeLists.txt index 01f8d6fed86..8fb39ce419d 100644 --- a/src/coreComponents/functions/CMakeLists.txt +++ b/src/coreComponents/functions/CMakeLists.txt @@ -1,3 +1,22 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package : functions + +Contains classes for storing and computing arbitrary N-dimensional functions. +#]] + # # Specify all headers # @@ -27,21 +46,27 @@ if( ENABLE_MATHPRESSO ) endif() -set( dependencyList ${parallelDeps} codingUtilities dataRepository fileIO ) +set( dependencyList ${parallelDeps} dataRepository ) if( ENABLE_MATHPRESSO ) list( APPEND dependencyList mathpresso ) endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) + blt_add_library( NAME functions SOURCES ${functions_sources} HEADERS ${functions_headers} - DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} + DEPENDS_ON ${decoratedDependencies} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} ) target_include_directories( functions PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +install( TARGETS functions LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) + if( GEOS_ENABLE_TESTS ) add_subdirectory( unitTests ) endif() diff --git a/src/coreComponents/functions/CompositeFunction.cpp b/src/coreComponents/functions/CompositeFunction.cpp index b47db537e68..58cc844a106 100644 --- a/src/coreComponents/functions/CompositeFunction.cpp +++ b/src/coreComponents/functions/CompositeFunction.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/functions/CompositeFunction.hpp b/src/coreComponents/functions/CompositeFunction.hpp index b483c2e63eb..be055245814 100644 --- a/src/coreComponents/functions/CompositeFunction.hpp +++ b/src/coreComponents/functions/CompositeFunction.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/functions/FunctionBase.cpp b/src/coreComponents/functions/FunctionBase.cpp index 60268960f43..07a831fb05f 100644 --- a/src/coreComponents/functions/FunctionBase.cpp +++ b/src/coreComponents/functions/FunctionBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -64,12 +65,23 @@ real64_array FunctionBase::evaluateStats( dataRepository::Group const & group, { result[0] = std::min( result[0], sub[ii] ); result[1] += sub[ii]; - result[2] = std::max( result[0], sub[ii] ); + result[2] = std::max( result[2], sub[ii] ); } result[1] /= N; return result; } +string const & FunctionBase::getOutputDirectory() +{ + static string outputDirectory; + return outputDirectory; +} +void FunctionBase::setOutputDirectory( string const & dir ) +{ + string & outputDirectory = const_cast< string & >( getOutputDirectory() ); + outputDirectory = dir; +} + } // end of namespace geos diff --git a/src/coreComponents/functions/FunctionBase.hpp b/src/coreComponents/functions/FunctionBase.hpp index 5c2fb4b6eb1..c86033050fd 100644 --- a/src/coreComponents/functions/FunctionBase.hpp +++ b/src/coreComponents/functions/FunctionBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -60,12 +61,6 @@ class FunctionBase : public dataRepository::Group */ virtual ~FunctionBase() override = default; - /** - * @brief Static Factory Catalog Functions - * @return the catalog name - */ - static string catalogName() { return "FunctionBase"; } - /** * @brief Function initialization */ @@ -129,6 +124,17 @@ class FunctionBase : public dataRepository::Group */ void setInputVarNames( string_array inputVarNames ) { m_inputVarNames = std::move( inputVarNames ); } + /** + * @brief Get the output directory for function output + * @return a string containing the output directory + */ + static string const & getOutputDirectory(); + + /** + * @brief Set the output directory for function output + * @param outputDir The output directory + */ + static void setOutputDirectory( string const & outputDir ); protected: /// names for the input variables @@ -148,7 +154,7 @@ class FunctionBase : public dataRepository::Group SortedArrayView< localIndex const > const & set, arrayView1d< real64 > const & result ) const; - virtual void postProcessInput() override { initializeFunction(); } + virtual void postInputInitialization() override { initializeFunction(); } }; diff --git a/src/coreComponents/functions/FunctionManager.cpp b/src/coreComponents/functions/FunctionManager.cpp index 2e532d784f8..0cd5a92ba9c 100644 --- a/src/coreComponents/functions/FunctionManager.cpp +++ b/src/coreComponents/functions/FunctionManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -52,7 +53,7 @@ FunctionManager & FunctionManager::getInstance() Group * FunctionManager::createChild( string const & functionCatalogKey, string const & functionName ) { - GEOS_LOG_RANK_0( " " << functionCatalogKey << ": " << functionName ); + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), functionCatalogKey, functionName ) ); std::unique_ptr< FunctionBase > function = FunctionBase::CatalogInterface::factory( functionCatalogKey, functionName, this ); return &this->registerGroup< FunctionBase >( functionName, std::move( function ) ); } diff --git a/src/coreComponents/functions/FunctionManager.hpp b/src/coreComponents/functions/FunctionManager.hpp index 659dea61c38..dac7ad85b0a 100644 --- a/src/coreComponents/functions/FunctionManager.hpp +++ b/src/coreComponents/functions/FunctionManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/functions/MultivariableTableFunction.cpp b/src/coreComponents/functions/MultivariableTableFunction.cpp index 97136c32f21..4f8db1244bb 100644 --- a/src/coreComponents/functions/MultivariableTableFunction.cpp +++ b/src/coreComponents/functions/MultivariableTableFunction.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/functions/MultivariableTableFunction.hpp b/src/coreComponents/functions/MultivariableTableFunction.hpp index 6d77961aa45..927a020d817 100644 --- a/src/coreComponents/functions/MultivariableTableFunction.hpp +++ b/src/coreComponents/functions/MultivariableTableFunction.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,7 +22,7 @@ #include "FunctionBase.hpp" -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include "LvArray/src/tensorOps.hpp" namespace geos diff --git a/src/coreComponents/functions/MultivariableTableFunctionKernels.hpp b/src/coreComponents/functions/MultivariableTableFunctionKernels.hpp index 53a8163725d..99022f23dc0 100644 --- a/src/coreComponents/functions/MultivariableTableFunctionKernels.hpp +++ b/src/coreComponents/functions/MultivariableTableFunctionKernels.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/functions/SymbolicFunction.cpp b/src/coreComponents/functions/SymbolicFunction.cpp index 53e9879af12..26ae27b1be5 100644 --- a/src/coreComponents/functions/SymbolicFunction.cpp +++ b/src/coreComponents/functions/SymbolicFunction.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/functions/SymbolicFunction.hpp b/src/coreComponents/functions/SymbolicFunction.hpp index c8548edf40b..5f0c3ea79e5 100644 --- a/src/coreComponents/functions/SymbolicFunction.hpp +++ b/src/coreComponents/functions/SymbolicFunction.hpp @@ -2,15 +2,17 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ + #ifndef GEOS_FUNCTIONS_SYMBOLICFUNCTION_HPP_ #define GEOS_FUNCTIONS_SYMBOLICFUNCTION_HPP_ diff --git a/src/coreComponents/functions/TableFunction.cpp b/src/coreComponents/functions/TableFunction.cpp index 0a8751c28ab..74f031fef87 100644 --- a/src/coreComponents/functions/TableFunction.cpp +++ b/src/coreComponents/functions/TableFunction.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,6 @@ #include "TableFunction.hpp" #include "codingUtilities/Parsing.hpp" #include "common/DataTypes.hpp" -#include "fileIO/Outputs/OutputBase.hpp" #include @@ -177,81 +177,13 @@ void TableFunction::checkCoord( real64 const coord, localIndex const dim ) const real64 const upperBound = m_coordinates[dim][m_coordinates.sizeOfArray( dim ) - 1]; GEOS_THROW_IF( coord > upperBound || coord < lowerBound, GEOS_FMT( "{}: Requested {} is out of the table bounds ( lower bound: {} -> upper bound: {} ).", - getDataContext(), units::formatValue( coord, getDimUnit( dim ) ), lowerBound, upperBound ), + getDataContext(), + units::formatValue( coord, getDimUnit( dim ) ), + units::formatValue( lowerBound, getDimUnit( dim ) ), + units::formatValue( upperBound, getDimUnit( dim ) ) ), SimulationError ); } -void TableFunction::print( std::string const & filename ) const -{ - std::ofstream os( joinPath( OutputBase::getOutputDirectory(), filename + ".csv" ) ); - - integer const numDimensions = LvArray::integerConversion< integer >( m_coordinates.size() ); - - if( numDimensions != 2 ) - { - // print header - - for( integer d = 0; d < numDimensions; d++ ) - { - os << units::getDescription( getDimUnit( d )) << ","; - } - os << units::getDescription( m_valueUnit ) << "\n"; - - // print values - - // prepare dividers - std::vector< integer > div( numDimensions ); - div[0] = 1; - for( integer d = 1; d < numDimensions; d++ ) - { - div[d] = div[d-1] * m_coordinates[d-1].size(); - } - // loop through all the values - for( integer v = 0; v < m_values.size(); v++ ) - { - // find coords indices - std::vector< integer > idx( numDimensions ); - integer r = v; - for( integer d = numDimensions-1; d >= 0; d-- ) - { - idx[d] = r / div[d]; - r = r % div[d]; - } - // finally print out in right order - for( integer d = 0; d < numDimensions; d++ ) - { - arraySlice1d< real64 const > const coords = m_coordinates[d]; - os << coords[idx[d]] << ","; - } - os << m_values[v] << "\n"; - } - } - else // numDimensions == 2 - { - arraySlice1d< real64 const > const coordsX = m_coordinates[0]; - arraySlice1d< real64 const > const coordsY = m_coordinates[1]; - integer const nX = coordsX.size(); - integer const nY = coordsY.size(); - os< const coordinates, + arrayView1d< real64 const > const values ) +{ + // prepare dividers + std::vector< integer > div( numDimensions ); + div[0] = 1; + for( integer d = 1; d < numDimensions; d++ ) + { + div[d] = div[d-1] * coordinates[d-1].size(); + } + // loop through all the values + for( integer v = 0; v < values.size(); v++ ) + { + // find coords indices + std::vector< integer > idx( numDimensions ); + integer r = v; + for( integer d = numDimensions-1; d >= 0; d-- ) + { + idx[d] = r / div[d]; + r = r % div[d]; + } + // finally print out in right order + for( integer d = 0; d < numDimensions; d++ ) + { + arraySlice1d< real64 const > const coords = coordinates[d]; + formatterStream << coords[idx[d]] << ","; + } + formatterStream << values[v] << "\n"; + } +} + +void TableFunction::outputPVTTableData( OutputOptions const pvtOutputOpts ) const +{ + if( pvtOutputOpts.writeInLog && this->numDimensions() <= 2 ) + { + TableTextFormatter textFormatter; + GEOS_LOG_RANK_0( textFormatter.toString( *this )); + } + if( pvtOutputOpts.writeCSV || ( pvtOutputOpts.writeInLog && this->numDimensions() >= 3 ) ) + { + string const filename = this->getName(); + std::ofstream logStream( joinPath( FunctionBase::getOutputDirectory(), filename + ".csv" ) ); + GEOS_LOG_RANK_0( GEOS_FMT( "CSV Generated to {}/{}.csv \n", + FunctionBase::getOutputDirectory(), + filename )); + TableCSVFormatter csvFormatter; + logStream << csvFormatter.toString( *this ); + } +} + +template<> +string TableCSVFormatter::toString< TableFunction >( TableFunction const & tableFunction ) const +{ + ArrayOfArraysView< real64 const > const coordinates = tableFunction.getCoordinates(); + arrayView1d< real64 const > const values = tableFunction.getValues(); + units::Unit const valueUnit = tableFunction.getValueUnit(); + std::ostringstream formatterStream; + + integer const numDimensions = LvArray::integerConversion< integer >( coordinates.size() ); + if( numDimensions != 2 ) + { + collectHeaders( formatterStream, tableFunction, numDimensions, valueUnit ); + collectValues( formatterStream, numDimensions, coordinates, values ); + } + else + { + TableData2D tableData2D; + TableData2D::TableDataHolder tableConverted; + tableConverted = tableData2D.convertTable2D( values, + valueUnit, + coordinates, + units::getDescription( tableFunction.getDimUnit( 0 ) ), + units::getDescription( tableFunction.getDimUnit( 1 ) ) ); + + TableLayout tableLayout( tableConverted.headerNames ); + + TableCSVFormatter csvFormat( tableLayout ); + formatterStream << csvFormat.headerToString() << csvFormat.dataToString( tableConverted.tableData ); + } + return formatterStream.str(); +} + +template<> +string TableTextFormatter::toString< TableFunction >( TableFunction const & tableFunction ) const +{ + ArrayOfArraysView< real64 const > coordinates = tableFunction.getCoordinates(); + units::Unit const valueUnit = tableFunction.getValueUnit(); + arrayView1d< real64 const > const values = tableFunction.getValues(); + integer const numDimensions = LvArray::integerConversion< integer >( coordinates.size() ); + string const filename = tableFunction.getName(); + string logOutput; + + GEOS_LOG_RANK_0( GEOS_FMT( "Values in the table are represented by : {}", units::getDescription( valueUnit ))); + + if( numDimensions == 1 ) + { + TableData tableData; + arraySlice1d< real64 const > const coords = coordinates[0]; + for( integer idx = 0; idx < values.size(); idx++ ) + { + tableData.addRow( coords[idx], values[idx] ); + } + + TableLayout const tableLayout( { + string( units::getDescription( tableFunction.getDimUnit( 0 ))), + string( units::getDescription( valueUnit )) + }, filename ); + + TableTextFormatter const logTable( tableLayout ); + logOutput = logTable.toString( tableData ); + } + else if( numDimensions == 2 ) + { + integer const nX = coordinates[0].size(); + integer const nY = coordinates[1].size(); + if( nX * nY <= 500 ) + { + TableData2D tableData2D; + TableData2D::TableDataHolder tableConverted; + tableConverted = tableData2D.convertTable2D( values, + valueUnit, + coordinates, + units::getDescription( tableFunction.getDimUnit( 0 ) ), + units::getDescription( tableFunction.getDimUnit( 1 ) )); + + TableLayout tableLayout( tableConverted.headerNames, filename ); + + TableTextFormatter const table2DLog( tableLayout ); + logOutput = table2DLog.toString( tableConverted.tableData ); + } + else + { + string log = GEOS_FMT( "The {} PVT table exceeding 500 rows.\nTo visualize the tables, go to the generated csv \n", filename ); + TableLayout const tableLayoutInfos( {TableLayout::ColumnParam{{log}, TableLayout::Alignment::left}}, filename ); + TableTextFormatter const tableLog( tableLayoutInfos ); + logOutput = tableLog.layoutToString(); + } + } + return logOutput; +} + REGISTER_CATALOG_ENTRY( FunctionBase, TableFunction, string const &, Group * const ) } // end of namespace geos diff --git a/src/coreComponents/functions/TableFunction.hpp b/src/coreComponents/functions/TableFunction.hpp index 216fd08ca51..b7be867d123 100644 --- a/src/coreComponents/functions/TableFunction.hpp +++ b/src/coreComponents/functions/TableFunction.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,8 +22,9 @@ #include "FunctionBase.hpp" -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include "LvArray/src/tensorOps.hpp" +#include "common/format/table/TableFormatter.hpp" #include "common/Units.hpp" namespace geos @@ -46,6 +48,15 @@ class TableFunction : public FunctionBase Lower }; + /// Struct containing output options + struct OutputOptions + { + /// Output PVT in CSV file + bool writeCSV; + /// Output PVT in log + bool writeInLog; + }; + /// maximum dimensions for the coordinates in the table static constexpr integer maxDimensions = 4; @@ -276,7 +287,9 @@ class TableFunction : public FunctionBase * @return The unit of a coordinate dimension, or units::Unknown if no units has been specified. */ units::Unit getDimUnit( localIndex const dim ) const - { return size_t(dim) < m_dimUnits.size() ? m_dimUnits[dim] : units::Unknown; } + { + return size_t(dim) < m_dimUnits.size() ? m_dimUnits[dim] : units::Unknown; + } /** * @brief Set the interpolation method @@ -317,11 +330,17 @@ class TableFunction : public FunctionBase m_valueUnit = unit; } +/** + * @return The table unit + */ + units::Unit getValueUnit() const { return m_valueUnit; } + + /** - * @brief Print table into a CSV file (only 1d and 2d tables are supported) - * @param filename Filename for output + * @brief Print the table(s) in the log and/or CSV files when requested by the user. + * @param pvtOutputOpts Struct containing output options */ - void print( std::string const & filename ) const; + void outputPVTTableData( OutputOptions const pvtOutputOpts ) const; /** * @brief Create an instance of the kernel wrapper @@ -354,6 +373,7 @@ class TableFunction : public FunctionBase */ void readFile( string const & filename, array1d< real64 > & target ); + /// Coordinates for 1D table array1d< real64 > m_tableCoordinates1D; @@ -673,6 +693,22 @@ ENUM_STRINGS( TableFunction::InterpolationType, "upper", "lower" ); +/** + * @brief Template specialisation to convert a TableFunction to a CSV string. + * @param tableData The TableFunction object to convert. + * @return The CSV string representation of the TableFunction. + */ +template<> +string TableTextFormatter::toString< TableFunction >( TableFunction const & tableData ) const; + +/** + * @brief Template specialisation to convert a TableFunction to a table string. + * @param tableData The TableFunction object to convert. + * @return The table string representation of the TableFunction. + */ +template<> +string TableCSVFormatter::toString< TableFunction >( TableFunction const & tableData ) const; + } /* namespace geos */ #endif /* GEOS_FUNCTIONS_TABLEFUNCTION_HPP_ */ diff --git a/src/coreComponents/functions/docs/FunctionManager.rst b/src/coreComponents/functions/docs/FunctionManager.rst index ef58be85a27..66c1e34e503 100644 --- a/src/coreComponents/functions/docs/FunctionManager.rst +++ b/src/coreComponents/functions/docs/FunctionManager.rst @@ -64,8 +64,8 @@ TableFunction A table function uses a set of pre-computed values defined at points on a structured grid to represent an arbitrary-dimensional function. Typically, the axes of the table will represent time and/or spatial dimensions; however, these can be applied to represent phase diagrams, etc. -.. include:: ../../../coreComponents/schema/docs/TableFunction.rst - +.. include:: /docs/sphinx/datastructure/TableFunction.rst + :start-line: 3 1D Table ************* @@ -157,7 +157,8 @@ SymbolicFunction This function leverages the symbolic expression library mathpresso to define and evaluate functions. These functions are processed using an x86-64 JIT compiler, so are nearly as efficient as natively compiled C++ expressions. -.. include:: ../../../coreComponents/schema/docs/SymbolicFunction.rst +.. include:: /docs/sphinx/datastructure/SymbolicFunction.rst + :start-line: 3 The ``variableNames`` attribute defines a set of single-character names for the inputs to the symbolic function. There should be a definition for each scalar input and for each component of a vector input. @@ -187,8 +188,8 @@ CompositeFunction This function is derived from the symbolic function. However, instead of using the time or object as inputs, it is used to combine the outputs of other functions using a symbolic expression. -.. include:: ../../../coreComponents/schema/docs/CompositeFunction.rst - +.. include:: /docs/sphinx/datastructure/CompositeFunction.rst + :start-line: 3 The ``functionNames`` attribute defines the set of input functions to use (these may be of any type, and may each have any number of inputs). The ``variableNames`` attribute defines a set of single-character names for each function. diff --git a/src/coreComponents/functions/unitTests/CMakeLists.txt b/src/coreComponents/functions/unitTests/CMakeLists.txt index 84f7539e085..825cfe81687 100644 --- a/src/coreComponents/functions/unitTests/CMakeLists.txt +++ b/src/coreComponents/functions/unitTests/CMakeLists.txt @@ -5,12 +5,6 @@ set( gtest_geosx_tests set( dependencyList ${parallelDeps} gtest functions ) -# if ( GEOSX_BUILD_SHARED_LIBS ) -# list( APPEND dependencyList geosx_core ) -# else() -# list( APPEND dependencyList ${geosx_core_libs} ) -# endif() - if (TARGET pugixml::pugixml) list( APPEND dependencyList pugixml::pugixml ) endif() @@ -19,8 +13,8 @@ if (TARGET pugixml) list( APPEND dependencyList pugixml ) endif() -if (TARGET fmt::fmt) - list( APPEND dependencyList fmt::fmt ) +if (TARGET fmt::fmt-header-only) + list( APPEND dependencyList fmt::fmt-header-only ) endif() if (TARGET fmt) diff --git a/src/coreComponents/functions/unitTests/testFunctions.cpp b/src/coreComponents/functions/unitTests/testFunctions.cpp index c9353b8c82f..04ca26acca6 100644 --- a/src/coreComponents/functions/unitTests/testFunctions.cpp +++ b/src/coreComponents/functions/unitTests/testFunctions.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -22,7 +23,7 @@ #include "functions/MultivariableTableFunctionKernels.hpp" //#include "mainInterface/GeosxState.hpp" -#ifdef GEOSX_USE_MATHPRESSO +#ifdef GEOS_USE_MATHPRESSO #include "functions/SymbolicFunction.hpp" #endif @@ -539,7 +540,7 @@ TEST( FunctionTests, 4DTable_derivatives ) } } -#ifdef GEOSX_USE_MATHPRESSO +#ifdef GEOS_USE_MATHPRESSO TEST( FunctionTests, 4DTable_symbolic ) { diff --git a/src/coreComponents/linearAlgebra/CMakeLists.txt b/src/coreComponents/linearAlgebra/CMakeLists.txt index 3ae8298a43d..99cc0bc77d4 100644 --- a/src/coreComponents/linearAlgebra/CMakeLists.txt +++ b/src/coreComponents/linearAlgebra/CMakeLists.txt @@ -1,4 +1,29 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: linearAlgebra + +Contains: + - management implementations to handle all degrees of freedom associated with field element on + mesh elements. + - linear solvers implementations. + - interfaces to different external linear solvers libraries (hypre, Petsc, trilinos). +#]] + +# # Specify all headers +# set( linearAlgebra_headers DofManager.hpp DofManagerHelpers.hpp @@ -35,8 +60,9 @@ set( linearAlgebra_headers utilities/NormalOperator.hpp utilities/ReverseCutHillMcKeeOrdering.hpp utilities/TransposeOperator.hpp ) - +# # Specify all sources +# set( linearAlgebra_sources DofManager.cpp solvers/BicgstabSolver.cpp @@ -47,16 +73,17 @@ set( linearAlgebra_sources solvers/SeparateComponentPreconditioner.cpp utilities/ReverseCutHillMcKeeOrdering.cpp ) -set( dependencyList ${parallelDeps} mesh denseLinearAlgebra ) +set( dependencyList ${parallelDeps} mesh denseLinearAlgebra finiteVolume ) +set( tplDependencyList "" ) list( APPEND linearAlgebra_headers interfaces/direct/SuiteSparse.hpp ) list( APPEND linearAlgebra_sources interfaces/direct/SuiteSparse.cpp ) -list( APPEND dependencyList suitesparse ) +list( APPEND tplDependencyList suitesparse ) if( ENABLE_SUPERLU_DIST ) list( APPEND linearAlgebra_headers interfaces/direct/SuperLUDist.hpp ) list( APPEND linearAlgebra_sources interfaces/direct/SuperLUDist.cpp ) - list( APPEND dependencyList superlu_dist ) + list( APPEND tplDependencyList superlu_dist ) endif( ) if( ENABLE_TRILINOS ) @@ -78,7 +105,7 @@ if( ENABLE_TRILINOS ) interfaces/trilinos/TrilinosPreconditioner.cpp interfaces/trilinos/TrilinosSolver.cpp ) - list( APPEND dependencyList trilinos ) + list( APPEND tplDependencyList trilinos ) endif() @@ -109,6 +136,7 @@ if( ENABLE_HYPRE ) interfaces/hypre/mgrStrategies/SinglePhaseReservoirHybridFVM.hpp interfaces/hypre/mgrStrategies/SolidMechanicsEmbeddedFractures.hpp interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseFVM.hpp + interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp interfaces/hypre/mgrStrategies/ThermalMultiphasePoromechanics.hpp interfaces/hypre/mgrStrategies/ThermalSinglePhasePoromechanics.hpp ) list( APPEND linearAlgebra_sources @@ -122,7 +150,7 @@ if( ENABLE_HYPRE ) interfaces/hypre/HypreUtils.cpp interfaces/hypre/HypreVector.cpp ) - list( APPEND dependencyList hypre umpire ) + list( APPEND tplDependencyList hypre umpire ) endif() @@ -145,19 +173,24 @@ if( ENABLE_PETSC ) interfaces/petsc/PetscSolver.cpp interfaces/petsc/PetscVector.cpp ) - list( APPEND dependencyList petsc ) + list( APPEND tplDependencyList petsc ) endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) + blt_add_library( NAME linearAlgebra SOURCES ${linearAlgebra_sources} HEADERS ${linearAlgebra_headers} - DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} ) target_include_directories( linearAlgebra PUBLIC ${CMAKE_CURRENT_LIST_DIR} ) +install( TARGETS linearAlgebra LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) if( GEOS_ENABLE_TESTS ) add_subdirectory( unitTests ) diff --git a/src/coreComponents/linearAlgebra/DofManager.cpp b/src/coreComponents/linearAlgebra/DofManager.cpp index 12380d90a59..64af6fb82e3 100644 --- a/src/coreComponents/linearAlgebra/DofManager.cpp +++ b/src/coreComponents/linearAlgebra/DofManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -1789,7 +1790,7 @@ void DofManager::makeRestrictor( std::vector< SubComponent > const & selection, void DofManager::printFieldInfo( std::ostream & os ) const { - if( MpiWrapper::commRank( MPI_COMM_GEOSX ) == 0 ) + if( MpiWrapper::commRank( MPI_COMM_GEOS ) == 0 ) { localIndex const numFields = LvArray::integerConversion< localIndex >( m_fields.size() ); @@ -1877,15 +1878,15 @@ void DofManager::printFieldInfo( std::ostream & os ) const bool const transpose, \ LAI::ParallelMatrix & restrictor ) const; -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS MAKE_DOFMANAGER_METHOD_INST( TrilinosInterface ) #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE MAKE_DOFMANAGER_METHOD_INST( HypreInterface ) #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC MAKE_DOFMANAGER_METHOD_INST( PetscInterface ) #endif diff --git a/src/coreComponents/linearAlgebra/DofManager.hpp b/src/coreComponents/linearAlgebra/DofManager.hpp index db8b7a01c8d..c37dcc1a450 100644 --- a/src/coreComponents/linearAlgebra/DofManager.hpp +++ b/src/coreComponents/linearAlgebra/DofManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/DofManagerHelpers.hpp b/src/coreComponents/linearAlgebra/DofManagerHelpers.hpp index 186c2f7d2bc..6ae81b10790 100644 --- a/src/coreComponents/linearAlgebra/DofManagerHelpers.hpp +++ b/src/coreComponents/linearAlgebra/DofManagerHelpers.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/common/LinearOperator.hpp b/src/coreComponents/linearAlgebra/common/LinearOperator.hpp index 995ef2b6936..57476c305bc 100644 --- a/src/coreComponents/linearAlgebra/common/LinearOperator.hpp +++ b/src/coreComponents/linearAlgebra/common/LinearOperator.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/common/LinearSolverBase.hpp b/src/coreComponents/linearAlgebra/common/LinearSolverBase.hpp index f20b2a1501b..045d096dfbc 100644 --- a/src/coreComponents/linearAlgebra/common/LinearSolverBase.hpp +++ b/src/coreComponents/linearAlgebra/common/LinearSolverBase.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/linearAlgebra/common/PreconditionerBase.hpp b/src/coreComponents/linearAlgebra/common/PreconditionerBase.hpp index d8869c7eb2e..ac9d0b022a9 100644 --- a/src/coreComponents/linearAlgebra/common/PreconditionerBase.hpp +++ b/src/coreComponents/linearAlgebra/common/PreconditionerBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/common/common.hpp b/src/coreComponents/linearAlgebra/common/common.hpp index f729fafe3fc..54cd03337a7 100644 --- a/src/coreComponents/linearAlgebra/common/common.hpp +++ b/src/coreComponents/linearAlgebra/common/common.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,6 +20,7 @@ #define GEOS_LINEARALGEBRA_INTERFACES_COMMON_HPP_ #include "common/DataTypes.hpp" +#include "common/logger/Logger.hpp" /** * Whether to check preconditions at runtime in LAI functions diff --git a/src/coreComponents/linearAlgebra/common/traits.hpp b/src/coreComponents/linearAlgebra/common/traits.hpp index 546307b670d..d300b7b782c 100644 --- a/src/coreComponents/linearAlgebra/common/traits.hpp +++ b/src/coreComponents/linearAlgebra/common/traits.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/linearAlgebra/docs/DofManager.rst b/src/coreComponents/linearAlgebra/docs/DofManager.rst index d13e2ee7c9c..6948b36f1ae 100644 --- a/src/coreComponents/linearAlgebra/docs/DofManager.rst +++ b/src/coreComponents/linearAlgebra/docs/DofManager.rst @@ -2,8 +2,6 @@ DoF Manager ############################################################################### -This will contains a description of the DoF manager in GEOS. - Brief description ======================== diff --git a/src/coreComponents/linearAlgebra/docs/LinearSolvers.rst b/src/coreComponents/linearAlgebra/docs/LinearSolvers.rst index bda0ecc9543..6f68efac64d 100644 --- a/src/coreComponents/linearAlgebra/docs/LinearSolvers.rst +++ b/src/coreComponents/linearAlgebra/docs/LinearSolvers.rst @@ -14,14 +14,14 @@ Any physics solver relying on standard finite element and finite volume techniqu \mathsf{A} \mathsf{x} = \mathsf{b} -with a :math:`\mathsf{A}` a square sparse matrix, :math:`\mathsf{x}` the solution vector, and :math:`\mathsf{b}` the right-hand side. +where :math:`\mathsf{A}` is the square sparse matrix, :math:`\mathsf{x}` the solution vector, and :math:`\mathsf{b}` the right-hand side. For example, in a classical linear elastostatics problem :math:`\mathsf{A}` is the stiffness matrix, and :math:`\mathsf{x}` and :math:`\mathsf{b}` are the displacement and nodal force vectors, respectively. This solution stage represents the most computationally expensive portion of a typical simulation. Solution algorithms generally belong to two families of methods: direct methods and iterative methods. In GEOS both options are made available wrapping around well-established open-source linear algebra libraries, namely -`HYPRE `__, +`HYPRE `__, `PETSc `__, `SuperLU `__, and `Trilinos `__. @@ -38,7 +38,7 @@ Irrespective of the selected direct solver implementation, three stages can be i (#) **Solve Stage**: the solution to the linear systems involving the factorized matrix is computed (#) **Finalize Stage**: the systems involving the factorized matrix have been solved and the direct solver lifetime ends -The default option in GEOS relies on `SuperLU `__, a general purpose library for the direct solution of large, sparse, nonsymmetric systems of linear equations, that is called taking advantage of the interface provided in `HYPRE `__. +The default option in GEOS relies on `SuperLU `__, a general purpose library for the direct solution of large, sparse, nonsymmetric systems of linear equations, that is called taking advantage of the interface provided in `HYPRE `__. ****************** Iterative methods @@ -66,7 +66,7 @@ Summary The following table summarizes the available input parameters for the linear solver. -.. include:: ../../schema/docs/LinearSolverParameters.rst +.. include:: /docs/sphinx/datastructure/LinearSolverParameters.rst *************************** Preconditioner descriptions @@ -110,8 +110,8 @@ This section provides a brief description of the available preconditioners. - `PETSc documentation `__, - `Trilinos documentation `__. -* **MGR**: multigrid reduction. Available through *hypre* interface only. Specific documentation coming soon. - Further details can be found in `MGR documentation `__. +* **MGR**: multigrid reduction. Available through *hypre* interface only. + Further details can be found in `MGR documentation `__, also see section below. * **Block**: custom preconditioner designed for a 2 x 2 block matrix. @@ -119,7 +119,7 @@ This section provides a brief description of the available preconditioners. HYPRE MGR Preconditioner ************************ -MGR stands for multigrid reduction, a multigrid method that uses the interpolation, restriction operators, and the Galerkin triple product, to reduce a linear system to a smaller one, similar to a Schur complement approach. As such, it is designed to target block linear systems resulting from discretizations of multiphysics problems. GEOS uses MGR through an implementation in `HYPRE `__. More information regarding MGR can be found `here `__. Currently, MGR strategies are implemented for hydraulic fracturing, poroelastic, compositional flow with and without wells. More multiphysics solvers with MGR will be enabled in the future. +MGR stands for multigrid reduction, a multigrid method that uses the interpolation, restriction operators, and the Galerkin triple product, to reduce a linear system to a smaller one, similar to a Schur complement approach. As such, it is designed to target block linear systems resulting from discretizations of multiphysics problems. GEOS uses MGR through an implementation in `HYPRE `__. More information regarding MGR can be found `here `__. Currently, MGR strategies are implemented for hydraulic fracturing, singlephase and multiphase poromechanics, singlephase poromechanics with fractures, compositional flow with and without wells. More multiphysics solvers with MGR will be enabled in the future. To use MGR for a specific block system, several components need to be specified. @@ -157,3 +157,16 @@ Moreover, a block scaling is available. Feasible options are: * none: keep the original scaling; * Frobenius norm: equilibrate Frobenius norm of the diagonal blocks; * user provided. + +******************** +Adaptive tolerance +******************** + +This feature is available for iterative solvers and can be enabled using `krylovAdaptiveTol` flag in `LinearSolverParameters`. It follows the Eisenstat-Walker inexact Newton approach described in [Eisenstat and Walker 1996]. The key idea is to relax the linear solver tolerance at the beginning of the nonlinear iterations loop and tighten it when getting closer to the final solution. The initial tolerance is defined by `krylovWeakestTol` and starting from second nonlinear iteration the tolerance is chosen using the following steps: + +- compute the current to previous nonlinear norm ratio: :math:`\mathsf{nr} = \mathsf{min}( \mathsf{norm}^{curr} / \mathsf{norm}^{prev}, 1.0 )` +- estimate the new linear solver tolerance: :math:`\mathsf{tol}_{new} = \mathsf{\gamma} \cdot \mathsf{nr}^{ax}` +- compute a safeguard to avoid too sharp tolerance reduction: :math:`\mathsf{tol}_{alt} = \mathsf{tol}_{old}^{2}` (the bound is the quadratic reduction with respect to the previous tolerance value) +- apply safeguards and compute the final tolerance: :math:`\mathsf{tol} = \mathsf{max}( \mathsf{tol}_{new}, \mathsf{tol}_{alt} )`, :math:`\mathsf{tol} = \mathsf{min}( \mathsf{tol}_{max}, \mathsf{max}( \mathsf{tol}_{min}, \mathsf{tol} ) )` + +Here :math:`\mathsf{\gamma}` is the forcing term, :math:`ax` is the adaptivity exponent, :math:`\mathsf{tol}_{min}` and :math:`\mathsf{tol}_{max}` are prescribed tolerance bounds (defined by `krylovStrongestTol` and `krylovWeakestTol`, respectively). diff --git a/src/coreComponents/linearAlgebra/interfaces/InterfaceTypes.hpp b/src/coreComponents/linearAlgebra/interfaces/InterfaceTypes.hpp index 0566bd819df..25098fc623b 100644 --- a/src/coreComponents/linearAlgebra/interfaces/InterfaceTypes.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/InterfaceTypes.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,15 +22,15 @@ #include "common/GeosxConfig.hpp" -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS #include "linearAlgebra/interfaces/trilinos/TrilinosInterface.hpp" #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE #include "linearAlgebra/interfaces/hypre/HypreInterface.hpp" #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC #include "linearAlgebra/interfaces/petsc/PetscInterface.hpp" #endif @@ -37,7 +38,7 @@ namespace geos { /// Alias for current interface -using LAInterface = GEOS_CONCAT( GEOSX_LA_INTERFACE, Interface ); +using LAInterface = GEOS_CONCAT( GEOS_LA_INTERFACE, Interface ); /// Alias for ParallelMatrix using ParallelMatrix = LAInterface::ParallelMatrix; @@ -50,13 +51,13 @@ using ParallelVector = LAInterface::ParallelVector; */ inline void setupLAI() { -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS TrilinosInterface::initialize(); #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE HypreInterface::initialize(); #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC PetscInterface::initialize(); #endif } @@ -66,13 +67,13 @@ inline void setupLAI() */ inline void finalizeLAI() { -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS TrilinosInterface::finalize(); #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE HypreInterface::finalize(); #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC PetscInterface::finalize(); #endif } diff --git a/src/coreComponents/linearAlgebra/interfaces/MatrixBase.hpp b/src/coreComponents/linearAlgebra/interfaces/MatrixBase.hpp index 65a9df9b176..302e220b213 100644 --- a/src/coreComponents/linearAlgebra/interfaces/MatrixBase.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/MatrixBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/VectorBase.hpp b/src/coreComponents/linearAlgebra/interfaces/VectorBase.hpp index 6c2a8fb555e..2efb0725fa0 100644 --- a/src/coreComponents/linearAlgebra/interfaces/VectorBase.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/VectorBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/direct/SuiteSparse.cpp b/src/coreComponents/linearAlgebra/interfaces/direct/SuiteSparse.cpp index d0a4d678beb..53a45e2ce7f 100644 --- a/src/coreComponents/linearAlgebra/interfaces/direct/SuiteSparse.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/direct/SuiteSparse.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -29,7 +30,7 @@ // Pre-define some suitesparse variables since they are not properly defined // in the header for alternate index types. -//#if GEOSX_GLOBALINDEX_TYPE_FLAG==0 +//#if GEOS_GLOBALINDEX_TYPE_FLAG==0 #if 0 /// Set alias for SuiteSparse_long #define SuiteSparse_long int @@ -370,15 +371,15 @@ real64 SuiteSparse< LAI >::estimateConditionNumberAdvanced() const // ----------------------- // Explicit Instantiations // ----------------------- -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS template class SuiteSparse< TrilinosInterface >; #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE template class SuiteSparse< HypreInterface >; #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC template class SuiteSparse< PetscInterface >; #endif diff --git a/src/coreComponents/linearAlgebra/interfaces/direct/SuiteSparse.hpp b/src/coreComponents/linearAlgebra/interfaces/direct/SuiteSparse.hpp index c506917c773..77534242052 100644 --- a/src/coreComponents/linearAlgebra/interfaces/direct/SuiteSparse.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/direct/SuiteSparse.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/direct/SuperLUDist.cpp b/src/coreComponents/linearAlgebra/interfaces/direct/SuperLUDist.cpp index 52a62dfa2b3..e4c1bdaa8a0 100644 --- a/src/coreComponents/linearAlgebra/interfaces/direct/SuperLUDist.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/direct/SuperLUDist.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -436,15 +437,15 @@ real64 SuperLUDist< LAI >::estimateConditionNumberAdvanced() const // ----------------------- // Explicit Instantiations // ----------------------- -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS template class SuperLUDist< TrilinosInterface >; #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE template class SuperLUDist< HypreInterface >; #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC template class SuperLUDist< PetscInterface >; #endif diff --git a/src/coreComponents/linearAlgebra/interfaces/direct/SuperLUDist.hpp b/src/coreComponents/linearAlgebra/interfaces/direct/SuperLUDist.hpp index 20f3fd742ae..779ad77cee0 100644 --- a/src/coreComponents/linearAlgebra/interfaces/direct/SuperLUDist.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/direct/SuperLUDist.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreExport.cpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreExport.cpp index 7e335a47e1c..9f8f33bc659 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreExport.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreExport.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreExport.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreExport.hpp index 2e9e03e02a5..9db9201ab56 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreExport.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreExport.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreInterface.cpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreInterface.cpp index d5b231ad971..783c2e6b483 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreInterface.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreInterface.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -24,7 +25,7 @@ #include "linearAlgebra/interfaces/hypre/HypreSolver.hpp" #include "linearAlgebra/interfaces/hypre/HypreUtils.hpp" -#if defined(GEOSX_USE_SUPERLU_DIST) +#if defined(GEOS_USE_SUPERLU_DIST) #include "linearAlgebra/interfaces/direct/SuperLUDist.hpp" #endif @@ -39,7 +40,19 @@ namespace geos void HypreInterface::initialize() { - HYPRE_Init(); +#if defined(GEOS_USE_OPENMP) && defined(HYPRE_USING_OPENMP) + GEOS_LOG_RANK_0_IF( omp_get_max_threads() > 1, + "\n" + "********************************************************************\n" + "* *\n" + "* WARNING: OMP_NUM_THREADS > 1 MAY NOT BE OPTIMAL FOR CERTAIN *\n" + "* HYPRE PRECONDITIONING OPTIONS! *\n" + "* *\n" + "********************************************************************\n" + ); +#endif + + HYPRE_Initialize(); #if GEOS_USE_HYPRE_DEVICE == GEOS_USE_HYPRE_CUDA || GEOS_USE_HYPRE_DEVICE == GEOS_USE_HYPRE_HIP HYPRE_SetExecutionPolicy( HYPRE_EXEC_DEVICE ); HYPRE_SetSpGemmUseVendor( 0 ); @@ -47,6 +60,15 @@ void HypreInterface::initialize() #endif HYPRE_SetMemoryLocation( hypre::memoryLocation ); HYPRE_SetPrintErrorMode( 1 ); + +#if defined(HYPRE_USING_UMPIRE) + HYPRE_SetUmpireUMPoolName( "HYPRE_UM" ); + HYPRE_SetUmpireHostPoolName( "HYPRE_HOST" ); + HYPRE_SetUmpireDevicePoolName( "HYPRE_DEVICE" ); + HYPRE_SetUmpirePinnedPoolName( "HYPRE_PINNED" ); +#endif + + HYPRE_SetLogLevel( getenv( "HYPRE_LOG_LEVEL" ) ? atoi( getenv( "HYPRE_LOG_LEVEL" ) ) : 0 ); } void HypreInterface::finalize() @@ -61,11 +83,11 @@ HypreInterface::createSolver( LinearSolverParameters params ) { if( params.direct.parallel ) { -#if defined(GEOSX_USE_SUPERLU_DIST) +#if defined(GEOS_USE_SUPERLU_DIST) return std::make_unique< SuperLUDist< HypreInterface > >( std::move( params ) ); #else GEOS_ERROR( "GEOSX is configured without support for SuperLU_dist." ); - return std::unique_ptr< LinearSolverBase< HypreInterface > >( NULL ); + return std::unique_ptr< LinearSolverBase< HypreInterface > >( nullptr ); #endif } else diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreInterface.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreInterface.hpp index d4a8eb1ef45..d6bdfd44d0a 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreInterface.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreInterface.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreKernels.cpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreKernels.cpp index 0ebfc519d66..31627dd91cb 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreKernels.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreKernels.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreKernels.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreKernels.hpp index eac1f2c468d..b71248aa0d5 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreKernels.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreKernels.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMGR.cpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMGR.cpp index aa85b90b68a..03791b006e1 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMGR.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMGR.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -37,6 +38,7 @@ #include "linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseReservoirFVM.hpp" #include "linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseReservoirHybridFVM.hpp" #include "linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseFVM.hpp" +#include "linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp" #include "linearAlgebra/interfaces/hypre/mgrStrategies/ThermalSinglePhasePoromechanics.hpp" #include "linearAlgebra/interfaces/hypre/mgrStrategies/ThermalMultiphasePoromechanics.hpp" #include "linearAlgebra/interfaces/hypre/mgrStrategies/SolidMechanicsEmbeddedFractures.hpp" @@ -111,6 +113,11 @@ void hypre::mgr::createMGR( LinearSolverParameters const & params, setStrategy< ThermalCompositionalMultiphaseFVM >( params.mgr, numComponentsPerField, precond, mgrData ); break; } + case LinearSolverParameters::MGR::StrategyType::thermalCompositionalMultiphaseReservoirFVM: + { + setStrategy< ThermalCompositionalMultiphaseReservoirFVM >( params.mgr, numComponentsPerField, precond, mgrData ); + break; + } case LinearSolverParameters::MGR::StrategyType::hybridSinglePhasePoromechanics: { setStrategy< HybridSinglePhasePoromechanics >( params.mgr, numComponentsPerField, precond, mgrData ); diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMGR.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMGR.hpp index 6063db453c3..8bacdf8b978 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMGR.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMGR.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -73,23 +74,24 @@ class MGRStrategyBase { public: - static constexpr HYPRE_Int numLevels = NLEVEL; ///< Number of levels + static constexpr HYPRE_Int numLevels = NLEVEL; ///< Number of levels protected: - HYPRE_Int m_numBlocks{ 0 }; ///< Number of different matrix blocks treated separately + HYPRE_Int m_numBlocks{ 0 }; ///< Number of different matrix blocks treated separately - std::vector< HYPRE_Int > m_labels[numLevels]{}; ///< Dof labels kept at each level - HYPRE_Int m_numLabels[numLevels]{ -1 }; ///< Number of dof labels kept - HYPRE_Int * m_ptrLabels[numLevels]{ nullptr }; ///< Pointers to each level's labels, as consumed by MGR + std::vector< HYPRE_Int > m_labels[numLevels]{}; ///< Dof labels kept at each level + HYPRE_Int m_numLabels[numLevels]{ -1 }; ///< Number of dof labels kept + HYPRE_Int * m_ptrLabels[numLevels]{ nullptr }; ///< Pointers to each level's labels, as consumed by MGR - MGRFRelaxationType m_levelFRelaxType[numLevels]; ///< F-relaxation type for each level - HYPRE_Int m_levelFRelaxIters[numLevels]{ -1 }; ///< Number of F-relaxation iterations for each level - MGRInterpolationType m_levelInterpType[numLevels]; ///< Interpolation type for each level - MGRRestrictionType m_levelRestrictType[numLevels]; ///< Restriction type for each level - MGRCoarseGridMethod m_levelCoarseGridMethod[numLevels]; ///< Coarse grid method for each level + MGRFRelaxationType m_levelFRelaxType[numLevels]; ///< F-relaxation type for each level + HYPRE_Int m_levelFRelaxIters[numLevels]{ -1 }; ///< Number of F-relaxation iterations for each level + MGRInterpolationType m_levelInterpType[numLevels]; ///< Interpolation type for each level + MGRRestrictionType m_levelRestrictType[numLevels]; ///< Restriction type for each level + MGRCoarseGridMethod m_levelCoarseGridMethod[numLevels]; ///< Coarse grid method for each level MGRGlobalSmootherType m_levelGlobalSmootherType[numLevels]; ///< Global smoother type for each level - HYPRE_Int m_levelGlobalSmootherIters[numLevels]{ -1 }; ///< Number of global smoother iterations for each level + HYPRE_Int m_levelGlobalSmootherIters[numLevels]{ -1 }; ///< Number of global smoother iterations for each level + HYPRE_Real m_coarseGridThreshold{ 1.0e-20 }; ///< Coarse grid truncation threshold // TODO: the following options are currently commented out in MGR's code. // Let's consider their use when re-enable in hypre @@ -159,22 +161,26 @@ class MGRStrategyBase GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetCoarseGridMethod( precond.ptr, toUnderlyingPtr( m_levelCoarseGridMethod ) ) ); GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetLevelSmoothType( precond.ptr, toUnderlyingPtr( m_levelGlobalSmootherType ) ) ); GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetLevelSmoothIters( precond.ptr, m_levelGlobalSmootherIters ) ); + GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetTruncateCoarseGridThreshold( precond.ptr, m_coarseGridThreshold ) ); GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetNonCpointsToFpoints( precond.ptr, 1 )); + GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetNonGalerkinMaxElmts( precond.ptr, 1 )); } /** * @brief Set up BoomerAMG to perform the solve for the displacement system * @param solver the solver wrapper + * @param separateComponents flag controlling the use of the separate displacement component (SDC) approximation */ - void setDisplacementAMG( HyprePrecWrapper & solver ) + void setDisplacementAMG( HyprePrecWrapper & solver, + integer const & separateComponents ) { GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGCreate( &solver.ptr ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetTol( solver.ptr, 0.0 ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetMaxIter( solver.ptr, 1 ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetMaxRowSum( solver.ptr, 1.0 ) ); - GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetStrongThreshold( solver.ptr, 0.8 ) ); + GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetStrongThreshold( solver.ptr, 0.6 ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetPrintLevel( solver.ptr, 0 ) ); - + GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetInterpType( solver.ptr, hypre::getAMGInterpolationType( LinearSolverParameters::AMG::InterpType::modifiedExtendedE )) ); #if GEOS_USE_HYPRE_DEVICE == GEOS_USE_HYPRE_CUDA || GEOS_USE_HYPRE_DEVICE == GEOS_USE_HYPRE_HIP GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetCoarsenType( solver.ptr, hypre::getAMGCoarseningType( LinearSolverParameters::AMG::CoarseningType::PMIS ) ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetRelaxType( solver.ptr, hypre::getAMGRelaxationType( LinearSolverParameters::AMG::SmootherType::chebyshev ) ) ); @@ -184,6 +190,7 @@ class MGRStrategyBase #endif GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetNumFunctions( solver.ptr, 3 ) ); + GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetFilterFunctions( solver.ptr, separateComponents ) ); solver.setup = HYPRE_BoomerAMGSetup; solver.solve = HYPRE_BoomerAMGSolve; @@ -200,10 +207,12 @@ class MGRStrategyBase GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetPrintLevel( solver.ptr, 0 ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetMaxIter( solver.ptr, 1 ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetAggNumLevels( solver.ptr, 1 ) ); - GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetAggPMaxElmts( solver.ptr, 16 ) ); + GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetAggPMaxElmts( solver.ptr, 20 ) ); + GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetAggInterpType( solver.ptr, hypre::getAMGAggressiveInterpolationType( LinearSolverParameters::AMG::AggInterpType::multipass ) ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetTol( solver.ptr, 0.0 ) ); #if GEOS_USE_HYPRE_DEVICE == GEOS_USE_HYPRE_CUDA || GEOS_USE_HYPRE_DEVICE == GEOS_USE_HYPRE_HIP - GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetCoarsenType( solver.ptr, toUnderlying( AMGCoarseningType::PMIS ) ) ); + GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetAggInterpType( solver.ptr, hypre::getAMGAggressiveInterpolationType( LinearSolverParameters::AMG::AggInterpType::modifiedExtendedE ) ) ); + GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetCoarsenType( solver.ptr, hypre::getAMGCoarseningType( LinearSolverParameters::AMG::CoarseningType::PMIS ) ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetRelaxType( solver.ptr, getAMGRelaxationType( LinearSolverParameters::AMG::SmootherType::l1jacobi ) ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetNumSweeps( solver.ptr, 2 ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetMaxRowSum( solver.ptr, 1.0 ) ); @@ -225,11 +234,12 @@ class MGRStrategyBase GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGCreate( &solver.ptr ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetPrintLevel( solver.ptr, 0 ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetMaxIter( solver.ptr, 1 ) ); - // TODO: keep or not 1 aggressive level? - GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetAggNumLevels( solver.ptr, 1 ) ); + GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetAggNumLevels( solver.ptr, 1 ) ); // TODO: keep or not 1 aggressive level? + GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetAggPMaxElmts( solver.ptr, 16 ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetTol( solver.ptr, 0.0 ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetNumFunctions( solver.ptr, 2 ) ); // pressure and temperature (CPTR) #if GEOS_USE_HYPRE_DEVICE == GEOS_USE_HYPRE_CUDA || GEOS_USE_HYPRE_DEVICE == GEOS_USE_HYPRE_HIP + GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetAggNumLevels( solver.ptr, 0 ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetCoarsenType( solver.ptr, toUnderlying( AMGCoarseningType::PMIS ) ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetRelaxType( solver.ptr, getAMGRelaxationType( LinearSolverParameters::AMG::SmootherType::l1jacobi ) ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetNumSweeps( solver.ptr, 2 ) ); @@ -247,14 +257,16 @@ class MGRStrategyBase * @brief Set up BoomerAMG to perform the mechanics F-solve for the first F-relaxation * @param precond the preconditioner wrapper * @param mgrData auxiliary MGR data + * @param separateComponents flag controlling the use of the separate displacement component (SDC) approximation * * @note This function should be rethought once MGR allows for customizing boomerAMG (or * any other solver) for F-relaxation at any level */ void setMechanicsFSolver( HyprePrecWrapper & precond, - HypreMGRData & mgrData ) + HypreMGRData & mgrData, + integer const & separateComponents ) { - setDisplacementAMG( mgrData.mechSolver ); + setDisplacementAMG( mgrData.mechSolver, separateComponents ); HYPRE_MGRSetFSolver( precond.ptr, mgrData.mechSolver.solve, mgrData.mechSolver.setup, mgrData.mechSolver.ptr ); } diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMatrix.cpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMatrix.cpp index c45c30a10b5..5e68ad1887d 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMatrix.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMatrix.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -1052,8 +1053,10 @@ void HypreMatrix::getRowCopy( globalIndex const globalRowIndex, -1, &numEntries, &row, + nullptr, hypre::toHypreBigInt( colIndices ), - values ) ); + values, + 0 ) ); } void HypreMatrix::extractDiagonal( HypreVector & dst ) const diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMatrix.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMatrix.hpp index 41a7610c31c..c3dc2055bcc 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMatrix.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMatrix.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HyprePreconditioner.cpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HyprePreconditioner.cpp index a6ed6bbd705..06d2a98981c 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HyprePreconditioner.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HyprePreconditioner.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -87,7 +88,6 @@ void createAMG( LinearSolverParameters const & params, GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetTol( precond.ptr, 0.0 ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetMaxIter( precond.ptr, 1 ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetPrintLevel( precond.ptr, logLevel ) ); - GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetNumFunctions( precond.ptr, params.dofsPerNode ) ); // Set maximum number of multigrid levels (default 25) GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetMaxLevels( precond.ptr, LvArray::integerConversion< HYPRE_Int >( params.amg.maxLevels ) ) ); @@ -173,7 +173,9 @@ void createAMG( LinearSolverParameters const & params, GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetPMaxElmts( precond.ptr, params.amg.interpolationMaxNonZeros ) ); } + // Unknown-based AMG parameters GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetNumFunctions( precond.ptr, params.amg.numFunctions ) ); + GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetFilterFunctions( precond.ptr, params.amg.separateComponents ) ); if( params.amg.aggressiveNumLevels ) { @@ -182,6 +184,7 @@ void createAMG( LinearSolverParameters const & params, GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetNumPaths( precond.ptr, params.amg.aggressiveNumPaths ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetAggNumLevels( precond.ptr, params.amg.aggressiveNumLevels ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetAggInterpType( precond.ptr, aggInterpType ) ); + GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetAggPMaxElmts( precond.ptr, params.amg.aggressiveInterpMaxNonZeros ) ); } // Set coarsest level solver @@ -338,32 +341,6 @@ void HyprePreconditioner::create( DofManager const * const dofManager ) HypreMatrix const & HyprePreconditioner::setupPreconditioningMatrix( HypreMatrix const & mat ) { - GEOS_MARK_FUNCTION; - - if( m_params.preconditionerType == LinearSolverParameters::PreconditionerType::mgr && m_params.mgr.separateComponents ) - { - GEOS_LAI_ASSERT_MSG( mat.dofManager() != nullptr, "MGR preconditioner requires a DofManager instance" ); - HypreMatrix Pu; - HypreMatrix Auu; - { - Stopwatch timer( m_makeRestrictorTime ); - mat.dofManager()->makeRestrictor( { { m_params.mgr.displacementFieldName, { 3, true } } }, mat.comm(), true, Pu ); - } - { - Stopwatch timer( m_computeAuuTime ); - mat.multiplyPtAP( Pu, Auu ); - } - { - Stopwatch timer( m_componentFilterTime ); - Auu.separateComponentFilter( m_precondMatrix, m_params.dofsPerNode ); - } - } - else if( m_params.preconditionerType == LinearSolverParameters::PreconditionerType::amg && m_params.amg.separateComponents ) - { - Stopwatch timer( m_componentFilterTime ); - mat.separateComponentFilter( m_precondMatrix, m_params.dofsPerNode ); - return m_precondMatrix; - } return mat; } @@ -383,12 +360,6 @@ void HyprePreconditioner::setup( Matrix const & mat ) { LvArray::system::FloatingPointExceptionGuard guard( FE_ALL_EXCEPT ); - // Perform setup of the MGR mechanics F-solver with SDC matrix, if used - if( m_mgrData && m_mgrData->mechSolver.ptr && m_mgrData->mechSolver.setup ) - { -// GEOS_LAI_CHECK_ERROR( m_mgrData->mechSolver.setup( m_mgrData->mechSolver.ptr, m_precondMatrix.unwrapped(), nullptr, nullptr ) ); - } - // Perform setup of the main solver, if needed if( m_precond->setup ) { @@ -414,7 +385,7 @@ void HyprePreconditioner::setup( Matrix const & mat ) { m_precond->destroy( m_precond->ptr ); } -#if defined(GEOSX_USE_SUPERLU_DIST) +#if defined(GEOS_USE_SUPERLU_DIST) hypre_SLUDistSetup( &m_precond->ptr, precondMat.unwrapped(), 0 ); #endif } diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HyprePreconditioner.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HyprePreconditioner.hpp index 57828e65a7a..f26f15a636f 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HyprePreconditioner.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HyprePreconditioner.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -94,26 +95,6 @@ class HyprePreconditioner final : public PreconditionerBase< HypreInterface > */ HyprePrecWrapper const & unwrapped() const; - /** - * @brief @return time spent setting up separate component matrix. - */ - real64 componentFilterTime() const - { - return m_componentFilterTime; - } - - /// @return time to construct restrictor matrix. - real64 makeRestrictorTime() const - { - return m_makeRestrictorTime; - } - - /// @return time to apply restrictor matrix. - real64 computeAuuTime() const - { - return m_computeAuuTime; - } - private: /** @@ -143,15 +124,6 @@ class HyprePreconditioner final : public PreconditionerBase< HypreInterface > /// Null space vectors std::unique_ptr< HypreNullSpace > m_nullSpace; - - /// Timing of separate component matrix construction - real64 m_componentFilterTime = 0.0; - - /// Timing of the restrictor matrix construction - real64 m_makeRestrictorTime = 0.0; - - /// Timing of the cost of applying the restrictor matrix to the system - real64 m_computeAuuTime = 0.0; }; } diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreSolver.cpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreSolver.cpp index 3a54f603c3c..35263458231 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreSolver.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreSolver.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -200,11 +201,7 @@ void HypreSolver::setup( HypreMatrix const & mat ) clear(); Base::setup( mat ); Stopwatch timer( m_result.setupTime ); - m_precond.setup( mat ); - m_componentFilterTime = m_precond.componentFilterTime(); - m_makeRestrictorTime = m_precond.makeRestrictorTime(); - m_computeAuuTime = m_precond.computeAuuTime(); m_solver = std::make_unique< HypreSolverWrapper >(); createHypreKrylovSolver( m_params, mat.comm(), *m_solver ); @@ -275,14 +272,18 @@ void HypreSolver::solve( HypreVector const & rhs, if( m_params.logLevel >= 1 ) { - GEOS_LOG_RANK_0( " Linear Solver | " << m_result.status << - " | Iterations: " << m_result.numIterations << - " | Final Rel Res: " << m_result.residualReduction << - " | Make Restrictor Time: " << m_makeRestrictorTime << - " | Compute Auu Time: " << m_computeAuuTime << - " | SC Filter Time: " << m_componentFilterTime << - " | Setup Time: " << m_result.setupTime << " s" << - " | Solve Time: " << m_result.solveTime << " s" ); + HYPRE_BigInt global_num_rows, global_num_nonzeros; + + // This involves an MPI collective call, and therefore we call it only when necessary + GEOS_LAI_CHECK_ERROR( HYPRE_IJMatrixGetGlobalInfo( matrix().unwrappedIJ(), + &global_num_rows, + &global_num_rows, // This is intentional and assuming the matrix is square + &global_num_nonzeros ) ); + + GEOS_LOG_RANK_0( GEOS_FMT( " Linear Solver | {} | Unknowns: {} | Nonzeros: {} | Iterations: {} | Final Rel Res: {:.4e} | Setup Time: {:.3f} s | Solve Time: {:.3f} s", + m_result.status, stringutilities::addCommaSeparators( global_num_rows ), + stringutilities::addCommaSeparators( global_num_nonzeros ), m_result.numIterations, + m_result.residualReduction, m_result.setupTime, m_result.solveTime ) ); } } @@ -297,4 +298,4 @@ void HypreSolver::clear() m_solver.reset(); } -} // end geosx namespace +} // end geos namespace diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreSolver.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreSolver.hpp index ff1162c8a33..42c4bde43e8 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreSolver.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreSolver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -92,13 +93,8 @@ class HypreSolver final : public LinearSolverBase< HypreInterface > /// Pointers to hypre functions for the krylov solver std::unique_ptr< HypreSolverWrapper > m_solver; - - /// Time of the most recent SC matrix construction - real64 m_componentFilterTime; - real64 m_makeRestrictorTime; - real64 m_computeAuuTime; }; -} // end geosx namespace +} // end geos namespace #endif /* HYPRESOLVER_HPP_ */ diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreUtils.cpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreUtils.cpp index cd20aa4a653..80a6ffba199 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreUtils.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreUtils.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 Total, S.A - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -59,7 +60,7 @@ HYPRE_Int SuperLUDistSolve( HYPRE_Solver solver, HYPRE_ParVector x ) { GEOS_UNUSED_VAR( A ); -#if defined(GEOSX_USE_SUPERLU_DIST) +#if defined(GEOS_USE_SUPERLU_DIST) return hypre_SLUDistSolve( solver, b, x ); #else GEOS_UNUSED_VAR( solver ); @@ -72,7 +73,7 @@ HYPRE_Int SuperLUDistSolve( HYPRE_Solver solver, HYPRE_Int SuperLUDistDestroy( HYPRE_Solver solver ) { -#if defined(GEOSX_USE_SUPERLU_DIST) +#if defined(GEOS_USE_SUPERLU_DIST) return hypre_SLUDistDestroy( solver ); #else GEOS_UNUSED_VAR( solver ); diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreUtils.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreUtils.hpp index 6bf3d1b9631..47f901330f0 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreUtils.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreUtils.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -157,7 +158,7 @@ inline void checkDeviceErrors( char const * msg, char const * file, int const li GEOS_ERROR_IF( err != cudaSuccess, GEOS_FMT( "Previous CUDA errors found: {} ({} at {}:{})", msg, cudaGetErrorString( err ), file, line ) ); #elif GEOS_USE_HYPRE_DEVICE == GEOS_USE_HYPRE_HIP hipError_t const err = hipGetLastError(); - GEOS_UNUSED_VAR( msg, file, line ); // on crusher geosx_error_if ultimately resolves to an assert, which drops the content on release + GEOS_UNUSED_VAR( msg, file, line ); // on crusher geos_error_if ultimately resolves to an assert, which drops the content on release // builds GEOS_ERROR_IF( err != hipSuccess, GEOS_FMT( "Previous HIP errors found: {} ({} at {}:{})", msg, hipGetErrorString( err ), file, line ) ); #else @@ -398,6 +399,8 @@ inline HYPRE_Int getAMGCoarseType( LinearSolverParameters::AMG::CoarseType const { LinearSolverParameters::AMG::CoarseType::direct, 9 }, { LinearSolverParameters::AMG::CoarseType::chebyshev, 16 }, { LinearSolverParameters::AMG::CoarseType::l1jacobi, 18 }, + { LinearSolverParameters::AMG::CoarseType::gsElimWPivoting, 99 }, + { LinearSolverParameters::AMG::CoarseType::gsElimWInverse, 199 }, }; return findOption( typeMap, type, "multigrid coarse solver", "HyprePreconditioner" ); } @@ -515,9 +518,8 @@ enum class MGRCoarseGridMethod : HYPRE_Int //!< approximated by its diagonal inverse cprLikeBlockDiag = 3, //!< Non-Galerkin coarse grid computation with dropping strategy: CPR-like approximation with inv(A_FF) //!< approximated by its block diagonal inverse - approximateInverse = 4, //!< Non-Galerkin coarse grid computation with dropping strategy: inv(A_FF) approximated by sparse approximate + approximateInverse = 4 //!< Non-Galerkin coarse grid computation with dropping strategy: inv(A_FF) approximated by sparse approximate //!< inverse - galerkinRAI = 5 //!< Galerkin coarse grid computation with arbitrary classical restriction and injective prolongation }; /** diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreVector.cpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreVector.cpp index 7353fc698ce..5b6f7b30790 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreVector.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreVector.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreVector.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreVector.hpp index 4f345531ad1..771c1cfe30a 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreVector.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreVector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseFVM.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseFVM.hpp index 4c0f16f5766..e496997a70c 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseFVM.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseFVM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -70,11 +71,10 @@ class CompositionalMultiphaseFVM : public MGRStrategyBase< 2 > m_levelCoarseGridMethod[0] = MGRCoarseGridMethod::galerkin; m_levelGlobalSmootherType[0] = MGRGlobalSmootherType::none; - m_levelFRelaxType[1] = MGRFRelaxationType::jacobi; - m_levelFRelaxIters[1] = 1; + m_levelFRelaxType[1] = MGRFRelaxationType::none; m_levelInterpType[1] = MGRInterpolationType::injection; m_levelRestrictType[1] = MGRRestrictionType::blockColLumped; // True-IMPES - m_levelCoarseGridMethod[1] = MGRCoarseGridMethod::galerkinRAI; + m_levelCoarseGridMethod[1] = MGRCoarseGridMethod::galerkin; m_levelGlobalSmootherType[1] = MGRGlobalSmootherType::ilu0; m_levelGlobalSmootherIters[1] = 1; } diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseHybridFVM.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseHybridFVM.hpp index 091e55857b1..5f1b8a87f98 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseHybridFVM.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseHybridFVM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -79,11 +80,10 @@ class CompositionalMultiphaseHybridFVM : public MGRStrategyBase< 3 > m_levelGlobalSmootherType[0] = MGRGlobalSmootherType::none; // Level 1 - m_levelFRelaxType[1] = MGRFRelaxationType::jacobi; - m_levelFRelaxIters[1] = 1; + m_levelFRelaxType[1] = MGRFRelaxationType::none; m_levelInterpType[1] = MGRInterpolationType::jacobi; m_levelRestrictType[1] = MGRRestrictionType::blockColLumped; // True-IMPES - m_levelCoarseGridMethod[1] = MGRCoarseGridMethod::galerkinRAI; + m_levelCoarseGridMethod[1] = MGRCoarseGridMethod::galerkin; m_levelGlobalSmootherType[1] = MGRGlobalSmootherType::none; // Level 2 diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseReservoirFVM.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseReservoirFVM.hpp index 2c994aef5e3..1042906b43e 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseReservoirFVM.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseReservoirFVM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -91,11 +92,10 @@ class CompositionalMultiphaseReservoirFVM : public MGRStrategyBase< 3 > m_levelGlobalSmootherType[1] = MGRGlobalSmootherType::none; // level 2 - m_levelFRelaxType[2] = MGRFRelaxationType::jacobi; - m_levelFRelaxIters[2] = 1; + m_levelFRelaxType[2] = MGRFRelaxationType::none; m_levelInterpType[2] = MGRInterpolationType::injection; m_levelRestrictType[2] = MGRRestrictionType::blockColLumped; // True-IMPES - m_levelCoarseGridMethod[2] = MGRCoarseGridMethod::galerkinRAI; + m_levelCoarseGridMethod[2] = MGRCoarseGridMethod::galerkin; m_levelGlobalSmootherType[2] = MGRGlobalSmootherType::ilu0; m_levelGlobalSmootherIters[2] = 1; } diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseReservoirHybridFVM.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseReservoirHybridFVM.hpp index 929c02d598c..8fcf6d3b189 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseReservoirHybridFVM.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseReservoirHybridFVM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -99,11 +100,10 @@ class CompositionalMultiphaseReservoirHybridFVM : public MGRStrategyBase< 4 > m_levelGlobalSmootherType[1] = MGRGlobalSmootherType::none; // Level 2 - m_levelFRelaxType[2] = MGRFRelaxationType::jacobi; - m_levelFRelaxIters[2] = 1; + m_levelFRelaxType[2] = MGRFRelaxationType::none; m_levelInterpType[2] = MGRInterpolationType::injection; m_levelRestrictType[2] = MGRRestrictionType::blockColLumped; // True-IMPES - m_levelCoarseGridMethod[2] = MGRCoarseGridMethod::galerkinRAI; + m_levelCoarseGridMethod[2] = MGRCoarseGridMethod::galerkin; m_levelGlobalSmootherType[2] = MGRGlobalSmootherType::none; // Level 3 diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/HybridSinglePhasePoromechanics.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/HybridSinglePhasePoromechanics.hpp index 1621c9c2c45..1b595cb0cee 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/HybridSinglePhasePoromechanics.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/HybridSinglePhasePoromechanics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -83,10 +84,11 @@ class HybridSinglePhasePoromechanics : public MGRStrategyBase< 2 > /** * @brief Setup the MGR strategy. + * @param mgrParams MGR configuration parameters * @param precond preconditioner wrapper * @param mgrData auxiliary MGR data */ - void setup( LinearSolverParameters::MGR const &, + void setup( LinearSolverParameters::MGR const & mgrParams, HyprePrecWrapper & precond, HypreMGRData & mgrData ) { @@ -95,7 +97,7 @@ class HybridSinglePhasePoromechanics : public MGRStrategyBase< 2 > GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetPMaxElmts( precond.ptr, 0 )); // Configure the BoomerAMG solver used as F-relaxation for the first level - setMechanicsFSolver( precond, mgrData ); + setMechanicsFSolver( precond, mgrData, mgrParams.separateComponents ); // Configure the BoomerAMG solver used as mgr coarse solver for the pressure reduced system setPressureAMG( mgrData.coarseSolver ); diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/Hydrofracture.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/Hydrofracture.hpp index 1e5b07c1fa6..3555d7d824e 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/Hydrofracture.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/Hydrofracture.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -69,17 +70,18 @@ class Hydrofracture : public MGRStrategyBase< 1 > /** * @brief Setup the MGR strategy. + * @param mgrParams MGR configuration parameters * @param precond preconditioner wrapper * @param mgrData auxiliary MGR data */ - void setup( LinearSolverParameters::MGR const &, + void setup( LinearSolverParameters::MGR const & mgrParams, HyprePrecWrapper & precond, HypreMGRData & mgrData ) { setReduction( precond, mgrData ); // Configure the BoomerAMG solver used as F-relaxation for the first level - setMechanicsFSolver( precond, mgrData ); + setMechanicsFSolver( precond, mgrData, mgrParams.separateComponents ); // Configure the BoomerAMG solver used as mgr coarse solver for the pressure reduced system setPressureAMG( mgrData.coarseSolver ); diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/LagrangianContactMechanics.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/LagrangianContactMechanics.hpp index 09955322284..40d9d565a9e 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/LagrangianContactMechanics.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/LagrangianContactMechanics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -75,10 +76,11 @@ class LagrangianContactMechanics : public MGRStrategyBase< 1 > /** * @brief Setup the MGR strategy. + * @param mgrParams MGR configuration parameters * @param precond preconditioner wrapper * @param mgrData auxiliary MGR data */ - void setup( LinearSolverParameters::MGR const &, + void setup( LinearSolverParameters::MGR const & mgrParams, HyprePrecWrapper & precond, HypreMGRData & mgrData ) { @@ -86,7 +88,7 @@ class LagrangianContactMechanics : public MGRStrategyBase< 1 > // Configure the BoomerAMG solver used as mgr coarse solver for the displacement reduced system // (note that no separate displacement component approach is used here) - setDisplacementAMG( mgrData.coarseSolver ); + setDisplacementAMG( mgrData.coarseSolver, mgrParams.separateComponents ); } }; diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/MultiphasePoromechanics.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/MultiphasePoromechanics.hpp index c8a9c878213..90c0d3d3d05 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/MultiphasePoromechanics.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/MultiphasePoromechanics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -71,46 +72,44 @@ class MultiphasePoromechanics : public MGRStrategyBase< 3 > setupLabels(); // Level 0 - m_levelFRelaxType[0] = MGRFRelaxationType::amgVCycle; - m_levelFRelaxIters[0] = 1; - m_levelInterpType[0] = MGRInterpolationType::jacobi; - m_levelRestrictType[0] = MGRRestrictionType::injection; - m_levelCoarseGridMethod[0] = MGRCoarseGridMethod::nonGalerkin; - m_levelGlobalSmootherType[0] = MGRGlobalSmootherType::none; + m_levelFRelaxType[0] = MGRFRelaxationType::amgVCycle; + m_levelFRelaxIters[0] = 1; + m_levelInterpType[0] = MGRInterpolationType::jacobi; + m_levelRestrictType[0] = MGRRestrictionType::injection; + m_levelCoarseGridMethod[0] = MGRCoarseGridMethod::nonGalerkin; + m_levelGlobalSmootherType[0] = MGRGlobalSmootherType::none; // Level 1 - m_levelFRelaxType[1] = MGRFRelaxationType::jacobi; - m_levelFRelaxIters[1] = 1; - m_levelInterpType[1] = MGRInterpolationType::jacobi; - m_levelRestrictType[1] = MGRRestrictionType::injection; - m_levelCoarseGridMethod[1] = MGRCoarseGridMethod::galerkin; - m_levelGlobalSmootherType[1] = MGRGlobalSmootherType::none; + m_levelFRelaxType[1] = MGRFRelaxationType::jacobi; + m_levelFRelaxIters[1] = 1; + m_levelInterpType[1] = MGRInterpolationType::jacobi; + m_levelRestrictType[1] = MGRRestrictionType::injection; + m_levelCoarseGridMethod[1] = MGRCoarseGridMethod::galerkin; + m_levelGlobalSmootherType[1] = MGRGlobalSmootherType::none; // Level 2 - m_levelFRelaxType[2] = MGRFRelaxationType::jacobi; - m_levelFRelaxIters[2] = 1; + m_levelFRelaxType[2] = MGRFRelaxationType::none; m_levelInterpType[2] = MGRInterpolationType::injection; m_levelRestrictType[2] = MGRRestrictionType::blockColLumped; // True-IMPES - m_levelCoarseGridMethod[2] = MGRCoarseGridMethod::galerkinRAI; + m_levelCoarseGridMethod[2] = MGRCoarseGridMethod::galerkin; m_levelGlobalSmootherType[2] = MGRGlobalSmootherType::ilu0; m_levelGlobalSmootherIters[2] = 1; } /** * @brief Setup the MGR strategy. + * @param mgrParams MGR configuration parameters * @param precond preconditioner wrapper * @param mgrData auxiliary MGR data */ - void setup( LinearSolverParameters::MGR const &, + void setup( LinearSolverParameters::MGR const & mgrParams, HyprePrecWrapper & precond, HypreMGRData & mgrData ) { setReduction( precond, mgrData ); - GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetPMaxElmts( precond.ptr, 0 )); - // Configure the BoomerAMG solver used as F-relaxation for the first level - setMechanicsFSolver( precond, mgrData ); + setMechanicsFSolver( precond, mgrData, mgrParams.separateComponents ); // Configure the BoomerAMG solver used as mgr coarse solver for the pressure reduced system setPressureAMG( mgrData.coarseSolver ); diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/MultiphasePoromechanicsReservoirFVM.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/MultiphasePoromechanicsReservoirFVM.hpp index 22b3843b4d6..97c91e28979 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/MultiphasePoromechanicsReservoirFVM.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/MultiphasePoromechanicsReservoirFVM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -83,42 +84,41 @@ class MultiphasePoromechanicsReservoirFVM : public MGRStrategyBase< 4 > setupLabels(); // Level 0 - m_levelFRelaxType[0] = MGRFRelaxationType::amgVCycle; - m_levelFRelaxIters[0] = 1; - m_levelInterpType[0] = MGRInterpolationType::jacobi; - m_levelRestrictType[0] = MGRRestrictionType::injection; - m_levelCoarseGridMethod[0] = MGRCoarseGridMethod::nonGalerkin; - m_levelGlobalSmootherType[0] = MGRGlobalSmootherType::none; + m_levelFRelaxType[0] = MGRFRelaxationType::amgVCycle; + m_levelFRelaxIters[0] = 1; + m_levelInterpType[0] = MGRInterpolationType::jacobi; + m_levelRestrictType[0] = MGRRestrictionType::injection; + m_levelCoarseGridMethod[0] = MGRCoarseGridMethod::nonGalerkin; + m_levelGlobalSmootherType[0] = MGRGlobalSmootherType::none; // Level 1 m_levelFRelaxType[1] = MGRFRelaxationType::gsElimWInverse; - m_levelFRelaxIters[1] = 1; - m_levelInterpType[1] = MGRInterpolationType::blockJacobi; - m_levelRestrictType[1] = MGRRestrictionType::injection; - m_levelCoarseGridMethod[1] = MGRCoarseGridMethod::galerkin; - m_levelGlobalSmootherType[0] = MGRGlobalSmootherType::none; + m_levelFRelaxIters[1] = 1; + m_levelInterpType[1] = MGRInterpolationType::blockJacobi; + m_levelRestrictType[1] = MGRRestrictionType::injection; + m_levelCoarseGridMethod[1] = MGRCoarseGridMethod::galerkin; + m_levelGlobalSmootherType[1] = MGRGlobalSmootherType::none; // Level 2 - m_levelFRelaxType[2] = MGRFRelaxationType::jacobi; //default, i.e. Jacobi - m_levelFRelaxIters[2] = 1; - m_levelInterpType[2] = MGRInterpolationType::jacobi; - m_levelRestrictType[2] = MGRRestrictionType::injection; - m_levelCoarseGridMethod[2] = MGRCoarseGridMethod::galerkin; - m_levelGlobalSmootherType[2] = MGRGlobalSmootherType::none; - - // Level 3 m_levelFRelaxType[2] = MGRFRelaxationType::jacobi; //default, i.e. Jacobi m_levelFRelaxIters[2] = 1; + m_levelInterpType[2] = MGRInterpolationType::jacobi; + m_levelRestrictType[2] = MGRRestrictionType::injection; + m_levelCoarseGridMethod[2] = MGRCoarseGridMethod::galerkin; + m_levelGlobalSmootherType[2] = MGRGlobalSmootherType::none; + + // Level 3 + m_levelFRelaxType[3] = MGRFRelaxationType::none; m_levelInterpType[3] = MGRInterpolationType::injection; m_levelRestrictType[3] = MGRRestrictionType::blockColLumped; // True-IMPES - m_levelCoarseGridMethod[3] = MGRCoarseGridMethod::galerkinRAI; + m_levelCoarseGridMethod[3] = MGRCoarseGridMethod::galerkin; m_levelGlobalSmootherType[3] = MGRGlobalSmootherType::ilu0; m_levelGlobalSmootherIters[3] = 1; } /** * @brief Setup the MGR strategy. - * @param mgrParams parameters for the configuration of the MGR recipe + * @param mgrParams MGR configuration parameters * @param precond preconditioner wrapper * @param mgrData auxiliary MGR data */ @@ -135,10 +135,8 @@ class MultiphasePoromechanicsReservoirFVM : public MGRStrategyBase< 4 > setReduction( precond, mgrData ); - GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetPMaxElmts( precond.ptr, 0 )); - // Configure the BoomerAMG solver used as F-relaxation for the first level - setMechanicsFSolver( precond, mgrData ); + setMechanicsFSolver( precond, mgrData, mgrParams.separateComponents ); // Configure the BoomerAMG solver used as mgr coarse solver for the pressure reduced system setPressureAMG( mgrData.coarseSolver ); diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ReactiveCompositionalMultiphaseOBL.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ReactiveCompositionalMultiphaseOBL.hpp index 38792f6baff..ee2561ad491 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ReactiveCompositionalMultiphaseOBL.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ReactiveCompositionalMultiphaseOBL.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -65,8 +66,7 @@ class ReactiveCompositionalMultiphaseOBL : public MGRStrategyBase< 1 > setupLabels(); - m_levelFRelaxType[0] = MGRFRelaxationType::jacobi; - m_levelFRelaxIters[0] = 1; + m_levelFRelaxType[0] = MGRFRelaxationType::none; m_levelInterpType[0] = MGRInterpolationType::injection; m_levelRestrictType[0] = MGRRestrictionType::injection; m_levelCoarseGridMethod[0] = MGRCoarseGridMethod::cprLikeBlockDiag; diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseHybridFVM.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseHybridFVM.hpp index f740db535e9..b7c9c5dc78e 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseHybridFVM.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseHybridFVM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanics.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanics.hpp index dd1b14b568d..47fc589406b 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanics.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -69,19 +70,18 @@ class SinglePhasePoromechanics : public MGRStrategyBase< 1 > /** * @brief Setup the MGR strategy. + * @param mgrParams MGR configuration parameters * @param precond preconditioner wrapper * @param mgrData auxiliary MGR data */ - void setup( LinearSolverParameters::MGR const &, + void setup( LinearSolverParameters::MGR const & mgrParams, HyprePrecWrapper & precond, HypreMGRData & mgrData ) { setReduction( precond, mgrData ); - GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetPMaxElmts( precond.ptr, 0 )); - // Configure the BoomerAMG solver used as F-relaxation for the first level - setMechanicsFSolver( precond, mgrData ); + setMechanicsFSolver( precond, mgrData, mgrParams.separateComponents ); // Configure the BoomerAMG solver used as mgr coarse solver for the pressure reduced system setPressureAMG( mgrData.coarseSolver ); diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanicsConformingFractures.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanicsConformingFractures.hpp index 0dfb0b0ec88..ad7c37179a0 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanicsConformingFractures.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanicsConformingFractures.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,8 +22,6 @@ #include "linearAlgebra/interfaces/hypre/HypreMGR.hpp" -#define BRANCH_MGR_FSOLVER - namespace geos { @@ -38,15 +37,15 @@ namespace mgr * dofLabel: 0 = displacement, x-component * dofLabel: 1 = displacement, y-component * dofLabel: 2 = displacement, z-component - * dofLabel: 3 = pressure (cell elem + fracture elems) - * dofLabel: 4 = face-centered lagrange multiplier (tn) - * dofLabel: 5 = face-centered lagrange multiplier (tt1) - * dofLabel: 6 = face-centered lagrange multiplier (tt2) + * dofLabel: 3 = face-centered lagrange multiplier (tn) + * dofLabel: 4 = face-centered lagrange multiplier (tt1) + * dofLabel: 5 = face-centered lagrange multiplier (tt2) + * dofLabel: 6 = pressure (cell elem + fracture elems) * * Ingredients: - * 1. Level 1: F-points displacement (4,5,6), C-points pressure (0,1,2,3) - * 2. Level 2: F-points displacement (0,1,2), C-points pressure (3) + * 1. Level 1: F-points displacement (3,4,5), C-points pressure (0,1,2,6) + * 2. Level 2: F-points displacement (0,1,2), C-points pressure (6) * 2. F-points smoother: BoomerAMG, single V-cycle * 3. C-points coarse-grid/Schur complement solver: BoomerAMG * 4. Global smoother: none @@ -66,9 +65,9 @@ class SinglePhasePoromechanicsConformingFractures : public MGRStrategyBase< 2 > m_labels[0].push_back( 0 ); m_labels[0].push_back( 1 ); m_labels[0].push_back( 2 ); - m_labels[0].push_back( 3 ); + m_labels[0].push_back( 6 ); // we keep p - m_labels[1].push_back( 3 ); + m_labels[1].push_back( 6 ); setupLabels(); @@ -103,7 +102,6 @@ class SinglePhasePoromechanicsConformingFractures : public MGRStrategyBase< 2 > HypreMGRData & mgrData ) { setReduction( precond, mgrData ); - GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetPMaxElmts( precond.ptr, 0 )); // Configure the BoomerAMG solver used as F-relaxation for the second level GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGCreate( &mgrData.mechSolver.ptr ) ); @@ -121,7 +119,7 @@ class SinglePhasePoromechanicsConformingFractures : public MGRStrategyBase< 2 > #else GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetRelaxOrder( mgrData.mechSolver.ptr, 1 ) ); #endif - GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetFSolverAtLevel( 1, precond.ptr, mgrData.mechSolver.ptr ) ); + GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetFSolverAtLevel( precond.ptr, mgrData.mechSolver.ptr, 1 ) ); // Configure the BoomerAMG solver used as mgr coarse solver for the pressure reduced system setPressureAMG( mgrData.coarseSolver ); diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanicsEmbeddedFractures.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanicsEmbeddedFractures.hpp index 36d8051f1ad..8546b24fcef 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanicsEmbeddedFractures.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanicsEmbeddedFractures.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -82,7 +83,6 @@ class SinglePhasePoromechanicsEmbeddedFractures : public MGRStrategyBase< 2 > m_levelInterpType[1] = MGRInterpolationType::jacobi; m_levelRestrictType[1] = MGRRestrictionType::injection; m_levelCoarseGridMethod[1] = MGRCoarseGridMethod::nonGalerkin; - } /** @@ -96,8 +96,6 @@ class SinglePhasePoromechanicsEmbeddedFractures : public MGRStrategyBase< 2 > { setReduction( precond, mgrData ); - GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetPMaxElmts( precond.ptr, 0 )); - // Configure the BoomerAMG solver used as F-relaxation for the second level GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGCreate( &mgrData.mechSolver.ptr ) ); GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetTol( mgrData.mechSolver.ptr, 0.0 ) ); @@ -114,7 +112,7 @@ class SinglePhasePoromechanicsEmbeddedFractures : public MGRStrategyBase< 2 > #else GEOS_LAI_CHECK_ERROR( HYPRE_BoomerAMGSetRelaxOrder( mgrData.mechSolver.ptr, 1 ) ); #endif - GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetFSolverAtLevel( 1, precond.ptr, mgrData.mechSolver.ptr ) ); + GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetFSolverAtLevel( precond.ptr, mgrData.mechSolver.ptr, 1 ) ); // Configure the BoomerAMG solver used as mgr coarse solver for the pressure reduced system setPressureAMG( mgrData.coarseSolver ); diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanicsReservoirFVM.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanicsReservoirFVM.hpp index 97ace112cf8..a3f5b05918f 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanicsReservoirFVM.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhasePoromechanicsReservoirFVM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -74,7 +75,7 @@ class SinglePhasePoromechanicsReservoirFVM : public MGRStrategyBase< 2 > m_levelGlobalSmootherType[0] = MGRGlobalSmootherType::none; // Level 1 - m_levelFRelaxType[1] = MGRFRelaxationType::gsElimWInverse; + m_levelFRelaxType[1] = MGRFRelaxationType::gsElimWInverse; m_levelFRelaxIters[1] = 1; m_levelInterpType[1] = MGRInterpolationType::blockJacobi; m_levelRestrictType[1] = MGRRestrictionType::injection; @@ -84,19 +85,18 @@ class SinglePhasePoromechanicsReservoirFVM : public MGRStrategyBase< 2 > /** * @brief Setup the MGR strategy. + * @param mgrParams MGR configuration parameters * @param precond preconditioner wrapper * @param mgrData auxiliary MGR data */ - void setup( LinearSolverParameters::MGR const &, + void setup( LinearSolverParameters::MGR const & mgrParams, HyprePrecWrapper & precond, HypreMGRData & mgrData ) { setReduction( precond, mgrData ); - GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetPMaxElmts( precond.ptr, 0 )); - // Configure the BoomerAMG solver used as F-relaxation for the first level - setMechanicsFSolver( precond, mgrData ); + setMechanicsFSolver( precond, mgrData, mgrParams.separateComponents ); // Configure the BoomerAMG solver used as mgr coarse solver for the pressure reduced system setPressureAMG( mgrData.coarseSolver ); diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseReservoirFVM.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseReservoirFVM.hpp index d72c64c5c3a..39f4d796889 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseReservoirFVM.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseReservoirFVM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseReservoirHybridFVM.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseReservoirHybridFVM.hpp index e8ef8c7900b..fcb2c664e49 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseReservoirHybridFVM.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseReservoirHybridFVM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SolidMechanicsEmbeddedFractures.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SolidMechanicsEmbeddedFractures.hpp index 22f11501731..83cee477b41 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SolidMechanicsEmbeddedFractures.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/SolidMechanicsEmbeddedFractures.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -64,7 +65,7 @@ class SolidMechanicsEmbeddedFractures : public MGRStrategyBase< 1 > setupLabels(); // Level 0 - m_levelFRelaxType[0] = MGRFRelaxationType::gsElimWInverse; + m_levelFRelaxType[0] = MGRFRelaxationType::jacobi; m_levelFRelaxIters[0] = 1; m_levelInterpType[0] = MGRInterpolationType::blockJacobi; m_levelRestrictType[0] = MGRRestrictionType::injection; @@ -74,18 +75,18 @@ class SolidMechanicsEmbeddedFractures : public MGRStrategyBase< 1 > /** * @brief Setup the MGR strategy. + * @param mgrParams MGR configuration parameters * @param precond preconditioner wrapper * @param mgrData auxiliary MGR data */ - void setup( LinearSolverParameters::MGR const &, + void setup( LinearSolverParameters::MGR const & mgrParams, HyprePrecWrapper & precond, HypreMGRData & mgrData ) { setReduction( precond, mgrData ); - GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetPMaxElmts( precond.ptr, 0 )); // Configure the BoomerAMG solver used as mgr coarse solver for the displacement reduced system - setDisplacementAMG( mgrData.coarseSolver ); + setDisplacementAMG( mgrData.coarseSolver, mgrParams.separateComponents ); } }; diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseFVM.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseFVM.hpp index 0cea36ca96e..08800ab2d64 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseFVM.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseFVM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -70,13 +71,12 @@ class ThermalCompositionalMultiphaseFVM : public MGRStrategyBase< 2 > m_levelFRelaxIters[0] = 1; m_levelInterpType[0] = MGRInterpolationType::jacobi; // Diagonal scaling (Jacobi) m_levelRestrictType[0] = MGRRestrictionType::injection; - m_levelCoarseGridMethod[0] = MGRCoarseGridMethod::galerkin; // Standard Galerkin + m_levelCoarseGridMethod[0] = MGRCoarseGridMethod::galerkin; m_levelGlobalSmootherType[0] = MGRGlobalSmootherType::blockGaussSeidel; m_levelGlobalSmootherIters[0] = 1; - m_levelFRelaxType[1] = MGRFRelaxationType::jacobi; - m_levelFRelaxIters[1] = 1; - m_levelInterpType[1] = MGRInterpolationType::injection; // Injection + m_levelFRelaxType[1] = MGRFRelaxationType::none; + m_levelInterpType[1] = MGRInterpolationType::injection; m_levelRestrictType[1] = MGRRestrictionType::injection; m_levelCoarseGridMethod[1] = MGRCoarseGridMethod::cprLikeBlockDiag; // Non-Galerkin Quasi-IMPES CPR m_levelGlobalSmootherType[1] = MGRGlobalSmootherType::ilu0; diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp new file mode 100644 index 00000000000..09b5b832035 --- /dev/null +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp @@ -0,0 +1,132 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalCompositionalMultiphaseFVM.hpp + */ + +#ifndef GEOS_LINEARALGEBRA_INTERFACES_HYPREMGRTHERMALCOMPOSITIONALMULTIPHASERESERVOIRFVM_HPP_ +#define GEOS_LINEARALGEBRA_INTERFACES_HYPREMGRTHERMALCOMPOSITIONALMULTIPHASERESERVOIRFVM_HPP_ + +#include "linearAlgebra/interfaces/hypre/HypreMGR.hpp" + +namespace geos +{ + +namespace hypre +{ + +namespace mgr +{ + +/** + * @brief ThermalCompositionalMultiphaseReservoirFVM strategy. + * + * Labels description stored in point_marker_array + * 0 = reservoir pressure + * 1 = reservoir density (component 1 ) + * ... = reservoir densities (# components , NC) + * NC + 1 = reservoir temperature + * + * numResLabels - 1 = reservoir temperature + * numResLabels = well pressure + * numResLabels + 1 = well density + * ... = ... (well densities) + * numResLabels + numWellLabels - 3 = last well density + * numResLabels + numWellLabels - 2 = well rate + * numResLabels + numWellLabels - 1 = well temperature + * + * 3-level MGR reduction strategy + * - 1st level: eliminate the well block + * - 2nd level: eliminate the reservoir density associated with the volume constraint + * - 3rd level: eliminate the remaining the reservoir densities + * - The coarse grid (pressure and temperature system) is solved with BoomerAMG with numFunctions==2. + * + */ + +class ThermalCompositionalMultiphaseReservoirFVM : public MGRStrategyBase< 3 > +{ +public: + /** + * @brief Constructor. + * @param numComponentsPerField array with number of components for each field + */ + explicit ThermalCompositionalMultiphaseReservoirFVM( arrayView1d< int const > const & numComponentsPerField ) + : MGRStrategyBase( LvArray::integerConversion< HYPRE_Int >( numComponentsPerField[0] + numComponentsPerField[1] ) ) + { + HYPRE_Int const numResLabels = LvArray::integerConversion< HYPRE_Int >( numComponentsPerField[0] ); + + // Level 0: eliminate the well block + m_labels[0].resize( numResLabels ); + std::iota( m_labels[0].begin(), m_labels[0].end(), 0 ); + + // Level 1: eliminate last density which corresponds to the volume constraint equation + m_labels[1].resize( numResLabels - 2 ); + std::iota( m_labels[1].begin(), m_labels[1].end(), 0 ); + m_labels[1].push_back( numResLabels-1 ); // keep temperature + // Level 2: eliminate the other densities + m_labels[2].push_back( 0 ); // keep pressure + m_labels[2].push_back( numResLabels-1 ); // keep temperature + + setupLabels(); + + // level 0 + m_levelFRelaxType[0] = MGRFRelaxationType::gsElimWInverse; + m_levelFRelaxIters[0] = 1; + m_levelInterpType[0] = MGRInterpolationType::blockJacobi; + m_levelRestrictType[0] = MGRRestrictionType::injection; + m_levelCoarseGridMethod[0] = MGRCoarseGridMethod::galerkin; + m_levelGlobalSmootherType[0] = MGRGlobalSmootherType::none; + + m_levelFRelaxType[1] = MGRFRelaxationType::jacobi; + m_levelFRelaxIters[1] = 1; + m_levelInterpType[1] = MGRInterpolationType::jacobi; // Diagonal scaling (Jacobi) + m_levelRestrictType[1] = MGRRestrictionType::injection; + m_levelCoarseGridMethod[1] = MGRCoarseGridMethod::galerkin; // Standard Galerkin + m_levelGlobalSmootherType[1] = MGRGlobalSmootherType::blockGaussSeidel; + m_levelGlobalSmootherIters[1] = 1; + + m_levelFRelaxType[2] = MGRFRelaxationType::jacobi; + m_levelFRelaxIters[2] = 1; + m_levelInterpType[2] = MGRInterpolationType::injection; // Injection + m_levelRestrictType[2] = MGRRestrictionType::injection; + m_levelCoarseGridMethod[2] = MGRCoarseGridMethod::cprLikeBlockDiag; // Non-Galerkin Quasi-IMPES CPR + m_levelGlobalSmootherType[2] = MGRGlobalSmootherType::ilu0; + m_levelGlobalSmootherIters[2] = 1; + } + + /** + * @brief Setup the MGR strategy. + * @param precond preconditioner wrapper + * @param mgrData auxiliary MGR data + */ + void setup( LinearSolverParameters::MGR const &, + HyprePrecWrapper & precond, + HypreMGRData & mgrData ) + { + setReduction( precond, mgrData ); + + // Configure the BoomerAMG solver used as mgr coarse solver for the pressure/temperature reduced system + setPressureTemperatureAMG( mgrData.coarseSolver ); + } +}; + +} // namespace mgr + +} // namespace hypre + +} // namespace geos + +#endif /*GEOS_LINEARALGEBRA_INTERFACES_HYPREMGRCOMPOSITIONALMULTIPHASERESERVOIRFVM_HPP_*/ diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalMultiphasePoromechanics.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalMultiphasePoromechanics.hpp index 68ea0e4cf10..a276456ee32 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalMultiphasePoromechanics.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalMultiphasePoromechanics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -74,24 +75,23 @@ class ThermalMultiphasePoromechanics : public MGRStrategyBase< 3 > setupLabels(); // Level 0 - m_levelFRelaxType[0] = MGRFRelaxationType::amgVCycle; - m_levelFRelaxIters[0] = 1; - m_levelInterpType[0] = MGRInterpolationType::jacobi; - m_levelRestrictType[0] = MGRRestrictionType::injection; - m_levelCoarseGridMethod[0] = MGRCoarseGridMethod::nonGalerkin; - m_levelGlobalSmootherType[0] = MGRGlobalSmootherType::none; + m_levelFRelaxType[0] = MGRFRelaxationType::amgVCycle; + m_levelFRelaxIters[0] = 1; + m_levelInterpType[0] = MGRInterpolationType::jacobi; + m_levelRestrictType[0] = MGRRestrictionType::injection; + m_levelCoarseGridMethod[0] = MGRCoarseGridMethod::nonGalerkin; + m_levelGlobalSmootherType[0] = MGRGlobalSmootherType::none; // Level 1 - m_levelFRelaxType[1] = MGRFRelaxationType::jacobi; - m_levelFRelaxIters[1] = 1; - m_levelInterpType[1] = MGRInterpolationType::jacobi; - m_levelRestrictType[1] = MGRRestrictionType::injection; - m_levelCoarseGridMethod[1] = MGRCoarseGridMethod::galerkin; - m_levelGlobalSmootherType[1] = MGRGlobalSmootherType::none; + m_levelFRelaxType[1] = MGRFRelaxationType::jacobi; + m_levelFRelaxIters[1] = 1; + m_levelInterpType[1] = MGRInterpolationType::jacobi; + m_levelRestrictType[1] = MGRRestrictionType::injection; + m_levelCoarseGridMethod[1] = MGRCoarseGridMethod::galerkin; + m_levelGlobalSmootherType[1] = MGRGlobalSmootherType::none; // Level 2 - m_levelFRelaxType[2] = MGRFRelaxationType::jacobi; - m_levelFRelaxIters[2] = 1; + m_levelFRelaxType[2] = MGRFRelaxationType::none; m_levelInterpType[2] = MGRInterpolationType::injection; m_levelRestrictType[2] = MGRRestrictionType::injection; m_levelCoarseGridMethod[2] = MGRCoarseGridMethod::cprLikeBlockDiag; @@ -101,20 +101,18 @@ class ThermalMultiphasePoromechanics : public MGRStrategyBase< 3 > /** * @brief Setup the MGR strategy. + * @param mgrParams MGR configuration parameters * @param precond preconditioner wrapper * @param mgrData auxiliary MGR data */ - void setup( LinearSolverParameters::MGR const &, + void setup( LinearSolverParameters::MGR const & mgrParams, HyprePrecWrapper & precond, HypreMGRData & mgrData ) { setReduction( precond, mgrData ); - GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetPMaxElmts( precond.ptr, 0 )); - - // CHECK: the mechanics solver setup was missing: was there a reason? // Configure the BoomerAMG solver used as F-relaxation for the first level - setMechanicsFSolver( precond, mgrData ); + setMechanicsFSolver( precond, mgrData, mgrParams.separateComponents ); // Configure the BoomerAMG solver used as mgr coarse solver for the pressure/temperature reduced system setPressureTemperatureAMG( mgrData.coarseSolver ); diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalSinglePhasePoromechanics.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalSinglePhasePoromechanics.hpp index 69933bab004..bd0aa80d5da 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalSinglePhasePoromechanics.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalSinglePhasePoromechanics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -71,20 +72,18 @@ class ThermalSinglePhasePoromechanics : public MGRStrategyBase< 1 > /** * @brief Setup the MGR strategy. + * @param mgrParams MGR configuration parameters * @param precond preconditioner wrapper * @param mgrData auxiliary MGR data */ - void setup( LinearSolverParameters::MGR const &, + void setup( LinearSolverParameters::MGR const & mgrParams, HyprePrecWrapper & precond, HypreMGRData & mgrData ) { setReduction( precond, mgrData ); - GEOS_LAI_CHECK_ERROR( HYPRE_MGRSetPMaxElmts( precond.ptr, 0 )); - - // CHECK: the mechanics solver setup was missing: was there a reason? // Configure the BoomerAMG solver used as F-relaxation for the first level - setMechanicsFSolver( precond, mgrData ); + setMechanicsFSolver( precond, mgrData, mgrParams.separateComponents ); // Configure the BoomerAMG solver used as mgr coarse solver for the pressure/temperature reduced system setPressureTemperatureAMG( mgrData.coarseSolver ); diff --git a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscExport.cpp b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscExport.cpp index 4316315e80d..a4e3361252c 100644 --- a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscExport.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscExport.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscExport.hpp b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscExport.hpp index 685e3650f66..e32eab2ab40 100644 --- a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscExport.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscExport.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscInterface.cpp b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscInterface.cpp index b57a3e6a553..bb404c744eb 100644 --- a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscInterface.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscInterface.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -32,7 +33,7 @@ void PetscInterface::initialize() { PetscOptionsSetValue( nullptr, "-no_signal_handler", "" ); PetscOptionsSetValue( nullptr, "-on_error_abort", "" ); - PETSC_COMM_WORLD = MPI_COMM_GEOSX; + PETSC_COMM_WORLD = MPI_COMM_GEOS; PetscInitializeNoArguments(); } diff --git a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscInterface.hpp b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscInterface.hpp index a5c98a456d2..d49caa38cee 100644 --- a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscInterface.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscInterface.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscMatrix.cpp b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscMatrix.cpp index 3d2341cfab7..1ddf73808e2 100644 --- a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscMatrix.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscMatrix.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -733,7 +734,7 @@ void PetscMatrix::separateComponentFilter( PetscMatrix & dst, GEOS_LAI_CHECK_ERROR( MatRestoreRow( m_mat, row, &numEntries, nullptr, &vals ) ); } - dst.create( tempMatView.toViewConst(), numLocalCols(), MPI_COMM_GEOSX ); + dst.create( tempMatView.toViewConst(), numLocalCols(), MPI_COMM_GEOS ); dst.setDofManager( dofManager() ); } @@ -1287,4 +1288,4 @@ void PetscMatrix::write( string const & filename, GEOS_LAI_CHECK_ERROR( PetscViewerDestroy( &viewer ) ); } -} // end geosx namespace +} // end geos namespace diff --git a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscMatrix.hpp b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscMatrix.hpp index 1ebad306c2c..8c1666d4c42 100644 --- a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscMatrix.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscMatrix.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscPreconditioner.cpp b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscPreconditioner.cpp index 3ea2a64e951..822bf336aae 100644 --- a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscPreconditioner.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscPreconditioner.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -48,7 +49,7 @@ void convertRigidBodyModes( LinearSolverParameters const & params, GEOS_LAI_CHECK_ERROR( VecSetBlockSize( nullvecs[i], params.dofsPerNode ) ); GEOS_LAI_CHECK_ERROR( VecSetUp( nullvecs[i] ) ); } - GEOS_LAI_CHECK_ERROR( MatNullSpaceCreate( MPI_COMM_GEOSX, PETSC_FALSE, numRBM, nullvecs.data(), &nullsp ) ); + GEOS_LAI_CHECK_ERROR( MatNullSpaceCreate( MPI_COMM_GEOS, PETSC_FALSE, numRBM, nullvecs.data(), &nullsp ) ); for( localIndex i = 0; i < numRBM; ++i ) { GEOS_LAI_CHECK_ERROR( VecDestroy( &nullvecs[i] ) ); @@ -221,7 +222,7 @@ void createPetscAMG( LinearSolverParameters const & params, // Sanity checks GEOS_LAI_ASSERT_EQ( n_local, 1 ); - GEOS_LAI_ASSERT_EQ( first_local, MpiWrapper::commRank( MPI_COMM_GEOSX ) ); + GEOS_LAI_ASSERT_EQ( first_local, MpiWrapper::commRank( MPI_COMM_GEOS ) ); // Set up local block ILU preconditioner PC prec_local; diff --git a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscPreconditioner.hpp b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscPreconditioner.hpp index 3b8a49c2f7b..ac4a9891247 100644 --- a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscPreconditioner.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscPreconditioner.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscSolver.cpp b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscSolver.cpp index 19e5b1a4eae..1470cd2e4a9 100644 --- a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscSolver.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscSolver.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -24,7 +25,7 @@ #include #include -// Put everything under the geosx namespace. +// Put everything under the geos namespace. namespace geos { @@ -165,4 +166,4 @@ void PetscSolver::clear() } } -} // end geosx namespace +} // end geos namespace diff --git a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscSolver.hpp b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscSolver.hpp index 6415901b18e..4264573bda3 100644 --- a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscSolver.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscSolver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -86,6 +87,6 @@ class PetscSolver final : public LinearSolverBase< PetscInterface > KSP m_solver{}; }; -} // end geosx namespace +} // end geos namespace #endif /* PETSCSOLVER_HPP_ */ diff --git a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscUtils.hpp b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscUtils.hpp index 18a51c3a3c1..94002ab46bb 100644 --- a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscUtils.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscUtils.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscVector.cpp b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscVector.cpp index 6e38d1b1471..5e2106127bf 100644 --- a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscVector.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscVector.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -385,4 +386,4 @@ MPI_Comm PetscVector::comm() const return comm; } -} // end geosx +} // end geos diff --git a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscVector.hpp b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscVector.hpp index e561331b6e4..16a325323ff 100644 --- a/src/coreComponents/linearAlgebra/interfaces/petsc/PetscVector.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/petsc/PetscVector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -210,6 +211,6 @@ class PetscVector final : private VectorBase< PetscVector > Vec m_vec; }; -} // end geosx namespace +} // end geos namespace #endif /*GEOS_LINEARALGEBRA_INTERFACES_PETSCVECTOR_HPP_*/ diff --git a/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraExport.cpp b/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraExport.cpp index 85a9ad5ed42..30537c0764e 100644 --- a/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraExport.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraExport.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraExport.hpp b/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraExport.hpp index 139d1a74968..51e055152bc 100644 --- a/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraExport.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraExport.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraMatrix.cpp b/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraMatrix.cpp index 46dc04a9cf1..4b92501c57a 100644 --- a/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraMatrix.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraMatrix.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,6 +19,7 @@ #include "EpetraMatrix.hpp" +#include "codingUtilities/RTTypes.hpp" #include "codingUtilities/Utilities.hpp" #include "linearAlgebra/interfaces/trilinos/EpetraUtils.hpp" @@ -574,7 +576,7 @@ void EpetraMatrix::separateComponentFilter( EpetraMatrix & dst, } } ); - dst.create( tempMatView.toViewConst(), numLocalCols(), MPI_COMM_GEOSX ); + dst.create( tempMatView.toViewConst(), numLocalCols(), MPI_COMM_GEOS ); dst.setDofManager( dofManager() ); } @@ -1038,10 +1040,10 @@ localIndex EpetraMatrix::numLocalRows() const MPI_Comm EpetraMatrix::comm() const { GEOS_LAI_ASSERT( created() ); -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return dynamicCast< Epetra_MpiComm const & >( m_matrix->RowMap().Comm() ).Comm(); #else - return MPI_COMM_GEOSX; + return MPI_COMM_GEOS; #endif } @@ -1100,4 +1102,4 @@ void EpetraMatrix::multiply( bool const transA, C.m_assembled = true; } -} // end geosx namespace +} // end geos namespace diff --git a/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraMatrix.hpp b/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraMatrix.hpp index 44d907d37d5..501e5d03916 100644 --- a/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraMatrix.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraMatrix.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraUtils.hpp b/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraUtils.hpp index 980d0e52810..7ca7495574d 100644 --- a/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraUtils.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraUtils.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #include "common/DataTypes.hpp" -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI #include #else #include @@ -43,7 +44,7 @@ static_assert( std::is_signed< long long >::value == std::is_signed< geos::globa static_assert( std::is_same< double, geos::real64 >::value, "double and geos::real64 must be the same type" ); -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI /// Alias for Epetra communicator using EpetraComm = Epetra_MpiComm; #else diff --git a/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraVector.cpp b/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraVector.cpp index a94b11b8c45..a9285597103 100644 --- a/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraVector.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraVector.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,6 +19,7 @@ #include "EpetraVector.hpp" +#include "codingUtilities/RTTypes.hpp" #include "codingUtilities/Utilities.hpp" #include "linearAlgebra/interfaces/trilinos/EpetraUtils.hpp" @@ -289,11 +291,11 @@ globalIndex EpetraVector::iupper() const MPI_Comm EpetraVector::comm() const { GEOS_LAI_ASSERT( created() ); -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI return dynamicCast< Epetra_MpiComm const & >( m_vec->Map().Comm() ).Comm(); #else - return MPI_COMM_GEOSX; + return MPI_COMM_GEOS; #endif } -} // end geosx +} // end geos diff --git a/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraVector.hpp b/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraVector.hpp index 917bd365b1a..0d1b394a005 100644 --- a/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraVector.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/trilinos/EpetraVector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -190,6 +191,6 @@ class EpetraVector final : private VectorBase< EpetraVector > std::unique_ptr< Epetra_Vector > m_vec; }; -} // end geosx namespace +} // end geos namespace #endif /*GEOS_LINEARALGEBRA_INTERFACES_EPETRAVECTOR_HPP_*/ diff --git a/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosInterface.cpp b/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosInterface.cpp index 1c2d4d3fce2..39c5883876f 100644 --- a/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosInterface.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosInterface.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosInterface.hpp b/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosInterface.hpp index d2fba7c2bc5..6c3a2a06925 100644 --- a/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosInterface.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosInterface.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosPreconditioner.cpp b/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosPreconditioner.cpp index 94963add498..1f2bfb02faf 100644 --- a/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosPreconditioner.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosPreconditioner.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosPreconditioner.hpp b/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosPreconditioner.hpp index 3219767b841..2efdf01b192 100644 --- a/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosPreconditioner.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosPreconditioner.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosSolver.cpp b/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosSolver.cpp index 01b97d058c3..e6dec1a5082 100644 --- a/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosSolver.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosSolver.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -164,4 +165,4 @@ void TrilinosSolver::solve( EpetraVector const & rhs, } } -} // end geosx namespace +} // end geos namespace diff --git a/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosSolver.hpp b/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosSolver.hpp index d0bb2e7038b..a8f6b78cb0b 100644 --- a/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosSolver.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/trilinos/TrilinosSolver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -88,6 +89,6 @@ class TrilinosSolver final : public LinearSolverBase< TrilinosInterface > std::unique_ptr< AztecOO > m_solver; }; -} // end geosx namespace +} // end geos namespace #endif /* TRILINOSSOLVER_HPP_ */ diff --git a/src/coreComponents/linearAlgebra/solvers/BicgstabSolver.cpp b/src/coreComponents/linearAlgebra/solvers/BicgstabSolver.cpp index 8ba335f54dd..e8e486916d8 100644 --- a/src/coreComponents/linearAlgebra/solvers/BicgstabSolver.cpp +++ b/src/coreComponents/linearAlgebra/solvers/BicgstabSolver.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -91,8 +92,8 @@ void BicgstabSolver< VECTOR >::solve( Vector const & b, // Compute r0.rk real64 const rho = r.dot( r0 ); - GEOSX_KRYLOV_BREAKDOWN_IF_ZERO( rho_old ) - GEOSX_KRYLOV_BREAKDOWN_IF_ZERO( omega ) + GEOS_KRYLOV_BREAKDOWN_IF_ZERO( rho_old ) + GEOS_KRYLOV_BREAKDOWN_IF_ZERO( omega ) // Compute beta real64 const beta = rho / rho_old * alpha / omega; @@ -107,7 +108,7 @@ void BicgstabSolver< VECTOR >::solve( Vector const & b, // Compute alpha real64 const vr0 = v.dot( r0 ); - GEOSX_KRYLOV_BREAKDOWN_IF_ZERO( vr0 ) + GEOS_KRYLOV_BREAKDOWN_IF_ZERO( vr0 ) alpha = rho / vr0; // compute x = x + alpha*y @@ -125,7 +126,7 @@ void BicgstabSolver< VECTOR >::solve( Vector const & b, // Update omega real64 const t2 = t.dot( t ); - GEOSX_KRYLOV_BREAKDOWN_IF_ZERO( t2 ) + GEOS_KRYLOV_BREAKDOWN_IF_ZERO( t2 ) omega = t.dot( s ) / t2; // Update x = x + omega*z @@ -147,17 +148,17 @@ void BicgstabSolver< VECTOR >::solve( Vector const & b, // ----------------------- // Explicit Instantiations // ----------------------- -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS template class BicgstabSolver< TrilinosInterface::ParallelVector >; template class BicgstabSolver< BlockVectorView< TrilinosInterface::ParallelVector > >; #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE template class BicgstabSolver< HypreInterface::ParallelVector >; template class BicgstabSolver< BlockVectorView< HypreInterface::ParallelVector > >; #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC template class BicgstabSolver< PetscInterface::ParallelVector >; template class BicgstabSolver< BlockVectorView< PetscInterface::ParallelVector > >; #endif diff --git a/src/coreComponents/linearAlgebra/solvers/BicgstabSolver.hpp b/src/coreComponents/linearAlgebra/solvers/BicgstabSolver.hpp index 0c940c7edfe..41400be9b27 100644 --- a/src/coreComponents/linearAlgebra/solvers/BicgstabSolver.hpp +++ b/src/coreComponents/linearAlgebra/solvers/BicgstabSolver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/solvers/BlockPreconditioner.cpp b/src/coreComponents/linearAlgebra/solvers/BlockPreconditioner.cpp index 15840c09da6..4cbbbace185 100644 --- a/src/coreComponents/linearAlgebra/solvers/BlockPreconditioner.cpp +++ b/src/coreComponents/linearAlgebra/solvers/BlockPreconditioner.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -247,15 +248,15 @@ void BlockPreconditioner< LAI >::clear() // ----------------------- // Explicit Instantiations // ----------------------- -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS template class BlockPreconditioner< TrilinosInterface >; #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE template class BlockPreconditioner< HypreInterface >; #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC template class BlockPreconditioner< PetscInterface >; #endif diff --git a/src/coreComponents/linearAlgebra/solvers/BlockPreconditioner.hpp b/src/coreComponents/linearAlgebra/solvers/BlockPreconditioner.hpp index f6ea90dd635..d7648406aa0 100644 --- a/src/coreComponents/linearAlgebra/solvers/BlockPreconditioner.hpp +++ b/src/coreComponents/linearAlgebra/solvers/BlockPreconditioner.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/solvers/CgSolver.cpp b/src/coreComponents/linearAlgebra/solvers/CgSolver.cpp index bceaa44c1da..ca80ddb1c5a 100644 --- a/src/coreComponents/linearAlgebra/solvers/CgSolver.cpp +++ b/src/coreComponents/linearAlgebra/solvers/CgSolver.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -113,7 +114,7 @@ void CgSolver< VECTOR >::solve( Vector const & b, Vector & x ) const // compute alpha real64 const pAp = p.dot( Ap ); - GEOSX_KRYLOV_BREAKDOWN_IF_ZERO( pAp ) + GEOS_KRYLOV_BREAKDOWN_IF_ZERO( pAp ) real64 const alpha = tau / pAp; // Update x = x + alpha*p @@ -136,17 +137,17 @@ void CgSolver< VECTOR >::solve( Vector const & b, Vector & x ) const // ----------------------- // Explicit Instantiations // ----------------------- -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS template class CgSolver< TrilinosInterface::ParallelVector >; template class CgSolver< BlockVectorView< TrilinosInterface::ParallelVector > >; #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE template class CgSolver< HypreInterface::ParallelVector >; template class CgSolver< BlockVectorView< HypreInterface::ParallelVector > >; #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC template class CgSolver< PetscInterface::ParallelVector >; template class CgSolver< BlockVectorView< PetscInterface::ParallelVector > >; #endif diff --git a/src/coreComponents/linearAlgebra/solvers/CgSolver.hpp b/src/coreComponents/linearAlgebra/solvers/CgSolver.hpp index f5d6b821bb0..bc88229735d 100644 --- a/src/coreComponents/linearAlgebra/solvers/CgSolver.hpp +++ b/src/coreComponents/linearAlgebra/solvers/CgSolver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/solvers/GmresSolver.cpp b/src/coreComponents/linearAlgebra/solvers/GmresSolver.cpp index 4274c50f294..f2b801c5d04 100644 --- a/src/coreComponents/linearAlgebra/solvers/GmresSolver.cpp +++ b/src/coreComponents/linearAlgebra/solvers/GmresSolver.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -165,7 +166,7 @@ void GmresSolver< VECTOR >::solve( Vector const & b, } H( j+1, j ) = w.norm2(); - GEOSX_KRYLOV_BREAKDOWN_IF_ZERO( H( j+1, j ) ) + GEOS_KRYLOV_BREAKDOWN_IF_ZERO( H( j+1, j ) ) m_kspace[j+1].axpby( 1.0 / H( j+1, j ), w, 0.0 ); // Apply all previous rotations to the new column @@ -202,17 +203,17 @@ void GmresSolver< VECTOR >::solve( Vector const & b, // ----------------------- // Explicit Instantiations // ----------------------- -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS template class GmresSolver< TrilinosInterface::ParallelVector >; template class GmresSolver< BlockVectorView< TrilinosInterface::ParallelVector > >; #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE template class GmresSolver< HypreInterface::ParallelVector >; template class GmresSolver< BlockVectorView< HypreInterface::ParallelVector > >; #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC template class GmresSolver< PetscInterface::ParallelVector >; template class GmresSolver< BlockVectorView< PetscInterface::ParallelVector > >; #endif diff --git a/src/coreComponents/linearAlgebra/solvers/GmresSolver.hpp b/src/coreComponents/linearAlgebra/solvers/GmresSolver.hpp index 15edabbe0a4..1f41810c7d5 100644 --- a/src/coreComponents/linearAlgebra/solvers/GmresSolver.hpp +++ b/src/coreComponents/linearAlgebra/solvers/GmresSolver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/solvers/KrylovSolver.cpp b/src/coreComponents/linearAlgebra/solvers/KrylovSolver.cpp index d3c461ba08b..c2c7eb4d59d 100644 --- a/src/coreComponents/linearAlgebra/solvers/KrylovSolver.cpp +++ b/src/coreComponents/linearAlgebra/solvers/KrylovSolver.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -100,17 +101,17 @@ void KrylovSolver< VECTOR >::logResult() const // ----------------------- // Explicit Instantiations // ----------------------- -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS template class KrylovSolver< TrilinosInterface::ParallelVector >; template class KrylovSolver< BlockVectorView< TrilinosInterface::ParallelVector > >; #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE template class KrylovSolver< HypreInterface::ParallelVector >; template class KrylovSolver< BlockVectorView< HypreInterface::ParallelVector > >; #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC template class KrylovSolver< PetscInterface::ParallelVector >; template class KrylovSolver< BlockVectorView< PetscInterface::ParallelVector > >; #endif diff --git a/src/coreComponents/linearAlgebra/solvers/KrylovSolver.hpp b/src/coreComponents/linearAlgebra/solvers/KrylovSolver.hpp index 33504c4b105..44856621892 100644 --- a/src/coreComponents/linearAlgebra/solvers/KrylovSolver.hpp +++ b/src/coreComponents/linearAlgebra/solvers/KrylovSolver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/solvers/KrylovUtils.hpp b/src/coreComponents/linearAlgebra/solvers/KrylovUtils.hpp index 01bf8aef804..3b69ee74b54 100644 --- a/src/coreComponents/linearAlgebra/solvers/KrylovUtils.hpp +++ b/src/coreComponents/linearAlgebra/solvers/KrylovUtils.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -24,7 +25,7 @@ * @brief Exit solver iteration and report a breakdown if value too close to zero. * @param VAR the variable or expression */ -#define GEOSX_KRYLOV_BREAKDOWN_IF_ZERO( VAR ) \ +#define GEOS_KRYLOV_BREAKDOWN_IF_ZERO( VAR ) \ if( isZero( VAR, 0.0 ) ) \ { \ if( m_params.logLevel >= 1 ) \ diff --git a/src/coreComponents/linearAlgebra/solvers/PreconditionerBlockJacobi.hpp b/src/coreComponents/linearAlgebra/solvers/PreconditionerBlockJacobi.hpp index 086f826e30b..7fe79b244a4 100644 --- a/src/coreComponents/linearAlgebra/solvers/PreconditionerBlockJacobi.hpp +++ b/src/coreComponents/linearAlgebra/solvers/PreconditionerBlockJacobi.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/linearAlgebra/solvers/PreconditionerIdentity.hpp b/src/coreComponents/linearAlgebra/solvers/PreconditionerIdentity.hpp index 1d3a9e133c4..696a8ab481d 100644 --- a/src/coreComponents/linearAlgebra/solvers/PreconditionerIdentity.hpp +++ b/src/coreComponents/linearAlgebra/solvers/PreconditionerIdentity.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/solvers/PreconditionerJacobi.hpp b/src/coreComponents/linearAlgebra/solvers/PreconditionerJacobi.hpp index cdf5b7a1a14..e5034cd57e6 100644 --- a/src/coreComponents/linearAlgebra/solvers/PreconditionerJacobi.hpp +++ b/src/coreComponents/linearAlgebra/solvers/PreconditionerJacobi.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/linearAlgebra/solvers/SeparateComponentPreconditioner.cpp b/src/coreComponents/linearAlgebra/solvers/SeparateComponentPreconditioner.cpp index 1859c5ce354..0c27b3b5291 100644 --- a/src/coreComponents/linearAlgebra/solvers/SeparateComponentPreconditioner.cpp +++ b/src/coreComponents/linearAlgebra/solvers/SeparateComponentPreconditioner.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -66,15 +67,15 @@ void SeparateComponentPreconditioner< LAI >::clear() // ----------------------- // Explicit Instantiations // ----------------------- -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS template class SeparateComponentPreconditioner< TrilinosInterface >; #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE template class SeparateComponentPreconditioner< HypreInterface >; #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC template class SeparateComponentPreconditioner< PetscInterface >; #endif diff --git a/src/coreComponents/linearAlgebra/solvers/SeparateComponentPreconditioner.hpp b/src/coreComponents/linearAlgebra/solvers/SeparateComponentPreconditioner.hpp index 15cd81e6e54..d2b3b6e19a2 100644 --- a/src/coreComponents/linearAlgebra/solvers/SeparateComponentPreconditioner.hpp +++ b/src/coreComponents/linearAlgebra/solvers/SeparateComponentPreconditioner.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/unitTests/testComponentMask.cpp b/src/coreComponents/linearAlgebra/unitTests/testComponentMask.cpp index 15dd95ce5f2..23aef693db0 100644 --- a/src/coreComponents/linearAlgebra/unitTests/testComponentMask.cpp +++ b/src/coreComponents/linearAlgebra/unitTests/testComponentMask.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/unitTests/testExternalSolvers.cpp b/src/coreComponents/linearAlgebra/unitTests/testExternalSolvers.cpp index c9a2807677f..d9ed3a881dc 100644 --- a/src/coreComponents/linearAlgebra/unitTests/testExternalSolvers.cpp +++ b/src/coreComponents/linearAlgebra/unitTests/testExternalSolvers.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -150,7 +151,7 @@ class SolverTestLaplace2D : public SolverTestBase< LAI > void SetUp() override { globalIndex constexpr n = 100; - geos::testing::compute2DLaplaceOperator( MPI_COMM_GEOSX, n, this->matrix ); + geos::testing::compute2DLaplaceOperator( MPI_COMM_GEOS, n, this->matrix ); // Condition number for the Laplacian matrix estimate: 4 * n^2 / pi^2 this->cond_est = 4.0 * n * n / std::pow( M_PI, 2 ); @@ -203,15 +204,15 @@ REGISTER_TYPED_TEST_SUITE_P( SolverTestLaplace2D, CG_AMG ); #endif -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS INSTANTIATE_TYPED_TEST_SUITE_P( Trilinos, SolverTestLaplace2D, TrilinosInterface, ); #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE INSTANTIATE_TYPED_TEST_SUITE_P( Hypre, SolverTestLaplace2D, HypreInterface, ); #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC INSTANTIATE_TYPED_TEST_SUITE_P( Petsc, SolverTestLaplace2D, PetscInterface, ); #endif @@ -231,7 +232,7 @@ class SolverTestElasticity2D : public SolverTestBase< LAI > void SetUp() override { globalIndex constexpr n = 100; - geos::testing::compute2DElasticityOperator( MPI_COMM_GEOSX, 1.0, 1.0, n, n, 10000., 0.2, this->matrix ); + geos::testing::compute2DElasticityOperator( MPI_COMM_GEOS, 1.0, 1.0, n, n, 10000., 0.2, this->matrix ); this->cond_est = 1e4; // not a true condition number estimate, but enough to pass tests } }; @@ -269,15 +270,15 @@ REGISTER_TYPED_TEST_SUITE_P( SolverTestElasticity2D, GMRES_AMG ); #endif -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS INSTANTIATE_TYPED_TEST_SUITE_P( Trilinos, SolverTestElasticity2D, TrilinosInterface, ); #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE INSTANTIATE_TYPED_TEST_SUITE_P( Hypre, SolverTestElasticity2D, HypreInterface, ); #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC INSTANTIATE_TYPED_TEST_SUITE_P( Petsc, SolverTestElasticity2D, PetscInterface, ); #endif diff --git a/src/coreComponents/linearAlgebra/unitTests/testKrylovSolvers.cpp b/src/coreComponents/linearAlgebra/unitTests/testKrylovSolvers.cpp index da8d734d661..898cfa63f41 100644 --- a/src/coreComponents/linearAlgebra/unitTests/testKrylovSolvers.cpp +++ b/src/coreComponents/linearAlgebra/unitTests/testKrylovSolvers.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -50,6 +51,7 @@ LinearSolverParameters params_GMRES() LinearSolverParameters parameters; parameters.krylov.relTolerance = 1e-8; parameters.krylov.maxIterations = 500; + parameters.krylov.maxRestart = 100; parameters.solverType = geos::LinearSolverParameters::SolverType::gmres; return parameters; } @@ -123,13 +125,13 @@ class KrylovSolverTest : public KrylovSolverTestBase< typename LAI::ParallelMatr { // Compute matrix and preconditioner globalIndex constexpr n = 100; - geos::testing::compute2DLaplaceOperator( MPI_COMM_GEOSX, n, this->matrix ); + geos::testing::compute2DLaplaceOperator( MPI_COMM_GEOS, n, this->matrix ); this->precond.setup( this->matrix ); // Set up vectors - this->sol_true.create( this->matrix.numLocalCols(), MPI_COMM_GEOSX ); - this->sol_comp.create( this->matrix.numLocalCols(), MPI_COMM_GEOSX ); - this->rhs_true.create( this->matrix.numLocalRows(), MPI_COMM_GEOSX ); + this->sol_true.create( this->matrix.numLocalCols(), MPI_COMM_GEOS ); + this->sol_comp.create( this->matrix.numLocalCols(), MPI_COMM_GEOS ); + this->rhs_true.create( this->matrix.numLocalRows(), MPI_COMM_GEOS ); // Condition number for the Laplacian matrix estimate: 4 * n^2 / pi^2 this->cond_est = 1.5 * 4.0 * n * n / std::pow( M_PI, 2 ); @@ -158,15 +160,15 @@ REGISTER_TYPED_TEST_SUITE_P( KrylovSolverTest, BiCGSTAB, GMRES ); -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS INSTANTIATE_TYPED_TEST_SUITE_P( Trilinos, KrylovSolverTest, TrilinosInterface, ); #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE INSTANTIATE_TYPED_TEST_SUITE_P( Hypre, KrylovSolverTest, HypreInterface, ); #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC INSTANTIATE_TYPED_TEST_SUITE_P( Petsc, KrylovSolverTest, PetscInterface, ); #endif @@ -196,7 +198,7 @@ class KrylovSolverBlockTest : public KrylovSolverTestBase< BlockOperatorWrapper< void SetUp() override { globalIndex constexpr n = 100; - geos::testing::compute2DLaplaceOperator( MPI_COMM_GEOSX, n, laplace2D ); + geos::testing::compute2DLaplaceOperator( MPI_COMM_GEOS, n, laplace2D ); // We are going to assembly the following dummy system // [L 0] [x_true] = [b_0] @@ -216,9 +218,9 @@ class KrylovSolverBlockTest : public KrylovSolverTestBase< BlockOperatorWrapper< for( localIndex i = 0; i < 2; ++i ) { - this->sol_true.block( i ).create( laplace2D.numLocalCols(), MPI_COMM_GEOSX ); - this->sol_comp.block( i ).create( laplace2D.numLocalCols(), MPI_COMM_GEOSX ); - this->rhs_true.block( i ).create( laplace2D.numLocalRows(), MPI_COMM_GEOSX ); + this->sol_true.block( i ).create( laplace2D.numLocalCols(), MPI_COMM_GEOS ); + this->sol_comp.block( i ).create( laplace2D.numLocalCols(), MPI_COMM_GEOS ); + this->rhs_true.block( i ).create( laplace2D.numLocalRows(), MPI_COMM_GEOS ); } // Condition number for the Laplacian matrix estimate: 4 * n^2 / pi^2 @@ -248,15 +250,15 @@ REGISTER_TYPED_TEST_SUITE_P( KrylovSolverBlockTest, BiCGSTAB, GMRES ); -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS INSTANTIATE_TYPED_TEST_SUITE_P( Trilinos, KrylovSolverBlockTest, TrilinosInterface, ); #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE INSTANTIATE_TYPED_TEST_SUITE_P( Hypre, KrylovSolverBlockTest, HypreInterface, ); #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC INSTANTIATE_TYPED_TEST_SUITE_P( Petsc, KrylovSolverBlockTest, PetscInterface, ); #endif diff --git a/src/coreComponents/linearAlgebra/unitTests/testLinearAlgebraUtils.hpp b/src/coreComponents/linearAlgebra/unitTests/testLinearAlgebraUtils.hpp index a2ba329510a..19cd2754d33 100644 --- a/src/coreComponents/linearAlgebra/unitTests/testLinearAlgebraUtils.hpp +++ b/src/coreComponents/linearAlgebra/unitTests/testLinearAlgebraUtils.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/unitTests/testLinearSolverParametersEnums.cpp b/src/coreComponents/linearAlgebra/unitTests/testLinearSolverParametersEnums.cpp index c136a58229c..689188e9bfd 100644 --- a/src/coreComponents/linearAlgebra/unitTests/testLinearSolverParametersEnums.cpp +++ b/src/coreComponents/linearAlgebra/unitTests/testLinearSolverParametersEnums.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2020- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/linearAlgebra/unitTests/testMatrices.cpp b/src/coreComponents/linearAlgebra/unitTests/testMatrices.cpp index a4cdfd40a2b..baadb01ce9f 100644 --- a/src/coreComponents/linearAlgebra/unitTests/testMatrices.cpp +++ b/src/coreComponents/linearAlgebra/unitTests/testMatrices.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -36,8 +37,8 @@ TYPED_TEST_P( MatrixTest, MatrixFunctions ) using Matrix = typename TypeParam::ParallelMatrix; // Get the MPI rank - int numranks = MpiWrapper::commSize( MPI_COMM_GEOSX ); - int rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int numranks = MpiWrapper::commSize( MPI_COMM_GEOS ); + int rank = MpiWrapper::commRank( MPI_COMM_GEOS ); std::cout << "*** Rank: " << rank << std::endl; @@ -47,7 +48,7 @@ TYPED_TEST_P( MatrixTest, MatrixFunctions ) { // Test matrix-matrix product: C = A*B Matrix A; - geos::testing::compute2DLaplaceOperator( MPI_COMM_GEOSX, 2 * numranks, A ); + geos::testing::compute2DLaplaceOperator( MPI_COMM_GEOS, 2 * numranks, A ); Matrix B( A ); A.multiply( B, C ); @@ -57,10 +58,10 @@ TYPED_TEST_P( MatrixTest, MatrixFunctions ) // Define some vectors, matrices Vector vec1, vec2, vec3; Matrix mat1, mat2, mat3, mat4; - mat1.createWithLocalSize( 2, 2, MPI_COMM_GEOSX ); // 2*numranks x 2*numranks - mat2.createWithGlobalSize( 2, 2, MPI_COMM_GEOSX ); // 2x2 - mat3.createWithLocalSize( 2, 3, 3, MPI_COMM_GEOSX ); // 2*numranks x 3*numranks - mat4.createWithGlobalSize( 3, 4, 3, MPI_COMM_GEOSX ); // 3x4 + mat1.createWithLocalSize( 2, 2, MPI_COMM_GEOS ); // 2*numranks x 2*numranks + mat2.createWithGlobalSize( 2, 2, MPI_COMM_GEOS ); // 2x2 + mat3.createWithLocalSize( 2, 3, 3, MPI_COMM_GEOS ); // 2*numranks x 3*numranks + mat4.createWithGlobalSize( 3, 4, 3, MPI_COMM_GEOS ); // 3x4 // Testing create, globalRows, globalCols EXPECT_EQ( mat1.numGlobalRows(), 2 * numranks ); @@ -124,7 +125,7 @@ TYPED_TEST_P( MatrixTest, MatrixFunctions ) } // Testing add/set/insert array1d Matrix mat6; - mat6.createWithGlobalSize( 4, 4, MPI_COMM_GEOSX ); + mat6.createWithGlobalSize( 4, 4, MPI_COMM_GEOS ); array1d< real64 > vals6( 3 ); array1d< real64 > vals7( 3 ); array1d< globalIndex > inds6( 3 ); @@ -151,7 +152,7 @@ TYPED_TEST_P( MatrixTest, MatrixFunctions ) // Testing add/set/insert array2d Matrix mat7; - mat7.createWithGlobalSize( 4, 4, MPI_COMM_GEOSX ); + mat7.createWithGlobalSize( 4, 4, MPI_COMM_GEOS ); array1d< globalIndex > rows( 2 ); array1d< globalIndex > cols( 2 ); array2d< real64 > vals8( 2, 2 ); @@ -183,8 +184,8 @@ TYPED_TEST_P( MatrixTest, MatrixFunctions ) mat1.close(); // Testing vector multiply, matrix multiply, MatrixMatrixMultiply - vec1.createWithGlobalSize( 2, MPI_COMM_GEOSX ); - vec2.createWithGlobalSize( 2, MPI_COMM_GEOSX ); + vec1.createWithGlobalSize( 2, MPI_COMM_GEOS ); + vec2.createWithGlobalSize( 2, MPI_COMM_GEOS ); vec1.set( 1 ); vec1.close(); globalIndex inds4[2] = { 0, 1 }; @@ -229,7 +230,7 @@ TYPED_TEST_P( MatrixTest, MatrixMatrixOperations ) globalIndex const n = 100; Matrix A; - geos::testing::compute2DLaplaceOperator( MPI_COMM_GEOSX, n, A ); + geos::testing::compute2DLaplaceOperator( MPI_COMM_GEOS, n, A ); Matrix A_squared; A.multiply( A, A_squared ); @@ -245,14 +246,14 @@ TYPED_TEST_P( MatrixTest, RectangularMatrixOperations ) { using Matrix = typename TypeParam::ParallelMatrix; - int const mpiSize = MpiWrapper::commSize( MPI_COMM_GEOSX ); + int const mpiSize = MpiWrapper::commSize( MPI_COMM_GEOS ); // Set a size that allows to run with arbitrary number of processes globalIndex const nRows = std::max( 100, mpiSize ); globalIndex const nCols = 2 * nRows; Matrix A; - A.createWithGlobalSize( nRows, nCols, 2, MPI_COMM_GEOSX ); + A.createWithGlobalSize( nRows, nCols, 2, MPI_COMM_GEOS ); A.open(); for( globalIndex i = A.ilower(); i < A.iupper(); ++i ) @@ -282,15 +283,15 @@ REGISTER_TYPED_TEST_SUITE_P( MatrixTest, MatrixMatrixOperations, RectangularMatrixOperations ); -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS INSTANTIATE_TYPED_TEST_SUITE_P( Trilinos, MatrixTest, TrilinosInterface, ); #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE INSTANTIATE_TYPED_TEST_SUITE_P( Hypre, MatrixTest, HypreInterface, ); #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC INSTANTIATE_TYPED_TEST_SUITE_P( Petsc, MatrixTest, PetscInterface, ); #endif diff --git a/src/coreComponents/linearAlgebra/unitTests/testReverseCutHillMcKeeOrdering.cpp b/src/coreComponents/linearAlgebra/unitTests/testReverseCutHillMcKeeOrdering.cpp index d79d9631f7d..88db5cb59dc 100644 --- a/src/coreComponents/linearAlgebra/unitTests/testReverseCutHillMcKeeOrdering.cpp +++ b/src/coreComponents/linearAlgebra/unitTests/testReverseCutHillMcKeeOrdering.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/unitTests/testVectors.cpp b/src/coreComponents/linearAlgebra/unitTests/testVectors.cpp index 632abbe61b2..927f818b3ba 100644 --- a/src/coreComponents/linearAlgebra/unitTests/testVectors.cpp +++ b/src/coreComponents/linearAlgebra/unitTests/testVectors.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -33,11 +34,11 @@ void createAndAssemble( localIndex const startSize, VEC & x ) // - startSize on rank 0; // - startSize + 1 on rank 1; // - etc. - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); localIndex const localSize = rank + startSize; globalIndex const rankOffset = rank * ( rank - 1 ) / 2 + rank * startSize; - x.create( localSize, MPI_COMM_GEOSX ); + x.create( localSize, MPI_COMM_GEOS ); arrayView1d< real64 > const values = x.open(); forAll< POLICY >( localSize, [=] GEOS_HOST_DEVICE ( localIndex const i ) { @@ -126,7 +127,7 @@ TYPED_TEST_P( VectorTest, create ) { using Vector = typename TypeParam::ParallelVector; - MPI_Comm const comm = MPI_COMM_GEOSX; + MPI_Comm const comm = MPI_COMM_GEOS; int const rank = MpiWrapper::commRank( comm ); int const nproc = MpiWrapper::commSize( comm ); @@ -178,7 +179,7 @@ TYPED_TEST_P( VectorTest, moveConstruction ) Vector y( std::move( x ) ); EXPECT_TRUE( y.ready() ); - EXPECT_TRUE( MpiWrapper::commCompare( y.comm(), MPI_COMM_GEOSX ) ); + EXPECT_TRUE( MpiWrapper::commCompare( y.comm(), MPI_COMM_GEOS ) ); EXPECT_EQ( y.localSize(), localSize ); EXPECT_EQ( y.globalSize(), globalSize ); compareValues( y.values(), values ); @@ -206,7 +207,7 @@ TYPED_TEST_P( VectorTest, setAllValues ) real64 const value = 1.23; Vector x; - x.create( localSize, MPI_COMM_GEOSX ); + x.create( localSize, MPI_COMM_GEOS ); x.set( value ); arrayView1d< real64 const > const values = x.values(); @@ -364,15 +365,15 @@ REGISTER_TYPED_TEST_SUITE_P( VectorTest, norm2, normInf ); -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS INSTANTIATE_TYPED_TEST_SUITE_P( Trilinos, VectorTest, TrilinosInterface, ); #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE INSTANTIATE_TYPED_TEST_SUITE_P( Hypre, VectorTest, HypreInterface, ); #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC INSTANTIATE_TYPED_TEST_SUITE_P( Petsc, VectorTest, PetscInterface, ); #endif diff --git a/src/coreComponents/linearAlgebra/utilities/Arnoldi.hpp b/src/coreComponents/linearAlgebra/utilities/Arnoldi.hpp index 33c8fe80f9b..d399b278b2d 100644 --- a/src/coreComponents/linearAlgebra/utilities/Arnoldi.hpp +++ b/src/coreComponents/linearAlgebra/utilities/Arnoldi.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/utilities/BlockOperator.hpp b/src/coreComponents/linearAlgebra/utilities/BlockOperator.hpp index 3d91ea20501..f25068efeb4 100644 --- a/src/coreComponents/linearAlgebra/utilities/BlockOperator.hpp +++ b/src/coreComponents/linearAlgebra/utilities/BlockOperator.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/utilities/BlockOperatorView.hpp b/src/coreComponents/linearAlgebra/utilities/BlockOperatorView.hpp index 82b69dc0dbc..a7da7ca9a79 100644 --- a/src/coreComponents/linearAlgebra/utilities/BlockOperatorView.hpp +++ b/src/coreComponents/linearAlgebra/utilities/BlockOperatorView.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -339,7 +340,7 @@ auto BlockOperatorView< VECTOR, OPERATOR >::computeColSize( FUNC func ) const -> return colSize; } -}// end geosx namespace +}// end geos namespace #endif /*GEOS_LINEARALGEBRA_UTILITIES_BLOCKOPERATORVIEW_HPP_*/ diff --git a/src/coreComponents/linearAlgebra/utilities/BlockOperatorWrapper.hpp b/src/coreComponents/linearAlgebra/utilities/BlockOperatorWrapper.hpp index 7b3964e7e59..4cab49d47e6 100644 --- a/src/coreComponents/linearAlgebra/utilities/BlockOperatorWrapper.hpp +++ b/src/coreComponents/linearAlgebra/utilities/BlockOperatorWrapper.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/utilities/BlockVector.hpp b/src/coreComponents/linearAlgebra/utilities/BlockVector.hpp index 5fa88df0d97..c71e0a59c8c 100644 --- a/src/coreComponents/linearAlgebra/utilities/BlockVector.hpp +++ b/src/coreComponents/linearAlgebra/utilities/BlockVector.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/utilities/BlockVectorView.hpp b/src/coreComponents/linearAlgebra/utilities/BlockVectorView.hpp index 447b9f2e47e..626744a796b 100644 --- a/src/coreComponents/linearAlgebra/utilities/BlockVectorView.hpp +++ b/src/coreComponents/linearAlgebra/utilities/BlockVectorView.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -405,7 +406,7 @@ std::ostream & operator<<( std::ostream & os, return os; } -} // end geosx namespace +} // end geos namespace #endif /* GEOS_LINEARALGEBRA_UTILITIES_BLOCKVECTORVIEW_HPP_ */ diff --git a/src/coreComponents/linearAlgebra/utilities/BlockVectorWrapper.hpp b/src/coreComponents/linearAlgebra/utilities/BlockVectorWrapper.hpp index cc84cd1018b..b1a7f1ab603 100644 --- a/src/coreComponents/linearAlgebra/utilities/BlockVectorWrapper.hpp +++ b/src/coreComponents/linearAlgebra/utilities/BlockVectorWrapper.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/utilities/ComponentMask.hpp b/src/coreComponents/linearAlgebra/utilities/ComponentMask.hpp index 1e0130b97f5..a27d1a37a64 100644 --- a/src/coreComponents/linearAlgebra/utilities/ComponentMask.hpp +++ b/src/coreComponents/linearAlgebra/utilities/ComponentMask.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #define GEOS_LINEARALGEBRA_UTILITIES_COMPONENTMASK_HPP_ #include "common/GeosxMacros.hpp" -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" #include diff --git a/src/coreComponents/linearAlgebra/utilities/InverseNormalOperator.hpp b/src/coreComponents/linearAlgebra/utilities/InverseNormalOperator.hpp index 3ab698cefe8..977135fb419 100644 --- a/src/coreComponents/linearAlgebra/utilities/InverseNormalOperator.hpp +++ b/src/coreComponents/linearAlgebra/utilities/InverseNormalOperator.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/linearAlgebra/utilities/LAIHelperFunctions.hpp b/src/coreComponents/linearAlgebra/utilities/LAIHelperFunctions.hpp index f92fa2ccfec..6a06e310583 100644 --- a/src/coreComponents/linearAlgebra/utilities/LAIHelperFunctions.hpp +++ b/src/coreComponents/linearAlgebra/utilities/LAIHelperFunctions.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -74,7 +75,7 @@ void createPermutationMatrix( NodeManager const & nodeManager, */ localIndex const numLocalRows = nodeManager.getNumberOfLocalIndices() * nDofPerNode; - permutationMatrix.createWithLocalSize( numLocalRows, numLocalRows, 1, MPI_COMM_GEOSX ); + permutationMatrix.createWithLocalSize( numLocalRows, numLocalRows, 1, MPI_COMM_GEOS ); arrayView1d< globalIndex const > const & dofNumber = nodeManager.getReference< globalIndex_array >( dofKey ); arrayView1d< globalIndex const > const & localToGlobal = nodeManager.localToGlobalMap(); @@ -126,7 +127,7 @@ void createPermutationMatrix( ElementRegionManager const & elemManager, numLocalRows += elementSubRegion.getNumberOfLocalIndices() * nDofPerCell; } } ); - permutationMatrix.createWithLocalSize( numLocalRows, numLocalRows, 1, MPI_COMM_GEOSX ); + permutationMatrix.createWithLocalSize( numLocalRows, numLocalRows, 1, MPI_COMM_GEOS ); permutationMatrix.open(); elemManager.forElementSubRegions< ElementSubRegionBase >( [&]( ElementSubRegionBase const & elementSubRegion ) @@ -249,7 +250,7 @@ void computeRigidBodyModes( MeshLevel const & mesh, rigidBodyModes.resize( numRidigBodyModes ); for( localIndex k = 0; k < numComponents; ++k ) { - rigidBodyModes[k].create( numNodes * numComponents, MPI_COMM_GEOSX ); + rigidBodyModes[k].create( numNodes * numComponents, MPI_COMM_GEOS ); arrayView1d< real64 > const values = rigidBodyModes[k].open(); forAll< parallelHostPolicy >( numNodes, [=]( localIndex const i ) { @@ -263,7 +264,7 @@ void computeRigidBodyModes( MeshLevel const & mesh, case 2: { localIndex const k = 2; - rigidBodyModes[k].create( numNodes*numComponents, MPI_COMM_GEOSX ); + rigidBodyModes[k].create( numNodes*numComponents, MPI_COMM_GEOS ); { arrayView1d< real64 > const values = rigidBodyModes[k].open(); forAll< parallelHostPolicy >( numNodes, [=]( localIndex const i ) @@ -284,7 +285,7 @@ void computeRigidBodyModes( MeshLevel const & mesh, case 3: { localIndex k = 3; - rigidBodyModes[k].create( numNodes*numComponents, MPI_COMM_GEOSX ); + rigidBodyModes[k].create( numNodes*numComponents, MPI_COMM_GEOS ); { arrayView1d< real64 > const values = rigidBodyModes[k].open(); forAll< parallelHostPolicy >( numNodes, [=]( localIndex const i ) @@ -302,7 +303,7 @@ void computeRigidBodyModes( MeshLevel const & mesh, rigidBodyModes[k].scale( 1.0 / rigidBodyModes[k].norm2() ); ++k; - rigidBodyModes[k].create( numNodes*numComponents, MPI_COMM_GEOSX ); + rigidBodyModes[k].create( numNodes*numComponents, MPI_COMM_GEOS ); { arrayView1d< real64 > const values = rigidBodyModes[k].open(); forAll< parallelHostPolicy >( numNodes, [=]( localIndex const i ) @@ -320,7 +321,7 @@ void computeRigidBodyModes( MeshLevel const & mesh, rigidBodyModes[k].scale( 1.0 / rigidBodyModes[k].norm2() ); ++k; - rigidBodyModes[k].create( numNodes*numComponents, MPI_COMM_GEOSX ); + rigidBodyModes[k].create( numNodes*numComponents, MPI_COMM_GEOS ); { arrayView1d< real64 > const values = rigidBodyModes[k].open(); forAll< parallelHostPolicy >( numNodes, [=]( localIndex const i ) @@ -347,6 +348,6 @@ void computeRigidBodyModes( MeshLevel const & mesh, } // LAIHelperFunctions namespace -} // geosx namespace +} // geos namespace #endif /*GEOS_LINEARALGEBRA_UTILITIES_LAIHELPERFUNCTIONS_HPP_*/ diff --git a/src/coreComponents/linearAlgebra/utilities/LinearSolverParameters.hpp b/src/coreComponents/linearAlgebra/utilities/LinearSolverParameters.hpp index 881fcc9984c..803946ac95c 100644 --- a/src/coreComponents/linearAlgebra/utilities/LinearSolverParameters.hpp +++ b/src/coreComponents/linearAlgebra/utilities/LinearSolverParameters.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,7 @@ #ifndef GEOS_LINEARALGEBRA_UTILITIES_LINEARSOLVERPARAMETERS_HPP_ #define GEOS_LINEARALGEBRA_UTILITIES_LINEARSOLVERPARAMETERS_HPP_ -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" namespace geos { @@ -116,9 +117,16 @@ struct LinearSolverParameters { real64 relTolerance = 1e-6; ///< Relative convergence tolerance for iterative solvers integer maxIterations = 200; ///< Max iterations before declaring convergence failure - integer maxRestart = 200; ///< Max number of vectors in Krylov basis before restarting +#if GEOS_USE_HYPRE_DEVICE == GEOS_USE_HYPRE_CUDA || GEOS_USE_HYPRE_DEVICE == GEOS_USE_HYPRE_HIP + integer maxRestart = 100; ///< Max number of vectors in Krylov basis before restarting (GPUs) +#else + integer maxRestart = 200; ///< Max number of vectors in Krylov basis before restarting (CPUs) +#endif integer useAdaptiveTol = false; ///< Use Eisenstat-Walker adaptive tolerance real64 weakestTol = 1e-3; ///< Weakest allowed tolerance when using adaptive method + real64 strongestTol = 1e-8; ///< Strongest allowed tolerance when using adaptive method + real64 adaptiveGamma = 0.1; ///< Gamma parameter for adaptive method + real64 adaptiveExponent = 1.0; ///< Exponent parameter for adaptive method } krylov; ///< Krylov-method parameter struct @@ -176,7 +184,9 @@ struct LinearSolverParameters l1sgs, ///< l1-Symmetric Gauss-Seidel chebyshev, ///< Chebyshev polynomial (GPU support in hypre) direct, ///< Direct solver as preconditioner - bgs ///< Gauss-Seidel smoothing (backward sweep) + bgs, ///< Gauss-Seidel smoothing (backward sweep) + gsElimWPivoting, ///< Gaussian Elimination with pivoting direct solver + gsElimWInverse ///< Direct inverse with Gaussian Elimination }; /// AMG coarsening types (HYPRE only) @@ -227,12 +237,12 @@ struct LinearSolverParameters rigidBodyModes ///< Rigid body modes }; -#if defined(GEOSX_USE_HYPRE_CUDA) || defined(GEOSX_USE_HYPRE_HIP) - CoarseningType coarseningType = CoarseningType::PMIS; ///< Coarsening algorithm - SmootherType smootherType = SmootherType::l1jacobi; ///< Smoother type +#if GEOS_USE_HYPRE_DEVICE == GEOS_USE_HYPRE_CUDA || GEOS_USE_HYPRE_DEVICE == GEOS_USE_HYPRE_HIP + CoarseningType coarseningType = CoarseningType::PMIS; ///< Coarsening algorithm (GPUs) + SmootherType smootherType = SmootherType::l1jacobi; ///< Smoother type (GPUs) #else - CoarseningType coarseningType = CoarseningType::HMIS; ///< Coarsening algorithm - SmootherType smootherType = SmootherType::l1sgs; ///< Smoother type + CoarseningType coarseningType = CoarseningType::HMIS; ///< Coarsening algorithm (CPUs) + SmootherType smootherType = SmootherType::l1sgs; ///< Smoother type (CPUs) #endif integer maxLevels = 20; ///< Maximum number of coarsening levels @@ -246,6 +256,7 @@ struct LinearSolverParameters integer aggressiveNumPaths = 1; ///< Number of paths agg. coarsening. integer aggressiveNumLevels = 0; ///< Number of levels for aggressive coarsening. AggInterpType aggressiveInterpType = AggInterpType::multipass; ///< Interp. type for agg. coarsening. + integer aggressiveInterpMaxNonZeros = 16; ///< Aggressive Interpolation - Max. nonzeros/row. PreOrPost preOrPostSmoothing = PreOrPost::both; ///< Pre and/or post smoothing real64 threshold = 0.0; ///< Threshold for "strong connections" (for classical ///< and smoothed-aggregation AMG) @@ -262,35 +273,35 @@ struct LinearSolverParameters */ enum class StrategyType : integer { - invalid, ///< default value, to ensure solver sets something - singlePhaseReservoirFVM, ///< finite volume single-phase flow with wells - singlePhaseHybridFVM, ///< hybrid finite volume single-phase flow - singlePhaseReservoirHybridFVM, ///< hybrid finite volume single-phase flow with wells - singlePhasePoromechanics, ///< single phase poromechanics with finite volume single phase flow - thermalSinglePhasePoromechanics, ///< thermal single phase poromechanics with finite volume single phase flow - hybridSinglePhasePoromechanics, ///< single phase poromechanics with hybrid finite volume single phase flow - singlePhasePoromechanicsEmbeddedFractures, ///< single phase poromechanics with FV embedded fractures - singlePhasePoromechanicsConformingFractures, ///< single phase poromechanics with FV conforming fractures - singlePhasePoromechanicsReservoirFVM, ///< single phase poromechanics with finite volume single phase flow with wells - compositionalMultiphaseFVM, ///< finite volume compositional multiphase flow - compositionalMultiphaseHybridFVM, ///< hybrid finite volume compositional multiphase flow - compositionalMultiphaseReservoirFVM, ///< finite volume compositional multiphase flow with wells - compositionalMultiphaseReservoirHybridFVM, ///< hybrid finite volume compositional multiphase flow with wells - reactiveCompositionalMultiphaseOBL, ///< finite volume reactive compositional flow with OBL - thermalCompositionalMultiphaseFVM, ///< finite volume thermal compositional multiphase flow - multiphasePoromechanics, ///< multiphase poromechanics with finite volume compositional multiphase flow - multiphasePoromechanicsReservoirFVM, ///< multiphase poromechanics with finite volume compositional multiphase flow with wells - thermalMultiphasePoromechanics, ///< thermal multiphase poromechanics with finite volume compositional multiphase flow - hydrofracture, ///< hydrofracture - lagrangianContactMechanics, ///< Lagrangian contact mechanics - solidMechanicsEmbeddedFractures ///< Embedded fractures mechanics + invalid, ///< default value, to ensure solver sets something + singlePhaseReservoirFVM, ///< finite volume single-phase flow with wells + singlePhaseHybridFVM, ///< hybrid finite volume single-phase flow + singlePhaseReservoirHybridFVM, ///< hybrid finite volume single-phase flow with wells + singlePhasePoromechanics, ///< single phase poromechanics with finite volume single phase flow + thermalSinglePhasePoromechanics, ///< thermal single phase poromechanics with finite volume single phase flow + hybridSinglePhasePoromechanics, ///< single phase poromechanics with hybrid finite volume single phase flow + singlePhasePoromechanicsEmbeddedFractures, ///< single phase poromechanics with FV embedded fractures + singlePhasePoromechanicsConformingFractures, ///< single phase poromechanics with FV embedded fractures + singlePhasePoromechanicsReservoirFVM, ///< single phase poromechanics with finite volume single phase flow with wells + compositionalMultiphaseFVM, ///< finite volume compositional multiphase flow + compositionalMultiphaseHybridFVM, ///< hybrid finite volume compositional multiphase flow + compositionalMultiphaseReservoirFVM, ///< finite volume compositional multiphase flow with wells + compositionalMultiphaseReservoirHybridFVM, ///< hybrid finite volume compositional multiphase flow with wells + reactiveCompositionalMultiphaseOBL, ///< finite volume reactive compositional flow with OBL + thermalCompositionalMultiphaseFVM, ///< finite volume thermal compositional multiphase flow + thermalCompositionalMultiphaseReservoirFVM,///< finite volume thermal compositional multiphase flow + multiphasePoromechanics, ///< multiphase poromechanics with finite volume compositional multiphase flow + multiphasePoromechanicsReservoirFVM, ///< multiphase poromechanics with finite volume compositional multiphase flow with wells + thermalMultiphasePoromechanics, ///< thermal multiphase poromechanics with finite volume compositional multiphase flow + hydrofracture, ///< hydrofracture + lagrangianContactMechanics, ///< Lagrangian contact mechanics + solidMechanicsEmbeddedFractures ///< Embedded fractures mechanics }; StrategyType strategy = StrategyType::invalid; ///< Predefined MGR solution strategy (solver specific) integer separateComponents = false; ///< Apply a separate displacement component (SDC) filter before AMG construction - string displacementFieldName; ///< Displacement field name need for SDC filter - integer areWellsShut = false; ///< Flag to let MGR know that wells are shut, and that jacobi can be applied to the - ///< well block + integer areWellsShut = false; ///< Flag to let MGR know that wells are shut, and that jacobi can be applied to the + ///< well block } mgr; ///< Multigrid reduction (MGR) parameters @@ -370,6 +381,7 @@ ENUM_STRINGS( LinearSolverParameters::MGR::StrategyType, "compositionalMultiphaseReservoirHybridFVM", "reactiveCompositionalMultiphaseOBL", "thermalCompositionalMultiphaseFVM", + "thermalCompositionalMultiphaseReservoirFVM", "multiphasePoromechanics", "multiphasePoromechanicsReservoirFVM", "thermalMultiphasePoromechanics", @@ -413,7 +425,9 @@ ENUM_STRINGS( LinearSolverParameters::AMG::CoarseType, "l1sgs", "chebyshev", "direct", - "bgs" ); + "bgs", + "gsElimWPivoting", + "gsElimWInverse" ); /// Declare strings associated with enumeration values. ENUM_STRINGS( LinearSolverParameters::AMG::CoarseningType, diff --git a/src/coreComponents/linearAlgebra/utilities/LinearSolverResult.hpp b/src/coreComponents/linearAlgebra/utilities/LinearSolverResult.hpp index 6a6c5281802..3a12e612a79 100644 --- a/src/coreComponents/linearAlgebra/utilities/LinearSolverResult.hpp +++ b/src/coreComponents/linearAlgebra/utilities/LinearSolverResult.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/utilities/NormalOperator.hpp b/src/coreComponents/linearAlgebra/utilities/NormalOperator.hpp index 39b22017893..2382af2e0c2 100644 --- a/src/coreComponents/linearAlgebra/utilities/NormalOperator.hpp +++ b/src/coreComponents/linearAlgebra/utilities/NormalOperator.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/linearAlgebra/utilities/ReverseCutHillMcKeeOrdering.cpp b/src/coreComponents/linearAlgebra/utilities/ReverseCutHillMcKeeOrdering.cpp index 89b18650cd8..8716ee585e9 100644 --- a/src/coreComponents/linearAlgebra/utilities/ReverseCutHillMcKeeOrdering.cpp +++ b/src/coreComponents/linearAlgebra/utilities/ReverseCutHillMcKeeOrdering.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/utilities/ReverseCutHillMcKeeOrdering.hpp b/src/coreComponents/linearAlgebra/utilities/ReverseCutHillMcKeeOrdering.hpp index fa74a5c5ce4..01b8479b964 100644 --- a/src/coreComponents/linearAlgebra/utilities/ReverseCutHillMcKeeOrdering.hpp +++ b/src/coreComponents/linearAlgebra/utilities/ReverseCutHillMcKeeOrdering.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/linearAlgebra/utilities/TransposeOperator.hpp b/src/coreComponents/linearAlgebra/utilities/TransposeOperator.hpp index 8e5ce025f9b..18d1ed2c35a 100644 --- a/src/coreComponents/linearAlgebra/utilities/TransposeOperator.hpp +++ b/src/coreComponents/linearAlgebra/utilities/TransposeOperator.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/mainInterface/CMakeLists.txt b/src/coreComponents/mainInterface/CMakeLists.txt index 70cbacd9e61..a7b02f95041 100644 --- a/src/coreComponents/mainInterface/CMakeLists.txt +++ b/src/coreComponents/mainInterface/CMakeLists.txt @@ -1,3 +1,25 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: mainInterface + +Contains: + - GEOS `main` entry point. + - the class managing the operation flow of the problem being ran in GEOS. + - basic initialization and environment setup routines. +#]] + # # Specify all headers # @@ -18,16 +40,21 @@ set( mainInterface_sources version.cpp ) -set( dependencyList ${parallelDeps} physicsSolvers discretizationMethods fieldSpecification linearAlgebra dataRepository events fileIO optionparser ) +set( dependencyList ${parallelDeps} physicsSolvers constitutiveDrivers optionparser ) + +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) blt_add_library( NAME mainInterface SOURCES ${mainInterface_sources} HEADERS ${mainInterface_headers} - DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} + DEPENDS_ON ${decoratedDependencies} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} ) add_dependencies( mainInterface generate_version ) target_include_directories( mainInterface PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +install( TARGETS mainInterface LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) diff --git a/src/coreComponents/mainInterface/GeosxState.cpp b/src/coreComponents/mainInterface/GeosxState.cpp index e965076b89c..12cb2baf62a 100644 --- a/src/coreComponents/mainInterface/GeosxState.cpp +++ b/src/coreComponents/mainInterface/GeosxState.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -23,7 +24,7 @@ // TPL includes #include -#if defined( GEOSX_USE_CALIPER ) +#if defined( GEOS_USE_CALIPER ) #include #endif @@ -83,7 +84,7 @@ GeosxState::GeosxState( std::unique_ptr< CommandLineOptions > && commandLineOpti m_rootNode( std::make_unique< conduit::Node >() ), m_problemManager( nullptr ), m_commTools( std::make_unique< CommunicationTools >() ), -#if defined( GEOSX_USE_CALIPER ) +#if defined( GEOS_USE_CALIPER ) m_caliperManager( std::make_unique< cali::ConfigManager >() ), #endif m_initTime(), @@ -91,7 +92,7 @@ GeosxState::GeosxState( std::unique_ptr< CommandLineOptions > && commandLineOpti { Timer timer( m_initTime ); -#if defined( GEOSX_USE_CALIPER ) +#if defined( GEOS_USE_CALIPER ) setupCaliper( *m_caliperManager, getCommandLineOptions() ); #endif @@ -111,7 +112,7 @@ GeosxState::GeosxState( std::unique_ptr< CommandLineOptions > && commandLineOpti ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// GeosxState::~GeosxState() { -#if defined( GEOSX_USE_CALIPER ) +#if defined( GEOS_USE_CALIPER ) m_caliperManager->flush(); #endif @@ -165,7 +166,7 @@ void GeosxState::applyInitialConditions() } m_state = State::READY_TO_RUN; - MpiWrapper::barrier( MPI_COMM_GEOSX ); + MpiWrapper::barrier( MPI_COMM_GEOS ); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreComponents/mainInterface/GeosxState.hpp b/src/coreComponents/mainInterface/GeosxState.hpp index 8f3bb7402f5..43d44de6674 100644 --- a/src/coreComponents/mainInterface/GeosxState.hpp +++ b/src/coreComponents/mainInterface/GeosxState.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -21,6 +22,7 @@ // Source includes #include "common/DataTypes.hpp" +#include "common/logger/Logger.hpp" // System includes #include @@ -32,7 +34,7 @@ namespace conduit class Node; } -#if defined( GEOSX_USE_CALIPER ) +#if defined( GEOS_USE_CALIPER ) //Forward declaration of cali::ConfigManager. namespace cali { @@ -234,7 +236,7 @@ class GeosxState /// The CommunicationTools. std::unique_ptr< CommunicationTools > m_commTools; -#if defined( GEOSX_USE_CALIPER ) +#if defined( GEOS_USE_CALIPER ) /// The Caliper ConfigManager. std::unique_ptr< cali::ConfigManager > m_caliperManager; #endif diff --git a/src/coreComponents/mainInterface/GeosxVersion.hpp.in b/src/coreComponents/mainInterface/GeosxVersion.hpp.in index 4e5793e5ed9..57e801ba7f0 100644 --- a/src/coreComponents/mainInterface/GeosxVersion.hpp.in +++ b/src/coreComponents/mainInterface/GeosxVersion.hpp.in @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + /** * @file GeosxVersion.hpp * @@ -9,25 +24,25 @@ #define GEOS_MAININTERFACE_VERSION_HPP_ /// GEOS major version number -#define GEOSX_VERSION_MAJOR @GEOSX_VERSION_MAJOR@ +#define GEOS_VERSION_MAJOR @GEOS_VERSION_MAJOR@ /// GEOS minor version number -#define GEOSX_VERSION_MINOR @GEOSX_VERSION_MINOR@ +#define GEOS_VERSION_MINOR @GEOS_VERSION_MINOR@ /// GEOS patch version number -#define GEOSX_VERSION_PATCH @GEOSX_VERSION_PATCH@ +#define GEOS_VERSION_PATCH @GEOS_VERSION_PATCH@ /// GEOS full version number string -#define GEOSX_VERSION_FULL "@GEOSX_VERSION_FULL@" +#define GEOS_VERSION_FULL "@GEOS_VERSION_FULL@" /// GEOS development branch string -#cmakedefine GEOSX_GIT_BRANCH "@GEOSX_GIT_BRANCH@" +#cmakedefine GEOS_GIT_BRANCH "@GEOS_GIT_BRANCH@" /// GEOS development branch string -#cmakedefine GEOSX_GIT_HASH "@GEOSX_GIT_HASH@" +#cmakedefine GEOS_GIT_HASH "@GEOS_GIT_HASH@" /// GEOS development branch string -#cmakedefine GEOSX_GIT_TAG "@GEOSX_GIT_TAG@" +#cmakedefine GEOS_GIT_TAG "@GEOS_GIT_TAG@" #endif /* GEOS_MAININTERFACE_VERSION_HPP_ */ diff --git a/src/coreComponents/mainInterface/ProblemManager.cpp b/src/coreComponents/mainInterface/ProblemManager.cpp index 3e677e9c4c8..652c1d3193d 100644 --- a/src/coreComponents/mainInterface/ProblemManager.cpp +++ b/src/coreComponents/mainInterface/ProblemManager.cpp @@ -2,27 +2,29 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ -#define GEOSX_DISPATCH_VEM /// enables VEM in FiniteElementDispatch +#define GEOS_DISPATCH_VEM /// enables VEM in FiniteElementDispatch // Source includes #include "ProblemManager.hpp" #include "GeosxState.hpp" #include "initialization.hpp" -#include "codingUtilities/StringUtilities.hpp" +#include "common/format/StringUtilities.hpp" #include "common/Path.hpp" #include "common/TimingMacros.hpp" #include "constitutive/ConstitutiveManager.hpp" +#include "constitutiveDrivers/solid/TriaxialDriver.hpp" #include "dataRepository/ConduitRestart.hpp" #include "dataRepository/RestartFlags.hpp" #include "dataRepository/KeyNames.hpp" @@ -37,6 +39,7 @@ #include "fileIO/Outputs/OutputBase.hpp" #include "fileIO/Outputs/OutputManager.hpp" #include "functions/FunctionManager.hpp" +#include "mesh/ExternalDataSourceManager.hpp" #include "mesh/DomainPartition.hpp" #include "mesh/MeshBody.hpp" #include "mesh/MeshManager.hpp" @@ -44,7 +47,7 @@ #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "mesh/mpiCommunications/SpatialPartition.hpp" #include "physicsSolvers/PhysicsSolverManager.hpp" -#include "physicsSolvers/SolverBase.hpp" +#include "physicsSolvers/PhysicsSolverBase.hpp" #include "schema/schemaUtilities.hpp" // System includes @@ -71,6 +74,8 @@ ProblemManager::ProblemManager( conduit::Node & root ): setInputFlags( InputFlags::PROBLEM_ROOT ); + registerGroup< ExternalDataSourceManager >( groupKeys.externalDataSourceManager ); + m_fieldSpecificationManager = ®isterGroup< FieldSpecificationManager >( groupKeys.fieldSpecificationManager ); m_eventManager = ®isterGroup< EventManager >( groupKeys.eventManager ); @@ -79,7 +84,7 @@ ProblemManager::ProblemManager( conduit::Node & root ): registerGroup< MeshManager >( groupKeys.meshManager ); registerGroup< OutputManager >( groupKeys.outputManager ); m_physicsSolverManager = ®isterGroup< PhysicsSolverManager >( groupKeys.physicsSolverManager ); - registerGroup< TasksManager >( groupKeys.tasksManager ); + m_tasksManager = ®isterGroup< TasksManager >( groupKeys.tasksManager ); m_functionManager = ®isterGroup< FunctionManager >( groupKeys.functionManager ); // Command line entries @@ -136,11 +141,21 @@ ProblemManager::ProblemManager( conduit::Node & root ): setApplyDefaultValue( 0 ). setRestartFlags( RestartFlags::WRITE ). setDescription( "Whether to disallow using pinned memory allocations for MPI communication buffers." ); - } ProblemManager::~ProblemManager() -{} +{ + { + // This is a dummy to force the inclusion of constitutiveDrivers in the linking process for systems that have "--no-as-needed" as a + // default. + // The "correct" way to do this is in cmake using: + // target_link_options(constitutiveDrivers INTERFACE "SHELL:LINKER:--no-as-needed") + // but this applies "--no-as-needed" to all targets that link to constitutiveDrivers, which is not what we want. + // Also "--no-as-needed" is not supported on all platforms, so we have to guard the use of it. + // This is a workaround until we can figure out in cmake without too much trouble. + TriaxialDriver dummy( "dummy", this ); + } +} Group * ProblemManager::createChild( string const & GEOS_UNUSED_PARAM( childKey ), string const & GEOS_UNUSED_PARAM( childName ) ) @@ -150,7 +165,7 @@ Group * ProblemManager::createChild( string const & GEOS_UNUSED_PARAM( childKey void ProblemManager::problemSetup() { GEOS_MARK_FUNCTION; - postProcessInputRecursive(); + postInputInitializationRecursive(); generateMesh(); @@ -490,7 +505,7 @@ void ProblemManager::parseXMLDocument( xmlWrapper::xmlDocument & xmlDocument ) } -void ProblemManager::postProcessInput() +void ProblemManager::postInputInitialization() { DomainPartition & domain = getDomainPartition(); @@ -525,7 +540,7 @@ void ProblemManager::postProcessInput() if( repartition ) { partition.setPartitions( xpar, ypar, zpar ); - int const mpiSize = MpiWrapper::commSize( MPI_COMM_GEOSX ); + int const mpiSize = MpiWrapper::commSize( MPI_COMM_GEOS ); // Case : Using MPI domain decomposition and partition are not defined (mainly for external mesh readers) if( mpiSize > 1 && xpar == 1 && ypar == 1 && zpar == 1 ) { @@ -540,22 +555,22 @@ void ProblemManager::initializationOrder( string_array & order ) { SortedArray< string > usedNames; + // first, numerical methods + order.emplace_back( groupKeys.numericalMethodsManager.key() ); + usedNames.insert( groupKeys.numericalMethodsManager.key() ); - { - order.emplace_back( groupKeys.numericalMethodsManager.key() ); - usedNames.insert( groupKeys.numericalMethodsManager.key() ); - } + // next, domain + order.emplace_back( groupKeys.domain.key() ); + usedNames.insert( groupKeys.domain.key() ); - { - order.emplace_back( groupKeys.domain.key() ); - usedNames.insert( groupKeys.domain.key() ); - } + // next, events + order.emplace_back( groupKeys.eventManager.key() ); + usedNames.insert( groupKeys.eventManager.key() ); - { - order.emplace_back( groupKeys.eventManager.key() ); - usedNames.insert( groupKeys.eventManager.key() ); - } + // (keeping outputs for the end) + usedNames.insert( groupKeys.outputManager.key() ); + // next, everything... for( auto const & subGroup : this->getSubGroups() ) { if( usedNames.count( subGroup.first ) == 0 ) @@ -563,6 +578,9 @@ void ProblemManager::initializationOrder( string_array & order ) order.emplace_back( subGroup.first ); } } + + // end with outputs (in order to define the chunk sizes after any data source) + order.emplace_back( groupKeys.outputManager.key() ); } @@ -665,6 +683,7 @@ void ProblemManager::generateMesh() } domain.setupCommunications( useNonblockingMPI ); + domain.outputPartitionInformation(); domain.forMeshBodies( [&]( MeshBody & meshBody ) { @@ -683,13 +702,21 @@ void ProblemManager::generateMesh() FaceManager & faceManager = meshLevel.getFaceManager(); EdgeManager & edgeManager = meshLevel.getEdgeManager(); NodeManager const & nodeManager = meshLevel.getNodeManager(); + ElementRegionManager & elementManager = meshLevel.getElemManager(); - // The computation of geometric quantities is now possible for `FaceElementSubRegion`, - // because the ghosting ensures that the neighbor cells of the fracture elements are available. - // These neighbor cells are providing the node information to the fracture elements. - meshLevel.getElemManager().forElementSubRegions< FaceElementSubRegion >( [&]( FaceElementSubRegion & subRegion ) + elementManager.forElementSubRegions< FaceElementSubRegion >( [&]( FaceElementSubRegion & subRegion ) { + /// 1. The computation of geometric quantities which is now possible for `FaceElementSubRegion`, + // because the ghosting ensures that the neighbor cells of the fracture elements are available. + // These neighbor cells are providing the node information to the fracture elements. subRegion.calculateElementGeometricQuantities( nodeManager, faceManager ); + + // 2. Reorder the face map based on global numbering of neighboring cells + subRegion.flipFaceMap( faceManager, elementManager ); + + // 3. We flip the face normals of faces adjacent to the faceElements if they are not pointing in the + // direction of the fracture. + subRegion.fixNeighboringFacesNormals( faceManager, elementManager ); } ); faceManager.setIsExternal(); @@ -742,7 +769,7 @@ ProblemManager::getDiscretizations() const DomainPartition const & domain = getDomainPartition(); Group const & meshBodies = domain.getMeshBodies(); - m_physicsSolverManager->forSubGroups< SolverBase >( [&]( SolverBase & solver ) + m_physicsSolverManager->forSubGroups< PhysicsSolverBase >( [&]( PhysicsSolverBase & solver ) { solver.generateMeshTargetsFromTargetRegions( meshBodies ); @@ -878,7 +905,7 @@ map< std::tuple< string, string, string, string >, localIndex > ProblemManager:: for( localIndex solverIndex=0; solverIndexnumSubGroups(); ++solverIndex ) { - SolverBase const * const solver = m_physicsSolverManager->getGroupPointer< SolverBase >( solverIndex ); + PhysicsSolverBase const * const solver = m_physicsSolverManager->getGroupPointer< PhysicsSolverBase >( solverIndex ); if( solver != nullptr ) { diff --git a/src/coreComponents/mainInterface/ProblemManager.hpp b/src/coreComponents/mainInterface/ProblemManager.hpp index aaeb01951da..8ff875005d2 100644 --- a/src/coreComponents/mainInterface/ProblemManager.hpp +++ b/src/coreComponents/mainInterface/ProblemManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #ifndef GEOS_MAININTERFACE_PROBLEMMANAGER_HPP_ #define GEOS_MAININTERFACE_PROBLEMMANAGER_HPP_ -#include "events/EventManager.hpp" +#include "dataRepository/Group.hpp" namespace geos { @@ -34,6 +35,8 @@ namespace constitutive { class ConstitutiveManager; } +class EventManager; +class TasksManager; class FunctionManager; class FieldSpecificationManager; struct CommandLineOptions; @@ -240,6 +243,7 @@ class ProblemManager : public dataRepository::Group dataRepository::GroupKey constitutiveManager = { "Constitutive" }; ///< Constitutive key dataRepository::GroupKey domain = { "domain" }; ///< Domain key dataRepository::GroupKey eventManager = { "Events" }; ///< Events key + dataRepository::GroupKey externalDataSourceManager = { "ExternalDataSource" }; ///< External Data Source key dataRepository::GroupKey fieldSpecificationManager = { "FieldSpecifications" }; ///< Field specification key dataRepository::GroupKey functionManager = { "Functions" }; ///< Functions key dataRepository::GroupKey geometricObjectManager = { "Geometry" }; ///< Geometry key @@ -308,19 +312,25 @@ class ProblemManager : public dataRepository::Group return *m_fieldSpecificationManager; } - /** - * @brief Returns the const EventManager. - * @return The const EventManager. + * @brief Returns the EventManager. + * @return The EventManager. */ EventManager & getEventManager() {return *m_eventManager;} + /** + * @brief Returns the TasksManager. + * @return The TasksManager. + */ + TasksManager & getTasksManager() + {return *m_tasksManager;} + protected: /** * @brief Post process the command line input */ - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; private: @@ -367,6 +377,9 @@ class ProblemManager : public dataRepository::Group /// The EventManager EventManager * m_eventManager; + /// The TasksManager + TasksManager * m_tasksManager; + /// The FunctionManager FunctionManager * m_functionManager; diff --git a/src/coreComponents/mainInterface/initialization.cpp b/src/coreComponents/mainInterface/initialization.cpp index 75ea5de3b61..c33da0c59a7 100644 --- a/src/coreComponents/mainInterface/initialization.cpp +++ b/src/coreComponents/mainInterface/initialization.cpp @@ -1,11 +1,12 @@ /* * ------------------------------------------------------------------------------------------------------------ - * SPDX-LiCense-Identifier: LGPL-2.1-only + * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mainInterface/initialization.hpp b/src/coreComponents/mainInterface/initialization.hpp index 6a33a4580e0..85cd4331066 100644 --- a/src/coreComponents/mainInterface/initialization.hpp +++ b/src/coreComponents/mainInterface/initialization.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mainInterface/version.cpp b/src/coreComponents/mainInterface/version.cpp index 123025930d8..0ed60fc6b18 100644 --- a/src/coreComponents/mainInterface/version.cpp +++ b/src/coreComponents/mainInterface/version.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -13,7 +14,7 @@ */ #include "common/GeosxConfig.hpp" -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" #include "mainInterface/GeosxVersion.hpp" namespace geos @@ -21,10 +22,10 @@ namespace geos std::string getVersion() { -#if defined(GEOSX_GIT_BRANCH) && defined(GEOSX_GIT_HASH) - return GEOSX_VERSION_FULL " (" GEOSX_GIT_BRANCH ", sha1: " GEOSX_GIT_HASH ")"; +#if defined(GEOS_GIT_BRANCH) && defined(GEOS_GIT_HASH) + return GEOS_VERSION_FULL " (" GEOS_GIT_BRANCH ", sha1: " GEOS_GIT_HASH ")"; #else - return GEOSX_VERSION_FULL; + return GEOS_VERSION_FULL; #endif } @@ -80,7 +81,7 @@ void outputVersionInfo() GEOS_LOG_RANK_0( " - openmp version: " << _OPENMP ); #endif -#if defined(GEOSX_USE_MPI) +#if defined(GEOS_USE_MPI) { char version[MPI_MAX_LIBRARY_VERSION_STRING]; int len; @@ -122,11 +123,11 @@ void outputVersionInfo() #endif #if defined(metis_VERSION) - GEOS_LOG_RANK_0( " - METIS version: " << STRINGIZE( METIS_VERSION ) ); + GEOS_LOG_RANK_0( " - METIS version: " << STRINGIZE( metis_VERSION ) ); #endif #if defined(parmetis_VERSION) - GEOS_LOG_RANK_0( " - PARAMETIS version: " << STRINGIZE( PARAMETIS_VERSION ) ); + GEOS_LOG_RANK_0( " - PARAMETIS version: " << STRINGIZE( parmetis_VERSION ) ); #endif #if defined(scotch_VERSION) @@ -163,7 +164,7 @@ void outputVersionInfo() #if \ defined(GEOS_USE_DEVICE) && \ - defined(GEOSX_USE_HYPRE) && \ + defined(GEOS_USE_HYPRE) && \ ( GEOS_USE_HYPRE_DEVICE == GEOS_USE_HYPRE_CPU ) GEOS_LOG_RANK_0( "" ); GEOS_LOG_RANK_0( "**************************************************" ); diff --git a/src/coreComponents/mainInterface/version.hpp b/src/coreComponents/mainInterface/version.hpp index 9f063922769..8d4847c9497 100644 --- a/src/coreComponents/mainInterface/version.hpp +++ b/src/coreComponents/mainInterface/version.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/math/CMakeLists.txt b/src/coreComponents/math/CMakeLists.txt index 290f23808db..9af283583e3 100644 --- a/src/coreComponents/math/CMakeLists.txt +++ b/src/coreComponents/math/CMakeLists.txt @@ -1,3 +1,22 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package : math + +Contains interpolation and extrapolation math functions. +#]] + # # Specify all headers # @@ -6,11 +25,12 @@ set( math_headers extrapolation/Extrapolation.hpp) blt_add_library( NAME math - SOURCES + SOURCES HEADERS ${math_headers} - DEPENDS_ON + DEPENDS_ON SHARED FALSE ) - + target_include_directories( math INTERFACE ${CMAKE_SOURCE_DIR}/coreComponents ) +install( TARGETS math LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) diff --git a/src/coreComponents/math/extrapolation/Extrapolation.hpp b/src/coreComponents/math/extrapolation/Extrapolation.hpp index af79fb69f1c..9df48fdefb8 100644 --- a/src/coreComponents/math/extrapolation/Extrapolation.hpp +++ b/src/coreComponents/math/extrapolation/Extrapolation.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/math/interpolation/Interpolation.hpp b/src/coreComponents/math/interpolation/Interpolation.hpp index 0ba6b6f7ddb..1b72fe943bb 100644 --- a/src/coreComponents/math/interpolation/Interpolation.hpp +++ b/src/coreComponents/math/interpolation/Interpolation.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/BufferOps.cpp b/src/coreComponents/mesh/BufferOps.cpp index a81b84e8518..408e11839a7 100644 --- a/src/coreComponents/mesh/BufferOps.cpp +++ b/src/coreComponents/mesh/BufferOps.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/BufferOps.hpp b/src/coreComponents/mesh/BufferOps.hpp index 8070854d4c4..ef6b926ac8d 100644 --- a/src/coreComponents/mesh/BufferOps.hpp +++ b/src/coreComponents/mesh/BufferOps.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/CMakeLists.txt b/src/coreComponents/mesh/CMakeLists.txt index 6065ef14dae..05f09e22dc8 100644 --- a/src/coreComponents/mesh/CMakeLists.txt +++ b/src/coreComponents/mesh/CMakeLists.txt @@ -1,7 +1,33 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: mesh + +Contains: + - components allowing to import, store and access the mesh. + - partitioning and communication tools (ParMETIS, Scotch and VTK interfaces). + - GEOS components defining simple geometric objects. + - basic geometric and mesh utilities. +#]] + +# # Specify all headers +# set( mesh_headers BufferOps.hpp CellElementRegion.hpp + CellElementRegionSelector.hpp CellElementSubRegion.hpp DomainPartition.hpp EdgeManager.hpp @@ -9,6 +35,8 @@ set( mesh_headers ElementRegionManager.hpp ElementSubRegionBase.hpp ElementType.hpp + ExternalDataSourceBase.hpp + ExternalDataSourceManager.hpp EmbeddedSurfaceNodeManager.hpp EmbeddedSurfaceSubRegion.hpp MeshFields.hpp @@ -54,12 +82,13 @@ set( mesh_headers generators/InternalMeshGenerator.hpp generators/InternalWellGenerator.hpp generators/InternalWellboreGenerator.hpp + generators/MeshComponentBase.hpp generators/MeshGeneratorBase.hpp generators/ParMETISInterface.hpp generators/ParticleMeshGenerator.hpp generators/PartitionDescriptor.hpp generators/PrismUtilities.hpp - generators/WellGeneratorABC.hpp + generators/Region.hpp generators/WellGeneratorBase.hpp mpiCommunications/CommID.hpp mpiCommunications/CommunicationTools.hpp @@ -77,16 +106,19 @@ set( mesh_headers simpleGeometricObjects/SimpleGeometricObjectBase.hpp simpleGeometricObjects/PlanarGeometricObject.hpp simpleGeometricObjects/ThickPlane.hpp - utilities/AverageOverQuadraturePointsKernel.hpp + utilities/AverageOverQuadraturePointsKernel.hpp utilities/CIcomputationKernel.hpp utilities/ComputationalGeometry.hpp utilities/MeshMapUtilities.hpp utilities/StructuredGridUtilities.hpp ) +# # Specify all sources +# set( mesh_sources BufferOps.cpp CellElementRegion.cpp + CellElementRegionSelector.cpp CellElementSubRegion.cpp DomainPartition.cpp EdgeManager.cpp @@ -95,6 +127,8 @@ set( mesh_sources ElementSubRegionBase.cpp EmbeddedSurfaceNodeManager.cpp EmbeddedSurfaceSubRegion.cpp + ExternalDataSourceBase.cpp + ExternalDataSourceManager.cpp FaceElementSubRegion.cpp FaceManager.cpp MeshBody.cpp @@ -127,9 +161,11 @@ set( mesh_sources generators/InternalMeshGenerator.cpp generators/InternalWellGenerator.cpp generators/InternalWellboreGenerator.cpp + generators/MeshComponentBase.cpp generators/MeshGeneratorBase.cpp generators/ParMETISInterface.cpp generators/ParticleMeshGenerator.cpp + generators/Region.cpp generators/WellGeneratorBase.cpp mpiCommunications/CommID.cpp mpiCommunications/CommunicationTools.cpp @@ -148,13 +184,14 @@ set( mesh_sources simpleGeometricObjects/ThickPlane.cpp utilities/ComputationalGeometry.cpp ) -set( dependencyList ${parallelDeps} schema dataRepository constitutive finiteElement parmetis metis ) +set( dependencyList ${parallelDeps} schema constitutive finiteElement parmetis metis ) if( ENABLE_VTK ) message(STATUS "Adding VTK readers") set( mesh_headers ${mesh_headers} generators/CollocatedNodes.hpp generators/VTKFaceBlockUtilities.hpp + generators/VTKHierarchicalDataSource.hpp generators/VTKMeshGenerator.hpp generators/VTKMeshGeneratorTools.hpp generators/VTKWellGenerator.hpp @@ -163,11 +200,12 @@ if( ENABLE_VTK ) set( mesh_sources ${mesh_sources} generators/CollocatedNodes.cpp generators/VTKFaceBlockUtilities.cpp + generators/VTKHierarchicalDataSource.cpp generators/VTKMeshGenerator.cpp generators/VTKMeshGeneratorTools.cpp generators/VTKWellGenerator.cpp generators/VTKUtilities.cpp - ) + ) list( APPEND dependencyList VTK::IOLegacy VTK::FiltersParallelDIY2 ) if( ENABLE_MPI ) list( APPEND dependencyList VTK::IOParallelXML VTK::ParallelMPI ) @@ -180,14 +218,21 @@ if( ENABLE_SCOTCH ) list( APPEND dependencyList ptscotch ) endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) + blt_add_library( NAME mesh SOURCES ${mesh_sources} HEADERS ${mesh_headers} - DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} ) + DEPENDS_ON ${decoratedDependencies} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} + ) target_include_directories( mesh PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +install( TARGETS mesh LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) + if( ENABLE_VTK ) # Avoid compiling with nvcc which sometimes segfaults in debug set_source_files_properties( generators/VTKMeshGeneratorTools.cpp PROPERTIES LANGUAGE CXX ) diff --git a/src/coreComponents/mesh/CellElementRegion.cpp b/src/coreComponents/mesh/CellElementRegion.cpp index 3d614db6606..4207cdefdca 100644 --- a/src/coreComponents/mesh/CellElementRegion.cpp +++ b/src/coreComponents/mesh/CellElementRegion.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,6 +17,8 @@ #include "CellElementSubRegion.hpp" #include "mesh/generators/CellBlockABC.hpp" +#include + namespace geos { using namespace dataRepository; @@ -23,9 +26,24 @@ using namespace dataRepository; CellElementRegion::CellElementRegion( string const & name, Group * const parent ): ElementRegionBase( name, parent ) { + std::vector< string > elementNames; + for( int i = 0; i < numElementTypes(); ++i ) + { + if( getElementDim( (ElementType)i ) == 3 ) + { + elementNames.push_back( getElementTypeName( (ElementType)i ) ); + } + } + registerWrapper( viewKeyStruct::sourceCellBlockNamesString(), &m_cellBlockNames ). setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ). - setInputFlag( InputFlags::REQUIRED ); + setInputFlag( InputFlags::REQUIRED ). + setDescription( GEOS_FMT( "List of the desired cell-blocks qualifiers to contain in this {}. Qualifiers can be either cell-block " + "names, region attribute values, or fnmatch pattern." + "The form of loaded cell-block names is of \"regionAttribute_elementType\", so \"1_tetrahedra\" " + " contains the tetrahedric elements for which the regionAttribute is 1.\n" + "The element types are: {}.", + catalogName(), stringutilities::join( elementNames, ", " ) ) ); registerWrapper( viewKeyStruct::coarseningRatioString(), &m_coarseningRatio ). setInputFlag( InputFlags::OPTIONAL ). @@ -37,13 +55,22 @@ CellElementRegion::~CellElementRegion() void CellElementRegion::generateMesh( Group const & cellBlocks ) { - Group & elementSubRegions = this->getGroup( viewKeyStruct::elementSubRegions() ); - - for( string const & cellBlockName : this->m_cellBlockNames ) + GEOS_THROW_IF( m_cellBlockNames.empty(), + GEOS_FMT( "{}: No cellBlock selected in this region.", + getDataContext() ), + InputError ); + Group & subRegions = this->getGroup( viewKeyStruct::elementSubRegions() ); + for( string const & cbName : m_cellBlockNames ) { - CellElementSubRegion & subRegion = elementSubRegions.registerGroup< CellElementSubRegion >( cellBlockName ); - CellBlockABC const & source = cellBlocks.getGroup< CellBlockABC >( subRegion.getName() ); - subRegion.copyFromCellBlock( source ); + CellBlockABC const * cellBlock = cellBlocks.getGroupPointer< CellBlockABC >( cbName ); + GEOS_THROW_IF( cellBlock == nullptr, + GEOS_FMT( "{}: No cellBlock named '{}' found.\nAvailable cellBlock list: {{ {} }}\nNo CellElementRegionSelector has been used to verify the cellBlock selection.", + getDataContext(), cbName, stringutilities::join( m_cellBlockNames, ", " ) ), + InputError ); + + // subRegion name must be the same as the cell-block (so we can match them and reference them in errors). + CellElementSubRegion & subRegion = subRegions.registerGroup< CellElementSubRegion >( cbName ); + subRegion.copyFromCellBlock( *cellBlock ); } } diff --git a/src/coreComponents/mesh/CellElementRegion.hpp b/src/coreComponents/mesh/CellElementRegion.hpp index 130423b42bc..95d9d978de8 100644 --- a/src/coreComponents/mesh/CellElementRegion.hpp +++ b/src/coreComponents/mesh/CellElementRegion.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -84,16 +85,15 @@ class CellElementRegion : public ElementRegionBase /** - * @brief Getter for m_cellBlockNames - * @return The array of cell block names. + * @return List of user-requested mesh cellBlocks names. + * @note the list may be incomplete / illegible if CellElementRegionSelectorhas not been used on + * the instance. */ arrayView1d< string const > getCellBlockNames() const - { - return m_cellBlockNames.toViewConst(); - } + { return m_cellBlockNames.toViewConst(); } /** - * @brief Add a cellBlockRegion name to the list. + * @brief Select a cellBlock by its name for generateMesh(). * @param cellBlockName string containing the cell block region name. */ void addCellBlockName( string const & cellBlockName ) @@ -102,17 +102,25 @@ class CellElementRegion : public ElementRegionBase } /** - * @brief Add an array cellBlockRegion name to the list. + * @brief Select cellBlocks by their names for generateMesh(). * @param cellBlockNames array of string containing the cell block region names. */ - void addCellBlockNames( arrayView1d< string const > const & cellBlockNames ) + template< typename StringContainerType > + void setCellBlockNames( StringContainerType const & cellBlockNames ) { + m_cellBlockNames.clear(); for( auto const & name: cellBlockNames ) { m_cellBlockNames.emplace_back( name ); } } + /** + * @brief register every cellBlocks that is requested in the cellBlockNames list. + * @note Assume that the cellBlockNames list is filled valid `cellBlocks` names + * (use CellElementRegionSelector to verify & fill this list after the user-requests). + * @param cellBlocks Cell blocks from where the mesh is extracted. + */ virtual void generateMesh( Group const & cellBlocks ) override; ///@} @@ -126,19 +134,26 @@ class CellElementRegion : public ElementRegionBase /// @return String key for the coarsening ratio static constexpr char const * coarseningRatioString() {return "coarseningRatio"; } - /// @return String key for the cell block names + /// @return String key for the user-requested mesh cellBlocks qualifiers: cellblock names, cellblock match patterns, attribute values. static constexpr char const * sourceCellBlockNamesString() {return "cellBlocks"; } }; - private: - // Cell block names + /// @brief List of user-requested mesh cellBlocks qualifiers: cellblock names, cellblock match patterns, attribute values. string_array m_cellBlockNames; - // Coarsening ratio + /// @brief Coarsening ratio real64 m_coarseningRatio; + + /** + * @return all cell-block names entries from m_cellBlockAttributeValues, + * m_cellBlockMatchPatterns and m_cellBlockNames. + * @param cellBlocks the input mesh cell-block list + */ + std::set< string > computeSelectedCellBlocks( std::set< string > const & cellBlocksNames ) const; + }; } /* namespace geos */ diff --git a/src/coreComponents/mesh/CellElementRegionSelector.cpp b/src/coreComponents/mesh/CellElementRegionSelector.cpp new file mode 100644 index 00000000000..f5bbc006116 --- /dev/null +++ b/src/coreComponents/mesh/CellElementRegionSelector.cpp @@ -0,0 +1,194 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "mesh/CellElementRegionSelector.hpp" + +#include +#include + + +namespace geos +{ +using namespace dataRepository; +using ViewKeys = CellElementRegion::viewKeyStruct; + + +CellElementRegionSelector::CellElementRegionSelector( + Group const & cellBlocks, + std::map< integer, std::set< string > > const & regionsCellBlocks ) +{ + // The owners lists need to be initialized so we will be able to verify later that it is not empty. + + cellBlocks.forSubGroups< CellBlockABC >( [&] ( CellBlockABC const & cellBlock ) + { + string const name = cellBlock.getName(); + m_cellBlocksOwners.emplace( name, std::vector< CellElementRegion const * >() ); + } ); + + for( auto const & regionCellBlocks : regionsCellBlocks ) + { + string const regionAttributeStr = std::to_string( regionCellBlocks.first ); + m_regionAttributesCellBlocks.emplace( regionAttributeStr, regionCellBlocks.second ); + m_regionAttributesOwners.emplace( regionAttributeStr, std::vector< CellElementRegion const * >() ); + } +} + + +std::set< string > +CellElementRegionSelector::getMatchingCellblocks( CellElementRegion const & region, + string_view matchPattern ) const +{ + std::set< string > matchedCellBlocks; + bool matching = false; + for( auto const & [cellBlockName, owners] : m_cellBlocksOwners ) + { + // if the pattern matches the tested cellBlock name + if( fnmatch( matchPattern.data(), cellBlockName.c_str(), 0 ) == 0 ) + { + matching = true; + matchedCellBlocks.emplace( cellBlockName ); + } + } + + GEOS_THROW_IF( !matching, + GEOS_FMT( "{}: No cellBlock name is satisfying the qualifier '{}'.\n" + "Available cellBlock list: {{ {} }}\nAvailable region attribute list: {{ {} }}", + region.getWrapperDataContext( ViewKeys::sourceCellBlockNamesString() ), + matchPattern, + stringutilities::joinLamda( m_regionAttributesOwners, ", ", + []( auto pair ) { return pair->first; } ), + stringutilities::joinLamda( m_cellBlocksOwners, ", ", + []( auto pair ) { return pair->first; } ) ), + InputError ); + return matchedCellBlocks; +} + +void +CellElementRegionSelector::verifyRequestedCellBlocks( CellElementRegion const & region, + std::set< string > const & cellBlockNames ) const +{ + for( string const & requestedCellBlockName : cellBlockNames ) + { + // if cell block does not exist in the mesh + GEOS_THROW_IF( m_cellBlocksOwners.count( requestedCellBlockName ) == 0, + GEOS_FMT( "{}: No cellBlock named '{}'.\nAvailable cellBlock list: {{ {} }}", + region.getWrapperDataContext( ViewKeys::sourceCellBlockNamesString() ), + requestedCellBlockName, + stringutilities::joinLamda( m_cellBlocksOwners, ", ", + []( auto pair ) { return pair->first; } ) ), + InputError ); + } +} + + +void +CellElementRegionSelector::registerRegionSelection( CellElementRegion const & region, + std::set< string > const & cellBlockNames, + std::set< string > const & attributeValues ) +{ + for( string attributeValue : attributeValues ) + { + m_regionAttributesOwners[attributeValue].push_back( ®ion ); + } + + for( string const & cellBlockName : cellBlockNames ) + { + m_cellBlocksOwners[cellBlockName].push_back( ®ion ); + } +} + + +std::set< string > CellElementRegionSelector::buildCellBlocksSelection( CellElementRegion const & region ) +{ + std::set< string > cellBlocksSelection; + std::set< string > regionAttributeSelection; + + auto const qualifiers = region.getCellBlockNames(); + for( string const & qualifier : qualifiers ) + { + auto const regionCellBlocks = m_regionAttributesCellBlocks.find( qualifier ); + if( regionCellBlocks != m_regionAttributesCellBlocks.end() ) + { // if the qualifier is a region attribute value, let's select it + regionAttributeSelection.emplace( regionCellBlocks->first ); + for( string const & cellBlock : regionCellBlocks->second ) + { + cellBlocksSelection.emplace( cellBlock ); + } + } + else + { // the qualifier is a match pattern, or a simple cellblock name, let's select all matching cell-blocks + std::set< string > const matchedCellBlocks = getMatchingCellblocks( region, qualifier ); + cellBlocksSelection.insert( matchedCellBlocks.begin(), matchedCellBlocks.end() ); + } + } + + verifyRequestedCellBlocks( region, cellBlocksSelection ); + registerRegionSelection( region, cellBlocksSelection, regionAttributeSelection ); + + return cellBlocksSelection; +} + +void CellElementRegionSelector::checkSelectionConsistency() const +{ + auto const getRegionStr = []( auto regionPtrIterator ) -> string { + return GEOS_FMT( "- {}", (*regionPtrIterator)->getDataContext() ); + }; + + auto const checkOwnerCount = [&]( string_view qualifierType, + auto const & qualifiersOwners, + auto & orphanList ) { + // Search of never or multiple selected attribute values + std::vector< string > multipleRefsErrors; + for( auto const & [qualifier, owningRegions] : qualifiersOwners ) + { + if( owningRegions.size() == 0 ) + { + orphanList.insert( qualifier ); + } + else if( owningRegions.size() > 1 ) + { + multipleRefsErrors.push_back( + GEOS_FMT( "The {} '{}' has been referenced in multiple {}:\n{}", + qualifierType, qualifier, CellElementRegion::catalogName(), + stringutilities::joinLamda( owningRegions, '\n', getRegionStr ) ) ); + } + } + GEOS_THROW_IF( !multipleRefsErrors.empty(), stringutilities::join( multipleRefsErrors, "\n\n" ), InputError ); + }; + + std::set< string > orphanRegionAttributes; + std::set< string > orphanCellBlockNames; + checkOwnerCount( "region attribute", m_regionAttributesOwners, orphanRegionAttributes ); + checkOwnerCount( "cell-block", m_cellBlocksOwners, orphanCellBlockNames ); + + if( !orphanCellBlockNames.empty() ) + { + std::ostringstream oss; + if( !orphanRegionAttributes.empty() ) + { + oss << GEOS_FMT( "The region attributes {{ {} }} has not been referenced in any {}.\n", + stringutilities::join( orphanRegionAttributes, ", " ), + CellElementRegion::catalogName() ); + } + oss << GEOS_FMT( "The following cell-blocks has not been referenced in any region: {{ {} }}.\n", + stringutilities::join( orphanCellBlockNames, ", " ) ); + oss << GEOS_FMT( "Please add it in an existing {} (through the '{}' attribute), or consider creating a new one to describe your model.", + CellElementRegion::catalogName(), ViewKeys::sourceCellBlockNamesString() ); + GEOS_THROW( oss.str(), InputError ); + } +} + + +} /* namespace geos */ diff --git a/src/coreComponents/mesh/CellElementRegionSelector.hpp b/src/coreComponents/mesh/CellElementRegionSelector.hpp new file mode 100644 index 00000000000..d3d1c6a840d --- /dev/null +++ b/src/coreComponents/mesh/CellElementRegionSelector.hpp @@ -0,0 +1,125 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CellElementRegionSelector.hpp + */ + +#ifndef GEOS_MESH_CELLELEMENTREGIONSELECTOR_HPP_ +#define GEOS_MESH_CELLELEMENTREGIONSELECTOR_HPP_ + +#include "mesh/CellElementRegion.hpp" + +namespace geos +{ + +/** + * @class CellElementRegionSelector + * + * CellElementRegionSelector allows a CellElementRegion to safely select cell-blocks according to the user input. + * It handles all user input checks and throws an exception in the event of inconsistency. + */ +class CellElementRegionSelector +{ +public: + + /** + * @brief Construct a new CellElementRegionSelector. + * @param cellBlocks a Group containing all the available cell-blocks. + * @param cellBlocksRegion A map of the cellblocks name lists for each region attributes value. + */ + CellElementRegionSelector( dataRepository::Group const & cellBlocks, + std::map< integer, std::set< string > > const & cellBlocksRegion ); + + /** + * @brief Select the mesh cell-blocks for the specified region following the user inputs. + * @throw an InputError if the user setting are inconsistant. + * @param region the region for which we want to select the cell-blocks. + * @return the selected cell-blocks names. + */ + std::set< string > buildCellBlocksSelection( CellElementRegion const & region ); + + /** + * @throw An InputError if region cell-blocks selections is inconsistent: + * - cell-block is in more than one region, + * - orphan cell-block + * @todo For now, multiple regions per cell is not supported (ElementRegionManager::getCellBlockToSubRegionMap()). + * We could refactor the CellElementRegion & Mesh classes so regions are mapped to cell-blocks IN the mesh (and potentially + * to multiple regions per cell). So, for external meshes, the cell-blocks would no longer be exposed to the final user. + */ + void checkSelectionConsistency() const; + +private: + + /// @brief The separator between the regionAttribute value and the type of the shape in a given cellBlock. + static constexpr string_view cellBlockTypeSeparator = "_"; + + /// @brief A map that link every cell-block name to the CellElementRegion(s) that references it. + std::map< string, std::vector< CellElementRegion const * > > m_cellBlocksOwners; + + /// @brief A map that link every region attribute values to the CellElementRegion(s) that references it. + std::map< string, std::vector< CellElementRegion const * > > m_regionAttributesOwners; + + /** + * @brief A map of the cellblocks name lists for each region attributes value. Internal attribute type + * is integer to facilitate comparison with cellBlock qualifiers. + */ + std::map< string, std::set< string > const & > m_regionAttributesCellBlocks; + + /** + * @return A set of the FNMatch pattern from the provided lists. + * @param region The region for which we collect the match-patterns. + * @param requestedAttributeValues The user requested attribute values. They will get converted to + * match-pattern that select the coresponding cell-blocks. + * @param requestedMatchPatterns The match patterns that the user requested explicitely. + * @throw An InputError if the attribute values does not exist in the mesh. + */ + std::set< string > buildMatchPatterns( CellElementRegion const & region, + std::set< string > const & attributeValues, + std::set< string > const & matchPatterns ) const; + + /** + * @return A set of the cell-blocks that the provided match-patterns select. + * @param region The region for which we collect the cell-blocks. + * @param matchPatterns The FNMatch pattern + * @throw An InputError if a FNMatch pattern does not select any cell-block. + */ + std::set< string > getMatchingCellblocks( CellElementRegion const & region, + string_view matchPattern ) const; + + /** + * @brief A set of the cell-blocks that the provided match-patterns select. + * @param region The region for which we collect the cell-blocks. + * @param matchPatterns The FNMatch pattern set. + * @throw An InputError if a FNMatch pattern does not select any cell-block. + */ + void verifyRequestedCellBlocks( CellElementRegion const & region, + std::set< string > const & cellBlockNames ) const; + + /** + * @brief Effectively select the specified cell-blocks & region attribute for the specified region. + * @param region The region for which when want to select cell-blocks + * @param attributeValues The attribute values we want to select (can be empty). + * @param cellBlockNames The cell-block names we want to select (can be empty). + */ + void registerRegionSelection( CellElementRegion const & region, + std::set< string > const & cellBlockNames, + std::set< string > const & attributeValues ); + +}; + +} /* namespace geos */ + +#endif /* GEOS_MESH_CELLELEMENTREGIONSELECTOR_HPP_ */ diff --git a/src/coreComponents/mesh/CellElementSubRegion.cpp b/src/coreComponents/mesh/CellElementSubRegion.cpp index 550b3614871..d324b6189c0 100644 --- a/src/coreComponents/mesh/CellElementSubRegion.cpp +++ b/src/coreComponents/mesh/CellElementSubRegion.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -44,6 +45,10 @@ CellElementSubRegion::CellElementSubRegion( string const & name, Group * const p registerWrapper( viewKeyStruct::fracturedCellsString(), &m_fracturedCells ).setSizedFromParent( 1 ); + registerWrapper( viewKeyStruct::bubbleCellsString(), &m_bubbleCells ).setSizedFromParent( 0 ); + + registerWrapper( viewKeyStruct::toFaceElementsString(), &m_toFaceElements ).setSizedFromParent( 0 ); + excludeWrappersFromPacking( { viewKeyStruct::nodeListString(), viewKeyStruct::edgeListString(), viewKeyStruct::faceListString(), @@ -187,6 +192,11 @@ localIndex CellElementSubRegion::unpackUpDownMaps( buffer_unit_type const * & bu this->globalToLocalMap(), faceList().relatedObjectGlobalToLocal() ); + + GEOS_ERROR_IF_NE( m_unmappedGlobalIndicesInNodelist.size(), 0 ); + GEOS_ERROR_IF_NE( m_unmappedGlobalIndicesInEdgelist.size(), 0 ); + GEOS_ERROR_IF_NE( m_unmappedGlobalIndicesInFacelist.size(), 0 ); + return unPackedSize; } diff --git a/src/coreComponents/mesh/CellElementSubRegion.hpp b/src/coreComponents/mesh/CellElementSubRegion.hpp index 37e6c3537e2..cdb158fa88f 100644 --- a/src/coreComponents/mesh/CellElementSubRegion.hpp +++ b/src/coreComponents/mesh/CellElementSubRegion.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -191,6 +192,10 @@ class CellElementSubRegion : public ElementSubRegionBase static constexpr char const * toEmbSurfString() { return "ToEmbeddedSurfaces"; } /// @return String key to fracturedCells static constexpr char const * fracturedCellsString() { return "fracturedCells"; } + /// @return String key to bubbleCells + static constexpr char const * bubbleCellsString() { return "bubbleCells"; } + /// @return String key to toFaceElements + static constexpr char const * toFaceElementsString() { return "toFaceElements"; } /// ViewKey for the constitutive grouping dataRepository::ViewKey constitutiveGrouping = { constitutiveGroupingString() }; @@ -315,6 +320,32 @@ class CellElementSubRegion : public ElementSubRegionBase */ EmbSurfMapType const & embeddedSurfacesList() const { return m_toEmbeddedSurfaces; } + /** + * @brief Set the array of bubble elements. + * @param[in] bubbleCells The array of bubble elements. + */ + void setBubbleElementsList( arrayView1d< localIndex const > const bubbleCells ) + { m_bubbleCells = bubbleCells; } + + /** + * @brief @return The array view of bubble elements. + */ + arrayView1d< localIndex const > const bubbleElementsList() const + { return m_bubbleCells.toViewConst(); } + + /** + * @brief Set the array of neighboring face elements. + * @param[in] faceElemsList The array of neighboring face elements. + */ + void setFaceElementsList( arrayView2d< localIndex const > const faceElemsList ) + { m_toFaceElements = faceElemsList; } + + /** + * @brief @return The array of neighboring face elements. + */ + arrayView2d< localIndex const > const faceElementsList() const + { return m_toFaceElements.toViewConst(); } + /** * @brief Compute the center of each element in the subregion. * @param[in] X an arrayView of (const) node positions @@ -379,6 +410,14 @@ class CellElementSubRegion : public ElementSubRegionBase /// Map from local Cell Elements to Embedded Surfaces EmbSurfMapType m_toEmbeddedSurfaces; + /// List of the elements adjacent to faceElement (useful for bubble elements) + array1d< localIndex > m_bubbleCells; + + /// List of face IDs adjacent to faceElement (useful for bubble elements). + /// A 2D array is needed to store both the face ID in the physical space + /// and the corresponding face ID in the parent element space. + array2d< localIndex > m_toFaceElements; + /** * @brief Pack element-to-node and element-to-face maps * @tparam DO_PACKING the flag for the bufferOps::Pack function diff --git a/src/coreComponents/mesh/DomainPartition.cpp b/src/coreComponents/mesh/DomainPartition.cpp index 50cecbc24d9..befc10b4850 100644 --- a/src/coreComponents/mesh/DomainPartition.cpp +++ b/src/coreComponents/mesh/DomainPartition.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -26,7 +27,6 @@ #include "mesh/mpiCommunications/SpatialPartition.hpp" - namespace geos { using namespace dataRepository; @@ -78,7 +78,7 @@ void DomainPartition::setupBaseLevelMeshGlobalInfo() { GEOS_MARK_FUNCTION; -#if defined(GEOSX_USE_MPI) +#if defined(GEOS_USE_MPI) PartitionBase & partition1 = getReference< PartitionBase >( keys::partitionManager ); SpatialPartition & partition = dynamic_cast< SpatialPartition & >(partition1); @@ -90,10 +90,10 @@ void DomainPartition::setupBaseLevelMeshGlobalInfo() MPI_Comm cartcomm; { int reorder = 0; - MpiWrapper::cartCreate( MPI_COMM_GEOSX, 3, partition.getPartitions().data(), partition.m_Periodic.data(), reorder, &cartcomm ); + MpiWrapper::cartCreate( MPI_COMM_GEOS, 3, partition.getPartitions().data(), partition.m_Periodic.data(), reorder, &cartcomm ); GEOS_ERROR_IF( cartcomm == MPI_COMM_NULL, "Fail to run MPI_Cart_create and establish communications" ); } - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); int nsdof = 3; MpiWrapper::cartCoords( cartcomm, rank, nsdof, partition.m_coords.data() ); @@ -125,7 +125,7 @@ void DomainPartition::setupBaseLevelMeshGlobalInfo() for( std::size_t i = 0; i < m_neighbors.size(); ++i ) { - MpiWrapper::iSend( firstNeighborRanks.toView(), m_neighbors[ i ].neighborRank(), neighborsTag, MPI_COMM_GEOSX, &requests[ i ] ); + MpiWrapper::iSend( firstNeighborRanks.toView(), m_neighbors[ i ].neighborRank(), neighborsTag, MPI_COMM_GEOS, &requests[ i ] ); } // This set will contain the second (neighbor of) neighbors ranks. @@ -134,7 +134,7 @@ void DomainPartition::setupBaseLevelMeshGlobalInfo() array1d< int > neighborOfNeighborRanks; for( std::size_t i = 0; i < m_neighbors.size(); ++i ) { - MpiWrapper::recv( neighborOfNeighborRanks, m_neighbors[ i ].neighborRank(), neighborsTag, MPI_COMM_GEOSX, MPI_STATUS_IGNORE ); + MpiWrapper::recv( neighborOfNeighborRanks, m_neighbors[ i ].neighborRank(), neighborsTag, MPI_COMM_GEOS, MPI_STATUS_IGNORE ); // Insert the neighbors of the current neighbor into the set of second neighbors. secondNeighborRanks.insert( neighborOfNeighborRanks.begin(), neighborOfNeighborRanks.end() ); @@ -320,4 +320,145 @@ void DomainPartition::addNeighbors( const unsigned int idim, } } +void DomainPartition::outputPartitionInformation() const +{ + + auto numberOfEntities = []( ObjectManagerBase const & objectManager ) + { + return std::make_pair( objectManager.getNumberOfLocalIndices(), objectManager.getNumberOfGhosts() ); + }; + + GEOS_LOG_RANK_0( "MPI Partition information:" ); + + forMeshBodies( [&]( MeshBody const & meshBody ) + { + meshBody.getMeshLevels().forSubGroupsIndex< MeshLevel >( [&]( int const level, MeshLevel const & meshLevel ) + { + if( level!=0 ) + { + + // get the number of local and ghost entities for each type + auto const [ numLocalNodes, numGhostNodes ] = numberOfEntities( meshLevel.getNodeManager() ); + real64 const nodeRatio = ( numLocalNodes + numGhostNodes ) > 0 ? real64( numLocalNodes ) / real64( numLocalNodes + numGhostNodes ) : -1.0; + auto const [ numLocalEdges, numGhostEdges ] = numberOfEntities( meshLevel.getEdgeManager() ); + real64 const edgeRatio = ( numLocalEdges + numGhostEdges ) > 0 ? real64( numLocalEdges ) / real64( numLocalEdges + numGhostEdges ) : -1.0; + auto const [ numLocalFaces, numGhostFaces ] = numberOfEntities( meshLevel.getFaceManager() ); + real64 const faceRatio = ( numLocalFaces + numGhostFaces ) > 0 ? real64( numLocalFaces ) / real64( numLocalFaces + numGhostFaces ) : -1.0; + + localIndex numLocalElems = 0; + localIndex numGhostElems = 0; + meshLevel.getElemManager().forElementSubRegions< CellElementSubRegion >( [&]( CellElementSubRegion const & subRegion ) + { + auto [ numLocalElemsInSubRegion, numGhostElemsInSubRegion ] = numberOfEntities( subRegion ); + numLocalElems += numLocalElemsInSubRegion; + numGhostElems += numGhostElemsInSubRegion; + } ); + real64 const elemRatio = ( numLocalElems + numGhostElems ) > 0 ? real64( numLocalElems ) / real64( numLocalElems + numGhostElems ) : -1.0; + + localIndex const values[8] = { numLocalNodes, numGhostNodes, numLocalEdges, numGhostEdges, numLocalFaces, numGhostFaces, numLocalElems, numGhostElems }; + localIndex minValues[8] = {0}; + localIndex maxValues[8] = {0}; + MpiWrapper::allReduce( values, minValues, 8, MPI_MIN, MPI_COMM_WORLD ); + MpiWrapper::allReduce( values, maxValues, 8, MPI_MAX, MPI_COMM_WORLD ); + localIndex const minNumLocalNodes = minValues[0]; + localIndex const maxNumLocalNodes = maxValues[0]; + localIndex const minNumGhostNodes = minValues[1]; + localIndex const maxNumGhostNodes = maxValues[1]; + localIndex const minNumLocalEdges = minValues[2]; + localIndex const maxNumLocalEdges = maxValues[2]; + localIndex const minNumGhostEdges = minValues[3]; + localIndex const maxNumGhostEdges = maxValues[3]; + localIndex const minNumLocalFaces = minValues[4]; + localIndex const maxNumLocalFaces = maxValues[4]; + localIndex const minNumGhostFaces = minValues[5]; + localIndex const maxNumGhostFaces = maxValues[5]; + localIndex const minNumLocalElems = minValues[6]; + localIndex const maxNumLocalElems = maxValues[6]; + localIndex const minNumGhostElems = minValues[7]; + localIndex const maxNumGhostElems = maxValues[7]; + + real64 const ratios[4] = { nodeRatio, edgeRatio, faceRatio, elemRatio }; + real64 minRatios[4] = {0}; + real64 maxRatios[4] = {0}; + MpiWrapper::allReduce( ratios, minRatios, 4, MPI_MIN, MPI_COMM_WORLD ); + MpiWrapper::allReduce( ratios, maxRatios, 4, MPI_MAX, MPI_COMM_WORLD ); + real64 const minNodeRatio = minRatios[0]; + real64 const maxNodeRatio = maxRatios[0]; + real64 const minEdgeRatio = minRatios[1]; + real64 const maxEdgeRatio = maxRatios[1]; + real64 const minFaceRatio = minRatios[2]; + real64 const maxFaceRatio = maxRatios[2]; + real64 const minElemRatio = minRatios[3]; + real64 const maxElemRatio = maxRatios[3]; + + GEOS_LOG_RANK_0( " MeshBody: " + meshBody.getName() + " MeshLevel: " + meshLevel.getName() + "\n" ); + GEOS_LOG_RANK_0( " |------------------------------------------------------------------------------------------------------------------------------------------------|" ); + GEOS_LOG_RANK_0( " | | Nodes | Edges | Faces | Elems |" ); + GEOS_LOG_RANK_0( " |------------------------------------------------------------------------------------------------------------------------------------------------|" ); + GEOS_LOG_RANK_0( GEOS_FMT( " |min(local/total)| {:4.2f} | {:4.2f} | {:4.2f} | {:4.2f} | ", + minNodeRatio, + minEdgeRatio, + minFaceRatio, + minElemRatio ) ); + GEOS_LOG_RANK_0( GEOS_FMT( " |max(local/total)| {:4.2f} | {:4.2f} | {:4.2f} | {:4.2f} | ", + maxNodeRatio, + maxEdgeRatio, + maxFaceRatio, + maxElemRatio ) ); + GEOS_LOG_RANK_0( " |------------------------------------------------------------------------------------------------------------------------------------------------|" ); + GEOS_LOG_RANK_0( " | Rank | local | ghost | local | ghost | local | ghost | local | ghost |" ); + GEOS_LOG_RANK_0( " |----------------|---------------|---------------|---------------|---------------|---------------|---------------|---------------|---------------|" ); + + + GEOS_LOG_RANK_0( GEOS_FMT( " | min | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} |", + stringutilities::addCommaSeparators( minNumLocalNodes ), + stringutilities::addCommaSeparators( minNumGhostNodes ), + stringutilities::addCommaSeparators( minNumLocalEdges ), + stringutilities::addCommaSeparators( minNumGhostEdges ), + stringutilities::addCommaSeparators( minNumLocalFaces ), + stringutilities::addCommaSeparators( minNumGhostFaces ), + stringutilities::addCommaSeparators( minNumLocalElems ), + stringutilities::addCommaSeparators( minNumGhostElems ) ) ); + + GEOS_LOG_RANK_0( GEOS_FMT( " | max | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} |", + stringutilities::addCommaSeparators( maxNumLocalNodes ), + stringutilities::addCommaSeparators( maxNumGhostNodes ), + stringutilities::addCommaSeparators( maxNumLocalEdges ), + stringutilities::addCommaSeparators( maxNumGhostEdges ), + stringutilities::addCommaSeparators( maxNumLocalFaces ), + stringutilities::addCommaSeparators( maxNumGhostFaces ), + stringutilities::addCommaSeparators( maxNumLocalElems ), + stringutilities::addCommaSeparators( maxNumGhostElems ) ) ); + + GEOS_LOG_RANK_0( " |------------------------------------------------------------------------------------------------------------------------------------------------|" ); + + // output in rank order + int const thisRank = MpiWrapper::commRank(); + for( int rank=0; rank13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | ", + rank, + stringutilities::addCommaSeparators( numLocalNodes ), + stringutilities::addCommaSeparators( numGhostNodes ), + stringutilities::addCommaSeparators( numLocalEdges ), + stringutilities::addCommaSeparators( numGhostEdges ), + stringutilities::addCommaSeparators( numLocalFaces ), + stringutilities::addCommaSeparators( numGhostFaces ), + stringutilities::addCommaSeparators( numLocalElems ), + stringutilities::addCommaSeparators( numGhostElems ) ) ); + } + MpiWrapper::barrier(); + } + MpiWrapper::barrier(); + GEOS_LOG_RANK_0( " |------------------------------------------------------------------------------------------------------------------------------------------------|" ); + } + } ); + } + + ); + +} + } /* namespace geos */ diff --git a/src/coreComponents/mesh/DomainPartition.hpp b/src/coreComponents/mesh/DomainPartition.hpp index 7a41174df1c..0af42ee9256 100644 --- a/src/coreComponents/mesh/DomainPartition.hpp +++ b/src/coreComponents/mesh/DomainPartition.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -115,6 +116,12 @@ class DomainPartition : public dataRepository::Group void addNeighbors( const unsigned int idim, MPI_Comm & cartcomm, int * ncoords ); + + /** + * @brief Outputs information about the partitioning of the domain. + */ + void outputPartitionInformation() const; + ///@} diff --git a/src/coreComponents/mesh/EdgeManager.cpp b/src/coreComponents/mesh/EdgeManager.cpp index 108676e1f25..f8227cb4a67 100644 --- a/src/coreComponents/mesh/EdgeManager.cpp +++ b/src/coreComponents/mesh/EdgeManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -269,6 +270,7 @@ localIndex EdgeManager::unpackUpDownMaps( buffer_unit_type const * & buffer, m_toFacesRelation.relatedObjectGlobalToLocal(), overwriteUpMaps ); + GEOS_ERROR_IF_NE( m_unmappedGlobalIndicesInToNodes.size(), 0 ); return unPackedSize; } diff --git a/src/coreComponents/mesh/EdgeManager.hpp b/src/coreComponents/mesh/EdgeManager.hpp index 0eedb9a0870..f955b9dd83e 100644 --- a/src/coreComponents/mesh/EdgeManager.hpp +++ b/src/coreComponents/mesh/EdgeManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/ElementRegionBase.cpp b/src/coreComponents/mesh/ElementRegionBase.cpp index 305c111c59b..97304535015 100644 --- a/src/coreComponents/mesh/ElementRegionBase.cpp +++ b/src/coreComponents/mesh/ElementRegionBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/ElementRegionBase.hpp b/src/coreComponents/mesh/ElementRegionBase.hpp index 049173a74e6..60f0f9b7a5e 100644 --- a/src/coreComponents/mesh/ElementRegionBase.hpp +++ b/src/coreComponents/mesh/ElementRegionBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -214,6 +215,20 @@ class ElementRegionBase : public ObjectManagerBase template< typename CONSTITUTIVE_TYPE > string_array getConstitutiveNames() const; + /** + * @return the parent region of the given sub-region. + * @param subRegion the sub-region that we want the parent. + */ + static ElementRegionBase & getParentRegion( ElementSubRegionBase & subRegion ) + { return dynamicCast< ElementRegionBase & >( subRegion.getParent().getParent() ); } + + /** + * @return the parent region of the given sub-region. + * @param subRegion the sub-region that we want the parent. + */ + static ElementRegionBase const & getParentRegion( ElementSubRegionBase const & subRegion ) + { return dynamicCast< ElementRegionBase const & >( subRegion.getParent().getParent() ); } + ///@} diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index b967a2b9e76..18da04ec066 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,6 +18,7 @@ #include "ElementRegionManager.hpp" +#include "common/DataLayouts.hpp" #include "common/TimingMacros.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "SurfaceElementRegion.hpp" @@ -27,6 +29,8 @@ #include "mesh/utilities/MeshMapUtilities.hpp" #include "schema/schemaUtilities.hpp" #include "mesh/generators/LineBlockABC.hpp" +#include "mesh/CellElementRegionSelector.hpp" + namespace geos { @@ -62,7 +66,7 @@ void ElementRegionManager::setMaxGlobalIndex() m_localMaxGlobalIndex = std::max( m_localMaxGlobalIndex, subRegion.maxGlobalIndex() ); } ); - m_maxGlobalIndex = MpiWrapper::max( m_localMaxGlobalIndex, MPI_COMM_GEOSX ); + m_maxGlobalIndex = MpiWrapper::max( m_localMaxGlobalIndex, MPI_COMM_GEOS ); } @@ -71,12 +75,11 @@ Group * ElementRegionManager::createChild( string const & childKey, string const { GEOS_ERROR_IF( !(CatalogInterface::hasKeyName( childKey )), "KeyName ("<getGroup( ElementRegionManager::groupKeyStruct::elementRegionsGroup() ); return &elementRegions.registerGroup( childName, CatalogInterface::factory( childKey, childName, &elementRegions ) ); - } void ElementRegionManager::expandObjectCatalogs() @@ -119,12 +122,23 @@ void ElementRegionManager::setSchemaDeviations( xmlWrapper::xmlNode schemaRoot, } } + void ElementRegionManager::generateMesh( CellBlockManagerABC const & cellBlockManager ) { - this->forElementRegions< CellElementRegion >( [&]( CellElementRegion & elemRegion ) - { - elemRegion.generateMesh( cellBlockManager.getCellBlocks() ); - } ); + { // cellBlocks loading + Group const & cellBlocks = cellBlockManager.getCellBlocks(); + CellElementRegionSelector cellBlockSelector{ cellBlocks, + cellBlockManager.getRegionAttributesCellBlocks() }; + this->forElementRegions< CellElementRegion >( [&]( CellElementRegion & elemRegion ) + { + elemRegion.setCellBlockNames( cellBlockSelector.buildCellBlocksSelection( elemRegion ) ); + elemRegion.generateMesh( cellBlocks ); + } ); + // selecting all cellblocks is mandatory + cellBlockSelector.checkSelectionConsistency(); + } + + this->forElementRegions< SurfaceElementRegion >( [&]( SurfaceElementRegion & elemRegion ) { elemRegion.generateMesh( cellBlockManager.getFaceBlocks() ); @@ -137,20 +151,32 @@ void ElementRegionManager::generateMesh( CellBlockManagerABC const & cellBlockMa array2d< localIndex > const blockToSubRegion = this->getCellBlockToSubRegionMap( cellBlockManager ); this->forElementRegions< SurfaceElementRegion >( [&]( SurfaceElementRegion & elemRegion ) { - SurfaceElementSubRegion & subRegion = elemRegion.getUniqueSubRegion< SurfaceElementSubRegion >(); + SurfaceElementSubRegion & surfaceSubRegion = elemRegion.getUniqueSubRegion< SurfaceElementSubRegion >(); // While indicated as containing element subregion information, // `relation` currently contains cell block information // that will be transformed into element subregion information. // This is why we copy the information into a temporary, // which frees space for the final information (of same size). - OrderedVariableToManyElementRelation & relation = subRegion.getToCellRelation(); - ToCellRelation< ArrayOfArrays< localIndex > > const tmp( relation.m_toElementSubRegion, - relation.m_toElementIndex ); - meshMapUtilities::transformCellBlockToRegionMap< parallelHostPolicy >( blockToSubRegion.toViewConst(), - tmp, - relation ); - } ); + if( auto * const faceElementSubRegion = dynamic_cast< FaceElementSubRegion * >( &surfaceSubRegion ) ) + { + FixedToManyElementRelation & relation = faceElementSubRegion->getToCellRelation(); + ToCellRelation< array2d< localIndex > > const tmp( relation.m_toElementSubRegion, + relation.m_toElementIndex ); + meshMapUtilities::transformCellBlockToRegionMap< parallelHostPolicy >( blockToSubRegion.toViewConst(), + tmp, + relation ); + } + else if( auto * const embeddedSurfaceSubRegion = dynamic_cast< EmbeddedSurfaceSubRegion * >( &surfaceSubRegion ) ) + { + OrderedVariableToManyElementRelation & relation = embeddedSurfaceSubRegion->getToCellRelation(); + ToCellRelation< ArrayOfArrays< localIndex > > const tmp( relation.m_toElementSubRegion, + relation.m_toElementIndex ); + meshMapUtilities::transformCellBlockToRegionMap< parallelHostPolicy >( blockToSubRegion.toViewConst(), + tmp, + relation ); + } + } ); } void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockManager, @@ -510,14 +536,6 @@ int ElementRegionManager::packUpDownMapsImpl( buffer_unit_type * & buffer, return packedSize; } -//template int -//ElementRegionManager:: -//PackUpDownMapsImpl( buffer_unit_type * & buffer, -// ElementViewAccessor> const & packList ) const; -//template int -//ElementRegionManager:: -//PackUpDownMapsImpl( buffer_unit_type * & buffer, -// ElementViewAccessor> const & packList ) const; int ElementRegionManager::unpackUpDownMaps( buffer_unit_type const * & buffer, @@ -553,6 +571,98 @@ ElementRegionManager::unpackUpDownMaps( buffer_unit_type const * & buffer, return unpackedSize; } +int ElementRegionManager::packFaceElementToFaceSize( ElementViewAccessor< arrayView1d< localIndex > > const & packList ) const +{ + buffer_unit_type * junk = nullptr; + return packFaceElementToFaceImpl< false >( junk, packList ); +} + +int ElementRegionManager::packFaceElementToFace( buffer_unit_type * & buffer, + ElementViewAccessor< arrayView1d< localIndex > > const & packList ) const +{ + return packFaceElementToFaceImpl< true >( buffer, packList ); +} + +template< bool DO_PACKING, typename T > +int ElementRegionManager::packFaceElementToFaceImpl( buffer_unit_type * & buffer, + T const & packList ) const +{ + int packedSize = 0; + + packedSize += bufferOps::Pack< DO_PACKING >( buffer, numRegions() ); + + for( typename dataRepository::indexType kReg=0; kReg( buffer, elemRegion.getName() ); + + + + localIndex numFaceElementSubregions = 0; + elemRegion.forElementSubRegionsIndex< FaceElementSubRegion >( + [&]( localIndex const, FaceElementSubRegion const & ) + { + ++numFaceElementSubregions; + } ); + + + packedSize += bufferOps::Pack< DO_PACKING >( buffer, numFaceElementSubregions ); + + elemRegion.forElementSubRegionsIndex< FaceElementSubRegion >( + [&]( localIndex const esr, FaceElementSubRegion const & subRegion ) + { + packedSize += bufferOps::Pack< DO_PACKING >( buffer, subRegion.getName() ); + + arrayView1d< localIndex > const elemList = packList[kReg][esr]; + if( DO_PACKING ) + { + packedSize += subRegion.packToFaceRelation( buffer, elemList ); + } + else + { + packedSize += subRegion.packToFaceRelationSize( elemList ); + } + } ); + } + + return packedSize; +} + + +int +ElementRegionManager::unpackFaceElementToFace( buffer_unit_type const * & buffer, + ElementReferenceAccessor< localIndex_array > & packList, + bool const overwriteMap ) +{ + int unpackedSize = 0; + + localIndex numRegionsRead; + unpackedSize += bufferOps::Unpack( buffer, numRegionsRead ); + for( localIndex kReg=0; kReg( + [&]( localIndex const kSubReg, FaceElementSubRegion & subRegion ) + { + string subRegionName; + unpackedSize += bufferOps::Unpack( buffer, subRegionName ); + GEOS_ERROR_IF( subRegionName != subRegion.getName(), + "Unpacked subregion name (" << subRegionName << ") does not equal object name (" << subRegion.getName() << ")" ); + + localIndex_array & elemList = packList[kReg][kSubReg]; + unpackedSize += subRegion.unpackToFaceRelation( buffer, elemList, false, overwriteMap ); + } ); + } + + return unpackedSize; +} + + int ElementRegionManager::packFracturedElementsSize( ElementViewAccessor< arrayView1d< localIndex > > const & packList, string const fractureRegionName ) const { @@ -682,6 +792,94 @@ ElementRegionManager::getCellBlockToSubRegionMap( CellBlockManagerABC const & ce return blockMap; } +void ElementRegionManager::outputObjectConnectivity() const +{ + int const numRanks = MpiWrapper::commSize(); + int const thisRank = MpiWrapper::commRank(); + + for( int rank=0; rankgetName().c_str() ); + + forElementRegions< CellElementRegion >( [&]( CellElementRegion const & elemRegion ) + { + elemRegion.forElementSubRegions< CellElementSubRegion >( [&]( CellElementSubRegion const & subRegion ) + { + printf( " %s\n", subRegion.getName().c_str() ); + + CellElementSubRegion::NodeMapType const & elemToNodeRelation = subRegion.nodeList(); + arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemToNode = elemToNodeRelation; + arrayView1d< globalIndex const > const & elemLocalToGlobal = subRegion.localToGlobalMap(); + auto const & elemGlobalToLocal = subRegion.globalToLocalMap(); + arrayView1d< globalIndex const > const & nodeLocalToGlobal = elemToNodeRelation.relatedObjectLocalToGlobal(); + auto const & refCoords = getParent().getGroup< NodeManager >( "nodeManager" ).referencePosition(); + + printf( " ElementToNodes map:\n" ); + for( localIndex k=0; k const sortedGlobalToLocalMap( elemGlobalToLocal.begin(), + elemGlobalToLocal.end()); + for( auto indexPair : sortedGlobalToLocalMap ) + { + globalIndex const gk = indexPair.first; + localIndex const k = indexPair.second; + + printf( " %3d( %3lld ): ", k, gk ); + for( localIndex a=0; a & packList, bool const overwriteMap ); + + /** + * @brief Get the buffer size needed to pack element-to-node and element-to-face maps. + * @param packList list of indices to pack + * @return the size of data packed. + */ + int packFaceElementToFaceSize( ElementViewAccessor< arrayView1d< localIndex > > const & packList ) const; + + /** + * @brief Pack element-to-node and element-to-face maps. + * @param buffer pointer to the buffer to be packed + * @param packList list of indices to pack + * @return the size of data packed. + */ + int packFaceElementToFace( buffer_unit_type * & buffer, + ElementViewAccessor< arrayView1d< localIndex > > const & packList ) const; + + /** + * @brief Unpack element-to-node and element-to-face maps. + * @param buffer pointer to the buffer to be unpacked + * @param packList list of indices to pack + * @param overwriteMap flag to indicate whether to overwrite the local map + * @return the size of data packed. + */ + int unpackFaceElementToFace( buffer_unit_type const * & buffer, + ElementReferenceAccessor< localIndex_array > & packList, + bool const overwriteMap ); + /** * @brief Get the buffer size needed to pack the set of fractured elements and the map toEmbSurfaces. * @param packList list of indices to pack @@ -1120,6 +1149,12 @@ class ElementRegionManager : public ObjectManagerBase ElementReferenceAccessor< localIndex_array > & packList, string const fractureRegionName ); + /** + * @brief Function to output connectivity in order to assist debugging issues + * with object connectivity. + */ + virtual void outputObjectConnectivity() const override final; + private: @@ -1153,6 +1188,12 @@ class ElementRegionManager : public ObjectManagerBase int packUpDownMapsImpl( buffer_unit_type * & buffer, T const & packList ) const; + + template< bool DO_PACKING, typename T > + int + packFaceElementToFaceImpl( buffer_unit_type * & buffer, + T const & packList ) const; + /** * @brief Unpack element-to-node and element-to-face maps. * @param buffer pointer to the buffer to be unpacked @@ -1185,8 +1226,6 @@ class ElementRegionManager : public ObjectManagerBase * @return reference to this object */ ElementRegionManager & operator=( const ElementRegionManager & ); - - }; diff --git a/src/coreComponents/mesh/ElementSubRegionBase.cpp b/src/coreComponents/mesh/ElementSubRegionBase.cpp index 41f236ef4f0..6234dbaca94 100644 --- a/src/coreComponents/mesh/ElementSubRegionBase.cpp +++ b/src/coreComponents/mesh/ElementSubRegionBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/ElementSubRegionBase.hpp b/src/coreComponents/mesh/ElementSubRegionBase.hpp index 1a77a06b5db..c61289839c8 100644 --- a/src/coreComponents/mesh/ElementSubRegionBase.hpp +++ b/src/coreComponents/mesh/ElementSubRegionBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/ElementType.hpp b/src/coreComponents/mesh/ElementType.hpp index 8345080149f..0ebb7ba5e03 100644 --- a/src/coreComponents/mesh/ElementType.hpp +++ b/src/coreComponents/mesh/ElementType.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,7 @@ #ifndef GEOS_MESH_ELEMENTTYPE_HPP #define GEOS_MESH_ELEMENTTYPE_HPP -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" namespace geos { @@ -109,9 +110,39 @@ ENUM_STRINGS( ElementType, "HendecagonalPrism", "Polyhedron" ); +/** + * @brief Returns a string describing the element. + * @param[in] type The element type. + * @return The name. + * @warning This information will be visible in the input file... Consider refactoring with great care. + */ +inline string getElementTypeName( ElementType const type ) +{ + switch( type ) + { + case ElementType::Hexahedron: return "hexahedra"; + case ElementType::Tetrahedron: return "tetrahedra"; + case ElementType::Wedge: return "wedges"; + case ElementType::Pyramid: return "pyramids"; + case ElementType::Prism5: return "pentagonalPrisms"; + case ElementType::Prism6: return "hexagonalPrisms"; + case ElementType::Prism7: return "heptagonalPrisms"; + case ElementType::Prism8: return "octagonalPrisms"; + case ElementType::Prism9: return "nonagonalPrisms"; + case ElementType::Prism10: return "decagonalPrisms"; + case ElementType::Prism11: return "hendecagonalPrisms"; + case ElementType::Polyhedron: return "polyhedra"; + default: + { + GEOS_ERROR( "Element type '" << type << "' is not supported" ); + return {}; + } + } +} + /// String available for mesh errors inline auto constexpr generalMeshErrorAdvice = "Consider checking the validity of your mesh with " - "the `mesh_doctor` GEOS python tools (documentation at" + "the `mesh_doctor` GEOS python tools (documentation at " "https://geosx-geosx.readthedocs-hosted.com/en/latest/docs/sphinx/pythonTools/mesh_doctor.html)."; } // namespace geos diff --git a/src/coreComponents/mesh/EmbeddedSurfaceNodeManager.cpp b/src/coreComponents/mesh/EmbeddedSurfaceNodeManager.cpp index 928cc8078f3..d8d053b7951 100644 --- a/src/coreComponents/mesh/EmbeddedSurfaceNodeManager.cpp +++ b/src/coreComponents/mesh/EmbeddedSurfaceNodeManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -202,7 +203,7 @@ localIndex EmbeddedSurfaceNodeManager::packNewNodesGlobalMapsImpl( buffer_unit_t // this doesn't link without the string()...no idea why. packedSize += bufferOps::Pack< DO_PACKING >( buffer, string( viewKeyStruct::localToGlobalMapString() ) ); - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); packedSize += bufferOps::Pack< DO_PACKING >( buffer, rank ); localIndex const numPackedIndices = packList.size(); @@ -249,7 +250,7 @@ localIndex EmbeddedSurfaceNodeManager::unpackNewNodesGlobalMaps( buffer_unit_typ unpackedSize += bufferOps::Unpack( buffer, localToGlobalString ); GEOS_ERROR_IF( localToGlobalString != viewKeyStruct::localToGlobalMapString(), "ObjectManagerBase::unpack(): label incorrect" ); - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); int sendingRank; unpackedSize += bufferOps::Unpack( buffer, sendingRank ); diff --git a/src/coreComponents/mesh/EmbeddedSurfaceNodeManager.hpp b/src/coreComponents/mesh/EmbeddedSurfaceNodeManager.hpp index 636bb0e2824..7d49caf0ff3 100644 --- a/src/coreComponents/mesh/EmbeddedSurfaceNodeManager.hpp +++ b/src/coreComponents/mesh/EmbeddedSurfaceNodeManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/EmbeddedSurfaceSubRegion.cpp b/src/coreComponents/mesh/EmbeddedSurfaceSubRegion.cpp index 6dd53dec055..875d23b289f 100644 --- a/src/coreComponents/mesh/EmbeddedSurfaceSubRegion.cpp +++ b/src/coreComponents/mesh/EmbeddedSurfaceSubRegion.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -40,24 +41,13 @@ void surfaceWithGhostNodes::insert( globalIndex const & edgeIndex ) EmbeddedSurfaceSubRegion::EmbeddedSurfaceSubRegion( string const & name, dataRepository::Group * const parent ): SurfaceElementSubRegion( name, parent ), - m_normalVector(), - m_tangentVector1(), - m_tangentVector2(), m_numOfJumpEnrichments( 3 ), m_connectivityIndex(), - m_parentPlaneName() + m_parentPlaneName(), + m_2dElemToElems() { m_elementType = ElementType::Polygon; - registerWrapper( viewKeyStruct::normalVectorString(), &m_normalVector ). - setDescription( "Unit normal vector to the embedded surface." ); - - registerWrapper( viewKeyStruct::t1VectorString(), &m_tangentVector1 ). - setDescription( "Unit vector in the first tangent direction to the embedded surface." ); - - registerWrapper( viewKeyStruct::t2VectorString(), &m_tangentVector2 ). - setDescription( "Unit vector in the second tangent direction to the embedded surface." ); - registerWrapper( viewKeyStruct::elementCenterString(), &m_elementCenter ). setDescription( "The center of each EmbeddedSurface element." ); @@ -74,10 +64,25 @@ EmbeddedSurfaceSubRegion::EmbeddedSurfaceSubRegion( string const & name, setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ). setDescription( "A map of surface element to the parent fracture name" ); + registerWrapper( viewKeyStruct::surfaceElementsToCellRegionsString(), &m_2dElemToElems.m_toElementRegion ). + setPlotLevel( PlotLevel::NOPLOT ). + setDescription( "A map of face element local indices to the cell local indices" ); + + registerWrapper( viewKeyStruct::surfaceElementsToCellSubRegionsString(), &m_2dElemToElems.m_toElementSubRegion ). + setPlotLevel( PlotLevel::NOPLOT ). + setDescription( "A map of face element local indices to the cell local indices" ); + + registerWrapper( viewKeyStruct::surfaceElementsToCellIndexString(), &m_2dElemToElems.m_toElementIndex ). + setPlotLevel( PlotLevel::NOPLOT ). + setDescription( "A map of face element local indices to the cell local indices" ); + m_normalVector.resizeDimension< 1 >( 3 ); m_tangentVector1.resizeDimension< 1 >( 3 ); m_tangentVector2.resizeDimension< 1 >( 3 ); m_2dElemToElems.resize( 0, 1 ); + + m_2dElemToElems.setElementRegionManager( dynamicCast< ElementRegionManager & >( getParent().getParent().getParent().getParent() ) ); + } void EmbeddedSurfaceSubRegion::calculateElementGeometricQuantities( NodeManager const & GEOS_UNUSED_PARAM( nodeManager ), diff --git a/src/coreComponents/mesh/EmbeddedSurfaceSubRegion.hpp b/src/coreComponents/mesh/EmbeddedSurfaceSubRegion.hpp index 95d5c649d4e..5baa73ec274 100644 --- a/src/coreComponents/mesh/EmbeddedSurfaceSubRegion.hpp +++ b/src/coreComponents/mesh/EmbeddedSurfaceSubRegion.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -178,15 +179,6 @@ class EmbeddedSurfaceSubRegion : public SurfaceElementSubRegion */ struct viewKeyStruct : SurfaceElementSubRegion::viewKeyStruct { - /// @return Embedded surface element normal vector string - static constexpr char const * normalVectorString() { return "normalVector"; } - - /// @return Tangent vector 1 string - static constexpr char const * t1VectorString() { return "tangentVector1"; } - - /// @return Tangent vector 2 string - static constexpr char const * t2VectorString() { return "tangentVector2"; } - /// @return Connectivity index string static constexpr char const * connectivityIndexString() { return "connectivityIndex"; } @@ -216,19 +208,6 @@ class EmbeddedSurfaceSubRegion : public SurfaceElementSubRegion */ localIndex const & numOfJumpEnrichments() const {return m_numOfJumpEnrichments;} - /** - * @brief Get normal vectors. - * @return an array of normal vectors. - */ - arrayView2d< real64 const > getNormalVector() const { return m_normalVector; } - - /** - * @brief Get normal vector of a specific embedded surface element. - * @param k index of the embedded surface element - * @return the normal vector of a specific embedded surface element - */ - arraySlice1d< real64 const > getNormalVector( localIndex k ) const { return m_normalVector[k]; } - /** * @brief Get the name of the bounding plate that was used to generate fracture element k. * @param k the index of the embedded surface element @@ -236,32 +215,6 @@ class EmbeddedSurfaceSubRegion : public SurfaceElementSubRegion */ string const & getFractureName( localIndex k ) const { return m_parentPlaneName[k]; } - /** - * @brief Get an array of the first tangent vector of the embedded surface elements. - * @return an array of the first tangent vector of the embedded surface elements - */ - arrayView2d< real64 const > getTangentVector1() const { return m_tangentVector1; } - - /** - * @brief Get the first tangent vector of a specific embedded surface element. - * @param k index of the embedded surface element - * @return the first tangent vector of a specific embedded surface element - */ - arraySlice1d< real64 const > getTangentVector1( localIndex k ) const { return m_tangentVector1[k]; } - - /** - * @brief Get an array of the second tangent vector of the embedded surface elements. - * @return an array of the second tangent vector of the embedded surface elements - */ - arrayView2d< real64 const > getTangentVector2() const { return m_tangentVector2.toViewConst(); } - - /** - * @brief Get the second tangent vector of a specific embedded surface element. - * @param k index of the embedded surface element - * @return the second tangent vector of a specific embedded surface element - */ - arraySlice1d< real64 const > getTangentVector2( localIndex k ) const { return m_tangentVector2[k];} - /** * @brief Get the connectivity index of the embedded surface element. * @return the connectivity index @@ -279,6 +232,23 @@ class EmbeddedSurfaceSubRegion : public SurfaceElementSubRegion */ std::vector< struct surfaceWithGhostNodes > surfaceWithGhostNodes() { return m_surfaceWithGhostNodes; } + /** + * @brief Get the surface element to cells map. + * @return The surface element to cells map + */ + OrderedVariableToManyElementRelation & getToCellRelation() + { + return m_2dElemToElems; + } + + /** + * @copydoc getToCellRelation() + */ + OrderedVariableToManyElementRelation const & getToCellRelation() const + { + return m_2dElemToElems; + } + ///@} private: @@ -294,15 +264,6 @@ class EmbeddedSurfaceSubRegion : public SurfaceElementSubRegion localIndex packUpDownMapsImpl( buffer_unit_type * & buffer, arrayView1d< localIndex const > const & packList ) const; - /// normal vector to the embedded surface element - array2d< real64 > m_normalVector; - - // tangential direction 1 - array2d< real64 > m_tangentVector1; - - // tangential direction 2 - array2d< real64 > m_tangentVector2; - /// The number of jump enrichments localIndex m_numOfJumpEnrichments; @@ -314,6 +275,10 @@ class EmbeddedSurfaceSubRegion : public SurfaceElementSubRegion /// Surfaces with ghost nodes std::vector< struct surfaceWithGhostNodes > m_surfaceWithGhostNodes; + + /// Map between the surface elements and the cells + OrderedVariableToManyElementRelation m_2dElemToElems; + }; diff --git a/src/coreComponents/mesh/ExternalDataSourceBase.cpp b/src/coreComponents/mesh/ExternalDataSourceBase.cpp new file mode 100644 index 00000000000..157fe3de31e --- /dev/null +++ b/src/coreComponents/mesh/ExternalDataSourceBase.cpp @@ -0,0 +1,55 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "ExternalDataSourceBase.hpp" + +namespace geos +{ +using namespace dataRepository; + +ExternalDataSourceBase::ExternalDataSourceBase( string const & name, Group * const parent ): + Group( name, parent ) +{ + setInputFlags( InputFlags::OPTIONAL_NONUNIQUE ); +} + +Group * ExternalDataSourceBase::createChild( string const & childKey, string const & childName ) +{ + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) ); + std::unique_ptr< ExternalDataSourceBase > event = ExternalDataSourceBase::CatalogInterface::factory( childKey, childName, this ); + return &this->registerGroup< ExternalDataSourceBase >( childName, std::move( event ) ); +} + +void ExternalDataSourceBase::expandObjectCatalogs() +{ + // Only add children if the parent is of type EventManager + // otherwise, this would fall into a loop + if( strcmp( this->getParent().getName().c_str(), "ExternalDataSource" ) == 0 ) + { + for( auto & catalogIter: ExternalDataSourceBase::getCatalog()) + { + createChild( catalogIter.first, catalogIter.first ); + } + } +} + +ExternalDataSourceBase::CatalogInterface::CatalogType & ExternalDataSourceBase::getCatalog() +{ + static ExternalDataSourceBase::CatalogInterface::CatalogType catalog; + return catalog; +} + + +} diff --git a/src/coreComponents/mesh/ExternalDataSourceBase.hpp b/src/coreComponents/mesh/ExternalDataSourceBase.hpp new file mode 100644 index 00000000000..0e2f9a4ab17 --- /dev/null +++ b/src/coreComponents/mesh/ExternalDataSourceBase.hpp @@ -0,0 +1,78 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ExternalDataSourceBase.hpp + */ + +#ifndef GEOS_MESH_EXTERNALDATASOURCEBASE_HPP +#define GEOS_MESH_EXTERNALDATASOURCEBASE_HPP + +#include "dataRepository/Group.hpp" +#include "dataRepository/WrapperBase.hpp" +#include "codingUtilities/Utilities.hpp" +#include "common/DataTypes.hpp" + + +namespace geos +{ + +/** + * @class ExternalDataSourceBase + * @brief The ExternalDataSourceBase class provides an abstract base class implementation for different mesh types. + * The ExternalDataSourceBase is the Group specialization for different type of mesh handling. + */ +class ExternalDataSourceBase : public dataRepository::Group +{ +public: + + /** + * @brief Main constructor for ExternalDataSourceBase base class. + * @param[in] name of the ExternalDataSourceBase object + * @param[in] parent the parent Group pointer for the ExternalDataSourceBase object + */ + explicit ExternalDataSourceBase( string const & name, + Group * const parent ); + + /// This function is used to expand any catalogs in the data structure + virtual void expandObjectCatalogs() override; + + /// using alias for templated Catalog ExternalDataSourceBase type + using CatalogInterface = dataRepository::CatalogInterface< ExternalDataSourceBase, string const &, Group * const >; + + /** + * @brief Create a new geometric object (box, plane, etc) as a child of this group. + * @param childKey the catalog key of the new geometric object to create + * @param childName the name of the new geometric object in the repository + * @return the group child + */ + virtual Group * createChild( string const & childKey, string const & childName ) override; + + /** + * @brief Accessor for the singleton Catalog object + * @return a static reference to the Catalog object + */ + static CatalogInterface::CatalogType & getCatalog(); + + /** + * @brief This function provides the capability to open an external data repository + * from another component whatever its format. + */ + virtual void open() = 0; +}; + +} + +#endif /* GEOS_MESH_EXTERNALDATASOURCEBASE_HPP */ diff --git a/src/coreComponents/mesh/ExternalDataSourceManager.cpp b/src/coreComponents/mesh/ExternalDataSourceManager.cpp new file mode 100644 index 00000000000..8a22203af8e --- /dev/null +++ b/src/coreComponents/mesh/ExternalDataSourceManager.cpp @@ -0,0 +1,63 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + + +#include "ExternalDataSourceManager.hpp" +#include "ExternalDataSourceBase.hpp" + + +namespace geos +{ + +using namespace dataRepository; + +ExternalDataSourceManager::ExternalDataSourceManager( string const & name, + Group * const parent ): + Group( name, parent ) +{ + setInputFlags( InputFlags::REQUIRED ); +} + +ExternalDataSourceManager::~ExternalDataSourceManager() +{} + +Group * ExternalDataSourceManager::createChild( string const & childKey, string const & childName ) +{ + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) ); + std::unique_ptr< ExternalDataSourceBase > externalDataSource = ExternalDataSourceBase::CatalogInterface::factory( childKey, childName, this ); + return &this->registerGroup< ExternalDataSourceBase >( childName, std::move( externalDataSource ) ); +} + + +void ExternalDataSourceManager::expandObjectCatalogs() +{ + // During schema generation, register one of each type derived from ExternalDataSourceBase here + for( auto & catalogIter: ExternalDataSourceBase::getCatalog()) + { + createChild( catalogIter.first, catalogIter.first ); + } +} + + +void ExternalDataSourceManager::open( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) +{ + forSubGroups< ExternalDataSourceBase >( []( ExternalDataSourceBase & external ) + { + external.open(); + } ); +} + + +} /* namespace geos */ diff --git a/src/coreComponents/mesh/ExternalDataSourceManager.hpp b/src/coreComponents/mesh/ExternalDataSourceManager.hpp new file mode 100644 index 00000000000..28ccecb2fc1 --- /dev/null +++ b/src/coreComponents/mesh/ExternalDataSourceManager.hpp @@ -0,0 +1,76 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ExternalDataSourceManager.hpp + */ + +#ifndef GEOS_MESH_EXTERNALDATASOURCEMANAGER_HPP_ +#define GEOS_MESH_EXTERNALDATASOURCEMANAGER_HPP_ + +#include "dataRepository/Group.hpp" +#include "mesh/DomainPartition.hpp" + +namespace geos +{ + +/** + * @class ExternalDataSourceManager + * @brief This class manages a data repository whereof objects can be imported to GEOS (reservoir mesh, well mesh) + */ +class ExternalDataSourceManager : public dataRepository::Group +{ +public: + + /** + * @brief Constructor for the ExternalDataSourceManager object. + * @param[in] name the name of the ExternalDataSourceManager object in the repository + * @param[in] parent the parent group of the ExternalDataSourceManager object being constructed + */ + ExternalDataSourceManager( string const & name, + Group * const parent ); + + virtual ~ExternalDataSourceManager() override; + + + /** + * @brief Create a new sub data repository. + * @param[in] childKey the key of the new object in the ObjectCatalog + * @param[in] childName the name of the new object in the collection of sub-meshes + * @return A pointer to the Group node in the dataRepository of the new object created + */ + virtual Group * createChild( string const & childKey, string const & childName ) override; + + /// This function is used to expand any catalogs in the data structure + virtual void expandObjectCatalogs() override; + + /** + * @brief Generate the meshes of the physical DomainPartition. + * @param[in] domain a reference to the physical domain + */ + void open( DomainPartition & domain ); + +private: + + /** + * @brief Deleted default constructor of the ExternalDataSourceManager + */ + ExternalDataSourceManager() = delete; + +}; + +} /* namespace geos */ + +#endif /* GEOS_MESH_EXTERNALDATASOURCEMANAGER_HPP_ */ diff --git a/src/coreComponents/mesh/FaceElementSubRegion.cpp b/src/coreComponents/mesh/FaceElementSubRegion.cpp index 894071a752c..f1e1162a060 100644 --- a/src/coreComponents/mesh/FaceElementSubRegion.cpp +++ b/src/coreComponents/mesh/FaceElementSubRegion.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -32,7 +33,8 @@ FaceElementSubRegion::FaceElementSubRegion( string const & name, m_unmappedGlobalIndicesInToEdges(), m_unmappedGlobalIndicesInToFaces(), m_newFaceElements(), - m_toFacesRelation() + m_toFacesRelation(), + m_2dElemToElems() { m_elementType = ElementType::Hexahedron; @@ -41,6 +43,7 @@ FaceElementSubRegion::FaceElementSubRegion( string const & name, registerWrapper( viewKeyStruct::detJString(), &m_detJ ).setSizedFromParent( 1 ).reference(); registerWrapper( viewKeyStruct::faceListString(), &m_toFacesRelation ). + setApplyDefaultValue( -1 ). setDescription( "Map to the faces attached to each FaceElement." ). reference().resize( 0, 2 ); @@ -64,7 +67,22 @@ FaceElementSubRegion::FaceElementSubRegion( string const & name, setDescription( "A map eventually containing all the collocated nodes." ). setSizedFromParent( 1 ); -#ifdef GEOSX_USE_SEPARATION_COEFFICIENT + registerWrapper( viewKeyStruct::surfaceElementsToCellRegionsString(), &m_2dElemToElems.m_toElementRegion ). + setApplyDefaultValue( -1 ). + setPlotLevel( PlotLevel::NOPLOT ). + setDescription( "A map of face element local indices to the cell local indices" ); + + registerWrapper( viewKeyStruct::surfaceElementsToCellSubRegionsString(), &m_2dElemToElems.m_toElementSubRegion ). + setApplyDefaultValue( -1 ). + setPlotLevel( PlotLevel::NOPLOT ). + setDescription( "A map of face element local indices to the cell local indices" ); + + registerWrapper( viewKeyStruct::surfaceElementsToCellIndexString(), &m_2dElemToElems.m_toElementIndex ). + setApplyDefaultValue( -1 ). + setPlotLevel( PlotLevel::NOPLOT ). + setDescription( "A map of face element local indices to the cell local indices" ); + +#ifdef GEOS_USE_SEPARATION_COEFFICIENT registerWrapper( viewKeyStruct::separationCoeffString(), &m_separationCoefficient ). setApplyDefaultValue( 0.0 ). setPlotLevel( dataRepository::PlotLevel::LEVEL_1 ). @@ -76,12 +94,16 @@ FaceElementSubRegion::FaceElementSubRegion( string const & name, m_2dElemToElems.resize( 0, 2 ); m_numNodesPerElement = 8; + + + m_2dElemToElems.setElementRegionManager( dynamicCast< ElementRegionManager & >( getParent().getParent().getParent().getParent() ) ); + } void FaceElementSubRegion::copyFromCellBlock( FaceBlockABC const & faceBlock ) { localIndex const num2dElements = faceBlock.num2dElements(); - resize( faceBlock.num2dElements() ); + resize( num2dElements ); m_toNodesRelation.base() = faceBlock.get2dElemToNodes(); m_toEdgesRelation.base() = faceBlock.get2dElemToEdges(); @@ -155,22 +177,26 @@ void FaceElementSubRegion::copyFromCellBlock( FaceBlockABC const & faceBlock ) // we store the cell block mapping at the sub region mapping location. // It will later be transformed into a sub regions mapping. // Last, we fill the regions mapping with dummy -1 values that should all be replaced eventually. - auto const elem2dToElems = faceBlock.get2dElemToElems(); - m_2dElemToElems.resize( num2dElements, 2 ); - for( int i = 0; i < num2dElements; ++i ) + auto const & elem2dToElems = faceBlock.get2dElemToElems(); + for( int kfe = 0; kfe < num2dElements; ++kfe ) { - for( localIndex const & j: elem2dToElems.toCellIndex[i] ) + for( localIndex k=0; k const & elem2dToFaces = faceBlock.get2dElemToFaces(); + + for( localIndex kfe = 0; kfe < num2dElements; ++kfe ) + { + for( localIndex kf=0; kfglobalToLocalMap() ); + + GEOS_ERROR_IF_NE( m_unmappedGlobalIndicesInToNodes.size(), 0 ); + GEOS_ERROR_IF_NE( m_unmappedGlobalIndicesInToEdges.size(), 0 ); +// GEOS_ERROR_IF_NE( m_unmappedGlobalIndicesInToFaces.size(), 0 ); + + return unPackedSize; +} + +localIndex FaceElementSubRegion::packToFaceRelationSize( arrayView1d< localIndex const > const & packList ) const +{ + buffer_unit_type * junk = nullptr; + return packToFaceRelationImpl< false >( junk, packList ); +} + +localIndex FaceElementSubRegion::packToFaceRelation( buffer_unit_type * & buffer, + arrayView1d< localIndex const > const & packList ) const +{ + return packToFaceRelationImpl< true >( buffer, packList ); +} + + +template< bool DO_PACKING > +localIndex FaceElementSubRegion::packToFaceRelationImpl( buffer_unit_type * & buffer, + arrayView1d< localIndex const > const & packList ) const +{ + arrayView1d< globalIndex const > const localToGlobal = this->localToGlobalMap(); + arrayView1d< globalIndex const > const faceLocalToGlobal = m_toFacesRelation.relatedObjectLocalToGlobal(); + + localIndex packedSize = 0; + packedSize += bufferOps::Pack< DO_PACKING >( buffer, string( viewKeyStruct::faceListString() ) ); + packedSize += bufferOps::Pack< DO_PACKING >( buffer, + m_toFacesRelation.toViewConst(), + m_unmappedGlobalIndicesInToFaces, + packList, + localToGlobal, + faceLocalToGlobal ); + return packedSize; +} + + +localIndex FaceElementSubRegion::unpackToFaceRelation( buffer_unit_type const * & buffer, + localIndex_array & packList, + bool const GEOS_UNUSED_PARAM( overwriteUpMaps ), + bool const GEOS_UNUSED_PARAM( overwriteDownMaps ) ) +{ + localIndex unPackedSize = 0; + + string faceListString; + unPackedSize += bufferOps::Unpack( buffer, faceListString ); + GEOS_ERROR_IF_NE( faceListString, viewKeyStruct::faceListString() ); + + unPackedSize += bufferOps::Unpack( buffer, + m_toFacesRelation, + packList, + m_unmappedGlobalIndicesInToFaces, + this->globalToLocalMap(), + m_toFacesRelation.relatedObjectGlobalToLocal() ); + return unPackedSize; } @@ -363,55 +447,49 @@ localIndex FaceElementSubRegion::unpackUpDownMaps( buffer_unit_type const * & bu * in the sense that each @p face for a given index must "belong" to @p 3d @p element at the same index. * @param[in] fractureName The name of the fracture for which we're checking the mapping consistency. * @param[in] elem2dToElems3d A mapping. - * @param[inout] elem2dToFaces This mapping will be corrected if needed to match @p elem2dToElems3d. + * @param[in,out] elem2dToFaces This mapping will be corrected if needed to match @p elem2dToElems3d. */ void fixNeighborMappingsInconsistency( string const & fractureName, - OrderedVariableToManyElementRelation const & elem2dToElems3d, + FixedToManyElementRelation const & elem2dToElems3d, FaceElementSubRegion::FaceMapType & elem2dToFaces ) { { - localIndex const num2dElems = elem2dToFaces.size(); + localIndex const num2dElems = elem2dToFaces.size( 0 ); for( int e2d = 0; e2d < num2dElems; ++e2d ) { - std::set< localIndex > const sizes{ - elem2dToFaces[e2d].size(), - elem2dToElems3d.m_toElementRegion[e2d].size(), - elem2dToElems3d.m_toElementSubRegion[e2d].size(), - elem2dToElems3d.m_toElementIndex[e2d].size() - }; - - if( sizes.size() != 1 || sizes.find( 2 ) == sizes.cend() ) + if( !( elem2dToFaces[e2d][0] == -1 || elem2dToFaces[e2d][1] == -1 || + elem2dToElems3d.m_toElementRegion[e2d][0] == -1 || elem2dToElems3d.m_toElementRegion[e2d][1] == -1 || + elem2dToElems3d.m_toElementSubRegion[e2d][0] == -1 || elem2dToElems3d.m_toElementSubRegion[e2d][1] == -1 || + elem2dToElems3d.m_toElementSubRegion[e2d][0] == -1 || elem2dToElems3d.m_toElementSubRegion[e2d][1] == -1 ) ) { - continue; - } - - localIndex const f0 = elem2dToFaces[e2d][0]; - localIndex const er0 = elem2dToElems3d.m_toElementRegion[e2d][0]; - localIndex const esr0 = elem2dToElems3d.m_toElementSubRegion[e2d][0]; - localIndex const ei0 = elem2dToElems3d.m_toElementIndex[e2d][0]; - auto const & faces0 = elem2dToElems3d.getElementRegionManager()->getRegion( er0 ).getSubRegion< CellElementSubRegion >( esr0 ).faceList()[ei0]; - - localIndex const f1 = elem2dToFaces[e2d][1]; - localIndex const er1 = elem2dToElems3d.m_toElementRegion[e2d][1]; - localIndex const esr1 = elem2dToElems3d.m_toElementSubRegion[e2d][1]; - localIndex const ei1 = elem2dToElems3d.m_toElementIndex[e2d][1]; - auto const & faces1 = elem2dToElems3d.getElementRegionManager()->getRegion( er1 ).getSubRegion< CellElementSubRegion >( esr1 ).faceList()[ei1]; - - bool const match00 = std::find( faces0.begin(), faces0.end(), f0 ) != faces0.end(); - bool const match11 = std::find( faces1.begin(), faces1.end(), f1 ) != faces1.end(); - bool const match01 = std::find( faces0.begin(), faces0.end(), f1 ) != faces0.end(); - bool const match10 = std::find( faces1.begin(), faces1.end(), f0 ) != faces1.end(); - - bool const matchCrossed = !match00 && !match11 && match01 && match10; - bool const matchStraight = match00 && match11 && !match01 && !match10; - - if( matchCrossed ) - { - std::swap( elem2dToFaces[e2d][0], elem2dToFaces[e2d][1] ); - } - else if( !matchStraight ) - { - GEOS_ERROR( "Mapping neighbor inconsistency detected for fracture " << fractureName ); + localIndex const f0 = elem2dToFaces[e2d][0]; + localIndex const er0 = elem2dToElems3d.m_toElementRegion[e2d][0]; + localIndex const esr0 = elem2dToElems3d.m_toElementSubRegion[e2d][0]; + localIndex const ei0 = elem2dToElems3d.m_toElementIndex[e2d][0]; + auto const & faces0 = elem2dToElems3d.getElementRegionManager()->getRegion( er0 ).getSubRegion< CellElementSubRegion >( esr0 ).faceList()[ei0]; + + localIndex const f1 = elem2dToFaces[e2d][1]; + localIndex const er1 = elem2dToElems3d.m_toElementRegion[e2d][1]; + localIndex const esr1 = elem2dToElems3d.m_toElementSubRegion[e2d][1]; + localIndex const ei1 = elem2dToElems3d.m_toElementIndex[e2d][1]; + auto const & faces1 = elem2dToElems3d.getElementRegionManager()->getRegion( er1 ).getSubRegion< CellElementSubRegion >( esr1 ).faceList()[ei1]; + + bool const match00 = std::find( faces0.begin(), faces0.end(), f0 ) != faces0.end(); + bool const match11 = std::find( faces1.begin(), faces1.end(), f1 ) != faces1.end(); + bool const match01 = std::find( faces0.begin(), faces0.end(), f1 ) != faces0.end(); + bool const match10 = std::find( faces1.begin(), faces1.end(), f0 ) != faces1.end(); + + bool const matchCrossed = !match00 && !match11 && match01 && match10; + bool const matchStraight = match00 && match11 && !match01 && !match10; + + if( matchCrossed ) + { + std::swap( elem2dToFaces[e2d][0], elem2dToFaces[e2d][1] ); + } + else if( !matchStraight ) + { + GEOS_ERROR( "Mapping neighbor inconsistency detected for fracture " << fractureName ); + } } } } @@ -432,6 +510,11 @@ void FaceElementSubRegion::fixUpDownMaps( bool const clearIfUnmapped ) clearIfUnmapped ); fixNeighborMappingsInconsistency( getName(), m_2dElemToElems, m_toFacesRelation ); + + GEOS_ERROR_IF_NE( m_unmappedGlobalIndicesInToNodes.size(), 0 ); + GEOS_ERROR_IF_NE( m_unmappedGlobalIndicesInToEdges.size(), 0 ); + GEOS_ERROR_IF_NE( m_unmappedGlobalIndicesInToFaces.size(), 0 ); + } /** @@ -474,30 +557,47 @@ std::map< globalIndex, globalIndex > buildReferenceCollocatedNodes( ArrayOfArray /** - * @brief Returns a mapping that links any collocated edge to the collocated edge with the lowest index. - * @param referenceCollocatedNodes The mapping that links any collocated node to its collocated node with the lowest index. - * @param nl2g The local to glocal mapping for nodes. - * @param edgeToNodes The edge to nodes mapping. - * @param elem2dToEdges The 2d elem to edges mapping. - * @param edgeGhostRanks The ghost rank of the edges. - * @return The computed map. + * @brief Computes the mapping which links a pair of collocated nodes + * to all the edges having their nodes collocated to this key pair of nodes. + * @param referenceCollocatedNodes Mapping that link all the collocated nodes + * to the collocated node with the lowest index (considered as a reference). + * The reference node can then be used to make connection between geometrical objects + * relying on collocated nodes (in the case of this function, edges). + * @param nl2g The node local to global mapping. + * @param edgeToNodes The mapping from local edges to local nodes. + * @return The computed mapping. + * @details For each edge based on collocated nodes (i.e. each edge on the fracture), + * we consider each node and compute the reference collocated node. + * There will be multiple edges with the same pair of reference collocated nodes. + * This information is contained in the returned mapping. */ -std::map< localIndex, localIndex > buildReferenceCollocatedEdges( std::map< globalIndex, globalIndex > const & referenceCollocatedNodes, - arrayView1d< globalIndex const > const nl2g, - EdgeManager::NodeMapType const & edgeToNodes, - ArrayOfArraysView< localIndex const > const elem2dToEdges, - arrayView1d< integer const > edgeGhostRanks ) +std::map< std::pair< globalIndex, globalIndex >, std::set< localIndex > > +buildCollocatedEdgeBuckets( std::map< globalIndex, globalIndex > const & referenceCollocatedNodes, + arrayView1d< globalIndex const > const nl2g, + arrayView2d< localIndex const > const edgeToNodes ) { - // `edgeIds` maps the nodes of the edges of the face element sub-region to its index. + GEOS_ASSERT_EQ( edgeToNodes.size( 1 ), 2 ); + + // Checks if the node `gni` is handled as a collocated node on the curren rank. + auto hasCollocatedNode = [&]( globalIndex const gni ) -> bool + { + return referenceCollocatedNodes.find( gni ) != referenceCollocatedNodes.cend(); + }; + + // `edgeIds` is a temporary container that maps the two nodes of any edge of all the face elements, + // to the local index of the edge itself. We fill this container using the `edgeToNodes` mapping + // because we want to be sure to test all the combinations of nodes, + // and therefore not to forget any possible edge. + // It's important to note that the key of `edgeIds` are the global indices of the nodes, in no particular order. std::map< std::pair< globalIndex, globalIndex >, localIndex > edgesIds; - for( int ei = 0; ei < elem2dToEdges.size(); ++ei ) + for( localIndex lei = 0; lei < edgeToNodes.size( 0 ); ++lei ) { - for( localIndex const & edi: elem2dToEdges[ei] ) + auto const & nodes = edgeToNodes[lei]; + globalIndex const & gni0 = nl2g[nodes[0]]; + globalIndex const & gni1 = nl2g[nodes[1]]; + if( hasCollocatedNode( gni0 ) && hasCollocatedNode( gni1 ) ) { - auto const nodes = edgeToNodes[edi]; - GEOS_ASSERT_EQ( nodes.size(), 2 ); - auto const p = std::minmax( { nl2g[nodes[0]], nl2g[nodes[1]] } ); - edgesIds[p] = edi; + edgesIds[{ gni0, gni1 }] = lei; } } @@ -506,22 +606,38 @@ std::map< localIndex, localIndex > buildReferenceCollocatedEdges( std::map< glob // But this trick lets us define some kind of _hash_ that allows to compare the location of the edges: // edges sharing the same hash lie in the same position. std::map< std::pair< globalIndex, globalIndex >, std::set< localIndex > > collocatedEdgeBuckets; - // The `collocatedEdgeIds` map gathers all the collocated edges together. for( auto const & p: edgesIds ) { + static constexpr std::string_view nodeNotFound = "Internal error when trying to access the reference collocated node for global node {}."; + std::pair< globalIndex, globalIndex > const & nodes = p.first; localIndex const & edge = p.second; auto it0 = referenceCollocatedNodes.find( nodes.first ); - globalIndex const n0 = it0 != referenceCollocatedNodes.cend() ? it0->second : nodes.first; + GEOS_ERROR_IF( it0 == referenceCollocatedNodes.cend(), GEOS_FMT( nodeNotFound, nodes.first ) ); + globalIndex const n0 = it0->second; auto it1 = referenceCollocatedNodes.find( nodes.second ); - globalIndex const n1 = it1 != referenceCollocatedNodes.cend() ? it1->second : nodes.second; + GEOS_ERROR_IF( it1 == referenceCollocatedNodes.cend(), GEOS_FMT( nodeNotFound, nodes.second ) ); + globalIndex const n1 = it1->second; std::pair< globalIndex, globalIndex > const edgeHash = std::minmax( n0, n1 ); collocatedEdgeBuckets[edgeHash].insert( edge ); } + return collocatedEdgeBuckets; +} + + +/** + * @brief Returns a mapping that links any collocated edge to the collocated edge with the lowest index. + * @param collocatedEdgeBuckets Links the pairs of reference collocated nodes to the edges overlapping those nodes (even with other nodes). + * @param edgeGhostRanks The ghost rank of the edges. + * @return The computed mapping. + */ +std::map< localIndex, localIndex > buildReferenceCollocatedEdges( std::map< std::pair< globalIndex, globalIndex >, std::set< localIndex > > const & collocatedEdgeBuckets, + arrayView1d< integer const > const edgeGhostRanks ) +{ std::map< localIndex, localIndex > referenceCollocatedEdges; // We want to consider in priority the edges that are owned by the rank. @@ -568,20 +684,20 @@ SortedArray< localIndex > makeSortedArrayIota( localIndex newSize, localIndex va /** * @brief Builds the 2d face to 2d elements mapping. - * @param num2dFaces The number of 2d faces. - * @param num2dElems The number of 2d elements. * @param elem2dToEdges The 2d element (geometrical faces in 3d) to edges mapping. * @param edgesTo2dFaces The edges to 2d faces (geometrical edges in 3d) mapping. * @param referenceCollocatedEdges The mapping that, for a given edge index, returns the collocated edge with lowest index. * @return The computed mapping. */ -ArrayOfArrays< geos::localIndex > build2dFaceTo2dElems( std::size_t num2dFaces, - localIndex num2dElems, - ArrayOfArraysView< localIndex const > const elem2dToEdges, +ArrayOfArrays< geos::localIndex > build2dFaceTo2dElems( ArrayOfArraysView< localIndex const > const elem2dToEdges, map< localIndex, localIndex > const & edgesTo2dFaces, std::map< geos::localIndex, geos::localIndex > const & referenceCollocatedEdges ) { - ArrayOfArrays< localIndex > m_2dFaceTo2dElems; + ArrayOfArrays< localIndex > face2dTo2dElems; + + auto const num2dElems = elem2dToEdges.size(); + auto const num2dFaces = edgesTo2dFaces.size(); + // `tmp` contains the 2d face to 2d elements mappings as a `std` container. // Eventually, it's copied into an `LvArray` container. std::vector< std::vector< localIndex > > tmp( num2dFaces ); @@ -589,6 +705,10 @@ ArrayOfArrays< geos::localIndex > build2dFaceTo2dElems( std::size_t num2dFaces, { for( auto const & e: elem2dToEdges[i] ) { + if( e < 0 ) + { + continue; + } tmp[edgesTo2dFaces.at( referenceCollocatedEdges.at( e ) )].push_back( i ); } } @@ -598,64 +718,248 @@ ArrayOfArrays< geos::localIndex > build2dFaceTo2dElems( std::size_t num2dFaces, { sizes.push_back( t.size() ); } - for( auto i = 0; i < m_2dFaceTo2dElems.size(); ++i ) - { - m_2dFaceTo2dElems.clearArray( i ); - } - m_2dFaceTo2dElems.resizeFromCapacities< serialPolicy >( sizes.size(), sizes.data() ); + + face2dTo2dElems.resizeFromCapacities< serialPolicy >( sizes.size(), sizes.data() ); for( std::size_t i = 0; i < tmp.size(); ++i ) { for( std::size_t j = 0; j < tmp[i].size(); ++j ) { - m_2dFaceTo2dElems.emplaceBack( i, tmp[i][j] ); + face2dTo2dElems.emplaceBack( i, tmp[i][j] ); } } - return m_2dFaceTo2dElems; + return face2dTo2dElems; } -void FaceElementSubRegion::fixSecondaryMappings( NodeManager const & nodeManager, - EdgeManager const & edgeManager, - FaceManager const & faceManager, - ElementRegionManager const & elemManager ) +/** + * @brief Adds some missing connections to the @p elem2dToNodes mapping. + * @param[in] elem2dToCollocatedNodesBuckets The bucket of all the collocated nodes nodes, for each 2d element. + * @param[in] ng2l The global to local node mapping. + * @param[in,out] elem2dToNodes The 2d element to nodes mapping that will receive new connections + * @details Due to the specific way 2d elements are managing nodes, some connections may be missing before the ghosting process. + * After the ghosting has been performed, those connections can be added using this function. + * @note This functions is meant to be called after the ghosting has occurred. + */ +void fillMissing2dElemToNodes( ArrayOfArrays< array1d< globalIndex > > const & elem2dToCollocatedNodesBuckets, + unordered_map< globalIndex, localIndex > const & ng2l, + ArrayOfArrays< localIndex > & elem2dToNodes ) { - arrayView1d< globalIndex const > const nl2g = nodeManager.localToGlobalMap(); + auto const num2dElems = elem2dToNodes.size(); - // First let's create the reference mappings for both nodes and edges. - std::map< globalIndex, globalIndex > const referenceCollocatedNodes = buildReferenceCollocatedNodes( m_2dElemToCollocatedNodesBuckets ); - std::map< localIndex, localIndex > const referenceCollocatedEdges = - buildReferenceCollocatedEdges( referenceCollocatedNodes, nl2g, edgeManager.nodeList(), m_toEdgesRelation.toViewConst(), edgeManager.ghostRank().toViewConst() ); + // We loop over all the collocated nodes attached to the 2d elements. + // If a node is on the rank while not attached to the 2d element, then we add a connection. + for( int e2d = 0; e2d < num2dElems; ++e2d ) + { + auto bucket = elem2dToCollocatedNodesBuckets[e2d]; + for( array1d< globalIndex > const & collocatedNodes: bucket ) + { + for( globalIndex const & collocatedNode: collocatedNodes ) + { + auto g2l = ng2l.find( collocatedNode ); + if( g2l != ng2l.cend() ) + { + localIndex const lni = g2l->second; + auto nodes = elem2dToNodes[e2d]; + if( std::find( nodes.begin(), nodes.end(), lni ) == nodes.end() ) + { + elem2dToNodes.emplaceBack( e2d, lni ); + } + } + } + } + } +} - localIndex const num2dElems = this->size(); - localIndex const num2dFaces = LvArray::integerConversion< localIndex >( referenceCollocatedEdges.size() ); + +/** + * @brief Adds some missing connections to the @p elem2dToEdges mapping. + * @param[in] elem2dToNodes The 2d elements to nodes mappings. + * @param[in] nodesToEdges The nodes to edges mapping. + * @param[in] nl2g The global to local mapping for nodes. + * @param[in] referenceCollocatedNodes A mapping that link all each collocated node to the node that must be used as a reference. + * @param[in] collocatedEdgeBuckets A specific mapping that links all pair of collocated nodes + * to the reference edge built on top of the two locations. + * @param[in,out] elem2dToEdges The 2d element to edges that will be completed/corrected. + * @details The @p elem2dToEdges is (for the moment) used to build connection between the 2d elements. + * Due to the specific way 2d elements are managing nodes, before the ghosting process: + * - some edges may be missing, + * - some edges may be "wrong" (in the sense where there may be multiple collocated edges, + * and we must be sure that all the elements use the same reference edges). + * After the ghosting's been performed, those connections can be reset. + */ +void fillMissing2dElemToEdges( ArrayOfArraysView< localIndex const > const elem2dToNodes, + ArrayOfSetsView< localIndex const > const nodesToEdges, + arrayView1d< globalIndex const > const nl2g, + std::map< globalIndex, globalIndex > const & referenceCollocatedNodes, + std::map< std::pair< globalIndex, globalIndex >, std::set< localIndex > > const & collocatedEdgeBuckets, + ArrayOfArrays< localIndex > & elem2dToEdges ) +{ + localIndex const num2dElems = elem2dToNodes.size(); + for( localIndex e2d = 0; e2d < num2dElems; ++e2d ) + { + auto const numNodes = elem2dToNodes.sizeOfArray( e2d ); + auto const numEdges = elem2dToEdges.sizeOfArray( e2d ); + if( 2 * numEdges == numNodes ) + { + // If the previous conditions is true, all the information could be constructed and therefore should be OK. + // There's no need to proceed. + continue; + } + + // `nodesOfEdgesTouching2dElem` deals with the edges that have at least one point touching the 2d element. + // While `nodesOfEdgesOf2dElem` deals with the edges for which all two nodes are on the 2d element. + // For both mappings, the key is the edge index and the values are the local nodes indices of the concerned edges. + std::map< localIndex, std::vector< localIndex > > nodesOfEdgesTouching2dElem, nodesOfEdgesOf2dElem; + for( localIndex const & n: elem2dToNodes[e2d] ) + { + for( localIndex const & e: nodesToEdges[n] ) + { + nodesOfEdgesTouching2dElem[e].push_back( n ); + } + } + for( auto const & ens: nodesOfEdgesTouching2dElem ) + { + if( ens.second.size() == 2 ) + { + nodesOfEdgesOf2dElem.insert( ens ); + } + } + // We are now recomputing all the edges of the 2d elements. + // Even if some edges were already present in the initial `elem2dToEdges` mapping, + // we'll ditch them and start with a new collection. + std::set< localIndex > allEdgesOf2dElem; + for( auto const & ens: nodesOfEdgesOf2dElem ) + { + std::vector< localIndex > const & nodesOfEdge = ens.second; + globalIndex const & gn0 = referenceCollocatedNodes.at( nl2g[ nodesOfEdge[0] ] ); + globalIndex const & gn1 = referenceCollocatedNodes.at( nl2g[ nodesOfEdge[1] ] ); + std::set< localIndex > candidateEdges = collocatedEdgeBuckets.at( std::minmax( { gn0, gn1 } ) ); + auto const min = std::min_element( candidateEdges.cbegin(), candidateEdges.cend() ); + allEdgesOf2dElem.insert( *min ); + } + elem2dToEdges.clearArray( e2d ); + for( localIndex const & e: allEdgesOf2dElem ) + { + elem2dToEdges.emplaceBack( e2d, e ); + } + } +} + + +/** + * @brief Builds a 2d face to edges mapping + * @param referenceCollocatedEdges Maps all the collocated edges to a single reference collocated edge. + * @return A 1d array that maps local index of a 2d face to the equivalent (3d) reference edge. + * @details The @p referenceCollocatedEdges input basically contains all the edges of the fracture. + * This function only selects the reference edges and builds a 2d face for each. + * The 2d face ordering is more or less random (actually it's sorted on the index of the reference edge). + * But the ordering is not critical as long as it's consistent withing the fracture. + */ +array1d< localIndex > build2dFaceToEdge( std::map< localIndex, localIndex > const & referenceCollocatedEdges ) +{ + std::set< localIndex > const referenceEdges = mapValues< std::set >( referenceCollocatedEdges ); + + localIndex const num2dFaces = LvArray::integerConversion< localIndex >( referenceEdges.size() ); // For the `m_2dFaceToEdge`, we can select any values that we want. // But then we need to be consistent... - m_2dFaceToEdge.clear(); - m_2dFaceToEdge.reserve( num2dFaces ); - for( auto const & p: referenceCollocatedEdges ) + array1d< localIndex > face2dToEdge; + face2dToEdge.reserve( num2dFaces ); + for( localIndex const & refEdge: referenceEdges ) { - globalIndex const & refEdge = p.second; - m_2dFaceToEdge.emplace_back( refEdge ); + face2dToEdge.emplace_back( refEdge ); } + GEOS_ASSERT_EQ( num2dFaces, face2dToEdge.size() ); + + return face2dToEdge; +} + + +/** + * @brief Builds the edges to 2d faces mappings by inverting the 2d faces to edges mappings. + * @param face2dToEdges The mappings to be inverted. + * @return The mapping + */ +map< localIndex, localIndex > buildEdgesToFace2d( arrayView1d< localIndex const > const face2dToEdges ) +{ + map< localIndex, localIndex > edgesToFace2d; + localIndex const num2dFaces = face2dToEdges.size(); - // `m_edgesTo2dFaces` is computed by the simple inversion of `m_2dFaceToEdge` - m_edgesTo2dFaces.clear(); for( localIndex i = 0; i < num2dFaces; ++i ) { - m_edgesTo2dFaces[m_2dFaceToEdge[i]] = i; + edgesToFace2d[face2dToEdges[i]] = i; } + GEOS_ASSERT_EQ_MSG( LvArray::integerConversion< localIndex >( edgesToFace2d.size() ), num2dFaces, "Internal error. The mappings `edgesToFace2d` and `face2dToEdges` should have the same size" ); + + return edgesToFace2d; +} + + +/** + * @brief Uses the two input mappings to reorder the @p elem2dToNodes mapping. + * @param[in] elem2dToFaces The 2d element to faces mapping. + * @param[in] facesToNodes The face to nodes mapping. + * @param[out] elem2dToNodes The 2d element to nodes that will be overwritten. + * @details The @p elem2dToNodes a priori does not respect any specific nodes order. + * But the vtk output expects the first half of the nodes to make a first face (in the correct order), + * and the second to make a second face. But nothing imposes this in our design. + * Even if we should have a more explicit design, + * the current function resets this implicit information in our mappings. + */ +void fixNodesOrder( arrayView2d< localIndex const > const elem2dToFaces, + ArrayOfArraysView< localIndex const > const facesToNodes, + ArrayOfArrays< localIndex > & elem2dToNodes ) +{ + localIndex const num2dElems = elem2dToNodes.size(); + for( localIndex e2d = 0; e2d < num2dElems; ++e2d ) + { + std::vector< localIndex > nodesOfFace; + for( localIndex fi: elem2dToFaces[e2d] ) + { + if( fi != -1 ) + { + for( localIndex ni: facesToNodes[fi] ) + { + nodesOfFace.push_back( ni ); + } + } + } + elem2dToNodes.clearArray( e2d ); + elem2dToNodes.appendToArray( e2d, nodesOfFace.cbegin(), nodesOfFace.cend() ); + } +} + + +void FaceElementSubRegion::fixSecondaryMappings( NodeManager const & nodeManager, + EdgeManager const & edgeManager, + FaceManager const & faceManager, + ElementRegionManager const & elemManager ) +{ + arrayView1d< globalIndex const > const nl2g = nodeManager.localToGlobalMap(); + ArrayOfArraysView< localIndex const > const faceToNodes = faceManager.nodeList().toViewConst(); + + // First let's create the reference mappings for both nodes and edges. + std::map< globalIndex, globalIndex > const referenceCollocatedNodes = buildReferenceCollocatedNodes( m_2dElemToCollocatedNodesBuckets ); + + fillMissing2dElemToNodes( m_2dElemToCollocatedNodesBuckets, nodeManager.globalToLocalMap(), m_toNodesRelation ); + + std::map< std::pair< globalIndex, globalIndex >, std::set< localIndex > > const collocatedEdgeBuckets = buildCollocatedEdgeBuckets( referenceCollocatedNodes, nl2g, edgeManager.nodeList() ); + std::map< localIndex, localIndex > const referenceCollocatedEdges = buildReferenceCollocatedEdges( collocatedEdgeBuckets, edgeManager.ghostRank() ); + + m_2dFaceToEdge = build2dFaceToEdge( referenceCollocatedEdges ); + m_edgesTo2dFaces = buildEdgesToFace2d( m_2dFaceToEdge.toViewConst() ); + + localIndex const num2dElems = this->size(); + localIndex const num2dFaces = m_2dFaceToEdge.size(); // Mark 2d elements and their connections as "new" so they get considered during the stencil computations. // This is mainly due to the dynamic process of the fracture propagation and the legacy unique way to import the fracture // by splitting the mesh during the first steps of the simulations. m_newFaceElements = makeSortedArrayIota( num2dElems ); m_recalculateConnectionsFor2dFaces = makeSortedArrayIota( num2dFaces ); - m_2dFaceTo2dElems = build2dFaceTo2dElems( num2dFaces, num2dElems, m_toEdgesRelation.toViewConst(), m_edgesTo2dFaces, referenceCollocatedEdges ); - // When a fracture element has only one (or less!) neighbor, let's try to find the other one. // The `ElemPath` provides all the information of a given face: obviously its face index, // but also the element index that touch the face, and the node indices of the face as well. @@ -674,7 +978,7 @@ void FaceElementSubRegion::fixSecondaryMappings( NodeManager const & nodeManager }; // We are building the mapping that connects all the reference (collocated) nodes of any face to the elements those nodes are touching. - // Using this nodal information will let use reconnect the fracture 2d element to its 3d neighbor. + // Using this nodal information will let us reconnect the fracture 2d element to its 3d neighbor. std::map< std::set< globalIndex >, std::set< ElemPath > > faceRefNodesToElems; elemManager.forElementSubRegionsComplete< CellElementSubRegion >( [&]( localIndex const er, localIndex const esr, @@ -682,7 +986,6 @@ void FaceElementSubRegion::fixSecondaryMappings( NodeManager const & nodeManager CellElementSubRegion const & subRegion ) { auto const & elemToFaces = subRegion.faceList().base(); - auto const & faceToNodes = faceManager.nodeList(); for( localIndex ei = 0; ei < elemToFaces.size( 0 ); ++ei ) { for( auto const & face: elemToFaces[ei] ) @@ -705,26 +1008,20 @@ void FaceElementSubRegion::fixSecondaryMappings( NodeManager const & nodeManager } // We still double-check that all the nodes of the face were found, // even if there's no chance for this entry to successfully match any request. - if( nodesOfFace.size() == LvArray::integerConversion< std::size_t >( faceToNodes[face].size() ) ) + auto const & nodes = faceToNodes[face]; + if( nodesOfFace.size() == LvArray::integerConversion< std::size_t >( nodes.size() ) ) { - std::vector< localIndex > const nodes( faceToNodes[face].begin(), faceToNodes[face].end() ); - faceRefNodesToElems[nodesOfFace].insert( ElemPath{ er, esr, ei, face, nodes } ); + std::vector< localIndex > const ns( nodes.begin(), nodes.end() ); + faceRefNodesToElems[nodesOfFace].insert( ElemPath{ er, esr, ei, face, ns } ); } } } } ); - // The `misMatches` array will contain fracture element that did not find all of its neighbors. - // This is used to display a more precise error message. - std::vector< localIndex > misMatches; // Here we loop over all the elements of the fracture. // When there's neighbor missing, we search for a face that would lie on the collocated nodes of the fracture element. for( int e2d = 0; e2d < num2dElems; ++e2d ) { - if( m_2dElemToElems.m_toElementIndex.sizeOfArray( e2d ) >= 2 ) // All the neighbors are known. - { - continue; - } std::set< globalIndex > refNodes; if( m_toNodesRelation[e2d].size() != 0 ) @@ -761,30 +1058,31 @@ void FaceElementSubRegion::fixSecondaryMappings( NodeManager const & nodeManager for( ElemPath const & path: match->second ) { // This `if` prevents from storing the same data twice. - if( m_2dElemToElems.m_toElementIndex.sizeOfArray( e2d ) == 0 || m_2dElemToElems.m_toElementIndex[e2d][0] != path.ei ) + if( m_2dElemToElems.m_toElementIndex.size( 1 ) == 0 || m_2dElemToElems.m_toElementIndex[e2d][0] != path.ei ) { - m_2dElemToElems.m_toElementRegion.emplaceBack( e2d, path.er ); - m_2dElemToElems.m_toElementSubRegion.emplaceBack( e2d, path.esr ); - m_2dElemToElems.m_toElementIndex.emplaceBack( e2d, path.ei ); - m_toFacesRelation.emplaceBack( e2d, path.face ); + m_2dElemToElems.m_toElementRegion( e2d, 1 ) = path.er; + m_2dElemToElems.m_toElementSubRegion( e2d, 1 ) = path.esr; + m_2dElemToElems.m_toElementIndex( e2d, 1 ) = path.ei; + m_toFacesRelation( e2d, 1 ) = path.face; for( localIndex const & n: path.nodes ) { - m_toNodesRelation.emplaceBack( e2d, n ); + auto currentNodes = m_toNodesRelation[e2d]; + if( std::find( currentNodes.begin(), currentNodes.end(), n ) == currentNodes.end() ) + { + m_toNodesRelation.emplaceBack( e2d, n ); + } } } } } } - GEOS_ERROR_IF( !misMatches.empty(), - "Fracture " << this->getName() << " has elements {" << stringutilities::join( misMatches, ", " ) << "} without two neighbors." ); - // Checking that each face has two neighboring elements. // If not, we pop up an error. std::vector< localIndex > isolatedFractureElements; for( int e2d = 0; e2d < num2dElems; ++e2d ) { - if( m_2dElemToElems.m_toElementIndex.sizeOfArray( e2d ) < 2 && m_ghostRank[e2d] < 0 ) + if( m_2dElemToElems.m_toElementIndex.size( 1 )< 2 && m_ghostRank[e2d] < 0 ) { isolatedFractureElements.push_back( e2d ); } @@ -792,7 +1090,18 @@ void FaceElementSubRegion::fixSecondaryMappings( NodeManager const & nodeManager GEOS_ERROR_IF( !isolatedFractureElements.empty(), "Fracture " << this->getName() << " has elements {" << stringutilities::join( isolatedFractureElements, ", " ) << "} with less than two neighbors." ); + fillMissing2dElemToEdges( m_toNodesRelation.toViewConst(), + nodeManager.edgeList().toViewConst(), + nl2g, + referenceCollocatedNodes, + collocatedEdgeBuckets, + m_toEdgesRelation ); + + m_2dFaceTo2dElems = build2dFaceTo2dElems( m_toEdgesRelation.toViewConst(), m_edgesTo2dFaces, referenceCollocatedEdges ); + fixNeighborMappingsInconsistency( getName(), m_2dElemToElems, m_toFacesRelation ); + + fixNodesOrder( m_toFacesRelation.toViewConst(), faceToNodes, m_toNodesRelation ); } void FaceElementSubRegion::inheritGhostRankFromParentFace( FaceManager const & faceManager, @@ -822,4 +1131,100 @@ std::set< std::set< globalIndex > > FaceElementSubRegion::getCollocatedNodes() c return result; } +void FaceElementSubRegion::flipFaceMap( FaceManager & faceManager, + ElementRegionManager const & elemManager ) +{ + arrayView2d< localIndex > const & elems2dToFaces = faceList().toView(); + arrayView2d< localIndex const > const & faceToElementRegionIndex = faceManager.elementRegionList(); + arrayView2d< localIndex const > const & faceToElementSubRegionIndex = faceManager.elementSubRegionList(); + arrayView2d< localIndex const > const & faceToElementIndex = faceManager.elementList(); + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > const cellElemGlobalIndex = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( ObjectManagerBase::viewKeyStruct::localToGlobalMapString() ); + + forAll< parallelHostPolicy >( this->size(), [=]( localIndex const kfe ) + { + if( !( elems2dToFaces[kfe][0] == -1 || elems2dToFaces[kfe][1] == -1 ) ) + { + localIndex & f0 = elems2dToFaces[kfe][0]; + localIndex & f1 = elems2dToFaces[kfe][1]; + + localIndex const er0 = faceToElementRegionIndex[f0][0]; + localIndex const esr0 = faceToElementSubRegionIndex[f0][0]; + localIndex const ek0 = faceToElementIndex[f0][0]; + + localIndex const er1 = faceToElementRegionIndex[f1][0]; + localIndex const esr1 = faceToElementSubRegionIndex[f1][0]; + localIndex const ek1 = faceToElementIndex[f1][0]; + + globalIndex const globalIndexElem0 = cellElemGlobalIndex[er0][esr0][ek0]; + globalIndex const globalIndexElem1 = cellElemGlobalIndex[er1][esr1][ek1]; + + if( globalIndexElem0 > globalIndexElem1 ) + { + std::swap( f0, f1 ); + } + } + } ); + +} + +void FaceElementSubRegion::fixNeighboringFacesNormals( FaceManager & faceManager, + ElementRegionManager const & elemManager ) +{ + arrayView2d< localIndex > const & elems2dToFaces = faceList().toView(); + arrayView2d< localIndex const > const & faceToElementRegionIndex = faceManager.elementRegionList(); + arrayView2d< localIndex const > const & faceToElementSubRegionIndex = faceManager.elementSubRegionList(); + arrayView2d< localIndex const > const & faceToElementIndex = faceManager.elementList(); + + arrayView2d< real64 const > const faceCenter = faceManager.faceCenter(); + FaceManager::NodeMapType & faceToNodes = faceManager.nodeList(); + + auto elemCenter = elemManager.constructArrayViewAccessor< real64, 2 >( CellElementSubRegion::viewKeyStruct::elementCenterString() ); + + // We need to modify the normals and the nodes ordering to be consistent. + arrayView2d< real64 > const faceNormal = faceManager.faceNormal(); + forAll< parallelHostPolicy >( this->size(), [=, &faceToNodes]( localIndex const kfe ) + { + if( !( elems2dToFaces[kfe][0] == -1 || elems2dToFaces[kfe][1] == -1 ) ) + { + localIndex const f0 = elems2dToFaces[kfe][0]; + localIndex const f1 = elems2dToFaces[kfe][1]; + + /// Note: I am assuming that the 0 element is the elementSubregion one for faces + /// touching both a 3D and a 2D cell. + localIndex const er0 = faceToElementRegionIndex[f0][0]; + localIndex const esr0 = faceToElementSubRegionIndex[f0][0]; + localIndex const ek0 = faceToElementIndex[f0][0]; + + localIndex const er1 = faceToElementRegionIndex[f1][0]; + localIndex const esr1 = faceToElementSubRegionIndex[f1][0]; + localIndex const ek1 = faceToElementIndex[f1][0]; + + real64 f0e0vector[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3( faceCenter[f0] ); + real64 f1e1vector[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3( faceCenter[f1] ); + + LvArray::tensorOps::subtract< 3 >( f0e0vector, elemCenter[er0][esr0][ek0] ); + LvArray::tensorOps::subtract< 3 >( f1e1vector, elemCenter[er1][esr1][ek1] ); + + // If the vector connecting the face center and the elem center is in the same + // direction as the unit normal, we flip the normal coz it should be pointing outward + // (i.e., towards the fracture element). + if( LvArray::tensorOps::AiBi< 3 >( faceNormal[f0], f0e0vector ) < 0.0 ) + { + GEOS_WARNING( GEOS_FMT( "For fracture element {}, I had to flip the normal nf0 of face {}", kfe, f0 ) ); + LvArray::tensorOps::scale< 3 >( faceNormal[f0], -1.0 ); + std::reverse( faceToNodes[f0].begin(), faceToNodes[f0].end() ); + } + if( LvArray::tensorOps::AiBi< 3 >( faceNormal[f1], f1e1vector ) < 0.0 ) + { + GEOS_WARNING( GEOS_FMT( "For fracture element {}, I had to flip the normal nf1 of face {}", kfe, f1 ) ); + LvArray::tensorOps::scale< 3 >( faceNormal[f1], -1.0 ); + std::reverse( faceToNodes[f1].begin(), faceToNodes[f1].end() ); + } + } + } ); + +} + } /* namespace geos */ diff --git a/src/coreComponents/mesh/FaceElementSubRegion.hpp b/src/coreComponents/mesh/FaceElementSubRegion.hpp index 262f0aeeba5..42655d7a274 100644 --- a/src/coreComponents/mesh/FaceElementSubRegion.hpp +++ b/src/coreComponents/mesh/FaceElementSubRegion.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -38,7 +39,7 @@ class FaceElementSubRegion : public SurfaceElementSubRegion public: /// Face element to faces map type - using FaceMapType = InterObjectRelation< ArrayOfArrays< localIndex > >; + using FaceMapType = FixedOneToManyRelation; /** * @name Static factory catalog functions @@ -109,6 +110,38 @@ class FaceElementSubRegion : public SurfaceElementSubRegion bool const overwriteUpMaps, bool const overwriteDownMaps ) override; + + /** + * @brief Size of packing of the FaceElement to face relation. + * @param packList The list of face elements to pack + * @return The size of the packed data + */ + localIndex packToFaceRelationSize( arrayView1d< localIndex const > const & packList ) const; + + /** + * @brief Pack the FaceElement to face relation. + * @param buffer The buffer to pack the data into + * @param packList The list of face elements to pack + * @return The size of the packed data + */ + localIndex packToFaceRelation( buffer_unit_type * & buffer, + arrayView1d< localIndex const > const & packList ) const; + + /** + * @brief Unpack the FaceElement to face relation. + * @param buffer The buffer to unpack the data from + * @param packList The list of face elements to unpack + * @param overwriteUpMaps Flag to overwrite the up maps + * @param overwriteDownMaps Flag to overwrite the down maps + * @return The size of the unpacked data + */ + localIndex unpackToFaceRelation( buffer_unit_type const * & buffer, + array1d< localIndex > & packList, + bool const overwriteUpMaps, + bool const overwriteDownMaps ); + + + virtual void fixUpDownMaps( bool const clearIfUnmapped ) override; /** @@ -133,6 +166,30 @@ class FaceElementSubRegion : public SurfaceElementSubRegion void inheritGhostRankFromParentFace( FaceManager const & faceManager, std::set< localIndex > const & indices ); + /** + * @brief Function to flip the face normals of faces adjacent to the faceElements if they are not pointing in the direction of the + * fracture. + * @param faceManager The face manager group + * @param elemManager The element region manager + * @details We want to flip the normals of the faces neighboring the fracture element. To do so, we check + * if the vector connecting the face center and the element center of the neighboring 3d cell is in the same + * direction as the unit normal of the face. If they are not, we flip the normal because it should be pointing outward + * (i.e., towards the fracture element). + */ + void fixNeighboringFacesNormals( FaceManager & faceManager, + ElementRegionManager const & elemManager ); + + /** + * @brief Function to flip the face map based on the gloal index of the nighboring elements + * @param faceManager The face manager group + * @param elemManager The element region manager + * @details In order to keep a consistent normal between multi processors ranks, we force the faces to be ordered + * based on the global numbering of the 3d elements attached to each face. The first face is always the one + * attached to the 3d cell with the smallest globalIndex. + */ + void flipFaceMap( FaceManager & faceManager, + ElementRegionManager const & elemManager ); + /** * @brief Struct containing the keys to all face element views. * @struct viewKeyStruct @@ -152,7 +209,7 @@ class FaceElementSubRegion : public SurfaceElementSubRegion /// @return String key to collocated nodes buckets. static constexpr char const * elem2dToCollocatedNodesBucketsString() { return "elem2dToCollocatedNodesBuckets"; } -#if GEOSX_USE_SEPARATION_COEFFICIENT +#if GEOS_USE_SEPARATION_COEFFICIENT /// Separation coefficient string. constexpr static char const * separationCoeffString() { return "separationCoeff"; } /// dSepCoeffdAper string. @@ -200,7 +257,7 @@ class FaceElementSubRegion : public SurfaceElementSubRegion */ //virtual localIndex numNodesPerElement( localIndex const k ) const override { return m_toNodesRelation[k].size(); } -#ifdef GEOSX_USE_SEPARATION_COEFFICIENT +#ifdef GEOS_USE_SEPARATION_COEFFICIENT /** * @brief Get separation coefficient. * @return the separation coefficient @@ -286,6 +343,23 @@ class FaceElementSubRegion : public SurfaceElementSubRegion return m_2dElemToCollocatedNodesBuckets.toViewConst(); } + /** + * @brief Get the surface element to cells map. + * @return The surface element to cells map + */ + FixedToManyElementRelation & getToCellRelation() + { + return m_2dElemToElems; + } + + /** + * @copydoc getToCellRelation() + */ + FixedToManyElementRelation const & getToCellRelation() const + { + return m_2dElemToElems; + } + private: /** @@ -299,6 +373,11 @@ class FaceElementSubRegion : public SurfaceElementSubRegion localIndex packUpDownMapsImpl( buffer_unit_type * & buffer, arrayView1d< localIndex const > const & packList ) const; + + template< bool DO_PACKING > + localIndex packToFaceRelationImpl( buffer_unit_type * & buffer, + arrayView1d< localIndex const > const & packList ) const; + /// The array of shape function derivaties. array4d< real64 > m_dNdX; @@ -314,7 +393,10 @@ class FaceElementSubRegion : public SurfaceElementSubRegion */ ArrayOfArrays< array1d< globalIndex > > m_2dElemToCollocatedNodesBuckets; -#ifdef GEOSX_USE_SEPARATION_COEFFICIENT + /// Map between the surface elements and the cells + FixedToManyElementRelation m_2dElemToElems; + +#ifdef GEOS_USE_SEPARATION_COEFFICIENT /// Separation coefficient array1d< real64 > m_separationCoefficient; #endif diff --git a/src/coreComponents/mesh/FaceManager.cpp b/src/coreComponents/mesh/FaceManager.cpp index 93ab06f4c64..044cd1beb47 100644 --- a/src/coreComponents/mesh/FaceManager.cpp +++ b/src/coreComponents/mesh/FaceManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,8 +20,9 @@ #include "FaceManager.hpp" #include "common/GEOS_RAJA_Interface.hpp" -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" #include "common/TimingMacros.hpp" +#include "common/MpiWrapper.hpp" #include "LvArray/src/tensorOps.hpp" #include "mesh/BufferOps.hpp" #include "mesh/ElementRegionManager.hpp" @@ -122,17 +124,18 @@ void FaceManager::setDomainBoundaryObjects( ElementRegionManager const & elemReg } FaceElementSubRegion const & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); - ArrayOfArraysView< localIndex const > const elem2dToFaces = subRegion.faceList().toViewConst(); - for( int ei = 0; ei < elem2dToFaces.size(); ++ei ) + arrayView2d< localIndex const > const elem2dToFaces = subRegion.faceList().toViewConst(); + for( int ei = 0; ei < elem2dToFaces.size( 0 ); ++ei ) { - if( elem2dToFaces.sizeOfArray( ei ) == 2 ) + if( elem2dToFaces[ei][0] == -1 || elem2dToFaces[ei][1] == -1 ) { - continue; - } - - for( localIndex const & face: elem2dToFaces[ei] ) - { - isFaceOnDomainBoundary[face] = 1; + for( localIndex const & face: elem2dToFaces[ei] ) + { + if( face != -1 ) + { + isFaceOnDomainBoundary[face] = 1; + } + } } } }; @@ -178,22 +181,25 @@ void FaceManager::setGeometricalRelations( CellBlockManagerABC const & cellBlock // The fracture subregion knows the faces it's connected to. // And since a 2d element is connected to a given face, and since a face can only have 2 neighbors, // then the second neighbor of the face is bound to be undefined (i.e. -1). - ArrayOfArraysView< localIndex const > const & elem2dToFaces = subRegion.faceList().toViewConst(); - for( localIndex ei = 0; ei < elem2dToFaces.size(); ++ei ) + arrayView2d< localIndex const > const & elem2dToFaces = subRegion.faceList().toViewConst(); + for( localIndex ei = 0; ei < elem2dToFaces.size( 0 ); ++ei ) { - for( localIndex const & face: elem2dToFaces[ei] ) + for( localIndex const & faceIndex: elem2dToFaces[ei] ) { - GEOS_ERROR_IF_EQ_MSG( m_toElements.m_toElementRegion( face, 0 ), -1, GEOS_FMT( err, face ) ); - GEOS_ERROR_IF_EQ_MSG( m_toElements.m_toElementSubRegion( face, 0 ), -1, GEOS_FMT( err, face ) ); - GEOS_ERROR_IF_EQ_MSG( m_toElements.m_toElementIndex( face, 0 ), -1, GEOS_FMT( err, face ) ); + if( faceIndex != -1 ) + { + GEOS_ERROR_IF_EQ_MSG( m_toElements.m_toElementRegion( faceIndex, 0 ), -1, GEOS_FMT( err, faceIndex ) ); + GEOS_ERROR_IF_EQ_MSG( m_toElements.m_toElementSubRegion( faceIndex, 0 ), -1, GEOS_FMT( err, faceIndex ) ); + GEOS_ERROR_IF_EQ_MSG( m_toElements.m_toElementIndex( faceIndex, 0 ), -1, GEOS_FMT( err, faceIndex ) ); - GEOS_ERROR_IF_NE_MSG( m_toElements.m_toElementRegion( face, 1 ), -1, GEOS_FMT( err, face ) ); - GEOS_ERROR_IF_NE_MSG( m_toElements.m_toElementSubRegion( face, 1 ), -1, GEOS_FMT( err, face ) ); - GEOS_ERROR_IF_NE_MSG( m_toElements.m_toElementIndex( face, 1 ), -1, GEOS_FMT( err, face ) ); + GEOS_ERROR_IF_NE_MSG( m_toElements.m_toElementRegion( faceIndex, 1 ), -1, GEOS_FMT( err, faceIndex ) ); + GEOS_ERROR_IF_NE_MSG( m_toElements.m_toElementSubRegion( faceIndex, 1 ), -1, GEOS_FMT( err, faceIndex ) ); + GEOS_ERROR_IF_NE_MSG( m_toElements.m_toElementIndex( faceIndex, 1 ), -1, GEOS_FMT( err, faceIndex ) ); - m_toElements.m_toElementRegion( face, 1 ) = er; - m_toElements.m_toElementSubRegion( face, 1 ) = esr; - m_toElements.m_toElementIndex( face, 1 ) = ei; + m_toElements.m_toElementRegion( faceIndex, 1 ) = er; + m_toElements.m_toElementSubRegion( faceIndex, 1 ) = esr; + m_toElements.m_toElementIndex( faceIndex, 1 ) = ei; + } } } }; @@ -271,11 +277,7 @@ void FaceManager::sortAllFaceNodes( NodeManager const & nodeManager, if( facesToElements( faceIndex, 0 ) < 0 && facesToElements( faceIndex, 1 ) < 0 ) { GEOS_ERROR( getDataContext() << ": Face " << faceIndex << - " is not connected to any cell.\n" - "You might have:\n" - "- an invalid mesh,\n" - "- not enough CellElementRegions to describe your input mesh (all regions, simulated or not, must be listed),\n" - "- forgotten one cell type in an existing \"" << CellElementRegion::viewKeyStruct::sourceCellBlockNamesString() << "\'." ); + " is not connected to any cell. You might have an invalid mesh." ); } // Take the first defined face-to-(elt/region/sub region) to sorting direction. @@ -516,6 +518,9 @@ localIndex FaceManager::unpackUpDownMaps( buffer_unit_type const * & buffer, m_toElements.getElementRegionManager(), overwriteUpMaps ); + GEOS_ERROR_IF_NE( m_unmappedGlobalIndicesInToNodes.size(), 0 ); + GEOS_ERROR_IF_NE( m_unmappedGlobalIndicesInToEdges.size(), 0 ); + return unPackedSize; } diff --git a/src/coreComponents/mesh/FaceManager.hpp b/src/coreComponents/mesh/FaceManager.hpp index 2c7948b145f..97fc8187671 100644 --- a/src/coreComponents/mesh/FaceManager.hpp +++ b/src/coreComponents/mesh/FaceManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -434,6 +435,11 @@ class FaceManager : public ObjectManagerBase ///}@ + /** + * @brief Get the maximum number of nodes per face. + * @return the maximum number of nodes per face + */ + constexpr static int maxFaceNodes() { return MAX_FACE_NODES; } private: /** diff --git a/src/coreComponents/mesh/FieldIdentifiers.hpp b/src/coreComponents/mesh/FieldIdentifiers.hpp index b7a8fb6312b..82a05050565 100644 --- a/src/coreComponents/mesh/FieldIdentifiers.hpp +++ b/src/coreComponents/mesh/FieldIdentifiers.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,8 @@ #define GEOS_MESH_MPICOMMUNICATIONS_FIELDIDENTIFIERS_HPP_ #include "common/DataTypes.hpp" -#include "codingUtilities/StringUtilities.hpp" +#include "common/format/StringUtilities.hpp" +#include "common/logger/Logger.hpp" namespace geos { @@ -96,11 +98,11 @@ class FieldIdentifiers * @brief Get the Location object * * @param key key used to store the list of fields in the map. - * @param location mesh location where fields defined by the key provided were registered. + * @return mesh location where fields defined by the key provided were registered. */ - void getLocation( string const & key, - FieldLocation & location ) const + FieldLocation getLocation( string const & key ) const { + FieldLocation location{}; if( key.find( m_locationKeys.nodesKey() ) != string::npos ) { location = FieldLocation::Node; @@ -121,6 +123,7 @@ class FieldIdentifiers { GEOS_ERROR( GEOS_FMT( "Invalid key, {}, was provided. Location cannot be retrieved.", key ) ); } + return location; } private: diff --git a/src/coreComponents/mesh/InterObjectRelation.hpp b/src/coreComponents/mesh/InterObjectRelation.hpp index 08a4b1c126e..b48f99f1a61 100644 --- a/src/coreComponents/mesh/InterObjectRelation.hpp +++ b/src/coreComponents/mesh/InterObjectRelation.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/MeshBody.cpp b/src/coreComponents/mesh/MeshBody.cpp index df7a3279116..7695972f6d4 100644 --- a/src/coreComponents/mesh/MeshBody.cpp +++ b/src/coreComponents/mesh/MeshBody.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/MeshBody.hpp b/src/coreComponents/mesh/MeshBody.hpp index be1992183ce..bf06ca72501 100644 --- a/src/coreComponents/mesh/MeshBody.hpp +++ b/src/coreComponents/mesh/MeshBody.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/MeshFields.hpp b/src/coreComponents/mesh/MeshFields.hpp index 1b4cca146b3..dc8ff969e64 100644 --- a/src/coreComponents/mesh/MeshFields.hpp +++ b/src/coreComponents/mesh/MeshFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -114,6 +115,14 @@ DECLARE_FIELD( elementAperture, WRITE_AND_READ, "Element aperture." ); +DECLARE_FIELD( elementArea, + "elementArea", + array1d< real64 >, + 0, + LEVEL_0, + WRITE_AND_READ, + "Element area." ); + DECLARE_FIELD( parentIndex, "parentIndex", array1d< localIndex >, @@ -146,6 +155,30 @@ DECLARE_FIELD( ruptureTime, WRITE_AND_READ, "Time that the object was ruptured/split." ); +DECLARE_FIELD( normalVector, + "normalVector", + array2d< real64 >, + 0.0, + LEVEL_0, + WRITE_AND_READ, + "Unit normal vector to the surface." ); + +DECLARE_FIELD( tangentVector1, + "tangentVector1", + array2d< real64 >, + 0.0, + LEVEL_0, + WRITE_AND_READ, + "Unit vector in the first tangent direction to the surface." ); + +DECLARE_FIELD( tangentVector2, + "tangentVector2", + array2d< real64 >, + 0.0, + LEVEL_0, + WRITE_AND_READ, + "Unit vector in the second tangent direction to the surface." ); + } // namespace fields } // namespace geos diff --git a/src/coreComponents/mesh/MeshForLoopInterface.hpp b/src/coreComponents/mesh/MeshForLoopInterface.hpp index 28df35fce77..b7c126b1e23 100644 --- a/src/coreComponents/mesh/MeshForLoopInterface.hpp +++ b/src/coreComponents/mesh/MeshForLoopInterface.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/MeshLevel.cpp b/src/coreComponents/mesh/MeshLevel.cpp index 6097bd0067e..be5bc7763d8 100644 --- a/src/coreComponents/mesh/MeshLevel.cpp +++ b/src/coreComponents/mesh/MeshLevel.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -203,8 +204,8 @@ MeshLevel::MeshLevel( string const & name, // create element region with the same name as source element region "Region" CellElementRegion & region = *(dynamic_cast< CellElementRegion * >( m_elementManager->createChild( sourceRegion.getCatalogName(), sourceRegion.getName() ) ) ); - // add cell block to the new element region with the same name as cell block name from source element region - region.addCellBlockNames( sourceRegion.getCellBlockNames() ); + // set cell block to the new element region with the same name as cell block name from source element region + region.setCellBlockNames( sourceRegion.getCellBlockNames() ); sourceRegion.forElementSubRegions< CellElementSubRegion >( [&]( CellElementSubRegion const & sourceSubRegion ) { @@ -338,7 +339,7 @@ void MeshLevel::generateAdjacencyLists( arrayView1d< localIndex const > const & { ArrayOfArraysView< localIndex const > const elems2dToNodes = subRegion.nodeList().toViewConst(); ArrayOfArraysView< localIndex const > const elem2dToEdges = subRegion.edgeList().toViewConst(); - ArrayOfArraysView< localIndex const > const elems2dToFaces = subRegion.faceList().toViewConst(); + arrayView2d< localIndex const > const elems2dToFaces = subRegion.faceList().toViewConst(); for( localIndex const ei: elementAdjacencySet[er][esr] ) { @@ -352,7 +353,10 @@ void MeshLevel::generateAdjacencyLists( arrayView1d< localIndex const > const & } for( localIndex const & fi: elems2dToFaces[ei] ) { - faceAdjacencySet.insert( fi ); + if( fi != -1 ) + { + faceAdjacencySet.insert( fi ); + } } } }; diff --git a/src/coreComponents/mesh/MeshLevel.hpp b/src/coreComponents/mesh/MeshLevel.hpp index 727a9514cb0..f61892216c4 100644 --- a/src/coreComponents/mesh/MeshLevel.hpp +++ b/src/coreComponents/mesh/MeshLevel.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/MeshManager.cpp b/src/coreComponents/mesh/MeshManager.cpp index d1e48b4f419..662b06002b6 100644 --- a/src/coreComponents/mesh/MeshManager.cpp +++ b/src/coreComponents/mesh/MeshManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,6 @@ #include "mesh/mpiCommunications/SpatialPartition.hpp" #include "generators/CellBlockManagerABC.hpp" -#include "generators/MeshGeneratorBase.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "common/TimingMacros.hpp" @@ -42,9 +42,9 @@ MeshManager::~MeshManager() Group * MeshManager::createChild( string const & childKey, string const & childName ) { - GEOS_LOG_RANK_0( "Adding Mesh: " << childKey << ", " << childName ); - std::unique_ptr< MeshGeneratorBase > solver = MeshGeneratorBase::CatalogInterface::factory( childKey, childName, this ); - return &this->registerGroup< MeshGeneratorBase >( childName, std::move( solver ) ); + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) ); + std::unique_ptr< MeshGeneratorBase > mesh = MeshGeneratorBase::CatalogInterface::factory( childKey, childName, this ); + return &this->registerGroup< MeshGeneratorBase >( childName, std::move( mesh ) ); } @@ -80,7 +80,7 @@ void MeshManager::generateMeshes( DomainPartition & domain ) void MeshManager::generateMeshLevels( DomainPartition & domain ) { - this->forSubGroups< MeshGeneratorBase >( [&]( MeshGeneratorBase & meshGen ) + forSubGroups< MeshGeneratorBase >( [&]( MeshGeneratorBase & meshGen ) { string const & meshName = meshGen.getName(); domain.getMeshBodies().registerGroup< MeshBody >( meshName ).createMeshLevel( MeshBody::groupStructKeys::baseDiscretizationString() ); @@ -125,50 +125,10 @@ void MeshManager::importFields( DomainPartition & domain ) } GEOS_LOG_RANK_0( GEOS_FMT( "{}: importing field data from mesh dataset", generator.getName() ) ); - - auto const importFields = [&generator]( ElementRegionBase const & region, - ElementSubRegionBase & subRegion, - MeshGeneratorBase::Block block, - std::map< string, string > const & fieldsMapping, - FieldIdentifiers & fieldsToBeSync ) - { - std::unordered_set< string > const materialWrapperNames = getMaterialWrapperNames( subRegion ); - // Writing properties - for( auto const & pair : fieldsMapping ) - { - string const & meshFieldName = pair.first; - string const & geosxFieldName = pair.second; - // Find destination - if( !subRegion.hasWrapper( geosxFieldName ) ) - { - // Skip - the user may have not enabled a particular physics model/solver on this destination region. - if( generator.getLogLevel() >= 1 ) - { - GEOS_LOG_RANK_0( "Skipping import of " << meshFieldName << " -> " << geosxFieldName << - " on " << region.getName() << "/" << subRegion.getName() << " (field not found)" ); - } - - continue; - } - - // Now that we know that the subRegion has this wrapper, - // we can add the geosxFieldName to the list of fields to synchronize - fieldsToBeSync.addElementFields( { geosxFieldName }, { region.getName() } ); - WrapperBase & wrapper = subRegion.getWrapperBase( geosxFieldName ); - if( generator.getLogLevel() >= 1 ) - { - GEOS_LOG_RANK_0( "Importing field " << meshFieldName << " into " << geosxFieldName << - " on " << region.getName() << "/" << subRegion.getName() ); - } - - bool const isMaterialField = materialWrapperNames.count( geosxFieldName ) > 0 && wrapper.numArrayDims() > 1; - generator.importFieldOnArray( block, subRegion.getName(), meshFieldName, isMaterialField, wrapper ); - } - }; - - dataRepository::Group & meshLevels = domain.getMeshBody( generator.getName() ).getMeshLevels(); - meshLevels.forSubGroups< MeshLevel >( [&]( MeshLevel & meshLevel ) + MeshBody & meshBody = domain.getMeshBody( generator.getName() ); + meshBody.forMeshLevels( [&]( MeshLevel & meshLevel ) { + GEOS_LOG_RANK_0( GEOS_FMT( " mesh level = {}", meshLevel.getName() ) ); FieldIdentifiers fieldsToBeSync; meshLevel.getElemManager().forElementSubRegionsComplete< CellElementSubRegion >( [&]( localIndex, @@ -176,7 +136,8 @@ void MeshManager::importFields( DomainPartition & domain ) ElementRegionBase const & region, CellElementSubRegion & subRegion ) { - importFields( region, subRegion, MeshGeneratorBase::Block::VOLUMIC, generator.getVolumicFieldsMapping(), fieldsToBeSync ); + GEOS_LOG_RANK_0( GEOS_FMT( " volumic fields on {}/{}", region.getName(), subRegion.getName() ) ); + importFields( generator, region.getName(), subRegion, MeshGeneratorBase::Block::VOLUMIC, generator.getVolumicFieldsMapping(), fieldsToBeSync ); } ); meshLevel.getElemManager().forElementSubRegionsComplete< FaceElementSubRegion >( [&]( localIndex, @@ -184,7 +145,8 @@ void MeshManager::importFields( DomainPartition & domain ) ElementRegionBase const & region, FaceElementSubRegion & subRegion ) { - importFields( region, subRegion, MeshGeneratorBase::Block::SURFACIC, generator.getSurfacicFieldsMapping(), fieldsToBeSync ); + GEOS_LOG_RANK_0( GEOS_FMT( " surfaic fields on {}/{}", region.getName(), subRegion.getName() ) ); + importFields( generator, region.getName(), subRegion, MeshGeneratorBase::Block::SURFACIC, generator.getSurfacicFieldsMapping(), fieldsToBeSync ); } ); CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync, meshLevel, domain.getNeighbors(), false ); // TODO Validate this. } ); @@ -196,4 +158,43 @@ void MeshManager::importFields( DomainPartition & domain ) } ); } +void MeshManager::importFields( MeshGeneratorBase const & generator, + string const & regionName, + ElementSubRegionBase & subRegion, + MeshGeneratorBase::Block const block, + std::map< string, string > const & fieldsMapping, + FieldIdentifiers & fieldsToBeSync ) +{ + std::unordered_set< string > const materialWrapperNames = getMaterialWrapperNames( subRegion ); + // Writing properties + for( auto const & pair : fieldsMapping ) + { + string const & meshFieldName = pair.first; + string const & geosFieldName = pair.second; + // Find destination + if( !subRegion.hasWrapper( geosFieldName ) ) + { + // Skip - the user may have not enabled a particular physics model/solver on this destination region. + if( generator.getLogLevel() >= 1 ) + { + GEOS_LOG_RANK_0( GEOS_FMT( " Skipping import of {} -> {} (field not found)", meshFieldName, geosFieldName ) ); + } + + continue; + } + + // Now that we know that the subRegion has this wrapper, + // we can add the geosFieldName to the list of fields to synchronize + fieldsToBeSync.addElementFields( { geosFieldName }, { regionName } ); + WrapperBase & wrapper = subRegion.getWrapperBase( geosFieldName ); + if( generator.getLogLevel() >= 1 ) + { + GEOS_LOG_RANK_0( GEOS_FMT( " {} -> {}", meshFieldName, geosFieldName ) ); + } + + bool const isMaterialField = materialWrapperNames.count( geosFieldName ) > 0 && wrapper.numArrayDims() > 1; + generator.importFieldOnArray( block, subRegion.getName(), meshFieldName, isMaterialField, wrapper ); + } +} + } /* namespace geos */ diff --git a/src/coreComponents/mesh/MeshManager.hpp b/src/coreComponents/mesh/MeshManager.hpp index b7aac9276bc..d2f7eff56d0 100644 --- a/src/coreComponents/mesh/MeshManager.hpp +++ b/src/coreComponents/mesh/MeshManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,10 +22,10 @@ #include "dataRepository/Group.hpp" #include "mesh/DomainPartition.hpp" +#include "generators/MeshGeneratorBase.hpp" namespace geos { -class SolverBase; /** * @class MeshManager @@ -74,6 +75,22 @@ class MeshManager : public dataRepository::Group */ void importFields( DomainPartition & domain ); + /** + * @brief Import fields data + * @param[in] generator reference to mesh generator + * @param[in] regionName name of the region + * @param[in] subRegion reference to the subregion + * @param[in] block block type + * @param[in] fieldsMapping mapping for fields + * @param[out] fieldsToBeSync list of fields to synchronize + */ + static void importFields( MeshGeneratorBase const & generator, + string const & regionName, + ElementSubRegionBase & subRegion, + MeshGeneratorBase::Block block, + std::map< string, string > const & fieldsMapping, + FieldIdentifiers & fieldsToBeSync ); + private: /** diff --git a/src/coreComponents/mesh/MeshObjectPath.cpp b/src/coreComponents/mesh/MeshObjectPath.cpp index 992cc4755a3..31481e53b72 100644 --- a/src/coreComponents/mesh/MeshObjectPath.cpp +++ b/src/coreComponents/mesh/MeshObjectPath.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/MeshObjectPath.hpp b/src/coreComponents/mesh/MeshObjectPath.hpp index 983fb822fc0..5aa5ec98758 100644 --- a/src/coreComponents/mesh/MeshObjectPath.hpp +++ b/src/coreComponents/mesh/MeshObjectPath.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #define GEOS_MESH_MESHOBJECTPATH_HPP_ -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include "MeshLevel.hpp" namespace geos diff --git a/src/coreComponents/mesh/NodeManager.cpp b/src/coreComponents/mesh/NodeManager.cpp index 2bc39dc498f..55f6aed4568 100644 --- a/src/coreComponents/mesh/NodeManager.cpp +++ b/src/coreComponents/mesh/NodeManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -25,6 +26,7 @@ #include "mesh/FaceManager.hpp" #include "mesh/ToElementRelation.hpp" #include "mesh/utilities/MeshMapUtilities.hpp" +#include "common/MpiWrapper.hpp" namespace geos { @@ -270,7 +272,7 @@ localIndex NodeManager::unpackUpDownMaps( buffer_unit_type const * & buffer, string temp; unPackedSize += bufferOps::Unpack( buffer, temp ); - GEOS_ERROR_IF( temp != viewKeyStruct::edgeListString(), "" ); + GEOS_ERROR_IF_NE( temp, viewKeyStruct::edgeListString() ); unPackedSize += bufferOps::Unpack( buffer, m_toEdgesRelation, packList, @@ -359,6 +361,90 @@ void NodeManager::depopulateUpMaps( std::set< localIndex > const & receivedNodes } } -REGISTER_CATALOG_ENTRY( ObjectManagerBase, NodeManager, string const &, Group * const ) +void NodeManager::outputObjectConnectivity() const +{ + + int const numRanks = MpiWrapper::commSize(); + int const thisRank = MpiWrapper::commRank(); + + for( int rank=0; rankgetName().c_str() ); + + printf( " Reference positions:\n" ); + for( localIndex a=0; asize(); ++a ) + { + printf( " %3d( %3lld ): %6.2f, %6.2f, %6.2f \n", a, m_localToGlobalMap( a ), m_referencePosition( a, 0 ), m_referencePosition( a, 1 ), m_referencePosition( a, 2 ) ); + } + + printf( "\n Reference positions (sorted by global):\n" ); + map< globalIndex, localIndex > const sortedGlobalToLocalMap( m_globalToLocalMap.begin(), m_globalToLocalMap.end()); + for( auto indexPair : sortedGlobalToLocalMap ) + { + localIndex const a = indexPair.second; + printf( " %3d( %3lld ): %6.2f, %6.2f, %6.2f \n", a, m_localToGlobalMap( a ), m_referencePosition( a, 0 ), m_referencePosition( a, 1 ), m_referencePosition( a, 2 ) ); + } + + printf( " toEdgesRelation: \n" ); + arrayView1d< globalIndex const > const & edgeLocalToGlobal = m_toEdgesRelation.relatedObjectLocalToGlobal(); + for( localIndex a=0; asize(); ++a ) + { + printf( " %3d(%3lld): ", a, m_localToGlobalMap( a ) ); + + for( localIndex b=0; b const & faceLocalToGlobal = m_toFacesRelation.relatedObjectLocalToGlobal(); + for( localIndex a=0; asize(); ++a ) + { + printf( " %3d(%3lld): ", a, m_localToGlobalMap( a ) ); + + for( localIndex b=0; b >( viewKeyStruct::domainBoundaryIndicatorString(), &m_domainBoundaryIndicator ); + registerWrapper( viewKeyStruct::localMaxGlobalIndexString(), &m_localMaxGlobalIndex ). + setApplyDefaultValue( -1 ). + setRestartFlags( RestartFlags::WRITE_AND_READ ). + setPlotLevel( PlotLevel::NOPLOT ); + + registerWrapper( viewKeyStruct::maxGlobalIndexString(), &m_maxGlobalIndex ). + setApplyDefaultValue( -1 ). + setRestartFlags( RestartFlags::WRITE_AND_READ ). + setPlotLevel( PlotLevel::NOPLOT ); + m_sets.registerWrapper< SortedArray< localIndex > >( this->m_ObjectManagerBaseViewKeys.externalSet ); excludeWrappersFromPacking( { viewKeyStruct::localToGlobalMapString(), @@ -239,7 +251,7 @@ localIndex ObjectManagerBase::packImpl( buffer_unit_type * & buffer, localIndex packedSize = 0; packedSize += bufferOps::Pack< DO_PACKING >( buffer, this->getName() ); - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); packedSize += bufferOps::Pack< DO_PACKING >( buffer, rank ); localIndex const numPackedIndices = packList.size(); @@ -522,7 +534,7 @@ localIndex ObjectManagerBase::packGlobalMapsImpl( buffer_unit_type * & buffer, arrayView1d< localIndex const > const & packList, integer const recursive ) const { - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); localIndex packedSize = bufferOps::Pack< DO_PACKING >( buffer, this->getName() ); @@ -584,7 +596,7 @@ localIndex ObjectManagerBase::unpackGlobalMaps( buffer_unit_type const * & buffe integer const recursive ) { GEOS_MARK_FUNCTION; - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); localIndex unpackedSize = 0; string groupName; @@ -857,7 +869,7 @@ void ObjectManagerBase::eraseObject( std::set< localIndex > const & indicesToEra void ObjectManagerBase::setMaxGlobalIndex() { - m_maxGlobalIndex = MpiWrapper::max( m_localMaxGlobalIndex, MPI_COMM_GEOSX ); + m_maxGlobalIndex = MpiWrapper::max( m_localMaxGlobalIndex, MPI_COMM_GEOS ); } void ObjectManagerBase::cleanUpMap( std::set< localIndex > const & targetIndices, diff --git a/src/coreComponents/mesh/ObjectManagerBase.hpp b/src/coreComponents/mesh/ObjectManagerBase.hpp index a85e87afa3f..1ac1297ed26 100644 --- a/src/coreComponents/mesh/ObjectManagerBase.hpp +++ b/src/coreComponents/mesh/ObjectManagerBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -684,6 +685,12 @@ class ObjectManagerBase : public dataRepository::Group /// @return String key to the local->global map static constexpr char const * localToGlobalMapString() { return "localToGlobalMap"; } + /// @return String key for m_localMaxGlobalIndexString + static constexpr char const * localMaxGlobalIndexString() { return "localMaxGlobalIndex"; } + + /// @return String key for m_maxGlobalIndexString + static constexpr char const * maxGlobalIndexString() { return "maxGlobalIndex"; } + /// View key to external set dataRepository::ViewKey externalSet = { externalSetString() }; @@ -923,6 +930,15 @@ class ObjectManagerBase : public dataRepository::Group return m_domainBoundaryIndicator.toViewConst(); } + /** + * @brief Function to output connectivity in order to assist debugging issues + * with object connectivity. + */ + virtual void outputObjectConnectivity() const + { + GEOS_ERROR( "Called outputObjectConnectivity in ObjectManagerBase. Function should be implemented." ); + } + protected: /// Group that holds object sets. Group m_sets; @@ -994,7 +1010,10 @@ void ObjectManagerBase::fixUpDownMaps( TYPE_RELATION & relation, allValuesMapped = false; } } - GEOS_ERROR_IF( relation[li][a] == unmappedLocalIndexValue, "Index not set" ); + // temporarily disabled this check to allow for the case where the index is not set + // this entire fixUpDownMaps will be removed in a future PR as the unpacking is modified + // s.t. there are no invalid unpacked values that are not expected. + //GEOS_ERROR_IF( relation[li][a] == unmappedLocalIndexValue, "Index not set" ); } } GEOS_ERROR_IF( !allValuesMapped, "some values of unmappedIndices were not used" ); diff --git a/src/coreComponents/mesh/ParticleManager.cpp b/src/coreComponents/mesh/ParticleManager.cpp index 0bbf3919cf1..314c23120b4 100644 --- a/src/coreComponents/mesh/ParticleManager.cpp +++ b/src/coreComponents/mesh/ParticleManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -80,14 +81,14 @@ void ParticleManager::setMaxGlobalIndex() &m_maxGlobalIndex, 1, MPI_MAX, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); } Group * ParticleManager::createChild( string const & childKey, string const & childName ) { GEOS_ERROR_IF( !(CatalogInterface::hasKeyName( childKey )), "KeyName ("<getGroup( ParticleManager::groupKeyStruct::particleRegionsGroup() ); return &particleRegions.registerGroup( childName, diff --git a/src/coreComponents/mesh/ParticleManager.hpp b/src/coreComponents/mesh/ParticleManager.hpp index 0a6a8b58ddd..2af33a6eb76 100644 --- a/src/coreComponents/mesh/ParticleManager.hpp +++ b/src/coreComponents/mesh/ParticleManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,8 +17,8 @@ * @file ParticleManager.hpp */ -#ifndef GEOSX_MESH_PARTICLEREGIONMANAGER_HPP -#define GEOSX_MESH_PARTICLEREGIONMANAGER_HPP +#ifndef GEOS_MESH_PARTICLEREGIONMANAGER_HPP +#define GEOS_MESH_PARTICLEREGIONMANAGER_HPP #include "generators/ParticleBlock.hpp" #include "generators/ParticleBlockManager.hpp" @@ -1518,4 +1519,4 @@ ParticleManager::constructFullConstitutiveAccessor( constitutive::ConstitutiveMa } } -#endif /* GEOSX_MESH_PARTICLEREGIONMANAGER_HPP */ +#endif /* GEOS_MESH_PARTICLEREGIONMANAGER_HPP */ diff --git a/src/coreComponents/mesh/ParticleRegion.cpp b/src/coreComponents/mesh/ParticleRegion.cpp index 1204ee5295c..d79e35ade22 100644 --- a/src/coreComponents/mesh/ParticleRegion.cpp +++ b/src/coreComponents/mesh/ParticleRegion.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -48,7 +49,7 @@ void ParticleRegion::generateMesh( Group & particleBlocks ) subRegion.copyFromParticleBlock( source ); // Set the rank of particles on each subregion - int const mpiRank = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int const mpiRank = MpiWrapper::commRank( MPI_COMM_GEOS ); subRegion.setParticleRank( mpiRank ); // Set the number of vertices of the particles on each subregion diff --git a/src/coreComponents/mesh/ParticleRegion.hpp b/src/coreComponents/mesh/ParticleRegion.hpp index 8d1f6df1736..4967a043200 100644 --- a/src/coreComponents/mesh/ParticleRegion.hpp +++ b/src/coreComponents/mesh/ParticleRegion.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,8 +18,8 @@ * */ -#ifndef GEOSX_MESH_PARTICLEREGION_HPP_ -#define GEOSX_MESH_PARTICLEREGION_HPP_ +#ifndef GEOS_MESH_PARTICLEREGION_HPP_ +#define GEOS_MESH_PARTICLEREGION_HPP_ #include "ParticleRegionBase.hpp" @@ -132,4 +133,4 @@ class ParticleRegion : public ParticleRegionBase } /* namespace geos */ -#endif /* GEOSX_MESH_PARTICLEREGION_HPP_ */ +#endif /* GEOS_MESH_PARTICLEREGION_HPP_ */ diff --git a/src/coreComponents/mesh/ParticleRegionBase.cpp b/src/coreComponents/mesh/ParticleRegionBase.cpp index 3138b93d58d..8dff7c56f96 100644 --- a/src/coreComponents/mesh/ParticleRegionBase.cpp +++ b/src/coreComponents/mesh/ParticleRegionBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/ParticleRegionBase.hpp b/src/coreComponents/mesh/ParticleRegionBase.hpp index 817327eaffd..ae551db35ba 100644 --- a/src/coreComponents/mesh/ParticleRegionBase.hpp +++ b/src/coreComponents/mesh/ParticleRegionBase.hpp @@ -2,18 +2,19 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ -#ifndef GEOSX_MESH_PARTICLEREGIONBASE_HPP -#define GEOSX_MESH_PARTICLEREGIONBASE_HPP +#ifndef GEOS_MESH_PARTICLEREGIONBASE_HPP +#define GEOS_MESH_PARTICLEREGIONBASE_HPP #include "ParticleSubRegion.hpp" #include "mesh/ObjectManagerBase.hpp" @@ -350,4 +351,4 @@ string_array ParticleRegionBase::getConstitutiveNames() const -#endif /* GEOSX_MESH_PARTICLEREGIONBASE_HPP */ +#endif /* GEOS_MESH_PARTICLEREGIONBASE_HPP */ diff --git a/src/coreComponents/mesh/ParticleSubRegion.cpp b/src/coreComponents/mesh/ParticleSubRegion.cpp index 738dcc9b392..ea30521dc70 100644 --- a/src/coreComponents/mesh/ParticleSubRegion.cpp +++ b/src/coreComponents/mesh/ParticleSubRegion.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/ParticleSubRegion.hpp b/src/coreComponents/mesh/ParticleSubRegion.hpp index ccd113ad299..1f9111b43d9 100644 --- a/src/coreComponents/mesh/ParticleSubRegion.hpp +++ b/src/coreComponents/mesh/ParticleSubRegion.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -13,8 +14,8 @@ */ -#ifndef GEOSX_MESH_PARTICLEELEMENTSUBREGION_HPP_ -#define GEOSX_MESH_PARTICLEELEMENTSUBREGION_HPP_ +#ifndef GEOS_MESH_PARTICLEELEMENTSUBREGION_HPP_ +#define GEOS_MESH_PARTICLEELEMENTSUBREGION_HPP_ #include "mesh/generators/ParticleBlockABC.hpp" #include "mesh/utilities/ComputationalGeometry.hpp" @@ -141,4 +142,4 @@ class ParticleSubRegion : public ParticleSubRegionBase } /* namespace geos */ -#endif /* GEOSX_MESH_CELLELEMENTSUBREGION_HPP_ */ +#endif /* GEOS_MESH_CELLELEMENTSUBREGION_HPP_ */ diff --git a/src/coreComponents/mesh/ParticleSubRegionBase.cpp b/src/coreComponents/mesh/ParticleSubRegionBase.cpp index 6021839456c..829f1f4a376 100644 --- a/src/coreComponents/mesh/ParticleSubRegionBase.cpp +++ b/src/coreComponents/mesh/ParticleSubRegionBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -154,7 +155,7 @@ void ParticleSubRegionBase::setActiveParticleIndices() forAll< serialPolicy >( this->size(), [&, particleRank] GEOS_HOST ( localIndex const p ) // This must be on host since we're dealing with // a sorted array. Parallelize with atomics? { - if( particleRank[p] == MpiWrapper::commRank( MPI_COMM_GEOSX ) ) + if( particleRank[p] == MpiWrapper::commRank( MPI_COMM_GEOS ) ) { m_activeParticleIndices.insert( p ); } diff --git a/src/coreComponents/mesh/ParticleSubRegionBase.hpp b/src/coreComponents/mesh/ParticleSubRegionBase.hpp index 4db23951f57..b89af32a1ab 100644 --- a/src/coreComponents/mesh/ParticleSubRegionBase.hpp +++ b/src/coreComponents/mesh/ParticleSubRegionBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,8 +17,8 @@ * @file ParticleSubRegionBase.hpp */ -#ifndef GEOSX_MESH_PARTICLESUBREGIONBASE_HPP_ -#define GEOSX_MESH_PARTICLESUBREGIONBASE_HPP_ +#ifndef GEOS_MESH_PARTICLESUBREGIONBASE_HPP_ +#define GEOS_MESH_PARTICLESUBREGIONBASE_HPP_ #include "mesh/ParticleType.hpp" #include "mesh/ObjectManagerBase.hpp" @@ -483,4 +484,4 @@ class ParticleSubRegionBase : public ObjectManagerBase } /* namespace geos */ -#endif /* GEOSX_MESH_PARTICLESUBREGIONBASE_HPP_ */ +#endif /* GEOS_MESH_PARTICLESUBREGIONBASE_HPP_ */ diff --git a/src/coreComponents/mesh/ParticleType.hpp b/src/coreComponents/mesh/ParticleType.hpp index f39a6dd2559..3a61803ebcb 100644 --- a/src/coreComponents/mesh/ParticleType.hpp +++ b/src/coreComponents/mesh/ParticleType.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,10 +17,10 @@ * @file ParticleType.hpp */ -#ifndef GEOSX_MESH_PARTICLETYPE_HPP -#define GEOSX_MESH_PARTICLETYPE_HPP +#ifndef GEOS_MESH_PARTICLETYPE_HPP +#define GEOS_MESH_PARTICLETYPE_HPP -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" namespace geos { @@ -44,4 +45,4 @@ ENUM_STRINGS( ParticleType, } // namespace geos -#endif //GEOSX_MESH_PARTICLETYPE_HPP +#endif //GEOS_MESH_PARTICLETYPE_HPP diff --git a/src/coreComponents/mesh/Perforation.cpp b/src/coreComponents/mesh/Perforation.cpp index 7a02efbca2d..74ade6d4269 100644 --- a/src/coreComponents/mesh/Perforation.cpp +++ b/src/coreComponents/mesh/Perforation.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -48,7 +49,7 @@ Perforation::Perforation( string const & name, Group * const parent ) } -void Perforation::postProcessInput() +void Perforation::postInputInitialization() { GEOS_ERROR_IF( m_distanceFromHead <= 0, getWrapperDataContext( viewKeyStruct::distanceFromHeadString() ) << diff --git a/src/coreComponents/mesh/Perforation.hpp b/src/coreComponents/mesh/Perforation.hpp index f29d306479a..5a3a3ae8721 100644 --- a/src/coreComponents/mesh/Perforation.hpp +++ b/src/coreComponents/mesh/Perforation.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -126,7 +127,7 @@ class Perforation : public dataRepository::Group viewKeysPerforation; protected: - void postProcessInput() override; + void postInputInitialization() override; private: /// Linear distance from well head diff --git a/src/coreComponents/mesh/PerforationData.cpp b/src/coreComponents/mesh/PerforationData.cpp index e7453add682..4363c2ac1cb 100644 --- a/src/coreComponents/mesh/PerforationData.cpp +++ b/src/coreComponents/mesh/PerforationData.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -38,6 +39,8 @@ PerforationData::PerforationData( string const & name, Group * const parent ) registerField( fields::perforation::reservoirElementRegion{}, &m_toMeshElements.m_toElementRegion ); registerField( fields::perforation::reservoirElementSubRegion{}, &m_toMeshElements.m_toElementSubRegion ); registerField( fields::perforation::reservoirElementIndex{}, &m_toMeshElements.m_toElementIndex ); + registerField( fields::perforation::reservoirElementGlobalIndex{}, &m_reservoirElementGlobalIndex ); + registerField( fields::perforation::wellElementIndex{}, &m_wellElementIndex ); registerField( fields::perforation::location{}, &m_location ); registerField( fields::perforation::wellTransmissibility{}, &m_wellTransmissibility ); diff --git a/src/coreComponents/mesh/PerforationData.hpp b/src/coreComponents/mesh/PerforationData.hpp index 0c3a4828e03..1bc24f45a1f 100644 --- a/src/coreComponents/mesh/PerforationData.hpp +++ b/src/coreComponents/mesh/PerforationData.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -149,6 +150,20 @@ class PerforationData : public ObjectManagerBase */ arrayView1d< localIndex const > getWellElements() const { return m_wellElementIndex; } + /** + * @brief Get perforation-to-reservoir-element connectivity. + * @return list of global reservoir element index connected to each perforation + */ + arrayView1d< globalIndex > getReservoirElementGlobalIndex() { return m_reservoirElementGlobalIndex; } + + + + /** + * @brief Provide an immutable accessor to a const perforation-to-reservoir-element connectivity. + * @return list of well element index connected to each perforation + */ + arrayView1d< globalIndex const > getReservoirElementGlobalIndex() const { return m_reservoirElementGlobalIndex; } + /** * @brief Get perforation locations. @@ -274,6 +289,9 @@ class PerforationData : public ObjectManagerBase /// Indices of the well elements to which perforations are attached array1d< localIndex > m_wellElementIndex; + /// Global indices of reservoir cell containing perforation + array1d< globalIndex > m_reservoirElementGlobalIndex; + /// Location of the perforations array2d< real64 > m_location; diff --git a/src/coreComponents/mesh/PerforationFields.hpp b/src/coreComponents/mesh/PerforationFields.hpp index 43451e8ec04..b9438b1afd0 100644 --- a/src/coreComponents/mesh/PerforationFields.hpp +++ b/src/coreComponents/mesh/PerforationFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -57,6 +58,14 @@ DECLARE_FIELD( reservoirElementIndex, WRITE_AND_READ, "For each perforation, element index of the perforated element" ); +DECLARE_FIELD( reservoirElementGlobalIndex, + "reservoirElementGlobalIndex", + array1d< globalIndex >, + 0, + NOPLOT, + WRITE_AND_READ, + "For each perforation, global element index of the perforated element" ); + DECLARE_FIELD( wellElementIndex, "wellElementIndex", array1d< localIndex >, diff --git a/src/coreComponents/mesh/SurfaceElementRegion.cpp b/src/coreComponents/mesh/SurfaceElementRegion.cpp index 021e914310e..e6b47dbae4d 100644 --- a/src/coreComponents/mesh/SurfaceElementRegion.cpp +++ b/src/coreComponents/mesh/SurfaceElementRegion.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,6 +20,7 @@ #include "MeshFields.hpp" #include "EdgeManager.hpp" #include "SurfaceElementRegion.hpp" +#include "common/MpiWrapper.hpp" namespace geos @@ -74,9 +76,13 @@ void SurfaceElementRegion::generateMesh( Group const & faceBlocks ) void SurfaceElementRegion::initializePreSubGroups() { + GEOS_ERROR_IF_LE_MSG( m_defaultAperture, 0.0, + getWrapperDataContext( viewKeyStruct::defaultApertureString() ) << + ": default aperture must be larger than 0.0" ); + this->forElementSubRegions< SurfaceElementSubRegion >( [&] ( SurfaceElementSubRegion & subRegion ) { - subRegion.getWrapper< array1d< real64 > >( SurfaceElementSubRegion::viewKeyStruct::elementApertureString() ). + subRegion.getWrapper< array1d< real64 > >( fields::elementAperture::key() ). setApplyDefaultValue( m_defaultAperture ); } ); } @@ -101,11 +107,8 @@ localIndex SurfaceElementRegion::addToFractureMesh( real64 const time_np1, arrayView1d< real64 > const ruptureTime = subRegion.getField< fields::ruptureTime >(); - arrayView1d< real64 > const creationMass = subRegion.getReference< real64_array >( FaceElementSubRegion::viewKeyStruct::creationMassString() ); - arrayView2d< real64 const > const faceCenter = faceManager->faceCenter(); arrayView2d< real64 > const elemCenter = subRegion.getElementCenter(); - arrayView1d< real64 const > const elemArea = subRegion.getElementArea().toViewConst(); arrayView1d< integer > const subRegionGhostRank = subRegion.ghostRank(); @@ -122,7 +125,6 @@ localIndex SurfaceElementRegion::addToFractureMesh( real64 const time_np1, LvArray::tensorOps::copy< 3 >( elemCenter[ kfe ], faceCenter[ faceIndices[ 0 ] ] ); - faceMap.resizeArray( kfe, 2 ); faceMap[kfe][0] = faceIndices[0]; faceMap[kfe][1] = faceIndices[1]; @@ -166,19 +168,20 @@ localIndex SurfaceElementRegion::addToFractureMesh( real64 const time_np1, } // Add the cell region/subregion/index to the faceElementToCells map - OrderedVariableToManyElementRelation & faceElementsToCells = subRegion.getToCellRelation(); + FixedToManyElementRelation & faceElementsToCells = subRegion.getToCellRelation(); for( localIndex ke = 0; ke < 2; ++ke ) { - localIndex const & er = faceToElementRegion[faceIndices[ke]][ke]; - localIndex const & esr = faceToElementSubRegion[faceIndices[ke]][ke]; - localIndex const & ei = faceToElementIndex[faceIndices[ke]][ke]; + + localIndex const er = faceToElementRegion[faceIndices[ke]][ke]; + localIndex const esr = faceToElementSubRegion[faceIndices[ke]][ke]; + localIndex const ei = faceToElementIndex[faceIndices[ke]][ke]; if( er != -1 && esr != -1 && ei != -1 ) { - faceElementsToCells.m_toElementRegion.emplaceBack( kfe, er ); - faceElementsToCells.m_toElementSubRegion.emplaceBack( kfe, esr ); - faceElementsToCells.m_toElementIndex.emplaceBack( kfe, ei ); + faceElementsToCells.m_toElementRegion[kfe][ke] = er; + faceElementsToCells.m_toElementSubRegion[kfe][ke] = esr; + faceElementsToCells.m_toElementIndex[kfe][ke] = ei; } } @@ -207,14 +210,12 @@ localIndex SurfaceElementRegion::addToFractureMesh( real64 const time_np1, subRegion.calculateSingleElementGeometricQuantities( kfe, faceManager->faceArea() ); - creationMass[kfe] *= elemArea[kfe]; - // update the sets for( auto const & setIter : faceManager->sets().wrappers() ) { SortedArrayView< localIndex const > const & faceSet = faceManager->sets().getReference< SortedArray< localIndex > >( setIter.first ); SortedArray< localIndex > & faceElementSet = subRegion.sets().registerWrapper< SortedArray< localIndex > >( setIter.first ).reference(); - for( localIndex a = 0; a < faceMap.size(); ++a ) + for( localIndex a = 0; a < faceMap.size( 0 ); ++a ) { if( faceSet.count( faceMap[a][0] ) ) { diff --git a/src/coreComponents/mesh/SurfaceElementRegion.hpp b/src/coreComponents/mesh/SurfaceElementRegion.hpp index c00ea71af46..f15de2d63f6 100644 --- a/src/coreComponents/mesh/SurfaceElementRegion.hpp +++ b/src/coreComponents/mesh/SurfaceElementRegion.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,7 +22,7 @@ #define GEOS_MESH_SURFACEELEMENTREGION_HPP_ #include "ElementRegionBase.hpp" -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" namespace geos { diff --git a/src/coreComponents/mesh/SurfaceElementSubRegion.cpp b/src/coreComponents/mesh/SurfaceElementSubRegion.cpp index 8261deb0bae..3b371106393 100644 --- a/src/coreComponents/mesh/SurfaceElementSubRegion.cpp +++ b/src/coreComponents/mesh/SurfaceElementSubRegion.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,6 +21,7 @@ #include "SurfaceElementSubRegion.hpp" #include "ElementRegionManager.hpp" +#include "MeshFields.hpp" namespace geos { @@ -29,12 +31,14 @@ using namespace dataRepository; SurfaceElementSubRegion::SurfaceElementSubRegion( string const & name, dataRepository::Group * const parent ): ElementSubRegionBase( name, parent ), - m_2dElemToElems(), m_unmappedGlobalIndicesInToNodes(), m_toNodesRelation(), m_toEdgesRelation(), m_elementAperture(), - m_elementArea() + m_elementArea(), + m_normalVector(), + m_tangentVector1(), + m_tangentVector2() { registerWrapper( viewKeyStruct::nodeListString(), &m_toNodesRelation ). setDescription( "Map to the nodes attached to each SurfaceElement." ); @@ -42,32 +46,18 @@ SurfaceElementSubRegion::SurfaceElementSubRegion( string const & name, registerWrapper( viewKeyStruct::edgeListString(), &m_toEdgesRelation ). setDescription( "Map to the edges attached to each SurfaceElement." ); - registerWrapper( viewKeyStruct::surfaceElementsToCellRegionsString(), &m_2dElemToElems.m_toElementRegion ). - setPlotLevel( PlotLevel::NOPLOT ). - setDescription( "A map of face element local indices to the cell local indices" ); + registerField( fields::elementAperture{}, &m_elementAperture ); - registerWrapper( viewKeyStruct::surfaceElementsToCellSubRegionsString(), &m_2dElemToElems.m_toElementSubRegion ). - setPlotLevel( PlotLevel::NOPLOT ). - setDescription( "A map of face element local indices to the cell local indices" ); + registerField( fields::elementArea{}, &m_elementArea ); - registerWrapper( viewKeyStruct::surfaceElementsToCellIndexString(), &m_2dElemToElems.m_toElementIndex ). - setPlotLevel( PlotLevel::NOPLOT ). - setDescription( "A map of face element local indices to the cell local indices" ); + registerField( fields::normalVector{}, &m_normalVector ). + reference().resizeDimension< 1 >( 3 ); - registerWrapper( viewKeyStruct::elementApertureString(), &m_elementAperture ). - setApplyDefaultValue( 1.0e-5 ). - setPlotLevel( dataRepository::PlotLevel::LEVEL_0 ). - setDescription( "The aperture of each SurfaceElement." ); + registerField( fields::tangentVector1{}, &m_tangentVector1 ). + reference().resizeDimension< 1 >( 3 ); - registerWrapper( viewKeyStruct::elementAreaString(), &m_elementArea ). - setApplyDefaultValue( -1.0 ). - setPlotLevel( dataRepository::PlotLevel::LEVEL_2 ). - setDescription( "The area of each SurfaceElement." ); - - registerWrapper< real64_array >( viewKeyStruct::creationMassString() ). - setApplyDefaultValue( 0.0 ). - setPlotLevel( dataRepository::PlotLevel::LEVEL_1 ). - setDescription( "The amount of remaining mass that was introduced when the SurfaceElement was created." ); + registerField( fields::tangentVector2{}, &m_tangentVector2 ). + reference().resizeDimension< 1 >( 3 ); excludeWrappersFromPacking( { viewKeyStruct::nodeListString(), viewKeyStruct::edgeListString(), @@ -75,8 +65,6 @@ SurfaceElementSubRegion::SurfaceElementSubRegion( string const & name, viewKeyStruct::surfaceElementsToCellSubRegionsString(), viewKeyStruct::surfaceElementsToCellIndexString() } ); - // TODO there has to be a cleaner way than this. - m_2dElemToElems.setElementRegionManager( dynamicCast< ElementRegionManager & >( getParent().getParent().getParent().getParent() ) ); } diff --git a/src/coreComponents/mesh/SurfaceElementSubRegion.hpp b/src/coreComponents/mesh/SurfaceElementSubRegion.hpp index df5f199524e..f2c367b475d 100644 --- a/src/coreComponents/mesh/SurfaceElementSubRegion.hpp +++ b/src/coreComponents/mesh/SurfaceElementSubRegion.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -32,7 +33,7 @@ namespace geos * @class SurfaceElementSubRegion * * The SurfaceElementSubRegion class contains the functionality to support the concept of a - * surface element that can be either and embedded surface element or a face element. + * surface element that can be either and surface element or a face element. */ class SurfaceElementSubRegion : public ElementSubRegionBase { @@ -153,23 +154,6 @@ class SurfaceElementSubRegion : public ElementSubRegionBase localIndex numNodesPerElement( localIndex const k ) const final { return m_toNodesRelation[k].size(); } - /** - * @brief Get the surface element to cells map. - * @return The surface element to cells map - */ - OrderedVariableToManyElementRelation & getToCellRelation() - { - return m_2dElemToElems; - } - - /** - * @copydoc getToCellRelation() - */ - OrderedVariableToManyElementRelation const & getToCellRelation() const - { - return m_2dElemToElems; - } - ///@} @@ -201,10 +185,68 @@ class SurfaceElementSubRegion : public ElementSubRegionBase */ arrayView1d< real64 const > getElementArea() const { return m_elementArea; } + /** + * @brief Const accessor to the normal vectors. + * @return a const view to the array of normal vectors. + */ + arrayView2d< real64 const > getNormalVector() const { return m_normalVector; } + + /** + * @brief Non const accessor to the normal vectors. + * @return a non const view to the array of normal vectors. + */ + arrayView2d< real64 > getNormalVector() { return m_normalVector; } + + /** + * @brief Get normal vector of a specific surface element. + * @param k index of the surface element + * @return the normal vector of a specific surface element + */ + arraySlice1d< real64 const > getNormalVector( localIndex k ) const { return m_normalVector[k]; } + + /** + * @brief Get an array of the first tangent vector of the surface elements. + * @return an array of the first tangent vector of the surface elements + */ + arrayView2d< real64 const > getTangentVector1() const { return m_tangentVector1; } + + /** + * @brief Get an array of the first tangent vector of the surface elements. + * @return a non const view to the array of the first tangent vector of the surface elements + */ + arrayView2d< real64 > getTangentVector1() { return m_tangentVector1; } + + /** + * @brief Get the first tangent vector of a specific surface element. + * @param k index of the surface element + * @return the first tangent vector of a specific surface element + */ + arraySlice1d< real64 const > getTangentVector1( localIndex const k ) const { return m_tangentVector1[k]; } + + /** + * @brief Get an array of the second tangent vector of the surface elements. + * @return aconst view to the array of the second tangent vector of the surface elements + */ + arrayView2d< real64 const > getTangentVector2() const { return m_tangentVector2.toViewConst(); } + + /** + * @brief Get an array of the first tangent vector of the surface elements. + * @return a non const view to the array of the second tangent vector of the surface elements + */ + arrayView2d< real64 > getTangentVector2() { return m_tangentVector2; } + + /** + * @brief Get the second tangent vector of a specific surface element. + * @param k index of the surface element + * @return the second tangent vector of a specific surface element + */ + arraySlice1d< real64 const > getTangentVector2( localIndex const k ) const { return m_tangentVector2[k];} + + ///@} /** - * @brief Struct containing the keys to all embedded surface element views. + * @brief Struct containing the keys to all surface element views. * @struct viewKeyStruct */ struct viewKeyStruct : ElementSubRegionBase::viewKeyStruct @@ -218,25 +260,12 @@ class SurfaceElementSubRegion : public ElementSubRegionBase /// @return Face element to cell indices map string. static constexpr char const * surfaceElementsToCellIndexString() { return "fractureElementsToCellIndices"; } - - /// @return Embedded surface element aperture string - static constexpr char const * elementApertureString() { return "elementAperture"; } - - /// @return Embedded surface element surface are string - static constexpr char const * elementAreaString() { return "elementArea"; } - - /// @return Mass creation string. - constexpr static char const * creationMassString() { return "creationMass"; } - - /// @return embedded surface element to parent plane string. + /// @return surface element to parent plane string. constexpr static char const * surfaceElementToParentPlaneString() { return "surfaceElementToParentPlane"; } }; protected: - /// Map between the surface elements and the cells - OrderedVariableToManyElementRelation m_2dElemToElems; - /// Unmapped surface elements to nodes map map< localIndex, array1d< globalIndex > > m_unmappedGlobalIndicesInToNodes; @@ -252,6 +281,15 @@ class SurfaceElementSubRegion : public ElementSubRegionBase /// Member level field for the element center array1d< real64 > m_elementArea; + /// Normal vector to the surface element + array2d< real64 > m_normalVector; + + /// Unit vector indicating the first tangential direction + array2d< real64 > m_tangentVector1; + + /// Unit vector indicating the second tangential direction + array2d< real64 > m_tangentVector2; + }; } /* namespace geos */ diff --git a/src/coreComponents/mesh/ToElementRelation.cpp b/src/coreComponents/mesh/ToElementRelation.cpp index dda022be675..2e657bb51d4 100644 --- a/src/coreComponents/mesh/ToElementRelation.cpp +++ b/src/coreComponents/mesh/ToElementRelation.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/ToElementRelation.hpp b/src/coreComponents/mesh/ToElementRelation.hpp index 458b681c66e..097b58faea5 100644 --- a/src/coreComponents/mesh/ToElementRelation.hpp +++ b/src/coreComponents/mesh/ToElementRelation.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/ToParticleRelation.cpp b/src/coreComponents/mesh/ToParticleRelation.cpp index 4d402251253..78989d32479 100644 --- a/src/coreComponents/mesh/ToParticleRelation.cpp +++ b/src/coreComponents/mesh/ToParticleRelation.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/ToParticleRelation.hpp b/src/coreComponents/mesh/ToParticleRelation.hpp index 6e32a26dd88..f9e0e540d40 100644 --- a/src/coreComponents/mesh/ToParticleRelation.hpp +++ b/src/coreComponents/mesh/ToParticleRelation.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,8 +17,8 @@ * @file ToParticleRelation.hpp */ -#ifndef GEOSX_MESH_TOPARTICLERELATION_HPP_ -#define GEOSX_MESH_TOPARTICLERELATION_HPP_ +#ifndef GEOS_MESH_TOPARTICLERELATION_HPP_ +#define GEOS_MESH_TOPARTICLERELATION_HPP_ #include "InterObjectRelation.hpp" @@ -185,4 +186,4 @@ void reserveNeighbors( OrderedVariableToManyParticleRelation & relation, } /* namespace geos */ -#endif /* GEOSX_MESH_TOPARTICLERELATION_HPP_ */ +#endif /* GEOS_MESH_TOPARTICLERELATION_HPP_ */ diff --git a/src/coreComponents/mesh/WellElementRegion.cpp b/src/coreComponents/mesh/WellElementRegion.cpp index 00e53298651..ec70f49d042 100644 --- a/src/coreComponents/mesh/WellElementRegion.cpp +++ b/src/coreComponents/mesh/WellElementRegion.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/WellElementRegion.hpp b/src/coreComponents/mesh/WellElementRegion.hpp index c3416030931..5a41cf19526 100644 --- a/src/coreComponents/mesh/WellElementRegion.hpp +++ b/src/coreComponents/mesh/WellElementRegion.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/WellElementSubRegion.cpp b/src/coreComponents/mesh/WellElementSubRegion.cpp index f6046b802c4..cd8d5cde24f 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.cpp +++ b/src/coreComponents/mesh/WellElementSubRegion.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -147,6 +148,7 @@ void collectElementNodes( CellElementSubRegion const & subRegion, * @param[inout] erMatched the region index of the reservoir element that contains "location", if any * @param[inout] esrMatched the subregion index of the reservoir element that contains "location", if any * @param[inout] eiMatched the element index of the reservoir element that contains "location", if any + * @param[inout] giMatched the element global index of the reservoir element that contains "location", if any */ bool visitNeighborElements( MeshLevel const & mesh, real64 const (&location)[3], @@ -154,7 +156,8 @@ bool visitNeighborElements( MeshLevel const & mesh, SortedArray< globalIndex > & elements, localIndex & erMatched, localIndex & esrMatched, - localIndex & eiMatched ) + localIndex & eiMatched, + globalIndex & giMatched ) { ElementRegionManager const & elemManager = mesh.getElemManager(); NodeManager const & nodeManager = mesh.getNodeManager(); @@ -163,7 +166,6 @@ bool visitNeighborElements( MeshLevel const & mesh, ArrayOfArraysView< localIndex const > const & toElementRegionList = nodeManager.elementRegionList(); ArrayOfArraysView< localIndex const > const & toElementSubRegionList = nodeManager.elementSubRegionList(); ArrayOfArraysView< localIndex const > const & toElementList = nodeManager.elementList(); - arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const referencePosition = nodeManager.referencePosition().toViewConst(); @@ -182,7 +184,7 @@ bool visitNeighborElements( MeshLevel const & mesh, // that contains only the nodes that have already been visited // the newly added nodes will be added to "nodes" SortedArray< localIndex > currNodes = nodes; - + giMatched = -1; // for all the nodes already visited for( localIndex currNode : currNodes ) { @@ -192,7 +194,6 @@ bool visitNeighborElements( MeshLevel const & mesh, localIndex const er = toElementRegionList[currNode][b]; localIndex const esr = toElementSubRegionList[currNode][b]; localIndex const eiLocal = toElementList[currNode][b]; - CellElementRegion const & region = elemManager.getRegion< CellElementRegion >( er ); CellElementSubRegion const & subRegion = region.getSubRegion< CellElementSubRegion >( esr ); arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList(); @@ -220,6 +221,7 @@ bool visitNeighborElements( MeshLevel const & mesh, erMatched = er; esrMatched = esr; eiMatched = eiLocal; + giMatched = eiGlobal; matched = true; break; } @@ -291,6 +293,7 @@ void initializeLocalSearch( MeshLevel const & mesh, * @param[inout] erMatched the region index of the reservoir element that contains "location", if any * @param[inout] esrMatched the subregion index of the reservoir element that contains "location", if any * @param[inout] eiMatched the element index of the reservoir element that contains "location", if any + * @param[inout] giMatched the element global index of the reservoir element that contains "location", if any */ bool searchLocalElements( MeshLevel const & mesh, real64 const (&location)[3], @@ -300,7 +303,8 @@ bool searchLocalElements( MeshLevel const & mesh, localIndex const & eiInit, localIndex & erMatched, localIndex & esrMatched, - localIndex & eiMatched ) + localIndex & eiMatched, + globalIndex & giMatched ) { // search locally, starting from the location of the previous perforation // the assumption here is that perforations have been entered in order of depth @@ -323,7 +327,6 @@ bool searchLocalElements( MeshLevel const & mesh, // collect the nodes of the current element // they will be used to access the neighbors and check if they contain the perforation collectElementNodes( subRegion, eiInit, nodes ); - // if no match is found, enlarge the neighborhood m_searchDepth'th times for( localIndex d = 0; d < searchDepth; ++d ) { @@ -333,7 +336,7 @@ bool searchLocalElements( MeshLevel const & mesh, // stop if a reservoir element containing the perforation is found // if not, enlarge the set "nodes" resElemFound = visitNeighborElements( mesh, location, nodes, elements, - erMatched, esrMatched, eiMatched ); + erMatched, esrMatched, eiMatched, giMatched ); if( resElemFound || nNodes == nodes.size()) { break; @@ -432,6 +435,14 @@ void WellElementSubRegion::generate( MeshLevel & mesh, // this assumes that the elemToNodes maps has been filled at Step 5) updateNodeManagerNodeToElementMap( mesh ); + // Store local to global index mapping + integer n_localElems = localElems.size(); + m_globalWellElementIndex.resize( n_localElems ); + for( integer i=0; i 0) { // remove the duplicate elements - if( MpiWrapper::commRank( MPI_COMM_GEOSX ) == iownerRank ) + if( MpiWrapper::commRank( MPI_COMM_GEOS ) == iownerRank ) { localElems.remove( iwelemGlobal ); } @@ -778,6 +790,7 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, localIndex erInit = -1; localIndex esrInit = -1; localIndex eiInit = -1; + globalIndex giMatched = -1; // for each perforation, we have to find the reservoir element that contains the perforation @@ -792,7 +805,7 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, // to do that, we loop over the reservoir elements that are in the neighborhood of (erInit,esrInit,eiInit) bool resElemFound = searchLocalElements( mesh, location, m_searchDepth, erInit, esrInit, eiInit, - erMatched, esrMatched, eiMatched ); + erMatched, esrMatched, eiMatched, giMatched ); // if the element was found if( resElemFound ) @@ -801,6 +814,7 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, m_perforationData.getMeshElements().m_toElementRegion[iperfLocal] = erMatched; m_perforationData.getMeshElements().m_toElementSubRegion[iperfLocal] = esrMatched; m_perforationData.getMeshElements().m_toElementIndex[iperfLocal] = eiMatched; + m_perforationData.getReservoirElementGlobalIndex()[iperfLocal] = giMatched; // construct the local wellTransmissibility and location maps m_perforationData.getWellTransmissibility()[iperfLocal] = perfWellTransmissibilityGlobal[iperfGlobal]; @@ -845,7 +859,7 @@ void WellElementSubRegion::reconstructLocalConnectivity() bool WellElementSubRegion::isLocallyOwned() const { - return m_topRank == MpiWrapper::commRank( MPI_COMM_GEOSX ); + return m_topRank == MpiWrapper::commRank( MPI_COMM_GEOS ); } diff --git a/src/coreComponents/mesh/WellElementSubRegion.hpp b/src/coreComponents/mesh/WellElementSubRegion.hpp index 9155ed79139..9abc515064b 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.hpp +++ b/src/coreComponents/mesh/WellElementSubRegion.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -126,6 +127,14 @@ class WellElementSubRegion : public ElementSubRegionBase return m_topWellElementIndex; } + /** + * @brief Get for the top element index. + * @return local index of well's top element or -1 if it is not on current rank + */ + arrayView1d< globalIndex const > getGlobalWellElementIndex() const + { + return m_globalWellElementIndex; + } /** * @brief Set the name of the WellControls object of this well. * @param[in] name the name of the WellControls object @@ -393,6 +402,9 @@ class WellElementSubRegion : public ElementSubRegionBase /// Element-to-node relation is one to one relation. NodeMapType m_toNodesRelation; + /// Local indices of the next well element (used in solvers) + array1d< globalIndex > m_globalWellElementIndex; + /// Local indices of the next well element (used in solvers) array1d< localIndex > m_nextWellElementIndex; diff --git a/src/coreComponents/mesh/docs/Mesh.rst b/src/coreComponents/mesh/docs/Mesh.rst index d4231f7ac20..829d4a9a59d 100644 --- a/src/coreComponents/mesh/docs/Mesh.rst +++ b/src/coreComponents/mesh/docs/Mesh.rst @@ -23,7 +23,7 @@ Basic Example The Internal Mesh Generator allows one to quickly build simple cartesian grids and divide them into several regions. The following attributes are supported in the input block for InternalMesh: -.. include:: /coreComponents/schema/docs/InternalMesh.rst +.. include:: /docs/sphinx/datastructure/InternalMesh.rst The following is an example XML ```` block, which will generate a vertical beam with two ``CellBlocks`` (one in red and one in blue in the following picture). @@ -32,14 +32,14 @@ The following is an example XML ```` block, which will generate a vertical + elementTypes="{ C3D8 }" + xCoords="{ 0, 1 }" + yCoords="{ 0, 1 }" + zCoords="{ 0, 2, 6 }" + nx="{ 1 }" + ny="{ 1 }" + nz="{ 2, 4 }" + cellBlockNames="{ cb1, cb2 }"/> - ``name`` the name of the mesh body @@ -121,15 +121,18 @@ with the following code. nx="{5, 5}" ny="{5, 5}" nz="{3, 3, 3, 3}" - cellBlockNames="{b00,b01,b02,b03,b04,b05,b06,b07,b08,b09,b10,b11,b12,b13,b14,b15}"/> + cellBlockNames="{cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, + cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1, + cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2, + cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3}"/> @@ -139,6 +142,7 @@ Thus, the generated mesh will be : :align: center :width: 500 +Note that ``CellBlocks`` are ordered following the natural IJK logic, with indices increasing first in I (x-direction), then in J (y-direction) and last in K (z-direction). .. _ExternalMeshUsage: @@ -164,7 +168,7 @@ The supported mesh elements for volume elements consist of the following: The mesh can be divided in several regions. These regions are intended to support different physics or to define different constitutive properties. -We usually use the ``attribute`` field is usually considered to define the regions. +By default, we use the ``attribute`` field to define the regions. .. _ImportingExternalMesh: @@ -175,7 +179,7 @@ Importing regions ***************** Several blocks are involved to import an external mesh into GEOS, defined in the XML input file. -These are the ```` block and the ```` block. +These are the ```` block and the ```` block. The mesh block has the following syntax: @@ -185,65 +189,108 @@ The mesh block has the following syntax: + file="/path/to/the/mesh/file.vtk" + regionAttribute="myAttribute" /> -We advise users to use absolute path to the mesh file, and strongly recommend the use of a logLevel -of 1 or more to obtain some information about the mesh import. This information contains for -example the list of regions that are imported with their names, which is particularly useful to -fill the ``cellBlocks`` field of the ``ElementRegions`` block (see below). Some information about the -imported surfaces is also provided. +..note:: + We advise users to use absolute path to the mesh file, and recommend the use of a ``logLevel`` + of 1 or more to obtain some information about the mesh import, including the list of regions that + are imported with their names, which is particularly useful to fill the field of the + ``CellElementRegions`` block (see below). Some information about the imported surfaces is also provided. -GEOS uses ``ElementRegions`` to support different physics -or to define different constitutive properties. -The ``ElementRegions`` block can contain several ``CellElementRegion`` blocks. A ``CellElementRegion`` is defined as a set of ``CellBlocks``. -A ``CellBlock`` is an ensemble of elements with the same element geometry. +GEOS uses ``ElementRegions`` to support different physics or to define different constitutive properties. +The ``ElementRegions`` block can contain several ``CellElementRegion`` blocks. A ``CellElementRegion`` +is defined as a set of cell-blocks, which are sets of elements with the same element +geometry, defined within the ``cellBlocks`` attribute. + +The naming of cell-blocks depends on if the mesh contains a data array which has the +same value as the ``regionAttribute`` of the ``VTKMesh`` (which is ``attribute`` by default). +This attribute is used to define regions in the vtu file and assign the cells to a given region. -The naming of the imported ``cellBlocks`` depends on whether the data array called ``regionAttribute`` is -present in the vtu file or not. This data array is used to define regions in the vtu file and -assign the cells to a given region. The ``regionAttribute`` is a integer and not a string -(unfortunately). +For now, loaded regions has the following limitations: +- The ``regionAttribute`` can only refer to integer values (no texts), +- Each element can belong to only one region. .. figure:: mesh_multi.png :align: center :width: 500 -In the example presented above, the mesh is is composed of two regions (*Top* and *Bot*). -Each region contains 4 ``cellBlocks``. +In GEOS, there are three different ways to select ``cellBlocks`` in a ``CellElementRegion``: -- If the vtu file does not contain ``regionAttribute``, then all the cells are grouped in a single - region, and the cell block names are just constructed from the cell types (hexahedra, wedges, - tetrahedra, etc). Then in the exemple above, the ``ElementRegions`` can be defined as bellow: +- Using a list of the desired ``regionAttribute`` values. + I.e. ``"{ 1, 2 }"`` selects all the cell-blocks of the ``regionAttribute`` 1 and 2. -.. code-block:: xml +- Using a list of the exact cell-blocks names from the mesh to contain in this CellElementRegion. + I.e. ``{ 1_tetrahedra, 1_pyramid, 1_hexahedra, 2_tetrahedra, 2_pyramid, 2_hexahedra }`` - - - +- Using a list of `fnmatch patterns `_ to match cell-block names to add them in this ``CellElementRegion``. + I.e. ``{ * }`` selects every elements, ``{ 1_* }`` selects the ``{ 1_tetrahedra, 1_pyramid, 1_hexahedra }`` cell-blocks. + +In the example presented above, the mesh is is composed of two regions. Each region contains 4 element types. + +- If the vtu file contains an attribute equals to the ``regionAttribute`` of the ``VTKMesh``, + then all ``cellBlock`` are named with this convention: ``regionAttribute_elementType``. Let's assume that + the top region of the exemple above has ``myAttribute`` to 1, and that the bottom region has ``myAttribute`` to 2, -- If the vtu file contains ``regionAttribute``, then the cells are grouped by regions based on their - individual (numeric) ``regionAttribute``. In that case, the naming convention for the ``cellBlocks`` is - ``regionAttribute_elementType``. Let's assume that the top region of the exemple above is identified - by the ``regionAttribute`` 1, and that the bottom region is identified with 2, - * If we want the ``CellElementRegion`` to contain all the cells, we write: .. code-block:: xml + + + + + + - * If we want two CellElementRegion with the top and bottom regions separated, we write: + + + + + + * If we want two ``CellElementRegion`` with the top and bottom regions separated, we write: .. code-block:: xml + + + + + + + + + + + + + +- If the vtu file does not contain any region attribute field, then all the cells are grouped in a single + region, and cellBlock names consist of just the cell types (hexahedra, wedges, tetrahedra, etc). + Then in the exemple above, the ``ElementRegions`` can be defined as bellow: + +.. code-block:: xml + + + + + + + + + + + + + + + + .. warning:: - We remind the user that **all** the imported ``cellBlocks`` must be included in one of the - ``CellElementRegion``. Even if some cells are meant to be inactive during the simulation, - they still have to be included in a ``CellElementRegion`` (this ``CellElementRegion`` should + **All** the imported ``cellBlocks`` must be included in one (and only one) of the ``CellElementRegion``. + Even if some cells are meant to be inactive during the simulation, they still have to be + included in a ``CellElementRegion`` (this ``CellElementRegion`` should simply not be included as a targetRegion of any of the solvers involved in the simulation). -The keywords for the ``cellBlocks`` element types are : +The ``cellBlocks`` element types are : - `hexahedra `_ - `tetrahedra `_ @@ -282,22 +359,26 @@ An example of a ``vtk`` file with all the physical regions defined is used in :r Importing surfaces ****************** -Surfaces are imported through point sets in GEOS. This feature is supported using only the ``vtk`` file format. -In the same way than the regions, the surfaces of interests can be defined using the `physical entity names`_. -The surfaces are automatically import in GEOS if they exist in the ``vtk`` file. +Surfaces are imported through point sets in GEOS. This feature is only supported using the ``vtk`` file format. +In the same way than the regions, the surfaces of interests can be defined using the `physical entity names`. +The surfaces are automatically imported in GEOS if they exist in the ``vtk`` file. Within GEOS, the point set will have the same name than the one given in the file. This name can be used -again to impose boundary condition. For instance, if a surface is named "Bottom" and the user wants to -impose a Dirichlet boundary condition of 0 on it, it can be easily done using this syntax. +again to impose boundary condition. + +For instance, if a surface is named "Bottom" and the user wants to +impose a Dirichlet boundary condition of 0 on it, it can be easily done using this syntax: .. code-block:: xml - + + + The name of the surface of interest appears under the keyword ``setNames``. Again, an example of a ``vtk`` file with the surfaces fully defined is available within :ref:`TutorialFieldCase` or :ref:`ExampleIsothermalHystInjection`. diff --git a/src/coreComponents/mesh/docs/meshDeveloperGuide.rst b/src/coreComponents/mesh/docs/meshDeveloperGuide.rst index c0ba2ca9598..5145efa3f95 100644 --- a/src/coreComponents/mesh/docs/meshDeveloperGuide.rst +++ b/src/coreComponents/mesh/docs/meshDeveloperGuide.rst @@ -30,7 +30,7 @@ regions (Top and Bottom) (:numref:`modelMeshDevFig`). DomainPartition =============== -In :numref:`MeshObjectInstantiationHierarchy` the top level object ``DomainPartition`` represents +In :numref:`diagMeshDevFig` the top level object ``DomainPartition`` represents a partition of the decomposed physical domain. At this time there is a unique ``DomainPartition`` for every MPI rank. @@ -135,3 +135,13 @@ tetrahedra, one for all hexahedra, one for all wedges and one for all the pyrami Now that all the classes of the mesh hierarchy has been described, we propose to adapt the diagram presented in :numref:`diagMeshDevFig` to match with the example presented in :numref:`modelMeshDevFig`. + +Direct links to some useful class documentation: + +`ObjectManagerBase API <../../../doxygen_output/html/classgeos_1_1_object_manager_base.html>`_ + +`MeshLevel API <../../../doxygen_output/html/classgeos_1_1_mesh_level.html>`_ + +`NodeManager API <../../../doxygen_output/html/classgeos_1_1_node_manager.html>`_ + +`FaceManager API <../../../doxygen_output/html/classgeos_1_1_face_manager.html>`_ diff --git a/src/coreComponents/mesh/docs/staircase.svg b/src/coreComponents/mesh/docs/staircase.svg index bda6f11f955..4a5dffd595d 100644 --- a/src/coreComponents/mesh/docs/staircase.svg +++ b/src/coreComponents/mesh/docs/staircase.svg @@ -2,24 +2,24 @@ + inkscape:export-ydpi="96" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + inkscape:object-paths="true" + inkscape:showpageshadow="2" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" /> @@ -55,7 +58,7 @@ image/svg+xml - + @@ -1611,263 +1614,280 @@ transform="translate(433.05483,92.624135)"> b00 + sodipodi:role="line">cb_0-0-0 b01 + sodipodi:role="line">cb_0-0-1 b02 - b07 + sodipodi:role="line">cb_0-0-2 b03 - cb_0-0-3 + b08 - cb_1-0-0 + b09 - cb_1-0-1 + b10 - cb_1-0-2 + b11 + sodipodi:role="line" + id="tspan1275-0" + x="-237.57898" + y="16.654467" + style="stroke-width:0.264583">cb_1-0-3 b03 + sodipodi:role="line">cb_0-0-3 b08 - cb_1-0-0 + b09 - cb_1-0-1 + b10 - cb_1-0-2 + b11 + inkscape:export-ydpi="96" + transform="skewY(-40)">cb_1-0-3 + cb_1-1-0 + cb_1-1-1 + cb_1-1-2 + cb_1-1-3 b11 + style="stroke-width:0.264583">cb_1-0-3 b12 + style="stroke-width:0.264583" + y="-66.60495" + x="-256.42575" + id="tspan1311-8" + sodipodi:role="line">cb_0-1-3 b13 + id="tspan1331-0" + x="-165.55382" + y="-66.60495" + style="stroke-width:0.264583">cb_1-1-3 b14 - b15 - b15 + id="tspan1" + style="stroke-width:0.264583" /> diff --git a/src/coreComponents/mesh/generators/CellBlock.cpp b/src/coreComponents/mesh/generators/CellBlock.cpp index 91aea8b2c2f..cd60545c5e9 100644 --- a/src/coreComponents/mesh/generators/CellBlock.cpp +++ b/src/coreComponents/mesh/generators/CellBlock.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/generators/CellBlock.hpp b/src/coreComponents/mesh/generators/CellBlock.hpp index dbb686c0f44..6fa0de501a9 100644 --- a/src/coreComponents/mesh/generators/CellBlock.hpp +++ b/src/coreComponents/mesh/generators/CellBlock.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,8 +17,6 @@ #define GEOS_MESH_CELLBLOCK_HPP_ #include "dataRepository/Group.hpp" -#include "mesh/utilities/ComputationalGeometry.hpp" -#include "common/GEOS_RAJA_Interface.hpp" #include "mesh/generators/CellBlockABC.hpp" #include "mesh/ElementType.hpp" diff --git a/src/coreComponents/mesh/generators/CellBlockABC.hpp b/src/coreComponents/mesh/generators/CellBlockABC.hpp index fadde416894..7749ce687fe 100644 --- a/src/coreComponents/mesh/generators/CellBlockABC.hpp +++ b/src/coreComponents/mesh/generators/CellBlockABC.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2020- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -52,7 +53,7 @@ class CellBlockABC : public dataRepository::Group /** * @brief Get the type of element in this subregion. - * @return a string specifying the type of element in this subregion + * @return the type of element in this subregion * * See class FiniteElementBase for possible element type. */ diff --git a/src/coreComponents/mesh/generators/CellBlockManager.cpp b/src/coreComponents/mesh/generators/CellBlockManager.cpp index 356bd937d18..2dd41c0987a 100644 --- a/src/coreComponents/mesh/generators/CellBlockManager.cpp +++ b/src/coreComponents/mesh/generators/CellBlockManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -248,13 +249,13 @@ struct FaceBuilder */ auto duplicateFaceEquality() const { - return [duplicateFaces = duplicateFaces.toViewConst()] + return [faces = duplicateFaces.toViewConst()] ( NodesAndElementOfFace const & lhs, NodesAndElementOfFace const & rhs ) { - return std::equal( duplicateFaces[ lhs.duplicateFaceNodesIndex ].begin(), - duplicateFaces[ lhs.duplicateFaceNodesIndex ].end(), - duplicateFaces[ rhs.duplicateFaceNodesIndex ].begin(), - duplicateFaces[ rhs.duplicateFaceNodesIndex ].end() ); + return std::equal( faces[ lhs.duplicateFaceNodesIndex ].begin(), + faces[ lhs.duplicateFaceNodesIndex ].end(), + faces[ rhs.duplicateFaceNodesIndex ].begin(), + faces[ rhs.duplicateFaceNodesIndex ].end() ); }; } @@ -768,6 +769,14 @@ CellBlock & CellBlockManager::registerCellBlock( string const & name ) return this->getCellBlocks().registerGroup< CellBlock >( name ); } +CellBlock & CellBlockManager::registerCellBlock( string const & cellBlockName, + integer regionAttribute ) +{ + CellBlock & cb = this->getCellBlocks().registerGroup< CellBlock >( cellBlockName ); + m_regionAttributesCellBlocks[ regionAttribute ].emplace( cellBlockName ); + return cb; +} + FaceBlock & CellBlockManager::registerFaceBlock( string const & name ) { return this->getFaceBlocks().registerGroup< FaceBlock >( name ); @@ -822,61 +831,78 @@ static array1d< real64 > gaussLobattoPoints( int order ) switch( order ) { - case 1: - GaussLobattoPts[0] = -1.0; - GaussLobattoPts[1] = 1.0; - break; case 2: - GaussLobattoPts[0] = -1.0; - GaussLobattoPts[1] = 0.0; - GaussLobattoPts[2] = 1.0; + GaussLobattoPts[0] = 0; break; case 3: static constexpr real64 sqrt5 = 2.2360679774997897; - GaussLobattoPts[0] = -1.0; - GaussLobattoPts[1] = -1./sqrt5; - GaussLobattoPts[2] = 1./sqrt5; - GaussLobattoPts[3] = 1.; + GaussLobattoPts[0] = -1./sqrt5; + GaussLobattoPts[1] = 1./sqrt5; break; case 4: static constexpr real64 sqrt3_7 = 0.6546536707079771; - GaussLobattoPts[0] = -1.0; - GaussLobattoPts[1] = -sqrt3_7; - GaussLobattoPts[2] = 0.0; - GaussLobattoPts[3] = sqrt3_7; - GaussLobattoPts[4] = 1.0; + GaussLobattoPts[0] = -sqrt3_7; + GaussLobattoPts[1] = 0.0; + GaussLobattoPts[2] = sqrt3_7; break; case 5: static constexpr real64 sqrt__7_plus_2sqrt7__ = 3.50592393273573196; static constexpr real64 sqrt__7_mins_2sqrt7__ = 1.30709501485960033; static constexpr real64 sqrt_inv21 = 0.218217890235992381; - GaussLobattoPts[0] = -1.0; - GaussLobattoPts[1] = -sqrt_inv21*sqrt__7_plus_2sqrt7__; - GaussLobattoPts[2] = -sqrt_inv21*sqrt__7_mins_2sqrt7__; - GaussLobattoPts[3] = sqrt_inv21*sqrt__7_mins_2sqrt7__; - GaussLobattoPts[4] = sqrt_inv21*sqrt__7_plus_2sqrt7__; - GaussLobattoPts[5] = 1.0; + GaussLobattoPts[0] = -sqrt_inv21*sqrt__7_plus_2sqrt7__; + GaussLobattoPts[1] = -sqrt_inv21*sqrt__7_mins_2sqrt7__; + GaussLobattoPts[2] = sqrt_inv21*sqrt__7_mins_2sqrt7__; + GaussLobattoPts[3] = sqrt_inv21*sqrt__7_plus_2sqrt7__; break; } return GaussLobattoPts; } +static void linearInterp( real64 const alpha, + arrayView2d< real64, nodes::REFERENCE_POSITION_USD > const refPos, + localIndex const vi[2], + arrayView2d< real64, nodes::REFERENCE_POSITION_USD > refPosNew, + localIndex const v ) +{ + for( int i=0; i<3; i++ ) + { + refPosNew( v, i ) = refPos( vi[0], i )*( 1.0-alpha )+ + refPos( vi[1], i )* alpha; + } +} +static void bilinearInterp( real64 const alpha, + real64 const beta, + arrayView2d< real64, nodes::REFERENCE_POSITION_USD > const refPos, + localIndex const vi[4], + arrayView2d< real64, nodes::REFERENCE_POSITION_USD > refPosNew, + localIndex const v ) +{ + for( int i=0; i<3; i++ ) + { + refPosNew( v, i ) = refPos( vi[0], i )*( 1.0-alpha )*( 1.0-beta )+ + refPos( vi[1], i )* alpha *( 1.0-beta )+ + refPos( vi[2], i )*( 1.0-alpha )* beta + + refPos( vi[3], i )* alpha * beta; + } +} static void trilinearInterp( real64 const alpha, real64 const beta, real64 const gamma, - real64 const (&X)[8][3], - real64 (& coords)[3] ) + arrayView2d< real64, nodes::REFERENCE_POSITION_USD > const refPos, + localIndex const vi[8], + arrayView2d< real64, nodes::REFERENCE_POSITION_USD > refPosNew, + localIndex const v ) { for( int i=0; i<3; i++ ) { - coords[i] = X[0][i]*( 1.0-alpha )*( 1.0-beta )*( 1.0-gamma )+ - X[1][i]* alpha *( 1.0-beta )*( 1.0-gamma )+ - X[2][i]*( 1.0-alpha )* beta *( 1.0-gamma )+ - X[3][i]* alpha * beta *( 1.0-gamma )+ - X[4][i]*( 1.0-alpha )*( 1.0-beta )* gamma+ - X[5][i]* alpha *( 1.0-beta )* gamma+ - X[6][i]*( 1.0-alpha )* beta * gamma+ - X[7][i]* alpha * beta * gamma; + refPosNew( v, i ) = refPos( vi[0], i ) *( 1.0-alpha )*( 1.0-beta )*( 1.0-gamma )+ + refPos( vi[1], i ) * alpha *( 1.0-beta )*( 1.0-gamma )+ + refPos( vi[2], i ) *( 1.0-alpha )* beta *( 1.0-gamma )+ + refPos( vi[3], i ) * alpha * beta *( 1.0-gamma )+ + refPos( vi[4], i ) *( 1.0-alpha )*( 1.0-beta )* gamma+ + refPos( vi[5], i ) * alpha *( 1.0-beta )* gamma+ + refPos( vi[6], i ) *( 1.0-alpha )* beta * gamma+ + refPos( vi[7], i ) * alpha * beta * gamma; } } @@ -888,10 +914,34 @@ void CellBlockManager::generateHighOrderMaps( localIndex const order, arrayView1d< globalIndex const > const faceLocalToGlobal ) { - // constants for hex mesh + // The general idea for building higher-order nodes is as follows: + // 1. Original mesh-level 0 nodes are added, keeping their global IDs; + // 2. Nodes internal to edges, faces and elements are added in this order. + // Their global IDs are computed based on the global IDs of the edge, face or element containing them. + // 3. The edge, face and element-to-node maps are created by adding nodes in a hierarchical order: + // Endpoints/vertices, then edge nodes, face nodes and element nodes last + // 4. The maps are then re-ordered in the usual tensor-product ordering using a hash map, using nodeKeys as the keys of the map. + // 5. Finally, global orientation consistency across MPI ranks is guaranteed by using a consistent global face/edge orientation + // to create node global IDs. This is obtained using nodeKeys, which always order nodes in a consistent manner. + // + // nodeKeys identify each high-order node with a list of 6 integers [i1, i2, i3, i4, a, b], as follows: + // - nodes on a mesh vertex v are identified by the vector [v, -1, -1, -1, -1, -1]; + // - nodes internal to an edge are given by a linear interpolation between vertices v1 and v2, 'a' steps away from v1. + // The edge erndpoints are oriented such that v1 < v2, and the vertex is and identified with [v1, v2, -1, -1, a, -1]); + // - nodes internal to a face are given by a bilinear interpolation between edges v1->v2 and v3->v4 + // (v1-v4 and v2-v3 are the diagonals), with interpolation parameters 'a' and 'b' respectively. + // Faces are oriented so that v1 is always the smallest index, and v2 < v3. Then face nodes are identified with [v1, v2, v3, v4, a, b]; + // - Nodes internal to mesh cells do not need to be oriented, as they are not used for global data exchange. + GEOS_MARK_FUNCTION; + // constants for hex mesh + localIndex const numEdgesPerFace = 4; + localIndex const numFacesPerCell = 6; + localIndex const numEdgesPerCell = 12; + localIndex const numVerticesPerFace = 4; localIndex const numVerticesPerCell = 8; + localIndex const numNodesPerEdge = ( order+1 ); localIndex const numNodesPerFace = ( order+1 )*( order+1 ); localIndex const numNodesPerCell = ( order+1 )*( order+1 )*( order+1 ); @@ -929,38 +979,26 @@ void CellBlockManager::generateHighOrderMaps( localIndex const order, m_edgeToNodes.resize( m_numEdges, order+1 ); m_nodesPositions.resize( m_numNodes ); + // also assign node coordinates using trilinear interpolation in th elements + arrayView2d< real64, nodes::REFERENCE_POSITION_USD > refPosNew = this->getNodePositions(); + refPosNew.setValues< parallelHostPolicy >( -1.0 ); + array1d< real64 > glCoords = gaussLobattoPoints( order ); - // --------------------------------------- - // initialize the node local to global map - // --------------------------------------- - - // The general idea for building nodes local-to-global map for the high-order meshes are: - // 1. for all the nodes that already in the base mesh-level, we keep their globalIDs the same - // 2. for the new nodes on the edges, we assign their global ID according to the global information from edgeLocalToGlobal map - // 3. for the new nodes on the faces, we assign their global ID according to the global information from faceLocalToGlobal map - // 4. for the new nodes on the internal of each elements, we assign the global ID for the new nodes - // according to the global information for the elements from elementLocalToGlobal map. arrayView1d< globalIndex > nodeLocalToGlobalNew = m_nodeLocalToGlobal.toView(); + localIndex localNodeOffset = 0; - // nodeIDs is a hash map that contains unique vertices and their indices for shared nodes: - // - A vertex is identified by 6 integers [i1 i2 i3 i4 a b], as follows: - // - nodes on a vertex v are identified by the vector [v -1 -1 -1 -1 -1] - // - nodes on a edge are given by a linear interpolation between vertices v1 and v2, 'a' steps away from v1 - // (we assume that v1 < v2 and identify these nodes with [v1 v2 -1 -1 a -1]). - // - nodes on a face are given by a bilinear interpolation between edges v1-v2 and v3-v4 - // (v1-v4 and v2-v3 are the diagonals), with interpolation parameters 'a' and 'b'. - // (we assume that v1 is the smallest, and that v2 < v3) Then these nodes are identified with [v1 v2 v3 v4 a b] - // - nodes within the internal of a cell are encountered only once, and thus do not need to be put in the hash map - std::unordered_map< std::array< localIndex, 6 >, localIndex, NodeKeyHasher< localIndex > > nodeIDs; - - // Create new nodes, with local and global IDs - localIndex localNodeID = 0; - for( localIndex iter_vertex=0; iter_vertex < numLocalVertices; iter_vertex++ ) + forAll< parallelHostPolicy >( numLocalVertices, + [ nodeLocalToGlobalSource=nodeLocalToGlobalSource.toView(), + nodeLocalToGlobalNew=nodeLocalToGlobalNew.toView(), + refPosSource=refPosSource.toView(), + refPosNew=refPosNew.toView() ]( localIndex const iter_vertex ) { - nodeLocalToGlobalNew[ localNodeID ] = nodeLocalToGlobalSource.toView()[ iter_vertex ]; - nodeIDs[ createNodeKey( iter_vertex ) ] = localNodeID; - localNodeID++; - } + nodeLocalToGlobalNew[ iter_vertex ] = nodeLocalToGlobalSource[ iter_vertex ]; + refPosNew[ iter_vertex ][0] = refPosSource[ iter_vertex ][0]; + refPosNew[ iter_vertex ][1] = refPosSource[ iter_vertex ][1]; + refPosNew[ iter_vertex ][2] = refPosSource[ iter_vertex ][2]; + } ); + localNodeOffset = numLocalVertices; ////////////////////////// // Edges @@ -972,34 +1010,47 @@ void CellBlockManager::generateHighOrderMaps( localIndex const order, arrayView2d< localIndex > edgeToNodeMapNew = m_edgeToNodes.toView(); // create / retrieve nodes on edges - localIndex offset = maxVertexGlobalID; - for( localIndex iter_edge = 0; iter_edge < numLocalEdges; iter_edge++ ) + localIndex globalNodeOffset = maxVertexGlobalID; + + forAll< parallelHostPolicy >( numLocalEdges, + [ edgeToNodesMapSource=edgeToNodesMapSource.toView(), + edgeToNodeMapNew=edgeToNodeMapNew.toView(), + refPosSrc=refPosSource.toView(), + refPosNew=refPosNew.toView(), + edgeLocalToGlobal=edgeLocalToGlobal.toView(), + nodeLocalToGlobalNew=nodeLocalToGlobalNew.toView(), + numInternalNodesPerEdge, numNodesPerEdge, globalNodeOffset, glCoords, localNodeOffset, order]( localIndex const iter_edge ) { - localIndex v1 = edgeToNodesMapSource[ iter_edge ][ 0 ]; - localIndex v2 = edgeToNodesMapSource[ iter_edge ][ 1 ]; - globalIndex gv1 = nodeLocalToGlobalSource.toView()[v1]; - globalIndex gv2 = nodeLocalToGlobalSource.toView()[v2]; - for( int q=0; q, localIndex, NodeKeyHasher< localIndex > > nodeIDs; + localIndex edgeHeadNode = edgeToNodesMapSource[ iter_edge ][ 0 ]; + localIndex edgeEndNode = edgeToNodesMapSource[ iter_edge ][ 1 ]; + globalIndex edgeHeadNodeG = nodeLocalToGlobalNew[ edgeHeadNode ]; + globalIndex edgeEndNodeG = nodeLocalToGlobalNew[ edgeEndNode ]; + array1d< localIndex > const edgeToNodeMapWork( numNodesPerEdge ); + edgeToNodeMapWork[ 0 ] = edgeHeadNode; + edgeToNodeMapWork[ 1 ] = edgeEndNode; + nodeIDs[ createNodeKey( edgeHeadNode ) ] = 0; + nodeIDs[ createNodeKey( edgeEndNode ) ] = 1; + + for( localIndex iter_node = 0; iter_node < numInternalNodesPerEdge; iter_node++ ) { - localIndex nodeID; - std::array< localIndex, 6 > nodeKey = createNodeKey( v1, v2, q, order ); - if( nodeIDs.count( nodeKey ) == 0 ) - { - // this is an internal edge node: create it - nodeID = localNodeID; - nodeIDs[ nodeKey ] = nodeID; - std::array< globalIndex, 6 > referenceOrientation = createNodeKey( gv1, gv2, q, order ); - int gq = referenceOrientation[4] - 1; - nodeLocalToGlobalNew[ nodeID ] = offset + edgeLocalToGlobal[ iter_edge ] * numInternalNodesPerEdge + gq; - localNodeID++; - } - else - { - nodeID = nodeIDs[ nodeKey ]; - } - edgeToNodeMapNew[ iter_edge ][ q ] = nodeID; + real64 alpha = ( glCoords[ iter_node ] + 1.0 ) / 2.0; + localIndex nodeLocalID = localNodeOffset + iter_edge * ( numInternalNodesPerEdge ) + iter_node; + edgeToNodeMapWork[ iter_node + 2 ] = nodeLocalID; + nodeIDs[ createNodeKey( edgeHeadNode, edgeEndNode, iter_node + 1, order ) ] = iter_node + 2; + std::array< globalIndex, 6 > referenceOrientation = createNodeKey( edgeHeadNodeG, edgeEndNodeG, iter_node + 1, order ); + int gq = referenceOrientation[4] - 1; + nodeLocalToGlobalNew[ nodeLocalID ] = globalNodeOffset + edgeLocalToGlobal[ iter_edge ] * numInternalNodesPerEdge + gq; + localIndex e[2] = { edgeHeadNode, edgeEndNode }; + linearInterp( alpha, refPosSrc, e, refPosNew, nodeLocalID ); } - } + // reorder map + for( localIndex q = 0; q < numNodesPerEdge; q++ ) + { + edgeToNodeMapNew[ iter_edge ][ q ] = edgeToNodeMapWork[ nodeIDs[ createNodeKey( edgeHeadNode, edgeEndNode, q, order ) ] ]; + } + } ); + localNodeOffset += numInternalNodesPerEdge * numLocalEdges; ///////////////////////// // Faces @@ -1022,48 +1073,76 @@ void CellBlockManager::generateHighOrderMaps( localIndex const order, } } ); - // create / retrieve nodes on faces - // by default, faces are oriented so that the normal has an outward orientation for the current rank. - // For this reason : - // - The 3rd and 4th node need to be swapped, to be consistent with the GL ordering - // - The global IDs of the internal nodes must be referred to a global "reference" orientation (using the createNodeKey method) - offset = maxVertexGlobalID + maxEdgeGlobalID * numInternalNodesPerEdge; - for( localIndex iter_face = 0; iter_face < numLocalFaces; iter_face++ ) + globalNodeOffset = maxVertexGlobalID + maxEdgeGlobalID * numInternalNodesPerEdge; + + forAll< parallelHostPolicy >( numLocalFaces, + [ =, faceToNodesMapSource=faceToNodesMapSource.toView(), + edgeToNodeMapNew=edgeToNodeMapNew.toView(), + faceToNodeMapNew=faceToNodeMapNew.toView(), + faceToEdges=m_faceToEdges.toView(), + refPosSrc=refPosSource.toView(), + refPosNew=refPosNew.toView(), + faceLocalToGlobal=faceLocalToGlobal.toView(), + nodeLocalToGlobalNew=nodeLocalToGlobalNew.toView() ]( localIndex const iter_face ) { - localIndex v1 = faceToNodesMapSource[ iter_face ][ 0 ]; - localIndex v2 = faceToNodesMapSource[ iter_face ][ 1 ]; - localIndex v3 = faceToNodesMapSource[ iter_face ][ 2 ]; - localIndex v4 = faceToNodesMapSource[ iter_face ][ 3 ]; - std::swap( v3, v4 ); - globalIndex gv1 = nodeLocalToGlobalSource.toView()[v1]; - globalIndex gv2 = nodeLocalToGlobalSource.toView()[v2]; - globalIndex gv3 = nodeLocalToGlobalSource.toView()[v3]; - globalIndex gv4 = nodeLocalToGlobalSource.toView()[v4]; - for( int q1=0; q1, localIndex, NodeKeyHasher< localIndex > > nodeIDs; + localIndex faceVertID[ numVerticesPerFace ]; + globalIndex faceVertGID[ numVerticesPerFace ]; + array1d< localIndex > const faceToNodeMapWork( numNodesPerFace ); + for( localIndex iter_node=0; iter_node nodeKey = createNodeKey( v1, v2, v3, v4, q1, q2, order ); - if( nodeIDs.count( nodeKey ) == 0 ) - { - // this is an internal face node: create it - nodeID = localNodeID; - nodeIDs[ nodeKey ] = nodeID; - std::array< globalIndex, 6 > referenceOrientation = createNodeKey( gv1, gv2, gv3, gv4, q1, q2, order ); - int gq1 = referenceOrientation[4] - 1; - int gq2 = referenceOrientation[5] - 1; - nodeLocalToGlobalNew[ nodeID ] = offset + faceLocalToGlobal[ iter_face ] * numInternalNodesPerFace + gq1* numInternalNodesPerEdge + gq2; - localNodeID++; - } - else - { - nodeID = nodeIDs[ nodeKey ]; - } - faceToNodeMapNew[ iter_face ][ q2 + q1*numNodesPerEdge ] = nodeID; + localIndex nodeIdxInMap = numVerticesPerFace + iter_edge * numInternalNodesPerEdge + iter_node; + localIndex edge = faceToEdges[ iter_face ][ iter_edge ]; + faceToNodeMapWork[ nodeIdxInMap ] = edgeToNodeMapNew[ edge ][ iter_node + 1 ]; + nodeIDs[ createNodeKey( edgeToNodeMapNew[ edge ][ 0 ], edgeToNodeMapNew[ edge ][ numNodesPerEdge - 1 ], iter_node + 1, order ) ] = nodeIdxInMap; } } - } + for( localIndex iter_node=0; iter_node referenceOrientation = createNodeKey( faceVertGID[ 0 ], faceVertGID[ 1 ], faceVertGID[ 2 ], faceVertGID[ 3 ], + q1 + 1, q2 + 1, order ); + int gq1 = referenceOrientation[4] - 1; + int gq2 = referenceOrientation[5] - 1; + nodeLocalToGlobalNew[ nodeLocalID ] = globalNodeOffset + faceLocalToGlobal[ iter_face ] * numInternalNodesPerFace + gq2 * numInternalNodesPerEdge + gq1; + + bilinearInterp( alpha, beta, refPosSrc, faceVertID, refPosNew, nodeLocalID ); + } + // reorder map + for( localIndex q = 0; q < numNodesPerFace; q++ ) + { + localIndex q1 = q % numNodesPerEdge; + localIndex q2 = ( q / numNodesPerEdge ) % numNodesPerEdge; + if( q1 == 0 || q1 == numNodesPerEdge - 1 || q2 == 0 || q2 == numNodesPerEdge - 1 ) + { + faceToNodeMapNew[ iter_face ][ q ] = faceToNodeMapWork[ + nodeIDs[ createNodeKey( faceVertID[0], faceVertID[1], faceVertID[2], faceVertID[3], q1, q2, order ) ] ]; + } + } + } ); + + localNodeOffset += numInternalNodesPerFace * numLocalFaces; // add all nodes to the target set "all" SortedArray< localIndex > & allNodesSet = this->getNodeSets()[ "all" ]; @@ -1074,20 +1153,12 @@ void CellBlockManager::generateHighOrderMaps( localIndex const order, allNodesSet.insert( iter_nodes ); } + ///////////////////////// // Elements ////////////////////////// - // also assign node coordinates using trilinear interpolation in th elements - arrayView2d< real64, nodes::REFERENCE_POSITION_USD > refPosNew = this->getNodePositions(); - refPosNew.setValues< parallelHostPolicy >( -1.0 ); - - real64 Xmesh[ numVerticesPerCell ][ 3 ] = { { } }; - real64 X[ 3 ] = { { } }; - array1d< real64 > glCoords = gaussLobattoPoints( order ); - localIndex elemMeshVertices[ numVerticesPerCell ] = { }; - offset = maxVertexGlobalID + maxEdgeGlobalID * numInternalNodesPerEdge + maxFaceGlobalID * numInternalNodesPerFace; - std::array< localIndex, 6 > const nullKey = std::array< localIndex, 6 >{ -1, -1, -1, -1, -1, -1 }; + globalNodeOffset = maxVertexGlobalID + maxEdgeGlobalID * numInternalNodesPerEdge + maxFaceGlobalID * numInternalNodesPerFace; // initialize the elements-to-nodes map arrayView2d< localIndex, cells::NODE_MAP_USD > elemsToNodesNew; @@ -1097,61 +1168,89 @@ void CellBlockManager::generateHighOrderMaps( localIndex const order, arrayView1d< globalIndex > elementLocalToGlobal( cellBlock.localToGlobalMap() ); array2d< localIndex, cells::NODE_MAP_PERMUTATION > elemsToNodesSource ( cellBlock.getElemToNodes() ); + array2d< localIndex > elemsToEdges ( cellBlock.getElemToEdges() ); + array2d< localIndex > elemsToFaces ( cellBlock.getElemToFaces() ); + cellBlock.resizeNumNodes( numNodesPerCell ); elemsToNodesNew = cellBlock.getElemToNode(); localIndex const numCellElements = cellBlock.numElements(); - // then loop through all the elements and assign the globalID according to the globalID of the Element - // and insert the new local to global ID ( for the internal nodes of elements ) into the nodeLocalToGlobal - // retrieve finite element type - for( localIndex iter_elem = 0; iter_elem < numCellElements; ++iter_elem ) + forAll< parallelHostPolicy >( numCellElements, + [ =, + elemsToNodesSource=elemsToNodesSource.toView(), + elemsToNodesNew=elemsToNodesNew.toView(), + elemsToEdges=elemsToEdges.toView(), + elemsToFaces=elemsToFaces.toView(), + edgeToNodeMapNew=edgeToNodeMapNew.toView(), + faceToNodeMapNew=faceToNodeMapNew.toView(), + refPosSrc=refPosSource.toView(), + refPosNew=refPosNew.toView(), + elementLocalToGlobal=elementLocalToGlobal.toView(), + nodeLocalToGlobalNew=nodeLocalToGlobalNew.toView() ]( localIndex const iter_elem ) { - localIndex newCellNodes = 0; - for( localIndex iter_vertex = 0; iter_vertex < numVerticesPerCell; iter_vertex++ ) + std::unordered_map< std::array< localIndex, 6 >, localIndex, NodeKeyHasher< localIndex > > nodeIDs; + localIndex elemVertID[ numVerticesPerCell]; + array1d< localIndex > const elemToNodeMapWork( numNodesPerCell ); + for( localIndex iter_node=0; iter_node < numVerticesPerCell; iter_node++ ) { - elemMeshVertices[ iter_vertex ] = elemsToNodesSource[ iter_elem ][ iter_vertex ]; - for( int i =0; i < 3; i++ ) - { - Xmesh[ iter_vertex ][ i ] = refPosSource[ elemMeshVertices[ iter_vertex ] ][ i ]; - } + elemVertID[ iter_node ] = elemsToNodesSource[ iter_elem ][ iter_node ]; + elemToNodeMapWork[ iter_node ] = elemVertID[ iter_node ]; + nodeIDs[ createNodeKey( elemVertID[ iter_node ] ) ] = iter_node; } - for( int q = 0; q < numNodesPerCell; q++ ) + for( localIndex iter_edge=0; iter_edge < numEdgesPerCell; iter_edge++ ) { - localIndex nodeID; - int dof = q; - int q1 = dof % numNodesPerEdge; - dof /= ( numNodesPerEdge ); - int q2 = dof % ( numNodesPerEdge ); - dof /= ( numNodesPerEdge ); - int q3 = dof % ( numNodesPerEdge ); - // compute node coords - real64 alpha = ( glCoords[ q1 ] + 1.0 ) / 2.0; - real64 beta = ( glCoords[ q2 ] + 1.0 ) / 2.0; - real64 gamma = ( glCoords[ q3 ] + 1.0 ) / 2.0; - trilinearInterp( alpha, beta, gamma, Xmesh, X ); - // find node ID - std::array< localIndex, 6 > nodeKey = createNodeKey( elemMeshVertices, q1, q2, q3, order ); - if( nodeKey == nullKey ) + for( localIndex iter_node=0; iter_node < numInternalNodesPerEdge; iter_node++ ) { - // the node is internal to a cell -- create it - nodeID = localNodeID; - nodeLocalToGlobalNew[ nodeID ] = offset + elementLocalToGlobal[ iter_elem ] * numInternalNodesPerCell + newCellNodes; - localNodeID++; - newCellNodes++; + localIndex nodeIdxInMap = numVerticesPerCell + iter_edge * numInternalNodesPerEdge + iter_node; + localIndex edge = elemsToEdges[iter_elem][iter_edge]; + elemToNodeMapWork[ nodeIdxInMap ] = edgeToNodeMapNew[ edge ][iter_node+1]; + nodeIDs[ createNodeKey( edgeToNodeMapNew[ edge ][ 0 ], edgeToNodeMapNew[ edge ][ numNodesPerEdge - 1 ], iter_node + 1, order ) ] = nodeIdxInMap; } - else + } + for( localIndex iter_face=0; iter_face < numFacesPerCell; iter_face++ ) + { + for( localIndex iter_node=0; iter_node < numInternalNodesPerFace; iter_node++ ) { - nodeID = nodeIDs[ nodeKey ]; + localIndex q1 = iter_node % numInternalNodesPerEdge; + localIndex q2 = ( iter_node / numInternalNodesPerEdge ) % numInternalNodesPerEdge; + localIndex nodeIdxInMap = numVerticesPerCell + numEdgesPerCell * numInternalNodesPerEdge + iter_face * numInternalNodesPerFace + iter_node; + localIndex face = elemsToFaces[iter_elem][iter_face]; + elemToNodeMapWork[ nodeIdxInMap ] = faceToNodeMapNew[face][(q2 + 1) * numNodesPerEdge + (q1 + 1 )]; + nodeIDs[ createNodeKey( faceToNodeMapNew[ face ][ 0 ], faceToNodeMapNew[ face ][ numNodesPerEdge - 1 ], + faceToNodeMapNew[ face ][ numNodesPerFace - numNodesPerEdge ], faceToNodeMapNew[ face ][ numNodesPerFace- 1 ], q1 + 1, q2 + 1, order ) ] = nodeIdxInMap; } - for( int i=0; i<3; i++ ) + } + for( localIndex iter_node=0; iter_node < numInternalNodesPerCell; iter_node++ ) + { + localIndex q1 = iter_node % numInternalNodesPerEdge; + localIndex q2 = ( iter_node / numInternalNodesPerEdge ) % numInternalNodesPerEdge; + localIndex q3 = ( iter_node / numInternalNodesPerEdge ) / numInternalNodesPerEdge; + real64 alpha = ( glCoords[ q1 ] + 1.0 ) / 2.0; + real64 beta = ( glCoords[ q2 ] + 1.0 ) / 2.0; + real64 gamma = ( glCoords[ q3 ] + 1.0 ) / 2.0; + + localIndex nodeLocalID = localNodeOffset + iter_elem * numInternalNodesPerCell + iter_node; + elemsToNodesNew[ iter_elem ][ (q3 + 1) * numNodesPerFace + (q2 + 1) * numNodesPerEdge + (q1 + 1) ] = nodeLocalID; + nodeLocalToGlobalNew[ nodeLocalID ] = globalNodeOffset + elementLocalToGlobal[ iter_elem ] * numInternalNodesPerCell + iter_node; + trilinearInterp( alpha, beta, gamma, refPosSrc, elemVertID, refPosNew, nodeLocalID ); + + } + // reorder map + for( localIndex q = 0; q < numNodesPerCell; q++ ) + { + localIndex q1 = q % numNodesPerEdge; + localIndex q2 = ( q / numNodesPerEdge ) % numNodesPerEdge; + localIndex q3 = ( q / numNodesPerEdge ) / numNodesPerEdge; + if( q1 == 0 || q1 == numNodesPerEdge - 1 || q2 == 0 || q2 == numNodesPerEdge - 1 || q3 == 0 || q3 == numNodesPerEdge - 1 ) { - refPosNew( nodeID, i ) = X[ i ]; + elemsToNodesNew[ iter_elem ][ q ] = elemToNodeMapWork[ + nodeIDs[ createNodeKey( elemVertID, q1, q2, q3, order ) ] ]; } - elemsToNodesNew[ iter_elem ][ q ] = nodeID; } - } + } ); + localNodeOffset += numCellElements; } ); } -} +} // namespace geos diff --git a/src/coreComponents/mesh/generators/CellBlockManager.hpp b/src/coreComponents/mesh/generators/CellBlockManager.hpp index 517e7f61f0f..4e8d2688564 100644 --- a/src/coreComponents/mesh/generators/CellBlockManager.hpp +++ b/src/coreComponents/mesh/generators/CellBlockManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -157,6 +158,9 @@ class CellBlockManager : public CellBlockManagerABC Group & getCellBlocks() override; + std::map< integer, std::set< string > > const & getRegionAttributesCellBlocks() const override + { return m_regionAttributesCellBlocks; } + Group const & getFaceBlocks() const override; Group & getFaceBlocks() override; @@ -170,6 +174,14 @@ class CellBlockManager : public CellBlockManagerABC */ CellBlock & registerCellBlock( string const & name ); + /** + * @brief Registers and returns a cell block of name @p name. + * @param cellBlockName The name of the created cell block. + * @param regionAttribute The region attribute of the created cell block. + * @return A reference to the new cell block. The CellBlockManager owns this new instance. + */ + CellBlock & registerCellBlock( string const & cellBlockName, integer regionAttribute ); + /** * @brief Registers and returns a face block of name @p name. * @param name The name of the created face block. @@ -271,6 +283,8 @@ class CellBlockManager : public CellBlockManagerABC std::map< string, SortedArray< localIndex > > m_nodeSets; + std::map< integer, std::set< string > > m_regionAttributesCellBlocks; + real64 m_globalLength; localIndex m_numNodes; diff --git a/src/coreComponents/mesh/generators/CellBlockManagerABC.hpp b/src/coreComponents/mesh/generators/CellBlockManagerABC.hpp index d32f994a52e..c68c2a1bf13 100644 --- a/src/coreComponents/mesh/generators/CellBlockManagerABC.hpp +++ b/src/coreComponents/mesh/generators/CellBlockManagerABC.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2020- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -112,13 +113,18 @@ class CellBlockManagerABC : public dataRepository::Group * @brief Returns a group containing the cell blocks as CellBlockABC instances * @return Const reference to the Group instance. */ - virtual const Group & getCellBlocks() const = 0; + virtual Group const & getCellBlocks() const = 0; /** * @brief Returns a group containing the face blocks as FaceBlockABC instances * @return Const reference to the Group instance. */ - virtual const Group & getFaceBlocks() const = 0; + virtual Group const & getFaceBlocks() const = 0; + + /** + * @return A map of the cellblocks list for each region attribute values. + */ + virtual std::map< integer, std::set< string > > const & getRegionAttributesCellBlocks() const = 0; /** * @brief Total number of nodes across all the cell blocks. diff --git a/src/coreComponents/mesh/generators/CellBlockUtilities.cpp b/src/coreComponents/mesh/generators/CellBlockUtilities.cpp index 74190802863..6c2f902e556 100644 --- a/src/coreComponents/mesh/generators/CellBlockUtilities.cpp +++ b/src/coreComponents/mesh/generators/CellBlockUtilities.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2020- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -15,8 +16,6 @@ #include "CellBlockUtilities.hpp" #include "codingUtilities/Utilities.hpp" -#include "common/GEOS_RAJA_Interface.hpp" -#include "common/TimingMacros.hpp" #include "mesh/generators/CellBlockManagerABC.hpp" #include "mesh/generators/PrismUtilities.hpp" diff --git a/src/coreComponents/mesh/generators/CellBlockUtilities.hpp b/src/coreComponents/mesh/generators/CellBlockUtilities.hpp index 3db5a67d4ed..ab2d83b52ba 100644 --- a/src/coreComponents/mesh/generators/CellBlockUtilities.hpp +++ b/src/coreComponents/mesh/generators/CellBlockUtilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2020- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/generators/CollocatedNodes.cpp b/src/coreComponents/mesh/generators/CollocatedNodes.cpp index 80ebf967963..89f6fdcd484 100644 --- a/src/coreComponents/mesh/generators/CollocatedNodes.cpp +++ b/src/coreComponents/mesh/generators/CollocatedNodes.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -14,6 +15,11 @@ #include "CollocatedNodes.hpp" +#include "common/MpiWrapper.hpp" + + +#include + namespace geos::vtk { diff --git a/src/coreComponents/mesh/generators/CollocatedNodes.hpp b/src/coreComponents/mesh/generators/CollocatedNodes.hpp index a4819d67e08..54fea6afef7 100644 --- a/src/coreComponents/mesh/generators/CollocatedNodes.hpp +++ b/src/coreComponents/mesh/generators/CollocatedNodes.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,14 +18,10 @@ #include "common/DataTypes.hpp" -#include "common/MpiWrapper.hpp" - #include #include -#include #include - namespace geos::vtk { diff --git a/src/coreComponents/mesh/generators/ExternalMeshGeneratorBase.cpp b/src/coreComponents/mesh/generators/ExternalMeshGeneratorBase.cpp index a6d86b02ab5..ff3cd238c91 100644 --- a/src/coreComponents/mesh/generators/ExternalMeshGeneratorBase.cpp +++ b/src/coreComponents/mesh/generators/ExternalMeshGeneratorBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -45,23 +46,23 @@ ExternalMeshGeneratorBase::ExternalMeshGeneratorBase( string const & name, setInputFlag( InputFlags::OPTIONAL ). setDescription( "Volumic fields to be imported from the external mesh file" ); - registerWrapper( viewKeyStruct::volumicFieldsInGEOSXString(), &m_volumicFieldsInGEOSX ). + registerWrapper( viewKeyStruct::volumicFieldsInGEOSString(), &m_volumicFieldsInGEOS ). setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ). setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Names of the volumic fields in GEOSX to import into" ); + setDescription( "Names of the volumic fields in GEOS to import into" ); registerWrapper( viewKeyStruct::surfacicFieldsToImportString(), &m_surfacicFieldsToImport ). setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ). setInputFlag( InputFlags::OPTIONAL ). setDescription( "Surfacic fields to be imported from the external mesh file" ); - registerWrapper( viewKeyStruct::surfacicFieldsInGEOSXString(), &m_surfacicFieldsInGEOSX ). + registerWrapper( viewKeyStruct::surfacicFieldsInGEOSString(), &m_surfacicFieldsInGEOS ). setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ). setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Names of the surfacic fields in GEOSX to import into" ); + setDescription( "Names of the surfacic fields in GEOS to import into" ); } -void ExternalMeshGeneratorBase::postProcessInput() +void ExternalMeshGeneratorBase::postInputInitialization() { auto const checkSizes = [this]( arrayView1d< string const > from, arrayView1d< string const > to, string const & fromKey, string const & toKey ) @@ -72,8 +73,8 @@ void ExternalMeshGeneratorBase::postProcessInput() " must contain the same number of values.", InputError ); }; - checkSizes( m_volumicFieldsToImport, m_volumicFieldsInGEOSX, viewKeyStruct::volumicFieldsToImportString(), viewKeyStruct::volumicFieldsInGEOSXString() ); - checkSizes( m_surfacicFieldsToImport, m_surfacicFieldsInGEOSX, viewKeyStruct::surfacicFieldsToImportString(), viewKeyStruct::surfacicFieldsInGEOSXString() ); + checkSizes( m_volumicFieldsToImport, m_volumicFieldsInGEOS, viewKeyStruct::volumicFieldsToImportString(), viewKeyStruct::volumicFieldsInGEOSString() ); + checkSizes( m_surfacicFieldsToImport, m_surfacicFieldsInGEOS, viewKeyStruct::surfacicFieldsToImportString(), viewKeyStruct::surfacicFieldsInGEOSString() ); auto const checkDuplicates = [this]( arrayView1d< string const > v, string const & key ) { @@ -85,8 +86,8 @@ void ExternalMeshGeneratorBase::postProcessInput() "' already present in list of fields to import.", InputError ); }; - checkDuplicates( m_volumicFieldsInGEOSX, viewKeyStruct::volumicFieldsInGEOSXString() ); - checkDuplicates( m_surfacicFieldsInGEOSX, viewKeyStruct::surfacicFieldsInGEOSXString() ); + checkDuplicates( m_volumicFieldsInGEOS, viewKeyStruct::volumicFieldsInGEOSString() ); + checkDuplicates( m_surfacicFieldsInGEOS, viewKeyStruct::surfacicFieldsInGEOSString() ); // Building the fields mapping from the two separated input/output vectors. auto const buildMapping = [&]( arrayView1d< string const > from, @@ -100,8 +101,8 @@ void ExternalMeshGeneratorBase::postProcessInput() return mapping; }; - MeshGeneratorBase::m_volumicFields = buildMapping( m_volumicFieldsToImport.toViewConst(), m_volumicFieldsInGEOSX.toViewConst() ); - MeshGeneratorBase::m_surfacicFields = buildMapping( m_surfacicFieldsToImport.toViewConst(), m_surfacicFieldsInGEOSX.toViewConst() ); + MeshGeneratorBase::m_volumicFields = buildMapping( m_volumicFieldsToImport.toViewConst(), m_volumicFieldsInGEOS.toViewConst() ); + MeshGeneratorBase::m_surfacicFields = buildMapping( m_surfacicFieldsToImport.toViewConst(), m_surfacicFieldsInGEOS.toViewConst() ); } } // namespace geos diff --git a/src/coreComponents/mesh/generators/ExternalMeshGeneratorBase.hpp b/src/coreComponents/mesh/generators/ExternalMeshGeneratorBase.hpp index 96833a03066..f01d3938b7b 100644 --- a/src/coreComponents/mesh/generators/ExternalMeshGeneratorBase.hpp +++ b/src/coreComponents/mesh/generators/ExternalMeshGeneratorBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -48,13 +49,13 @@ class ExternalMeshGeneratorBase : public MeshGeneratorBase constexpr static char const * scaleString() { return "scale"; } constexpr static char const * translateString() { return "translate"; } constexpr static char const * volumicFieldsToImportString() { return "fieldsToImport"; } - constexpr static char const * volumicFieldsInGEOSXString() { return "fieldNamesInGEOSX"; } + constexpr static char const * volumicFieldsInGEOSString() { return "fieldNamesInGEOS"; } constexpr static char const * surfacicFieldsToImportString() { return "surfacicFieldsToImport"; } - constexpr static char const * surfacicFieldsInGEOSXString() { return "surfacicFieldsInGEOSX"; } + constexpr static char const * surfacicFieldsInGEOSString() { return "surfacicFieldsInGEOS"; } }; /// @endcond - void postProcessInput() override; + void postInputInitialization() override; /// Path to the mesh file Path m_filePath; @@ -65,17 +66,17 @@ class ExternalMeshGeneratorBase : public MeshGeneratorBase /// Scale factor that will be applied to the point coordinates (after translation) R1Tensor m_scale; - /// Names of the fields to be copied from an external reader into GEOSX data structure + /// Names of the fields to be copied from an external reader into GEOS data structure array1d< string > m_volumicFieldsToImport; - /// String array of the GEOSX user declared volumic fields - array1d< string > m_volumicFieldsInGEOSX; + /// String array of the GEOS user declared volumic fields + array1d< string > m_volumicFieldsInGEOS; - /// Names of the surfacic fields to be copied from an external reader into GEOSX data structure + /// Names of the surfacic fields to be copied from an external reader into GEOS data structure array1d< string > m_surfacicFieldsToImport; - /// String array of the GEOSX user declared surfacic fields - array1d< string > m_surfacicFieldsInGEOSX; + /// String array of the GEOS user declared surfacic fields + array1d< string > m_surfacicFieldsInGEOS; }; } // namespace geos diff --git a/src/coreComponents/mesh/generators/FaceBlock.cpp b/src/coreComponents/mesh/generators/FaceBlock.cpp index b7b701479d3..717f3395f99 100644 --- a/src/coreComponents/mesh/generators/FaceBlock.cpp +++ b/src/coreComponents/mesh/generators/FaceBlock.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2020- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/generators/FaceBlock.hpp b/src/coreComponents/mesh/generators/FaceBlock.hpp index 5788cf0d154..55b0d5840b8 100644 --- a/src/coreComponents/mesh/generators/FaceBlock.hpp +++ b/src/coreComponents/mesh/generators/FaceBlock.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2020- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/generators/FaceBlockABC.hpp b/src/coreComponents/mesh/generators/FaceBlockABC.hpp index fb4bc201e07..2df82db9913 100644 --- a/src/coreComponents/mesh/generators/FaceBlockABC.hpp +++ b/src/coreComponents/mesh/generators/FaceBlockABC.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2020- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/mesh/generators/InternalMeshGenerator.cpp b/src/coreComponents/mesh/generators/InternalMeshGenerator.cpp index 52727b04258..ace6dd8846e 100644 --- a/src/coreComponents/mesh/generators/InternalMeshGenerator.cpp +++ b/src/coreComponents/mesh/generators/InternalMeshGenerator.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,6 @@ #include "CellBlockManager.hpp" #include "common/DataTypes.hpp" -#include "common/TimingMacros.hpp" #include @@ -96,7 +96,8 @@ InternalMeshGenerator::InternalMeshGenerator( string const & name, Group * const registerWrapper( viewKeyStruct::elementTypesString(), &m_elementType ). setInputFlag( InputFlags::REQUIRED ). setSizedFromParent( 0 ). - setDescription( "Element types of each mesh block" ); + setDescription( GEOS_FMT( "Element types of each mesh block. Use \"C3D8\" for linear brick element. Possible values are: {}.", + stringutilities::join( EnumStrings< ElementType >::get(), ", " ) ) ); registerWrapper( viewKeyStruct::trianglePatternString(), &m_trianglePattern ). setApplyDefaultValue( 0 ). @@ -128,7 +129,7 @@ static int getNumElemPerBox( ElementType const elementType ) } } -void InternalMeshGenerator::postProcessInput() +void InternalMeshGenerator::postInputInitialization() { m_dim = getElementDim( EnumStrings< ElementType >::fromString( m_elementType[0] ) ); @@ -586,54 +587,54 @@ void InternalMeshGenerator::fillCellBlockManager( CellBlockManager & cellBlockMa // Find elemCenters for even uniform element sizes array1d< array1d< real64 > > elemCenterCoords( 3 ); - for( int i = 0; i < 3; ++i ) + for( int dim = 0; dim < m_dim; ++dim ) { - m_numElemsTotal[i] = 0; - for( int block = 0; block < m_nElems[i].size(); ++block ) + m_numElemsTotal[dim] = 0; + for( int block = 0; block < m_nElems[dim].size(); ++block ) { - m_numElemsTotal[i] += m_nElems[i][block]; + m_numElemsTotal[dim] += m_nElems[dim][block]; } array1d< int > const & parts = partition.getPartitions(); - GEOS_ERROR_IF( parts[i] > m_numElemsTotal[i], "Number of partitions in a direction should not exceed the number of elements in that direction" ); + GEOS_ERROR_IF( parts[dim] > m_numElemsTotal[dim], "Number of partitions in a direction should not exceed the number of elements in that direction" ); - elemCenterCoords[i].resize( m_numElemsTotal[i] ); - array1d< real64 > elemCenterCoordsLocal( m_numElemsTotal[i] ); - for( int k = 0; k < m_numElemsTotal[i]; ++k ) + elemCenterCoords[dim].resize( m_numElemsTotal[dim] ); + array1d< real64 > elemCenterCoordsLocal( m_numElemsTotal[dim] ); + for( integer k = 0; k < m_numElemsTotal[dim]; ++k ) { - elemCenterCoordsLocal[k] = m_min[i] + ( m_max[i] - m_min[i] ) * ( k + 0.5 ) / m_numElemsTotal[i]; + elemCenterCoordsLocal[k] = m_min[dim] + ( m_max[dim] - m_min[dim] ) * ( k + 0.5 ) / m_numElemsTotal[dim]; } MpiWrapper::allReduce( elemCenterCoordsLocal.data(), - elemCenterCoords[i].data(), - m_numElemsTotal[i], + elemCenterCoords[dim].data(), + m_numElemsTotal[dim], MPI_MAX, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); } // Find starting/ending index // Get the first and last indices in this partition each direction - int firstElemIndexInPartition[3] = { -1, -1, -1 }; - int lastElemIndexInPartition[3] = { -2, -2, -2 }; + integer firstElemIndexInPartition[3] = { -1, -1, -1 }; + integer lastElemIndexInPartition[3] = { -2, -2, -2 }; - for( int i = 0; i < 3; ++i ) + for( int dim = 0; dim < m_dim; ++dim ) { // firstElemIndexInPartition[i] = -1; // lastElemIndexInPartition[i] = -2; - for( int k = 0; k < m_numElemsTotal[i]; ++k ) + for( int k = 0; k < m_numElemsTotal[dim]; ++k ) { - if( partition.isCoordInPartition( elemCenterCoords[i][k], i ) ) + if( partition.isCoordInPartition( elemCenterCoords[dim][k], dim ) ) { - firstElemIndexInPartition[i] = k; + firstElemIndexInPartition[dim] = k; break; } } - if( firstElemIndexInPartition[i] > -1 ) + if( firstElemIndexInPartition[dim] > -1 ) { - for( int k = firstElemIndexInPartition[i]; k < m_numElemsTotal[i]; ++k ) + for( int k = firstElemIndexInPartition[dim]; k < m_numElemsTotal[dim]; ++k ) { - if( partition.isCoordInPartition( elemCenterCoords[i][k], i ) ) + if( partition.isCoordInPartition( elemCenterCoords[dim][k], dim ) ) { - lastElemIndexInPartition[i] = k; + lastElemIndexInPartition[dim] = k; } } } @@ -648,28 +649,28 @@ void InternalMeshGenerator::fillCellBlockManager( CellBlockManager & cellBlockMa array1d< integer > firstElemIndexForBlockInPartition[3]; array1d< integer > lastElemIndexForBlockInPartition[3]; - for( int dir = 0; dir < 3; ++dir ) + for( int dim = 0; dim < 3; ++dim ) { - firstElemIndexForBlockInPartition[dir] = m_firstElemIndexForBlock[dir]; - lastElemIndexForBlockInPartition[dir] = m_lastElemIndexForBlock[dir]; + firstElemIndexForBlockInPartition[dim] = m_firstElemIndexForBlock[dim]; + lastElemIndexForBlockInPartition[dim] = m_lastElemIndexForBlock[dim]; - for( int block = 0; block < m_nElems[dir].size(); ++block ) + for( integer block = 0; block < m_nElems[dim].size(); ++block ) { - if( firstElemIndexForBlockInPartition[dir][block] > lastElemIndexInPartition[dir] || - lastElemIndexForBlockInPartition[dir][block] < firstElemIndexInPartition[dir] ) + if( firstElemIndexForBlockInPartition[dim][block] > lastElemIndexInPartition[dim] || + lastElemIndexForBlockInPartition[dim][block] < firstElemIndexInPartition[dim] ) { - firstElemIndexForBlockInPartition[dir][block] = -1; - lastElemIndexForBlockInPartition[dir][block] = -2; + firstElemIndexForBlockInPartition[dim][block] = -1; + lastElemIndexForBlockInPartition[dim][block] = -2; } else { - if( firstElemIndexForBlockInPartition[dir][block] < firstElemIndexInPartition[dir] ) + if( firstElemIndexForBlockInPartition[dim][block] < firstElemIndexInPartition[dim] ) { - firstElemIndexForBlockInPartition[dir][block] = firstElemIndexInPartition[dir]; + firstElemIndexForBlockInPartition[dim][block] = firstElemIndexInPartition[dim]; } - if( lastElemIndexForBlockInPartition[dir][block] > lastElemIndexInPartition[dir] ) + if( lastElemIndexForBlockInPartition[dim][block] > lastElemIndexInPartition[dim] ) { - lastElemIndexForBlockInPartition[dir][block] = lastElemIndexInPartition[dir]; + lastElemIndexForBlockInPartition[dim][block] = lastElemIndexInPartition[dim]; } } } @@ -677,11 +678,11 @@ void InternalMeshGenerator::fillCellBlockManager( CellBlockManager & cellBlockMa // TODO This needs to be rewritten for dimensions lower than 3. localIndex regionOffset = 0; - for( int iblock = 0; iblock < m_nElems[0].size(); ++iblock ) + for( integer kblock = 0; kblock < m_nElems[2].size(); ++kblock ) { - for( int jblock = 0; jblock < m_nElems[1].size(); ++jblock ) + for( integer jblock = 0; jblock < m_nElems[1].size(); ++jblock ) { - for( int kblock = 0; kblock < m_nElems[2].size(); ++kblock, ++regionOffset ) + for( integer iblock = 0; iblock < m_nElems[0].size(); ++iblock, ++regionOffset ) { numElemsInRegions[ m_regionNames[ regionOffset ] ] = 0; elemTypeInRegions[ m_regionNames[ regionOffset ] ] = ElementType::Quadrilateral; @@ -692,13 +693,13 @@ void InternalMeshGenerator::fillCellBlockManager( CellBlockManager & cellBlockMa regionOffset = 0; { localIndex iR = 0; - for( int iblock = 0; iblock < m_nElems[0].size(); ++iblock ) + for( integer kblock = 0; kblock < m_nElems[2].size(); ++kblock ) { - for( int jblock = 0; jblock < m_nElems[1].size(); ++jblock ) + for( integer jblock = 0; jblock < m_nElems[1].size(); ++jblock ) { - for( int kblock = 0; kblock < m_nElems[2].size(); ++kblock, ++regionOffset, ++iR ) + for( integer iblock = 0; iblock < m_nElems[0].size(); ++iblock, ++regionOffset, ++iR ) { - int numElemsInRegion = 1; + integer numElemsInRegion = 1; numElemsInRegion *= lastElemIndexForBlockInPartition[0][iblock] - firstElemIndexForBlockInPartition[0][iblock] + 1; if( m_dim > 1 ) @@ -720,10 +721,9 @@ void InternalMeshGenerator::fillCellBlockManager( CellBlockManager & cellBlockMa localIndex numNodes = 1; integer numNodesInDir[3] = { 1, 1, 1 }; - - for( int i = 0; i < m_dim; ++i ) + for( int dim = 0; dim < m_dim; ++dim ) { - numNodesInDir[i] = lastElemIndexInPartition[i] - firstElemIndexInPartition[i] + 2; + numNodesInDir[dim] = lastElemIndexInPartition[dim] - firstElemIndexInPartition[dim] + 2; } reduceNumNodesForPeriodicBoundary( partition, numNodesInDir ); numNodes = numNodesInDir[0] * numNodesInDir[1] * numNodesInDir[2]; @@ -736,17 +736,17 @@ void InternalMeshGenerator::fillCellBlockManager( CellBlockManager & cellBlockMa { localIndex localNodeIndex = 0; - for( int i = 0; i < numNodesInDir[0]; ++i ) + for( integer k = 0; k < numNodesInDir[2]; ++k ) { - for( int j = 0; j < numNodesInDir[1]; ++j ) + for( integer j = 0; j < numNodesInDir[1]; ++j ) { - for( int k = 0; k < numNodesInDir[2]; ++k ) + for( integer i = 0; i < numNodesInDir[0]; ++i ) { - int globalIJK[3] = { i, j, k }; + integer globalIJK[3] = { i, j, k }; - for( int a = 0; a < m_dim; ++a ) + for( int dim = 0; dim < m_dim; ++dim ) { - globalIJK[a] += firstElemIndexInPartition[a]; + globalIJK[dim] += firstElemIndexInPartition[dim]; } getNodePosition( globalIJK, m_trianglePattern, X[localNodeIndex] ); @@ -825,11 +825,11 @@ void InternalMeshGenerator::fillCellBlockManager( CellBlockManager & cellBlockMa numNodes = numNodesInDir[0] * numNodesInDir[1] * numNodesInDir[2]; } - for( int iblock = 0; iblock < m_nElems[0].size(); ++iblock ) + for( integer kblock = 0; kblock < m_nElems[2].size(); ++kblock ) { - for( int jblock = 0; jblock < m_nElems[1].size(); ++jblock ) + for( integer jblock = 0; jblock < m_nElems[1].size(); ++jblock ) { - for( int kblock = 0; kblock < m_nElems[2].size(); ++kblock, ++regionOffset, ++iR ) + for( integer iblock = 0; iblock < m_nElems[0].size(); ++iblock, ++regionOffset, ++iR ) { ElementType const elementType = EnumStrings< ElementType >::fromString( m_elementType[iR] ); @@ -840,25 +840,25 @@ void InternalMeshGenerator::fillCellBlockManager( CellBlockManager & cellBlockMa arrayView2d< localIndex, cells::NODE_MAP_USD > elemsToNodes = cellBlock.getElemToNode(); arrayView1d< globalIndex > const & elemLocalToGlobal = cellBlock.localToGlobalMap(); - int numElemsInDirForBlock[3] = + integer numElemsInDirForBlock[3] = { lastElemIndexForBlockInPartition[0][iblock] - firstElemIndexForBlockInPartition[0][iblock] + 1, lastElemIndexForBlockInPartition[1][jblock] - firstElemIndexForBlockInPartition[1][jblock] + 1, lastElemIndexForBlockInPartition[2][kblock] - firstElemIndexForBlockInPartition[2][kblock] + 1 }; - for( int i = 0; i < numElemsInDirForBlock[0]; ++i ) + for( integer k = 0; k < numElemsInDirForBlock[2]; ++k ) { - for( int j = 0; j < numElemsInDirForBlock[1]; ++j ) + for( integer j = 0; j < numElemsInDirForBlock[1]; ++j ) { - for( int k = 0; k < numElemsInDirForBlock[2]; ++k ) + for( integer i = 0; i < numElemsInDirForBlock[0]; ++i ) { - int globalIJK[3] = + integer globalIJK[3] = { i + firstElemIndexForBlockInPartition[0][iblock], j + firstElemIndexForBlockInPartition[1][jblock], k + firstElemIndexForBlockInPartition[2][kblock] }; - const localIndex firstNodeIndex = numNodesInDir[1] * numNodesInDir[2] * ( globalIJK[0] - firstElemIndexInPartition[0] ) - + numNodesInDir[2] * ( globalIJK[1] - firstElemIndexInPartition[1] ) - + ( globalIJK[2] - firstElemIndexInPartition[2] ); + localIndex const firstNodeIndex = ( globalIJK[0] - firstElemIndexInPartition[0] ) + + numNodesInDir[0] * ( globalIJK[1] - firstElemIndexInPartition[1] ) + + numNodesInDir[0] * numNodesInDir[1] * ( globalIJK[2] - firstElemIndexInPartition[2] ); localIndex nodeOfBox[8]; if( elementType == ElementType::Quadrilateral || elementType == ElementType::Triangle ) @@ -870,15 +870,17 @@ void InternalMeshGenerator::fillCellBlockManager( CellBlockManager & cellBlockMa } else { + localIndex const stride[3] = { 1, numNodesInDir[0], numNodesInDir[0] * numNodesInDir[1] }; + nodeOfBox[0] = firstNodeIndex; - nodeOfBox[1] = numNodesInDir[1] * numNodesInDir[2] + firstNodeIndex; - nodeOfBox[2] = numNodesInDir[1] * numNodesInDir[2] + numNodesInDir[2] + firstNodeIndex; - nodeOfBox[3] = numNodesInDir[2] + firstNodeIndex; + nodeOfBox[1] = nodeOfBox[0] + stride[0]; + nodeOfBox[2] = nodeOfBox[1] + stride[1]; + nodeOfBox[3] = nodeOfBox[0] + stride[1]; - nodeOfBox[4] = firstNodeIndex + 1; - nodeOfBox[5] = numNodesInDir[1] * numNodesInDir[2] + firstNodeIndex + 1; - nodeOfBox[6] = numNodesInDir[1] * numNodesInDir[2] + numNodesInDir[2] + firstNodeIndex + 1; - nodeOfBox[7] = numNodesInDir[2] + firstNodeIndex + 1; + nodeOfBox[4] = nodeOfBox[0] + stride[2]; + nodeOfBox[5] = nodeOfBox[1] + stride[2]; + nodeOfBox[6] = nodeOfBox[2] + stride[2]; + nodeOfBox[7] = nodeOfBox[3] + stride[2]; // 7___________________ 6 // / /| @@ -978,6 +980,8 @@ InternalMeshGenerator:: int const (&firstElemIndexInPartition)[3], localIndex (& nodeOfBox)[8] ) { + GEOS_ERROR_IF( component != 1, "Connectivity for periodic boundary implemented for the 1-component only" ); + // Condition is: // 1) element is last index in component direction // 2) first local element in component partition is zero @@ -987,14 +991,14 @@ InternalMeshGenerator:: // Last set of nodes int modGlobalIJK[3] = { globalIJK[0], globalIJK[1], globalIJK[2] }; modGlobalIJK[component] = 0; - const localIndex firstNodeIndex = numNodesInDir[1] * numNodesInDir[2] * ( modGlobalIJK[0] - firstElemIndexInPartition[0] ) - + numNodesInDir[2] * ( modGlobalIJK[1] - 0 ) - + ( modGlobalIJK[2] - firstElemIndexInPartition[2] ); + localIndex const firstNodeIndex = ( modGlobalIJK[0] - firstElemIndexInPartition[0] ) + + numNodesInDir[0] * ( modGlobalIJK[1] - firstElemIndexInPartition[1] ) + + numNodesInDir[0] * numNodesInDir[1] * ( modGlobalIJK[2] - firstElemIndexInPartition[2] ); nodeOfBox[3] = firstNodeIndex; - nodeOfBox[2] = numNodesInDir[1] * numNodesInDir[2] + firstNodeIndex; - nodeOfBox[7] = firstNodeIndex + 1; - nodeOfBox[6] = numNodesInDir[1] * numNodesInDir[2] + firstNodeIndex + 1; + nodeOfBox[2] = nodeOfBox[3] + 1; + nodeOfBox[7] = nodeOfBox[3] + numNodesInDir[0] * numNodesInDir[1]; + nodeOfBox[6] = nodeOfBox[7] + 1; } } diff --git a/src/coreComponents/mesh/generators/InternalMeshGenerator.hpp b/src/coreComponents/mesh/generators/InternalMeshGenerator.hpp index 9b95d975df9..c9d86cc35a7 100644 --- a/src/coreComponents/mesh/generators/InternalMeshGenerator.hpp +++ b/src/coreComponents/mesh/generators/InternalMeshGenerator.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,7 @@ #ifndef GEOS_MESH_GENERATORS_INTERNALMESHGENERATOR_HPP #define GEOS_MESH_GENERATORS_INTERNALMESHGENERATOR_HPP -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include "mesh/generators/MeshGeneratorBase.hpp" #include "mesh/generators/CellBlockManager.hpp" #include "mesh/mpiCommunications/SpatialPartition.hpp" @@ -162,7 +163,7 @@ class InternalMeshGenerator : public MeshGeneratorBase }; /// @endcond - void postProcessInput() override; + void postInputInitialization() override; /// Mesh number of dimension int m_dim; @@ -271,7 +272,7 @@ class InternalMeshGenerator : public MeshGeneratorBase */ inline globalIndex nodeGlobalIndex( int const index[3] ) { - return index[0]*(m_numElemsTotal[1]+1)*(m_numElemsTotal[2]+1) + index[1]*(m_numElemsTotal[2]+1) + index[2]; + return index[0] + index[1]*(m_numElemsTotal[0]+1) + index[2]*(m_numElemsTotal[0]+1)*(m_numElemsTotal[1]+1); } /** @@ -280,7 +281,7 @@ class InternalMeshGenerator : public MeshGeneratorBase */ inline globalIndex elemGlobalIndex( int const index[3] ) { - return index[0]*m_numElemsTotal[1]*m_numElemsTotal[2] + index[1]*m_numElemsTotal[2] + index[2]; + return index[0] + index[1]*m_numElemsTotal[0] + index[2]*m_numElemsTotal[0]*m_numElemsTotal[1]; } /** diff --git a/src/coreComponents/mesh/generators/InternalWellGenerator.cpp b/src/coreComponents/mesh/generators/InternalWellGenerator.cpp index 5e5d9211a58..ffffbd7e3a8 100644 --- a/src/coreComponents/mesh/generators/InternalWellGenerator.cpp +++ b/src/coreComponents/mesh/generators/InternalWellGenerator.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -39,7 +40,7 @@ InternalWellGenerator::InternalWellGenerator( string const & name, Group * const setDescription( "Connectivity of the polyline segments" ); } -void InternalWellGenerator::postProcessInput() +void InternalWellGenerator::postInputInitialization() { GEOS_THROW_IF( m_polyNodeCoords.size( 1 ) != m_nDims, "InternalWell " << getWrapperDataContext( viewKeyStruct::polylineNodeCoordsString() ) << @@ -62,5 +63,5 @@ void InternalWellGenerator::postProcessInput() } -REGISTER_CATALOG_ENTRY( WellGeneratorBase, InternalWellGenerator, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( MeshComponentBase, InternalWellGenerator, string const &, Group * const ) } diff --git a/src/coreComponents/mesh/generators/InternalWellGenerator.hpp b/src/coreComponents/mesh/generators/InternalWellGenerator.hpp index 16cdeee3553..6f58313f1b7 100644 --- a/src/coreComponents/mesh/generators/InternalWellGenerator.hpp +++ b/src/coreComponents/mesh/generators/InternalWellGenerator.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -66,7 +67,7 @@ class InternalWellGenerator : public WellGeneratorBase * @brief This function provides capability to post process input values prior to * any other initialization operations. */ - void postProcessInput() override; + void postInputInitialization() override; }; } diff --git a/src/coreComponents/mesh/generators/InternalWellboreGenerator.cpp b/src/coreComponents/mesh/generators/InternalWellboreGenerator.cpp index 9dfe5df2c53..008ff4f91f3 100644 --- a/src/coreComponents/mesh/generators/InternalWellboreGenerator.cpp +++ b/src/coreComponents/mesh/generators/InternalWellboreGenerator.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,7 +19,6 @@ #include "InternalWellboreGenerator.hpp" -#include "mesh/DomainPartition.hpp" #include "mesh/mpiCommunications/SpatialPartition.hpp" namespace geos @@ -112,7 +112,7 @@ InternalWellboreGenerator::InternalWellboreGenerator( string const & name, } -void InternalWellboreGenerator::postProcessInput() +void InternalWellboreGenerator::postInputInitialization() { GEOS_ERROR_IF( m_nElems[1].size() > 1, @@ -299,7 +299,7 @@ void InternalWellboreGenerator::postProcessInput() } } - InternalMeshGenerator::postProcessInput(); + InternalMeshGenerator::postInputInitialization(); } void InternalWellboreGenerator::reduceNumNodesForPeriodicBoundary( SpatialPartition & partition, diff --git a/src/coreComponents/mesh/generators/InternalWellboreGenerator.hpp b/src/coreComponents/mesh/generators/InternalWellboreGenerator.hpp index ab45284f602..5076a9e39c1 100644 --- a/src/coreComponents/mesh/generators/InternalWellboreGenerator.hpp +++ b/src/coreComponents/mesh/generators/InternalWellboreGenerator.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,7 @@ #ifndef GEOS_MESHUTILITIES_INTERNALWELLBOREGENERATOR_HPP #define GEOS_MESHUTILITIES_INTERNALWELLBOREGENERATOR_HPP -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include "dataRepository/Group.hpp" #include "InternalMeshGenerator.hpp" @@ -88,7 +89,7 @@ class InternalWellboreGenerator : public InternalMeshGenerator }; /// @endcond - void postProcessInput() override final; + void postInputInitialization() override final; private: diff --git a/src/coreComponents/mesh/generators/LineBlock.cpp b/src/coreComponents/mesh/generators/LineBlock.cpp index b49289325b4..d87b3a63240 100644 --- a/src/coreComponents/mesh/generators/LineBlock.cpp +++ b/src/coreComponents/mesh/generators/LineBlock.cpp @@ -2,24 +2,18 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ -/** - * @file DomainPartition.cpp - */ - -#include "mesh/Perforation.hpp" #include "mesh/generators/LineBlock.hpp" -#include "mesh/generators/InternalWellGenerator.hpp" - namespace geos diff --git a/src/coreComponents/mesh/generators/LineBlock.hpp b/src/coreComponents/mesh/generators/LineBlock.hpp index 0582ee45f21..e2af5724ec5 100644 --- a/src/coreComponents/mesh/generators/LineBlock.hpp +++ b/src/coreComponents/mesh/generators/LineBlock.hpp @@ -2,21 +2,21 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2020- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ -#ifndef GEOSX_WELLBLOCK_HPP -#define GEOSX_WELLBLOCK_HPP +#ifndef GEOS_WELLBLOCK_HPP +#define GEOS_WELLBLOCK_HPP #include "mesh/generators/LineBlockABC.hpp" -#include "mesh/generators/InternalWellGenerator.hpp" namespace geos diff --git a/src/coreComponents/mesh/generators/LineBlockABC.hpp b/src/coreComponents/mesh/generators/LineBlockABC.hpp index 240f1b633ef..2855789ed66 100644 --- a/src/coreComponents/mesh/generators/LineBlockABC.hpp +++ b/src/coreComponents/mesh/generators/LineBlockABC.hpp @@ -2,23 +2,22 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2020- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ -#ifndef GEOSX_WELLBLOCKABC_HPP -#define GEOSX_WELLBLOCKABC_HPP +#ifndef GEOS_WELLBLOCKABC_HPP +#define GEOS_WELLBLOCKABC_HPP #include "dataRepository/Group.hpp" -#include "mesh/ElementType.hpp" #include "common/DataTypes.hpp" -#include "dataRepository/Group.hpp" #include @@ -167,4 +166,4 @@ class LineBlockABC : public dataRepository::Group } -#endif //GEOSX_WELLBLOCKABC_HPP +#endif //GEOS_WELLBLOCKABC_HPP diff --git a/src/coreComponents/mesh/generators/MeshComponentBase.cpp b/src/coreComponents/mesh/generators/MeshComponentBase.cpp new file mode 100644 index 00000000000..75742a87e30 --- /dev/null +++ b/src/coreComponents/mesh/generators/MeshComponentBase.cpp @@ -0,0 +1,39 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "MeshComponentBase.hpp" + +namespace geos +{ + +using namespace dataRepository; + +MeshComponentBase::MeshComponentBase( const string & name, + Group * const parent ) + : Group( name, parent ) +{ + setInputFlags( InputFlags::OPTIONAL_NONUNIQUE ); +} + +MeshComponentBase::~MeshComponentBase() +{} + +MeshComponentBase::CatalogInterface::CatalogType & MeshComponentBase::getCatalog() +{ + static CatalogInterface::CatalogType catalog; + return catalog; +} + +} diff --git a/src/coreComponents/mesh/generators/MeshComponentBase.hpp b/src/coreComponents/mesh/generators/MeshComponentBase.hpp new file mode 100644 index 00000000000..e24ee2b42d8 --- /dev/null +++ b/src/coreComponents/mesh/generators/MeshComponentBase.hpp @@ -0,0 +1,70 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/* + * @file MeshComponentBase.hpp + * + */ + +#ifndef GEOS_MESH_GENERATORS_MESHCOMPONENTBASE_HPP_ +#define GEOS_MESH_GENERATORS_MESHCOMPONENTBASE_HPP_ + +#include "dataRepository/Group.hpp" +#include "codingUtilities/Utilities.hpp" +#include "common/DataTypes.hpp" + + +namespace geos +{ + +/** + * @class MeshComponentBase + * + * Abstract base class defining the information provided by any the well generator class. + */ +class MeshComponentBase : public dataRepository::Group +{ +public: + + /** + * @brief Constructor. + * @param name name of the object in the data hierarchy. + * @param parent pointer to the parent group in the data hierarchy. + */ + MeshComponentBase( string const & name, + Group * const parent ); + + /** + * @brief Default destructor. + */ + virtual ~MeshComponentBase(); + + /** + * @brief Get the catalog name. + * @return the name of this type in the catalog + */ + static string catalogName() { return "MeshComponentBase"; } + + /** + * @brief Type alias for catalog interface used by this class. See CatalogInterface. + */ + using CatalogInterface = dataRepository::CatalogInterface< MeshComponentBase, string const &, Group * const >; + + /// @copydoc dataRepository::Group::getCatalog() + static CatalogInterface::CatalogType & getCatalog(); +}; + +} +#endif /* GEOS_MESH_GENERATORS_MESHCOMPONENTBASE_HPP_ */ diff --git a/src/coreComponents/mesh/generators/MeshGeneratorBase.cpp b/src/coreComponents/mesh/generators/MeshGeneratorBase.cpp index e085887ef3f..555bef92167 100644 --- a/src/coreComponents/mesh/generators/MeshGeneratorBase.cpp +++ b/src/coreComponents/mesh/generators/MeshGeneratorBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -15,7 +16,7 @@ #include "MeshGeneratorBase.hpp" #include "mesh/generators/CellBlockManager.hpp" #include "mesh/generators/ParticleBlockManager.hpp" - +#include "mesh/generators/MeshComponentBase.hpp" namespace geos { using namespace dataRepository; @@ -28,15 +29,15 @@ MeshGeneratorBase::MeshGeneratorBase( string const & name, Group * const parent Group * MeshGeneratorBase::createChild( string const & childKey, string const & childName ) { - GEOS_LOG_RANK_0( "Adding Mesh attribute: " << childKey << ", " << childName ); - std::unique_ptr< WellGeneratorBase > wellGen = WellGeneratorBase::CatalogInterface::factory( childKey, childName, this ); - return &this->registerGroup< WellGeneratorBase >( childName, std::move( wellGen ) ); + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) ); + std::unique_ptr< MeshComponentBase > comp = MeshComponentBase::CatalogInterface::factory( childKey, childName, this ); + return &this->registerGroup< MeshComponentBase >( childName, std::move( comp ) ); } void MeshGeneratorBase::expandObjectCatalogs() { - // During schema generation, register one of each type derived from WellGeneratorBase here - for( auto & catalogIter: WellGeneratorBase::getCatalog()) + // During schema generation, register one of each type derived from MeshComponentBase here + for( auto & catalogIter: MeshComponentBase::getCatalog()) { createChild( catalogIter.first, catalogIter.first ); } diff --git a/src/coreComponents/mesh/generators/MeshGeneratorBase.hpp b/src/coreComponents/mesh/generators/MeshGeneratorBase.hpp index db085ee8b14..d71de5cac30 100644 --- a/src/coreComponents/mesh/generators/MeshGeneratorBase.hpp +++ b/src/coreComponents/mesh/generators/MeshGeneratorBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,6 @@ #define GEOS_MESH_GENERATORS_MESHGENERATORBASE_HPP #include "mesh/mpiCommunications/SpatialPartition.hpp" -#include "mesh/generators/CellBlockManagerABC.hpp" #include "dataRepository/Group.hpp" #include "dataRepository/WrapperBase.hpp" @@ -54,12 +54,6 @@ class MeshGeneratorBase : public dataRepository::Group explicit MeshGeneratorBase( string const & name, Group * const parent ); - /** - * @brief Return the name of the MeshGenerator in object catalog. - * @return string that contains the catalog name of the MeshGenerator - */ - static string catalogName() { return "MeshGeneratorBase"; } - /// This function is used to expand any catalogs in the data structure virtual void expandObjectCatalogs() override; @@ -120,22 +114,22 @@ class MeshGeneratorBase : public dataRepository::Group virtual void freeResources() {} /** - * @brief Get the name mapping between mesh volumic field names and internal GEOSX volumic field names. + * @brief Get the name mapping between mesh volumic field names and internal GEOS volumic field names. * @return The string to string mapping of field names. */ std::map< string, string > const & getVolumicFieldsMapping() const { return m_volumicFields; } /** - * @brief Get the name mapping between mesh surfacic field names and internal GEOSX surfacic field names. + * @brief Get the name mapping between mesh surfacic field names and internal GEOS surfacic field names. * @return The string to string mapping of field names. */ std::map< string, string > const & getSurfacicFieldsMapping() const { return m_surfacicFields; } protected: - /// Mapping from volumic field source to GEOSX field. + /// Mapping from volumic field source to GEOS field. std::map< string, string > m_volumicFields; - /// Mapping from surfacic field source to GEOSX field. + /// Mapping from surfacic field source to GEOS field. std::map< string, string > m_surfacicFields; private: diff --git a/src/coreComponents/mesh/generators/PTScotchInterface.cpp b/src/coreComponents/mesh/generators/PTScotchInterface.cpp index 72e64b0aa95..2737c42db70 100644 --- a/src/coreComponents/mesh/generators/PTScotchInterface.cpp +++ b/src/coreComponents/mesh/generators/PTScotchInterface.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/generators/PTScotchInterface.hpp b/src/coreComponents/mesh/generators/PTScotchInterface.hpp index 6806ece7ed8..e188aadd55b 100644 --- a/src/coreComponents/mesh/generators/PTScotchInterface.hpp +++ b/src/coreComponents/mesh/generators/PTScotchInterface.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,6 +21,7 @@ #define GEOS_MESH_GENERATORS_PTSCOTCHINTERFACE_HPP_ #include "common/DataTypes.hpp" + #include "common/MpiWrapper.hpp" namespace geos diff --git a/src/coreComponents/mesh/generators/ParMETISInterface.cpp b/src/coreComponents/mesh/generators/ParMETISInterface.cpp index 25a30543296..4567826b341 100644 --- a/src/coreComponents/mesh/generators/ParMETISInterface.cpp +++ b/src/coreComponents/mesh/generators/ParMETISInterface.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/generators/ParMETISInterface.hpp b/src/coreComponents/mesh/generators/ParMETISInterface.hpp index 533f78c5cea..fa1bb2c8545 100644 --- a/src/coreComponents/mesh/generators/ParMETISInterface.hpp +++ b/src/coreComponents/mesh/generators/ParMETISInterface.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/generators/ParticleBlock.cpp b/src/coreComponents/mesh/generators/ParticleBlock.cpp index 55caa0aaadb..3cf22ea8ae2 100644 --- a/src/coreComponents/mesh/generators/ParticleBlock.cpp +++ b/src/coreComponents/mesh/generators/ParticleBlock.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,8 +20,6 @@ #include "ParticleBlock.hpp" -#include "common/GEOS_RAJA_Interface.hpp" - namespace geos { using namespace dataRepository; diff --git a/src/coreComponents/mesh/generators/ParticleBlock.hpp b/src/coreComponents/mesh/generators/ParticleBlock.hpp index ff054619bc4..947533e1e53 100644 --- a/src/coreComponents/mesh/generators/ParticleBlock.hpp +++ b/src/coreComponents/mesh/generators/ParticleBlock.hpp @@ -2,25 +2,25 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ -#ifndef GEOSX_MESH_PARTICLEBLOCK_HPP_ -#define GEOSX_MESH_PARTICLEBLOCK_HPP_ +#ifndef GEOS_MESH_PARTICLEBLOCK_HPP_ +#define GEOS_MESH_PARTICLEBLOCK_HPP_ -#include "dataRepository/Group.hpp" -#include "mesh/utilities/ComputationalGeometry.hpp" -#include "common/GEOS_RAJA_Interface.hpp" #include "mesh/generators/ParticleBlockABC.hpp" #include "mesh/ParticleType.hpp" +#include "dataRepository/Group.hpp" + namespace geos { @@ -272,4 +272,4 @@ class ParticleBlock : public ParticleBlockABC } -#endif /* GEOSX_MESH_CELLBLOCK_HPP_ */ +#endif /* GEOS_MESH_CELLBLOCK_HPP_ */ diff --git a/src/coreComponents/mesh/generators/ParticleBlockABC.hpp b/src/coreComponents/mesh/generators/ParticleBlockABC.hpp index 030e2ce3e92..c8f16c03e46 100644 --- a/src/coreComponents/mesh/generators/ParticleBlockABC.hpp +++ b/src/coreComponents/mesh/generators/ParticleBlockABC.hpp @@ -2,21 +2,23 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2020- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ -#ifndef GEOSX_PARTICLEBLOCKABC_HPP -#define GEOSX_PARTICLEBLOCKABC_HPP +#ifndef GEOS_PARTICLEBLOCKABC_HPP +#define GEOS_PARTICLEBLOCKABC_HPP -#include "dataRepository/Group.hpp" #include "mesh/ParticleType.hpp" + +#include "dataRepository/Group.hpp" #include "common/DataTypes.hpp" #include @@ -168,4 +170,4 @@ class ParticleBlockABC : public dataRepository::Group } -#endif //GEOSX_CELLBLOCKABC_HPP +#endif //GEOS_CELLBLOCKABC_HPP diff --git a/src/coreComponents/mesh/generators/ParticleBlockManager.cpp b/src/coreComponents/mesh/generators/ParticleBlockManager.cpp index 48b8b0ba126..d96f11711dc 100644 --- a/src/coreComponents/mesh/generators/ParticleBlockManager.cpp +++ b/src/coreComponents/mesh/generators/ParticleBlockManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -14,10 +15,6 @@ #include "ParticleBlockManager.hpp" -#include "mesh/generators/CellBlockUtilities.hpp" -#include "mesh/utilities/MeshMapUtilities.hpp" - -#include namespace geos { diff --git a/src/coreComponents/mesh/generators/ParticleBlockManager.hpp b/src/coreComponents/mesh/generators/ParticleBlockManager.hpp index 70c8cb588b8..87e69c767e3 100644 --- a/src/coreComponents/mesh/generators/ParticleBlockManager.hpp +++ b/src/coreComponents/mesh/generators/ParticleBlockManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,11 +17,11 @@ * @file ParticleBlockManager.hpp */ -#ifndef GEOSX_MESH_PARTICLEBLOCKMANAGER_H_ -#define GEOSX_MESH_PARTICLEBLOCKMANAGER_H_ +#ifndef GEOS_MESH_PARTICLEBLOCKMANAGER_H_ +#define GEOS_MESH_PARTICLEBLOCKMANAGER_H_ -#include "mesh/generators/ParticleBlockManagerABC.hpp" #include "mesh/generators/ParticleBlock.hpp" +#include "mesh/generators/ParticleBlockManagerABC.hpp" namespace geos { @@ -110,4 +111,4 @@ class ParticleBlockManager : public ParticleBlockManagerABC }; } -#endif /* GEOSX_MESH_PARTICLEBLOCKMANAGER_H_ */ +#endif /* GEOS_MESH_PARTICLEBLOCKMANAGER_H_ */ diff --git a/src/coreComponents/mesh/generators/ParticleBlockManagerABC.hpp b/src/coreComponents/mesh/generators/ParticleBlockManagerABC.hpp index 4777179f57d..c622f31af24 100644 --- a/src/coreComponents/mesh/generators/ParticleBlockManagerABC.hpp +++ b/src/coreComponents/mesh/generators/ParticleBlockManagerABC.hpp @@ -2,23 +2,22 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2020- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ -#ifndef GEOSX_PARTICLEBLOCKMANAGERABC_HPP -#define GEOSX_PARTICLEBLOCKMANAGERABC_HPP +#ifndef GEOS_PARTICLEBLOCKMANAGERABC_HPP +#define GEOS_PARTICLEBLOCKMANAGERABC_HPP #include "dataRepository/Group.hpp" -#include "mesh/ParticleType.hpp" #include "common/DataTypes.hpp" -#include "dataRepository/Group.hpp" namespace geos { diff --git a/src/coreComponents/mesh/generators/ParticleMeshGenerator.cpp b/src/coreComponents/mesh/generators/ParticleMeshGenerator.cpp index 5f3ad2510d6..eeef02ae013 100644 --- a/src/coreComponents/mesh/generators/ParticleMeshGenerator.cpp +++ b/src/coreComponents/mesh/generators/ParticleMeshGenerator.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,11 +18,9 @@ */ #include "ParticleMeshGenerator.hpp" +#include "ParticleBlockManager.hpp" -#include "mesh/DomainPartition.hpp" -#include "mesh/mpiCommunications/PartitionBase.hpp" #include "mesh/mpiCommunications/SpatialPartition.hpp" -#include "ParticleBlockManager.hpp" #include "common/DataTypes.hpp" #include "common/TimingMacros.hpp" @@ -328,9 +327,9 @@ void ParticleMeshGenerator::fillParticleBlockManager( ParticleBlockManager & par //GEOS_LOG_RANK( "Total number of particles on this rank: " << particleManager.size() ); } -void ParticleMeshGenerator::postProcessInput() +void ParticleMeshGenerator::postInputInitialization() { - //GEOS_LOG_RANK_0( "Someone called ParticleMeshGenerator::postProcessInput!" ); + //GEOS_LOG_RANK_0( "Someone called ParticleMeshGenerator::postInputInitialization!" ); } void ParticleMeshGenerator::importFieldOnArray( Block block, diff --git a/src/coreComponents/mesh/generators/ParticleMeshGenerator.hpp b/src/coreComponents/mesh/generators/ParticleMeshGenerator.hpp index 0ae0de19e9e..b6ee283aaac 100644 --- a/src/coreComponents/mesh/generators/ParticleMeshGenerator.hpp +++ b/src/coreComponents/mesh/generators/ParticleMeshGenerator.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,11 +17,12 @@ * @file ParticleMeshGenerator.hpp */ -#ifndef GEOSX_MESH_GENERATORS_PARTICLEMESHGENERATOR_HPP -#define GEOSX_MESH_GENERATORS_PARTICLEMESHGENERATOR_HPP +#ifndef GEOS_MESH_GENERATORS_PARTICLEMESHGENERATOR_HPP +#define GEOS_MESH_GENERATORS_PARTICLEMESHGENERATOR_HPP -#include "codingUtilities/EnumStrings.hpp" -#include "mesh/generators/ExternalMeshGeneratorBase.hpp" +#include "mesh/generators/MeshGeneratorBase.hpp" + +#include "common/format/EnumStrings.hpp" namespace geos { @@ -79,7 +81,7 @@ class ParticleMeshGenerator : public MeshGeneratorBase }; /// @endcond - void postProcessInput() override; + void postInputInitialization() override; /// Mesh number of dimension int m_dim; @@ -110,4 +112,4 @@ class ParticleMeshGenerator : public MeshGeneratorBase } /* namespace geos */ -#endif /* GEOSX_MESH_GENERATORS_PARTICLEMESHGENERATOR_HPP */ +#endif /* GEOS_MESH_GENERATORS_PARTICLEMESHGENERATOR_HPP */ diff --git a/src/coreComponents/mesh/generators/PartitionDescriptor.hpp b/src/coreComponents/mesh/generators/PartitionDescriptor.hpp index 5e4ad6b782f..ef4e4bb4566 100644 --- a/src/coreComponents/mesh/generators/PartitionDescriptor.hpp +++ b/src/coreComponents/mesh/generators/PartitionDescriptor.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,8 +17,8 @@ * @file PartitionDescriptor.hpp */ -#ifndef GEOSX_MESH_PARTITIONDESCRIPTOR_H_ -#define GEOSX_MESH_PARTITIONDESCRIPTOR_H_ +#ifndef GEOS_MESH_PARTITIONDESCRIPTOR_H_ +#define GEOS_MESH_PARTITIONDESCRIPTOR_H_ #include "mesh/mpiCommunications/SpatialPartition.hpp" @@ -94,4 +95,4 @@ class PartitionDescriptor }; } -#endif /* GEOSX_MESH_PARTITIONDESCRIPTOR_H_ */ +#endif /* GEOS_MESH_PARTITIONDESCRIPTOR_H_ */ diff --git a/src/coreComponents/mesh/generators/PrismUtilities.hpp b/src/coreComponents/mesh/generators/PrismUtilities.hpp index d6a4a359f98..f6e70aef310 100644 --- a/src/coreComponents/mesh/generators/PrismUtilities.hpp +++ b/src/coreComponents/mesh/generators/PrismUtilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2020- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/generators/Region.cpp b/src/coreComponents/mesh/generators/Region.cpp new file mode 100644 index 00000000000..b707e6077ba --- /dev/null +++ b/src/coreComponents/mesh/generators/Region.cpp @@ -0,0 +1,46 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file Region.cpp + */ + +#include "Region.hpp" + + +namespace geos +{ + +using namespace dataRepository; + +Region::Region( string const & name, + Group * const parent ) + : MeshComponentBase( name, parent ) +{ + registerWrapper( viewKeyStruct::idString(), &m_id ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Interval region identifier" ); + + registerWrapper( viewKeyStruct::pathInRepositoryString(), &m_pathInRepository ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Path of the dataset in the repository" ); +} + +Region::~Region() +{} + +REGISTER_CATALOG_ENTRY( MeshComponentBase, Region, string const &, Group * const ) + +} diff --git a/src/coreComponents/mesh/generators/Region.hpp b/src/coreComponents/mesh/generators/Region.hpp new file mode 100644 index 00000000000..6a5af64d92e --- /dev/null +++ b/src/coreComponents/mesh/generators/Region.hpp @@ -0,0 +1,76 @@ + +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file Region.hpp + */ + +#ifndef GEOS_MESH_GENERATORS_REGION_HPP +#define GEOS_MESH_GENERATORS_REGION_HPP + +#include "MeshComponentBase.hpp" + +namespace geos +{ + +/** + * @brief Region parameters with Group capabilities + * + * This class has dataRepository::Group capabilities to allow for XML input. + * + */ +class Region : public MeshComponentBase +{ +public: + /** + * @brief Constructor. + * @param name name of the object in the data hierarchy. + * @param parent pointer to the parent group in the data hierarchy. + */ + Region( const string & name, Group * const parent ); + + /** + * @brief Default destructor. + */ + ~Region() override; + + /** + * @brief Get the catalog name. + * @return the name of this type in the catalog + */ + static string catalogName() { return "Region"; } + + ///@cond DO_NOT_DOCUMENT + /// Keys appearing in XML + struct viewKeyStruct + { + static constexpr char const * idString() { return "id"; } + static constexpr char const * pathInRepositoryString() { return "pathInRepository"; } + }; + /// @endcond + +private: + + /// Interval region identifier + integer m_id = 0; + + /// Path of the dataset in the repository + string m_pathInRepository = ""; +}; + +} // namespace GEOS + +#endif diff --git a/src/coreComponents/mesh/generators/VTKFaceBlockUtilities.cpp b/src/coreComponents/mesh/generators/VTKFaceBlockUtilities.cpp index f76540ce576..2618d8138f9 100644 --- a/src/coreComponents/mesh/generators/VTKFaceBlockUtilities.cpp +++ b/src/coreComponents/mesh/generators/VTKFaceBlockUtilities.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2020- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,10 +21,10 @@ #include "dataRepository/Group.hpp" #include - +#include #include #include -#include +#include #include @@ -176,16 +177,18 @@ ArrayOfArrays< localIndex > build2dElemTo2dNodes( vtkSmartPointer< vtkDataSet > ArrayOfArrays< array1d< globalIndex > > buildCollocatedNodesBucketsOf2dElemsMap( ArrayOfArrays< localIndex > const & elem2dTo2dNodes, ArrayOfArrays< globalIndex > const & nodes2dToCollocatedNodes ) { + localIndex const num2dElems = elem2dTo2dNodes.size(); ArrayOfArrays< array1d< globalIndex > > result; // Allocation... - result.resize( elem2dTo2dNodes.size() ); - for( localIndex e2d = 0; e2d < elem2dTo2dNodes.size(); ++e2d ) + result.resize( num2dElems ); + for( localIndex e2d = 0; e2d < num2dElems; ++e2d ) { result.resizeArray( e2d, elem2dTo2dNodes[e2d].size() ); } - for( localIndex e2d = 0; e2d < elem2dTo2dNodes.size(); ++e2d ) + for( localIndex e2d = 0; e2d < num2dElems; ++e2d ) { - for( integer ni = 0; ni < elem2dTo2dNodes[e2d].size(); ++ni ) + auto const numNodes = elem2dTo2dNodes[e2d].size(); + for( integer ni = 0; ni < numNodes; ++ni ) { auto & dest = result( e2d, ni ); localIndex const node = elem2dTo2dNodes[e2d][ni]; @@ -269,7 +272,8 @@ ArrayOfArrays< localIndex > buildFace2dToElems2d( vtkPolyData * edges, * @param edges[in] The edges as computed by vtk. * @param collocatedNodes[in] The collocated nodes information. * @param nodeToEdges[in] The node to edges mapping. - * @return The 2d face to 3d edge mapping. + * @return The 2d face to 3d edge mapping. In the case where the face is at the boundary of the MPI domain, + * then the edge index will be set to @e -1 for further actions. */ array1d< localIndex > buildFace2dToEdge( vtkIdTypeArray const * globalPtIds, vtkPolyData * edges, @@ -314,7 +318,11 @@ array1d< localIndex > buildFace2dToEdge( vtkIdTypeArray const * globalPtIds, } } auto const res = std::max_element( edgeCount.cbegin(), edgeCount.cend(), comp ); - face2dToEdge[i] = LvArray::integerConversion< localIndex >( res->first ); + // If we're in a case where there aren't two edges sharing two nodes, + // then it means that we're in a corner case where the 2d element is on the boundary of the MPI domain, + // and maybe some nodes are missing for the 2d element to be properly and consistently defines. + // In this case, we explicitly set the edge index at `-1`, so we can get back on it later. + face2dToEdge[i] = res->second < 2 ? -1: LvArray::integerConversion< localIndex >( res->first ); } return face2dToEdge; @@ -361,7 +369,11 @@ ArrayOfArrays< localIndex > buildElem2dToEdges( vtkIdType num2dElements, { for( auto const & face2dIndex: elem2dToFace2d[elemIndex] ) { - elem2dToEdges.emplaceBack( elemIndex, face2dToEdge[face2dIndex] ); + localIndex const & e = face2dToEdge[face2dIndex]; + if( e > -1 ) + { + elem2dToEdges.emplaceBack( elemIndex, e ); + } } } @@ -369,17 +381,28 @@ ArrayOfArrays< localIndex > buildElem2dToEdges( vtkIdType num2dElements, } /** - * @brief Utility structure which connects 2d element to their 3d element and faces neighbors. + * @brief Utility structure which connects 2d element to their 3d element, faces and nodes neighbors. */ struct Elem2dTo3dInfo { ToCellRelation< ArrayOfArrays< localIndex > > elem2dToElem3d; ArrayOfArrays< localIndex > elem2dToFaces; + /** + * @brief All the neighboring points of the 2d element @e available on the current MPI rank. + * @note During the MPI partitioning, a 2d element may not already have its neighbors (face, 3d element). + * But this does not mean that the 2d element has no neighboring points. + * @note This container will not keep the order of the nodes. + * @note This container may not contain all the nodes of the 2d element. + * The missing nodes must therefore be added as part of the ghosting process. + */ + ArrayOfArrays< localIndex > elem2dToNodes; Elem2dTo3dInfo( ToCellRelation< ArrayOfArrays< localIndex > > && elem2dToElem3d_, - ArrayOfArrays< localIndex > && elem2dToFaces_ ) + ArrayOfArrays< localIndex > && elem2dToFaces_, + ArrayOfArrays< localIndex > && elem2dToNodes_ ) : elem2dToElem3d( elem2dToElem3d_ ), - elem2dToFaces( elem2dToFaces_ ) + elem2dToFaces( elem2dToFaces_ ), + elem2dToNodes( elem2dToNodes_ ) { } }; @@ -419,12 +442,23 @@ Elem2dTo3dInfo buildElem2dTo3dElemAndFaces( vtkSmartPointer< vtkDataSet > faceMe vtkIdTypeArray const * globalPtIds = vtkIdTypeArray::FastDownCast( mesh->GetPointData()->GetGlobalIds() ); vtkIdTypeArray const * globalCellIds = vtkIdTypeArray::FastDownCast( mesh->GetCellData()->GetGlobalIds() ); - // Let's build the elem2d to elem3d mapping. We need to find the 3d elements! + std::map< vtkIdType, localIndex > ng2l; // global to local mapping for nodes. + for( vtkIdType i = 0; i < globalPtIds->GetNumberOfValues(); ++i ) + { + ng2l[globalPtIds->GetValue( i )] = i; + } + + // Let's build the elem2d to elem3d mapping. + // We need to find the 3d elements (and only the 3d elements, so we can safely ignore the others). // First we compute the mapping from all the boundary nodes to the 3d elements that rely on those nodes. std::map< vtkIdType, std::vector< vtkIdType > > nodesToCellsFull; for( vtkIdType i = 0; i < boundary->GetNumberOfCells(); ++i ) { vtkIdType const cellId = boundaryCells->GetValue( i ); + if( mesh->GetCell( cellId )->GetCellDimension() != 3 ) + { + continue; + } vtkIdList * pointIds = boundary->GetCell( i )->GetPointIds(); for( int j = 0; j < pointIds->GetNumberOfIds(); ++j ) { @@ -460,12 +494,13 @@ Elem2dTo3dInfo buildElem2dTo3dElemAndFaces( vtkSmartPointer< vtkDataSet > faceMe ArrayOfArrays< localIndex > elem2dToElem3d( num2dElements, 2 ); ArrayOfArrays< localIndex > elem2dToCellBlock( num2dElements, 2 ); ArrayOfArrays< localIndex > elem2dToFaces( num2dElements, 2 ); + ArrayOfArrays< localIndex > elem2dToNodes( num2dElements, 10 ); // Now we loop on all the 2d elements. - for( int i = 0; i < num2dElements; ++i ) + for( int e2d = 0; e2d < num2dElements; ++e2d ) { // We collect all the duplicated points that are involved for each 2d element. - vtkIdList * pointIds = faceMesh->GetCell( i )->GetPointIds(); + vtkIdList * pointIds = faceMesh->GetCell( e2d )->GetPointIds(); std::size_t const elem2dNumPoints = pointIds->GetNumberOfIds(); // All the duplicated points of the 2d element. Note that we lose the collocation of the duplicated nodes. std::set< vtkIdType > duplicatedPointOfElem2d; @@ -475,6 +510,21 @@ Elem2dTo3dInfo buildElem2dTo3dElemAndFaces( vtkSmartPointer< vtkDataSet > faceMe duplicatedPointOfElem2d.insert( ns.cbegin(), ns.cend() ); } + for( vtkIdType const & gni: duplicatedPointOfElem2d ) + { + auto it = ng2l.find( gni ); + if( it != ng2l.cend() ) // If the node is not on this rank, we want to ignore this entry. + { + // The node lists in `elem2dToNodes` may be in any order. + // Anyway, there will be a specific step to reset the appropriate order. + // Note that due to ghosting, there will also always be some cases where + // some nodes will be missing in `elem2dToNodes` _before_ the ghosting. + // After the ghosting, the whole information will be gathered, + // but a reordering step will always be compulsory. + elem2dToNodes.emplaceBack( e2d, it->second ); + } + } + // Here, we collect all the 3d elements that are concerned by at least one of those duplicated elements. std::map< vtkIdType, std::set< vtkIdType > > elem3dToDuplicatedNodes; for( vtkIdType const & n: duplicatedPointOfElem2d ) @@ -495,7 +545,7 @@ Elem2dTo3dInfo buildElem2dTo3dElemAndFaces( vtkSmartPointer< vtkDataSet > faceMe if( e2n.second.size() == elem2dNumPoints ) { // Now we know that the element 3d has a face that touches the element 2d. Let's find which one. - elem2dToElem3d.emplaceBack( i, elemToFaces.getElementIndexInCellBlock( e2n.first ) ); + elem2dToElem3d.emplaceBack( e2d, elemToFaces.getElementIndexInCellBlock( e2n.first ) ); // Computing the elem2dToFaces mapping. auto faces = elemToFaces[e2n.first]; for( int j = 0; j < faces.size( 0 ); ++j ) @@ -509,8 +559,8 @@ Elem2dTo3dInfo buildElem2dTo3dElemAndFaces( vtkSmartPointer< vtkDataSet > faceMe } if( globalNodes == e2n.second ) { - elem2dToFaces.emplaceBack( i, faceIndex ); - elem2dToCellBlock.emplaceBack( i, elemToFaces.getCellBlockIndex( e2n.first ) ); + elem2dToFaces.emplaceBack( e2d, faceIndex ); + elem2dToCellBlock.emplaceBack( e2d, elemToFaces.getCellBlockIndex( e2n.first ) ); break; } } @@ -519,44 +569,7 @@ Elem2dTo3dInfo buildElem2dTo3dElemAndFaces( vtkSmartPointer< vtkDataSet > faceMe } auto cellRelation = ToCellRelation< ArrayOfArrays< localIndex > >( std::move( elem2dToCellBlock ), std::move( elem2dToElem3d ) ); - return Elem2dTo3dInfo( std::move( cellRelation ), std::move( elem2dToFaces ) ); -} - - -/** - * @brief Computes the 2d element to nodes mapping. - * @param num2dElements Number of (2d) elements in the fracture. - * @param faceToNodes The face to nodes mapping. - * @param elem2dToFaces The 2d element to faces mapping. - * @return The computed mapping. - */ -ArrayOfArrays< localIndex > buildElem2dToNodes( vtkIdType num2dElements, - ArrayOfArraysView< localIndex const > faceToNodes, - ArrayOfArraysView< localIndex const > elem2dToFaces ) -{ - ArrayOfArrays< localIndex > elem2dToNodes( LvArray::integerConversion< localIndex >( num2dElements ) ); - for( localIndex elem2dIndex = 0; elem2dIndex < elem2dToFaces.size(); ++elem2dIndex ) - { - for( localIndex const & faceIndex: elem2dToFaces[elem2dIndex] ) - { - if( faceIndex < 0 ) - { - continue; - } - std::set< localIndex > tmp; - for( auto j = 0; j < faceToNodes[faceIndex].size(); ++j ) - { - localIndex const & nodeIndex = faceToNodes[faceIndex][j]; - tmp.insert( nodeIndex ); - } - for( localIndex const & nodeIndex: tmp ) - { - elem2dToNodes.emplaceBack( elem2dIndex, nodeIndex ); - } - } - } - - return elem2dToNodes; + return Elem2dTo3dInfo( std::move( cellRelation ), std::move( elem2dToFaces ), std::move( elem2dToNodes ) ); } @@ -615,20 +628,19 @@ void importFractureNetwork( string const & faceBlockName, vtkIdType const num2dElements = faceMesh->GetNumberOfCells(); // Now let's build the elem2dTo* mappings. Elem2dTo3dInfo elem2dTo3d = buildElem2dTo3dElemAndFaces( faceMesh, mesh, collocatedNodes, faceToNodes.toViewConst(), elemToFaces ); - ArrayOfArrays< localIndex > elem2dToNodes = buildElem2dToNodes( num2dElements, faceToNodes.toViewConst(), elem2dTo3d.elem2dToFaces.toViewConst() ); ArrayOfArrays< localIndex > face2dToElems2d = buildFace2dToElems2d( edges, faceMesh ); array1d< localIndex > face2dToEdge = buildFace2dToEdge( vtkIdTypeArray::FastDownCast( mesh->GetPointData()->GetGlobalIds() ), edges, collocatedNodes, nodeToEdges.toViewConst() ); ArrayOfArrays< localIndex > const elem2dToFace2d = buildElem2dToFace2d( num2dElements, face2dToElems2d.toViewConst() ); - ArrayOfArrays< localIndex > elem2DToEdges = buildElem2dToEdges( num2dElements, face2dToEdge.toViewConst(), elem2dToFace2d.toViewConst() ); + ArrayOfArrays< localIndex > elem2dToEdges = buildElem2dToEdges( num2dElements, face2dToEdge.toViewConst(), elem2dToFace2d.toViewConst() ); // Mappings are now computed. Just create the face block by value. FaceBlock & faceBlock = cellBlockManager.registerFaceBlock( faceBlockName ); faceBlock.setNum2dElements( num2dElements ); faceBlock.setNum2dFaces( num2dFaces ); - faceBlock.set2dElemToNodes( std::move( elem2dToNodes ) ); - faceBlock.set2dElemToEdges( std::move( elem2DToEdges ) ); + faceBlock.set2dElemToNodes( std::move( elem2dTo3d.elem2dToNodes ) ); + faceBlock.set2dElemToEdges( std::move( elem2dToEdges ) ); faceBlock.set2dFaceToEdge( std::move( face2dToEdge ) ); faceBlock.set2dFaceTo2dElems( std::move( face2dToElems2d ) ); diff --git a/src/coreComponents/mesh/generators/VTKFaceBlockUtilities.hpp b/src/coreComponents/mesh/generators/VTKFaceBlockUtilities.hpp index 468b54f107a..f812071440d 100644 --- a/src/coreComponents/mesh/generators/VTKFaceBlockUtilities.hpp +++ b/src/coreComponents/mesh/generators/VTKFaceBlockUtilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2020- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -15,9 +16,10 @@ #ifndef GEOS_VTKFACEBLOCKUTILITIES_HPP #define GEOS_VTKFACEBLOCKUTILITIES_HPP -#include "common/DataTypes.hpp" #include "CellBlockManager.hpp" +#include "common/DataTypes.hpp" + #include #include diff --git a/src/coreComponents/mesh/generators/VTKHierarchicalDataSource.cpp b/src/coreComponents/mesh/generators/VTKHierarchicalDataSource.cpp new file mode 100644 index 00000000000..cd0e3d83729 --- /dev/null +++ b/src/coreComponents/mesh/generators/VTKHierarchicalDataSource.cpp @@ -0,0 +1,72 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file VTKHierarchicalDataSource.cpp + */ + +#include "mesh/generators/VTKHierarchicalDataSource.hpp" +#include "mesh/generators/VTKUtilities.hpp" +#include + +namespace geos +{ +using namespace dataRepository; + +VTKHierarchicalDataSource::VTKHierarchicalDataSource( string const & name, + Group * const parent ) + : ExternalDataSourceBase( name, parent ) +{ + registerWrapper( viewKeyStruct::filePathString(), &m_filePath ). + setRTTypeName( rtTypes::CustomTypes::groupNameRef ). + setInputFlag( InputFlags::REQUIRED ). + setApplyDefaultValue( "attribute" ). + setDescription( "Path to the mesh file" ); +} + +void VTKHierarchicalDataSource::open() +{ + string const extension = m_filePath.extension(); + GEOS_ERROR_IF( extension != "vtpc", "Unsupported vtk extension. File must be a vtpc file" ); + + vtkNew< vtkXMLPartitionedDataSetCollectionReader > reader; + reader->SetFileName( m_filePath.c_str()); + reader->Update(); + + m_collection = vtkSmartPointer< vtkPartitionedDataSetCollection >( vtkPartitionedDataSetCollection::SafeDownCast( reader->GetOutput())); + m_dataAssembly = vtkSmartPointer< vtkDataAssembly >( m_collection->GetDataAssembly() ); + + GEOS_ERROR_IF( m_dataAssembly == nullptr, "No data Assembly attached to this collection" ); +} + +vtkSmartPointer< vtkPartitionedDataSet > +VTKHierarchicalDataSource::search( string const & path ) +{ + int node = m_dataAssembly->GetFirstNodeByPath( path.c_str()); + GEOS_ERROR_IF( node == -1, "Node doesn't exist" ); + GEOS_ERROR_IF( m_dataAssembly->GetNumberOfChildren( node ) > 0, "Only leaf nodes can be queried." ); + + std::vector< unsigned int > indices = m_dataAssembly->GetDataSetIndices( node, false ); + + GEOS_ERROR_IF( indices.size() == 0, "Queried node has no dataset attached." ); + GEOS_ERROR_IF( indices.size() > 1, "Current constraint each tree node has only one dataset." ); + + return m_collection->GetPartitionedDataSet( indices[0] ); +} + +REGISTER_CATALOG_ENTRY( ExternalDataSourceBase, VTKHierarchicalDataSource, string const &, Group * const ) + + +} diff --git a/src/coreComponents/mesh/generators/VTKHierarchicalDataSource.hpp b/src/coreComponents/mesh/generators/VTKHierarchicalDataSource.hpp new file mode 100644 index 00000000000..adb9a69d830 --- /dev/null +++ b/src/coreComponents/mesh/generators/VTKHierarchicalDataSource.hpp @@ -0,0 +1,93 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file VTKHierarchicalDataSource.hpp + */ + +#ifndef GEOS_MESH_GENERATORS_VTKHIERARCHICALDATASOURCE_HPP +#define GEOS_MESH_GENERATORS_VTKHIERARCHICALDATASOURCE_HPP + +#include "dataRepository/Group.hpp" +#include "mesh/ExternalDataSourceBase.hpp" + +#include +#include +#include +#include +#include + +namespace geos +{ + +/** + * @class VTKHierarchicalDataSource + * @brief This class provides an API to access VTKPartitionedDataSetCollection through a vtkDataAssembly + */ +class VTKHierarchicalDataSource : public ExternalDataSourceBase +{ +public: + + /** + * @brief Main constructor for VTKHierarchicalDataSource base class. + * @param[in] name of the VTKHierarchicalDataSource object + * @param[in] parent the parent Group pointer for the VTKHierarchicalDataSource object + */ + VTKHierarchicalDataSource( string const & name, Group * const parent ); + + virtual ~VTKHierarchicalDataSource() override = default; + + /** + * @brief Return the name of the MeshGenerator in object catalog. + * @return string that contains the catalog name of the MeshGenerator + */ + static string catalogName() { return "VTKHierarchicalDataSource"; } + + /** + * @brief Opens a vtkPartitionedDataSetCollection and gets the colletion and the associated dataAssembly + * + */ + void open() override; + + /** + * @brief Performs a search in the dataAssembly to find a node of PartitionedDataSets + * + * @param path the path in the data assembly tree + * @return the found dataset + */ + vtkSmartPointer< vtkPartitionedDataSet > search( string const & path ); + +private: + + ///@cond DO_NOT_DOCUMENT + struct viewKeyStruct + { + constexpr static char const * filePathString() { return "file"; } + }; + /// @endcond + + /// Path to the mesh file + Path m_filePath; + + /// DataAssembly to query the dataset collection + vtkSmartPointer< vtkDataAssembly > m_dataAssembly; + + /// Collection of datasets + vtkSmartPointer< vtkPartitionedDataSetCollection > m_collection; +}; + +} + +#endif diff --git a/src/coreComponents/mesh/generators/VTKMeshGenerator.cpp b/src/coreComponents/mesh/generators/VTKMeshGenerator.cpp index 63e66cdeb85..6d791068dfd 100644 --- a/src/coreComponents/mesh/generators/VTKMeshGenerator.cpp +++ b/src/coreComponents/mesh/generators/VTKMeshGenerator.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,24 +19,30 @@ #include "VTKMeshGenerator.hpp" +#include "mesh/ExternalDataSourceManager.hpp" #include "mesh/generators/VTKFaceBlockUtilities.hpp" #include "mesh/generators/VTKMeshGeneratorTools.hpp" #include "mesh/generators/CellBlockManager.hpp" +#include "mesh/generators/Region.hpp" #include "common/DataTypes.hpp" -#include "common/DataLayouts.hpp" -#include "common/MpiWrapper.hpp" #include +#include +#include +#include namespace geos { using namespace dataRepository; - VTKMeshGenerator::VTKMeshGenerator( string const & name, Group * const parent ) - : ExternalMeshGeneratorBase( name, parent ) + : ExternalMeshGeneratorBase( name, parent ), + m_dataSource( nullptr ) { + getWrapperBase( ExternalMeshGeneratorBase::viewKeyStruct::filePathString()). + setInputFlag( InputFlags::OPTIONAL ); + registerWrapper( viewKeyStruct::regionAttributeString(), &m_attributeName ). setRTTypeName( rtTypes::CustomTypes::groupNameRef ). setInputFlag( InputFlags::OPTIONAL ). @@ -76,6 +83,34 @@ VTKMeshGenerator::VTKMeshGenerator( string const & name, " If set to 0 (default value), the GlobalId arrays in the input mesh are used if available, and generated otherwise." " If set to a negative value, the GlobalId arrays in the input mesh are not used, and generated global Ids are automatically generated." " If set to a positive value, the GlobalId arrays in the input mesh are used and required, and the simulation aborts if they are not available" ); + + registerWrapper( viewKeyStruct::dataSourceString(), &m_dataSourceName ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Name of the VTK data source" ); +} + +void VTKMeshGenerator::postInputInitialization() +{ + ExternalMeshGeneratorBase::postInputInitialization(); + + GEOS_ERROR_IF( !this->m_filePath.empty() && !m_dataSourceName.empty(), + getDataContext() << ": Access to the mesh via file or data source are mutually exclusive. " + "You can't set " << viewKeyStruct::dataSourceString() << " or " << viewKeyStruct::meshPathString() << " and " << + ExternalMeshGeneratorBase::viewKeyStruct::filePathString() ); + + if( !m_dataSourceName.empty()) + { + ExternalDataSourceManager & externalDataManager = this->getGroupByPath< ExternalDataSourceManager >( "/Problem/ExternalDataSource" ); + + m_dataSource = externalDataManager.getGroupPointer< VTKHierarchicalDataSource >( m_dataSourceName ); + + GEOS_THROW_IF( m_dataSource == nullptr, + getDataContext() << ": VTK Data Object Source not found: " << m_dataSourceName, + InputError ); + + m_dataSource->open(); + } + } void VTKMeshGenerator::fillCellBlockManager( CellBlockManager & cellBlockManager, SpatialPartition & partition ) @@ -83,41 +118,98 @@ void VTKMeshGenerator::fillCellBlockManager( CellBlockManager & cellBlockManager // TODO refactor void MeshGeneratorBase::generateMesh( DomainPartition & domain ) GEOS_MARK_FUNCTION; - MPI_Comm const comm = MPI_COMM_GEOSX; + MPI_Comm const comm = MPI_COMM_GEOS; vtkSmartPointer< vtkMultiProcessController > controller = vtk::getController(); vtkMultiProcessController::SetGlobalController( controller ); - GEOS_LOG_RANK_0( GEOS_FMT( "{} '{}': reading mesh from {}", catalogName(), getName(), m_filePath ) ); { - GEOS_LOG_LEVEL_RANK_0( 2, " reading the dataset..." ); - vtk::AllMeshes allMeshes = vtk::loadAllMeshes( m_filePath, m_mainBlockName, m_faceBlockNames ); - GEOS_LOG_LEVEL_RANK_0( 2, " redistributing mesh..." ); + vtk::AllMeshes allMeshes; + + GEOS_LOG_LEVEL_RANK_0( 2, GEOS_FMT( "{} '{}': reading the dataset...", catalogName(), getName() ) ); + + if( !m_filePath.empty()) + { + GEOS_LOG_RANK_0( GEOS_FMT( "{} '{}': reading mesh from {}", catalogName(), getName(), m_filePath ) ); + allMeshes = vtk::loadAllMeshes( m_filePath, m_mainBlockName, m_faceBlockNames ); + } + else if( !m_dataSourceName.empty()) + { + if( MpiWrapper::commRank() == 0 ) + { + std::vector< vtkSmartPointer< vtkPartitionedDataSet > > partitions; + vtkNew< vtkAppendFilter > appender; + appender->MergePointsOn(); + for( auto & [key, value] : this->getSubGroups()) + { + Region const & region = this->getGroup< Region >( key ); + + string path = region.getWrapper< string >( Region::viewKeyStruct::pathInRepositoryString()).reference(); + integer region_id = region.getWrapper< integer >( Region::viewKeyStruct::idString()).reference(); + + GEOS_LOG_RANK_0( GEOS_FMT( "{} '{}': reading partition from {}", catalogName(), getName(), path ) ); + vtkPartitionedDataSet * p = m_dataSource->search( path ); + + //load the grid + vtkDataObject * block = p->GetPartition( 0 ); + if( block->IsA( "vtkDataSet" ) ) + { + vtkSmartPointer< vtkDataSet > dataset = vtkDataSet::SafeDownCast( block ); + + vtkIntArray * arr = vtkIntArray::New(); + arr->SetName( m_attributeName.c_str()); + arr->SetNumberOfComponents( 1 ); + arr->SetNumberOfTuples( dataset->GetNumberOfCells()); + + arr->FillValue( region_id ); + + dataset->GetCellData()->AddArray( arr ); + appender->AddInputDataObject( dataset ); + } + } + appender->Update(); + vtkUnstructuredGrid * result = vtkUnstructuredGrid::SafeDownCast( appender->GetOutputDataObject( 0 ) ); + allMeshes.setMainMesh( result ); + + //DEBUG code + vtkNew< vtkXMLUnstructuredGridWriter > writer; + writer->SetFileName( "tmp_output.vtu" ); + writer->SetInputData( result ); + writer->Write(); + } + else + { + vtkUnstructuredGrid * result = vtkUnstructuredGrid::New(); + allMeshes.setMainMesh( result ); + } + } + + GEOS_LOG_LEVEL_RANK_0( 2, GEOS_FMT( "{} '{}': redistributing mesh...", catalogName(), getName() ) ); vtk::AllMeshes redistributedMeshes = vtk::redistributeMeshes( getLogLevel(), allMeshes.getMainMesh(), allMeshes.getFaceBlocks(), comm, m_partitionMethod, m_partitionRefinement, m_useGlobalIds ); m_vtkMesh = redistributedMeshes.getMainMesh(); m_faceBlockMeshes = redistributedMeshes.getFaceBlocks(); - GEOS_LOG_LEVEL_RANK_0( 2, " finding neighbor ranks..." ); + GEOS_LOG_LEVEL_RANK_0( 2, GEOS_FMT( "{} '{}': finding neighbor ranks...", catalogName(), getName() ) ); std::vector< vtkBoundingBox > boxes = vtk::exchangeBoundingBoxes( *m_vtkMesh, comm ); std::vector< int > const neighbors = vtk::findNeighborRanks( std::move( boxes ) ); partition.setMetisNeighborList( std::move( neighbors ) ); - GEOS_LOG_LEVEL_RANK_0( 2, " done!" ); + GEOS_LOG_LEVEL_RANK_0( 2, GEOS_FMT( "{} '{}': done!", catalogName(), getName() ) ); } - GEOS_LOG_RANK_0( GEOS_FMT( "{} '{}': generating GEOSX mesh data structure", catalogName(), getName() ) ); + GEOS_LOG_RANK_0( GEOS_FMT( "{} '{}': generating GEOS mesh data structure", catalogName(), getName() ) ); - GEOS_LOG_LEVEL_RANK_0( 2, " preprocessing..." ); + GEOS_LOG_LEVEL_RANK_0( 2, GEOS_FMT( "{} '{}': preprocessing...", catalogName(), getName() ) ); m_cellMap = vtk::buildCellMap( *m_vtkMesh, m_attributeName ); - GEOS_LOG_LEVEL_RANK_0( 2, " writing nodes..." ); + GEOS_LOG_LEVEL_RANK_0( 2, GEOS_FMT( "{} '{}': writing nodes...", catalogName(), getName() ) ); cellBlockManager.setGlobalLength( writeNodes( getLogLevel(), *m_vtkMesh, m_nodesetNames, cellBlockManager, this->m_translate, this->m_scale ) ); - GEOS_LOG_LEVEL_RANK_0( 2, " writing cells..." ); + GEOS_LOG_LEVEL_RANK_0( 2, GEOS_FMT( "{} '{}': writing cells...", catalogName(), getName() ) ); writeCells( getLogLevel(), *m_vtkMesh, m_cellMap, cellBlockManager ); - GEOS_LOG_LEVEL_RANK_0( 2, " writing surfaces..." ); + GEOS_LOG_LEVEL_RANK_0( 2, GEOS_FMT( "{} '{}': writing surfaces...", catalogName(), getName() ) ); writeSurfaces( getLogLevel(), *m_vtkMesh, m_cellMap, cellBlockManager ); - GEOS_LOG_LEVEL_RANK_0( 2, " building connectivity maps..." ); + GEOS_LOG_LEVEL_RANK_0( 2, GEOS_FMT( "{} '{}': building connectivity maps...", catalogName(), getName() ) ); cellBlockManager.buildMaps(); for( auto const & [name, mesh]: m_faceBlockMeshes ) @@ -125,7 +217,7 @@ void VTKMeshGenerator::fillCellBlockManager( CellBlockManager & cellBlockManager vtk::importFractureNetwork( name, mesh, m_vtkMesh, cellBlockManager ); } - GEOS_LOG_LEVEL_RANK_0( 2, " done!" ); + GEOS_LOG_LEVEL_RANK_0( 2, GEOS_FMT( "{} '{}': done!", catalogName(), getName() ) ); vtk::printMeshStatistics( *m_vtkMesh, m_cellMap, comm ); } @@ -216,6 +308,7 @@ void VTKMeshGenerator::freeResources() m_faceBlockMeshes.clear(); } + REGISTER_CATALOG_ENTRY( MeshGeneratorBase, VTKMeshGenerator, string const &, Group * const ) } // namespace geos diff --git a/src/coreComponents/mesh/generators/VTKMeshGenerator.hpp b/src/coreComponents/mesh/generators/VTKMeshGenerator.hpp index 7fa30004ee6..20747c848c2 100644 --- a/src/coreComponents/mesh/generators/VTKMeshGenerator.hpp +++ b/src/coreComponents/mesh/generators/VTKMeshGenerator.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,7 +22,8 @@ #include "mesh/generators/ExternalMeshGeneratorBase.hpp" #include "mesh/generators/VTKUtilities.hpp" - +#include "mesh/generators/VTKHierarchicalDataSource.hpp" +#include "mesh/mpiCommunications/SpatialPartition.hpp" #include namespace geos @@ -43,10 +45,10 @@ class VTKMeshGenerator : public ExternalMeshGeneratorBase VTKMeshGenerator( const string & name, Group * const parent ); -/** - * @brief Return the name of the VTKMeshGenerator in object Catalog. - * @return string that contains the key name to VTKMeshGenerator in the Catalog - */ + /** + * @brief Return the name of the VTKMeshGenerator in object Catalog. + * @return string that contains the key name to VTKMeshGenerator in the Catalog + */ static string catalogName() { return "VTKMesh"; } /** @@ -86,7 +88,7 @@ class VTKMeshGenerator : public ExternalMeshGeneratorBase * surfaces of interest, with triangles and/or quads holding an attribute value * of 1, 2 or 3, three node sets named "1", "2" and "3" will be instantiated by this method */ - virtual void fillCellBlockManager( CellBlockManager & cellBlockManager, SpatialPartition & partition ) override; + void fillCellBlockManager( CellBlockManager & cellBlockManager, SpatialPartition & partition ) override; void importFieldOnArray( Block block, string const & blockName, @@ -94,7 +96,10 @@ class VTKMeshGenerator : public ExternalMeshGeneratorBase bool isMaterialField, dataRepository::WrapperBase & wrapper ) const override; - virtual void freeResources() override; + void freeResources() override; + +protected: + void postInputInitialization() override; private: @@ -108,6 +113,13 @@ class VTKMeshGenerator : public ExternalMeshGeneratorBase constexpr static char const * partitionRefinementString() { return "partitionRefinement"; } constexpr static char const * partitionMethodString() { return "partitionMethod"; } constexpr static char const * useGlobalIdsString() { return "useGlobalIds"; } + constexpr static char const * dataSourceString() { return "dataSourceName"; } + constexpr static char const * meshPathString() { return "meshPath"; } + }; + + struct groupKeyStruct + { + constexpr static char const * regionString() { return "VTKRegion"; } }; /// @endcond @@ -153,6 +165,16 @@ class VTKMeshGenerator : public ExternalMeshGeneratorBase /// Lists of VTK cell ids, organized by element type, then by region vtk::CellMapType m_cellMap; + + /// Repository name + string m_dataSourceName; + + /// path to the mesh in the repository + string m_meshPath; + + /// Repository of VTK objects + VTKHierarchicalDataSource * m_dataSource; + }; } // namespace geos diff --git a/src/coreComponents/mesh/generators/VTKMeshGeneratorTools.cpp b/src/coreComponents/mesh/generators/VTKMeshGeneratorTools.cpp index e76a2079f17..a6d00f561ef 100644 --- a/src/coreComponents/mesh/generators/VTKMeshGeneratorTools.cpp +++ b/src/coreComponents/mesh/generators/VTKMeshGeneratorTools.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,15 +20,13 @@ #include "VTKMeshGeneratorTools.hpp" #include -#include #include +#include // NOTE: do NOT include anything from GEOS here. // See full explanation in VTKMeshGeneratorTools.hpp. -namespace geos -{ -namespace vtk +namespace geos::vtk { vtkSmartPointer< vtkUnstructuredGrid > @@ -264,5 +263,4 @@ exchangeBoundingBoxes( vtkDataSet & dataSet, MPI_Comm mpiComm ) return boxes; } -} // namespace vtk -} // namespace geos +} // namespace geos::vtk diff --git a/src/coreComponents/mesh/generators/VTKMeshGeneratorTools.hpp b/src/coreComponents/mesh/generators/VTKMeshGeneratorTools.hpp index 0e70f32d766..68740cefc92 100644 --- a/src/coreComponents/mesh/generators/VTKMeshGeneratorTools.hpp +++ b/src/coreComponents/mesh/generators/VTKMeshGeneratorTools.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,21 +20,19 @@ #ifndef GEOS_VTK_MESH_GENERATORS_VTKMESHGENERATORTOOLS_HPP_ #define GEOS_VTK_MESH_GENERATORS_VTKMESHGENERATORTOOLS_HPP_ +#include #include #include -#include #include -// NOTE: do NOT include anything from GEOSX here. -// In particular, nothing that directly or transitively includes "common/Format.hpp". -// The reason is "diy2" library includes an older version of {fmt} than the one used by GEOSX. +// NOTE: do NOT include anything from GEOS here. +// In particular, nothing that directly or transitively includes "common/format/Format.hpp". +// The reason is "diy2" library includes an older version of {fmt} than the one used by GEOS. // Collision of includes leads to all kinds of impossible to fix compilation errors. // Thankfully, no link errors, owing to namespace versioning employed by {fmt}. -namespace geos -{ -namespace vtk +namespace geos::vtk { /** @@ -59,7 +58,6 @@ redistribute( vtkPartitionedDataSet & localParts, MPI_Comm mpiComm ); std::vector< vtkBoundingBox > exchangeBoundingBoxes( vtkDataSet & dataSet, MPI_Comm mpiComm ); -} // namespace vtk -} // namespace geos +} // namespace geos::vtk #endif //GEOS_VTK_MESH_GENERATORS_VTKMESHGENERATORTOOLS_HPP_ diff --git a/src/coreComponents/mesh/generators/VTKUtilities.cpp b/src/coreComponents/mesh/generators/VTKUtilities.cpp index 47bce1e7aa0..a18b3e6767a 100644 --- a/src/coreComponents/mesh/generators/VTKUtilities.cpp +++ b/src/coreComponents/mesh/generators/VTKUtilities.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,7 +19,7 @@ #include "mesh/generators/VTKUtilities.hpp" #include "mesh/generators/ParMETISInterface.hpp" -#ifdef GEOSX_USE_SCOTCH +#ifdef GEOS_USE_SCOTCH #include "mesh/generators/PTScotchInterface.hpp" #endif @@ -60,7 +61,7 @@ #include #include -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI #include #include #else @@ -71,6 +72,7 @@ namespace geos { +using namespace dataRepository; namespace vtk { @@ -141,7 +143,7 @@ std::vector< T > collectUniqueValues( std::vector< T > const & data ) { // Exchange the sizes of the data across all ranks. array1d< int > dataSizes( MpiWrapper::commSize() ); - MpiWrapper::allGather( LvArray::integerConversion< int >( data.size() ), dataSizes, MPI_COMM_GEOSX ); + MpiWrapper::allGather( LvArray::integerConversion< int >( data.size() ), dataSizes, MPI_COMM_GEOS ); // `totalDataSize` contains the total data size across all the MPI ranks. int const totalDataSize = std::accumulate( dataSizes.begin(), dataSizes.end(), 0 ); @@ -152,7 +154,7 @@ std::vector< T > collectUniqueValues( std::vector< T > const & data ) // `displacements` is the offset (relative to the receive buffer) to store the data for each rank. std::vector< int > displacements( MpiWrapper::commSize(), 0 ); std::partial_sum( dataSizes.begin(), dataSizes.end() - 1, displacements.begin() + 1 ); - MpiWrapper::allgatherv( data.data(), data.size(), allData.data(), dataSizes.data(), displacements.data(), MPI_COMM_GEOSX ); + MpiWrapper::allgatherv( data.data(), data.size(), allData.data(), dataSizes.data(), displacements.data(), MPI_COMM_GEOS ); // Finalizing by sorting, removing duplicates and trimming the result vector at the proper size. std::sort( allData.begin(), allData.end() ); @@ -401,9 +403,9 @@ splitMeshByPartition( vtkSmartPointer< vtkDataSet > mesh, vtkSmartPointer< vtkMultiProcessController > getController() { -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI vtkNew< vtkMPIController > controller; - vtkMPICommunicatorOpaqueComm vtkGeosxComm( &MPI_COMM_GEOSX ); + vtkMPICommunicatorOpaqueComm vtkGeosxComm( &MPI_COMM_GEOS ); vtkNew< vtkMPICommunicator > communicator; communicator->InitializeExternal( &vtkGeosxComm ); controller->SetCommunicator( communicator ); @@ -641,7 +643,7 @@ AllMeshes redistributeByCellGraph( AllMeshes & input, } case PartitionMethod::ptscotch: { -#ifdef GEOSX_USE_SCOTCH +#ifdef GEOS_USE_SCOTCH GEOS_WARNING_IF( numRefinements > 0, "Partition refinement is not supported by 'ptscotch' partitioning method" ); return ptscotch::partition( graph.toViewConst(), numRanks, comm ); #else @@ -676,13 +678,13 @@ AllMeshes redistributeByCellGraph( AllMeshes & input, // First for the main 3d mesh... vtkSmartPointer< vtkPartitionedDataSet > const splitMesh = splitMeshByPartition( input.getMainMesh(), numRanks, newPartitions.toViewConst() ); - vtkSmartPointer< vtkUnstructuredGrid > finalMesh = vtk::redistribute( *splitMesh, MPI_COMM_GEOSX ); + vtkSmartPointer< vtkUnstructuredGrid > finalMesh = vtk::redistribute( *splitMesh, MPI_COMM_GEOS ); // ... and then for the fractures. std::map< string, vtkSmartPointer< vtkDataSet > > finalFractures; for( auto const & [fractureName, fracture]: input.getFaceBlocks() ) { vtkSmartPointer< vtkPartitionedDataSet > const splitFracMesh = splitMeshByPartition( fracture, numRanks, newFracturePartitions[fractureName].toViewConst() ); - vtkSmartPointer< vtkUnstructuredGrid > const finalFracMesh = vtk::redistribute( *splitFracMesh, MPI_COMM_GEOSX ); + vtkSmartPointer< vtkUnstructuredGrid > const finalFracMesh = vtk::redistribute( *splitFracMesh, MPI_COMM_GEOS ); finalFractures[fractureName] = finalFracMesh; } @@ -734,7 +736,7 @@ findNeighborRanks( std::vector< vtkBoundingBox > boundingBoxes ) } -vtkSmartPointer< vtkDataSet > manageGlobalIds( vtkSmartPointer< vtkDataSet > mesh, int useGlobalIds ) +vtkSmartPointer< vtkDataSet > manageGlobalIds( vtkSmartPointer< vtkDataSet > mesh, int useGlobalIds, bool isFractured ) { auto hasGlobalIds = []( vtkSmartPointer< vtkDataSet > m ) -> bool { @@ -745,7 +747,7 @@ vtkSmartPointer< vtkDataSet > manageGlobalIds( vtkSmartPointer< vtkDataSet > mes // Add global ids on the fly if needed int const me = hasGlobalIds( mesh ); int everyone; - MpiWrapper::allReduce( &me, &everyone, 1, MPI_MAX, MPI_COMM_GEOSX ); + MpiWrapper::allReduce( &me, &everyone, 1, MPI_MAX, MPI_COMM_GEOS ); if( everyone and not me ) { @@ -776,6 +778,8 @@ vtkSmartPointer< vtkDataSet > manageGlobalIds( vtkSmartPointer< vtkDataSet > mes } else { + GEOS_ERROR_IF( isFractured, "Automatic generation of global IDs for fractured meshes is disabled. Please split with mesh_doctor. \n" << generalMeshErrorAdvice ); + GEOS_LOG_RANK_0( "Generating global Ids from VTK mesh" ); output = generateGlobalIDs( mesh ); } @@ -888,7 +892,7 @@ ensureNoEmptyRank( vtkSmartPointer< vtkDataSet > mesh, "\nWarning! We strongly encourage the use of partitionRefinement > 5 for this number of MPI ranks \n" ); vtkSmartPointer< vtkPartitionedDataSet > const splitMesh = splitMeshByPartition( mesh, numProcs, newParts.toViewConst() ); - return vtk::redistribute( *splitMesh, MPI_COMM_GEOSX ); + return vtk::redistribute( *splitMesh, MPI_COMM_GEOS ); } @@ -910,7 +914,7 @@ redistributeMeshes( integer const logLevel, } // Generate global IDs for vertices and cells, if needed - vtkSmartPointer< vtkDataSet > mesh = manageGlobalIds( loadedMesh, useGlobalIds ); + vtkSmartPointer< vtkDataSet > mesh = manageGlobalIds( loadedMesh, useGlobalIds, !std::empty( fractures ) ); if( MpiWrapper::commRank( comm ) != ( MpiWrapper::commSize( comm ) - 1 ) ) { @@ -971,7 +975,7 @@ redistributeMeshes( integer const logLevel, * @brief Identify the GEOSX type of the polyhedron * * @param cell The vtk cell VTK_POLYHEDRON - * @return The geosx element type associated to VTK_POLYHEDRON + * @return The geos element type associated to VTK_POLYHEDRON */ geos::ElementType buildGeosxPolyhedronType( vtkCell * const cell ) { @@ -1696,7 +1700,7 @@ std::vector< int > getVtkToGeosxNodeOrdering( ElementType const elemType ) case ElementType::Prism6: return { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; default: { - GEOS_ERROR( "Cannot get vtk to geosx node ordering based on geosx element type " << elemType ); + GEOS_ERROR( "Cannot get vtk to geos node ordering based on geos element type " << elemType ); break; } } @@ -1720,7 +1724,7 @@ std::vector< int > getVtkToGeosxNodeOrdering( VTKCellType const vtkType ) case VTK_HEXAGONAL_PRISM: return getVtkToGeosxNodeOrdering( ElementType::Prism6 ); default: { - GEOS_ERROR( "Cannot get vtk to geosx node ordering based on vtk cell type " << vtkType ); + GEOS_ERROR( "Cannot get vtk to geos node ordering based on vtk cell type " << vtkType ); break; } } @@ -1813,36 +1817,6 @@ void fillCellBlock( vtkDataSet & mesh, } } -/** - * @brief Returns a string describing the element. - * @param[in] type The element type. - * @return The name. - * @warning This information will be visible in the input file... Consider refactoring with great care. - */ -string getElementTypeName( ElementType const type ) -{ - switch( type ) - { - case ElementType::Hexahedron: return "hexahedra"; - case ElementType::Tetrahedron: return "tetrahedra"; - case ElementType::Wedge: return "wedges"; - case ElementType::Pyramid: return "pyramids"; - case ElementType::Prism5: return "pentagonalPrisms"; - case ElementType::Prism6: return "hexagonalPrisms"; - case ElementType::Prism7: return "heptagonalPrisms"; - case ElementType::Prism8: return "octagonalPrisms"; - case ElementType::Prism9: return "nonagonalPrisms"; - case ElementType::Prism10: return "decagonalPrisms"; - case ElementType::Prism11: return "hendecagonalPrisms"; - case ElementType::Polyhedron: return "polyhedra"; - default: - { - GEOS_ERROR( "Element type '" << type << "' is not supported" ); - return {}; - } - } -} - void importMaterialField( std::vector< vtkIdType > const & cellIds, vtkDataArray * vtkArray, WrapperBase & wrapper ) @@ -2110,8 +2084,8 @@ real64 writeNodes( integer const logLevel, bb.GetMaxPoint( xMax ); } - MpiWrapper::min< real64 >( xMin, xMin, MPI_COMM_GEOSX ); - MpiWrapper::max< real64 >( xMax, xMax, MPI_COMM_GEOSX ); + MpiWrapper::min< real64 >( xMin, xMin, MPI_COMM_GEOS ); + MpiWrapper::max< real64 >( xMax, xMax, MPI_COMM_GEOS ); LvArray::tensorOps::subtract< 3 >( xMax, xMin ); return LvArray::tensorOps::l2Norm< 3 >( xMax ); } @@ -2139,7 +2113,7 @@ void writeCells( integer const logLevel, GEOS_LOG_RANK_0_IF( logLevel >= 1, "Importing cell block " << cellBlockName ); // Create and resize the cell block. - CellBlock & cellBlock = cellBlockManager.registerCellBlock( cellBlockName ); + CellBlock & cellBlock = cellBlockManager.registerCellBlock( cellBlockName, regionId ); cellBlock.setElementType( elemType ); cellBlock.resize( LvArray::integerConversion< localIndex >( cellIds.size() ) ); diff --git a/src/coreComponents/mesh/generators/VTKUtilities.hpp b/src/coreComponents/mesh/generators/VTKUtilities.hpp index bbe3581877b..0a2f5f3903a 100644 --- a/src/coreComponents/mesh/generators/VTKUtilities.hpp +++ b/src/coreComponents/mesh/generators/VTKUtilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,23 +21,18 @@ #define GEOS_MESH_GENERATORS_VTKUTILITIES_HPP #include "common/DataTypes.hpp" -#include "common/DataLayouts.hpp" #include "common/MpiWrapper.hpp" -#include "mesh/DomainPartition.hpp" #include "mesh/generators/CellBlockManager.hpp" -#include #include #include +#include #include #include namespace geos { - -using namespace dataRepository; - namespace vtk { @@ -223,7 +219,7 @@ string buildCellBlockName( ElementType const type, int const regionId ); */ void importMaterialField( std::vector< vtkIdType > const & cellIds, vtkDataArray * vtkArray, - WrapperBase & wrapper ); + dataRepository::WrapperBase & wrapper ); /** * @brief Imports 1d and 2d arrays from @p vtkArray to @p wrapper, only for @p cellIds @@ -233,7 +229,7 @@ void importMaterialField( std::vector< vtkIdType > const & cellIds, */ void importRegularField( std::vector< vtkIdType > const & cellIds, vtkDataArray * vtkArray, - WrapperBase & wrapper ); + dataRepository::WrapperBase & wrapper ); /** * @brief Imports 1d and 2d arrays from @p vtkArray to @p wrapper, for all the elements/cells of the provided wrapper. @@ -241,7 +237,7 @@ void importRegularField( std::vector< vtkIdType > const & cellIds, * @param wrapper The destination. */ void importRegularField( vtkDataArray * vtkArray, - WrapperBase & wrapper ); + dataRepository::WrapperBase & wrapper ); } // namespace vtk diff --git a/src/coreComponents/mesh/generators/VTKWellGenerator.cpp b/src/coreComponents/mesh/generators/VTKWellGenerator.cpp index 3dc7fe343bf..b52409d3f68 100644 --- a/src/coreComponents/mesh/generators/VTKWellGenerator.cpp +++ b/src/coreComponents/mesh/generators/VTKWellGenerator.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,7 +22,6 @@ #include "mesh/generators/VTKUtilities.hpp" #include -#include #include #include #include @@ -101,5 +101,5 @@ void VTKWellGenerator::fillPolylineDataStructure( ) } } -REGISTER_CATALOG_ENTRY( WellGeneratorBase, VTKWellGenerator, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( MeshComponentBase, VTKWellGenerator, string const &, Group * const ) } diff --git a/src/coreComponents/mesh/generators/VTKWellGenerator.hpp b/src/coreComponents/mesh/generators/VTKWellGenerator.hpp index 1290db3f7fe..3454044beba 100644 --- a/src/coreComponents/mesh/generators/VTKWellGenerator.hpp +++ b/src/coreComponents/mesh/generators/VTKWellGenerator.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,6 @@ #define GEOS_MESH_GENERATORS_VTKWELLGENERATOR_HPP #include "mesh/generators/WellGeneratorBase.hpp" -#include "mesh/Perforation.hpp" #include "dataRepository/Group.hpp" #include "codingUtilities/Utilities.hpp" #include "common/DataTypes.hpp" diff --git a/src/coreComponents/mesh/generators/WellGeneratorABC.hpp b/src/coreComponents/mesh/generators/WellGeneratorABC.hpp deleted file mode 100644 index e1b879de296..00000000000 --- a/src/coreComponents/mesh/generators/WellGeneratorABC.hpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/* - * @file WellGeneratorABC.hpp - * - */ - -#ifndef GEOS_MESH_GENERATORS_WELLGENERATORABC_HPP_ -#define GEOS_MESH_GENERATORS_WELLGENERATORABC_HPP_ - -#include "dataRepository/Group.hpp" -#include "codingUtilities/Utilities.hpp" -#include "common/DataTypes.hpp" - - -namespace geos -{ - -/** - * @class WellGeneratorABC - * - * Abstract base class defining the information provided by any the well generator class. - */ -class WellGeneratorABC : public dataRepository::Group -{ -public: - - /** - * @brief Constructor. - * @param name name of the object in the data hierarchy. - * @param parent pointer to the parent group in the data hierarchy. - */ - WellGeneratorABC( const string & name, - Group * const parent ) - : - Group( name, parent ) - { } - - /** - * @brief Main function of the class that generates the well geometry - */ - virtual void generateWellGeometry( ) = 0; - - /** - * @name Getters / Setters - */ - ///@{ - - // getters for element data - - /** - * @brief Get the global number of well elements. - * @return the global number of elements - */ - virtual globalIndex numElements() const = 0; - - /** - * @brief Getter to the Segment to PolyNode mapping - * @return The Segment to PolyNode mapping as a 2D array - */ - virtual const array2d< globalIndex > & getSegmentToPolyNodeMap() const = 0; - - /** - * @brief Get the number of nodes per well element - * @return the number of nodes per well element - */ - virtual globalIndex numNodesPerElement() const = 0; - - /** - * @brief Get the Coordinates of the polyline nodes - * @return the Coordinates of the polyline nodes - */ - virtual const array2d< real64 > & getPolyNodeCoord() const = 0; - - /** - * @return The minimum segment length - */ - virtual real64 getMinSegmentLength() const = 0; - - /** - * @return The minimum element length - */ - virtual real64 getMinElemLength() const = 0; - - /** - * @return The list of perforation names - */ - virtual const string_array & getPerforationList() const = 0; - - /** - * @brief Get the physical location of the centers of well elements. - * @return list of center locations of the well elements - */ - virtual arrayView2d< real64 const > getElemCoords() const = 0; - - /** - * @brief Get the global indices mapping an element to the next. - * @return list providing the global index of the next element for each element - */ - virtual arrayView1d< globalIndex const > getNextElemIndex() const = 0; - - /** - * @brief Get the global indices mapping an element to the previous ones. - * @return list providing the global indices of the previous elements for each element - */ - virtual arrayView1d< arrayView1d< globalIndex const > const > getPrevElemIndices() const = 0; - - /** - * @brief Get the global indices of the well nodes nodes connected to each element. - * @return list providing the global index of the well nodes for each well element - */ - virtual arrayView2d< globalIndex const > getElemToNodesMap() const = 0; - - /** - * @brief Get the volume of the well elements. - * @return list of volumes of the well elements - */ - virtual arrayView1d< real64 const > getElemVolume() const = 0; - - /** - * @brief Get the radius in the well. - * @return the radius in the well - */ - virtual real64 getElementRadius() const = 0; - - // getters for node data - - /** - * @brief Get the global number of well nodes. - * @return the global number of nodes - */ - virtual globalIndex numNodes() const = 0; - - /** - * @brief Get the physical location of the centers of well elements. - * @return list of center locations of the well elements - */ - virtual arrayView2d< real64 const > getNodeCoords() const = 0; - - - - // getters for perforation data - /** - * @brief Get the global number of perforations on this well. - * @return the global number of elements - */ - virtual globalIndex numPerforations() const = 0; - - /** - * @brief Get the locations of the perforations. - * @return list of locations of all the perforations on the well - */ - virtual arrayView2d< real64 const > getPerfCoords() const = 0; - - /** - * @brief Get the well transmissibility at the perforations. - * @return list of well transmissibility at all the perforations on the well - */ - virtual arrayView1d< real64 const > getPerfTransmissibility() const = 0; - - /** - * @brief Get the skin factor at a perforation. - * @return the skin factor at a perforation - */ - virtual arrayView1d< real64 const > getPerfSkinFactor() const = 0; - - /** - * @brief Get the global indices of the well elements connected to each perforation. - * @return list providing the global index of the connected well element for each perforation - */ - virtual arrayView1d< globalIndex const > getPerfElemIndex() const = 0; - - /** - * @returns The number of physical dimensions - */ - virtual int getPhysicalDimensionsNumber() const = 0; - - /** - * Getter for the associated well region name - * @return the associated well region name - */ - virtual const string getWellRegionName() const = 0; - - /** - * Getter for the associated well control name - * @return the associated well control name - */ - virtual const string getWellControlsName() const = 0; - ///@} -}; -} -#endif /* GEOS_MESH_GENERATORS_WELLGENERATORABC_HPP_ */ diff --git a/src/coreComponents/mesh/generators/WellGeneratorBase.cpp b/src/coreComponents/mesh/generators/WellGeneratorBase.cpp index 554f4530bf7..f64e0e9b7d0 100644 --- a/src/coreComponents/mesh/generators/WellGeneratorBase.cpp +++ b/src/coreComponents/mesh/generators/WellGeneratorBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,13 +18,14 @@ #include "mesh/Perforation.hpp" #include "mesh/generators/LineBlockABC.hpp" #include "LvArray/src/genericTensorOps.hpp" - +#include "common/format/table/TableFormatter.hpp" +#include "common/format/Format.hpp" namespace geos { using namespace dataRepository; WellGeneratorBase::WellGeneratorBase( string const & name, Group * const parent ): - WellGeneratorABC( name, parent ) + MeshComponentBase( name, parent ) , m_numPerforations( 0 ) , m_numElemsPerSegment( 0 ) , m_minSegmentLength( 1e-2 ) @@ -37,8 +39,6 @@ WellGeneratorBase::WellGeneratorBase( string const & name, Group * const parent , m_nDims( 3 ) , m_polylineHeadNodeId( -1 ) { - setInputFlags( InputFlags::OPTIONAL_NONUNIQUE ); - registerWrapper( viewKeyStruct::radiusString(), &m_radius ). setInputFlag( InputFlags::REQUIRED ). setSizedFromParent( 0 ). @@ -80,7 +80,7 @@ Group * WellGeneratorBase::createChild( string const & childKey, string const & // keep track of the perforations that have been added m_perforationList.emplace_back( childName ); - GEOS_LOG_RANK_0( "Adding Well attribute: " << childKey << ", " << childName ); + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) ); return ®isterGroup< Perforation >( childName ); } else @@ -95,12 +95,6 @@ void WellGeneratorBase::expandObjectCatalogs() createChild( viewKeyStruct::perforationString(), viewKeyStruct::perforationString() ); } -WellGeneratorBase::CatalogInterface::CatalogType & WellGeneratorBase::getCatalog() -{ - static WellGeneratorBase::CatalogInterface::CatalogType catalog; - return catalog; -} - void WellGeneratorBase::generateWellGeometry( ) { fillPolylineDataStructure(); @@ -141,14 +135,15 @@ void WellGeneratorBase::generateWellGeometry( ) // make sure that the perforation locations are valid checkPerforationLocationsValidity(); - if( getLogLevel() >= 1 ) + if( getLogLevel() >= 1 && MpiWrapper::commRank() == 0 ) { - debugWellGeometry(); + logInternalWell(); + logPerforationTable(); } } -void WellGeneratorBase::postProcessInput() +void WellGeneratorBase::postInputInitialization() { GEOS_THROW_IF( m_radius <= 0, "Invalid " << viewKeyStruct::radiusString() << " in well " << getName(), @@ -453,7 +448,7 @@ void WellGeneratorBase::checkPerforationLocationsValidity() // merge perforations to make sure that no well element is shared between two MPI domains // TODO: instead of merging perforations, split the well elements and do not change the physical location of the // perforation - int const mpiSize = MpiWrapper::commSize( MPI_COMM_GEOSX ); + int const mpiSize = MpiWrapper::commSize( MPI_COMM_GEOS ); if( mpiSize > 1 ) { mergePerforations( elemToPerfMap ); @@ -521,62 +516,58 @@ void WellGeneratorBase::mergePerforations( array1d< array1d< localIndex > > cons } } -void WellGeneratorBase::debugWellGeometry() const +void WellGeneratorBase::logInternalWell() const { - if( MpiWrapper::commRank( MPI_COMM_GEOSX ) != 0 ) - { - return; - } - - std::cout << std::endl; - std::cout << "++++++++++++++++++++++++++" << std::endl; - std::cout << "WellGeneratorBase = " << getName() << std::endl; - std::cout << "MPI rank = " << MpiWrapper::commRank( MPI_COMM_GEOSX ) << std::endl << std::endl; - std::cout << "Number of well elements = " << m_numElems << std::endl; - + TableData tableWellData; for( globalIndex iwelem = 0; iwelem < m_numElems; ++iwelem ) { - std::cout << "Well element #" << iwelem << std::endl; - std::cout << "Coordinates of the element center: " << m_elemCenterCoords[iwelem] << std::endl; - if( m_nextElemId[iwelem] < 0 ) - { - std::cout << "No next well element" << std::endl; - } - else - { - std::cout << "Next well element # = " << m_nextElemId[iwelem] << std::endl; - } - if( m_prevElemId[iwelem][0] < 0 ) - { - std::cout << "No previous well element" << std::endl; - } - else + std::optional< globalIndex > nextElement; + std::optional< globalIndex > prevElement; + + if( m_nextElemId[iwelem] >= 0 ) { - std::cout << "Previous well element #" << m_prevElemId[iwelem][0] << std::endl; + nextElement = m_nextElemId[iwelem]; } - for( globalIndex inode = 0; inode < m_numNodesPerElem; ++inode ) + + if( m_prevElemId[iwelem][0] >= 0 ) { - if( inode == 0 ) - { - std::cout << "First well node: #" << m_elemToNodesMap[iwelem][inode] << std::endl; - } - else - { - std::cout << "Second well node: #" << m_elemToNodesMap[iwelem][inode] << std::endl; - } + prevElement = m_prevElemId[iwelem][0]; } + + tableWellData.addRow( iwelem, + m_elemCenterCoords[iwelem][0], + m_elemCenterCoords[iwelem][1], + m_elemCenterCoords[iwelem][2], + prevElement, + nextElement ); } - std::cout << std::endl << "Number of perforations = " << m_numPerforations << std::endl; + string const wellTitle = GEOS_FMT( "Well '{}' Element Table", getName() ); + TableLayout const tableWellLayout = TableLayout( { + TableLayout::ColumnParam{"Element no.", TableLayout::Alignment::right}, + TableLayout::ColumnParam{"CoordX", TableLayout::Alignment::right}, + TableLayout::ColumnParam{"CoordY", TableLayout::Alignment::right}, + TableLayout::ColumnParam{"CoordZ", TableLayout::Alignment::right}, + TableLayout::ColumnParam{"Prev\nElement", TableLayout::Alignment::right}, + TableLayout::ColumnParam{"Next\nElement", TableLayout::Alignment::right}, + }, wellTitle ); + + TableTextFormatter const tableFormatter( tableWellLayout ); + GEOS_LOG_RANK_0( tableFormatter.toString( tableWellData )); +} +void WellGeneratorBase::logPerforationTable() const +{ + TableData tablePerfoData; for( globalIndex iperf = 0; iperf < m_numPerforations; ++iperf ) { - std::cout << "Perforation #" << iperf << std::endl; - std::cout << "Coordinates of the perforation: " << m_perfCoords[iperf] << std::endl; - std::cout << "Is connected to well element #" << m_perfElemId[iperf] << std::endl; + tablePerfoData.addRow( iperf, m_perfCoords[iperf], m_perfElemId[iperf] ); } - std::cout << std::endl; + TableLayout const tableLayoutPerfo ( {"Perforation no.", "Coordinates", "Well element no."}, + GEOS_FMT( "Well '{}' Perforation Table", getName() ) ); + TableTextFormatter const tablePerfoLog( tableLayoutPerfo ); + GEOS_LOG_RANK_0( tablePerfoLog.toString( tablePerfoData )); } } diff --git a/src/coreComponents/mesh/generators/WellGeneratorBase.hpp b/src/coreComponents/mesh/generators/WellGeneratorBase.hpp index a4c6cb5f577..fbe05157d6f 100644 --- a/src/coreComponents/mesh/generators/WellGeneratorBase.hpp +++ b/src/coreComponents/mesh/generators/WellGeneratorBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #ifndef GEOS_MESH_GENERATORS_WELLGENERATORBASE_HPP_ #define GEOS_MESH_GENERATORS_WELLGENERATORBASE_HPP_ -#include "mesh/generators/WellGeneratorABC.hpp" +#include "mesh/generators/MeshComponentBase.hpp" #include "dataRepository/Group.hpp" #include "codingUtilities/Utilities.hpp" #include "common/DataTypes.hpp" @@ -34,7 +35,7 @@ namespace geos * * This class processes the data of a single well from the XML and generates the well geometry */ -class WellGeneratorBase : public WellGeneratorABC +class WellGeneratorBase : public MeshComponentBase { public: @@ -46,19 +47,9 @@ class WellGeneratorBase : public WellGeneratorABC WellGeneratorBase( const string & name, Group * const parent ); - /** - * @brief Get the catalog name. - * @return the name of this type in the catalog - */ - static string catalogName() { return "WellGeneratorBase"; } - /// This function is used to expand any catalogs in the data structure virtual void expandObjectCatalogs() override; - /// using alias for templated Catalog meshGenerator type - using CatalogInterface = dataRepository::CatalogInterface< WellGeneratorBase, string const &, Group * const >; - - /** * @brief Create a new geometric object (box, plane, etc) as a child of this group. * @param childKey the catalog key of the new geometric object to create @@ -67,16 +58,10 @@ class WellGeneratorBase : public WellGeneratorABC */ virtual Group * createChild( string const & childKey, string const & childName ) override; - /** - * @brief Accessor for the singleton Catalog object - * @return a static reference to the Catalog object - */ - static CatalogInterface::CatalogType & getCatalog(); - /** * @brief Main function of the class that generates the well geometry */ - void generateWellGeometry( ) override; + void generateWellGeometry( ); /** @@ -90,76 +75,76 @@ class WellGeneratorBase : public WellGeneratorABC * @brief Get the global number of well elements. * @return the global number of elements */ - globalIndex numElements() const override { return m_numElems; } + globalIndex numElements() const { return m_numElems; } /** * @brief Getter to the Segment to PolyNode mapping * @return The Segment to PolyNode mapping as a 2D array */ - const array2d< globalIndex > & getSegmentToPolyNodeMap() const override { return m_segmentToPolyNodeMap; }; + const array2d< globalIndex > & getSegmentToPolyNodeMap() const { return m_segmentToPolyNodeMap; }; /** * @brief Get the number of nodes per well element * @return the number of nodes per well element */ - globalIndex numNodesPerElement() const override { return m_numNodesPerElem; } + globalIndex numNodesPerElement() const { return m_numNodesPerElem; } /** * @brief Get the Coordinates of the polyline nodes * @return the Coordinates of the polyline nodes */ - const array2d< real64 > & getPolyNodeCoord() const override { return m_polyNodeCoords; } + const array2d< real64 > & getPolyNodeCoord() const { return m_polyNodeCoords; } /** * @return The minimum segment length */ - real64 getMinSegmentLength() const override { return m_minSegmentLength; } + real64 getMinSegmentLength() const { return m_minSegmentLength; } /** * @return The minimum element length */ - real64 getMinElemLength() const override { return m_minElemLength; } + real64 getMinElemLength() const { return m_minElemLength; } /** * @return The list of perforation names */ - const string_array & getPerforationList() const override { return m_perforationList; } + const string_array & getPerforationList() const { return m_perforationList; } /** * @brief Get the physical location of the centers of well elements. * @return list of center locations of the well elements */ - arrayView2d< real64 const > getElemCoords() const override { return m_elemCenterCoords; } + arrayView2d< real64 const > getElemCoords() const { return m_elemCenterCoords; } /** * @brief Get the global indices mapping an element to the next. * @return list providing the global index of the next element for each element */ - arrayView1d< globalIndex const > getNextElemIndex() const override { return m_nextElemId; } + arrayView1d< globalIndex const > getNextElemIndex() const { return m_nextElemId; } /** * @brief Get the global indices mapping an element to the previous ones. * @return list providing the global indices of the previous elements for each element */ - arrayView1d< arrayView1d< globalIndex const > const > getPrevElemIndices() const override { return m_prevElemId.toNestedViewConst(); } + arrayView1d< arrayView1d< globalIndex const > const > getPrevElemIndices() const { return m_prevElemId.toNestedViewConst(); } /** * @brief Get the global indices of the well nodes nodes connected to each element. * @return list providing the global index of the well nodes for each well element */ - arrayView2d< globalIndex const > getElemToNodesMap() const override { return m_elemToNodesMap; } + arrayView2d< globalIndex const > getElemToNodesMap() const { return m_elemToNodesMap; } /** * @brief Get the volume of the well elements. * @return list of volumes of the well elements */ - arrayView1d< real64 const > getElemVolume() const override { return m_elemVolume; } + arrayView1d< real64 const > getElemVolume() const { return m_elemVolume; } /** * @brief Get the radius in the well. * @return the radius in the well */ - real64 getElementRadius() const override { return m_radius; } + real64 getElementRadius() const { return m_radius; } // getters for node data @@ -167,61 +152,61 @@ class WellGeneratorBase : public WellGeneratorABC * @brief Get the global number of well nodes. * @return the global number of nodes */ - globalIndex numNodes() const override { return m_numNodes; } + globalIndex numNodes() const { return m_numNodes; } /** * @brief Get the physical location of the centers of well elements. * @return list of center locations of the well elements */ - arrayView2d< real64 const > getNodeCoords() const override { return m_nodeCoords; } + arrayView2d< real64 const > getNodeCoords() const { return m_nodeCoords; } // getters for perforation data /** * @brief Get the global number of perforations on this well. * @return the global number of elements */ - globalIndex numPerforations() const override { return m_numPerforations; } + globalIndex numPerforations() const { return m_numPerforations; } /** * @brief Get the locations of the perforations. * @return list of locations of all the perforations on the well */ - arrayView2d< real64 const > getPerfCoords() const override { return m_perfCoords; } + arrayView2d< real64 const > getPerfCoords() const { return m_perfCoords; } /** * @brief Get the well transmissibility at the perforations. * @return list of well transmissibility at all the perforations on the well */ - arrayView1d< real64 const > getPerfTransmissibility() const override { return m_perfTransmissibility; } + arrayView1d< real64 const > getPerfTransmissibility() const { return m_perfTransmissibility; } /** * @brief Get the skin factor at a perforation. * @return the skin factor at a perforation */ - arrayView1d< real64 const > getPerfSkinFactor() const override { return m_perfSkinFactor; }; + arrayView1d< real64 const > getPerfSkinFactor() const { return m_perfSkinFactor; }; /** * @brief Get the global indices of the well elements connected to each perforation. * @return list providing the global index of the connected well element for each perforation */ - arrayView1d< globalIndex const > getPerfElemIndex() const override { return m_perfElemId; } + arrayView1d< globalIndex const > getPerfElemIndex() const { return m_perfElemId; } /** * @returns The number of physical dimensions */ - int getPhysicalDimensionsNumber() const override { return m_nDims; } + int getPhysicalDimensionsNumber() const { return m_nDims; } /** * Getter for the associated well region name * @return the associated well region name */ - const string getWellRegionName() const override { return m_wellRegionName; } + const string getWellRegionName() const { return m_wellRegionName; } /** * Getter for the associated well control name * @return the associated well control name */ - const string getWellControlsName() const override { return m_wellControlsName; } + const string getWellControlsName() const { return m_wellControlsName; } ///@cond DO_NOT_DOCUMENT struct viewKeyStruct @@ -244,7 +229,7 @@ class WellGeneratorBase : public WellGeneratorABC * @brief This function provides capability to post process input values prior to * any other initialization operations. */ - void postProcessInput() override; + void postInputInitialization() override; /** * @name Helper functions to construct the geometry of the well @@ -301,7 +286,8 @@ class WellGeneratorBase : public WellGeneratorABC ///@} /// @cond DO_NOT_DOCUMENT - void debugWellGeometry() const; + void logInternalWell() const; + void logPerforationTable() const; /// @endcond /// Global number of perforations diff --git a/src/coreComponents/mesh/mpiCommunications/CommID.cpp b/src/coreComponents/mesh/mpiCommunications/CommID.cpp index 0976c0e7950..da6d47a48cb 100644 --- a/src/coreComponents/mesh/mpiCommunications/CommID.cpp +++ b/src/coreComponents/mesh/mpiCommunications/CommID.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -14,7 +15,7 @@ #include "CommID.hpp" -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" #include diff --git a/src/coreComponents/mesh/mpiCommunications/CommID.hpp b/src/coreComponents/mesh/mpiCommunications/CommID.hpp index 143e55eb18c..259fc340985 100644 --- a/src/coreComponents/mesh/mpiCommunications/CommID.hpp +++ b/src/coreComponents/mesh/mpiCommunications/CommID.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -43,8 +44,6 @@ class CommID */ ~CommID(); - /// default copy constructor - CommID( CommID const & ) = default; /** * Move constructor @@ -52,6 +51,9 @@ class CommID */ CommID( CommID && src ); + /// deleted default copy constructor + CommID( CommID const & ) = delete; + /// deleted copy assignment operator CommID & operator=( CommID const & ) = delete; @@ -59,7 +61,7 @@ class CommID CommID & operator=( CommID && ) = delete; /// user defined conversion operator to int - constexpr operator int() + constexpr operator int() const { return m_id; } private: diff --git a/src/coreComponents/mesh/mpiCommunications/CommunicationTools.cpp b/src/coreComponents/mesh/mpiCommunications/CommunicationTools.cpp index 6562b8ffa07..0abb2fc2f53 100644 --- a/src/coreComponents/mesh/mpiCommunications/CommunicationTools.cpp +++ b/src/coreComponents/mesh/mpiCommunications/CommunicationTools.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -120,7 +121,7 @@ void CommunicationTools::assignGlobalIndices( ObjectManagerBase & manager, integer const numNeighbors = LvArray::integerConversion< integer >( neighbors.size() ); - MPI_iCommData commData( getCommID() ); + MPI_iCommData commData; commData.resize( numNeighbors ); array1d< int > receiveBufferSizes( numNeighbors ); @@ -138,7 +139,7 @@ void CommunicationTools::assignGlobalIndices( ObjectManagerBase & manager, 1, commData.mpiRecvBufferSizeRequest( neighborIndex ), commData.commID(), - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); } for( std::size_t count=0; counttempNeighborData.neighborNumbers[DomainPartition::FiniteElementNodeManager] to @@ -270,7 +271,7 @@ void CommunicationTools::assignGlobalIndices( ObjectManagerBase & manager, void CommunicationTools::assignNewGlobalIndices( ObjectManagerBase & manager, std::set< localIndex > const & indexList ) { - globalIndex const glocalIndexOffset = MpiWrapper::prefixSum< globalIndex >( indexList.size(), MPI_COMM_GEOSX ); + globalIndex const glocalIndexOffset = MpiWrapper::prefixSum< globalIndex >( indexList.size(), MPI_COMM_GEOS ); arrayView1d< globalIndex > const & localToGlobal = manager.localToGlobalMap(); @@ -300,7 +301,7 @@ CommunicationTools::assignNewGlobalIndices( ElementRegionManager & elementManage numberOfNewObjectsHere += LvArray::integerConversion< localIndex >( iter.second.size() ); } - globalIndex const glocalIndexOffset = MpiWrapper::prefixSum< globalIndex >( numberOfNewObjectsHere, MPI_COMM_GEOSX ); + globalIndex const glocalIndexOffset = MpiWrapper::prefixSum< globalIndex >( numberOfNewObjectsHere, MPI_COMM_GEOS ); localIndex nIndicesAssigned = 0; for( auto const & iter : newElems ) @@ -339,11 +340,11 @@ CommunicationTools::assignNewGlobalIndices( ElementRegionManager & elementManage * @return The data received from all the @p neighbors. Data at index @p i coming from neighbor at index @p i in the list of @p neighbors. */ template< class DATA_PROVIDER > -array1d< array1d< globalIndex > > exchange( int commId, - std::vector< NeighborCommunicator > & neighbors, +array1d< array1d< globalIndex > > exchange( std::vector< NeighborCommunicator > & neighbors, DATA_PROVIDER const & data ) { - MPI_iCommData commData( commId ); + MPI_iCommData commData; + int commId = commData.commID(); integer const numNeighbors = LvArray::integerConversion< integer >( neighbors.size() ); commData.resize( numNeighbors ); for( integer i = 0; i < numNeighbors; ++i ) @@ -352,7 +353,7 @@ array1d< array1d< globalIndex > > exchange( int commId, commData.mpiSendBufferSizeRequest( i ), commData.mpiRecvBufferSizeRequest( i ), commId, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); } MpiWrapper::waitAll( numNeighbors, commData.mpiSendBufferSizeRequest(), commData.mpiSendBufferSizeStatus() ); @@ -367,7 +368,7 @@ array1d< array1d< globalIndex > > exchange( int commId, output[i], commData.mpiRecvBufferRequest( i ), commId, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); } MpiWrapper::waitAll( numNeighbors, commData.mpiSendBufferRequest(), commData.mpiSendBufferStatus() ); MpiWrapper::waitAll( numNeighbors, commData.mpiRecvBufferRequest(), commData.mpiRecvBufferStatus() ); @@ -390,7 +391,7 @@ CommunicationTools::buildNeighborPartitionBoundaryObjects( ObjectManagerBase & m { return std::cref( globalPartitionBoundaryObjectsIndices ); }; - array1d< array1d< globalIndex > > const neighborPartitionBoundaryObjects = exchange( getCommID(), allNeighbors, data ); + array1d< array1d< globalIndex > > const neighborPartitionBoundaryObjects = exchange( allNeighbors, data ); integer const numNeighbors = LvArray::integerConversion< integer >( allNeighbors.size() ); for( integer i = 0; i < numNeighbors; ++i ) @@ -565,7 +566,7 @@ void CommunicationTools::findMatchedPartitionBoundaryNodes( NodeManager & nodeMa { return req.at( allNeighbors[i].neighborRank() ); }; - array1d< array1d< globalIndex > > const nodesRequestedByNeighbors = exchange( getCommID(), allNeighbors, data ); + array1d< array1d< globalIndex > > const nodesRequestedByNeighbors = exchange( allNeighbors, data ); // Then we store the requested nodes for each receiver. for( integer i = 0; i < numNeighbors; ++i ) @@ -679,7 +680,7 @@ void fixReceiveLists( ObjectManagerBase & objectManager, MpiWrapper::iSend( objectManager.getNeighborData( neighborRank ).nonLocalGhosts().toView(), neighborRank, nonLocalGhostsTag, - MPI_COMM_GEOSX, + MPI_COMM_GEOS, &nonLocalGhostsRequests[ i ] ); } @@ -692,7 +693,7 @@ void fixReceiveLists( ObjectManagerBase & objectManager, MpiWrapper::recv( ghostsFromSecondNeighbor, neighborRank, nonLocalGhostsTag, - MPI_COMM_GEOSX, + MPI_COMM_GEOS, MPI_STATUS_IGNORE ); /// Array of ghosts to fix. @@ -803,7 +804,7 @@ void CommunicationTools::setupGhosts( MeshLevel & meshLevel, bool const unorderedComms ) { GEOS_MARK_FUNCTION; - MPI_iCommData commData( getCommID() ); + MPI_iCommData commData; commData.resize( neighbors.size() ); NodeManager & nodeManager = meshLevel.getNodeManager(); @@ -850,6 +851,12 @@ void CommunicationTools::setupGhosts( MeshLevel & meshLevel, MpiWrapper::waitAll( commData.size(), commData.mpiSendBufferSizeRequest(), commData.mpiSendBufferSizeStatus() ); MpiWrapper::waitAll( commData.size(), commData.mpiSendBufferRequest(), commData.mpiSendBufferStatus() ); + // unpack the ghost inter-object maps and other data + for( auto & neighbor : neighbors ) + { + neighbor.unpackGhostsData( meshLevel, commData.commID() ); + } + nodeManager.setReceiveLists(); edgeManager.setReceiveLists(); faceManager.setReceiveLists(); @@ -941,7 +948,7 @@ void CommunicationTools::synchronizePackSendRecvSizes( FieldIdentifiers const & neighbor.mpiISendReceiveBufferSizes( icomm.commID(), icomm.mpiSendBufferSizeRequest( neighborIndex ), icomm.mpiRecvBufferSizeRequest( neighborIndex ), - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); neighbor.resizeSendBuffer( icomm.commID(), bufferSize ); } @@ -991,7 +998,7 @@ void CommunicationTools::asyncSendRecv( std::vector< NeighborCommunicator > & ne neighbor.mpiISendReceiveBuffers( icomm.commID(), icomm.mpiSendBufferRequest( neighborIndex ), icomm.mpiRecvBufferRequest( neighborIndex ), - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); } } @@ -1091,11 +1098,85 @@ void CommunicationTools::synchronizeFields( FieldIdentifiers const & fieldsToBeS std::vector< NeighborCommunicator > & neighbors, bool onDevice ) { - MPI_iCommData icomm( getCommID() ); + MPI_iCommData icomm; icomm.resize( neighbors.size() ); synchronizePackSendRecvSizes( fieldsToBeSync, mesh, neighbors, icomm, onDevice ); synchronizePackSendRecv( fieldsToBeSync, mesh, neighbors, icomm, onDevice ); synchronizeUnpack( mesh, neighbors, icomm, onDevice ); } + +void CommunicationTools::checkSendRecv( ObjectManagerBase const & objectManager, + std::vector< NeighborCommunicator > & neighbors ) +{ + MPI_iCommData commData; + commData.resize( neighbors.size() ); + arrayView1d< globalIndex const > const & localToGlobal = objectManager.localToGlobalMap(); + + std::cout< const ghostsToSend = objectManager.getNeighborData( neighborRank ).ghostsToSend(); + array1d< globalIndex > ghostsToSendGlobal( ghostsToSend.size() ); + + std::cout<<" Rank "< ghostThatAreSentToMeGlobal; + + MpiWrapper::recv( ghostThatAreSentToMeGlobal, + neighborRank, + tag, + MPI_COMM_GEOS, + &commData.mpiRecvBufferStatus( i ) ); + + arrayView1d< localIndex const > const ghostsToRecv = objectManager.getNeighborData( neighborRank ).ghostsToReceive(); + array1d< globalIndex > ghostToRecvGlobal( ghostsToRecv.size() ); + + + std::cout<<" Rank "< & neighbors ); + private: std::set< int > m_freeCommIDs; static CommunicationTools * m_instance; diff --git a/src/coreComponents/mesh/mpiCommunications/MPI_iCommData.cpp b/src/coreComponents/mesh/mpiCommunications/MPI_iCommData.cpp index bce3d4ba45e..59be5f37fc6 100644 --- a/src/coreComponents/mesh/mpiCommunications/MPI_iCommData.cpp +++ b/src/coreComponents/mesh/mpiCommunications/MPI_iCommData.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -13,13 +14,14 @@ */ #include "MPI_iCommData.hpp" +#include "CommunicationTools.hpp" namespace geos { -MPI_iCommData::MPI_iCommData( int const inputCommID ): +MPI_iCommData::MPI_iCommData(): m_size( 0 ), - m_commID( inputCommID ), // CommunicationTools::getInstance().getCommID() ), + m_commID( CommunicationTools::getInstance().getCommID() ), m_mpiSendBufferRequest(), m_mpiRecvBufferRequest(), m_mpiSendBufferStatus(), @@ -35,14 +37,14 @@ MPI_iCommData::~MPI_iCommData() { for( int neighbor=0; neighbor >; -using ElemAdjListRefWrapType = ElementRegionManager::ElementViewAccessor< ReferenceWrapper< localIndex_array > >; -using ElemAdjListRefType = ElementRegionManager::ElementReferenceAccessor< localIndex_array >; inline int GhostSize( NodeManager & nodeManager, arrayView1d< localIndex const > const nodeAdjacencyList, EdgeManager & edgeManager, arrayView1d< localIndex const > const edgeAdjacencyList, FaceManager & faceManager, arrayView1d< localIndex const > const faceAdjacencyList, - ElementRegionManager & elemManager, ElemAdjListViewType const & elementAdjacencyList ) + ElementRegionManager & elemManager, NeighborCommunicator::ElemAdjListViewType const & elementAdjacencyList ) { int bufferSize = 0; bufferSize += nodeManager.packGlobalMapsSize( nodeAdjacencyList, 0 ); @@ -210,7 +208,7 @@ inline int PackGhosts( buffer_unit_type * sendBufferPtr, NodeManager & nodeManager, arrayView1d< localIndex const > const nodeAdjacencyList, EdgeManager & edgeManager, arrayView1d< localIndex const > const edgeAdjacencyList, FaceManager & faceManager, arrayView1d< localIndex const > const faceAdjacencyList, - ElementRegionManager & elemManager, ElemAdjListViewType const & elementAdjacencyList ) + ElementRegionManager & elemManager, NeighborCommunicator::ElemAdjListViewType const & elementAdjacencyList ) { int packedSize = 0; packedSize += nodeManager.packGlobalMaps( sendBufferPtr, nodeAdjacencyList, 0 ); @@ -300,43 +298,55 @@ void NeighborCommunicator::unpackGhosts( MeshLevel & mesh, ElementRegionManager & elemManager = mesh.getElemManager(); buffer_type const & receiveBuff = receiveBuffer( commID ); - buffer_unit_type const * receiveBufferPtr = receiveBuff.data(); + m_receiveBufferPtr = receiveBuff.data(); + + m_unpackedSize = 0; - buffer_type::size_type unpackedSize = 0; + m_nodeUnpackList.resize( 0 ); + m_unpackedSize += nodeManager.unpackGlobalMaps( m_receiveBufferPtr, m_nodeUnpackList, 0 ); - localIndex_array nodeUnpackList; - unpackedSize += nodeManager.unpackGlobalMaps( receiveBufferPtr, nodeUnpackList, 0 ); + m_edgeUnpackList.resize( 0 ); + m_unpackedSize += edgeManager.unpackGlobalMaps( m_receiveBufferPtr, m_edgeUnpackList, 0 ); - localIndex_array edgeUnpackList; - unpackedSize += edgeManager.unpackGlobalMaps( receiveBufferPtr, edgeUnpackList, 0 ); + m_faceUnpackList.resize( 0 ); + m_unpackedSize += faceManager.unpackGlobalMaps( m_receiveBufferPtr, m_faceUnpackList, 0 ); - localIndex_array faceUnpackList; - unpackedSize += faceManager.unpackGlobalMaps( receiveBufferPtr, faceUnpackList, 0 ); + m_elementAdjacencyReceiveListArray = elemManager.constructReferenceAccessor< localIndex_array >( ObjectManagerBase::viewKeyStruct::ghostsToReceiveString(), + std::to_string( this->m_neighborRank ) ); - ElemAdjListRefType elementAdjacencyReceiveListArray = - elemManager.constructReferenceAccessor< localIndex_array >( ObjectManagerBase::viewKeyStruct::ghostsToReceiveString(), - std::to_string( this->m_neighborRank ) ); - unpackedSize += elemManager.unpackGlobalMaps( receiveBufferPtr, - elementAdjacencyReceiveListArray ); + m_unpackedSize += elemManager.unpackGlobalMaps( m_receiveBufferPtr, + m_elementAdjacencyReceiveListArray ); + +} + +void NeighborCommunicator::unpackGhostsData( MeshLevel & mesh, + int const commID ) +{ + NodeManager & nodeManager = mesh.getNodeManager(); + EdgeManager & edgeManager = mesh.getEdgeManager(); + FaceManager & faceManager = mesh.getFaceManager(); + ElementRegionManager & elemManager = mesh.getElemManager(); ElemAdjListViewType elementAdjacencyReceiveList = elemManager.constructViewAccessor< array1d< localIndex >, arrayView1d< localIndex > >( ObjectManagerBase::viewKeyStruct::ghostsToReceiveString(), std::to_string( this->m_neighborRank ) ); - unpackedSize += nodeManager.unpackUpDownMaps( receiveBufferPtr, nodeUnpackList, false, false ); - unpackedSize += edgeManager.unpackUpDownMaps( receiveBufferPtr, edgeUnpackList, false, false ); - unpackedSize += faceManager.unpackUpDownMaps( receiveBufferPtr, faceUnpackList, false, false ); - unpackedSize += elemManager.unpackUpDownMaps( receiveBufferPtr, elementAdjacencyReceiveListArray, false ); + + m_unpackedSize += nodeManager.unpackUpDownMaps( m_receiveBufferPtr, m_nodeUnpackList, false, false ); + m_unpackedSize += edgeManager.unpackUpDownMaps( m_receiveBufferPtr, m_edgeUnpackList, false, false ); + m_unpackedSize += faceManager.unpackUpDownMaps( m_receiveBufferPtr, m_faceUnpackList, false, false ); + m_unpackedSize += elemManager.unpackUpDownMaps( m_receiveBufferPtr, m_elementAdjacencyReceiveListArray, false ); parallelDeviceEvents events; - unpackedSize += nodeManager.unpack( receiveBufferPtr, nodeUnpackList, 0, false, events ); - unpackedSize += edgeManager.unpack( receiveBufferPtr, edgeUnpackList, 0, false, events ); - unpackedSize += faceManager.unpack( receiveBufferPtr, faceUnpackList, 0, false, events ); - unpackedSize += elemManager.unpack( receiveBufferPtr, elementAdjacencyReceiveList ); - waitAllDeviceEvents( events ); + m_unpackedSize += nodeManager.unpack( m_receiveBufferPtr, m_nodeUnpackList, 0, false, events ); + m_unpackedSize += edgeManager.unpack( m_receiveBufferPtr, m_edgeUnpackList, 0, false, events ); + m_unpackedSize += faceManager.unpack( m_receiveBufferPtr, m_faceUnpackList, 0, false, events ); + m_unpackedSize += elemManager.unpack( m_receiveBufferPtr, elementAdjacencyReceiveList ); - GEOS_ERROR_IF_NE( receiveBuff.size(), unpackedSize ); + waitAllDeviceEvents( events ); + buffer_type const & receiveBuff = receiveBuffer( commID ); + GEOS_ERROR_IF_NE( receiveBuff.size(), m_unpackedSize ); } void NeighborCommunicator::prepareAndSendSyncLists( MeshLevel const & mesh, @@ -501,8 +511,7 @@ int NeighborCommunicator::packCommSizeForSync( FieldIdentifiers const & fieldsTo for( auto const & iter : fieldsToBeSync.getFields() ) { - FieldLocation location{}; - fieldsToBeSync.getLocation( iter.first, location ); + FieldLocation const location = fieldsToBeSync.getLocation( iter.first ); switch( location ) { case FieldLocation::Node: @@ -559,8 +568,7 @@ void NeighborCommunicator::packCommBufferForSync( FieldIdentifiers const & field for( auto const & iter : fieldsToBeSync.getFields() ) { - FieldLocation location{}; - fieldsToBeSync.getLocation( iter.first, location ); + FieldLocation const location = fieldsToBeSync.getLocation( iter.first ); switch( location ) { case FieldLocation::Node: @@ -618,8 +626,7 @@ void NeighborCommunicator::unpackBufferForSync( FieldIdentifiers const & fieldsT for( auto const & iter : fieldsToBeSync.getFields() ) { - FieldLocation location{}; - fieldsToBeSync.getLocation( iter.first, location ); + FieldLocation const location = fieldsToBeSync.getLocation( iter.first ); switch( location ) { case FieldLocation::Node: diff --git a/src/coreComponents/mesh/mpiCommunications/NeighborCommunicator.hpp b/src/coreComponents/mesh/mpiCommunications/NeighborCommunicator.hpp index 6a32bca6835..06f07fddb82 100644 --- a/src/coreComponents/mesh/mpiCommunications/NeighborCommunicator.hpp +++ b/src/coreComponents/mesh/mpiCommunications/NeighborCommunicator.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,6 +22,7 @@ #include "common/GEOS_RAJA_Interface.hpp" #include "dataRepository/ReferenceWrapper.hpp" #include "LvArray/src/limits.hpp" +#include "../ElementRegionManager.hpp" namespace geos { @@ -29,7 +31,7 @@ inline int CommTag( int const GEOS_UNUSED_PARAM( senderRank ), int const comm ) { // int m_size; -// MPI_Comm_size( MPI_COMM_GEOSX, &m_size ); +// MPI_Comm_size( MPI_COMM_GEOS, &m_size ); // return senderRank * m_size + receiverRank + m_size * m_size * comm; return comm; } @@ -40,6 +42,9 @@ class MPI_iCommData; class NeighborCommunicator { public: + using ElemAdjListViewType = ElementRegionManager::ElementViewAccessor< arrayView1d< localIndex > >; + using ElemAdjListRefWrapType = ElementRegionManager::ElementViewAccessor< ReferenceWrapper< localIndex_array > >; + using ElemAdjListRefType = ElementRegionManager::ElementReferenceAccessor< localIndex_array >; explicit NeighborCommunicator( int rank ); @@ -192,6 +197,9 @@ class NeighborCommunicator void unpackGhosts( MeshLevel & meshLevel, int const commID ); + void unpackGhostsData( MeshLevel & meshLevel, + int const commID ); + /** * Posts non-blocking sends to m_neighborRank for * both the size and regular communication buffers @@ -209,7 +217,7 @@ class NeighborCommunicator /** * Unpack the receive buffer and process synchronization - * list information recieved from m_neighborRank. + * list information received from m_neighborRank. * This must be called after PostRecv is called, and * the request associated with that recv has * completed (retrieve the request using GetRecvRequest) @@ -293,6 +301,15 @@ class NeighborCommunicator std::vector< buffer_type > m_sendBuffer; std::vector< buffer_type > m_receiveBuffer; + localIndex_array m_nodeUnpackList; + localIndex_array m_edgeUnpackList; + localIndex_array m_faceUnpackList; + ElemAdjListRefType m_elementAdjacencyReceiveListArray; + buffer_type::size_type m_unpackedSize = 0; + buffer_unit_type const * m_receiveBufferPtr = nullptr; + + + }; template< typename T > diff --git a/src/coreComponents/mesh/mpiCommunications/NeighborData.hpp b/src/coreComponents/mesh/mpiCommunications/NeighborData.hpp index f0727d92744..236528cec9e 100644 --- a/src/coreComponents/mesh/mpiCommunications/NeighborData.hpp +++ b/src/coreComponents/mesh/mpiCommunications/NeighborData.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/mpiCommunications/PartitionBase.cpp b/src/coreComponents/mesh/mpiCommunications/PartitionBase.cpp index 3b93ce43722..a1175c74b62 100644 --- a/src/coreComponents/mesh/mpiCommunications/PartitionBase.cpp +++ b/src/coreComponents/mesh/mpiCommunications/PartitionBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/mpiCommunications/PartitionBase.hpp b/src/coreComponents/mesh/mpiCommunications/PartitionBase.hpp index 1e78e0af01d..b4b5bc402bc 100644 --- a/src/coreComponents/mesh/mpiCommunications/PartitionBase.hpp +++ b/src/coreComponents/mesh/mpiCommunications/PartitionBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/mpiCommunications/SpatialPartition.cpp b/src/coreComponents/mesh/mpiCommunications/SpatialPartition.cpp index 4fc9a7ff672..26f6f4c90a0 100644 --- a/src/coreComponents/mesh/mpiCommunications/SpatialPartition.cpp +++ b/src/coreComponents/mesh/mpiCommunications/SpatialPartition.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -180,7 +181,7 @@ void SpatialPartition::setSizes( real64 const ( &min )[ 3 ], { //get size of problem and decomposition - m_size = MpiWrapper::commSize( MPI_COMM_GEOSX ); + m_size = MpiWrapper::commSize( MPI_COMM_GEOS ); //check to make sure our dimensions agree { @@ -196,7 +197,7 @@ void SpatialPartition::setSizes( real64 const ( &min )[ 3 ], MPI_Comm cartcomm; { int reorder = 0; - MpiWrapper::cartCreate( MPI_COMM_GEOSX, nsdof, m_Partitions.data(), m_Periodic.data(), reorder, &cartcomm ); + MpiWrapper::cartCreate( MPI_COMM_GEOS, nsdof, m_Partitions.data(), m_Periodic.data(), reorder, &cartcomm ); } m_rank = MpiWrapper::commRank( cartcomm ); MpiWrapper::cartCoords( cartcomm, m_rank, nsdof, m_coords.data()); @@ -794,7 +795,7 @@ void SpatialPartition::sendCoordinateListToNeighbors( arrayView1d< R1Tensor > co 1, receiveRequest[n], commData.commID(), - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); } MPI_Waitall( nn, sendRequest.data(), sendStatus.data()); MPI_Waitall( nn, receiveRequest.data(), receiveStatus.data()); @@ -823,7 +824,7 @@ void SpatialPartition::sendCoordinateListToNeighbors( arrayView1d< R1Tensor > co sizeOfReceived[n], receiveRequest[n], commData.commID(), - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); } MPI_Waitall( nn, sendRequest.data(), sendStatus.data()); MPI_Waitall( nn, receiveRequest.data(), receiveStatus.data()); @@ -893,7 +894,7 @@ void SpatialPartition::sendListOfIndicesToNeighbors( std::vector< array1d< index 1, receiveRequest[n], commData.commID(), - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); } MPI_Waitall( nn, sendRequest.data(), sendStatus.data()); MPI_Waitall( nn, receiveRequest.data(), receiveStatus.data()); @@ -922,7 +923,7 @@ void SpatialPartition::sendListOfIndicesToNeighbors( std::vector< array1d< index sizeOfReceived[n], receiveRequest[n], commData.commID(), - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); } MPI_Waitall( nn, sendRequest.data(), sendStatus.data()); MPI_Waitall( nn, receiveRequest.data(), receiveStatus.data()); @@ -983,7 +984,7 @@ void SpatialPartition::sendParticlesToNeighbor( ParticleSubRegionBase & subRegio 1, receiveRequest[n], commData.commID(), - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); } MPI_Waitall( nn, sendRequest.data(), sendStatus.data() ); MPI_Waitall( nn, receiveRequest.data(), receiveStatus.data() ); @@ -1011,7 +1012,7 @@ void SpatialPartition::sendParticlesToNeighbor( ParticleSubRegionBase & subRegio sizeOfReceived[n], receiveRequest[n], commData.commID(), - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); } MPI_Waitall( nn, sendRequest.data(), sendStatus.data()); MPI_Waitall( nn, receiveRequest.data(), receiveStatus.data()); diff --git a/src/coreComponents/mesh/mpiCommunications/SpatialPartition.hpp b/src/coreComponents/mesh/mpiCommunications/SpatialPartition.hpp index 2f0a12622e6..00825c9b6e7 100644 --- a/src/coreComponents/mesh/mpiCommunications/SpatialPartition.hpp +++ b/src/coreComponents/mesh/mpiCommunications/SpatialPartition.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/simpleGeometricObjects/Box.cpp b/src/coreComponents/mesh/simpleGeometricObjects/Box.cpp index fc5aea65a46..c8ff70834c9 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/Box.cpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/Box.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -59,7 +60,7 @@ Box::~Box() -void Box::postProcessInput() +void Box::postInputInitialization() { LvArray::tensorOps::copy< 3 >( m_boxCenter, m_min ); LvArray::tensorOps::add< 3 >( m_boxCenter, m_max ); diff --git a/src/coreComponents/mesh/simpleGeometricObjects/Box.hpp b/src/coreComponents/mesh/simpleGeometricObjects/Box.hpp index 48b3e80f44f..feacb96c193 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/Box.hpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/Box.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -74,7 +75,7 @@ class Box : public SimpleGeometricObjectBase * @brief This function provides capability to post process input values prior to * any other initialization operations. */ - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; private: diff --git a/src/coreComponents/mesh/simpleGeometricObjects/CustomPolarObject.cpp b/src/coreComponents/mesh/simpleGeometricObjects/CustomPolarObject.cpp index 22e1bc0c0fc..5bcab75fcde 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/CustomPolarObject.cpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/CustomPolarObject.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -48,7 +49,7 @@ CustomPolarObject::CustomPolarObject( const string & name, Group * const parent CustomPolarObject::~CustomPolarObject() {} -void CustomPolarObject::postProcessInput() +void CustomPolarObject::postInputInitialization() { // Make sure that you have an orthonormal basis. LvArray::tensorOps::normalize< 3 >( m_normal ); @@ -85,4 +86,4 @@ bool CustomPolarObject::isCoordInObject( real64 const ( &coord ) [3] ) const REGISTER_CATALOG_ENTRY( SimpleGeometricObjectBase, CustomPolarObject, string const &, Group * const ) -} /* namespace geosx */ +} /* namespace geos */ diff --git a/src/coreComponents/mesh/simpleGeometricObjects/CustomPolarObject.hpp b/src/coreComponents/mesh/simpleGeometricObjects/CustomPolarObject.hpp index 99faea5eca8..1a320d3162c 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/CustomPolarObject.hpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/CustomPolarObject.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,8 +17,8 @@ * @file CustomPolarObject.hpp */ -#ifndef GEOSX_MESH_SIMPLEGEOMETRICOBJECTS_CUSTOMPOLAROBJECT_HPP_ -#define GEOSX_MESH_SIMPLEGEOMETRICOBJECTS_CUSTOMPOLAROBJECT_HPP_ +#ifndef GEOS_MESH_SIMPLEGEOMETRICOBJECTS_CUSTOMPOLAROBJECT_HPP_ +#define GEOS_MESH_SIMPLEGEOMETRICOBJECTS_CUSTOMPOLAROBJECT_HPP_ #include "PlanarGeometricObject.hpp" @@ -116,7 +117,7 @@ class CustomPolarObject : public PlanarGeometricObject * @brief This function provides the capability to post process input values prior to * any other initialization operations. */ - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; private: @@ -139,6 +140,6 @@ class CustomPolarObject : public PlanarGeometricObject /// @endcond }; -} /* namespace geosx */ +} /* namespace geos */ -#endif /* GEOSX_MESH_SIMPLEGEOMETRICOBJECTS_CustomPolarObject_HPP_*/ +#endif /* GEOS_MESH_SIMPLEGEOMETRICOBJECTS_CustomPolarObject_HPP_*/ diff --git a/src/coreComponents/mesh/simpleGeometricObjects/Cylinder.cpp b/src/coreComponents/mesh/simpleGeometricObjects/Cylinder.cpp index ff344c6901a..da38cb43438 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/Cylinder.cpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/Cylinder.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/simpleGeometricObjects/Cylinder.hpp b/src/coreComponents/mesh/simpleGeometricObjects/Cylinder.hpp index 5fb15c5ef7d..2185c4d315c 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/Cylinder.hpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/Cylinder.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/simpleGeometricObjects/Disc.cpp b/src/coreComponents/mesh/simpleGeometricObjects/Disc.cpp index eedd7bc979d..f88f139f73c 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/Disc.cpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/Disc.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -48,7 +49,7 @@ Disc::Disc( const string & name, Group * const parent ): Disc::~Disc() {} -void Disc::postProcessInput() +void Disc::postInputInitialization() { // Make sure that you have an orthonormal basis. LvArray::tensorOps::normalize< 3 >( m_normal ); @@ -81,4 +82,4 @@ bool Disc::isCoordInObject( real64 const ( &coord ) [3] ) const REGISTER_CATALOG_ENTRY( SimpleGeometricObjectBase, Disc, string const &, Group * const ) -} /* namespace geosx */ +} /* namespace geos */ diff --git a/src/coreComponents/mesh/simpleGeometricObjects/Disc.hpp b/src/coreComponents/mesh/simpleGeometricObjects/Disc.hpp index 0c9b5a5c87b..38b3c7c4d17 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/Disc.hpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/Disc.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,8 +17,8 @@ * @file Disc.hpp */ -#ifndef GEOSX_MESH_SIMPLEGEOMETRICOBJECTS_DISC_HPP_ -#define GEOSX_MESH_SIMPLEGEOMETRICOBJECTS_DISC_HPP_ +#ifndef GEOS_MESH_SIMPLEGEOMETRICOBJECTS_DISC_HPP_ +#define GEOS_MESH_SIMPLEGEOMETRICOBJECTS_DISC_HPP_ #include "PlanarGeometricObject.hpp" @@ -89,7 +90,7 @@ class Disc : public PlanarGeometricObject * @brief This function provides the capability to post process input values prior to * any other initialization operations. */ - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; private: @@ -112,6 +113,6 @@ class Disc : public PlanarGeometricObject /// @endcond }; -} /* namespace geosx */ +} /* namespace geos */ -#endif /* GEOSX_MESH_SIMPLEGEOMETRICOBJECTS_DISC_HPP_*/ +#endif /* GEOS_MESH_SIMPLEGEOMETRICOBJECTS_DISC_HPP_*/ diff --git a/src/coreComponents/mesh/simpleGeometricObjects/GeometricObjectManager.cpp b/src/coreComponents/mesh/simpleGeometricObjects/GeometricObjectManager.cpp index 4eda186c373..c5843dbc747 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/GeometricObjectManager.cpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/GeometricObjectManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -52,7 +53,7 @@ GeometricObjectManager & GeometricObjectManager::getInstance() Group * GeometricObjectManager::createChild( string const & childKey, string const & childName ) { - GEOS_LOG_RANK_0( "Adding Geometric Object: " << childKey << ", " << childName ); + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) ); std::unique_ptr< SimpleGeometricObjectBase > geometriObject = SimpleGeometricObjectBase::CatalogInterface::factory( childKey, childName, this ); return &this->registerGroup< SimpleGeometricObjectBase >( childName, std::move( geometriObject ) ); } diff --git a/src/coreComponents/mesh/simpleGeometricObjects/GeometricObjectManager.hpp b/src/coreComponents/mesh/simpleGeometricObjects/GeometricObjectManager.hpp index bb02a280045..7aef070b24f 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/GeometricObjectManager.hpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/GeometricObjectManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/simpleGeometricObjects/PlanarGeometricObject.cpp b/src/coreComponents/mesh/simpleGeometricObjects/PlanarGeometricObject.cpp index 857cccc2a78..f8539b88504 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/PlanarGeometricObject.cpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/PlanarGeometricObject.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -47,4 +48,4 @@ PlanarGeometricObject::~PlanarGeometricObject() //REGISTER_CATALOG_ENTRY( SimpleGeometricObjectBase, PlanarGeometricObject, string const &, Group * const ) -} /* namespace geosx */ +} /* namespace geos */ diff --git a/src/coreComponents/mesh/simpleGeometricObjects/PlanarGeometricObject.hpp b/src/coreComponents/mesh/simpleGeometricObjects/PlanarGeometricObject.hpp index 417f3da27b5..b7ed93439f1 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/PlanarGeometricObject.hpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/PlanarGeometricObject.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,8 +17,8 @@ * @file PlanarGeometricObject.hpp */ -#ifndef GEOSX_MESH_SIMPLEGEOMETRICOBJECTS_PLANARGEOMETRICOBJECT_HPP_ -#define GEOSX_MESH_SIMPLEGEOMETRICOBJECTS_PLANARGEOMETRICOBJECT_HPP_ +#ifndef GEOS_MESH_SIMPLEGEOMETRICOBJECTS_PLANARGEOMETRICOBJECT_HPP_ +#define GEOS_MESH_SIMPLEGEOMETRICOBJECTS_PLANARGEOMETRICOBJECT_HPP_ #include "SimpleGeometricObjectBase.hpp" @@ -147,6 +148,6 @@ class PlanarGeometricObject : public SimpleGeometricObjectBase /// @endcond }; -} /* namespace geosx */ +} /* namespace geos */ -#endif /* GEOSX_MESH_SIMPLEGEOMETRICOBJECTS_PLANARGEOMETRICOBJECT_HPP_*/ +#endif /* GEOS_MESH_SIMPLEGEOMETRICOBJECTS_PLANARGEOMETRICOBJECT_HPP_*/ diff --git a/src/coreComponents/mesh/simpleGeometricObjects/Rectangle.cpp b/src/coreComponents/mesh/simpleGeometricObjects/Rectangle.cpp index 71cb893e757..e8817e10dca 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/Rectangle.cpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/Rectangle.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -65,13 +66,13 @@ Rectangle::Rectangle( const real64 oldX, const real64 oldY, m_points.resize( 4, 3 ); //parent->registerGroup< Rectangle >( name, std::move( this ) ); - this->postProcessInput(); + this->postInputInitialization(); } Rectangle::~Rectangle() {} -void Rectangle::postProcessInput() +void Rectangle::postInputInitialization() { // Make sure that you have an orthonormal basis. LvArray::tensorOps::normalize< 3 >( m_normal ); @@ -170,4 +171,4 @@ bool Rectangle::isCoordInObject( real64 const ( &coord ) [3] ) const REGISTER_CATALOG_ENTRY( SimpleGeometricObjectBase, Rectangle, string const &, Group * const ) -} /* namespace geosx */ +} /* namespace geos */ diff --git a/src/coreComponents/mesh/simpleGeometricObjects/Rectangle.hpp b/src/coreComponents/mesh/simpleGeometricObjects/Rectangle.hpp index ef86ffbf390..03dd2f8ba8a 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/Rectangle.hpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/Rectangle.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,8 +17,8 @@ * @file Rectangle.hpp */ -#ifndef GEOSX_MESH_SIMPLEGEOMETRICOBJECTS_RECTANGLE_HPP_ -#define GEOSX_MESH_SIMPLEGEOMETRICOBJECTS_RECTANGLE_HPP_ +#ifndef GEOS_MESH_SIMPLEGEOMETRICOBJECTS_RECTANGLE_HPP_ +#define GEOS_MESH_SIMPLEGEOMETRICOBJECTS_RECTANGLE_HPP_ #include "PlanarGeometricObject.hpp" @@ -109,7 +110,7 @@ class Rectangle : public PlanarGeometricObject * @brief This function provides the capability to post process input values prior to * any other initialization operations. */ - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; private: @@ -134,6 +135,6 @@ class Rectangle : public PlanarGeometricObject /// @endcond }; -} /* namespace geosx */ +} /* namespace geos */ -#endif /* GEOSX_MESH_SIMPLEGEOMETRICOBJECTS_RECTANGLE_HPP_*/ +#endif /* GEOS_MESH_SIMPLEGEOMETRICOBJECTS_RECTANGLE_HPP_*/ diff --git a/src/coreComponents/mesh/simpleGeometricObjects/SimpleGeometricObjectBase.cpp b/src/coreComponents/mesh/simpleGeometricObjects/SimpleGeometricObjectBase.cpp index 937852766bc..8b823b233b7 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/SimpleGeometricObjectBase.cpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/SimpleGeometricObjectBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/simpleGeometricObjects/SimpleGeometricObjectBase.hpp b/src/coreComponents/mesh/simpleGeometricObjects/SimpleGeometricObjectBase.hpp index 099e3d7d3da..9b9338d6dc3 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/SimpleGeometricObjectBase.hpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/SimpleGeometricObjectBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #define GEOS_MESH_SIMPLEGEOMETRICOBJECTS_SIMPLEGEOMETRICOBJECTBASE_HPP_ #include "dataRepository/Group.hpp" -#include "codingUtilities/StringUtilities.hpp" +#include "common/format/StringUtilities.hpp" #include "dataRepository/ObjectCatalog.hpp" class Function; diff --git a/src/coreComponents/mesh/simpleGeometricObjects/ThickPlane.cpp b/src/coreComponents/mesh/simpleGeometricObjects/ThickPlane.cpp index db9820a8e93..d69092b79cc 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/ThickPlane.cpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/ThickPlane.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -46,7 +47,7 @@ ThickPlane::~ThickPlane() {} -void ThickPlane::postProcessInput() +void ThickPlane::postInputInitialization() { m_thickness *= 0.5; // actually store the half-thickness GEOS_ERROR_IF( m_thickness <= 0, diff --git a/src/coreComponents/mesh/simpleGeometricObjects/ThickPlane.hpp b/src/coreComponents/mesh/simpleGeometricObjects/ThickPlane.hpp index 6a5f646e7e9..ce4fa5fb65f 100644 --- a/src/coreComponents/mesh/simpleGeometricObjects/ThickPlane.hpp +++ b/src/coreComponents/mesh/simpleGeometricObjects/ThickPlane.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -100,7 +101,7 @@ class ThickPlane : public SimpleGeometricObjectBase * @brief This function provides capability to post process input values prior to * any other initialization operations. */ - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; private: diff --git a/src/coreComponents/mesh/unitTests/CMakeLists.txt b/src/coreComponents/mesh/unitTests/CMakeLists.txt index c017bec6962..862bbca219e 100644 --- a/src/coreComponents/mesh/unitTests/CMakeLists.txt +++ b/src/coreComponents/mesh/unitTests/CMakeLists.txt @@ -4,7 +4,7 @@ set( mesh_tests testComputationalGeometry.cpp testGeometricObjects.cpp ) -set( dependencyList gtest mesh ${parallelDeps} ) +set( dependencyList blas lapack gtest mesh ${parallelDeps} ) # Add gtest C++ based tests foreach(test ${mesh_tests}) diff --git a/src/coreComponents/mesh/unitTests/testComputationalGeometry.cpp b/src/coreComponents/mesh/unitTests/testComputationalGeometry.cpp index fe47cc598e4..403d5f25483 100644 --- a/src/coreComponents/mesh/unitTests/testComputationalGeometry.cpp +++ b/src/coreComponents/mesh/unitTests/testComputationalGeometry.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/unitTests/testGeometricObjects.cpp b/src/coreComponents/mesh/unitTests/testGeometricObjects.cpp index e9aeac97e9f..e767a9f46ff 100644 --- a/src/coreComponents/mesh/unitTests/testGeometricObjects.cpp +++ b/src/coreComponents/mesh/unitTests/testGeometricObjects.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/unitTests/testMeshObjectPath.cpp b/src/coreComponents/mesh/unitTests/testMeshObjectPath.cpp index 5a20bb6e2a0..e1f82992bd4 100644 --- a/src/coreComponents/mesh/unitTests/testMeshObjectPath.cpp +++ b/src/coreComponents/mesh/unitTests/testMeshObjectPath.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/utilities/AverageOverQuadraturePointsKernel.hpp b/src/coreComponents/mesh/utilities/AverageOverQuadraturePointsKernel.hpp index 3530d3eb590..254bc81fcce 100644 --- a/src/coreComponents/mesh/utilities/AverageOverQuadraturePointsKernel.hpp +++ b/src/coreComponents/mesh/utilities/AverageOverQuadraturePointsKernel.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/utilities/CIcomputationKernel.hpp b/src/coreComponents/mesh/utilities/CIcomputationKernel.hpp index 1a5d56ac8a5..d9abae9ed31 100644 --- a/src/coreComponents/mesh/utilities/CIcomputationKernel.hpp +++ b/src/coreComponents/mesh/utilities/CIcomputationKernel.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/utilities/ComputationalGeometry.cpp b/src/coreComponents/mesh/utilities/ComputationalGeometry.cpp index c1e76c69d9c..c920605de80 100644 --- a/src/coreComponents/mesh/utilities/ComputationalGeometry.cpp +++ b/src/coreComponents/mesh/utilities/ComputationalGeometry.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/mesh/utilities/ComputationalGeometry.hpp b/src/coreComponents/mesh/utilities/ComputationalGeometry.hpp index d90df153066..d9c054d3401 100644 --- a/src/coreComponents/mesh/utilities/ComputationalGeometry.hpp +++ b/src/coreComponents/mesh/utilities/ComputationalGeometry.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -34,7 +35,7 @@ namespace computationalGeometry { /// Machine epsilon for double-precision calculations -constexpr real64 machinePrecision = std::numeric_limits< real64 >::epsilon(); +constexpr real64 machinePrecision = LvArray::NumericLimits< real64 >::epsilon; /** * @brief Calculate the intersection between a line and a plane. @@ -179,6 +180,40 @@ real64 ComputeSurfaceArea( arrayView2d< real64 const > const & points, return surfaceArea * 0.5; } +/** + * @brief Calculate the diameter of a set of points in a given dimension. + * @tparam DIMENSION The dimensionality of the points. + * @tparam POINT_COORDS_TYPE The type of the container holding the point coordinates. + * @param[in] points The container holding the coordinates of the points. + * @param[in] numPoints The number of points in the container. + * @return The diameter of the set of points. + */ +template< localIndex DIMENSION, typename POINT_COORDS_TYPE > +GEOS_HOST_DEVICE +GEOS_FORCE_INLINE +real64 computeDiameter( POINT_COORDS_TYPE points, + localIndex const & numPoints ) +{ + real64 diameter = 0; + for( localIndex numPoint = 0; numPoint < numPoints; ++numPoint ) + { + for( localIndex numOthPoint = 0; numOthPoint < numPoint; ++numOthPoint ) + { + real64 candidateDiameter = 0.0; + for( localIndex i = 0; i < DIMENSION; ++i ) + { + real64 coordDiff = points[numPoint][i] - points[numOthPoint][i]; + candidateDiameter += coordDiff * coordDiff; + } + if( diameter < candidateDiameter ) + { + diameter = candidateDiameter; + } + } + } + return LvArray::math::sqrt< real64 >( diameter ); +} + /** * @brief Calculate the centroid of a convex 3D polygon as well as the normal and the rotation matrix. * @tparam CENTER_TYPE The type of @p center. @@ -346,7 +381,6 @@ int sign( T const val ) return (T( 0 ) < val) - (val < T( 0 )); } - /** * @brief Check if a point is inside a convex polyhedron (3D polygon) * @tparam POINT_TYPE type of @p point @@ -400,6 +434,402 @@ bool isPointInsidePolyhedron( arrayView2d< real64 const, nodes::REFERENCE_POSITI } +/** + * @brief Method to perform lexicographic comparison of two nodes based on coordinates. + * @tparam COORD_TYPE type of coordinate + * @tparam POINT_TYPE type of point + * @param[in] ax x-coordinate of the first vertex + * @param[in] ay y-coordinate of the first vertex + * @param[in] az z-coordinate of the first vertex + * @param[in] bx x-coordinate of the second vertex + * @param[in] by y-coordinate of the second vertex + * @param[in] bz z-coordinate of the second vertex + * @return 0 if the vertices coincide, +1 if a > b and -1 if b > a + */ +template< typename COORD_TYPE, typename POINT_TYPE > +GEOS_HOST_DEVICE +int lexicographicalCompareVertex( POINT_TYPE const ax, POINT_TYPE const ay, POINT_TYPE const az, + COORD_TYPE const bx, COORD_TYPE const by, COORD_TYPE const bz ) +{ + if( ax < bx ) + return -1; + else if( ax > bx ) + return 1; + if( ay < by ) + return -1; + else if( ay > by ) + return 1; + if( az < bz ) + return -1; + else if( az > bz ) + return 1; + return 0; +} + +/** + * @brief Method to perform lexicographic comparison of a node and an edge based on coordinates. + * @tparam COORD_TYPE type of coordinate + * @tparam POINT_TYPE type of point + * @param[in] ax x-coordinate of the first vertex + * @param[in] ay y-coordinate of the first vertex + * @param[in] az z-coordinate of the first vertex + * @param[in] e1x x-coordinate of the first edge vertex + * @param[in] e1y y-coordinate of the first edge vertex + * @param[in] e1z z-coordinate of the first edge vertex + * @param[in] e2x x-coordinate of the second edge vertex + * @param[in] e2y y-coordinate of the second edge vertex + * @param[in] e2z z-coordinate of the second edge vertex + * @return 0 if the vertices lies on the edge, +1 if e > a and -1 if a > e + */ +template< typename COORD_TYPE, typename POINT_TYPE > +GEOS_HOST_DEVICE +int lexicographicalCompareEdge( POINT_TYPE const ax, POINT_TYPE const ay, POINT_TYPE const az, + COORD_TYPE const e1x, COORD_TYPE const e1y, COORD_TYPE const e1z, + COORD_TYPE const e2x, COORD_TYPE const e2y, COORD_TYPE const e2z ) +{ + return lexicographicalCompareVertex( ( e1y - ay ) * ( e2x - ax ), + ( e1z - az ) * ( e2x - ax ), + ( e1z - az ) * ( e2y - ay ), + ( e1x - ax ) * ( e2y - ay ), + ( e1x - ax ) * ( e2z - az ), + ( e1y - ay ) * ( e2z - az ) ); +} + +/** + * @brief Method to perform lexicographic comparison of a node and a triangle based on coordinates. + * @tparam COORD_TYPE type of coordinate + * @tparam POINT_TYPE type of point + * @param[in] ax x-coordinate of the first vertex + * @param[in] ay y-coordinate of the first vertex + * @param[in] az z-coordinate of the first vertex + * @param[in] t1x x-coordinate of the first triangle vertex + * @param[in] t1y y-coordinate of the first triangle vertex + * @param[in] t1z z-coordinate of the first triangle vertex + * @param[in] t2x x-coordinate of the second triangle vertex + * @param[in] t2y y-coordinate of the second triangle vertex + * @param[in] t2z z-coordinate of the second triangle vertex + * @param[in] t3x x-coordinate of the third triangle vertex + * @param[in] t3y y-coordinate of the third triangle vertex + * @param[in] t3z z-coordinate of the third triangle vertex + * @return 0 if the vertices lies on the triangle, +1 if t > a and -1 if t > e + */ +template< typename COORD_TYPE, typename POINT_TYPE > +GEOS_HOST_DEVICE +int lexicographicalCompareTriangle( POINT_TYPE const ax, POINT_TYPE const ay, POINT_TYPE const az, + COORD_TYPE const t1x, COORD_TYPE const t1y, COORD_TYPE const t1z, + COORD_TYPE const t2x, COORD_TYPE const t2y, COORD_TYPE const t2z, + COORD_TYPE const t3x, COORD_TYPE const t3y, COORD_TYPE const t3z ) +{ + COORD_TYPE v1x = t1x - ax; + COORD_TYPE v1y = t1y - ay; + COORD_TYPE v1z = t1z - az; + COORD_TYPE v2x = t2x - ax; + COORD_TYPE v2y = t2y - ay; + COORD_TYPE v2z = t2z - az; + COORD_TYPE v3x = t3x - ax; + COORD_TYPE v3y = t3y - ay; + COORD_TYPE v3z = t3z - az; + COORD_TYPE sign = ( v1x * v2y - v1y * v2x ) * v3z + + ( v2x * v3y - v2y * v3x ) * v1z + + ( v3x * v1y - v3y * v1x ) * v2z; + if( sign > 0 ) + return 1; + else if( sign < 0 ) + return -1; + return 0; +} +/** + * @brief Method to find the reference element touching a vertex. The element with the lowest global ID is chosen + * from the list. + * @param[in] nodeElements the list of elements adjacent to the vertex + * @param[in] elementGlobalIndex the global IDs for elements + * @return element touching the vertex with the least global index + */ +template< typename ... LIST_TYPE > +GEOS_HOST_DEVICE +int findVertexRefElement( arraySlice1d< localIndex const > const & nodeElements, + arrayView1d< globalIndex const > const & elementGlobalIndex ) +{ + localIndex minElement = -1; + globalIndex minElementGID = LvArray::NumericLimits< globalIndex >::max; + for( int i = 0; i < nodeElements.size(); i++ ) + { + localIndex e = nodeElements( i ); + if( elementGlobalIndex[ e ] < minElementGID ) + { + minElementGID = elementGlobalIndex[ e ]; + minElement = e; + } + } + return minElement; +} + +/** + * @brief Method to find the reference element for an edge. The element with the lowest global ID is chosen + * from the list. + * @param[in] nodeElements1 the list of elements adjacent to the first node + * @param[in] nodeElements2 the list of elements adjacent to the second node + * @param[in] elementGlobalIndex the global IDs for elements + * @return the element shared by the two nodes, with the minimal global index + */ +template< typename ... LIST_TYPE > +GEOS_HOST_DEVICE +int findEdgeRefElement( arraySlice1d< localIndex const > const & nodeElements1, + arraySlice1d< localIndex const > const & nodeElements2, + arrayView1d< globalIndex const > const & elementGlobalIndex ) +{ + localIndex minElement = -1; + globalIndex minElementGID = LvArray::NumericLimits< globalIndex >::max; + for( int i = 0; i < nodeElements1.size(); i++ ) + { + localIndex e1 = nodeElements1( i ); + for( int j = 0; j < nodeElements2.size(); j++ ) + { + localIndex e2 = nodeElements2( j ); + if( e1 == e2 ) + { + if( elementGlobalIndex[ e1 ] < minElementGID ) + { + minElementGID = elementGlobalIndex[ e1 ]; + minElement = e1; + } + } + } + } + return minElement; +} + +/** + * @brief Method to find the reference element for a triangle. The element with the lowest global ID is chosen + * from the list. + * @param[in] nodeElements1 the list of elements adjacent to the first node + * @param[in] nodeElements2 the list of elements adjacent to the second node + * @param[in] nodeElements3 the list of elements adjacent to the third node + * @param[in] elementGlobalIndex the global IDs for elements + * @return the element shared by the three nodes, with the minimal global index + */ +template< typename ... LIST_TYPE > +GEOS_HOST_DEVICE +int findTriangleRefElement( arraySlice1d< localIndex const > const & nodeElements1, + arraySlice1d< localIndex const > const & nodeElements2, + arraySlice1d< localIndex const > const & nodeElements3, + arrayView1d< globalIndex const > const & elementGlobalIndex ) +{ + localIndex minElement = -1; + globalIndex minElementGID = LvArray::NumericLimits< globalIndex >::max; + for( int i = 0; i < nodeElements1.size(); i++ ) + { + localIndex e1 = nodeElements1( i ); + for( int j = 0; j < nodeElements2.size(); j++ ) + { + localIndex e2 = nodeElements2( j ); + for( int k = 0; k < nodeElements3.size(); k++ ) + { + localIndex e3 = nodeElements3( k ); + if( e1 == e2 && e2 == e3 ) + { + if( elementGlobalIndex[ e1 ] < minElementGID ) + { + minElementGID = elementGlobalIndex[ e1 ]; + minElement = e1; + } + } + } + } + } + return minElement; +} + +/** + * @brief Computes the winding number of a point with respecto to a mesh element. + * @tparam POINT_TYPE type of @p point + * @param[in] element the element to be checked + * @param[in] nodeCoordinates a global array of nodal coordinates + * @param[in] elementsToFaces map from elements to faces + * @param[in] facesToNodes map from faces to nodes + * @param[in] nodesToElements map from nodes to elements + * @param[in] nodeLocalToGlobal global indices of nodes + * @param[in] elementLocalToGlobal global indices of elements + * @param[in] elemCenter coordinates of the element centroid + * @param[in] point coordinates of the query point + * @return the signed winding number, which is positive if and only if the point is inside the mesh element. + */ +template< typename COORD_TYPE, typename POINT_TYPE > +GEOS_HOST_DEVICE +bool computeWindingNumber( localIndex element, + arrayView2d< COORD_TYPE const, nodes::REFERENCE_POSITION_USD > const & nodeCoordinates, + arrayView2d< localIndex const > const & elementsToFaces, + ArrayOfArraysView< localIndex const > const & facesToNodes, + ArrayOfArraysView< localIndex const > const & nodesToElements, + arrayView1d< globalIndex const > const & nodeLocalToGlobal, + arrayView1d< globalIndex const > const & elementLocalToGlobal, + POINT_TYPE const & elemCenter, + POINT_TYPE const & point ) +{ + arraySlice1d< localIndex const > const & faceIndices = elementsToFaces[ element ]; + localIndex const numFaces = faceIndices.size(); + int omega = 0; + for( localIndex kf = 0; kf < numFaces; ++kf ) + { + // triangulate the face. The triangulation must be done in a consistent way across ranks. + // This can be achieved by always picking the vertex with the lowest global index as root. + localIndex const faceIndex = faceIndices[kf]; + globalIndex minGlobalId = LvArray::NumericLimits< globalIndex >::max; + localIndex minVertex = -1; + localIndex numFaceVertices = facesToNodes[faceIndex].size(); + for( localIndex v = 0; v < numFaceVertices; v++ ) + { + localIndex vIndex = facesToNodes( faceIndex, v ); + globalIndex globalId = nodeLocalToGlobal[ vIndex ]; + if( globalId < minGlobalId ) + { + minGlobalId = globalId; + minVertex = vIndex; + } + } + // triangulate the face using the minimum-id vertex as root + localIndex vi[ 3 ] = { minVertex, -1, -1 }; + for( localIndex v = 0; v < numFaceVertices; v++ ) + { + vi[ 1 ] = facesToNodes( faceIndex, v ); + vi[ 2 ] = facesToNodes( faceIndex, (v + 1) % numFaceVertices ); + if( vi[ 1 ] != minVertex && vi[ 2 ] != minVertex ) + { + // To make the algorithm independent of rank, always take the two additional vertices in increasing global ID + if( nodeLocalToGlobal[ vi[ 1 ] ] > nodeLocalToGlobal[ vi[ 2 ] ] ) + { + localIndex temp = vi[ 1 ]; + vi[ 1 ] = vi[ 2 ]; + vi[ 2 ] = temp; + } + COORD_TYPE v1x = nodeCoordinates( vi[ 0 ], 0 ); + COORD_TYPE v1y = nodeCoordinates( vi[ 0 ], 1 ); + COORD_TYPE v1z = nodeCoordinates( vi[ 0 ], 2 ); + COORD_TYPE v2x = nodeCoordinates( vi[ 1 ], 0 ); + COORD_TYPE v2y = nodeCoordinates( vi[ 1 ], 1 ); + COORD_TYPE v2z = nodeCoordinates( vi[ 1 ], 2 ); + COORD_TYPE v3x = nodeCoordinates( vi[ 2 ], 0 ); + COORD_TYPE v3y = nodeCoordinates( vi[ 2 ], 1 ); + COORD_TYPE v3z = nodeCoordinates( vi[ 2 ], 2 ); + // check the orientation of this triangle + R1Tensor vv1 = { v2x - v1x, v2y - v1y, v2z - v1z }; + R1Tensor vv2 = { v3x - v1x, v3y - v1y, v3z - v1z }; + R1Tensor dist = { elemCenter[ 0 ] - ( v1x + v2x + v3x )/3.0, + elemCenter[ 1 ] - ( v1y + v2y + v3y )/3.0, + elemCenter[ 2 ] - ( v1z + v2z + v3z )/3.0 }; + R1Tensor norm = { }; + LvArray::tensorOps::crossProduct( norm, vv1, vv2 ); + // check if face is oriented coherently, and change sign otherwise + int sign = LvArray::tensorOps::AiBi< 3 >( norm, dist ) > 0 ? -1 : +1; + // Compute the winding number contributed by this triangle + int cmp1 = lexicographicalCompareVertex( point[ 0 ], point[ 1 ], point[ 2 ], v1x, v1y, v1z ); + if( cmp1 == 0 ) + { + return findVertexRefElement( nodesToElements[ vi[ 0 ] ], elementLocalToGlobal ) == element; + } + int cmp2 = lexicographicalCompareVertex( point[ 0 ], point[ 1 ], point[ 2 ], v2x, v2y, v2z ); + if( cmp2 == 0 ) + { + return findVertexRefElement( nodesToElements[ vi[ 1 ] ], elementLocalToGlobal ) == element; + } + int cmp3 = lexicographicalCompareVertex( point[ 0 ], point[ 1 ], point[ 2 ], v3x, v3y, v3z ); + if( cmp3 == 0 ) + { + return findVertexRefElement( nodesToElements[ vi[ 2 ] ], elementLocalToGlobal ) == element; + } + int facecmp = 0; + int edgecmp = 0; + if( cmp1 != cmp2 ) + { + edgecmp = lexicographicalCompareEdge( point[ 0 ], point[ 1 ], point[ 2 ], + v1x, v1y, v1z, + v2x, v2y, v2z ); + if( edgecmp == 0 ) + { + return findEdgeRefElement( nodesToElements[ vi[ 0 ] ], nodesToElements[ vi[ 1 ] ], elementLocalToGlobal ) == element; + } + facecmp += sign * edgecmp; + } + if( cmp2 != cmp3 ) + { + edgecmp = lexicographicalCompareEdge( point[ 0 ], point[ 1 ], point[ 2 ], + v2x, v2y, v2z, + v3x, v3y, v3z ); + if( edgecmp == 0 ) + { + return findEdgeRefElement( nodesToElements[ vi[ 1 ] ], nodesToElements[ vi[ 2 ] ], elementLocalToGlobal ) == element; + } + facecmp += sign * edgecmp; + } + if( cmp3 != cmp1 ) + { + edgecmp = lexicographicalCompareEdge( point[ 0 ], point[ 1 ], point[ 2 ], + v3x, v3y, v3z, + v1x, v1y, v1z ); + if( edgecmp == 0 ) + { + return findEdgeRefElement( nodesToElements[ vi[ 0 ] ], nodesToElements[ vi[ 2 ] ], elementLocalToGlobal ) == element; + } + facecmp += sign * edgecmp; + } + // if all edges are on the same side, this triangle does not contribute to the winding number + if( facecmp == 0 ) + continue; + facecmp = lexicographicalCompareTriangle( point[ 0 ], point[ 1 ], point[ 2 ], + v1x, v1y, v1z, + v2x, v2y, v2z, + v3x, v3y, v3z ); + + if( facecmp == 0 ) + { + return findTriangleRefElement( nodesToElements[ vi[ 0 ] ], nodesToElements[ vi[ 1 ] ], nodesToElements[ vi[ 2 ] ], elementLocalToGlobal ) == element; + } + omega += sign * facecmp; + } + } + } + + return omega; +} + +/** + * @brief Check if a point is inside a convex polyhedron (3D polygon), using a robust method + * to avoid ambiguity when the point lies on an interface. + * This method is based on the following method: + * - the winding number omega of the point with respect to the cell is used to determine if the point is inside (omega=1) or not (omega=0) + * - corner cases (point lying on a face, edge or vertex of the cell) are detected using a robust method based on lexicographical + * comparisons + * - these comparisons are made consistent across MPI ranks by consistently arranging items based on global indices (GIDs). In particular: + * - Faces are triangulated using the vertex with the smallest GID as root; + * - Edges and faces are described by vertices in increasing GID order + * - Finally, if the point lies on a (vertex, edge, face), it is assigned to the first shared element with the least global index + * @tparam POINT_TYPE type of @p point + * @param[in] element the element to be checked + * @param[in] nodeCoordinates a global array of nodal coordinates + * @param[in] elementsToFaces map from elements to faces + * @param[in] facesToNodes map from faces to nodes + * @param[in] nodesToElements map from nodes to elements + * @param[in] nodeLocalToGlobal global indices of nodes + * @param[in] elementLocalToGlobal global indices of elements + * @param[in] elemCenter coordinates of the element centroid + * @param[in] point coordinates of the query point + * @return whether the point is inside + */ +template< typename COORD_TYPE, typename POINT_TYPE > +GEOS_HOST_DEVICE +bool isPointInsideConvexPolyhedronRobust( localIndex element, + arrayView2d< COORD_TYPE const, nodes::REFERENCE_POSITION_USD > const & nodeCoordinates, + arrayView2d< localIndex const > const & elementsToFaces, + ArrayOfArraysView< localIndex const > const & facesToNodes, + ArrayOfArraysView< localIndex const > const & nodesToElements, + arrayView1d< globalIndex const > const & nodeLocalToGlobal, + arrayView1d< globalIndex const > const & elementLocalToGlobal, + POINT_TYPE const & elemCenter, + POINT_TYPE const & point ) +{ + return computeWindingNumber( element, nodeCoordinates, elementsToFaces, facesToNodes, nodesToElements, nodeLocalToGlobal, elementLocalToGlobal, elemCenter, point ) > 0; +} + /** * @brief Compute the dimensions of the bounding box containing the element * defined here by the coordinates of its vertices. @@ -422,7 +852,7 @@ void getBoundingBox( localIndex const elemIndex, LvArray::NumericLimits< real64 >::max }; // boxDims is used to hold the max coordinates. - LvArray::tensorOps::fill< 3 >( boxDims, LvArray::NumericLimits< real64 >::min ); + LvArray::tensorOps::fill< 3 >( boxDims, LvArray::NumericLimits< real64 >::lowest ); // loop over all the vertices of the element to get the min and max coords for( localIndex a = 0; a < pointIndices.size( 1 ); ++a ) diff --git a/src/coreComponents/mesh/utilities/MeshMapUtilities.hpp b/src/coreComponents/mesh/utilities/MeshMapUtilities.hpp index dabfb7cd03b..a3508a6e55b 100644 --- a/src/coreComponents/mesh/utilities/MeshMapUtilities.hpp +++ b/src/coreComponents/mesh/utilities/MeshMapUtilities.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/mesh/utilities/StructuredGridUtilities.hpp b/src/coreComponents/mesh/utilities/StructuredGridUtilities.hpp index 02f530b2d0e..41c62f6a860 100644 --- a/src/coreComponents/mesh/utilities/StructuredGridUtilities.hpp +++ b/src/coreComponents/mesh/utilities/StructuredGridUtilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/CMakeLists.txt b/src/coreComponents/physicsSolvers/CMakeLists.txt index c7d26a6bfd3..37c1da41495 100644 --- a/src/coreComponents/physicsSolvers/CMakeLists.txt +++ b/src/coreComponents/physicsSolvers/CMakeLists.txt @@ -1,219 +1,84 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: physicsSolvers + +Contains: + - physics solvers base and manager classes. + - implementations of different physics models. + - physics solver wrapper designed for PyGEOSX interface. +#]] + +# # Specify solver headers +# set( physicsSolvers_headers LinearSolverParameters.hpp NonlinearSolverParameters.hpp PhysicsSolverManager.hpp - SolverBase.hpp - SolverBaseKernels.hpp + PhysicsSolverBase.hpp + PhysicsSolverBaseKernels.hpp SolverStatistics.hpp FieldStatisticsBase.hpp - contact/ContactSolverBase.hpp - contact/ContactFields.hpp - contact/SolidMechanicsEFEMKernelsBase.hpp - contact/SolidMechanicsEFEMKernels.hpp - contact/SolidMechanicsEFEMStaticCondensationKernels.hpp - contact/SolidMechanicsEFEMKernelsHelper.hpp - contact/SolidMechanicsEmbeddedFractures.hpp - contact/SolidMechanicsLagrangeContact.hpp - fluidFlow/CompositionalMultiphaseBase.hpp - fluidFlow/CompositionalMultiphaseBaseFields.hpp - fluidFlow/CompositionalMultiphaseStatistics.hpp - fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp - fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp - fluidFlow/CompositionalMultiphaseFVM.hpp - fluidFlow/IsothermalCompositionalMultiphaseFVMKernels.hpp - fluidFlow/IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp - fluidFlow/ThermalCompositionalMultiphaseFVMKernels.hpp - fluidFlow/CompositionalMultiphaseHybridFVM.hpp - fluidFlow/CompositionalMultiphaseHybridFVMKernels.hpp - fluidFlow/CompositionalMultiphaseUtilities.hpp - fluidFlow/ReactiveCompositionalMultiphaseOBL.hpp - fluidFlow/ReactiveCompositionalMultiphaseOBLFields.hpp - fluidFlow/ReactiveCompositionalMultiphaseOBLKernels.hpp - fluidFlow/FlowSolverBase.hpp - fluidFlow/FlowSolverBaseFields.hpp - fluidFlow/FlowSolverBaseKernels.hpp - fluidFlow/FluxKernelsHelper.hpp - fluidFlow/HybridFVMHelperKernels.hpp - fluidFlow/proppantTransport/ProppantTransport.hpp - fluidFlow/proppantTransport/ProppantTransportFields.hpp - fluidFlow/proppantTransport/ProppantTransportKernels.hpp - fluidFlow/SinglePhaseBase.hpp - fluidFlow/SinglePhaseBaseFields.hpp - fluidFlow/SinglePhaseBaseKernels.hpp - fluidFlow/SinglePhaseStatistics.hpp - fluidFlow/SinglePhaseFVM.hpp - fluidFlow/SinglePhaseFVMKernels.hpp - fluidFlow/SinglePhaseHybridFVM.hpp - fluidFlow/SinglePhaseHybridFVMKernels.hpp - fluidFlow/SinglePhaseProppantBase.hpp - fluidFlow/SinglePhaseProppantBaseKernels.hpp - fluidFlow/SinglePhaseProppantFluxKernels.hpp - fluidFlow/StabilizedCompositionalMultiphaseFVMKernels.hpp - fluidFlow/StencilAccessors.hpp - fluidFlow/ThermalSinglePhaseBaseKernels.hpp - fluidFlow/ThermalSinglePhaseFVMKernels.hpp - fluidFlow/wells/CompositionalMultiphaseWell.hpp - fluidFlow/wells/CompositionalMultiphaseWellFields.hpp - fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp - fluidFlow/wells/SinglePhaseWell.hpp - fluidFlow/wells/SinglePhaseWellFields.hpp - fluidFlow/wells/SinglePhaseWellKernels.hpp - fluidFlow/wells/WellConstants.hpp - fluidFlow/wells/WellControls.hpp - fluidFlow/wells/WellSolverBase.hpp - fluidFlow/wells/WellSolverBaseFields.hpp - multiphysics/CompositionalMultiphaseReservoirAndWells.hpp - multiphysics/CoupledReservoirAndWellsBase.hpp - multiphysics/CoupledSolver.hpp - multiphysics/PoromechanicsSolver.hpp - multiphysics/FlowProppantTransportSolver.hpp - multiphysics/HydrofractureSolver.hpp - multiphysics/HydrofractureSolverKernels.hpp - multiphysics/MultiphasePoromechanics.hpp - multiphysics/PhaseFieldFractureSolver.hpp - multiphysics/PoromechanicsInitialization.hpp - multiphysics/PoromechanicsFields.hpp - multiphysics/PoromechanicsInitialization.hpp - multiphysics/poromechanicsKernels/MultiphasePoromechanics.hpp - multiphysics/poromechanicsKernels/MultiphasePoromechanics_impl.hpp - multiphysics/poromechanicsKernels/PoromechanicsBase.hpp - multiphysics/poromechanicsKernels/SinglePhasePoromechanics.hpp - multiphysics/poromechanicsKernels/SinglePhasePoromechanics_impl.hpp - multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp - multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM.hpp - multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM_impl.hpp - multiphysics/poromechanicsKernels/SinglePhasePoromechanicsFractures.hpp - multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEmbeddedFractures.hpp - multiphysics/poromechanicsKernels/ThermalMultiphasePoromechanics.hpp - multiphysics/poromechanicsKernels/ThermalMultiphasePoromechanics_impl.hpp - multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanics.hpp - multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanics_impl.hpp - multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEFEM.hpp - multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEFEM_impl.hpp - multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsConformingFractures.hpp - multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEmbeddedFractures.hpp - multiphysics/SinglePhasePoromechanics.hpp - multiphysics/SinglePhasePoromechanicsEmbeddedFractures.hpp - multiphysics/SinglePhasePoromechanicsConformingFractures.hpp - multiphysics/SinglePhaseReservoirAndWells.hpp - simplePDE/LaplaceBaseH1.hpp - simplePDE/LaplaceFEM.hpp - simplePDE/LaplaceFEMKernels.hpp - simplePDE/PhaseFieldDamageFEM.hpp - simplePDE/PhaseFieldDamageFEMKernels.hpp - solidMechanics/SolidMechanicsFields.hpp - solidMechanics/SolidMechanicsLagrangianFEM.hpp - solidMechanics/SolidMechanicsLagrangianSSLE.hpp - solidMechanics/kernels/SolidMechanicsLagrangianFEMKernels.hpp - solidMechanics/SolidMechanicsMPM.hpp - solidMechanics/MPMSolverFields.hpp - solidMechanics/kernels/ExplicitFiniteStrain.hpp - solidMechanics/kernels/ExplicitFiniteStrain_impl.hpp - solidMechanics/kernels/ExplicitMPM.hpp - solidMechanics/kernels/ExplicitSmallStrain.hpp - solidMechanics/kernels/ExplicitSmallStrain_impl.hpp - solidMechanics/kernels/FixedStressThermoPoromechanics.hpp - solidMechanics/kernels/FixedStressThermoPoromechanics_impl.hpp - solidMechanics/kernels/ImplicitSmallStrainNewmark.hpp - solidMechanics/kernels/ImplicitSmallStrainNewmark_impl.hpp - solidMechanics/kernels/ImplicitSmallStrainQuasiStatic.hpp - solidMechanics/kernels/ImplicitSmallStrainQuasiStatic_impl.hpp - solidMechanics/SolidMechanicsStateReset.hpp - solidMechanics/SolidMechanicsStatistics.hpp - surfaceGeneration/EmbeddedSurfaceGenerator.hpp - surfaceGeneration/EmbeddedSurfacesParallelSynchronization.hpp - surfaceGeneration/ParallelTopologyChange.hpp - surfaceGeneration/SurfaceGenerator.hpp - surfaceGeneration/SurfaceGeneratorFields.hpp - surfaceGeneration/kernels/surfaceGenerationKernels.hpp - surfaceGeneration/kernels/surfaceGenerationKernelsHelpers.hpp - wavePropagation/WaveSolverBase.hpp - wavePropagation/WaveSolverUtils.hpp - wavePropagation/AcousticFields.hpp - wavePropagation/AcousticWaveEquationSEM.hpp - wavePropagation/AcousticWaveEquationSEMKernel.hpp - wavePropagation/ElasticFields.hpp - wavePropagation/ElasticWaveEquationSEM.hpp - wavePropagation/ElasticWaveEquationSEMKernel.hpp - wavePropagation/ElasticFirstOrderWaveEquationSEM.hpp - wavePropagation/ElasticFirstOrderWaveEquationSEMKernel.hpp - wavePropagation/AcousticFirstOrderWaveEquationSEM.hpp - wavePropagation/AcousticFirstOrderWaveEquationSEMKernel.hpp - wavePropagation/AcousticVTIFields.hpp - wavePropagation/AcousticVTIWaveEquationSEM.hpp - wavePropagation/AcousticVTIWaveEquationSEMKernel.hpp - wavePropagation/AcoustoElasticFields.hpp - wavePropagation/AcousticElasticWaveEquationSEM.hpp - wavePropagation/AcousticElasticWaveEquationSEMKernel.hpp ) + LogLevelsInfo.hpp ) +# # Specify solver sources +# set( physicsSolvers_sources LinearSolverParameters.cpp NonlinearSolverParameters.cpp PhysicsSolverManager.cpp - SolverBase.cpp - SolverStatistics.cpp - contact/ContactSolverBase.cpp - contact/SolidMechanicsEmbeddedFractures.cpp - contact/SolidMechanicsLagrangeContact.cpp - fluidFlow/CompositionalMultiphaseBase.cpp - fluidFlow/CompositionalMultiphaseFVM.cpp - fluidFlow/CompositionalMultiphaseStatistics.cpp - fluidFlow/IsothermalCompositionalMultiphaseFVMKernels.cpp - fluidFlow/CompositionalMultiphaseHybridFVM.cpp - fluidFlow/CompositionalMultiphaseHybridFVMKernels.cpp - fluidFlow/ReactiveCompositionalMultiphaseOBL.cpp - fluidFlow/FlowSolverBase.cpp - fluidFlow/proppantTransport/ProppantTransport.cpp - fluidFlow/proppantTransport/ProppantTransportKernels.cpp - fluidFlow/SinglePhaseBase.cpp - fluidFlow/SinglePhaseStatistics.cpp - fluidFlow/SinglePhaseFVM.cpp - fluidFlow/SinglePhaseHybridFVM.cpp - fluidFlow/SinglePhaseProppantBase.cpp - fluidFlow/SinglePhaseProppantFluxKernels.cpp - fluidFlow/wells/CompositionalMultiphaseWell.cpp - fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp - fluidFlow/wells/SinglePhaseWell.cpp - fluidFlow/wells/SinglePhaseWellKernels.cpp - fluidFlow/wells/WellControls.cpp - fluidFlow/wells/WellSolverBase.cpp - multiphysics/CompositionalMultiphaseReservoirAndWells.cpp - multiphysics/CoupledReservoirAndWellsBase.cpp - multiphysics/FlowProppantTransportSolver.cpp - multiphysics/HydrofractureSolver.cpp - multiphysics/MultiphasePoromechanics.cpp - multiphysics/PhaseFieldFractureSolver.cpp - multiphysics/PoromechanicsInitialization.cpp - multiphysics/SinglePhasePoromechanics.cpp - multiphysics/SinglePhasePoromechanicsEmbeddedFractures.cpp - multiphysics/SinglePhasePoromechanicsConformingFractures.cpp - multiphysics/SinglePhaseReservoirAndWells.cpp - simplePDE/LaplaceBaseH1.cpp - simplePDE/LaplaceFEM.cpp - simplePDE/PhaseFieldDamageFEM.cpp - solidMechanics/SolidMechanicsLagrangianFEM.cpp - solidMechanics/SolidMechanicsLagrangianSSLE.cpp - solidMechanics/SolidMechanicsMPM.cpp - solidMechanics/SolidMechanicsStateReset.cpp - solidMechanics/SolidMechanicsStatistics.cpp - surfaceGeneration/EmbeddedSurfaceGenerator.cpp - surfaceGeneration/EmbeddedSurfacesParallelSynchronization.cpp - surfaceGeneration/ParallelTopologyChange.cpp - surfaceGeneration/SurfaceGenerator.cpp - wavePropagation/WaveSolverBase.cpp - wavePropagation/AcousticWaveEquationSEM.cpp - wavePropagation/ElasticWaveEquationSEM.cpp - wavePropagation/ElasticFirstOrderWaveEquationSEM.cpp - wavePropagation/AcousticFirstOrderWaveEquationSEM.cpp - wavePropagation/AcousticVTIWaveEquationSEM.cpp - wavePropagation/AcousticElasticWaveEquationSEM.cpp ) + PhysicsSolverBase.cpp + SolverStatistics.cpp ) - include( solidMechanics/kernels/SolidMechanicsKernels.cmake) +if( GEOS_ENABLE_CONTACT ) + add_subdirectory( contact ) +endif() + +if( GEOS_ENABLE_FLUIDFLOW ) + add_subdirectory( fluidFlow ) +endif() + +if( GEOS_ENABLE_INDUCEDSEISMICITY ) + add_subdirectory( inducedSeismicity ) +endif() + +if( GEOS_ENABLE_MULTIPHYSICS ) + add_subdirectory( multiphysics ) include( multiphysics/poromechanicsKernels/PoromechanicsKernels.cmake) +endif() + +if( GEOS_ENABLE_SIMPLEPDE ) + add_subdirectory( simplePDE ) +endif() + +if( GEOS_ENABLE_SOLIDMECHANICS ) + add_subdirectory( solidMechanics ) + include( solidMechanics/kernels/SolidMechanicsKernels.cmake) +endif() + +if( GEOS_ENABLE_SURFACEGENERATION ) + add_subdirectory( surfaceGeneration ) +endif() + +if( GEOS_ENABLE_WAVEPROPAGATION ) + add_subdirectory( wavePropagation ) +endif() + +set( dependencyList ${parallelDeps} fileIO discretizationMethods events linearAlgebra ) -set( dependencyList ${parallelDeps} constitutive mesh linearAlgebra discretizationMethods events ) if( ENABLE_PYGEOSX ) list( APPEND physicsSolvers_headers python/PySolver.hpp @@ -223,13 +88,21 @@ if( ENABLE_PYGEOSX ) list( APPEND dependencyList Python3::Python pylvarray ) endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) + blt_add_library( NAME physicsSolvers SOURCES ${physicsSolvers_sources} HEADERS ${physicsSolvers_headers} - DEPENDS_ON ${dependencyList} ${externalComponentDeps} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} ) + DEPENDS_ON ${decoratedDependencies} ${externalComponentDeps} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} + ) target_include_directories( physicsSolvers PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) + +install( TARGETS physicsSolvers LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) + if( externalComponentDeps ) target_include_directories( physicsSolvers PUBLIC ${CMAKE_SOURCE_DIR}/externalComponents ) endif() diff --git a/src/coreComponents/physicsSolvers/FieldStatisticsBase.hpp b/src/coreComponents/physicsSolvers/FieldStatisticsBase.hpp index fc1f4a2c5a3..c2516decb26 100644 --- a/src/coreComponents/physicsSolvers/FieldStatisticsBase.hpp +++ b/src/coreComponents/physicsSolvers/FieldStatisticsBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,7 +22,6 @@ #include "events/tasks/TaskBase.hpp" #include "physicsSolvers/PhysicsSolverManager.hpp" -#include "mainInterface/ProblemManager.hpp" #include "mesh/MeshLevel.hpp" #include "fileIO/Outputs/OutputBase.hpp" @@ -81,10 +81,10 @@ class FieldStatisticsBase : public TaskBase protected: - void postProcessInput() override + void postInputInitialization() override { - ProblemManager & problemManager = this->getGroupByPath< ProblemManager >( "/Problem" ); - PhysicsSolverManager & physicsSolverManager = problemManager.getPhysicsSolverManager(); + Group & problemManager = this->getGroupByPath( "/Problem" ); + Group & physicsSolverManager = problemManager.getGroup( "Solvers" ); m_solver = physicsSolverManager.getGroupPointer< SOLVER >( m_solverName ); GEOS_THROW_IF( m_solver == nullptr, diff --git a/src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp b/src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp new file mode 100644 index 00000000000..99dd27435c1 --- /dev/null +++ b/src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp @@ -0,0 +1,175 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file KernelLaunchSelectors.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_KERNELLAUNCHSELECTORS_HPP +#define GEOS_PHYSICSSOLVERS_KERNELLAUNCHSELECTORS_HPP + +namespace geos +{ +namespace internal +{ + +template< typename S, typename T, typename LAMBDA > +void invokePhaseDispatchLambda ( S val, T numPhases, LAMBDA && lambda ) +{ + if( numPhases == 1 ) + { + lambda( val, std::integral_constant< T, 1 >()); + return; + } + else if( numPhases == 2 ) + { + lambda( val, std::integral_constant< T, 2 >()); + return; + } + else if( numPhases == 3 ) + { + lambda( val, std::integral_constant< T, 3 >()); + return; + } + else + { + GEOS_ERROR( "Unsupported state: " << numPhases ); + } +} + +template< typename S, typename T, typename LAMBDA > +void invokeThermalDispatchLambda ( S val, T isThermal, LAMBDA && lambda ) +{ + if( isThermal == 1 ) + { + lambda( val, std::integral_constant< T, 1 >()); + return; + } + else if( isThermal == 0 ) + { + lambda( val, std::integral_constant< T, 0 >()); + return; + } + else + { + GEOS_ERROR( "Unsupported state: " << isThermal ); + } +} + +template< typename T, typename LAMBDA > +void kernelLaunchSelectorThermalSwitch( T value, LAMBDA && lambda ) +{ + static_assert( std::is_integral< T >::value, "kernelLaunchSelectorThermalSwitch: type should be integral" ); + + switch( value ) + { + case 0: + { + lambda( std::integral_constant< T, 0 >() ); + return; + } + case 1: + { + lambda( std::integral_constant< T, 1 >() ); + return; + } + default: + { + GEOS_ERROR( "Unsupported thermal state: " << value ); + } + } +} + +template< typename T, typename LAMBDA > +void kernelLaunchSelectorCompThermSwitch( T value, bool const isThermal, LAMBDA && lambda ) +{ + static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: value type should be integral" ); + + + switch( value ) + { + case 1: + { + invokeThermalDispatchLambda( std::integral_constant< T, 1 >(), isThermal, lambda ); return; + } + case 2: + { + invokeThermalDispatchLambda( std::integral_constant< T, 2 >(), isThermal, lambda ); + return; + } + case 3: + { + invokeThermalDispatchLambda( std::integral_constant< T, 3 >(), isThermal, lambda ); + return; + } + case 4: + { + invokeThermalDispatchLambda( std::integral_constant< T, 4 >(), isThermal, lambda ); + return; + } + case 5: + { + invokeThermalDispatchLambda( std::integral_constant< T, 5 >(), isThermal, lambda ); + return; + } + default: + { + GEOS_ERROR( "Unsupported number of components: " << value ); + } + } +} + +template< typename T, typename LAMBDA > +void kernelLaunchSelectorCompPhaseSwitch( T value, T n_phase, LAMBDA && lambda ) +{ + static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: value type should be integral" ); + switch( value ) + { + case 1: + { + invokePhaseDispatchLambda( std::integral_constant< T, 1 >(), n_phase, lambda ); + return; + } + case 2: + { + invokePhaseDispatchLambda( std::integral_constant< T, 2 >(), n_phase, lambda ); + return; + } + case 3: + { + invokePhaseDispatchLambda( std::integral_constant< T, 3 >(), n_phase, lambda ); + return; + } + case 4: + { + invokePhaseDispatchLambda( std::integral_constant< T, 4 >(), n_phase, lambda ); + return; + } + case 5: + { + invokePhaseDispatchLambda( std::integral_constant< T, 5 >(), n_phase, lambda ); + return; + } + default: + { GEOS_ERROR( "Unsupported number of components: " << value ); } + } +} + + +} // end namspace internal +} // end namespace geos + + +#endif // GEOS_PHYSICSSOLVERS_KERNELLAUNCHSELECTORS_HPP diff --git a/src/coreComponents/physicsSolvers/LinearSolverParameters.cpp b/src/coreComponents/physicsSolvers/LinearSolverParameters.cpp index 6fa15ae76e4..a5f5b402760 100644 --- a/src/coreComponents/physicsSolvers/LinearSolverParameters.cpp +++ b/src/coreComponents/physicsSolvers/LinearSolverParameters.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,6 +18,7 @@ */ #include "LinearSolverParameters.hpp" +#include "common/format/table/TableFormatter.hpp" namespace geos { @@ -113,6 +115,21 @@ LinearSolverParametersInput::LinearSolverParametersInput( string const & name, setInputFlag( InputFlags::OPTIONAL ). setDescription( "Weakest-allowed tolerance for adaptive method" ); + registerWrapper( viewKeyStruct::krylovStrongTolString(), &m_parameters.krylov.strongestTol ). + setApplyDefaultValue( m_parameters.krylov.strongestTol ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Strongest-allowed tolerance for adaptive method" ); + + registerWrapper( viewKeyStruct::adaptiveGammaString(), &m_parameters.krylov.adaptiveGamma ). + setApplyDefaultValue( m_parameters.krylov.adaptiveGamma ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Gamma parameter for adaptive method" ); + + registerWrapper( viewKeyStruct::adaptiveExponentString(), &m_parameters.krylov.adaptiveExponent ). + setApplyDefaultValue( m_parameters.krylov.adaptiveExponent ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Exponent parameter for adaptive method" ); + registerWrapper( viewKeyStruct::amgNumSweepsString(), &m_parameters.amg.numSweeps ). setApplyDefaultValue( m_parameters.amg.numSweeps ). setInputFlag( InputFlags::OPTIONAL ). @@ -200,7 +217,7 @@ LinearSolverParametersInput::LinearSolverParametersInput( string const & name, setDescription( "ILU(T) threshold factor" ); } -void LinearSolverParametersInput::postProcessInput() +void LinearSolverParametersInput::postInputInitialization() { m_parameters.logLevel = getLogLevel(); @@ -257,6 +274,79 @@ void LinearSolverParametersInput::postProcessInput() ": Invalid value." ); // TODO input validation for other AMG parameters ? + + if( getLogLevel() > 0 ) + print(); +} + +void LinearSolverParametersInput::print() +{ + TableData tableData; + tableData.addRow( "Log level", getLogLevel()); + tableData.addRow( "Linear solver type", m_parameters.solverType ); + tableData.addRow( "Preconditioner type", m_parameters.preconditionerType ); + tableData.addRow( "Stop if error", m_parameters.stopIfError ); + if( m_parameters.solverType == LinearSolverParameters::SolverType::direct ) + { + tableData.addRow( "Check residual", m_parameters.direct.checkResidual ); + tableData.addRow( "Scale rows and columns", m_parameters.direct.equilibrate ); + tableData.addRow( "Columns permutation", m_parameters.direct.colPerm ); + tableData.addRow( "Rows permutation", m_parameters.direct.rowPerm ); + tableData.addRow( "Replace tiny pivots", m_parameters.direct.replaceTinyPivot ); + tableData.addRow( "Perform iterative refinement", m_parameters.direct.iterativeRefine ); + tableData.addRow( "Use parallel solver", m_parameters.direct.parallel ); + } + else + { + tableData.addRow( "Maximum iterations", m_parameters.krylov.maxIterations ); + if( m_parameters.solverType == LinearSolverParameters::SolverType::gmres || + m_parameters.solverType == LinearSolverParameters::SolverType::fgmres ) + { + tableData.addRow( "Maximum iterations before restart", m_parameters.krylov.maxRestart ); + } + tableData.addRow( "Use adaptive tolerance", m_parameters.krylov.useAdaptiveTol ); + if( m_parameters.krylov.useAdaptiveTol ) + { + tableData.addRow( "Weakest-allowed tolerance", m_parameters.krylov.weakestTol ); + } + else + { + tableData.addRow( "Relative convergence tolerance", m_parameters.krylov.relTolerance ); + } + } + if( m_parameters.preconditionerType == LinearSolverParameters::PreconditionerType::amg ) + { + tableData.addRow( "AMG", "" ); + tableData.addRow( " Smoother sweeps", m_parameters.amg.numSweeps ); + tableData.addRow( " Smoother type", m_parameters.amg.smootherType ); + tableData.addRow( " Relaxation factor for the smoother", m_parameters.amg.relaxWeight ); + tableData.addRow( " Coarsest level solver/smoother type", m_parameters.amg.coarseType ); + tableData.addRow( " Coarsening algorithm", m_parameters.amg.coarseningType ); + tableData.addRow( " Interpolation algorithm", m_parameters.amg.interpolationType ); + tableData.addRow( " Interpolation maximum number of nonzeros per row", m_parameters.amg.interpolationMaxNonZeros ); + tableData.addRow( " Number of functions", m_parameters.amg.numFunctions ); + tableData.addRow( " Number of paths for aggressive coarsening", m_parameters.amg.aggressiveNumPaths ); + tableData.addRow( " Number of levels for aggressive coarsening", m_parameters.amg.aggressiveNumLevels ); + tableData.addRow( " Aggressive interpolation algorithm", m_parameters.amg.aggressiveInterpType ); + tableData.addRow( " Strength-of-connection threshold", m_parameters.amg.threshold ); + tableData.addRow( " Apply separate component filter for multi-variable problems", m_parameters.amg.separateComponents ); + tableData.addRow( " Near null space approximation", m_parameters.amg.nullSpaceType ); + } + else if( m_parameters.preconditionerType == LinearSolverParameters::PreconditionerType::iluk || + m_parameters.preconditionerType == LinearSolverParameters::PreconditionerType::ilut ) + { + tableData.addRow( "ILU(K) fill factor", m_parameters.ifact.fill ); + if( m_parameters.preconditionerType == LinearSolverParameters::PreconditionerType::ilut ) + { + tableData.addRow( "ILU(T) threshold factor", m_parameters.ifact.threshold ); + } + } + TableLayout const tableLayout = TableLayout( { + TableLayout::ColumnParam{"Parameter", TableLayout::Alignment::left}, + TableLayout::ColumnParam{"Value", TableLayout::Alignment::left}, + }, GEOS_FMT( "{}: linear solver", getParent().getName() ) ); + TableTextFormatter const tableFormatter( tableLayout ); + GEOS_LOG_RANK_0( tableFormatter.toString( tableData )); } REGISTER_CATALOG_ENTRY( Group, LinearSolverParametersInput, string const &, Group * const ) diff --git a/src/coreComponents/physicsSolvers/LinearSolverParameters.hpp b/src/coreComponents/physicsSolvers/LinearSolverParameters.hpp index ced2aa2b62a..4b1699a1615 100644 --- a/src/coreComponents/physicsSolvers/LinearSolverParameters.hpp +++ b/src/coreComponents/physicsSolvers/LinearSolverParameters.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -57,7 +58,9 @@ class LinearSolverParametersInput : public dataRepository::Group static string catalogName() { return "LinearSolverParameters"; } /// Postprocessing of input - virtual void postProcessInput() override; + virtual void postInputInitialization() override; + + void print(); LinearSolverParameters const & get() const { return m_parameters; } @@ -100,6 +103,12 @@ class LinearSolverParametersInput : public dataRepository::Group static constexpr char const * krylovAdaptiveTolString() { return "krylovAdaptiveTol"; } /// Krylov weakest tolerance key static constexpr char const * krylovWeakTolString() { return "krylovWeakestTol"; } + /// Krylov strongest tolerance key + static constexpr char const * krylovStrongTolString() { return "krylovStrongestTol"; } + /// Adaptive gamma parameter key + static constexpr char const * adaptiveGammaString() { return "adaptiveGamma"; } + /// Adaptive exponent parameter key + static constexpr char const * adaptiveExponentString() { return "adaptiveExponent"; } /// AMG number of sweeps key static constexpr char const * amgNumSweepsString() { return "amgNumSweeps"; } diff --git a/src/coreComponents/physicsSolvers/LogLevelsInfo.hpp b/src/coreComponents/physicsSolvers/LogLevelsInfo.hpp new file mode 100644 index 00000000000..85f17120411 --- /dev/null +++ b/src/coreComponents/physicsSolvers/LogLevelsInfo.hpp @@ -0,0 +1,100 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file LogLevelsInfo.hpp + * This file contains common log level informations for physics solvers + */ + +#ifndef GEOS_PHYSICSSOLVERS_LOGLEVELSINFO_HPP +#define GEOS_PHYSICSSOLVERS_LOGLEVELSINFO_HPP + +#include "common/DataTypes.hpp" + +namespace geos +{ + +namespace logInfo +{ + +/** + * @name Common LogLevels info structures. They must comply with the `is_log_level_info` trait. + */ +///@{ + +/// @cond DO_NOT_DOCUMENT + +struct Fields +{ + static constexpr int getMinLogLevel() { return 2; } + static constexpr std::string_view getDescription() { return "The summary of declared fields and coupling"; } +}; + +struct LineSearch +{ + static constexpr int getMinLogLevel() { return 1; } + static constexpr std::string_view getDescription() { return "Line search information"; } +}; + +struct Solution +{ + static constexpr int getMinLogLevel() { return 1; } + static constexpr std::string_view getDescription() { return "Solution information (scaling, maximum changes, quality check)"; } +}; + +struct Convergence +{ + static constexpr int getMinLogLevel() { return 1; } + static constexpr std::string_view getDescription() { return "Convergence information"; } +}; + +struct TimeStep +{ + static constexpr int getMinLogLevel() { return 1; } + static constexpr std::string_view getDescription() { return "Time step information"; } +}; + +struct LinearSolver +{ + static constexpr int getMinLogLevel() { return 1; } + static constexpr std::string_view getDescription() { return "Linear solver information"; } +}; + +struct NonlinearSolver +{ + static constexpr int getMinLogLevel() { return 1; } + static constexpr std::string_view getDescription() { return "Nonlinear solver information"; } +}; + +struct Timers +{ + static constexpr int getMinLogLevel() { return 1; } + static constexpr std::string_view getDescription() { return "Solver timers information"; } +}; + +struct Initialization +{ + static constexpr int getMinLogLevel() { return 1; } + static constexpr std::string_view getDescription() { return "Initialization information"; } +}; + +/// @endcond +///@} + +} + +} + +#endif // GEOS_PHYSICSSOLVERS_LOGLEVELSINFO_HPP diff --git a/src/coreComponents/physicsSolvers/NonlinearSolverParameters.cpp b/src/coreComponents/physicsSolvers/NonlinearSolverParameters.cpp index 05946aa15b8..86563d4be24 100644 --- a/src/coreComponents/physicsSolvers/NonlinearSolverParameters.cpp +++ b/src/coreComponents/physicsSolvers/NonlinearSolverParameters.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -13,7 +14,8 @@ */ #include "NonlinearSolverParameters.hpp" -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" +#include "common/format/table/TableFormatter.hpp" namespace geos { @@ -35,7 +37,7 @@ NonlinearSolverParameters::NonlinearSolverParameters( string const & name, setDescription( "How the line search is to be used. Options are: \n " "* None - Do not use line search.\n" "* Attempt - Use line search. Allow exit from line search without achieving smaller residual than starting residual.\n" - "* Require - Use line search. If smaller residual than starting resdual is not achieved, cut time step." ); + "* Require - Use line search. If smaller residual than starting resdual is not achieved, cut time-step." ); registerWrapper( viewKeysStruct::lineSearchInterpolationTypeString(), &m_lineSearchInterpType ). setApplyDefaultValue( LineSearchInterpolationType::Linear ). @@ -60,11 +62,16 @@ NonlinearSolverParameters::NonlinearSolverParameters( string const & name, setInputFlag( InputFlags::OPTIONAL ). setDescription( "Iteration when line search starts." ); + registerWrapper( viewKeysStruct::lineSearchResidualFactorString(), &m_lineSearchResidualFactor ). + setApplyDefaultValue( 1.0 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Factor to determine residual increase (recommended values: 1.1 (conservative), 2.0 (relaxed), 10.0 (aggressive))." ); + registerWrapper( viewKeysStruct::normTypeString(), &m_normType ). setInputFlag( InputFlags::FALSE ). - setApplyDefaultValue( solverBaseKernels::NormType::Linf ). + setApplyDefaultValue( physicsSolverBaseKernels::NormType::Linf ). setDescription( "Norm used by the flow solver to check nonlinear convergence. " - "Valid options:\n* " + EnumStrings< solverBaseKernels::NormType >::concat( "\n* " ) ); + "Valid options:\n* " + EnumStrings< physicsSolverBaseKernels::NormType >::concat( "\n* " ) ); registerWrapper( viewKeysStruct::minNormalizerString(), &m_minNormalizer ). setInputFlag( dataRepository::InputFlags::OPTIONAL ). @@ -105,32 +112,37 @@ NonlinearSolverParameters::NonlinearSolverParameters( string const & name, registerWrapper( viewKeysStruct::timeStepDecreaseIterLimString(), &m_timeStepDecreaseIterLimit ). setApplyDefaultValue( 0.7 ). setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Fraction of the max Newton iterations above which the solver asks for the time-step to be decreased for the next time step." ); + setDescription( "Fraction of the max Newton iterations above which the solver asks for the time-step to be decreased for the next time-step." ); registerWrapper( viewKeysStruct::timeStepIncreaseIterLimString(), &m_timeStepIncreaseIterLimit ). setApplyDefaultValue( 0.4 ). setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Fraction of the max Newton iterations below which the solver asks for the time-step to be increased for the next time step." ); + setDescription( "Fraction of the max Newton iterations below which the solver asks for the time-step to be increased for the next time-step." ); registerWrapper( viewKeysStruct::timeStepDecreaseFactorString(), &m_timeStepDecreaseFactor ). setApplyDefaultValue( 0.5 ). setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Factor by which the time step is decreased when the number of Newton iterations is large." ); + setDescription( "Factor by which the time-step is decreased when the number of Newton iterations is large." ); registerWrapper( viewKeysStruct::timeStepIncreaseFactorString(), &m_timeStepIncreaseFactor ). setApplyDefaultValue( 2.0 ). setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Factor by which the time step is increased when the number of Newton iterations is small." ); + setDescription( "Factor by which the time-step is increased when the number of Newton iterations is small." ); + + registerWrapper( viewKeysStruct::minTimeStepIncreaseIntervalString(), &m_minTimeStepIncreaseInterval ). + setApplyDefaultValue( 10 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Minimum number of cycles since the last time-step cut for increasing the time-step again." ); registerWrapper( viewKeysStruct::timeStepCutFactorString(), &m_timeStepCutFactor ). setApplyDefaultValue( 0.5 ). setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Factor by which the time step will be cut if a timestep cut is required." ); + setDescription( "Factor by which the time-step will be cut if a time-step cut is required." ); registerWrapper( viewKeysStruct::maxTimeStepCutsString(), &m_maxTimeStepCuts ). setApplyDefaultValue( 2 ). setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Max number of time step cuts" ); + setDescription( "Max number of time-step cuts" ); registerWrapper( viewKeysStruct::maxSubStepsString(), &m_maxSubSteps ). setApplyDefaultValue( 10 ). @@ -142,6 +154,11 @@ NonlinearSolverParameters::NonlinearSolverParameters( string const & name, setInputFlag( InputFlags::OPTIONAL ). setDescription( "Max number of times that the configuration can be changed" ); + registerWrapper( viewKeysStruct::configurationToleranceString(), &m_configurationTolerance ). + setApplyDefaultValue( 0.0 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Configuration tolerance" ); + /// GEOS mainly uses FIM coupling so let's define FIM as the default. registerWrapper( viewKeysStruct::couplingTypeString(), &m_couplingType ). setInputFlag( dataRepository::InputFlags::OPTIONAL ). @@ -160,54 +177,71 @@ NonlinearSolverParameters::NonlinearSolverParameters( string const & name, setApplyDefaultValue( 0 ). setDescription( "Flag to decide whether to iterate between sequentially coupled solvers or not." ); - this->registerWrapper( viewKeysStruct::nonlinearAccelerationTypeString(), &m_nonlinearAccelerationType ). + registerWrapper( viewKeysStruct::nonlinearAccelerationTypeString(), &m_nonlinearAccelerationType ). setApplyDefaultValue( NonlinearAccelerationType::None ). setInputFlag( dataRepository::InputFlags::OPTIONAL ). setDescription( "Nonlinear acceleration type for sequential solver." ); } -void NonlinearSolverParameters::postProcessInput() +void NonlinearSolverParameters::postInputInitialization() { GEOS_ERROR_IF_LE_MSG( m_timeStepDecreaseIterLimit, m_timeStepIncreaseIterLimit, getWrapperDataContext( viewKeysStruct::timeStepIncreaseIterLimString() ) << ": should be smaller than " << viewKeysStruct::timeStepDecreaseIterLimString() ); + GEOS_ERROR_IF_LE_MSG( m_lineSearchResidualFactor, 0.0, + getWrapperDataContext( viewKeysStruct::lineSearchResidualFactorString() ) << ": should be positive" ); + if( getLogLevel() > 0 ) { - GEOS_LOG_RANK_0( "Nonlinear solver parameters:" ); - GEOS_LOG_RANK_0( GEOS_FMT( " Line search action = {}", EnumStrings< LineSearchAction >::toString( m_lineSearchAction ) ) ); - if( m_lineSearchAction != LineSearchAction::None ) - { - GEOS_LOG_RANK_0( GEOS_FMT( " Line search interpolation type = {}", EnumStrings< LineSearchInterpolationType >::toString( m_lineSearchInterpType ) ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Line search maximum number of cuts = {}", m_lineSearchMaxCuts ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Line search cut factor = {}", m_lineSearchCutFactor ) ); - } - GEOS_LOG_RANK_0( GEOS_FMT( " Norm type (flow solver) = {}", EnumStrings< solverBaseKernels::NormType >::toString( m_normType ) ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Minimum residual normalizer = {}", m_minNormalizer ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Convergence tolerance = {}", m_newtonTol ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Maximum iterations = {}", m_maxIterNewton ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Minimum iterations = {}", m_minIterNewton ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Maximum allowed residual norm = {}", m_maxAllowedResidualNorm ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Allow non-converged = {}", m_allowNonConverged ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Time step decrease iterations limit = {}", m_timeStepDecreaseIterLimit ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Time step increase iterations limit = {}", m_timeStepIncreaseIterLimit ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Time step decrease factor = {}", m_timeStepDecreaseFactor ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Time step increase factor = {}", m_timeStepDecreaseFactor ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Time step cut factor = {}", m_timeStepCutFactor ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Maximum time step cuts = {}", m_maxTimeStepCuts ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Maximum sub time steps = {}", m_maxSubSteps ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Maximum number of configuration attempts = {}", m_maxNumConfigurationAttempts ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Coupling type = {}", EnumStrings< CouplingType >::toString( m_couplingType ) ) ); - if( m_couplingType == CouplingType::Sequential ) - { - GEOS_LOG_RANK_0( GEOS_FMT( " Sequential convergence criterion = {}", EnumStrings< SequentialConvergenceCriterion >::toString( m_sequentialConvergenceCriterion ) ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " Subcycling = {}", m_subcyclingOption ) ); - } + print(); } } - +void NonlinearSolverParameters::print() const +{ + TableData tableData; + tableData.addRow( "Log level", getLogLevel()); + tableData.addRow( "Line search", "" ); + tableData.addRow( " Action", m_lineSearchAction ); + if( m_lineSearchAction != LineSearchAction::None ) + { + tableData.addRow( " Interpolation type", m_lineSearchInterpType ); + tableData.addRow( " Maximum number of cuts", m_lineSearchMaxCuts ); + tableData.addRow( " Cut factor", m_lineSearchCutFactor ); + tableData.addRow( " Starting iteration", m_lineSearchStartingIteration ); + tableData.addRow( " Residual increase factor", m_lineSearchResidualFactor ); + } + tableData.addRow( "Norm type (flow solver)", m_normType ); + tableData.addRow( "Minimum residual normalizer", m_minNormalizer ); + tableData.addRow( "Convergence tolerance", m_newtonTol ); + tableData.addRow( "Maximum iterations", m_maxIterNewton ); + tableData.addRow( "Minimum iterations", m_minIterNewton ); + tableData.addRow( "Maximum allowed residual norm", m_maxAllowedResidualNorm ); + tableData.addRow( "Allow non-converged", m_allowNonConverged ); + tableData.addRow( "Time-step decrease iterations limit", m_timeStepDecreaseIterLimit ); + tableData.addRow( "Time-step increase iterations limit", m_timeStepIncreaseIterLimit ); + tableData.addRow( "Time-step decrease factor", m_timeStepDecreaseFactor ); + tableData.addRow( "Time-step increase factor", m_timeStepDecreaseFactor ); + tableData.addRow( "Time-step cut factor", m_timeStepCutFactor ); + tableData.addRow( "Minimum time-step increase interval", m_minTimeStepIncreaseInterval ); + tableData.addRow( "Maximum time-step cuts", m_maxTimeStepCuts ); + tableData.addRow( "Maximum sub time-steps", m_maxSubSteps ); + tableData.addRow( "Maximum number of configuration attempts", m_maxNumConfigurationAttempts ); + tableData.addRow( "Coupling type", m_couplingType ); + if( m_couplingType == CouplingType::Sequential ) + { + tableData.addRow( "Sequential convergence criterion", m_sequentialConvergenceCriterion ); + tableData.addRow( "Subcycling", m_subcyclingOption ); + } + TableLayout const tableLayout = TableLayout( { + TableLayout::ColumnParam{"Parameter", TableLayout::Alignment::left}, + TableLayout::ColumnParam{"Value", TableLayout::Alignment::left}, + }, GEOS_FMT( "{}: nonlinear solver", getParent().getName() ) ); + TableTextFormatter const tableFormatter( tableLayout ); + GEOS_LOG_RANK_0( tableFormatter.toString( tableData )); +} REGISTER_CATALOG_ENTRY( Group, NonlinearSolverParameters, string const &, Group * const ) diff --git a/src/coreComponents/physicsSolvers/NonlinearSolverParameters.hpp b/src/coreComponents/physicsSolvers/NonlinearSolverParameters.hpp index 9f9f93da0fc..a1efed70d84 100644 --- a/src/coreComponents/physicsSolvers/NonlinearSolverParameters.hpp +++ b/src/coreComponents/physicsSolvers/NonlinearSolverParameters.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -15,9 +16,9 @@ #ifndef GEOS_PHYSICSSOLVERS_NONLINEARSOLVERPARAMETERS_HPP_ #define GEOS_PHYSICSSOLVERS_NONLINEARSOLVERPARAMETERS_HPP_ -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include "dataRepository/Group.hpp" -#include "physicsSolvers/SolverBaseKernels.hpp" +#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" namespace geos { @@ -64,6 +65,7 @@ class NonlinearSolverParameters : public dataRepository::Group m_lineSearchMaxCuts = params.m_lineSearchMaxCuts; m_lineSearchCutFactor = params.m_lineSearchCutFactor; m_lineSearchStartingIteration = params.m_lineSearchStartingIteration; + m_lineSearchResidualFactor = params.m_lineSearchResidualFactor; m_newtonTol = params.m_newtonTol; m_maxIterNewton = params.m_maxIterNewton; @@ -77,10 +79,14 @@ class NonlinearSolverParameters : public dataRepository::Group m_timeStepIncreaseIterLimit = params.m_timeStepIncreaseIterLimit; m_timeStepDecreaseFactor = params.m_timeStepDecreaseFactor; m_timeStepIncreaseFactor = params.m_timeStepIncreaseFactor; + m_minTimeStepIncreaseInterval = params.m_minTimeStepIncreaseInterval; m_maxSubSteps = params.m_maxSubSteps; m_maxTimeStepCuts = params.m_maxTimeStepCuts; m_timeStepCutFactor = params.m_timeStepCutFactor; m_maxNumConfigurationAttempts = params.m_maxNumConfigurationAttempts; + m_configurationTolerance = params.m_configurationTolerance; + + setLogLevel( params.getLogLevel()); return *this; } @@ -94,7 +100,9 @@ class NonlinearSolverParameters : public dataRepository::Group */ static string catalogName() { return "NonlinearSolverParameters"; } - virtual void postProcessInput() override; + virtual void postInputInitialization() override; + + void print() const; struct viewKeysStruct { @@ -103,6 +111,7 @@ class NonlinearSolverParameters : public dataRepository::Group static constexpr char const * lineSearchCutFactorString() { return "lineSearchCutFactor"; } static constexpr char const * lineSearchInterpolationTypeString() { return "lineSearchInterpolationType"; } static constexpr char const * lineSearchStartingIterationString() { return "lineSearchStartingIteration"; } + static constexpr char const * lineSearchResidualFactorString() { return "lineSearchResidualFactor"; } static constexpr char const * normTypeString() { return "normType"; } static constexpr char const * minNormalizerString() { return "minNormalizer"; } @@ -117,15 +126,15 @@ class NonlinearSolverParameters : public dataRepository::Group static constexpr char const * timeStepIncreaseIterLimString() { return "timeStepIncreaseIterLimit"; } static constexpr char const * timeStepDecreaseFactorString() { return "timeStepDecreaseFactor"; } static constexpr char const * timeStepIncreaseFactorString() { return "timeStepIncreaseFactor"; } + static constexpr char const * minTimeStepIncreaseIntervalString() { return "minTimeStepIncreaseInterval"; } static constexpr char const * maxSubStepsString() { return "maxSubSteps"; } static constexpr char const * maxTimeStepCutsString() { return "maxTimeStepCuts"; } - static constexpr char const * minNumNewtonIterationsString() { return "minNumberOfNewtonIterations"; } static constexpr char const * timeStepCutFactorString() { return "timeStepCutFactor"; } static constexpr char const * maxAllowedResidualNormString() { return "maxAllowedResidualNorm"; } - static constexpr char const * numConfigurationAttemptsString() { return "numConfigurationAttempts"; } static constexpr char const * maxNumConfigurationAttemptsString() { return "maxNumConfigurationAttempts"; } + static constexpr char const * configurationToleranceString() { return "configurationTolerance"; } static constexpr char const * couplingTypeString() { return "couplingType"; } static constexpr char const * sequentialConvergenceCriterionString() { return "sequentialConvergenceCriterion"; } @@ -219,11 +228,20 @@ class NonlinearSolverParameters : public dataRepository::Group return m_timeStepIncreaseFactor; } + /** + * @brief Getter for the minimum interval for increasing the time-step + * @return the minimum interval for increasing the time-step + */ + integer minTimeStepIncreaseInterval() const + { + return m_minTimeStepIncreaseInterval; + } + /** * @brief Getter for the norm type used to check convergence in the flow/well solvers * @return the norm type */ - solverBaseKernels::NormType normType() const + physicsSolverBaseKernels::NormType normType() const { return m_normType; } @@ -261,8 +279,11 @@ class NonlinearSolverParameters : public dataRepository::Group /// Iteration when line search starts integer m_lineSearchStartingIteration; + /// Factor to determine residual increase + real64 m_lineSearchResidualFactor; + /// Norm used to check the nonlinear loop convergence - solverBaseKernels::NormType m_normType; + physicsSolverBaseKernels::NormType m_normType; /// The tolerance for the nonlinear convergence check. real64 m_newtonTol; @@ -294,6 +315,9 @@ class NonlinearSolverParameters : public dataRepository::Group /// Factor used to increase the time step size real64 m_timeStepIncreaseFactor; + /// Minimum interval, since the last time-step cut, for increasing the time-step + integer m_minTimeStepIncreaseInterval; + /// Maximum number of time sub-steps allowed for the solver integer m_maxSubSteps; @@ -312,6 +336,9 @@ class NonlinearSolverParameters : public dataRepository::Group /// Max number of times that the configuration can be changed integer m_maxNumConfigurationAttempts; + /// Configuration tolerance + double m_configurationTolerance; + /// Type of coupling CouplingType m_couplingType; diff --git a/src/coreComponents/physicsSolvers/PhysicsSolverBase.cpp b/src/coreComponents/physicsSolvers/PhysicsSolverBase.cpp new file mode 100644 index 00000000000..14ec3cbfd45 --- /dev/null +++ b/src/coreComponents/physicsSolvers/PhysicsSolverBase.cpp @@ -0,0 +1,1445 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "PhysicsSolverBase.hpp" +#include "PhysicsSolverManager.hpp" + +#include "common/TimingMacros.hpp" +#include "linearAlgebra/solvers/KrylovSolver.hpp" +#include "mesh/DomainPartition.hpp" +#include "math/interpolation/Interpolation.hpp" +#include "common/Timer.hpp" +#include "common/Units.hpp" +#include "dataRepository/LogLevelsInfo.hpp" + +#if defined(GEOS_USE_PYGEOSX) +#include "python/PySolverType.hpp" +#endif + +namespace geos +{ + +using namespace dataRepository; + +PhysicsSolverBase::PhysicsSolverBase( string const & name, + Group * const parent ) + : + ExecutableGroup( name, parent ), + m_cflFactor(), + m_maxStableDt{ 1e99 }, + m_nextDt( 1e99 ), + m_numTimestepsSinceLastDtCut( -1 ), + m_dofManager( name ), + m_linearSolverParameters( groupKeyStruct::linearSolverParametersString(), this ), + m_nonlinearSolverParameters( groupKeyStruct::nonlinearSolverParametersString(), this ), + m_solverStatistics( groupKeyStruct::solverStatisticsString(), this ), + m_systemSetupTimestamp( 0 ) +{ + setInputFlags( InputFlags::OPTIONAL_NONUNIQUE ); + + // This sets a flag to indicate that this object is going to select the time step size + this->setTimesteppingBehavior( ExecutableGroup::TimesteppingBehavior::DeterminesTimeStepSize ); + + registerWrapper( viewKeyStruct::cflFactorString(), &m_cflFactor ). + setApplyDefaultValue( 0.5 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Factor to apply to the `CFL condition `_" + " when calculating the maximum allowable time step. Values should be in the interval (0,1] " ); + + registerWrapper( viewKeyStruct::maxStableDtString(), &m_maxStableDt ). + setApplyDefaultValue( 0.5 ). + setInputFlag( InputFlags::FALSE ). + setDescription( "Value of the Maximum Stable Timestep for this solver." ); + + this->registerWrapper( viewKeyStruct::discretizationString(), &m_discretizationName ). + setRTTypeName( rtTypes::CustomTypes::groupNameRef ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this " + "solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` " + "should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` " + "discretization should be specified." ); + + registerWrapper( viewKeyStruct::targetRegionsString(), &m_targetRegionNames ). + setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Allowable regions that the solver may be applied to. Note that this does not indicate that " + "the solver will be applied to these regions, only that allocation will occur such that the " + "solver may be applied to these regions. The decision about what regions this solver will be" + "applied to rests in the EventManager." ); + + registerWrapper( viewKeyStruct::meshTargetsString(), &m_meshTargets ). + setInputFlag( InputFlags::FALSE ). + setRestartFlags( RestartFlags::NO_WRITE ). + setDescription( "MeshBody/Region combinations that the solver will be applied to." ); + + registerWrapper( viewKeyStruct::initialDtString(), &m_nextDt ). + setApplyDefaultValue( 1e99 ). + setInputFlag( InputFlags::OPTIONAL ). + setRestartFlags( RestartFlags::WRITE_AND_READ ). + setDescription( "Initial time-step value required by the solver to the event manager." ); + + registerWrapper( viewKeyStruct::writeLinearSystemString(), &m_writeLinearSystem ). + setApplyDefaultValue( 0 ). + setInputFlag( InputFlags::OPTIONAL ). + setRestartFlags( RestartFlags::WRITE_AND_READ ). + setDescription( "Write matrix, rhs, solution to screen ( = 1) or file ( = 2)." ); + + addLogLevel< logInfo::Fields >(); + addLogLevel< logInfo::LineSearch >(); + addLogLevel< logInfo::Solution >(); + addLogLevel< logInfo::Convergence >(); + addLogLevel< logInfo::TimeStep >(); + addLogLevel< logInfo::LinearSolver >(); + addLogLevel< logInfo::NonlinearSolver >(); + addLogLevel< logInfo::Timers >(); + + registerGroup( groupKeyStruct::linearSolverParametersString(), &m_linearSolverParameters ); + registerGroup( groupKeyStruct::nonlinearSolverParametersString(), &m_nonlinearSolverParameters ); + registerGroup( groupKeyStruct::solverStatisticsString(), &m_solverStatistics ); + + m_localMatrix.setName( this->getName() + "/localMatrix" ); + m_matrix.setDofManager( &m_dofManager ); +} + +PhysicsSolverBase::~PhysicsSolverBase() = default; + +void PhysicsSolverBase::initialize_postMeshGeneration() +{ + ExecutableGroup::initialize_postMeshGeneration(); + DomainPartition const & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); + generateMeshTargetsFromTargetRegions( domain.getMeshBodies()); +} + +void PhysicsSolverBase::generateMeshTargetsFromTargetRegions( Group const & meshBodies ) +{ + for( auto const & target : m_targetRegionNames ) + { + + std::vector< string > targetTokens = stringutilities::tokenize( target, "/" ); + + if( targetTokens.size()==1 ) // no MeshBody or MeshLevel specified + { + GEOS_ERROR_IF( meshBodies.numSubGroups() != 1, + getDataContext() << ": No MeshBody information is specified in" << + " PhysicsSolverBase::meshTargets, but there are multiple MeshBody objects" ); + MeshBody const & meshBody = meshBodies.getGroup< MeshBody >( 0 ); + string const meshBodyName = meshBody.getName(); + + string const meshLevelName = m_discretizationName; + + string const regionName = target; + auto const key = std::make_pair( meshBodyName, meshLevelName ); + m_meshTargets[key].emplace_back( regionName ); + } + else if( targetTokens.size()==2 ) + { + string const meshBodyName = targetTokens[0]; + GEOS_ERROR_IF( !meshBodies.hasGroup( meshBodyName ), + getWrapperDataContext( viewKeyStruct::targetRegionsString() ) << ": MeshBody (" << + meshBodyName << ") is specified in targetRegions, but does not exist." ); + + string const meshLevelName = m_discretizationName; + + string const regionName = targetTokens[1]; + + + auto const key = std::make_pair( meshBodyName, meshLevelName ); + m_meshTargets[key].emplace_back( regionName ); + } + else + { + GEOS_ERROR( getDataContext() << ": Invalid specification of targetRegions" ); + } + } +} + + +void PhysicsSolverBase::registerDataOnMesh( Group & meshBodies ) +{ + ExecutableGroup::registerDataOnMesh( meshBodies ); + + forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + elemManager.forElementSubRegions< ElementSubRegionBase >( regionNames, + [&]( localIndex const, + ElementSubRegionBase & subRegion ) + { + setConstitutiveNamesCallSuper( subRegion ); + setConstitutiveNames( subRegion ); + } ); + + } ); + +} + + + +Group * PhysicsSolverBase::createChild( string const & GEOS_UNUSED_PARAM( childKey ), string const & GEOS_UNUSED_PARAM( childName ) ) +{ + return nullptr; +} + +PhysicsSolverBase::CatalogInterface::CatalogType & PhysicsSolverBase::getCatalog() +{ + static PhysicsSolverBase::CatalogInterface::CatalogType catalog; + return catalog; +} + +localIndex PhysicsSolverBase::targetRegionIndex( string const & regionName ) const +{ + auto const pos = std::find( m_targetRegionNames.begin(), m_targetRegionNames.end(), regionName ); + GEOS_ERROR_IF( pos == m_targetRegionNames.end(), + GEOS_FMT( "{}: Region {} is not a target of the solver.", + getDataContext(), regionName ) ); + return std::distance( m_targetRegionNames.begin(), pos ); +} + +bool PhysicsSolverBase::registerCallback( void * func, const std::type_info & funcType ) +{ + if( std::type_index( funcType ) == std::type_index( typeid( std::function< void( CRSMatrix< real64, globalIndex >, array1d< real64 > ) > ) ) ) + { + m_assemblyCallback = *reinterpret_cast< std::function< void( CRSMatrix< real64, globalIndex >, array1d< real64 > ) > * >( func ); + return true; + } + + return false; +} + +real64 PhysicsSolverBase::solverStep( real64 const & time_n, + real64 const & dt, + const integer cycleNumber, + DomainPartition & domain ) +{ + GEOS_MARK_FUNCTION; + + // Only build the sparsity pattern if the mesh has changed + Timestamp const meshModificationTimestamp = getMeshModificationTimestamp( domain ); + + if( meshModificationTimestamp > getSystemSetupTimestamp() ) + { + setupSystem( domain, m_dofManager, m_localMatrix, m_rhs, m_solution ); + setSystemSetupTimestamp( meshModificationTimestamp ); + + std::ostringstream oss; + m_dofManager.printFieldInfo( oss ); + GEOS_LOG_LEVEL_INFO( logInfo::Fields, oss.str()) + } + + implicitStepSetup( time_n, dt, domain ); + + // currently the only method is implicit time integration + real64 const dt_return = nonlinearImplicitStep( time_n, dt, cycleNumber, domain ); + + // final step for completion of timestep. typically secondary variable updates and cleanup. + implicitStepComplete( time_n, dt_return, domain ); + + return dt_return; +} + +bool PhysicsSolverBase::execute( real64 const time_n, + real64 const dt, + integer const cycleNumber, + integer const GEOS_UNUSED_PARAM( eventCounter ), + real64 const GEOS_UNUSED_PARAM( eventProgress ), + DomainPartition & domain ) +{ + GEOS_MARK_FUNCTION; + + /* + * Reset counter indicating the number of cycles since the last timestep cut + * when the new timestep. "-1" means that no time-step cut has ocurred. + * */ + if( dt < m_nextDt ) + { + m_numTimestepsSinceLastDtCut = -1; + } + + real64 dtRemaining = dt; + real64 nextDt = dt; + + integer const maxSubSteps = m_nonlinearSolverParameters.m_maxSubSteps; + + // Keep track of substeps. It is useful to output these. + std::vector< real64 > subStepDt( maxSubSteps, 0.0 ); + integer numOfSubSteps = 0; + + for( integer subStep = 0; subStep < maxSubSteps && dtRemaining > 0.0; ++subStep ) + { + // reset number of nonlinear and linear iterations + m_solverStatistics.initializeTimeStepStatistics(); + + real64 const dtAccepted = solverStep( time_n + (dt - dtRemaining), + nextDt, + cycleNumber, + domain ); + numOfSubSteps++; + subStepDt[subStep] = dtAccepted; + + // increment the cumulative number of nonlinear and linear iterations + m_solverStatistics.saveTimeStepStatistics(); + + /* + * Let us check convergence history of previous solve: + * - number of nonlinear iter. + * - if the time-step was chopped. Then we can add some heuristics to choose next dt. + * */ + dtRemaining -= dtAccepted; + + if( dtRemaining > 0.0 ) + { + nextDt = setNextDt( dtAccepted, domain ); + if( nextDt < dtRemaining ) + { + // better to do two equal steps than one big and one small (even potentially tiny) + if( nextDt * 2 > dtRemaining ) + { + nextDt = dtRemaining / 2; + if( m_nonlinearSolverParameters.getLogLevel() > 0 ) + GEOS_LOG_RANK_0( GEOS_FMT( "{}: shortening time step to {} to cover remaining time {} in two steps", getName(), nextDt, dtRemaining )); + } + } + else + { + nextDt = dtRemaining; + if( m_nonlinearSolverParameters.getLogLevel() > 0 ) + GEOS_LOG_RANK_0( GEOS_FMT( "{}: shortening time step to {} to match remaining time", getName(), nextDt )); + } + } + + if( dtRemaining > 0.0 ) + { + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, + GEOS_FMT( "{}: sub-step = {}, accepted dt = {}, next dt = {}, remaining dt = {}", getName(), subStep, dtAccepted, nextDt, dtRemaining ) ); + } + } + + GEOS_ERROR_IF( dtRemaining > 0.0, getDataContext() << ": Maximum allowed number of sub-steps" + " reached. Consider increasing maxSubSteps." ); + + // Decide what to do with the next Dt for the event running the solver. + m_nextDt = setNextDt( nextDt, domain ); + + // Increase counter to indicate how many cycles since the last timestep cut + if( m_numTimestepsSinceLastDtCut >= 0 ) + { + m_numTimestepsSinceLastDtCut++; + } + + logEndOfCycleInformation( cycleNumber, numOfSubSteps, subStepDt ); + + return false; +} + +void PhysicsSolverBase::logEndOfCycleInformation( integer const cycleNumber, + integer const numOfSubSteps, + std::vector< real64 > const & subStepDt ) const +{ + // The formating here is a work in progress. + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, "\n------------------------- TIMESTEP END -------------------------" ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( " - Cycle: {}", cycleNumber ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( " - N substeps: {}", numOfSubSteps ) ); + std::string logMessage = " - dt:"; + for( integer i = 0; i < numOfSubSteps; ++i ) + { + logMessage += " " + units::TimeFormatInfo::fromSeconds( subStepDt[i] ).toString(); + } + // Log the complete message once + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, logMessage ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, "------------------------------------------------------------------\n" ); +} + +real64 PhysicsSolverBase::setNextDt( real64 const & currentDt, + DomainPartition & domain ) +{ + integer const minTimeStepIncreaseInterval = m_nonlinearSolverParameters.minTimeStepIncreaseInterval(); + real64 const nextDtNewton = setNextDtBasedOnNewtonIter( currentDt ); + if( m_nonlinearSolverParameters.getLogLevel() > 0 ) + GEOS_LOG_RANK_0( GEOS_FMT( "{}: next time step based on Newton iterations = {}", getName(), nextDtNewton )); + real64 const nextDtStateChange = setNextDtBasedOnStateChange( currentDt, domain ); + if( m_nonlinearSolverParameters.getLogLevel() > 0 ) + GEOS_LOG_RANK_0( GEOS_FMT( "{}: next time step based on state change = {}", getName(), nextDtStateChange )); + + if( ( m_numTimestepsSinceLastDtCut >= 0 ) && ( m_numTimestepsSinceLastDtCut < minTimeStepIncreaseInterval ) ) + { + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( "{}: time-step size will be kept the same since it's been {} cycles since last cut.", + getName(), m_numTimestepsSinceLastDtCut ) ); + return currentDt; + } + + if( nextDtNewton < nextDtStateChange ) // time step size decided based on convergence + { + if( nextDtNewton > currentDt ) + { + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( "{}: time-step required will be increased based on number of iterations.", + getName() ) ); + } + else if( nextDtNewton < currentDt ) + { + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( "{}: time-step required will be decreased based on number of iterations.", + getName() ) ); + } + else + { + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( "{}: time-step required will be kept the same based on number of iterations.", + getName() ) ); + } + } + else // time step size decided based on state change + { + if( nextDtStateChange > currentDt ) + { + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( "{}: time-step required will be increased based on state change.", + getName())); + } + else if( nextDtStateChange < currentDt ) + { + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( "{}: time-step required will be decreased based on state change.", + getName())); + } + else + { + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( "{}: time-step required will be kept the same based on state change.", + getName())); + } + } + + return std::min( nextDtNewton, nextDtStateChange ); +} + +real64 PhysicsSolverBase::setNextDtBasedOnStateChange( real64 const & currentDt, + DomainPartition & domain ) +{ + GEOS_UNUSED_VAR( currentDt, domain ); + return LvArray::NumericLimits< real64 >::max; // i.e., not implemented +} + +real64 PhysicsSolverBase::setNextDtBasedOnNewtonIter( real64 const & currentDt ) +{ + integer & newtonIter = m_nonlinearSolverParameters.m_numNewtonIterations; + integer const iterDecreaseLimit = m_nonlinearSolverParameters.timeStepDecreaseIterLimit(); + integer const iterIncreaseLimit = m_nonlinearSolverParameters.timeStepIncreaseIterLimit(); + + real64 nextDt = 0; + if( newtonIter < iterIncreaseLimit ) + { + // Easy convergence, let's increase the time-step. + nextDt = currentDt * m_nonlinearSolverParameters.timeStepIncreaseFactor(); + if( m_nonlinearSolverParameters.getLogLevel() > 0 ) + GEOS_LOG_RANK_0( GEOS_FMT( "{}: number of iterations = {} is less than {}, next time step = {} (increase)", getName(), newtonIter, iterIncreaseLimit, nextDt )); + } + else if( newtonIter > iterDecreaseLimit ) + { + // Tough convergence let us make the time-step smaller! + nextDt = currentDt * m_nonlinearSolverParameters.timeStepDecreaseFactor(); + if( m_nonlinearSolverParameters.getLogLevel() > 0 ) + GEOS_LOG_RANK_0( GEOS_FMT( "{}: number of iterations = {} is more than {}, next time step = {} (decrease)", getName(), newtonIter, iterDecreaseLimit, nextDt )); + } + else + { + nextDt = currentDt; + if( m_nonlinearSolverParameters.getLogLevel() > 0 ) + GEOS_LOG_RANK_0( GEOS_FMT( "{}: number of iterations = {} is between {} and {}, next time step = {} (no change)", getName(), newtonIter, iterIncreaseLimit, iterDecreaseLimit, nextDt )); + } + return nextDt; +} + + +real64 PhysicsSolverBase::setNextDtBasedOnCFL( const geos::real64 & currentDt, geos::DomainPartition & domain ) +{ + GEOS_UNUSED_VAR( currentDt, domain ); + return LvArray::NumericLimits< real64 >::max; // i.e., not implemented +} + + + +real64 PhysicsSolverBase::linearImplicitStep( real64 const & time_n, + real64 const & dt, + integer const GEOS_UNUSED_PARAM( cycleNumber ), + DomainPartition & domain ) +{ + // call setup for physics solver. Pre step allocations etc. + // TODO: Nonlinear step does not call its own setup, need to decide on consistent behavior + implicitStepSetup( time_n, dt, domain ); + + { + Timer timer( m_timers["assemble"] ); + + // zero out matrix/rhs before assembly + m_localMatrix.zero(); + m_rhs.zero(); + + arrayView1d< real64 > const localRhs = m_rhs.open(); + + // call assemble to fill the matrix and the rhs + assembleSystem( time_n, + dt, + domain, + m_dofManager, + m_localMatrix.toViewConstSizes(), + localRhs ); + + // apply boundary conditions to system + applyBoundaryConditions( time_n, + dt, + domain, + m_dofManager, + m_localMatrix.toViewConstSizes(), + localRhs ); + + m_rhs.close(); + + if( m_assemblyCallback ) + { + // Make a copy of LA objects and ship off to the callback + array1d< real64 > localRhsCopy( m_rhs.localSize() ); + localRhsCopy.setValues< parallelDevicePolicy<> >( m_rhs.values() ); + m_assemblyCallback( m_localMatrix, std::move( localRhsCopy ) ); + } + } + + { + Timer timer( m_timers["linear solver total"] ); + + // TODO: Trilinos currently requires this, re-evaluate after moving to Tpetra-based solvers + if( m_precond ) + { + m_precond->clear(); + } + + { + Timer timer_create( m_timers["linear solver create"] ); + + // Compose parallel LA matrix out of local matrix + m_matrix.create( m_localMatrix.toViewConst(), m_dofManager.numLocalDofs(), MPI_COMM_GEOS ); + } + + // Output the linear system matrix/rhs for debugging purposes + debugOutputSystem( 0.0, 0, 0, m_matrix, m_rhs ); + + // Solve the linear system + solveLinearSystem( m_dofManager, m_matrix, m_rhs, m_solution ); + } + + // Increment the solver statistics for reporting purposes + m_solverStatistics.logNonlinearIteration( m_linearSolverResult.numIterations ); + + // Output the linear system solution for debugging purposes + debugOutputSolution( 0.0, 0, 0, m_solution ); + + { + Timer timer( m_timers["apply solution"] ); + + // apply the system solution to the fields/variables + applySystemSolution( m_dofManager, m_solution.values(), 1.0, dt, domain ); + } + + { + Timer timer( m_timers["update state"] ); + + // update non-primary variables (constitutive models) + updateState( domain ); + } + + // final step for completion of timestep. typically secondary variable updates and cleanup. + implicitStepComplete( time_n, dt, domain ); + + // return the achieved timestep + return dt; +} + + +bool PhysicsSolverBase::lineSearch( real64 const & time_n, + real64 const & dt, + integer const GEOS_UNUSED_PARAM( cycleNumber ), + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + ParallelVector & rhs, + ParallelVector & solution, + real64 const scaleFactor, + real64 & lastResidual ) +{ + Timer timer( m_timers["line search"] ); + + integer const maxNumberLineSearchCuts = m_nonlinearSolverParameters.m_lineSearchMaxCuts; + real64 const lineSearchCutFactor = m_nonlinearSolverParameters.m_lineSearchCutFactor; + + // flag to determine if we should solve the system and apply the solution. If the line + // search fails we just bail. + bool lineSearchSuccess = false; + + real64 residualNorm = lastResidual; + + // scale factor is value applied to the previous solution. In this case we want to + // subtract a portion of the previous solution. + real64 localScaleFactor = -scaleFactor; + real64 cumulativeScale = scaleFactor; + + // main loop for the line search. + for( integer lineSearchIteration = 0; lineSearchIteration < maxNumberLineSearchCuts; ++lineSearchIteration ) + { + // cut the scale factor by half. This means that the scale factors will + // have values of -0.5, -0.25, -0.125, ... + localScaleFactor *= lineSearchCutFactor; + cumulativeScale += localScaleFactor; + + if( !checkSystemSolution( domain, dofManager, solution.values(), localScaleFactor ) ) + { + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::LineSearch, GEOS_FMT( " Line search {}, solution check failed", lineSearchIteration ) ); + continue; + } + + applySystemSolution( dofManager, solution.values(), localScaleFactor, dt, domain ); + + // update non-primary variables (constitutive models) + updateState( domain ); + + // re-assemble system + localMatrix.zero(); + rhs.zero(); + + arrayView1d< real64 > const localRhs = rhs.open(); + assembleSystem( time_n, dt, domain, dofManager, localMatrix, localRhs ); + applyBoundaryConditions( time_n, dt, domain, dofManager, localMatrix, localRhs ); + rhs.close(); + + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::LineSearch, GEOS_FMT( " Line search @ {:0.3f}: ", cumulativeScale )); + + // get residual norm + residualNorm = calculateResidualNorm( time_n, dt, domain, dofManager, rhs.values() ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::LineSearch, GEOS_FMT( " ( R ) = ( {:4.2e} )", residualNorm ) ); + + // if the residual norm is less than the last residual, we can proceed to the + // solution step + if( residualNorm < lastResidual ) + { + lineSearchSuccess = true; + break; + } + } + + lastResidual = residualNorm; + return lineSearchSuccess; +} + +bool PhysicsSolverBase::lineSearchWithParabolicInterpolation( real64 const & time_n, + real64 const & dt, + integer const GEOS_UNUSED_PARAM( cycleNumber ), + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + ParallelVector & rhs, + ParallelVector & solution, + real64 const scaleFactor, + real64 & lastResidual, + real64 & residualNormT ) +{ + Timer timer( m_timers["line search"] ); + + bool lineSearchSuccess = true; + + integer const maxNumberLineSearchCuts = m_nonlinearSolverParameters.m_lineSearchMaxCuts; + + real64 const sigma1 = 0.5; + real64 const alpha = 1.e-4; + + real64 localScaleFactor = scaleFactor; + real64 lamm = scaleFactor; + real64 lamc = localScaleFactor; + integer lineSearchIteration = 0; + + real64 residualNorm0 = lastResidual; + + real64 ff0 = residualNorm0*residualNorm0; + real64 ffT = residualNormT*residualNormT; + real64 ffm = ffT; + real64 cumulativeScale = scaleFactor; + + while( residualNormT >= (1.0 - alpha*localScaleFactor)*residualNorm0 ) + { + real64 const previousLocalScaleFactor = localScaleFactor; + // Apply the three point parabolic model + if( lineSearchIteration == 0 ) + { + localScaleFactor *= sigma1; + } + else + { + localScaleFactor = interpolation::parabolicInterpolationThreePoints( lamc, lamm, ff0, ffT, ffm ); + } + + // Update x; keep the books on lambda + real64 const deltaLocalScaleFactor = ( localScaleFactor - previousLocalScaleFactor ); + cumulativeScale += deltaLocalScaleFactor; + + if( !checkSystemSolution( domain, dofManager, solution.values(), deltaLocalScaleFactor ) ) + { + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::LineSearch, GEOS_FMT( " Line search {}, solution check failed", lineSearchIteration ) ); + continue; + } + + applySystemSolution( dofManager, solution.values(), deltaLocalScaleFactor, dt, domain ); + + updateState( domain ); + + lamm = lamc; + lamc = localScaleFactor; + + // Keep the books on the function norms + + // re-assemble system + // TODO: add a flag to avoid a completely useless Jacobian computation: rhs is enough + localMatrix.zero(); + rhs.zero(); + + arrayView1d< real64 > const localRhs = rhs.open(); + assembleSystem( time_n, dt, domain, dofManager, localMatrix, localRhs ); + applyBoundaryConditions( time_n, dt, domain, dofManager, localMatrix, localRhs ); + rhs.close(); + + if( logger::internal::rank==0 ) + { + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::LineSearch, GEOS_FMT( " Line search @ {:0.3f}: ", cumulativeScale ) ); + } + + // get residual norm + residualNormT = calculateResidualNorm( time_n, dt, domain, dofManager, rhs.values() ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::LineSearch, GEOS_FMT( " ( R ) = ( {:4.2e} )", residualNormT ) ); + + + ffm = ffT; + ffT = residualNormT*residualNormT; + lineSearchIteration += 1; + + if( lineSearchIteration > maxNumberLineSearchCuts ) + { + lineSearchSuccess = false; + break; + } + } + + lastResidual = residualNormT; + + return lineSearchSuccess; +} + + +real64 PhysicsSolverBase::eisenstatWalker( real64 const newNewtonNorm, + real64 const oldNewtonNorm, + LinearSolverParameters::Krylov const & krylovParams ) +{ + real64 normRatio = std::min( newNewtonNorm / oldNewtonNorm, 1.0 ); + real64 newKrylovTol = krylovParams.adaptiveGamma * std::pow( normRatio, krylovParams.adaptiveExponent ); + // the following is a safeguard to avoid too sharp tolerance reduction + // the bound is the quadratic reduction wrt previous value + real64 altKrylovTol = std::pow( krylovParams.relTolerance, 2.0 ); + + real64 krylovTol = std::max( newKrylovTol, altKrylovTol ); + krylovTol = std::min( krylovTol, krylovParams.weakestTol ); + krylovTol = std::max( krylovTol, krylovParams.strongestTol ); + + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::LinearSolver, + GEOS_FMT( " Adaptive linear tolerance = {:4.2e} (norm ratio = {:4.2e}, old tolerance = {:4.2e}, new tolerance = {:4.2e}, safeguard = {:4.2e})", + krylovTol, normRatio, krylovParams.relTolerance, newKrylovTol, altKrylovTol ) ); + + return krylovTol; +} + +real64 PhysicsSolverBase::nonlinearImplicitStep( real64 const & time_n, + real64 const & dt, + integer const cycleNumber, + DomainPartition & domain ) +{ + GEOS_MARK_FUNCTION; + // dt may be cut during the course of this step, so we are keeping a local + // value to track the achieved dt for this step. + real64 stepDt = dt; + + integer const maxNumberDtCuts = m_nonlinearSolverParameters.m_maxTimeStepCuts; + real64 const dtCutFactor = m_nonlinearSolverParameters.m_timeStepCutFactor; + + bool const allowNonConverged = m_nonlinearSolverParameters.m_allowNonConverged > 0; + + integer & dtAttempt = m_nonlinearSolverParameters.m_numTimeStepAttempts; + + integer const & maxConfigurationIter = m_nonlinearSolverParameters.m_maxNumConfigurationAttempts; + + integer & configurationLoopIter = m_nonlinearSolverParameters.m_numConfigurationAttempts; + + bool isConfigurationLoopConverged = false; + + // outer loop attempts to apply full timestep, and managed the cutting of the timestep if + // required. + for( dtAttempt = 0; dtAttempt < maxNumberDtCuts; ++dtAttempt ) + { + // reset the solver state, since we are restarting the time step + if( dtAttempt > 0 ) + { + resetStateToBeginningOfStep( domain ); + resetConfigurationToBeginningOfStep( domain ); + } + + // it's the simplest configuration that can be attempted whenever Newton's fails as a last resource. + bool attemptedSimplestConfiguration = false; + + // Configuration loop + for( configurationLoopIter = 0; configurationLoopIter < maxConfigurationIter; ++configurationLoopIter ) + { + + outputConfigurationStatistics( domain ); + + bool const isNewtonConverged = solveNonlinearSystem( time_n, + stepDt, + cycleNumber, + domain ); + + if( isNewtonConverged ) + { + isConfigurationLoopConverged = updateConfiguration( domain ); + + if( isConfigurationLoopConverged ) + { + break; // get out of configuration loop coz everything converged. + } + else + { + // increment the solver statistics for reporting purposes + m_solverStatistics.logOuterLoopIteration(); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::NonlinearSolver, "---------- Configuration did not converge. Testing new configuration. ----------" ); + } + } + else if( !attemptedSimplestConfiguration ) + { + resetStateToBeginningOfStep( domain ); + bool const breakLoop = resetConfigurationToDefault( domain ); + attemptedSimplestConfiguration = true; + if( breakLoop ) + { + break; + } + } + else + { + break; // get out of configuration loop and cut the time-step if you can. + } + + } // end of configuration loop + + if( isConfigurationLoopConverged ) + { + // get out of outer loop + break; + } + else + { + // cut timestep, go back to beginning of step and restart the Newton loop + stepDt *= dtCutFactor; + m_numTimestepsSinceLastDtCut = 0; + GEOS_LOG_LEVEL_INFO_RANK_0 ( logInfo::TimeStep, GEOS_FMT( "New dt = {}", stepDt ) ); + + // notify the solver statistics counter that this is a time step cut + m_solverStatistics.logTimeStepCut(); + } + } // end of outer loop (dt chopping strategy) + + if( !isConfigurationLoopConverged ) + { + GEOS_LOG_RANK_0( "Convergence not achieved." ); + + if( allowNonConverged ) + { + GEOS_LOG_RANK_0( "The accepted solution may be inaccurate." ); + } + else + { + GEOS_ERROR( "Nonconverged solutions not allowed. Terminating..." ); + } + } + + // return the achieved timestep + return stepDt; +} + +bool PhysicsSolverBase::solveNonlinearSystem( real64 const & time_n, + real64 const & stepDt, + integer const cycleNumber, + DomainPartition & domain ) +{ + integer const maxNewtonIter = m_nonlinearSolverParameters.m_maxIterNewton; + integer & dtAttempt = m_nonlinearSolverParameters.m_numTimeStepAttempts; + integer & configurationLoopIter = m_nonlinearSolverParameters.m_numConfigurationAttempts; + integer const minNewtonIter = m_nonlinearSolverParameters.m_minIterNewton; + real64 const newtonTol = m_nonlinearSolverParameters.m_newtonTol; + + // keep residual from previous iteration in case we need to do a line search + real64 lastResidual = 1e99; + integer & newtonIter = m_nonlinearSolverParameters.m_numNewtonIterations; + real64 scaleFactor = 1.0; + + bool isNewtonConverged = false; + + for( newtonIter = 0; newtonIter < maxNewtonIter; ++newtonIter ) + { + + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::NonlinearSolver, + GEOS_FMT( " Attempt: {:2}, ConfigurationIter: {:2}, NewtonIter: {:2}", dtAttempt, configurationLoopIter, newtonIter ) ); + + { + Timer timer( m_timers["assemble"] ); + + // We sync the nonlinear convergence history. The coupled solver parameters are the one being + // used. We want to propagate the info to subsolvers. It can be important for solvers that + // have special treatment for specific iterations. + synchronizeNonlinearSolverParameters(); + + // zero out matrix/rhs before assembly + m_localMatrix.zero(); + m_rhs.zero(); + + arrayView1d< real64 > const localRhs = m_rhs.open(); + + // call assemble to fill the matrix and the rhs + assembleSystem( time_n, + stepDt, + domain, + m_dofManager, + m_localMatrix.toViewConstSizes(), + localRhs ); + + // apply boundary conditions to system + applyBoundaryConditions( time_n, + stepDt, + domain, + m_dofManager, + m_localMatrix.toViewConstSizes(), + localRhs ); + + m_rhs.close(); + + if( m_assemblyCallback ) + { + // Make a copy of LA objects and ship off to the callback + array1d< real64 > localRhsCopy( m_rhs.localSize() ); + localRhsCopy.setValues< parallelDevicePolicy<> >( m_rhs.values() ); + m_assemblyCallback( m_localMatrix, std::move( localRhsCopy ) ); + } + } + + real64 residualNorm = 0; + { + Timer timer( m_timers["convergence check"] ); + + // get residual norm + residualNorm = calculateResidualNorm( time_n, stepDt, domain, m_dofManager, m_rhs.values() ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Convergence, GEOS_FMT( " ( R ) = ( {:4.2e} )", residualNorm ) ); + } + + // if the residual norm is less than the Newton tolerance we denote that we have + // converged and break from the Newton loop immediately. + if( residualNorm < newtonTol && newtonIter >= minNewtonIter ) + { + isNewtonConverged = true; + break; + } + + // if the residual norm is above the max allowed residual norm, we break from + // the Newton loop to avoid crashes due to Newton divergence + if( residualNorm > m_nonlinearSolverParameters.m_maxAllowedResidualNorm ) + { + string const maxAllowedResidualNormString = NonlinearSolverParameters::viewKeysStruct::maxAllowedResidualNormString(); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Convergence, GEOS_FMT( " The residual norm is above the {} of {}. Newton loop terminated.", + maxAllowedResidualNormString, + m_nonlinearSolverParameters.m_maxAllowedResidualNorm ) ); + isNewtonConverged = false; + break; + } + + // do line search in case residual has increased + if( m_nonlinearSolverParameters.m_lineSearchAction != NonlinearSolverParameters::LineSearchAction::None + && residualNorm > lastResidual * m_nonlinearSolverParameters.m_lineSearchResidualFactor + && newtonIter >= m_nonlinearSolverParameters.m_lineSearchStartingIteration ) + { + bool lineSearchSuccess = false; + if( m_nonlinearSolverParameters.m_lineSearchInterpType == NonlinearSolverParameters::LineSearchInterpolationType::Linear ) + { + residualNorm = lastResidual; + lineSearchSuccess = lineSearch( time_n, + stepDt, + cycleNumber, + domain, + m_dofManager, + m_localMatrix.toViewConstSizes(), + m_rhs, + m_solution, + scaleFactor, + residualNorm ); + } + else + { + lineSearchSuccess = lineSearchWithParabolicInterpolation( time_n, + stepDt, + cycleNumber, + domain, + m_dofManager, + m_localMatrix.toViewConstSizes(), + m_rhs, + m_solution, + scaleFactor, + lastResidual, + residualNorm ); + } + + if( !lineSearchSuccess ) + { + if( m_nonlinearSolverParameters.m_lineSearchAction == NonlinearSolverParameters::LineSearchAction::Attempt ) + { + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::LineSearch, " Line search failed to produce reduced residual. Accepting iteration." ); + } + else if( m_nonlinearSolverParameters.m_lineSearchAction == NonlinearSolverParameters::LineSearchAction::Require ) + { + // if line search failed, then break out of the main Newton loop. Timestep will be cut. + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::LineSearch, " Line search failed to produce reduced residual. Exiting Newton Loop." ); + break; + } + } + } + + { + Timer timer( m_timers["linear solver total"] ); + + // if using adaptive Krylov tolerance scheme, update tolerance. + LinearSolverParameters::Krylov & krylovParams = m_linearSolverParameters.get().krylov; + if( krylovParams.useAdaptiveTol ) + { + krylovParams.relTolerance = newtonIter > 0 ? eisenstatWalker( residualNorm, lastResidual, krylovParams ) : krylovParams.weakestTol; + } + + // TODO: Trilinos currently requires this, re-evaluate after moving to Tpetra-based solvers + if( m_precond ) + { + m_precond->clear(); + } + + { + Timer timer_setup( m_timers["linear solver create"] ); + + // Compose parallel LA matrix/rhs out of local LA matrix/rhs + // + m_matrix.create( m_localMatrix.toViewConst(), m_dofManager.numLocalDofs(), MPI_COMM_GEOS ); + } + + // Output the linear system matrix/rhs for debugging purposes + debugOutputSystem( time_n, cycleNumber, newtonIter, m_matrix, m_rhs ); + + // Solve the linear system + solveLinearSystem( m_dofManager, m_matrix, m_rhs, m_solution ); + + // Increment the solver statistics for reporting purposes + m_solverStatistics.logNonlinearIteration( m_linearSolverResult.numIterations ); + + // Output the linear system solution for debugging purposes + debugOutputSolution( time_n, cycleNumber, newtonIter, m_solution ); + } + + { + Timer timer( m_timers["apply solution"] ); + + // Compute the scaling factor for the Newton update + scaleFactor = scalingForSystemSolution( domain, m_dofManager, m_solution.values() ); + + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, GEOS_FMT( " {}: Global solution scaling factor = {}", getName(), scaleFactor ) ); + + if( !checkSystemSolution( domain, m_dofManager, m_solution.values(), scaleFactor ) ) + { + // TODO try chopping (similar to line search) + GEOS_LOG_RANK_0( GEOS_FMT( " {}: Solution check failed. Newton loop terminated.", getName()) ); + break; + } + + // apply the system solution to the fields/variables + applySystemSolution( m_dofManager, m_solution.values(), scaleFactor, stepDt, domain ); + } + + { + Timer timer( m_timers["update state"] ); + + // update non-primary variables (constitutive models) + updateState( domain ); + } + + lastResidual = residualNorm; + } + + return isNewtonConverged; +} + +real64 PhysicsSolverBase::explicitStep( real64 const & GEOS_UNUSED_PARAM( time_n ), + real64 const & GEOS_UNUSED_PARAM( dt ), + integer const GEOS_UNUSED_PARAM( cycleNumber ), + DomainPartition & GEOS_UNUSED_PARAM( domain ) ) +{ + GEOS_THROW( "PhysicsSolverBase::ExplicitStep called!. Should be overridden.", std::runtime_error ); + return 0; +} + +void PhysicsSolverBase::implicitStepSetup( real64 const & GEOS_UNUSED_PARAM( time_n ), + real64 const & GEOS_UNUSED_PARAM( dt ), + DomainPartition & GEOS_UNUSED_PARAM( domain ) ) +{ + GEOS_THROW( "PhysicsSolverBase::ImplicitStepSetup called!. Should be overridden.", std::runtime_error ); +} + +void PhysicsSolverBase::setupDofs( DomainPartition const & GEOS_UNUSED_PARAM( domain ), + DofManager & GEOS_UNUSED_PARAM( dofManager ) ) const +{ + GEOS_ERROR( "PhysicsSolverBase::setupDofs called!. Should be overridden." ); +} + +void PhysicsSolverBase::setupSystem( DomainPartition & domain, + DofManager & dofManager, + CRSMatrix< real64, globalIndex > & localMatrix, + ParallelVector & rhs, + ParallelVector & solution, + bool const setSparsity ) +{ + GEOS_MARK_FUNCTION; + + dofManager.setDomain( domain ); + + setupDofs( domain, dofManager ); + dofManager.reorderByRank(); + + if( setSparsity ) + { + SparsityPattern< globalIndex > pattern; + dofManager.setSparsityPattern( pattern ); + localMatrix.assimilate< parallelDevicePolicy<> >( std::move( pattern ) ); + } + localMatrix.setName( this->getName() + "/matrix" ); + + rhs.setName( this->getName() + "/rhs" ); + rhs.create( dofManager.numLocalDofs(), MPI_COMM_GEOS ); + + solution.setName( this->getName() + "/solution" ); + solution.create( dofManager.numLocalDofs(), MPI_COMM_GEOS ); +} + +void PhysicsSolverBase::assembleSystem( real64 const GEOS_UNUSED_PARAM( time ), + real64 const GEOS_UNUSED_PARAM( dt ), + DomainPartition & GEOS_UNUSED_PARAM( domain ), + DofManager const & GEOS_UNUSED_PARAM( dofManager ), + CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ), + arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) +{ + GEOS_ERROR( "PhysicsSolverBase::Assemble called!. Should be overridden." ); +} + +void PhysicsSolverBase::applyBoundaryConditions( real64 const GEOS_UNUSED_PARAM( time ), + real64 const GEOS_UNUSED_PARAM( dt ), + DomainPartition & GEOS_UNUSED_PARAM( domain ), + DofManager const & GEOS_UNUSED_PARAM( dofManager ), + CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ), + arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) +{ + GEOS_ERROR( "PhysicsSolverBase::applyBoundaryConditions called!. Should be overridden." ); +} + +namespace +{ + +/** + * @brief Helper for debug output of linear algebra objects (matrices and vectors) + * @tparam T type of LA object (must have stream insertion and .write() implemented) + * @param obj the object to output + * @param cycleNumber event cycle number + * @param nonlinearIteration nonlinear iteration number + * @param filePrefix short filename prefix (e.g. "mat") + * @param screenName long name for screen output (e.g. "System matrix") + * @param toScreen whether to print on screen + * @param toFile whether to write to file + */ +template< typename T > +void debugOutputLAObject( T const & obj, + real64 const & GEOS_UNUSED_PARAM( time ), + integer const cycleNumber, + integer const nonlinearIteration, + string const & filePrefix, + string const & screenName, + bool const toScreen, + bool const toFile ) +{ + if( toScreen ) + { + string const frame( screenName.size() + 1, '=' ); + GEOS_LOG_RANK_0( frame << "\n" << screenName << ":\n" << frame ); + GEOS_LOG( obj ); + } + + if( toFile ) + { + string const filename = GEOS_FMT( "{}_{:06}_{:02}.mtx", filePrefix.c_str(), cycleNumber, nonlinearIteration ); + obj.write( filename, LAIOutputFormat::NATIVE_ASCII ); + GEOS_LOG_RANK_0( screenName << " written to " << filename ); + } +} + +} + +void PhysicsSolverBase::debugOutputSystem( real64 const & time, + integer const cycleNumber, + integer const nonlinearIteration, + ParallelMatrix const & matrix, + ParallelVector const & rhs ) const +{ + // special case when flag value > 2 + if( m_writeLinearSystem > 2 && cycleNumber < m_writeLinearSystem ) + return; + + debugOutputLAObject( matrix, + time, + cycleNumber, + nonlinearIteration, + getName() + "_mat", + "System matrix", + m_writeLinearSystem == 1, + m_writeLinearSystem >= 2 ); + + debugOutputLAObject( rhs, + time, + cycleNumber, + nonlinearIteration, + getName() + "_rhs", + "System right-hand side", + m_writeLinearSystem == 1, + m_writeLinearSystem >= 2 ); +} + +void PhysicsSolverBase::debugOutputSolution( real64 const & time, + integer const cycleNumber, + integer const nonlinearIteration, + ParallelVector const & solution ) const +{ + // special case when flag value > 2 + if( m_writeLinearSystem > 2 && cycleNumber < m_writeLinearSystem ) + return; + + debugOutputLAObject( solution, + time, + cycleNumber, + nonlinearIteration, + getName() + "_sol", + "System solution", + m_writeLinearSystem == 1, + m_writeLinearSystem >= 2 ); +} + +real64 +PhysicsSolverBase::calculateResidualNorm( real64 const & GEOS_UNUSED_PARAM( time ), + real64 const & GEOS_UNUSED_PARAM( dt ), + DomainPartition const & GEOS_UNUSED_PARAM( domain ), + DofManager const & GEOS_UNUSED_PARAM( dofManager ), + arrayView1d< real64 const > const & GEOS_UNUSED_PARAM( localRhs ) ) +{ + GEOS_ERROR( "PhysicsSolverBase::calculateResidualNorm called!. Should be overridden." ); + return 0; +} + +void PhysicsSolverBase::solveLinearSystem( DofManager const & dofManager, + ParallelMatrix & matrix, + ParallelVector & rhs, + ParallelVector & solution ) +{ + GEOS_MARK_FUNCTION; + + rhs.scale( -1.0 ); + solution.zero(); + + LinearSolverParameters const & params = m_linearSolverParameters.get(); + matrix.setDofManager( &dofManager ); + + if( params.solverType == LinearSolverParameters::SolverType::direct || !m_precond ) + { + std::unique_ptr< LinearSolverBase< LAInterface > > solver = LAInterface::createSolver( params ); + { + Timer timer_setup( m_timers["linear solver setup"] ); + solver->setup( matrix ); + } + { + Timer timer_setup( m_timers["linear solver solve"] ); + solver->solve( rhs, solution ); + } + m_linearSolverResult = solver->result(); + } + else + { + { + Timer timer_setup( m_timers["linear solver setup"] ); + m_precond->setup( matrix ); + } + std::unique_ptr< KrylovSolver< ParallelVector > > solver = KrylovSolver< ParallelVector >::create( params, matrix, *m_precond ); + { + Timer timer_setup( m_timers["linear solver solve"] ); + solver->solve( rhs, solution ); + } + m_linearSolverResult = solver->result(); + } + + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::LinearSolver, GEOS_FMT( " Last LinSolve(iter,res) = ( {:3}, {:4.2e} )", + m_linearSolverResult.numIterations, + m_linearSolverResult.residualReduction ) ); + + if( params.stopIfError ) + { + GEOS_ERROR_IF( m_linearSolverResult.breakdown(), getDataContext() << ": Linear solution breakdown -> simulation STOP" ); + } + else + { + GEOS_WARNING_IF( !m_linearSolverResult.success(), getDataContext() << ": Linear solution failed" ); + } +} + +bool PhysicsSolverBase::checkSystemSolution( DomainPartition & GEOS_UNUSED_PARAM( domain ), + DofManager const & GEOS_UNUSED_PARAM( dofManager ), + arrayView1d< real64 const > const & GEOS_UNUSED_PARAM( localSolution ), + real64 const GEOS_UNUSED_PARAM( scalingFactor ) ) +{ + return true; +} + +real64 PhysicsSolverBase::scalingForSystemSolution( DomainPartition & GEOS_UNUSED_PARAM( domain ), + DofManager const & GEOS_UNUSED_PARAM( dofManager ), + arrayView1d< real64 const > const & GEOS_UNUSED_PARAM( localSolution ) ) +{ + return 1.0; +} + +void PhysicsSolverBase::applySystemSolution( DofManager const & GEOS_UNUSED_PARAM( dofManager ), + arrayView1d< real64 const > const & GEOS_UNUSED_PARAM( localSolution ), + real64 const GEOS_UNUSED_PARAM( scalingFactor ), + real64 const GEOS_UNUSED_PARAM( dt ), + DomainPartition & GEOS_UNUSED_PARAM( domain ) ) +{ + GEOS_ERROR( "PhysicsSolverBase::applySystemSolution called!. Should be overridden." ); +} + +void PhysicsSolverBase::updateState( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) +{ + GEOS_ERROR( "PhysicsSolverBase::updateState called!. Should be overridden." ); +} + +bool PhysicsSolverBase::updateConfiguration( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) +{ + return true; +} + +void PhysicsSolverBase::outputConfigurationStatistics( DomainPartition const & GEOS_UNUSED_PARAM( domain ) ) const +{ + // For most solvers there is nothing to do. +} + +void PhysicsSolverBase::resetConfigurationToBeginningOfStep( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) +{ + // For most solvers there is nothing to do. +} + +void PhysicsSolverBase::resetStateToBeginningOfStep( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) +{ + GEOS_ERROR( "PhysicsSolverBase::ResetStateToBeginningOfStep called!. Should be overridden." ); +} + +bool PhysicsSolverBase::resetConfigurationToDefault( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) const +{ + // for most solvers it just breaks the loop. + return true; +} + +void PhysicsSolverBase::implicitStepComplete( real64 const & GEOS_UNUSED_PARAM( time ), + real64 const & GEOS_UNUSED_PARAM( dt ), + DomainPartition & GEOS_UNUSED_PARAM( domain ) ) +{ + GEOS_ERROR( "PhysicsSolverBase::ImplicitStepComplete called!. Should be overridden." ); +} + +void PhysicsSolverBase::cleanup( real64 const GEOS_UNUSED_PARAM( time_n ), + integer const GEOS_UNUSED_PARAM( cycleNumber ), + integer const GEOS_UNUSED_PARAM( eventCounter ), + real64 const GEOS_UNUSED_PARAM( eventProgress ), + DomainPartition & GEOS_UNUSED_PARAM( domain ) ) +{ + m_solverStatistics.outputStatistics(); + + for( auto & timer : m_timers ) + { + real64 const time = std::chrono::duration< double >( timer.second ).count(); + real64 const minTime = MpiWrapper::min( time ); + real64 const maxTime = MpiWrapper::max( time ); + if( maxTime > 0 ) + { + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Timers, GEOS_FMT( "{}: {} time = {} s (min), {} s (max)", getName(), timer.first, minTime, maxTime ) ); + } + } + +} + +Timestamp PhysicsSolverBase::getMeshModificationTimestamp( DomainPartition & domain ) const +{ + Timestamp meshModificationTimestamp = 0; + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + { + if( meshModificationTimestamp < mesh.getModificationTimestamp() ) + { + meshModificationTimestamp = mesh.getModificationTimestamp(); + } + } ); + return meshModificationTimestamp; +} + +R1Tensor const PhysicsSolverBase::gravityVector() const +{ + R1Tensor rval; + if( dynamicCast< PhysicsSolverManager const * >( &getParent() ) != nullptr ) + { + rval = getParent().getReference< R1Tensor >( PhysicsSolverManager::viewKeyStruct::gravityVectorString() ); + } + else + { + rval = {0.0, 0.0, -9.81}; + } + return rval; +} + +bool PhysicsSolverBase::checkSequentialSolutionIncrements( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) const +{ + // default behavior - assume converged + return true; +} + +void PhysicsSolverBase::saveSequentialIterationState( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) +{ + // up to specific solver to save what is needed + GEOS_ERROR( "Call to PhysicsSolverBase::saveSequentialIterationState. Method should be overloaded by the solver" ); +} + +#if defined(GEOS_USE_PYGEOSX) +PyTypeObject * PhysicsSolverBase::getPythonType() const +{ return python::getPySolverType(); } +#endif + +} // namespace geos diff --git a/src/coreComponents/physicsSolvers/PhysicsSolverBase.hpp b/src/coreComponents/physicsSolvers/PhysicsSolverBase.hpp new file mode 100644 index 00000000000..92b004f8624 --- /dev/null +++ b/src/coreComponents/physicsSolvers/PhysicsSolverBase.hpp @@ -0,0 +1,1135 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PhysicsSolverBase.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_PHYSICSSOLVERBASE_HPP_ +#define GEOS_PHYSICSSOLVERS_PHYSICSSOLVERBASE_HPP_ + +#include "codingUtilities/traits.hpp" +#include "common/DataTypes.hpp" +#include "dataRepository/ExecutableGroup.hpp" +#include "linearAlgebra/interfaces/InterfaceTypes.hpp" +#include "linearAlgebra/utilities/LinearSolverResult.hpp" +#include "linearAlgebra/DofManager.hpp" +#include "mesh/MeshBody.hpp" +#include "physicsSolvers/NonlinearSolverParameters.hpp" +#include "physicsSolvers/LinearSolverParameters.hpp" +#include "physicsSolvers/SolverStatistics.hpp" +#include "physicsSolvers/LogLevelsInfo.hpp" + +#include + +namespace geos +{ + +class DomainPartition; + +/** + * @class PhysicsSolverBase + * @brief Base class for all physics solvers + * + * This class provides the base interface for all physics solvers. It provides the basic + * functionality for setting up and solving a linear system, as well as the interface for + * performing a timestep. + */ +class PhysicsSolverBase : public ExecutableGroup +{ +public: + + /** + * @brief Constructor for PhysicsSolverBase + * @param name the name of this instantiation of PhysicsSolverBase + * @param parent the parent group of this instantiation of PhysicsSolverBase + */ + explicit PhysicsSolverBase( string const & name, + Group * const parent ); + + /** + * @brief Move constructor for PhysicsSolverBase + */ + PhysicsSolverBase( PhysicsSolverBase && ) = default; + + /** + * @brief Destructor for PhysicsSolverBase + */ + virtual ~PhysicsSolverBase() override; + + /** + * @brief Deleted constructor + */ + PhysicsSolverBase() = delete; + + /** + * @brief Deleted copy constructor + */ + PhysicsSolverBase( PhysicsSolverBase const & ) = delete; + + /** + * @brief Deleted copy assignment operator + */ + PhysicsSolverBase & operator=( PhysicsSolverBase const & ) = delete; + + /** + * @brief Deleted move assignment operator + */ + PhysicsSolverBase & operator=( PhysicsSolverBase && ) = delete; + + /** + * @return Get the final class Catalog name + */ + virtual string getCatalogName() const = 0; + + + /** + * @brief Register wrappers that contain data on the mesh objects + * @param MeshBodies the group of mesh bodies + */ + virtual void registerDataOnMesh( Group & MeshBodies ) override; + + /** + * @brief Initialization tasks after mesh generation is completed. + */ + virtual void initialize_postMeshGeneration() override; + + /** + * @brief Generate mesh targets from target regions + * @param meshBodies the group of mesh bodies + */ + void generateMeshTargetsFromTargetRegions( Group const & meshBodies ); + + /** + * @copydoc ExecutableGroup::cleanup + */ + virtual void cleanup( real64 const time_n, + integer const cycleNumber, + integer const eventCounter, + real64 const eventProgress, + DomainPartition & domain ) override; + + /** + * @copydoc ExecutableGroup::execute + */ + virtual bool execute( real64 const time_n, + real64 const dt, + integer const cycleNumber, + integer const eventCounter, + real64 const eventProgress, + DomainPartition & domain ) override; + + /** + * @brief Getter for system matrix + * @return a reference to linear system matrix of this solver + */ + ParallelMatrix & getSystemMatrix() { return m_matrix; } + + /** + * @brief Getter for system rhs vector + * @return a reference to linear system right-hand side of this solver + */ + ParallelMatrix const & getSystemMatrix() const { return m_matrix; } + + /** + * @brief Getter for system rhs vector + * @return a reference to linear system right-hand side of this solver + */ + ParallelVector & getSystemRhs() { return m_rhs; } + + /** + * @brief Getter for system rhs vector + * @return a reference to linear system right-hand side of this solver + */ + ParallelVector const & getSystemRhs() const { return m_rhs; } + + /** + * @brief Getter for system solution vector + * @return a reference to solution vector of this solver + */ + ParallelVector & getSystemSolution() { return m_solution; } + + /** + * @brief Getter for system solution vector + * @return a reference to solution vector of this solver + */ + ParallelVector const & getSystemSolution() const { return m_solution; } + + /** + * @brief Getter for degree-of-freedom manager + * @return a reference to degree-of-freedom manager of this solver + */ + DofManager & getDofManager() { return m_dofManager; } + + /** + * @brief Getter for degree-of-freedom manager + * @return a reference to degree-of-freedom manager of this solver + */ + DofManager const & getDofManager() const { return m_dofManager; } + + /** + * @brief Getter for local matrix + * @return a reference to linear system matrix of this solver + */ + CRSMatrix< real64, globalIndex > & getLocalMatrix() { return m_localMatrix; } + + /** + * @brief Getter for local matrix + * @return a reference to linear system matrix of this solver + */ + CRSMatrixView< real64 const, globalIndex const > getLocalMatrix() const { return m_localMatrix.toViewConst(); } + + /** + * @defgroup Solver Interface Functions + * + * These functions provide the primary interface that is required for derived classes + */ + /**@{*/ + + /** + * @brief entry function to perform a solver step + * @param time_n time at the beginning of the step + * @param dt the perscribed timestep + * @param cycleNumber the current cycle number + * @param domain the domain object + * @return return the timestep that was achieved during the step. + * + * This function is the entry point to perform a solver step. The choice of time integration + * method is determined in this function, and the appropriate step function is called. + */ + virtual real64 solverStep( real64 const & time_n, + real64 const & dt, + integer const cycleNumber, + DomainPartition & domain ); + + /** + * @brief function to set the next time step size + * @param[in] currentDt the current time step size + * @param[in] domain the domain object + * @return the prescribed time step size + */ + virtual real64 setNextDt( real64 const & currentDt, + DomainPartition & domain ); + + /** + * @brief function to set the next time step size based on Newton convergence + * @param[in] currentDt the current time step size + * @return the prescribed time step size + */ + virtual real64 setNextDtBasedOnNewtonIter( real64 const & currentDt ); + + /** + * @brief function to set the next dt based on state change + * @param [in] currentDt the current time step size + * @param[in] domain the domain object + * @return the prescribed time step size + */ + virtual real64 setNextDtBasedOnStateChange( real64 const & currentDt, + DomainPartition & domain ); + + /** + * @brief function to set the next dt based on state change + * @param [in] currentDt the current time step size + * @param[in] domain the domain object + * @return the prescribed time step size + */ + virtual real64 setNextDtBasedOnCFL( real64 const & currentDt, + DomainPartition & domain ); + + + + /** + * @brief Entry function for an explicit time integration step + * @param time_n time at the beginning of the step + * @param dt the perscribed timestep + * @param cycleNumber the current cycle number + * @param domain the domain object + * @return return the timestep that was achieved during the step. + */ + virtual real64 explicitStep( real64 const & time_n, + real64 const & dt, + integer const cycleNumber, + DomainPartition & domain ); + + /** + * @brief Function for a nonlinear implicit integration step + * @param time_n time at the beginning of the step + * @param dt the perscribed timestep + * @param cycleNumber the current cycle number + * @param domain the domain object + * @return return the timestep that was achieved during the step. + * + * This function implements a nonlinear newton method for implicit problems. It requires that the + * other functions in the solver interface are implemented in the derived physics solver. The + * nonlinear loop includes a simple line search algorithm, and will cut the timestep if + * convergence is not achieved according to the parameters in linearSolverParameters member. + */ + virtual real64 nonlinearImplicitStep( real64 const & time_n, + real64 const & dt, + integer const cycleNumber, + DomainPartition & domain ); + + /** + * @brief Function to perform line search + * @param time_n time at the beginning of the step + * @param dt the perscribed timestep + * @param cycleNumber the current cycle number + * @param domain the domain object + * @param dofManager degree-of-freedom manager associated with the linear system + * @param localMatrix the system matrix + * @param rhs the system right-hand side vector + * @param solution the solution vector + * @param scaleFactor the scaling factor to apply to the solution + * @param lastResidual (in) target value below which to reduce residual norm, (out) achieved residual norm + * @return return true if line search succeeded, false otherwise + * + * This function implements a nonlinear newton method for implicit problems. It requires that the + * other functions in the solver interface are implemented in the derived physics solver. The + * nonlinear loop includes a simple line search algorithm, and will cut the timestep if + * convergence is not achieved according to the parameters in linearSolverParameters member. + */ + virtual bool + lineSearch( real64 const & time_n, + real64 const & dt, + integer const cycleNumber, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + ParallelVector & rhs, + ParallelVector & solution, + real64 const scaleFactor, + real64 & lastResidual ); + + /** + * @brief Function to perform line search using a parabolic interpolation to find the scaling factor. + * @param time_n time at the beginning of the step + * @param dt the prescribed timestep + * @param cycleNumber the current cycle number + * @param domain the domain object + * @param dofManager degree-of-freedom manager associated with the linear system + * @param localMatrix the system matrix + * @param rhs the system right-hand side vector + * @param solution the solution vector + * @param scaleFactor the scaling factor to apply to the solution + * @param lastResidual (in) target value below which to reduce residual norm, (out) achieved residual norm + * @param residualNormT the residual norm at the end of the line search + * @return return true if line search succeeded, false otherwise + * + */ + virtual bool + lineSearchWithParabolicInterpolation ( real64 const & time_n, + real64 const & dt, + integer const cycleNumber, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + ParallelVector & rhs, + ParallelVector & solution, + real64 const scaleFactor, + real64 & lastResidual, + real64 & residualNormT ); + + /** + * @brief Function for a linear implicit integration step + * @param time_n time at the beginning of the step + * @param dt the perscribed timestep + * @param cycleNumber the current cycle number + * @param domain the domain object + * @return return the timestep that was achieved during the step. + * + * This function implements a single linear step. Similar to the nonlinear step, however it + * assumes that the solution is achieved in a iteration. The use of this function requires that + * the other functions in the solver interface are implemented in the derived physics solver. The + * nonlinear loop includes a simple line search algorithm, and will cut the timestep if + * convergence is not achieved according to the parameters in linearSolverParameters member. + */ + virtual real64 linearImplicitStep( real64 const & time_n, + real64 const & dt, + integer const cycleNumber, + DomainPartition & domain ); + + /** + * @brief function to perform setup for implicit timestep + * @param time_n the time at the beginning of the step + * @param dt the desired timestep + * @param domain the domain partition + * + * This function should contain any step level initialization required to perform an implicit + * step. + * + * @note This function must be overridden in the derived physics solver in order to use an implict + * solution method such as LinearImplicitStep() or NonlinearImplicitStep(). + */ + virtual void + implicitStepSetup( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ); + + /** + * @brief Populate degree-of-freedom manager with fields relevant to this solver + * @param domain the domain containing the mesh and fields + * @param dofManager degree-of-freedom manager associated with the linear system + */ + virtual void + setupDofs( DomainPartition const & domain, + DofManager & dofManager ) const; + + /** + * @brief Set up the linear system (DOF indices and sparsity patterns) + * @param domain the domain containing the mesh and fields + * @param dofManager degree-of-freedom manager associated with the linear system + * @param localMatrix the system matrix + * @param rhs the system right-hand side vector + * @param solution the solution vector + * @param setSparsity flag to indicate if the sparsity pattern should be set + * + * @note While the function is virtual, the base class implementation should be + * sufficient for most single-physics solvers. + */ + virtual void + setupSystem( DomainPartition & domain, + DofManager & dofManager, + CRSMatrix< real64, globalIndex > & localMatrix, + ParallelVector & rhs, + ParallelVector & solution, + bool const setSparsity = true ); + + /** + * @brief function to assemble the linear system matrix and rhs + * @param time the time at the beginning of the step + * @param dt the desired timestep + * @param domain the domain partition + * @param dofManager degree-of-freedom manager associated with the linear system + * @param localMatrix the system matrix + * @param localRhs the system right-hand side vector + * + * This function assembles the residual and the jacobian of the residual wrt the primary + * variables. In a stand alone physics solver, this function will fill a single block in the + * block system. However the capability to query the block system structure for any coupled blocks + * may be implemented to fill in off diagonal blocks of the system to enable coupling between + * solvers. + * + * @note This function must be overridden in the derived physics solver in order to use an implict + * solution method such as LinearImplicitStep() or NonlinearImplicitStep(). + */ + virtual void + assembleSystem( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); + + /** + * @brief apply boundary condition to system + * @param time the time at the beginning of the step + * @param dt the desired timestep + * @param domain the domain partition + * @param dofManager degree-of-freedom manager associated with the linear system + * @param localMatrix the system matrix + * @param localRhs the system right-hand side vector + * + * This function applies all boundary conditions to the linear system. This is essentially a + * completion of the system assembly, but is separated for use in coupled solvers. + */ + virtual void + applyBoundaryConditions( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); + + /** + * @brief Output the assembled linear system for debug purposes. + * @param time beginning-of-step time + * @param cycleNumber event cycle number + * @param nonlinearIteration current nonlinear iteration number + * @param matrix system matrix + * @param rhs system right-hand side vector + */ + void + debugOutputSystem( real64 const & time, + integer const cycleNumber, + integer const nonlinearIteration, + ParallelMatrix const & matrix, + ParallelVector const & rhs ) const; + + /** + * @brief Output the linear system solution for debug purposes. + * @param time beginning-of-step time + * @param cycleNumber event cycle number + * @param nonlinearIteration current nonlinear iteration number + * @param solution system solution vector + */ + void + debugOutputSolution( real64 const & time, + integer const cycleNumber, + integer const nonlinearIteration, + ParallelVector const & solution ) const; + + /** + * @brief calculate the norm of the global system residual + * @param time the time at the beginning of the step + * @param dt the desired timestep + * @param domain the domain partition + * @param dofManager degree-of-freedom manager associated with the linear system + * @param localRhs the system right-hand side vector + * @return norm of the residual + * + * This function returns the norm of global residual vector, which is suitable for comparison with + * a tolerance. + */ + virtual real64 + calculateResidualNorm( real64 const & time, + real64 const & dt, + DomainPartition const & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localRhs ); + + /** + * @brief function to apply a linear system solver to the assembled system. + * @param dofManager degree-of-freedom manager associated with the linear system + * @param matrix the system matrix + * @param rhs the system right-hand side vector + * @param solution the solution vector + * + * This function calls the linear solver package to perform a single linear solve on the block + * system. The derived physics solver is required to specify the call, as no default is provided. + * + * @note This function must be overridden in the derived physics solver in order to use an implict + * solution method such as LinearImplicitStep() or NonlinearImplicitStep(). + */ + virtual void + solveLinearSystem( DofManager const & dofManager, + ParallelMatrix & matrix, + ParallelVector & rhs, + ParallelVector & solution ); + + /** + * @brief Function to check system solution for physical consistency and constraint violation + * @param domain the domain partition + * @param dofManager degree-of-freedom manager associated with the linear system + * @param localSolution the solution vector + * @param scalingFactor factor to scale the solution prior to application + * @return true if solution can be safely applied without violating physical constraints, false otherwise + * + * @note This function must be overridden in the derived physics solver in order to use an implict + * solution method such as LinearImplicitStep() or NonlinearImplicitStep(). + * + */ + virtual bool + checkSystemSolution( DomainPartition & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localSolution, + real64 const scalingFactor ); + + /** + * @brief Function to determine if the solution vector should be scaled back in order to maintain a known constraint. + * @param[in] domain The domain partition. + * @param[in] dofManager degree-of-freedom manager associated with the linear system + * @param[in] localSolution the solution vector + * @return The factor that should be used to scale the solution vector values when they are being applied. + */ + virtual real64 + scalingForSystemSolution( DomainPartition & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localSolution ); + + /** + * @brief Function to apply the solution vector to the state + * @param dofManager degree-of-freedom manager associated with the linear system + * @param localSolution the solution vector + * @param scalingFactor factor to scale the solution prior to application + * @param dt the timestep + * @param domain the domain partition + * + * This function performs 2 operations: + * 1) extract the solution vector for the "blockSystem" parameter, and applies the + * contents of the solution vector to the primary variable field data, + * 2) perform a synchronization of the primary field variable such that all ghosts are updated, + * + * The "scalingFactor" parameter allows for the scaled application of the solution vector. For + * instance, a line search may apply a negative scaling factor to remove part of the previously + * applied solution. + * + * @note This function must be overridden in the derived physics solver in order to use an implict + * solution method such as LinearImplicitStep() or NonlinearImplicitStep(). + * + */ + virtual void + applySystemSolution( DofManager const & dofManager, + arrayView1d< real64 const > const & localSolution, + real64 const scalingFactor, + real64 const dt, + DomainPartition & domain ); + + /** + * @brief updates the configuration (if needed) based on the state after a converged Newton loop. + * @param domain the domain containing the mesh and fields + * @return a bool that states whether the configuration used to solve the nonlinear loop is still valid or not. + */ + virtual bool updateConfiguration( DomainPartition & domain ); + + /** + * @brief + * @param domain the domain containing the mesh and fields + */ + virtual void outputConfigurationStatistics( DomainPartition const & domain ) const; + + /** + * @brief resets the configuration to the beginning of the time-step. + * @param domain the domain containing the mesh and fields + */ + virtual void resetConfigurationToBeginningOfStep( DomainPartition & domain ); + + /** + * @brief resets the configuration to the default value. + * @param domain the domain containing the mesh and fields + * @return a bool that states whether the configuration was reset or not. + */ + virtual bool resetConfigurationToDefault( DomainPartition & domain ) const; + + + /** + * @brief Recompute all dependent quantities from primary variables (including constitutive models) + * @param domain the domain containing the mesh and fields + */ + virtual void updateState( DomainPartition & domain ); + + /** + * @brief reset state of physics back to the beginning of the step. + * @param domain + * + * This function essentially abandons the step, and resets all variables back to thier values at + * the beginning of the step. This is useful for cases where convergence was not achieved, and + * a cut in timestep was required. + * + * @note This function must be overridden in the derived physics solver in order to use an implict + * solution method such as LinearImplicitStep() or NonlinearImplicitStep(). + */ + virtual void + resetStateToBeginningOfStep( DomainPartition & domain ); + + /** + * @brief perform cleanup for implicit timestep + * @param time the time at the beginning of the step + * @param dt the desired timestep + * @param domain the domain partition + * + * This function performs whatever tasks are required to complete an implicit timestep. For + * example, the acceptance of the solution will occur during this step, and deallocation of + * temporaries will be be performed in this function. + * + * @note This function must be overridden in the derived physics solver in order to use an implict + * solution method such as LinearImplicitStep() or NonlinearImplicitStep(). + */ + virtual void + implicitStepComplete( real64 const & time, + real64 const & dt, + DomainPartition & domain ); + + + /** + * @brief getter for the next timestep size + * @return the next timestep size m_nextDt + */ + virtual real64 getTimestepRequest( real64 const ) override + {return m_nextDt;}; + /**@}*/ + + /** + * @brief getter for the next timestep size + * @return the next timestep size m_nextDt + */ + real64 getTimestepRequest() + {return m_nextDt;}; + + /** + * @brief creates a child group of of this PhysicsSolverBase instantiation + * @param childKey the key of the child type + * @param childName the name of the child + * @return a pointer to the child group + */ + virtual Group * createChild( string const & childKey, string const & childName ) override; + + /** + * @brief Type alias for catalog interface used by this class. See CatalogInterface. + */ + using CatalogInterface = dataRepository::CatalogInterface< PhysicsSolverBase, string const &, Group * const >; + + /** + * @brief Get the singleton catalog for PhysicsSolverBase. + * @return reference to the catalog object + */ + static CatalogInterface::CatalogType & getCatalog(); + + /** + * @brief Structure to hold scoped key names + */ + struct viewKeyStruct + { + /// @return string for the cflFactor wrapper + static constexpr char const * cflFactorString() { return "cflFactor"; } + + /// @return string for the initialDt wrapper + static constexpr char const * initialDtString() { return "initialDt"; } + + /// @return string for the minDtIncreaseInterval wrapper + static constexpr char const * minDtIncreaseIntervalString() { return "minDtIncreaseInterval"; } + + /// @return string for the maxStableDt wrapper + static constexpr char const * maxStableDtString() { return "maxStableDt"; } + + /// @return string for the discretization wrapper + static constexpr char const * discretizationString() { return "discretization"; } + + /// @return string for the nextDt targetRegions wrapper + static constexpr char const * targetRegionsString() { return "targetRegions"; } + + /// @return string for the meshTargets wrapper + static constexpr char const * meshTargetsString() { return "meshTargets"; } + + /// @return string for the writeLinearSystem wrapper + static constexpr char const * writeLinearSystemString() { return "writeLinearSystem"; } + }; + + /** + * @brief Structure to hold scoped key names + */ + struct groupKeyStruct + { + /// @return string for the linearSolverParameters wrapper + static constexpr char const * linearSolverParametersString() { return "LinearSolverParameters"; } + + /// @return string for the nonlinearSolverParameters wrapper + static constexpr char const * nonlinearSolverParametersString() { return "NonlinearSolverParameters"; } + + /// @return string for the solverStatistics wrapper + static constexpr char const * solverStatisticsString() { return "SolverStatistics"; } + }; + + /** + * @brief getter for the timestamp of the system setup + * @return the timestamp of the last time systemSetup was called + */ + Timestamp getSystemSetupTimestamp() const { return m_systemSetupTimestamp; } + + /** + * @brief getter for the timestamp of the mesh modification on the mesh levels + * @param[in] domain the domain partition (cannot be const because we use forDiscretizationsInMeshTargets inside the function) + * @return the timestamp of the last time at which one of the mesh levels was modified + */ + Timestamp getMeshModificationTimestamp( DomainPartition & domain ) const; + + /** + * @brief set the timestamp of the system setup + * @param[in] timestamp the new timestamp of system setup + */ + void setSystemSetupTimestamp( Timestamp timestamp ) { m_systemSetupTimestamp = timestamp; } + + /** + * @brief return the value of the gravity vector specified in PhysicsSolverManager + * @return the value of the gravity vector + * + * @note if the solver is instantiated outside of a simulation (for instance for a unit test) + * and therefore does not have a parent of type PhysicsSolverManager, this function returns + * {0.0,0.0,-9.81} + */ + R1Tensor const gravityVector() const; + + /** + * @brief Check if the solution increments are ok to use + * @param domain the domain partition + * @return true if the solution increments are ok to use, false otherwise + */ + virtual bool checkSequentialSolutionIncrements( DomainPartition & domain ) const; + + /** + * @brief Save the state of the solver for sequential iteration + * @param domain the domain partition + */ + virtual void saveSequentialIterationState( DomainPartition & domain ); + + /** + * @brief accessor for the linear solver parameters. + * @return the linear solver parameter list + */ + LinearSolverParameters & getLinearSolverParameters() + { + return m_linearSolverParameters.get(); + } + + /** + * @brief const accessor for the linear solver parameters. + * @return the linear solver parameter list + */ + LinearSolverParameters const & getLinearSolverParameters() const + { + return m_linearSolverParameters.get(); + } + + /** + * @brief accessor for the nonlinear solver parameters. + * @return the nonlinear solver parameter list + */ + NonlinearSolverParameters & getNonlinearSolverParameters() + { + return m_nonlinearSolverParameters; + } + + /** + * @brief const accessor for the nonlinear solver parameters. + * @return the nonlinear solver parameter list + */ + NonlinearSolverParameters const & getNonlinearSolverParameters() const + { + return m_nonlinearSolverParameters; + } + + /** + * @brief syncronize the nonlinear solver parameters. + */ + virtual void + synchronizeNonlinearSolverParameters() + { /* empty here, overriden in CoupledSolver */ } + + /** + * @brief Get position of a given region within solver's target region list + * @param regionName the region name to find + * @return index within target regions list + */ + localIndex targetRegionIndex( string const & regionName ) const; + + + + /** + * @brief Loop over the target discretization on all mesh targets and apply callback. + * @tparam LAMBDA The callback function type + * @param meshBodies The group of MeshBodies + * @param lambda The callback function. Takes the name of the meshBody, + * reference to the MeshLevel, and a list of regionNames. + */ + template< typename LAMBDA > + void forDiscretizationOnMeshTargets( Group const & meshBodies, LAMBDA && lambda ) const + { + for( auto const & target: m_meshTargets ) + { + string const meshBodyName = target.first.first; + string const meshLevelName = target.first.second; + arrayView1d< string const > const & regionNames = target.second.toViewConst(); + MeshBody const & meshBody = meshBodies.getGroup< MeshBody >( meshBodyName ); + + MeshLevel const * meshLevelPtr = meshBody.getMeshLevels().getGroupPointer< MeshLevel >( meshLevelName ); + if( meshLevelPtr==nullptr ) + { + meshLevelPtr = meshBody.getMeshLevels().getGroupPointer< MeshLevel >( MeshBody::groupStructKeys::baseDiscretizationString() ); + } + lambda( meshBodyName, *meshLevelPtr, regionNames ); + } + } + + /** + * @brief Loop over the target discretization on all mesh targets and apply callback. + * @tparam LAMBDA The callback function type + * @param meshBodies The group of MeshBodies + * @param lambda The callback function. Takes the name of the meshBody, + * reference to the MeshLevel, and a list of regionNames. + */ + template< typename LAMBDA > + void forDiscretizationOnMeshTargets( Group & meshBodies, LAMBDA && lambda ) const + { + for( auto const & target: m_meshTargets ) + { + string const meshBodyName = target.first.first; + string const meshLevelName = target.first.second; + arrayView1d< string const > const & regionNames = target.second.toViewConst(); + MeshBody & meshBody = meshBodies.getGroup< MeshBody >( meshBodyName ); + + MeshLevel * meshLevelPtr = meshBody.getMeshLevels().getGroupPointer< MeshLevel >( meshLevelName ); + if( meshLevelPtr==nullptr ) + { + meshLevelPtr = meshBody.getMeshLevels().getGroupPointer< MeshLevel >( MeshBody::groupStructKeys::baseDiscretizationString() ); + } + lambda( meshBodyName, *meshLevelPtr, regionNames ); + } + } + + /** + * @brief return the name of the discretization object + * @return the name of the discretization object + */ + string getDiscretizationName() const {return m_discretizationName;} + + /** + * @brief function to set the value of m_assemblyCallback + * @param func the function to set m_assemblyCallback to + * @param funcType the type of the function + * @return true if the function was successfully set, false otherwise + * + * This is used to provide a callback function for to be called in the assembly step. + */ + virtual bool registerCallback( void * func, const std::type_info & funcType ) final override; + + /** + * @brief accessor for the solver statistics. + * @return reference to m_solverStatistics + */ + SolverStatistics & getSolverStatistics() { return m_solverStatistics; } + + /** + * @brief const accessor for the solver statistics. + * @return reference to m_solverStatistics + */ + SolverStatistics const & getSolverStatistics() const { return m_solverStatistics; } + +#if defined(GEOS_USE_PYGEOSX) + /** + * @brief Return PySolver type. + * @return Return PySolver type. + */ + virtual PyTypeObject * getPythonType() const override; +#endif + + /** + * @brief accessor for m_meshTargets + * @return reference to m_meshTargets + */ + map< std::pair< string, string >, array1d< string > > const & getMeshTargets() const + { + return m_meshTargets; + } +protected: + + /** + * @brief Eisenstat-Walker adaptive tolerance + * + * This method enables an inexact-Newton method is which the linear solver + * tolerance is chosen based on the nonlinear solver convergence behavior. + * In early Newton iterations, the search direction is usually imprecise, and + * therefore a weak linear convergence tolerance can be chosen to minimize + * computational cost. As the search gets closer to the true solution, however, + * more stringent linear tolerances are necessary to maintain quadratic convergence + * behavior. + * + * The user can set the weakest tolerance allowed, with a default of 1e-3. + * Even weaker values (e.g. 1e-2,1e-1) can be used for further speedup, but may + * occasionally cause convergence problems. Use this parameter with caution. The + * most stringent tolerance is hardcoded to 1e-8, which is sufficient for + * most problems. + * + * See Eisenstat, S.C. and Walker, H.F., 1996. Choosing the forcing terms in an + * inexact Newton method. SIAM Journal on Scientific Computing, 17(1), pp.16-32. + * + * @param newNewtonNorm Residual norm at current iteration + * @param oldNewtonNorm Residual norm at previous iteration + * @param krylovParams Linear solver parameters + * @return Adaptive tolerance recommendation + */ + real64 eisenstatWalker( real64 const newNewtonNorm, + real64 const oldNewtonNorm, + LinearSolverParameters::Krylov const & krylovParams ); + + /** + * @brief Get the Constitutive Name object + * + * @tparam CONSTITUTIVE_BASE_TYPE the base type of the constitutive model. + * @param subRegion the element subregion on which the constitutive model is registered + * @return the name name of the constitutive model of type CONSTITUTIVE_BASE_TYPE registered on the subregion. + */ + template< typename CONSTITUTIVE_BASE_TYPE > + static string getConstitutiveName( ElementSubRegionBase const & subRegion ); + + /** + * @brief Get the Constitutive Name object + * + * @tparam CONSTITUTIVE_BASE_TYPE the base type of the constitutive model. + * @param subRegion the particle subregion on which the constitutive model is registered + * @return the name name of the constitutive model of type CONSTITUTIVE_BASE_TYPE registered on the subregion. + */ + template< typename CONSTITUTIVE_BASE_TYPE > + static string getConstitutiveName( ParticleSubRegionBase const & subRegion ); // particle overload + + /** + * @brief This function sets constitutive name fields on an + * ElementSubRegionBase, and calls the base function it overrides. + * @param subRegion The ElementSubRegionBase that will have constitutive + * names set. + */ + virtual void setConstitutiveNamesCallSuper( ElementSubRegionBase & subRegion ) const { GEOS_UNUSED_VAR( subRegion ); } + + + /** + * @brief Get the Constitutive Model object + * @tparam BASETYPE the base type of the constitutive model. + * @tparam LOOKUP_TYPE the type of the key used to look up the constitutive model. + * @param dataGroup the data group containing the constitutive models. + * @param key the key used to look up the constitutive model. + * @return the constitutive model of type @p BASETYPE registered on the @p dataGroup with the key @p key. + */ + template< typename BASETYPE = constitutive::ConstitutiveBase, typename LOOKUP_TYPE > + static BASETYPE const & getConstitutiveModel( dataRepository::Group const & dataGroup, LOOKUP_TYPE const & key ) + { + dataRepository::Group const & constitutiveModels = dataGroup.getGroup( ElementSubRegionBase::groupKeyStruct::constitutiveModelsString() ); + return constitutiveModels.getGroup< BASETYPE >( key ); + } + + /** + * @brief Get the Constitutive Model object + * @tparam BASETYPE the base type of the constitutive model. + * @tparam LOOKUP_TYPE the type of the key used to look up the constitutive model. + * @param dataGroup the data group containing the constitutive models. + * @param key the key used to look up the constitutive model. + * @return the constitutive model of type @p BASETYPE registered on the @p dataGroup with the key @p key. + */ + template< typename BASETYPE = constitutive::ConstitutiveBase, typename LOOKUP_TYPE > + static BASETYPE & getConstitutiveModel( dataRepository::Group & dataGroup, LOOKUP_TYPE const & key ) + { + dataRepository::Group & constitutiveModels = dataGroup.getGroup( ElementSubRegionBase::groupKeyStruct::constitutiveModelsString() ); + return constitutiveModels.getGroup< BASETYPE >( key ); + } + + + + /// Courant–Friedrichs–Lewy factor for the timestep + real64 m_cflFactor; + + /// maximum stable time step + real64 m_maxStableDt; + + /// timestep of the next cycle + real64 m_nextDt; + + /// Number of cycles since last timestep cut + integer m_numTimestepsSinceLastDtCut; + + /// name of the FV discretization object in the data repository + string m_discretizationName; + + /// Data structure to handle degrees of freedom + DofManager m_dofManager; + + /// System matrix + ParallelMatrix m_matrix; + + /// System right-hand side vector + ParallelVector m_rhs; + + /// System solution vector + ParallelVector m_solution; + + /// Local system matrix and rhs + CRSMatrix< real64, globalIndex > m_localMatrix; + + /// Custom preconditioner for the "native" iterative solver + std::unique_ptr< PreconditionerBase< LAInterface > > m_precond; + + /// flag for debug output of matrix, rhs, and solution + integer m_writeLinearSystem; + + /// Linear solver parameters + LinearSolverParametersInput m_linearSolverParameters; + + /// Result of the last linear solve + LinearSolverResult m_linearSolverResult; + + /// Nonlinear solver parameters + NonlinearSolverParameters m_nonlinearSolverParameters; + + /// Solver statistics + SolverStatistics m_solverStatistics; + + /// Timestamp of the last call to setup system + Timestamp m_systemSetupTimestamp; + + /// Callback function for assembly step + std::function< void( CRSMatrix< real64, globalIndex >, array1d< real64 > ) > m_assemblyCallback; + + /// Timers for the aggregate profiling of the solver + std::map< std::string, std::chrono::system_clock::duration > m_timers; + +private: + /// List of names of regions the solver will be applied to + array1d< string > m_targetRegionNames; + + /// Map containing the array of target regions (value) for each MeshBody (key). + map< std::pair< string, string >, array1d< string > > m_meshTargets; + + /** + * @brief This function sets constitutive name fields on an + * ElementSubRegionBase, and DOES NOT call the base function it overrides. + * @param subRegion The ElementSubRegionBase that will have constitutive + * names set. + */ + virtual void setConstitutiveNames( ElementSubRegionBase & subRegion ) const { GEOS_UNUSED_VAR( subRegion ); } + + /** + * @brief Solve a nonlinear system using a Newton method + * @param time_n the time at the beginning of the step + * @param dt the desired timestep + * @param cycleNumber the current cycle number + * @param domain the domain partition + * @return true if the nonlinear system was solved, false otherwise + */ + bool solveNonlinearSystem( real64 const & time_n, + real64 const & dt, + integer const cycleNumber, + DomainPartition & domain ); + + /** + * @brief output information about the cycle to the log + * @param cycleNumber the current cycle number + * @param numOfSubSteps the number of substeps taken + * @param subStepDt the time step size for each substep + */ + void logEndOfCycleInformation( integer const cycleNumber, + integer const numOfSubSteps, + std::vector< real64 > const & subStepDt ) const; + +}; + +template< typename CONSTITUTIVE_BASE_TYPE > +string PhysicsSolverBase::getConstitutiveName( ElementSubRegionBase const & subRegion ) +{ + string validName; + dataRepository::Group const & constitutiveModels = subRegion.getConstitutiveModels(); + + constitutiveModels.forSubGroups< CONSTITUTIVE_BASE_TYPE >( [&]( dataRepository::Group const & model ) + { + GEOS_ERROR_IF( !validName.empty(), "A valid constitutive model was already found." ); + validName = model.getName(); + } ); + return validName; +} + +template< typename CONSTITUTIVE_BASE_TYPE > +string PhysicsSolverBase::getConstitutiveName( ParticleSubRegionBase const & subRegion ) // particle overload +{ + string validName; + dataRepository::Group const & constitutiveModels = subRegion.getConstitutiveModels(); + + constitutiveModels.forSubGroups< CONSTITUTIVE_BASE_TYPE >( [&]( dataRepository::Group const & model ) + { + GEOS_ERROR_IF( !validName.empty(), "A valid constitutive model was already found." ); + validName = model.getName(); + } ); + return validName; +} + + +} // namespace geos + + +#endif /* GEOS_PHYSICSSOLVERS_PHYSICSSOLVERBASE_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/PhysicsSolverBaseKernels.hpp b/src/coreComponents/physicsSolvers/PhysicsSolverBaseKernels.hpp new file mode 100644 index 00000000000..ac8433b208b --- /dev/null +++ b/src/coreComponents/physicsSolvers/PhysicsSolverBaseKernels.hpp @@ -0,0 +1,349 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PhysicsSolverBaseKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_SOLVERBASEKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_SOLVERBASEKERNELS_HPP + +#include "common/format/EnumStrings.hpp" +#include "common/DataTypes.hpp" +#include "common/MpiWrapper.hpp" + +namespace geos +{ + +namespace physicsSolverBaseKernels +{ + +/******************************** ResidualNormKernelBase ********************************/ + +/** + * @tparam NUM_NORM number of norms to compute (NUM_NORM is related to the number of equations to solve) + * For instance, NUM_NORM=1 for isothermal simulations and NUM_NORM=2 for thermal simulations + * @brief Define the base interface for the residual calculations + */ +template< integer NUM_NORM > +class ResidualNormKernelBase +{ +public: + + + /// Compile time value for the number of norms to compute + static constexpr integer numNorm = NUM_NORM; + + ResidualNormKernelBase( globalIndex const rankOffset, + arrayView1d< real64 const > const & localResidual, + arrayView1d< globalIndex const > const & dofNumber, + arrayView1d< localIndex const > const & ghostRank, + real64 const minNormalizer ): + m_rankOffset( rankOffset ), + m_localResidual( localResidual ), + m_dofNumber( dofNumber ), + m_ghostRank( ghostRank ), + m_minNormalizer( minNormalizer ) + {} + + /** + * @struct LinfStackVariables + * @brief Kernel variables located on the stack for Linf norm + */ + struct LinfStackVariables + { + /// Index of the local row in the residual vector + localIndex localRow; + + /// Normalized residual value for the element/node/face + real64 localValue[numNorm]{}; + }; + + /** + * @struct L2StackVariables + * @brief Kernel variables located on the stack for L2 norm + */ + struct L2StackVariables : public LinfStackVariables + { + /// Normalizer value for the element/node/face + real64 localNormalizer[numNorm]{}; + }; + + + /** + * @brief Getter for the ghost rank + * @param[in] i the looping index of the element/node/face + * @return the ghost rank of the element/node/face + */ + GEOS_HOST_DEVICE + integer ghostRank( localIndex const i ) const + { return m_ghostRank( i ); } + + /** + * @brief Setup the residual Linf normal calculations + * @param[in] i the element/node/face index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + virtual void setupLinf( localIndex const i, + LinfStackVariables & stack ) const + { + stack.localRow = m_dofNumber[i] - m_rankOffset; + } + + /** + * @brief Setup the residual L2 normal calculations + * @param[in] i the element/node/face index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + virtual void setupL2( localIndex const i, + L2StackVariables & stack ) const + { + stack.localRow = m_dofNumber[i] - m_rankOffset; + } + + + /** + * @brief Compute the local values for the Linf norm + * @param[in] i the element/node/face index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + virtual void computeLinf( localIndex const i, + LinfStackVariables & stack ) const = 0; + + /** + * @brief Compute the local values and normalizer for the L2 norm + * @param[in] i the element/node/face index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + virtual void computeL2( localIndex const i, + L2StackVariables & stack ) const = 0; + + /** + * @brief Performs the kernel launch for the L-\infty norm + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] size the number of elements/nodes/faces + * @param[inout] kernelComponent the kernel component providing access to the compute function + * @param[inout] residualNorms the norms to compute + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launchLinf( localIndex const size, + KERNEL_TYPE const & kernelComponent, + real64 (& residualNorm)[numNorm] ) + { + RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > localResidualNorm[numNorm]{}; + + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const i ) + { + if( kernelComponent.ghostRank( i ) >= 0 ) + { + return; + } + + typename KERNEL_TYPE::LinfStackVariables stack; + kernelComponent.setupLinf( i, stack ); + kernelComponent.computeLinf( i, stack ); + + for( integer j = 0; j < numNorm; ++j ) + { + localResidualNorm[j].max( LvArray::math::abs( stack.localValue[j] ) ); + } + } ); + + for( integer j = 0; j < numNorm; ++j ) + { + residualNorm[j] = localResidualNorm[j].get(); + } + } + + /** + * @brief Performs the kernel launch for the L2 norm + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] size the number of elements/nodes/faces + * @param[inout] kernelComponent the kernel component providing access to the compute function + * @param[inout] residualNorm the norms to compute + * @param[inout] residualNormalizer the norms to compute + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launchL2( localIndex const size, + KERNEL_TYPE const & kernelComponent, + real64 (& residualNorm)[numNorm], + real64 (& residualNormalizer)[numNorm] ) + { + RAJA::ReduceSum< ReducePolicy< POLICY >, real64 > localResidualNorm[numNorm]{}; + RAJA::ReduceSum< ReducePolicy< POLICY >, real64 > localResidualNormalizer[numNorm]{}; + + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const i ) + { + if( kernelComponent.ghostRank( i ) >= 0 ) + { + return; + } + + typename KERNEL_TYPE::L2StackVariables stack; + kernelComponent.setupL2( i, stack ); + kernelComponent.computeL2( i, stack ); + + for( integer j = 0; j < numNorm; ++j ) + { + localResidualNorm[j] += stack.localValue[j]; + localResidualNormalizer[j] += stack.localNormalizer[j]; + } + } ); + + for( integer j = 0; j < numNorm; ++j ) + { + residualNorm[j] = localResidualNorm[j].get(); + residualNormalizer[j] = localResidualNormalizer[j].get(); + } + } + + +protected: + + /// Offset for my MPI rank + globalIndex const m_rankOffset; + + /// View on the local residual + arrayView1d< real64 const > const m_localResidual; + + /// View on the dof numbers + arrayView1d< globalIndex const > const m_dofNumber; + + /// View on the ghost ranks + arrayView1d< integer const > const m_ghostRank; + + /// Value used to make sure that normalizers are never zero + real64 const m_minNormalizer; + +}; + +/** + * @class LinfResidualNormHelper + * @brief Utility class to compute the global Linf residual norm + */ +class LinfResidualNormHelper +{ +public: + + template< integer NUM_NORM > + static void updateLocalNorm( real64 const (&subRegionResidualNorm)[NUM_NORM], + array1d< real64 > & localResidualNorm ) + { + for( integer i = 0; i < NUM_NORM; ++i ) + { + if( subRegionResidualNorm[i] > localResidualNorm[i] ) + { + localResidualNorm[i] = subRegionResidualNorm[i]; + } + } + } + + static void computeGlobalNorm( real64 const & localResidualNorm, + real64 & globalResidualNorm ) + { + globalResidualNorm = MpiWrapper::max( localResidualNorm ); + } + + static void computeGlobalNorm( array1d< real64 > const & localResidualNorm, + array1d< real64 > & globalResidualNorm ) + { + MpiWrapper::allReduce( localResidualNorm.data(), + globalResidualNorm.data(), + localResidualNorm.size(), + MpiWrapper::getMpiOp( MpiWrapper::Reduction::Max ), + MPI_COMM_GEOS ); + } +}; + +/** + * @class L2ResidualNormHelper + * @brief Utility class to compute the global L2 residual norm + */ +class L2ResidualNormHelper +{ +public: + + template< integer NUM_NORM > + static void updateLocalNorm( real64 const (&subRegionResidualNorm)[NUM_NORM], + real64 const (&subRegionResidualNormalizer)[NUM_NORM], + array1d< real64 > & localResidualNorm, + array1d< real64 > & localResidualNormalizer ) + { + for( integer i = 0; i < NUM_NORM; ++i ) + { + localResidualNorm[i] += subRegionResidualNorm[i]; + localResidualNormalizer[i] += subRegionResidualNormalizer[i]; + } + } + + static void computeGlobalNorm( real64 const & localResidualNorm, + real64 const & localResidualNormalizer, + real64 & globalResidualNorm ) + { + globalResidualNorm = sqrt( MpiWrapper::sum( localResidualNorm ) ) / sqrt( MpiWrapper::sum( localResidualNormalizer ) ); + } + + static void computeGlobalNorm( array1d< real64 > const & localResidualNorm, + array1d< real64 > const & localResidualNormalizer, + array1d< real64 > & globalResidualNorm ) + { + array1d< real64 > sumLocalResidualNorm( localResidualNorm.size() ); + array1d< real64 > sumLocalResidualNormalizer( localResidualNormalizer.size() ); + MpiWrapper::allReduce( localResidualNorm.data(), + sumLocalResidualNorm.data(), + localResidualNorm.size(), + MpiWrapper::getMpiOp( MpiWrapper::Reduction::Sum ), + MPI_COMM_GEOS ); + MpiWrapper::allReduce( localResidualNormalizer.data(), + sumLocalResidualNormalizer.data(), + localResidualNormalizer.size(), + MpiWrapper::getMpiOp( MpiWrapper::Reduction::Sum ), + MPI_COMM_GEOS ); + for( integer i = 0; i < localResidualNorm.size(); ++i ) + { + globalResidualNorm[i] = sqrt( sumLocalResidualNorm[i] ) / sqrt( sumLocalResidualNormalizer[i] ); + } + } + +}; + +/** + * @brief Type of norm used to check convergence + * TODO: find a way to put this inside the class + */ +enum class NormType : integer +{ + Linf, /**< Linfinity norm */ + L2 /**< L2 */ +}; + +ENUM_STRINGS( NormType, + "Linfinity", + "L2" ); + + +} // namespace physicsSolverBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_SOLVERBASEKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/PhysicsSolverManager.cpp b/src/coreComponents/physicsSolvers/PhysicsSolverManager.cpp index 8ae4e8d8145..0267c7df811 100644 --- a/src/coreComponents/physicsSolvers/PhysicsSolverManager.cpp +++ b/src/coreComponents/physicsSolvers/PhysicsSolverManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,7 +19,7 @@ #include "PhysicsSolverManager.hpp" -#include "SolverBase.hpp" +#include "PhysicsSolverBase.hpp" namespace geos { @@ -46,11 +47,11 @@ PhysicsSolverManager::~PhysicsSolverManager() Group * PhysicsSolverManager::createChild( string const & childKey, string const & childName ) { Group * rval = nullptr; - if( SolverBase::CatalogInterface::hasKeyName( childKey ) ) + if( PhysicsSolverBase::CatalogInterface::hasKeyName( childKey ) ) { - GEOS_LOG_RANK_0( "Adding Solver of type " << childKey << ", named " << childName ); + GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) ); rval = ®isterGroup( childName, - SolverBase::CatalogInterface::factory( childKey, childName, this ) ); + PhysicsSolverBase::CatalogInterface::factory( childKey, childName, this ) ); } return rval; } @@ -58,8 +59,8 @@ Group * PhysicsSolverManager::createChild( string const & childKey, string const void PhysicsSolverManager::expandObjectCatalogs() { - // During schema generation, register one of each type derived from SolverBase here - for( auto & catalogIter: SolverBase::getCatalog()) + // During schema generation, register one of each type derived from PhysicsSolverBase here + for( auto & catalogIter: PhysicsSolverBase::getCatalog()) { createChild( catalogIter.first, catalogIter.first ); } diff --git a/src/coreComponents/physicsSolvers/PhysicsSolverManager.hpp b/src/coreComponents/physicsSolvers/PhysicsSolverManager.hpp index 7b8f5b99cd2..3399cf5c631 100644 --- a/src/coreComponents/physicsSolvers/PhysicsSolverManager.hpp +++ b/src/coreComponents/physicsSolvers/PhysicsSolverManager.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -24,7 +25,6 @@ class xml_node; namespace geos { -class SolverBase; class PhysicsSolverManager : public dataRepository::Group { diff --git a/src/coreComponents/physicsSolvers/SolutionStrategy.rst b/src/coreComponents/physicsSolvers/SolutionStrategy.rst index 3a7f0f0bb31..e0ca4873f5f 100644 --- a/src/coreComponents/physicsSolvers/SolutionStrategy.rst +++ b/src/coreComponents/physicsSolvers/SolutionStrategy.rst @@ -88,4 +88,4 @@ All parameters defining the behavior of the nonlinear solver and determining the timestep size requested by the physics solver are defined in the NonlinearSolverParameters and are presented in the following table. -.. include:: /coreComponents/schema/docs/NonlinearSolverParameters.rst +.. include:: /docs/sphinx/datastructure/NonlinearSolverParameters.rst diff --git a/src/coreComponents/physicsSolvers/SolverBase.cpp b/src/coreComponents/physicsSolvers/SolverBase.cpp deleted file mode 100644 index 59d5e29a041..00000000000 --- a/src/coreComponents/physicsSolvers/SolverBase.cpp +++ /dev/null @@ -1,1367 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -#include "SolverBase.hpp" -#include "PhysicsSolverManager.hpp" - -#include "common/TimingMacros.hpp" -#include "linearAlgebra/utilities/LinearSolverParameters.hpp" -#include "linearAlgebra/solvers/KrylovSolver.hpp" -#include "mesh/DomainPartition.hpp" -#include "math/interpolation/Interpolation.hpp" -#include "common/Timer.hpp" - -#if defined(GEOSX_USE_PYGEOSX) -#include "python/PySolverType.hpp" -#endif - -namespace geos -{ - -using namespace dataRepository; - -SolverBase::SolverBase( string const & name, - Group * const parent ) - : - ExecutableGroup( name, parent ), - m_cflFactor(), - m_maxStableDt{ 1e99 }, - m_nextDt( 1e99 ), - m_dofManager( name ), - m_linearSolverParameters( groupKeyStruct::linearSolverParametersString(), this ), - m_nonlinearSolverParameters( groupKeyStruct::nonlinearSolverParametersString(), this ), - m_solverStatistics( groupKeyStruct::solverStatisticsString(), this ), - m_systemSetupTimestamp( 0 ) -{ - setInputFlags( InputFlags::OPTIONAL_NONUNIQUE ); - - // This enables logLevel filtering - enableLogLevelInput(); - - // This sets a flag to indicate that this object is going to select the time step size - this->setTimesteppingBehavior( ExecutableGroup::TimesteppingBehavior::DeterminesTimeStepSize ); - - registerWrapper( viewKeyStruct::cflFactorString(), &m_cflFactor ). - setApplyDefaultValue( 0.5 ). - setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Factor to apply to the `CFL condition `_" - " when calculating the maximum allowable time step. Values should be in the interval (0,1] " ); - - registerWrapper( viewKeyStruct::maxStableDtString(), &m_maxStableDt ). - setApplyDefaultValue( 0.5 ). - setInputFlag( InputFlags::FALSE ). - setDescription( "Value of the Maximum Stable Timestep for this solver." ); - - this->registerWrapper( viewKeyStruct::discretizationString(), &m_discretizationName ). - setRTTypeName( rtTypes::CustomTypes::groupNameRef ). - setInputFlag( InputFlags::REQUIRED ). - setDescription( "Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this " - "solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` " - "should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` " - "discretization should be specified." ); - - registerWrapper( viewKeyStruct::targetRegionsString(), &m_targetRegionNames ). - setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ). - setInputFlag( InputFlags::REQUIRED ). - setDescription( "Allowable regions that the solver may be applied to. Note that this does not indicate that " - "the solver will be applied to these regions, only that allocation will occur such that the " - "solver may be applied to these regions. The decision about what regions this solver will be" - "applied to rests in the EventManager." ); - - registerWrapper( viewKeyStruct::meshTargetsString(), &m_meshTargets ). - setInputFlag( InputFlags::FALSE ). - setRestartFlags( RestartFlags::NO_WRITE ). - setDescription( "MeshBody/Region combinations that the solver will be applied to." ); - - registerWrapper( viewKeyStruct::initialDtString(), &m_nextDt ). - setApplyDefaultValue( 1e99 ). - setInputFlag( InputFlags::OPTIONAL ). - setRestartFlags( RestartFlags::WRITE_AND_READ ). - setDescription( "Initial time-step value required by the solver to the event manager." ); - - registerGroup( groupKeyStruct::linearSolverParametersString(), &m_linearSolverParameters ); - registerGroup( groupKeyStruct::nonlinearSolverParametersString(), &m_nonlinearSolverParameters ); - registerGroup( groupKeyStruct::solverStatisticsString(), &m_solverStatistics ); - - m_localMatrix.setName( this->getName() + "/localMatrix" ); - m_matrix.setDofManager( &m_dofManager ); -} - -SolverBase::~SolverBase() = default; - -void SolverBase::initialize_postMeshGeneration() -{ - ExecutableGroup::initialize_postMeshGeneration(); - DomainPartition const & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); - generateMeshTargetsFromTargetRegions( domain.getMeshBodies()); -} - -void SolverBase::generateMeshTargetsFromTargetRegions( Group const & meshBodies ) -{ - for( auto const & target : m_targetRegionNames ) - { - - std::vector< string > targetTokens = stringutilities::tokenize( target, "/" ); - - if( targetTokens.size()==1 ) // no MeshBody or MeshLevel specified - { - GEOS_ERROR_IF( meshBodies.numSubGroups() != 1, - getDataContext() << ": No MeshBody information is specified in" << - " SolverBase::meshTargets, but there are multiple MeshBody objects" ); - MeshBody const & meshBody = meshBodies.getGroup< MeshBody >( 0 ); - string const meshBodyName = meshBody.getName(); - - string const meshLevelName = m_discretizationName; - - string const regionName = target; - auto const key = std::make_pair( meshBodyName, meshLevelName ); - m_meshTargets[key].emplace_back( regionName ); - } - else if( targetTokens.size()==2 ) - { - string const meshBodyName = targetTokens[0]; - GEOS_ERROR_IF( !meshBodies.hasGroup( meshBodyName ), - getWrapperDataContext( viewKeyStruct::targetRegionsString() ) << ": MeshBody (" << - meshBodyName << ") is specified in targetRegions, but does not exist." ); - - string const meshLevelName = m_discretizationName; - - string const regionName = targetTokens[1]; - - - auto const key = std::make_pair( meshBodyName, meshLevelName ); - m_meshTargets[key].emplace_back( regionName ); - } - else - { - GEOS_ERROR( getDataContext() << ": Invalid specification of targetRegions" ); - } - } -} - - -void SolverBase::registerDataOnMesh( Group & meshBodies ) -{ - ExecutableGroup::registerDataOnMesh( meshBodies ); - - forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - ElementRegionManager & elemManager = mesh.getElemManager(); - elemManager.forElementSubRegions< ElementSubRegionBase >( regionNames, - [&]( localIndex const, - ElementSubRegionBase & subRegion ) - { - setConstitutiveNamesCallSuper( subRegion ); - setConstitutiveNames( subRegion ); - } ); - - } ); - -} - - - -Group * SolverBase::createChild( string const & GEOS_UNUSED_PARAM( childKey ), string const & GEOS_UNUSED_PARAM( childName ) ) -{ - return nullptr; -} - -SolverBase::CatalogInterface::CatalogType & SolverBase::getCatalog() -{ - static SolverBase::CatalogInterface::CatalogType catalog; - return catalog; -} - -localIndex SolverBase::targetRegionIndex( string const & regionName ) const -{ - auto const pos = std::find( m_targetRegionNames.begin(), m_targetRegionNames.end(), regionName ); - GEOS_ERROR_IF( pos == m_targetRegionNames.end(), - GEOS_FMT( "{}: Region {} is not a target of the solver.", - getDataContext(), regionName ) ); - return std::distance( m_targetRegionNames.begin(), pos ); -} - -bool SolverBase::registerCallback( void * func, const std::type_info & funcType ) -{ - if( std::type_index( funcType ) == std::type_index( typeid( std::function< void( CRSMatrix< real64, globalIndex >, array1d< real64 > ) > ) ) ) - { - m_assemblyCallback = *reinterpret_cast< std::function< void( CRSMatrix< real64, globalIndex >, array1d< real64 > ) > * >( func ); - return true; - } - - return false; -} - -real64 SolverBase::solverStep( real64 const & time_n, - real64 const & dt, - const integer cycleNumber, - DomainPartition & domain ) -{ - GEOS_MARK_FUNCTION; - - // Only build the sparsity pattern if the mesh has changed - Timestamp const meshModificationTimestamp = getMeshModificationTimestamp( domain ); - - if( meshModificationTimestamp > getSystemSetupTimestamp() ) - { - setupSystem( domain, m_dofManager, m_localMatrix, m_rhs, m_solution ); - setSystemSetupTimestamp( meshModificationTimestamp ); - } - - implicitStepSetup( time_n, dt, domain ); - - // currently the only method is implicit time integration - real64 const dt_return = nonlinearImplicitStep( time_n, dt, cycleNumber, domain ); - - // final step for completion of timestep. typically secondary variable updates and cleanup. - implicitStepComplete( time_n, dt_return, domain ); - - return dt_return; -} - -bool SolverBase::execute( real64 const time_n, - real64 const dt, - integer const cycleNumber, - integer const GEOS_UNUSED_PARAM( eventCounter ), - real64 const GEOS_UNUSED_PARAM( eventProgress ), - DomainPartition & domain ) -{ - GEOS_MARK_FUNCTION; - real64 dtRemaining = dt; - real64 nextDt = dt; - - integer const maxSubSteps = m_nonlinearSolverParameters.m_maxSubSteps; - - for( integer subStep = 0; subStep < maxSubSteps && dtRemaining > 0.0; ++subStep ) - { - // reset number of nonlinear and linear iterations - m_solverStatistics.initializeTimeStepStatistics(); - - real64 const dtAccepted = solverStep( time_n + (dt - dtRemaining), - nextDt, - cycleNumber, - domain ); - - // increment the cumulative number of nonlinear and linear iterations - m_solverStatistics.saveTimeStepStatistics(); - - /* - * Let us check convergence history of previous solve: - * - number of nonlinear iter. - * - if the time-step was chopped. Then we can add some heuristics to choose next dt. - * */ - dtRemaining -= dtAccepted; - - if( dtRemaining > 0.0 ) - { - nextDt = setNextDt( dtAccepted, domain ); - if( nextDt < dtRemaining ) - { - // better to do two equal steps than one big and one small (even potentially tiny) - if( nextDt * 2 > dtRemaining ) - nextDt = dtRemaining / 2; - } - else - { - nextDt = dtRemaining; - } - } - - if( getLogLevel() >= 1 && dtRemaining > 0.0 ) - { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: sub-step = {}, accepted dt = {}, next dt = {}, remaining dt = {}", getName(), subStep, dtAccepted, nextDt, dtRemaining ) ); - } - } - - GEOS_ERROR_IF( dtRemaining > 0.0, getDataContext() << ": Maximum allowed number of sub-steps" - " reached. Consider increasing maxSubSteps." ); - - // Decide what to do with the next Dt for the event running the solver. - m_nextDt = setNextDt( nextDt, domain ); - - return false; -} - -real64 SolverBase::setNextDt( real64 const & currentDt, - DomainPartition & domain ) -{ - real64 const nextDtNewton = setNextDtBasedOnNewtonIter( currentDt ); - real64 const nextDtStateChange = setNextDtBasedOnStateChange( currentDt, domain ); - - if( nextDtNewton < nextDtStateChange ) // time step size decided based on convergence - { - integer const iterDecreaseLimit = m_nonlinearSolverParameters.timeStepDecreaseIterLimit(); - integer const iterIncreaseLimit = m_nonlinearSolverParameters.timeStepIncreaseIterLimit(); - if( nextDtNewton > currentDt ) - { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: solver converged in less than {} iterations, time-step required will be increased.", - getName(), iterIncreaseLimit ) ); - } - else if( nextDtNewton < currentDt ) - { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: solver converged in more than {} iterations, time-step required will be decreased.", - getName(), iterDecreaseLimit ) ); - } - } - else // time step size decided based on state change - { - if( nextDtStateChange > currentDt ) - { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: Time-step required will be increased based on state change.", - getName())); - } - else if( nextDtStateChange < currentDt ) - { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: Time-step required will be decreased based on state change.", - getName())); - } - } - - return std::min( nextDtNewton, nextDtStateChange ); -} - -real64 SolverBase::setNextDtBasedOnStateChange( real64 const & currentDt, - DomainPartition & domain ) -{ - GEOS_UNUSED_VAR( currentDt, domain ); - return LvArray::NumericLimits< real64 >::max; // i.e., not implemented -} - -real64 SolverBase::setNextDtBasedOnNewtonIter( real64 const & currentDt ) -{ - integer & newtonIter = m_nonlinearSolverParameters.m_numNewtonIterations; - integer const iterDecreaseLimit = m_nonlinearSolverParameters.timeStepDecreaseIterLimit(); - integer const iterIncreaseLimit = m_nonlinearSolverParameters.timeStepIncreaseIterLimit(); - - real64 nextDt = 0; - if( newtonIter < iterIncreaseLimit ) - { - // Easy convergence, let's increase the time-step. - nextDt = currentDt * m_nonlinearSolverParameters.timeStepIncreaseFactor(); - } - else if( newtonIter > iterDecreaseLimit ) - { - // Tough convergence let us make the time-step smaller! - nextDt = currentDt * m_nonlinearSolverParameters.timeStepDecreaseFactor(); - } - else - { - nextDt = currentDt; - } - return nextDt; -} - - -real64 SolverBase::setNextDtBasedOnCFL( const geos::real64 & currentDt, geos::DomainPartition & domain ) -{ - GEOS_UNUSED_VAR( currentDt, domain ); - return LvArray::NumericLimits< real64 >::max; // i.e., not implemented -} - - - -real64 SolverBase::linearImplicitStep( real64 const & time_n, - real64 const & dt, - integer const GEOS_UNUSED_PARAM( cycleNumber ), - DomainPartition & domain ) -{ - // call setup for physics solver. Pre step allocations etc. - // TODO: Nonlinear step does not call its own setup, need to decide on consistent behavior - implicitStepSetup( time_n, dt, domain ); - - { - Timer timer( m_timers["assemble"] ); - - // zero out matrix/rhs before assembly - m_localMatrix.zero(); - m_rhs.zero(); - - arrayView1d< real64 > const localRhs = m_rhs.open(); - - // call assemble to fill the matrix and the rhs - assembleSystem( time_n, - dt, - domain, - m_dofManager, - m_localMatrix.toViewConstSizes(), - localRhs ); - - // apply boundary conditions to system - applyBoundaryConditions( time_n, - dt, - domain, - m_dofManager, - m_localMatrix.toViewConstSizes(), - localRhs ); - - m_rhs.close(); - - if( m_assemblyCallback ) - { - // Make a copy of LA objects and ship off to the callback - array1d< real64 > localRhsCopy( m_rhs.localSize() ); - localRhsCopy.setValues< parallelDevicePolicy<> >( m_rhs.values() ); - m_assemblyCallback( m_localMatrix, std::move( localRhsCopy ) ); - } - } - - { - Timer timer( m_timers["linear solver total"] ); - - // TODO: Trilinos currently requires this, re-evaluate after moving to Tpetra-based solvers - if( m_precond ) - { - m_precond->clear(); - } - - { - Timer timer_create( m_timers["linear solver create"] ); - - // Compose parallel LA matrix out of local matrix - m_matrix.create( m_localMatrix.toViewConst(), m_dofManager.numLocalDofs(), MPI_COMM_GEOSX ); - } - - // Output the linear system matrix/rhs for debugging purposes - debugOutputSystem( 0.0, 0, 0, m_matrix, m_rhs ); - - // Solve the linear system - solveLinearSystem( m_dofManager, m_matrix, m_rhs, m_solution ); - } - - // Increment the solver statistics for reporting purposes - m_solverStatistics.logNonlinearIteration( m_linearSolverResult.numIterations ); - - // Output the linear system solution for debugging purposes - debugOutputSolution( 0.0, 0, 0, m_solution ); - - { - Timer timer( m_timers["apply solution"] ); - - // apply the system solution to the fields/variables - applySystemSolution( m_dofManager, m_solution.values(), 1.0, dt, domain ); - } - - { - Timer timer( m_timers["update state"] ); - - // update non-primary variables (constitutive models) - updateState( domain ); - } - - // final step for completion of timestep. typically secondary variable updates and cleanup. - implicitStepComplete( time_n, dt, domain ); - - // return the achieved timestep - return dt; -} - - -bool SolverBase::lineSearch( real64 const & time_n, - real64 const & dt, - integer const GEOS_UNUSED_PARAM( cycleNumber ), - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - ParallelVector & rhs, - ParallelVector & solution, - real64 const scaleFactor, - real64 & lastResidual ) -{ - Timer timer( m_timers["line search"] ); - - integer const maxNumberLineSearchCuts = m_nonlinearSolverParameters.m_lineSearchMaxCuts; - real64 const lineSearchCutFactor = m_nonlinearSolverParameters.m_lineSearchCutFactor; - - // flag to determine if we should solve the system and apply the solution. If the line - // search fails we just bail. - bool lineSearchSuccess = false; - - real64 residualNorm = lastResidual; - - // scale factor is value applied to the previous solution. In this case we want to - // subtract a portion of the previous solution. - real64 localScaleFactor = -scaleFactor; - real64 cumulativeScale = scaleFactor; - - // main loop for the line search. - for( integer lineSearchIteration = 0; lineSearchIteration < maxNumberLineSearchCuts; ++lineSearchIteration ) - { - // cut the scale factor by half. This means that the scale factors will - // have values of -0.5, -0.25, -0.125, ... - localScaleFactor *= lineSearchCutFactor; - cumulativeScale += localScaleFactor; - - if( !checkSystemSolution( domain, dofManager, solution.values(), localScaleFactor ) ) - { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " Line search {}, solution check failed", lineSearchIteration ) ); - continue; - } - - applySystemSolution( dofManager, solution.values(), localScaleFactor, dt, domain ); - - // update non-primary variables (constitutive models) - updateState( domain ); - - // re-assemble system - localMatrix.zero(); - rhs.zero(); - - arrayView1d< real64 > const localRhs = rhs.open(); - assembleSystem( time_n, dt, domain, dofManager, localMatrix, localRhs ); - applyBoundaryConditions( time_n, dt, domain, dofManager, localMatrix, localRhs ); - rhs.close(); - - if( getLogLevel() >= 1 && logger::internal::rank==0 ) - { - std::cout << GEOS_FMT( " Line search @ {:0.3f}: ", cumulativeScale ); - } - - // get residual norm - residualNorm = calculateResidualNorm( time_n, dt, domain, dofManager, rhs.values() ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " ( R ) = ( {:4.2e} )", residualNorm ) ); - - // if the residual norm is less than the last residual, we can proceed to the - // solution step - if( residualNorm < lastResidual ) - { - lineSearchSuccess = true; - break; - } - } - - lastResidual = residualNorm; - return lineSearchSuccess; -} - -bool SolverBase::lineSearchWithParabolicInterpolation( real64 const & time_n, - real64 const & dt, - integer const GEOS_UNUSED_PARAM( cycleNumber ), - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - ParallelVector & rhs, - ParallelVector & solution, - real64 const scaleFactor, - real64 & lastResidual, - real64 & residualNormT ) -{ - Timer timer( m_timers["line search"] ); - - bool lineSearchSuccess = true; - - integer const maxNumberLineSearchCuts = m_nonlinearSolverParameters.m_lineSearchMaxCuts; - - real64 const sigma1 = 0.5; - real64 const alpha = 1.e-4; - - real64 localScaleFactor = scaleFactor; - real64 lamm = scaleFactor; - real64 lamc = localScaleFactor; - integer lineSearchIteration = 0; - - real64 residualNorm0 = lastResidual; - - real64 ff0 = residualNorm0*residualNorm0; - real64 ffT = residualNormT*residualNormT; - real64 ffm = ffT; - real64 cumulativeScale = scaleFactor; - - while( residualNormT >= (1.0 - alpha*localScaleFactor)*residualNorm0 ) - { - real64 const previousLocalScaleFactor = localScaleFactor; - // Apply the three point parabolic model - if( lineSearchIteration == 0 ) - { - localScaleFactor *= sigma1; - } - else - { - localScaleFactor = interpolation::parabolicInterpolationThreePoints( lamc, lamm, ff0, ffT, ffm ); - } - - // Update x; keep the books on lambda - real64 const deltaLocalScaleFactor = ( localScaleFactor - previousLocalScaleFactor ); - cumulativeScale += deltaLocalScaleFactor; - - if( !checkSystemSolution( domain, dofManager, solution.values(), deltaLocalScaleFactor ) ) - { - GEOS_LOG_LEVEL_RANK_0( 1, " Line search " << lineSearchIteration << ", solution check failed" ); - continue; - } - - applySystemSolution( dofManager, solution.values(), deltaLocalScaleFactor, dt, domain ); - - updateState( domain ); - - lamm = lamc; - lamc = localScaleFactor; - - // Keep the books on the function norms - - // re-assemble system - // TODO: add a flag to avoid a completely useless Jacobian computation: rhs is enough - localMatrix.zero(); - rhs.zero(); - - arrayView1d< real64 > const localRhs = rhs.open(); - assembleSystem( time_n, dt, domain, dofManager, localMatrix, localRhs ); - applyBoundaryConditions( time_n, dt, domain, dofManager, localMatrix, localRhs ); - rhs.close(); - - if( getLogLevel() >= 1 && logger::internal::rank==0 ) - { - std::cout << GEOS_FMT( " Line search @ {:0.3f}: ", cumulativeScale ); - } - - // get residual norm - residualNormT = calculateResidualNorm( time_n, dt, domain, dofManager, rhs.values() ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " ( R ) = ( {:4.2e} )", residualNormT ) ); - - ffm = ffT; - ffT = residualNormT*residualNormT; - lineSearchIteration += 1; - - if( lineSearchIteration > maxNumberLineSearchCuts ) - { - lineSearchSuccess = false; - break; - } - } - - lastResidual = residualNormT; - - return lineSearchSuccess; -} - -/** - * @brief Eisenstat-Walker adaptive tolerance - * - * This method enables an inexact-Newton method is which the linear solver - * tolerance is chosen based on the nonlinear solver convergence behavior. - * In early Newton iterations, the search direction is usually imprecise, and - * therefore a weak linear convergence tolerance can be chosen to minimize - * computational cost. As the search gets closer to the true solution, however, - * more stringent linear tolerances are necessary to maintain quadratic convergence - * behavior. - * - * The user can set the weakest tolerance allowed, with a default of 1e-3. - * Even weaker values (e.g. 1e-2,1e-1) can be used for further speedup, but may - * occasionally cause convergence problems. Use this parameter with caution. The - * most stringent tolerance is hardcoded to 1e-8, which is sufficient for - * most problems. - * - * See Eisenstat, S.C. and Walker, H.F., 1996. Choosing the forcing terms in an - * inexact Newton method. SIAM Journal on Scientific Computing, 17(1), pp.16-32. - * - * @param newNewtonNorm Residual norm at current iteration - * @param oldNewtonNorm Residual norm at previous iteration - * @param weakestTol Weakest tolerance allowed (default 1e-3). - * @return Adaptive tolerance recommendation - */ -real64 SolverBase::eisenstatWalker( real64 const newNewtonNorm, - real64 const oldNewtonNorm, - real64 const weakestTol ) -{ - real64 const strongestTol = 1e-8; - real64 const exponent = 2.0; - real64 const gamma = 0.9; - - real64 normRatio = newNewtonNorm / oldNewtonNorm; - if( normRatio > 1 ) - normRatio = 1; - - real64 newKrylovTol = gamma*std::pow( normRatio, exponent ); - real64 altKrylovTol = gamma*std::pow( oldNewtonNorm, exponent ); - - real64 krylovTol = std::max( newKrylovTol, altKrylovTol ); - krylovTol = std::min( krylovTol, weakestTol ); - krylovTol = std::max( krylovTol, strongestTol ); - - return krylovTol; -} - -real64 SolverBase::nonlinearImplicitStep( real64 const & time_n, - real64 const & dt, - integer const cycleNumber, - DomainPartition & domain ) -{ - GEOS_MARK_FUNCTION; - // dt may be cut during the course of this step, so we are keeping a local - // value to track the achieved dt for this step. - real64 stepDt = dt; - - integer const maxNumberDtCuts = m_nonlinearSolverParameters.m_maxTimeStepCuts; - real64 const dtCutFactor = m_nonlinearSolverParameters.m_timeStepCutFactor; - - bool const allowNonConverged = m_nonlinearSolverParameters.m_allowNonConverged > 0; - - integer & dtAttempt = m_nonlinearSolverParameters.m_numTimeStepAttempts; - - integer const & maxConfigurationIter = m_nonlinearSolverParameters.m_maxNumConfigurationAttempts; - - integer & configurationLoopIter = m_nonlinearSolverParameters.m_numConfigurationAttempts; - - bool isConfigurationLoopConverged = false; - - // outer loop attempts to apply full timestep, and managed the cutting of the timestep if - // required. - for( dtAttempt = 0; dtAttempt < maxNumberDtCuts; ++dtAttempt ) - { - // reset the solver state, since we are restarting the time step - if( dtAttempt > 0 ) - { - resetStateToBeginningOfStep( domain ); - resetConfigurationToBeginningOfStep( domain ); - } - - // it's the simplest configuration that can be attempted whenever Newton's fails as a last resource. - bool attemptedSimplestConfiguration = false; - - // Configuration loop - for( configurationLoopIter = 0; configurationLoopIter < maxConfigurationIter; ++configurationLoopIter ) - { - - outputConfigurationStatistics( domain ); - - bool const isNewtonConverged = solveNonlinearSystem( time_n, - stepDt, - cycleNumber, - domain ); - - if( isNewtonConverged ) - { - isConfigurationLoopConverged = updateConfiguration( domain ); - - if( isConfigurationLoopConverged ) - { - break; // get out of configuration loop coz everything converged. - } - else - { - // increment the solver statistics for reporting purposes - m_solverStatistics.logOuterLoopIteration(); - - GEOS_LOG_LEVEL_RANK_0( 1, "---------- Configuration did not converge. Testing new configuration. ----------" ); - } - } - else if( !attemptedSimplestConfiguration ) - { - resetStateToBeginningOfStep( domain ); - bool const breakLoop = resetConfigurationToDefault( domain ); - attemptedSimplestConfiguration = true; - if( breakLoop ) - { - break; - } - } - else - { - break; // get out of configuration loop and cut the time-step if you can. - } - - } // end of configuration loop - - if( isConfigurationLoopConverged ) - { - // get out of outer loop - break; - } - else - { - // cut timestep, go back to beginning of step and restart the Newton loop - stepDt *= dtCutFactor; - GEOS_LOG_LEVEL_RANK_0 ( 1, GEOS_FMT( "New dt = {}", stepDt ) ); - - // notify the solver statistics counter that this is a time step cut - m_solverStatistics.logTimeStepCut(); - } - } // end of outer loop (dt chopping strategy) - - if( !isConfigurationLoopConverged ) - { - GEOS_LOG_RANK_0( "Convergence not achieved." ); - - if( allowNonConverged ) - { - GEOS_LOG_RANK_0( "The accepted solution may be inaccurate." ); - } - else - { - GEOS_ERROR( "Nonconverged solutions not allowed. Terminating..." ); - } - } - - // return the achieved timestep - return stepDt; -} - -bool SolverBase::solveNonlinearSystem( real64 const & time_n, - real64 const & stepDt, - integer const cycleNumber, - DomainPartition & domain ) -{ - integer const maxNewtonIter = m_nonlinearSolverParameters.m_maxIterNewton; - integer & dtAttempt = m_nonlinearSolverParameters.m_numTimeStepAttempts; - integer & configurationLoopIter = m_nonlinearSolverParameters.m_numConfigurationAttempts; - integer const minNewtonIter = m_nonlinearSolverParameters.m_minIterNewton; - real64 const newtonTol = m_nonlinearSolverParameters.m_newtonTol; - - // keep residual from previous iteration in case we need to do a line search - real64 lastResidual = 1e99; - integer & newtonIter = m_nonlinearSolverParameters.m_numNewtonIterations; - real64 scaleFactor = 1.0; - - bool isNewtonConverged = false; - - for( newtonIter = 0; newtonIter < maxNewtonIter; ++newtonIter ) - { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " Attempt: {:2}, ConfigurationIter: {:2}, NewtonIter: {:2}", dtAttempt, configurationLoopIter, newtonIter ) ); - - { - Timer timer( m_timers["assemble"] ); - - // zero out matrix/rhs before assembly - m_localMatrix.zero(); - m_rhs.zero(); - - arrayView1d< real64 > const localRhs = m_rhs.open(); - - // call assemble to fill the matrix and the rhs - assembleSystem( time_n, - stepDt, - domain, - m_dofManager, - m_localMatrix.toViewConstSizes(), - localRhs ); - - // apply boundary conditions to system - applyBoundaryConditions( time_n, - stepDt, - domain, - m_dofManager, - m_localMatrix.toViewConstSizes(), - localRhs ); - - m_rhs.close(); - - if( m_assemblyCallback ) - { - // Make a copy of LA objects and ship off to the callback - array1d< real64 > localRhsCopy( m_rhs.localSize() ); - localRhsCopy.setValues< parallelDevicePolicy<> >( m_rhs.values() ); - m_assemblyCallback( m_localMatrix, std::move( localRhsCopy ) ); - } - } - - real64 residualNorm = 0; - { - Timer timer( m_timers["convergence check"] ); - - // get residual norm - residualNorm = calculateResidualNorm( time_n, stepDt, domain, m_dofManager, m_rhs.values() ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " ( R ) = ( {:4.2e} )", residualNorm ) ); - } - - // if the residual norm is less than the Newton tolerance we denote that we have - // converged and break from the Newton loop immediately. - if( residualNorm < newtonTol && newtonIter >= minNewtonIter ) - { - isNewtonConverged = true; - break; - } - - // if the residual norm is above the max allowed residual norm, we break from - // the Newton loop to avoid crashes due to Newton divergence - if( residualNorm > m_nonlinearSolverParameters.m_maxAllowedResidualNorm ) - { - string const maxAllowedResidualNormString = NonlinearSolverParameters::viewKeysStruct::maxAllowedResidualNormString(); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " The residual norm is above the {} of {}. Newton loop terminated.", - maxAllowedResidualNormString, - m_nonlinearSolverParameters.m_maxAllowedResidualNorm ) ); - isNewtonConverged = false; - break; - } - - // do line search in case residual has increased - if( m_nonlinearSolverParameters.m_lineSearchAction != NonlinearSolverParameters::LineSearchAction::None - && residualNorm > lastResidual && newtonIter >= m_nonlinearSolverParameters.m_lineSearchStartingIteration ) - { - bool lineSearchSuccess = false; - if( m_nonlinearSolverParameters.m_lineSearchInterpType == NonlinearSolverParameters::LineSearchInterpolationType::Linear ) - { - residualNorm = lastResidual; - lineSearchSuccess = lineSearch( time_n, - stepDt, - cycleNumber, - domain, - m_dofManager, - m_localMatrix.toViewConstSizes(), - m_rhs, - m_solution, - scaleFactor, - residualNorm ); - } - else - { - lineSearchSuccess = lineSearchWithParabolicInterpolation( time_n, - stepDt, - cycleNumber, - domain, - m_dofManager, - m_localMatrix.toViewConstSizes(), - m_rhs, - m_solution, - scaleFactor, - lastResidual, - residualNorm ); - } - - if( !lineSearchSuccess ) - { - if( m_nonlinearSolverParameters.m_lineSearchAction == NonlinearSolverParameters::LineSearchAction::Attempt ) - { - GEOS_LOG_LEVEL_RANK_0( 1, " Line search failed to produce reduced residual. Accepting iteration." ); - } - else if( m_nonlinearSolverParameters.m_lineSearchAction == NonlinearSolverParameters::LineSearchAction::Require ) - { - // if line search failed, then break out of the main Newton loop. Timestep will be cut. - GEOS_LOG_LEVEL_RANK_0( 1, " Line search failed to produce reduced residual. Exiting Newton Loop." ); - break; - } - } - } - - // if using adaptive Krylov tolerance scheme, update tolerance. - LinearSolverParameters::Krylov & krylovParams = m_linearSolverParameters.get().krylov; - if( krylovParams.useAdaptiveTol ) - { - krylovParams.relTolerance = eisenstatWalker( residualNorm, lastResidual, krylovParams.weakestTol ); - } - - { - Timer timer( m_timers["linear solver total"] ); - - // TODO: Trilinos currently requires this, re-evaluate after moving to Tpetra-based solvers - if( m_precond ) - { - m_precond->clear(); - } - - { - Timer timer_setup( m_timers["linear solver create"] ); - - // Compose parallel LA matrix/rhs out of local LA matrix/rhs - // - m_matrix.create( m_localMatrix.toViewConst(), m_dofManager.numLocalDofs(), MPI_COMM_GEOSX ); - } - - // Output the linear system matrix/rhs for debugging purposes - debugOutputSystem( time_n, cycleNumber, newtonIter, m_matrix, m_rhs ); - - // Solve the linear system - solveLinearSystem( m_dofManager, m_matrix, m_rhs, m_solution ); - } - - // Increment the solver statistics for reporting purposes - m_solverStatistics.logNonlinearIteration( m_linearSolverResult.numIterations ); - - // Output the linear system solution for debugging purposes - debugOutputSolution( time_n, cycleNumber, newtonIter, m_solution ); - - { - Timer timer( m_timers["apply solution"] ); - - // Compute the scaling factor for the Newton update - scaleFactor = scalingForSystemSolution( domain, m_dofManager, m_solution.values() ); - - if( getLogLevel() >= 1 ) - { - GEOS_LOG_RANK_0( GEOS_FMT( " {}: Global solution scaling factor = {}", getName(), scaleFactor ) ); - } - - if( !checkSystemSolution( domain, m_dofManager, m_solution.values(), scaleFactor ) ) - { - // TODO try chopping (similar to line search) - GEOS_LOG_RANK_0( " Solution check failed. Newton loop terminated." ); - break; - } - - // apply the system solution to the fields/variables - applySystemSolution( m_dofManager, m_solution.values(), scaleFactor, stepDt, domain ); - } - - { - Timer timer( m_timers["update state"] ); - - // update non-primary variables (constitutive models) - updateState( domain ); - } - - lastResidual = residualNorm; - } - - return isNewtonConverged; -} - -real64 SolverBase::explicitStep( real64 const & GEOS_UNUSED_PARAM( time_n ), - real64 const & GEOS_UNUSED_PARAM( dt ), - integer const GEOS_UNUSED_PARAM( cycleNumber ), - DomainPartition & GEOS_UNUSED_PARAM( domain ) ) -{ - GEOS_THROW( "SolverBase::ExplicitStep called!. Should be overridden.", std::runtime_error ); - return 0; -} - -void SolverBase::implicitStepSetup( real64 const & GEOS_UNUSED_PARAM( time_n ), - real64 const & GEOS_UNUSED_PARAM( dt ), - DomainPartition & GEOS_UNUSED_PARAM( domain ) ) -{ - GEOS_THROW( "SolverBase::ImplicitStepSetup called!. Should be overridden.", std::runtime_error ); -} - -void SolverBase::setupDofs( DomainPartition const & GEOS_UNUSED_PARAM( domain ), - DofManager & GEOS_UNUSED_PARAM( dofManager ) ) const -{ - GEOS_ERROR( "SolverBase::setupDofs called!. Should be overridden." ); -} - -void SolverBase::setupSystem( DomainPartition & domain, - DofManager & dofManager, - CRSMatrix< real64, globalIndex > & localMatrix, - ParallelVector & rhs, - ParallelVector & solution, - bool const setSparsity ) -{ - GEOS_MARK_FUNCTION; - - dofManager.setDomain( domain ); - - setupDofs( domain, dofManager ); - dofManager.reorderByRank(); - - if( setSparsity ) - { - SparsityPattern< globalIndex > pattern; - dofManager.setSparsityPattern( pattern ); - localMatrix.assimilate< parallelDevicePolicy<> >( std::move( pattern ) ); - } - localMatrix.setName( this->getName() + "/matrix" ); - - rhs.setName( this->getName() + "/rhs" ); - rhs.create( dofManager.numLocalDofs(), MPI_COMM_GEOSX ); - - solution.setName( this->getName() + "/solution" ); - solution.create( dofManager.numLocalDofs(), MPI_COMM_GEOSX ); -} - -void SolverBase::assembleSystem( real64 const GEOS_UNUSED_PARAM( time ), - real64 const GEOS_UNUSED_PARAM( dt ), - DomainPartition & GEOS_UNUSED_PARAM( domain ), - DofManager const & GEOS_UNUSED_PARAM( dofManager ), - CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ), - arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) -{ - GEOS_ERROR( "SolverBase::Assemble called!. Should be overridden." ); -} - -void SolverBase::applyBoundaryConditions( real64 const GEOS_UNUSED_PARAM( time ), - real64 const GEOS_UNUSED_PARAM( dt ), - DomainPartition & GEOS_UNUSED_PARAM( domain ), - DofManager const & GEOS_UNUSED_PARAM( dofManager ), - CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ), - arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) -{ - GEOS_ERROR( "SolverBase::applyBoundaryConditions called!. Should be overridden." ); -} - -namespace -{ - -/** - * @brief Helper for debug output of linear algebra objects (matrices and vectors) - * @tparam T type of LA object (must have stream insertion and .write() implemented) - * @param obj the object to output - * @param cycleNumber event cycle number - * @param nonlinearIteration nonlinear iteration number - * @param filePrefix short filename prefix (e.g. "mat") - * @param screenName long name for screen output (e.g. "System matrix") - * @param toScreen whether to print on screen - * @param toFile whether to write to file - */ -template< typename T > -void debugOutputLAObject( T const & obj, - real64 const & GEOS_UNUSED_PARAM( time ), - integer const cycleNumber, - integer const nonlinearIteration, - string const & filePrefix, - string const & screenName, - bool const toScreen, - bool const toFile ) -{ - if( toScreen ) - { - string const frame( screenName.size() + 1, '=' ); - GEOS_LOG_RANK_0( frame << "\n" << screenName << ":\n" << frame ); - GEOS_LOG( obj ); - } - - if( toFile ) - { - string const filename = GEOS_FMT( "{}_{:06}_{:02}.mtx", filePrefix.c_str(), cycleNumber, nonlinearIteration ); - obj.write( filename, LAIOutputFormat::MATRIX_MARKET ); - GEOS_LOG_RANK_0( screenName << " written to " << filename ); - } -} - -} - -void SolverBase::debugOutputSystem( real64 const & time, - integer const cycleNumber, - integer const nonlinearIteration, - ParallelMatrix const & matrix, - ParallelVector const & rhs ) const -{ - debugOutputLAObject( matrix, - time, - cycleNumber, - nonlinearIteration, - getName() + "_mat", - "System matrix", - getLogLevel() == 2, - getLogLevel() >= 3 ); - - debugOutputLAObject( rhs, - time, - cycleNumber, - nonlinearIteration, - getName() + "_rhs", - "System right-hand side", - getLogLevel() == 2, - getLogLevel() >= 3 ); -} - -void SolverBase::debugOutputSolution( real64 const & time, - integer const cycleNumber, - integer const nonlinearIteration, - ParallelVector const & solution ) const -{ - debugOutputLAObject( solution, - time, - cycleNumber, - nonlinearIteration, - getName() + "_sol", - "System solution", - getLogLevel() == 2, - getLogLevel() >= 3 ); -} - -real64 -SolverBase::calculateResidualNorm( real64 const & GEOS_UNUSED_PARAM( time ), - real64 const & GEOS_UNUSED_PARAM( dt ), - DomainPartition const & GEOS_UNUSED_PARAM( domain ), - DofManager const & GEOS_UNUSED_PARAM( dofManager ), - arrayView1d< real64 const > const & GEOS_UNUSED_PARAM( localRhs ) ) -{ - GEOS_ERROR( "SolverBase::calculateResidualNorm called!. Should be overridden." ); - return 0; -} - -void SolverBase::solveLinearSystem( DofManager const & dofManager, - ParallelMatrix & matrix, - ParallelVector & rhs, - ParallelVector & solution ) -{ - GEOS_MARK_FUNCTION; - - rhs.scale( -1.0 ); - solution.zero(); - - LinearSolverParameters const & params = m_linearSolverParameters.get(); - matrix.setDofManager( &dofManager ); - - if( params.solverType == LinearSolverParameters::SolverType::direct || !m_precond ) - { - std::unique_ptr< LinearSolverBase< LAInterface > > solver = LAInterface::createSolver( params ); - { - Timer timer_setup( m_timers["linear solver setup"] ); - solver->setup( matrix ); - } - { - Timer timer_setup( m_timers["linear solver solve"] ); - solver->solve( rhs, solution ); - } - m_linearSolverResult = solver->result(); - } - else - { - { - Timer timer_setup( m_timers["linear solver setup"] ); - m_precond->setup( matrix ); - } - std::unique_ptr< KrylovSolver< ParallelVector > > solver = KrylovSolver< ParallelVector >::create( params, matrix, *m_precond ); - { - Timer timer_setup( m_timers["linear solver solve"] ); - solver->solve( rhs, solution ); - } - m_linearSolverResult = solver->result(); - } - - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " Last LinSolve(iter,res) = ( {:3}, {:4.2e} )", - m_linearSolverResult.numIterations, - m_linearSolverResult.residualReduction ) ); - - if( params.stopIfError ) - { - GEOS_ERROR_IF( m_linearSolverResult.breakdown(), getDataContext() << ": Linear solution breakdown -> simulation STOP" ); - } - else - { - GEOS_WARNING_IF( !m_linearSolverResult.success(), getDataContext() << ": Linear solution failed" ); - } -} - -bool SolverBase::checkSystemSolution( DomainPartition & GEOS_UNUSED_PARAM( domain ), - DofManager const & GEOS_UNUSED_PARAM( dofManager ), - arrayView1d< real64 const > const & GEOS_UNUSED_PARAM( localSolution ), - real64 const GEOS_UNUSED_PARAM( scalingFactor ) ) -{ - return true; -} - -real64 SolverBase::scalingForSystemSolution( DomainPartition & GEOS_UNUSED_PARAM( domain ), - DofManager const & GEOS_UNUSED_PARAM( dofManager ), - arrayView1d< real64 const > const & GEOS_UNUSED_PARAM( localSolution ) ) -{ - return 1.0; -} - -void SolverBase::applySystemSolution( DofManager const & GEOS_UNUSED_PARAM( dofManager ), - arrayView1d< real64 const > const & GEOS_UNUSED_PARAM( localSolution ), - real64 const GEOS_UNUSED_PARAM( scalingFactor ), - real64 const GEOS_UNUSED_PARAM( dt ), - DomainPartition & GEOS_UNUSED_PARAM( domain ) ) -{ - GEOS_ERROR( "SolverBase::applySystemSolution called!. Should be overridden." ); -} - -void SolverBase::updateState( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) -{ - GEOS_ERROR( "SolverBase::updateState called!. Should be overridden." ); -} - -bool SolverBase::updateConfiguration( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) -{ - return true; -} - -void SolverBase::outputConfigurationStatistics( DomainPartition const & GEOS_UNUSED_PARAM( domain ) ) const -{ - // For most solvers there is nothing to do. -} - -void SolverBase::resetConfigurationToBeginningOfStep( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) -{ - // For most solvers there is nothing to do. -} - -void SolverBase::resetStateToBeginningOfStep( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) -{ - GEOS_ERROR( "SolverBase::ResetStateToBeginningOfStep called!. Should be overridden." ); -} - -bool SolverBase::resetConfigurationToDefault( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) const -{ - // for most solvers it just breaks the loop. - return true; -} - -void SolverBase::implicitStepComplete( real64 const & GEOS_UNUSED_PARAM( time ), - real64 const & GEOS_UNUSED_PARAM( dt ), - DomainPartition & GEOS_UNUSED_PARAM( domain ) ) -{ - GEOS_ERROR( "SolverBase::ImplicitStepComplete called!. Should be overridden." ); -} - -void SolverBase::cleanup( real64 const GEOS_UNUSED_PARAM( time_n ), - integer const GEOS_UNUSED_PARAM( cycleNumber ), - integer const GEOS_UNUSED_PARAM( eventCounter ), - real64 const GEOS_UNUSED_PARAM( eventProgress ), - DomainPartition & GEOS_UNUSED_PARAM( domain ) ) -{ - m_solverStatistics.outputStatistics(); - - if( getLogLevel() > 0 ) - { - for( auto & timer : m_timers ) - { - real64 const time = std::chrono::duration< double >( timer.second ).count(); - real64 const minTime = MpiWrapper::min( time ); - real64 const maxTime = MpiWrapper::max( time ); - if( maxTime > 0 ) - { - GEOS_LOG_RANK_0( GEOS_FMT( "{}: {} time = {} s (min), {} s (max)", getName(), timer.first, minTime, maxTime ) ); - } - } - } -} - -Timestamp SolverBase::getMeshModificationTimestamp( DomainPartition & domain ) const -{ - Timestamp meshModificationTimestamp = 0; - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & ) - { - if( meshModificationTimestamp < mesh.getModificationTimestamp() ) - { - meshModificationTimestamp = mesh.getModificationTimestamp(); - } - } ); - return meshModificationTimestamp; -} - -R1Tensor const SolverBase::gravityVector() const -{ - R1Tensor rval; - if( dynamicCast< PhysicsSolverManager const * >( &getParent() ) != nullptr ) - { - rval = getParent().getReference< R1Tensor >( PhysicsSolverManager::viewKeyStruct::gravityVectorString() ); - } - else - { - rval = {0.0, 0.0, -9.81}; - } - return rval; -} - -bool SolverBase::checkSequentialSolutionIncrements( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) const -{ - // default behavior - assume converged - return true; -} - -void SolverBase::saveSequentialIterationState( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) const -{ - // up to specific solver to save what is needed - GEOS_ERROR( "Call to SolverBase::saveSequentialIterationState. Method should be overloaded by the solver" ); -} - -#if defined(GEOSX_USE_PYGEOSX) -PyTypeObject * SolverBase::getPythonType() const -{ return python::getPySolverType(); } -#endif - -} // namespace geos diff --git a/src/coreComponents/physicsSolvers/SolverBase.hpp b/src/coreComponents/physicsSolvers/SolverBase.hpp deleted file mode 100644 index b3390f828e6..00000000000 --- a/src/coreComponents/physicsSolvers/SolverBase.hpp +++ /dev/null @@ -1,895 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -#ifndef GEOS_PHYSICSSOLVERS_SOLVERBASE_HPP_ -#define GEOS_PHYSICSSOLVERS_SOLVERBASE_HPP_ - -#include "codingUtilities/traits.hpp" -#include "common/DataTypes.hpp" -#include "dataRepository/ExecutableGroup.hpp" -#include "linearAlgebra/interfaces/InterfaceTypes.hpp" -#include "linearAlgebra/utilities/LinearSolverResult.hpp" -#include "linearAlgebra/DofManager.hpp" -#include "mesh/DomainPartition.hpp" -#include "mesh/MeshBody.hpp" -#include "physicsSolvers/NonlinearSolverParameters.hpp" -#include "physicsSolvers/LinearSolverParameters.hpp" -#include "physicsSolvers/SolverStatistics.hpp" - - -#include - -namespace geos -{ - -class DomainPartition; - -class SolverBase : public ExecutableGroup -{ -public: - - explicit SolverBase( string const & name, - Group * const parent ); - - SolverBase( SolverBase && ) = default; - - virtual ~SolverBase() override; - - SolverBase() = delete; - SolverBase( SolverBase const & ) = delete; - SolverBase & operator=( SolverBase const & ) = delete; - SolverBase & operator=( SolverBase && ) = delete; - - static string catalogName() { return "SolverBase"; } - - /** - * @return Get the final class Catalog name - */ - virtual string getCatalogName() const = 0; - - - virtual void registerDataOnMesh( Group & MeshBodies ) override; - - virtual void initialize_postMeshGeneration() override; - - void generateMeshTargetsFromTargetRegions( Group const & meshBodies ); - - virtual void cleanup( real64 const time_n, - integer const cycleNumber, - integer const eventCounter, - real64 const eventProgress, - DomainPartition & domain ) override; - - /** - * This method is called when its host event is triggered - */ - virtual bool execute( real64 const time_n, - real64 const dt, - integer const cycleNumber, - integer const eventCounter, - real64 const eventProgress, - DomainPartition & domain ) override; - - /** - * @brief Getter for system matrix - * @return a reference to linear system matrix of this solver - */ - ParallelMatrix & getSystemMatrix() { return m_matrix; } - ParallelMatrix const & getSystemMatrix() const { return m_matrix; } - - /** - * @brief Getter for system rhs vector - * @return a reference to linear system right-hand side of this solver - */ - ParallelVector & getSystemRhs() { return m_rhs; } - ParallelVector const & getSystemRhs() const { return m_rhs; } - - /** - * @brief Getter for system solution vector - * @return a reference to solution vector of this solver - */ - ParallelVector & getSystemSolution() { return m_solution; } - ParallelVector const & getSystemSolution() const { return m_solution; } - - /** - * @brief Getter for degree-of-freedom manager - * @return a reference to degree-of-freedom manager of this solver - */ - DofManager & getDofManager() { return m_dofManager; } - DofManager const & getDofManager() const { return m_dofManager; } - - /** - * @brief Getter for local matrix - * @return a reference to linear system matrix of this solver - */ - CRSMatrix< real64, globalIndex > & getLocalMatrix() { return m_localMatrix; } - CRSMatrixView< real64 const, globalIndex const > getLocalMatrix() const { return m_localMatrix.toViewConst(); } - - /** - * @defgroup Solver Interface Functions - * - * These functions provide the primary interface that is required for derived classes - */ - /**@{*/ - - /** - * @brief entry function to perform a solver step - * @param time_n time at the beginning of the step - * @param dt the perscribed timestep - * @param cycleNumber the current cycle number - * @param domain the domain object - * @return return the timestep that was achieved during the step. - * - * This function is the entry point to perform a solver step. The choice of time integration - * method is determined in this function, and the appropriate step function is called. - */ - virtual real64 solverStep( real64 const & time_n, - real64 const & dt, - integer const cycleNumber, - DomainPartition & domain ); - - /** - * @brief function to set the next time step size - * @param[in] currentDt the current time step size - * @param[in] domain the domain object - * @return the prescribed time step size - */ - virtual real64 setNextDt( real64 const & currentDt, - DomainPartition & domain ); - - /** - * @brief function to set the next time step size based on Newton convergence - * @param[in] currentDt the current time step size - * @return the prescribed time step size - */ - virtual real64 setNextDtBasedOnNewtonIter( real64 const & currentDt ); - - /** - * @brief function to set the next dt based on state change - * @param [in] currentDt the current time step size - * @param[in] domain the domain object - * @return the prescribed time step size - */ - virtual real64 setNextDtBasedOnStateChange( real64 const & currentDt, - DomainPartition & domain ); - - /** - * @brief function to set the next dt based on state change - * @param [in] currentDt the current time step size - * @param[in] domain the domain object - * @return the prescribed time step size - */ - virtual real64 setNextDtBasedOnCFL( real64 const & currentDt, - DomainPartition & domain ); - - - - /** - * @brief Entry function for an explicit time integration step - * @param time_n time at the beginning of the step - * @param dt the perscribed timestep - * @param cycleNumber the current cycle number - * @param domain the domain object - * @return return the timestep that was achieved during the step. - */ - virtual real64 explicitStep( real64 const & time_n, - real64 const & dt, - integer const cycleNumber, - DomainPartition & domain ); - - /** - * @brief Function for a nonlinear implicit integration step - * @param time_n time at the beginning of the step - * @param dt the perscribed timestep - * @param cycleNumber the current cycle number - * @param domain the domain object - * @return return the timestep that was achieved during the step. - * - * This function implements a nonlinear newton method for implicit problems. It requires that the - * other functions in the solver interface are implemented in the derived physics solver. The - * nonlinear loop includes a simple line search algorithm, and will cut the timestep if - * convergence is not achieved according to the parameters in linearSolverParameters member. - */ - virtual real64 nonlinearImplicitStep( real64 const & time_n, - real64 const & dt, - integer const cycleNumber, - DomainPartition & domain ); - - /** - * @brief Function to perform line search - * @param time_n time at the beginning of the step - * @param dt the perscribed timestep - * @param cycleNumber the current cycle number - * @param domain the domain object - * @param dofManager degree-of-freedom manager associated with the linear system - * @param localMatrix the system matrix - * @param rhs the system right-hand side vector - * @param solution the solution vector - * @param lastResidual (in) target value below which to reduce residual norm, (out) achieved residual norm - * @return return true if line search succeeded, false otherwise - * - * This function implements a nonlinear newton method for implicit problems. It requires that the - * other functions in the solver interface are implemented in the derived physics solver. The - * nonlinear loop includes a simple line search algorithm, and will cut the timestep if - * convergence is not achieved according to the parameters in linearSolverParameters member. - */ - virtual bool - lineSearch( real64 const & time_n, - real64 const & dt, - integer const cycleNumber, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - ParallelVector & rhs, - ParallelVector & solution, - real64 const scaleFactor, - real64 & lastResidual ); - - /** - * @brief Function to perform line search using a parabolic interpolation to find the scaling factor. - * @param time_n time at the beginning of the step - * @param dt the perscribed timestep - * @param cycleNumber the current cycle number - * @param domain the domain object - * @param dofManager degree-of-freedom manager associated with the linear system - * @param localMatrix the system matrix - * @param rhs the system right-hand side vector - * @param solution the solution vector - * @param lastResidual (in) target value below which to reduce residual norm, (out) achieved residual norm - * @return return true if line search succeeded, false otherwise - * - */ - virtual bool - lineSearchWithParabolicInterpolation ( real64 const & time_n, - real64 const & dt, - integer const cycleNumber, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - ParallelVector & rhs, - ParallelVector & solution, - real64 const scaleFactor, - real64 & lastResidual, - real64 & residualNormT ); - - /** - * @brief Function for a linear implicit integration step - * @param time_n time at the beginning of the step - * @param dt the perscribed timestep - * @param cycleNumber the current cycle number - * @param domain the domain object - * @return return the timestep that was achieved during the step. - * - * This function implements a single linear step. Similar to the nonlinear step, however it - * assumes that the solution is achieved in a iteration. The use of this function requires that - * the other functions in the solver interface are implemented in the derived physics solver. The - * nonlinear loop includes a simple line search algorithm, and will cut the timestep if - * convergence is not achieved according to the parameters in linearSolverParameters member. - */ - virtual real64 linearImplicitStep( real64 const & time_n, - real64 const & dt, - integer const cycleNumber, - DomainPartition & domain ); - - /** - * @brief function to perform setup for implicit timestep - * @param time_n the time at the beginning of the step - * @param dt the desired timestep - * @param domain the domain partition - * - * This function should contain any step level initialization required to perform an implicit - * step. - * - * @note This function must be overridden in the derived physics solver in order to use an implict - * solution method such as LinearImplicitStep() or NonlinearImplicitStep(). - */ - virtual void - implicitStepSetup( real64 const & time_n, - real64 const & dt, - DomainPartition & domain ); - - /** - * @brief Populate degree-of-freedom manager with fields relevant to this solver - * @param dofManager degree-of-freedom manager associated with the linear system - */ - virtual void - setupDofs( DomainPartition const & domain, - DofManager & dofManager ) const; - - /** - * @brief Set up the linear system (DOF indices and sparsity patterns) - * @param domain the domain containing the mesh and fields - * @param dofManager degree-of-freedom manager associated with the linear system - * @param localMatrix the system matrix - * @param rhs the system right-hand side vector - * @param solution the solution vector - * - * @note While the function is virtual, the base class implementation should be - * sufficient for most single-physics solvers. - */ - virtual void - setupSystem( DomainPartition & domain, - DofManager & dofManager, - CRSMatrix< real64, globalIndex > & localMatrix, - ParallelVector & rhs, - ParallelVector & solution, - bool const setSparsity = true ); - - /** - * @brief function to assemble the linear system matrix and rhs - * @param time the time at the beginning of the step - * @param dt the desired timestep - * @param domain the domain partition - * @param dofManager degree-of-freedom manager associated with the linear system - * @param localMatrix the system matrix - * @param rhs the system right-hand side vector - * @return the residual for convergence evaluation - * - * This function assembles the residual and the jacobian of the residual wrt the primary - * variables. In a stand alone physics solver, this function will fill a single block in the - * block system. However the capability to query the block system structure for any coupled blocks - * may be implemented to fill in off diagonal blocks of the system to enable coupling between - * solvers. - * - * @note This function must be overridden in the derived physics solver in order to use an implict - * solution method such as LinearImplicitStep() or NonlinearImplicitStep(). - */ - virtual void - assembleSystem( real64 const time, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ); - - /** - * @brief apply boundary condition to system - * @param time the time at the beginning of the step - * @param dt the desired timestep - * @param domain the domain partition - * @param dofManager degree-of-freedom manager associated with the linear system - * @param localMatrix the system matrix - * @param rhs the system right-hand side vector - * - * This function applies all boundary conditions to the linear system. This is essentially a - * completion of the system assembly, but is separated for use in coupled solvers. - */ - virtual void - applyBoundaryConditions( real64 const time, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ); - - /** - * @brief Output the assembled linear system for debug purposes. - * @param time beginning-of-step time - * @param cycleNumber event cycle number - * @param nonlinearIteration current nonlinear iteration number - * @param matrix system matrix - * @param rhs system right-hand side vector - */ - void - debugOutputSystem( real64 const & time, - integer const cycleNumber, - integer const nonlinearIteration, - ParallelMatrix const & matrix, - ParallelVector const & rhs ) const; - - /** - * @brief Output the linear system solution for debug purposes. - * @param time beginning-of-step time - * @param cycleNumber event cycle number - * @param nonlinearIteration current nonlinear iteration number - * @param solution system solution vector - */ - void - debugOutputSolution( real64 const & time, - integer const cycleNumber, - integer const nonlinearIteration, - ParallelVector const & solution ) const; - - /** - * @brief calculate the norm of the global system residual - * @param time the time at the beginning of the step - * @param dt the desired timestep - * @param domain the domain partition - * @param dofManager degree-of-freedom manager associated with the linear system - * @param localRhs the system right-hand side vector - * @return norm of the residual - * - * This function returns the norm of global residual vector, which is suitable for comparison with - * a tolerance. - */ - virtual real64 - calculateResidualNorm( real64 const & time, - real64 const & dt, - DomainPartition const & domain, - DofManager const & dofManager, - arrayView1d< real64 const > const & localRhs ); - - /** - * @brief function to apply a linear system solver to the assembled system. - * @param dofManager degree-of-freedom manager associated with the linear system - * @param matrix the system matrix - * @param rhs the system right-hand side vector - * @param solution the solution vector - * - * This function calls the linear solver package to perform a single linear solve on the block - * system. The derived physics solver is required to specify the call, as no default is provided. - * - * @note This function must be overridden in the derived physics solver in order to use an implict - * solution method such as LinearImplicitStep() or NonlinearImplicitStep(). - */ - virtual void - solveLinearSystem( DofManager const & dofManager, - ParallelMatrix & matrix, - ParallelVector & rhs, - ParallelVector & solution ); - - /** - * @brief Function to check system solution for physical consistency and constraint violation - * @param matrix the system matrix - * @param rhs the system right-hand side vector - * @param solution the solution vector - * @param dofManager degree-of-freedom manager associated with the linear system - * @param scalingFactor factor to scale the solution prior to application - * @param objectManager the object manager that holds the fields we wish to apply the solution to - * @return true if solution can be safely applied without violating physical constraints, false otherwise - * - * @note This function must be overridden in the derived physics solver in order to use an implict - * solution method such as LinearImplicitStep() or NonlinearImplicitStep(). - * - */ - virtual bool - checkSystemSolution( DomainPartition & domain, - DofManager const & dofManager, - arrayView1d< real64 const > const & localSolution, - real64 const scalingFactor ); - - /** - * @brief Function to determine if the solution vector should be scaled back in order to maintain a known constraint. - * @param[in] domain The domain partition. - * @param[in] dofManager degree-of-freedom manager associated with the linear system - * @param[in] solution the solution vector - * @return The factor that should be used to scale the solution vector values when they are being applied. - */ - virtual real64 - scalingForSystemSolution( DomainPartition & domain, - DofManager const & dofManager, - arrayView1d< real64 const > const & localSolution ); - - /** - * @brief Function to apply the solution vector to the state - * @param matrix the system matrix - * @param rhs the system right-hand side vector - * @param solution the solution vector - * @param dofManager degree-of-freedom manager associated with the linear system - * @param scalingFactor factor to scale the solution prior to application - * @param objectManager the object manager that holds the fields we wish to apply the solution to - * - * This function performs 2 operations: - * 1) extract the solution vector for the "blockSystem" parameter, and applies the - * contents of the solution vector to the primary variable field data, - * 2) perform a synchronization of the primary field variable such that all ghosts are updated, - * - * The "scalingFactor" parameter allows for the scaled application of the solution vector. For - * instance, a line search may apply a negative scaling factor to remove part of the previously - * applied solution. - * - * @note This function must be overridden in the derived physics solver in order to use an implict - * solution method such as LinearImplicitStep() or NonlinearImplicitStep(). - * - */ - virtual void - applySystemSolution( DofManager const & dofManager, - arrayView1d< real64 const > const & localSolution, - real64 const scalingFactor, - real64 const dt, - DomainPartition & domain ); - - /** - * @brief updates the configuration (if needed) based on the state after a converged Newton loop. - * @param domain the domain containing the mesh and fields - * @return a bool that states whether the configuration used to solve the nonlinear loop is still valid or not. - */ - virtual bool updateConfiguration( DomainPartition & domain ); - - /** - * @brief - * @param domain the domain containing the mesh and fields - */ - virtual void outputConfigurationStatistics( DomainPartition const & domain ) const; - - /** - * @brief resets the configuration to the beginning of the time-step. - * @param domain the domain containing the mesh and fields - */ - virtual void resetConfigurationToBeginningOfStep( DomainPartition & domain ); - - /** - * @brief set the simplest configuration state. - * @param domain the domain containing the mesh and fields - */ - virtual bool resetConfigurationToDefault( DomainPartition & domain ) const; - - - /** - * @brief Recompute all dependent quantities from primary variables (including constitutive models) - * @param domain the domain containing the mesh and fields - */ - virtual void updateState( DomainPartition & domain ); - - /** - * @brief reset state of physics back to the beginning of the step. - * @param domain - * - * This function essentially abandons the step, and resets all variables back to thier values at - * the beginning of the step. This is useful for cases where convergence was not achieved, and - * a cut in timestep was required. - * - * @note This function must be overridden in the derived physics solver in order to use an implict - * solution method such as LinearImplicitStep() or NonlinearImplicitStep(). - */ - virtual void - resetStateToBeginningOfStep( DomainPartition & domain ); - - /** - * @brief perform cleanup for implicit timestep - * @param time_n the time at the beginning of the step - * @param dt the desired timestep - * @param domain the domain partition - * - * This function performs whatever tasks are required to complete an implicit timestep. For - * example, the acceptance of the solution will occur during this step, and deallocation of - * temporaries will be be performed in this function. - * - * @note This function must be overridden in the derived physics solver in order to use an implict - * solution method such as LinearImplicitStep() or NonlinearImplicitStep(). - */ - virtual void - implicitStepComplete( real64 const & time, - real64 const & dt, - DomainPartition & domain ); - - - /* - * Returns the requirement for the next time-step to the event executing the solver. - */ - virtual real64 getTimestepRequest( real64 const GEOS_UNUSED_PARAM( time ) ) override - {return m_nextDt;}; - /**@}*/ - - real64 getTimestepRequest() - {return m_nextDt;}; - - virtual Group * createChild( string const & childKey, string const & childName ) override; - - using CatalogInterface = dataRepository::CatalogInterface< SolverBase, string const &, Group * const >; - static CatalogInterface::CatalogType & getCatalog(); - - struct viewKeyStruct - { - static constexpr char const * cflFactorString() { return "cflFactor"; } - static constexpr char const * initialDtString() { return "initialDt"; } - static constexpr char const * maxStableDtString() { return "maxStableDt"; } - static constexpr char const * discretizationString() { return "discretization"; } - static constexpr char const * targetRegionsString() { return "targetRegions"; } - static constexpr char const * meshTargetsString() { return "meshTargets"; } - - }; - - struct groupKeyStruct - { - static constexpr char const * linearSolverParametersString() { return "LinearSolverParameters"; } - static constexpr char const * nonlinearSolverParametersString() { return "NonlinearSolverParameters"; } - static constexpr char const * solverStatisticsString() { return "SolverStatistics"; } - }; - - /** - * @brief getter for the timestamp of the system setup - * @return the timestamp of the last time systemSetup was called - */ - Timestamp getSystemSetupTimestamp() const { return m_systemSetupTimestamp; } - - /** - * @brief getter for the timestamp of the mesh modification on the mesh levels - * @param[in] domain the domain partition (cannot be const because we use forDiscretizationsInMeshTargets inside the function) - * @return the timestamp of the last time at which one of the mesh levels was modified - */ - Timestamp getMeshModificationTimestamp( DomainPartition & domain ) const; - - /** - * @brief set the timestamp of the system setup - * @param[in] timestamp the new timestamp of system setup - */ - void setSystemSetupTimestamp( Timestamp timestamp ) { m_systemSetupTimestamp = timestamp; } - - /** - * @brief return the value of the gravity vector specified in PhysicsSolverManager - * @return the value of the gravity vector - * - * @note if the solver is instantiated outside of a simulation (for instance for a unit test) - * and therefore does not have a parent of type PhysicsSolverManager, this function returns - * {0.0,0.0,-9.81} - */ - R1Tensor const gravityVector() const; - - virtual bool checkSequentialSolutionIncrements( DomainPartition & domain ) const; - - virtual void saveSequentialIterationState( DomainPartition & domain ) const; - - /** - * @brief accessor for the linear solver parameters. - * @return the linear solver parameter list - */ - LinearSolverParameters & getLinearSolverParameters() - { - return m_linearSolverParameters.get(); - } - - /** - * @brief const accessor for the linear solver parameters. - * @return the linear solver parameter list - */ - LinearSolverParameters const & getLinearSolverParameters() const - { - return m_linearSolverParameters.get(); - } - - /** - * @brief accessor for the nonlinear solver parameters. - * @return the nonlinear solver parameter list - */ - NonlinearSolverParameters & getNonlinearSolverParameters() - { - return m_nonlinearSolverParameters; - } - - /** - * @brief const accessor for the nonlinear solver parameters. - * @return the nonlinear solver parameter list - */ - NonlinearSolverParameters const & getNonlinearSolverParameters() const - { - return m_nonlinearSolverParameters; - } - - /** - * @brief Get position of a given region within solver's target region list - * @param regionName the region name to find - * @return index within target regions list - */ - localIndex targetRegionIndex( string const & regionName ) const; - - - - /** - * @brief Loop over the target discretization on all mesh targets and apply callback. - * @tparam LAMBDA The callback function type - * @param meshBodies The group of MeshBodies - * @param lambda The callback function. Takes the name of the meshBody, - * reference to the MeshLevel, and a list of regionNames. - */ - template< typename LAMBDA > - void forDiscretizationOnMeshTargets( Group const & meshBodies, LAMBDA && lambda ) const - { - for( auto const & target: m_meshTargets ) - { - string const meshBodyName = target.first.first; - string const meshLevelName = target.first.second; - arrayView1d< string const > const & regionNames = target.second.toViewConst(); - MeshBody const & meshBody = meshBodies.getGroup< MeshBody >( meshBodyName ); - - MeshLevel const * meshLevelPtr = meshBody.getMeshLevels().getGroupPointer< MeshLevel >( meshLevelName ); - if( meshLevelPtr==nullptr ) - { - meshLevelPtr = meshBody.getMeshLevels().getGroupPointer< MeshLevel >( MeshBody::groupStructKeys::baseDiscretizationString() ); - } - lambda( meshBodyName, *meshLevelPtr, regionNames ); - } - } - - /** - * @brief Loop over the target discretization on all mesh targets and apply callback. - * @tparam LAMBDA The callback function type - * @param meshBodies The group of MeshBodies - * @param lambda The callback function. Takes the name of the meshBody, - * reference to the MeshLevel, and a list of regionNames. - */ - template< typename LAMBDA > - void forDiscretizationOnMeshTargets( Group & meshBodies, LAMBDA && lambda ) const - { - for( auto const & target: m_meshTargets ) - { - string const meshBodyName = target.first.first; - string const meshLevelName = target.first.second; - arrayView1d< string const > const & regionNames = target.second.toViewConst(); - MeshBody & meshBody = meshBodies.getGroup< MeshBody >( meshBodyName ); - - MeshLevel * meshLevelPtr = meshBody.getMeshLevels().getGroupPointer< MeshLevel >( meshLevelName ); - if( meshLevelPtr==nullptr ) - { - meshLevelPtr = meshBody.getMeshLevels().getGroupPointer< MeshLevel >( MeshBody::groupStructKeys::baseDiscretizationString() ); - } - lambda( meshBodyName, *meshLevelPtr, regionNames ); - } - } - - - string getDiscretizationName() const {return m_discretizationName;} - - virtual bool registerCallback( void * func, const std::type_info & funcType ) final override; - - SolverStatistics & getSolverStatistics() { return m_solverStatistics; } - - /** - * @brief Return PySolver type. - * @return Return PySolver type. - */ -#if defined(GEOSX_USE_PYGEOSX) - virtual PyTypeObject * getPythonType() const override; -#endif - - map< std::pair< string, string >, array1d< string > > const & getMeshTargets() const - { - return m_meshTargets; - } -protected: - - static real64 eisenstatWalker( real64 const newNewtonNorm, - real64 const oldNewtonNorm, - real64 const weakestTol ); - - /** - * @brief Get the Constitutive Name object - * - * @tparam CONSTITUTIVE_BASE_TYPE the base type of the constitutive model. - * @param subregion the element subregion on which the constitutive model is registered - * @return the name name of the constitutive model of type @p CONSTITUTIVE_BASE_TYPE registered on the @p subregion. - */ - template< typename CONSTITUTIVE_BASE_TYPE > - static string getConstitutiveName( ElementSubRegionBase const & subRegion ); - - template< typename CONSTITUTIVE_BASE_TYPE > - static string getConstitutiveName( ParticleSubRegionBase const & subRegion ); // particle overload - - /** - * @brief This function sets constitutive name fields on an - * ElementSubRegionBase, and calls the base function it overrides. - * @param subRegion The ElementSubRegionBase that will have constitutive - * names set. - */ - virtual void setConstitutiveNamesCallSuper( ElementSubRegionBase & subRegion ) const { GEOS_UNUSED_VAR( subRegion ); } - virtual void setConstitutiveNamesCallSuper( ParticleSubRegionBase & subRegion ) const { GEOS_UNUSED_VAR( subRegion ); } // particle - // overload - - template< typename BASETYPE = constitutive::ConstitutiveBase, typename LOOKUP_TYPE > - static BASETYPE const & getConstitutiveModel( dataRepository::Group const & dataGroup, LOOKUP_TYPE const & key ); - - template< typename BASETYPE = constitutive::ConstitutiveBase, typename LOOKUP_TYPE > - static BASETYPE & getConstitutiveModel( dataRepository::Group & dataGroup, LOOKUP_TYPE const & key ); - - real64 m_cflFactor; - real64 m_maxStableDt; - real64 m_nextDt; - - /// name of the FV discretization object in the data repository - string m_discretizationName; - - /// Data structure to handle degrees of freedom - DofManager m_dofManager; - - /// System matrix, rhs and solution - ParallelMatrix m_matrix; - ParallelVector m_rhs; - ParallelVector m_solution; - - /// Local system matrix and rhs - CRSMatrix< real64, globalIndex > m_localMatrix; - - /// Custom preconditioner for the "native" iterative solver - std::unique_ptr< PreconditionerBase< LAInterface > > m_precond; - - /// Linear solver parameters - LinearSolverParametersInput m_linearSolverParameters; - - /// Result of the last linear solve - LinearSolverResult m_linearSolverResult; - - /// Nonlinear solver parameters - NonlinearSolverParameters m_nonlinearSolverParameters; - - /// Solver statistics - SolverStatistics m_solverStatistics; - - /// Timestamp of the last call to setup system - Timestamp m_systemSetupTimestamp; - - std::function< void( CRSMatrix< real64, globalIndex >, array1d< real64 > ) > m_assemblyCallback; - - std::map< std::string, std::chrono::system_clock::duration > m_timers; - -private: - /// List of names of regions the solver will be applied to - array1d< string > m_targetRegionNames; - - /// Map containing the array of target regions (value) for each MeshBody (key). - map< std::pair< string, string >, array1d< string > > m_meshTargets; - - /** - * @brief This function sets constitutive name fields on an - * ElementSubRegionBase, and DOES NOT call the base function it overrides. - * @param subRegion The ElementSubRegionBase that will have constitutive - * names set. - */ - virtual void setConstitutiveNames( ElementSubRegionBase & subRegion ) const { GEOS_UNUSED_VAR( subRegion ); } - virtual void setConstitutiveNames( ParticleSubRegionBase & subRegion ) const { GEOS_UNUSED_VAR( subRegion ); } // particle overload - - bool solveNonlinearSystem( real64 const & time_n, - real64 const & dt, - integer const cycleNumber, - DomainPartition & domain ); - -}; - -template< typename CONSTITUTIVE_BASE_TYPE > -string SolverBase::getConstitutiveName( ElementSubRegionBase const & subRegion ) -{ - string validName; - dataRepository::Group const & constitutiveModels = subRegion.getConstitutiveModels(); - - constitutiveModels.forSubGroups< CONSTITUTIVE_BASE_TYPE >( [&]( dataRepository::Group const & model ) - { - GEOS_ERROR_IF( !validName.empty(), "A valid constitutive model was already found." ); - validName = model.getName(); - } ); - return validName; -} - -template< typename CONSTITUTIVE_BASE_TYPE > -string SolverBase::getConstitutiveName( ParticleSubRegionBase const & subRegion ) // particle overload -{ - string validName; - dataRepository::Group const & constitutiveModels = subRegion.getConstitutiveModels(); - - constitutiveModels.forSubGroups< CONSTITUTIVE_BASE_TYPE >( [&]( dataRepository::Group const & model ) - { - GEOS_ERROR_IF( !validName.empty(), "A valid constitutive model was already found." ); - validName = model.getName(); - } ); - return validName; -} - -template< typename BASETYPE, typename LOOKUP_TYPE > -BASETYPE const & SolverBase::getConstitutiveModel( dataRepository::Group const & dataGroup, LOOKUP_TYPE const & key ) -{ - dataRepository::Group const & constitutiveModels = dataGroup.getGroup( ElementSubRegionBase::groupKeyStruct::constitutiveModelsString() ); - - return constitutiveModels.getGroup< BASETYPE >( key ); -} - -template< typename BASETYPE, typename LOOKUP_TYPE > -BASETYPE & SolverBase::getConstitutiveModel( dataRepository::Group & dataGroup, LOOKUP_TYPE const & key ) -{ - Group & constitutiveModels = dataGroup.getGroup( ElementSubRegionBase::groupKeyStruct::constitutiveModelsString() ); - - return constitutiveModels.getGroup< BASETYPE >( key ); -} - -} // namespace geos - - -#endif /* GEOS_PHYSICSSOLVERS_SOLVERBASE_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/SolverBaseKernels.hpp b/src/coreComponents/physicsSolvers/SolverBaseKernels.hpp deleted file mode 100644 index 6e635ca3ed7..00000000000 --- a/src/coreComponents/physicsSolvers/SolverBaseKernels.hpp +++ /dev/null @@ -1,348 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file SolverBaseKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_SOLVERBASEKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_SOLVERBASEKERNELS_HPP - -#include "codingUtilities/EnumStrings.hpp" -#include "common/DataTypes.hpp" -#include "common/MpiWrapper.hpp" - -namespace geos -{ - -namespace solverBaseKernels -{ - -/******************************** ResidualNormKernelBase ********************************/ - -/** - * @tparam NUM_NORM number of norms to compute (NUM_NORM is related to the number of equations to solve) - * For instance, NUM_NORM=1 for isothermal simulations and NUM_NORM=2 for thermal simulations - * @brief Define the base interface for the residual calculations - */ -template< integer NUM_NORM > -class ResidualNormKernelBase -{ -public: - - - /// Compile time value for the number of norms to compute - static constexpr integer numNorm = NUM_NORM; - - ResidualNormKernelBase( globalIndex const rankOffset, - arrayView1d< real64 const > const & localResidual, - arrayView1d< globalIndex const > const & dofNumber, - arrayView1d< localIndex const > const & ghostRank, - real64 const minNormalizer ): - m_rankOffset( rankOffset ), - m_localResidual( localResidual ), - m_dofNumber( dofNumber ), - m_ghostRank( ghostRank ), - m_minNormalizer( minNormalizer ) - {} - - /** - * @struct LinfStackVariables - * @brief Kernel variables located on the stack for Linf norm - */ - struct LinfStackVariables - { - /// Index of the local row in the residual vector - localIndex localRow; - - /// Normalized residual value for the element/node/face - real64 localValue[numNorm]{}; - }; - - /** - * @struct L2StackVariables - * @brief Kernel variables located on the stack for L2 norm - */ - struct L2StackVariables : public LinfStackVariables - { - /// Normalizer value for the element/node/face - real64 localNormalizer[numNorm]{}; - }; - - - /** - * @brief Getter for the ghost rank - * @param[in] i the looping index of the element/node/face - * @return the ghost rank of the element/node/face - */ - GEOS_HOST_DEVICE - integer ghostRank( localIndex const i ) const - { return m_ghostRank( i ); } - - /** - * @brief Setup the residual Linf normal calculations - * @param[in] i the element/node/face index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - virtual void setupLinf( localIndex const i, - LinfStackVariables & stack ) const - { - stack.localRow = m_dofNumber[i] - m_rankOffset; - } - - /** - * @brief Setup the residual L2 normal calculations - * @param[in] i the element/node/face index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - virtual void setupL2( localIndex const i, - L2StackVariables & stack ) const - { - stack.localRow = m_dofNumber[i] - m_rankOffset; - } - - - /** - * @brief Compute the local values for the Linf norm - * @param[in] i the element/node/face index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - virtual void computeLinf( localIndex const i, - LinfStackVariables & stack ) const = 0; - - /** - * @brief Compute the local values and normalizer for the L2 norm - * @param[in] i the element/node/face index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - virtual void computeL2( localIndex const i, - L2StackVariables & stack ) const = 0; - - /** - * @brief Performs the kernel launch for the L-\infty norm - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] size the number of elements/nodes/faces - * @param[inout] kernelComponent the kernel component providing access to the compute function - * @param[inout] residualNorms the norms to compute - */ - template< typename POLICY, typename KERNEL_TYPE > - static void - launchLinf( localIndex const size, - KERNEL_TYPE const & kernelComponent, - real64 (& residualNorm)[numNorm] ) - { - RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > localResidualNorm[numNorm]{}; - - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const i ) - { - if( kernelComponent.ghostRank( i ) >= 0 ) - { - return; - } - - typename KERNEL_TYPE::LinfStackVariables stack; - kernelComponent.setupLinf( i, stack ); - kernelComponent.computeLinf( i, stack ); - - for( integer j = 0; j < numNorm; ++j ) - { - localResidualNorm[j].max( LvArray::math::abs( stack.localValue[j] ) ); - } - } ); - - for( integer j = 0; j < numNorm; ++j ) - { - residualNorm[j] = localResidualNorm[j].get(); - } - } - - /** - * @brief Performs the kernel launch for the L2 norm - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] size the number of elements/nodes/faces - * @param[inout] kernelComponent the kernel component providing access to the compute function - * @param[inout] residualNorm the norms to compute - * @param[inout] residualNormalizer the norms to compute - */ - template< typename POLICY, typename KERNEL_TYPE > - static void - launchL2( localIndex const size, - KERNEL_TYPE const & kernelComponent, - real64 (& residualNorm)[numNorm], - real64 (& residualNormalizer)[numNorm] ) - { - RAJA::ReduceSum< ReducePolicy< POLICY >, real64 > localResidualNorm[numNorm]{}; - RAJA::ReduceSum< ReducePolicy< POLICY >, real64 > localResidualNormalizer[numNorm]{}; - - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const i ) - { - if( kernelComponent.ghostRank( i ) >= 0 ) - { - return; - } - - typename KERNEL_TYPE::L2StackVariables stack; - kernelComponent.setupL2( i, stack ); - kernelComponent.computeL2( i, stack ); - - for( integer j = 0; j < numNorm; ++j ) - { - localResidualNorm[j] += stack.localValue[j]; - localResidualNormalizer[j] += stack.localNormalizer[j]; - } - } ); - - for( integer j = 0; j < numNorm; ++j ) - { - residualNorm[j] = localResidualNorm[j].get(); - residualNormalizer[j] = localResidualNormalizer[j].get(); - } - } - - -protected: - - /// Offset for my MPI rank - globalIndex const m_rankOffset; - - /// View on the local residual - arrayView1d< real64 const > const m_localResidual; - - /// View on the dof numbers - arrayView1d< globalIndex const > const m_dofNumber; - - /// View on the ghost ranks - arrayView1d< integer const > const m_ghostRank; - - /// Value used to make sure that normalizers are never zero - real64 const m_minNormalizer; - -}; - -/** - * @class LinfResidualNormHelper - * @brief Utility class to compute the global Linf residual norm - */ -class LinfResidualNormHelper -{ -public: - - template< integer NUM_NORM > - static void updateLocalNorm( real64 const (&subRegionResidualNorm)[NUM_NORM], - array1d< real64 > & localResidualNorm ) - { - for( integer i = 0; i < NUM_NORM; ++i ) - { - if( subRegionResidualNorm[i] > localResidualNorm[i] ) - { - localResidualNorm[i] = subRegionResidualNorm[i]; - } - } - } - - static void computeGlobalNorm( real64 const & localResidualNorm, - real64 & globalResidualNorm ) - { - globalResidualNorm = MpiWrapper::max( localResidualNorm ); - } - - static void computeGlobalNorm( array1d< real64 > const & localResidualNorm, - array1d< real64 > & globalResidualNorm ) - { - MpiWrapper::allReduce( localResidualNorm.data(), - globalResidualNorm.data(), - localResidualNorm.size(), - MpiWrapper::getMpiOp( MpiWrapper::Reduction::Max ), - MPI_COMM_GEOSX ); - } -}; - -/** - * @class L2ResidualNormHelper - * @brief Utility class to compute the global L2 residual norm - */ -class L2ResidualNormHelper -{ -public: - - template< integer NUM_NORM > - static void updateLocalNorm( real64 const (&subRegionResidualNorm)[NUM_NORM], - real64 const (&subRegionResidualNormalizer)[NUM_NORM], - array1d< real64 > & localResidualNorm, - array1d< real64 > & localResidualNormalizer ) - { - for( integer i = 0; i < NUM_NORM; ++i ) - { - localResidualNorm[i] += subRegionResidualNorm[i]; - localResidualNormalizer[i] += subRegionResidualNormalizer[i]; - } - } - - static void computeGlobalNorm( real64 const & localResidualNorm, - real64 const & localResidualNormalizer, - real64 & globalResidualNorm ) - { - globalResidualNorm = sqrt( MpiWrapper::sum( localResidualNorm ) ) / sqrt( MpiWrapper::sum( localResidualNormalizer ) ); - } - - static void computeGlobalNorm( array1d< real64 > const & localResidualNorm, - array1d< real64 > const & localResidualNormalizer, - array1d< real64 > & globalResidualNorm ) - { - array1d< real64 > sumLocalResidualNorm( localResidualNorm.size() ); - array1d< real64 > sumLocalResidualNormalizer( localResidualNormalizer.size() ); - MpiWrapper::allReduce( localResidualNorm.data(), - sumLocalResidualNorm.data(), - localResidualNorm.size(), - MpiWrapper::getMpiOp( MpiWrapper::Reduction::Sum ), - MPI_COMM_GEOSX ); - MpiWrapper::allReduce( localResidualNormalizer.data(), - sumLocalResidualNormalizer.data(), - localResidualNormalizer.size(), - MpiWrapper::getMpiOp( MpiWrapper::Reduction::Sum ), - MPI_COMM_GEOSX ); - for( integer i = 0; i < localResidualNorm.size(); ++i ) - { - globalResidualNorm[i] = sqrt( sumLocalResidualNorm[i] ) / sqrt( sumLocalResidualNormalizer[i] ); - } - } - -}; - -/** - * @brief Type of norm used to check convergence - * TODO: find a way to put this inside the class - */ -enum class NormType : integer -{ - Linf, /**< Linfinity norm */ - L2 /**< L2 */ -}; - -ENUM_STRINGS( NormType, - "Linfinity", - "L2" ); - - -} // namespace solverBaseKernels - -} // namespace geos - -#endif //GEOS_PHYSICSSOLVERS_SOLVERBASEKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/SolverStatistics.cpp b/src/coreComponents/physicsSolvers/SolverStatistics.cpp index f3687b46042..9928a95bec7 100644 --- a/src/coreComponents/physicsSolvers/SolverStatistics.cpp +++ b/src/coreComponents/physicsSolvers/SolverStatistics.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -37,7 +38,6 @@ SolverStatistics::SolverStatistics( string const & name, Group * const parent ) setApplyDefaultValue( 0 ). setDescription( "Number of time step cuts" ); - registerWrapper( viewKeyStruct::numSuccessfulOuterLoopIterationsString(), &m_numSuccessfulOuterLoopIterations ). setApplyDefaultValue( 0 ). setDescription( "Cumulative number of successful outer loop iterations" ); diff --git a/src/coreComponents/physicsSolvers/SolverStatistics.hpp b/src/coreComponents/physicsSolvers/SolverStatistics.hpp index 7ec3b7cc532..7bb1abc0f44 100644 --- a/src/coreComponents/physicsSolvers/SolverStatistics.hpp +++ b/src/coreComponents/physicsSolvers/SolverStatistics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -79,7 +80,54 @@ class SolverStatistics : public dataRepository::Group */ void outputStatistics() const; -private: + /** + * @return Number of time steps + */ + integer getNumTimeSteps() const + { return m_numTimeSteps; } + + /** + * @return Number of time step cuts + */ + integer getNumTimeStepCuts() const + { return m_numTimeStepCuts; } + + /** + * @return Cumulative number of successful outer loop iterations + */ + integer getNumSuccessfulOuterLoopIterations() const + { return m_numSuccessfulOuterLoopIterations; } + + /** + * @return Cumulative number of successful nonlinear iterations + */ + integer getNumSuccessfulNonlinearIterations() const + { return m_numSuccessfulNonlinearIterations; } + + /** + * @return Cumulative number of successful linear iterations + */ + integer getNumSuccessfulLinearIterations() const + { return m_numSuccessfulLinearIterations; } + + /** + * @return Cumulative number of discarded outer loop iterations + */ + integer getNumDiscardedOuterLoopIterations() const + { return m_numDiscardedOuterLoopIterations; } + + /** + * @return Cumulative number of discarded nonlinear iterations + */ + integer getNumDiscardedNonlinearIterations() const + { return m_numDiscardedNonlinearIterations; } + + /** + * @return Cumulative number of discarded linear iterations + */ + integer getNumDiscardedLinearIterations() const + { return m_numDiscardedLinearIterations; } + /** * @brief Struct to serve as a container for variable strings and keys. @@ -107,6 +155,7 @@ class SolverStatistics : public dataRepository::Group static constexpr char const * numDiscardedLinearIterationsString() { return "numDiscardedLinearIterations"; } }; +private: /// Number of time steps integer m_numTimeSteps; diff --git a/src/coreComponents/physicsSolvers/contact/CMakeLists.txt b/src/coreComponents/physicsSolvers/contact/CMakeLists.txt new file mode 100644 index 00000000000..ac5fbe3bc1a --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/CMakeLists.txt @@ -0,0 +1,33 @@ +# Specify solver headers +set( physicsSolvers_headers + ${physicsSolvers_headers} + contact/ContactSolverBase.hpp + contact/ContactFields.hpp + contact/SolidMechanicsEmbeddedFractures.hpp + contact/SolidMechanicsLagrangeContact.hpp + contact/SolidMechanicsLagrangeContactBubbleStab.hpp + contact/SolidMechanicsAugmentedLagrangianContact.hpp + contact/kernels/SolidMechanicsConformingContactKernelsBase.hpp + contact/kernels/SolidMechanicsDisplacementJumpUpdateKernels.hpp + contact/kernels/SolidMechanicsEFEMKernelsBase.hpp + contact/kernels/SolidMechanicsEFEMKernels.hpp + contact/kernels/SolidMechanicsEFEMStaticCondensationKernels.hpp + contact/kernels/SolidMechanicsEFEMKernelsHelper.hpp + contact/kernels/SolidMechanicsALMKernelsBase.hpp + contact/kernels/SolidMechanicsALMKernels.hpp + contact/kernels/SolidMechanicsConformingContactKernelsHelper.hpp + contact/kernels/SolidMechanicsContactFaceBubbleKernels.hpp + contact/kernels/SolidMechanicsLagrangeContactKernels.hpp + contact/LogLevelsInfo.hpp + PARENT_SCOPE ) + + +# Specify solver sources +set( physicsSolvers_sources + ${physicsSolvers_sources} + contact/ContactSolverBase.cpp + contact/SolidMechanicsEmbeddedFractures.cpp + contact/SolidMechanicsLagrangeContact.cpp + contact/SolidMechanicsLagrangeContactBubbleStab.cpp + contact/SolidMechanicsAugmentedLagrangianContact.cpp + PARENT_SCOPE ) \ No newline at end of file diff --git a/src/coreComponents/physicsSolvers/contact/ContactFields.hpp b/src/coreComponents/physicsSolvers/contact/ContactFields.hpp index 214ca10513c..df37934c0cd 100644 --- a/src/coreComponents/physicsSolvers/contact/ContactFields.hpp +++ b/src/coreComponents/physicsSolvers/contact/ContactFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #define GEOS_PHYSICSSOLVERS_CONTACT_CONTACTFIELDS_HPP_ #include "mesh/MeshFields.hpp" -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" namespace geos { @@ -49,13 +50,53 @@ struct FractureState }; }; +DECLARE_FIELD( iterativePenalty, + "iterativePenalty", + array2d< real64 >, + 1.e5, + LEVEL_0, + WRITE_AND_READ, + "Penalty coefficients used in the iterative procedure of the Augmented Lagrangian Method" ); + +DECLARE_FIELD( rotationMatrix, + "rotationMatrix", + array3d< real64 >, + 0, + LEVEL_0, + WRITE_AND_READ, + "An array that holds the rotation matrices on the fracture" ); + DECLARE_FIELD( dispJump, "displacementJump", array2d< real64 >, 0, LEVEL_0, WRITE_AND_READ, - "Displacement jump vector" ); + "Displacement jump vector in the local reference system" ); + +DECLARE_FIELD( dispJump_n, + "displacementJump", + array2d< real64 >, + 0, + NOPLOT, + WRITE_AND_READ, + "Displacement jump vector in the local reference system at the current time-step" ); + +DECLARE_FIELD( slip, + "slip", + array1d< real64 >, + 0, + LEVEL_0, + NO_WRITE, + "Slip." ); + +DECLARE_FIELD( deltaSlip, + "deltaSlip", + array2d< real64 >, + 0.0, + LEVEL_0, + WRITE_AND_READ, + "Slip increment" ); DECLARE_FIELD( deltaDispJump, "deltaDisplacementJump", @@ -78,8 +119,16 @@ DECLARE_FIELD( traction, array2d< real64 >, 0, LEVEL_0, - NO_WRITE, - "Fracture traction vector" ); + WRITE_AND_READ, + "Fracture traction vector in the local reference system." ); + +DECLARE_FIELD( traction_n, + "traction_n", + array2d< real64 >, + 0, + NOPLOT, + WRITE_AND_READ, + "Initial fracture traction vector in the local reference system at this time-step." ); DECLARE_FIELD( deltaTraction, "deltaTraction", @@ -89,7 +138,6 @@ DECLARE_FIELD( deltaTraction, NO_WRITE, "An array that holds the traction increments on the fracture." ); - DECLARE_FIELD( dTraction_dJump, "dTraction_dJump", array3d< real64 >, @@ -110,8 +158,8 @@ DECLARE_FIELD( fractureState, "fractureState", array1d< integer >, FractureState::Stick, - NOPLOT, - NO_WRITE, + LEVEL_0, + WRITE_AND_READ, "Fracture state." ); DECLARE_FIELD( oldFractureState, @@ -122,6 +170,14 @@ DECLARE_FIELD( oldFractureState, NO_WRITE, "Fracture state at the previous timestep." ); +DECLARE_FIELD( targetIncrementalJump, + "targetIncrementalJump", + array2d< real64 >, + 0, + NOPLOT, + WRITE_AND_READ, + "It's the target incremental jump in a timestep (e.g., slip coming from RS)." ); + ENUM_STRINGS( FractureState::State, "stick", "new_slip", "slip", "open" ); diff --git a/src/coreComponents/physicsSolvers/contact/ContactSolverBase.cpp b/src/coreComponents/physicsSolvers/contact/ContactSolverBase.cpp index b9f0e1d8645..6fecd60e93c 100644 --- a/src/coreComponents/physicsSolvers/contact/ContactSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/contact/ContactSolverBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,15 +20,10 @@ #include "ContactSolverBase.hpp" #include "common/TimingMacros.hpp" -#include "constitutive/ConstitutiveManager.hpp" -#include "constitutive/contact/ContactSelector.hpp" -#include "constitutive/solid/ElasticIsotropic.hpp" -#include "finiteElement/elementFormulations/FiniteElementBase.hpp" -#include "linearAlgebra/utilities/LAIHelperFunctions.hpp" +#include "constitutive/contact/FrictionBase.hpp" #include "mesh/DomainPartition.hpp" -#include "fieldSpecification/FieldSpecificationManager.hpp" -#include "mesh/NodeManager.hpp" #include "mesh/SurfaceElementRegion.hpp" +#include "physicsSolvers/contact/LogLevelsInfo.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp" #include "common/GEOS_RAJA_Interface.hpp" @@ -49,9 +45,9 @@ ContactSolverBase::ContactSolverBase( const string & name, setInputFlag( dataRepository::InputFlags::FALSE ); } -void ContactSolverBase::postProcessInput() +void ContactSolverBase::postInputInitialization() { - SolidMechanicsLagrangianFEM::postProcessInput(); + SolidMechanicsLagrangianFEM::postInputInitialization(); GEOS_THROW_IF( m_timeIntegrationOption != TimeIntegrationOption::QuasiStatic, GEOS_FMT( "{} {}: The attribute `{}` must be `{}`", @@ -94,6 +90,10 @@ void ContactSolverBase::registerDataOnMesh( dataRepository::Group & meshBodies ) subRegion.registerField< fields::contact::fractureState >( getName() ); subRegion.registerField< fields::contact::oldFractureState >( getName() ); + + subRegion.registerField< fields::contact::slip >( getName() ); + + subRegion.registerField< fields::contact::deltaSlip >( getName() ); } ); } ); @@ -120,19 +120,20 @@ void ContactSolverBase::setFractureRegions( dataRepository::Group const & meshBo void ContactSolverBase::computeFractureStateStatistics( MeshLevel const & mesh, globalIndex & numStick, + globalIndex & numNewSlip, globalIndex & numSlip, globalIndex & numOpen ) const { ElementRegionManager const & elemManager = mesh.getElemManager(); - array1d< globalIndex > localCounter( 3 ); + array1d< globalIndex > localCounter( 4 ); elemManager.forElementSubRegions< SurfaceElementSubRegion >( [&]( SurfaceElementSubRegion const & subRegion ) { arrayView1d< integer const > const & ghostRank = subRegion.ghostRank(); arrayView1d< integer const > const & fractureState = subRegion.getField< fields::contact::fractureState >(); - RAJA::ReduceSum< parallelHostReduce, localIndex > stickCount( 0 ), slipCount( 0 ), openCount( 0 ); + RAJA::ReduceSum< parallelHostReduce, localIndex > stickCount( 0 ), newSlipCount( 0 ), slipCount( 0 ), openCount( 0 ); forAll< parallelHostPolicy >( subRegion.size(), [=] ( localIndex const kfe ) { if( ghostRank[kfe] < 0 ) @@ -145,6 +146,10 @@ void ContactSolverBase::computeFractureStateStatistics( MeshLevel const & mesh, break; } case FractureState::NewSlip: + { + newSlipCount += 1; + break; + } case FractureState::Slip: { slipCount += 1; @@ -160,21 +165,23 @@ void ContactSolverBase::computeFractureStateStatistics( MeshLevel const & mesh, } ); localCounter[0] += stickCount.get(); - localCounter[1] += slipCount.get(); - localCounter[2] += openCount.get(); + localCounter[1] += newSlipCount.get(); + localCounter[2] += slipCount.get(); + localCounter[3] += openCount.get(); } ); - array1d< globalIndex > totalCounter( 3 ); + array1d< globalIndex > totalCounter( 4 ); MpiWrapper::allReduce( localCounter.data(), totalCounter.data(), - 3, + 4, MPI_SUM, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); - numStick = totalCounter[0]; - numSlip = totalCounter[1]; - numOpen = totalCounter[2]; + numStick = totalCounter[0]; + numNewSlip = totalCounter[1]; + numSlip = totalCounter[2]; + numOpen = totalCounter[3]; } void ContactSolverBase::outputConfigurationStatistics( DomainPartition const & domain ) const @@ -182,6 +189,7 @@ void ContactSolverBase::outputConfigurationStatistics( DomainPartition const & d if( getLogLevel() >=1 ) { globalIndex numStick = 0; + globalIndex numNewSlip = 0; globalIndex numSlip = 0; globalIndex numOpen = 0; @@ -189,11 +197,11 @@ void ContactSolverBase::outputConfigurationStatistics( DomainPartition const & d MeshLevel const & mesh, arrayView1d< string const > const & ) { - computeFractureStateStatistics( mesh, numStick, numSlip, numOpen ); + computeFractureStateStatistics( mesh, numStick, numNewSlip, numSlip, numOpen ); GEOS_LOG_RANK_0( GEOS_FMT( " Number of element for each fracture state:" - " stick: {:12} | slip: {:12} | open: {:12}", - numStick, numSlip, numOpen ) ); + " stick: {:12} | new slip: {:12} | slip: {:12} | open: {:12}", + numStick, numNewSlip, numSlip, numOpen ) ); } ); } } @@ -233,16 +241,16 @@ void ContactSolverBase::setConstitutiveNamesCallSuper( ElementSubRegionBase & su } else if( dynamic_cast< SurfaceElementSubRegion * >( &subRegion ) ) { - subRegion.registerWrapper< string >( viewKeyStruct::contactRelationNameString() ). + subRegion.registerWrapper< string >( viewKeyStruct::frictionLawNameString() ). setPlotLevel( PlotLevel::NOPLOT ). setRestartFlags( RestartFlags::NO_WRITE ). setSizedFromParent( 0 ); - string & contactRelationName = subRegion.getReference< string >( viewKeyStruct::contactRelationNameString() ); - contactRelationName = SolverBase::getConstitutiveName< ContactBase >( subRegion ); - GEOS_ERROR_IF( contactRelationName.empty(), GEOS_FMT( "{}: ContactBase model not found on subregion {}", - getDataContext(), subRegion.getDataContext() ) ); + string & frictionLawName = subRegion.getReference< string >( viewKeyStruct::frictionLawNameString() ); + frictionLawName = PhysicsSolverBase::getConstitutiveName< FrictionBase >( subRegion ); + GEOS_ERROR_IF( frictionLawName.empty(), GEOS_FMT( "{}: FrictionBase model not found on subregion {}", + getDataContext(), subRegion.getDataContext() ) ); } } -} /* namespace geos */ +} /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/contact/ContactSolverBase.hpp b/src/coreComponents/physicsSolvers/contact/ContactSolverBase.hpp index b46be82ee5c..646d6b17277 100644 --- a/src/coreComponents/physicsSolvers/contact/ContactSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/contact/ContactSolverBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -53,15 +54,19 @@ class ContactSolverBase : public SolidMechanicsLagrangianFEM constexpr static char const * fractureStateString() { return "fractureState"; } constexpr static char const * oldFractureStateString() { return "oldFractureState"; } + + constexpr static char const * frictionLawNameString() { return "frictionLawName"; } + }; protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void setConstitutiveNamesCallSuper( ElementSubRegionBase & subRegion ) const override final; void computeFractureStateStatistics( MeshLevel const & mesh, globalIndex & numStick, + globalIndex & numNewSlip, globalIndex & numSlip, globalIndex & numOpen ) const; diff --git a/src/coreComponents/physicsSolvers/contact/LogLevelsInfo.hpp b/src/coreComponents/physicsSolvers/contact/LogLevelsInfo.hpp new file mode 100644 index 00000000000..09228674f74 --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/LogLevelsInfo.hpp @@ -0,0 +1,52 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file LogLevelsInfo.hpp + * This file contains log level informations for contact solvers + */ + +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_LOGLEVELSINFO_HPP +#define GEOS_PHYSICSSOLVERS_CONTACT_LOGLEVELSINFO_HPP + +#include "common/DataTypes.hpp" + +namespace geos +{ + +namespace logInfo +{ + +/** + * @name Wells LogLevels info structures. They must comply with the `is_log_level_info` trait. + */ +///@{ + +/// @cond DO_NOT_DOCUMENT + +struct Configuration +{ + static constexpr int getMinLogLevel() { return 2; } + static constexpr std::string_view getDescription() { return "Configuration information"; } +}; + +/// @endcond +///@} + +} + +} + +#endif // GEOS_PHYSICSSOLVERS_CONTACT_LOGLEVELSINFO_HPP diff --git a/src/coreComponents/physicsSolvers/contact/SolidMechanicsAugmentedLagrangianContact.cpp b/src/coreComponents/physicsSolvers/contact/SolidMechanicsAugmentedLagrangianContact.cpp new file mode 100644 index 00000000000..c940cb45289 --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/SolidMechanicsAugmentedLagrangianContact.cpp @@ -0,0 +1,1722 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/* + * SolidMechanicsAugmentedLagrangianContact.cpp + */ + +#include "mesh/DomainPartition.hpp" +#include "SolidMechanicsAugmentedLagrangianContact.hpp" + +#include "physicsSolvers/contact/kernels/SolidMechanicsConformingContactKernelsBase.hpp" +#include "physicsSolvers/contact/kernels/SolidMechanicsALMKernels.hpp" +#include "physicsSolvers/contact/kernels/SolidMechanicsALMKernelsBase.hpp" +#include "physicsSolvers/contact/kernels/SolidMechanicsALMSimultaneousKernels.hpp" +#include "physicsSolvers/contact/kernels/SolidMechanicsDisplacementJumpUpdateKernels.hpp" +#include "physicsSolvers/contact/kernels/SolidMechanicsContactFaceBubbleKernels.hpp" +#include "physicsSolvers/contact/LogLevelsInfo.hpp" + +#include "constitutive/ConstitutiveManager.hpp" +#include "constitutive/contact/FrictionSelector.hpp" + +namespace geos +{ + +using namespace constitutive; +using namespace dataRepository; +using namespace fields; + +SolidMechanicsAugmentedLagrangianContact::SolidMechanicsAugmentedLagrangianContact( const string & name, + Group * const parent ): + ContactSolverBase( name, parent ) +{ + + m_faceTypeToFiniteElements["Quadrilateral"] = std::make_unique< finiteElement::H1_QuadrilateralFace_Lagrange1_GaussLegendre2 >(); + m_faceTypeToFiniteElements["Triangle"] = std::make_unique< finiteElement::H1_TriangleFace_Lagrange1_Gauss1 >(); + + LinearSolverParameters & linParams = m_linearSolverParameters.get(); + addLogLevel< logInfo::Configuration >(); + + linParams.isSymmetric = true; + linParams.dofsPerNode = 3; + linParams.mgr.separateComponents = true; + // TODO Implement the MGR strategy + //linParams.mgr.strategy = LinearSolverParameters::MGR::StrategyType::solidMechanicsAugumentedLagrangianContact; +} + +SolidMechanicsAugmentedLagrangianContact::~SolidMechanicsAugmentedLagrangianContact() +{} + +void SolidMechanicsAugmentedLagrangianContact::registerDataOnMesh( dataRepository::Group & meshBodies ) +{ + + ContactSolverBase::registerDataOnMesh( meshBodies ); + + forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & meshLevel, + arrayView1d< string const > const & ) + { + FaceManager & faceManager = meshLevel.getFaceManager(); + + // Register the total bubble displacement + faceManager.registerField< solidMechanics::totalBubbleDisplacement >( this->getName() ). + reference().resizeDimension< 1 >( 3 ); + + // Register the incremental bubble displacement + faceManager.registerField< solidMechanics::incrementalBubbleDisplacement >( this->getName() ). + reference().resizeDimension< 1 >( 3 ); + } ); + + forFractureRegionOnMeshTargets( meshBodies, [&] ( SurfaceElementRegion & fractureRegion ) + { + fractureRegion.forElementSubRegions< SurfaceElementSubRegion >( [&]( SurfaceElementSubRegion & subRegion ) + { + subRegion.registerField< fields::contact::deltaTraction >( getName() ). + reference().resizeDimension< 1 >( 3 ); + + // Register the rotation matrix + subRegion.registerField< contact::rotationMatrix >( this->getName() ). + reference().resizeDimension< 1, 2 >( 3, 3 ); + + // Register the penalty coefficients for the iterative procedure + subRegion.registerField< contact::iterativePenalty >( this->getName() ). + reference().resizeDimension< 1 >( 5 ); + + subRegion.registerWrapper< array1d< real64 > >( viewKeyStruct::normalTractionToleranceString() ). + setPlotLevel( PlotLevel::NOPLOT ). + setRegisteringObjects( this->getName()). + setDescription( "An array that holds the normal traction tolerance." ); + + subRegion.registerWrapper< array1d< real64 > >( viewKeyStruct::normalDisplacementToleranceString() ). + setPlotLevel( PlotLevel::NOPLOT ). + setRegisteringObjects( this->getName()). + setDescription( "An array that holds the normal displacement tolerance." ); + + subRegion.registerWrapper< array1d< real64 > >( viewKeyStruct::slidingToleranceString() ). + setPlotLevel( PlotLevel::NOPLOT ). + setRegisteringObjects( this->getName()). + setDescription( "An array that holds the sliding tolerance." ); + + subRegion.registerWrapper< array2d< real64 > >( viewKeyStruct::dispJumpUpdPenaltyString() ). + setPlotLevel( PlotLevel::NOPLOT ). + setRegisteringObjects( this->getName()). + setDescription( "An array that stores the displacement jumps used to update the penalty coefficients." ). + reference().resizeDimension< 1 >( 3 ); + + } ); + } ); + +} + +void SolidMechanicsAugmentedLagrangianContact::setupDofs( DomainPartition const & domain, + DofManager & dofManager ) const +{ + + GEOS_MARK_FUNCTION; + SolidMechanicsLagrangianFEM::setupDofs( domain, dofManager ); + + map< std::pair< string, string >, array1d< string > > meshTargets; + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshBodyName, + MeshLevel const & meshLevel, + arrayView1d< string const > const & ) + { + array1d< string > regions; + regions.emplace_back( getUniqueFractureRegionName() ); + meshTargets[std::make_pair( meshBodyName, meshLevel.getName())] = std::move( regions ); + } ); + + dofManager.addField( solidMechanics::totalBubbleDisplacement::key(), + FieldLocation::Face, + 3, + meshTargets ); + + // Add coupling between bubble + // Useful to create connection between bubble dofs for Augmented Lagrangian formulation + dofManager.addCoupling( solidMechanics::totalBubbleDisplacement::key(), + solidMechanics::totalBubbleDisplacement::key(), + DofManager::Connector::Elem ); + +} + +void SolidMechanicsAugmentedLagrangianContact::setupSystem( DomainPartition & domain, + DofManager & dofManager, + CRSMatrix< real64, globalIndex > & localMatrix, + ParallelVector & rhs, + ParallelVector & solution, + bool const setSparsity ) +{ + + GEOS_MARK_FUNCTION; + GEOS_UNUSED_VAR( setSparsity ); + + // Create the lists of interface elements that have same type. + createFaceTypeList( domain ); + + // Create the lists of interface elements that have same type and same fracture state. + updateStickSlipList( domain ); + + // Create the list of cell elements that they are enriched with bubble functions. + createBubbleCellList( domain ); + + dofManager.setDomain( domain ); + setupDofs( domain, dofManager ); + dofManager.reorderByRank(); + + // Set the sparsity pattern without the Abu and Aub blocks. + SparsityPattern< globalIndex > patternDiag; + dofManager.setSparsityPattern( patternDiag ); + + // Get the original row lengths (diagonal blocks only) + array1d< localIndex > rowLengths( patternDiag.numRows() ); + for( localIndex localRow = 0; localRow < patternDiag.numRows(); ++localRow ) + { + rowLengths[localRow] = patternDiag.numNonZeros( localRow ); + } + + // Add the number of nonzeros induced by coupling + this->addCouplingNumNonzeros( domain, dofManager, rowLengths.toView() ); + + // Create a new pattern with enough capacity for coupled matrix + SparsityPattern< globalIndex > pattern; + pattern.resizeFromRowCapacities< parallelHostPolicy >( patternDiag.numRows(), patternDiag.numColumns(), rowLengths.data() ); + + // Copy the original nonzeros + for( localIndex localRow = 0; localRow < patternDiag.numRows(); ++localRow ) + { + globalIndex const * cols = patternDiag.getColumns( localRow ).dataIfContiguous(); + pattern.insertNonZeros( localRow, cols, cols + patternDiag.numNonZeros( localRow ) ); + } + + // Add the nonzeros from coupling + this->addCouplingSparsityPattern( domain, dofManager, pattern.toView() ); + + // Finally, steal the pattern into a CRS matrix + localMatrix.assimilate< parallelDevicePolicy<> >( std::move( pattern ) ); + localMatrix.setName( this->getName() + "/localMatrix" ); + + rhs.setName( this->getName() + "/rhs" ); + rhs.create( dofManager.numLocalDofs(), MPI_COMM_GEOS ); + + solution.setName( this->getName() + "/solution" ); + solution.create( dofManager.numLocalDofs(), MPI_COMM_GEOS ); + +} + +void SolidMechanicsAugmentedLagrangianContact::implicitStepSetup( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) +{ + + SolidMechanicsLagrangianFEM::implicitStepSetup( time_n, dt, domain ); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + { + + FaceManager & faceManager = mesh.getFaceManager(); + ElementRegionManager & elemManager = mesh.getElemManager(); + + SurfaceElementRegion & region = elemManager.getRegion< SurfaceElementRegion >( getUniqueFractureRegionName() ); + FaceElementSubRegion & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); + + arrayView2d< real64 const > const faceNormal = faceManager.faceNormal(); + arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); + + arrayView2d< real64 > const incrBubbleDisp = + faceManager.getField< fields::solidMechanics::incrementalBubbleDisplacement >(); + + arrayView3d< real64 > const + rotationMatrix = subRegion.getField< fields::contact::rotationMatrix >().toView(); + + arrayView2d< real64 > const unitNormal = subRegion.getNormalVector(); + arrayView2d< real64 > const unitTangent1 = subRegion.getTangentVector1(); + arrayView2d< real64 > const unitTangent2 = subRegion.getTangentVector2(); + + // Compute rotation matrices + solidMechanicsConformingContactKernels::ComputeRotationMatricesKernel:: + launch< parallelDevicePolicy<> >( subRegion.size(), + faceNormal, + elemsToFaces, + rotationMatrix, + unitNormal, + unitTangent1, + unitTangent2 ); + + // Set the tollerances + computeTolerances( domain ); + + // Set array to update penalty coefficients + arrayView2d< real64 > const dispJumpUpdPenalty = + subRegion.getReference< array2d< real64 > >( viewKeyStruct::dispJumpUpdPenaltyString() ); + + arrayView2d< real64 > const + iterativePenalty = subRegion.getField< fields::contact::iterativePenalty >().toView(); + arrayView1d< integer const > const fractureState = subRegion.getField< contact::fractureState >(); + + if( m_simultaneous ) + { + // Set the iterative penalty coefficients + forAll< parallelDevicePolicy<> >( subRegion.size(), + [=] + GEOS_HOST_DEVICE ( localIndex const k ) + { + if( fractureState[k] == contact::FractureState::Stick ) + { + iterativePenalty[k][2] = iterativePenalty[k][1]; + iterativePenalty[k][3] = iterativePenalty[k][1]; + iterativePenalty[k][4] = 0.0; + } + else + { + iterativePenalty[k][2] = 0.0; + iterativePenalty[k][3] = 0.0; + iterativePenalty[k][4] = 0.0; + } + } ); + } + + forAll< parallelDevicePolicy<> >( subRegion.size(), + [ = ] + GEOS_HOST_DEVICE ( localIndex const k ) + { + LvArray::tensorOps::fill< 3 >( dispJumpUpdPenalty[k], 0.0 ); + localIndex const kf0 = elemsToFaces[k][0]; + localIndex const kf1 = elemsToFaces[k][1]; + LvArray::tensorOps::fill< 3 >( incrBubbleDisp[kf0], 0.0 ); + LvArray::tensorOps::fill< 3 >( incrBubbleDisp[kf1], 0.0 ); + } ); + } ); + + // Sync iterativePenalty + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + { + FieldIdentifiers fieldsToBeSync; + + fieldsToBeSync.addElementFields( { contact::iterativePenalty::key() }, + { getUniqueFractureRegionName() } ); + + CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync, + mesh, + domain.getNeighbors(), + true ); + } ); + +} + +void SolidMechanicsAugmentedLagrangianContact::assembleSystem( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + + GEOS_MARK_FUNCTION; + + synchronizeFractureState( domain ); + + SolidMechanicsLagrangianFEM::assembleSystem( time, + dt, + domain, + dofManager, + localMatrix, + localRhs ); + + //ParallelMatrix parallel_matrix; + //parallel_matrix.create( localMatrix.toViewConst(), dofManager.numLocalDofs(), MPI_COMM_GEOS ); + //parallel_matrix.write("mech.mtx"); + + // Loop for assembling contributes from interface elements (Aut*eps^-1*Atu and Aub*eps^-1*Abu) + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshName, + MeshLevel & mesh, + arrayView1d< string const > const & ) + + { + + NodeManager const & nodeManager = mesh.getNodeManager(); + FaceManager const & faceManager = mesh.getFaceManager(); + + string const & dispDofKey = dofManager.getKey( solidMechanics::totalDisplacement::key() ); + string const & bubbleDofKey = dofManager.getKey( solidMechanics::totalBubbleDisplacement::key() ); + + arrayView1d< globalIndex const > const dispDofNumber = nodeManager.getReference< globalIndex_array >( dispDofKey ); + arrayView1d< globalIndex const > const bubbleDofNumber = faceManager.getReference< globalIndex_array >( bubbleDofKey ); + + string const & fractureRegionName = this->getUniqueFractureRegionName(); + + forFiniteElementOnStickFractureSubRegions( meshName, [&] ( string const &, + finiteElement::FiniteElementBase const & subRegionFE, + arrayView1d< localIndex const > const & faceElementList, + bool const ) + { + + if( m_simultaneous ) + { + solidMechanicsALMKernels::ALMSimultaneousFactory kernelFactory( dispDofNumber, + bubbleDofNumber, + dofManager.rankOffset(), + localMatrix, + localRhs, + dt, + faceElementList ); + + real64 maxTraction = finiteElement:: + interfaceBasedKernelApplication + < parallelDevicePolicy< >, + constitutive::CoulombFriction >( mesh, + fractureRegionName, + faceElementList, + subRegionFE, + viewKeyStruct::frictionLawNameString(), + kernelFactory ); + + GEOS_UNUSED_VAR( maxTraction ); + + } + else + { + solidMechanicsALMKernels::ALMFactory kernelFactory( dispDofNumber, + bubbleDofNumber, + dofManager.rankOffset(), + localMatrix, + localRhs, + dt, + faceElementList, + m_symmetric ); + + real64 maxTraction = finiteElement:: + interfaceBasedKernelApplication + < parallelDevicePolicy< >, + constitutive::CoulombFriction >( mesh, + fractureRegionName, + faceElementList, + subRegionFE, + viewKeyStruct::frictionLawNameString(), + kernelFactory ); + + GEOS_UNUSED_VAR( maxTraction ); + } + + } ); + + forFiniteElementOnSlipFractureSubRegions( meshName, [&] ( string const &, + finiteElement::FiniteElementBase const & subRegionFE, + arrayView1d< localIndex const > const & faceElementList, + bool const ) + { + + if( m_simultaneous ) + { + solidMechanicsALMKernels::ALMSimultaneousFactory kernelFactory( dispDofNumber, + bubbleDofNumber, + dofManager.rankOffset(), + localMatrix, + localRhs, + dt, + faceElementList ); + + real64 maxTraction = finiteElement:: + interfaceBasedKernelApplication + < parallelDevicePolicy< >, + constitutive::CoulombFriction >( mesh, + fractureRegionName, + faceElementList, + subRegionFE, + viewKeyStruct::frictionLawNameString(), + kernelFactory ); + + GEOS_UNUSED_VAR( maxTraction ); + + } + else + { + solidMechanicsALMKernels::ALMFactory kernelFactory( dispDofNumber, + bubbleDofNumber, + dofManager.rankOffset(), + localMatrix, + localRhs, + dt, + faceElementList, + m_symmetric ); + + real64 maxTraction = finiteElement:: + interfaceBasedKernelApplication + < parallelDevicePolicy< >, + constitutive::CoulombFriction >( mesh, + fractureRegionName, + faceElementList, + subRegionFE, + viewKeyStruct::frictionLawNameString(), + kernelFactory ); + + GEOS_UNUSED_VAR( maxTraction ); + } + + } ); + + } ); + + // Loop for assembling contributes of bubble elements (Abb, Abu, Aub) + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + NodeManager const & nodeManager = mesh.getNodeManager(); + FaceManager const & faceManager = mesh.getFaceManager(); + + string const & dispDofKey = dofManager.getKey( solidMechanics::totalDisplacement::key() ); + string const & bubbleDofKey = dofManager.getKey( solidMechanics::totalBubbleDisplacement::key() ); + + arrayView1d< globalIndex const > const dispDofNumber = nodeManager.getReference< globalIndex_array >( dispDofKey ); + arrayView1d< globalIndex const > const bubbleDofNumber = faceManager.getReference< globalIndex_array >( bubbleDofKey ); + + real64 const gravityVectorData[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3( gravityVector() ); + + + solidMechanicsConformingContactKernels::FaceBubbleFactory kernelFactory( dispDofNumber, + bubbleDofNumber, + dofManager.rankOffset(), + localMatrix, + localRhs, + dt, + gravityVectorData ); + + real64 maxTraction = finiteElement:: + regionBasedKernelApplication + < parallelDevicePolicy< >, + constitutive::ElasticIsotropic, + CellElementSubRegion >( mesh, + regionNames, + getDiscretizationName(), + SolidMechanicsLagrangianFEM::viewKeyStruct::solidMaterialNamesString(), + kernelFactory ); + + GEOS_UNUSED_VAR( maxTraction ); + + } ); + +} + +void SolidMechanicsAugmentedLagrangianContact::implicitStepComplete( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) +{ + + SolidMechanicsLagrangianFEM::implicitStepComplete( time_n, dt, domain ); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + SurfaceElementRegion & region = elemManager.getRegion< SurfaceElementRegion >( getUniqueFractureRegionName() ); + FaceElementSubRegion & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); + + arrayView2d< real64 const > const dispJump = subRegion.getField< contact::dispJump >(); + arrayView2d< real64 > const oldDispJump = subRegion.getField< contact::oldDispJump >(); + arrayView2d< real64 > const deltaDispJump = subRegion.getField< contact::deltaDispJump >(); + + arrayView1d< integer const > const fractureState = subRegion.getField< contact::fractureState >(); + arrayView1d< integer > const oldFractureState = subRegion.getField< contact::oldFractureState >(); + + forAll< parallelDevicePolicy<> >( subRegion.size(), + [ = ] + GEOS_HOST_DEVICE ( localIndex const kfe ) + { + LvArray::tensorOps::fill< 3 >( deltaDispJump[kfe], 0.0 ); + LvArray::tensorOps::copy< 3 >( oldDispJump[kfe], dispJump[kfe] ); + oldFractureState[kfe] = fractureState[kfe]; + } ); + + } ); + +} + +real64 SolidMechanicsAugmentedLagrangianContact::calculateResidualNorm( real64 const & time, + real64 const & dt, + DomainPartition const & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localRhs ) +{ + + GEOS_MARK_FUNCTION; + + real64 const solidResidualNorm = SolidMechanicsLagrangianFEM::calculateResidualNorm( time, dt, domain, dofManager, localRhs ); + + string const bubbleDofKey = dofManager.getKey( solidMechanics::totalBubbleDisplacement::key() ); + + globalIndex const rankOffset = dofManager.rankOffset(); + + RAJA::ReduceSum< parallelDeviceReduce, real64 > localSum( 0.0 ); + + // globalResidualNorm[0]: the sum of all the local sum(rhs^2). + // globalResidualNorm[1]: max of max force of each rank. Basically max force globally + real64 globalResidualNorm[2] = {0, 0}; + + // Bubble residual + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const ) + { + FaceManager const & faceManager = mesh.getFaceManager(); + ElementRegionManager const & elemManager = mesh.getElemManager(); + + SurfaceElementRegion const & region = elemManager.getRegion< SurfaceElementRegion >( getUniqueFractureRegionName() ); + FaceElementSubRegion const & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); + + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + + arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); + + arrayView1d< globalIndex const > const bubbleDofNumber = faceManager.getReference< globalIndex_array >( bubbleDofKey ); + + forAll< parallelDevicePolicy<> >( subRegion.size(), + [ = ] + GEOS_HOST_DEVICE ( localIndex const kfe ) + { + + if( ghostRank[kfe] < 0 ) + { + for( int kk=0; kk<2; ++kk ) + { + localIndex const k = elemsToFaces[kfe][kk]; + localIndex const localRow = LvArray::integerConversion< localIndex >( bubbleDofNumber[k] - rankOffset ); + for( localIndex i = 0; i < 3; ++i ) + { + localSum += localRhs[localRow + i] * localRhs[localRow + i]; + } + } + } + + } ); + real64 const localResidualNorm[2] = { localSum.get(), SolidMechanicsLagrangianFEM::getMaxForce() }; + + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); + int const numRanks = MpiWrapper::commSize( MPI_COMM_GEOS ); + array1d< real64 > globalValues( numRanks * 2 ); + + // Everything is done on rank 0 + MpiWrapper::gather( localResidualNorm, + 2, + globalValues.data(), + 2, + 0, + MPI_COMM_GEOS ); + + if( rank==0 ) + { + for( int r=0; r= 1 && logger::internal::rank==0 ) + { + std::cout << GEOS_FMT( " ( RBubbleDisp ) = ( {:4.2e} )", bubbleResidualNorm ); + } + + return sqrt( solidResidualNorm * solidResidualNorm + bubbleResidualNorm * bubbleResidualNorm ); + +} + +void SolidMechanicsAugmentedLagrangianContact::applySystemSolution( DofManager const & dofManager, + arrayView1d< real64 const > const & localSolution, + real64 const scalingFactor, + real64 const dt, + DomainPartition & domain ) +{ + + GEOS_MARK_FUNCTION; + + SolidMechanicsLagrangianFEM::applySystemSolution( dofManager, + localSolution, + scalingFactor, + dt, + domain ); + + dofManager.addVectorToField( localSolution, + solidMechanics::totalBubbleDisplacement::key(), + solidMechanics::totalBubbleDisplacement::key(), + scalingFactor ); + + dofManager.addVectorToField( localSolution, + solidMechanics::totalBubbleDisplacement::key(), + solidMechanics::incrementalBubbleDisplacement::key(), + scalingFactor ); + + + // Loop for updating the displacement jump + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshName, + MeshLevel & mesh, + arrayView1d< string const > const & ) + + { + + NodeManager const & nodeManager = mesh.getNodeManager(); + FaceManager const & faceManager = mesh.getFaceManager(); + + string const & dispDofKey = dofManager.getKey( solidMechanics::totalDisplacement::key() ); + string const & bubbleDofKey = dofManager.getKey( solidMechanics::totalBubbleDisplacement::key() ); + + arrayView1d< globalIndex const > const dispDofNumber = nodeManager.getReference< globalIndex_array >( dispDofKey ); + arrayView1d< globalIndex const > const bubbleDofNumber = faceManager.getReference< globalIndex_array >( bubbleDofKey ); + + string const & fractureRegionName = this->getUniqueFractureRegionName(); + + CRSMatrix< real64, globalIndex > const voidMatrix; + array1d< real64 > const voidRhs; + + forFiniteElementOnFractureSubRegions( meshName, [&] ( string const &, + finiteElement::FiniteElementBase const & subRegionFE, + arrayView1d< localIndex const > const & faceElementList ) + { + + solidMechanicsConformingContactKernels::DispJumpUpdateFactory kernelFactory( dispDofNumber, + bubbleDofNumber, + dofManager.rankOffset(), + voidMatrix.toViewConstSizes(), + voidRhs.toView(), + dt, + faceElementList ); + + real64 maxTraction = finiteElement:: + interfaceBasedKernelApplication + < parallelDevicePolicy< >, + constitutive::NullModel >( mesh, + fractureRegionName, + faceElementList, + subRegionFE, + "", + kernelFactory ); + + GEOS_UNUSED_VAR( maxTraction ); + + } ); + } ); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + + { + FieldIdentifiers fieldsToBeSync; + + fieldsToBeSync.addFields( FieldLocation::Face, + { solidMechanics::incrementalBubbleDisplacement::key(), + solidMechanics::totalBubbleDisplacement::key() } ); + + fieldsToBeSync.addElementFields( { contact::dispJump::key(), + contact::deltaDispJump::key() }, + { getUniqueFractureRegionName() } ); + + CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync, + mesh, + domain.getNeighbors(), + true ); + } ); + +} + +void SolidMechanicsAugmentedLagrangianContact::updateState( DomainPartition & domain ) +{ + GEOS_UNUSED_VAR( domain ); +} + +bool SolidMechanicsAugmentedLagrangianContact::updateConfiguration( DomainPartition & domain ) +{ + GEOS_MARK_FUNCTION; + + array1d< int > condConv; + localIndex globalCondConv[5] = {0, 0, 0, 0, 0}; + + array2d< real64 > traction_new; + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + + elemManager.forElementSubRegions< FaceElementSubRegion >( regionNames, [&]( localIndex const, + FaceElementSubRegion & subRegion ) + { + + string const & frictionLawName = subRegion.template getReference< string >( viewKeyStruct::frictionLawNameString() ); + FrictionBase const & frictionLaw = getConstitutiveModel< FrictionBase >( subRegion, frictionLawName ); + + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + arrayView2d< real64 const > const traction = subRegion.getField< contact::traction >(); + arrayView2d< real64 const > const dispJump = subRegion.getField< contact::dispJump >(); + + arrayView2d< real64 const > const deltaDispJump = subRegion.getField< contact::deltaDispJump >(); + arrayView2d< real64 const > const iterativePenalty = subRegion.getField< contact::iterativePenalty >(); + arrayView1d< integer const > const fractureState = subRegion.getField< contact::fractureState >(); + + arrayView1d< real64 const > const normalDisplacementTolerance = + subRegion.getReference< array1d< real64 > >( viewKeyStruct::normalDisplacementToleranceString() ); + arrayView1d< real64 > const & slidingTolerance = + subRegion.getReference< array1d< real64 > >( viewKeyStruct::slidingToleranceString() ); + arrayView1d< real64 const > const & normalTractionTolerance = + subRegion.getReference< array1d< real64 > >( viewKeyStruct::normalTractionToleranceString() ); + + arrayView1d< real64 const > const faceElementArea = subRegion.getElementArea().toViewConst(); + + std::ptrdiff_t const sizes[ 2 ] = {subRegion.size(), 3}; + traction_new.resize( 2, sizes ); + arrayView2d< real64 > const traction_new_v = traction_new.toView(); + + condConv.resize( subRegion.size()); + arrayView1d< int > const condConv_v = condConv.toView(); + + // Update the traction field based on the displacement results from the nonlinear solve + constitutiveUpdatePassThru( frictionLaw, [&] ( auto & castedFrictionLaw ) + { + using FrictionType = TYPEOFREF( castedFrictionLaw ); + typename FrictionType::KernelWrapper frictionWrapper = castedFrictionLaw.createKernelUpdates(); + + if( m_simultaneous ) + { + solidMechanicsALMKernels::ComputeTractionSimultaneousKernel:: + launch< parallelDevicePolicy<> >( subRegion.size(), + iterativePenalty, + traction, + dispJump, + deltaDispJump, + faceElementArea, + traction_new_v ); + } + else + { + solidMechanicsALMKernels::ComputeTractionKernel:: + launch< parallelDevicePolicy<> >( subRegion.size(), + frictionWrapper, + iterativePenalty, + traction, + dispJump, + deltaDispJump, + faceElementArea, + traction_new_v ); + } + } ); + + real64 const slidingCheckTolerance = m_slidingCheckTolerance; + + constitutiveUpdatePassThru( frictionLaw, [&] ( auto & castedFrictionLaw ) + { + using FrictionType = TYPEOFREF( castedFrictionLaw ); + typename FrictionType::KernelWrapper frictionWrapper = castedFrictionLaw.createKernelUpdates(); + + solidMechanicsALMKernels::ConstraintCheckKernel:: + launch< parallelDevicePolicy<> >( subRegion.size(), + frictionWrapper, + ghostRank, + traction_new_v, + dispJump, + deltaDispJump, + normalTractionTolerance, + normalDisplacementTolerance, + slidingTolerance, + slidingCheckTolerance, + fractureState, + condConv_v ); + } ); + + RAJA::ReduceSum< parallelDeviceReduce, localIndex > localSum[5] = + { RAJA::ReduceSum< parallelDeviceReduce, localIndex >( 0 ), + RAJA::ReduceSum< parallelDeviceReduce, localIndex >( 0 ), + RAJA::ReduceSum< parallelDeviceReduce, localIndex >( 0 ), + RAJA::ReduceSum< parallelDeviceReduce, localIndex >( 0 ), + RAJA::ReduceSum< parallelDeviceReduce, localIndex >( 0 ) }; + forAll< parallelDevicePolicy<> >( subRegion.size(), [ = ] GEOS_HOST_DEVICE ( localIndex const kfe ) + { + if( ghostRank[kfe] < 0 ) + { + localSum[condConv_v[kfe]] += 1; + } + } ); + + localIndex const localConvCond[5] = { static_cast< localIndex >( localSum[0].get()), + static_cast< localIndex >( localSum[1].get()), + static_cast< localIndex >( localSum[2].get()), + static_cast< localIndex >( localSum[3].get()), + static_cast< localIndex >( localSum[4].get()) }; + + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); + int const numRanks = MpiWrapper::commSize( MPI_COMM_GEOS ); + array1d< localIndex > globalValues( numRanks * 5 ); + + // Everything is done on rank 0 + MpiWrapper::gather( localConvCond, + 5, + globalValues.data(), + 5, + 0, + MPI_COMM_GEOS ); + + if( rank==0 ) + { + for( int r=0; r0: {:6} | compenetration: {:6} | stick & gt>lim: {:6} | tau>tauLim: {:6}\n", + globalCondConv[0], globalCondConv[1], globalCondConv[2], + globalCondConv[3], globalCondConv[4] )); + + if( hasConfigurationConvergedGlobally ) + { + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + + elemManager.forElementSubRegions< FaceElementSubRegion >( regionNames, [&]( localIndex const, + FaceElementSubRegion & subRegion ) + { + + arrayView2d< real64 > const traction_new_v = traction_new.toView(); + arrayView2d< real64 > const traction = subRegion.getField< contact::traction >(); + + forAll< parallelDevicePolicy<> >( subRegion.size(), [ = ] GEOS_HOST_DEVICE ( localIndex const kfe ) + { + LvArray::tensorOps::copy< 3 >( traction[kfe], traction_new_v[kfe] ); + } ); + } ); + } ); + } + else + { + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + + elemManager.forElementSubRegions< FaceElementSubRegion >( regionNames, [&]( localIndex const, + FaceElementSubRegion & subRegion ) + { + + string const & frictionLawName = subRegion.template getReference< string >( viewKeyStruct::frictionLawNameString() ); + FrictionBase const & frictionLaw = getConstitutiveModel< FrictionBase >( subRegion, frictionLawName ); + + arrayView2d< real64 > const traction = subRegion.getField< contact::traction >(); + + arrayView1d< real64 const > const normalTractionTolerance = + subRegion.getReference< array1d< real64 > >( viewKeyStruct::normalTractionToleranceString() ); + + arrayView2d< real64 > const iterativePenalty = subRegion.getField< fields::contact::iterativePenalty >().toView(); + + arrayView2d< real64 > const dispJumpUpdPenalty = + subRegion.getReference< array2d< real64 > >( viewKeyStruct::dispJumpUpdPenaltyString() ); + + arrayView1d< integer > const fractureState = subRegion.getField< contact::fractureState >(); + + arrayView2d< real64 const > const dispJump = subRegion.getField< contact::dispJump >(); + + arrayView2d< real64 const > const oldDispJump = subRegion.getField< contact::oldDispJump >(); + + arrayView2d< real64 const > const deltaDispJump = subRegion.getField< contact::deltaDispJump >(); + + arrayView1d< real64 const > const faceElementArea = subRegion.getField< fields::elementArea >(); + + constitutiveUpdatePassThru( frictionLaw, [&] ( auto & castedFrictionLaw ) + { + using FrictionType = TYPEOFREF( castedFrictionLaw ); + typename FrictionType::KernelWrapper frictionWrapper = castedFrictionLaw.createKernelUpdates(); + + solidMechanicsALMKernels::UpdateStateKernel:: + launch< parallelDevicePolicy<> >( subRegion.size(), + frictionWrapper, + oldDispJump, + dispJump, + iterativePenalty, + faceElementArea, + m_symmetric, + normalTractionTolerance, + traction, + fractureState ); + } ); + + forAll< parallelDevicePolicy<> >( subRegion.size(), [ = ] + GEOS_HOST_DEVICE ( localIndex const kfe ) + { + dispJumpUpdPenalty[kfe][0] = dispJump[kfe][0]; + dispJumpUpdPenalty[kfe][1] = deltaDispJump[kfe][1]; + dispJumpUpdPenalty[kfe][2] = deltaDispJump[kfe][2]; + } ); + } ); + } ); + } + + // Need to synchronize the fracture state due to the use will be made of in AssemblyStabilization + synchronizeFractureState( domain ); + + // Update lists of stick and slip elements + if( !hasConfigurationConvergedGlobally ) + { + updateStickSlipList( domain ); + } + + return hasConfigurationConvergedGlobally; + +} + +void SolidMechanicsAugmentedLagrangianContact::updateStickSlipList( DomainPartition const & domain ) +{ + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshName, + MeshLevel const & mesh, + arrayView1d< string const > const & ) + + { + + ElementRegionManager const & elemManager = mesh.getElemManager(); + SurfaceElementRegion const & region = elemManager.getRegion< SurfaceElementRegion >( getUniqueFractureRegionName() ); + FaceElementSubRegion const & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); + + arrayView1d< integer const > const fractureState = subRegion.getField< contact::fractureState >(); + + forFiniteElementOnFractureSubRegions( meshName, [&] ( string const & finiteElementName, + finiteElement::FiniteElementBase const &, + arrayView1d< localIndex const > const & faceElementList ) + { + + array1d< localIndex > keys( subRegion.size()); + array1d< localIndex > vals( subRegion.size()); + array1d< localIndex > stickList; + array1d< localIndex > slipList; + RAJA::ReduceSum< ReducePolicy< parallelDevicePolicy<> >, localIndex > nStick_r( 0 ); + RAJA::ReduceSum< ReducePolicy< parallelDevicePolicy<> >, localIndex > nSlip_r( 0 ); + + arrayView1d< localIndex > const keys_v = keys.toView(); + arrayView1d< localIndex > const vals_v = vals.toView(); + forAll< parallelDevicePolicy<> >( faceElementList.size(), + [ = ] + GEOS_HOST_DEVICE ( localIndex const kfe ) + { + + localIndex const faceIndex = faceElementList[kfe]; + if( fractureState[faceIndex] == contact::FractureState::Stick ) + { + keys_v[kfe]=0; + vals_v[kfe]=faceIndex; + nStick_r += 1; + } + else if(( fractureState[faceIndex] == contact::FractureState::Slip ) || + (fractureState[faceIndex] == contact::FractureState::NewSlip)) + { + keys_v[kfe]=1; + vals_v[kfe]=faceIndex; + nSlip_r += 1; + } + else + { + keys_v[kfe] = 2; + } + + } ); + + localIndex nStick = static_cast< localIndex >(nStick_r.get()); + localIndex nSlip = static_cast< localIndex >(nSlip_r.get()); + + // Sort vals according to keys to ensure that + // elements of the same type are adjacent in the vals list. + // This arrangement allows for efficient copying into the container + // by leveraging parallelism. + RAJA::sort_pairs< parallelDevicePolicy<> >( keys_v, vals_v ); + + stickList.resize( nStick ); + slipList.resize( nSlip ); + arrayView1d< localIndex > const stickList_v = stickList.toView(); + arrayView1d< localIndex > const slipList_v = slipList.toView(); + + forAll< parallelDevicePolicy<> >( nStick, [ = ] + GEOS_HOST_DEVICE ( localIndex const kfe ) + { + stickList_v[kfe] = vals_v[kfe]; + } ); + + forAll< parallelDevicePolicy<> >( nSlip, [ = ] + GEOS_HOST_DEVICE ( localIndex const kfe ) + { + slipList_v[kfe] = vals_v[nStick+kfe]; + } ); + + this->m_faceTypesToFaceElementsStick[meshName][finiteElementName] = stickList; + this->m_faceTypesToFaceElementsSlip[meshName][finiteElementName] = slipList; + + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Configuration, GEOS_FMT( "# stick elements: {}, # slip elements: {}", nStick, nSlip )) + } ); + } ); + +} + +void SolidMechanicsAugmentedLagrangianContact::createFaceTypeList( DomainPartition const & domain ) +{ + + // Generate lists containing elements of various face types + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshName, + MeshLevel const & mesh, + arrayView1d< string const > const ) + { + FaceManager const & faceManager = mesh.getFaceManager(); + ElementRegionManager const & elemManager = mesh.getElemManager(); + ArrayOfArraysView< localIndex const > const faceToNodeMap = faceManager.nodeList().toViewConst(); + + SurfaceElementRegion const & region = elemManager.getRegion< SurfaceElementRegion >( getUniqueFractureRegionName() ); + FaceElementSubRegion const & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); + + array1d< localIndex > keys( subRegion.size()); + array1d< localIndex > vals( subRegion.size()); + array1d< localIndex > quadList; + array1d< localIndex > triList; + RAJA::ReduceSum< ReducePolicy< parallelDevicePolicy<> >, localIndex > nTri_r( 0 ); + RAJA::ReduceSum< ReducePolicy< parallelDevicePolicy<> >, localIndex > nQuad_r( 0 ); + + arrayView1d< localIndex > const keys_v = keys.toView(); + arrayView1d< localIndex > const vals_v = vals.toView(); + // Determine the size of the lists and generate the vector keys and vals for parallel indexing into lists. + // (With RAJA, parallelizing this operation seems the most viable approach.) + forAll< parallelDevicePolicy<> >( subRegion.size(), + [ = ] GEOS_HOST_DEVICE ( localIndex const kfe ) + { + + localIndex const numNodesPerFace = faceToNodeMap.sizeOfArray( kfe ); + if( numNodesPerFace == 3 ) + { + keys_v[kfe]=0; + vals_v[kfe]=kfe; + nTri_r += 1; + } + else if( numNodesPerFace == 4 ) + { + keys_v[kfe]=1; + vals_v[kfe]=kfe; + nQuad_r += 1; + } + else + { + GEOS_ERROR( "SolidMechanicsAugmentedLagrangianContact:: invalid face type" ); + } + } ); + + localIndex nQuad = static_cast< localIndex >(nQuad_r.get()); + localIndex nTri = static_cast< localIndex >(nTri_r.get()); + + // Sort vals according to keys to ensure that + // elements of the same type are adjacent in the vals list. + // This arrangement allows for efficient copying into the container + // by leveraging parallelism. + RAJA::sort_pairs< parallelDevicePolicy<> >( keys_v, vals_v ); + + quadList.resize( nQuad ); + triList.resize( nTri ); + arrayView1d< localIndex > const quadList_v = quadList.toView(); + arrayView1d< localIndex > const triList_v = triList.toView(); + + forAll< parallelDevicePolicy<> >( nTri, [ = ] GEOS_HOST_DEVICE ( localIndex const kfe ) + { + triList_v[kfe] = vals_v[kfe]; + } ); + + forAll< parallelDevicePolicy<> >( nQuad, [ = ] GEOS_HOST_DEVICE ( localIndex const kfe ) + { + quadList_v[kfe] = vals_v[nTri+kfe]; + } ); + + this->m_faceTypesToFaceElements[meshName]["Quadrilateral"] = quadList; + this->m_faceTypesToFaceElements[meshName]["Triangle"] = triList; + } ); + +} + +void SolidMechanicsAugmentedLagrangianContact::createBubbleCellList( DomainPartition & domain ) const +{ + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const regionNames ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + + SurfaceElementRegion const & region = elemManager.getRegion< SurfaceElementRegion >( getUniqueFractureRegionName() ); + FaceElementSubRegion const & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); + // Array to store face indexes + array1d< localIndex > tmpSpace( 2*subRegion.size()); + SortedArray< localIndex > faceIdList; + + arrayView1d< localIndex > const tmpSpace_v = tmpSpace.toView(); + // Store indexes of faces in the temporany array. + { + arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); + + forAll< parallelDevicePolicy<> >( subRegion.size(), [ = ] GEOS_HOST_DEVICE ( localIndex const kfe ) + { + + localIndex const kf0 = elemsToFaces[kfe][0], kf1 = elemsToFaces[kfe][1]; + tmpSpace_v[2*kfe] = kf0, tmpSpace_v[2*kfe+1] = kf1; + + } ); + } + + // Sort indexes to enable efficient searching using binary search. + RAJA::stable_sort< parallelDevicePolicy<> >( tmpSpace_v ); + faceIdList.insert( tmpSpace_v.begin(), tmpSpace_v.end()); + + // Search for bubble element on each CellElementSubRegion and + // store element indexes, global and local face indexes. + elemManager.forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, CellElementSubRegion & cellElementSubRegion ) + { + + arrayView2d< localIndex const > const elemsToFaces = cellElementSubRegion.faceList().toViewConst(); + + RAJA::ReduceSum< ReducePolicy< parallelDevicePolicy<> >, localIndex > nBubElems_r( 0 ); + + localIndex const n_max = cellElementSubRegion.size() * elemsToFaces.size( 1 ); + array1d< localIndex > keys( n_max ); + array1d< localIndex > perms( n_max ); + array1d< localIndex > vals( n_max ); + array1d< localIndex > localFaceIds( n_max ); + + arrayView1d< localIndex > const keys_v = keys.toView(); + arrayView1d< localIndex > const perms_v = perms.toView(); + arrayView1d< localIndex > const vals_v = vals.toView(); + arrayView1d< localIndex > const localFaceIds_v = localFaceIds.toView(); + SortedArrayView< localIndex const > const faceIdList_v = faceIdList.toViewConst(); + + forAll< parallelDevicePolicy<> >( cellElementSubRegion.size(), + [ = ] + GEOS_HOST_DEVICE ( localIndex const kfe ) + { + for( int i=0; i < elemsToFaces.size( 1 ); ++i ) + { + perms_v[kfe*elemsToFaces.size( 1 )+i] = kfe*elemsToFaces.size( 1 )+i; + if( faceIdList_v.contains( elemsToFaces[kfe][i] )) + { + keys_v[kfe*elemsToFaces.size( 1 )+i] = 0; + vals_v[kfe*elemsToFaces.size( 1 )+i] = kfe; + localFaceIds_v[kfe*elemsToFaces.size( 1 )+i] = i; + nBubElems_r += 1; + } + else + { + keys_v[kfe*elemsToFaces.size( 1 )+i] = 1; + vals_v[kfe*elemsToFaces.size( 1 )+i] = -1; + localFaceIds_v[kfe*elemsToFaces.size( 1 )+i] = -1; + } + } + } ); + + // Sort perms according to keys to ensure that bubble elements are adjacent + // and occupy the first positions of the list. + // This arrangement allows for efficient copying into the container + // by leveraging parallelism. + localIndex nBubElems = static_cast< localIndex >(nBubElems_r.get()); + RAJA::sort_pairs< parallelDevicePolicy<> >( keys_v, perms_v ); + + array1d< localIndex > bubbleElemsList; + bubbleElemsList.resize( nBubElems ); + + arrayView1d< localIndex > const bubbleElemsList_v = bubbleElemsList.toView(); + + forAll< parallelDevicePolicy<> >( n_max, [ = ] GEOS_HOST_DEVICE ( localIndex const k ) + { + keys_v[k] = vals_v[perms_v[k]]; + } ); + + forAll< parallelDevicePolicy<> >( nBubElems, [ = ] GEOS_HOST_DEVICE ( localIndex const k ) + { + bubbleElemsList_v[k] = keys_v[k]; + } ); + cellElementSubRegion.setBubbleElementsList( bubbleElemsList.toViewConst()); + + forAll< parallelDevicePolicy<> >( n_max, [ = ] GEOS_HOST_DEVICE ( localIndex const k ) + { + keys_v[k] = localFaceIds_v[perms_v[k]]; + } ); + + array2d< localIndex > faceElemsList; + faceElemsList.resize( nBubElems, 2 ); + + arrayView2d< localIndex > const faceElemsList_v = faceElemsList.toView(); + + forAll< parallelDevicePolicy<> >( nBubElems, + [ = ] + GEOS_HOST_DEVICE ( localIndex const k ) + { + localIndex const kfe = bubbleElemsList_v[k]; + faceElemsList_v[k][0] = elemsToFaces[kfe][keys_v[k]]; + faceElemsList_v[k][1] = keys_v[k]; + } ); + cellElementSubRegion.setFaceElementsList( faceElemsList.toViewConst()); + + } ); + + } ); + +} + +void SolidMechanicsAugmentedLagrangianContact::addCouplingNumNonzeros( DomainPartition & domain, + DofManager & dofManager, + arrayView1d< localIndex > const & rowLengths ) const +{ + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) + { + + ElementRegionManager const & elemManager = mesh.getElemManager(); + NodeManager const & nodeManager = mesh.getNodeManager(); + FaceManager const & faceManager = mesh.getFaceManager(); + + ArrayOfArraysView< localIndex const > const faceToNodeMap = faceManager.nodeList().toViewConst(); + + globalIndex const rankOffset = dofManager.rankOffset(); + + string const bubbleDofKey = dofManager.getKey( solidMechanics::totalBubbleDisplacement::key() ); + string const dispDofKey = dofManager.getKey( solidMechanics::totalDisplacement::key() ); + + arrayView1d< globalIndex const > const bubbleDofNumber = faceManager.getReference< globalIndex_array >( bubbleDofKey ); + arrayView1d< globalIndex const > const dispDofNumber = nodeManager.getReference< globalIndex_array >( dispDofKey ); + + elemManager.forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, CellElementSubRegion const & cellElementSubRegion ) + { + + arrayView1d< localIndex const > const bubbleElemsList = cellElementSubRegion.bubbleElementsList(); + arrayView2d< localIndex const > const faceElemsList = cellElementSubRegion.faceElementsList(); + + localIndex const numDispDof = 3*cellElementSubRegion.numNodesPerElement(); + + for( localIndex bi=0; bi( bubbleDofNumber[k] - rankOffset ); + + if( localRow >= 0 && localRow < rowLengths.size() ) + { + for( localIndex i=0; i<3; ++i ) + { + rowLengths[localRow + i] += numDispDof; + } + } + + for( localIndex a=0; a( dispDofNumber[node] - rankOffset ); + + if( localDispRow >= 0 && localDispRow < rowLengths.size() ) + { + for( int d=0; d<3; ++d ) + { + rowLengths[localDispRow + d] += 3; + } + } + } + } + + } ); + + SurfaceElementRegion const & region = elemManager.getRegion< SurfaceElementRegion >( getUniqueFractureRegionName() ); + FaceElementSubRegion const & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); + arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); + + for( localIndex kfe=0; kfe( bubbleDofNumber[kf] - rankOffset ); + + if( localRow >= 0 && localRow < rowLengths.size() ) + { + for( localIndex i=0; i<3; ++i ) + { + rowLengths[localRow + i] += numDispDof; + } + } + + for( localIndex a=0; a( dispDofNumber[node] - rankOffset ); + + if( localDispRow >= 0 && localDispRow < rowLengths.size() ) + { + for( int d=0; d<3; ++d ) + { + rowLengths[localDispRow + d] += 3; + } + } + } + } + + } + + } ); +} + +void SolidMechanicsAugmentedLagrangianContact::addCouplingSparsityPattern( DomainPartition const & domain, + DofManager const & dofManager, + SparsityPatternView< globalIndex > const & pattern ) const +{ + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) + { + + ElementRegionManager const & elemManager = mesh.getElemManager(); + NodeManager const & nodeManager = mesh.getNodeManager(); + FaceManager const & faceManager = mesh.getFaceManager(); + + globalIndex const rankOffset = dofManager.rankOffset(); + + string const bubbleDofKey = dofManager.getKey( solidMechanics::totalBubbleDisplacement::key() ); + string const dispDofKey = dofManager.getKey( solidMechanics::totalDisplacement::key() ); + + arrayView1d< globalIndex const > const bubbleDofNumber = faceManager.getReference< globalIndex_array >( bubbleDofKey ); + arrayView1d< globalIndex const > const dispDofNumber = nodeManager.getReference< globalIndex_array >( dispDofKey ); + + static constexpr int maxNumDispDof = 3 * 8; + + elemManager.forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, CellElementSubRegion const & cellElementSubRegion ) + { + + arrayView1d< localIndex const > const bubbleElemsList = cellElementSubRegion.bubbleElementsList(); + arrayView2d< localIndex const > const faceElemsList = cellElementSubRegion.faceElementsList(); + + localIndex const numDispDof = 3*cellElementSubRegion.numNodesPerElement(); + + for( localIndex bi=0; bi eqnRowIndicesDisp ( numDispDof ); + stackArray1d< globalIndex, 3 > eqnRowIndicesBubble( 3 ); + stackArray1d< globalIndex, maxNumDispDof > dofColIndicesDisp ( numDispDof ); + stackArray1d< globalIndex, 3 > dofColIndicesBubble( 3 ); + + for( localIndex idof = 0; idof < 3; ++idof ) + { + eqnRowIndicesBubble[idof] = bubbleDofNumber[k] + idof - rankOffset; + dofColIndicesBubble[idof] = bubbleDofNumber[k] + idof; + } + + for( localIndex a=0; a= 0 && eqnRowIndicesDisp[i] < pattern.numRows() ) + { + for( localIndex j = 0; j < dofColIndicesBubble.size(); ++j ) + { + pattern.insertNonZero( eqnRowIndicesDisp[i], dofColIndicesBubble[j] ); + } + } + } + + for( localIndex i = 0; i < eqnRowIndicesBubble.size(); ++i ) + { + if( eqnRowIndicesBubble[i] >= 0 && eqnRowIndicesBubble[i] < pattern.numRows() ) + { + for( localIndex j=0; j < dofColIndicesDisp.size(); ++j ) + { + pattern.insertNonZero( eqnRowIndicesBubble[i], dofColIndicesDisp[j] ); + } + } + } + + } + + } ); + + SurfaceElementRegion const & region = elemManager.getRegion< SurfaceElementRegion >( getUniqueFractureRegionName() ); + FaceElementSubRegion const & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); + arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); + ArrayOfArraysView< localIndex const > const faceToNodeMap = faceManager.nodeList().toViewConst(); + + static constexpr int maxNumDispFaceDof = 3 * 4; + + for( localIndex kfe=0; kfe eqnRowIndicesDisp ( numDispDof ); + stackArray1d< globalIndex, 3 > eqnRowIndicesBubble( 3 ); + stackArray1d< globalIndex, maxNumDispFaceDof > dofColIndicesDisp ( numDispDof ); + stackArray1d< globalIndex, 3 > dofColIndicesBubble( 3 ); + + for( localIndex idof = 0; idof < 3; ++idof ) + { + eqnRowIndicesBubble[idof] = bubbleDofNumber[kf] + idof - rankOffset; + dofColIndicesBubble[idof] = bubbleDofNumber[kf] + idof; + } + + for( localIndex a=0; a= 0 && eqnRowIndicesDisp[i] < pattern.numRows() ) + { + for( localIndex j = 0; j < dofColIndicesBubble.size(); ++j ) + { + pattern.insertNonZero( eqnRowIndicesDisp[i], dofColIndicesBubble[j] ); + } + } + } + + for( localIndex i = 0; i < eqnRowIndicesBubble.size(); ++i ) + { + if( eqnRowIndicesBubble[i] >= 0 && eqnRowIndicesBubble[i] < pattern.numRows() ) + { + for( localIndex j=0; j < dofColIndicesDisp.size(); ++j ) + { + pattern.insertNonZero( eqnRowIndicesBubble[i], dofColIndicesDisp[j] ); + } + } + } + + } + } + } ); + +} + +void SolidMechanicsAugmentedLagrangianContact::computeTolerances( DomainPartition & domain ) const +{ + GEOS_MARK_FUNCTION; + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + { + FaceManager const & faceManager = mesh.getFaceManager(); + NodeManager const & nodeManager = mesh.getNodeManager(); + ElementRegionManager & elemManager = mesh.getElemManager(); + + // Get the "face to element" map (valid for the entire mesh) + FaceManager::ElemMapType const & faceToElem = faceManager.toElementRelation(); + arrayView2d< localIndex const > const faceToElemRegion = faceToElem.m_toElementRegion; + arrayView2d< localIndex const > const faceToElemSubRegion = faceToElem.m_toElementSubRegion; + arrayView2d< localIndex const > const faceToElemIndex = faceToElem.m_toElementIndex; + + // Get the volume for all elements + ElementRegionManager::ElementViewAccessor< arrayView1d< real64 const > > const elemVolume = + elemManager.constructViewAccessor< array1d< real64 >, arrayView1d< real64 const > >( ElementSubRegionBase::viewKeyStruct::elementVolumeString() ); + + // Get the coordinates for all nodes + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const nodePosition = nodeManager.referencePosition(); + + // Bulk modulus accessor + ElementRegionManager::ElementViewAccessor< arrayView1d< real64 const > > const bulkModulus = + elemManager.constructMaterialViewAccessor< ElasticIsotropic, array1d< real64 >, arrayView1d< real64 const > >( ElasticIsotropic::viewKeyStruct::bulkModulusString() ); + // Shear modulus accessor + ElementRegionManager::ElementViewAccessor< arrayView1d< real64 const > > const shearModulus = + elemManager.constructMaterialViewAccessor< ElasticIsotropic, array1d< real64 >, arrayView1d< real64 const > >( ElasticIsotropic::viewKeyStruct::shearModulusString() ); + + using NodeMapViewType = arrayView2d< localIndex const, cells::NODE_MAP_USD >; + ElementRegionManager::ElementViewAccessor< NodeMapViewType > const elemToNode = + elemManager.constructViewAccessor< CellElementSubRegion::NodeMapType, NodeMapViewType >( ElementSubRegionBase::viewKeyStruct::nodeListString() ); + ElementRegionManager::ElementViewConst< NodeMapViewType > const elemToNodeView = elemToNode.toNestedViewConst(); + + elemManager.forElementSubRegions< FaceElementSubRegion >( [&]( FaceElementSubRegion & subRegion ) + { + if( subRegion.hasField< contact::traction >() ) + { + arrayView1d< real64 const > const faceArea = subRegion.getElementArea().toViewConst(); + arrayView3d< real64 const > const faceRotationMatrix = subRegion.getField< fields::contact::rotationMatrix >().toView(); + arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); + + arrayView1d< real64 > const normalTractionTolerance = + subRegion.getReference< array1d< real64 > >( viewKeyStruct::normalTractionToleranceString() ); + arrayView1d< real64 > const normalDisplacementTolerance = + subRegion.getReference< array1d< real64 > >( viewKeyStruct::normalDisplacementToleranceString() ); + arrayView1d< real64 > const slidingTolerance = + subRegion.getReference< array1d< real64 > >( viewKeyStruct::slidingToleranceString() ); + + arrayView2d< real64 > const + iterativePenalty = subRegion.getField< fields::contact::iterativePenalty >().toView(); + + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + + forAll< parallelHostPolicy >( subRegion.size(), [=] ( localIndex const kfe ) + { + + if( ghostRank[kfe] < 0 ) + { + real64 const area = faceArea[kfe]; + // approximation of the stiffness along coordinate directions + // ( first, second ) index -> ( element index, direction ) + // 1. T -> top (index 0), B -> bottom (index 1) + // 2. the coordinate direction (x, y, z) + real64 stiffDiagApprox[ 2 ][ 3 ]; + real64 averageYoungModulus = 0.0; + real64 averageConstrainedModulus = 0.0; + real64 averageBoxSize0 = 0.0; + + for( localIndex i = 0; i < 2; ++i ) + { + localIndex const faceIndex = elemsToFaces[kfe][i]; + localIndex const er = faceToElemRegion[faceIndex][0]; + localIndex const esr = faceToElemSubRegion[faceIndex][0]; + localIndex const ei = faceToElemIndex[faceIndex][0]; + + real64 const volume = elemVolume[er][esr][ei]; + + // Get the "element to node" map for the specific region/subregion + NodeMapViewType const & cellElemsToNodes = elemToNodeView[er][esr]; + localIndex const numNodesPerElem = cellElemsToNodes.size( 1 ); + + // Compute the box size + real64 maxSize[3]; + real64 minSize[3]; + for( localIndex j = 0; j < 3; ++j ) + { + maxSize[j] = nodePosition[cellElemsToNodes[ei][0]][j]; + minSize[j] = nodePosition[cellElemsToNodes[ei][0]][j]; + } + for( localIndex a = 1; a < numNodesPerElem; ++a ) + { + for( localIndex j = 0; j < 3; ++j ) + { + maxSize[j] = fmax( maxSize[j], nodePosition[cellElemsToNodes[ei][a]][j] ); + minSize[j] = fmin( minSize[j], nodePosition[cellElemsToNodes[ei][a]][j] ); + } + } + + real64 boxSize[3]; + for( localIndex j = 0; j < 3; ++j ) + { + boxSize[j] = maxSize[j] - minSize[j]; + } + + // Get linear elastic isotropic constitutive parameters for the element + real64 const K = bulkModulus[er][esr][ei]; + real64 const G = shearModulus[er][esr][ei]; + real64 const E = 9.0 * K * G / ( 3.0 * K + G ); + real64 const nu = ( 3.0 * K - 2.0 * G ) / ( 2.0 * ( 3.0 * K + G ) ); + real64 const M = K + 4.0 / 3.0 * G; + + // Combine E and nu to obtain a stiffness approximation (like it was an hexahedron) + for( localIndex j = 0; j < 3; ++j ) + { + stiffDiagApprox[ i ][ j ] = E / ( ( 1.0 + nu )*( 1.0 - 2.0*nu ) ) * 4.0 / 9.0 * ( 2.0 - 3.0 * nu ) * volume / ( boxSize[j]*boxSize[j] ); + } + + averageYoungModulus += 0.5*E; + averageConstrainedModulus += 0.5*M; + averageBoxSize0 += 0.5*boxSize[0]; + } + + // Average the stiffness and compute the inverse + real64 invStiffApprox[ 3 ][ 3 ] = { { 0 } }; + for( localIndex j = 0; j < 3; ++j ) + { + invStiffApprox[ j ][ j ] = ( stiffDiagApprox[ 0 ][ j ] + stiffDiagApprox[ 1 ][ j ] ) / ( stiffDiagApprox[ 0 ][ j ] * stiffDiagApprox[ 1 ][ j ] ); + } + + // Rotate in the local reference system, computing R^T * (invK) * R + real64 temp[ 3 ][ 3 ]; + LvArray::tensorOps::Rij_eq_AkiBkj< 3, 3, 3 >( temp, faceRotationMatrix[ kfe ], invStiffApprox ); + real64 rotatedInvStiffApprox[ 3 ][ 3 ]; + LvArray::tensorOps::Rij_eq_AikBkj< 3, 3, 3 >( rotatedInvStiffApprox, temp, faceRotationMatrix[ kfe ] ); + LvArray::tensorOps::scale< 3, 3 >( rotatedInvStiffApprox, area ); + + // Finally, compute tolerances for the given fracture element + normalDisplacementTolerance[kfe] = rotatedInvStiffApprox[ 0 ][ 0 ] * averageYoungModulus / 2.e+7; + slidingTolerance[kfe] = sqrt( pow( rotatedInvStiffApprox[ 1 ][ 1 ], 2 ) + + pow( rotatedInvStiffApprox[ 2 ][ 2 ], 2 )) * averageYoungModulus / 2.e+5; + normalTractionTolerance[kfe] = (1.0 / 2.0) * (averageConstrainedModulus / averageBoxSize0) * + (normalDisplacementTolerance[kfe]); + iterativePenalty[kfe][0] = 1e+01*averageConstrainedModulus/(averageBoxSize0*area); + iterativePenalty[kfe][1] = 1e-01*averageConstrainedModulus/(averageBoxSize0*area); + } + } ); + } + } ); + } ); +} + +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SolidMechanicsAugmentedLagrangianContact, string const &, Group * const ) +} /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/contact/SolidMechanicsAugmentedLagrangianContact.hpp b/src/coreComponents/physicsSolvers/contact/SolidMechanicsAugmentedLagrangianContact.hpp new file mode 100644 index 00000000000..0ed5d059b8a --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/SolidMechanicsAugmentedLagrangianContact.hpp @@ -0,0 +1,259 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/* + * SolidMechanicsAugmentedLagrangianContact.hpp + * + */ + +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSAUGMENTEDLAGRANGIANCONTACT_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSAUGMENTEDLAGRANGIANCONTACT_HPP_ + +#include "physicsSolvers/contact/ContactSolverBase.hpp" + +namespace geos +{ + +class SolidMechanicsAugmentedLagrangianContact : public ContactSolverBase +{ +public: + SolidMechanicsAugmentedLagrangianContact( const string & name, + Group * const parent ); + + ~SolidMechanicsAugmentedLagrangianContact() override; + + /** + * @brief name of the node manager in the object catalog + * @return string that contains the catalog name to generate a new NodeManager object through the object catalog. + */ + static string catalogName() + { + return "SolidMechanicsAugmentedLagrangianContact"; + } + /** + * @copydoc PhysicsSolverBase::getCatalogName() + */ + string getCatalogName() const override { return catalogName(); } + + virtual void registerDataOnMesh( dataRepository::Group & meshBodies ) override final; + + virtual void setupDofs( DomainPartition const & domain, + DofManager & dofManager ) const override; + + virtual void setupSystem( DomainPartition & domain, + DofManager & dofManager, + CRSMatrix< real64, globalIndex > & localMatrix, + ParallelVector & rhs, + ParallelVector & solution, + bool const setSparsity = true ) override final; + + virtual void implicitStepSetup( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) override final; + + virtual void implicitStepComplete( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) override final; + + virtual void assembleSystem( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) override; + + virtual real64 calculateResidualNorm( real64 const & time_n, + real64 const & dt, + DomainPartition const & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localRhs ) override; + + virtual void applySystemSolution( DofManager const & dofManager, + arrayView1d< real64 const > const & localSolution, + real64 const scalingFactor, + real64 const dt, + DomainPartition & domain ) override; + + void updateState( DomainPartition & domain ) override final; + + virtual bool updateConfiguration( DomainPartition & domain ) override final; + + + /** + * @brief Loop over the finite element type on the fracture subregions of meshName and apply callback. + * @tparam LAMBDA The callback function type + * @param meshName The mesh name. + * @param lambda The callback function. Take the finite element type name and + * the list of face element of the same type. + */ + template< typename LAMBDA > + void forFiniteElementOnFractureSubRegions( string const & meshName, LAMBDA && lambda ) const + { + + std::map< string, + array1d< localIndex > > const & faceTypesToFaceElements = m_faceTypesToFaceElements.at( meshName ); + + for( const auto & [finiteElementName, faceElementList] : faceTypesToFaceElements ) + { + arrayView1d< localIndex const > const faceElemList = faceElementList.toViewConst(); + + finiteElement::FiniteElementBase const & subRegionFE = *(m_faceTypeToFiniteElements.at( finiteElementName )); + + lambda( finiteElementName, subRegionFE, faceElemList ); + } + + } + + /** + * @brief Loop over the finite element type on the stick fracture subregions of meshName and apply callback. + * @tparam LAMBDA The callback function type + * @param meshName The mesh name. + * @param lambda The callback function. Take the finite element type name and + * the list of face element of the same type. + */ + template< typename LAMBDA > + void forFiniteElementOnStickFractureSubRegions( string const & meshName, LAMBDA && lambda ) const + { + + bool const isStickState = true; + + std::map< string, array1d< localIndex > > const & + faceTypesToFaceElements = m_faceTypesToFaceElementsStick.at( meshName ); + + for( const auto & [finiteElementName, faceElementList] : faceTypesToFaceElements ) + { + arrayView1d< localIndex const > const faceElemList = faceElementList.toViewConst(); + + finiteElement::FiniteElementBase const & subRegionFE = *(m_faceTypeToFiniteElements.at( finiteElementName )); + + lambda( finiteElementName, subRegionFE, faceElemList, isStickState ); + } + + } + + /** + * @brief Loop over the finite element type on the slip fracture subregions of meshName and apply callback. + * @tparam LAMBDA The callback function type + * @param meshName The mesh name. + * @param lambda The callback function. Take the finite element type name and + * the list of face element of the same type. + */ + template< typename LAMBDA > + void forFiniteElementOnSlipFractureSubRegions( string const & meshName, LAMBDA && lambda ) const + { + + bool const isStickState = false; + + std::map< string, array1d< localIndex > > const & + faceTypesToFaceElements = m_faceTypesToFaceElementsSlip.at( meshName ); + + for( const auto & [finiteElementName, faceElementList] : faceTypesToFaceElements ) + { + arrayView1d< localIndex const > const faceElemList = faceElementList.toViewConst(); + + finiteElement::FiniteElementBase const & subRegionFE = *(m_faceTypeToFiniteElements.at( finiteElementName )); + + lambda( finiteElementName, subRegionFE, faceElemList, isStickState ); + } + + } + + /** + * @brief Create the list of finite elements of the same type + * for each FaceElementSubRegion (Triangle or Quadrilateral) + * and of the same fracture state (Stick or Slip). + * @param domain The physical domain object + */ + void updateStickSlipList( DomainPartition const & domain ); + + /** + * @brief Create the list of finite elements of the same type + * for each FaceElementSubRegion (Triangle or Quadrilateral). + * @param domain The physical domain object + */ + void createFaceTypeList( DomainPartition const & domain ); + + /** + * @brief Create the list of elements belonging to CellElementSubRegion + * that are enriched with the bubble basis functions + * @param domain The physical domain object + */ + void createBubbleCellList( DomainPartition & domain ) const; + +private: + + /** + * @brief add the number of non-zero elements induced by the coupling between + * nodal and bubble displacement. + * @param domain the physical domain object + * @param dofManager degree-of-freedom manager associated with the linear system + * @param rowLengths the array containing the number of non-zero elements for each row + */ + void addCouplingNumNonzeros( DomainPartition & domain, + DofManager & dofManager, + arrayView1d< localIndex > const & rowLengths ) const; + + /** + * @Brief add the sparsity pattern induced by the coupling + * @param domain the physical domain object + * @param dofManager degree-of-freedom manager associated with the linear system + * @param pattern the sparsity pattern + */ + void addCouplingSparsityPattern( DomainPartition const & domain, + DofManager const & dofManager, + SparsityPatternView< globalIndex > const & pattern ) const; + + void computeTolerances( DomainPartition & domain ) const; + + /// Finite element type to face element index map + std::map< string, std::map< string, array1d< localIndex > > > m_faceTypesToFaceElements; + + /// Finite element type to face element index map (stick mode) + std::map< string, std::map< string, array1d< localIndex > > > m_faceTypesToFaceElementsStick; + + /// Finite element type to face element index map (slip mode) + std::map< string, std::map< string, array1d< localIndex > > > m_faceTypesToFaceElementsSlip; + + /// Finite element type to finite element object map + std::map< string, std::unique_ptr< geos::finiteElement::FiniteElementBase > > m_faceTypeToFiniteElements; + + struct viewKeyStruct : ContactSolverBase::viewKeyStruct + { + + constexpr static char const * normalDisplacementToleranceString() { return "normalDisplacementTolerance"; } + + constexpr static char const * normalTractionToleranceString() { return "normalTractionTolerance"; } + + constexpr static char const * slidingToleranceString() { return "slidingTolerance"; } + + constexpr static char const * dispJumpUpdPenaltyString() { return "dispJumpUpdPenalty"; } + }; + + /// Tolerance for the sliding check: the tangential traction must exceed (1 + m_slidingCheckTolerance) * t_lim to activate the sliding + /// condition + real64 const m_slidingCheckTolerance = 0.05; + + /// Flag to update the Lagrange multiplier at each Newton iteration (true), or only after the Newton loop has converged (false) + bool m_simultaneous = true; + + /// Flag to neglect the non-symmetric contribution in the tangential matrix, i.e., the derivative of tangential traction with respect to + /// the normal displacement is neglected + bool m_symmetric = true; + +}; + +} /* namespace geos */ + +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSAUGMENTEDLAGRANGIANCONTACT_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/contact/SolidMechanicsEmbeddedFractures.cpp b/src/coreComponents/physicsSolvers/contact/SolidMechanicsEmbeddedFractures.cpp index 0a082067cfa..b78afce691a 100644 --- a/src/coreComponents/physicsSolvers/contact/SolidMechanicsEmbeddedFractures.cpp +++ b/src/coreComponents/physicsSolvers/contact/SolidMechanicsEmbeddedFractures.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,7 +22,7 @@ #include "common/TimingMacros.hpp" #include "common/GEOS_RAJA_Interface.hpp" #include "constitutive/ConstitutiveManager.hpp" -#include "constitutive/contact/ContactSelector.hpp" +#include "constitutive/contact/FrictionSelector.hpp" #include "constitutive/solid/ElasticIsotropic.hpp" #include "fieldSpecification/FieldSpecificationManager.hpp" #include "finiteElement/elementFormulations/FiniteElementBase.hpp" @@ -31,9 +32,9 @@ #include "mesh/SurfaceElementRegion.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsFields.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp" -#include "physicsSolvers/contact/SolidMechanicsEFEMKernels.hpp" -#include "physicsSolvers/contact/SolidMechanicsEFEMStaticCondensationKernels.hpp" -#include "physicsSolvers/contact/SolidMechanicsEFEMJumpUpdateKernels.hpp" +#include "physicsSolvers/contact/kernels/SolidMechanicsEFEMKernels.hpp" +#include "physicsSolvers/contact/kernels/SolidMechanicsEFEMStaticCondensationKernels.hpp" +#include "physicsSolvers/contact/kernels/SolidMechanicsEFEMJumpUpdateKernels.hpp" namespace geos { @@ -50,6 +51,10 @@ SolidMechanicsEmbeddedFractures::SolidMechanicsEmbeddedFractures( const string & setInputFlag( InputFlags::OPTIONAL ). setApplyDefaultValue( 0 ). setDescription( "Defines whether to use static condensation or not." ); + + getWrapperBase( viewKeyStruct::contactPenaltyStiffnessString() ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Value of the penetration penalty stiffness. Units of Pressure/length" ); } SolidMechanicsEmbeddedFractures::~SolidMechanicsEmbeddedFractures() @@ -57,24 +62,39 @@ SolidMechanicsEmbeddedFractures::~SolidMechanicsEmbeddedFractures() // TODO Auto-generated destructor stub } -void SolidMechanicsEmbeddedFractures::postProcessInput() +void SolidMechanicsEmbeddedFractures::postInputInitialization() { - SolidMechanicsLagrangianFEM::postProcessInput(); - - LinearSolverParameters & linParams = m_linearSolverParameters.get(); + ContactSolverBase::postInputInitialization(); + LinearSolverParameters & linearSolverParameters = m_linearSolverParameters.get(); if( m_useStaticCondensation ) { - linParams.dofsPerNode = 3; - linParams.isSymmetric = true; - linParams.amg.separateComponents = true; + // configure AMG + linearSolverParameters.isSymmetric = true; + linearSolverParameters.amg.separateComponents = true; + linearSolverParameters.dofsPerNode = 3; } else { - linParams.mgr.strategy = LinearSolverParameters::MGR::StrategyType::solidMechanicsEmbeddedFractures; + setMGRStrategy(); } } +void SolidMechanicsEmbeddedFractures::setMGRStrategy() +{ + LinearSolverParameters & linearSolverParameters = m_linearSolverParameters.get(); + + if( linearSolverParameters.preconditionerType != LinearSolverParameters::PreconditionerType::mgr ) + return; + + linearSolverParameters.mgr.separateComponents = true; + linearSolverParameters.dofsPerNode = 3; + + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::solidMechanicsEmbeddedFractures; + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: MGR strategy set to {}", getName(), + EnumStrings< LinearSolverParameters::MGR::StrategyType >::toString( linearSolverParameters.mgr.strategy ))); +} + void SolidMechanicsEmbeddedFractures::registerDataOnMesh( dataRepository::Group & meshBodies ) { ContactSolverBase::registerDataOnMesh( meshBodies ); @@ -148,6 +168,20 @@ void SolidMechanicsEmbeddedFractures::implicitStepComplete( real64 const & time_ arrayView2d< real64 > oldDispJump = subRegion.getField< contact::oldDispJump >(); arrayView2d< real64 const > const dispJump = subRegion.getField< contact::dispJump >(); + // update elastic slip before copying dispJump to oldDispJump + string const & frictionLawName = subRegion.template getReference< string >( viewKeyStruct::frictionLawNameString() ); + FrictionBase const & frictionLaw = getConstitutiveModel< FrictionBase >( subRegion, frictionLawName ); + arrayView2d< real64 const > const & traction = subRegion.getField< fields::contact::traction >(); + arrayView1d< integer > const & fractureState = subRegion.getField< fields::contact::fractureState >(); + constitutiveUpdatePassThru( frictionLaw, [&] ( auto & castedFrictionLaw ) + { + using FrictionType = TYPEOFREF( castedFrictionLaw ); + typename FrictionType::KernelWrapper frictionWrapper = castedFrictionLaw.createKernelUpdates(); + + updateElasticSlip( subRegion, frictionWrapper, dispJump, oldDispJump, traction, fractureState ); + } ); + + // now update oldDispJump = dispJump forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) { @@ -156,6 +190,20 @@ void SolidMechanicsEmbeddedFractures::implicitStepComplete( real64 const & time_ } ); } +template< typename WRAPPER_TYPE > +void SolidMechanicsEmbeddedFractures::updateElasticSlip( EmbeddedSurfaceSubRegion const & subRegion, + WRAPPER_TYPE & frictionWrapper, + arrayView2d< real64 const > const & dispJump, + arrayView2d< real64 const > const & oldDispJump, + arrayView2d< real64 const > const & traction, + arrayView1d< integer > const & fractureState ) +{ + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const kfe ) + { + frictionWrapper.updateElasticSlip( kfe, dispJump[kfe], oldDispJump[kfe], traction[kfe], fractureState[kfe] ); + } ); +} + void SolidMechanicsEmbeddedFractures::setupDofs( DomainPartition const & domain, DofManager & dofManager ) const { @@ -236,10 +284,10 @@ void SolidMechanicsEmbeddedFractures::setupSystem( DomainPartition & domain, localMatrix.setName( this->getName() + "/localMatrix" ); rhs.setName( this->getName() + "/rhs" ); - rhs.create( dofManager.numLocalDofs(), MPI_COMM_GEOSX ); + rhs.create( dofManager.numLocalDofs(), MPI_COMM_GEOS ); solution.setName( this->getName() + "/solution" ); - solution.create( dofManager.numLocalDofs(), MPI_COMM_GEOSX ); + solution.create( dofManager.numLocalDofs(), MPI_COMM_GEOS ); } else { @@ -537,83 +585,90 @@ real64 SolidMechanicsEmbeddedFractures::calculateResidualNorm( real64 const & ti if( !m_useStaticCondensation ) { + real64 const fractureResidualNorm = calculateFractureResidualNorm( domain, dofManager, localRhs ); - string const jumpDofKey = dofManager.getKey( contact::dispJump::key() ); + return sqrt( solidResidualNorm * solidResidualNorm + fractureResidualNorm * fractureResidualNorm ); + } + else + { + return solidResidualNorm; + } +} - globalIndex const rankOffset = dofManager.rankOffset(); +real64 SolidMechanicsEmbeddedFractures::calculateFractureResidualNorm( DomainPartition const & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localRhs ) const +{ + string const jumpDofKey = dofManager.getKey( contact::dispJump::key() ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > localSum( 0.0 ); + globalIndex const rankOffset = dofManager.rankOffset(); - // globalResidualNorm[0]: the sum of all the local sum(rhs^2). - // globalResidualNorm[1]: max of max force of each rank. Basically max force globally - real64 globalResidualNorm[2] = {0, 0}; + RAJA::ReduceSum< parallelDeviceReduce, real64 > localSum( 0.0 ); - // Fracture residual - forFractureRegionOnMeshTargets( domain.getMeshBodies(), [&] ( SurfaceElementRegion const & fractureRegion ) + // globalResidualNorm[0]: the sum of all the local sum(rhs^2). + // globalResidualNorm[1]: max of max force of each rank. Basically max force globally + real64 globalResidualNorm[2] = {0.0, 0.0}; + + // Fracture residual + forFractureRegionOnMeshTargets( domain.getMeshBodies(), [&] ( SurfaceElementRegion const & fractureRegion ) + { + fractureRegion.forElementSubRegions< SurfaceElementSubRegion >( [&]( SurfaceElementSubRegion const & subRegion ) { - fractureRegion.forElementSubRegions< SurfaceElementSubRegion >( [&]( SurfaceElementSubRegion const & subRegion ) - { - arrayView1d< globalIndex const > const & - dofNumber = subRegion.getReference< array1d< globalIndex > >( jumpDofKey ); - arrayView1d< integer const > const & ghostRank = subRegion.ghostRank(); + arrayView1d< globalIndex const > const & + dofNumber = subRegion.getReference< array1d< globalIndex > >( jumpDofKey ); + arrayView1d< integer const > const & ghostRank = subRegion.ghostRank(); - forAll< parallelDevicePolicy<> >( subRegion.size(), - [localRhs, localSum, dofNumber, rankOffset, ghostRank] GEOS_HOST_DEVICE ( localIndex const k ) + forAll< parallelDevicePolicy<> >( subRegion.size(), + [localRhs, localSum, dofNumber, rankOffset, ghostRank] GEOS_HOST_DEVICE ( localIndex const k ) + { + if( ghostRank[k] < 0 ) { - if( ghostRank[k] < 0 ) + localIndex const localRow = LvArray::integerConversion< localIndex >( dofNumber[k] - rankOffset ); + for( int i = 0; i < 3; ++i ) { - localIndex const localRow = LvArray::integerConversion< localIndex >( dofNumber[k] - rankOffset ); - for( localIndex i = 0; i < 3; ++i ) - { - localSum += localRhs[localRow + i] * localRhs[localRow + i]; - } + localSum += localRhs[localRow + i] * localRhs[localRow + i]; } - } ); - + } } ); - real64 const localResidualNorm[2] = { localSum.get(), SolidMechanicsLagrangianFEM::getMaxForce() }; + } ); + real64 const localResidualNorm[2] = { localSum.get(), SolidMechanicsLagrangianFEM::getMaxForce() }; - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); - int const numRanks = MpiWrapper::commSize( MPI_COMM_GEOSX ); - array1d< real64 > globalValues( numRanks * 2 ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); + int const numRanks = MpiWrapper::commSize( MPI_COMM_GEOS ); + array1d< real64 > globalValues( numRanks * 2 ); - // Everything is done on rank 0 - MpiWrapper::gather( localResidualNorm, - 2, - globalValues.data(), - 2, - 0, - MPI_COMM_GEOSX ); + // Everything is done on rank 0 + MpiWrapper::gather( localResidualNorm, + 2, + globalValues.data(), + 2, + 0, + MPI_COMM_GEOS ); - if( rank==0 ) + if( rank==0 ) + { + for( int r=0; r= 1 && logger::internal::rank==0 ) - { - std::cout << GEOS_FMT( " ( RFracture ) = ( {:4.2e} )", fractureResidualNorm ); - } + real64 const fractureResidualNorm = sqrt( globalResidualNorm[0] )/(globalResidualNorm[1]+1); // the + 1 is for the first + // time-step when maxForce = 0; - return sqrt( solidResidualNorm * solidResidualNorm + fractureResidualNorm * fractureResidualNorm ); - } - else + if( getLogLevel() >= 1 && logger::internal::rank==0 ) { - return solidResidualNorm; + std::cout << GEOS_FMT( " ( RFracture ) = ( {:4.2e} )", fractureResidualNorm ); } + + return fractureResidualNorm; } void SolidMechanicsEmbeddedFractures::applySystemSolution( DofManager const & dofManager, @@ -710,8 +765,8 @@ void SolidMechanicsEmbeddedFractures::updateState( DomainPartition & domain ) { fractureRegion.forElementSubRegions< SurfaceElementSubRegion >( [&]( SurfaceElementSubRegion & subRegion ) { - string const & contactRelationName = subRegion.template getReference< string >( viewKeyStruct::contactRelationNameString() ); - ContactBase const & contact = getConstitutiveModel< ContactBase >( subRegion, contactRelationName ); + string const & frictionLawName = subRegion.template getReference< string >( viewKeyStruct::frictionLawNameString() ); + FrictionBase const & frictionLaw = getConstitutiveModel< FrictionBase >( subRegion, frictionLawName ); arrayView2d< real64 const > const & jump = subRegion.getField< contact::dispJump >(); @@ -723,19 +778,23 @@ void SolidMechanicsEmbeddedFractures::updateState( DomainPartition & domain ) arrayView1d< integer const > const & fractureState = subRegion.getField< contact::fractureState >(); - constitutiveUpdatePassThru( contact, [&] ( auto & castedContact ) + arrayView1d< real64 > const & slip = subRegion.getField< fields::contact::slip >(); + + constitutiveUpdatePassThru( frictionLaw, [&] ( auto & castedFrictionLaw ) { - using ContactType = TYPEOFREF( castedContact ); - typename ContactType::KernelWrapper contactWrapper = castedContact.createKernelWrapper(); + using FrictionType = TYPEOFREF( castedFrictionLaw ); + typename FrictionType::KernelWrapper frictionWrapper = castedFrictionLaw.createKernelUpdates(); solidMechanicsEFEMKernels::StateUpdateKernel:: launch< parallelDevicePolicy<> >( subRegion.size(), - contactWrapper, + frictionWrapper, + m_contactPenaltyStiffness, oldJump, jump, fractureTraction, dFractureTraction_dJump, - fractureState ); + fractureState, + slip ); } ); } ); } ); @@ -754,13 +813,13 @@ bool SolidMechanicsEmbeddedFractures::updateConfiguration( DomainPartition & dom arrayView2d< real64 const > const & traction = subRegion.getField< fields::contact::traction >(); arrayView1d< integer > const & fractureState = subRegion.getField< fields::contact::fractureState >(); - string const & contactRelationName = subRegion.template getReference< string >( viewKeyStruct::contactRelationNameString() ); - ContactBase const & contact = getConstitutiveModel< ContactBase >( subRegion, contactRelationName ); + string const & frictionLawName = subRegion.template getReference< string >( viewKeyStruct::frictionLawNameString() ); + FrictionBase const & frictionLaw = getConstitutiveModel< FrictionBase >( subRegion, frictionLawName ); - constitutiveUpdatePassThru( contact, [&] ( auto & castedContact ) + constitutiveUpdatePassThru( frictionLaw, [&] ( auto & castedFrictionLaw ) { - using ContactType = TYPEOFREF( castedContact ); - typename ContactType::KernelWrapper contactWrapper = castedContact.createKernelWrapper(); + using FrictionType = TYPEOFREF( castedFrictionLaw ); + typename FrictionType::KernelWrapper frictionWrapper = castedFrictionLaw.createKernelUpdates(); RAJA::ReduceMin< parallelHostReduce, integer > checkActiveSetSub( 1 ); @@ -769,7 +828,7 @@ bool SolidMechanicsEmbeddedFractures::updateConfiguration( DomainPartition & dom if( ghostRank[kfe] < 0 ) { integer const originalFractureState = fractureState[kfe]; - contactWrapper.updateFractureState( kfe, dispJump[kfe], traction[kfe], fractureState[kfe] ); + frictionWrapper.updateFractureState( dispJump[kfe], traction[kfe], fractureState[kfe] ); checkActiveSetSub.min( compareFractureStates( originalFractureState, fractureState[kfe] ) ); } } ); @@ -787,7 +846,7 @@ bool SolidMechanicsEmbeddedFractures::updateConfiguration( DomainPartition & dom &hasConfigurationConvergedGlobally, 1, MPI_LAND, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); // for this solver it makes sense to reset the state. // if( !hasConfigurationConvergedGlobally ) @@ -796,5 +855,5 @@ bool SolidMechanicsEmbeddedFractures::updateConfiguration( DomainPartition & dom return hasConfigurationConvergedGlobally; } -REGISTER_CATALOG_ENTRY( SolverBase, SolidMechanicsEmbeddedFractures, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SolidMechanicsEmbeddedFractures, string const &, Group * const ) } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/contact/SolidMechanicsEmbeddedFractures.hpp b/src/coreComponents/physicsSolvers/contact/SolidMechanicsEmbeddedFractures.hpp index 3069cfd28e6..384137706c9 100644 --- a/src/coreComponents/physicsSolvers/contact/SolidMechanicsEmbeddedFractures.hpp +++ b/src/coreComponents/physicsSolvers/contact/SolidMechanicsEmbeddedFractures.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -24,7 +25,6 @@ namespace geos { -using namespace constitutive; class SolidMechanicsEmbeddedFractures : public ContactSolverBase { @@ -43,7 +43,7 @@ class SolidMechanicsEmbeddedFractures : public ContactSolverBase return "SolidMechanicsEmbeddedFractures"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -63,6 +63,14 @@ class SolidMechanicsEmbeddedFractures : public ContactSolverBase real64 const & dt, DomainPartition & domain ) override final; + template< typename WRAPPER_TYPE > + static void updateElasticSlip( EmbeddedSurfaceSubRegion const & subRegion, + WRAPPER_TYPE & frictionWrapper, + arrayView2d< real64 const > const & dispJump, + arrayView2d< real64 const > const & oldDispJump, + arrayView2d< real64 const > const & traction, + arrayView1d< integer > const & fractureState ); + virtual void assembleSystem( real64 const time, real64 const dt, DomainPartition & domain, @@ -77,6 +85,10 @@ class SolidMechanicsEmbeddedFractures : public ContactSolverBase DofManager const & dofManager, arrayView1d< real64 const > const & localRhs ) override; + real64 calculateFractureResidualNorm( DomainPartition const & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localRhs ) const; + virtual void applySystemSolution( DofManager const & dofManager, arrayView1d< real64 const > const & localSolution, @@ -106,14 +118,24 @@ class SolidMechanicsEmbeddedFractures : public ContactSolverBase real64 const dt, DomainPartition & domain ); - virtual bool updateConfiguration( DomainPartition & domain ) override final; + bool useStaticCondensation() const { return m_useStaticCondensation; } + + struct viewKeyStruct : ContactSolverBase::viewKeyStruct + { + constexpr static char const * useStaticCondensationString() { return "useStaticCondensation"; } + + constexpr static char const * contactPenaltyStiffnessString() { return "contactPenaltyStiffness"; } + }; + protected: virtual void initializePostInitialConditionsPreSubGroups() override final; - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; + + void setMGRStrategy(); private: @@ -124,10 +146,9 @@ class SolidMechanicsEmbeddedFractures : public ContactSolverBase /// decide whether to use static condensation or not integer m_useStaticCondensation; - struct viewKeyStruct : ContactSolverBase::viewKeyStruct - { - constexpr static char const * useStaticCondensationString() { return "useStaticCondensation"; } - }; + // TODO: activate when solidMechanicsPenalty contact is used and this is removed from base solver. + // real64 m_contactPenaltyStiffness; + }; diff --git a/src/coreComponents/physicsSolvers/contact/SolidMechanicsLagrangeContact.cpp b/src/coreComponents/physicsSolvers/contact/SolidMechanicsLagrangeContact.cpp index 82502764d63..9a76b95632b 100644 --- a/src/coreComponents/physicsSolvers/contact/SolidMechanicsLagrangeContact.cpp +++ b/src/coreComponents/physicsSolvers/contact/SolidMechanicsLagrangeContact.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,12 +17,12 @@ * @file SolidMechanicsLagrangeContact.cpp * */ - +#define GEOS_DISPATCH_VEM #include "SolidMechanicsLagrangeContact.hpp" #include "common/TimingMacros.hpp" #include "constitutive/ConstitutiveManager.hpp" -#include "constitutive/contact/ContactSelector.hpp" +#include "constitutive/contact/FrictionSelector.hpp" #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" #include "finiteVolume/FiniteVolumeManager.hpp" #include "finiteVolume/FluxApproximationBase.hpp" @@ -34,6 +35,7 @@ #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" // needed to register pressure(_n) #include "physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp" #include "physicsSolvers/contact/ContactFields.hpp" +#include "physicsSolvers/contact/LogLevelsInfo.hpp" #include "common/GEOS_RAJA_Interface.hpp" #include "linearAlgebra/utilities/LAIHelperFunctions.hpp" #include "linearAlgebra/solvers/PreconditionerJacobi.hpp" @@ -54,6 +56,7 @@ using namespace constitutive; using namespace dataRepository; using namespace fields; using namespace finiteElement; +const localIndex geos::SolidMechanicsLagrangeContact::m_maxFaceNodes = 11; SolidMechanicsLagrangeContact::SolidMechanicsLagrangeContact( const string & name, Group * const parent ): @@ -64,11 +67,34 @@ SolidMechanicsLagrangeContact::SolidMechanicsLagrangeContact( const string & nam setInputFlag( InputFlags::REQUIRED ). setDescription( "Name of the stabilization to use in the lagrangian contact solver" ); - LinearSolverParameters & linSolParams = m_linearSolverParameters.get(); - linSolParams.mgr.strategy = LinearSolverParameters::MGR::StrategyType::lagrangianContactMechanics; - linSolParams.mgr.separateComponents = true; - linSolParams.mgr.displacementFieldName = solidMechanics::totalDisplacement::key(); - linSolParams.dofsPerNode = 3; + registerWrapper( viewKeyStruct::stabilizationScalingCoefficientString(), &m_stabilitzationScalingCoefficient ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( 1.0 ). + setDescription( "It be used to increase the scale of the stabilization entries. A value < 1.0 results in larger entries in the stabilization matrix." ); + + addLogLevel< logInfo::Configuration >(); +} + +void SolidMechanicsLagrangeContact::postInputInitialization() +{ + ContactSolverBase::postInputInitialization(); + + setMGRStrategy(); +} + +void SolidMechanicsLagrangeContact::setMGRStrategy() +{ + LinearSolverParameters & linearSolverParameters = m_linearSolverParameters.get(); + + if( linearSolverParameters.preconditionerType != LinearSolverParameters::PreconditionerType::mgr ) + return; + + linearSolverParameters.mgr.separateComponents = true; + linearSolverParameters.dofsPerNode = 3; + + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::lagrangianContactMechanics; + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: MGR strategy set to {}", getName(), + EnumStrings< LinearSolverParameters::MGR::StrategyType >::toString( linearSolverParameters.mgr.strategy ))); } void SolidMechanicsLagrangeContact::registerDataOnMesh( Group & meshBodies ) @@ -147,18 +173,18 @@ void SolidMechanicsLagrangeContact::initializePreSubGroups() fluxApprox.addFieldName( contact::traction::key() ); fluxApprox.setCoeffName( "penaltyStiffness" ); + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshBodyName, - MeshLevel &, + MeshLevel & mesh, arrayView1d< string const > const & regionNames ) { - array1d< string > & stencilTargetRegions = fluxApprox.targetRegions( meshBodyName ); - std::set< string > stencilTargetRegionsSet( stencilTargetRegions.begin(), stencilTargetRegions.end() ); - stencilTargetRegionsSet.insert( regionNames.begin(), regionNames.end() ); - stencilTargetRegions.clear(); - for( auto const & targetRegion: stencilTargetRegionsSet ) + mesh.getElemManager().forElementRegions< SurfaceElementRegion >( regionNames, + [&]( localIndex const, + SurfaceElementRegion const & region ) { - stencilTargetRegions.emplace_back( targetRegion ); - } + array1d< string > & stencilTargetRegions = fluxApprox.targetRegions( meshBodyName ); + stencilTargetRegions.emplace_back( region.getName() ); + } ); } ); } @@ -177,7 +203,7 @@ void SolidMechanicsLagrangeContact::setupSystem( DomainPartition & domain, } // setup monolithic coupled system - SolverBase::setupSystem( domain, dofManager, localMatrix, rhs, solution, true ); // "true" is to force setSparsity + PhysicsSolverBase::setupSystem( domain, dofManager, localMatrix, rhs, solution, true ); // "true" is to force setSparsity if( !m_precond && m_linearSolverParameters.get().solverType != LinearSolverParameters::SolverType::direct ) { @@ -247,6 +273,13 @@ void SolidMechanicsLagrangeContact::computeTolerances( DomainPartition & domain { GEOS_MARK_FUNCTION; + real64 minNormalTractionTolerance( 1e10 ); + real64 maxNormalTractionTolerance( -1e10 ); + real64 minNormalDisplacementTolerance( 1e10 ); + real64 maxNormalDisplacementTolerance( -1e10 ); + real64 minSlidingTolerance( 1e10 ); + real64 maxSlidingTolerance( -1e10 ); + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & mesh, arrayView1d< string const > const & ) @@ -287,7 +320,7 @@ void SolidMechanicsLagrangeContact::computeTolerances( DomainPartition & domain arrayView1d< integer const > const & ghostRank = subRegion.ghostRank(); arrayView1d< real64 const > const & faceArea = subRegion.getElementArea().toViewConst(); arrayView3d< real64 const > const & faceRotationMatrix = subRegion.getReference< array3d< real64 > >( viewKeyStruct::rotationMatrixString() ); - ArrayOfArraysView< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); + arrayView2d< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); arrayView1d< real64 > const & normalTractionTolerance = subRegion.getReference< array1d< real64 > >( viewKeyStruct::normalTractionToleranceString() ); @@ -296,6 +329,13 @@ void SolidMechanicsLagrangeContact::computeTolerances( DomainPartition & domain arrayView1d< real64 > const & slidingTolerance = subRegion.getReference< array1d< real64 > >( viewKeyStruct::slidingToleranceString() ); + RAJA::ReduceMin< ReducePolicy< parallelHostPolicy >, real64 > minSubRegionNormalTractionTolerance( 1e10 ); + RAJA::ReduceMax< ReducePolicy< parallelHostPolicy >, real64 > maxSubRegionNormalTractionTolerance( -1e10 ); + RAJA::ReduceMin< ReducePolicy< parallelHostPolicy >, real64 > minSubRegionNormalDisplacementTolerance( 1e10 ); + RAJA::ReduceMax< ReducePolicy< parallelHostPolicy >, real64 > maxSubRegionNormalDisplacementTolerance( -1e10 ); + RAJA::ReduceMin< ReducePolicy< parallelHostPolicy >, real64 > minSubRegionSlidingTolerance( 1e10 ); + RAJA::ReduceMax< ReducePolicy< parallelHostPolicy >, real64 > maxSubRegionSlidingTolerance( -1e10 ); + forAll< parallelHostPolicy >( subRegion.size(), [=] ( localIndex const kfe ) { if( ghostRank[kfe] < 0 ) @@ -310,7 +350,7 @@ void SolidMechanicsLagrangeContact::computeTolerances( DomainPartition & domain real64 averageConstrainedModulus = 0.0; real64 averageBoxSize0 = 0.0; - for( localIndex i = 0; i < elemsToFaces.sizeOfArray( kfe ); ++i ) + for( localIndex i = 0; i < 2; ++i ) { localIndex const faceIndex = elemsToFaces[kfe][i]; localIndex const er = faceToElemRegion[faceIndex][0]; @@ -379,15 +419,37 @@ void SolidMechanicsLagrangeContact::computeTolerances( DomainPartition & domain LvArray::tensorOps::scale< 3, 3 >( rotatedInvStiffApprox, area ); // Finally, compute tolerances for the given fracture element + normalDisplacementTolerance[kfe] = rotatedInvStiffApprox[ 0 ][ 0 ] * averageYoungModulus / 2.e+7; + minSubRegionNormalDisplacementTolerance.min( normalDisplacementTolerance[kfe] ); + maxSubRegionNormalDisplacementTolerance.max( normalDisplacementTolerance[kfe] ); + slidingTolerance[kfe] = sqrt( rotatedInvStiffApprox[ 1 ][ 1 ] * rotatedInvStiffApprox[ 1 ][ 1 ] + rotatedInvStiffApprox[ 2 ][ 2 ] * rotatedInvStiffApprox[ 2 ][ 2 ] ) * averageYoungModulus / 2.e+7; + minSubRegionSlidingTolerance.min( slidingTolerance[kfe] ); + maxSubRegionSlidingTolerance.max( slidingTolerance[kfe] ); + normalTractionTolerance[kfe] = 1.0 / 2.0 * averageConstrainedModulus / averageBoxSize0 * normalDisplacementTolerance[kfe]; + minSubRegionNormalTractionTolerance.min( normalTractionTolerance[kfe] ); + maxSubRegionNormalTractionTolerance.max( normalTractionTolerance[kfe] ); } } ); + + minNormalDisplacementTolerance = std::min( minNormalDisplacementTolerance, minSubRegionNormalDisplacementTolerance.get() ); + maxNormalDisplacementTolerance = std::max( maxNormalDisplacementTolerance, maxSubRegionNormalDisplacementTolerance.get() ); + minSlidingTolerance = std::min( minSlidingTolerance, minSubRegionSlidingTolerance.get() ); + maxSlidingTolerance = std::max( maxSlidingTolerance, maxSubRegionSlidingTolerance.get() ); + minNormalTractionTolerance = std::min( minNormalTractionTolerance, minSubRegionNormalTractionTolerance.get() ); + maxNormalTractionTolerance = std::max( maxNormalTractionTolerance, maxSubRegionNormalTractionTolerance.get() ); } } ); } ); + + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Configuration, + GEOS_FMT( "{}: normal displacement tolerance = [{}, {}], sliding tolerance = [{}, {}], normal traction tolerance = [{}, {}]", + this->getName(), minNormalDisplacementTolerance, maxNormalDisplacementTolerance, + minSlidingTolerance, maxSlidingTolerance, + minNormalTractionTolerance, maxNormalTractionTolerance ) ); } void SolidMechanicsLagrangeContact::resetStateToBeginningOfStep( DomainPartition & domain ) @@ -433,13 +495,18 @@ void SolidMechanicsLagrangeContact::computeFaceDisplacementJump( DomainPartition { NodeManager const & nodeManager = mesh.getNodeManager(); FaceManager & faceManager = mesh.getFaceManager(); + EdgeManager const & edgeManager = mesh.getEdgeManager(); ElementRegionManager & elemManager = mesh.getElemManager(); - // Get the coordinates for all nodes - arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & nodePosition = nodeManager.referencePosition(); - ArrayOfArraysView< localIndex const > const faceToNodeMap = faceManager.nodeList().toViewConst(); + ArrayOfArraysView< localIndex const > const faceToEdgeMap = faceManager.edgeList().toViewConst(); + arrayView2d< localIndex const > const & edgeToNodeMap = edgeManager.nodeList().toViewConst(); + arrayView2d< real64 const > faceCenters = faceManager.faceCenter(); + arrayView2d< real64 const > faceNormals = faceManager.faceNormal(); + arrayView1d< real64 const > faceAreas = faceManager.faceArea(); + // Get the coordinates for all nodes + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & nodePosition = nodeManager.referencePosition(); arrayView2d< real64 const, nodes::TOTAL_DISPLACEMENT_USD > const & u = nodeManager.getField< solidMechanics::totalDisplacement >(); @@ -451,23 +518,40 @@ void SolidMechanicsLagrangeContact::computeFaceDisplacementJump( DomainPartition { arrayView3d< real64 > const & rotationMatrix = subRegion.getReference< array3d< real64 > >( viewKeyStruct::rotationMatrixString() ); - ArrayOfArraysView< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); - arrayView2d< real64 > const & dispJump = subRegion.getField< contact::dispJump >(); + arrayView2d< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); arrayView1d< real64 const > const & area = subRegion.getElementArea().toViewConst(); + arrayView2d< real64 > const dispJump = subRegion.getField< contact::dispJump >(); + arrayView1d< real64 > const slip = subRegion.getField< fields::contact::slip >(); + arrayView1d< real64 > const aperture = subRegion.getField< fields::elementAperture >(); + forAll< parallelHostPolicy >( subRegion.size(), [=] ( localIndex const kfe ) { - if( elemsToFaces.sizeOfArray( kfe ) != 2 ) - { - return; - } // Contact constraints localIndex const numNodesPerFace = faceToNodeMap.sizeOfArray( elemsToFaces[kfe][0] ); - array1d< real64 > nodalArea0, nodalArea1; - computeFaceNodalArea( nodePosition, faceToNodeMap, elemsToFaces[kfe][0], nodalArea0 ); - computeFaceNodalArea( nodePosition, faceToNodeMap, elemsToFaces[kfe][1], nodalArea1 ); + stackArray1d< real64, FaceManager::maxFaceNodes() > nodalArea0; + stackArray1d< real64, FaceManager::maxFaceNodes() > nodalArea1; + computeFaceNodalArea( elemsToFaces[kfe][0], + nodePosition, + faceToNodeMap, + faceToEdgeMap, + edgeToNodeMap, + faceCenters, + faceNormals, + faceAreas, + nodalArea0 ); + + computeFaceNodalArea( elemsToFaces[kfe][1], + nodePosition, + faceToNodeMap, + faceToEdgeMap, + edgeToNodeMap, + faceCenters, + faceNormals, + faceAreas, + nodalArea1 ); real64 globalJumpTemp[ 3 ] = { 0 }; for( localIndex a = 0; a < numNodesPerFace; ++a ) @@ -483,6 +567,10 @@ void SolidMechanicsLagrangeContact::computeFaceDisplacementJump( DomainPartition real64 dispJumpTemp[ 3 ]; LvArray::tensorOps::Ri_eq_AjiBj< 3, 3 >( dispJumpTemp, rotationMatrix[ kfe ], globalJumpTemp ); LvArray::tensorOps::copy< 3 >( dispJump[ kfe ], dispJumpTemp ); + + slip[ kfe ] = LvArray::math::sqrt( LvArray::math::square( dispJump( kfe, 1 ) ) + + LvArray::math::square( dispJump( kfe, 2 ) ) ); + aperture[ kfe ] = dispJump[ kfe ][ 0 ]; } ); } } ); @@ -518,15 +606,16 @@ void SolidMechanicsLagrangeContact::setupDofs( DomainPartition const & domain, 3, meshTargets ); - dofManager.addCoupling( contact::traction::key(), - contact::traction::key(), - DofManager::Connector::Face, - meshTargets ); - dofManager.addCoupling( solidMechanics::totalDisplacement::key(), contact::traction::key(), DofManager::Connector::Elem, meshTargets ); + + NumericalMethodsManager const & numericalMethodManager = domain.getNumericalMethodManager(); + FiniteVolumeManager const & fvManager = numericalMethodManager.getFiniteVolumeManager(); + FluxApproximationBase const & stabilizationMethod = fvManager.getFluxApproximation( m_stabilizationName ); + + dofManager.addCoupling( contact::traction::key(), stabilizationMethod ); } void SolidMechanicsLagrangeContact::assembleSystem( real64 const time, @@ -548,6 +637,17 @@ void SolidMechanicsLagrangeContact::assembleSystem( real64 const time, localRhs ); assembleContact( domain, dofManager, localMatrix, localRhs ); + + // for sequential: add (fixed) pressure force contribution into residual (no derivatives) + if( m_isFixedStressPoromechanicsUpdate ) + { + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) + { + assembleForceResidualPressureContribution( mesh, regionNames, dofManager, localMatrix, localRhs ); + } ); + } } void SolidMechanicsLagrangeContact::assembleContact( DomainPartition & domain, @@ -568,127 +668,210 @@ void SolidMechanicsLagrangeContact::assembleContact( DomainPartition & domain, } ); } -real64 SolidMechanicsLagrangeContact::calculateResidualNorm( real64 const & time, - real64 const & dt, - DomainPartition const & domain, - DofManager const & dofManager, - arrayView1d< real64 const > const & localRhs ) +void SolidMechanicsLagrangeContact:: + assembleForceResidualPressureContribution( MeshLevel const & mesh, + arrayView1d< string const > const & regionNames, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; - real64 const solidResidual = SolidMechanicsLagrangianFEM::calculateResidualNorm( time, dt, domain, dofManager, localRhs ); + FaceManager const & faceManager = mesh.getFaceManager(); + NodeManager const & nodeManager = mesh.getNodeManager(); + EdgeManager const & edgeManager = mesh.getEdgeManager(); + ElementRegionManager const & elemManager = mesh.getElemManager(); - real64 momentumR2 = 0.0; - real64 contactR2 = 0.0; + ArrayOfArraysView< localIndex const > const faceToNodeMap = faceManager.nodeList().toViewConst(); + ArrayOfArraysView< localIndex const > const faceToEdgeMap = faceManager.edgeList().toViewConst(); + arrayView2d< localIndex const > const & edgeToNodeMap = edgeManager.nodeList().toViewConst(); + arrayView2d< real64 const > faceCenters = faceManager.faceCenter(); + arrayView2d< real64 const > faceNormal = faceManager.faceNormal(); + arrayView1d< real64 const > faceAreas = faceManager.faceArea(); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) - { - NodeManager const & nodeManager = mesh.getNodeManager(); - arrayView1d< globalIndex const > const & dispDofNumber = - nodeManager.getReference< array1d< globalIndex > >( dofManager.getKey( solidMechanics::totalDisplacement::key() ) ); + string const & dispDofKey = dofManager.getKey( solidMechanics::totalDisplacement::key() ); - string const & dofKey = dofManager.getKey( contact::traction::key() ); - globalIndex const rankOffset = dofManager.rankOffset(); + arrayView1d< globalIndex const > const & + dispDofNumber = nodeManager.getReference< globalIndex_array >( dispDofKey ); + globalIndex const rankOffset = dofManager.rankOffset(); - arrayView1d< integer const > const & elemGhostRank = nodeManager.ghostRank(); + // Get the coordinates for all nodes + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & nodePosition = nodeManager.referencePosition(); + + elemManager.forElementSubRegions< FaceElementSubRegion >( regionNames, + [&]( localIndex const, + FaceElementSubRegion const & subRegion ) + { + arrayView1d< real64 const > const & pressure = subRegion.getReference< array1d< real64 > >( flow::pressure::key() ); + arrayView2d< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); - RAJA::ReduceSum< parallelDeviceReduce, real64 > localSum0( 0.0 ); - forAll< parallelDevicePolicy<> >( nodeManager.size(), - [localRhs, localSum0, dispDofNumber, rankOffset, elemGhostRank] GEOS_HOST_DEVICE ( localIndex const k ) + forAll< serialPolicy >( subRegion.size(), [=]( localIndex const kfe ) { - if( elemGhostRank[k] < 0 ) + localIndex const kf0 = elemsToFaces[kfe][0]; + localIndex const numNodesPerFace = faceToNodeMap.sizeOfArray( kf0 ); + + real64 Nbar[3]; + Nbar[ 0 ] = faceNormal[elemsToFaces[kfe][0]][0] - faceNormal[elemsToFaces[kfe][1]][0]; + Nbar[ 1 ] = faceNormal[elemsToFaces[kfe][0]][1] - faceNormal[elemsToFaces[kfe][1]][1]; + Nbar[ 2 ] = faceNormal[elemsToFaces[kfe][0]][2] - faceNormal[elemsToFaces[kfe][1]][2]; + LvArray::tensorOps::normalize< 3 >( Nbar ); + + globalIndex rowDOF[3 * m_maxFaceNodes]; + real64 nodeRHS[3 * m_maxFaceNodes]; + stackArray1d< real64, 3 * m_maxFaceNodes > dRdP( 3*m_maxFaceNodes ); + + for( localIndex kf=0; kf<2; ++kf ) { - localIndex const localRow = LvArray::integerConversion< localIndex >( dispDofNumber[k] - rankOffset ); - for( localIndex dim = 0; dim < 3; ++dim ) + localIndex const faceIndex = elemsToFaces[kfe][kf]; + // Compute local area contribution for each node + stackArray1d< real64, FaceManager::maxFaceNodes() > nodalArea; + computeFaceNodalArea( elemsToFaces[kfe][kf], + nodePosition, + faceToNodeMap, + faceToEdgeMap, + edgeToNodeMap, + faceCenters, + faceNormal, + faceAreas, + nodalArea ); + + for( localIndex a=0; a( globalNodalForce, Nbar, nodalForceMag ); + + for( localIndex i=0; i<3; ++i ) + { + rowDOF[3*a+i] = dispDofNumber[faceToNodeMap( faceIndex, a )] + LvArray::integerConversion< globalIndex >( i ); + // Opposite sign w.r.t. theory because of minus sign in stiffness matrix definition (K < 0) + nodeRHS[3*a+i] = +globalNodalForce[i] * pow( -1, kf ); + } + } + + for( localIndex idof = 0; idof < numNodesPerFace * 3; ++idof ) { - localSum0 += localRhs[localRow + dim] * localRhs[localRow + dim]; + localIndex const localRow = LvArray::integerConversion< localIndex >( rowDOF[idof] - rankOffset ); + + if( localRow >= 0 && localRow < localMatrix.numRows() ) + { + RAJA::atomicAdd( parallelHostAtomic{}, &localRhs[localRow], nodeRHS[idof] ); + } } } } ); - momentumR2 += localSum0.get(); + } ); +} +real64 SolidMechanicsLagrangeContact::calculateResidualNorm( real64 const & time, + real64 const & dt, + DomainPartition const & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localRhs ) +{ + GEOS_MARK_FUNCTION; + + real64 const solidResidual = SolidMechanicsLagrangianFEM::calculateResidualNorm( time, dt, domain, dofManager, localRhs ); + + real64 const contactResidual = calculateContactResidualNorm( domain, dofManager, localRhs ); + + return sqrt( solidResidual * solidResidual + contactResidual * contactResidual ); +} + +real64 SolidMechanicsLagrangeContact::calculateContactResidualNorm( DomainPartition const & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localRhs ) +{ + string const & dofKey = dofManager.getKey( contact::traction::key() ); + globalIndex const rankOffset = dofManager.rankOffset(); + + real64 stickResidual = 0.0; + real64 slipResidual = 0.0; + real64 slipNormalizer = 0.0; + real64 openResidual = 0.0; + real64 openNormalizer = 0.0; + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) + { mesh.getElemManager().forElementSubRegions< FaceElementSubRegion >( regionNames, [&]( localIndex const, FaceElementSubRegion const & subRegion ) { arrayView1d< globalIndex const > const & dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); arrayView1d< integer const > const & ghostRank = subRegion.ghostRank(); + arrayView1d< integer const > const & fractureState = subRegion.getField< contact::fractureState >(); + arrayView1d< real64 const > const & area = subRegion.getElementArea(); - RAJA::ReduceSum< parallelHostReduce, real64 > localSum( 0.0 ); + RAJA::ReduceSum< parallelHostReduce, real64 > stickSum( 0.0 ); + RAJA::ReduceSum< parallelHostReduce, real64 > slipSum( 0.0 ); + RAJA::ReduceMax< parallelHostReduce, real64 > slipMax( 0.0 ); + RAJA::ReduceSum< parallelHostReduce, real64 > openSum( 0.0 ); + RAJA::ReduceMax< parallelHostReduce, real64 > openMax( 0.0 ); forAll< parallelHostPolicy >( subRegion.size(), [=] ( localIndex const k ) { if( ghostRank[k] < 0 ) { localIndex const localRow = LvArray::integerConversion< localIndex >( dofNumber[k] - rankOffset ); - for( localIndex dim = 0; dim < 3; ++dim ) + switch( fractureState[k] ) { - localSum += localRhs[localRow + dim] * localRhs[localRow + dim]; + case contact::FractureState::Stick: + { + for( localIndex dim = 0; dim < 3; ++dim ) + { + real64 const norm = localRhs[localRow + dim] / area[k]; + stickSum += norm * norm; + } + break; + } + case contact::FractureState::Slip: + case contact::FractureState::NewSlip: + { + for( localIndex dim = 0; dim < 3; ++dim ) + { + slipSum += localRhs[localRow + dim] * localRhs[localRow + dim]; + slipMax.max( LvArray::math::abs( localRhs[localRow + dim] ) ); + } + break; + } + case contact::FractureState::Open: + { + for( localIndex dim = 0; dim < 3; ++dim ) + { + openSum += localRhs[localRow + dim] * localRhs[localRow + dim]; + openMax.max( LvArray::math::abs( localRhs[localRow + dim] ) ); + } + break; + } } } } ); - contactR2 += localSum.get(); + + stickResidual += stickSum.get(); + slipResidual += slipSum.get(); + slipNormalizer = LvArray::math::max( slipNormalizer, slipMax.get()); + openResidual += openSum.get(); + openNormalizer = LvArray::math::max( openNormalizer, openMax.get()); } ); } ); - real64 localR2[2] = { momentumR2, contactR2 }; - real64 globalResidualNorm[3]{}; - - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); - int const size = MpiWrapper::commSize( MPI_COMM_GEOSX ); - array1d< real64 > globalR2( 2 * size ); - globalR2.zero(); - - // Everything is done on rank 0 - MpiWrapper::gather( localR2, - 2, - globalR2.data(), - 2, - 0, - MPI_COMM_GEOSX ); - - if( rank==0 ) - { - globalResidualNorm[0] = 0.0; - globalResidualNorm[1] = 0.0; - for( int r=0; r= 1 && logger::internal::rank == 0 ) + slipResidual = MpiWrapper::sum( slipResidual ); + slipNormalizer = MpiWrapper::max( slipNormalizer ); + slipResidual = sqrt( slipResidual ) / ( slipNormalizer + 1.0 ); + + openResidual = MpiWrapper::sum( openResidual ); + openNormalizer = MpiWrapper::max( openNormalizer ); + openResidual = sqrt( openResidual ) / ( openNormalizer + 1.0 ); + + if( getLogLevel() >= 1 && logger::internal::rank==0 ) { - std::cout<< GEOS_FMT( - " ( Rdisplacement, Rtraction, Rtotal ) = ( {:15.6e}, {:15.6e}, {:15.6e} )", - globalResidualNorm[0], - globalResidualNorm[1], - globalResidualNorm[2] ); + std::cout << GEOS_FMT( " ( Rstick Rslip Ropen ) = ( {:15.6e} {:15.6e} {:15.6e} )", stickResidual, slipResidual, openResidual ); } - return sqrt( globalResidualNorm[2]*globalResidualNorm[2] + solidResidual*solidResidual ); + + return sqrt( stickResidual * stickResidual + slipResidual * slipResidual + openResidual * openResidual ); } void SolidMechanicsLagrangeContact::createPreconditioner( DomainPartition const & domain ) @@ -770,59 +953,281 @@ void SolidMechanicsLagrangeContact::computeRotationMatrices( DomainPartition & d arrayView1d< string const > const & regionNames ) { FaceManager const & faceManager = mesh.getFaceManager(); - ElementRegionManager & elemManager = mesh.getElemManager(); - arrayView2d< real64 const > const & faceNormal = faceManager.faceNormal(); + arrayView2d< real64 const > const faceNormal = faceManager.faceNormal(); - elemManager.forElementSubRegions< FaceElementSubRegion >( regionNames, - [&]( localIndex const, - FaceElementSubRegion & subRegion ) + mesh.getElemManager().forElementSubRegions< FaceElementSubRegion >( regionNames, + [&]( localIndex const, + FaceElementSubRegion & subRegion ) { - ArrayOfArraysView< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); + arrayView2d< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); arrayView3d< real64 > const & rotationMatrix = subRegion.getReference< array3d< real64 > >( viewKeyStruct::rotationMatrixString() ); + arrayView2d< real64 > const unitNormal = subRegion.getNormalVector(); + arrayView2d< real64 > const unitTangent1 = subRegion.getTangentVector1(); + arrayView2d< real64 > const unitTangent2 = subRegion.getTangentVector2(); forAll< parallelHostPolicy >( subRegion.size(), [=]( localIndex const kfe ) { - if( elemsToFaces.sizeOfArray( kfe ) != 2 ) - { - return; - } + + + localIndex const f0 = elemsToFaces[kfe][0]; + localIndex const f1 = elemsToFaces[kfe][1]; stackArray1d< real64, 3 > Nbar( 3 ); - localIndex const & f0 = elemsToFaces[kfe][0], f1 = elemsToFaces[kfe][1]; Nbar[ 0 ] = faceNormal[f0][0] - faceNormal[f1][0]; Nbar[ 1 ] = faceNormal[f0][1] - faceNormal[f1][1]; Nbar[ 2 ] = faceNormal[f0][2] - faceNormal[f1][2]; LvArray::tensorOps::normalize< 3 >( Nbar ); computationalGeometry::RotationMatrix_3D( Nbar.toSliceConst(), rotationMatrix[kfe] ); + real64 const columnVector1[3] = { rotationMatrix[kfe][ 0 ][ 1 ], + rotationMatrix[kfe][ 1 ][ 1 ], + rotationMatrix[kfe][ 2 ][ 1 ] }; + + real64 const columnVector2[3] = { rotationMatrix[kfe][ 0 ][ 2 ], + rotationMatrix[kfe][ 1 ][ 2 ], + rotationMatrix[kfe][ 2 ][ 2 ] }; + + LvArray::tensorOps::copy< 3 >( unitNormal[kfe], Nbar ); + LvArray::tensorOps::copy< 3 >( unitTangent1[kfe], columnVector1 ); + LvArray::tensorOps::copy< 3 >( unitTangent2[kfe], columnVector2 ); } ); } ); } ); } -void SolidMechanicsLagrangeContact::computeFaceNodalArea( arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & nodePosition, - ArrayOfArraysView< localIndex const > const & faceToNodeMap, - localIndex const kf0, - array1d< real64 > & nodalArea ) const +void SolidMechanicsLagrangeContact::computeFaceIntegrals( arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & nodesCoords, + localIndex const (&faceToNodes)[11], + localIndex const (&faceToEdges)[11], + localIndex const & numFaceVertices, + real64 const & faceArea, + real64 const (&faceCenter)[3], + real64 const (&faceNormal)[3], + arrayView2d< localIndex const > const & edgeToNodes, + real64 const & invCellDiameter, + real64 const (&cellCenter)[3], + stackArray1d< real64, FaceManager::maxFaceNodes() > & basisIntegrals, + real64 (& threeDMonomialIntegrals)[3] ) const { - // I've tried to access the finiteElement::dispatch3D with - // finiteElement::FiniteElementBase const & - // fe = fractureSubRegion->getReference< finiteElement::FiniteElementBase >( surfaceGenerator->getDiscretizationName() ); - // but it's either empty (unknown discretization) or for 3D only (e.g., hexahedra) GEOS_MARK_FUNCTION; + localIndex const MFN = m_maxFaceNodes; // Max number of face vertices. + basisIntegrals.resize( numFaceVertices ); + // Rotate the face. + // - compute rotation matrix. + real64 faceRotationMatrix[ 3 ][ 3 ]; + computationalGeometry::RotationMatrix_3D( faceNormal, faceRotationMatrix ); + // - below we compute the diameter, the rotated vertices and the rotated center. + real64 faceRotatedVertices[ MFN ][ 2 ]; + real64 faceDiameter = 0; + + for( localIndex numVertex = 0; numVertex < numFaceVertices; ++numVertex ) + { + // apply the transpose (that is the inverse) of the rotation matrix to face vertices. + // NOTE: + // the second and third rows of the transpose of the rotation matrix rotate on the 2D face. + faceRotatedVertices[numVertex][0] = + faceRotationMatrix[ 0 ][ 1 ]*nodesCoords( faceToNodes[ numVertex ], 0 ) + + faceRotationMatrix[ 1 ][ 1 ]*nodesCoords( faceToNodes[ numVertex ], 1 ) + + faceRotationMatrix[ 2 ][ 1 ]*nodesCoords( faceToNodes[ numVertex ], 2 ); + faceRotatedVertices[numVertex][1] = + faceRotationMatrix[ 0 ][ 2 ]*nodesCoords( faceToNodes[ numVertex ], 0 ) + + faceRotationMatrix[ 1 ][ 2 ]*nodesCoords( faceToNodes[ numVertex ], 1 ) + + faceRotationMatrix[ 2 ][ 2 ]*nodesCoords( faceToNodes[ numVertex ], 2 ); + } + faceDiameter = computationalGeometry::computeDiameter< 2 >( faceRotatedVertices, + numFaceVertices ); + real64 const invFaceDiameter = 1.0/faceDiameter; + // - rotate the face centroid as done for the vertices. + real64 faceRotatedCentroid[2]; + faceRotatedCentroid[0] = + faceRotationMatrix[ 0 ][ 1 ]*faceCenter[0] + + faceRotationMatrix[ 1 ][ 1 ]*faceCenter[1] + + faceRotationMatrix[ 2 ][ 1 ]*faceCenter[2]; + faceRotatedCentroid[1] = + faceRotationMatrix[ 0 ][ 2 ]*faceCenter[0] + + faceRotationMatrix[ 1 ][ 2 ]*faceCenter[1] + + faceRotationMatrix[ 2 ][ 2 ]*faceCenter[2]; + // - compute edges' lengths, outward pointing normals and local edge-to-nodes map. + real64 edgeOutwardNormals[ MFN ][ 2 ]; + real64 edgeLengths[ MFN ]; + localIndex localEdgeToNodes[ MFN ][ 2 ]; + + for( localIndex numEdge = 0; numEdge < numFaceVertices; ++numEdge ) + { + if( edgeToNodes( faceToEdges[numEdge], 0 ) == faceToNodes[ numEdge ] ) + { + localEdgeToNodes[ numEdge ][ 0 ] = numEdge; + localEdgeToNodes[ numEdge ][ 1 ] = (numEdge+1)%numFaceVertices; + } + else + { + localEdgeToNodes[ numEdge ][ 0 ] = (numEdge+1)%numFaceVertices; + localEdgeToNodes[ numEdge ][ 1 ] = numEdge; + } + real64 edgeTangent[2]; + edgeTangent[0] = faceRotatedVertices[(numEdge+1)%numFaceVertices][0] - + faceRotatedVertices[numEdge][0]; + edgeTangent[1] = faceRotatedVertices[(numEdge+1)%numFaceVertices][1] - + faceRotatedVertices[numEdge][1]; + edgeOutwardNormals[numEdge][0] = edgeTangent[1]; + edgeOutwardNormals[numEdge][1] = -edgeTangent[0]; + real64 signTestVector[2]; + signTestVector[0] = faceRotatedVertices[numEdge][0] - faceRotatedCentroid[0]; + signTestVector[1] = faceRotatedVertices[numEdge][1] - faceRotatedCentroid[1]; + if( signTestVector[0]*edgeOutwardNormals[numEdge][0] + + signTestVector[1]*edgeOutwardNormals[numEdge][1] < 0 ) + { + edgeOutwardNormals[numEdge][0] = -edgeOutwardNormals[numEdge][0]; + edgeOutwardNormals[numEdge][1] = -edgeOutwardNormals[numEdge][1]; + } + edgeLengths[numEdge] = LvArray::math::sqrt< real64 >( edgeTangent[0]*edgeTangent[0] + + edgeTangent[1]*edgeTangent[1] ); + edgeOutwardNormals[numEdge][0] /= edgeLengths[numEdge]; + edgeOutwardNormals[numEdge][1] /= edgeLengths[numEdge]; + } + + // Compute boundary quadrature weights (also equal to the integrals of basis functions on the + // boundary). + real64 boundaryQuadratureWeights[ MFN ]; + for( localIndex numWeight = 0; numWeight < numFaceVertices; ++numWeight ) + boundaryQuadratureWeights[numWeight] = 0.0; + for( localIndex numEdge = 0; numEdge < numFaceVertices; ++numEdge ) + { + boundaryQuadratureWeights[ localEdgeToNodes[ numEdge ][ 0 ] ] += 0.5*edgeLengths[numEdge]; + boundaryQuadratureWeights[ localEdgeToNodes[ numEdge ][ 1 ] ] += 0.5*edgeLengths[numEdge]; + } + + // Compute scaled monomials' integrals on edges. + real64 monomBoundaryIntegrals[3] = { 0.0 }; + for( localIndex numVertex = 0; numVertex < numFaceVertices; ++numVertex ) + { + monomBoundaryIntegrals[0] += boundaryQuadratureWeights[ numVertex ]; + monomBoundaryIntegrals[1] += (faceRotatedVertices[ numVertex ][ 0 ] - faceRotatedCentroid[0]) * + invFaceDiameter*boundaryQuadratureWeights[ numVertex ]; + monomBoundaryIntegrals[2] += (faceRotatedVertices[ numVertex ][ 1 ] - faceRotatedCentroid[1]) * + invFaceDiameter*boundaryQuadratureWeights[ numVertex ]; + } + + // Compute non constant 2D and 3D scaled monomials' integrals on the face. + real64 monomInternalIntegrals[2] = { 0.0 }; + for( localIndex numSubTriangle = 0; numSubTriangle < numFaceVertices; ++numSubTriangle ) + { + localIndex const nextVertex = (numSubTriangle+1)%numFaceVertices; + // - compute value of 2D monomials at the quadrature point on the sub-triangle (the + // barycenter). + // The result is ((v(0)+v(1)+faceCenter)/3 - faceCenter) / faceDiameter = + // = (v(0) + v(1) - 2*faceCenter)/(3*faceDiameter). + real64 monomialValues[2]; + for( localIndex i = 0; i < 2; ++i ) + { + monomialValues[i] = (faceRotatedVertices[numSubTriangle][i] + + faceRotatedVertices[nextVertex][i] - + 2.0*faceRotatedCentroid[i]) / (3.0*faceDiameter); + } + // compute value of 3D monomials at the quadrature point on the sub-triangle (the + // barycenter). The result is + // ((v(0) + v(1) + faceCenter)/3 - cellCenter)/cellDiameter. + real64 threeDMonomialValues[3]; + for( localIndex i = 0; i < 3; ++i ) + { + threeDMonomialValues[i] = ( (faceCenter[i] + + nodesCoords[faceToNodes[ numSubTriangle ]][i] + + nodesCoords[faceToNodes[ nextVertex ]][i]) / 3.0 - + cellCenter[i] ) * invCellDiameter; + } + // compute quadrature weight associated to the quadrature point (the area of the + // sub-triangle). + real64 edgesTangents[2][2]; // used to compute the area of the sub-triangle + for( localIndex i = 0; i < 2; ++i ) + { + edgesTangents[0][i] = faceRotatedVertices[numSubTriangle][i] - faceRotatedCentroid[i]; + } + for( localIndex i = 0; i < 2; ++i ) + { + edgesTangents[1][i] = faceRotatedVertices[nextVertex][i] - faceRotatedCentroid[i]; + } + real64 subTriangleArea = 0.5*LvArray::math::abs + ( edgesTangents[0][0]*edgesTangents[1][1] - + edgesTangents[0][1]*edgesTangents[1][0] ); + // compute the integrals on the sub-triangle and add it to the global integrals + for( localIndex i = 0; i < 2; ++i ) + { + monomInternalIntegrals[ i ] += monomialValues[ i ]*subTriangleArea; + } + for( localIndex i = 0; i < 3; ++i ) + { + // threeDMonomialIntegrals is assumed to be initialized to 0 by the caller + threeDMonomialIntegrals[ i ] += threeDMonomialValues[ i ]*subTriangleArea; + } + } + + // Compute integral of basis functions times normal derivative of monomials on the boundary. + real64 basisTimesMonomNormalDerBoundaryInt[ MFN ][ 2 ]; + for( localIndex numVertex = 0; numVertex < numFaceVertices; ++numVertex ) + { + for( localIndex i = 0; i < 2; ++i ) + { + basisTimesMonomNormalDerBoundaryInt[ numVertex ][ i ] = 0.0; + } + } + for( localIndex numVertex = 0; numVertex < numFaceVertices; ++numVertex ) + { + for( localIndex i = 0; i < 2; ++i ) + { + real64 thisEdgeIntTimesNormal_i = edgeOutwardNormals[numVertex][i]*edgeLengths[numVertex]; + basisTimesMonomNormalDerBoundaryInt[ localEdgeToNodes[ numVertex ][ 0 ] ][i] += thisEdgeIntTimesNormal_i; + basisTimesMonomNormalDerBoundaryInt[ localEdgeToNodes[ numVertex ][ 1 ] ][i] += thisEdgeIntTimesNormal_i; + } + } + for( localIndex numVertex = 0; numVertex < numFaceVertices; ++numVertex ) + { + for( localIndex i = 0; i < 2; ++i ) + { + basisTimesMonomNormalDerBoundaryInt[ numVertex ][ i ] *= 0.5*invFaceDiameter; + } + } + + // Compute integral mean of basis functions on this face. + real64 const invFaceArea = 1.0/faceArea; + real64 const monomialDerivativeInverse = (faceDiameter*faceDiameter)*invFaceArea; + for( localIndex numVertex = 0; numVertex < numFaceVertices; ++numVertex ) + { + real64 piNablaDofs[ 3 ]; + piNablaDofs[ 1 ] = monomialDerivativeInverse * + basisTimesMonomNormalDerBoundaryInt[ numVertex ][ 0 ]; + piNablaDofs[ 2 ] = monomialDerivativeInverse * + basisTimesMonomNormalDerBoundaryInt[ numVertex ][ 1 ]; + piNablaDofs[ 0 ] = (boundaryQuadratureWeights[ numVertex ] - + piNablaDofs[ 1 ]*monomBoundaryIntegrals[ 1 ] - + piNablaDofs[ 2 ]*monomBoundaryIntegrals[ 2 ])/monomBoundaryIntegrals[ 0 ]; + basisIntegrals[ numVertex ] = piNablaDofs[ 0 ]*faceArea + + (piNablaDofs[ 1 ]*monomInternalIntegrals[ 0 ] + + piNablaDofs[ 2 ]*monomInternalIntegrals[ 1 ]); + } +} + +void SolidMechanicsLagrangeContact::computeFaceNodalArea( localIndex const kf0, + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & nodePosition, + ArrayOfArraysView< localIndex const > const & faceToNodeMap, + ArrayOfArraysView< localIndex const > const & faceToEdgeMap, + arrayView2d< localIndex const > const & edgeToNodeMap, + arrayView2d< real64 const > const faceCenters, + arrayView2d< real64 const > const faceNormals, + arrayView1d< real64 const > const faceAreas, + stackArray1d< real64, FaceManager::maxFaceNodes() > & basisIntegrals ) const +{ + GEOS_MARK_FUNCTION; localIndex const TriangularPermutation[3] = { 0, 1, 2 }; localIndex const QuadrilateralPermutation[4] = { 0, 1, 3, 2 }; - localIndex const numNodesPerFace = faceToNodeMap.sizeOfArray( kf0 ); - nodalArea.resize( numNodesPerFace ); + basisIntegrals.resize( numNodesPerFace ); for( localIndex a = 0; a < numNodesPerFace; ++a ) { - nodalArea[a] = 0.0; + basisIntegrals[a] = 0.0; } localIndex const * const permutation = ( numNodesPerFace == 3 ) ? TriangularPermutation : QuadrilateralPermutation; if( numNodesPerFace == 3 ) @@ -842,7 +1247,7 @@ void SolidMechanicsLagrangeContact::computeFaceNodalArea( arrayView2d< real64 co H1_TriangleFace_Lagrange1_Gauss1::calcN( q, N ); for( localIndex a = 0; a < numNodesPerFace; ++a ) { - nodalArea[a] += detJ * N[permutation[a]]; + basisIntegrals[a] += detJ * N[permutation[a]]; } } } @@ -863,14 +1268,56 @@ void SolidMechanicsLagrangeContact::computeFaceNodalArea( arrayView2d< real64 co H1_QuadrilateralFace_Lagrange1_GaussLegendre2::calcN( q, N ); for( localIndex a = 0; a < numNodesPerFace; ++a ) { - nodalArea[a] += detJ * N[permutation[a]]; + basisIntegrals[a] += detJ * N[permutation[a]]; } } } + else if( numNodesPerFace > 4 && numNodesPerFace <= m_maxFaceNodes ) + { + // we need to L2 projector based on VEM to approximate the quadrature weights + // we need to use extra geometry information to computing L2 projector + + localIndex const MFN = m_maxFaceNodes; // Max number of face vertices. + localIndex const faceIndex = kf0; + localIndex const numFaceNodes = faceToNodeMap[ faceIndex ].size(); + + // get the face center and normal. + real64 const faceArea = faceAreas[ faceIndex ]; + localIndex faceToNodes[ MFN ]; + localIndex faceToEdges[ MFN ]; + for( localIndex i = 0; i < numFaceNodes; ++i ) + { + faceToNodes[i] = faceToNodeMap[ faceIndex ][ i ]; + faceToEdges[i] = faceToEdgeMap[ faceIndex ][ i ]; + } + // - get outward face normal and center + real64 faceNormal[3] = { faceNormals[faceIndex][0], + faceNormals[faceIndex][1], + faceNormals[faceIndex][2] }; + real64 const faceCenter[3] { faceCenters[faceIndex][0], + faceCenters[faceIndex][1], + faceCenters[faceIndex][2] }; + // - compute integrals calling auxiliary method + real64 threeDMonomialIntegrals[3] = { 0.0 }; + real64 const invCellDiameter = 0.0; + real64 const cellCenter[3] { 0.0, 0.0, 0.0 }; + computeFaceIntegrals( nodePosition, + faceToNodes, + faceToEdges, + numFaceNodes, + faceArea, + faceCenter, + faceNormal, + edgeToNodeMap, + invCellDiameter, + cellCenter, + basisIntegrals, + threeDMonomialIntegrals ); + } else { GEOS_ERROR( "SolidMechanicsLagrangeContact " << getDataContext() << ": face with " << numNodesPerFace << - " nodes. Only triangles and quadrilaterals are supported." ); + " nodes. Only triangles and quadrilaterals and PEBI prisms up to 11 sides are supported." ); } } @@ -885,9 +1332,15 @@ void SolidMechanicsLagrangeContact:: FaceManager const & faceManager = mesh.getFaceManager(); NodeManager const & nodeManager = mesh.getNodeManager(); + EdgeManager const & edgeManager = mesh.getEdgeManager(); ElementRegionManager const & elemManager = mesh.getElemManager(); ArrayOfArraysView< localIndex const > const faceToNodeMap = faceManager.nodeList().toViewConst(); + ArrayOfArraysView< localIndex const > const faceToEdgeMap = faceManager.edgeList().toViewConst(); + arrayView2d< localIndex const > const & edgeToNodeMap = edgeManager.nodeList().toViewConst(); + arrayView2d< real64 const > faceCenters = faceManager.faceCenter(); + arrayView2d< real64 const > faceNormals = faceManager.faceNormal(); + arrayView1d< real64 const > faceAreas = faceManager.faceArea(); string const & tracDofKey = dofManager.getKey( contact::traction::key() ); string const & dispDofKey = dofManager.getKey( solidMechanics::totalDisplacement::key() ); @@ -905,106 +1358,75 @@ void SolidMechanicsLagrangeContact:: arrayView1d< globalIndex const > const & tracDofNumber = subRegion.getReference< globalIndex_array >( tracDofKey ); arrayView2d< real64 const > const & traction = subRegion.getReference< array2d< real64 > >( contact::traction::key() ); arrayView3d< real64 const > const & rotationMatrix = subRegion.getReference< array3d< real64 > >( viewKeyStruct::rotationMatrixString() ); - ArrayOfArraysView< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); - - constexpr localIndex TriangularPermutation[3] = { 0, 1, 2 }; - constexpr localIndex QuadrilateralPermutation[4] = { 0, 1, 3, 2 }; + arrayView2d< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); forAll< parallelHostPolicy >( subRegion.size(), [=] ( localIndex const kfe ) { - if( elemsToFaces.sizeOfArray( kfe ) != 2 ) - { - return; - } localIndex const numNodesPerFace = faceToNodeMap.sizeOfArray( elemsToFaces[kfe][0] ); - localIndex const numQuadraturePointsPerElem = numNodesPerFace==3 ? 1 : 4; - globalIndex rowDOF[12]; - real64 nodeRHS[12]; - stackArray2d< real64, 3*4*3 > dRdT( 3*numNodesPerFace, 3 ); + globalIndex rowDOF[3 * m_maxFaceNodes]; // this needs to be changed when dealing with arbitrary element types + real64 nodeRHS[3 * m_maxFaceNodes]; + stackArray2d< real64, 3 * m_maxFaceNodes * 3 > dRdT( 3 * m_maxFaceNodes, 3 ); globalIndex colDOF[3]; for( localIndex i = 0; i < 3; ++i ) { colDOF[i] = tracDofNumber[kfe] + i; } - localIndex const * const permutation = ( numNodesPerFace == 3 ) ? TriangularPermutation : QuadrilateralPermutation; - real64 xLocal[2][4][3]; for( localIndex kf = 0; kf < 2; ++kf ) { + constexpr int normalSign[2] = { 1, -1 }; + // Testing the face integral on polygonal faces + stackArray1d< real64, FaceManager::maxFaceNodes() > nodalArea; localIndex const faceIndex = elemsToFaces[kfe][kf]; + computeFaceNodalArea( faceIndex, + nodePosition, + faceToNodeMap, + faceToEdgeMap, + edgeToNodeMap, + faceCenters, + faceNormals, + faceAreas, + nodalArea ); + for( localIndex a = 0; a < numNodesPerFace; ++a ) { - for( localIndex j = 0; j < 3; ++j ) + real64 const localNodalForce[ 3 ] = { traction( kfe, 0 ) * nodalArea[a], + traction( kfe, 1 ) * nodalArea[a], + traction( kfe, 2 ) * nodalArea[a] }; + real64 globalNodalForce[ 3 ]; + LvArray::tensorOps::Ri_eq_AijBj< 3, 3 >( globalNodalForce, rotationMatrix[ kfe ], localNodalForce ); + + for( localIndex i = 0; i < 3; ++i ) { - xLocal[kf][a][j] = nodePosition[ faceToNodeMap( faceIndex, permutation[a] ) ][j]; + rowDOF[3*a+i] = dispDofNumber[faceToNodeMap( faceIndex, a )] + i; + // Opposite sign w.r.t. to formulation presented in + // Algebraically Stabilized Lagrange Multiplier Method for Frictional Contact Mechanics with + // Hydraulically Active Fractures + // Franceschini, A., Castelletto, N., White, J. A., Tchelepi, H. A. + // Computer Methods in Applied Mechanics and Engineering (2020) 368, 113161 + // doi: 10.1016/j.cma.2020.113161 + nodeRHS[3*a+i] = +globalNodalForce[i] * normalSign[ kf ]; + + // Opposite sign w.r.t. to the same formulation as above + dRdT( 3*a+i, 0 ) = rotationMatrix( kfe, i, 0 ) * normalSign[ kf ] * nodalArea[a]; + dRdT( 3*a+i, 1 ) = rotationMatrix( kfe, i, 1 ) * normalSign[ kf ] * nodalArea[a]; + dRdT( 3*a+i, 2 ) = rotationMatrix( kfe, i, 2 ) * normalSign[ kf ] * nodalArea[a]; } } - } - - real64 N[4]; - for( localIndex q=0; q(N) ); - } - else if( numNodesPerFace==4 ) + for( localIndex idof = 0; idof < numNodesPerFace * 3; ++idof ) { - H1_QuadrilateralFace_Lagrange1_GaussLegendre2::calcN( q, N ); - } + localIndex const localRow = LvArray::integerConversion< localIndex >( rowDOF[idof] - rankOffset ); - constexpr int normalSign[2] = { 1, -1 }; - for( localIndex kf = 0; kf < 2; ++kf ) - { - localIndex const faceIndex = elemsToFaces[kfe][kf]; - using xLocalTriangle = real64[3][3]; - real64 const detJxW = numNodesPerFace==3 ? - H1_TriangleFace_Lagrange1_Gauss1::transformedQuadratureWeight( q, reinterpret_cast< xLocalTriangle & >( xLocal[kf] ) ) : - H1_QuadrilateralFace_Lagrange1_GaussLegendre2::transformedQuadratureWeight( q, xLocal[kf] ); - - for( localIndex a = 0; a < numNodesPerFace; ++a ) - { - real64 const NaDetJxQ = N[permutation[a]] * detJxW; - real64 const localNodalForce[ 3 ] = { traction( kfe, 0 ) * NaDetJxQ, - traction( kfe, 1 ) * NaDetJxQ, - traction( kfe, 2 ) * NaDetJxQ }; - real64 globalNodalForce[ 3 ]; - LvArray::tensorOps::Ri_eq_AijBj< 3, 3 >( globalNodalForce, rotationMatrix[ kfe ], localNodalForce ); - - for( localIndex i = 0; i < 3; ++i ) - { - rowDOF[3*a+i] = dispDofNumber[faceToNodeMap( faceIndex, a )] + i; - // Opposite sign w.r.t. to formulation presented in - // Algebraically Stabilized Lagrange Multiplier Method for Frictional Contact Mechanics with - // Hydraulically Active Fractures - // Franceschini, A., Castelletto, N., White, J. A., Tchelepi, H. A. - // Computer Methods in Applied Mechanics and Engineering (2020) 368, 113161 - // doi: 10.1016/j.cma.2020.113161 - nodeRHS[3*a+i] = +globalNodalForce[i] * normalSign[ kf ]; - - // Opposite sign w.r.t. to the same formulation as above - dRdT( 3*a+i, 0 ) = rotationMatrix( kfe, i, 0 ) * normalSign[ kf ] * NaDetJxQ; - dRdT( 3*a+i, 1 ) = rotationMatrix( kfe, i, 1 ) * normalSign[ kf ] * NaDetJxQ; - dRdT( 3*a+i, 2 ) = rotationMatrix( kfe, i, 2 ) * normalSign[ kf ] * NaDetJxQ; - } - } - - for( localIndex idof = 0; idof < numNodesPerFace * 3; ++idof ) + if( localRow >= 0 && localRow < localMatrix.numRows() ) { - localIndex const localRow = LvArray::integerConversion< localIndex >( rowDOF[idof] - rankOffset ); - - if( localRow >= 0 && localRow < localMatrix.numRows() ) - { - localMatrix.addToRow< parallelHostAtomic >( localRow, - colDOF, - dRdT[idof].dataIfContiguous(), - 3 ); - RAJA::atomicAdd( parallelHostAtomic{}, &localRhs[localRow], nodeRHS[idof] ); - } + localMatrix.addToRow< parallelHostAtomic >( localRow, + colDOF, + dRdT[idof].dataIfContiguous(), + 3 ); + RAJA::atomicAdd( parallelHostAtomic{}, &localRhs[localRow], nodeRHS[idof] ); } } } @@ -1012,6 +1434,7 @@ void SolidMechanicsLagrangeContact:: } ); } + void SolidMechanicsLagrangeContact:: assembleTractionResidualDerivativeWrtDisplacementAndTraction( MeshLevel const & mesh, arrayView1d< string const > const & regionNames, @@ -1022,9 +1445,15 @@ void SolidMechanicsLagrangeContact:: GEOS_MARK_FUNCTION; FaceManager const & faceManager = mesh.getFaceManager(); NodeManager const & nodeManager = mesh.getNodeManager(); + EdgeManager const & edgeManager = mesh.getEdgeManager(); ElementRegionManager const & elemManager = mesh.getElemManager(); ArrayOfArraysView< localIndex const > const faceToNodeMap = faceManager.nodeList().toViewConst(); + ArrayOfArraysView< localIndex const > const faceToEdgeMap = faceManager.edgeList().toViewConst(); + arrayView2d< localIndex const > const & edgeToNodeMap = edgeManager.nodeList().toViewConst(); + arrayView2d< real64 const > faceCenters = faceManager.faceCenter(); + arrayView2d< real64 const > faceNormals = faceManager.faceNormal(); + arrayView1d< real64 const > faceAreas = faceManager.faceArea(); string const & tracDofKey = dofManager.getKey( contact::traction::key() ); string const & dispDofKey = dofManager.getKey( solidMechanics::totalDisplacement::key() ); @@ -1039,37 +1468,34 @@ void SolidMechanicsLagrangeContact:: [&]( localIndex const, FaceElementSubRegion const & subRegion ) { - string const & contactRelationName = subRegion.template getReference< string >( viewKeyStruct::contactRelationNameString() ); - ContactBase const & contact = getConstitutiveModel< ContactBase >( subRegion, contactRelationName ); + string const & frictionLawName = subRegion.template getReference< string >( viewKeyStruct::frictionLawNameString() ); + FrictionBase const & frictionLaw = getConstitutiveModel< FrictionBase >( subRegion, frictionLawName ); arrayView1d< globalIndex const > const & tracDofNumber = subRegion.getReference< globalIndex_array >( tracDofKey ); arrayView1d< integer const > const & ghostRank = subRegion.ghostRank(); arrayView1d< real64 const > const & area = subRegion.getElementArea(); arrayView3d< real64 const > const & rotationMatrix = subRegion.getReference< array3d< real64 > >( viewKeyStruct::rotationMatrixString() ); - ArrayOfArraysView< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); + arrayView2d< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); arrayView2d< real64 const > const & traction = subRegion.getField< contact::traction >(); arrayView1d< integer const > const & fractureState = subRegion.getField< contact::fractureState >(); arrayView2d< real64 const > const & dispJump = subRegion.getField< contact::dispJump >(); arrayView2d< real64 const > const & previousDispJump = subRegion.getField< contact::oldDispJump >(); arrayView1d< real64 const > const & slidingTolerance = subRegion.getReference< array1d< real64 > >( viewKeyStruct::slidingToleranceString() ); - constitutiveUpdatePassThru( contact, [&] ( auto & castedContact ) + constitutiveUpdatePassThru( frictionLaw, [&] ( auto & castedFrictionLaw ) { - using ContactType = TYPEOFREF( castedContact ); - typename ContactType::KernelWrapper contactWrapper = castedContact.createKernelWrapper(); + using FrictionType = TYPEOFREF( castedFrictionLaw ); + typename FrictionType::KernelWrapper frictionWrapper = castedFrictionLaw.createKernelUpdates(); forAll< parallelHostPolicy >( subRegion.size(), [=] ( localIndex const kfe ) { - if( elemsToFaces.sizeOfArray( kfe ) != 2 ) - { - return; - } + if( ghostRank[kfe] < 0 ) { localIndex const numNodesPerFace = faceToNodeMap.sizeOfArray( elemsToFaces[kfe][0] ); - globalIndex nodeDOF[24]; + globalIndex nodeDOF[2 * 3 * m_maxFaceNodes]; globalIndex elemDOF[3]; for( localIndex i = 0; i < 3; ++i ) { @@ -1079,7 +1505,7 @@ void SolidMechanicsLagrangeContact:: real64 elemRHS[3] = {0.0, 0.0, 0.0}; real64 const Ja = area[kfe]; - stackArray2d< real64, 2 * 3 * 4 * 3 > dRdU( 3, 2 * 3 * numNodesPerFace ); + stackArray2d< real64, 2 * 3 * m_maxFaceNodes * 3 > dRdU( 3, 2 * 3 * m_maxFaceNodes ); stackArray2d< real64, 3 * 3 > dRdT( 3, 3 ); switch( fractureState[kfe] ) @@ -1090,19 +1516,27 @@ void SolidMechanicsLagrangeContact:: { if( i == 0 ) { - elemRHS[i] = +Ja * dispJump[kfe][i]; + elemRHS[i] = Ja * dispJump[kfe][i]; } else { - elemRHS[i] = +Ja * ( dispJump[kfe][i] - previousDispJump[kfe][i] ); + elemRHS[i] = Ja * ( dispJump[kfe][i] - previousDispJump[kfe][i] ); } } for( localIndex kf = 0; kf < 2; ++kf ) { // Compute local area contribution for each node - array1d< real64 > nodalArea; - computeFaceNodalArea( nodePosition, faceToNodeMap, elemsToFaces[kfe][kf], nodalArea ); + stackArray1d< real64, FaceManager::maxFaceNodes() > nodalArea; + computeFaceNodalArea( elemsToFaces[kfe][kf], + nodePosition, + faceToNodeMap, + faceToEdgeMap, + edgeToNodeMap, + faceCenters, + faceNormals, + faceAreas, + nodalArea ); for( localIndex a = 0; a < numNodesPerFace; ++a ) { @@ -1122,13 +1556,21 @@ void SolidMechanicsLagrangeContact:: case contact::FractureState::Slip: case contact::FractureState::NewSlip: { - elemRHS[0] = +Ja * dispJump[kfe][0]; + elemRHS[0] = Ja * dispJump[kfe][0]; for( localIndex kf = 0; kf < 2; ++kf ) { // Compute local area contribution for each node - array1d< real64 > nodalArea; - computeFaceNodalArea( nodePosition, faceToNodeMap, elemsToFaces[kfe][kf], nodalArea ); + stackArray1d< real64, FaceManager::maxFaceNodes() > nodalArea; + computeFaceNodalArea( elemsToFaces[kfe][kf], + nodePosition, + faceToNodeMap, + faceToEdgeMap, + edgeToNodeMap, + faceCenters, + faceNormals, + faceAreas, + nodalArea ); for( localIndex a = 0; a < numNodesPerFace; ++a ) { @@ -1142,8 +1584,8 @@ void SolidMechanicsLagrangeContact:: } real64 dLimitTau_dNormalTraction = 0; - real64 const limitTau = contactWrapper.computeLimitTangentialTractionNorm( traction[kfe][0], - dLimitTau_dNormalTraction ); + real64 const limitTau = frictionWrapper.computeLimitTangentialTractionNorm( traction[kfe][0], + dLimitTau_dNormalTraction ); real64 sliding[ 2 ] = { dispJump[kfe][1] - previousDispJump[kfe][1], dispJump[kfe][2] - previousDispJump[kfe][2] }; real64 slidingNorm = sqrt( sliding[ 0 ]*sliding[ 0 ] + sliding[ 1 ]*sliding[ 1 ] ); @@ -1153,7 +1595,10 @@ void SolidMechanicsLagrangeContact:: { for( localIndex i = 1; i < 3; ++i ) { - elemRHS[i] = +Ja * ( traction[kfe][i] - limitTau * sliding[ i-1 ] / slidingNorm ); + elemRHS[i] = Ja * ( traction[kfe][i] - limitTau * sliding[ i-1 ] / slidingNorm ); + + dRdT( i, 0 ) = -Ja * dLimitTau_dNormalTraction * sliding[ i-1 ] / slidingNorm; + dRdT( i, i ) = Ja; } // A symmetric 2x2 matrix. @@ -1165,8 +1610,16 @@ void SolidMechanicsLagrangeContact:: for( localIndex kf = 0; kf < 2; ++kf ) { // Compute local area contribution for each node - array1d< real64 > nodalArea; - computeFaceNodalArea( nodePosition, faceToNodeMap, elemsToFaces[kfe][kf], nodalArea ); + stackArray1d< real64, FaceManager::maxFaceNodes() > nodalArea; + computeFaceNodalArea( elemsToFaces[kfe][kf], + nodePosition, + faceToNodeMap, + faceToEdgeMap, + edgeToNodeMap, + faceCenters, + faceNormals, + faceAreas, + nodalArea ); for( localIndex a = 0; a < numNodesPerFace; ++a ) { @@ -1181,11 +1634,6 @@ void SolidMechanicsLagrangeContact:: } } } - for( localIndex i = 1; i < 3; ++i ) - { - dRdT( i, 0 ) = Ja * dLimitTau_dNormalTraction * sliding[ i-1 ] / slidingNorm; - dRdT( i, i ) = Ja; - } } else { @@ -1195,21 +1643,18 @@ void SolidMechanicsLagrangeContact:: { for( localIndex i = 1; i < 3; ++i ) { - elemRHS[i] = +Ja * ( traction[kfe][i] - limitTau * vaux[ i-1 ] / vauxNorm ); - } - for( localIndex i = 1; i < 3; ++i ) - { + elemRHS[i] = Ja * traction[kfe][i] * ( 1.0 - limitTau / vauxNorm ); + + dRdT( i, 0 ) = -Ja * traction[kfe][i] * dLimitTau_dNormalTraction / vauxNorm; dRdT( i, i ) = Ja; } } else { - for( localIndex i = 1; i < 3; ++i ) + for( int i = 1; i < 3; ++i ) { elemRHS[i] = 0.0; - } - for( localIndex i = 1; i < 3; ++i ) - { + dRdT( i, i ) = Ja; } } @@ -1218,13 +1663,10 @@ void SolidMechanicsLagrangeContact:: } case contact::FractureState::Open: { - for( localIndex i = 0; i < 3; ++i ) + for( int i = 0; i < 3; ++i ) { - elemRHS[i] = +Ja * traction[kfe][i]; - } + elemRHS[i] = Ja * traction[kfe][i]; - for( localIndex i = 0; i < 3; ++i ) - { dRdT( i, i ) = Ja; } break; @@ -1233,13 +1675,13 @@ void SolidMechanicsLagrangeContact:: localIndex const localRow = LvArray::integerConversion< localIndex >( elemDOF[0] - rankOffset ); - for( localIndex idof = 0; idof < 3; ++idof ) { localRhs[localRow + idof] += elemRHS[idof]; if( fractureState[kfe] != contact::FractureState::Open ) { + localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( localRow + idof, nodeDOF, dRdU[idof].dataIfContiguous(), @@ -1270,6 +1712,7 @@ void SolidMechanicsLagrangeContact::assembleStabilization( MeshLevel const & mes FaceManager const & faceManager = mesh.getFaceManager(); NodeManager const & nodeManager = mesh.getNodeManager(); + EdgeManager const & edgeManager = mesh.getEdgeManager(); ElementRegionManager const & elemManager = mesh.getElemManager(); string const & tracDofKey = dofManager.getKey( contact::traction::key() ); @@ -1288,9 +1731,8 @@ void SolidMechanicsLagrangeContact::assembleStabilization( MeshLevel const & mes SurfaceElementRegion const & fractureRegion = elemManager.getRegion< SurfaceElementRegion >( getUniqueFractureRegionName() ); FaceElementSubRegion const & fractureSubRegion = fractureRegion.getUniqueSubRegion< FaceElementSubRegion >(); - GEOS_ERROR_IF( !fractureSubRegion.hasField< contact::traction >(), - getDataContext() << ": The fracture subregion must contain traction field." ); - ArrayOfArraysView< localIndex const > const elem2dToFaces = fractureSubRegion.faceList().toViewConst(); + GEOS_ERROR_IF( !fractureSubRegion.hasField< contact::traction >(), "The fracture subregion must contain traction field." ); + arrayView2d< localIndex const > const elem2dToFaces = fractureSubRegion.faceList().toViewConst(); // Get the state of fracture elements arrayView1d< integer const > const & fractureState = @@ -1308,7 +1750,12 @@ void SolidMechanicsLagrangeContact::assembleStabilization( MeshLevel const & mes arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & nodePosition = nodeManager.referencePosition(); // Get area and rotation matrix for all faces - ArrayOfArraysView< localIndex const > const & faceToNodeMap = faceManager.nodeList().toViewConst(); + ArrayOfArraysView< localIndex const > const faceToNodeMap = faceManager.nodeList().toViewConst(); + ArrayOfArraysView< localIndex const > const faceToEdgeMap = faceManager.edgeList().toViewConst(); + arrayView2d< localIndex const > const & edgeToNodeMap = edgeManager.nodeList().toViewConst(); + arrayView2d< real64 const > faceCenters = faceManager.faceCenter(); + arrayView2d< real64 const > faceNormals = faceManager.faceNormal(); + arrayView1d< real64 const > const & faceArea = faceManager.faceArea(); arrayView3d< real64 const > const & faceRotationMatrix = fractureSubRegion.getReference< array3d< real64 > >( viewKeyStruct::rotationMatrixString() ); @@ -1339,7 +1786,8 @@ void SolidMechanicsLagrangeContact::assembleStabilization( MeshLevel const & mes if( numFluxElems == 2 ) { // Find shared edge (pair of nodes) - array1d< real64 > Nbar0( 3 ), Nbar1( 3 ); + real64 Nbar0[3]; + real64 Nbar1[3]; Nbar0[ 0 ] = faceRotationMatrix[ sei[iconn][0] ][0][0]; Nbar0[ 1 ] = faceRotationMatrix[ sei[iconn][0] ][1][0]; Nbar0[ 2 ] = faceRotationMatrix[ sei[iconn][0] ][2][0]; @@ -1407,9 +1855,31 @@ void SolidMechanicsLagrangeContact::assembleStabilization( MeshLevel const & mes node1index1 = i; } } - array1d< real64 > nodalArea0, nodalArea1; - computeFaceNodalArea( nodePosition, faceToNodeMap, elem2dToFaces[sei[iconn][0]][0], nodalArea0 ); - computeFaceNodalArea( nodePosition, faceToNodeMap, elem2dToFaces[sei[iconn][1]][id1], nodalArea1 ); + stackArray1d< real64, FaceManager::maxFaceNodes() > nodalArea0; + stackArray1d< real64, FaceManager::maxFaceNodes() > nodalArea1; + localIndex const faceIndex0 = elem2dToFaces[sei[iconn][0]][0]; + localIndex const faceIndex1 = elem2dToFaces[sei[iconn][1]][id1]; + + computeFaceNodalArea( faceIndex0, + nodePosition, + faceToNodeMap, + faceToEdgeMap, + edgeToNodeMap, + faceCenters, + faceNormals, + faceArea, + nodalArea0 ); + + computeFaceNodalArea( faceIndex1, + nodePosition, + faceToNodeMap, + faceToEdgeMap, + edgeToNodeMap, + faceCenters, + faceNormals, + faceArea, + nodalArea1 ); + real64 const areafac = nodalArea0[node0index0] * nodalArea1[node0index1] + nodalArea0[node1index0] * nodalArea1[node1index1]; // first index: face, second index: element (T/B), third index: dof (x, y, z) @@ -1465,7 +1935,7 @@ void SolidMechanicsLagrangeContact::assembleStabilization( MeshLevel const & mes // Combine E and nu to obtain a stiffness approximation (like it was an hexahedron) for( localIndex j = 0; j < 3; ++j ) { - stiffDiagApprox[ kf ][ i ][ j ] = E / ( ( 1.0 + nu )*( 1.0 - 2.0*nu ) ) * 2.0 / 9.0 * ( 2.0 - 3.0 * nu ) * volume / ( boxSize[j]*boxSize[j] ); + stiffDiagApprox[ kf ][ i ][ j ] = m_stabilitzationScalingCoefficient * E / ( ( 1.0 + nu )*( 1.0 - 2.0*nu ) ) * 2.0 / 9.0 * ( 2.0 - 3.0 * nu ) * volume / ( boxSize[j]*boxSize[j] ); } } } @@ -1496,13 +1966,13 @@ void SolidMechanicsLagrangeContact::assembleStabilization( MeshLevel const & mes // otherwise, compute the average rotation matrix else { - array1d< real64 > avgNbar( 3 ); + real64 avgNbar[3]; avgNbar[ 0 ] = faceArea[elem2dToFaces[ sei[iconn][0] ][0]] * Nbar0[0] + faceArea[elem2dToFaces[ sei[iconn][1] ][0]] * Nbar1[0]; avgNbar[ 1 ] = faceArea[elem2dToFaces[ sei[iconn][0] ][0]] * Nbar0[1] + faceArea[elem2dToFaces[ sei[iconn][1] ][0]] * Nbar1[1]; avgNbar[ 2 ] = faceArea[elem2dToFaces[ sei[iconn][0] ][0]] * Nbar0[2] + faceArea[elem2dToFaces[ sei[iconn][1] ][0]] * Nbar1[2]; LvArray::tensorOps::normalize< 3 >( avgNbar ); - computationalGeometry::RotationMatrix_3D( avgNbar.toSliceConst(), avgRotationMatrix ); + computationalGeometry::RotationMatrix_3D( avgNbar, avgRotationMatrix ); } // Compute R^T * (invK) * R @@ -1715,7 +2185,6 @@ void SolidMechanicsLagrangeContact::applySystemSolution( DofManager const & dofM void SolidMechanicsLagrangeContact::updateState( DomainPartition & domain ) { GEOS_MARK_FUNCTION; - computeFaceDisplacementJump( domain ); } @@ -1756,7 +2225,8 @@ bool SolidMechanicsLagrangeContact::updateConfiguration( DomainPartition & domai using namespace fields::contact; - int hasConfigurationConverged = true; + real64 changedArea = 0; + real64 totalArea = 0; forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & mesh, @@ -1767,45 +2237,51 @@ bool SolidMechanicsLagrangeContact::updateConfiguration( DomainPartition & domai elemManager.forElementSubRegions< FaceElementSubRegion >( regionNames, [&]( localIndex const, FaceElementSubRegion & subRegion ) { - string const & contactRelationName = subRegion.template getReference< string >( viewKeyStruct::contactRelationNameString() ); - ContactBase const & contact = getConstitutiveModel< ContactBase >( subRegion, contactRelationName ); + string const & fricitonLawName = subRegion.template getReference< string >( viewKeyStruct::frictionLawNameString() ); + FrictionBase const & frictionLaw = getConstitutiveModel< FrictionBase >( subRegion, fricitonLawName ); arrayView1d< integer const > const & ghostRank = subRegion.ghostRank(); arrayView2d< real64 const > const & traction = subRegion.getField< contact::traction >(); arrayView2d< real64 const > const & dispJump = subRegion.getField< contact::dispJump >(); arrayView1d< integer > const & fractureState = subRegion.getField< contact::fractureState >(); + arrayView1d< real64 const > const & faceArea = subRegion.getElementArea().toViewConst(); arrayView1d< real64 const > const & normalTractionTolerance = subRegion.getReference< array1d< real64 > >( viewKeyStruct::normalTractionToleranceString() ); arrayView1d< real64 const > const & normalDisplacementTolerance = subRegion.getReference< array1d< real64 > >( viewKeyStruct::normalDisplacementToleranceString() ); - RAJA::ReduceMin< parallelHostReduce, integer > checkActiveSetSub( 1 ); + RAJA::ReduceSum< parallelHostReduce, real64 > changed( 0 ); + RAJA::ReduceSum< parallelHostReduce, real64 > total( 0 ); - constitutiveUpdatePassThru( contact, [&] ( auto & castedContact ) + constitutiveUpdatePassThru( frictionLaw, [&] ( auto & castedFrictionLaw ) { - using ContactType = TYPEOFREF( castedContact ); - typename ContactType::KernelWrapper contactWrapper = castedContact.createKernelWrapper(); + using FrictionType = TYPEOFREF( castedFrictionLaw ); + typename FrictionType::KernelWrapper frictionWrapper = castedFrictionLaw.createKernelUpdates(); forAll< parallelHostPolicy >( subRegion.size(), [=] ( localIndex const kfe ) { if( ghostRank[kfe] < 0 ) { integer const originalFractureState = fractureState[kfe]; - if( originalFractureState == contact::FractureState::Open ) + if( originalFractureState == FractureState::Open ) { - if( dispJump[kfe][0] > -normalDisplacementTolerance[kfe] ) + if( dispJump[kfe][0] <= -normalDisplacementTolerance[kfe] ) { - fractureState[kfe] = contact::FractureState::Open; - } - else - { - fractureState[kfe] = contact::FractureState::Stick; + fractureState[kfe] = FractureState::Stick; + if( getLogLevel() >= 10 ) + GEOS_LOG( GEOS_FMT( "{}: {} -> {}: dispJump = {}, normalDisplacementTolerance = {}", + kfe, originalFractureState, fractureState[kfe], + dispJump[kfe][0], normalDisplacementTolerance[kfe] ) ); } } else if( traction[kfe][0] > normalTractionTolerance[kfe] ) { - fractureState[kfe] = contact::FractureState::Open; + fractureState[kfe] = FractureState::Open; + if( getLogLevel() >= 10 ) + GEOS_LOG( GEOS_FMT( "{}: {} -> {}: traction = {}, normalTractionTolerance = {}", + kfe, originalFractureState, fractureState[kfe], + traction[kfe][0], normalTractionTolerance[kfe] ) ); } else { @@ -1813,75 +2289,76 @@ bool SolidMechanicsLagrangeContact::updateConfiguration( DomainPartition & domai real64 dLimitTangentialTractionNorm_dTraction = 0.0; real64 const limitTau = - contactWrapper.computeLimitTangentialTractionNorm( traction[kfe][0], - dLimitTangentialTractionNorm_dTraction ); + frictionWrapper.computeLimitTangentialTractionNorm( traction[kfe][0], + dLimitTangentialTractionNorm_dTraction ); - if( originalFractureState == contact::FractureState::Stick && currentTau >= limitTau ) + if( originalFractureState == FractureState::Stick && currentTau >= limitTau ) { currentTau *= (1.0 - m_slidingCheckTolerance); } - else if( originalFractureState != contact::FractureState::Stick && currentTau <= limitTau ) + else if( originalFractureState != FractureState::Stick && currentTau <= limitTau ) { currentTau *= (1.0 + m_slidingCheckTolerance); } if( currentTau > limitTau ) { - if( originalFractureState == contact::FractureState::Stick ) + if( originalFractureState == FractureState::Stick ) { - fractureState[kfe] = contact::FractureState::NewSlip; + fractureState[kfe] = FractureState::NewSlip; } else { - fractureState[kfe] = contact::FractureState::Slip; + fractureState[kfe] = FractureState::Slip; } } else { - fractureState[kfe] = contact::FractureState::Stick; + fractureState[kfe] = FractureState::Stick; } + if( getLogLevel() >= 10 && fractureState[kfe] != originalFractureState ) + GEOS_LOG( GEOS_FMT( "{}: {} -> {}: currentTau = {}, limitTau = {}", + kfe, originalFractureState, fractureState[kfe], + currentTau, limitTau ) ); } - checkActiveSetSub.min( compareFractureStates( originalFractureState, fractureState[kfe] ) ); + + changed += faceArea[kfe] * !compareFractureStates( originalFractureState, fractureState[kfe] ); + total += faceArea[kfe]; } } ); } ); - hasConfigurationConverged &= checkActiveSetSub.get(); + changedArea += changed.get(); + totalArea += total.get(); } ); } ); + // Need to synchronize the fracture state due to the use will be made of in AssemblyStabilization synchronizeFractureState( domain ); - // Compute if globally the fracture state has changed - int hasConfigurationConvergedGlobally; - MpiWrapper::allReduce( &hasConfigurationConverged, - &hasConfigurationConvergedGlobally, - 1, - MPI_LAND, - MPI_COMM_GEOSX ); + // Compute global area of changed elements + changedArea = MpiWrapper::sum( changedArea ); + // and total area of fracture elements + totalArea = MpiWrapper::sum( totalArea ); - return hasConfigurationConvergedGlobally; + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Configuration, GEOS_FMT( " {}: changed area {} out of {}", getName(), changedArea, totalArea ) ); + + // Assume converged if changed area is below certain fraction of total area + return changedArea <= m_nonlinearSolverParameters.m_configurationTolerance * totalArea; } bool SolidMechanicsLagrangeContact::isFractureAllInStickCondition( DomainPartition const & domain ) const { - globalIndex numStick, numSlip, numOpen; + globalIndex numStick, numNewSlip, numSlip, numOpen; forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel const & mesh, arrayView1d< string const > const & ) { - computeFractureStateStatistics( mesh, numStick, numSlip, numOpen ); + computeFractureStateStatistics( mesh, numStick, numNewSlip, numSlip, numOpen ); } ); - return ( ( numSlip + numOpen ) == 0 ); -} - -real64 SolidMechanicsLagrangeContact::setNextDt( real64 const & currentDt, - DomainPartition & domain ) -{ - GEOS_UNUSED_VAR( domain ); - return currentDt; + return ( ( numNewSlip + numSlip + numOpen ) == 0 ); } -REGISTER_CATALOG_ENTRY( SolverBase, SolidMechanicsLagrangeContact, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SolidMechanicsLagrangeContact, string const &, Group * const ) } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/contact/SolidMechanicsLagrangeContact.hpp b/src/coreComponents/physicsSolvers/contact/SolidMechanicsLagrangeContact.hpp index f2999e54c01..a39b1374735 100644 --- a/src/coreComponents/physicsSolvers/contact/SolidMechanicsLagrangeContact.hpp +++ b/src/coreComponents/physicsSolvers/contact/SolidMechanicsLagrangeContact.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -25,12 +26,11 @@ namespace geos { -class SolidMechanicsLagrangianFEM; +class NumericalMethodsManager; class SolidMechanicsLagrangeContact : public ContactSolverBase { public: - SolidMechanicsLagrangeContact( const string & name, Group * const parent ); @@ -45,7 +45,7 @@ class SolidMechanicsLagrangeContact : public ContactSolverBase return "SolidMechanicsLagrangeContact"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -100,10 +100,6 @@ class SolidMechanicsLagrangeContact : public ContactSolverBase virtual void resetStateToBeginningOfStep( DomainPartition & domain ) override; - virtual real64 - setNextDt( real64 const & currentDt, - DomainPartition & domain ) override; - void updateState( DomainPartition & domain ) override final; void assembleContact( DomainPartition & domain, @@ -123,6 +119,12 @@ class SolidMechanicsLagrangeContact : public ContactSolverBase CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ); + void assembleForceResidualPressureContribution( MeshLevel const & mesh, + arrayView1d< string const > const & regionNames, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); + void assembleStabilization( MeshLevel const & mesh, NumericalMethodsManager const & numericalMethodManager, DofManager const & dofManager, @@ -139,21 +141,51 @@ class SolidMechanicsLagrangeContact : public ContactSolverBase void computeTolerances( DomainPartition & domain ) const; - void computeFaceNodalArea( arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & nodePosition, + void computeFaceNodalArea( localIndex const kf0, + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & nodePosition, ArrayOfArraysView< localIndex const > const & faceToNodeMap, - localIndex const kf0, - array1d< real64 > & nodalArea ) const; + ArrayOfArraysView< localIndex const > const & faceToEdgeMap, + arrayView2d< localIndex const > const & edgeToNodeMap, + arrayView2d< real64 const > const faceCenters, + arrayView2d< real64 const > const faceNormals, + arrayView1d< real64 const > const faceAreas, + stackArray1d< real64, FaceManager::maxFaceNodes() > & nodalArea ) const; + + void computeFaceIntegrals( arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & nodesCoords, + localIndex const (&faceToNodes)[11], + localIndex const (&faceToEdges)[11], + localIndex const & numFaceVertices, + real64 const & faceArea, + real64 const (&faceCenter)[3], + real64 const (&faceNormal)[3], + arrayView2d< localIndex const > const & edgeToNodes, + real64 const & invCellDiameter, + real64 const (&cellCenter)[3], + stackArray1d< real64, FaceManager::maxFaceNodes() > & basisIntegrals, + real64 ( &threeDMonomialIntegrals )[3] ) const; real64 const machinePrecision = std::numeric_limits< real64 >::epsilon(); string getStabilizationName() const { return m_stabilizationName; } +protected: + + real64 calculateContactResidualNorm( DomainPartition const & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localRhs ); + + virtual void postInputInitialization() override final; + + void setMGRStrategy(); + private: string m_stabilizationName; real64 const m_slidingCheckTolerance = 0.05; - real64 m_initialResidual[3] = {0.0, 0.0, 0.0}; + real64 m_stabilitzationScalingCoefficient = 1.0; + + static const localIndex m_maxFaceNodes; // Maximum number of nodes on a contact face void createPreconditioner( DomainPartition const & domain ); @@ -166,10 +198,14 @@ class SolidMechanicsLagrangeContact : public ContactSolverBase constexpr static char const * rotationMatrixString() { return "rotationMatrix"; } constexpr static char const * normalDisplacementToleranceString() { return "normalDisplacementTolerance"; } + constexpr static char const * normalTractionToleranceString() { return "normalTractionTolerance"; } + constexpr static char const * slidingToleranceString() { return "slidingTolerance"; } constexpr static char const * transMultiplierString() { return "penaltyStiffnessTransMultiplier"; } + + constexpr static char const * stabilizationScalingCoefficientString() { return "stabilizationScalingCoefficient"; } }; }; diff --git a/src/coreComponents/physicsSolvers/contact/SolidMechanicsLagrangeContactBubbleStab.cpp b/src/coreComponents/physicsSolvers/contact/SolidMechanicsLagrangeContactBubbleStab.cpp new file mode 100644 index 00000000000..2d1f139362b --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/SolidMechanicsLagrangeContactBubbleStab.cpp @@ -0,0 +1,1180 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolidMechanicsLagrangeContactBubbleStab.cpp + * + */ + +#include "mesh/DomainPartition.hpp" +#include "SolidMechanicsLagrangeContactBubbleStab.hpp" + +#include "physicsSolvers/contact/kernels/SolidMechanicsConformingContactKernelsBase.hpp" +#include "physicsSolvers/contact/kernels/SolidMechanicsLagrangeContactKernels.hpp" +#include "physicsSolvers/contact/kernels/SolidMechanicsDisplacementJumpUpdateKernels.hpp" +#include "physicsSolvers/contact/kernels/SolidMechanicsContactFaceBubbleKernels.hpp" +#include "physicsSolvers/contact/LogLevelsInfo.hpp" + +#include "constitutive/ConstitutiveManager.hpp" +#include "constitutive/contact/FrictionSelector.hpp" +#include "fieldSpecification/FieldSpecificationManager.hpp" + + +namespace geos +{ + +using namespace constitutive; +using namespace dataRepository; +using namespace fields; + +SolidMechanicsLagrangeContactBubbleStab::SolidMechanicsLagrangeContactBubbleStab( const string & name, + Group * const parent ): + ContactSolverBase( name, parent ) +{ + m_faceTypeToFiniteElements["Quadrilateral"] = std::make_unique< finiteElement::H1_QuadrilateralFace_Lagrange1_GaussLegendre2 >(); + m_faceTypeToFiniteElements["Triangle"] = std::make_unique< finiteElement::H1_TriangleFace_Lagrange1_Gauss1 >(); + +} + +SolidMechanicsLagrangeContactBubbleStab::~SolidMechanicsLagrangeContactBubbleStab() +{ + // TODO Auto-generated destructor stub +} + +real64 SolidMechanicsLagrangeContactBubbleStab::solverStep( real64 const & time_n, + real64 const & dt, + const integer cycleNumber, + DomainPartition & domain ) +{ + if( cycleNumber == 0 ) + { + /// Apply initial conditions to the Fault + FieldSpecificationManager & fieldSpecificationManager = FieldSpecificationManager::getInstance(); + + forDiscretizationOnMeshTargets ( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + + { + fieldSpecificationManager.applyInitialConditions( mesh ); + // Would like to do it like this but it is not working. There is a cast in Object path that tries to cast + // all objects that derive from ElementSubRegionBase to the specified type so this obviously fails. + // fieldSpecificationManager.forSubGroups< FieldSpecificationBase >( [&] ( FieldSpecificationBase const & fs ) + // { + // if( fs.initialCondition() ) + // { + // fs.apply< SurfaceElementSubRegion >( mesh, + // [&]( FieldSpecificationBase const & bc, + // string const &, + // SortedArrayView< localIndex const > const & targetSet, + // SurfaceElementSubRegion & targetGroup, + // string const fieldName ) + // { + // bc.applyFieldValue< FieldSpecificationEqual >( targetSet, 0.0, targetGroup, fieldName ); + // } ); + // } + // } ); + } ); + } + + return ContactSolverBase::solverStep( time_n, dt, cycleNumber, domain ); +} + +void SolidMechanicsLagrangeContactBubbleStab::registerDataOnMesh( Group & meshBodies ) +{ + ContactSolverBase::registerDataOnMesh( meshBodies ); + + forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & meshLevel, + arrayView1d< string const > const & ) + { + FaceManager & faceManager = meshLevel.getFaceManager(); + + // Register the total bubble displacement + faceManager.registerField< solidMechanics::totalBubbleDisplacement >( this->getName() ). + reference().resizeDimension< 1 >( 3 ); + + // Register the incremental bubble displacement + faceManager.registerField< solidMechanics::incrementalBubbleDisplacement >( this->getName() ). + reference().resizeDimension< 1 >( 3 ); + } ); + + forFractureRegionOnMeshTargets( meshBodies, [&] ( SurfaceElementRegion & fractureRegion ) + { + fractureRegion.forElementSubRegions< SurfaceElementSubRegion >( [&]( SurfaceElementSubRegion & subRegion ) + { + // Register the rotation matrix + subRegion.registerField< contact::rotationMatrix >( this->getName() ). + reference().resizeDimension< 1, 2 >( 3, 3 ); + + subRegion.registerField< fields::contact::deltaTraction >( getName() ). + reference().resizeDimension< 1 >( 3 ); + + subRegion.registerField< fields::contact::targetIncrementalJump >( getName() ). + reference().resizeDimension< 1 >( 3 ); + } ); + } ); +} + +void SolidMechanicsLagrangeContactBubbleStab::setupDofs( DomainPartition const & domain, + DofManager & dofManager ) const +{ + GEOS_MARK_FUNCTION; + + SolidMechanicsLagrangianFEM::setupDofs( domain, dofManager ); + + map< std::pair< string, string >, array1d< string > > meshTargets; + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshBodyName, + MeshLevel const & meshLevel, + arrayView1d< string const > const & regionNames ) + { + array1d< string > regions; + ElementRegionManager const & elementRegionManager = meshLevel.getElemManager(); + elementRegionManager.forElementRegions< SurfaceElementRegion >( regionNames, + [&]( localIndex const, + SurfaceElementRegion const & region ) + { + regions.emplace_back( region.getName() ); + } ); + meshTargets[std::make_pair( meshBodyName, meshLevel.getName())] = std::move( regions ); + } ); + + dofManager.addField( solidMechanics::totalBubbleDisplacement::key(), + FieldLocation::Face, + 3, + meshTargets ); + + dofManager.addField( contact::traction::key(), + FieldLocation::Elem, + 3, + meshTargets ); + + // Add coupling between bubble + dofManager.addCoupling( solidMechanics::totalBubbleDisplacement::key(), + solidMechanics::totalBubbleDisplacement::key(), + DofManager::Connector::Elem ); + + dofManager.addCoupling( contact::traction::key(), + contact::traction::key(), + DofManager::Connector::Elem ); + + dofManager.addCoupling( solidMechanics::totalDisplacement::key(), + contact::traction::key(), + DofManager::Connector::Elem, + meshTargets ); + + dofManager.addCoupling( solidMechanics::totalBubbleDisplacement::key(), + contact::traction::key(), + DofManager::Connector::Elem, + meshTargets ); + + dofManager.addCoupling( solidMechanics::totalDisplacement::key(), + solidMechanics::totalBubbleDisplacement::key(), + DofManager::Connector::Elem, + meshTargets ); +} + +void SolidMechanicsLagrangeContactBubbleStab::setupSystem( DomainPartition & domain, + DofManager & dofManager, + CRSMatrix< real64, globalIndex > & localMatrix, + ParallelVector & rhs, + ParallelVector & solution, + bool const GEOS_UNUSED_PARAM( setSparsity ) ) +{ + + + // setup monolithic coupled system + + // Create the lists of interface elements that have same type. + createFaceTypeList( domain ); + + // Create the lists of interface elements that have same type and same fracture state. + updateStickSlipList( domain ); + + // Create the list of cell elements that they are enriched with bubble functions. + createBubbleCellList( domain ); + + dofManager.setDomain( domain ); + setupDofs( domain, dofManager ); + dofManager.reorderByRank(); + + // Set the sparsity pattern without the Abu and Aub blocks. + SparsityPattern< globalIndex > patternDiag; + dofManager.setSparsityPattern( patternDiag ); + + // Get the original row lengths (diagonal blocks only) + array1d< localIndex > rowLengths( patternDiag.numRows() ); + for( localIndex localRow = 0; localRow < patternDiag.numRows(); ++localRow ) + { + rowLengths[localRow] = patternDiag.numNonZeros( localRow ); + } + + // Add the number of nonzeros induced by coupling + this->addCouplingNumNonzeros( domain, dofManager, rowLengths.toView() ); + + // Create a new pattern with enough capacity for coupled matrix + SparsityPattern< globalIndex > pattern; + pattern.resizeFromRowCapacities< parallelHostPolicy >( patternDiag.numRows(), patternDiag.numColumns(), rowLengths.data() ); + + // Copy the original nonzeros + for( localIndex localRow = 0; localRow < patternDiag.numRows(); ++localRow ) + { + globalIndex const * cols = patternDiag.getColumns( localRow ).dataIfContiguous(); + pattern.insertNonZeros( localRow, cols, cols + patternDiag.numNonZeros( localRow ) ); + } + + // Add the nonzeros from coupling + this->addCouplingSparsityPattern( domain, dofManager, pattern.toView() ); + + // Finally, steal the pattern into a CRS matrix + localMatrix.assimilate< parallelDevicePolicy<> >( std::move( pattern ) ); + localMatrix.setName( this->getName() + "/localMatrix" ); + + rhs.setName( this->getName() + "/rhs" ); + rhs.create( dofManager.numLocalDofs(), MPI_COMM_GEOS ); + + solution.setName( this->getName() + "/solution" ); + solution.create( dofManager.numLocalDofs(), MPI_COMM_GEOS ); + + computeRotationMatrices( domain ); +} + +void SolidMechanicsLagrangeContactBubbleStab::computeRotationMatrices( DomainPartition & domain ) const +{ + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + { + + FaceManager & faceManager = mesh.getFaceManager(); + ElementRegionManager & elemManager = mesh.getElemManager(); + + SurfaceElementRegion & region = elemManager.getRegion< SurfaceElementRegion >( getUniqueFractureRegionName() ); + FaceElementSubRegion & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); + + arrayView2d< real64 const > const faceNormal = faceManager.faceNormal(); + arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); + + arrayView2d< real64 > const incrBubbleDisp = + faceManager.getField< fields::solidMechanics::incrementalBubbleDisplacement >(); + + arrayView3d< real64 > const rotationMatrix = + subRegion.getField< fields::contact::rotationMatrix >().toView(); + + arrayView2d< real64 > const unitNormal = subRegion.getNormalVector(); + arrayView2d< real64 > const unitTangent1 = subRegion.getTangentVector1(); + arrayView2d< real64 > const unitTangent2 = subRegion.getTangentVector2(); + + // Compute rotation matrices + solidMechanicsConformingContactKernels::ComputeRotationMatricesKernel::launch< parallelDevicePolicy<> >( subRegion.size(), + faceNormal, + elemsToFaces, + rotationMatrix, + unitNormal, + unitTangent1, + unitTangent2 ); + + forAll< parallelDevicePolicy<> >( subRegion.size(), + [ = ] + GEOS_HOST_DEVICE ( localIndex const k ) + { + localIndex const kf0 = elemsToFaces[k][0]; + localIndex const kf1 = elemsToFaces[k][1]; + LvArray::tensorOps::fill< 3 >( incrBubbleDisp[kf0], 0.0 ); + LvArray::tensorOps::fill< 3 >( incrBubbleDisp[kf1], 0.0 ); + } ); + } ); +} + +void SolidMechanicsLagrangeContactBubbleStab::implicitStepSetup( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) +{ + SolidMechanicsLagrangianFEM::implicitStepSetup( time_n, dt, domain ); +} + +void SolidMechanicsLagrangeContactBubbleStab::assembleSystem( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + GEOS_MARK_FUNCTION; + + SolidMechanicsLagrangianFEM::assembleSystem( time, + dt, + domain, + dofManager, + localMatrix, + localRhs ); + + assembleStabilization( dt, domain, dofManager, localMatrix, localRhs ); + + assembleContact( dt, domain, dofManager, localMatrix, localRhs ); + + // parallel_matrix.create( localMatrix.toViewConst(), dofManager.numLocalDofs(), MPI_COMM_GEOS ); + // parallel_matrix.write("newMatrix.mtx"); + // std::cout << localRhs << std::endl; +} + +void SolidMechanicsLagrangeContactBubbleStab::assembleStabilization( real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + // Loop for assembling contributes of bubble elements (Abb, Abu, Aub) + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + NodeManager const & nodeManager = mesh.getNodeManager(); + FaceManager const & faceManager = mesh.getFaceManager(); + + string const & dispDofKey = dofManager.getKey( solidMechanics::totalDisplacement::key() ); + string const & bubbleDofKey = dofManager.getKey( solidMechanics::totalBubbleDisplacement::key() ); + + arrayView1d< globalIndex const > const dispDofNumber = nodeManager.getReference< globalIndex_array >( dispDofKey ); + arrayView1d< globalIndex const > const bubbleDofNumber = faceManager.getReference< globalIndex_array >( bubbleDofKey ); + + real64 const gravityVectorData[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3( gravityVector() ); + + + solidMechanicsConformingContactKernels::FaceBubbleFactory kernelFactory( dispDofNumber, + bubbleDofNumber, + dofManager.rankOffset(), + localMatrix, + localRhs, + dt, + gravityVectorData ); + + real64 maxTraction = finiteElement:: + regionBasedKernelApplication + < parallelDevicePolicy< >, + constitutive::ElasticIsotropic, + CellElementSubRegion >( mesh, + regionNames, + getDiscretizationName(), + SolidMechanicsLagrangianFEM::viewKeyStruct::solidMaterialNamesString(), + kernelFactory ); + + GEOS_UNUSED_VAR( maxTraction ); + + } ); +} + +void SolidMechanicsLagrangeContactBubbleStab::assembleContact( real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshName, + MeshLevel & mesh, + arrayView1d< string const > const & ) + { + NodeManager const & nodeManager = mesh.getNodeManager(); + FaceManager const & faceManager = mesh.getFaceManager(); + + string const & dispDofKey = dofManager.getKey( solidMechanics::totalDisplacement::key() ); + string const & bubbleDofKey = dofManager.getKey( solidMechanics::totalBubbleDisplacement::key() ); + string const & tractionDofKey = dofManager.getKey( contact::traction::key() ); + + arrayView1d< globalIndex const > const dispDofNumber = nodeManager.getReference< globalIndex_array >( dispDofKey ); + arrayView1d< globalIndex const > const bubbleDofNumber = faceManager.getReference< globalIndex_array >( bubbleDofKey ); + + string const & fractureRegionName = this->getUniqueFractureRegionName(); + + forFiniteElementOnStickFractureSubRegions( meshName, [&] ( string const &, + finiteElement::FiniteElementBase const & subRegionFE, + arrayView1d< localIndex const > const & faceElementList, + bool const ) + { + solidMechanicsLagrangeContactKernels::LagrangeContactFactory kernelFactory( dispDofNumber, + bubbleDofNumber, + dofManager.rankOffset(), + localMatrix, + localRhs, + dt, + faceElementList, + tractionDofKey ); + + real64 maxTraction = finiteElement:: + interfaceBasedKernelApplication + < parallelDevicePolicy< >, + constitutive::FrictionBase >( mesh, + fractureRegionName, + faceElementList, + subRegionFE, + viewKeyStruct::frictionLawNameString(), + kernelFactory ); + + GEOS_UNUSED_VAR( maxTraction ); + } ); + } ); +} + +void SolidMechanicsLagrangeContactBubbleStab::implicitStepComplete( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) +{ + SolidMechanicsLagrangianFEM::implicitStepComplete( time_n, dt, domain ); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + { + mesh.getElemManager().forElementSubRegions< FaceElementSubRegion >( [&]( FaceElementSubRegion & subRegion ) + { + arrayView2d< real64 > const deltaTraction = subRegion.getField< contact::deltaTraction >(); + arrayView2d< real64 > const deltaDispJump = subRegion.getField< contact::deltaDispJump >(); + arrayView2d< real64 const > const dispJump = subRegion.getField< contact::dispJump >(); + arrayView2d< real64 > const oldDispJump = subRegion.getField< contact::oldDispJump >(); + + forAll< parallelHostPolicy >( subRegion.size(), [=] ( localIndex const kfe ) + { + LvArray::tensorOps::fill< 3 >( deltaDispJump[kfe], 0.0 ); + LvArray::tensorOps::fill< 3 >( deltaTraction[kfe], 0.0 ); + LvArray::tensorOps::copy< 3 >( oldDispJump[kfe], dispJump[kfe] ); + } ); + } ); + } ); +} + +real64 SolidMechanicsLagrangeContactBubbleStab::calculateResidualNorm( real64 const & time, + real64 const & dt, + DomainPartition const & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localRhs ) +{ + GEOS_MARK_FUNCTION; + + real64 const solidResidual = SolidMechanicsLagrangianFEM::calculateResidualNorm( time, dt, domain, dofManager, localRhs ); + + real64 const contactResidual = calculateContactResidualNorm( domain, dofManager, localRhs ); + + return sqrt( solidResidual * solidResidual + contactResidual * contactResidual ); +} + +real64 SolidMechanicsLagrangeContactBubbleStab::calculateContactResidualNorm( DomainPartition const & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localRhs ) +{ + string const & dofKey = dofManager.getKey( contact::traction::key() ); + globalIndex const rankOffset = dofManager.rankOffset(); + + real64 stickResidual = 0.0; + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< FaceElementSubRegion >( regionNames, + [&]( localIndex const, FaceElementSubRegion const & subRegion ) + { + arrayView1d< globalIndex const > const & dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); + arrayView1d< integer const > const & ghostRank = subRegion.ghostRank(); + arrayView1d< real64 const > const & area = subRegion.getElementArea(); + + RAJA::ReduceSum< parallelHostReduce, real64 > stickSum( 0.0 ); + forAll< parallelHostPolicy >( subRegion.size(), [=] ( localIndex const k ) + { + if( ghostRank[k] < 0 ) + { + localIndex const localRow = LvArray::integerConversion< localIndex >( dofNumber[k] - rankOffset ); + for( localIndex dim = 0; dim < 3; ++dim ) + { + real64 const norm = localRhs[localRow + dim] / area[k]; + stickSum += norm * norm; + } + } + } ); + + stickResidual += stickSum.get(); + } ); + } ); + + stickResidual = MpiWrapper::sum( stickResidual ); + stickResidual = sqrt( stickResidual ); + + if( getLogLevel() >= 1 && logger::internal::rank==0 ) + { + std::cout << GEOS_FMT( " ( Rt ) = ( {:15.6e} )", stickResidual ); + } + + return sqrt( stickResidual * stickResidual ); +} + + +void SolidMechanicsLagrangeContactBubbleStab::applySystemSolution( DofManager const & dofManager, + arrayView1d< real64 const > const & localSolution, + real64 const scalingFactor, + real64 const dt, + DomainPartition & domain ) +{ + GEOS_MARK_FUNCTION; + + SolidMechanicsLagrangianFEM::applySystemSolution( dofManager, localSolution, scalingFactor, dt, domain ); + + dofManager.addVectorToField( localSolution, + contact::traction::key(), + contact::deltaTraction::key(), + scalingFactor ); + + dofManager.addVectorToField( localSolution, + contact::traction::key(), + contact::traction::key(), + scalingFactor ); + + dofManager.addVectorToField( localSolution, + solidMechanics::totalBubbleDisplacement::key(), + solidMechanics::totalBubbleDisplacement::key(), + scalingFactor ); + + dofManager.addVectorToField( localSolution, + solidMechanics::totalBubbleDisplacement::key(), + solidMechanics::incrementalBubbleDisplacement::key(), + scalingFactor ); + + + // Loop for updating the displacement jump + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshName, + MeshLevel & mesh, + arrayView1d< string const > const & ) + + { + + NodeManager const & nodeManager = mesh.getNodeManager(); + FaceManager const & faceManager = mesh.getFaceManager(); + + string const & dispDofKey = dofManager.getKey( solidMechanics::totalDisplacement::key() ); + string const & bubbleDofKey = dofManager.getKey( solidMechanics::totalBubbleDisplacement::key() ); + + arrayView1d< globalIndex const > const dispDofNumber = nodeManager.getReference< globalIndex_array >( dispDofKey ); + arrayView1d< globalIndex const > const bubbleDofNumber = faceManager.getReference< globalIndex_array >( bubbleDofKey ); + + string const & fractureRegionName = this->getUniqueFractureRegionName(); + + CRSMatrix< real64, globalIndex > const voidMatrix; + array1d< real64 > const voidRhs; + + forFiniteElementOnFractureSubRegions( meshName, [&] ( string const &, + finiteElement::FiniteElementBase const & subRegionFE, + arrayView1d< localIndex const > const & faceElementList ) + { + + solidMechanicsConformingContactKernels::DispJumpUpdateFactory kernelFactory( dispDofNumber, + bubbleDofNumber, + dofManager.rankOffset(), + voidMatrix.toViewConstSizes(), + voidRhs.toView(), + dt, + faceElementList ); + + real64 maxTraction = finiteElement:: + interfaceBasedKernelApplication + < parallelDevicePolicy< >, + constitutive::NullModel >( mesh, + fractureRegionName, + faceElementList, + subRegionFE, + "", + kernelFactory ); + + GEOS_UNUSED_VAR( maxTraction ); + + } ); + } ); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + { + FieldIdentifiers fieldsToBeSync; + + fieldsToBeSync.addFields( FieldLocation::Face, + { solidMechanics::incrementalBubbleDisplacement::key(), + solidMechanics::totalBubbleDisplacement::key() } ); + + fieldsToBeSync.addElementFields( { contact::traction::key(), + contact::deltaTraction::key(), + contact::dispJump::key() }, + { getUniqueFractureRegionName() } ); + + CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync, + mesh, + domain.getNeighbors(), + true ); + } ); +} + +void SolidMechanicsLagrangeContactBubbleStab::addCouplingNumNonzeros( DomainPartition & domain, + DofManager & dofManager, + arrayView1d< localIndex > const & rowLengths ) const +{ + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) + { + + ElementRegionManager const & elemManager = mesh.getElemManager(); + NodeManager const & nodeManager = mesh.getNodeManager(); + FaceManager const & faceManager = mesh.getFaceManager(); + + ArrayOfArraysView< localIndex const > const faceToNodeMap = faceManager.nodeList().toViewConst(); + + globalIndex const rankOffset = dofManager.rankOffset(); + + string const bubbleDofKey = dofManager.getKey( solidMechanics::totalBubbleDisplacement::key() ); + string const dispDofKey = dofManager.getKey( solidMechanics::totalDisplacement::key() ); + + arrayView1d< globalIndex const > const bubbleDofNumber = faceManager.getReference< globalIndex_array >( bubbleDofKey ); + arrayView1d< globalIndex const > const dispDofNumber = nodeManager.getReference< globalIndex_array >( dispDofKey ); + + elemManager.forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, CellElementSubRegion const & cellElementSubRegion ) + { + + arrayView1d< localIndex const > const bubbleElemsList = cellElementSubRegion.bubbleElementsList(); + arrayView2d< localIndex const > const faceElemsList = cellElementSubRegion.faceElementsList(); + + localIndex const numDispDof = 3*cellElementSubRegion.numNodesPerElement(); + + for( localIndex bi=0; bi( bubbleDofNumber[k] - rankOffset ); + + if( localRow >= 0 && localRow < rowLengths.size() ) + { + for( localIndex i=0; i<3; ++i ) + { + rowLengths[localRow + i] += numDispDof; + } + } + + for( localIndex a=0; a( dispDofNumber[node] - rankOffset ); + + if( localDispRow >= 0 && localDispRow < rowLengths.size() ) + { + for( int d=0; d<3; ++d ) + { + rowLengths[localDispRow + d] += 3; + } + } + } + } + + } ); + + SurfaceElementRegion const & region = elemManager.getRegion< SurfaceElementRegion >( getUniqueFractureRegionName() ); + FaceElementSubRegion const & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); + arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); + + for( localIndex kfe=0; kfe( bubbleDofNumber[kf] - rankOffset ); + + if( localRow >= 0 && localRow < rowLengths.size() ) + { + for( localIndex i=0; i<3; ++i ) + { + rowLengths[localRow + i] += numDispDof; + } + } + + for( localIndex a=0; a( dispDofNumber[node] - rankOffset ); + + if( localDispRow >= 0 && localDispRow < rowLengths.size() ) + { + for( int d=0; d<3; ++d ) + { + rowLengths[localDispRow + d] += 3; + } + } + } + } + + } + + } ); +} + +void SolidMechanicsLagrangeContactBubbleStab::addCouplingSparsityPattern( DomainPartition const & domain, + DofManager const & dofManager, + SparsityPatternView< globalIndex > const & pattern ) const +{ + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) + { + + ElementRegionManager const & elemManager = mesh.getElemManager(); + NodeManager const & nodeManager = mesh.getNodeManager(); + FaceManager const & faceManager = mesh.getFaceManager(); + + globalIndex const rankOffset = dofManager.rankOffset(); + + string const bubbleDofKey = dofManager.getKey( solidMechanics::totalBubbleDisplacement::key() ); + string const dispDofKey = dofManager.getKey( solidMechanics::totalDisplacement::key() ); + + arrayView1d< globalIndex const > const bubbleDofNumber = faceManager.getReference< globalIndex_array >( bubbleDofKey ); + arrayView1d< globalIndex const > const dispDofNumber = nodeManager.getReference< globalIndex_array >( dispDofKey ); + + static constexpr int maxNumDispDof = 3 * 8; + + elemManager.forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, CellElementSubRegion const & cellElementSubRegion ) + { + + arrayView1d< localIndex const > const bubbleElemsList = cellElementSubRegion.bubbleElementsList(); + arrayView2d< localIndex const > const faceElemsList = cellElementSubRegion.faceElementsList(); + + localIndex const numDispDof = 3*cellElementSubRegion.numNodesPerElement(); + + for( localIndex bi=0; bi eqnRowIndicesDisp ( numDispDof ); + stackArray1d< globalIndex, 3 > eqnRowIndicesBubble( 3 ); + stackArray1d< globalIndex, maxNumDispDof > dofColIndicesDisp ( numDispDof ); + stackArray1d< globalIndex, 3 > dofColIndicesBubble( 3 ); + + for( localIndex idof = 0; idof < 3; ++idof ) + { + eqnRowIndicesBubble[idof] = bubbleDofNumber[k] + idof - rankOffset; + dofColIndicesBubble[idof] = bubbleDofNumber[k] + idof; + } + + for( localIndex a=0; a= 0 && eqnRowIndicesDisp[i] < pattern.numRows() ) + { + for( localIndex j = 0; j < dofColIndicesBubble.size(); ++j ) + { + pattern.insertNonZero( eqnRowIndicesDisp[i], dofColIndicesBubble[j] ); + } + } + } + + for( localIndex i = 0; i < eqnRowIndicesBubble.size(); ++i ) + { + if( eqnRowIndicesBubble[i] >= 0 && eqnRowIndicesBubble[i] < pattern.numRows() ) + { + for( localIndex j=0; j < dofColIndicesDisp.size(); ++j ) + { + pattern.insertNonZero( eqnRowIndicesBubble[i], dofColIndicesDisp[j] ); + } + } + } + + } + + } ); + + SurfaceElementRegion const & region = elemManager.getRegion< SurfaceElementRegion >( getUniqueFractureRegionName() ); + FaceElementSubRegion const & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); + arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); + ArrayOfArraysView< localIndex const > const faceToNodeMap = faceManager.nodeList().toViewConst(); + + static constexpr int maxNumDispFaceDof = 3 * 4; + + for( localIndex kfe=0; kfe eqnRowIndicesDisp ( numDispDof ); + stackArray1d< globalIndex, 3 > eqnRowIndicesBubble( 3 ); + stackArray1d< globalIndex, maxNumDispFaceDof > dofColIndicesDisp ( numDispDof ); + stackArray1d< globalIndex, 3 > dofColIndicesBubble( 3 ); + + for( localIndex idof = 0; idof < 3; ++idof ) + { + eqnRowIndicesBubble[idof] = bubbleDofNumber[kf] + idof - rankOffset; + dofColIndicesBubble[idof] = bubbleDofNumber[kf] + idof; + } + + for( localIndex a=0; a= 0 && eqnRowIndicesDisp[i] < pattern.numRows() ) + { + for( localIndex j = 0; j < dofColIndicesBubble.size(); ++j ) + { + pattern.insertNonZero( eqnRowIndicesDisp[i], dofColIndicesBubble[j] ); + } + } + } + + for( localIndex i = 0; i < eqnRowIndicesBubble.size(); ++i ) + { + if( eqnRowIndicesBubble[i] >= 0 && eqnRowIndicesBubble[i] < pattern.numRows() ) + { + for( localIndex j=0; j < dofColIndicesDisp.size(); ++j ) + { + pattern.insertNonZero( eqnRowIndicesBubble[i], dofColIndicesDisp[j] ); + } + } + } + + } + } + } ); + +} + +void SolidMechanicsLagrangeContactBubbleStab::updateStickSlipList( DomainPartition const & domain ) +{ + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshName, + MeshLevel const & mesh, + arrayView1d< string const > const & ) + + { + + ElementRegionManager const & elemManager = mesh.getElemManager(); + SurfaceElementRegion const & region = elemManager.getRegion< SurfaceElementRegion >( getUniqueFractureRegionName() ); + FaceElementSubRegion const & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); + + arrayView1d< integer const > const fractureState = subRegion.getField< contact::fractureState >(); + + forFiniteElementOnFractureSubRegions( meshName, [&] ( string const & finiteElementName, + finiteElement::FiniteElementBase const &, + arrayView1d< localIndex const > const & faceElementList ) + { + + array1d< localIndex > keys( subRegion.size()); + array1d< localIndex > vals( subRegion.size()); + array1d< localIndex > stickList; + array1d< localIndex > slipList; + RAJA::ReduceSum< ReducePolicy< parallelDevicePolicy<> >, localIndex > nStick_r( 0 ); + RAJA::ReduceSum< ReducePolicy< parallelDevicePolicy<> >, localIndex > nSlip_r( 0 ); + + arrayView1d< localIndex > const keys_v = keys.toView(); + arrayView1d< localIndex > const vals_v = vals.toView(); + forAll< parallelDevicePolicy<> >( faceElementList.size(), + [ = ] + GEOS_HOST_DEVICE ( localIndex const kfe ) + { + + localIndex const faceIndex = faceElementList[kfe]; + if( fractureState[faceIndex] == contact::FractureState::Stick ) + { + keys_v[kfe]=0; + vals_v[kfe]=faceIndex; + nStick_r += 1; + } + else if(( fractureState[faceIndex] == contact::FractureState::Slip ) || + (fractureState[faceIndex] == contact::FractureState::NewSlip)) + { + keys_v[kfe]=1; + vals_v[kfe]=faceIndex; + nSlip_r += 1; + } + else + { + keys_v[kfe] = 2; + } + + } ); + + localIndex nStick = static_cast< localIndex >(nStick_r.get()); + localIndex nSlip = static_cast< localIndex >(nSlip_r.get()); + + // Sort vals according to keys to ensure that + // elements of the same type are adjacent in the vals list. + // This arrangement allows for efficient copying into the container + // by leveraging parallelism. + RAJA::sort_pairs< parallelDevicePolicy<> >( keys_v, vals_v ); + + stickList.resize( nStick ); + slipList.resize( nSlip ); + arrayView1d< localIndex > const stickList_v = stickList.toView(); + arrayView1d< localIndex > const slipList_v = slipList.toView(); + + forAll< parallelDevicePolicy<> >( nStick, [ = ] + GEOS_HOST_DEVICE ( localIndex const kfe ) + { + stickList_v[kfe] = vals_v[kfe]; + } ); + + forAll< parallelDevicePolicy<> >( nSlip, [ = ] + GEOS_HOST_DEVICE ( localIndex const kfe ) + { + slipList_v[kfe] = vals_v[nStick+kfe]; + } ); + + this->m_faceTypesToFaceElementsStick[meshName][finiteElementName] = stickList; + this->m_faceTypesToFaceElementsSlip[meshName][finiteElementName] = slipList; + + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Configuration, GEOS_FMT( "# stick elements: {}, # slip elements: {}", nStick, nSlip )) + } ); + } ); + +} + +void SolidMechanicsLagrangeContactBubbleStab::createFaceTypeList( DomainPartition const & domain ) +{ + + // Generate lists containing elements of various face types + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshName, + MeshLevel const & mesh, + arrayView1d< string const > const ) + { + FaceManager const & faceManager = mesh.getFaceManager(); + ElementRegionManager const & elemManager = mesh.getElemManager(); + ArrayOfArraysView< localIndex const > const faceToNodeMap = faceManager.nodeList().toViewConst(); + + SurfaceElementRegion const & region = elemManager.getRegion< SurfaceElementRegion >( getUniqueFractureRegionName() ); + FaceElementSubRegion const & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); + + array1d< localIndex > keys( subRegion.size()); + array1d< localIndex > vals( subRegion.size()); + array1d< localIndex > quadList; + array1d< localIndex > triList; + RAJA::ReduceSum< ReducePolicy< parallelDevicePolicy<> >, localIndex > nTri_r( 0 ); + RAJA::ReduceSum< ReducePolicy< parallelDevicePolicy<> >, localIndex > nQuad_r( 0 ); + + arrayView1d< localIndex > const keys_v = keys.toView(); + arrayView1d< localIndex > const vals_v = vals.toView(); + // Determine the size of the lists and generate the vector keys and vals for parallel indexing into lists. + // (With RAJA, parallelizing this operation seems the most viable approach.) + forAll< parallelDevicePolicy<> >( subRegion.size(), + [ = ] GEOS_HOST_DEVICE ( localIndex const kfe ) + { + + localIndex const numNodesPerFace = faceToNodeMap.sizeOfArray( kfe ); + if( numNodesPerFace == 3 ) + { + keys_v[kfe]=0; + vals_v[kfe]=kfe; + nTri_r += 1; + } + else if( numNodesPerFace == 4 ) + { + keys_v[kfe]=1; + vals_v[kfe]=kfe; + nQuad_r += 1; + } + else + { + GEOS_ERROR( "SolidMechanicsLagrangeContactBubbleStab:: invalid face type" ); + } + } ); + + localIndex nQuad = static_cast< localIndex >(nQuad_r.get()); + localIndex nTri = static_cast< localIndex >(nTri_r.get()); + + // Sort vals according to keys to ensure that + // elements of the same type are adjacent in the vals list. + // This arrangement allows for efficient copying into the container + // by leveraging parallelism. + RAJA::sort_pairs< parallelDevicePolicy<> >( keys_v, vals_v ); + + quadList.resize( nQuad ); + triList.resize( nTri ); + arrayView1d< localIndex > const quadList_v = quadList.toView(); + arrayView1d< localIndex > const triList_v = triList.toView(); + + forAll< parallelDevicePolicy<> >( nTri, [ = ] GEOS_HOST_DEVICE ( localIndex const kfe ) + { + triList_v[kfe] = vals_v[kfe]; + } ); + + forAll< parallelDevicePolicy<> >( nQuad, [ = ] GEOS_HOST_DEVICE ( localIndex const kfe ) + { + quadList_v[kfe] = vals_v[nTri+kfe]; + } ); + + this->m_faceTypesToFaceElements[meshName]["Quadrilateral"] = quadList; + this->m_faceTypesToFaceElements[meshName]["Triangle"] = triList; + } ); + +} + +void SolidMechanicsLagrangeContactBubbleStab::createBubbleCellList( DomainPartition & domain ) const +{ + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const regionNames ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + + SurfaceElementRegion const & region = elemManager.getRegion< SurfaceElementRegion >( getUniqueFractureRegionName() ); + FaceElementSubRegion const & subRegion = region.getUniqueSubRegion< FaceElementSubRegion >(); + // Array to store face indexes + array1d< localIndex > tmpSpace( 2*subRegion.size()); + SortedArray< localIndex > faceIdList; + + arrayView1d< localIndex > const tmpSpace_v = tmpSpace.toView(); + // Store indexes of faces in the temporany array. + { + arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); + + forAll< parallelDevicePolicy<> >( subRegion.size(), [ = ] GEOS_HOST_DEVICE ( localIndex const kfe ) + { + + localIndex const kf0 = elemsToFaces[kfe][0], kf1 = elemsToFaces[kfe][1]; + tmpSpace_v[2*kfe] = kf0, tmpSpace_v[2*kfe+1] = kf1; + + } ); + } + + // Sort indexes to enable efficient searching using binary search. + RAJA::stable_sort< parallelDevicePolicy<> >( tmpSpace_v ); + faceIdList.insert( tmpSpace_v.begin(), tmpSpace_v.end()); + + // Search for bubble element on each CellElementSubRegion and + // store element indexes, global and local face indexes. + elemManager.forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, CellElementSubRegion & cellElementSubRegion ) + { + + arrayView2d< localIndex const > const elemsToFaces = cellElementSubRegion.faceList().toViewConst(); + + RAJA::ReduceSum< ReducePolicy< parallelDevicePolicy<> >, localIndex > nBubElems_r( 0 ); + + localIndex const n_max = cellElementSubRegion.size() * elemsToFaces.size( 1 ); + array1d< localIndex > keys( n_max ); + array1d< localIndex > perms( n_max ); + array1d< localIndex > vals( n_max ); + array1d< localIndex > localFaceIds( n_max ); + + arrayView1d< localIndex > const keys_v = keys.toView(); + arrayView1d< localIndex > const perms_v = perms.toView(); + arrayView1d< localIndex > const vals_v = vals.toView(); + arrayView1d< localIndex > const localFaceIds_v = localFaceIds.toView(); + SortedArrayView< localIndex const > const faceIdList_v = faceIdList.toViewConst(); + + forAll< parallelDevicePolicy<> >( cellElementSubRegion.size(), + [ = ] + GEOS_HOST_DEVICE ( localIndex const kfe ) + { + for( int i=0; i < elemsToFaces.size( 1 ); ++i ) + { + perms_v[kfe*elemsToFaces.size( 1 )+i] = kfe*elemsToFaces.size( 1 )+i; + if( faceIdList_v.contains( elemsToFaces[kfe][i] )) + { + keys_v[kfe*elemsToFaces.size( 1 )+i] = 0; + vals_v[kfe*elemsToFaces.size( 1 )+i] = kfe; + localFaceIds_v[kfe*elemsToFaces.size( 1 )+i] = i; + nBubElems_r += 1; + } + else + { + keys_v[kfe*elemsToFaces.size( 1 )+i] = 1; + vals_v[kfe*elemsToFaces.size( 1 )+i] = -1; + localFaceIds_v[kfe*elemsToFaces.size( 1 )+i] = -1; + } + } + } ); + + // Sort perms according to keys to ensure that bubble elements are adjacent + // and occupy the first positions of the list. + // This arrangement allows for efficient copying into the container + // by leveraging parallelism. + localIndex nBubElems = static_cast< localIndex >(nBubElems_r.get()); + RAJA::sort_pairs< parallelDevicePolicy<> >( keys_v, perms_v ); + + array1d< localIndex > bubbleElemsList; + bubbleElemsList.resize( nBubElems ); + + arrayView1d< localIndex > const bubbleElemsList_v = bubbleElemsList.toView(); + + forAll< parallelDevicePolicy<> >( n_max, [ = ] GEOS_HOST_DEVICE ( localIndex const k ) + { + keys_v[k] = vals_v[perms_v[k]]; + } ); + + forAll< parallelDevicePolicy<> >( nBubElems, [ = ] GEOS_HOST_DEVICE ( localIndex const k ) + { + bubbleElemsList_v[k] = keys_v[k]; + } ); + cellElementSubRegion.setBubbleElementsList( bubbleElemsList.toViewConst()); + + forAll< parallelDevicePolicy<> >( n_max, [ = ] GEOS_HOST_DEVICE ( localIndex const k ) + { + keys_v[k] = localFaceIds_v[perms_v[k]]; + } ); + + array2d< localIndex > faceElemsList; + faceElemsList.resize( nBubElems, 2 ); + + arrayView2d< localIndex > const faceElemsList_v = faceElemsList.toView(); + + forAll< parallelDevicePolicy<> >( nBubElems, + [ = ] + GEOS_HOST_DEVICE ( localIndex const k ) + { + localIndex const kfe = bubbleElemsList_v[k]; + faceElemsList_v[k][0] = elemsToFaces[kfe][keys_v[k]]; + faceElemsList_v[k][1] = keys_v[k]; + } ); + cellElementSubRegion.setFaceElementsList( faceElemsList.toViewConst()); + + } ); + + } ); + +} + +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SolidMechanicsLagrangeContactBubbleStab, string const &, Group * const ) + +} /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/contact/SolidMechanicsLagrangeContactBubbleStab.hpp b/src/coreComponents/physicsSolvers/contact/SolidMechanicsLagrangeContactBubbleStab.hpp new file mode 100644 index 00000000000..8daefd588fc --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/SolidMechanicsLagrangeContactBubbleStab.hpp @@ -0,0 +1,240 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolidMechanicsLagrangeContactBubbleStab.hpp + * + */ + +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSLAGRANGECONTACTBUBBLESTAB_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSLAGRANGECONTACTBUBBLESTAB_HPP_ + +#include "physicsSolvers/contact/ContactSolverBase.hpp" + +namespace geos +{ + +class NumericalMethodsManager; + +class SolidMechanicsLagrangeContactBubbleStab : public ContactSolverBase +{ +public: + + SolidMechanicsLagrangeContactBubbleStab( const string & name, + Group * const parent ); + + ~SolidMechanicsLagrangeContactBubbleStab() override; + + /** + * @brief name of the node manager in the object catalog + * @return string that contains the catalog name to generate a new NodeManager object through the object catalog. + */ + static string catalogName() + { + return "SolidMechanicsLagrangeContactBubbleStab"; + } + /** + * @copydoc SolverBase::getCatalogName() + */ + string getCatalogName() const override { return catalogName(); } + + virtual void registerDataOnMesh( Group & MeshBodies ) override final; + + real64 solverStep( real64 const & time_n, + real64 const & dt, + const integer cycleNumber, + DomainPartition & domain ) override final; + + virtual void + setupDofs( DomainPartition const & domain, + DofManager & dofManager ) const override; + + virtual void + setupSystem( DomainPartition & domain, + DofManager & dofManager, + CRSMatrix< real64, globalIndex > & localMatrix, + ParallelVector & rhs, + ParallelVector & solution, + bool const setSparsity = true ) override final; + + virtual void + implicitStepSetup( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) override final; + + virtual void + implicitStepComplete( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) override final; + + virtual void + assembleSystem( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) override; + + virtual real64 + calculateResidualNorm( real64 const & time, + real64 const & dt, + DomainPartition const & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localRhs ) override; + + virtual void + applySystemSolution( DofManager const & dofManager, + arrayView1d< real64 const > const & localSolution, + real64 const scalingFactor, + real64 const dt, + DomainPartition & domain ) override; + + void assembleContact( real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); + + void assembleStabilization( real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); + + real64 calculateContactResidualNorm( DomainPartition const & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localRhs ); + + /** + * @brief Loop over the finite element type on the fracture subregions of meshName and apply callback. + * @tparam LAMBDA The callback function type + * @param meshName The mesh name. + * @param lambda The callback function. Take the finite element type name and + * the list of face element of the same type. + */ + template< typename LAMBDA > + void forFiniteElementOnFractureSubRegions( string const & meshName, LAMBDA && lambda ) const + { + std::map< string, + array1d< localIndex > > const & faceTypesToFaceElements = m_faceTypesToFaceElements.at( meshName ); + + for( const auto & [finiteElementName, faceElementList] : faceTypesToFaceElements ) + { + arrayView1d< localIndex const > const faceElemList = faceElementList.toViewConst(); + + finiteElement::FiniteElementBase const & subRegionFE = *(m_faceTypeToFiniteElements.at( finiteElementName )); + + lambda( finiteElementName, subRegionFE, faceElemList ); + } + } + + /** + * @brief Loop over the finite element type on the stick fracture subregions of meshName and apply callback. + * @tparam LAMBDA The callback function type + * @param meshName The mesh name. + * @param lambda The callback function. Take the finite element type name and + * the list of face element of the same type. + */ + template< typename LAMBDA > + void forFiniteElementOnStickFractureSubRegions( string const & meshName, LAMBDA && lambda ) const + { + bool const isStickState = true; + + std::map< string, array1d< localIndex > > const & + faceTypesToFaceElements = m_faceTypesToFaceElementsStick.at( meshName ); + + for( const auto & [finiteElementName, faceElementList] : faceTypesToFaceElements ) + { + arrayView1d< localIndex const > const faceElemList = faceElementList.toViewConst(); + + finiteElement::FiniteElementBase const & subRegionFE = *(m_faceTypeToFiniteElements.at( finiteElementName )); + + lambda( finiteElementName, subRegionFE, faceElemList, isStickState ); + } + } + +/** + * @brief Create the list of finite elements of the same type + * for each FaceElementSubRegion (Triangle or Quadrilateral) + * and of the same fracture state (Stick or Slip). + * @param domain The physical domain object + */ + void updateStickSlipList( DomainPartition const & domain ); + + /** + * @brief Create the list of finite elements of the same type + * for each FaceElementSubRegion (Triangle or Quadrilateral). + * @param domain The physical domain object + */ + void createFaceTypeList( DomainPartition const & domain ); + + /** + * @brief Create the list of elements belonging to CellElementSubRegion + * that are enriched with the bubble basis functions + * @param domain The physical domain object + */ + void createBubbleCellList( DomainPartition & domain ) const; + + /** + * @brief Compute rotation matrices and unit normal vectors for Face elements. + * @param domain The domain partition object + */ + void computeRotationMatrices( DomainPartition & domain ) const; + + +private: + /** + * @brief add the number of non-zero elements induced by the coupling between + * nodal and bubble displacement. + * @param domain the physical domain object + * @param dofManager degree-of-freedom manager associated with the linear system + * @param rowLengths the array containing the number of non-zero elements for each row + */ + void addCouplingNumNonzeros( DomainPartition & domain, + DofManager & dofManager, + arrayView1d< localIndex > const & rowLengths ) const; + + /** + * @Brief add the sparsity pattern induced by the coupling + * @param domain the physical domain object + * @param dofManager degree-of-freedom manager associated with the linear system + * @param pattern the sparsity pattern + */ + void addCouplingSparsityPattern( DomainPartition const & domain, + DofManager const & dofManager, + SparsityPatternView< globalIndex > const & pattern ) const; + + /// Finite element type to face element index map + std::map< string, std::map< string, array1d< localIndex > > > m_faceTypesToFaceElements; + + /// Finite element type to face element index map (stick mode) + std::map< string, std::map< string, array1d< localIndex > > > m_faceTypesToFaceElementsStick; + + /// Finite element type to face element index map (slip mode) + std::map< string, std::map< string, array1d< localIndex > > > m_faceTypesToFaceElementsSlip; + + /// Finite element type to finite element object map + std::map< string, std::unique_ptr< geos::finiteElement::FiniteElementBase > > m_faceTypeToFiniteElements; + + struct viewKeyStruct : ContactSolverBase::viewKeyStruct + { + constexpr static char const * rotationMatrixString() { return "rotationMatrix"; } + }; + +}; + +} /* namespace geos */ + +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSLAGRANGECONTACTBUBBLESTAB_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/contact/SolidMechanicsPenaltyContact.cpp b/src/coreComponents/physicsSolvers/contact/SolidMechanicsPenaltyContact.cpp new file mode 100644 index 00000000000..04d82d10cb6 --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/SolidMechanicsPenaltyContact.cpp @@ -0,0 +1,236 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolidMechanicsPenaltyContact.cpp + * + */ + +#include "SolidMechanicsPenaltyContact.hpp" + +#include "common/TimingMacros.hpp" +#include "constitutive/ConstitutiveManager.hpp" +#include "constitutive/contact/FrictionSelector.hpp" + + +#if defined( __INTEL_COMPILER ) +#pragma GCC optimize "O0" +#endif + +namespace geos +{ + +using namespace constitutive; +using namespace dataRepository; +using namespace fields; +using namespace finiteElement; + +SolidMechanicsPenaltyContact::SolidMechanicsPenaltyContact( const string & name, + Group * const parent ): + ContactSolverBase( name, parent ) +{ + registerWrapper( viewKeyStruct::contactPenaltyStiffnessString(), &m_contactPenaltyStiffness ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Value of the penetration penalty stiffness. Units of Pressure/length" ); +} + +SolidMechanicsPenaltyContact::~SolidMechanicsPenaltyContact() +{ + // TODO Auto-generated destructor stub +} + +void SolidMechanicsPenaltyContact::setupSystem( DomainPartition & domain, + DofManager & dofManager, + CRSMatrix< real64, globalIndex > & localMatrix, + ParallelVector & rhs, + ParallelVector & solution, + bool const setSparsity ) +{ + GEOS_MARK_FUNCTION; + PhysicsSolverBase::setupSystem( domain, dofManager, localMatrix, rhs, solution, false ); + + SparsityPattern< globalIndex > sparsityPattern( dofManager.numLocalDofs(), + dofManager.numGlobalDofs(), + 8*8*3*1.2 ); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + NodeManager const & nodeManager = mesh.getNodeManager(); + arrayView1d< globalIndex const > const + dofNumber = nodeManager.getReference< globalIndex_array >( dofManager.getKey( solidMechanics::totalDisplacement::key() ) ); + + + ElementRegionManager const & elemManager = mesh.getElemManager(); + array1d< string > allFaceElementRegions; + elemManager.forElementRegions< SurfaceElementRegion >( [&]( SurfaceElementRegion const & elemRegion ) + { + allFaceElementRegions.emplace_back( elemRegion.getName() ); + } ); + + finiteElement:: + fillSparsity< FaceElementSubRegion, + solidMechanicsLagrangianFEMKernels::ImplicitSmallStrainQuasiStatic >( mesh, + allFaceElementRegions, + this->getDiscretizationName(), + dofNumber, + dofManager.rankOffset(), + sparsityPattern ); + + finiteElement::fillSparsity< CellElementSubRegion, + solidMechanicsLagrangianFEMKernels::ImplicitSmallStrainQuasiStatic >( mesh, + regionNames, + this->getDiscretizationName(), + dofNumber, + dofManager.rankOffset(), + sparsityPattern ); + + + } ); + + sparsityPattern.compress(); + localMatrix.assimilate< parallelDevicePolicy<> >( std::move( sparsityPattern ) ); +} + +void SolidMechanicsPenaltyContact::assembleSystem( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + GEOS_MARK_FUNCTION; + + synchronizeFractureState( domain ); + + SolidMechanicsLagrangianFEM::assembleSystem( time, + dt, + domain, + dofManager, + localMatrix, + localRhs ); + + assembleContact( domain, dofManager, localMatrix, localRhs ); +} + +void SolidMechanicsPenaltyContact::assembleContact( DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + { + FaceManager const & faceManager = mesh.getFaceManager(); + NodeManager & nodeManager = mesh.getNodeManager(); + ElementRegionManager & elemManager = mesh.getElemManager(); + + solidMechanics::arrayViewConst2dLayoutTotalDisplacement const u = + nodeManager.getField< solidMechanics::totalDisplacement >(); + arrayView2d< real64 > const fc = nodeManager.getField< solidMechanics::contactForce >(); + fc.zero(); + + arrayView2d< real64 const > const faceNormal = faceManager.faceNormal(); + ArrayOfArraysView< localIndex const > const facesToNodes = faceManager.nodeList().toViewConst(); + + string const dofKey = dofManager.getKey( solidMechanics::totalDisplacement::key() ); + arrayView1d< globalIndex > const nodeDofNumber = nodeManager.getReference< globalIndex_array >( dofKey ); + globalIndex const rankOffset = dofManager.rankOffset(); + + // TODO: this bound may need to change + constexpr localIndex maxNodexPerFace = 4; + constexpr localIndex maxDofPerElem = maxNodexPerFace * 3 * 2; + + elemManager.forElementSubRegions< FaceElementSubRegion >( [&]( FaceElementSubRegion & subRegion ) + { + real64 const contactStiffness = m_contactPenaltyStiffness; + + arrayView1d< real64 > const area = subRegion.getElementArea(); + arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); + + // TODO: use parallel policy? + forAll< serialPolicy >( subRegion.size(), [=] ( localIndex const kfe ) + { + localIndex const kf0 = elemsToFaces[kfe][0], kf1 = elemsToFaces[kfe][1]; + real64 Nbar[ 3 ] = { faceNormal[kf0][0] - faceNormal[kf1][0], + faceNormal[kf0][1] - faceNormal[kf1][1], + faceNormal[kf0][2] - faceNormal[kf1][2] }; + + LvArray::tensorOps::normalize< 3 >( Nbar ); + + localIndex const numNodesPerFace=facesToNodes.sizeOfArray( kf0 ); + real64 const Ja = area[kfe] / numNodesPerFace; + + stackArray1d< globalIndex, maxDofPerElem > rowDOF( numNodesPerFace*3*2 ); + stackArray1d< real64, maxDofPerElem > nodeRHS( numNodesPerFace*3*2 ); + stackArray2d< real64, maxDofPerElem *maxDofPerElem > dRdP( numNodesPerFace*3*2, numNodesPerFace*3*2 ); + + for( localIndex a=0; a( gap, u[node0] ); + real64 const gapNormal = LvArray::tensorOps::AiBi< 3 >( gap, Nbar ); + + for( int i=0; i<3; ++i ) + { + rowDOF[3*a+i] = nodeDofNumber[node0]+i; + rowDOF[3*(numNodesPerFace + a)+i] = nodeDofNumber[node1]+i; + } + + if( gapNormal < 0 ) + { + LvArray::tensorOps::scale< 3 >( penaltyForce, -contactStiffness * gapNormal * Ja ); + for( int i=0; i<3; ++i ) + { + LvArray::tensorOps::subtract< 3 >( fc[node0], penaltyForce ); + LvArray::tensorOps::add< 3 >( fc[node1], penaltyForce ); + nodeRHS[3*a+i] -= penaltyForce[i]; + nodeRHS[3*(numNodesPerFace + a)+i] += penaltyForce[i]; + + dRdP( 3*a+i, 3*a+i ) -= contactStiffness * Ja * Nbar[i] * Nbar[i]; + dRdP( 3*a+i, 3*(numNodesPerFace + a)+i ) += contactStiffness * Ja * Nbar[i] * Nbar[i]; + dRdP( 3*(numNodesPerFace + a)+i, 3*a+i ) += contactStiffness * Ja * Nbar[i] * Nbar[i]; + dRdP( 3*(numNodesPerFace + a)+i, 3*(numNodesPerFace + a)+i ) -= contactStiffness * Ja * Nbar[i] * Nbar[i]; + } + } + } + + for( localIndex idof = 0; idof < numNodesPerFace*3*2; ++idof ) + { + localIndex const localRow = LvArray::integerConversion< localIndex >( rowDOF[idof] - rankOffset ); + + if( localRow >= 0 && localRow < localMatrix.numRows() ) + { + localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( localRow, + rowDOF.data(), + dRdP[idof].dataIfContiguous(), + numNodesPerFace*3*2 ); + RAJA::atomicAdd( serialAtomic{}, &localRhs[localRow], nodeRHS[idof] ); + } + } + } ); + } ); + } ); +} + + +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SolidMechanicsPenaltyContact, string const &, Group * const ) + +} /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/contact/SolidMechanicsPenaltyContact.hpp b/src/coreComponents/physicsSolvers/contact/SolidMechanicsPenaltyContact.hpp new file mode 100644 index 00000000000..3b1c0da697c --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/SolidMechanicsPenaltyContact.hpp @@ -0,0 +1,93 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolidMechanicsPenaltyContact.hpp + * + */ + +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSPENALTYCONTACT_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSPENALTYCONTACT_HPP_ + +#include "physicsSolvers/contact/ContactSolverBase.hpp" +#include "../../linearAlgebra/DofManager.hpp" +#include "../../common/DataTypes.hpp" + +namespace geos +{ + +class SolidMechanicsLagrangianFEM; + +class SolidMechanicsPenaltyContact : public ContactSolverBase +{ +public: + + SolidMechanicsPenaltyContact( const string & name, + Group * const parent ); + + ~SolidMechanicsPenaltyContact() override; + + /** + * @brief name of the node manager in the object catalog + * @return string that contains the catalog name to generate a new NodeManager object through the object catalog. + */ + static string catalogName() + { + return "SolidMechanicsPenaltyContact"; + } + /** + * @copydoc PhysicsSolverBase::getCatalogName() + */ + string getCatalogName() const override { return catalogName(); } + + /// String used to form the solverName used to register single-physics solvers in CoupledSolver + static string coupledSolverAttributePrefix() { return "PenaltyContact"; } + + virtual void + setupSystem( DomainPartition & domain, + DofManager & dofManager, + CRSMatrix< real64, globalIndex > & localMatrix, + ParallelVector & rhs, + ParallelVector & solution, + bool const setSparsity = true ) override final; + + virtual void + assembleSystem( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) override; + + void assembleContact( DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); + +protected: + +private: + + struct viewKeyStruct : ContactSolverBase::viewKeyStruct + { + constexpr static char const * contactPenaltyStiffnessString() { return "contactPenaltyStiffness"; } + }; + + real64 m_contactPenaltyStiffness; +}; + +} /* namespace geos */ + +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSPENALTYCONTACT_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/contact/docs/SolidMechanicsConformingFractures.rst b/src/coreComponents/physicsSolvers/contact/docs/SolidMechanicsConformingFractures.rst index 0a8fe63a76f..5f70bfcbb5d 100644 --- a/src/coreComponents/physicsSolvers/contact/docs/SolidMechanicsConformingFractures.rst +++ b/src/coreComponents/physicsSolvers/contact/docs/SolidMechanicsConformingFractures.rst @@ -1,8 +1,8 @@ .. _SolidMechanicsConformingFractures: -##################################### +########################################### Solid mechanics conforming fractures solver -##################################### +########################################### Introduction ============ @@ -24,9 +24,9 @@ Parameters In the preceding XML block, The `SolidMechanicsLagrangeContact` is specified by the title of the subblock of the `Solvers` block. The following attributes are supported in the input block for `SolidMechanicsLagrangeContact`: -.. include:: /coreComponents/schema/docs/SolidMechanicsLagrangeContact.rst +.. include:: /docs/sphinx/datastructure/SolidMechanicsLagrangeContact.rst The following data are allocated and used by the solver: -.. include:: /coreComponents/schema/docs/SolidMechanicsLagrangeContact_other.rst +.. include:: /docs/sphinx/datastructure/SolidMechanicsLagrangeContact_other.rst diff --git a/src/coreComponents/physicsSolvers/contact/docs/SolidMechanicsEmbeddedFractures.rst b/src/coreComponents/physicsSolvers/contact/docs/SolidMechanicsEmbeddedFractures.rst index 0e138bd2b84..739c9ab5226 100644 --- a/src/coreComponents/physicsSolvers/contact/docs/SolidMechanicsEmbeddedFractures.rst +++ b/src/coreComponents/physicsSolvers/contact/docs/SolidMechanicsEmbeddedFractures.rst @@ -1,8 +1,8 @@ .. _SolidMechanicsEmbeddedFractures: -##################################### +######################################### Solid mechanics embedded fractures solver -##################################### +######################################### @@ -11,7 +11,7 @@ Introduction Discretization & soltuion strategy -========================= +================================== The linear momentum balance equation is discretized using a low order finite element method. Moreover, to account for the influence of the fractures on the overall behavior, we utilize the enriched finite element method (EFEM) with a piece-wise constant enrichment. This method employs an element-local enrichment of the FE space using the concept of assumedenhanced strain [1-6]. @@ -22,7 +22,7 @@ Example An example of a valid XML block is given here: -.. literalinclude:: ../../../../../inputFiles/efemFractureMechanics/Sneddon_embeddedFrac_base.xml +.. literalinclude:: ../../../../../inputFiles/efemFractureMechanics/Sneddon_embeddedFrac_smoke.xml :language: xml :start-after: :end-before: @@ -34,11 +34,11 @@ In the preceding XML block, The `SolidMechanicsEmbeddedFractures` is specified b Note that the `SolidMechanicsEmbeddedFractures` always relies on the existance of a The following attributes are supported in the input block for `SolidMechanicsEmbeddedFractures`: -.. include:: /coreComponents/schema/docs/SolidMechanicsEmbeddedFractures.rst +.. include:: /docs/sphinx/datastructure/SolidMechanicsEmbeddedFractures.rst The following data are allocated and used by the solver: -.. include:: /coreComponents/schema/docs/SolidMechanicsEmbeddedFractures_other.rst +.. include:: /docs/sphinx/datastructure/SolidMechanicsEmbeddedFractures_other.rst References ========== diff --git a/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsALMKernels.hpp b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsALMKernels.hpp new file mode 100644 index 00000000000..b93406cf877 --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsALMKernels.hpp @@ -0,0 +1,434 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolidMechanicsALMKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSALMKERNELS_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSALMKERNELS_HPP_ + +#include "SolidMechanicsConformingContactKernelsBase.hpp" +#include "mesh/MeshFields.hpp" + + +namespace geos +{ + +namespace solidMechanicsALMKernels +{ + +/** + * @copydoc geos::finiteElement::ImplicitKernelBase + */ +template< typename CONSTITUTIVE_TYPE, + typename FE_TYPE > +class ALM : + public solidMechanicsConformingContactKernels::ConformingContactKernelsBase< CONSTITUTIVE_TYPE, + FE_TYPE > +{ +public: + /// Alias for the base class. + using Base = solidMechanicsConformingContactKernels::ConformingContactKernelsBase< CONSTITUTIVE_TYPE, + FE_TYPE >; + + /// Maximum number of nodes per element, which is equal to the maxNumTestSupportPointPerElem and + /// maxNumTrialSupportPointPerElem by definition. + static constexpr int numNodesPerElem = Base::maxNumTestSupportPointsPerElem; + + /// Compile time value for the number of quadrature points per element. + static constexpr int numQuadraturePointsPerElem = FE_TYPE::numQuadraturePoints; + + /// The number of displacement dofs per element. + static constexpr int numUdofs = Base::numUdofs; + + /// The number of bubble dofs per element. + static constexpr int numBdofs = Base::numBdofs; + + /// The number of lagrange multiplier dofs per element. + static constexpr int numTdofs = Base::numTdofs; + + using Base::m_elemsToFaces; + using Base::m_faceToNodes; + using Base::m_finiteElementSpace; + using Base::m_constitutiveUpdate; + using Base::m_dofNumber; + using Base::m_bDofNumber; + using Base::m_dofRankOffset; + using Base::m_X; + using Base::m_rotationMatrix; + using Base::m_dispJump; + using Base::m_oldDispJump; + using Base::m_matrix; + using Base::m_rhs; + + /** + * @brief Constructor + * @copydoc geos::finiteElement::InterfaceKernelBase::InterfaceKernelBase + */ + ALM( NodeManager const & nodeManager, + EdgeManager const & edgeManager, + FaceManager const & faceManager, + localIndex const targetRegionIndex, + FaceElementSubRegion & elementSubRegion, + FE_TYPE const & finiteElementSpace, + CONSTITUTIVE_TYPE & inputConstitutiveType, + arrayView1d< globalIndex const > const uDofNumber, + arrayView1d< globalIndex const > const bDofNumber, + globalIndex const rankOffset, + CRSMatrixView< real64, globalIndex const > const inputMatrix, + arrayView1d< real64 > const inputRhs, + real64 const inputDt, + arrayView1d< localIndex const > const & faceElementList, + bool const isSymmetric ): + Base( nodeManager, + edgeManager, + faceManager, + targetRegionIndex, + elementSubRegion, + finiteElementSpace, + inputConstitutiveType, + uDofNumber, + bDofNumber, + rankOffset, + inputMatrix, + inputRhs, + inputDt, + faceElementList ), + m_traction( elementSubRegion.getField< fields::contact::traction >().toViewConst()), + m_symmetric( isSymmetric ), + m_penalty( elementSubRegion.getField< fields::contact::iterativePenalty >().toViewConst() ), + m_faceArea( elementSubRegion.getField< fields::elementArea >().toViewConst() ) + {} + + //*************************************************************************** + + /** + * @copydoc finiteElement::KernelBase::StackVariables + */ + struct StackVariables : public Base::StackVariables + { + +public: + + GEOS_HOST_DEVICE + StackVariables(): + Base::StackVariables(), + dispEqnRowIndices{}, + dispColIndices{}, + bEqnRowIndices{}, + bColIndices{}, + localRu{}, + localRb{}, + localAutAtu{ {} }, + localAbtAtb{ {} }, + localAbtAtu{ {} }, + localAutAtb{ {} }, + tLocal{} + {} + + /// C-array storage for the element local row degrees of freedom. + globalIndex dispEqnRowIndices[numUdofs]; + + /// C-array storage for the element local column degrees of freedom. + globalIndex dispColIndices[numUdofs]; + + /// C-array storage for the element local row degrees of freedom. + globalIndex bEqnRowIndices[numBdofs]; + + /// C-array storage for the element local column degrees of freedom. + globalIndex bColIndices[numBdofs]; + + /// C-array storage for the element local Ru residual vector. + real64 localRu[numUdofs]; + + /// C-array storage for the element local Rb residual vector. + real64 localRb[numBdofs]; + + /// C-array storage for the element local AutAtu matrix. + real64 localAutAtu[numUdofs][numUdofs]; + + /// C-array storage for the element local AbtAtb matrix. + real64 localAbtAtb[numBdofs][numBdofs]; + + /// C-array storage for the element local AbtAtu matrix. + real64 localAbtAtu[numBdofs][numUdofs]; + + /// C-array storage for the element local AbtAtu matrix. + real64 localAutAtb[numUdofs][numBdofs]; + + /// Stack storage for the element local lagrange multiplier vector + real64 tLocal[numTdofs]; + + }; + + //*************************************************************************** + + //START_kernelLauncher + template< typename POLICY, + typename KERNEL_TYPE > + static + real64 + kernelLaunch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + return Base::template kernelLaunch< POLICY, KERNEL_TYPE >( numElems, kernelComponent ); + } + //END_kernelLauncher + + /** + * @brief Copy global values from primary field to a local stack array. + * @copydoc ::geos::finiteElement::InterfaceKernelBase::setup + */ + GEOS_HOST_DEVICE + inline + void setup( localIndex const k, + StackVariables & stack ) const + { + constexpr int shift = numNodesPerElem * 3; + + int permutation[numNodesPerElem]; + m_finiteElementSpace.getPermutation( permutation ); + + localIndex const kf0 = m_elemsToFaces[k][0]; + localIndex const kf1 = m_elemsToFaces[k][1]; + for( localIndex a=0; a::epsilon; + + real64 matRRtAtu[3][numUdofs], matDRtAtu[3][numUdofs]; + real64 matRRtAtb[3][numBdofs], matDRtAtb[3][numBdofs]; + + real64 tractionR[numUdofs]; + real64 tractionRb[numBdofs]; + + real64 tractionNew[3]; + + integer fractureState; + m_constitutiveUpdate.updateTraction( m_oldDispJump[k], + m_dispJump[k], + m_penalty[k], + m_traction[k], + m_faceArea[k], + m_symmetric, + m_symmetric, + zero, + zero, + stack.localPenalty, + tractionNew, + fractureState ); + + // transp(R) * Atu + LvArray::tensorOps::Rij_eq_AkiBkj< 3, numUdofs, 3 >( matRRtAtu, stack.localRotationMatrix, + stack.localAtu ); + // transp(R) * Atb + LvArray::tensorOps::Rij_eq_AkiBkj< 3, numBdofs, 3 >( matRRtAtb, stack.localRotationMatrix, + stack.localAtb ); + + // Compute the traction contribute of the local residuals + LvArray::tensorOps::Ri_eq_AjiBj< numUdofs, 3 >( tractionR, matRRtAtu, tractionNew ); + LvArray::tensorOps::Ri_eq_AjiBj< numBdofs, 3 >( tractionRb, matRRtAtb, tractionNew ); + + // D*RtAtu + LvArray::tensorOps::Rij_eq_AikBkj< 3, numUdofs, 3 >( matDRtAtu, stack.localPenalty, + matRRtAtu ); + // D*RtAtb + LvArray::tensorOps::Rij_eq_AikBkj< 3, numBdofs, 3 >( matDRtAtb, stack.localPenalty, + matRRtAtb ); + + // R*RtAtu + LvArray::tensorOps::Rij_eq_AikBkj< 3, numUdofs, 3 >( matRRtAtu, stack.localRotationMatrix, + matDRtAtu ); + // R*RtAtb + LvArray::tensorOps::Rij_eq_AikBkj< 3, numBdofs, 3 >( matRRtAtb, stack.localRotationMatrix, + matDRtAtb ); + + // transp(Atu)*RRtAtu + LvArray::tensorOps::Rij_eq_AkiBkj< numUdofs, numUdofs, 3 >( stack.localAutAtu, stack.localAtu, + matRRtAtu ); + // transp(Atb)*RRtAtb + LvArray::tensorOps::Rij_eq_AkiBkj< numBdofs, numBdofs, 3 >( stack.localAbtAtb, stack.localAtb, + matRRtAtb ); + + // transp(Atb)*RRtAtu + LvArray::tensorOps::Rij_eq_AkiBkj< numBdofs, numUdofs, 3 >( stack.localAbtAtu, stack.localAtb, + matRRtAtu ); + + // transp(Atu)*RRtAtb + LvArray::tensorOps::Rij_eq_AkiBkj< numUdofs, numBdofs, 3 >( stack.localAutAtb, stack.localAtu, + matRRtAtb ); + + // Compute the local residuals + LvArray::tensorOps::scaledAdd< numUdofs >( stack.localRu, tractionR, -1 ); + + LvArray::tensorOps::scaledAdd< numBdofs >( stack.localRb, tractionRb, -1 ); + + for( localIndex i=0; i < numUdofs; ++i ) + { + localIndex const dof = LvArray::integerConversion< localIndex >( stack.dispEqnRowIndices[ i ] ); + + if( dof < 0 || dof >= m_matrix.numRows() ) continue; + + // Is it necessary? Each row should be indepenedent + RAJA::atomicAdd< parallelDeviceAtomic >( &m_rhs[dof], stack.localRu[i] ); + + // Fill in matrix + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.dispColIndices, + stack.localAutAtu[i], + numUdofs ); + + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.bColIndices, + stack.localAutAtb[i], + numBdofs ); + } + + for( localIndex i=0; i < numBdofs; ++i ) + { + localIndex const dof = LvArray::integerConversion< localIndex >( stack.bEqnRowIndices[ i ] ); + + if( dof < 0 || dof >= m_matrix.numRows() ) continue; + + // Is it necessary? Each row should be indepenedent + RAJA::atomicAdd< parallelDeviceAtomic >( &m_rhs[dof], stack.localRb[i] ); + + // Fill in matrix + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.bColIndices, + stack.localAbtAtb[i], + numBdofs ); + + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.dispColIndices, + stack.localAbtAtu[i], + numUdofs ); + } + + return 0.0; + } + +protected: + + arrayView2d< real64 const > const m_traction; + + bool const m_symmetric; + + /// The array containing the penalty coefficients for each element. + arrayView2d< real64 const > const m_penalty; + + arrayView1d< real64 const > const m_faceArea; +}; + +/// The factory used to construct the kernel. +using ALMFactory = finiteElement::InterfaceKernelFactory< ALM, + arrayView1d< globalIndex const > const, + arrayView1d< globalIndex const > const, + globalIndex const, + CRSMatrixView< real64, globalIndex const > const, + arrayView1d< real64 > const, + real64 const, + arrayView1d< localIndex const > const, + bool const >; + +/** + * @brief A struct to compute the traction after nonlinear solve + */ +struct ComputeTractionKernel +{ + + /** + * @brief Launch the kernel function to compute the traction + * @tparam POLICY the type of policy used in the kernel launch + * @tparam CONTACT_WRAPPER the type of contact wrapper doing the fracture traction updates + * @param[in] size the size of the subregion + * @param[in] penalty the array containing the tangential penalty matrix + * @param[in] traction the array containing the current traction + * @param[in] dispJump the array containing the displacement jump + * @param[in] deltaDispJump the array containing the delta displacement jump + * @param[out] tractionNew the array containing the new traction + */ + template< typename POLICY, typename CONTACT_WRAPPER > + static void + launch( localIndex const size, + CONTACT_WRAPPER const & contactWrapper, + arrayView2d< real64 const > const & penalty, + arrayView2d< real64 const > const & traction, + arrayView2d< real64 const > const & dispJump, + arrayView2d< real64 const > const & deltaDispJump, + arrayView1d< real64 const > const & faceArea, + arrayView2d< real64 > const & tractionNew ) + { + + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + + contactWrapper.updateTractionOnly( dispJump[k], deltaDispJump[k], + penalty[k], traction[k], faceArea[k], tractionNew[k] ); + + } ); + } +}; + +} // namespace SolidMechanicsALMKernels + +} // namespace geos + + +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSALMKERNELS_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsALMKernelsBase.hpp b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsALMKernelsBase.hpp new file mode 100644 index 00000000000..b3f96f9f182 --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsALMKernelsBase.hpp @@ -0,0 +1,173 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolidMechanicsALMKernelsBase.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSALMKERNELSBASE_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSALMKERNELSBASE_HPP_ + +#include "finiteElement/kernelInterface/InterfaceKernelBase.hpp" +#include "SolidMechanicsConformingContactKernelsHelper.hpp" + +namespace geos +{ + +namespace solidMechanicsALMKernels +{ + +/** + * @brief A struct to check for constraint satisfaction + */ +struct ConstraintCheckKernel +{ + + /** + * @brief Launch the kernel function to check the constraint satisfaction + * @tparam POLICY the type of policy used in the kernel launch + * @tparam CONTACT_WRAPPER the type of contact wrapper doing the fracture traction updates + * @param[in] size the size of the subregion + * @param[in] traction the array containing the current traction + * @param[in] dispJump the array containing the displacement jump + * @param[in] deltaDispJump the array containing the delta displacement jump + * @param[in] normalTractionTolerance Check tolerance (normal traction) + * @param[in] normalDisplacementTolerance Check tolerance (compenetration) + * @param[in] slidingTolerance Check tolerance (sliding) + * @param[in] slidingCheckTolerance Check tolerance (if shear strass exceeds tauLim) + * @param[in] area interface element area + * @param[in] fractureState the array containing the fracture state + * @param[out] condConv the array containing the convergence flag: + * 0: Constraint conditions satisfied + * 1: Open + * 2: Compenetration + * 3: Slip exceeds sliding tolerance + * 4: Shear stress exceeds tauLim + */ + template< typename POLICY, typename CONTACT_WRAPPER > + static void + launch( localIndex const size, + CONTACT_WRAPPER const & contactWrapper, + arrayView1d< integer const > const & ghostRank, + arrayView2d< real64 > const & traction, + arrayView2d< real64 const > const & dispJump, + arrayView2d< real64 const > const & deltaDispJump, + arrayView1d< real64 const > const & normalTractionTolerance, + arrayView1d< real64 const > const & normalDisplacementTolerance, + arrayView1d< real64 const > const & slidingTolerance, + real64 const slidingCheckTolerance, + arrayView1d< integer const > const & fractureState, + arrayView1d< integer > const & condConv ) + { + + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + if( ghostRank[k] < 0 ) + { + contactWrapper.constraintCheck( dispJump[k], + deltaDispJump[k], + traction[k], + fractureState[k], + normalTractionTolerance[k], + normalDisplacementTolerance[k], + slidingTolerance[k], + slidingCheckTolerance, + condConv[k] ); + } + + } ); + } +}; + +/** + * @brief A struct to check for constraint satisfaction + */ +struct UpdateStateKernel +{ + + /** + * @brief Launch the kernel function to check the constraint satisfaction + * @tparam POLICY the type of policy used in the kernel launch + * @tparam CONTACT_WRAPPER the type of contact wrapper doing the fracture traction updates + * @param[in] size the size of the subregion + * @param[in] oldDispJump the array containing the old displacement jump (previous time step) + * @param[in] dispJump the array containing the displacement jump + * @param[in] penalty the array containing the penalty coefficients + * @param[in] symmetric flag to compute symmetric penalty matrix + * @param[in] normalTractionTolerance Check tolerance (normal traction) + * @param[in] traction the array containing the current traction + * @param[in] fractureState the array containing the fracture state + */ + template< typename POLICY, typename CONTACT_WRAPPER > + static void + launch( localIndex const size, + CONTACT_WRAPPER const & contactWrapper, + arrayView2d< real64 const > const & oldDispJump, + arrayView2d< real64 const > const & dispJump, + arrayView2d< real64 > const & penalty, + arrayView1d< real64 const > const & faceArea, + bool const symmetric, + arrayView1d< real64 const > const & normalTractionTolerance, + arrayView2d< real64 > const & traction, + arrayView1d< integer > const & fractureState ) + + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + + real64 const zero = LvArray::NumericLimits< real64 >::epsilon; + + real64 localPenalty[3][3]{}; + real64 localTractionNew[3]{}; + contactWrapper.updateTraction( oldDispJump[k], + dispJump[k], + penalty[k], + traction[k], + faceArea[k], + symmetric, + false, + normalTractionTolerance[k], + zero, + localPenalty, + localTractionNew, + fractureState[k] ); + + if( fractureState[k] == fields::contact::FractureState::Open ) + { + + LvArray::tensorOps::fill< 3 >( localTractionNew, 0.0 ); + } + else if( LvArray::math::abs( localTractionNew[ 0 ] ) < normalTractionTolerance[k] ) + { + LvArray::tensorOps::fill< 3 >( localTractionNew, 0.0 ); + fractureState[k] = fields::contact::FractureState::Slip; + } + + LvArray::tensorOps::copy< 3 >( traction[k], localTractionNew ); + penalty[k][2] = -localPenalty[1][1]; + penalty[k][3] = -localPenalty[2][2]; + penalty[k][4] = -localPenalty[1][2]; + + } ); + } + +}; + +} // namespace SolidMechanicsALMKernels + +} // namespace geos + + +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSALMKERNELSBASE_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsALMSimultaneousKernels.hpp b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsALMSimultaneousKernels.hpp new file mode 100644 index 00000000000..2769a101963 --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsALMSimultaneousKernels.hpp @@ -0,0 +1,447 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolidMechanicsALMSimultaneousKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSALMSIMULTANEOUSKERNELS_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSALMSIMULTANEOUSKERNELS_HPP_ + +#include "SolidMechanicsConformingContactKernelsBase.hpp" +#include "mesh/MeshFields.hpp" + +namespace geos +{ + +namespace solidMechanicsALMKernels +{ + +/** + * @copydoc geos::finiteElement::ImplicitKernelBase + */ +template< typename CONSTITUTIVE_TYPE, + typename FE_TYPE > +class ALMSimultaneous : + public solidMechanicsConformingContactKernels::ConformingContactKernelsBase< CONSTITUTIVE_TYPE, + FE_TYPE > +{ +public: + /// Alias for the base class. + using Base = solidMechanicsConformingContactKernels::ConformingContactKernelsBase< CONSTITUTIVE_TYPE, + FE_TYPE >; + + /// Maximum number of nodes per element, which is equal to the maxNumTestSupportPointPerElem and + /// maxNumTrialSupportPointPerElem by definition. + static constexpr int numNodesPerElem = Base::maxNumTestSupportPointsPerElem; + + /// Compile time value for the number of quadrature points per element. + static constexpr int numQuadraturePointsPerElem = FE_TYPE::numQuadraturePoints; + + /// The number of displacement dofs per element. + static constexpr int numUdofs = Base::numUdofs; + + /// The number of bubble dofs per element. + static constexpr int numBdofs = Base::numBdofs; + + /// The number of lagrange multiplier dofs per element. + static constexpr int numTdofs = Base::numTdofs; + + using Base::m_elemsToFaces; + using Base::m_faceToNodes; + using Base::m_finiteElementSpace; + using Base::m_dofNumber; + using Base::m_bDofNumber; + using Base::m_dofRankOffset; + using Base::m_X; + using Base::m_rotationMatrix; + using Base::m_dispJump; + using Base::m_oldDispJump; + using Base::m_matrix; + using Base::m_rhs; + + /** + * @brief Constructor + * @copydoc geos::finiteElement::InterfaceKernelBase::InterfaceKernelBase + */ + ALMSimultaneous( NodeManager const & nodeManager, + EdgeManager const & edgeManager, + FaceManager const & faceManager, + localIndex const targetRegionIndex, + FaceElementSubRegion & elementSubRegion, + FE_TYPE const & finiteElementSpace, + CONSTITUTIVE_TYPE & inputConstitutiveType, + arrayView1d< globalIndex const > const uDofNumber, + arrayView1d< globalIndex const > const bDofNumber, + globalIndex const rankOffset, + CRSMatrixView< real64, globalIndex const > const inputMatrix, + arrayView1d< real64 > const inputRhs, + real64 const inputDt, + arrayView1d< localIndex const > const & faceElementList ): + Base( nodeManager, + edgeManager, + faceManager, + targetRegionIndex, + elementSubRegion, + finiteElementSpace, + inputConstitutiveType, + uDofNumber, + bDofNumber, + rankOffset, + inputMatrix, + inputRhs, + inputDt, + faceElementList ), + m_traction( elementSubRegion.getField< fields::contact::traction >().toViewConst()), + m_penalty( elementSubRegion.getField< fields::contact::iterativePenalty >().toViewConst() ), + m_faceArea( elementSubRegion.getField< fields::elementArea >().toViewConst() ) + {} + + //*************************************************************************** + + /** + * @copydoc finiteElement::KernelBase::StackVariables + */ + struct StackVariables : public Base::StackVariables + { + + /// The number of displacement dofs per element. + static constexpr int numUdofs = numNodesPerElem * 3 * 2; + + /// The number of lagrange multiplier dofs per element. + static constexpr int numTdofs = 3; + + /// The number of bubble dofs per element. + static constexpr int numBdofs = 3*2; + +public: + + GEOS_HOST_DEVICE + StackVariables(): + Base::StackVariables(), + dispEqnRowIndices{}, + dispColIndices{}, + bEqnRowIndices{}, + bColIndices{}, + localRu{}, + localRb{}, + localAutAtu{ {} }, + localAbtAtb{ {} }, + localAbtAtu{ {} }, + localAutAtb{ {} }, + tLocal{} + {} + + /// C-array storage for the element local row degrees of freedom. + globalIndex dispEqnRowIndices[numUdofs]; + + /// C-array storage for the element local column degrees of freedom. + globalIndex dispColIndices[numUdofs]; + + /// C-array storage for the element local row degrees of freedom. + globalIndex bEqnRowIndices[numBdofs]; + + /// C-array storage for the element local column degrees of freedom. + globalIndex bColIndices[numBdofs]; + + /// C-array storage for the element local Ru residual vector. + real64 localRu[numUdofs]; + + /// C-array storage for the element local Rb residual vector. + real64 localRb[numBdofs]; + + /// C-array storage for the element local AutAtu matrix. + real64 localAutAtu[numUdofs][numUdofs]; + + /// C-array storage for the element local AbtAtb matrix. + real64 localAbtAtb[numBdofs][numBdofs]; + + /// C-array storage for the element local AbtAtu matrix. + real64 localAbtAtu[numBdofs][numUdofs]; + + /// C-array storage for the element local AbtAtu matrix. + real64 localAutAtb[numUdofs][numBdofs]; + + /// Stack storage for the element local lagrange multiplier vector + real64 tLocal[numTdofs]; + + }; + + //*************************************************************************** + + //START_kernelLauncher + template< typename POLICY, + typename KERNEL_TYPE > + static + real64 + kernelLaunch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + return Base::template kernelLaunch< POLICY, KERNEL_TYPE >( numElems, kernelComponent ); + } + //END_kernelLauncher + + /** + * @brief Copy global values from primary field to a local stack array. + * @copydoc ::geos::finiteElement::InterfaceKernelBase::setup + */ + GEOS_HOST_DEVICE + inline + void setup( localIndex const k, + StackVariables & stack ) const + { + constexpr int shift = numNodesPerElem * 3; + + int permutation[numNodesPerElem]; + m_finiteElementSpace.getPermutation( permutation ); + + localIndex const kf0 = m_elemsToFaces[k][0]; + localIndex const kf1 = m_elemsToFaces[k][1]; + for( localIndex a=0; a( tractionNew, stack.tLocal, -1.0 ); + LvArray::tensorOps::Ri_add_AijBj< 3, 3 >( tractionNew, stack.localPenalty, dispJump ); + + // If normal tangential trial is positive (opening) + //if (tractionNew[ 0 ] < -zero) + //{ + // tractionNew[0] = 0.0; + // stack.localPenalty[0][0] = 0.0; + //} + + // transp(R) * Atu + LvArray::tensorOps::Rij_eq_AkiBkj< 3, numUdofs, 3 >( matRRtAtu, stack.localRotationMatrix, + stack.localAtu ); + // transp(R) * Atb + LvArray::tensorOps::Rij_eq_AkiBkj< 3, numBdofs, 3 >( matRRtAtb, stack.localRotationMatrix, + stack.localAtb ); + + // Compute the traction contribute of the local residuals + LvArray::tensorOps::Ri_eq_AjiBj< numUdofs, 3 >( tractionR, matRRtAtu, tractionNew ); + LvArray::tensorOps::Ri_eq_AjiBj< numBdofs, 3 >( tractionRb, matRRtAtb, tractionNew ); + + // D*RtAtu + LvArray::tensorOps::Rij_eq_AikBkj< 3, numUdofs, 3 >( matDRtAtu, stack.localPenalty, + matRRtAtu ); + // D*RtAtb + LvArray::tensorOps::Rij_eq_AikBkj< 3, numBdofs, 3 >( matDRtAtb, stack.localPenalty, + matRRtAtb ); + + // R*RtAtu + LvArray::tensorOps::Rij_eq_AikBkj< 3, numUdofs, 3 >( matRRtAtu, stack.localRotationMatrix, + matDRtAtu ); + // R*RtAtb + LvArray::tensorOps::Rij_eq_AikBkj< 3, numBdofs, 3 >( matRRtAtb, stack.localRotationMatrix, + matDRtAtb ); + + // transp(Atu)*RRtAtu + LvArray::tensorOps::Rij_eq_AkiBkj< numUdofs, numUdofs, 3 >( stack.localAutAtu, stack.localAtu, + matRRtAtu ); + // transp(Atb)*RRtAtb + LvArray::tensorOps::Rij_eq_AkiBkj< numBdofs, numBdofs, 3 >( stack.localAbtAtb, stack.localAtb, + matRRtAtb ); + + // transp(Atb)*RRtAtu + LvArray::tensorOps::Rij_eq_AkiBkj< numBdofs, numUdofs, 3 >( stack.localAbtAtu, stack.localAtb, + matRRtAtu ); + + // transp(Atu)*RRtAtb + LvArray::tensorOps::Rij_eq_AkiBkj< numUdofs, numBdofs, 3 >( stack.localAutAtb, stack.localAtu, + matRRtAtb ); + + // Compute the local residuals + LvArray::tensorOps::scaledAdd< numUdofs >( stack.localRu, tractionR, 1 ); + + LvArray::tensorOps::scaledAdd< numBdofs >( stack.localRb, tractionRb, 1 ); + + for( localIndex i=0; i < numUdofs; ++i ) + { + localIndex const dof = LvArray::integerConversion< localIndex >( stack.dispEqnRowIndices[ i ] ); + + if( dof < 0 || dof >= m_matrix.numRows() ) continue; + + // Is it necessary? Each row should be indepenedent + RAJA::atomicAdd< parallelDeviceAtomic >( &m_rhs[dof], stack.localRu[i] ); + + // Fill in matrix + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.dispColIndices, + stack.localAutAtu[i], + numUdofs ); + + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.bColIndices, + stack.localAutAtb[i], + numBdofs ); + } + + for( localIndex i=0; i < numBdofs; ++i ) + { + localIndex const dof = LvArray::integerConversion< localIndex >( stack.bEqnRowIndices[ i ] ); + + if( dof < 0 || dof >= m_matrix.numRows() ) continue; + + // Is it necessary? Each row should be indepenedent + RAJA::atomicAdd< parallelDeviceAtomic >( &m_rhs[dof], stack.localRb[i] ); + + // Fill in matrix + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.bColIndices, + stack.localAbtAtb[i], + numBdofs ); + + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.dispColIndices, + stack.localAbtAtu[i], + numUdofs ); + } + + return 0.0; + } + +protected: + + arrayView2d< real64 const > const m_traction; + + /// The array containing the penalty coefficients for each element. + arrayView2d< real64 const > const m_penalty; + + arrayView1d< real64 const > const m_faceArea; +}; + +/// The factory used to construct the kernel. +using ALMSimultaneousFactory = finiteElement::InterfaceKernelFactory< ALMSimultaneous, + arrayView1d< globalIndex const > const, + arrayView1d< globalIndex const > const, + globalIndex const, + CRSMatrixView< real64, globalIndex const > const, + arrayView1d< real64 > const, + real64 const, + arrayView1d< localIndex const > const >; + +/** + * @brief A struct to compute the traction after nonlinear solve + */ +struct ComputeTractionSimultaneousKernel +{ + + /** + * @brief Launch the kernel function to comute traction + * @tparam POLICY the type of policy used in the kernel launch + * @param[in] size the size of the subregion + * @param[in] penalty the array containing the tangential penalty matrix + * @param[in] traction the array containing the current traction + * @param[in] dispJump the array containing the displacement jump + * @param[in] deltaDispJump the array containing the delta displacement jump + * @param[out] tractionNew the array containing the new traction + */ + template< typename POLICY > + static void + launch( localIndex const size, + arrayView2d< real64 const > const & penalty, + arrayView2d< real64 const > const & traction, + arrayView2d< real64 const > const & dispJump, + arrayView2d< real64 const > const & deltaDispJump, + arrayView1d< real64 const > const & faceElementArea, + arrayView2d< real64 > const & tractionNew ) + { + + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const kfe ) + { + tractionNew[kfe][0] = traction[kfe][0] + penalty[kfe][0] * dispJump[kfe][0] * faceElementArea[kfe]; + tractionNew[kfe][1] = traction[kfe][1] + ( penalty[kfe][2] * deltaDispJump[kfe][1]+ + penalty[kfe][4] * deltaDispJump[kfe][2] ) * faceElementArea[kfe]; + tractionNew[kfe][2] = traction[kfe][2] + ( penalty[kfe][3] * deltaDispJump[kfe][2] + + penalty[kfe][4] * deltaDispJump[kfe][1] ) * faceElementArea[kfe]; + } ); + } + +}; + +} // namespace SolidMechanicsALMKernels + +} // namespace geos + + +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSALMKERNELS_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsConformingContactKernelsBase.hpp b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsConformingContactKernelsBase.hpp new file mode 100644 index 00000000000..dc5de425b0d --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsConformingContactKernelsBase.hpp @@ -0,0 +1,327 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolidMechanicsALMKernelsBase.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSCONFORMINGCONTACTKERNELSBASE_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSCONFORMINGCONTACTKERNELSBASE_HPP_ + +#include "finiteElement/kernelInterface/InterfaceKernelBase.hpp" +#include "SolidMechanicsConformingContactKernelsHelper.hpp" +#include "codingUtilities/Utilities.hpp" + +namespace geos +{ + +namespace solidMechanicsConformingContactKernels +{ + +/** + * @brief Implements kernels for ALM. + * @copydoc geos::finiteElement::InterfaceKernelBase + * + */ +template< typename CONSTITUTIVE_TYPE, + typename FE_TYPE > +class ConformingContactKernelsBase : + public finiteElement::InterfaceKernelBase< CONSTITUTIVE_TYPE, + FE_TYPE, + 3, 3 > +{ +public: + /// Alias for the base class; + using Base = finiteElement::InterfaceKernelBase< CONSTITUTIVE_TYPE, + FE_TYPE, + 3, 3 >; + + /// Number of nodes per element...which is equal to the + /// numTestSupportPointPerElem and numTrialSupportPointPerElem by definition. + static constexpr int numNodesPerElem = Base::maxNumTestSupportPointsPerElem; + + /// Compile time value for the number of quadrature points per element. + static constexpr int numQuadraturePointsPerElem = FE_TYPE::numQuadraturePoints; + + /// The number of displacement dofs per element. + static constexpr int numUdofs = numNodesPerElem * 3 * 2; + + /// The number of lagrange multiplier dofs per element. + static constexpr int numTdofs = 3; + + /// The number of bubble dofs per element. + static constexpr int numBdofs = 3*2; + + using Base::m_dofNumber; + using Base::m_dofRankOffset; + using Base::m_finiteElementSpace; + using Base::m_matrix; + using Base::m_rhs; + + /** + * @brief Constructor + * @copydoc geos::finiteElement::InterfaceKernelBase::InterfaceKernelBase + */ + ConformingContactKernelsBase( NodeManager const & nodeManager, + EdgeManager const & edgeManager, + FaceManager const & faceManager, + localIndex const targetRegionIndex, + FaceElementSubRegion & elementSubRegion, + FE_TYPE const & finiteElementSpace, + CONSTITUTIVE_TYPE & inputConstitutiveType, + arrayView1d< globalIndex const > const uDofNumber, + arrayView1d< globalIndex const > const bDofNumber, + globalIndex const rankOffset, + CRSMatrixView< real64, globalIndex const > const inputMatrix, + arrayView1d< real64 > const inputRhs, + real64 const inputDt, + arrayView1d< localIndex const > const & faceElementList ): + Base( nodeManager, + edgeManager, + faceManager, + targetRegionIndex, + elementSubRegion, + finiteElementSpace, + inputConstitutiveType, + uDofNumber, + rankOffset, + inputMatrix, + inputRhs, + inputDt ), + m_X( nodeManager.referencePosition()), + m_faceToNodes( faceManager.nodeList().toViewConst()), + m_elemsToFaces( elementSubRegion.faceList().toViewConst()), + m_faceElementList( faceElementList ), + m_bDofNumber( bDofNumber ), + m_rotationMatrix( elementSubRegion.getField< fields::contact::rotationMatrix >().toViewConst()), + m_dispJump( elementSubRegion.getField< fields::contact::dispJump >().toView() ), + m_oldDispJump( elementSubRegion.getField< fields::contact::oldDispJump >().toViewConst() ) + {} + + //*************************************************************************** + /** + * @copydoc finiteElement::InterfaceKernelBase::StackVariables + */ + struct StackVariables + { + + +public: + + GEOS_HOST_DEVICE + StackVariables(): + localAtu{ {} }, + localAtb{ {} }, + localRotationMatrix{ {} }, + localPenalty{ {} }, + dispJumpLocal{}, + oldDispJumpLocal{}, + X{ {} } + {} + + /// C-array storage for the element local Atu matrix. + real64 localAtu[numTdofs][numUdofs]; + + /// C-array storage for the element local Atb matrix. + real64 localAtb[numTdofs][numBdofs]; + + /// C-array storage for rotation matrix + real64 localRotationMatrix[3][3]; + + /// C-array storage for penalty matrix + real64 localPenalty[3][3]; + + /// Stack storage for the element local displacement jump vector + real64 dispJumpLocal[numTdofs]; + + /// Stack storage for the element local old displacement jump vector + real64 oldDispJumpLocal[numTdofs]; + + /// local nodal coordinates + real64 X[ numNodesPerElem ][ 3 ]; + + }; + + //*************************************************************************** + + /** + * @copydoc ::geos::finiteElement::InterfaceKernelBase::kernelLaunch + * + */ + //START_kernelLauncher + template< typename POLICY, + typename KERNEL_TYPE > + static + real64 + kernelLaunch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + GEOS_UNUSED_VAR( numElems ); + + // Define a RAJA reduction variable to get the maximum residual contribution. + RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxResidual( 0 ); + + forAll< POLICY >( kernelComponent.m_faceElementList.size(), + [=] GEOS_HOST_DEVICE ( localIndex const i ) + { + + localIndex k = kernelComponent.m_faceElementList[i]; + typename KERNEL_TYPE::StackVariables stack; + + kernelComponent.setup( k, stack ); + for( integer q=0; q + GEOS_HOST_DEVICE + inline + void quadraturePointKernel( localIndex const k, + localIndex const q, + StackVariables & stack, + LAMBDA && lambda = NoOpFunc{} ) const + { + GEOS_UNUSED_VAR( k ); + + real64 const detJ = m_finiteElementSpace.transformedQuadratureWeight( q, stack.X ); + + real64 N[ numNodesPerElem ]; + m_finiteElementSpace.calcN( q, N ); + + real64 BubbleN[1]; + // Next line is needed because I only inserted a placeholder for calcBubbleN in some finite elements + BubbleN[0]=0.0; //make 0 + constexpr int bperm[1] = {0}; + m_finiteElementSpace.calcBubbleN( q, BubbleN ); + + int permutation[numNodesPerElem]; + m_finiteElementSpace.getPermutation( permutation ); + + // TODO: Try using bilinear utilities to perform these two operations + solidMechanicsConformingContactKernelsHelper::accumulateAtuLocalOperator< numTdofs, + numUdofs, + numNodesPerElem >( stack.localAtu, + N, + permutation, + detJ ); + + solidMechanicsConformingContactKernelsHelper::accumulateAtuLocalOperator< numTdofs, + numBdofs, + 1 >( stack.localAtb, + BubbleN, + bperm, + detJ ); + + lambda( detJ ); + } + +protected: + + /// The array containing the nodal position array. + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const m_X; + + /// The array of array containing the face to node map. + ArrayOfArraysView< localIndex const > const m_faceToNodes; + + /// The array of array containing the element to face map. + arrayView2d< localIndex const > const m_elemsToFaces; + + /// The array containing the list of face element of the same type. + arrayView1d< localIndex const > const m_faceElementList; + + /// The global degree of freedom number of bubble. + arrayView1d< globalIndex const > const m_bDofNumber; + + /// The array containing the rotation matrix for each element. + arrayView3d< real64 const > const m_rotationMatrix; + + /// The array containing the displacement jump. + arrayView2d< real64 > const m_dispJump; + + /// The array containing the displacement jump of previus time step. + arrayView2d< real64 const > const m_oldDispJump; +}; + + +/** + * @brief A struct to compute rotation matrices + */ +struct ComputeRotationMatricesKernel +{ + + /** + * @brief Launch the kernel function to comute rotation matrices + * @tparam POLICY the type of policy used in the kernel launch + * @param[in] size the size of the subregion + * @param[in] faceNormal the array of array containing the face to nodes map + * @param[in] elemsToFaces the array of array containing the element to faces map + * @param[out] rotationMatrix the array containing the rotation matrices + */ + template< typename POLICY > + static void + launch( localIndex const size, + arrayView2d< real64 const > const & faceNormal, + arrayView2d< localIndex const > const & elemsToFaces, + arrayView3d< real64 > const & rotationMatrix, + arrayView2d< real64 > const & unitNormal, + arrayView2d< real64 > const & unitTangent1, + arrayView2d< real64 > const & unitTangent2 ) + { + + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + + localIndex const & f0 = elemsToFaces[k][0]; + localIndex const & f1 = elemsToFaces[k][1]; + + real64 Nbar[3]; + Nbar[0] = faceNormal[f0][0] - faceNormal[f1][0]; + Nbar[1] = faceNormal[f0][1] - faceNormal[f1][1]; + Nbar[2] = faceNormal[f0][2] - faceNormal[f1][2]; + + LvArray::tensorOps::normalize< 3 >( Nbar ); + computationalGeometry::RotationMatrix_3D( Nbar, rotationMatrix[k] ); + + real64 const columnVector1[3] = { rotationMatrix[k][ 0 ][ 1 ], + rotationMatrix[k][ 1 ][ 1 ], + rotationMatrix[k][ 2 ][ 1 ] }; + + real64 const columnVector2[3] = { rotationMatrix[k][ 0 ][ 2 ], + rotationMatrix[k][ 1 ][ 2 ], + rotationMatrix[k][ 2 ][ 2 ] }; + + LvArray::tensorOps::copy< 3 >( unitNormal[k], Nbar ); + LvArray::tensorOps::copy< 3 >( unitTangent1[k], columnVector1 ); + LvArray::tensorOps::copy< 3 >( unitTangent2[k], columnVector2 ); + } ); + } + +}; + + +} // namespace solidMechanicsConformingContactKernels + +} // namespace geos + + +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSCONFORMINGCONTACTKERNELSBASE_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsConformingContactKernelsHelper.hpp b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsConformingContactKernelsHelper.hpp new file mode 100644 index 00000000000..ac79e062648 --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsConformingContactKernelsHelper.hpp @@ -0,0 +1,83 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + + +/** + * @file SolidMechanicsConformingContactKernelsHelper.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSCONFORMINGCONTACTKERNELSHELPER_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSCONFORMINGCONTACTKERNELSHELPER_HPP_ + +#include "common/GeosxMacros.hpp" + +namespace geos +{ + +namespace solidMechanicsConformingContactKernelsHelper +{ + +template< int I_SIZE, + int J_SIZE, + int NUM_NODES > +GEOS_HOST_DEVICE +inline +void accumulateAtuLocalOperator( real64 ( & matrix )[I_SIZE][J_SIZE], + real64 ( & N )[NUM_NODES], + int const ( &perm )[NUM_NODES], + real64 const detJ ) +{ + for( int a=0; a < NUM_NODES; ++a ) + { + for( int i=0; i < I_SIZE; ++i ) + { + matrix[i][ a*3 + i ] += -N[ perm[ a ] ] * detJ; + matrix[i][ 3*NUM_NODES + a*3 + i ] += N[ perm[ a ] ] * detJ; + } + } +} + +template< int I_SIZE, + int J_SIZE, + int NUM_SUPPORTS > +GEOS_HOST_DEVICE +inline +void assembleStrainOperator( real64 ( & strainMatrix )[I_SIZE][J_SIZE], + real64 ( & dNdX )[NUM_SUPPORTS][3] ) +{ + LvArray::tensorOps::fill< I_SIZE, J_SIZE >( strainMatrix, 0 ); //make 0 + for( int a=0; a < NUM_SUPPORTS; ++a ) + { + + strainMatrix[0][a*3 + 0] = dNdX[a][0]; + strainMatrix[1][a*3 + 1] = dNdX[a][1]; + strainMatrix[2][a*3 + 2] = dNdX[a][2]; + + strainMatrix[3][a*3 + 1] = dNdX[a][2]; + strainMatrix[3][a*3 + 2] = dNdX[a][1]; + + strainMatrix[4][a*3 + 0] = dNdX[a][2]; + strainMatrix[4][a*3 + 2] = dNdX[a][0]; + + strainMatrix[5][a*3 + 0] = dNdX[a][1]; + strainMatrix[5][a*3 + 1] = dNdX[a][0]; + } +} + +} // solidMechanicsConformingContactKernelsHelper + +} // geos + +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSCONFORMINGCONTACTKERNELSHELPER_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsContactFaceBubbleKernels.hpp b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsContactFaceBubbleKernels.hpp new file mode 100644 index 00000000000..46e8034c581 --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsContactFaceBubbleKernels.hpp @@ -0,0 +1,442 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolidMechanicsContactFaceBubbleKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSCONTACTFACEBUBBLEKERNELS_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSCONTACTFACEBUBBLEKERNELS_HPP_ + +#include "physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainQuasiStatic.hpp" +#include "SolidMechanicsConformingContactKernelsHelper.hpp" + +// TODO: Use the bilinear form utilities +//#include "finiteElement/BilinearFormUtilities.hpp" + +namespace geos +{ + +namespace solidMechanicsConformingContactKernels +{ + +/** + * @brief Implements kernels for solving quasi-static equilibrium. + * @copydoc geos::finiteElement::ImplicitKernelBase + * + */ +template< typename SUBREGION_TYPE, + typename CONSTITUTIVE_TYPE, + typename FE_TYPE > +class FaceBubbleKernels : + public solidMechanicsLagrangianFEMKernels::ImplicitSmallStrainQuasiStatic< SUBREGION_TYPE, + CONSTITUTIVE_TYPE, + FE_TYPE > +{ +public: + /// Alias for the base class; + using Base = solidMechanicsLagrangianFEMKernels::ImplicitSmallStrainQuasiStatic< SUBREGION_TYPE, + CONSTITUTIVE_TYPE, + FE_TYPE >; + + /// Number of nodes per element, which is equal to the + /// numTestSupportPointPerElem and numTrialSupportPointPerElem by definition. + static constexpr int numNodesPerElem = Base::maxNumTestSupportPointsPerElem; + + /// Compile time value for the number of faces per element. + static constexpr int numFacesPerElem = FE_TYPE::numFaces; + + /// Compile time value for the number of quadrature points per element. + static constexpr int numQuadraturePointsPerElem = FE_TYPE::numQuadraturePoints; + + using Base::m_X; + using Base::m_elemsToNodes; + using Base::m_finiteElementSpace; + using Base::m_constitutiveUpdate; + using Base::m_dofNumber; + using Base::m_dofRankOffset; + using Base::m_matrix; + using Base::m_rhs; + using Base::m_disp; + + /** + * @brief Constructor + * @copydoc geos::finiteElement::ImplicitKernelBase::ImplicitKernelBase + */ + FaceBubbleKernels( NodeManager const & nodeManager, + EdgeManager const & edgeManager, + FaceManager const & faceManager, + localIndex const targetRegionIndex, + SUBREGION_TYPE const & elementSubRegion, + FE_TYPE const & finiteElementSpace, + CONSTITUTIVE_TYPE & inputConstitutiveType, + arrayView1d< globalIndex const > const uDofNumber, + arrayView1d< globalIndex const > const bDofNumber, + globalIndex const rankOffset, + CRSMatrixView< real64, globalIndex const > const inputMatrix, + arrayView1d< real64 > const inputRhs, + real64 const inputDt, + real64 const (&inputGravityVector)[3] ): + Base( nodeManager, + edgeManager, + faceManager, + targetRegionIndex, + elementSubRegion, + finiteElementSpace, + inputConstitutiveType, + uDofNumber, + rankOffset, + inputMatrix, + inputRhs, + inputDt, + inputGravityVector ), + m_bubbleDisp( faceManager.getField< fields::solidMechanics::totalBubbleDisplacement >().toViewConst() ), + m_bDofNumber( bDofNumber ), + m_bubbleElems( elementSubRegion.bubbleElementsList() ), + m_elemsToFaces( elementSubRegion.faceElementsList() ) + {} + + //*************************************************************************** + + /** + * @copydoc finiteElement::ImplicitKernelBase::StackVariables + */ + struct StackVariables + { +public: + /// The number of displacement dofs per element. + static constexpr int numUdofs = numNodesPerElem * 3; + + /// The number of jump dofs per element. + static constexpr int numBubbleUdofs = numFacesPerElem * 3; + + /** + * Default constructor + */ + GEOS_HOST_DEVICE + StackVariables(): + dispEqnRowIndices{}, + dispColIndices{}, + bEqnRowIndices{}, + bColIndices{}, + localRu{}, + localRb{}, + localAbb{ {} }, + localAbu{ {} }, + localAub{ {} }, + bLocal{}, + uLocal{}, + X{ {} }, + constitutiveStiffness{ {} } + {} + + /// C-array storage for the element local row degrees of freedom. + globalIndex dispEqnRowIndices[numUdofs]; + + /// C-array storage for the element local column degrees of freedom. + globalIndex dispColIndices[numUdofs]; + + /// C-array storage for the element local row degrees of freedom. + globalIndex bEqnRowIndices[3]; + + /// C-array storage for the element local column degrees of freedom. + globalIndex bColIndices[3]; + + /// C-array storage for the element local Ru residual vector. + real64 localRu[numUdofs]; + + /// C-array storage for the element local Rb residual vector. + real64 localRb[numBubbleUdofs]; + + /// C-array storage for the element local Abb matrix. + real64 localAbb[numBubbleUdofs][numBubbleUdofs]; + + /// C-array storage for the element local Abu matrix. + real64 localAbu[numBubbleUdofs][numUdofs]; + + /// C-array storage for the element local Aub matrix. + real64 localAub[numUdofs][numBubbleUdofs]; + + /// Stack storage for the element local bubble vector + real64 bLocal[3]; + + /// Stack storage for the element displacement vector. + real64 uLocal[numUdofs]; + + /// local nodal coordinates + real64 X[ numNodesPerElem ][ 3 ]; + + /// Stack storage for the constitutive stiffness at a quadrature point. + real64 constitutiveStiffness[ 6 ][ 6 ]; + + }; + + //*************************************************************************** + + /** + * @copydoc ::geos::finiteElement::KernelBase::kernelLaunch + * + * @detail it uses the kernelLaunch interface of KernelBase but it only launches the kernel + * on the set of elements that have bubble dof within the subregion. + * + */ + //START_kernelLauncher + template< typename POLICY, + typename KERNEL_TYPE > + static + real64 + kernelLaunch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + + GEOS_MARK_FUNCTION; + GEOS_UNUSED_VAR( numElems ); + + // Define a RAJA reduction variable to get the maximum residual contribution. + RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxResidual( 0 ); + + forAll< POLICY >( kernelComponent.m_bubbleElems.size(), + [=] GEOS_HOST_DEVICE ( localIndex const i ) + { + typename KERNEL_TYPE::StackVariables stack; + + kernelComponent.setup( i, stack ); + for( integer q=0; q( dBubbleNdX, 0 ); //make 0 + + real64 detJ = m_finiteElementSpace.calcGradFaceBubbleN( q, stack.X, dBubbleNdX ); + + real64 dNdX[ numNodesPerElem ][ 3 ]; + detJ = m_finiteElementSpace.calcGradN( q, stack.X, dNdX ); + + m_constitutiveUpdate.getElasticStiffness( k, q, stack.constitutiveStiffness ); + + real64 strainMatrix[6][nUdof]; + solidMechanicsConformingContactKernelsHelper::assembleStrainOperator< 6, nUdof, numNodesPerElem >( strainMatrix, dNdX ); + + real64 strainBubbleMatrix[6][nBubbleUdof]; + solidMechanicsConformingContactKernelsHelper::assembleStrainOperator< 6, nBubbleUdof, numFacesPerElem >( strainBubbleMatrix, dBubbleNdX ); + + // TODO: It would be nice use BilinearFormUtilities::compute + + real64 matBD[nBubbleUdof][6]; + real64 Abb_gauss[nBubbleUdof][nBubbleUdof], Abu_gauss[nBubbleUdof][nUdof], Aub_gauss[nUdof][nBubbleUdof]; + + // transp(Bb)D + LvArray::tensorOps::Rij_eq_AkiBkj< nBubbleUdof, 6, 6 >( matBD, strainBubbleMatrix, stack.constitutiveStiffness ); + + // transp(Bb)DB + LvArray::tensorOps::Rij_eq_AikBkj< nBubbleUdof, nUdof, 6 >( Abu_gauss, matBD, strainMatrix ); + + // transp(Bb)DBb + LvArray::tensorOps::Rij_eq_AikBkj< nBubbleUdof, nBubbleUdof, 6 >( Abb_gauss, matBD, strainBubbleMatrix ); + + // transp(B)DBb + LvArray::tensorOps::transpose< nUdof, nBubbleUdof >( Aub_gauss, Abu_gauss ); + + // multiply by determinant and add to element matrix + LvArray::tensorOps::scaledAdd< nBubbleUdof, nBubbleUdof >( stack.localAbb, Abb_gauss, -detJ ); + LvArray::tensorOps::scaledAdd< nBubbleUdof, nUdof >( stack.localAbu, Abu_gauss, -detJ ); + LvArray::tensorOps::scaledAdd< nUdof, nBubbleUdof >( stack.localAub, Aub_gauss, -detJ ); + + // Compute the initial stress + // The following block assumes a linear elastic constitutive model + real64 rb_gauss[nBubbleUdof]{}; + real64 strain[6] = {0}; + LvArray::tensorOps::Ri_eq_AijBj< 6, nUdof >( strain, strainMatrix, stack.uLocal ); + + real64 initStressLocal[ 6 ] = {0}; + LvArray::tensorOps::Ri_eq_AijBj< 6, 6 >( initStressLocal, stack.constitutiveStiffness, strain ); + for( localIndex c = 0; c < 6; ++c ) + { + initStressLocal[ c ] -= m_constitutiveUpdate.m_newStress( k, q, c ); + } + + LvArray::tensorOps::Ri_eq_AjiBj< nBubbleUdof, 6 >( rb_gauss, strainBubbleMatrix, initStressLocal ); + LvArray::tensorOps::scaledAdd< nBubbleUdof >( stack.localRb, rb_gauss, detJ ); + + } + + GEOS_HOST_DEVICE + inline + real64 complete( localIndex const kk, + StackVariables & stack ) const + { + + real64 maxForce = 0; + constexpr int nUdof = numNodesPerElem*3; + + localIndex const parentFaceIndex = m_elemsToFaces[kk][1]; + + // Extract only the submatrix and known term corresponding to the index of the local face + // on which the bubble function was applied. + real64 localAub[nUdof][3]; + real64 localAbu[3][nUdof]; + real64 localAbb[3][3]; + real64 localRb[3]; + for( localIndex i = 0; i < 3; ++i ) + { + for( localIndex j = 0; j < nUdof; ++j ) + { + localAub[j][i] = stack.localAub[j][parentFaceIndex*3+i]; + } + for( localIndex j = 0; j < 3; ++j ) + { + localAbb[j][i] = stack.localAbb[parentFaceIndex*3+j][parentFaceIndex*3+i]; + } + localRb[i] = stack.localRb[parentFaceIndex*3+i]; + } + + for( localIndex j = 0; j < nUdof; ++j ) + { + for( localIndex i = 0; i < 3; ++i ) + { + localAbu[i][j] = stack.localAbu[parentFaceIndex*3+i][j]; + } + } + + // Compute the local residuals + LvArray::tensorOps::Ri_add_AijBj< 3, 3 >( localRb, localAbb, stack.bLocal ); + LvArray::tensorOps::Ri_add_AijBj< 3, nUdof >( localRb, localAbu, stack.uLocal ); + LvArray::tensorOps::Ri_add_AijBj< nUdof, 3 >( stack.localRu, localAub, stack.bLocal ); + + for( localIndex i = 0; i < nUdof; ++i ) + { + localIndex const dof = LvArray::integerConversion< localIndex >( stack.dispEqnRowIndices[ i ] ); + if( dof < 0 || dof >= m_matrix.numRows() ) continue; + + RAJA::atomicAdd< parallelDeviceAtomic >( &m_rhs[dof], stack.localRu[i] ); + + // fill in matrix + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.bColIndices, + localAub[i], + 3 ); + + } + + for( localIndex i=0; i < 3; ++i ) + { + localIndex const dof = LvArray::integerConversion< localIndex >( stack.bEqnRowIndices[ i ] ); + + if( dof < 0 || dof >= m_matrix.numRows() ) continue; + + RAJA::atomicAdd< parallelDeviceAtomic >( &m_rhs[dof], localRb[i] ); + + // fill in matrix + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.bColIndices, + localAbb[i], + 3 ); + + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.dispColIndices, + localAbu[i], + numNodesPerElem*3 ); + } + + return maxForce; + } + +protected: + + /// The array containing the bubble displacement. + arrayView2d< real64 const > const m_bubbleDisp; + + /// The global degree of freedom number of bubble + arrayView1d< globalIndex const > const m_bDofNumber; + + /// The array containing the list of bubble elements. + arrayView1d< localIndex const > const m_bubbleElems; + + /// The array containing the element to bubble face map. + /// The bubble face is the face of the element to which the bubble is applied. + /// Both the local and global face index are stored in this array. + arrayView2d< localIndex const > const m_elemsToFaces; + +}; + +/// The factory used to construct a QuasiStatic kernel. +using FaceBubbleFactory = finiteElement::KernelFactory< FaceBubbleKernels, + arrayView1d< globalIndex const > const, + arrayView1d< globalIndex const > const, + globalIndex const, + CRSMatrixView< real64, globalIndex const > const, + arrayView1d< real64 > const, + real64 const, + real64 const (&) [3] >; + +} // namespace SolidMechanicsContactFaceBubbleKernels + +} // namespace geos + + +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSCONTACTFACEBUBBLEKERNELS_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsDisplacementJumpUpdateKernels.hpp b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsDisplacementJumpUpdateKernels.hpp new file mode 100644 index 00000000000..c06b00ff819 --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsDisplacementJumpUpdateKernels.hpp @@ -0,0 +1,283 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolidMechanicsALMUpdateKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSDISPLACEMENTJUPDATEKERNELS_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSDISPLACEMENTJUPDATEKERNELS_HPP_ + +#include "SolidMechanicsConformingContactKernelsBase.hpp" +#include "mesh/MeshFields.hpp" + +namespace geos +{ + +namespace solidMechanicsConformingContactKernels +{ + +/** + * @copydoc geos::finiteElement::ImplicitKernelBase + */ +template< typename CONSTITUTIVE_TYPE, + typename FE_TYPE > +class DispJumpUpdate : + public ConformingContactKernelsBase< CONSTITUTIVE_TYPE, + FE_TYPE > +{ +public: + /// Alias for the base class; + using Base = ConformingContactKernelsBase< CONSTITUTIVE_TYPE, + FE_TYPE >; + + /// Maximum number of nodes per element, which is equal to the maxNumTestSupportPointPerElem and + /// maxNumTrialSupportPointPerElem by definition. + static constexpr int numNodesPerElem = Base::maxNumTestSupportPointsPerElem; + + /// The number of displacement dofs per element. + static constexpr int numUdofs = Base::numUdofs; + + /// The number of bubble dofs per element. + static constexpr int numBdofs = Base::numBdofs; + + /// The number of lagrange multiplier dofs per element. + static constexpr int numTdofs = Base::numTdofs; + + using Base::m_X; + using Base::m_finiteElementSpace; + using Base::m_dofNumber; + using Base::m_dofRankOffset; + using Base::m_elemsToFaces; + using Base::m_faceToNodes; + using Base::m_rotationMatrix; + using Base::m_dispJump; + + /** + * @brief Constructor + * @copydoc geos::finiteElement::InterfaceKernelBase::InterfaceKernelBase + */ + DispJumpUpdate( NodeManager const & nodeManager, + EdgeManager const & edgeManager, + FaceManager const & faceManager, + localIndex const targetRegionIndex, + FaceElementSubRegion & elementSubRegion, + FE_TYPE const & finiteElementSpace, + CONSTITUTIVE_TYPE & inputConstitutiveType, + arrayView1d< globalIndex const > const uDofNumber, + arrayView1d< globalIndex const > const bDofNumber, + globalIndex const rankOffset, + CRSMatrixView< real64, globalIndex const > const inputMatrix, + arrayView1d< real64 > const inputRhs, + real64 const inputDt, + arrayView1d< localIndex const > const & faceElementList ): + Base( nodeManager, + edgeManager, + faceManager, + targetRegionIndex, + elementSubRegion, + finiteElementSpace, + inputConstitutiveType, + uDofNumber, + bDofNumber, + rankOffset, + inputMatrix, + inputRhs, + inputDt, + faceElementList ), + m_displacement( nodeManager.getField< fields::solidMechanics::totalDisplacement >()), + m_bubbleDisp( faceManager.getField< fields::solidMechanics::totalBubbleDisplacement >() ), + m_incrDisp( nodeManager.getField< fields::solidMechanics::incrementalDisplacement >() ), + m_incrBubbleDisp( faceManager.getField< fields::solidMechanics::incrementalBubbleDisplacement >() ), + m_deltaDispJump( elementSubRegion.getField< fields::contact::deltaDispJump >().toView() ), + m_elementArea( elementSubRegion.getField< fields::elementArea >().toView() ), + m_slip( elementSubRegion.getField< fields::contact::slip >().toView() ) + {} + + //*************************************************************************** + + /** + * @copydoc finiteElement::KernelBase::StackVariables + */ + struct StackVariables : public Base::StackVariables + { + +public: + + GEOS_HOST_DEVICE + StackVariables(): + Base::StackVariables(), + uLocal{}, + bLocal{}, + duLocal{}, + dbLocal{}, + deltaDispJumpLocal{} + {} + + /// Stack storage for the element local displacement vector + real64 uLocal[numUdofs]; + + /// Stack storage for the element local bubble displacement vector + real64 bLocal[numBdofs]; + + /// Stack storage for the element local incremental displacement vector + real64 duLocal[numUdofs]; + + /// Stack storage for the element local incremental bubble displacement vector + real64 dbLocal[numBdofs]; + + /// Stack storage for the element local delta displacement jump vector + real64 deltaDispJumpLocal[numTdofs]; + + }; + + //*************************************************************************** + + //START_kernelLauncher + template< typename POLICY, + typename KERNEL_TYPE > + static + real64 + kernelLaunch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + return Base::template kernelLaunch< POLICY, KERNEL_TYPE >( numElems, kernelComponent ); + } + //END_kernelLauncher + + /** + * @brief Copy global values from primary field to a local stack array. + * @copydoc ::geos::finiteElement::InterfaceKernelBase::setup + */ + GEOS_HOST_DEVICE + inline + void setup( localIndex const k, + StackVariables & stack ) const + { + constexpr int shift = numNodesPerElem * 3; + + int permutation[numNodesPerElem]; + m_finiteElementSpace.getPermutation( permutation ); + + localIndex const kf0 = m_elemsToFaces[k][0]; + localIndex const kf1 = m_elemsToFaces[k][1]; + for( localIndex a=0; a( matRtAtu, stack.localRotationMatrix, + stack.localAtu ); + // transp(R) * Atb + LvArray::tensorOps::Rij_eq_AkiBkj< 3, numBdofs, 3 >( matRtAtb, stack.localRotationMatrix, + stack.localAtb ); + + // Compute the node contribute of the displacement and delta displacement jump + LvArray::tensorOps::Ri_eq_AijBj< 3, numUdofs >( stack.dispJumpLocal, matRtAtu, stack.uLocal ); + LvArray::tensorOps::Ri_eq_AijBj< 3, numUdofs >( stack.deltaDispJumpLocal, matRtAtu, stack.duLocal ); + + // Compute the bubble contribute of the displacement and delta displacement jump + LvArray::tensorOps::Ri_add_AijBj< 3, numBdofs >( stack.dispJumpLocal, matRtAtb, stack.bLocal ); + LvArray::tensorOps::Ri_add_AijBj< 3, numBdofs >( stack.deltaDispJumpLocal, matRtAtb, stack.dbLocal ); + + // Store the results + real64 const scale = 1 / m_elementArea[k]; + + for( int i=0; i<3; ++i ) + { + m_dispJump[ k ][ i ] = scale * stack.dispJumpLocal[ i ]; + m_deltaDispJump[ k ][ i ] = scale * stack.deltaDispJumpLocal[ i ]; + } + + m_slip[k] = LvArray::math::sqrt( LvArray::math::square( m_dispJump( k, 1 ) ) + LvArray::math::square( m_dispJump( k, 2 ) ) ); + + + return 0.0; + } + +protected: + + /// The rank-global displacement array. + arrayView2d< real64 const, nodes::TOTAL_DISPLACEMENT_USD > const m_displacement; + + /// The rank-global bubble displacement array. + arrayView2d< real64 const > const m_bubbleDisp; + + /// The rank-global incremental displacement array. + arrayView2d< real64 const, nodes::INCR_DISPLACEMENT_USD > const m_incrDisp; + + /// The rank-global incremental bubble displacement array. + arrayView2d< real64 const > const m_incrBubbleDisp; + + /// The rank-global delta displacement jump array. + arrayView2d< real64 > const m_deltaDispJump; + + arrayView1d< real64 const > const m_elementArea; + + arrayView1d< real64 > const m_slip; + +}; + +using DispJumpUpdateFactory = finiteElement::InterfaceKernelFactory< DispJumpUpdate, + arrayView1d< globalIndex const > const, + arrayView1d< globalIndex const > const, + globalIndex const, + CRSMatrixView< real64, globalIndex const > const, + arrayView1d< real64 > const, + real64 const, + arrayView1d< localIndex const > const >; + +} // namespace SolidMechanicsALMKernels + +} // namespace geos + +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSDISPLACEMENTJUPDATEKERNELS_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/contact/SolidMechanicsEFEMJumpUpdateKernels.hpp b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsEFEMJumpUpdateKernels.hpp similarity index 94% rename from src/coreComponents/physicsSolvers/contact/SolidMechanicsEFEMJumpUpdateKernels.hpp rename to src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsEFEMJumpUpdateKernels.hpp index 6d50dde371f..eab65325840 100644 --- a/src/coreComponents/physicsSolvers/contact/SolidMechanicsEFEMJumpUpdateKernels.hpp +++ b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsEFEMJumpUpdateKernels.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,8 +18,8 @@ * @file SolidMechanicsEFEMKernels.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSEFEMJUMPUPDATEKERNELS_HPP_ -#define GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSEFEMJUMPUPDATEKERNELS_HPP_ +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSEFEMJUMPUPDATEKERNELS_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSEFEMJUMPUPDATEKERNELS_HPP_ #include "SolidMechanicsEFEMKernelsBase.hpp" @@ -245,4 +246,4 @@ using EFEMJumpUpdateFactory = finiteElement::KernelFactory< EFEMJumpUpdate, } // namespace geos -#endif /* GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSEFEMJUMPUPDATEKERNELS_HPP_ */ +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSEFEMJUMPUPDATEKERNELS_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/contact/SolidMechanicsEFEMKernels.hpp b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsEFEMKernels.hpp similarity index 82% rename from src/coreComponents/physicsSolvers/contact/SolidMechanicsEFEMKernels.hpp rename to src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsEFEMKernels.hpp index a1c2b6c5b08..6cf1f59ceeb 100644 --- a/src/coreComponents/physicsSolvers/contact/SolidMechanicsEFEMKernels.hpp +++ b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsEFEMKernels.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,8 +18,8 @@ * @file SolidMechanicsEFEMKernels.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSEFEMKERNELS_HPP_ -#define GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSEFEMKERNELS_HPP_ +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSEFEMKERNELS_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSEFEMKERNELS_HPP_ #include "SolidMechanicsEFEMKernelsBase.hpp" @@ -219,8 +220,9 @@ class EFEM : // Compute the local residuals LvArray::tensorOps::Ri_add_AijBj< 3, 3 >( stack.localRw, stack.localKww, stack.wLocal ); - LvArray::tensorOps::Ri_add_AijBj< 3, nUdof >( stack.localRw, stack.localKwu, stack.uLocal ); LvArray::tensorOps::Ri_add_AijBj< nUdof, 3 >( stack.localRu, stack.localKuw, stack.wLocal ); + // add EqM * effStress into the residual of enrichment nodes + LvArray::tensorOps::add< 3 >( stack.localRw, stack.localEqMStress ); // Add traction contribution LvArray::tensorOps::scaledAdd< 3 >( stack.localRw, stack.tractionVec, -1 ); @@ -290,29 +292,50 @@ struct StateUpdateKernel /** * @brief Launch the kernel function doing fracture traction updates * @tparam POLICY the type of policy used in the kernel launch - * @tparam CONTACT_WRAPPER the type of contact wrapper doing the fracture traction updates + * @tparam FRICTION_WRAPPER the type of contact wrapper doing the fracture traction updates * @param[in] size the size of the subregion - * @param[in] contactWrapper the wrapper implementing the contact relationship + * @param[in] frictionWrapper the wrapper implementing the contact relationship * @param[in] jump the displacement jump * @param[out] fractureTraction the fracture traction * @param[out] dFractureTraction_dJump the derivative of the fracture traction wrt displacement jump */ - template< typename POLICY, typename CONTACT_WRAPPER > + template< typename POLICY, typename FRICTION_WRAPPER > static void launch( localIndex const size, - CONTACT_WRAPPER const & contactWrapper, + FRICTION_WRAPPER const & frictionWrapper, + real64 const contactPenaltyStiffness, arrayView2d< real64 const > const & oldJump, arrayView2d< real64 const > const & jump, arrayView2d< real64 > const & fractureTraction, arrayView3d< real64 > const & dFractureTraction_dJump, - arrayView1d< integer const > const & fractureState ) + arrayView1d< integer const > const & fractureState, + arrayView1d< real64 > const & slip ) { forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) { - contactWrapper.computeTraction( k, oldJump[k], jump[k], - fractureState[k], - fractureTraction[k], - dFractureTraction_dJump[k] ); + // Initialize traction and derivatives to 0 + LvArray::forValuesInSlice( fractureTraction[k], []( real64 & val ){ val = 0.0; } ); + LvArray::forValuesInSlice( dFractureTraction_dJump[k], []( real64 & val ){ val = 0.0; } ); + + // If the fracture is open the traction is 0 and so are its derivatives so there is nothing to do + bool const isOpen = fractureState[k] == fields::contact::FractureState::Open; + + if( !isOpen ) + { + // normal component of the traction + fractureTraction[k][0] = contactPenaltyStiffness * jump[k][0]; + + // derivative of the normal component w.r.t. to the normal dispJump + dFractureTraction_dJump[k][0][0] = contactPenaltyStiffness; + + frictionWrapper.computeShearTraction( k, oldJump[k], jump[k], + fractureState[k], + fractureTraction[k], + dFractureTraction_dJump[k] ); + } + + slip[ k ] = LvArray::math::sqrt( LvArray::math::square( jump( k, 1 ) ) + + LvArray::math::square( jump( k, 2 ) ) ); } ); } @@ -324,4 +347,4 @@ struct StateUpdateKernel } // namespace geos -#endif /* GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSEFEMKERNELS_HPP_ */ +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSEFEMKERNELS_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/contact/SolidMechanicsEFEMKernelsBase.hpp b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsEFEMKernelsBase.hpp similarity index 91% rename from src/coreComponents/physicsSolvers/contact/SolidMechanicsEFEMKernelsBase.hpp rename to src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsEFEMKernelsBase.hpp index 0697e48fe4a..4a0ad46b4e9 100644 --- a/src/coreComponents/physicsSolvers/contact/SolidMechanicsEFEMKernelsBase.hpp +++ b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsEFEMKernelsBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,8 +18,8 @@ * @file SolidMechanicsEFEMKernels.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSEFEMKERNELSBASE_HPP_ -#define GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSEFEMKERNELSBASE_HPP_ +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSEFEMKERNELSBASE_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSEFEMKERNELSBASE_HPP_ #include "physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainQuasiStatic.hpp" #include "SolidMechanicsEFEMKernelsHelper.hpp" @@ -106,6 +107,7 @@ class EFEMKernelsBase : inputDt, inputGravityVector ), m_w( embeddedSurfSubRegion.getField< fields::contact::dispJump >().toView() ), + m_effStress( inputConstitutiveType.getStress()), m_tractionVec( embeddedSurfSubRegion.getField< fields::contact::traction >().toViewConst() ), m_dTraction_dJump( embeddedSurfSubRegion.getField< fields::contact::dTraction_dJump >().toViewConst() ), m_nVec( embeddedSurfSubRegion.getNormalVector().toViewConst() ), @@ -143,6 +145,7 @@ class EFEMKernelsBase : localKww{ { 0.0 } }, localKwu{ { 0.0 } }, localKuw{ { 0.0 } }, + localEqMStress{ 0.0 }, wLocal(), uLocal(), hInv(), @@ -170,6 +173,9 @@ class EFEMKernelsBase : /// C-array storage for the element local Kuw matrix. real64 localKuw[numUdofs][numWdofs]; + /// C-array storage for the element local EqM*effStress vector. + real64 localEqMStress[numWdofs]; + /// Stack storage for the element local jump vector real64 wLocal[3]; @@ -248,6 +254,9 @@ class EFEMKernelsBase : // Gauss contribution to Kww, Kwu and Kuw blocks real64 Kww_gauss[3][3], Kwu_gauss[3][nUdof], Kuw_gauss[nUdof][3]; + // Gauss contirbution to eqMStress which is EqMatrix*effStress, all stresses are in Voigt notation + real64 eqMStress_gauss[3]{}; + // Compatibility, equilibrium and strain operators. The compatibility operator is constructed as // a 3 x 6 because it is more convenient for construction purposes (reduces number of local var). real64 compMatrix[3][6], strainMatrix[6][nUdof], eqMatrix[3][6]; @@ -291,17 +300,25 @@ class EFEMKernelsBase : LvArray::tensorOps::Rij_eq_AikBkj< 3, nUdof, 6 >( Kwu_gauss, matED, strainMatrix ); // transp(B)DB LvArray::tensorOps::Rij_eq_AikBjk< nUdof, 3, 6 >( Kuw_gauss, matBD, compMatrix ); + // EqMatrix * effStress + LvArray::tensorOps::Ri_eq_AijBj< 3, 6 >( eqMStress_gauss, eqMatrix, m_effStress[k][q] ); + + /// FIX: add old Equilibrium operator times oldStress (in Voigt notation) // multiply by determinant and add to element matrix LvArray::tensorOps::scaledAdd< 3, 3 >( stack.localKww, Kww_gauss, -detJ ); LvArray::tensorOps::scaledAdd< 3, nUdof >( stack.localKwu, Kwu_gauss, -detJ ); LvArray::tensorOps::scaledAdd< nUdof, 3 >( stack.localKuw, Kuw_gauss, -detJ ); + LvArray::tensorOps::scaledAdd< 3 >( stack.localEqMStress, eqMStress_gauss, -detJ ); } protected: arrayView2d< real64 > const m_w; + /// The effective stress at the current time + arrayView3d< real64 const, solid::STRESS_USD > m_effStress; + arrayView2d< real64 const > const m_tractionVec; arrayView3d< real64 const > const m_dTraction_dJump; @@ -328,4 +345,4 @@ class EFEMKernelsBase : } // namespace geos -#endif /* GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSEFEMKERNELSBASE_HPP_ */ +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSEFEMKERNELSBASE_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/contact/SolidMechanicsEFEMKernelsHelper.hpp b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsEFEMKernelsHelper.hpp similarity index 89% rename from src/coreComponents/physicsSolvers/contact/SolidMechanicsEFEMKernelsHelper.hpp rename to src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsEFEMKernelsHelper.hpp index 3045af31adf..07bd6ffb810 100644 --- a/src/coreComponents/physicsSolvers/contact/SolidMechanicsEFEMKernelsHelper.hpp +++ b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsEFEMKernelsHelper.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,8 +18,8 @@ * @file EFEMKernelsHelper.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSEFEMKERNELSHELPER_HPP_ -#define GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSEFEMKERNELSHELPER_HPP_ +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSEFEMKERNELSHELPER_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSEFEMKERNELSHELPER_HPP_ #include "common/DataTypes.hpp" @@ -148,7 +149,7 @@ void assembleEquilibriumOperator( real64 ( & eqMatrix )[3][6], } } -} // geosx +} // geos -#endif /* SRC_CORECOMPONENTS_PHYSICSSOLVERS_CONTACT_EFEMKERNELSHELPER_HPP_ */ +#endif /* SRC_CORECOMPONENTS_PHYSICSSOLVERS_CONTACT_KERNELS_EFEMKERNELSHELPER_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/contact/SolidMechanicsEFEMStaticCondensationKernels.hpp b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsEFEMStaticCondensationKernels.hpp similarity index 94% rename from src/coreComponents/physicsSolvers/contact/SolidMechanicsEFEMStaticCondensationKernels.hpp rename to src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsEFEMStaticCondensationKernels.hpp index 0223c214d8b..c6efed43093 100644 --- a/src/coreComponents/physicsSolvers/contact/SolidMechanicsEFEMStaticCondensationKernels.hpp +++ b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsEFEMStaticCondensationKernels.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,8 +18,8 @@ * @file SolidMechanicsEFEMKernels.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSEFEMSTATICCONDENSATIONKERNELS_HPP_ -#define GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSEFEMSTATICCONDENSATIONKERNELS_HPP_ +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSEFEMSTATICCONDENSATIONKERNELS_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSEFEMSTATICCONDENSATIONKERNELS_HPP_ #include "SolidMechanicsEFEMKernelsBase.hpp" @@ -251,4 +252,4 @@ using EFEMStaticCondensationFactory = finiteElement::KernelFactory< EFEMStaticCo } // namespace geos -#endif /* GEOS_PHYSICSSOLVERS_CONTACT_SOLIDMECHANICSEFEMSTATICCONDENSATIONKERNELS_HPP_ */ +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSEFEMSTATICCONDENSATIONKERNELS_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsLagrangeContactKernels.hpp b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsLagrangeContactKernels.hpp new file mode 100644 index 00000000000..b5ab97955b6 --- /dev/null +++ b/src/coreComponents/physicsSolvers/contact/kernels/SolidMechanicsLagrangeContactKernels.hpp @@ -0,0 +1,438 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolidMechanicsALMKernelsBase.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSLAGRANGECONTACTKERNELS_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSLAGRANGECONTACTKERNELS_HPP_ + +#include "finiteElement/kernelInterface/InterfaceKernelBase.hpp" +#include "SolidMechanicsConformingContactKernelsBase.hpp" + +namespace geos +{ + +namespace solidMechanicsLagrangeContactKernels +{ + +/** + * @copydoc geos::finiteElement::ImplicitKernelBase + */ +template< typename CONSTITUTIVE_TYPE, + typename FE_TYPE > +class LagrangeContact : + public solidMechanicsConformingContactKernels::ConformingContactKernelsBase< CONSTITUTIVE_TYPE, + FE_TYPE > +{ +public: + /// Alias for the base class. + using Base = solidMechanicsConformingContactKernels::ConformingContactKernelsBase< CONSTITUTIVE_TYPE, + FE_TYPE >; + + /// Maximum number of nodes per element, which is equal to the maxNumTestSupportPointPerElem and + /// maxNumTrialSupportPointPerElem by definition. + static constexpr int numNodesPerElem = Base::maxNumTestSupportPointsPerElem; + + /// Compile time value for the number of quadrature points per element. + static constexpr int numQuadraturePointsPerElem = FE_TYPE::numQuadraturePoints; + + using Base::numUdofs; + using Base::numTdofs; + using Base::numBdofs; + + using Base::m_elemsToFaces; + using Base::m_faceToNodes; + using Base::m_finiteElementSpace; + using Base::m_constitutiveUpdate; + using Base::m_dofNumber; + using Base::m_bDofNumber; + using Base::m_dofRankOffset; + using Base::m_X; + using Base::m_rotationMatrix; + using Base::m_dispJump; + using Base::m_oldDispJump; + using Base::m_matrix; + using Base::m_rhs; + + /** + * @brief Constructor + * @copydoc geos::finiteElement::InterfaceKernelBase::InterfaceKernelBase + */ + LagrangeContact( NodeManager const & nodeManager, + EdgeManager const & edgeManager, + FaceManager const & faceManager, + localIndex const targetRegionIndex, + FaceElementSubRegion & elementSubRegion, + FE_TYPE const & finiteElementSpace, + CONSTITUTIVE_TYPE & inputConstitutiveType, + arrayView1d< globalIndex const > const uDofNumber, + arrayView1d< globalIndex const > const bDofNumber, + globalIndex const rankOffset, + CRSMatrixView< real64, globalIndex const > const inputMatrix, + arrayView1d< real64 > const inputRhs, + real64 const inputDt, + arrayView1d< localIndex const > const & faceElementList, + string const tractionDofKey ): + Base( nodeManager, + edgeManager, + faceManager, + targetRegionIndex, + elementSubRegion, + finiteElementSpace, + inputConstitutiveType, + uDofNumber, + bDofNumber, + rankOffset, + inputMatrix, + inputRhs, + inputDt, + faceElementList ), + m_traction( elementSubRegion.getField< fields::contact::traction >().toViewConst() ), + m_tDofNumber( elementSubRegion.getReference< globalIndex_array >( tractionDofKey ).toViewConst() ), + m_incrDisp( nodeManager.getField< fields::solidMechanics::incrementalDisplacement >() ), + m_incrBubbleDisp( faceManager.getField< fields::solidMechanics::incrementalBubbleDisplacement >() ), + m_targetIncrementalJump( elementSubRegion.getField< fields::contact::targetIncrementalJump >().toViewConst() ) + {} + + /** + * @copydoc finiteElement::KernelBase::StackVariables + */ + struct StackVariables : public Base::StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables(): + Base::StackVariables(), + dispEqnRowIndices{}, + dispColIndices{}, + bEqnRowIndices{}, + bColIndices{}, + tColIndices{}, + localRu{}, + localRb{}, + localRt{}, + localAtt{ {} }, + localAut{ {} }, + localAbt{ {} }, + duLocal{}, + dbLocal{} + {} + + /// C-array storage for the element local row degrees of freedom. + localIndex dispEqnRowIndices[numUdofs]; + + /// C-array storage for the element local column degrees of freedom. + globalIndex dispColIndices[numUdofs]; + + /// C-array storage for the element local row degrees of freedom. + localIndex bEqnRowIndices[numBdofs]; + + /// C-array storage for the element local column degrees of freedom. + globalIndex bColIndices[numBdofs]; + + /// C-array storage for the traction local row degrees of freedom. + localIndex tEqnRowIndices[numTdofs]; + + /// C-array storage for the element local column degrees of freedom. + globalIndex tColIndices[numTdofs]; + + /// C-array storage for the element local Ru residual vector. + real64 localRu[numUdofs]; + + /// C-array storage for the element local Rb residual vector. + real64 localRb[numBdofs]; + + /// C-array storage for the element local Rt residual vector. + real64 localRt[numTdofs]; + + /// C-array storage for the element local Att matrix. + real64 localAtt[numTdofs][numTdofs]; + + /// C-array storage for the element local Aut matrix. + real64 localAut[numUdofs][numTdofs]; + + /// C-array storage for the element local Abt matrix. + real64 localAbt[numBdofs][numTdofs]; + + /// Stack storage for the element local incremental displacement vector + real64 duLocal[numUdofs]; + + /// Stack storage for the element local incremental bubble displacement vector + real64 dbLocal[numBdofs]; + }; + + //*************************************************************************** + + //START_kernelLauncher + template< typename POLICY, + typename KERNEL_TYPE > + static + real64 + kernelLaunch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + return Base::template kernelLaunch< POLICY, KERNEL_TYPE >( numElems, kernelComponent ); + } + //END_kernelLauncher + + /** + * @brief Copy global values from primary field to a local stack array. + * @copydoc ::geos::finiteElement::InterfaceKernelBase::setup + */ + GEOS_HOST_DEVICE + inline + void setup( localIndex const k, + StackVariables & stack ) const + { + constexpr int shift = numNodesPerElem * 3; + + int permutation[numNodesPerElem]; + m_finiteElementSpace.getPermutation( permutation ); + + localIndex const kf0 = m_elemsToFaces[k][0]; + localIndex const kf1 = m_elemsToFaces[k][1]; + for( localIndex a=0; a( matRRtAtu, stack.localRotationMatrix, stack.localAtu ); + // transp(R) * Atb + LvArray::tensorOps::Rij_eq_AkiBkj< 3, numBdofs, 3 >( matRRtAtb, stack.localRotationMatrix, stack.localAtb ); + + LvArray::tensorOps::copy< numTdofs, numUdofs >( stack.localAtu, matRRtAtu ); + LvArray::tensorOps::copy< numTdofs, numBdofs >( stack.localAtb, matRRtAtb ); + + LvArray::tensorOps::scale< numTdofs, numUdofs >( stack.localAtu, -1.0 ); + LvArray::tensorOps::scale< numTdofs, numBdofs >( stack.localAtb, -1.0 ); + + LvArray::tensorOps::transpose< numUdofs, numTdofs >( stack.localAut, stack.localAtu ); + LvArray::tensorOps::transpose< numBdofs, numTdofs >( stack.localAbt, stack.localAtb ); + + // Compute the traction contribute of the local residuals + LvArray::tensorOps::Ri_eq_AijBj< numUdofs, numTdofs >( tractionR, stack.localAut, m_traction[k] ); + LvArray::tensorOps::Ri_eq_AijBj< numBdofs, numTdofs >( tractionRb, stack.localAbt, m_traction[k] ); + + // Compute the local residuals + // Force Balance for nodal displacement dofs + LvArray::tensorOps::scaledAdd< numUdofs >( stack.localRu, tractionR, 1.0 ); + // Force Balance for the bubble dofs + LvArray::tensorOps::scaledAdd< numBdofs >( stack.localRb, tractionRb, 1.0 ); + + fillGlobalMatrix( stack ); + + return 0.0; + } + +protected: + + arrayView2d< real64 const > const m_traction; + + arrayView1d< globalIndex const > const m_tDofNumber; + + arrayView2d< real64 const, nodes::INCR_DISPLACEMENT_USD > const m_incrDisp; + + arrayView2d< real64 const > const m_incrBubbleDisp; + + arrayView2d< real64 const > const m_targetIncrementalJump; + + /** + * @brief Create the list of finite elements of the same type + * for each FaceElementSubRegion (Triangle or Quadrilateral) + * and of the same fracture state (Stick or Slip). + * @param domain The physical domain object + */ + void updateStickSlipList( DomainPartition const & domain ); + + /** + * @brief Create the list of finite elements of the same type + * for each FaceElementSubRegion (Triangle or Quadrilateral). + * @param domain The physical domain object + */ + void createFaceTypeList( DomainPartition const & domain ); + + /** + * @brief Create the list of elements belonging to CellElementSubRegion + * that are enriched with the bubble basis functions + * @param domain The physical domain object + */ + void createBubbleCellList( DomainPartition & domain ) const; + + /** + * @brief Fill global matrix and residual vector + * + * @param stack stack variables + */ + GEOS_HOST_DEVICE + void fillGlobalMatrix( StackVariables & stack ) const + { + + for( localIndex i=0; i < numTdofs; ++i ) + { + localIndex const dof = LvArray::integerConversion< localIndex >( stack.tEqnRowIndices[ i ] ); + + if( dof < 0 || dof >= m_matrix.numRows() ) continue; + + // TODO: May not need to be an atomic operation + RAJA::atomicAdd< parallelDeviceAtomic >( &m_rhs[dof], stack.localRt[i] ); + + // Fill in matrix block Att + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.tColIndices, + stack.localAtt[i], + numTdofs ); + + // Fill in matrix block Atu + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.dispColIndices, + stack.localAtu[i], + numUdofs ); + + // Fill in matrix block Atb + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.bColIndices, + stack.localAtb[i], + numBdofs ); + } + + for( localIndex i=0; i < numUdofs; ++i ) + { + localIndex const dof = LvArray::integerConversion< localIndex >( stack.dispEqnRowIndices[ i ] ); + + if( dof < 0 || dof >= m_matrix.numRows() ) continue; + + // Is it necessary? Each row should be indepenedent + RAJA::atomicAdd< parallelDeviceAtomic >( &m_rhs[dof], stack.localRu[i] ); + + // Fill in matrix + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.tColIndices, + stack.localAut[i], + numTdofs ); + + } + + for( localIndex i=0; i < numBdofs; ++i ) + { + localIndex const dof = LvArray::integerConversion< localIndex >( stack.bEqnRowIndices[ i ] ); + + if( dof < 0 || dof >= m_matrix.numRows() ) continue; + + // Is it necessary? Each row should be indepenedent + RAJA::atomicAdd< parallelDeviceAtomic >( &m_rhs[dof], stack.localRb[i] ); + + // Fill in matrix + m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof, + stack.tColIndices, + stack.localAbt[i], + numTdofs ); + } + } + +}; + +/// The factory used to construct the kernel. +using LagrangeContactFactory = finiteElement::InterfaceKernelFactory< LagrangeContact, + arrayView1d< globalIndex const > const, + arrayView1d< globalIndex const > const, + globalIndex const, + CRSMatrixView< real64, globalIndex const > const, + arrayView1d< real64 > const, + real64 const, + arrayView1d< localIndex const > const, + string const >; + +} // namespace solidMechanicsLagrangeContactKernels + +} // namespace geos + + +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_KERNELS_SOLIDMECHANICSLAGRANGECONTACTKERNELS_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt new file mode 100644 index 00000000000..651d9135e08 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt @@ -0,0 +1,137 @@ +# Specify solver headers +set( physicsSolvers_headers + ${physicsSolvers_headers} + fluidFlow/FlowSolverBase.hpp + fluidFlow/FlowSolverBaseFields.hpp + fluidFlow/CompositionalMultiphaseBase.hpp + fluidFlow/CompositionalMultiphaseBaseFields.hpp + fluidFlow/CompositionalMultiphaseStatistics.hpp + fluidFlow/CompositionalMultiphaseFVM.hpp + fluidFlow/CompositionalMultiphaseHybridFVM.hpp + fluidFlow/CompositionalMultiphaseUtilities.hpp + fluidFlow/ReactiveCompositionalMultiphaseOBL.hpp + fluidFlow/ReactiveCompositionalMultiphaseOBLFields.hpp + fluidFlow/SourceFluxStatistics.hpp + fluidFlow/SinglePhaseBase.hpp + fluidFlow/SinglePhaseBaseFields.hpp + fluidFlow/SinglePhaseStatistics.hpp + fluidFlow/SinglePhaseFVM.hpp + fluidFlow/SinglePhaseHybridFVM.hpp + fluidFlow/SinglePhaseProppantBase.hpp + fluidFlow/StencilAccessors.hpp + fluidFlow/StencilDataCollection.hpp + fluidFlow/LogLevelsInfo.hpp + fluidFlow/kernels/MinPoreVolumeMaxPorosityKernel.hpp + fluidFlow/kernels/StencilWeightsUpdateKernel.hpp + fluidFlow/kernels/HybridFVMHelperKernels.hpp + fluidFlow/kernels/singlePhase/AccumulationKernels.hpp + fluidFlow/kernels/singlePhase/AquiferBCKernel.hpp + fluidFlow/kernels/singlePhase/DirichletFluxComputeKernel.hpp + fluidFlow/kernels/singlePhase/FluidUpdateKernel.hpp + fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp + fluidFlow/kernels/singlePhase/FluxComputeKernelBase.hpp + fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp + fluidFlow/kernels/singlePhase/HydrostaticPressureKernel.hpp + fluidFlow/kernels/singlePhase/MobilityKernel.hpp + fluidFlow/kernels/singlePhase/ResidualNormKernel.hpp + fluidFlow/kernels/singlePhase/SinglePhaseHybridFVMKernels.hpp + fluidFlow/kernels/singlePhase/SolidInternalEnergyUpdateKernel.hpp + fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp + fluidFlow/kernels/singlePhase/SolutionScalingKernel.hpp + fluidFlow/kernels/singlePhase/StabilizedFluxComputeKernel.hpp + fluidFlow/kernels/singlePhase/StatisticsKernel.hpp + fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp + fluidFlow/kernels/singlePhase/ThermalDirichletFluxComputeKernel.hpp + fluidFlow/kernels/singlePhase/ThermalFluxComputeKernel.hpp + fluidFlow/kernels/singlePhase/proppant/ProppantBaseKernels.hpp + fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.hpp + fluidFlow/kernels/compositional/AccumulationKernel.hpp + fluidFlow/kernels/compositional/AquiferBCKernel.hpp + fluidFlow/kernels/compositional/PPUPhaseFlux.hpp + fluidFlow/kernels/compositional/C1PPUPhaseFlux.hpp + fluidFlow/kernels/compositional/CapillaryPressureUpdateKernel.hpp + fluidFlow/kernels/compositional/CFLKernel.hpp + fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp + fluidFlow/kernels/compositional/DiffusionDispersionFluxComputeKernel.hpp + fluidFlow/kernels/compositional/DirichletFluxComputeKernel.hpp + fluidFlow/kernels/compositional/DissipationFluxComputeKernel.hpp + fluidFlow/kernels/compositional/FluidUpdateKernel.hpp + fluidFlow/kernels/compositional/FluidUpdateKernel.hpp + fluidFlow/kernels/compositional/FluxComputeKernel.hpp + fluidFlow/kernels/compositional/FluxComputeKernelBase.hpp + fluidFlow/kernels/compositional/GlobalComponentFractionKernel.hpp + fluidFlow/kernels/compositional/HydrostaticPressureKernel.hpp + fluidFlow/kernels/compositional/IHUPhaseFlux.hpp + fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp + fluidFlow/kernels/compositional/PhaseComponentFlux.hpp + fluidFlow/kernels/compositional/PhaseMobilityKernel.hpp + fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp + fluidFlow/kernels/compositional/PotGrad.hpp + fluidFlow/kernels/compositional/PPUPhaseFlux.hpp + fluidFlow/kernels/compositional/PropertyKernelBase.hpp + fluidFlow/kernels/compositional/ReactiveCompositionalMultiphaseOBLKernels.hpp + fluidFlow/kernels/compositional/RelativePermeabilityUpdateKernel.hpp + fluidFlow/kernels/compositional/ResidualNormKernel.hpp + fluidFlow/kernels/compositional/SolidInternalEnergyUpdateKernel.hpp + fluidFlow/kernels/compositional/SolutionScalingAndCheckingKernelBase.hpp + fluidFlow/kernels/compositional/SolutionCheckKernel.hpp + fluidFlow/kernels/compositional/SolutionScalingKernel.hpp + fluidFlow/kernels/compositional/StabilizedFluxComputeKernel.hpp + fluidFlow/kernels/compositional/StatisticsKernel.hpp + fluidFlow/kernels/compositional/ThermalAccumulationKernel.hpp + fluidFlow/kernels/compositional/ThermalDiffusionDispersionFluxComputeKernel.hpp + fluidFlow/kernels/compositional/ThermalDirichletFluxComputeKernel.hpp + fluidFlow/kernels/compositional/ThermalFluxComputeKernel.hpp + fluidFlow/kernels/compositional/ThermalPhaseMobilityKernel.hpp + fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp + fluidFlow/kernels/compositional/ThermalResidualNormKernel.hpp + fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp + fluidFlow/kernels/compositional/ThermalSolutionScalingKernel.hpp + fluidFlow/wells/CompositionalMultiphaseWell.hpp + fluidFlow/wells/CompositionalMultiphaseWellFields.hpp + fluidFlow/wells/SinglePhaseWell.hpp + fluidFlow/wells/SinglePhaseWellFields.hpp + fluidFlow/wells/WellConstants.hpp + fluidFlow/wells/WellControls.hpp + fluidFlow/wells/WellSolverBase.hpp + fluidFlow/wells/WellSolverBaseFields.hpp + fluidFlow/wells/LogLevelsInfo.hpp + fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp + fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp + fluidFlow/proppantTransport/ProppantTransport.hpp + fluidFlow/proppantTransport/ProppantTransportFields.hpp + fluidFlow/proppantTransport/ProppantTransportKernels.hpp + PARENT_SCOPE ) + +# Specify solver sources +set( physicsSolvers_sources + ${physicsSolvers_sources} + fluidFlow/CompositionalMultiphaseBase.cpp + fluidFlow/CompositionalMultiphaseFVM.cpp + fluidFlow/CompositionalMultiphaseStatistics.cpp + fluidFlow/CompositionalMultiphaseHybridFVM.cpp + fluidFlow/ReactiveCompositionalMultiphaseOBL.cpp + fluidFlow/FlowSolverBase.cpp + fluidFlow/SinglePhaseBase.cpp + fluidFlow/SinglePhaseStatistics.cpp + fluidFlow/SinglePhaseFVM.cpp + fluidFlow/SinglePhaseHybridFVM.cpp + fluidFlow/SinglePhaseProppantBase.cpp + fluidFlow/SourceFluxStatistics.cpp + fluidFlow/StencilDataCollection.cpp + fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.cpp + fluidFlow/kernels/compositional/AquiferBCKernel.cpp + fluidFlow/kernels/compositional/CFLKernel.cpp + fluidFlow/kernels/compositional/FluxComputeKernelBase.cpp + fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.cpp + fluidFlow/wells/CompositionalMultiphaseWell.cpp + fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.cpp + fluidFlow/wells/SinglePhaseWell.cpp + fluidFlow/wells/kernels/SinglePhaseWellKernels.cpp + fluidFlow/wells/WellControls.cpp + fluidFlow/wells/WellSolverBase.cpp + fluidFlow/proppantTransport/ProppantTransport.cpp + fluidFlow/proppantTransport/ProppantTransportKernels.cpp + PARENT_SCOPE ) + + diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp index b1a01eec570..66c79677033 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,8 +19,6 @@ #include "CompositionalMultiphaseBase.hpp" -#include "common/DataTypes.hpp" -#include "common/TimingMacros.hpp" #include "constitutive/ConstitutiveManager.hpp" #include "constitutive/capillaryPressure/CapillaryPressureFields.hpp" #include "constitutive/capillaryPressure/capillaryPressureSelector.hpp" @@ -32,20 +31,29 @@ #include "constitutive/fluid/multifluid/MultiFluidSelector.hpp" #include "constitutive/relativePermeability/RelativePermeabilityFields.hpp" #include "constitutive/relativePermeability/RelativePermeabilitySelector.hpp" -#include "constitutive/solid/SolidBase.hpp" #include "constitutive/solid/SolidInternalEnergy.hpp" #include "constitutive/thermalConductivity/MultiPhaseThermalConductivitySelector.hpp" -#include "constitutive/permeability/PermeabilityFields.hpp" #include "fieldSpecification/AquiferBoundaryCondition.hpp" #include "fieldSpecification/EquilibriumInitialCondition.hpp" #include "fieldSpecification/SourceFluxBoundaryCondition.hpp" +#include "finiteVolume/FluxApproximationBase.hpp" #include "mesh/DomainPartition.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/SourceFluxStatistics.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalAccumulationKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/GlobalComponentFractionKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/FluidUpdateKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/RelativePermeabilityUpdateKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/CapillaryPressureUpdateKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolidInternalEnergyUpdateKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/HydrostaticPressureKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.hpp" #if defined( __INTEL_COMPILER ) #pragma GCC optimize "O0" @@ -66,11 +74,11 @@ CompositionalMultiphaseBase::CompositionalMultiphaseBase( const string & name, m_hasCapPressure( 0 ), m_hasDiffusion( 0 ), m_hasDispersion( 0 ), - m_keepFlowVariablesConstantDuringInitStep( 0 ), m_minScalingFactor( 0.01 ), m_allowCompDensChopping( 1 ), m_useTotalMassEquation( 1 ), m_useSimpleAccumulation( 1 ), + m_useNewGravity( 0 ), m_minCompDens( isothermalCompositionalMultiphaseBaseKernels::minDensForDivision ) { //START_SPHINX_INCLUDE_00 @@ -78,10 +86,13 @@ CompositionalMultiphaseBase::CompositionalMultiphaseBase( const string & name, setInputFlag( InputFlags::REQUIRED ). setDescription( "Temperature" ); //END_SPHINX_INCLUDE_00 + + // TODO: add more description on how useMass can alter the simulation (convergence issues?). How does it interact with wells useMass? this->registerWrapper( viewKeyStruct::useMassFlagString(), &m_useMass ). setApplyDefaultValue( 0 ). setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Use mass formulation instead of molar" ); + setDescription( GEOS_FMT( "Use mass formulation instead of molar. Warning : Affects {} rates units.", + SourceFluxBoundaryCondition::catalogName() ) ); this->registerWrapper( viewKeyStruct::solutionChangeScalingFactorString(), &m_solutionChangeScalingFactor ). setSizedFromParent( 0 ). @@ -103,6 +114,11 @@ CompositionalMultiphaseBase::CompositionalMultiphaseBase( const string & name, setInputFlag( InputFlags::OPTIONAL ). setApplyDefaultValue( 0.2 ). setDescription( "Target (absolute) change in phase volume fraction in a time step" ); + this->registerWrapper( viewKeyStruct::targetRelativeCompDensChangeString(), &m_targetRelativeCompDensChange ). + setSizedFromParent( 0 ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( LvArray::NumericLimits< real64 >::max ). // disabled by default + setDescription( "Target (relative) change in component density in a time step" ); this->registerWrapper( viewKeyStruct::maxCompFracChangeString(), &m_maxCompFracChange ). setSizedFromParent( 0 ). @@ -119,6 +135,11 @@ CompositionalMultiphaseBase::CompositionalMultiphaseBase( const string & name, setInputFlag( InputFlags::OPTIONAL ). setApplyDefaultValue( 0.5 ). setDescription( "Maximum (relative) change in temperature in a Newton iteration" ); + this->registerWrapper( viewKeyStruct::maxRelativeCompDensChangeString(), &m_maxRelativeCompDensChange ). + setSizedFromParent( 0 ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( LvArray::NumericLimits< real64 >::max/1.0e100 ). // disabled by default + setDescription( "Maximum (relative) change in a component density in a Newton iteration" ); this->registerWrapper( viewKeyStruct::allowLocalCompDensChoppingString(), &m_allowCompDensChopping ). setSizedFromParent( 0 ). @@ -130,7 +151,7 @@ CompositionalMultiphaseBase::CompositionalMultiphaseBase( const string & name, setApplyDefaultValue( -1. ). setInputFlag( InputFlags::OPTIONAL ). setDescription( "Target CFL condition `CFL condition `_" - "when computing the next timestep." ); + " when computing the next timestep." ); this->registerWrapper( viewKeyStruct::useTotalMassEquationString(), &m_useTotalMassEquation ). setSizedFromParent( 0 ). @@ -144,6 +165,12 @@ CompositionalMultiphaseBase::CompositionalMultiphaseBase( const string & name, setApplyDefaultValue( 1 ). setDescription( "Flag indicating whether simple accumulation form is used" ); + this->registerWrapper( viewKeyStruct::useNewGravityString(), &m_useNewGravity ). + setSizedFromParent( 0 ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( 0 ). + setDescription( "Flag indicating whether new gravity treatment is used" ); + this->registerWrapper( viewKeyStruct::minCompDensString(), &m_minCompDens ). setSizedFromParent( 0 ). setInputFlag( InputFlags::OPTIONAL ). @@ -155,11 +182,17 @@ CompositionalMultiphaseBase::CompositionalMultiphaseBase( const string & name, setInputFlag( InputFlags::OPTIONAL ). setApplyDefaultValue( 1.0 ). setDescription( "Maximum (absolute) component density change in a sequential iteration, used for outer loop convergence check" ); + + this->registerWrapper( viewKeyStruct::minScalingFactorString(), &m_minScalingFactor ). + setSizedFromParent( 0 ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( 0.01 ). + setDescription( "Minimum value for solution scaling factor" ); } -void CompositionalMultiphaseBase::postProcessInput() +void CompositionalMultiphaseBase::postInputInitialization() { - FlowSolverBase::postProcessInput(); + FlowSolverBase::postInputInitialization(); GEOS_ERROR_IF_GT_MSG( m_maxCompFracChange, 1.0, getWrapperDataContext( viewKeyStruct::maxCompFracChangeString() ) << @@ -173,15 +206,21 @@ void CompositionalMultiphaseBase::postProcessInput() GEOS_ERROR_IF_LE_MSG( m_maxRelativeTempChange, 0.0, getWrapperDataContext( viewKeyStruct::maxRelativeTempChangeString() ) << ": The maximum relative change in temperature in a Newton iteration must be larger than 0.0" ); + GEOS_ERROR_IF_LE_MSG( m_maxRelativeCompDensChange, 0.0, + getWrapperDataContext( viewKeyStruct::maxRelativeCompDensChangeString() ) << + ": The maximum relative change in component density in a Newton iteration must be larger than 0.0" ); GEOS_ERROR_IF_LE_MSG( m_targetRelativePresChange, 0.0, getWrapperDataContext( viewKeyStruct::targetRelativePresChangeString() ) << ": The target relative change in pressure in a time step must be larger than 0.0" ); GEOS_ERROR_IF_LE_MSG( m_targetRelativeTempChange, 0.0, getWrapperDataContext( viewKeyStruct::targetRelativeTempChangeString() ) << - ": The target relative change in temperature in a time step must be larger than to 0.0" ); + ": The target relative change in temperature in a time step must be larger than 0.0" ); GEOS_ERROR_IF_LE_MSG( m_targetPhaseVolFracChange, 0.0, getWrapperDataContext( viewKeyStruct::targetPhaseVolFracChangeString() ) << - ": The target change in phase volume fraction in a time step must be larger than to 0.0" ); + ": The target change in phase volume fraction in a time step must be larger than 0.0" ); + GEOS_ERROR_IF_LE_MSG( m_targetRelativeCompDensChange, 0.0, + getWrapperDataContext( viewKeyStruct::targetPhaseVolFracChangeString() ) << + ": The target change in component density in a time step must be larger than 0.0" ); GEOS_ERROR_IF_LT_MSG( m_solutionChangeScalingFactor, 0.0, getWrapperDataContext( viewKeyStruct::solutionChangeScalingFactorString() ) << @@ -189,6 +228,12 @@ void CompositionalMultiphaseBase::postProcessInput() GEOS_ERROR_IF_GT_MSG( m_solutionChangeScalingFactor, 1.0, getWrapperDataContext( viewKeyStruct::solutionChangeScalingFactorString() ) << ": The solution change scaling factor must be smaller or equal to 1.0" ); + GEOS_ERROR_IF_LE_MSG( m_minScalingFactor, 0.0, + getWrapperDataContext( viewKeyStruct::minScalingFactorString() ) << + ": The minumum scaling factor must be larger than 0.0" ); + GEOS_ERROR_IF_GT_MSG( m_minScalingFactor, 1.0, + getWrapperDataContext( viewKeyStruct::minScalingFactorString() ) << + ": The minumum scaling factor must be smaller or equal to 1.0" ); if( m_isThermal && m_useSimpleAccumulation == 1 ) // useSimpleAccumulation is not yet compatible with thermal { @@ -252,6 +297,7 @@ void CompositionalMultiphaseBase::registerDataOnMesh( Group & meshBodies ) MultiFluidBase const & referenceFluid = cm.getConstitutiveRelation< MultiFluidBase >( m_referenceFluidModelName ); m_numPhases = referenceFluid.numFluidPhases(); m_numComponents = referenceFluid.numFluidComponents(); + m_isThermal = referenceFluid.isThermal(); } // n_c components + one pressure ( + one temperature if needed ) @@ -363,10 +409,17 @@ void CompositionalMultiphaseBase::registerDataOnMesh( Group & meshBodies ) subRegion.registerField< dPhaseMobility >( getName() ). reference().resizeDimension< 1, 2 >( m_numPhases, m_numComponents + 2 ); // dP, dT, dC + // needed for time step selector subRegion.registerField< phaseVolumeFraction_n >( getName() ). reference().resizeDimension< 1 >( m_numPhases ); - subRegion.registerField< phaseMobility_n >( getName() ). - reference().resizeDimension< 1 >( m_numPhases ); + + subRegion.registerField< compAmount >( getName() ). + setDimLabels( 1, fluid.componentNames() ). + reference().resizeDimension< 1 >( m_numComponents ); + subRegion.registerField< compAmount_n >( getName() ). + setDimLabels( 1, fluid.componentNames() ). + reference().resizeDimension< 1 >( m_numComponents ); + } ); FaceManager & faceManager = mesh.getFaceManager(); @@ -549,18 +602,15 @@ void CompositionalMultiphaseBase::validateConstitutiveModels( DomainPartition co compareMultiphaseModels( fluid, referenceFluid ); compareMulticomponentModels( fluid, referenceFluid ); - constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) - { - bool const isFluidModelThermal = castedFluid.isThermal(); - GEOS_THROW_IF( m_isThermal && !isFluidModelThermal, - GEOS_FMT( "CompositionalMultiphaseBase {}: the thermal option is enabled in the solver, but the fluid model {} is incompatible with the thermal option", - getDataContext(), fluid.getDataContext() ), - InputError ); - GEOS_THROW_IF( !m_isThermal && isFluidModelThermal, - GEOS_FMT( "CompositionalMultiphaseBase {}: the thermal option is enabled in fluid model {}, but the solver options are incompatible with the thermal option", - getDataContext(), fluid.getDataContext() ), - InputError ); - } ); + bool const isFluidModelThermal = fluid.isThermal(); + GEOS_THROW_IF( m_isThermal && !isFluidModelThermal, + GEOS_FMT( "CompositionalMultiphaseBase {}: the thermal option is enabled in the solver, but the fluid model {} is incompatible with the thermal option", + getDataContext(), fluid.getDataContext() ), + InputError ); + GEOS_THROW_IF( !m_isThermal && isFluidModelThermal, + GEOS_FMT( "CompositionalMultiphaseBase {}: the thermal option is enabled in fluid model {}, but the solver options are incompatible with the thermal option", + getDataContext(), fluid.getDataContext() ), + InputError ); string const & relpermName = subRegion.getReference< string >( viewKeyStruct::relPermNamesString() ); RelativePermeabilityBase const & relPerm = getConstitutiveModel< RelativePermeabilityBase >( subRegion, relpermName ); @@ -701,6 +751,57 @@ void CompositionalMultiphaseBase::updateCapPressureModel( ObjectManagerBase & da } } +void CompositionalMultiphaseBase::updateCompAmount( ElementSubRegionBase & subRegion ) const +{ + GEOS_MARK_FUNCTION; + + string const & solidName = subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ); + CoupledSolidBase const & porousMaterial = getConstitutiveModel< CoupledSolidBase >( subRegion, solidName ); + arrayView2d< real64 const > const porosity = porousMaterial.getPorosity(); + arrayView1d< real64 const > const volume = subRegion.getElementVolume(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::flow::globalCompDensity >(); + arrayView2d< real64, compflow::USD_COMP > const compAmount = subRegion.getField< fields::flow::compAmount >(); + + integer const numComp = m_numComponents; + + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + for( integer ic = 0; ic < numComp; ++ic ) + { + compAmount[ei][ic] = porosity[ei][0] * volume[ei] * compDens[ei][ic]; + } + } ); +} + +void CompositionalMultiphaseBase::updateEnergy( ElementSubRegionBase & subRegion ) const +{ + GEOS_MARK_FUNCTION; + + string const & solidName = subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ); + CoupledSolidBase const & porousMaterial = getConstitutiveModel< CoupledSolidBase >( subRegion, solidName ); + arrayView2d< real64 const > const porosity = porousMaterial.getPorosity(); + arrayView2d< real64 const > rockInternalEnergy = porousMaterial.getInternalEnergy(); + arrayView1d< real64 const > const volume = subRegion.getElementVolume(); + arrayView2d< real64 const, compflow::USD_PHASE > const phaseVolFrac = subRegion.getField< fields::flow::phaseVolumeFraction >(); + string const & fluidName = getConstitutiveName< MultiFluidBase >( subRegion ); + MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); + arrayView3d< real64 const, multifluid::USD_PHASE > const phaseDens = fluid.phaseDensity(); + arrayView3d< real64 const, multifluid::USD_PHASE > const phaseInternalEnergy = fluid.phaseInternalEnergy(); + + arrayView1d< real64 > const energy = subRegion.getField< fields::flow::energy >(); + + integer const numPhases = m_numPhases; + + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + energy[ei] = volume[ei] * (1.0 - porosity[ei][0]) * rockInternalEnergy[ei][0]; + for( integer ip = 0; ip < numPhases; ++ip ) + { + energy[ei] += volume[ei] * porosity[ei][0] * phaseVolFrac[ei][ip] * phaseDens[ei][0][ip] * phaseInternalEnergy[ei][0][ip]; + } + } ); +} + void CompositionalMultiphaseBase::updateSolidInternalEnergyModel( ObjectManagerBase & dataGroup ) const { arrayView1d< real64 const > const temp = dataGroup.getField< fields::flow::temperature >(); @@ -719,12 +820,13 @@ void CompositionalMultiphaseBase::updateSolidInternalEnergyModel( ObjectManagerB temp ); } -real64 CompositionalMultiphaseBase::updateFluidState( ObjectManagerBase & subRegion ) const +real64 CompositionalMultiphaseBase::updateFluidState( ElementSubRegionBase & subRegion ) const { GEOS_MARK_FUNCTION; updateGlobalComponentFraction( subRegion ); updateFluidModel( subRegion ); + updateCompAmount( subRegion ); real64 const maxDeltaPhaseVolFrac = updatePhaseVolumeFraction( subRegion ); updateRelPermModel( subRegion ); updatePhaseMobility( subRegion ); @@ -736,30 +838,25 @@ real64 CompositionalMultiphaseBase::updateFluidState( ObjectManagerBase & subReg } void CompositionalMultiphaseBase::initializeFluidState( MeshLevel & mesh, - DomainPartition & domain, arrayView1d< string const > const & regionNames ) { GEOS_MARK_FUNCTION; integer const numComp = m_numComponents; - // 1. Compute hydrostatic equilibrium in the regions for which corresponding field specification tag has been specified - computeHydrostaticEquilibrium(); - mesh.getElemManager().forElementSubRegions( regionNames, [&]( localIndex const, ElementSubRegionBase & subRegion ) { - // 2. Assume global component fractions have been prescribed. + // Assume global component fractions have been prescribed. // Initialize constitutive state to get fluid density. updateFluidModel( subRegion ); - // 3. Back-calculate global component densities from fractions and total fluid density + // Back-calculate global component densities from fractions and total fluid density // in order to initialize the primary solution variables - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + string const & fluidName = subRegion.template getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); arrayView2d< real64 const, multifluid::USD_FLUID > const totalDens = fluid.totalDensity(); - arrayView2d< real64 const, compflow::USD_COMP > const compFrac = subRegion.getField< fields::flow::globalCompFraction >(); arrayView2d< real64, compflow::USD_COMP > const compDens = @@ -773,123 +870,78 @@ void CompositionalMultiphaseBase::initializeFluidState( MeshLevel & mesh, } } ); + // with initial component densities defined - check if they need to be corrected to avoid zero diags etc + if( m_allowCompDensChopping ) + { + chopNegativeDensities( subRegion ); + } } ); - // with initial component densities defined - check if they need to be corrected to avoid zero diags etc - chopNegativeDensities( domain ); - // for some reason CUDA does not want the host_device lambda to be defined inside the generic lambda // I need the exact type of the subRegion for updateSolidflowProperties to work well. mesh.getElemManager().forElementSubRegions< CellElementSubRegion, SurfaceElementSubRegion >( regionNames, [&]( localIndex const, auto & subRegion ) { - // 4. Initialize/update dependent state quantities + // Initialize/update dependent state quantities - // 4.1 Update the constitutive models that only depend on - // - the primary variables - // - the fluid constitutive quantities (as they have already been updated) - // We postpone the other constitutive models for now - // In addition, to avoid multiplying permeability/porosity bay netToGross in the assembly kernel, we do it once and for all here - arrayView1d< real64 const > const netToGross = subRegion.template getField< fields::flow::netToGross >(); - CoupledSolidBase const & porousSolid = - getConstitutiveModel< CoupledSolidBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ) ); - PermeabilityBase const & permeabilityModel = - getConstitutiveModel< PermeabilityBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::permeabilityNamesString() ) ); - permeabilityModel.scaleHorizontalPermeability( netToGross ); - porousSolid.scaleReferencePorosity( netToGross ); - saveConvergedState( subRegion ); // necessary for a meaningful porosity update in sequential schemes - updatePorosityAndPermeability( subRegion ); + updateCompAmount( subRegion ); updatePhaseVolumeFraction( subRegion ); - // Now, we initialize and update each constitutive model one by one + // Update the constitutive models that only depend on + // - the primary variables + // - the fluid constitutive quantities (as they have already been updated) + // We postpone the other constitutive models for now - // 4.2 Save the computed porosity into the old porosity - // - // Note: - // - This must be called after updatePorosityAndPermeability - // - This step depends on porosity - string const & solidName = subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ); - CoupledSolidBase const & porousMaterial = getConstitutiveModel< CoupledSolidBase >( subRegion, solidName ); - porousMaterial.initializeState(); - - // 4.3 Initialize/update the relative permeability model using the initial phase volume fraction - // This is needed to handle relative permeability hysteresis - // Also, initialize the fluid model - // - // Note: - // - This must be called after updatePhaseVolumeFraction - // - This step depends on phaseVolFraction + // Now, we initialize and update each constitutive model one by one // initialized phase volume fraction arrayView2d< real64 const, compflow::USD_PHASE > const phaseVolFrac = subRegion.template getField< fields::flow::phaseVolumeFraction >(); - string const & relpermName = subRegion.template getReference< string >( viewKeyStruct::relPermNamesString() ); - RelativePermeabilityBase & relPermMaterial = - getConstitutiveModel< RelativePermeabilityBase >( subRegion, relpermName ); - relPermMaterial.saveConvergedPhaseVolFractionState( phaseVolFrac ); // this needs to happen before calling updateRelPermModel + // Initialize/update the relative permeability model using the initial phase volume fraction + // Note: + // - This must be called after updatePhaseVolumeFraction + // - This step depends on phaseVolFraction + RelativePermeabilityBase & relPerm = + getConstitutiveModel< RelativePermeabilityBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::relPermNamesString() ) ); + relPerm.saveConvergedPhaseVolFractionState( phaseVolFrac ); // this needs to happen before calling updateRelPermModel updateRelPermModel( subRegion ); - relPermMaterial.saveConvergedState(); // this needs to happen after calling updateRelPermModel + relPerm.saveConvergedState(); // this needs to happen after calling updateRelPermModel string const & fluidName = subRegion.template getReference< string >( viewKeyStruct::fluidNamesString() ); - MultiFluidBase & fluidMaterial = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); - fluidMaterial.initializeState(); + MultiFluidBase & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + fluid.initializeState(); - // 4.4 Then, we initialize/update the capillary pressure model - // + // Update the phase mobility // Note: - // - This must be called after updatePorosityAndPermeability - // - This step depends on porosity and permeability + // - This must be called after updateRelPermModel + // - This step depends phaseRelPerm + updatePhaseMobility( subRegion ); + + // Initialize/update the capillary pressure model + // Note: + // - This must be called after updatePorosityAndPermeability and updatePhaseVolumeFraction + // - This step depends on porosity, permeability, and phaseVolFraction if( m_hasCapPressure ) { // initialized porosity - arrayView2d< real64 const > const porosity = porousMaterial.getPorosity(); + CoupledSolidBase const & porousSolid = + getConstitutiveModel< CoupledSolidBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ) ); + arrayView2d< real64 const > const porosity = porousSolid.getPorosity(); - string const & permName = subRegion.template getReference< string >( viewKeyStruct::permeabilityNamesString() ); - PermeabilityBase const & permeabilityMaterial = - getConstitutiveModel< PermeabilityBase >( subRegion, permName ); // initialized permeability + PermeabilityBase const & permeabilityMaterial = + getConstitutiveModel< PermeabilityBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::permeabilityNamesString() ) ); arrayView3d< real64 const > const permeability = permeabilityMaterial.permeability(); - string const & capPressureName = subRegion.template getReference< string >( viewKeyStruct::capPressureNamesString() ); - CapillaryPressureBase const & capPressureMaterial = - getConstitutiveModel< CapillaryPressureBase >( subRegion, capPressureName ); - capPressureMaterial.initializeRockState( porosity, permeability ); // this needs to happen before calling updateCapPressureModel + CapillaryPressureBase const & capPressure = + getConstitutiveModel< CapillaryPressureBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::capPressureNamesString() ) ); + capPressure.initializeRockState( porosity, permeability ); // this needs to happen before calling updateCapPressureModel updateCapPressureModel( subRegion ); } - // 4.5 Update the phase mobility - // - // Note: - // - This must be called after updateRelPermModel - // - This step depends phaseRelPerm - updatePhaseMobility( subRegion ); - - // 4.6 We initialize the rock thermal quantities: conductivity and solid internal energy - // - // Note: - // - This must be called after updatePorosityAndPermeability and updatePhaseVolumeFraction - // - This step depends on porosity and phaseVolFraction - if( m_isThermal ) - { - // initialized porosity - arrayView2d< real64 const > const porosity = porousMaterial.getPorosity(); - - string const & thermalConductivityName = subRegion.template getReference< string >( viewKeyStruct::thermalConductivityNamesString() ); - MultiPhaseThermalConductivityBase const & conductivityMaterial = - getConstitutiveModel< MultiPhaseThermalConductivityBase >( subRegion, thermalConductivityName ); - conductivityMaterial.initializeRockFluidState( porosity, phaseVolFrac ); - // note that there is nothing to update here because thermal conductivity is explicit for now - - updateSolidInternalEnergyModel( subRegion ); - string const & solidInternalEnergyName = subRegion.template getReference< string >( viewKeyStruct::solidInternalEnergyNamesString() ); - SolidInternalEnergy const & solidInternalEnergyMaterial = - getConstitutiveModel< SolidInternalEnergy >( subRegion, solidInternalEnergyName ); - solidInternalEnergyMaterial.saveConvergedState(); - } - - // Step 4.7: if the diffusion and/or dispersion is/are supported, initialize the two models + // If the diffusion and/or dispersion is/are supported, initialize the two models if( m_hasDiffusion ) { string const & diffusionName = subRegion.template getReference< string >( viewKeyStruct::diffusionNamesString() ); @@ -907,24 +959,42 @@ void CompositionalMultiphaseBase::initializeFluidState( MeshLevel & mesh, } } ); +} - // 5. Save initial pressure - mesh.getElemManager().forElementSubRegions( regionNames, [&]( localIndex const, - ElementSubRegionBase & subRegion ) +void CompositionalMultiphaseBase::initializeThermalState( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) +{ + mesh.getElemManager().forElementSubRegions< CellElementSubRegion, + SurfaceElementSubRegion >( regionNames, [&]( localIndex const, + auto & subRegion ) { - arrayView1d< real64 const > const pres = subRegion.getField< fields::flow::pressure >(); - arrayView1d< real64 > const initPres = subRegion.getField< fields::flow::initialPressure >(); - arrayView1d< real64 const > const temp = subRegion.getField< fields::flow::temperature >(); - arrayView1d< real64 > const initTemp = subRegion.template getField< fields::flow::initialTemperature >(); - initPres.setValues< parallelDevicePolicy<> >( pres ); - initTemp.setValues< parallelDevicePolicy<> >( temp ); + // initialized porosity + CoupledSolidBase const & porousSolid = + getConstitutiveModel< CoupledSolidBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ) ); + arrayView2d< real64 const > const porosity = porousSolid.getPorosity(); + + // initialized phase volume fraction + arrayView2d< real64 const, compflow::USD_PHASE > const phaseVolFrac = + subRegion.template getField< fields::flow::phaseVolumeFraction >(); + + string const & thermalConductivityName = subRegion.template getReference< string >( viewKeyStruct::thermalConductivityNamesString()); + MultiPhaseThermalConductivityBase const & conductivityMaterial = + getConstitutiveModel< MultiPhaseThermalConductivityBase >( subRegion, thermalConductivityName ); + conductivityMaterial.initializeRockFluidState( porosity, phaseVolFrac ); + // note that there is nothing to update here because thermal conductivity is explicit for now + + updateSolidInternalEnergyModel( subRegion ); + string const & solidInternalEnergyName = subRegion.template getReference< string >( viewKeyStruct::solidInternalEnergyNamesString()); + SolidInternalEnergy const & solidInternalEnergyMaterial = + getConstitutiveModel< SolidInternalEnergy >( subRegion, solidInternalEnergyName ); + solidInternalEnergyMaterial.saveConvergedState(); + + updateEnergy( subRegion ); } ); } -void CompositionalMultiphaseBase::computeHydrostaticEquilibrium() +void CompositionalMultiphaseBase::computeHydrostaticEquilibrium( DomainPartition & domain ) { FieldSpecificationManager & fsManager = FieldSpecificationManager::getInstance(); - DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); integer const numComps = m_numComponents; integer const numPhases = m_numPhases; @@ -948,7 +1018,7 @@ void CompositionalMultiphaseBase::computeHydrostaticEquilibrium() getCatalogName() << " " << getDataContext() << ": the gravity vector specified in this simulation (" << gravVector[0] << " " << gravVector[1] << " " << gravVector[2] << ") is not aligned with the z-axis. \n" - "This is incompatible with the " << EquilibriumInitialCondition::catalogName() << " " << bc.getDataContext() << + "This is incompatible with the " << bc.getCatalogName() << " " << bc.getDataContext() << "used in this simulation. To proceed, you can either: \n" << " - Use a gravityVector aligned with the z-axis, such as (0.0,0.0,-9.81)\n" << " - Remove the hydrostatic equilibrium initial condition from the XML file", @@ -1179,14 +1249,12 @@ void CompositionalMultiphaseBase::initializePostInitialConditionsPreSubGroups() DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); - // set mass fraction flag on fluid models forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) { FieldIdentifiers fieldsToBeSync; - fieldsToBeSync.addElementFields( { fields::flow::pressure::key(), - fields::flow::globalCompDensity::key() }, + fieldsToBeSync.addElementFields( { fields::flow::globalCompDensity::key() }, regionNames ); CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync, mesh, domain.getNeighbors(), false ); @@ -1195,38 +1263,14 @@ void CompositionalMultiphaseBase::initializePostInitialConditionsPreSubGroups() [&]( localIndex const, auto & subRegion ) { + // set mass fraction flag on fluid models string const & fluidName = subRegion.template getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); fluid.setMassFlag( m_useMass ); - - CoupledSolidBase const & porousSolid = - getConstitutiveModel< CoupledSolidBase >( subRegion, - subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ) ); - saveConvergedState( subRegion ); // necessary for a meaningful porosity update in sequential schemes - updatePorosityAndPermeability( subRegion ); - - porousSolid.initializeState(); } ); - - // Initialize primary variables from applied initial conditions - initializeFluidState( mesh, domain, regionNames ); - - mesh.getElemManager().forElementRegions< SurfaceElementRegion >( regionNames, - [&]( localIndex const, - SurfaceElementRegion & region ) - { - region.forElementSubRegions< FaceElementSubRegion >( [&]( FaceElementSubRegion & subRegion ) - { - subRegion.getWrapper< real64_array >( fields::flow::hydraulicAperture::key() ). - setApplyDefaultValue( region.getDefaultAperture() ); - } ); - } ); - } ); - // report to the user if some pore volumes are very small - // note: this function is here because: 1) porosity has been initialized and 2) NTG has been applied - validatePoreVolumes( domain ); + initializeState( domain ); } void @@ -1255,19 +1299,13 @@ CompositionalMultiphaseBase::implicitStepSetup( real64 const & GEOS_UNUSED_PARAM updateSolidInternalEnergyModel( subRegion ); } - // after the update, save the new saturation and phase mobilities + // after the update, save the new saturation arrayView2d< real64 const, compflow::USD_PHASE > const phaseVolFrac = subRegion.template getField< fields::flow::phaseVolumeFraction >(); arrayView2d< real64, compflow::USD_PHASE > const phaseVolFrac_n = subRegion.template getField< fields::flow::phaseVolumeFraction_n >(); phaseVolFrac_n.setValues< parallelDevicePolicy<> >( phaseVolFrac ); - arrayView2d< real64 const, compflow::USD_PHASE > const phaseMob = - subRegion.template getField< fields::flow::phaseMobility >(); - arrayView2d< real64, compflow::USD_PHASE > const phaseMob_n = - subRegion.template getField< fields::flow::phaseMobility_n >(); - phaseMob_n.setValues< parallelDevicePolicy<> >( phaseMob ); - } ); } ); } @@ -1286,11 +1324,22 @@ void CompositionalMultiphaseBase::assembleSystem( real64 const GEOS_UNUSED_PARAM localMatrix, localRhs ); - assembleFluxTerms( dt, - domain, - dofManager, - localMatrix, - localRhs ); + if( m_isJumpStabilized ) + { + assembleStabilizedFluxTerms( dt, + domain, + dofManager, + localMatrix, + localRhs ); + } + else + { + assembleFluxTerms( dt, + domain, + dofManager, + localMatrix, + localRhs ); + } } void CompositionalMultiphaseBase::assembleAccumulationAndVolumeBalanceTerms( DomainPartition & domain, @@ -1318,7 +1367,7 @@ void CompositionalMultiphaseBase::assembleAccumulationAndVolumeBalanceTerms( Dom if( m_isThermal ) { thermalCompositionalMultiphaseBaseKernels:: - ElementBasedAssemblyKernelFactory:: + AccumulationKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -1333,7 +1382,7 @@ void CompositionalMultiphaseBase::assembleAccumulationAndVolumeBalanceTerms( Dom else { isothermalCompositionalMultiphaseBaseKernels:: - ElementBasedAssemblyKernelFactory:: + AccumulationKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -1359,13 +1408,13 @@ void CompositionalMultiphaseBase::applyBoundaryConditions( real64 const time_n, { GEOS_MARK_FUNCTION; - if( m_keepFlowVariablesConstantDuringInitStep ) + if( m_keepVariablesConstantDuringInitStep ) { // this function is going to force the current flow state to be constant during the time step // this is used when the poromechanics solver is performing the stress initialization // TODO: in the future, a dedicated poromechanics kernel should eliminate the flow vars to construct a reduced system // which will remove the need for this brittle passing aroung of flag - keepFlowVariablesConstantDuringInitStep( time_n, dt, dofManager, domain, localMatrix.toViewConstSizes(), localRhs.toView() ); + keepVariablesConstantDuringInitStep( time_n, dt, dofManager, domain, localMatrix.toViewConstSizes(), localRhs.toView() ); } else { @@ -1450,8 +1499,8 @@ void CompositionalMultiphaseBase::applySourceFluxBC( real64 const time, { globalIndex const numTargetElems = MpiWrapper::sum< globalIndex >( targetSet.size() ); GEOS_LOG_RANK_0( GEOS_FMT( bcLogMessage, - getName(), time+dt, SourceFluxBoundaryCondition::catalogName(), - fs.getName(), setName, subRegion.getName(), fs.getScale(), numTargetElems ) ); + getName(), time+dt, fs.getCatalogName(), fs.getName(), + setName, subRegion.getName(), fs.getScale(), numTargetElems ) ); } if( targetSet.size() == 0 ) @@ -1480,6 +1529,8 @@ void CompositionalMultiphaseBase::applySourceFluxBC( real64 const time, arrayView1d< real64 > rhsContributionArrayView = rhsContributionArray.toView(); localIndex const rankOffset = dofManager.rankOffset(); + RAJA::ReduceSum< parallelDeviceReduce, real64 > massProd( 0.0 ); + // note that the dofArray will not be used after this step (simpler to use dofNumber instead) fs.computeRhsContribution< FieldSpecificationAdd, parallelDevicePolicy<> >( targetSet.toViewConst(), @@ -1513,7 +1564,8 @@ void CompositionalMultiphaseBase::applySourceFluxBC( real64 const time, useTotalMassEquation, dofNumber, rhsContributionArrayView, - localRhs] GEOS_HOST_DEVICE ( localIndex const a ) + localRhs, + massProd] GEOS_HOST_DEVICE ( localIndex const a ) { // we need to filter out ghosts here, because targetSet may contain them localIndex const ei = targetSet[a]; @@ -1522,27 +1574,34 @@ void CompositionalMultiphaseBase::applySourceFluxBC( real64 const time, return; } + real64 const rhsValue = rhsContributionArrayView[a] / sizeScalingFactor; // scale the contribution by the sizeScalingFactor here! + massProd += rhsValue; if( useTotalMassEquation > 0 ) { // for all "fluid components", we add the value to the total mass balance equation globalIndex const totalMassBalanceRow = dofNumber[ei] - rankOffset; - localRhs[totalMassBalanceRow] += rhsContributionArrayView[a] / sizeScalingFactor; // scale the contribution by the - // sizeScalingFactor - // here + localRhs[totalMassBalanceRow] += rhsValue; if( fluidComponentId < numFluidComponents - 1 ) { globalIndex const compMassBalanceRow = totalMassBalanceRow + fluidComponentId + 1; // component mass bal equations are shifted - localRhs[compMassBalanceRow] += rhsContributionArrayView[a] / sizeScalingFactor; // scale the contribution by the - // sizeScalingFactor here + localRhs[compMassBalanceRow] += rhsValue; } } else { globalIndex const compMassBalanceRow = dofNumber[ei] - rankOffset + fluidComponentId; - localRhs[compMassBalanceRow] += rhsContributionArrayView[a] / sizeScalingFactor; // scale the contribution by the - // sizeScalingFactor here + localRhs[compMassBalanceRow] += rhsValue; } } ); + + SourceFluxStatsAggregator::forAllFluxStatWrappers( subRegion, fs.getName(), + [&]( SourceFluxStatsAggregator::WrappedStats & wrapper ) + { + // set the new sub-region statistics for this timestep + array1d< real64 > massProdArr{ m_numComponents }; + massProdArr[fluidComponentId] = massProd.get(); + wrapper.gatherTimeStepStats( time, dt, massProdArr.toViewConst(), targetSet.size() ); + } ); } ); } ); } @@ -1582,7 +1641,8 @@ bool CompositionalMultiphaseBase::validateDirichletBC( DomainPartition & domain, if( subRegionSetMap.count( setName ) > 0 ) { bcConsistent = false; - GEOS_WARNING( GEOS_FMT( "Conflicting pressure boundary conditions on set {}/{}/{}", regionName, subRegionName, setName ) ); + GEOS_WARNING( BCMessage::pressureConflict( regionName, subRegionName, setName, + fields::flow::pressure::key() ) ); } subRegionSetMap[setName].setNumComp( m_numComponents ); } ); @@ -1607,7 +1667,8 @@ bool CompositionalMultiphaseBase::validateDirichletBC( DomainPartition & domain, if( tempSubRegionSetMap.count( setName ) > 0 ) { bcConsistent = false; - GEOS_WARNING( GEOS_FMT( "Conflicting temperature boundary conditions on set {}/{}/{}", regionName, subRegionName, setName ) ); + GEOS_WARNING( BCMessage::temperatureConflict( regionName, subRegionName, setName, + fields::flow::temperature::key() ) ); } tempSubRegionSetMap.insert( setName ); } ); @@ -1624,7 +1685,7 @@ bool CompositionalMultiphaseBase::validateDirichletBC( DomainPartition & domain, string const & ) { // 3.1 Check pressure, temperature, and record composition bc application - string const & subRegionName = subRegion.getName(); + string const & subRegionName = subRegion.getName( ); string const & regionName = subRegion.getParent().getParent().getName(); integer const comp = fs.getComponent(); @@ -1632,7 +1693,8 @@ bool CompositionalMultiphaseBase::validateDirichletBC( DomainPartition & domain, if( subRegionSetMap.count( setName ) == 0 ) { bcConsistent = false; - GEOS_WARNING( GEOS_FMT( "Pressure boundary condition not prescribed on set {}/{}/{}", regionName, subRegionName, setName ) ); + GEOS_WARNING( BCMessage::missingPressure( regionName, subRegionName, setName, + fields::flow::pressure::key() ) ); } if( m_isThermal ) { @@ -1640,13 +1702,15 @@ bool CompositionalMultiphaseBase::validateDirichletBC( DomainPartition & domain, if( tempSubRegionSetMap.count( setName ) == 0 ) { bcConsistent = false; - GEOS_WARNING( GEOS_FMT( "Temperature boundary condition not prescribed on set {}/{}/{}", regionName, subRegionName, setName ) ); + GEOS_WARNING( BCMessage::missingTemperature( regionName, subRegionName, setName, + fields::flow::temperature::key() ) ); } } if( comp < 0 || comp >= m_numComponents ) { bcConsistent = false; - GEOS_WARNING( GEOS_FMT( "Invalid component index [{}] in composition boundary condition {}", comp, fs.getName() ) ); + GEOS_WARNING( BCMessage::invalidComponentIndex( comp, fs.getName(), + fields::flow::globalCompFraction::key() ) ); return; // can't check next part with invalid component id } @@ -1654,7 +1718,13 @@ bool CompositionalMultiphaseBase::validateDirichletBC( DomainPartition & domain, if( compMask[comp] ) { bcConsistent = false; - GEOS_WARNING( GEOS_FMT( "Conflicting composition[{}] boundary conditions on set {}/{}/{}", comp, regionName, subRegionName, setName ) ); + fsManager.forSubGroups< EquilibriumInitialCondition >( [&] ( EquilibriumInitialCondition const & bc ) + { + arrayView1d< string const > componentNames = bc.getComponentNames(); + GEOS_WARNING( BCMessage::conflictingComposition( comp, componentNames[comp], + regionName, subRegionName, setName, + fields::flow::globalCompFraction::key() ) ); + } ); } compMask.set( comp ); } ); @@ -1668,15 +1738,21 @@ bool CompositionalMultiphaseBase::validateDirichletBC( DomainPartition & domain, for( auto const & setEntry : subRegionEntry.second ) { ComponentMask< MAX_NC > const & compMask = setEntry.second; - for( integer ic = 0; ic < m_numComponents; ++ic ) + + fsManager.forSubGroups< EquilibriumInitialCondition >( [&] ( EquilibriumInitialCondition const & fs ) { - if( !compMask[ic] ) + arrayView1d< string const > componentNames = fs.getComponentNames(); + for( int ic = 0; ic < componentNames.size(); ic++ ) { - bcConsistent = false; - GEOS_WARNING( GEOS_FMT( "Boundary condition not applied to composition[{}] on set {}/{}/{}", - ic, regionEntry.first, subRegionEntry.first, setEntry.first ) ); + if( !compMask[ic] ) + { + bcConsistent = false; + GEOS_WARNING( BCMessage::notAppliedOnRegion( ic, componentNames[ic], + regionEntry.first, subRegionEntry.first, setEntry.first, + fields::flow::globalCompFraction::key() ) ); + } } - } + } ); } } } @@ -1857,12 +1933,12 @@ void CompositionalMultiphaseBase::applyDirichletBC( real64 const time_n, } ); } -void CompositionalMultiphaseBase::keepFlowVariablesConstantDuringInitStep( real64 const time, - real64 const dt, - DofManager const & dofManager, - DomainPartition & domain, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) const +void CompositionalMultiphaseBase::keepVariablesConstantDuringInitStep( real64 const time, + real64 const dt, + DofManager const & dofManager, + DomainPartition & domain, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) const { GEOS_MARK_FUNCTION; @@ -1942,9 +2018,6 @@ void CompositionalMultiphaseBase::chopNegativeDensities( DomainPartition & domai using namespace isothermalCompositionalMultiphaseBaseKernels; - integer const numComp = m_numComponents; - real64 const minCompDens = m_minCompDens; - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) @@ -1953,25 +2026,33 @@ void CompositionalMultiphaseBase::chopNegativeDensities( DomainPartition & domai [&]( localIndex const, ElementSubRegionBase & subRegion ) { - arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + chopNegativeDensities( subRegion ); + } ); + } ); +} - arrayView2d< real64, compflow::USD_COMP > const compDens = - subRegion.getField< fields::flow::globalCompDensity >(); +void CompositionalMultiphaseBase::chopNegativeDensities( ElementSubRegionBase & subRegion ) +{ + integer const numComp = m_numComponents; + real64 const minCompDens = m_minCompDens; - forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + + arrayView2d< real64, compflow::USD_COMP > const compDens = + subRegion.getField< fields::flow::globalCompDensity >(); + + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( ghostRank[ei] < 0 ) + { + for( integer ic = 0; ic < numComp; ++ic ) { - if( ghostRank[ei] < 0 ) + if( compDens[ei][ic] < minCompDens ) { - for( integer ic = 0; ic < numComp; ++ic ) - { - if( compDens[ei][ic] < minCompDens ) - { - compDens[ei][ic] = minCompDens; - } - } + compDens[ei][ic] = minCompDens; } - } ); - } ); + } + } } ); } @@ -1980,6 +2061,7 @@ real64 CompositionalMultiphaseBase::setNextDtBasedOnStateChange( real64 const & { if( m_targetRelativePresChange >= 1.0 && m_targetPhaseVolFracChange >= 1.0 && + m_targetRelativeCompDensChange >= 1.0 && ( !m_isThermal || m_targetRelativeTempChange >= 1.0 ) ) { return LvArray::NumericLimits< real64 >::max; @@ -1988,8 +2070,10 @@ real64 CompositionalMultiphaseBase::setNextDtBasedOnStateChange( real64 const & real64 maxRelativePresChange = 0.0; real64 maxRelativeTempChange = 0.0; real64 maxAbsolutePhaseVolFracChange = 0.0; + real64 maxRelativeCompDensChange = 0.0; - real64 const numPhase = m_numPhases; + integer const numPhase = m_numPhases; + integer const numComp = m_numComponents; forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, MeshLevel & mesh, @@ -2009,28 +2093,38 @@ real64 CompositionalMultiphaseBase::setNextDtBasedOnStateChange( real64 const & subRegion.getField< fields::flow::phaseVolumeFraction >(); arrayView2d< real64 const, compflow::USD_PHASE > const phaseVolFrac_n = subRegion.getField< fields::flow::phaseVolumeFraction_n >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = + subRegion.getField< fields::flow::globalCompDensity >(); + arrayView2d< real64, compflow::USD_COMP > const compDens_n = + subRegion.getField< fields::flow::globalCompDensity_n >(); RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxPresChange( 0.0 ); RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxTempChange( 0.0 ); RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxPhaseVolFracChange( 0.0 ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxCompDensChange( 0.0 ); forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) { if( ghostRank[ei] < 0 ) { - // switch from relative to absolute when pressure less than 1 + // switch from relative to absolute when values less than 1 subRegionMaxPresChange.max( LvArray::math::abs( pres[ei] - pres_n[ei] ) / LvArray::math::max( LvArray::math::abs( pres_n[ei] ), 1.0 ) ); subRegionMaxTempChange.max( LvArray::math::abs( temp[ei] - temp_n[ei] ) / LvArray::math::max( LvArray::math::abs( temp_n[ei] ), 1.0 ) ); for( integer ip = 0; ip < numPhase; ++ip ) { subRegionMaxPhaseVolFracChange.max( LvArray::math::abs( phaseVolFrac[ei][ip] - phaseVolFrac_n[ei][ip] ) ); } + for( integer ic = 0; ic < numComp; ++ic ) + { + subRegionMaxCompDensChange.max( LvArray::math::abs( compDens[ei][ic] - compDens_n[ei][ic] ) / LvArray::math::max( LvArray::math::abs( compDens_n[ei][ic] ), 1.0 ) ); + } } } ); maxRelativePresChange = LvArray::math::max( maxRelativePresChange, subRegionMaxPresChange.get() ); maxRelativeTempChange = LvArray::math::max( maxRelativeTempChange, subRegionMaxTempChange.get() ); maxAbsolutePhaseVolFracChange = LvArray::math::max( maxAbsolutePhaseVolFracChange, subRegionMaxPhaseVolFracChange.get() ); + maxRelativeCompDensChange = LvArray::math::max( maxRelativeCompDensChange, subRegionMaxCompDensChange.get() ); } ); } ); @@ -2038,30 +2132,53 @@ real64 CompositionalMultiphaseBase::setNextDtBasedOnStateChange( real64 const & maxRelativePresChange = MpiWrapper::max( maxRelativePresChange ); maxAbsolutePhaseVolFracChange = MpiWrapper::max( maxAbsolutePhaseVolFracChange ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: Max relative pressure change during time step: {} %", - getName(), GEOS_FMT( "{:.{}f}", 100*maxRelativePresChange, 3 ) ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: Max absolute phase volume fraction change during time step: {}", - getName(), GEOS_FMT( "{:.{}f}", maxAbsolutePhaseVolFracChange, 3 ) ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( "{}: max relative pressure change during time step = {} %", + getName(), GEOS_FMT( "{:.{}f}", 100*maxRelativePresChange, 3 ) ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( "{}: max absolute phase volume fraction change during time step = {}", + getName(), GEOS_FMT( "{:.{}f}", maxAbsolutePhaseVolFracChange, 3 ) ) ); + + if( m_targetRelativeCompDensChange < LvArray::NumericLimits< real64 >::max ) + { + maxRelativeCompDensChange = MpiWrapper::max( maxRelativeCompDensChange ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( "{}: max relative component density change during time step = {} %", + getName(), GEOS_FMT( "{:.{}f}", 100*maxRelativeCompDensChange, 3 ) ) ); + } if( m_isThermal ) { maxRelativeTempChange = MpiWrapper::max( maxRelativeTempChange ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: Max relative temperature change during time step: {} %", - getName(), GEOS_FMT( "{:.{}f}", 100*maxRelativeTempChange, 3 ) ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( "{}: max relative temperature change during time step = {} %", + getName(), GEOS_FMT( "{:.{}f}", 100*maxRelativeTempChange, 3 ) ) ); } real64 const eps = LvArray::NumericLimits< real64 >::epsilon; - real64 const nextDtPressure = currentDt * ( 1.0 + m_solutionChangeScalingFactor ) * m_targetRelativePresChange + real64 const nextDtPressure = currentDt * ( 1.0 + m_solutionChangeScalingFactor ) * m_targetRelativePresChange / std::max( eps, maxRelativePresChange + m_solutionChangeScalingFactor * m_targetRelativePresChange ); - real64 const nextDtPhaseVolFrac = currentDt * ( 1.0 + m_solutionChangeScalingFactor ) * m_targetPhaseVolFracChange + if( m_nonlinearSolverParameters.getLogLevel() > 0 ) + GEOS_LOG_RANK_0( GEOS_FMT( "{}: next time step based on pressure change = {}", getName(), nextDtPressure )); + real64 const nextDtPhaseVolFrac = currentDt * ( 1.0 + m_solutionChangeScalingFactor ) * m_targetPhaseVolFracChange / std::max( eps, maxAbsolutePhaseVolFracChange + m_solutionChangeScalingFactor * m_targetPhaseVolFracChange ); - real64 const nextDtTemperature = m_isThermal - ? currentDt * ( 1.0 + m_solutionChangeScalingFactor ) * m_targetRelativeTempChange - / std::max( eps, maxRelativeTempChange + m_solutionChangeScalingFactor * m_targetRelativeTempChange ) - : LvArray::NumericLimits< real64 >::max; + if( m_nonlinearSolverParameters.getLogLevel() > 0 ) + GEOS_LOG_RANK_0( GEOS_FMT( "{}: next time step based on phase volume fraction change = {}", getName(), nextDtPhaseVolFrac )); + real64 nextDtCompDens = LvArray::NumericLimits< real64 >::max; + if( m_targetRelativeCompDensChange < LvArray::NumericLimits< real64 >::max ) + { + nextDtCompDens = currentDt * ( 1.0 + m_solutionChangeScalingFactor ) * m_targetRelativeCompDensChange + / std::max( eps, maxRelativeCompDensChange + m_solutionChangeScalingFactor * m_targetRelativeCompDensChange ); + if( m_nonlinearSolverParameters.getLogLevel() > 0 ) + GEOS_LOG_RANK_0( GEOS_FMT( "{}: next time step based on component density change = {}", getName(), nextDtCompDens )); + } + real64 nextDtTemperature = LvArray::NumericLimits< real64 >::max; + if( m_isThermal ) + { + nextDtTemperature = currentDt * ( 1.0 + m_solutionChangeScalingFactor ) * m_targetRelativeTempChange + / std::max( eps, maxRelativeTempChange + m_solutionChangeScalingFactor * m_targetRelativeTempChange ); + if( m_nonlinearSolverParameters.getLogLevel() > 0 ) + GEOS_LOG_RANK_0( GEOS_FMT( "{}: next time step based on temperature change = {}", getName(), nextDtPhaseVolFrac )); + } - return std::min( std::min( nextDtPressure, nextDtPhaseVolFrac ), nextDtTemperature ); + return std::min( std::min( nextDtPressure, std::min( nextDtPhaseVolFrac, nextDtCompDens ) ), nextDtTemperature ); } real64 CompositionalMultiphaseBase::setNextDtBasedOnCFL( const geos::real64 & currentDt, geos::DomainPartition & domain ) @@ -2071,11 +2188,11 @@ real64 CompositionalMultiphaseBase::setNextDtBasedOnCFL( const geos::real64 & cu computeCFLNumbers( domain, currentDt, maxPhaseCFL, maxCompCFL ); - GEOS_LOG_LEVEL_RANK_0( 1, getName() << ": Max phase CFL number: " << maxPhaseCFL ); - GEOS_LOG_LEVEL_RANK_0( 1, getName() << ": Max component CFL number: " << maxCompCFL ); - - return std::min( m_targetFlowCFL*currentDt/maxCompCFL, m_targetFlowCFL*currentDt/maxPhaseCFL ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( "{}: max phase CFL number = {}", getName(), maxPhaseCFL ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( "{}: max component CFL number = {} ", getName(), maxCompCFL ) ); + return std::min( m_targetFlowCFL * currentDt / maxCompCFL, + m_targetFlowCFL * currentDt / maxPhaseCFL ); } void CompositionalMultiphaseBase::computeCFLNumbers( geos::DomainPartition & domain, const geos::real64 & dt, @@ -2129,13 +2246,13 @@ void CompositionalMultiphaseBase::computeCFLNumbers( geos::DomainPartition & dom fluxApprox.forAllStencils( mesh, [&] ( auto & stencil ) { - typename TYPEOFREF( stencil ) ::KernelWrapper stencilWrapper = stencil.createKernelWrapper(); // While this kernel is waiting for a factory class, pass all the accessors here isothermalCompositionalMultiphaseBaseKernels::KernelLaunchSelector1 < isothermalCompositionalMultiphaseFVMKernels::CFLFluxKernel >( numComps, numPhases, + m_useNewGravity, dt, stencilWrapper, compFlowAccessors.get( fields::flow::pressure{} ), @@ -2310,7 +2427,7 @@ void CompositionalMultiphaseBase::implicitStepComplete( real64 const & time, // Step 3: save the converged solid state string const & solidName = subRegion.getReference< string >( viewKeyStruct::solidNamesString() ); CoupledSolidBase const & porousMaterial = getConstitutiveModel< CoupledSolidBase >( subRegion, solidName ); - if( m_keepFlowVariablesConstantDuringInitStep ) + if( m_keepVariablesConstantDuringInitStep ) { porousMaterial.ignoreConvergedState(); // newPorosity <- porosity_n } @@ -2385,6 +2502,13 @@ void CompositionalMultiphaseBase::saveConvergedState( ElementSubRegionBase & sub arrayView2d< real64, compflow::USD_COMP > const & compDens_n = subRegion.template getField< fields::flow::globalCompDensity_n >(); compDens_n.setValues< parallelDevicePolicy<> >( compDens ); + + arrayView2d< real64 const, compflow::USD_COMP > const & compAmount = + subRegion.template getField< fields::flow::compAmount >(); + arrayView2d< real64, compflow::USD_COMP > const & compAmount_n = + subRegion.template getField< fields::flow::compAmount_n >(); + compAmount_n.setValues< parallelDevicePolicy<> >( compAmount ); + if( m_isFixedStressPoromechanicsUpdate ) { arrayView2d< real64, compflow::USD_COMP > const & compDens_k = @@ -2393,55 +2517,9 @@ void CompositionalMultiphaseBase::saveConvergedState( ElementSubRegionBase & sub } } -void CompositionalMultiphaseBase::saveSequentialIterationState( DomainPartition & domain ) const +void CompositionalMultiphaseBase::saveSequentialIterationState( DomainPartition & domain ) { FlowSolverBase::saveSequentialIterationState( domain ); -} - -void CompositionalMultiphaseBase::saveSequentialIterationState( ElementSubRegionBase & subRegion ) const -{ - FlowSolverBase::saveSequentialIterationState( subRegion ); - - arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.template getField< fields::flow::globalCompDensity >(); - arrayView2d< real64, compflow::USD_COMP > const compDens_k = subRegion.template getField< fields::flow::globalCompDensity_k >(); - compDens_k.setValues< parallelDevicePolicy<> >( compDens ); -} - - -void CompositionalMultiphaseBase::updateState( DomainPartition & domain ) -{ - GEOS_MARK_FUNCTION; - - real64 maxDeltaPhaseVolFrac = 0.0; - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - mesh.getElemManager().forElementSubRegions< CellElementSubRegion, - SurfaceElementSubRegion >( regionNames, [&]( localIndex const, - auto & subRegion ) - { - // update porosity, permeability, and solid internal energy - updatePorosityAndPermeability( subRegion ); - // update all fluid properties - real64 const deltaPhaseVolFrac = updateFluidState( subRegion ); - maxDeltaPhaseVolFrac = LvArray::math::max( maxDeltaPhaseVolFrac, deltaPhaseVolFrac ); - // for thermal, update solid internal energy - if( m_isThermal ) - { - updateSolidInternalEnergyModel( subRegion ); - } - } ); - } ); - - maxDeltaPhaseVolFrac = MpiWrapper::max( maxDeltaPhaseVolFrac ); - - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max phase volume fraction change = {}", getName(), fmt::format( "{:.{}f}", maxDeltaPhaseVolFrac, 4 ) ) ); -} - -bool CompositionalMultiphaseBase::checkSequentialSolutionIncrements( DomainPartition & domain ) const -{ - bool isConverged = FlowSolverBase::checkSequentialSolutionIncrements( domain ); integer const numComp = m_numComponents; @@ -2458,7 +2536,7 @@ bool CompositionalMultiphaseBase::checkSequentialSolutionIncrements( DomainParti arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::flow::globalCompDensity >(); - arrayView2d< real64 const, compflow::USD_COMP > + arrayView2d< real64, compflow::USD_COMP > const compDens_k = subRegion.getField< fields::flow::globalCompDensity_k >(); RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxCompDensChange( 0.0 ); @@ -2472,6 +2550,7 @@ bool CompositionalMultiphaseBase::checkSequentialSolutionIncrements( DomainParti for( integer ic = 0; ic < numComp; ++ic ) { subRegionMaxCompDensChange.max( LvArray::math::abs( compDens[ei][ic] - compDens_k[ei][ic] ) ); + compDens_k[ei][ic] = compDens[ei][ic]; } } } ); @@ -2480,20 +2559,58 @@ bool CompositionalMultiphaseBase::checkSequentialSolutionIncrements( DomainParti } ); } ); - maxCompDensChange = MpiWrapper::max( maxCompDensChange ); + m_sequentialCompDensChange = MpiWrapper::max( maxCompDensChange ); // store to be later used for convergence check +} + +void CompositionalMultiphaseBase::updateState( DomainPartition & domain ) +{ + GEOS_MARK_FUNCTION; + + real64 maxDeltaPhaseVolFrac = 0.0; + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< CellElementSubRegion, + SurfaceElementSubRegion >( regionNames, [&]( localIndex const, + auto & subRegion ) + { + // update porosity, permeability, and solid internal energy + updatePorosityAndPermeability( subRegion ); + // update all fluid properties + real64 const deltaPhaseVolFrac = updateFluidState( subRegion ); + maxDeltaPhaseVolFrac = LvArray::math::max( maxDeltaPhaseVolFrac, deltaPhaseVolFrac ); + // for thermal, update solid internal energy + if( m_isThermal ) + { + updateSolidInternalEnergyModel( subRegion ); + updateEnergy( subRegion ); + } + } ); + } ); + + maxDeltaPhaseVolFrac = MpiWrapper::max( maxDeltaPhaseVolFrac ); + + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, + GEOS_FMT( " {}: Max phase volume fraction change = {}", getName(), fmt::format( "{:.{}f}", maxDeltaPhaseVolFrac, 4 ) ) ); +} + +bool CompositionalMultiphaseBase::checkSequentialSolutionIncrements( DomainPartition & domain ) const +{ + bool isConverged = FlowSolverBase::checkSequentialSolutionIncrements( domain ); string const unit = m_useMass ? "kg/m3" : "mol/m3"; - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max component density change during outer iteration: {} {}", - getName(), fmt::format( "{:.{}f}", maxCompDensChange, 3 ), unit ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Convergence, GEOS_FMT( " {}: Max component density change during outer iteration: {} {}", + getName(), fmt::format( "{:.{}f}", m_sequentialCompDensChange, 3 ), unit ) ); - return isConverged && (maxCompDensChange < m_maxSequentialCompDensChange); + return isConverged && (m_sequentialCompDensChange < m_maxSequentialCompDensChange); } real64 CompositionalMultiphaseBase::setNextDt( const geos::real64 & currentDt, geos::DomainPartition & domain ) { if( m_targetFlowCFL < 0 ) - return SolverBase::setNextDt( currentDt, domain ); + return PhysicsSolverBase::setNextDt( currentDt, domain ); else return setNextDtBasedOnCFL( currentDt, domain ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp index 21e16c269d2..1cec9ca685b 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,12 +20,8 @@ #ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASEBASE_HPP_ #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASEBASE_HPP_ -#include "common/DataLayouts.hpp" -#include "constitutive/fluid/multifluid/Layouts.hpp" -#include "constitutive/relativePermeability/layouts.hpp" -#include "constitutive/capillaryPressure/layouts.hpp" -#include "fieldSpecification/FieldSpecificationManager.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBase.hpp" +#include "fieldSpecification/FieldSpecificationManager.hpp" namespace geos { @@ -137,6 +134,18 @@ class CompositionalMultiphaseBase : public FlowSolverBase */ void updateCapPressureModel( ObjectManagerBase & dataGroup ) const; + /** + * @brief Update components mass/moles + * @param subRegion the subregion storing the required fields + */ + void updateCompAmount( ElementSubRegionBase & subRegion ) const; + + /** + * @brief Update energy + * @param subRegion the subregion storing the required fields + */ + void updateEnergy( ElementSubRegionBase & subRegion ) const; + /** * @brief Update all relevant solid internal energy models using current values of temperature * @param dataGroup the group storing the required fields @@ -149,11 +158,11 @@ class CompositionalMultiphaseBase : public FlowSolverBase */ virtual void updatePhaseMobility( ObjectManagerBase & dataGroup ) const = 0; - real64 updateFluidState( ObjectManagerBase & dataGroup ) const; + real64 updateFluidState( ElementSubRegionBase & subRegion ) const; virtual void saveConvergedState( ElementSubRegionBase & subRegion ) const override final; - virtual void saveSequentialIterationState( DomainPartition & domain ) const override final; + virtual void saveSequentialIterationState( DomainPartition & domain ) override final; virtual void updateState( DomainPartition & domain ) override final; @@ -175,6 +184,12 @@ class CompositionalMultiphaseBase : public FlowSolverBase */ string referenceFluidModelName() const { return m_referenceFluidModelName; } + /** + * @return The unit in which we evaluate the amount of fluid per element (Mass or Mole, depending on useMass). + */ + virtual units::Unit getMassUnit() const override + { return m_useMass ? units::Unit::Mass : units::Unit::Mole; } + /** * @brief assembles the accumulation and volume balance terms for all cells * @param time_n previous time value @@ -227,11 +242,9 @@ class CompositionalMultiphaseBase : public FlowSolverBase // inputs - static constexpr char const * inputTemperatureString() { return "temperature"; } static constexpr char const * useMassFlagString() { return "useMass"; } static constexpr char const * relPermNamesString() { return "relPermNames"; } static constexpr char const * capPressureNamesString() { return "capPressureNames"; } - static constexpr char const * thermalConductivityNamesString() { return "thermalConductivityNames"; } static constexpr char const * diffusionNamesString() { return "diffusionNames"; } static constexpr char const * dispersionNamesString() { return "dispersionNames"; } @@ -242,6 +255,7 @@ class CompositionalMultiphaseBase : public FlowSolverBase static constexpr char const * targetRelativePresChangeString() { return "targetRelativePressureChangeInTimeStep"; } static constexpr char const * targetRelativeTempChangeString() { return "targetRelativeTemperatureChangeInTimeStep"; } static constexpr char const * targetPhaseVolFracChangeString() { return "targetPhaseVolFractionChangeInTimeStep"; } + static constexpr char const * targetRelativeCompDensChangeString() { return "targetRelativeCompDensChangeInTimeStep"; } static constexpr char const * targetFlowCFLString() { return "targetFlowCFL"; } @@ -250,11 +264,14 @@ class CompositionalMultiphaseBase : public FlowSolverBase static constexpr char const * maxCompFracChangeString() { return "maxCompFractionChange"; } static constexpr char const * maxRelativePresChangeString() { return "maxRelativePressureChange"; } static constexpr char const * maxRelativeTempChangeString() { return "maxRelativeTemperatureChange"; } + static constexpr char const * maxRelativeCompDensChangeString() { return "maxRelativeCompDensChange"; } static constexpr char const * allowLocalCompDensChoppingString() { return "allowLocalCompDensityChopping"; } static constexpr char const * useTotalMassEquationString() { return "useTotalMassEquation"; } static constexpr char const * useSimpleAccumulationString() { return "useSimpleAccumulation"; } + static constexpr char const * useNewGravityString() { return "useNewGravity"; } static constexpr char const * minCompDensString() { return "minCompDens"; } static constexpr char const * maxSequentialCompDensChangeString() { return "maxSequentialCompDensChange"; } + static constexpr char const * minScalingFactorString() { return "minScalingFactor"; } }; @@ -266,12 +283,14 @@ class CompositionalMultiphaseBase : public FlowSolverBase * from prescribed intermediate values (i.e. global densities from global fractions) * and any applicable hydrostatic equilibration of the domain */ - void initializeFluidState( MeshLevel & mesh, DomainPartition & domain, arrayView1d< string const > const & regionNames ); + virtual void initializeFluidState( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) override; + + virtual void initializeThermalState( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) override; /** * @brief Compute the hydrostatic equilibrium using the compositions and temperature input tables */ - void computeHydrostaticEquilibrium(); + virtual void computeHydrostaticEquilibrium( DomainPartition & domain ) override; /** * @brief Function to perform the Application of Dirichlet type BC's @@ -321,14 +340,6 @@ class CompositionalMultiphaseBase : public FlowSolverBase CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) const = 0; - /** - * @brief Utility function to keep the flow variables during a time step (used in poromechanics simulations) - * @param[in] keepFlowVariablesConstantDuringInitStep flag to tell the solver to freeze its primary variables during a time step - * @detail This function is meant to be called by a specific task before/after the initialization step - */ - void keepFlowVariablesConstantDuringInitStep( bool const keepFlowVariablesConstantDuringInitStep ) - { m_keepFlowVariablesConstantDuringInitStep = keepFlowVariablesConstantDuringInitStep; } - /** * @brief Function to fix the initial state during the initialization step in coupled problems * @param[in] time current time @@ -337,15 +348,15 @@ class CompositionalMultiphaseBase : public FlowSolverBase * @param[in] domain the domain * @param[in] localMatrix local system matrix * @param[in] localRhs local system right-hand side vector - * @detail This function is meant to be called when the flag m_keepFlowVariablesConstantDuringInitStep is on + * @detail This function is meant to be called when the flag m_keepVariablesConstantDuringInitStep is on * The main use case is the initialization step in coupled problems during which we solve an elastic problem for a fixed pressure */ - void keepFlowVariablesConstantDuringInitStep( real64 const time, - real64 const dt, - DofManager const & dofManager, - DomainPartition & domain, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) const; + void keepVariablesConstantDuringInitStep( real64 const time, + real64 const dt, + DofManager const & dofManager, + DomainPartition & domain, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) const; /** @@ -354,6 +365,8 @@ class CompositionalMultiphaseBase : public FlowSolverBase */ void chopNegativeDensities( DomainPartition & domain ); + void chopNegativeDensities( ElementSubRegionBase & subRegion ); + virtual real64 setNextDtBasedOnStateChange( real64 const & currentDt, DomainPartition & domain ) override; @@ -381,7 +394,7 @@ class CompositionalMultiphaseBase : public FlowSolverBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void initializePreSubGroups() override; @@ -417,17 +430,12 @@ class CompositionalMultiphaseBase : public FlowSolverBase string const fieldKey, string const boundaryFieldKey ) const; - virtual void saveSequentialIterationState( ElementSubRegionBase & subRegion ) const override final; - /// the max number of fluid phases integer m_numPhases; /// the number of fluid components integer m_numComponents; - /// the input temperature - real64 m_inputTemperature; - /// flag indicating whether mass or molar formulation should be used integer m_useMass; @@ -440,9 +448,6 @@ class CompositionalMultiphaseBase : public FlowSolverBase /// flag to determine whether or not to apply dispersion integer m_hasDispersion; - /// flag to freeze the initial state during initialization in coupled problems - integer m_keepFlowVariablesConstantDuringInitStep; - /// maximum (absolute) change in a component fraction in a Newton iteration real64 m_maxCompFracChange; @@ -452,6 +457,9 @@ class CompositionalMultiphaseBase : public FlowSolverBase /// maximum (relative) change in temperature in a Newton iteration real64 m_maxRelativeTempChange; + /// maximum (relative) change in component density in a Newton iteration + real64 m_maxRelativeCompDensChange; + /// damping factor for solution change targets real64 m_solutionChangeScalingFactor; @@ -464,6 +472,9 @@ class CompositionalMultiphaseBase : public FlowSolverBase /// target (absolute) change in phase volume fraction in a time step real64 m_targetPhaseVolFracChange; + /// target (relative) change in component density in a time step + real64 m_targetRelativeCompDensChange; + /// minimum value of the scaling factor obtained by enforcing maxCompFracChange real64 m_minScalingFactor; @@ -476,6 +487,9 @@ class CompositionalMultiphaseBase : public FlowSolverBase /// flag indicating whether simple accumulation form is used integer m_useSimpleAccumulation; + /// flag indicating whether new gravity treatment is used + integer m_useNewGravity; + /// minimum allowed global component density real64 m_minCompDens; @@ -483,6 +497,7 @@ class CompositionalMultiphaseBase : public FlowSolverBase string m_referenceFluidModelName; /// maximum (absolute) component density change in a sequential iteration + real64 m_sequentialCompDensChange; real64 m_maxSequentialCompDensChange; /// the targeted CFL for timestep @@ -525,8 +540,8 @@ void CompositionalMultiphaseBase::applyFieldValue( real64 const & time_n, { globalIndex const numTargetElems = MpiWrapper::sum< globalIndex >( lset.size() ); GEOS_LOG_RANK_0( GEOS_FMT( logMessage, - getName(), time_n+dt, FieldSpecificationBase::catalogName(), - fs.getName(), setName, targetGroup.getName(), fs.getScale(), numTargetElems ) ); + getName(), time_n+dt, fs.getCatalogName(), fs.getName(), + setName, targetGroup.getName(), fs.getScale(), numTargetElems ) ); } // Specify the bc value of the field diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp index 847126b111b..68faa9d681b 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -119,6 +120,7 @@ DECLARE_FIELD( dPhaseMobility, NO_WRITE, "Derivative of phase volume fraction with respect to pressure, temperature, global component density" ); +// this is needed for time step selector DECLARE_FIELD( phaseVolumeFraction_n, "phaseVolumeFraction_n", array2dLayoutPhase, @@ -127,14 +129,6 @@ DECLARE_FIELD( phaseVolumeFraction_n, WRITE_AND_READ, "Phase volume fraction at the previous converged time step" ); -DECLARE_FIELD( phaseMobility_n, - "phaseMobility_n", - array2dLayoutPhase, - 0, - NOPLOT, - WRITE_AND_READ, - "Phase mobility at the previous converged time step" ); - DECLARE_FIELD( phaseOutflux, "phaseOutflux", array2dLayoutPhase, @@ -175,6 +169,22 @@ DECLARE_FIELD( globalCompDensityScalingFactor, NO_WRITE, "Scaling factors for global component densities" ); +DECLARE_FIELD( compAmount, + "compAmount", + array2dLayoutComp, + 0, + LEVEL_0, + WRITE_AND_READ, + "Component amount" ); + +DECLARE_FIELD( compAmount_n, + "compAmount_n", + array2dLayoutComp, + 0, + LEVEL_0, + WRITE_AND_READ, + "Component amount at the previous converged time step" ); + } } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp index 92c447071a4..9a64efef23d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp @@ -2,25 +2,26 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ + + /** * @file CompositionalMultiphaseFVM.cpp */ #include "CompositionalMultiphaseFVM.hpp" -#include "common/DataTypes.hpp" #include "common/MpiWrapper.hpp" -#include "common/TimingMacros.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" #include "constitutive/solid/CoupledSolidBase.hpp" @@ -33,14 +34,25 @@ #include "finiteVolume/FluxApproximationBase.hpp" #include "mesh/DomainPartition.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/StabilizedCompositionalMultiphaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/DissipationCompositionalMultiphaseFVMKernels.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ResidualNormKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalResidualNormKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionScalingKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/DiffusionDispersionFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalDiffusionDispersionFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/StabilizedFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/DissipationFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/DirichletFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalDirichletFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PhaseMobilityKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseMobilityKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.hpp" namespace geos { @@ -90,9 +102,9 @@ CompositionalMultiphaseFVM::CompositionalMultiphaseFVM( const string & name, "Valid options:\n* " + EnumStrings< ScalingType >::concat( "\n* " ) ); } -void CompositionalMultiphaseFVM::postProcessInput() +void CompositionalMultiphaseFVM::postInputInitialization() { - CompositionalMultiphaseBase::postProcessInput(); + CompositionalMultiphaseBase::postInputInitialization(); if( m_scalingType == ScalingType::Local && m_nonlinearSolverParameters.m_lineSearchAction != NonlinearSolverParameters::LineSearchAction::None ) { @@ -170,7 +182,7 @@ void CompositionalMultiphaseFVM::assembleFluxTerms( real64 const dt, if( m_isThermal ) { thermalCompositionalMultiphaseFVMKernels:: - FaceBasedAssemblyKernelFactory:: + FluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -189,7 +201,7 @@ void CompositionalMultiphaseFVM::assembleFluxTerms( real64 const dt, if( m_dbcParams.useDBC ) { dissipationCompositionalMultiphaseFVMKernels:: - FaceBasedAssemblyKernelFactory:: + FluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -212,13 +224,14 @@ void CompositionalMultiphaseFVM::assembleFluxTerms( real64 const dt, else { isothermalCompositionalMultiphaseFVMKernels:: - FaceBasedAssemblyKernelFactory:: + FluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), elemDofKey, m_hasCapPressure, m_useTotalMassEquation, + m_useNewGravity, fluxApprox.upwindingParams(), getName(), mesh.getElemManager(), @@ -236,7 +249,7 @@ void CompositionalMultiphaseFVM::assembleFluxTerms( real64 const dt, if( m_isThermal ) { thermalCompositionalMultiphaseFVMKernels:: - DiffusionDispersionFaceBasedAssemblyKernelFactory:: + DiffusionDispersionFluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -254,7 +267,7 @@ void CompositionalMultiphaseFVM::assembleFluxTerms( real64 const dt, else { isothermalCompositionalMultiphaseFVMKernels:: - DiffusionDispersionFaceBasedAssemblyKernelFactory:: + DiffusionDispersionFluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -303,7 +316,7 @@ void CompositionalMultiphaseFVM::assembleStabilizedFluxTerms( real64 const dt, // Thermal implementation not supported yet stabilizedCompositionalMultiphaseFVMKernels:: - FaceBasedAssemblyKernelFactory:: + FluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -329,13 +342,13 @@ real64 CompositionalMultiphaseFVM::calculateResidualNorm( real64 const & GEOS_UN { GEOS_MARK_FUNCTION; - integer constexpr numNorm = 2; // mass balance and energy balance + integer constexpr numNorm = 3; // mass/volume balance and energy balance array1d< real64 > localResidualNorm; array1d< real64 > localResidualNormalizer; localResidualNorm.resize( numNorm ); localResidualNormalizer.resize( numNorm ); - solverBaseKernels::NormType const normType = getNonlinearSolverParameters().normType(); + physicsSolverBaseKernels::NormType const normType = getNonlinearSolverParameters().normType(); globalIndex const rankOffset = dofManager.rankOffset(); string const dofKey = dofManager.getKey( viewKeyStruct::elemDofFieldString() ); @@ -382,8 +395,8 @@ real64 CompositionalMultiphaseFVM::calculateResidualNorm( real64 const & GEOS_UN } else { - real64 subRegionFlowResidualNorm[1]{}; - real64 subRegionFlowResidualNormalizer[1]{}; + real64 subRegionFlowResidualNorm[2]{}; + real64 subRegionFlowResidualNormalizer[2]{}; isothermalCompositionalMultiphaseBaseKernels:: ResidualNormKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( normType, @@ -397,20 +410,24 @@ real64 CompositionalMultiphaseFVM::calculateResidualNorm( real64 const & GEOS_UN m_nonlinearSolverParameters.m_minNormalizer, subRegionFlowResidualNorm, subRegionFlowResidualNormalizer ); + // mass subRegionResidualNorm[0] = subRegionFlowResidualNorm[0]; subRegionResidualNormalizer[0] = subRegionFlowResidualNormalizer[0]; + // volume + subRegionResidualNorm[1] = subRegionFlowResidualNorm[1]; + subRegionResidualNormalizer[1] = subRegionFlowResidualNormalizer[1]; } // step 2: first reduction across meshBodies/regions/subRegions - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { - solverBaseKernels::LinfResidualNormHelper:: + physicsSolverBaseKernels::LinfResidualNormHelper:: updateLocalNorm< numNorm >( subRegionResidualNorm, localResidualNorm ); } else { - solverBaseKernels::L2ResidualNormHelper:: + physicsSolverBaseKernels::L2ResidualNormHelper:: updateLocalNorm< numNorm >( subRegionResidualNorm, subRegionResidualNormalizer, localResidualNorm, localResidualNormalizer ); } } ); @@ -419,46 +436,43 @@ real64 CompositionalMultiphaseFVM::calculateResidualNorm( real64 const & GEOS_UN // step 3: second reduction across MPI ranks real64 residualNorm = 0.0; + array1d< real64 > globalResidualNorm; + globalResidualNorm.resize( numNorm ); if( m_isThermal ) { - - array1d< real64 > globalResidualNorm; - globalResidualNorm.resize( numNorm ); - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { - solverBaseKernels::LinfResidualNormHelper:: + physicsSolverBaseKernels::LinfResidualNormHelper:: computeGlobalNorm( localResidualNorm, globalResidualNorm ); } else { - solverBaseKernels::L2ResidualNormHelper:: + physicsSolverBaseKernels::L2ResidualNormHelper:: computeGlobalNorm( localResidualNorm, localResidualNormalizer, globalResidualNorm ); } - residualNorm = sqrt( globalResidualNorm[0] * globalResidualNorm[0] + globalResidualNorm[1] * globalResidualNorm[1] ); + residualNorm = sqrt( globalResidualNorm[0] * globalResidualNorm[0] + globalResidualNorm[1] * globalResidualNorm[1] + globalResidualNorm[2] * globalResidualNorm[2] ); - if( getLogLevel() >= 1 && logger::internal::rank == 0 ) - { - std::cout << GEOS_FMT( " ( R{} ) = ( {:4.2e} ) ( Renergy ) = ( {:4.2e} )", - coupledSolverAttributePrefix(), globalResidualNorm[0], globalResidualNorm[1] ); - } + GEOS_LOG_LEVEL_INFO_RANK_0_NLR( logInfo::Convergence, GEOS_FMT( " ( Rmass Rvol ) = ( {:4.2e} {:4.2e} ) ( Renergy ) = ( {:4.2e} )", + globalResidualNorm[0], globalResidualNorm[1], globalResidualNorm[2] )); } else { - - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { - solverBaseKernels::LinfResidualNormHelper::computeGlobalNorm( localResidualNorm[0], residualNorm ); + physicsSolverBaseKernels::LinfResidualNormHelper:: + computeGlobalNorm( localResidualNorm, globalResidualNorm ); } else { - solverBaseKernels::L2ResidualNormHelper::computeGlobalNorm( localResidualNorm[0], localResidualNormalizer[0], residualNorm ); + physicsSolverBaseKernels::L2ResidualNormHelper:: + computeGlobalNorm( localResidualNorm, localResidualNormalizer, globalResidualNorm ); } + residualNorm = sqrt( globalResidualNorm[0] * globalResidualNorm[0] + globalResidualNorm[1] * globalResidualNorm[1] ); - if( getLogLevel() >= 1 && logger::internal::rank == 0 ) - { - std::cout << GEOS_FMT( " ( R{} ) = ( {:4.2e} )", coupledSolverAttributePrefix(), residualNorm ); - } + GEOS_LOG_LEVEL_INFO_RANK_0_NLR( logInfo::Convergence, GEOS_FMT( " ( Rmass Rvol ) = ( {:4.2e} {:4.2e} )", + globalResidualNorm[0], globalResidualNorm[1] ) ); } + return residualNorm; } @@ -470,9 +484,13 @@ real64 CompositionalMultiphaseFVM::scalingForSystemSolution( DomainPartition & d string const dofKey = dofManager.getKey( viewKeyStruct::elemDofFieldString() ); real64 scalingFactor = 1.0; - real64 maxDeltaPres = 0.0, maxDeltaCompDens = 0.0, maxDeltaTemp = 0.0; real64 minPresScalingFactor = 1.0, minCompDensScalingFactor = 1.0, minTempScalingFactor = 1.0; + + std::vector< valueAndLocationType > regionDeltaPresMaxLoc; + std::vector< valueAndLocationType > regionDeltaTempMaxLoc; + std::vector< valueAndLocationType > regionDeltaCompDensMaxLoc; + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) @@ -481,70 +499,123 @@ real64 CompositionalMultiphaseFVM::scalingForSystemSolution( DomainPartition & d [&]( localIndex const, ElementSubRegionBase & subRegion ) { + arrayView1d< globalIndex const > const localToGlobalMap = subRegion.localToGlobalMap(); + arrayView1d< real64 const > const pressure = subRegion.getField< fields::flow::pressure >(); + arrayView1d< real64 const > const temperature = subRegion.getField< fields::flow::temperature >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::flow::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::flow::pressureScalingFactor >(); + arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::flow::temperatureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); + + const integer temperatureOffset = m_numComponents+1; + auto const subRegionData = m_isThermal ? thermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernelFactory:: + SolutionScalingKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, m_maxAbsolutePresChange, m_maxRelativeTempChange, m_maxCompFracChange, + m_maxRelativeCompDensChange, + pressure, + temperature, + compDens, + pressureScalingFactor, + compDensScalingFactor, + temperatureScalingFactor, dofManager.rankOffset(), m_numComponents, dofKey, subRegion, - localSolution ) + localSolution, + temperatureOffset ) : isothermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernelFactory:: + SolutionScalingKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, m_maxAbsolutePresChange, m_maxCompFracChange, + m_maxRelativeCompDensChange, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor, dofManager.rankOffset(), m_numComponents, dofKey, subRegion, localSolution ); - - if( m_scalingType == ScalingType::Global ) + if( subRegion.size() > 0 || subRegion.size() != subRegion.getNumberOfGhosts() ) { - scalingFactor = std::min( scalingFactor, subRegionData.localMinVal ); + if( m_scalingType == ScalingType::Global ) + { + scalingFactor = std::min( scalingFactor, subRegionData.localMinVal ); + } + + regionDeltaPresMaxLoc.push_back( valueAndLocationType( subRegionData.localMaxDeltaPres, localToGlobalMap[subRegionData.localMaxDeltaPresLoc] ) ); + minPresScalingFactor = std::min( minPresScalingFactor, subRegionData.localMinPresScalingFactor ); + + regionDeltaCompDensMaxLoc.push_back( valueAndLocationType( subRegionData.localMaxDeltaCompDens, localToGlobalMap[subRegionData.localMaxDeltaCompDensLoc] ) ); + minCompDensScalingFactor = std::min( minCompDensScalingFactor, subRegionData.localMinCompDensScalingFactor ); + + if( m_isThermal ) + { + regionDeltaTempMaxLoc.push_back( valueAndLocationType( subRegionData.localMaxDeltaTemp, localToGlobalMap[subRegionData.localMaxDeltaTempLoc] ) ); + minTempScalingFactor = std::min( minTempScalingFactor, subRegionData.localMinTempScalingFactor ); + } } - maxDeltaPres = std::max( maxDeltaPres, subRegionData.localMaxDeltaPres ); - maxDeltaCompDens = std::max( maxDeltaCompDens, subRegionData.localMaxDeltaCompDens ); - maxDeltaTemp = std::max( maxDeltaTemp, subRegionData.localMaxDeltaTemp ); - minPresScalingFactor = std::min( minPresScalingFactor, subRegionData.localMinPresScalingFactor ); - minCompDensScalingFactor = std::min( minCompDensScalingFactor, subRegionData.localMinCompDensScalingFactor ); - minTempScalingFactor = std::min( minTempScalingFactor, subRegionData.localMinTempScalingFactor ); } ); } ); + auto [localDeltaPresMax, localPresMaxLoc] = *std::max_element( begin( regionDeltaPresMaxLoc ), end( regionDeltaPresMaxLoc ), []( auto & lhs, auto & rhs ) { + return lhs.value < rhs.value; + } ); + auto globalDeltaPresMax = MpiWrapper::maxValLoc( valueAndLocationType( localDeltaPresMax, localPresMaxLoc )); + auto [ localDeltaCompDensMax, localCompDensMaxLoc ] = *std::max_element( begin( regionDeltaCompDensMaxLoc ), end( regionDeltaCompDensMaxLoc ), []( auto & lhs, auto & rhs ) { + return lhs.value < rhs.value; + } ); + auto globalDeltaCompDensMax = MpiWrapper::maxValLoc( valueAndLocationType( localDeltaCompDensMax, localCompDensMaxLoc )); + scalingFactor = MpiWrapper::min( scalingFactor ); - maxDeltaPres = MpiWrapper::max( maxDeltaPres ); - maxDeltaCompDens = MpiWrapper::max( maxDeltaCompDens ); minPresScalingFactor = MpiWrapper::min( minPresScalingFactor ); minCompDensScalingFactor = MpiWrapper::min( minCompDensScalingFactor ); string const massUnit = m_useMass ? "kg/m3" : "mol/m3"; - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max pressure change: {} Pa (before scaling)", - getName(), GEOS_FMT( "{:.{}f}", maxDeltaPres, 3 ) ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max component density change: {} {} (before scaling)", - getName(), GEOS_FMT( "{:.{}f}", maxDeltaCompDens, 3 ), massUnit ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, + GEOS_FMT( " {}: Max pressure change = {:.3f} Pa (before scaling) at cell {}", + getName(), + globalDeltaPresMax.value, + globalDeltaPresMax.location ) ); + + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, + GEOS_FMT( " {}: Max component density change = {:.3f} {} (before scaling) at cell {}", + getName(), + globalDeltaCompDensMax.value, + massUnit, + globalDeltaCompDensMax.location ) ); if( m_isThermal ) { - maxDeltaTemp = MpiWrapper::max( maxDeltaTemp ); + auto [localDeltaTempMax, localDeltaTempMaxLoc ] = *std::max_element( begin( regionDeltaTempMaxLoc ), end( regionDeltaTempMaxLoc ), []( auto & lhs, auto & rhs ) { + return lhs.value < rhs.value; + } ); + auto globalMaxDeltaTemp = MpiWrapper::maxValLoc( valueAndLocationType( localDeltaTempMax, localDeltaTempMaxLoc )); + minTempScalingFactor = MpiWrapper::min( minTempScalingFactor ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max temperature change: {} K (before scaling)", - getName(), GEOS_FMT( "{:.{}f}", maxDeltaTemp, 3 ) ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, + GEOS_FMT( " {}: Max temperature change = {:.3f} K (before scaling) at cell maxRegionDeltaTempLoc {}", + getName(), + globalMaxDeltaTemp.value, + globalMaxDeltaTemp.location ) ); } if( m_scalingType == ScalingType::Local ) { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min pressure scaling factor: {}", getName(), minPresScalingFactor ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min component density scaling factor: {}", getName(), minCompDensScalingFactor ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, GEOS_FMT( " {}: Min pressure scaling factor = {}", getName(), minPresScalingFactor ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, GEOS_FMT( " {}: Min component density scaling factor = {}", getName(), minCompDensScalingFactor ) ); if( m_isThermal ) { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min temperature scaling factor: {}", getName(), minTempScalingFactor ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, GEOS_FMT( " {}: Min temperature scaling factor = {}", getName(), minTempScalingFactor ) ); } } @@ -571,8 +642,18 @@ bool CompositionalMultiphaseFVM::checkSystemSolution( DomainPartition & domain, [&]( localIndex const, ElementSubRegionBase & subRegion ) { + arrayView1d< real64 const > const pressure = + subRegion.getField< fields::flow::pressure >(); + arrayView1d< real64 const > const temperature = + subRegion.getField< fields::flow::temperature >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = + subRegion.getField< fields::flow::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::flow::pressureScalingFactor >(); + arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::flow::temperatureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); // check that pressure and component densities are non-negative // for thermal, check that temperature is above 273.15 K + const integer temperatureOffset = m_numComponents+1; auto const subRegionData = m_isThermal ? thermalCompositionalMultiphaseBaseKernels:: @@ -581,17 +662,28 @@ bool CompositionalMultiphaseFVM::checkSystemSolution( DomainPartition & domain, m_allowNegativePressure, m_scalingType, scalingFactor, + pressure, + temperature, + compDens, + pressureScalingFactor, + temperatureScalingFactor, + compDensScalingFactor, dofManager.rankOffset(), m_numComponents, dofKey, subRegion, - localSolution ) + localSolution, + temperatureOffset ) : isothermalCompositionalMultiphaseBaseKernels:: SolutionCheckKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, m_allowNegativePressure, m_scalingType, scalingFactor, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor, dofManager.rankOffset(), m_numComponents, dofKey, @@ -617,15 +709,15 @@ bool CompositionalMultiphaseFVM::checkSystemSolution( DomainPartition & domain, numNegTotalDens = MpiWrapper::sum( numNegTotalDens ); if( numNegPres > 0 ) - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative pressure values: {}, minimum value: {} Pa", - getName(), numNegPres, fmt::format( "{:.{}f}", minPres, 3 ) ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, GEOS_FMT( " {}: Number of negative pressure values: {}, minimum value: {} Pa", + getName(), numNegPres, fmt::format( "{:.{}f}", minPres, 3 ) ) ); string const massUnit = m_useMass ? "kg/m3" : "mol/m3"; if( numNegDens > 0 ) - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative component density values: {}, minimum value: {} {}}", - getName(), numNegDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, GEOS_FMT( " {}: Number of negative component density values: {}, minimum value: {} {}}", + getName(), numNegDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); if( minTotalDens > 0 ) - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative total density values: {}, minimum value: {} {}}", - getName(), minTotalDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, GEOS_FMT( " {}: Number of negative total density values: {}, minimum value: {} {}}", + getName(), minTotalDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); return MpiWrapper::min( localCheck ); } @@ -763,7 +855,7 @@ void CompositionalMultiphaseFVM::applyBoundaryConditions( real64 time_n, { GEOS_MARK_FUNCTION; CompositionalMultiphaseBase::applyBoundaryConditions( time_n, dt, domain, dofManager, localMatrix, localRhs ); - if( !m_keepFlowVariablesConstantDuringInitStep ) + if( !m_keepVariablesConstantDuringInitStep ) { applyFaceDirichletBC( time_n, dt, dofManager, domain, localMatrix, localRhs ); } @@ -972,8 +1064,9 @@ void CompositionalMultiphaseFVM::applyFaceDirichletBC( real64 const time_n, if( m_isThermal ) { + //todo (jafranc) extend upwindScheme name if satisfied in isothermalCase thermalCompositionalMultiphaseFVMKernels:: - DirichletFaceBasedAssemblyKernelFactory:: + DirichletFluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -991,7 +1084,7 @@ void CompositionalMultiphaseFVM::applyFaceDirichletBC( real64 const time_n, else { isothermalCompositionalMultiphaseFVMKernels:: - DirichletFaceBasedAssemblyKernelFactory:: + DirichletFluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -1055,8 +1148,8 @@ void CompositionalMultiphaseFVM::applyAquiferBC( real64 const time, { globalIndex const numTargetFaces = MpiWrapper::sum< globalIndex >( stencil.size() ); GEOS_LOG_RANK_0( GEOS_FMT( faceBcLogMessage, - getName(), time+dt, AquiferBoundaryCondition::catalogName(), - bc.getName(), setName, faceManager.getName(), bc.getScale(), numTargetFaces ) ); + getName(), time+dt, bc.getCatalogName(), bc.getName(), + setName, faceManager.getName(), bc.getScale(), numTargetFaces ) ); } if( stencil.size() == 0 ) @@ -1104,6 +1197,6 @@ void CompositionalMultiphaseFVM::applyAquiferBC( real64 const time, } //START_SPHINX_INCLUDE_01 -REGISTER_CATALOG_ENTRY( SolverBase, CompositionalMultiphaseFVM, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, CompositionalMultiphaseFVM, string const &, Group * const ) //END_SPHINX_INCLUDE_01 }// namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp index 82776f70485..f14b2436740 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -72,7 +73,7 @@ class CompositionalMultiphaseFVM : public CompositionalMultiphaseBase */ static string catalogName() { return "CompositionalMultiphaseFVM"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } //END_SPHINX_INCLUDE_01 @@ -173,9 +174,22 @@ class CompositionalMultiphaseFVM : public CompositionalMultiphaseBase Local ///< Scale the Newton update locally (modifies the Newton direction) }; + /** + * @brief Storage for value and element location, used to determine global max + location + */ + template< typename VALUE_TYPE, typename INDEX_TYPE > + struct valueAndLocation + { + valueAndLocation(){} + valueAndLocation( VALUE_TYPE val, INDEX_TYPE loc ): value( val ), location( loc ){} + VALUE_TYPE value; + INDEX_TYPE location; + }; + typedef valueAndLocation< real64, globalIndex > valueAndLocationType; + protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void initializePreSubGroups() override; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp index 431a7320860..021ce8fd96b 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,7 +19,7 @@ #include "CompositionalMultiphaseHybridFVM.hpp" -#include "common/TimingMacros.hpp" +#include "mesh/DomainPartition.hpp" #include "constitutive/ConstitutivePassThru.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" @@ -27,14 +28,15 @@ #include "finiteVolume/HybridMimeticDiscretization.hpp" #include "finiteVolume/MimeticInnerProductDispatch.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVMKernels.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseHybridFVMKernels.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ResidualNormKernel.hpp" /** - * @namespace the geosx namespace that encapsulates the majority of the code + * @namespace the geos namespace that encapsulates the majority of the code */ namespace geos { @@ -424,7 +426,8 @@ void CompositionalMultiphaseHybridFVM::assembleStabilizedFluxTerms( real64 const arrayView1d< real64 > const & localRhs ) const { // stab not implemented - assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); + GEOS_UNUSED_VAR( dt, domain, dofManager, localMatrix, localRhs ); + GEOS_ERROR( "Stabilized flux not available for this flow solver" ); } real64 CompositionalMultiphaseHybridFVM::scalingForSystemSolution( DomainPartition & domain, @@ -444,12 +447,21 @@ real64 CompositionalMultiphaseHybridFVM::scalingForSystemSolution( DomainPartiti mesh.getElemManager().forElementSubRegions< ElementSubRegionBase >( regionNames, [&]( localIndex const, ElementSubRegionBase & subRegion ) { + arrayView1d< real64 const > const pressure = subRegion.getField< fields::flow::pressure >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::flow::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::flow::pressureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); auto const subRegionData = isothermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernelFactory:: + SolutionScalingKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, m_maxAbsolutePresChange, m_maxCompFracChange, + m_maxRelativeCompDensChange, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor, dofManager.rankOffset(), m_numComponents, dofKey, @@ -516,6 +528,13 @@ bool CompositionalMultiphaseHybridFVM::checkSystemSolution( DomainPartition & do mesh.getElemManager().forElementSubRegions< ElementSubRegionBase >( regionNames, [&]( localIndex const, ElementSubRegionBase & subRegion ) { + arrayView1d< real64 const > const pressure = + subRegion.getField< fields::flow::pressure >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = + subRegion.getField< fields::flow::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::flow::pressureScalingFactor >(); + arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::flow::temperatureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); // check that pressure and component densities are non-negative auto const subRegionData = isothermalCompositionalMultiphaseBaseKernels:: @@ -524,6 +543,10 @@ bool CompositionalMultiphaseHybridFVM::checkSystemSolution( DomainPartition & do m_allowNegativePressure, CompositionalMultiphaseFVM::ScalingType::Global, scalingFactor, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor, dofManager.rankOffset(), m_numComponents, elemDofKey, @@ -585,7 +608,7 @@ real64 CompositionalMultiphaseHybridFVM::calculateResidualNorm( real64 const & G real64 localResidualNorm = 0.0; real64 localResidualNormalizer = 0.0; - solverBaseKernels::NormType const normType = getNonlinearSolverParameters().normType(); + physicsSolverBaseKernels::NormType const normType = getNonlinearSolverParameters().normType(); // local residual globalIndex const rankOffset = dofManager.rankOffset(); @@ -608,8 +631,8 @@ real64 CompositionalMultiphaseHybridFVM::calculateResidualNorm( real64 const & G [&]( localIndex const, ElementSubRegionBase const & subRegion ) { - real64 subRegionResidualNorm[1]{}; - real64 subRegionResidualNormalizer[1]{}; + real64 subRegionResidualNorm[2]{}; + real64 subRegionResidualNormalizer[2]{}; string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); @@ -635,8 +658,10 @@ real64 CompositionalMultiphaseHybridFVM::calculateResidualNorm( real64 const & G // step 1.2: reduction across meshBodies/regions/subRegions - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { + // take max between mass and volume residual + subRegionResidualNorm[0] = LvArray::math::max( subRegionResidualNorm[0], subRegionResidualNorm[1] ); if( subRegionResidualNorm[0] > localResidualNorm ) { localResidualNorm = subRegionResidualNorm[0]; @@ -644,6 +669,8 @@ real64 CompositionalMultiphaseHybridFVM::calculateResidualNorm( real64 const & G } else { + // sum up mass and volume residual + subRegionResidualNorm[0] = subRegionResidualNorm[0] + subRegionResidualNorm[1]; localResidualNorm += subRegionResidualNorm[0]; localResidualNormalizer += subRegionResidualNormalizer[0]; } @@ -673,7 +700,7 @@ real64 CompositionalMultiphaseHybridFVM::calculateResidualNorm( real64 const & G // step 2.2: reduction across meshBodies/regions/subRegions - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { if( faceResidualNorm[0] > localResidualNorm ) { @@ -690,13 +717,13 @@ real64 CompositionalMultiphaseHybridFVM::calculateResidualNorm( real64 const & G // step 3: second reduction across MPI ranks real64 residualNorm = 0.0; - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { - solverBaseKernels::LinfResidualNormHelper::computeGlobalNorm( localResidualNorm, residualNorm ); + physicsSolverBaseKernels::LinfResidualNormHelper::computeGlobalNorm( localResidualNorm, residualNorm ); } else { - solverBaseKernels::L2ResidualNormHelper::computeGlobalNorm( localResidualNorm, localResidualNormalizer, residualNorm ); + physicsSolverBaseKernels::L2ResidualNormHelper::computeGlobalNorm( localResidualNorm, localResidualNormalizer, residualNorm ); } if( getLogLevel() >= 1 && logger::internal::rank == 0 ) @@ -809,5 +836,5 @@ void CompositionalMultiphaseHybridFVM::updatePhaseMobility( ObjectManagerBase & relperm ); } -REGISTER_CATALOG_ENTRY( SolverBase, CompositionalMultiphaseHybridFVM, std::string const &, Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, CompositionalMultiphaseHybridFVM, std::string const &, Group * const ) } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.hpp index 12e85758df4..d133610a7b1 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,6 @@ #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASEHYBRIDFVM_HPP_ #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVMKernels.hpp" namespace geos { @@ -69,7 +69,7 @@ class CompositionalMultiphaseHybridFVM : public CompositionalMultiphaseBase */ static string catalogName() { return "CompositionalMultiphaseHybridFVM"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.cpp index 137a760069d..254c2a72a17 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,19 +19,16 @@ #include "CompositionalMultiphaseStatistics.hpp" +#include "mesh/DomainPartition.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" #include "constitutive/solid/CoupledSolidBase.hpp" -#include "finiteVolume/FiniteVolumeManager.hpp" -#include "finiteVolume/FluxApproximationBase.hpp" -#include "mainInterface/ProblemManager.hpp" -#include "physicsSolvers/PhysicsSolverManager.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseFVMKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp" +#include "physicsSolvers/fluidFlow/LogLevelsInfo.hpp" namespace geos @@ -59,11 +57,14 @@ CompositionalMultiphaseStatistics::CompositionalMultiphaseStatistics( const stri setApplyDefaultValue( 1e-6 ). setInputFlag( InputFlags::OPTIONAL ). setDescription( "Flag to decide whether a phase is considered mobile (when the relperm is above the threshold) or immobile (when the relperm is below the threshold) in metric 2" ); + + addLogLevel< logInfo::CFL >(); + addLogLevel< logInfo::Statistics >(); } -void CompositionalMultiphaseStatistics::postProcessInput() +void CompositionalMultiphaseStatistics::postInputInitialization() { - Base::postProcessInput(); + Base::postInputInitialization(); if( dynamicCast< CompositionalMultiphaseHybridFVM * >( m_solver ) && m_computeCFLNumbers != 0 ) { @@ -115,8 +116,7 @@ void CompositionalMultiphaseStatistics::registerDataOnMesh( Group & meshBodies ) if( m_writeCSV > 0 && MpiWrapper::commRank() == 0 ) { std::ofstream outputFile( m_outputDir + "/" + regionNames[i] + ".csv" ); - integer const useMass = m_solver->getReference< integer >( CompositionalMultiphaseBase::viewKeyStruct::useMassFlagString() ); - string const massUnit = useMass ? "kg" : "mol"; + string_view massUnit = units::getSymbol( m_solver->getMassUnit() ); outputFile << "Time [s],Min pressure [Pa],Average pressure [Pa],Max pressure [Pa],Min delta pressure [Pa],Max delta pressure [Pa]," << "Min temperature [Pa],Average temperature [Pa],Max temperature [Pa],Total dynamic pore volume [rm^3]"; @@ -305,7 +305,7 @@ void CompositionalMultiphaseStatistics::computeRegionStatistics( real64 const ti subRegionImmobilePhaseMass.toView(), subRegionComponentMass.toView() ); - ElementRegionBase & region = elemManager.getRegion( subRegion.getParent().getParent().getName() ); + ElementRegionBase & region = elemManager.getRegion( ElementRegionBase::getParentRegion( subRegion ).getName() ); RegionStatistics & regionStatistics = region.getReference< RegionStatistics >( viewKeyStruct::regionStatisticsString() ); regionStatistics.averagePressure += subRegionAvgPresNumerator; @@ -391,8 +391,8 @@ void CompositionalMultiphaseStatistics::computeRegionStatistics( real64 const ti { regionStatistics.averagePressure = 0.0; regionStatistics.averageTemperature = 0.0; - GEOS_LOG_LEVEL_RANK_0( 1, getName() << ", " << regionNames[i] - << ": Cannot compute average pressure because region pore volume is zero." ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{}, {}: Cannot compute average pressure because region pore volume is zero.", getName(), regionNames[i] ) ); } @@ -405,36 +405,47 @@ void CompositionalMultiphaseStatistics::computeRegionStatistics( real64 const ti mobilePhaseMass[ip] = regionStatistics.phaseMass[ip] - regionStatistics.immobilePhaseMass[ip]; } - integer const useMass = m_solver->getReference< integer >( CompositionalMultiphaseBase::viewKeyStruct::useMassFlagString() ); - string const massUnit = useMass ? "kg" : "mol"; - - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Pressure (min, average, max): {}, {}, {} Pa", - getName(), regionNames[i], time, regionStatistics.minPressure, regionStatistics.averagePressure, regionStatistics.maxPressure ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Delta pressure (min, max): {}, {} Pa", - getName(), regionNames[i], time, regionStatistics.minDeltaPressure, regionStatistics.maxDeltaPressure ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Temperature (min, average, max): {}, {}, {} K", - getName(), regionNames[i], time, regionStatistics.minTemperature, regionStatistics.averageTemperature, regionStatistics.maxTemperature ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Total dynamic pore volume: {} rm^3", - getName(), regionNames[i], time, regionStatistics.totalPoreVolume ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Phase dynamic pore volume: {} rm^3", - getName(), regionNames[i], time, regionStatistics.phasePoreVolume ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Phase mass: {} {}", - getName(), regionNames[i], time, regionStatistics.phaseMass, massUnit ) ); - - // metric 1: trapping computed with the Land trapping coefficient (similar to Eclipse) - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Trapped phase mass (metric 1): {} {}", - getName(), regionNames[i], time, regionStatistics.trappedPhaseMass, massUnit ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Non-trapped phase mass (metric 1): {} {}", - getName(), regionNames[i], time, nonTrappedPhaseMass, massUnit ) ); + string_view massUnit = units::getSymbol( m_solver->getMassUnit() ); + string statPrefix = GEOS_FMT( "{}, {} (time {} s):", getName(), regionNames[i], time ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Pressure (min, average, max): {}, {}, {} Pa", + statPrefix, regionStatistics.minPressure, regionStatistics.averagePressure, regionStatistics.maxPressure ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Delta pressure (min, max): {}, {} Pa", + statPrefix, regionStatistics.minDeltaPressure, regionStatistics.maxDeltaPressure ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Temperature (min, average, max): {}, {}, {} K", + statPrefix, regionStatistics.minTemperature, regionStatistics.averageTemperature, + regionStatistics.maxTemperature ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Total dynamic pore volume: {} rm^3", + statPrefix, regionStatistics.totalPoreVolume ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Phase dynamic pore volume: {} rm^3", + statPrefix, regionStatistics.phasePoreVolume ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Phase mass: {} {}", + statPrefix, regionStatistics.phaseMass, massUnit ) ); + + // metric 1: trapping computed with the Land trapping coefficient + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Trapped phase mass (metric 1): {} {}", + statPrefix, regionStatistics.trappedPhaseMass, massUnit ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Non-trapped phase mass (metric 1): {} {}", + statPrefix, nonTrappedPhaseMass, massUnit ) ); // metric 2: immobile phase mass computed with a threshold on relative permeability - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Immobile phase mass (metric 2): {} {}", - getName(), regionNames[i], time, regionStatistics.immobilePhaseMass, massUnit ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Mobile phase mass (metric 2): {} {}", - getName(), regionNames[i], time, mobilePhaseMass, massUnit ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Immobile phase mass (metric 2): {} {}", + statPrefix, regionStatistics.immobilePhaseMass, massUnit ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Mobile phase mass (metric 2): {} {}", + statPrefix, mobilePhaseMass, massUnit ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Component mass: {} {}", - getName(), regionNames[i], time, regionStatistics.componentMass, massUnit ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Component mass: {} {}", + statPrefix, regionStatistics.componentMass, massUnit ) ); if( m_writeCSV > 0 && MpiWrapper::commRank() == 0 ) { @@ -473,8 +484,8 @@ void CompositionalMultiphaseStatistics::computeCFLNumbers( real64 const time, real64 maxPhaseCFL, maxCompCFL; m_solver->computeCFLNumbers( domain, dt, maxPhaseCFL, maxCompCFL ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{} (time {} s): Max phase CFL number: {}", getName(), time, maxPhaseCFL ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{} (time {} s): Max component CFL number: {}", getName(), time, maxCompCFL ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::CFL, GEOS_FMT( "{} (time {} s): Max phase CFL number: {}", getName(), time, maxPhaseCFL ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::CFL, GEOS_FMT( "{} (time {} s): Max component CFL number: {}", getName(), time, maxCompCFL ) ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.hpp index a4a46ad166a..bee1a2468a4 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -141,7 +142,7 @@ class CompositionalMultiphaseStatistics : public FieldStatisticsBase< Compositio real64 const dt, DomainPartition & domain ) const; - void postProcessInput() override; + void postInputInitialization() override; void registerDataOnMesh( Group & meshBodies ) override; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp index 12aca3a1227..3af76d4928d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/fluidFlow/DissipationCompositionalMultiphaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/DissipationCompositionalMultiphaseFVMKernels.hpp deleted file mode 100644 index 54cf3fb9ed9..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/DissipationCompositionalMultiphaseFVMKernels.hpp +++ /dev/null @@ -1,403 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file DissipationCompositionalMultiphaseFVMKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_DISSIPATIONCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_DISSIPATIONCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP - -#include "IsothermalCompositionalMultiphaseFVMKernels.hpp" -#include "constitutive/solid/porosity/PorosityBase.hpp" -#include "constitutive/solid/porosity/PorosityFields.hpp" - -namespace geos -{ - -namespace dissipationCompositionalMultiphaseFVMKernels -{ - -using namespace constitutive; - -static constexpr integer newtonContinuationCutoffIteration = 5; -static constexpr real64 initialDirectionalCoef = 100; -static constexpr real64 multiplierDirectionalCoef = 1000; - -/******************************** FaceBasedAssemblyKernel ********************************/ - -/** - * @class FaceBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @brief Define the interface for the assembly kernel in charge of flux terms - */ -template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > -class FaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > -{ -public: - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelBase; - using DofNumberAccessor = AbstractBase::DofNumberAccessor; - using CompFlowAccessors = AbstractBase::CompFlowAccessors; - using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; - using CapPressureAccessors = AbstractBase::CapPressureAccessors; - using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; - - using AbstractBase::m_dt; - using AbstractBase::m_gravCoef; - using AbstractBase::m_dCompFrac_dCompDens; - - using Base = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - using Base::numComp; - using Base::numDof; - using Base::numEqn; - using Base::numFluxSupportPoints; - using Base::m_permeability; - using Base::m_dPerm_dPres; - - using DissCompFlowAccessors = - StencilAccessors< fields::flow::pressure_n, - fields::flow::globalCompDensity, - fields::flow::globalCompFraction, - fields::elementVolume >; - - using PorosityAccessors = - StencilMaterialAccessors< PorosityBase, fields::porosity::porosity_n >; - - using Deriv = multifluid::DerivativeOffset; - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] hasCapPressure flag specifying whether capillary pressure is used or not - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dofNumberAccessor accessor for the dofs numbers - * @param[in] compFlowAccessor accessor for wrappers registered by the solver - * @param[in] dissCompFlowAccessor accessor for wrappers registered by the solver needed for dissipation - * @param[in] multiFluidAccessor accessor for wrappers registered by the multifluid model - * @param[in] capPressureAccessors accessor for wrappers registered by the cap pressure model - * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model - * @param[in] porosityAccessors accessor for wrappers registered by the porosity model - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - * @param[in] omega omega coefficient for DBC - * @param[in] curNewton current Newton iteration number - * @param[in] continuation flag indicating if continuation is used or not - * @param[in] miscible flag to trigger some treatment for miscible cases - * @param[in] kappamin minimum value for kappa coefficient in DBC - * @param[in] contMultiplier continuation multiplier factor (should be < 1) - */ - FaceBasedAssemblyKernel( integer const numPhases, - globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - DissCompFlowAccessors const & dissCompFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - CapPressureAccessors const & capPressureAccessors, - PermeabilityAccessors const & permeabilityAccessors, - PorosityAccessors const & porosityAccessors, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags, - real64 const omega, - integer const curNewton, - integer const continuation, - integer const miscible, - real64 const kappamin, - real64 const contMultiplier ) - : Base( numPhases, - rankOffset, - stencilWrapper, - dofNumberAccessor, - compFlowAccessors, - multiFluidAccessors, - capPressureAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs, - kernelFlags ), - m_pres_n( dissCompFlowAccessors.get( fields::flow::pressure_n {} ) ), - m_porosity_n( porosityAccessors.get( fields::porosity::porosity_n {} ) ), - m_volume( dissCompFlowAccessors.get( fields::elementVolume {} ) ), - m_compFrac( dissCompFlowAccessors.get( fields::flow::globalCompFraction {} ) ), - m_omegaDBC( omega ), - m_miscibleDBC( miscible ) - { - /// Step 1. Calculate the continuation parameter based on the current Newton iteration - m_kappaDBC = 1.0; // default value - - if( continuation ) // if continuation is enabled - { - if( curNewton >= newtonContinuationCutoffIteration ) - { - m_kappaDBC = kappamin; - } - else - { - for( int mp = 0; mp < curNewton; mp++ ) - { - m_kappaDBC *= contMultiplier; - } - m_kappaDBC = std::max( m_kappaDBC, kappamin ); - } - } - } - - /** - * @brief Compute the local flux contributions to the residual and Jacobian, including dissipation - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void computeFlux( localIndex const iconn, - typename Base::StackVariables & stack ) const - { - // *********************************************** - // First, we call the base computeFlux to compute: - // 1) compFlux and its derivatives, - // - // We use the lambda below (called **inside** the phase loop of the base computeFlux) to compute dissipation terms - Base::computeFlux( iconn, stack, [&] ( integer const ip, - localIndex const (&k)[2], - localIndex const (&seri)[2], - localIndex const (&sesri)[2], - localIndex const (&sei)[2], - localIndex const connectionIndex, - localIndex const k_up, - localIndex const er_up, - localIndex const esr_up, - localIndex const ei_up, - real64 const & potGrad, - real64 const & phaseFlux, - real64 const (&dPhaseFlux_dP)[2], - real64 const (&dPhaseFlux_dC)[2][numComp] ) - { - GEOS_UNUSED_VAR( k_up, potGrad, phaseFlux, dPhaseFlux_dP, dPhaseFlux_dC, er_up, esr_up, ei_up ); - - /// Storing dissipation flux and its derivatives locally - real64 dissFlux[numComp]{}; - real64 dDissFlux_dP[numFluxSupportPoints][numComp]{}; - real64 dDissFlux_dC[numFluxSupportPoints][numComp][numComp]{}; - real64 fluxPointCoef[numFluxSupportPoints] = {1.0, -1.0}; // for gradients - - real64 viscosityMult[3] = {1.0, 1.0, 1.0}; // for viscosity - - /// Step 2. Collect all contributions - real64 poreVolume_n = 0.0; // Pore volume contribution - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - poreVolume_n += m_volume[seri[ke]][sesri[ke]][sei[ke]] * m_porosity_n[seri[ke]][sesri[ke]][sei[ke]][0]; - } - poreVolume_n /= numFluxSupportPoints; - - // potential gradient contribution - // pressure - real64 pressure_gradient = 0; - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - pressure_gradient += fluxPointCoef[ke] * m_pres_n[seri[ke]][sesri[ke]][sei[ke]]; - - real64 const potential_gradient = LvArray::math::abs( pressure_gradient ); - - real64 grad_depth = 0; - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - grad_depth += fluxPointCoef[ke] * m_gravCoef[seri[ke]][sesri[ke]][sei[ke]]; - } - - // bias towards x and y direction for miscible - /* The point of this "directional coefficient" was to add less dissipation flux in the direction of gravity and - more in all other directions. These hard-coded values of 1000 and 100 were picked by some tuning and as - expected are not robust. Further research/testing is needed to generalize this idea. - */ - real64 directional_coef = 1.0; - if( m_miscibleDBC ) - { - directional_coef = initialDirectionalCoef; - if( LvArray::math::abs( grad_depth ) > 0.0 ) - { - real64 const d2 = LvArray::math::abs( grad_depth * grad_depth ); - if( multiplierDirectionalCoef / d2 < initialDirectionalCoef ) - directional_coef = multiplierDirectionalCoef / d2; - } - } - - // multiplier with all contributions - real64 const multiplier = m_kappaDBC * m_omegaDBC / poreVolume_n * m_dt * potential_gradient * directional_coef; - - /// Step 3. Compute the dissipation flux and its derivative - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - real64 const coef = multiplier * viscosityMult[ip] * stack.transmissibility[connectionIndex][ke]; - for( integer ic = 0; ic < numComp; ++ic ) - { - localIndex const er = seri[ke]; - localIndex const esr = sesri[ke]; - localIndex const ei = sei[ke]; - - // composition gradient contribution to the dissipation flux - dissFlux[ic] += coef * m_compFrac[er][esr][ei][ic]; - - dDissFlux_dP[ke][ic] = 0; // no dependency on pressure at n+1, compFrad is global component fraction (z_c) - - for( integer jc = 0; jc < numComp; ++jc ) - { - // composition gradient derivative with respect to component density contribution to the dissipation flux - dDissFlux_dC[ke][ic][jc] += coef * m_dCompFrac_dCompDens[er][esr][ei][ic][jc]; - } - } - } - - /// Step 4: add the dissipation flux and its derivatives to the residual and Jacobian - for( integer ic = 0; ic < numComp; ++ic ) - { - integer const eqIndex0 = k[0] * numEqn + ic; - integer const eqIndex1 = k[1] * numEqn + ic; - - stack.localFlux[eqIndex0] += m_dt * dissFlux[ic]; - stack.localFlux[eqIndex1] -= m_dt * dissFlux[ic]; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - localIndex const localDofIndexPres = k[ke] * numDof; - stack.localFluxJacobian[eqIndex0][localDofIndexPres] += m_dt * dDissFlux_dP[ke][ic]; - stack.localFluxJacobian[eqIndex1][localDofIndexPres] -= m_dt * dDissFlux_dP[ke][ic]; - - for( integer jc = 0; jc < numComp; ++jc ) - { - localIndex const localDofIndexComp = localDofIndexPres + jc + 1; - stack.localFluxJacobian[eqIndex0][localDofIndexComp] += m_dt * dDissFlux_dC[ke][ic][jc]; - stack.localFluxJacobian[eqIndex1][localDofIndexComp] -= m_dt * dDissFlux_dC[ke][ic][jc]; - } - } - } - - } ); // end call to Base::computeFlux - - } - -protected: - - /// Views on flow properties at the previous converged time step - ElementViewConst< arrayView1d< real64 const > > const m_pres_n; - ElementViewConst< arrayView2d< real64 const > > const m_porosity_n; - - ElementViewConst< arrayView1d< real64 const > > const m_volume; - ElementViewConst< arrayView2d< real64 const, compflow::USD_COMP > > const m_compFrac; - - // DBC specific parameters - // input - real64 m_omegaDBC; - integer m_miscibleDBC; - // computed - real64 m_kappaDBC; -}; - -/** - * @class FaceBasedAssemblyKernelFactory - */ -class FaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @param[in] numComps the number of fluid components - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey string to get the element degrees of freedom numbers - * @param[in] hasCapPressure flag specifying whether capillary pressure is used or not - * @param[in] solverName name of the solver (to name accessors) - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY, typename STENCILWRAPPER > - static void - createAndLaunch( integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - string const & dofKey, - integer const hasCapPressure, - integer const useTotalMassEquation, - string const & solverName, - ElementRegionManager const & elemManager, - STENCILWRAPPER const & stencilWrapper, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - real64 const omega, - integer const curNewton, - integer const continuation, - integer const miscible, - real64 const kappamin, - real64 const contMultiplier ) - { - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) - { - integer constexpr NUM_COMP = NC(); - integer constexpr NUM_DOF = NC() + 1; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags; - if( hasCapPressure ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::CapPressure ); - if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::TotalMassEquation ); - - using KERNEL_TYPE = FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - typename KERNEL_TYPE::CompFlowAccessors compFlowAccessors( elemManager, solverName ); - typename KERNEL_TYPE::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); - typename KERNEL_TYPE::CapPressureAccessors capPressureAccessors( elemManager, solverName ); - typename KERNEL_TYPE::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); - typename KERNEL_TYPE::PorosityAccessors porosityAccessors( elemManager, solverName ); - typename KERNEL_TYPE::DissCompFlowAccessors dissCompFlowAccessors( elemManager, solverName ); - - KERNEL_TYPE kernel( numPhases, rankOffset, stencilWrapper, dofNumberAccessor, compFlowAccessors, dissCompFlowAccessors, - multiFluidAccessors, capPressureAccessors, permeabilityAccessors, porosityAccessors, - dt, localMatrix, localRhs, kernelFlags, omega, curNewton, continuation, miscible, kappamin, contMultiplier ); - KERNEL_TYPE::template launch< POLICY >( stencilWrapper.size(), kernel ); - } ); - } -}; - -} // namespace DissipationCompositionalMultiphaseFVMKernels - -} // namespace geos - - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_DISSIPATIONCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.cpp index 26aec0a2c1a..c081f20d4ce 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,6 +22,7 @@ #include "constitutive/ConstitutivePassThru.hpp" #include "constitutive/permeability/PermeabilityFields.hpp" #include "constitutive/solid/SolidInternalEnergy.hpp" +#include "constitutive/contact/HydraulicApertureBase.hpp" #include "discretizationMethods/NumericalMethodsManager.hpp" #include "fieldSpecification/AquiferBoundaryCondition.hpp" #include "fieldSpecification/EquilibriumInitialCondition.hpp" @@ -29,10 +31,9 @@ #include "finiteVolume/FiniteVolumeManager.hpp" #include "finiteVolume/FluxApproximationBase.hpp" #include "mesh/DomainPartition.hpp" -#include "physicsSolvers/fluidFlow/FluxKernelsHelper.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/FlowSolverBaseKernels.hpp" -#include "physicsSolvers/NonlinearSolverParameters.hpp" +#include "physicsSolvers/fluidFlow/kernels/MinPoreVolumeMaxPorosityKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/StencilWeightsUpdateKernel.hpp" namespace geos { @@ -40,29 +41,6 @@ namespace geos using namespace dataRepository; using namespace constitutive; -template< typename POROUSWRAPPER_TYPE > -void updatePorosityAndPermeabilityFromPressureAndTemperature( POROUSWRAPPER_TYPE porousWrapper, - CellElementSubRegion & subRegion, - arrayView1d< real64 const > const & pressure, - arrayView1d< real64 const > const & pressure_n, - arrayView1d< real64 const > const & temperature, - arrayView1d< real64 const > const & temperature_n ) -{ - forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_DEVICE ( localIndex const k ) - { - for( localIndex q = 0; q < porousWrapper.numGauss(); ++q ) - { - porousWrapper.updateStateFromPressureAndTemperature( k, q, - pressure[k], - pressure[k], // will not be used - pressure_n[k], // will not be used - temperature[k], - temperature[k], // will not be used - temperature_n[k] ); // will not be used - } - } ); -} - template< typename POROUSWRAPPER_TYPE > void updatePorosityAndPermeabilityFromPressureAndTemperature( POROUSWRAPPER_TYPE porousWrapper, CellElementSubRegion & subRegion, @@ -75,7 +53,6 @@ void updatePorosityAndPermeabilityFromPressureAndTemperature( POROUSWRAPPER_TYPE { forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_DEVICE ( localIndex const k ) { - for( localIndex q = 0; q < porousWrapper.numGauss(); ++q ) { porousWrapper.updateStateFromPressureAndTemperature( k, q, @@ -111,10 +88,13 @@ void updatePorosityAndPermeabilityFromPressureAndAperture( POROUSWRAPPER_TYPE po FlowSolverBase::FlowSolverBase( string const & name, Group * const parent ): - SolverBase( name, parent ), + PhysicsSolverBase( name, parent ), m_numDofPerCell( 0 ), m_isThermal( 0 ), - m_isFixedStressPoromechanicsUpdate( false ) + m_keepVariablesConstantDuringInitStep( 0 ), + m_isFixedStressPoromechanicsUpdate( false ), + m_isJumpStabilized( false ), + m_isLaggingFractureStencilWeightsUpdate( 0 ) { this->registerWrapper( viewKeyStruct::isThermalString(), &m_isThermal ). setApplyDefaultValue( 0 ). @@ -145,12 +125,12 @@ FlowSolverBase::FlowSolverBase( string const & name, setDescription( "Maximum (absolute) temperature change in a sequential iteration, used for outer loop convergence check" ); // allow the user to select a norm - getNonlinearSolverParameters().getWrapper< solverBaseKernels::NormType >( NonlinearSolverParameters::viewKeysStruct::normTypeString() ).setInputFlag( InputFlags::OPTIONAL ); + getNonlinearSolverParameters().getWrapper< physicsSolverBaseKernels::NormType >( NonlinearSolverParameters::viewKeysStruct::normTypeString() ).setInputFlag( InputFlags::OPTIONAL ); } void FlowSolverBase::registerDataOnMesh( Group & meshBodies ) { - SolverBase::registerDataOnMesh( meshBodies ); + PhysicsSolverBase::registerDataOnMesh( meshBodies ); forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, MeshLevel & mesh, @@ -185,6 +165,11 @@ void FlowSolverBase::registerDataOnMesh( Group & meshBodies ) { subRegion.registerField< fields::flow::temperature_k >( getName() ); // needed for the fixed-stress porosity update } + if( m_isThermal ) + { + subRegion.registerField< fields::flow::energy >( getName() ); + subRegion.registerField< fields::flow::energy_n >( getName() ); + } } ); elemManager.forElementSubRegionsComplete< SurfaceElementSubRegion >( [&]( localIndex const, @@ -202,9 +187,6 @@ void FlowSolverBase::registerDataOnMesh( Group & meshBodies ) subRegion.registerField< fields::flow::hydraulicAperture >( getName() ). setApplyDefaultValue( faceRegion.getDefaultAperture() ); - subRegion.registerField< fields::flow::minimumHydraulicAperture >( getName() ). - setApplyDefaultValue( faceRegion.getDefaultAperture() ); - } ); FaceManager & faceManager = mesh.getFaceManager(); @@ -243,6 +225,13 @@ void FlowSolverBase::saveConvergedState( ElementSubRegionBase & subRegion ) cons arrayView1d< real64 > const temp_n = subRegion.template getField< fields::flow::temperature_n >(); temp_n.setValues< parallelDevicePolicy<> >( temp ); + if( m_isThermal ) + { + arrayView1d< real64 const > const energy = subRegion.template getField< fields::flow::energy >(); + arrayView1d< real64 > const energy_n = subRegion.template getField< fields::flow::energy_n >(); + energy_n.setValues< parallelDevicePolicy<> >( energy ); + } + if( m_isFixedStressPoromechanicsUpdate ) { arrayView1d< real64 > const pres_k = subRegion.template getField< fields::flow::pressure_k >(); @@ -252,41 +241,54 @@ void FlowSolverBase::saveConvergedState( ElementSubRegionBase & subRegion ) cons } } -void FlowSolverBase::saveSequentialIterationState( ElementSubRegionBase & subRegion ) const +void FlowSolverBase::saveSequentialIterationState( DomainPartition & domain ) { GEOS_ASSERT( m_isFixedStressPoromechanicsUpdate ); - arrayView1d< real64 const > const pres = subRegion.template getField< fields::flow::pressure >(); - arrayView1d< real64 const > const temp = subRegion.template getField< fields::flow::temperature >(); - arrayView1d< real64 > const pres_k = subRegion.template getField< fields::flow::pressure_k >(); - arrayView1d< real64 > const temp_k = subRegion.template getField< fields::flow::temperature_k >(); - pres_k.setValues< parallelDevicePolicy<> >( pres ); - temp_k.setValues< parallelDevicePolicy<> >( temp ); -} - -void FlowSolverBase::saveSequentialIterationState( DomainPartition & domain ) const -{ - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + real64 maxPresChange = 0.0; + real64 maxTempChange = 0.0; + forDiscretizationOnMeshTargets ( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { - mesh.getElemManager().forElementSubRegions( regionNames, - [&]( localIndex const, - ElementSubRegionBase & subRegion ) + mesh.getElemManager().forElementSubRegions ( regionNames, + [&]( localIndex const, + ElementSubRegionBase & subRegion ) { - saveSequentialIterationState( subRegion ); + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + + arrayView1d< real64 const > const pres = subRegion.getField< fields::flow::pressure >(); + arrayView1d< real64 > const pres_k = subRegion.getField< fields::flow::pressure_k >(); + arrayView1d< real64 const > const temp = subRegion.getField< fields::flow::temperature >(); + arrayView1d< real64 > const temp_k = subRegion.getField< fields::flow::temperature_k >(); + + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxPresChange( 0.0 ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxTempChange( 0.0 ); + + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( ghostRank[ei] < 0 ) + { + subRegionMaxPresChange.max( LvArray::math::abs( pres[ei] - pres_k[ei] ) ); + pres_k[ei] = pres[ei]; + subRegionMaxTempChange.max( LvArray::math::abs( temp[ei] - temp_k[ei] ) ); + temp_k[ei] = temp[ei]; + } + } ); + + maxPresChange = LvArray::math::max( maxPresChange, subRegionMaxPresChange.get() ); + maxTempChange = LvArray::math::max( maxTempChange, subRegionMaxTempChange.get() ); } ); } ); -} -void FlowSolverBase::enableFixedStressPoromechanicsUpdate() -{ - m_isFixedStressPoromechanicsUpdate = true; + // store to be later used in convergence check + m_sequentialPresChange = MpiWrapper::max( maxPresChange ); + m_sequentialTempChange = m_isThermal ? MpiWrapper::max( maxTempChange ) : 0.0; } void FlowSolverBase::setConstitutiveNamesCallSuper( ElementSubRegionBase & subRegion ) const { - SolverBase::setConstitutiveNamesCallSuper( subRegion ); + PhysicsSolverBase::setConstitutiveNamesCallSuper( subRegion ); subRegion.registerWrapper< string >( viewKeyStruct::fluidNamesString() ). setPlotLevel( PlotLevel::NOPLOT ). @@ -337,7 +339,7 @@ void FlowSolverBase::setConstitutiveNames( ElementSubRegionBase & subRegion ) co void FlowSolverBase::initializePreSubGroups() { - SolverBase::initializePreSubGroups(); + PhysicsSolverBase::initializePreSubGroups(); DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); @@ -376,8 +378,8 @@ void FlowSolverBase::validatePoreVolumes( DomainPartition const & domain ) const MeshLevel const & mesh, arrayView1d< string const > const & regionNames ) { - mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, - CellElementSubRegion const & subRegion ) + mesh.getElemManager().forElementSubRegions< ElementSubRegionBase >( regionNames, [&]( localIndex const, + ElementSubRegionBase const & subRegion ) { string const & solidName = subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ); @@ -434,7 +436,7 @@ void FlowSolverBase::validatePoreVolumes( DomainPartition const & domain ) const void FlowSolverBase::initializePostInitialConditionsPreSubGroups() { - SolverBase::initializePostInitialConditionsPreSubGroups(); + PhysicsSolverBase::initializePostInitialConditionsPreSubGroups(); DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); @@ -443,6 +445,12 @@ void FlowSolverBase::initializePostInitialConditionsPreSubGroups() arrayView1d< string const > const & regionNames ) { precomputeData( mesh, regionNames ); + + FieldIdentifiers fieldsToBeSync; + fieldsToBeSync.addElementFields( { fields::flow::pressure::key(), fields::flow::temperature::key() }, + regionNames ); + + CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync, mesh, domain.getNeighbors(), false ); } ); } @@ -479,6 +487,97 @@ void FlowSolverBase::precomputeData( MeshLevel & mesh, } } +void FlowSolverBase::initializeState( DomainPartition & domain ) +{ + // Compute hydrostatic equilibrium in the regions for which corresponding field specification tag has been specified + computeHydrostaticEquilibrium( domain ); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + initializePorosityAndPermeability( mesh, regionNames ); + initializeHydraulicAperture( mesh, regionNames ); + + // Initialize primary variables from applied initial conditions + initializeFluidState( mesh, regionNames ); + + // Initialize the rock thermal quantities: conductivity and solid internal energy + // Note: + // - This must be called after updatePorosityAndPermeability and updatePhaseVolumeFraction + // - This step depends on porosity and phaseVolFraction + if( m_isThermal ) + { + initializeThermalState( mesh, regionNames ); + } + + // Save initial pressure and temperature fields + saveInitialPressureAndTemperature( mesh, regionNames ); + } ); + + // report to the user if some pore volumes are very small + // note: this function is here because: 1) porosity has been initialized and 2) NTG has been applied + validatePoreVolumes( domain ); +} + +void FlowSolverBase::initializePorosityAndPermeability( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) +{ + // Update porosity and permeability + // In addition, to avoid multiplying permeability/porosity bay netToGross in the assembly kernel, we do it once and for all here + mesh.getElemManager().forElementSubRegions< CellElementSubRegion, SurfaceElementSubRegion >( regionNames, [&]( localIndex const, + auto & subRegion ) + { + // Apply netToGross to reference porosity and horizontal permeability + CoupledSolidBase const & porousSolid = + getConstitutiveModel< CoupledSolidBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ) ); + PermeabilityBase const & permeability = + getConstitutiveModel< PermeabilityBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::permeabilityNamesString() ) ); + arrayView1d< real64 const > const netToGross = subRegion.template getField< fields::flow::netToGross >(); + porousSolid.scaleReferencePorosity( netToGross ); + permeability.scaleHorizontalPermeability( netToGross ); + + // in some initializeState versions it uses newPorosity, so let's run updatePorosityAndPermeability to compute something + saveConvergedState( subRegion ); // necessary for a meaningful porosity update in sequential schemes + updatePorosityAndPermeability( subRegion ); + porousSolid.initializeState(); + + // run final update + saveConvergedState( subRegion ); // necessary for a meaningful porosity update in sequential schemes + updatePorosityAndPermeability( subRegion ); + + // Save the computed porosity into the old porosity + // Note: + // - This must be called after updatePorosityAndPermeability + // - This step depends on porosity + porousSolid.saveConvergedState(); + } ); +} + +void FlowSolverBase::initializeHydraulicAperture( MeshLevel & mesh, const arrayView1d< const string > & regionNames ) +{ + mesh.getElemManager().forElementRegions< SurfaceElementRegion >( regionNames, + [&]( localIndex const, + SurfaceElementRegion & region ) + { + region.forElementSubRegions< SurfaceElementSubRegion >( [&]( SurfaceElementSubRegion & subRegion ) + { subRegion.getWrapper< real64_array >( fields::flow::hydraulicAperture::key()).setApplyDefaultValue( region.getDefaultAperture()); } ); + } ); +} + +void FlowSolverBase::saveInitialPressureAndTemperature( MeshLevel & mesh, const arrayView1d< const string > & regionNames ) +{ + mesh.getElemManager().forElementSubRegions( regionNames, [&]( localIndex const, + ElementSubRegionBase & subRegion ) + { + arrayView1d< real64 const > const pres = subRegion.getField< fields::flow::pressure >(); + arrayView1d< real64 > const initPres = subRegion.getField< fields::flow::initialPressure >(); + arrayView1d< real64 const > const temp = subRegion.getField< fields::flow::temperature >(); + arrayView1d< real64 > const initTemp = subRegion.template getField< fields::flow::initialTemperature >(); + initPres.setValues< parallelDevicePolicy<> >( pres ); + initTemp.setValues< parallelDevicePolicy<> >( temp ); + } ); +} + void FlowSolverBase::updatePorosityAndPermeability( CellElementSubRegion & subRegion ) const { GEOS_MARK_FUNCTION; @@ -495,23 +594,16 @@ void FlowSolverBase::updatePorosityAndPermeability( CellElementSubRegion & subRe constitutive::ConstitutivePassThru< CoupledSolidBase >::execute( porousSolid, [=, &subRegion] ( auto & castedPorousSolid ) { typename TYPEOFREF( castedPorousSolid ) ::KernelWrapper porousWrapper = castedPorousSolid.createKernelUpdates(); - - if( m_isFixedStressPoromechanicsUpdate ) // for sequential simulations + if( m_isFixedStressPoromechanicsUpdate ) { arrayView1d< real64 const > const & pressure_k = subRegion.getField< fields::flow::pressure_k >(); arrayView1d< real64 const > const & temperature_k = subRegion.getField< fields::flow::temperature_k >(); - - updatePorosityAndPermeabilityFromPressureAndTemperature( porousWrapper, subRegion, - pressure, pressure_k, pressure_n, - temperature, temperature_k, temperature_n ); + updatePorosityAndPermeabilityFromPressureAndTemperature( porousWrapper, subRegion, pressure, pressure_k, pressure_n, temperature, temperature_k, temperature_n ); } - else // for fully implicit simulations + else { - updatePorosityAndPermeabilityFromPressureAndTemperature( porousWrapper, subRegion, - pressure, pressure_n, - temperature, temperature_n ); + updatePorosityAndPermeabilityFromPressureAndTemperature( porousWrapper, subRegion, pressure, pressure_n, pressure_n, temperature, temperature_n, temperature_n ); } - } ); } @@ -582,12 +674,12 @@ void FlowSolverBase::findMinMaxElevationInEquilibriumTarget( DomainPartition & d maxElevation.data(), localMaxElevation.size(), MpiWrapper::getMpiOp( MpiWrapper::Reduction::Max ), - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); MpiWrapper::allReduce( localMinElevation.data(), minElevation.data(), localMinElevation.size(), MpiWrapper::getMpiOp( MpiWrapper::Reduction::Min ), - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); } void FlowSolverBase::computeSourceFluxSizeScalingFactor( real64 const & time, @@ -637,7 +729,7 @@ void FlowSolverBase::computeSourceFluxSizeScalingFactor( real64 const & time, bcAllSetsSize.data(), bcAllSetsSize.size(), MpiWrapper::getMpiOp( MpiWrapper::Reduction::Sum ), - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); } void FlowSolverBase::saveAquiferConvergedState( real64 const & time, @@ -704,14 +796,13 @@ void FlowSolverBase::saveAquiferConvergedState( real64 const & time, elemManager.constructFieldAccessor< fields::flow::gravityCoefficient >(); gravCoef.setName( getName() + "/accessors/" + fields::flow::gravityCoefficient::key() ); - real64 const targetSetSumFluxes = - fluxKernelsHelper::AquiferBCKernel::sumFluxes( stencil, - aquiferBCWrapper, - pressure.toNestedViewConst(), - pressure_n.toNestedViewConst(), - gravCoef.toNestedViewConst(), - time, - dt ); + real64 const targetSetSumFluxes = sumAquiferFluxes( stencil, + aquiferBCWrapper, + pressure.toNestedViewConst(), + pressure_n.toNestedViewConst(), + gravCoef.toNestedViewConst(), + time, + dt ); localIndex const aquiferIndex = aquiferNameToAquiferId.at( bc.getName() ); localSumFluxes[aquiferIndex] += targetSetSumFluxes; @@ -721,7 +812,7 @@ void FlowSolverBase::saveAquiferConvergedState( real64 const & time, globalSumFluxes.data(), localSumFluxes.size(), MpiWrapper::getMpiOp( MpiWrapper::Reduction::Sum ), - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); // Step 3: we are ready to save the summed fluxes for each individual aquifer @@ -732,13 +823,56 @@ void FlowSolverBase::saveAquiferConvergedState( real64 const & time, if( bc.getLogLevel() >= 1 ) { GEOS_LOG_RANK_0( GEOS_FMT( "{} {}: at time {} s, the boundary condition produces a volume of {} m3.", - AquiferBoundaryCondition::catalogName(), bc.getName(), + bc.getCatalogName(), bc.getName(), time + dt, dt * globalSumFluxes[aquiferIndex] ) ); } bc.saveConvergedState( dt * globalSumFluxes[aquiferIndex] ); } ); } +/** + * @brief Function to sum the aquiferBC fluxes (as later save them) at the end of the time step + * This function is applicable for both single-phase and multiphase flow + */ +real64 +FlowSolverBase::sumAquiferFluxes( BoundaryStencil const & stencil, + AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & presOld, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + real64 const & timeAtBeginningOfStep, + real64 const & dt ) +{ + using Order = BoundaryStencil::Order; + + BoundaryStencil::IndexContainerViewConstType const & seri = stencil.getElementRegionIndices(); + BoundaryStencil::IndexContainerViewConstType const & sesri = stencil.getElementSubRegionIndices(); + BoundaryStencil::IndexContainerViewConstType const & sefi = stencil.getElementIndices(); + BoundaryStencil::WeightContainerViewConstType const & weight = stencil.getWeights(); + + RAJA::ReduceSum< parallelDeviceReduce, real64 > targetSetSumFluxes( 0.0 ); + + forAll< parallelDevicePolicy<> >( stencil.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + localIndex const er = seri( iconn, Order::ELEM ); + localIndex const esr = sesri( iconn, Order::ELEM ); + localIndex const ei = sefi( iconn, Order::ELEM ); + real64 const areaFraction = weight( iconn, Order::ELEM ); + + // compute the aquifer influx rate using the pressure influence function and the aquifer props + real64 dAquiferVolFlux_dPres = 0.0; + real64 const aquiferVolFlux = aquiferBCWrapper.compute( timeAtBeginningOfStep, + dt, + pres[er][esr][ei], + presOld[er][esr][ei], + gravCoef[er][esr][ei], + areaFraction, + dAquiferVolFlux_dPres ); + targetSetSumFluxes += aquiferVolFlux; + } ); + return targetSetSumFluxes.get(); +} + void FlowSolverBase::prepareStencilWeights( DomainPartition & domain ) const { forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, @@ -749,6 +883,8 @@ void FlowSolverBase::prepareStencilWeights( DomainPartition & domain ) const FiniteVolumeManager const & fvManager = numericalMethodManager.getFiniteVolumeManager(); FluxApproximationBase const & fluxApprox = fvManager.getFluxApproximation( getDiscretizationName() ); ElementRegionManager::ElementViewAccessor< arrayView1d< real64 const > > hydraulicAperture = + m_isLaggingFractureStencilWeightsUpdate ? + mesh.getElemManager().constructViewAccessor< array1d< real64 >, arrayView1d< real64 const > >( fields::flow::aperture0::key() ) : mesh.getElemManager().constructViewAccessor< array1d< real64 >, arrayView1d< real64 const > >( fields::flow::hydraulicAperture::key() ); fluxApprox.forStencils< SurfaceElementStencil, FaceElementToCellStencil, EmbeddedSurfaceToCellStencil >( mesh, [&]( auto & stencil ) @@ -785,54 +921,82 @@ void FlowSolverBase::updateStencilWeights( DomainPartition & domain ) const } ); } -bool FlowSolverBase::checkSequentialSolutionIncrements( DomainPartition & domain ) const +bool FlowSolverBase::checkSequentialSolutionIncrements( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) const { - real64 maxPresChange = 0.0; - real64 maxTempChange = 0.0; - forDiscretizationOnMeshTargets ( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Convergence, GEOS_FMT( " {}: Max pressure change during outer iteration: {} Pa", + getName(), GEOS_FMT( "{:.{}f}", m_sequentialPresChange, 3 ) ) ); + + if( m_isThermal ) { - mesh.getElemManager().forElementSubRegions ( regionNames, - [&]( localIndex const, - ElementSubRegionBase & subRegion ) - { - arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Convergence, GEOS_FMT( " {}: Max temperature change during outer iteration: {} K", + getName(), GEOS_FMT( "{:.{}f}", m_sequentialTempChange, 3 ) ) ); + } - arrayView1d< real64 const > const pres = subRegion.getField< fields::flow::pressure >(); - arrayView1d< real64 const > const pres_k = subRegion.getField< fields::flow::pressure_k >(); - arrayView1d< real64 const > const temp = subRegion.getField< fields::flow::temperature >(); - arrayView1d< real64 const > const temp_k = subRegion.getField< fields::flow::temperature_k >(); + return (m_sequentialPresChange < m_maxSequentialPresChange) && (m_sequentialTempChange < m_maxSequentialTempChange); +} - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxPresChange( 0.0 ); - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxTempChange( 0.0 ); +string FlowSolverBase::BCMessage::generateMessage( string_view baseMessage, + string_view fieldName, string_view setName ) +{ + return GEOS_FMT( "{}\nCheck if you have added or applied the appropriate fields to " + "the FieldSpecification component with fieldName=\"{}\" " + "and setNames=\"{}\"\n", baseMessage, fieldName, setName ); +} - forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( ghostRank[ei] < 0 ) - { - subRegionMaxPresChange.max( LvArray::math::abs( pres[ei] - pres_k[ei] ) ); - subRegionMaxTempChange.max( LvArray::math::abs( temp[ei] - temp_k[ei] ) ); - } - } ); +string FlowSolverBase::BCMessage::pressureConflict( string_view regionName, string_view subRegionName, + string_view setName, string_view fieldName ) +{ + return generateMessage( GEOS_FMT( "Conflicting pressure boundary conditions on set {}/{}/{}", + regionName, subRegionName, setName ), fieldName, setName ); +} - maxPresChange = LvArray::math::max( maxPresChange, subRegionMaxPresChange.get() ); - maxTempChange = LvArray::math::max( maxTempChange, subRegionMaxTempChange.get() ); - } ); - } ); +string FlowSolverBase::BCMessage::temperatureConflict( string_view regionName, string_view subRegionName, + string_view setName, string_view fieldName ) +{ + return generateMessage( GEOS_FMT( "Conflicting temperature boundary conditions on set {}/{}/{}", + regionName, subRegionName, setName ), fieldName, setName ); +} - maxPresChange = MpiWrapper::max( maxPresChange ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max pressure change during outer iteration: {} Pa", - getName(), fmt::format( "{:.{}f}", maxPresChange, 3 ) ) ); +string FlowSolverBase::BCMessage::missingPressure( string_view regionName, string_view subRegionName, + string_view setName, string_view fieldName ) +{ + return generateMessage( GEOS_FMT( "Pressure boundary condition not prescribed on set {}/{}/{}", + regionName, subRegionName, setName ), fieldName, setName ); +} - if( m_isThermal ) - { - maxTempChange = MpiWrapper::max( maxTempChange ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max temperature change during outer iteration: {} K", - getName(), fmt::format( "{:.{}f}", maxTempChange, 3 ) ) ); - } +string FlowSolverBase::BCMessage::missingTemperature( string_view regionName, string_view subRegionName, + string_view setName, string_view fieldName ) +{ + return generateMessage( GEOS_FMT( "Temperature boundary condition not prescribed on set {}/{}/{}", + regionName, subRegionName, setName ), fieldName, setName ); +} + +string FlowSolverBase::BCMessage::conflictingComposition( int comp, string_view componentName, + string_view regionName, string_view subRegionName, + string_view setName, string_view fieldName ) +{ + return generateMessage( GEOS_FMT( "Conflicting {} composition (no.{}) for boundary conditions on set {}/{}/{}", + componentName, comp, regionName, subRegionName, setName ), + fieldName, setName ); +} - return (maxPresChange < m_maxSequentialPresChange) && (maxTempChange < m_maxSequentialTempChange); +string FlowSolverBase::BCMessage::invalidComponentIndex( int comp, + string_view fsName, + string_view fieldName ) +{ + return generateMessage( GEOS_FMT( "Invalid component index no.{} in boundary condition {}", + comp, fsName ), fieldName, fsName ); +} + +string FlowSolverBase::BCMessage::notAppliedOnRegion( int componentIndex, string_view componentName, + string_view regionName, string_view subRegionName, + string_view setName, string_view fieldName ) +{ + return generateMessage( GEOS_FMT( "Boundary condition not applied to {} component (no.{})" + "on region {}/{}/{}\n", + componentName, componentIndex, regionName, subRegionName, setName ), + fieldName, setName ); } } // namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.hpp index 0dac0799c6b..4352e059405 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,10 @@ #ifndef GEOS_PHYSICSSOLVERS_FINITEVOLUME_FLOWSOLVERBASE_HPP_ #define GEOS_PHYSICSSOLVERS_FINITEVOLUME_FLOWSOLVERBASE_HPP_ -#include "physicsSolvers/SolverBase.hpp" +#include "physicsSolvers/PhysicsSolverBase.hpp" +#include "common/Units.hpp" +#include "finiteVolume/BoundaryStencil.hpp" +#include "fieldSpecification/AquiferBoundaryCondition.hpp" namespace geos { @@ -30,8 +34,11 @@ namespace geos * Base class for finite volume fluid flow solvers. * Provides some common features */ -class FlowSolverBase : public SolverBase +class FlowSolverBase : public PhysicsSolverBase { + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + public: /// String used to form the solverName used to register single-physics solvers in CoupledSolver @@ -63,14 +70,16 @@ class FlowSolverBase : public SolverBase virtual void registerDataOnMesh( Group & MeshBodies ) override; - struct viewKeyStruct : SolverBase::viewKeyStruct + struct viewKeyStruct : PhysicsSolverBase::viewKeyStruct { // misc inputs static constexpr char const * fluidNamesString() { return "fluidNames"; } static constexpr char const * solidNamesString() { return "solidNames"; } static constexpr char const * permeabilityNamesString() { return "permeabilityNames"; } static constexpr char const * isThermalString() { return "isThermal"; } + static constexpr char const * inputTemperatureString() { return "temperature"; } static constexpr char const * solidInternalEnergyNamesString() { return "solidInternalEnergyNames"; } + static constexpr char const * thermalConductivityNamesString() { return "thermalConductivityNames"; } static constexpr char const * allowNegativePressureString() { return "allowNegativePressure"; } static constexpr char const * maxAbsolutePresChangeString() { return "maxAbsolutePressureChange"; } static constexpr char const * maxSequentialPresChangeString() { return "maxSequentialPressureChange"; } @@ -91,7 +100,9 @@ class FlowSolverBase : public SolverBase */ void updateStencilWeights( DomainPartition & domain ) const; - void enableFixedStressPoromechanicsUpdate(); + void enableFixedStressPoromechanicsUpdate() { m_isFixedStressPoromechanicsUpdate = true; } + + void enableJumpStabilization() { m_isJumpStabilized = true; } void updatePorosityAndPermeability( CellElementSubRegion & subRegion ) const; @@ -101,7 +112,43 @@ class FlowSolverBase : public SolverBase * @brief Utility function to save the iteration state (useful for sequential simulations) * @param[in] domain the domain partition */ - virtual void saveSequentialIterationState( DomainPartition & domain ) const override; + virtual void saveSequentialIterationState( DomainPartition & domain ) override; + + integer & isThermal() { return m_isThermal; } + + /** + * @return The unit in which we evaluate the amount of fluid per element (Mass or Mole). + */ + virtual units::Unit getMassUnit() const { return units::Unit::Mass; } + + /** + * @brief Function to activate the flag allowing negative pressure + */ + void allowNegativePressure() { m_allowNegativePressure = 1; } + + /** + * @brief Utility function to keep the flow variables during a time step (used in poromechanics simulations) + * @param[in] keepVariablesConstantDuringInitStep flag to tell the solver to freeze its primary variables during a time step + * @detail This function is meant to be called by a specific task before/after the initialization step + */ + void setKeepVariablesConstantDuringInitStep( bool const keepVariablesConstantDuringInitStep ) + { m_keepVariablesConstantDuringInitStep = keepVariablesConstantDuringInitStep; } + + virtual bool checkSequentialSolutionIncrements( DomainPartition & domain ) const override; + + void enableLaggingFractureStencilWeightsUpdate(){ m_isLaggingFractureStencilWeightsUpdate = 1; }; + + real64 sumAquiferFluxes( BoundaryStencil const & stencil, + AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & presOld, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + real64 const & timeAtBeginningOfStep, + real64 const & dt ); + + virtual void initializeFluidState( MeshLevel & mesh, const arrayView1d< const string > & regionNames ) { GEOS_UNUSED_VAR( mesh, regionNames ); } + + virtual void initializeThermalState( MeshLevel & mesh, const arrayView1d< const string > & regionNames ) { GEOS_UNUSED_VAR( mesh, regionNames ); } /** * @brief For each equilibrium initial condition, loop over all the target cells and compute the min/max elevation @@ -129,15 +176,6 @@ class FlowSolverBase : public SolverBase std::map< string, localIndex > const & bcNameToBcId, arrayView1d< globalIndex > const & bcAllSetsSize ) const; - integer & isThermal() { return m_isThermal; } - - /** - * @brief Function to activate the flag allowing negative pressure - */ - void allowNegativePressure() { m_allowNegativePressure = 1; } - - virtual bool checkSequentialSolutionIncrements( DomainPartition & domain ) const override; - protected: /** @@ -159,12 +197,6 @@ class FlowSolverBase : public SolverBase */ virtual void saveConvergedState( ElementSubRegionBase & subRegion ) const; - /** - * @brief Utility function to save the state at the end of a sequential iteration - * @param[in] subRegion the element subRegion - */ - virtual void saveSequentialIterationState( ElementSubRegionBase & subRegion ) const; - /** * @brief Helper function to compute/report the elements with small pore volumes * @param[in] domain the domain partition @@ -178,6 +210,16 @@ class FlowSolverBase : public SolverBase virtual void initializePostInitialConditionsPreSubGroups() override; + void initializeState( DomainPartition & domain ); + + virtual void computeHydrostaticEquilibrium( DomainPartition & domain ) { GEOS_UNUSED_VAR( domain ); } + + void initializePorosityAndPermeability( MeshLevel & mesh, arrayView1d< string const > const & regionNames ); + + void initializeHydraulicAperture( MeshLevel & mesh, const arrayView1d< const string > & regionNames ); + + void saveInitialPressureAndTemperature( MeshLevel & mesh, const arrayView1d< const string > & regionNames ); + virtual void setConstitutiveNamesCallSuper( ElementSubRegionBase & subRegion ) const override; /// the number of Degrees of Freedom per cell @@ -186,9 +228,18 @@ class FlowSolverBase : public SolverBase /// flag to determine whether or not this is a thermal simulation integer m_isThermal; + /// the input temperature + real64 m_inputTemperature; + + /// flag to freeze the initial state during initialization in coupled problems + integer m_keepVariablesConstantDuringInitStep; + /// enable the fixed stress poromechanics update of porosity bool m_isFixedStressPoromechanicsUpdate; + /// enable pressure jump stabilzation for fixed-stress poromechanics + bool m_isJumpStabilized; + /// flag if negative pressure is allowed integer m_allowNegativePressure; @@ -196,14 +247,53 @@ class FlowSolverBase : public SolverBase real64 m_maxAbsolutePresChange; /// maximum (absolute) pressure change in a sequential iteration + real64 m_sequentialPresChange; real64 m_maxSequentialPresChange; /// maximum (absolute) temperature change in a sequential iteration + real64 m_sequentialTempChange; real64 m_maxSequentialTempChange; + /** + * @brief Class used for displaying boundary warning message + */ + class BCMessage + { +public: + static string pressureConflict( string_view regionName, string_view subRegionName, + string_view setName, string_view fieldName ); + + static string temperatureConflict( string_view regionName, string_view subRegionName, + string_view setName, string_view fieldName ); + + static string missingPressure( string_view regionName, string_view subRegionName, + string_view setName, string_view fieldName ); + + static string missingTemperature( string_view regionName, string_view subRegionName, + string_view setName, string_view fieldName ); + + static string conflictingComposition( int comp, string_view componentName, + string_view regionName, string_view subRegionName, + string_view setName, string_view fieldName ); + + static string invalidComponentIndex( int comp, + string_view fsName, string_view fieldName ); + + static string notAppliedOnRegion( int componentIndex, string_view componentName, + string_view regionName, string_view subRegionName, + string_view setName, string_view fieldName ); +private: + static string generateMessage( string_view baseMessage, + string_view fieldName, string_view setName ); + + BCMessage(); + }; + private: virtual void setConstitutiveNames( ElementSubRegionBase & subRegion ) const override; + // flag to determine whether or not to apply lagging update for the fracture stencil weights + integer m_isLaggingFractureStencilWeightsUpdate; }; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp index 0b17130255f..ddb20e7bf5c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -88,21 +89,21 @@ DECLARE_FIELD( facePressure_n, NO_WRITE, "Face pressure at the previous converged time step" ); -DECLARE_FIELD( temperature, - "temperature", - array1d< real64 >, +DECLARE_FIELD( pressureGradient, + "pressureGradient", + array2d< real64 >, 0, LEVEL_0, WRITE_AND_READ, - "Temperature" ); + "Pressure gradient" ); -DECLARE_FIELD( faceTemperature, - "faceTemperature", +DECLARE_FIELD( temperature, + "temperature", array1d< real64 >, 0, LEVEL_0, WRITE_AND_READ, - "Face temperature" ); + "Temperature" ); DECLARE_FIELD( temperature_n, "temperature_n", @@ -116,7 +117,7 @@ DECLARE_FIELD( temperature_k, "temperature_k", array1d< real64 >, 0, - LEVEL_0, + NOPLOT, NO_WRITE, "Temperature at the previous sequential iteration" ); @@ -128,6 +129,14 @@ DECLARE_FIELD( initialTemperature, WRITE_AND_READ, "Initial temperature" ); +DECLARE_FIELD( faceTemperature, + "faceTemperature", + array1d< real64 >, + 0, + LEVEL_0, + WRITE_AND_READ, + "Face temperature" ); + DECLARE_FIELD( netToGross, "netToGross", array1d< real64 >, @@ -160,14 +169,6 @@ DECLARE_FIELD( hydraulicAperture, WRITE_AND_READ, "Hydraulic aperture" ); -DECLARE_FIELD( minimumHydraulicAperture, - "minimumHydraulicAperture", - array1d< real64 >, - 0, - LEVEL_0, - WRITE_AND_READ, - "minimum value of the hydraulic aperture" ); - DECLARE_FIELD( gravityCoefficient, "gravityCoefficient", array1d< real64 >, @@ -240,6 +241,46 @@ DECLARE_FIELD( temperatureScalingFactor, NO_WRITE, "Scaling factors for temperature" ); +DECLARE_FIELD( mass, + "mass", + array1d< real64 >, + 0, + LEVEL_0, + WRITE_AND_READ, + "Mass" ); + +DECLARE_FIELD( mass_n, + "mass_n", + array1d< real64 >, + 0, + NOPLOT, + WRITE_AND_READ, + "Mass at the previous converged time step" ); + +DECLARE_FIELD( energy, + "energy", + array1d< real64 >, + 0, + LEVEL_0, + WRITE_AND_READ, + "Energy" ); + +DECLARE_FIELD( energy_n, + "energy_n", + array1d< real64 >, + 0, + NOPLOT, + WRITE_AND_READ, + "Energy at the previous converged time step" ); + +DECLARE_FIELD( massCreated, + "massCreated", + array1d< real64 >, + 0, + LEVEL_1, + WRITE_AND_READ, + "The amount of remaining mass that was introduced when the SurfaceElement was created." ); + } } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBaseKernels.hpp deleted file mode 100644 index 98ade87b7e7..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBaseKernels.hpp +++ /dev/null @@ -1,151 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file FlowSolverBaseKernels.hpp - */ - -#ifndef GEOSX_PHYSICSSOLVERS_FLUIDFLOW_FLOWSOLVERBASEKERNELS_HPP -#define GEOSX_PHYSICSSOLVERS_FLUIDFLOW_FLOWSOLVERBASEKERNELS_HPP - -#include "common/DataTypes.hpp" -#include "common/GEOS_RAJA_Interface.hpp" -#include "mesh/ElementRegionManager.hpp" - -namespace geos -{ - -namespace flowSolverBaseKernels -{ - -/// Threshold for the min pore volume (below, a warning is issued) -static constexpr real64 poreVolumeThreshold = 1e-4; - -template< typename VIEWTYPE > -using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - -/** - * @struct MinPoreVolumeMaxPorosityKernel - * @brief Kernel to compute the min pore volume and the max porosity in a subRegion - */ -struct MinPoreVolumeMaxPorosityKernel -{ - - /* - * @brief Kernel computing the min pore volume and the max porosity - * @param[in] size the number of elements in the subRegion - * @param[in] ghostRank the ghost ranks - * @param[in] porosity the current element porosity - * @param[in] volume the current element volume - * @param[out] minPoreVolumeInSubRegion the min pore volume - * @param[out] maxPorosityInSubRegion the max porosity - * @param[out] numElemsBelowPoreVolumeThresholdInSubRegion the number of elements below the pore volume threshold - * @param[out] numElemsAbovePorosityThresholdInSubRegion the number of elements with a porosity above 1 - */ - inline static void - computeMinPoreVolumeMaxPorosity( localIndex const size, - arrayView1d< integer const > const & ghostRank, - arrayView2d< real64 const > const & porosity, - arrayView1d< real64 const > const & volume, - real64 & minPoreVolumeInSubRegion, - real64 & maxPorosityInSubRegion, - localIndex & numElemsBelowPoreVolumeThresholdInSubRegion, - localIndex & numElemsAbovePorosityThresholdInSubRegion ) - { - RAJA::ReduceMin< parallelDeviceReduce, real64 > minPoreVolume( LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceMax< parallelDeviceReduce, real64 > maxPorosity( -LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceSum< parallelDeviceReduce, localIndex > numElemsBelowPoreVolumeThreshold( 0.0 ); - RAJA::ReduceSum< parallelDeviceReduce, localIndex > numElemsAbovePorosityThreshold( 0.0 ); - - real64 const pvThreshold = poreVolumeThreshold; - - forAll< parallelDevicePolicy<> >( size, [ghostRank, - porosity, - volume, - pvThreshold, - minPoreVolume, - maxPorosity, - numElemsBelowPoreVolumeThreshold, - numElemsAbovePorosityThreshold] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( ghostRank[ei] >= 0 ) - { - return; - } - - real64 const poreVolume = porosity[ei][0] * volume[ei]; - if( poreVolume < pvThreshold ) - { - numElemsBelowPoreVolumeThreshold += 1; - } - if( porosity[ei][0] > 1 ) - { - numElemsAbovePorosityThreshold += 1; - } - - minPoreVolume.min( poreVolume ); - maxPorosity.max( porosity[ei][0] ); - } ); - - minPoreVolumeInSubRegion = minPoreVolume.get(); - maxPorosityInSubRegion = maxPorosity.get(); - numElemsBelowPoreVolumeThresholdInSubRegion = numElemsBelowPoreVolumeThreshold.get(); - numElemsAbovePorosityThresholdInSubRegion = numElemsAbovePorosityThreshold.get(); - } -}; - -/** - * @brief - * - * @tparam STENCILWRAPPER - */ -template< typename STENCILWRAPPER > -struct stencilWeightsUpdateKernel -{ - /** - * @brief - * - * @param stencilWrappper - * @param hydraulicAperture - */ - inline static void prepareStencilWeights( STENCILWRAPPER & stencilWrapper, - ElementViewConst< arrayView1d< real64 const > > const hydraulicAperture ) - { - forAll< parallelDevicePolicy<> >( stencilWrapper.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - stencilWrapper.removeHydraulicApertureContribution( iconn, hydraulicAperture ); - } ); - } - - /** - * @brief - * - * @param stencilWrappper - * @param hydraulicAperture - */ - inline static void updateStencilWeights( STENCILWRAPPER & stencilWrapper, - ElementViewConst< arrayView1d< real64 const > > const hydraulicAperture ) - { - forAll< parallelDevicePolicy<> >( stencilWrapper.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - stencilWrapper.addHydraulicApertureContribution( iconn, hydraulicAperture ); - } ); - } -}; - -} // namespace flowSolverBaseKernels - -} // namespace geos - -#endif //GEOSX_PHYSICSSOLVERS_FLUIDFLOW_FLOWSOLVERBASEKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/FluxKernelsHelper.hpp b/src/coreComponents/physicsSolvers/fluidFlow/FluxKernelsHelper.hpp deleted file mode 100644 index 684ba86a658..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/FluxKernelsHelper.hpp +++ /dev/null @@ -1,349 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file FluxKernelsHelper.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_FLUXKERNELSHELPER_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_FLUXKERNELSHELPER_HPP - -#include "common/DataTypes.hpp" -#include "common/GEOS_RAJA_Interface.hpp" -#include "finiteVolume/BoundaryStencil.hpp" -#include "linearAlgebra/interfaces/InterfaceTypes.hpp" -#include "mesh/ElementRegionManager.hpp" - -namespace geos -{ - -namespace fluxKernelsHelper -{ - -template< typename VIEWTYPE > -using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - -GEOS_HOST_DEVICE -inline -void computeSinglePhaseFlux( localIndex const ( &seri )[2], - localIndex const ( &sesri )[2], - localIndex const ( &sei )[2], - real64 const ( &transmissibility )[2], - real64 const ( &dTrans_dPres )[2], - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const > > const & dens, - ElementViewConst< arrayView2d< real64 const > > const & dDens_dPres, - ElementViewConst< arrayView1d< real64 const > > const & mob, - ElementViewConst< arrayView1d< real64 const > > const & dMob_dPres, - real64 & alpha, - real64 & mobility, - real64 & potGrad, - real64 & fluxVal, - real64 ( & dFlux_dP )[2], - real64 & dFlux_dTrans ) -{ - // average density - real64 densMean = 0.0; - real64 dDensMean_dP[2]; - - for( localIndex ke = 0; ke < 2; ++ke ) - { - densMean += 0.5 * dens[seri[ke]][sesri[ke]][sei[ke]][0]; - dDensMean_dP[ke] = 0.5 * dDens_dPres[seri[ke]][sesri[ke]][sei[ke]][0]; - } - - // compute potential difference - real64 dpotGrad_dTrans = 0.0; - real64 sumWeightGrav = 0.0; - real64 potScale = 0.0; - int signpotGradf[2] = {1, -1}; - - for( localIndex ke = 0; ke < 2; ++ke ) - { - localIndex const er = seri[ke]; - localIndex const esr = sesri[ke]; - localIndex const ei = sei[ke]; - - real64 const pressure = pres[er][esr][ei]; - real64 const gravD = gravCoef[er][esr][ei]; - real64 const pot = transmissibility[ke] * ( pressure - densMean * gravD ); - - potGrad += pot; - dpotGrad_dTrans += signpotGradf[ke] * ( pressure - densMean * gravD ); - sumWeightGrav += transmissibility[ke] * gravD; - - potScale = fmax( potScale, fabs( pot ) ); - } - - // compute upwinding tolerance - real64 constexpr upwRelTol = 1e-8; - real64 const upwAbsTol = fmax( potScale * upwRelTol, LvArray::NumericLimits< real64 >::epsilon ); - - // decide mobility coefficients - smooth variation in [-upwAbsTol; upwAbsTol] - alpha = ( potGrad + upwAbsTol ) / ( 2 * upwAbsTol ); - - real64 dMobility_dP[2]{}; - if( alpha <= 0.0 || alpha >= 1.0 ) - { - // happy path: single upwind direction - localIndex const ke = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) ); - mobility = mob[seri[ke]][sesri[ke]][sei[ke]]; - dMobility_dP[ke] = dMob_dPres[seri[ke]][sesri[ke]][sei[ke]]; - } - else - { - // sad path: weighted averaging - real64 const mobWeights[2] = { alpha, 1.0 - alpha }; - for( localIndex ke = 0; ke < 2; ++ke ) - { - mobility += mobWeights[ke] * mob[seri[ke]][sesri[ke]][sei[ke]]; - dMobility_dP[ke] = mobWeights[ke] * dMob_dPres[seri[ke]][sesri[ke]][sei[ke]]; - } - } - - // compute the final flux and derivative w.r.t transmissibility - fluxVal = mobility * potGrad; - - dFlux_dTrans = mobility * dpotGrad_dTrans; - - for( localIndex ke = 0; ke < 2; ++ke ) - { - dFlux_dP[ke] = mobility * ( transmissibility[ke] - dDensMean_dP[ke] * sumWeightGrav ) - + dMobility_dP[ke] * potGrad + dFlux_dTrans * dTrans_dPres[ke]; - } - -} - - -template< typename ENERGYFLUX_DERIVATIVE_TYPE > -GEOS_HOST_DEVICE -void computeEnthalpyFlux( localIndex const ( &seri )[2], - localIndex const ( &sesri )[2], - localIndex const ( &sei )[2], - real64 const ( &transmissibility )[2], - ElementViewConst< arrayView2d< real64 const > > const & enthalpy, - ElementViewConst< arrayView2d< real64 const > > const & dEnthalpy_dPressure, - ElementViewConst< arrayView2d< real64 const > > const & dEnthalpy_dTemperature, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const > > const & dDens_dTemp, - ElementViewConst< arrayView1d< real64 const > > const & dMob_dTemp, - real64 const & alpha, - real64 const & mobility, - real64 const & potGrad, - real64 const & massFlux, - real64 const & dMassFlux_dTrans, - real64 const ( &dMassFlux_dP )[2], - real64 ( & dMassFlux_dT )[2], - real64 & energyFlux, - real64 & dEnergyFlux_dTrans, - ENERGYFLUX_DERIVATIVE_TYPE & dEnergyFlux_dP, - ENERGYFLUX_DERIVATIVE_TYPE & dEnergyFlux_dT ) -{ - // Step 1: compute the derivatives of the mean density at the interface wrt temperature - - real64 dDensMean_dT[2]{0.0, 0.0}; - - for( integer ke = 0; ke < 2; ++ke ) - { - real64 const dDens_dT = dDens_dTemp[seri[ke]][sesri[ke]][sei[ke]][0]; - dDensMean_dT[ke] = 0.5 * dDens_dT; - } - - // Step 2: compute the derivatives of the potential difference wrt temperature - //***** calculation of flux ***** - - real64 dGravHead_dT[2]{0.0, 0.0}; - - // compute potential difference - for( integer ke = 0; ke < 2; ++ke ) - { - localIndex const er = seri[ke]; - localIndex const esr = sesri[ke]; - localIndex const ei = sei[ke]; - - // compute derivative of gravity potential difference wrt temperature - real64 const gravD = transmissibility[ke] * gravCoef[er][esr][ei]; - - for( integer i = 0; i < 2; ++i ) - { - dGravHead_dT[i] += dDensMean_dT[i] * gravD; - } - } - - // Step 3: compute the derivatives of the (upwinded) compFlux wrt temperature - // *** upwinding *** - - // Step 3.1: compute the derivative of the mass flux wrt temperature - for( integer ke = 0; ke < 2; ++ke ) - { - dMassFlux_dT[ke] -= dGravHead_dT[ke]; - } - - for( integer ke = 0; ke < 2; ++ke ) - { - dMassFlux_dT[ke] *= mobility; - } - - real64 dMob_dT[2]{}; - - if( alpha <= 0.0 || alpha >= 1.0 ) - { - localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) ); - - dMob_dT[k_up] = dMob_dTemp[seri[k_up]][sesri[k_up]][sei[k_up]]; - } - else - { - real64 const mobWeights[2] = { alpha, 1.0 - alpha }; - for( integer ke = 0; ke < 2; ++ke ) - { - dMob_dT[ke] = mobWeights[ke] * dMob_dTemp[seri[ke]][sesri[ke]][sei[ke]]; - } - } - - // add contribution from upstream cell mobility derivatives - for( integer ke = 0; ke < 2; ++ke ) - { - dMassFlux_dT[ke] += dMob_dT[ke] * potGrad; - } - - // Step 4: compute the enthalpy flux - real64 enthalpyTimesMobWeight = 0.0; - real64 dEnthalpy_dP[2]{0.0, 0.0}; - real64 dEnthalpy_dT[2]{0.0, 0.0}; - - if( alpha <= 0.0 || alpha >= 1.0 ) - { - localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) ); - - enthalpyTimesMobWeight = enthalpy[seri[k_up]][sesri[k_up]][sei[k_up]][0]; - dEnthalpy_dP[k_up] = dEnthalpy_dPressure[seri[k_up]][sesri[k_up]][sei[k_up]][0]; - dEnthalpy_dT[k_up] = dEnthalpy_dTemperature[seri[k_up]][sesri[k_up]][sei[k_up]][0]; - } - else - { - real64 const mobWeights[2] = { alpha, 1.0 - alpha }; - for( integer ke = 0; ke < 2; ++ke ) - { - enthalpyTimesMobWeight += mobWeights[ke] * enthalpy[seri[ke]][sesri[ke]][sei[ke]][0]; - dEnthalpy_dP[ke] = mobWeights[ke] * dEnthalpy_dPressure[seri[ke]][sesri[ke]][sei[ke]][0]; - dEnthalpy_dT[ke] = mobWeights[ke] * dEnthalpy_dTemperature[seri[ke]][sesri[ke]][sei[ke]][0]; - } - } - - energyFlux += massFlux * enthalpyTimesMobWeight; - dEnergyFlux_dTrans = enthalpyTimesMobWeight * dMassFlux_dTrans; - - for( integer ke = 0; ke < 2; ++ke ) - { - dEnergyFlux_dP[ke] += dMassFlux_dP[ke] * enthalpyTimesMobWeight; - dEnergyFlux_dT[ke] += dMassFlux_dT[ke] * enthalpyTimesMobWeight; - } - - for( integer ke = 0; ke < 2; ++ke ) - { - dEnergyFlux_dP[ke] += massFlux * dEnthalpy_dP[ke]; - dEnergyFlux_dT[ke] += massFlux * dEnthalpy_dT[ke]; - } -} - - -template< typename ENERGYFLUX_DERIVATIVE_TYPE > -GEOS_HOST_DEVICE -void computeConductiveFlux( localIndex const ( &seri )[2], - localIndex const ( &sesri )[2], - localIndex const ( &sei )[2], - ElementViewConst< arrayView1d< real64 const > > const & temperature, - real64 const ( &thermalTrans )[2], - real64 & energyFlux, - ENERGYFLUX_DERIVATIVE_TYPE & dEnergyFlux_dT ) -{ - for( integer ke = 0; ke < 2; ++ke ) - { - localIndex const er = seri[ke]; - localIndex const esr = sesri[ke]; - localIndex const ei = sei[ke]; - - energyFlux += thermalTrans[ke] * temperature[er][esr][ei]; - dEnergyFlux_dT[ke] += thermalTrans[ke]; - } -} - -/******************************** AquiferBCKernel ********************************/ - -/** - * @brief Function to sum the aquiferBC fluxes (as later save them) at the end of the time step - * This function is applicable for both single-phase and multiphase flow - */ -struct AquiferBCKernel -{ - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - - static real64 - sumFluxes( BoundaryStencil const & stencil, - AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & presOld, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - real64 const & timeAtBeginningOfStep, - real64 const & dt ) - { - using Order = BoundaryStencil::Order; - - BoundaryStencil::IndexContainerViewConstType const & seri = stencil.getElementRegionIndices(); - BoundaryStencil::IndexContainerViewConstType const & sesri = stencil.getElementSubRegionIndices(); - BoundaryStencil::IndexContainerViewConstType const & sefi = stencil.getElementIndices(); - BoundaryStencil::WeightContainerViewConstType const & weight = stencil.getWeights(); - - RAJA::ReduceSum< parallelDeviceReduce, real64 > targetSetSumFluxes( 0.0 ); - - forAll< parallelDevicePolicy<> >( stencil.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - localIndex const er = seri( iconn, Order::ELEM ); - localIndex const esr = sesri( iconn, Order::ELEM ); - localIndex const ei = sefi( iconn, Order::ELEM ); - real64 const areaFraction = weight( iconn, Order::ELEM ); - - // compute the aquifer influx rate using the pressure influence function and the aquifer props - real64 dAquiferVolFlux_dPres = 0.0; - real64 const aquiferVolFlux = aquiferBCWrapper.compute( timeAtBeginningOfStep, - dt, - pres[er][esr][ei], - presOld[er][esr][ei], - gravCoef[er][esr][ei], - areaFraction, - dAquiferVolFlux_dPres ); - targetSetSumFluxes += aquiferVolFlux; - } ); - return targetSetSumFluxes.get(); - } - -}; - - -} // namespace fluxKernelsHelper - -} // namespace geos - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_FLUXKERNELSHELPER_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp deleted file mode 100644 index 8adafb2945a..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp +++ /dev/null @@ -1,2445 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file IsothermalCompositionalMultiphaseBaseKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEBASEKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEBASEKERNELS_HPP - -#include "codingUtilities/Utilities.hpp" -#include "common/DataLayouts.hpp" -#include "common/DataTypes.hpp" -#include "common/GEOS_RAJA_Interface.hpp" -#include "constitutive/solid/CoupledSolidBase.hpp" -#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" -#include "functions/TableFunction.hpp" -#include "mesh/ElementSubRegionBase.hpp" -#include "mesh/ObjectManagerBase.hpp" -#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" -#include "physicsSolvers/SolverBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" - -namespace geos -{ - -namespace isothermalCompositionalMultiphaseBaseKernels -{ - -using namespace constitutive; - -static constexpr real64 minDensForDivision = 1e-10; - -enum class ElementBasedAssemblyKernelFlags -{ - SimpleAccumulation = 1 << 0, // 1 - TotalMassEquation = 1 << 1, // 2 - /// Add more flags like that if needed: - // Flag3 = 1 << 2, // 4 - // Flag4 = 1 << 3, // 8 - // Flag5 = 1 << 4, // 16 - // Flag6 = 1 << 5, // 32 - // Flag7 = 1 << 6, // 64 - // Flag8 = 1 << 7 //128 -}; - -/******************************** PropertyKernelBase ********************************/ - -/** - * @class PropertyKernelBase - * @tparam NUM_COMP number of fluid components - * @brief Define the base interface for the property update kernels - */ -template< integer NUM_COMP > -class PropertyKernelBase -{ -public: - - /// Compile time value for the number of components - static constexpr integer numComp = NUM_COMP; - - /** - * @brief Performs the kernel launch - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] numElems the number of elements - * @param[inout] kernelComponent the kernel component providing access to the compute function - */ - template< typename POLICY, typename KERNEL_TYPE > - static void - launch( localIndex const numElems, - KERNEL_TYPE const & kernelComponent ) - { - forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - kernelComponent.compute( ei ); - } ); - } - - /** - * @brief Performs the kernel launch on a sorted array - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] targetSet the indices of the elements in which we compute the property - * @param[inout] kernelComponent the kernel component providing access to the compute function - */ - template< typename POLICY, typename KERNEL_TYPE > - static void - launch( SortedArrayView< localIndex const > const & targetSet, - KERNEL_TYPE const & kernelComponent ) - { - forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const i ) - { - localIndex const ei = targetSet[ i ]; - kernelComponent.compute( ei ); - } ); - } - -}; - -namespace internal -{ - -template< typename T, typename LAMBDA > -void kernelLaunchSelectorCompSwitch( T value, LAMBDA && lambda ) -{ - static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: type should be integral" ); - - switch( value ) - { - case 1: - { lambda( std::integral_constant< T, 1 >() ); return; } - case 2: - { lambda( std::integral_constant< T, 2 >() ); return; } - case 3: - { lambda( std::integral_constant< T, 3 >() ); return; } - case 4: - { lambda( std::integral_constant< T, 4 >() ); return; } - case 5: - { lambda( std::integral_constant< T, 5 >() ); return; } - default: - { GEOS_ERROR( "Unsupported number of components: " << value ); } - } -} - -} // namespace internal - - -/******************************** GlobalComponentFractionKernel ********************************/ - -/** - * @class GlobalComponentFractionKernel - * @tparam NUM_COMP number of fluid components - * @brief Define the interface for the update kernel in charge of computing the phase volume fractions - */ -template< integer NUM_COMP > -class GlobalComponentFractionKernel : public PropertyKernelBase< NUM_COMP > -{ -public: - - using Base = PropertyKernelBase< NUM_COMP >; - using Base::numComp; - - /** - * @brief Constructor - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - */ - GlobalComponentFractionKernel( ObjectManagerBase & subRegion ) - : Base(), - m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ), - m_compFrac( subRegion.getField< fields::flow::globalCompFraction >() ), - m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ) - {} - - /** - * @brief Compute the phase volume fractions in an element - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[in] phaseVolFractionKernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void compute( localIndex const ei, - FUNC && compFractionKernelOp = NoOpFunc{} ) const - { - arraySlice1d< real64 const, compflow::USD_COMP - 1 > const compDens = m_compDens[ei]; - arraySlice1d< real64, compflow::USD_COMP - 1 > const compFrac = m_compFrac[ei]; - arraySlice2d< real64, compflow::USD_COMP_DC - 1 > const dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; - - real64 totalDensity = 0.0; - - for( integer ic = 0; ic < numComp; ++ic ) - { - totalDensity += compDens[ic]; - } - - real64 const totalDensityInv = 1.0 / totalDensity; - - for( integer ic = 0; ic < numComp; ++ic ) - { - compFrac[ic] = compDens[ic] * totalDensityInv; - for( integer jc = 0; jc < numComp; ++jc ) - { - dCompFrac_dCompDens[ic][jc] = -compFrac[ic] * totalDensityInv; - } - dCompFrac_dCompDens[ic][ic] += totalDensityInv; - } - - compFractionKernelOp( compFrac, dCompFrac_dCompDens ); - } - -protected: - - // inputs - - // Views on component densities - arrayView2d< real64 const, compflow::USD_COMP > m_compDens; - - // outputs - - // Views on component fraction - arrayView2d< real64, compflow::USD_COMP > m_compFrac; - arrayView3d< real64, compflow::USD_COMP_DC > m_dCompFrac_dCompDens; - -}; - -/** - * @class GlobalComponentFractionKernelFactory - */ -class GlobalComponentFractionKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] numComp the number of fluid components - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - */ - template< typename POLICY > - static void - createAndLaunch( integer const numComp, - ObjectManagerBase & subRegion ) - { - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - GlobalComponentFractionKernel< NUM_COMP > kernel( subRegion ); - GlobalComponentFractionKernel< NUM_COMP >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - -}; - -/******************************** PhaseVolumeFractionKernel ********************************/ - -/** - * @class PhaseVolumeFractionKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_PHASE number of fluid phases - * @brief Define the interface for the property kernel in charge of computing the phase volume fractions - */ -template< integer NUM_COMP, integer NUM_PHASE > -class PhaseVolumeFractionKernel : public PropertyKernelBase< NUM_COMP > -{ -public: - - using Base = PropertyKernelBase< NUM_COMP >; - using Base::numComp; - - /// Compile time value for the number of phases - static constexpr integer numPhase = NUM_PHASE; - - /** - * @brief Constructor - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - */ - PhaseVolumeFractionKernel( ObjectManagerBase & subRegion, - MultiFluidBase const & fluid ) - : Base(), - m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), - m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ), - m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ), - m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ), - m_phaseFrac( fluid.phaseFraction() ), - m_dPhaseFrac( fluid.dPhaseFraction() ), - m_phaseDens( fluid.phaseDensity() ), - m_dPhaseDens( fluid.dPhaseDensity() ) - {} - - /** - * @brief Compute the phase volume fractions in an element - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[in] phaseVolFractionKernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - real64 compute( localIndex const ei, - FUNC && phaseVolFractionKernelOp = NoOpFunc{} ) const - { - using Deriv = multifluid::DerivativeOffset; - - arraySlice1d< real64 const, compflow::USD_COMP - 1 > const compDens = m_compDens[ei]; - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const phaseDens = m_phaseDens[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const phaseFrac = m_phaseFrac[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const dPhaseFrac = m_dPhaseFrac[ei][0]; - arraySlice1d< real64, compflow::USD_PHASE - 1 > const phaseVolFrac = m_phaseVolFrac[ei]; - arraySlice2d< real64, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; - - real64 work[numComp]{}; - - // compute total density from component partial densities - real64 totalDensity = 0.0; - real64 const dTotalDens_dCompDens = 1.0; - for( integer ic = 0; ic < numComp; ++ic ) - { - totalDensity += compDens[ic]; - } - - real64 maxDeltaPhaseVolFrac = 0.0; - - for( integer ip = 0; ip < numPhase; ++ip ) - { - - // set the saturation to zero if the phase is absent - bool const phaseExists = (phaseFrac[ip] > 0); - if( !phaseExists ) - { - phaseVolFrac[ip] = 0.; - for( integer jc = 0; jc < numComp+2; ++jc ) - { - dPhaseVolFrac[ip][jc] = 0.; - } - continue; - } - - // Expression for volume fractions: S_p = (nu_p / rho_p) * rho_t - real64 const phaseDensInv = 1.0 / phaseDens[ip]; - - // store old saturation to compute change later - real64 const satOld = phaseVolFrac[ip]; - - // compute saturation and derivatives except multiplying by the total density - phaseVolFrac[ip] = phaseFrac[ip] * phaseDensInv; - - dPhaseVolFrac[ip][Deriv::dP] = - (dPhaseFrac[ip][Deriv::dP] - phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP]) * phaseDensInv; - - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseVolFrac[ip][Deriv::dC+jc] = - (dPhaseFrac[ip][Deriv::dC+jc] - phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dC+jc]) * phaseDensInv; - } - - // apply chain rule to convert derivatives from global component fractions to densities - applyChainRuleInPlace( numComp, dCompFrac_dCompDens, dPhaseVolFrac[ip], work, Deriv::dC ); - - // call the lambda in the phase loop to allow the reuse of the phaseVolFrac and totalDensity - // possible use: assemble the derivatives wrt temperature - phaseVolFractionKernelOp( ip, phaseVolFrac[ip], phaseDensInv, totalDensity ); - - // now finalize the computation by multiplying by total density - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseVolFrac[ip][Deriv::dC+jc] *= totalDensity; - dPhaseVolFrac[ip][Deriv::dC+jc] += phaseVolFrac[ip] * dTotalDens_dCompDens; - } - - phaseVolFrac[ip] *= totalDensity; - dPhaseVolFrac[ip][Deriv::dP] *= totalDensity; - - real64 const deltaPhaseVolFrac = LvArray::math::abs( phaseVolFrac[ip] - satOld ); - if( maxDeltaPhaseVolFrac < deltaPhaseVolFrac ) - { - maxDeltaPhaseVolFrac = deltaPhaseVolFrac; - } - } - return maxDeltaPhaseVolFrac; - } - - /** - * @brief Performs the kernel launch - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] numElems the number of elements - * @param[inout] kernelComponent the kernel component providing access to the compute function - */ - template< typename POLICY, typename KERNEL_TYPE > - static real64 - launch( localIndex const numElems, - KERNEL_TYPE const & kernelComponent ) - { - RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaPhaseVolFrac( 0.0 ); - forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - real64 const deltaPhaseVolFrac = kernelComponent.compute( ei ); - maxDeltaPhaseVolFrac.max( deltaPhaseVolFrac ); - } ); - return maxDeltaPhaseVolFrac.get(); - } - -protected: - - // outputs - - /// Views on phase volume fractions - arrayView2d< real64, compflow::USD_PHASE > m_phaseVolFrac; - arrayView3d< real64, compflow::USD_PHASE_DC > m_dPhaseVolFrac; - - // inputs - - /// Views on component densities - arrayView2d< real64 const, compflow::USD_COMP > m_compDens; - arrayView3d< real64 const, compflow::USD_COMP_DC > m_dCompFrac_dCompDens; - - /// Views on phase fractions - arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseFrac; - arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dPhaseFrac; - - /// Views on phase densities - arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseDens; - arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dPhaseDens; - -}; - -/** - * @class PhaseVolumeFractionKernelFactory - */ -class PhaseVolumeFractionKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] numComp the number of fluid components - * @param[in] numPhase the number of fluid phases - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - */ - template< typename POLICY > - static real64 - createAndLaunch( integer const numComp, - integer const numPhase, - ObjectManagerBase & subRegion, - MultiFluidBase const & fluid ) - { - real64 maxDeltaPhaseVolFrac = 0.0; - if( numPhase == 2 ) - { - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseVolumeFractionKernel< NUM_COMP, 2 > kernel( subRegion, fluid ); - maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - else if( numPhase == 3 ) - { - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseVolumeFractionKernel< NUM_COMP, 3 > kernel( subRegion, fluid ); - maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - return maxDeltaPhaseVolFrac; - } -}; - - -/******************************** RelativePermeabilityUpdateKernel ********************************/ - -struct RelativePermeabilityUpdateKernel -{ - template< typename POLICY, typename RELPERM_WRAPPER > - static void - launch( localIndex const size, - RELPERM_WRAPPER const & relPermWrapper, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - for( localIndex q = 0; q < relPermWrapper.numGauss(); ++q ) - { - relPermWrapper.update( k, q, phaseVolFrac[k] ); - } - } ); - } - - template< typename POLICY, typename RELPERM_WRAPPER > - static void - launch( SortedArrayView< localIndex const > const & targetSet, - RELPERM_WRAPPER const & relPermWrapper, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) - { - forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - localIndex const k = targetSet[a]; - for( localIndex q = 0; q < relPermWrapper.numGauss(); ++q ) - { - relPermWrapper.update( k, q, phaseVolFrac[k] ); - } - } ); - } -}; - -/******************************** CapillaryPressureUpdateKernel ********************************/ - -struct CapillaryPressureUpdateKernel -{ - template< typename POLICY, typename CAPPRES_WRAPPER > - static void - launch( localIndex const size, - CAPPRES_WRAPPER const & capPresWrapper, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - for( localIndex q = 0; q < capPresWrapper.numGauss(); ++q ) - { - capPresWrapper.update( k, q, phaseVolFrac[k] ); - } - } ); - } - - template< typename POLICY, typename CAPPRES_WRAPPER > - static void - launch( SortedArrayView< localIndex const > const & targetSet, - CAPPRES_WRAPPER const & capPresWrapper, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) - { - forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - localIndex const k = targetSet[a]; - for( localIndex q = 0; q < capPresWrapper.numGauss(); ++q ) - { - capPresWrapper.update( k, q, phaseVolFrac[k] ); - } - } ); - } -}; - -/******************************** ElementBasedAssemblyKernel ********************************/ - -/** - * @class ElementBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @brief Define the interface for the assembly kernel in charge of accumulation and volume balance - */ -template< integer NUM_COMP, integer NUM_DOF > -class ElementBasedAssemblyKernel -{ -public: - - /// Compile time value for the number of components - static constexpr integer numComp = NUM_COMP; - - /// Compute time value for the number of degrees of freedom - static constexpr integer numDof = NUM_DOF; - - /// Compute time value for the number of equations - static constexpr integer numEqn = NUM_DOF; - - /** - * @brief Constructor - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - ElementBasedAssemblyKernel( localIndex const numPhases, - globalIndex const rankOffset, - string const dofKey, - ElementSubRegionBase const & subRegion, - MultiFluidBase const & fluid, - CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< ElementBasedAssemblyKernelFlags > const kernelFlags ) - : m_numPhases( numPhases ), - m_rankOffset( rankOffset ), - m_dofNumber( subRegion.getReference< array1d< globalIndex > >( dofKey ) ), - m_elemGhostRank( subRegion.ghostRank() ), - m_volume( subRegion.getElementVolume() ), - m_porosity_n( solid.getPorosity_n() ), - m_porosity( solid.getPorosity() ), - m_dPoro_dPres( solid.getDporosity_dPressure() ), - m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ), - m_phaseVolFrac_n( subRegion.getField< fields::flow::phaseVolumeFraction_n >() ), - m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), - m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ), - m_phaseDens_n( fluid.phaseDensity_n() ), - m_phaseDens( fluid.phaseDensity() ), - m_dPhaseDens( fluid.dPhaseDensity() ), - m_phaseCompFrac_n( fluid.phaseCompFraction_n() ), - m_phaseCompFrac( fluid.phaseCompFraction() ), - m_dPhaseCompFrac( fluid.dPhaseCompFraction() ), - m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ), - m_compDens_n( subRegion.getField< fields::flow::globalCompDensity_n >() ), - m_localMatrix( localMatrix ), - m_localRhs( localRhs ), - m_kernelFlags( kernelFlags ) - {} - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - struct StackVariables - { -public: - - // Pore volume information (used by both accumulation and volume balance) - - /// Pore volume at time n+1 - real64 poreVolume = 0.0; - - /// Pore volume at the previous converged time step - real64 poreVolume_n = 0.0; - - /// Derivative of pore volume with respect to pressure - real64 dPoreVolume_dPres = 0.0; - - // Residual information - - /// Index of the local row corresponding to this element - localIndex localRow = -1; - - /// Indices of the matrix rows/columns corresponding to the dofs in this element - globalIndex dofIndices[numDof]{}; - - /// C-array storage for the element local residual vector (all equations except volume balance) - real64 localResidual[numEqn]{}; - - /// C-array storage for the element local Jacobian matrix (all equations except volume balance, all dofs) - real64 localJacobian[numEqn][numDof]{}; - - }; - - /** - * @brief Getter for the ghost rank of an element - * @param[in] ei the element index - * @return the ghost rank of the element - */ - GEOS_HOST_DEVICE - integer elemGhostRank( localIndex const ei ) const - { return m_elemGhostRank( ei ); } - - - /** - * @brief Performs the setup phase for the kernel. - * @param[in] ei the element index - * @param[in] stack the stack variables - */ - GEOS_HOST_DEVICE - void setup( localIndex const ei, - StackVariables & stack ) const - { - // initialize the pore volume - stack.poreVolume = m_volume[ei] * m_porosity[ei][0]; - stack.poreVolume_n = m_volume[ei] * m_porosity_n[ei][0]; - stack.dPoreVolume_dPres = m_volume[ei] * m_dPoro_dPres[ei][0]; - - // set row index and degrees of freedom indices for this element - stack.localRow = m_dofNumber[ei] - m_rankOffset; - for( integer idof = 0; idof < numDof; ++idof ) - { - stack.dofIndices[idof] = m_dofNumber[ei] + idof; - } - } - - /** - * @brief Compute the local accumulation contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[inout] stack the stack variables - * @param[in] phaseAmountKernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void computeAccumulation( localIndex const ei, - StackVariables & stack, - FUNC && phaseAmountKernelOp = NoOpFunc{} ) const - { - if( m_kernelFlags.isSet( ElementBasedAssemblyKernelFlags::SimpleAccumulation ) ) - { - // ic - index of component whose conservation equation is assembled - // (i.e. row number in local matrix) - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 const compAmount = stack.poreVolume * m_compDens[ei][ic]; - real64 const compAmount_n = stack.poreVolume_n * m_compDens_n[ei][ic]; - - stack.localResidual[ic] += compAmount - compAmount_n; - - // Pavel: commented below is some experiment, needs to be re-tested - //real64 const compDens = (ic == 0 && m_compDens[ei][ic] < 1e-6) ? 1e-3 : m_compDens[ei][ic]; - real64 const dCompAmount_dP = stack.dPoreVolume_dPres * m_compDens[ei][ic]; - stack.localJacobian[ic][0] += dCompAmount_dP; - - real64 const dCompAmount_dC = stack.poreVolume; - stack.localJacobian[ic][ic + 1] += dCompAmount_dC; - } - } - else - { - using Deriv = multifluid::DerivativeOffset; - - // construct the slices for variables accessed multiple times - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; - - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac_n = m_phaseVolFrac_n[ei]; - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; - - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseDens_n = m_phaseDens_n[ei][0]; - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseDens = m_phaseDens[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseDens = m_dPhaseDens[ei][0]; - - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > phaseCompFrac_n = m_phaseCompFrac_n[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > phaseCompFrac = m_phaseCompFrac[ei][0]; - arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac = m_dPhaseCompFrac[ei][0]; - - // temporary work arrays - real64 dPhaseAmount_dC[numComp]{}; - real64 dPhaseCompFrac_dC[numComp]{}; - - // sum contributions to component accumulation from each phase - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - real64 const phaseAmount = stack.poreVolume * phaseVolFrac[ip] * phaseDens[ip]; - real64 const phaseAmount_n = stack.poreVolume_n * phaseVolFrac_n[ip] * phaseDens_n[ip]; - - real64 const dPhaseAmount_dP = stack.dPoreVolume_dPres * phaseVolFrac[ip] * phaseDens[ip] - + stack.poreVolume * ( dPhaseVolFrac[ip][Deriv::dP] * phaseDens[ip] - + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP] ); - - // assemble density dependence - applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], dPhaseAmount_dC, Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseAmount_dC[jc] = dPhaseAmount_dC[jc] * phaseVolFrac[ip] - + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC + jc]; - dPhaseAmount_dC[jc] *= stack.poreVolume; - } - - // ic - index of component whose conservation equation is assembled - // (i.e. row number in local matrix) - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 const phaseCompAmount = phaseAmount * phaseCompFrac[ip][ic]; - real64 const phaseCompAmount_n = phaseAmount_n * phaseCompFrac_n[ip][ic]; - - real64 const dPhaseCompAmount_dP = dPhaseAmount_dP * phaseCompFrac[ip][ic] - + phaseAmount * dPhaseCompFrac[ip][ic][Deriv::dP]; - - stack.localResidual[ic] += phaseCompAmount - phaseCompAmount_n; - stack.localJacobian[ic][0] += dPhaseCompAmount_dP; - - // jc - index of component w.r.t. whose compositional var the derivative is being taken - // (i.e. col number in local matrix) - - // assemble phase composition dependence - applyChainRule( numComp, dCompFrac_dCompDens, dPhaseCompFrac[ip][ic], dPhaseCompFrac_dC, Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - real64 const dPhaseCompAmount_dC = dPhaseCompFrac_dC[jc] * phaseAmount - + phaseCompFrac[ip][ic] * dPhaseAmount_dC[jc]; - - stack.localJacobian[ic][jc + 1] += dPhaseCompAmount_dC; - } - } - - // call the lambda in the phase loop to allow the reuse of the phase amounts and their derivatives - // possible use: assemble the derivatives wrt temperature, and the accumulation term of the energy equation for this phase - phaseAmountKernelOp( ip, phaseAmount, phaseAmount_n, dPhaseAmount_dP, dPhaseAmount_dC ); - - } - } - - // check zero diagonal (works only in debug) - for( integer ic = 0; ic < numComp; ++ic ) - { - GEOS_ASSERT_MSG( LvArray::math::abs( stack.localJacobian[ic][ic] ) > minDensForDivision, - GEOS_FMT( "Zero diagonal in Jacobian: equation {}, value = {}", ic, stack.localJacobian[ic][ic] ) ); - } - } - - /** - * @brief Compute the local volume balance contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[inout] stack the stack variables - * @param[in] phaseVolFractionSumKernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void computeVolumeBalance( localIndex const ei, - StackVariables & stack, - FUNC && phaseVolFractionSumKernelOp = NoOpFunc{} ) const - { - using Deriv = multifluid::DerivativeOffset; - - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; - - real64 oneMinusPhaseVolFracSum = 1.0; - - // sum contributions to component accumulation from each phase - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - oneMinusPhaseVolFracSum -= phaseVolFrac[ip]; - stack.localJacobian[numComp][0] -= dPhaseVolFrac[ip][Deriv::dP]; - - for( integer jc = 0; jc < numComp; ++jc ) - { - stack.localJacobian[numComp][jc+1] -= dPhaseVolFrac[ip][Deriv::dC+jc]; - } - } - - // call the lambda in the phase loop to allow the reuse of the phase amounts and their derivatives - // possible use: assemble the derivatives wrt temperature, and use oneMinusPhaseVolFracSum if poreVolume depends on temperature - phaseVolFractionSumKernelOp( oneMinusPhaseVolFracSum ); - - // scale saturation-based volume balance by pore volume (for better scaling w.r.t. other equations) - stack.localResidual[numComp] = stack.poreVolume * oneMinusPhaseVolFracSum; - for( integer idof = 0; idof < numDof; ++idof ) - { - stack.localJacobian[numComp][idof] *= stack.poreVolume; - } - stack.localJacobian[numComp][0] += stack.dPoreVolume_dPres * oneMinusPhaseVolFracSum; - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void complete( localIndex const GEOS_UNUSED_PARAM( ei ), - StackVariables & stack ) const - { - using namespace compositionalMultiphaseUtilities; - - if( m_kernelFlags.isSet( ElementBasedAssemblyKernelFlags::TotalMassEquation ) ) - { - // apply equation/variable change transformation to the component mass balance equations - real64 work[numDof]{}; - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numDof, stack.localJacobian, work ); - shiftElementsAheadByOneAndReplaceFirstElementWithSum( numComp, stack.localResidual ); - } - - // add contribution to residual and jacobian into: - // - the component mass balance equations (i = 0 to i = numComp-1) - // - the volume balance equations (i = numComp) - // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels - integer const numRows = numComp+1; - for( integer i = 0; i < numRows; ++i ) - { - m_localRhs[stack.localRow + i] += stack.localResidual[i]; - m_localMatrix.addToRow< serialAtomic >( stack.localRow + i, - stack.dofIndices, - stack.localJacobian[i], - numDof ); - } - } - - /** - * @brief Performs the kernel launch - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] numElems the number of elements - * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables - */ - template< typename POLICY, typename KERNEL_TYPE > - static void - launch( localIndex const numElems, - KERNEL_TYPE const & kernelComponent ) - { - GEOS_MARK_FUNCTION; - - forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( kernelComponent.elemGhostRank( ei ) >= 0 ) - { - return; - } - - typename KERNEL_TYPE::StackVariables stack; - - kernelComponent.setup( ei, stack ); - kernelComponent.computeAccumulation( ei, stack ); - kernelComponent.computeVolumeBalance( ei, stack ); - kernelComponent.complete( ei, stack ); - } ); - } - -protected: - - /// Number of fluid phases - integer const m_numPhases; - - /// Offset for my MPI rank - globalIndex const m_rankOffset; - - /// View on the dof numbers - arrayView1d< globalIndex const > const m_dofNumber; - - /// View on the ghost ranks - arrayView1d< integer const > const m_elemGhostRank; - - /// View on the element volumes - arrayView1d< real64 const > const m_volume; - - /// Views on the porosity - arrayView2d< real64 const > const m_porosity_n; - arrayView2d< real64 const > const m_porosity; - arrayView2d< real64 const > const m_dPoro_dPres; - - /// Views on the derivatives of comp fractions wrt component density - arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dCompFrac_dCompDens; - - /// Views on the phase volume fractions - arrayView2d< real64 const, compflow::USD_PHASE > const m_phaseVolFrac_n; - arrayView2d< real64 const, compflow::USD_PHASE > const m_phaseVolFrac; - arrayView3d< real64 const, compflow::USD_PHASE_DC > const m_dPhaseVolFrac; - - /// Views on the phase densities - arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseDens_n; - arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseDens; - arrayView4d< real64 const, multifluid::USD_PHASE_DC > const m_dPhaseDens; - - /// Views on the phase component fraction - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const m_phaseCompFrac_n; - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const m_phaseCompFrac; - arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > const m_dPhaseCompFrac; - - // Views on component densities - arrayView2d< real64 const, compflow::USD_COMP > m_compDens; - arrayView2d< real64 const, compflow::USD_COMP > m_compDens_n; - - /// View on the local CRS matrix - CRSMatrixView< real64, globalIndex const > const m_localMatrix; - /// View on the local RHS - arrayView1d< real64 > const m_localRhs; - - BitFlags< ElementBasedAssemblyKernelFlags > const m_kernelFlags; -}; - -/** - * @class ElementBasedAssemblyKernelFactory - */ -class ElementBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] numComps the number of fluid components - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY > - static void - createAndLaunch( integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - integer const useTotalMassEquation, - integer const useSimpleAccumulation, - string const dofKey, - ElementSubRegionBase const & subRegion, - MultiFluidBase const & fluid, - CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - internal::kernelLaunchSelectorCompSwitch( numComps, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - integer constexpr NUM_DOF = NC()+1; - - BitFlags< ElementBasedAssemblyKernelFlags > kernelFlags; - if( useTotalMassEquation ) - kernelFlags.set( ElementBasedAssemblyKernelFlags::TotalMassEquation ); - if( useSimpleAccumulation ) - kernelFlags.set( ElementBasedAssemblyKernelFlags::SimpleAccumulation ); - - ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > - kernel( numPhases, rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs, kernelFlags ); - ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - -}; - -/******************************** ScalingForSystemSolutionKernel ********************************/ - -/** - * @class ScalingAndCheckingSystemSolutionKernelBase - * @brief Define the kernel for scaling the solution and check its validity - */ -template< typename TYPE > -class ScalingAndCheckingSystemSolutionKernelBase -{ -public: - - /** - * @brief Create a new kernel instance - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - * @param[in] pressure the pressure vector - * @param[in] compDens the component density vector - * @param[in] pressureScalingFactor the pressure local scaling factor - * @param[in] compDensScalingFactor the component local scaling factor - */ - ScalingAndCheckingSystemSolutionKernelBase( globalIndex const rankOffset, - integer const numComp, - string const dofKey, - ElementSubRegionBase const & subRegion, - arrayView1d< real64 const > const localSolution, - arrayView1d< real64 const > const pressure, - arrayView2d< real64 const, compflow::USD_COMP > const compDens, - arrayView1d< real64 > pressureScalingFactor, - arrayView1d< real64 > compDensScalingFactor ) - : m_rankOffset( rankOffset ), - m_numComp( numComp ), - m_dofNumber( subRegion.getReference< array1d< globalIndex > >( dofKey ) ), - m_ghostRank( subRegion.ghostRank() ), - m_localSolution( localSolution ), - m_pressure( pressure ), // not passed with fields::flow to be able to reuse this for wells - m_compDens( compDens ), // same here - m_pressureScalingFactor( pressureScalingFactor ), - m_compDensScalingFactor( compDensScalingFactor ) - { } - - /** - * @struct StackVariables - * @brief Kernel variables located on the stack - */ - struct StackVariables - { - GEOS_HOST_DEVICE - StackVariables() - { } - - StackVariables( real64 _localMinVal ) - : - localMinVal( _localMinVal ) - { } - - /// Index of the local row corresponding to this element - localIndex localRow; - - /// The local value - TYPE localMinVal; - }; - - /** - * @brief Performs the setup phase for the kernel. - * @param[in] ei the element index - * @param[in] stack the stack variables - */ - GEOS_HOST_DEVICE - void setup( localIndex const ei, - StackVariables & stack ) const - { - stack.localMinVal = 1; - - // set row index and degrees of freedom indices for this element - stack.localRow = m_dofNumber[ei] - m_rankOffset; - } - - /** - * @brief Getter for the ghost rank - * @param[in] i the looping index of the element/node/face - * @return the ghost rank of the element/node/face - */ - GEOS_HOST_DEVICE - integer ghostRank( localIndex const i ) const - { return m_ghostRank( i ); } - - /** - * @brief Performs the kernel launch - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] numElems the number of elements - * @param[inout] kernelComponent the kernel component providing access to the compute function - */ - template< typename POLICY, typename KERNEL_TYPE > - static TYPE - launch( localIndex const numElems, - KERNEL_TYPE const & kernelComponent ) - { - RAJA::ReduceMin< ReducePolicy< POLICY >, TYPE > minVal( 1 ); - forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( kernelComponent.ghostRank( ei ) >= 0 ) - { - return; - } - - StackVariables stack; - kernelComponent.setup( ei, stack ); - kernelComponent.compute( ei, stack ); - minVal.min( stack.localMinVal ); - } ); - - return minVal.get(); - } - -protected: - - /// Offset for my MPI rank - globalIndex const m_rankOffset; - - /// Number of components - real64 const m_numComp; - - /// View on the dof numbers - arrayView1d< globalIndex const > const m_dofNumber; - - /// View on the ghost ranks - arrayView1d< integer const > const m_ghostRank; - - /// View on the local residual - arrayView1d< real64 const > const m_localSolution; - - /// View on the primary variables - arrayView1d< real64 const > const m_pressure; - arrayView2d< real64 const, compflow::USD_COMP > const m_compDens; - - /// View on the scaling factors - arrayView1d< real64 > const m_pressureScalingFactor; - arrayView1d< real64 > const m_compDensScalingFactor; - -}; - -/** - * @class ScalingForSystemSolutionKernel - * @brief Define the kernel for scaling the Newton update - */ -class ScalingForSystemSolutionKernel : public ScalingAndCheckingSystemSolutionKernelBase< real64 > -{ -public: - - using Base = ScalingAndCheckingSystemSolutionKernelBase< real64 >; - using Base::m_rankOffset; - using Base::m_numComp; - using Base::m_dofNumber; - using Base::m_ghostRank; - using Base::m_localSolution; - using Base::m_pressure; - using Base::m_compDens; - using Base::m_pressureScalingFactor; - using Base::m_compDensScalingFactor; - - /** - * @brief Create a new kernel instance - * @param[in] maxRelativePresChange the max allowed relative pressure change - * @param[in] maxCompFracChange the max allowed comp fraction change - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - * @param[in] pressure the pressure vector - * @param[in] compDens the component density vector - * @param[in] pressureScalingFactor the pressure local scaling factor - * @param[in] compDensScalingFactor the component density local scaling factor - */ - ScalingForSystemSolutionKernel( real64 const maxRelativePresChange, - real64 const maxAbsolutePresChange, - real64 const maxCompFracChange, - globalIndex const rankOffset, - integer const numComp, - string const dofKey, - ElementSubRegionBase const & subRegion, - arrayView1d< real64 const > const localSolution, - arrayView1d< real64 const > const pressure, - arrayView2d< real64 const, compflow::USD_COMP > const compDens, - arrayView1d< real64 > pressureScalingFactor, - arrayView1d< real64 > compDensScalingFactor ) - : Base( rankOffset, - numComp, - dofKey, - subRegion, - localSolution, - pressure, - compDens, - pressureScalingFactor, - compDensScalingFactor ), - m_maxRelativePresChange( maxRelativePresChange ), - m_maxAbsolutePresChange( maxAbsolutePresChange ), - m_maxCompFracChange( maxCompFracChange ) - {} - - /** - * @struct StackVariables - * @brief Kernel variables located on the stack - */ - struct StackVariables : public Base::StackVariables - { - GEOS_HOST_DEVICE - StackVariables() - { } - - StackVariables( real64 _localMinVal, - real64 _localMaxDeltaPres, - real64 _localMaxDeltaTemp, - real64 _localMaxDeltaCompDens, - real64 _localMinPresScalingFactor, - real64 _localMinTempScalingFactor, - real64 _localMinCompDensScalingFactor ) - : - Base::StackVariables( _localMinVal ), - localMaxDeltaPres( _localMaxDeltaPres ), - localMaxDeltaTemp( _localMaxDeltaTemp ), - localMaxDeltaCompDens( _localMaxDeltaCompDens ), - localMinPresScalingFactor( _localMinPresScalingFactor ), - localMinTempScalingFactor( _localMinTempScalingFactor ), - localMinCompDensScalingFactor( _localMinCompDensScalingFactor ) - { } - - real64 localMaxDeltaPres; - real64 localMaxDeltaTemp; - real64 localMaxDeltaCompDens; - - real64 localMinPresScalingFactor; - real64 localMinTempScalingFactor; - real64 localMinCompDensScalingFactor; - - }; - - /** - * @brief Performs the kernel launch - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] numElems the number of elements - * @param[inout] kernelComponent the kernel component providing access to the compute function - */ - template< typename POLICY, typename KERNEL_TYPE > - static StackVariables - launch( localIndex const numElems, - KERNEL_TYPE const & kernelComponent ) - { - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > globalScalingFactor( 1.0 ); - - RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaPres( 0.0 ); - RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaTemp( 0.0 ); - RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaCompDens( 0.0 ); - - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minPresScalingFactor( 1.0 ); - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minTempScalingFactor( 1.0 ); - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minCompDensScalingFactor( 1.0 ); - - forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( kernelComponent.ghostRank( ei ) >= 0 ) - { - return; - } - - StackVariables stack; - kernelComponent.setup( ei, stack ); - kernelComponent.compute( ei, stack ); - - globalScalingFactor.min( stack.localMinVal ); - - maxDeltaPres.max( stack.localMaxDeltaPres ); - maxDeltaTemp.max( stack.localMaxDeltaTemp ); - maxDeltaCompDens.max( stack.localMaxDeltaCompDens ); - - minPresScalingFactor.min( stack.localMinPresScalingFactor ); - minTempScalingFactor.min( stack.localMinTempScalingFactor ); - minCompDensScalingFactor.min( stack.localMinCompDensScalingFactor ); - } ); - - return StackVariables( globalScalingFactor.get(), - maxDeltaPres.get(), - maxDeltaTemp.get(), - maxDeltaCompDens.get(), - minPresScalingFactor.get(), - minTempScalingFactor.get(), - minCompDensScalingFactor.get() ); - } - - GEOS_HOST_DEVICE - void setup( localIndex const ei, - StackVariables & stack ) const - { - Base::setup( ei, stack ); - - stack.localMaxDeltaPres = 0.0; - stack.localMaxDeltaTemp = 0.0; - stack.localMaxDeltaCompDens = 0.0; - - stack.localMinPresScalingFactor = 1.0; - stack.localMinTempScalingFactor = 1.0; - stack.localMinCompDensScalingFactor = 1.0; - } - - /** - * @brief Compute the local value - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void compute( localIndex const ei, - StackVariables & stack ) const - { - computeScalingFactor( ei, stack ); - } - - /** - * @brief Compute the local value of the scaling factor - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[inout] stack the stack variables - * @param[in] kernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void computeScalingFactor( localIndex const ei, - StackVariables & stack, - FUNC && kernelOp = NoOpFunc{} ) const - { - real64 constexpr eps = minDensForDivision; - - // compute the change in pressure - real64 const pres = m_pressure[ei]; - real64 const absPresChange = LvArray::math::abs( m_localSolution[stack.localRow] ); - if( stack.localMaxDeltaPres < absPresChange ) - { - stack.localMaxDeltaPres = absPresChange; - } - - // compute pressure scaling factor - real64 presScalingFactor = 1.0; - // when enabled, absolute change scaling has a priority over relative change - if( m_maxAbsolutePresChange > 0.0 ) // maxAbsolutePresChange <= 0.0 means that absolute scaling is disabled - { - if( absPresChange > m_maxAbsolutePresChange ) - { - presScalingFactor = m_maxAbsolutePresChange / absPresChange; - } - } - else if( pres > eps ) - { - real64 const relativePresChange = absPresChange / pres; - if( relativePresChange > m_maxRelativePresChange ) - { - presScalingFactor = m_maxRelativePresChange / relativePresChange; - } - } - m_pressureScalingFactor[ei] = presScalingFactor; - if( stack.localMinVal > presScalingFactor ) - { - stack.localMinVal = presScalingFactor; - } - if( stack.localMinPresScalingFactor > presScalingFactor ) - { - stack.localMinPresScalingFactor = presScalingFactor; - } - - real64 prevTotalDens = 0; - for( integer ic = 0; ic < m_numComp; ++ic ) - { - prevTotalDens += m_compDens[ei][ic]; - } - - m_compDensScalingFactor[ei] = 1.0; - - // compute the change in component densities and component fractions - for( integer ic = 0; ic < m_numComp; ++ic ) - { - // compute scaling factor based on relative change in component densities - real64 const absCompDensChange = LvArray::math::abs( m_localSolution[stack.localRow + ic + 1] ); - if( stack.localMaxDeltaCompDens < absCompDensChange ) - { - stack.localMaxDeltaCompDens = absCompDensChange; - } - - real64 const maxAbsCompDensChange = m_maxCompFracChange * prevTotalDens; - - // This actually checks the change in component fraction, using a lagged total density - // Indeed we can rewrite the following check as: - // | prevCompDens / prevTotalDens - newCompDens / prevTotalDens | > maxCompFracChange - // Note that the total density in the second term is lagged (i.e, we use prevTotalDens) - // because I found it more robust than using directly newTotalDens (which can vary also - // wildly when the compDens change is large) - if( absCompDensChange > maxAbsCompDensChange && absCompDensChange > eps ) - { - real64 const compScalingFactor = maxAbsCompDensChange / absCompDensChange; - m_compDensScalingFactor[ei] = LvArray::math::min( m_compDensScalingFactor[ei], compScalingFactor ); - if( stack.localMinVal > compScalingFactor ) - { - stack.localMinVal = compScalingFactor; - } - if( stack.localMinCompDensScalingFactor > compScalingFactor ) - { - stack.localMinCompDensScalingFactor = compScalingFactor; - } - } - } - - // compute the scaling factor for other vars, such as temperature - kernelOp(); - } - -protected: - - /// Max allowed changes in primary variables - real64 const m_maxRelativePresChange; - real64 const m_maxAbsolutePresChange; - real64 const m_maxCompFracChange; - -}; - -/** - * @class ScalingForSystemSolutionKernelFactory - */ -class ScalingForSystemSolutionKernelFactory -{ -public: - - /* - * @brief Create and launch the kernel computing the scaling factor - * @tparam POLICY the kernel policy - * @param[in] maxRelativePresChange the max allowed relative pressure change - * @param[in] maxCompFracChange the max allowed comp fraction change - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - * @return the scaling factor - */ - template< typename POLICY > - static ScalingForSystemSolutionKernel::StackVariables - createAndLaunch( real64 const maxRelativePresChange, - real64 const maxAbsolutePresChange, - real64 const maxCompFracChange, - globalIndex const rankOffset, - integer const numComp, - string const dofKey, - ElementSubRegionBase & subRegion, - arrayView1d< real64 const > const localSolution ) - { - arrayView1d< real64 const > const pressure = - subRegion.getField< fields::flow::pressure >(); - arrayView2d< real64 const, compflow::USD_COMP > const compDens = - subRegion.getField< fields::flow::globalCompDensity >(); - arrayView1d< real64 > pressureScalingFactor = - subRegion.getField< fields::flow::pressureScalingFactor >(); - arrayView1d< real64 > compDensScalingFactor = - subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); - ScalingForSystemSolutionKernel kernel( maxRelativePresChange, maxAbsolutePresChange, maxCompFracChange, rankOffset, - numComp, dofKey, subRegion, localSolution, pressure, compDens, pressureScalingFactor, compDensScalingFactor ); - return ScalingForSystemSolutionKernel::launch< POLICY >( subRegion.size(), kernel ); - } -}; - -/******************************** SolutionCheckKernel ********************************/ - -/** - * @class SolutionCheckKernel - * @brief Define the kernel for checking the updated solution - */ -class SolutionCheckKernel : public ScalingAndCheckingSystemSolutionKernelBase< integer > -{ -public: - - using Base = ScalingAndCheckingSystemSolutionKernelBase< integer >; - using Base::m_rankOffset; - using Base::m_numComp; - using Base::m_dofNumber; - using Base::m_ghostRank; - using Base::m_localSolution; - using Base::m_pressure; - using Base::m_compDens; - - /** - * @brief Create a new kernel instance - * @param[in] allowCompDensChopping flag to allow the component density chopping - * @param[in] scalingFactor the scaling factor - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - * @param[in] pressure the pressure vector - * @param[in] compDens the component density vector - */ - SolutionCheckKernel( integer const allowCompDensChopping, - integer const allowNegativePressure, - CompositionalMultiphaseFVM::ScalingType const scalingType, - real64 const scalingFactor, - globalIndex const rankOffset, - integer const numComp, - string const dofKey, - ElementSubRegionBase const & subRegion, - arrayView1d< real64 const > const localSolution, - arrayView1d< real64 const > const pressure, - arrayView2d< real64 const, compflow::USD_COMP > const compDens, - arrayView1d< real64 > pressureScalingFactor, - arrayView1d< real64 > compDensScalingFactor ) - : Base( rankOffset, - numComp, - dofKey, - subRegion, - localSolution, - pressure, - compDens, - pressureScalingFactor, - compDensScalingFactor ), - m_allowCompDensChopping( allowCompDensChopping ), - m_allowNegativePressure( allowNegativePressure ), - m_scalingFactor( scalingFactor ), - m_scalingType( scalingType ) - {} - - /** - * @struct StackVariables - * @brief Kernel variables located on the stack - */ - struct StackVariables : public Base::StackVariables - { - GEOS_HOST_DEVICE - StackVariables() - { } - - StackVariables( real64 _localMinVal, - real64 _localMinPres, - real64 _localMinDens, - real64 _localMinTotalDens, - integer _localNumNegPressures, - integer _localNumNegDens, - integer _localNumNegTotalDens ) - : - Base::StackVariables( _localMinVal ), - localMinPres( _localMinPres ), - localMinDens( _localMinDens ), - localMinTotalDens( _localMinTotalDens ), - localNumNegPressures( _localNumNegPressures ), - localNumNegDens( _localNumNegDens ), - localNumNegTotalDens( _localNumNegTotalDens ) - { } - - real64 localMinPres; - real64 localMinDens; - real64 localMinTotalDens; - - integer localNumNegPressures; - integer localNumNegDens; - integer localNumNegTotalDens; - - }; - - /** - * @brief Performs the kernel launch - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] numElems the number of elements - * @param[inout] kernelComponent the kernel component providing access to the compute function - */ - template< typename POLICY, typename KERNEL_TYPE > - static StackVariables - launch( localIndex const numElems, - KERNEL_TYPE const & kernelComponent ) - { - RAJA::ReduceMin< ReducePolicy< POLICY >, integer > globalMinVal( 1 ); - - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minPres( 0.0 ); - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minDens( 0.0 ); - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minTotalDens( 0.0 ); - - RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegPressures( 0 ); - RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegDens( 0 ); - RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegTotalDens( 0 ); - - forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( kernelComponent.ghostRank( ei ) >= 0 ) - { - return; - } - - StackVariables stack; - kernelComponent.setup( ei, stack ); - kernelComponent.compute( ei, stack ); - - globalMinVal.min( stack.localMinVal ); - - minPres.min( stack.localMinPres ); - minDens.min( stack.localMinDens ); - minTotalDens.min( stack.localMinTotalDens ); - - numNegPressures += stack.localNumNegPressures; - numNegDens += stack.localNumNegDens; - numNegTotalDens += stack.localNumNegTotalDens; - } ); - - return StackVariables( globalMinVal.get(), - minPres.get(), - minDens.get(), - minTotalDens.get(), - numNegPressures.get(), - numNegDens.get(), - numNegTotalDens.get() ); - } - - GEOS_HOST_DEVICE - void setup( localIndex const ei, - StackVariables & stack ) const - { - Base::setup( ei, stack ); - - stack.localMinPres = 0.0; - stack.localMinDens = 0.0; - stack.localMinTotalDens = 0.0; - - stack.localNumNegPressures = 0; - stack.localNumNegDens = 0; - stack.localNumNegTotalDens = 0; - } - - /** - * @brief Compute the local value - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void compute( localIndex const ei, - StackVariables & stack ) const - { - computeSolutionCheck( ei, stack ); - } - - /** - * @brief Compute the local value of the check - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[inout] stack the stack variables - * @param[in] kernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void computeSolutionCheck( localIndex const ei, - StackVariables & stack, - FUNC && kernelOp = NoOpFunc{} ) const - { - bool const localScaling = m_scalingType == CompositionalMultiphaseFVM::ScalingType::Local; - - real64 const newPres = m_pressure[ei] + (localScaling ? m_pressureScalingFactor[ei] : m_scalingFactor) * m_localSolution[stack.localRow]; - if( newPres < 0 ) - { - if( !m_allowNegativePressure ) - { - stack.localMinVal = 0; - } - stack.localNumNegPressures += 1; - if( newPres < stack.localMinPres ) - stack.localMinPres = newPres; - } - - // if component density chopping is not allowed, the time step fails if a component density is negative - // otherwise, we just check that the total density is positive, and negative component densities - // will be chopped (i.e., set to zero) in ApplySystemSolution) - if( !m_allowCompDensChopping ) - { - for( integer ic = 0; ic < m_numComp; ++ic ) - { - real64 const newDens = m_compDens[ei][ic] + (localScaling ? m_compDensScalingFactor[ei] : m_scalingFactor) * m_localSolution[stack.localRow + ic + 1]; - if( newDens < 0 ) - { - stack.localMinVal = 0; - stack.localNumNegDens += 1; - if( newDens < stack.localMinDens ) - stack.localMinDens = newDens; - } - } - } - else - { - real64 totalDens = 0.0; - for( integer ic = 0; ic < m_numComp; ++ic ) - { - real64 const newDens = m_compDens[ei][ic] + (localScaling ? m_compDensScalingFactor[ei] : m_scalingFactor) * m_localSolution[stack.localRow + ic + 1]; - totalDens += ( newDens > 0.0 ) ? newDens : 0.0; - } - if( totalDens < 0 ) - { - stack.localMinVal = 0; - stack.localNumNegTotalDens += 1; - if( totalDens < stack.localMinTotalDens ) - stack.localMinTotalDens = totalDens; - } - } - - kernelOp(); - } - -protected: - - /// flag to allow the component density chopping - integer const m_allowCompDensChopping; - - /// flag to allow negative pressure values - integer const m_allowNegativePressure; - - /// scaling factor - real64 const m_scalingFactor; - - /// scaling type (global or local) - CompositionalMultiphaseFVM::ScalingType const m_scalingType; - -}; - -/** - * @class SolutionCheckKernelFactory - */ -class SolutionCheckKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] allowCompDensChopping flag to allow the component density chopping - * @param[in] scalingFactor the scaling factor - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - */ - template< typename POLICY > - static SolutionCheckKernel::StackVariables - createAndLaunch( integer const allowCompDensChopping, - integer const allowNegativePressure, - CompositionalMultiphaseFVM::ScalingType const scalingType, - real64 const scalingFactor, - globalIndex const rankOffset, - integer const numComp, - string const dofKey, - ElementSubRegionBase & subRegion, - arrayView1d< real64 const > const localSolution ) - { - arrayView1d< real64 const > const pressure = - subRegion.getField< fields::flow::pressure >(); - arrayView2d< real64 const, compflow::USD_COMP > const compDens = - subRegion.getField< fields::flow::globalCompDensity >(); - arrayView1d< real64 > pressureScalingFactor = - subRegion.getField< fields::flow::pressureScalingFactor >(); - arrayView1d< real64 > compDensScalingFactor = - subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); - SolutionCheckKernel kernel( allowCompDensChopping, allowNegativePressure, scalingType, scalingFactor, rankOffset, - numComp, dofKey, subRegion, localSolution, pressure, compDens, pressureScalingFactor, compDensScalingFactor ); - return SolutionCheckKernel::launch< POLICY >( subRegion.size(), kernel ); - } - -}; - -/******************************** ResidualNormKernel ********************************/ - -/** - * @class ResidualNormKernel - */ -class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > -{ -public: - - using Base = solverBaseKernels::ResidualNormKernelBase< 1 >; - using Base::m_minNormalizer; - using Base::m_rankOffset; - using Base::m_localResidual; - using Base::m_dofNumber; - - ResidualNormKernel( globalIndex const rankOffset, - arrayView1d< real64 const > const & localResidual, - arrayView1d< globalIndex const > const & dofNumber, - arrayView1d< localIndex const > const & ghostRank, - integer const numComponents, - ElementSubRegionBase const & subRegion, - MultiFluidBase const & fluid, - CoupledSolidBase const & solid, - real64 const minNormalizer ) - : Base( rankOffset, - localResidual, - dofNumber, - ghostRank, - minNormalizer ), - m_numComponents( numComponents ), - m_volume( subRegion.getElementVolume() ), - m_porosity_n( solid.getPorosity_n() ), - m_totalDens_n( fluid.totalDensity_n() ) - {} - - GEOS_HOST_DEVICE - virtual void computeLinf( localIndex const ei, - LinfStackVariables & stack ) const override - { - // this should never be zero if the simulation is set up correctly, but we never know - real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_totalDens_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); - real64 const volumeNormalizer = LvArray::math::max( m_minNormalizer, m_porosity_n[ei][0] * m_volume[ei] ); - - // step 1: mass residuals - - for( integer idof = 0; idof < m_numComponents; ++idof ) - { - real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / massNormalizer; - if( valMass > stack.localValue[0] ) - { - stack.localValue[0] = valMass; - } - } - - // step 2: volume residual - - real64 const valVol = LvArray::math::abs( m_localResidual[stack.localRow + m_numComponents] ) / volumeNormalizer; - if( valVol > stack.localValue[0] ) - { - stack.localValue[0] = valVol; - } - } - - GEOS_HOST_DEVICE - virtual void computeL2( localIndex const ei, - L2StackVariables & stack ) const override - { - // note: for the L2 norm, we bundle the volume and mass residuals/normalizers - - real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_totalDens_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); - - // step 1: mass residuals - - for( integer idof = 0; idof < m_numComponents; ++idof ) - { - stack.localValue[0] += m_localResidual[stack.localRow + idof] * m_localResidual[stack.localRow + idof]; - stack.localNormalizer[0] += massNormalizer; - } - - // step 2: volume residual - - real64 const val = m_localResidual[stack.localRow + m_numComponents] * m_totalDens_n[ei][0]; // we need a mass here, hence the - // multiplication - stack.localValue[0] += val * val; - stack.localNormalizer[0] += massNormalizer; - } - - -protected: - - /// Number of fluid coponents - integer const m_numComponents; - - /// View on the volume - arrayView1d< real64 const > const m_volume; - - /// View on porosity at the previous converged time step - arrayView2d< real64 const > const m_porosity_n; - - /// View on total mass/molar density at the previous converged time step - arrayView2d< real64 const, multifluid::USD_FLUID > const m_totalDens_n; - -}; - -/** - * @class ResidualNormKernelFactory - */ -class ResidualNormKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] normType the type of norm used (Linf or L2) - * @param[in] numComps the number of fluid components - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] localResidual the residual vector on my MPI rank - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[out] residualNorm the residual norm on the subRegion - * @param[out] residualNormalizer the residual normalizer on the subRegion - */ - template< typename POLICY > - static void - createAndLaunch( solverBaseKernels::NormType const normType, - integer const numComps, - globalIndex const rankOffset, - string const dofKey, - arrayView1d< real64 const > const & localResidual, - ElementSubRegionBase const & subRegion, - MultiFluidBase const & fluid, - CoupledSolidBase const & solid, - real64 const minNormalizer, - real64 (& residualNorm)[1], - real64 (& residualNormalizer)[1] ) - { - arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); - arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); - - ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, numComps, subRegion, fluid, solid, minNormalizer ); - if( normType == solverBaseKernels::NormType::Linf ) - { - ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); - } - else // L2 norm - { - ResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); - } - } - -}; - -/******************************** StatisticsKernel ********************************/ - -struct StatisticsKernel -{ - template< typename POLICY > - static void - saveDeltaPressure( localIndex const size, - arrayView1d< real64 const > const & pres, - arrayView1d< real64 const > const & initPres, - arrayView1d< real64 > const & deltaPres ) - { - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - deltaPres[ei] = pres[ei] - initPres[ei]; - } ); - } - - template< typename POLICY > - static void - launch( localIndex const size, - integer const numComps, - integer const numPhases, - real64 const relpermThreshold, - arrayView1d< integer const > const & elemGhostRank, - arrayView1d< real64 const > const & volume, - arrayView1d< real64 const > const & pres, - arrayView1d< real64 const > const & deltaPres, - arrayView1d< real64 const > const & temp, - arrayView1d< real64 const > const & refPorosity, - arrayView2d< real64 const > const & porosity, - arrayView3d< real64 const, multifluid::USD_PHASE > const & phaseDensity, - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & phaseCompFraction, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac, - arrayView3d< real64 const, relperm::USD_RELPERM > const & phaseTrappedVolFrac, - arrayView3d< real64 const, relperm::USD_RELPERM > const & phaseRelperm, - real64 & minPres, - real64 & avgPresNumerator, - real64 & maxPres, - real64 & minDeltaPres, - real64 & maxDeltaPres, - real64 & minTemp, - real64 & avgTempNumerator, - real64 & maxTemp, - real64 & totalUncompactedPoreVol, - arrayView1d< real64 > const & phaseDynamicPoreVol, - arrayView1d< real64 > const & phaseMass, - arrayView1d< real64 > const & trappedPhaseMass, - arrayView1d< real64 > const & immobilePhaseMass, - arrayView2d< real64 > const & dissolvedComponentMass ) - { - RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinPres( LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgPresNumerator( 0.0 ); - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxPres( -LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinDeltaPres( LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxDeltaPres( -LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinTemp( LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgTempNumerator( 0.0 ); - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxTemp( 0.0 ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalUncompactedPoreVol( 0.0 ); - - // For this arrays phaseDynamicPoreVol, phaseMass, dissolvedComponentMass, - // using an array of ReduceSum leads to a formal parameter overflow in CUDA. - // As a workaround, we use a slice with RAJA::atomicAdd instead - - forAll< parallelDevicePolicy<> >( size, [numComps, - numPhases, - relpermThreshold, - elemGhostRank, - volume, - refPorosity, - porosity, - pres, - deltaPres, - temp, - phaseDensity, - phaseVolFrac, - phaseTrappedVolFrac, - phaseRelperm, - phaseCompFraction, - subRegionMinPres, - subRegionAvgPresNumerator, - subRegionMaxPres, - subRegionMinDeltaPres, - subRegionMaxDeltaPres, - subRegionMinTemp, - subRegionAvgTempNumerator, - subRegionMaxTemp, - subRegionTotalUncompactedPoreVol, - phaseDynamicPoreVol, - phaseMass, - trappedPhaseMass, - immobilePhaseMass, - dissolvedComponentMass] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( elemGhostRank[ei] >= 0 ) - { - return; - } - - // To match our "reference", we have to use reference porosity here, not the actual porosity when we compute averages - real64 const uncompactedPoreVol = volume[ei] * refPorosity[ei]; - real64 const dynamicPoreVol = volume[ei] * porosity[ei][0]; - - subRegionMinPres.min( pres[ei] ); - subRegionAvgPresNumerator += uncompactedPoreVol * pres[ei]; - subRegionMaxPres.max( pres[ei] ); - - subRegionMaxDeltaPres.max( deltaPres[ei] ); - subRegionMinDeltaPres.min( deltaPres[ei] ); - - subRegionMinTemp.min( temp[ei] ); - subRegionAvgTempNumerator += uncompactedPoreVol * temp[ei]; - subRegionMaxTemp.max( temp[ei] ); - subRegionTotalUncompactedPoreVol += uncompactedPoreVol; - for( integer ip = 0; ip < numPhases; ++ip ) - { - real64 const elemPhaseVolume = dynamicPoreVol * phaseVolFrac[ei][ip]; - real64 const elemPhaseMass = phaseDensity[ei][0][ip] * elemPhaseVolume; - real64 const elemTrappedPhaseMass = phaseDensity[ei][0][ip] * dynamicPoreVol * phaseTrappedVolFrac[ei][0][ip]; - // RAJA::atomicAdd used here because we do not use ReduceSum here (for the reason explained above) - RAJA::atomicAdd( parallelDeviceAtomic{}, &phaseDynamicPoreVol[ip], elemPhaseVolume ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &phaseMass[ip], elemPhaseMass ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &trappedPhaseMass[ip], elemTrappedPhaseMass ); - if( phaseRelperm[ei][0][ip] < relpermThreshold ) - { - RAJA::atomicAdd( parallelDeviceAtomic{}, &immobilePhaseMass[ip], elemPhaseMass ); - } - for( integer ic = 0; ic < numComps; ++ic ) - { - // RAJA::atomicAdd used here because we do not use ReduceSum here (for the reason explained above) - RAJA::atomicAdd( parallelDeviceAtomic{}, &dissolvedComponentMass[ip][ic], phaseCompFraction[ei][0][ip][ic] * elemPhaseMass ); - } - } - - } ); - - minPres = subRegionMinPres.get(); - avgPresNumerator = subRegionAvgPresNumerator.get(); - maxPres = subRegionMaxPres.get(); - minDeltaPres = subRegionMinDeltaPres.get(); - maxDeltaPres = subRegionMaxDeltaPres.get(); - minTemp = subRegionMinTemp.get(); - avgTempNumerator = subRegionAvgTempNumerator.get(); - maxTemp = subRegionMaxTemp.get(); - totalUncompactedPoreVol = subRegionTotalUncompactedPoreVol.get(); - - // dummy loop to bring data back to the CPU - forAll< serialPolicy >( 1, [phaseDynamicPoreVol, phaseMass, trappedPhaseMass, immobilePhaseMass, dissolvedComponentMass] ( localIndex const ) - { - GEOS_UNUSED_VAR( phaseDynamicPoreVol, phaseMass, trappedPhaseMass, immobilePhaseMass, dissolvedComponentMass ); - } ); - } -}; - -/******************************** HydrostaticPressureKernel ********************************/ - -struct HydrostaticPressureKernel -{ - - // TODO: this type of constants should be centralized somewhere or provided by fluid model - static real64 constexpr MIN_FOR_PHASE_PRESENCE = 1e-12; - - enum class ReturnType : integer - { - FAILED_TO_CONVERGE = 0, - DETECTED_MULTIPHASE_FLOW = 1, - SUCCESS = 2 - }; - - template< typename FLUID_WRAPPER > - static ReturnType - computeHydrostaticPressure( integer const numComps, - integer const numPhases, - integer const ipInit, - integer const maxNumEquilIterations, - real64 const & equilTolerance, - real64 const (&gravVector)[ 3 ], - FLUID_WRAPPER fluidWrapper, - arrayView1d< TableFunction::KernelWrapper const > compFracTableWrappers, - TableFunction::KernelWrapper tempTableWrapper, - real64 const & refElevation, - real64 const & refPres, - arraySlice1d< real64 const > const & refPhaseMassDens, - real64 const & newElevation, - real64 & newPres, - arraySlice1d< real64 > const & newPhaseMassDens ) - { - // fluid properties at this elevation - StackArray< real64, 2, constitutive::MultiFluidBase::MAX_NUM_COMPONENTS, compflow::LAYOUT_COMP > compFrac( 1, numComps ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, multifluid::LAYOUT_PHASE > phaseFrac( 1, 1, numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, multifluid::LAYOUT_PHASE > phaseDens( 1, 1, numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, multifluid::LAYOUT_PHASE > phaseMassDens( 1, 1, numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, multifluid::LAYOUT_PHASE > phaseVisc( 1, 1, numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, multifluid::LAYOUT_PHASE > phaseEnthalpy( 1, 1, numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, multifluid::LAYOUT_PHASE > phaseInternalEnergy( 1, 1, numPhases ); - StackArray< real64, 4, constitutive::MultiFluidBase::MAX_NUM_PHASES *constitutive::MultiFluidBase::MAX_NUM_COMPONENTS, - multifluid::LAYOUT_PHASE_COMP > phaseCompFrac( 1, 1, numPhases, numComps ); - real64 totalDens = 0.0; - - bool isSinglePhaseFlow = true; - - // Step 1: compute the hydrostatic pressure at the current elevation - - real64 const gravCoef = gravVector[2] * ( refElevation - newElevation ); - real64 const temp = tempTableWrapper.compute( &newElevation ); - for( integer ic = 0; ic < numComps; ++ic ) - { - compFrac[0][ic] = compFracTableWrappers[ic].compute( &newElevation ); - } - - // Step 2: guess the pressure with the refPhaseMassDensity - - real64 pres0 = refPres - refPhaseMassDens[ipInit] * gravCoef; - real64 pres1 = 0.0; - - // Step 3: compute the mass density at this elevation using the guess, and update pressure - - MultiFluidBase::KernelWrapper::computeValues( fluidWrapper, - pres0, - temp, - compFrac[0], - phaseFrac[0][0], - phaseDens[0][0], - phaseMassDens[0][0], - phaseVisc[0][0], - phaseEnthalpy[0][0], - phaseInternalEnergy[0][0], - phaseCompFrac[0][0], - totalDens ); - pres1 = refPres - 0.5 * ( refPhaseMassDens[ipInit] + phaseMassDens[0][0][ipInit] ) * gravCoef; - - // Step 4: fixed-point iteration until convergence - - bool equilHasConverged = false; - for( integer eqIter = 0; eqIter < maxNumEquilIterations; ++eqIter ) - { - - // check convergence - equilHasConverged = ( LvArray::math::abs( pres0 - pres1 ) < equilTolerance ); - pres0 = pres1; - - // if converged, check number of phases and move on - if( equilHasConverged ) - { - // make sure that the fluid is single-phase, other we have to issue a warning (for now) - // if only one phase is mobile, we are in good shape (unfortunately it is hard to access relperm from here) - localIndex numberOfPhases = 0; - for( integer ip = 0; ip < numPhases; ++ip ) - { - if( phaseFrac[0][0][ip] > MIN_FOR_PHASE_PRESENCE ) - { - numberOfPhases++; - } - } - if( numberOfPhases > 1 ) - { - isSinglePhaseFlow = false; - } - - break; - } - - // compute the mass density at this elevation using the previous pressure, and compute the new pressure - MultiFluidBase::KernelWrapper::computeValues( fluidWrapper, - pres0, - temp, - compFrac[0], - phaseFrac[0][0], - phaseDens[0][0], - phaseMassDens[0][0], - phaseVisc[0][0], - phaseEnthalpy[0][0], - phaseInternalEnergy[0][0], - phaseCompFrac[0][0], - totalDens ); - pres1 = refPres - 0.5 * ( refPhaseMassDens[ipInit] + phaseMassDens[0][0][ipInit] ) * gravCoef; - } - - // Step 5: save the hydrostatic pressure and the corresponding density - - newPres = pres1; - for( integer ip = 0; ip < numPhases; ++ip ) - { - newPhaseMassDens[ip] = phaseMassDens[0][0][ip]; - } - - if( !equilHasConverged ) - { - return ReturnType::FAILED_TO_CONVERGE; - } - else if( !isSinglePhaseFlow ) - { - return ReturnType::DETECTED_MULTIPHASE_FLOW; - } - else - { - return ReturnType::SUCCESS; - } - } - - template< typename FLUID_WRAPPER > - static ReturnType - launch( localIndex const size, - integer const numComps, - integer const numPhases, - integer const ipInit, - integer const maxNumEquilIterations, - real64 const equilTolerance, - real64 const (&gravVector)[ 3 ], - real64 const & minElevation, - real64 const & elevationIncrement, - real64 const & datumElevation, - real64 const & datumPres, - FLUID_WRAPPER fluidWrapper, - arrayView1d< TableFunction::KernelWrapper const > compFracTableWrappers, - TableFunction::KernelWrapper tempTableWrapper, - arrayView1d< arrayView1d< real64 > const > elevationValues, - arrayView1d< real64 > pressureValues ) - { - - ReturnType returnVal = ReturnType::SUCCESS; - - // Step 1: compute the phase mass densities at datum - - // datum fluid properties - array2d< real64, compflow::LAYOUT_COMP > datumCompFrac( 1, numComps ); - array3d< real64, multifluid::LAYOUT_PHASE > datumPhaseFrac( 1, 1, numPhases ); - array3d< real64, multifluid::LAYOUT_PHASE > datumPhaseDens( 1, 1, numPhases ); - array3d< real64, multifluid::LAYOUT_PHASE > datumPhaseMassDens( 1, 1, numPhases ); - array3d< real64, multifluid::LAYOUT_PHASE > datumPhaseVisc( 1, 1, numPhases ); - array3d< real64, multifluid::LAYOUT_PHASE > datumPhaseEnthalpy( 1, 1, numPhases ); - array3d< real64, multifluid::LAYOUT_PHASE > datumPhaseInternalEnergy( 1, 1, numPhases ); - array4d< real64, multifluid::LAYOUT_PHASE_COMP > datumPhaseCompFrac( 1, 1, numPhases, numComps ); - real64 datumTotalDens = 0.0; - - real64 const datumTemp = tempTableWrapper.compute( &datumElevation ); - for( integer ic = 0; ic < numComps; ++ic ) - { - datumCompFrac[0][ic] = compFracTableWrappers[ic].compute( &datumElevation ); - } - MultiFluidBase::KernelWrapper::computeValues( fluidWrapper, - datumPres, - datumTemp, - datumCompFrac[0], - datumPhaseFrac[0][0], - datumPhaseDens[0][0], - datumPhaseMassDens[0][0], - datumPhaseVisc[0][0], - datumPhaseEnthalpy[0][0], - datumPhaseInternalEnergy[0][0], - datumPhaseCompFrac[0][0], - datumTotalDens ); - - // Step 2: find the closest elevation to datumElevation - - forAll< parallelHostPolicy >( size, [=] ( localIndex const i ) - { - real64 const elevation = minElevation + i * elevationIncrement; - elevationValues[0][i] = elevation; - } ); - integer const iRef = LvArray::sortedArrayManipulation::find( elevationValues[0].begin(), - elevationValues[0].size(), - datumElevation ); - - // Step 3: compute the mass density and pressure at the reference elevation - - array2d< real64 > phaseMassDens( pressureValues.size(), numPhases ); - // temporary array without permutation to compile on Lassen - array1d< real64 > datumPhaseMassDensTmp( numPhases ); - for( integer ip = 0; ip < numPhases; ++ip ) - { - datumPhaseMassDensTmp[ip] = datumPhaseMassDens[0][0][ip]; - } - - ReturnType const refReturnVal = - computeHydrostaticPressure( numComps, - numPhases, - ipInit, - maxNumEquilIterations, - equilTolerance, - gravVector, - fluidWrapper, - compFracTableWrappers, - tempTableWrapper, - datumElevation, - datumPres, - datumPhaseMassDensTmp, - elevationValues[0][iRef], - pressureValues[iRef], - phaseMassDens[iRef] ); - if( refReturnVal == ReturnType::FAILED_TO_CONVERGE ) - { - return ReturnType::FAILED_TO_CONVERGE; - } - else if( refReturnVal == ReturnType::DETECTED_MULTIPHASE_FLOW ) - { - returnVal = ReturnType::DETECTED_MULTIPHASE_FLOW; - } - - // Step 4: for each elevation above the reference elevation, compute the pressure - - localIndex const numEntriesAboveRef = size - iRef - 1; - forAll< serialPolicy >( numEntriesAboveRef, [=, &returnVal] ( localIndex const i ) - { - ReturnType const returnValAboveRef = - computeHydrostaticPressure( numComps, - numPhases, - ipInit, - maxNumEquilIterations, - equilTolerance, - gravVector, - fluidWrapper, - compFracTableWrappers, - tempTableWrapper, - elevationValues[0][iRef+i], - pressureValues[iRef+i], - phaseMassDens[iRef+i], - elevationValues[0][iRef+i+1], - pressureValues[iRef+i+1], - phaseMassDens[iRef+i+1] ); - if( returnValAboveRef == ReturnType::FAILED_TO_CONVERGE ) - { - returnVal = ReturnType::FAILED_TO_CONVERGE; - } - else if( ( returnValAboveRef == ReturnType::DETECTED_MULTIPHASE_FLOW ) && - ( returnVal != ReturnType::FAILED_TO_CONVERGE ) ) - { - returnVal = ReturnType::DETECTED_MULTIPHASE_FLOW; - } - - } ); - - // Step 5: for each elevation below the reference elevation, compute the pressure - - localIndex const numEntriesBelowRef = iRef; - forAll< serialPolicy >( numEntriesBelowRef, [=, &returnVal] ( localIndex const i ) - { - ReturnType const returnValBelowRef = - computeHydrostaticPressure( numComps, - numPhases, - ipInit, - maxNumEquilIterations, - equilTolerance, - gravVector, - fluidWrapper, - compFracTableWrappers, - tempTableWrapper, - elevationValues[0][iRef-i], - pressureValues[iRef-i], - phaseMassDens[iRef-i], - elevationValues[0][iRef-i-1], - pressureValues[iRef-i-1], - phaseMassDens[iRef-i-1] ); - if( returnValBelowRef == ReturnType::FAILED_TO_CONVERGE ) - { - returnVal = ReturnType::FAILED_TO_CONVERGE; - } - else if( ( returnValBelowRef == ReturnType::DETECTED_MULTIPHASE_FLOW ) && - ( returnVal != ReturnType::FAILED_TO_CONVERGE ) ) - { - returnVal = ReturnType::DETECTED_MULTIPHASE_FLOW; - } - - } ); - - return returnVal; - } - -}; - - -/******************************** Kernel launch machinery ********************************/ - -template< typename KERNELWRAPPER, typename ... ARGS > -void KernelLaunchSelector1( integer const numComp, ARGS && ... args ) -{ - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - KERNELWRAPPER::template launch< NC() >( std::forward< ARGS >( args )... ); - } ); -} - -template< typename KERNELWRAPPER, typename ... ARGS > -void KernelLaunchSelector2( integer const numComp, integer const numPhase, ARGS && ... args ) -{ - // Ideally this would be inside the dispatch, but it breaks on Summit with GCC 9.1.0 and CUDA 11.0.3. - if( numPhase == 2 ) - { - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - KERNELWRAPPER::template launch< NC(), 2 >( std::forward< ARGS >( args ) ... ); - } ); - } - else if( numPhase == 3 ) - { - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - KERNELWRAPPER::template launch< NC(), 3 >( std::forward< ARGS >( args ) ... ); - } ); - } - else - { - GEOS_ERROR( "Unsupported number of phases: " << numPhase ); - } -} - -} // namespace isothermalCompositionalMultiphaseBaseKernels - -} // namespace geos - - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEBASEKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp deleted file mode 100644 index f63126c5cbb..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp +++ /dev/null @@ -1,548 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp - */ - -#ifndef GEOSX_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEFVMKERNELUTILITIES_HPP_ -#define GEOSX_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEFVMKERNELUTILITIES_HPP_ - -#include "common/DataLayouts.hpp" -#include "common/DataTypes.hpp" -#include "constitutive/fluid/multifluid/Layouts.hpp" -#include "constitutive/capillaryPressure/layouts.hpp" -#include "mesh/ElementRegionManager.hpp" - - -namespace geos -{ - -namespace isothermalCompositionalMultiphaseFVMKernelUtilities -{ - -// TODO make input parameter -static constexpr real64 epsC1PPU = 5000; - -template< typename VIEWTYPE > -using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - -using Deriv = constitutive::multifluid::DerivativeOffset; - -struct PotGrad -{ - template< integer numComp, integer numFluxSupportPoints > - GEOS_HOST_DEVICE - static void - compute ( integer const numPhase, - integer const ip, - integer const hasCapPressure, - localIndex const ( &seri )[numFluxSupportPoints], - localIndex const ( &sesri )[numFluxSupportPoints], - localIndex const ( &sei )[numFluxSupportPoints], - real64 const ( &trans )[numFluxSupportPoints], - real64 const ( &dTrans_dPres )[numFluxSupportPoints], - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, - ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, - ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, - real64 & potGrad, - real64 ( & dPresGrad_dP )[numFluxSupportPoints], - real64 ( & dPresGrad_dC )[numFluxSupportPoints][numComp], - real64 ( & dGravHead_dP )[numFluxSupportPoints], - real64 ( & dGravHead_dC )[numFluxSupportPoints][numComp] ) - { - // assign derivatives arrays to zero - for( integer i = 0; i < numFluxSupportPoints; ++i ) - { - dPresGrad_dP[i] = 0.0; - dGravHead_dP[i] = 0.0; - for( integer jc = 0; jc < numComp; ++jc ) - { - dPresGrad_dC[i][jc] = 0.0; - dGravHead_dC[i][jc] = 0.0; - } - } - - // create local work arrays - real64 densMean = 0.0; - real64 dDensMean_dP[numFluxSupportPoints]{}; - real64 dDensMean_dC[numFluxSupportPoints][numComp]{}; - - real64 presGrad = 0.0; - real64 gravHead = 0.0; - real64 dCapPressure_dC[numComp]{}; - - real64 dProp_dC[numComp]{}; - - // calculate quantities on primary connected cells - for( integer i = 0; i < numFluxSupportPoints; ++i ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - // density - real64 const density = phaseMassDens[er][esr][ei][0][ip]; - real64 const dDens_dP = dPhaseMassDens[er][esr][ei][0][ip][Deriv::dP]; - - applyChainRule( numComp, - dCompFrac_dCompDens[er][esr][ei], - dPhaseMassDens[er][esr][ei][0][ip], - dProp_dC, - Deriv::dC ); - - // average density and derivatives - densMean += 0.5 * density; - dDensMean_dP[i] = 0.5 * dDens_dP; - for( integer jc = 0; jc < numComp; ++jc ) - { - dDensMean_dC[i][jc] = 0.5 * dProp_dC[jc]; - } - } - - /// compute the TPFA potential difference - for( integer i = 0; i < numFluxSupportPoints; i++ ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - // capillary pressure - real64 capPressure = 0.0; - real64 dCapPressure_dP = 0.0; - - for( integer ic = 0; ic < numComp; ++ic ) - { - dCapPressure_dC[ic] = 0.0; - } - - if( hasCapPressure ) - { - capPressure = phaseCapPressure[er][esr][ei][0][ip]; - - for( integer jp = 0; jp < numPhase; ++jp ) - { - real64 const dCapPressure_dS = dPhaseCapPressure_dPhaseVolFrac[er][esr][ei][0][ip][jp]; - dCapPressure_dP += dCapPressure_dS * dPhaseVolFrac[er][esr][ei][jp][Deriv::dP]; - - for( integer jc = 0; jc < numComp; ++jc ) - { - dCapPressure_dC[jc] += dCapPressure_dS * dPhaseVolFrac[er][esr][ei][jp][Deriv::dC+jc]; - } - } - } - - presGrad += trans[i] * (pres[er][esr][ei] - capPressure); - dPresGrad_dP[i] += trans[i] * (1 - dCapPressure_dP) - + dTrans_dPres[i] * (pres[er][esr][ei] - capPressure); - for( integer jc = 0; jc < numComp; ++jc ) - { - dPresGrad_dC[i][jc] += -trans[i] * dCapPressure_dC[jc]; - } - - real64 const gravD = trans[i] * gravCoef[er][esr][ei]; - real64 const dGravD_dP = dTrans_dPres[i] * gravCoef[er][esr][ei]; - - // the density used in the potential difference is always a mass density - // unlike the density used in the phase mobility, which is a mass density - // if useMass == 1 and a molar density otherwise - gravHead += densMean * gravD; - - // need to add contributions from both cells the mean density depends on - for( integer j = 0; j < numFluxSupportPoints; ++j ) - { - dGravHead_dP[j] += dDensMean_dP[j] * gravD + dGravD_dP * densMean; - for( integer jc = 0; jc < numComp; ++jc ) - { - dGravHead_dC[j][jc] += dDensMean_dC[j][jc] * gravD; - } - } - } - - // compute phase potential gradient - potGrad = presGrad - gravHead; - - } - -}; - -struct PPUPhaseFlux -{ - /** - * @brief Form the PhasePotentialUpwind from pressure gradient and gravitational head - * @tparam numComp number of components - * @tparam numFluxSupportPoints number of flux support points - * @param numPhase number of phases - * @param ip phase index - * @param hasCapPressure flag indicating if there is capillary pressure - * @param seri arraySlice of the stencil-implied element region index - * @param sesri arraySlice of the stencil-implied element subregion index - * @param sei arraySlice of the stencil-implied element index - * @param trans transmissibility at the connection - * @param dTrans_dPres derivative of transmissibility wrt pressure - * @param pres pressure - * @param gravCoef gravitational coefficient - * @param phaseMob phase mobility - * @param dPhaseMob derivative of phase mobility wrt pressure, temperature, comp density - * @param dPhaseVolFrac derivative of phase volume fraction wrt pressure, temperature, comp density - * @param dCompFrac_dCompDens derivative of component fraction wrt component density - * @param phaseMassDens phase mass density - * @param dPhaseMassDens derivative of phase mass density wrt pressure, temperature, comp fraction - * @param phaseCapPressure phase capillary pressure - * @param dPhaseCapPressure_dPhaseVolFrac derivative of phase capillary pressure wrt phase volume fraction - * @param k_up uptream index for this phase - * @param potGrad potential gradient for this phase - * @param phaseFlux phase flux - * @param dPhaseFlux_dP derivative of phase flux wrt pressure - * @param dPhaseFlux_dC derivative of phase flux wrt comp density - */ - template< integer numComp, integer numFluxSupportPoints > - GEOS_HOST_DEVICE - static void - compute( integer const numPhase, - integer const ip, - integer const hasCapPressure, - localIndex const ( &seri )[numFluxSupportPoints], - localIndex const ( &sesri )[numFluxSupportPoints], - localIndex const ( &sei )[numFluxSupportPoints], - real64 const ( &trans )[2], - real64 const ( &dTrans_dPres )[2], - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, - ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, - ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, - localIndex & k_up, - real64 & potGrad, - real64 ( &phaseFlux ), - real64 ( & dPhaseFlux_dP )[numFluxSupportPoints], - real64 ( & dPhaseFlux_dC )[numFluxSupportPoints][numComp] ) - { - real64 dPresGrad_dP[numFluxSupportPoints]{}; - real64 dPresGrad_dC[numFluxSupportPoints][numComp]{}; - real64 dGravHead_dP[numFluxSupportPoints]{}; - real64 dGravHead_dC[numFluxSupportPoints][numComp]{}; - PotGrad::compute< numComp, numFluxSupportPoints >( numPhase, ip, hasCapPressure, seri, sesri, sei, trans, dTrans_dPres, pres, - gravCoef, dPhaseVolFrac, dCompFrac_dCompDens, phaseMassDens, dPhaseMassDens, - phaseCapPressure, dPhaseCapPressure_dPhaseVolFrac, potGrad, dPresGrad_dP, - dPresGrad_dC, dGravHead_dP, dGravHead_dC ); - - // *** upwinding *** - - // choose upstream cell - k_up = (potGrad >= 0) ? 0 : 1; - - localIndex const er_up = seri[k_up]; - localIndex const esr_up = sesri[k_up]; - localIndex const ei_up = sei[k_up]; - - real64 const mobility = phaseMob[er_up][esr_up][ei_up][ip]; - - // pressure gradient depends on all points in the stencil - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dPhaseFlux_dP[ke] += dPresGrad_dP[ke] - dGravHead_dP[ke]; - dPhaseFlux_dP[ke] *= mobility; - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseFlux_dC[ke][jc] += dPresGrad_dC[ke][jc] - dGravHead_dC[ke][jc]; - dPhaseFlux_dC[ke][jc] *= mobility; - } - } - // compute phase flux using upwind mobility. - phaseFlux = mobility * potGrad; - - real64 const dMob_dP = dPhaseMob[er_up][esr_up][ei_up][ip][Deriv::dP]; - arraySlice1d< real64 const, compflow::USD_PHASE_DC - 2 > dPhaseMobSub = - dPhaseMob[er_up][esr_up][ei_up][ip]; - - // add contribution from upstream cell mobility derivatives - dPhaseFlux_dP[k_up] += dMob_dP * potGrad; - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseFlux_dC[k_up][jc] += dPhaseMobSub[Deriv::dC+jc] * potGrad; - } - } -}; - -struct C1PPUPhaseFlux -{ - /** - * @brief Form the PhasePotentialUpwind from pressure gradient and gravitational head - * @tparam numComp number of components - * @tparam numFluxSupportPoints number of flux support points - * @param numPhase number of phases - * @param ip phase index - * @param hasCapPressure flag indicating if there is capillary pressure - * @param seri arraySlice of the stencil-implied element region index - * @param sesri arraySlice of the stencil-implied element subregion index - * @param sei arraySlice of the stencil-implied element index - * @param trans transmissibility at the connection - * @param dTrans_dPres derivative of transmissibility wrt pressure - * @param pres pressure - * @param gravCoef gravitational coefficient - * @param phaseMob phase mobility - * @param dPhaseMob derivative of phase mobility wrt pressure, temperature, comp density - * @param dPhaseVolFrac derivative of phase volume fraction wrt pressure, temperature, comp density - * @param dCompFrac_dCompDens derivative of component fraction wrt component density - * @param phaseMassDens phase mass density - * @param dPhaseMassDens derivative of phase mass density wrt pressure, temperature, comp fraction - * @param phaseCapPressure phase capillary pressure - * @param dPhaseCapPressure_dPhaseVolFrac derivative of phase capillary pressure wrt phase volume fraction - * @param k_up uptream index for this phase - * @param potGrad potential gradient for this phase - * @param phaseFlux phase flux - * @param dPhaseFlux_dP derivative of phase flux wrt pressure - * @param dPhaseFlux_dC derivative of phase flux wrt comp density - */ - template< integer numComp, integer numFluxSupportPoints > - GEOS_HOST_DEVICE - static void - compute( integer const numPhase, - integer const ip, - integer const hasCapPressure, - //real64 const epsC1PPU, - localIndex const ( &seri )[numFluxSupportPoints], - localIndex const ( &sesri )[numFluxSupportPoints], - localIndex const ( &sei )[numFluxSupportPoints], - real64 const ( &trans )[2], - real64 const ( &dTrans_dPres )[2], - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, - ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, - ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, - localIndex & k_up, - real64 & potGrad, - real64 ( &phaseFlux ), - real64 ( & dPhaseFlux_dP )[numFluxSupportPoints], - real64 ( & dPhaseFlux_dC )[numFluxSupportPoints][numComp] ) - { - real64 dPresGrad_dP[numFluxSupportPoints]{}; - real64 dPresGrad_dC[numFluxSupportPoints][numComp]{}; - real64 dGravHead_dP[numFluxSupportPoints]{}; - real64 dGravHead_dC[numFluxSupportPoints][numComp]{}; - PotGrad::compute< numComp, numFluxSupportPoints >( numPhase, ip, hasCapPressure, seri, sesri, sei, trans, dTrans_dPres, pres, - gravCoef, dPhaseVolFrac, dCompFrac_dCompDens, phaseMassDens, dPhaseMassDens, - phaseCapPressure, dPhaseCapPressure_dPhaseVolFrac, potGrad, dPresGrad_dP, - dPresGrad_dC, dGravHead_dP, dGravHead_dC ); - - // gravity head - real64 gravHead = 0.0; - for( integer i = 0; i < numFluxSupportPoints; i++ ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - real64 const gravD = trans[i] * gravCoef[er][esr][ei]; - - gravHead += gravD; - } - - // *** upwinding *** - - // phase flux and derivatives - - // assuming TPFA in the code below - - real64 Ttrans = fabs( trans[0] ); - potGrad = potGrad / Ttrans; - - real64 const mobility_i = phaseMob[seri[0]][sesri[0]][sei[0]][ip]; - real64 const mobility_j = phaseMob[seri[1]][sesri[1]][sei[1]][ip]; - - // compute phase flux, see Eqs. (66) and (69) from the reference above - real64 smoEps = epsC1PPU; - if( fabs( gravHead ) <= 1e-20 ) - smoEps = 1000; - real64 const tmpSqrt = sqrt( potGrad * potGrad + smoEps * smoEps ); - real64 const smoMax = 0.5 * (-potGrad + tmpSqrt); - - phaseFlux = Ttrans * ( potGrad * mobility_i - smoMax * (mobility_j - mobility_i) ); - - // derivativess - - // first part, mobility derivative - - // dP - { - real64 const dMob_dP = dPhaseMob[seri[0]][sesri[0]][sei[0]][ip][Deriv::dP]; - dPhaseFlux_dP[0] += Ttrans * potGrad * dMob_dP; - } - - // dC - { - arraySlice1d< real64 const, compflow::USD_PHASE_DC - 2 > - dPhaseMobSub = dPhaseMob[seri[0]][sesri[0]][sei[0]][ip]; - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseFlux_dC[0][jc] += Ttrans * potGrad * dPhaseMobSub[Deriv::dC + jc]; - } - } - - real64 const tmpInv = 1.0 / tmpSqrt; - real64 const dSmoMax_x = 0.5 * (1.0 - potGrad * tmpInv); - - // pressure gradient and mobility difference depend on all points in the stencil - real64 const dMobDiff_sign[numFluxSupportPoints] = {-1.0, 1.0}; - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - // dP - - real64 const dPotGrad_dP = dPresGrad_dP[ke] - dGravHead_dP[ke]; - - // first part - dPhaseFlux_dP[ke] += dPotGrad_dP * mobility_i; - - // second part - real64 const dSmoMax_dP = -dPotGrad_dP * dSmoMax_x; - dPhaseFlux_dP[ke] += -dSmoMax_dP * (mobility_j - mobility_i); - - real64 const dMob_dP = dPhaseMob[seri[ke]][sesri[ke]][sei[ke]][ip][Deriv::dP]; - dPhaseFlux_dP[ke] += -Ttrans * smoMax * dMobDiff_sign[ke] * dMob_dP; - - // dC - - arraySlice1d< real64 const, compflow::USD_PHASE_DC - 2 > - dPhaseMobSub = dPhaseMob[seri[ke]][sesri[ke]][sei[ke]][ip]; - - for( integer jc = 0; jc < numComp; ++jc ) - { - real64 const dPotGrad_dC = dPresGrad_dC[ke][jc] - dGravHead_dC[ke][jc]; - - // first part - dPhaseFlux_dC[ke][jc] += dPotGrad_dC * mobility_i; - - // second part - real64 const dSmoMax_dC = -dPotGrad_dC * dSmoMax_x; - dPhaseFlux_dC[ke][jc] += -dSmoMax_dC * (mobility_j - mobility_i); - dPhaseFlux_dC[ke][jc] += -Ttrans * smoMax * dMobDiff_sign[ke] * dPhaseMobSub[Deriv::dC + jc]; - } - } - - potGrad = potGrad * Ttrans; - - // choose upstream cell for composition upwinding - k_up = (phaseFlux >= 0) ? 0 : 1; - - } -}; - -struct PhaseComponentFlux -{ - /** - * @brief Compute the component flux for a given phase - * @tparam numComp number of components - * @tparam numFluxSupportPoints number of flux support points - * @param ip phase index - * @param k_up uptream index for this phase - * @param seri arraySlice of the stencil-implied element region index - * @param sesri arraySlice of the stencil-implied element subregion index - * @param sei arraySlice of the stencil-implied element index - * @param phaseCompFrac phase component fraction - * @param dPhaseCompFrac derivative of phase component fraction wrt pressure, temperature, component fraction - * @param dCompFrac_dCompDens derivative of component fraction wrt component density - * @param phaseFlux phase flux - * @param dPhaseFlux_dP derivative of phase flux wrt pressure - * @param dPhaseFlux_dC derivative of phase flux wrt comp density - * @param compFlux component flux - * @param dCompFlux_dP derivative of phase flux wrt pressure - * @param dCompFlux_dC derivative of phase flux wrt comp density - */ - template< localIndex numComp, localIndex numFluxSupportPoints > - GEOS_HOST_DEVICE - static void - compute( localIndex const ip, - localIndex const k_up, - localIndex const ( &seri )[numFluxSupportPoints], - localIndex const ( &sesri )[numFluxSupportPoints], - localIndex const ( &sei )[numFluxSupportPoints], - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - real64 const & phaseFlux, - real64 const ( &dPhaseFlux_dP )[numFluxSupportPoints], - real64 const ( &dPhaseFlux_dC )[numFluxSupportPoints][numComp], - real64 ( & compFlux )[numComp], - real64 ( & dCompFlux_dP )[numFluxSupportPoints][numComp], - real64 ( & dCompFlux_dC )[numFluxSupportPoints][numComp][numComp] ) - { - localIndex const er_up = seri[k_up]; - localIndex const esr_up = sesri[k_up]; - localIndex const ei_up = sei[k_up]; - - real64 dProp_dC[numComp]{}; - - // slice some constitutive arrays to avoid too much indexing in component loop - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE_COMP-3 > phaseCompFracSub = - phaseCompFrac[er_up][esr_up][ei_up][0][ip]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC-3 > dPhaseCompFracSub = - dPhaseCompFrac[er_up][esr_up][ei_up][0][ip]; - - // compute component fluxes and derivatives using upstream cell composition - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 const ycp = phaseCompFracSub[ic]; - compFlux[ic] += phaseFlux * ycp; - - // derivatives stemming from phase flux - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dCompFlux_dP[ke][ic] += dPhaseFlux_dP[ke] * ycp; - for( integer jc = 0; jc < numComp; ++jc ) - { - dCompFlux_dC[ke][ic][jc] += dPhaseFlux_dC[ke][jc] * ycp; - } - } - - // additional derivatives stemming from upstream cell phase composition - dCompFlux_dP[k_up][ic] += phaseFlux * dPhaseCompFracSub[ic][Deriv::dP]; - - // convert derivatives of comp fraction w.r.t. comp fractions to derivatives w.r.t. comp densities - applyChainRule( numComp, - dCompFrac_dCompDens[er_up][esr_up][ei_up], - dPhaseCompFracSub[ic], - dProp_dC, - Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - dCompFlux_dC[k_up][ic][jc] += phaseFlux * dProp_dC[jc]; - } - } - } - -}; - -} // namespace isothermalCompositionalMultiPhaseFVMKernelUtilities - -} // namespace geosx - - -#endif // GEOSX_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEFVMKERNELUTILITIES_HPP_ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseFVMKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseFVMKernels.cpp deleted file mode 100644 index e6636d930fa..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseFVMKernels.cpp +++ /dev/null @@ -1,695 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file IsothermalCompositionalMultiphaseFVMKernels.cpp - */ - -#include "IsothermalCompositionalMultiphaseFVMKernels.hpp" -#include "CompositionalMultiphaseUtilities.hpp" - -#include "finiteVolume/CellElementStencilTPFA.hpp" -#include "finiteVolume/SurfaceElementStencil.hpp" -#include "finiteVolume/EmbeddedSurfaceToCellStencil.hpp" -#include "finiteVolume/FaceElementToCellStencil.hpp" -#include "mesh/utilities/MeshMapUtilities.hpp" - -namespace geos -{ - -namespace isothermalCompositionalMultiphaseFVMKernels -{ - -/******************************** FaceBasedAssemblyKernel ********************************/ - -FaceBasedAssemblyKernelBase::FaceBasedAssemblyKernelBase( integer const numPhases, - globalIndex const rankOffset, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags ) - : m_numPhases( numPhases ), - m_rankOffset( rankOffset ), - m_dt( dt ), - m_dofNumber( dofNumberAccessor.toNestedViewConst() ), - m_ghostRank( compFlowAccessors.get( fields::ghostRank {} ) ), - m_gravCoef( compFlowAccessors.get( fields::flow::gravityCoefficient {} ) ), - m_pres( compFlowAccessors.get( fields::flow::pressure {} ) ), - m_dCompFrac_dCompDens( compFlowAccessors.get( fields::flow::dGlobalCompFraction_dGlobalCompDensity {} ) ), - m_dPhaseVolFrac( compFlowAccessors.get( fields::flow::dPhaseVolumeFraction {} ) ), - m_phaseCompFrac( multiFluidAccessors.get( fields::multifluid::phaseCompFraction {} ) ), - m_dPhaseCompFrac( multiFluidAccessors.get( fields::multifluid::dPhaseCompFraction {} ) ), - m_localMatrix( localMatrix ), - m_localRhs( localRhs ), - m_kernelFlags( kernelFlags ) -{} - -/******************************** CFLFluxKernel ********************************/ - -template< integer NC, localIndex NUM_ELEMS, localIndex maxStencilSize > -GEOS_HOST_DEVICE -inline -void -CFLFluxKernel:: - compute( integer const numPhases, - localIndex const stencilSize, - real64 const dt, - arraySlice1d< localIndex const > const seri, - arraySlice1d< localIndex const > const sesri, - arraySlice1d< localIndex const > const sei, - real64 const (&transmissibility)[2], - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, - ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const & phaseRelPerm, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseVisc, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementView< arrayView2d< real64, compflow::USD_PHASE > > const & phaseOutflux, - ElementView< arrayView2d< real64, compflow::USD_COMP > > const & compOutflux ) -{ - // loop over phases, compute and upwind phase flux and sum contributions to each component's flux - for( integer ip = 0; ip < numPhases; ++ip ) - { - - // clear working arrays - real64 densMean{}; - - // create local work arrays - real64 presGrad{}; - real64 gravHead{}; - - // calculate quantities on primary connected cells - for( localIndex i = 0; i < NUM_ELEMS; ++i ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - // average density across the face - densMean += 0.5 * phaseMassDens[er][esr][ei][0][ip]; - } - - //***** calculation of phase volumetric flux ***** - - // compute potential difference MPFA-style - for( localIndex i = 0; i < stencilSize; ++i ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - presGrad += transmissibility[i] * pres[er][esr][ei]; - gravHead += transmissibility[i] * densMean * gravCoef[er][esr][ei]; - } - - // *** upwinding *** - - // compute phase potential gradient - real64 const potGrad = presGrad - gravHead; - - // choose upstream cell - localIndex const k_up = (potGrad >= 0) ? 0 : 1; - - localIndex const er_up = seri[k_up]; - localIndex const esr_up = sesri[k_up]; - localIndex const ei_up = sei[k_up]; - - // compute the phase flux only if the phase is present - bool const phaseExists = (phaseVolFrac[er_up][esr_up][ei_up][ip] > 0); - if( !phaseExists ) - { - continue; - } - - real64 const mobility = phaseRelPerm[er_up][esr_up][ei_up][0][ip] / phaseVisc[er_up][esr_up][ei_up][0][ip]; - - // increment the phase (volumetric) outflux of the upstream cell - real64 const absPhaseFlux = LvArray::math::abs( dt * mobility * potGrad ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &phaseOutflux[er_up][esr_up][ei_up][ip], absPhaseFlux ); - - // increment the component (mass/molar) outflux of the upstream cell - for( integer ic = 0; ic < NC; ++ic ) - { - real64 const absCompFlux = phaseCompFrac[er_up][esr_up][ei_up][0][ip][ic] - * phaseDens[er_up][esr_up][ei_up][0][ip] - * absPhaseFlux; - RAJA::atomicAdd( parallelDeviceAtomic{}, &compOutflux[er_up][esr_up][ei_up][ic], absCompFlux ); - } - } -} - -template< integer NC, typename STENCILWRAPPER_TYPE > -void -CFLFluxKernel:: - launch( integer const numPhases, - real64 const dt, - STENCILWRAPPER_TYPE const & stencilWrapper, - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, - ElementViewConst< arrayView3d< real64 const > > const & permeability, - ElementViewConst< arrayView3d< real64 const > > const & dPerm_dPres, - ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const & phaseRelPerm, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseVisc, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementView< arrayView2d< real64, compflow::USD_PHASE > > const & phaseOutflux, - ElementView< arrayView2d< real64, compflow::USD_COMP > > const & compOutflux ) -{ - typename STENCILWRAPPER_TYPE::IndexContainerViewConstType const & seri = stencilWrapper.getElementRegionIndices(); - typename STENCILWRAPPER_TYPE::IndexContainerViewConstType const & sesri = stencilWrapper.getElementSubRegionIndices(); - typename STENCILWRAPPER_TYPE::IndexContainerViewConstType const & sei = stencilWrapper.getElementIndices(); - - localIndex constexpr numElems = STENCILWRAPPER_TYPE::maxNumPointsInFlux; - localIndex constexpr maxStencilSize = STENCILWRAPPER_TYPE::maxStencilSize; - - forAll< parallelDevicePolicy<> >( stencilWrapper.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - // compute transmissibility - real64 transmissibility[STENCILWRAPPER_TYPE::maxNumConnections][2]; - real64 dTrans_dPres[STENCILWRAPPER_TYPE::maxNumConnections][2]; - - stencilWrapper.computeWeights( iconn, - permeability, - dPerm_dPres, - transmissibility, - dTrans_dPres ); - - CFLFluxKernel::compute< NC, numElems, maxStencilSize >( numPhases, - sei[iconn].size(), - dt, - seri[iconn], - sesri[iconn], - sei[iconn], - transmissibility[0], - pres, - gravCoef, - phaseVolFrac, - phaseRelPerm, - phaseVisc, - phaseDens, - phaseMassDens, - phaseCompFrac, - phaseOutflux, - compOutflux ); - } ); -} - -#define INST_CFLFluxKernel( NC, STENCILWRAPPER_TYPE ) \ - template \ - void CFLFluxKernel:: \ - launch< NC, STENCILWRAPPER_TYPE >( integer const numPhases, \ - real64 const dt, \ - STENCILWRAPPER_TYPE const & stencil, \ - ElementViewConst< arrayView1d< real64 const > > const & pres, \ - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, \ - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, \ - ElementViewConst< arrayView3d< real64 const > > const & permeability, \ - ElementViewConst< arrayView3d< real64 const > > const & dPerm_dPres, \ - ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const & phaseRelPerm, \ - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseVisc, \ - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, \ - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseMassDens, \ - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, \ - ElementView< arrayView2d< real64, compflow::USD_PHASE > > const & phaseOutflux, \ - ElementView< arrayView2d< real64, compflow::USD_COMP > > const & compOutflux ) - -INST_CFLFluxKernel( 1, CellElementStencilTPFAWrapper ); -INST_CFLFluxKernel( 2, CellElementStencilTPFAWrapper ); -INST_CFLFluxKernel( 3, CellElementStencilTPFAWrapper ); -INST_CFLFluxKernel( 4, CellElementStencilTPFAWrapper ); -INST_CFLFluxKernel( 5, CellElementStencilTPFAWrapper ); - -INST_CFLFluxKernel( 1, SurfaceElementStencilWrapper ); -INST_CFLFluxKernel( 2, SurfaceElementStencilWrapper ); -INST_CFLFluxKernel( 3, SurfaceElementStencilWrapper ); -INST_CFLFluxKernel( 4, SurfaceElementStencilWrapper ); -INST_CFLFluxKernel( 5, SurfaceElementStencilWrapper ); - -INST_CFLFluxKernel( 1, EmbeddedSurfaceToCellStencilWrapper ); -INST_CFLFluxKernel( 2, EmbeddedSurfaceToCellStencilWrapper ); -INST_CFLFluxKernel( 3, EmbeddedSurfaceToCellStencilWrapper ); -INST_CFLFluxKernel( 4, EmbeddedSurfaceToCellStencilWrapper ); -INST_CFLFluxKernel( 5, EmbeddedSurfaceToCellStencilWrapper ); - -INST_CFLFluxKernel( 1, FaceElementToCellStencilWrapper ); -INST_CFLFluxKernel( 2, FaceElementToCellStencilWrapper ); -INST_CFLFluxKernel( 3, FaceElementToCellStencilWrapper ); -INST_CFLFluxKernel( 4, FaceElementToCellStencilWrapper ); -INST_CFLFluxKernel( 5, FaceElementToCellStencilWrapper ); - -#undef INST_CFLFluxKernel - -/******************************** CFLKernel ********************************/ - -template< integer NP > -GEOS_HOST_DEVICE -void -CFLKernel:: - computePhaseCFL( real64 const poreVol, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac, - arraySlice1d< real64 const, relperm::USD_RELPERM - 2 > phaseRelPerm, - arraySlice2d< real64 const, relperm::USD_RELPERM_DS - 2 > dPhaseRelPerm_dPhaseVolFrac, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseVisc, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseOutflux, - real64 & phaseCFLNumber ) -{ - // first, check which phases are mobile in the cell - real64 mob[NP]{}; - localIndex mobilePhases[NP]{}; - localIndex numMobilePhases = 0; - for( localIndex ip = 0; ip < NP; ++ip ) - { - if( phaseVolFrac[ip] > 0 ) - { - mob[ip] = phaseRelPerm[ip] / phaseVisc[ip]; - if( mob[ip] > minPhaseMobility ) - { - mobilePhases[numMobilePhases] = ip; - numMobilePhases++; - } - } - } - - // then, depending on the regime, apply the appropriate CFL formula - phaseCFLNumber = 0; - - // single-phase flow regime - if( numMobilePhases == 1 ) - { - phaseCFLNumber = phaseOutflux[mobilePhases[0]] / poreVol; - } - // two-phase flow regime - else if( numMobilePhases == 2 ) - { - // from Hui Cao's PhD thesis - localIndex const ip0 = mobilePhases[0]; - localIndex const ip1 = mobilePhases[1]; - real64 const dMob_dVolFrac[2] = { dPhaseRelPerm_dPhaseVolFrac[ip0][ip0] / phaseVisc[ip0], - -dPhaseRelPerm_dPhaseVolFrac[ip1][ip1] / phaseVisc[ip1] }; // using S0 = 1 - S1 - real64 const denom = 1. / ( poreVol * ( mob[ip0] + mob[ip1] ) ); - real64 const coef0 = denom * mob[ip1] / mob[ip0] * dMob_dVolFrac[ip0]; - real64 const coef1 = -denom * mob[ip0] / mob[ip1] * dMob_dVolFrac[ip1]; - - phaseCFLNumber = LvArray::math::abs( coef0*phaseOutflux[ip0] + coef1*phaseOutflux[ip1] ); - } - // three-phase flow regime - else if( numMobilePhases == 3 ) - { - // from Keith Coats, IMPES stability: Selection of stable timesteps (2003) - real64 totalMob = 0.0; - for( integer ip = 0; ip < numMobilePhases; ++ip ) - { - totalMob += mob[ip]; - } - - real64 f[2][2]{}; - for( integer i = 0; i < 2; ++i ) - { - for( integer j = 0; j < 2; ++j ) - { - f[i][j] = ( i == j )*totalMob - mob[i]; - f[i][j] /= (totalMob * mob[j]); - real64 sum = 0; - for( integer k = 0; k < 3; ++k ) - { - sum += dPhaseRelPerm_dPhaseVolFrac[k][j] / phaseVisc[k] - * phaseOutflux[j]; - } - f[i][j] *= sum; - } - } - phaseCFLNumber = f[0][0] + f[1][1]; - phaseCFLNumber += sqrt( phaseCFLNumber*phaseCFLNumber - 4 * ( f[0][0]*f[1][1] - f[1][0]*f[0][1] ) ); - phaseCFLNumber = 0.5 * LvArray::math::abs( phaseCFLNumber ) / poreVol; - } -} - - -template< integer NC > -GEOS_HOST_DEVICE -void -CFLKernel:: - computeCompCFL( real64 const poreVol, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > compDens, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > compFrac, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > compOutflux, - real64 & compCFLNumber ) -{ - - - compCFLNumber = 0.0; - for( integer ic = 0; ic < NC; ++ic ) - { - if( compFrac[ic] > minComponentFraction ) - { - real64 const compMoles = compDens[ic] * poreVol; - real64 const CFL = compOutflux[ic] / compMoles; - if( CFL > compCFLNumber ) - { - compCFLNumber = CFL; - } - } - } -} - -template< integer NC, integer NP > -void -CFLKernel:: - launch( localIndex const size, - arrayView1d< real64 const > const & volume, - arrayView2d< real64 const > const & porosity, - arrayView2d< real64 const, compflow::USD_COMP > const & compDens, - arrayView2d< real64 const, compflow::USD_COMP > const & compFrac, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac, - arrayView3d< real64 const, relperm::USD_RELPERM > const & phaseRelPerm, - arrayView4d< real64 const, relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, - arrayView3d< real64 const, multifluid::USD_PHASE > const & phaseVisc, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseOutflux, - arrayView2d< real64 const, compflow::USD_COMP > const & compOutflux, - arrayView1d< real64 > const & phaseCFLNumber, - arrayView1d< real64 > const & compCFLNumber, - real64 & maxPhaseCFLNumber, - real64 & maxCompCFLNumber ) -{ - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionPhaseCFLNumber( 0.0 ); - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionCompCFLNumber( 0.0 ); - - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - real64 const poreVol = volume[ei] * porosity[ei][0]; - - // phase CFL number - real64 cellPhaseCFLNumber = 0.0; - computePhaseCFL< NP >( poreVol, - phaseVolFrac[ei], - phaseRelPerm[ei][0], - dPhaseRelPerm_dPhaseVolFrac[ei][0], - phaseVisc[ei][0], - phaseOutflux[ei], - cellPhaseCFLNumber ); - subRegionPhaseCFLNumber.max( cellPhaseCFLNumber ); - phaseCFLNumber[ei] = cellPhaseCFLNumber; - - // component CFL number - real64 cellCompCFLNumber = 0.0; - computeCompCFL< NC >( poreVol, - compDens[ei], - compFrac[ei], - compOutflux[ei], - cellCompCFLNumber ); - subRegionCompCFLNumber.max( cellCompCFLNumber ); - compCFLNumber[ei] = cellCompCFLNumber; - } ); - - maxPhaseCFLNumber = subRegionPhaseCFLNumber.get(); - maxCompCFLNumber = subRegionCompCFLNumber.get(); -} - -#define INST_CFLKernel( NC, NP ) \ - template \ - void CFLKernel:: \ - launch< NC, NP >( localIndex const size, \ - arrayView1d< real64 const > const & volume, \ - arrayView2d< real64 const > const & porosity, \ - arrayView2d< real64 const, compflow::USD_COMP > const & compDens, \ - arrayView2d< real64 const, compflow::USD_COMP > const & compFrac, \ - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac, \ - arrayView3d< real64 const, relperm::USD_RELPERM > const & phaseRelPerm, \ - arrayView4d< real64 const, relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, \ - arrayView3d< real64 const, multifluid::USD_PHASE > const & phaseVisc, \ - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseOutflux, \ - arrayView2d< real64 const, compflow::USD_COMP > const & compOutflux, \ - arrayView1d< real64 > const & phaseCFLNumber, \ - arrayView1d< real64 > const & compCFLNumber, \ - real64 & maxPhaseCFLNumber, \ - real64 & maxCompCFLNumber ) -INST_CFLKernel( 1, 2 ); -INST_CFLKernel( 2, 2 ); -INST_CFLKernel( 3, 2 ); -INST_CFLKernel( 4, 2 ); -INST_CFLKernel( 5, 2 ); - -INST_CFLKernel( 1, 3 ); -INST_CFLKernel( 2, 3 ); -INST_CFLKernel( 3, 3 ); -INST_CFLKernel( 4, 3 ); -INST_CFLKernel( 5, 3 ); - -#undef INST_CFLKernel - -/******************************** AquiferBCKernel ********************************/ - -template< integer NC > -GEOS_HOST_DEVICE -void -AquiferBCKernel:: - compute( integer const numPhases, - integer const ipWater, - bool const allowAllPhasesIntoAquifer, - real64 const aquiferVolFlux, - real64 const dAquiferVolFlux_dPres, - real64 const aquiferWaterPhaseDens, - arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseDens, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac, - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > phaseCompFrac, - arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens, - real64 const dt, - real64 (& localFlux)[NC], - real64 (& localFluxJacobian)[NC][NC+1] ) -{ - using Deriv = multifluid::DerivativeOffset; - - real64 dProp_dC[NC]{}; - real64 dPhaseFlux_dCompDens[NC]{}; - - if( aquiferVolFlux > 0 ) // aquifer is upstream - { - // in this case, we assume that: - // - only the water phase is present in the aquifer - // - the aquifer water phase composition is constant - - for( integer ic = 0; ic < NC; ++ic ) - { - real64 const phaseFlux = aquiferVolFlux * aquiferWaterPhaseDens; - localFlux[ic] -= dt * phaseFlux * aquiferWaterPhaseCompFrac[ic]; - localFluxJacobian[ic][0] -= dt * dAquiferVolFlux_dPres * aquiferWaterPhaseDens * aquiferWaterPhaseCompFrac[ic]; - } - } - else // reservoir is upstream - { - for( integer ip = 0; ip < numPhases; ++ip ) - { - - // Why two options below: - // - The aquifer model assumes single-phase water flow, so ideally, we should only allow water phase flow from the reservoir to the - // aquifer - // - But, if/when the CO2 plume reaches the reservoir cell connected to the aquifer and saturates it, the aquifer flux becomes zero - // if we don't let some CO2 go into the aquifer - - if( ip == ipWater || allowAllPhasesIntoAquifer ) - { - real64 const phaseDensVolFrac = phaseDens[ip] * phaseVolFrac[ip]; - real64 const phaseFlux = aquiferVolFlux * phaseDensVolFrac; - real64 const dPhaseFlux_dPres = dAquiferVolFlux_dPres * phaseDensVolFrac - + aquiferVolFlux * ( dPhaseDens[ip][Deriv::dP] * phaseVolFrac[ip] + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dP] ); - - applyChainRule( NC, dCompFrac_dCompDens, dPhaseDens[ip], dProp_dC, Deriv::dC ); - for( integer ic = 0; ic < NC; ++ic ) - { - dPhaseFlux_dCompDens[ic] = aquiferVolFlux * ( dProp_dC[ic] * phaseVolFrac[ip] + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC+ic] ); - } - - for( integer ic = 0; ic < NC; ++ic ) - { - localFlux[ic] -= dt * phaseFlux * phaseCompFrac[ip][ic]; - localFluxJacobian[ic][0] -= dt * ( dPhaseFlux_dPres * phaseCompFrac[ip][ic] + phaseFlux * dPhaseCompFrac[ip][ic][Deriv::dP] ); - - applyChainRule( NC, dCompFrac_dCompDens, dPhaseCompFrac[ip][ic], dProp_dC, Deriv::dC ); - for( integer jc = 0; jc < NC; ++jc ) - { - localFluxJacobian[ic][jc+1] -= dt * ( dPhaseFlux_dCompDens[jc] * phaseCompFrac[ip][ic] + phaseFlux * dProp_dC[jc] ); - } - } - } - } - } -} - -template< integer NC > -void -AquiferBCKernel:: - launch( integer const numPhases, - integer const ipWater, - bool const allowAllPhasesIntoAquifer, - integer const useTotalMassEquation, - BoundaryStencil const & stencil, - globalIndex const rankOffset, - ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, - AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, - real64 const aquiferWaterPhaseDens, - arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, - ElementViewConst< arrayView1d< integer const > > const & ghostRank, - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & presOld, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, - real64 const timeAtBeginningOfStep, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - - using namespace compositionalMultiphaseUtilities; - using Order = BoundaryStencil::Order; - - BoundaryStencil::IndexContainerViewConstType const & seri = stencil.getElementRegionIndices(); - BoundaryStencil::IndexContainerViewConstType const & sesri = stencil.getElementSubRegionIndices(); - BoundaryStencil::IndexContainerViewConstType const & sefi = stencil.getElementIndices(); - BoundaryStencil::WeightContainerViewConstType const & weight = stencil.getWeights(); - - forAll< parallelDevicePolicy<> >( stencil.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - constexpr integer NDOF = NC + 1; - - // working arrays - globalIndex dofColIndices[NDOF]{}; - real64 localFlux[NC]{}; - real64 localFluxJacobian[NC][NDOF]{}; - - localIndex const er = seri( iconn, Order::ELEM ); - localIndex const esr = sesri( iconn, Order::ELEM ); - localIndex const ei = sefi( iconn, Order::ELEM ); - real64 const areaFraction = weight( iconn, Order::ELEM ); - - // compute the aquifer influx rate using the pressure influence function and the aquifer props - real64 dAquiferVolFlux_dPres = 0.0; - real64 const aquiferVolFlux = aquiferBCWrapper.compute( timeAtBeginningOfStep, - dt, - pres[er][esr][ei], - presOld[er][esr][ei], - gravCoef[er][esr][ei], - areaFraction, - dAquiferVolFlux_dPres ); - - // compute the phase/component aquifer flux - AquiferBCKernel::compute< NC >( numPhases, - ipWater, - allowAllPhasesIntoAquifer, - aquiferVolFlux, - dAquiferVolFlux_dPres, - aquiferWaterPhaseDens, - aquiferWaterPhaseCompFrac, - phaseDens[er][esr][ei][0], - dPhaseDens[er][esr][ei][0], - phaseVolFrac[er][esr][ei], - dPhaseVolFrac[er][esr][ei], - phaseCompFrac[er][esr][ei][0], - dPhaseCompFrac[er][esr][ei][0], - dCompFrac_dCompDens[er][esr][ei], - dt, - localFlux, - localFluxJacobian ); - - // populate dof indices - globalIndex const offset = dofNumber[er][esr][ei]; - for( integer jdof = 0; jdof < NDOF; ++jdof ) - { - dofColIndices[jdof] = offset + jdof; - } - - if( useTotalMassEquation > 0 ) - { - // Apply equation/variable change transformation(s) - real64 work[NDOF]; - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NDOF, localFluxJacobian, work ); - shiftElementsAheadByOneAndReplaceFirstElementWithSum( NC, localFlux ); - } - - // Add to residual/jacobian - if( ghostRank[er][esr][ei] < 0 ) - { - globalIndex const globalRow = dofNumber[er][esr][ei]; - localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - rankOffset ); - GEOS_ASSERT_GE( localRow, 0 ); - GEOS_ASSERT_GT( localMatrix.numRows(), localRow + NC ); - - for( integer ic = 0; ic < NC; ++ic ) - { - RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[localRow + ic], localFlux[ic] ); - localMatrix.addToRow< parallelDeviceAtomic >( localRow + ic, - dofColIndices, - localFluxJacobian[ic], - NDOF ); - } - } - } ); -} - -#define INST_AquiferBCKernel( NC ) \ - template \ - void AquiferBCKernel:: \ - launch< NC >( integer const numPhases, \ - integer const ipWater, \ - bool const allowAllPhasesIntoAquifer, \ - integer const useTotalMassEquation, \ - BoundaryStencil const & stencil, \ - globalIndex const rankOffset, \ - ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, \ - AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, \ - real64 const aquiferWaterPhaseDens, \ - arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, \ - ElementViewConst< arrayView1d< integer const > > const & ghostRank, \ - ElementViewConst< arrayView1d< real64 const > > const & pres, \ - ElementViewConst< arrayView1d< real64 const > > const & dPres, \ - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, \ - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, \ - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, \ - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, \ - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, \ - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseDens, \ - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, \ - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, \ - real64 const timeAtBeginningOfStep, \ - real64 const dt, \ - CRSMatrixView< real64, globalIndex const > const & localMatrix, \ - arrayView1d< real64 > const & localRhs ) - -INST_AquiferBCKernel( 1 ); -INST_AquiferBCKernel( 2 ); -INST_AquiferBCKernel( 3 ); -INST_AquiferBCKernel( 4 ); -INST_AquiferBCKernel( 5 ); - -#undef INST_AquiferBCKernel - -} // namespace isothermalCompositionalMultiphaseFVMKernels - -} // namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseFVMKernels.hpp deleted file mode 100644 index da4e426d578..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseFVMKernels.hpp +++ /dev/null @@ -1,2362 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file IsothermalCompositionalMultiphaseFVMKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP - -#include "codingUtilities/Utilities.hpp" -#include "common/DataLayouts.hpp" -#include "common/DataTypes.hpp" -#include "common/GEOS_RAJA_Interface.hpp" -#include "constitutive/capillaryPressure/CapillaryPressureFields.hpp" -#include "constitutive/capillaryPressure/CapillaryPressureBase.hpp" -#include "constitutive/diffusion/DiffusionFields.hpp" -#include "constitutive/diffusion/DiffusionBase.hpp" -#include "constitutive/dispersion/DispersionFields.hpp" -#include "constitutive/dispersion/DispersionBase.hpp" -#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" -#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" -#include "constitutive/fluid/multifluid/MultiFluidSelector.hpp" -#include "constitutive/permeability/PermeabilityFields.hpp" -#include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" -#include "constitutive/relativePermeability/RelativePermeabilityFields.hpp" -#include "constitutive/solid/porosity/PorosityBase.hpp" -#include "constitutive/solid/porosity/PorosityFields.hpp" -#include "fieldSpecification/AquiferBoundaryCondition.hpp" -#include "finiteVolume/BoundaryStencil.hpp" -#include "mesh/ElementRegionManager.hpp" -#include "mesh/utilities/MeshMapUtilities.hpp" -#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" -#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp" -#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" -#include "finiteVolume/FluxApproximationBase.hpp" - -namespace geos -{ - -namespace isothermalCompositionalMultiphaseFVMKernels -{ - -using namespace constitutive; - -enum class FaceBasedAssemblyKernelFlags -{ - /// Flag to specify whether capillary pressure is used or not - CapPressure = 1 << 0, // 1 - /// Flag indicating whether total mass equation is formed or not - TotalMassEquation = 1 << 1, // 2 - /// Flag indicating whether C1-PPU is used or not - C1PPU = 1 << 2, // 4 - /// Add more flags like that if needed: - // Flag4 = 1 << 3, // 8 - // Flag5 = 1 << 4, // 16 - // Flag6 = 1 << 5, // 32 - // Flag7 = 1 << 6, // 64 - // Flag8 = 1 << 7 //128 -}; - -/******************************** PhaseMobilityKernel ********************************/ - -/** - * @class PhaseMobilityKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_PHASE number of fluid phases - * @brief Define the interface for the property kernel in charge of computing the phase mobilities - */ -template< integer NUM_COMP, integer NUM_PHASE > -class PhaseMobilityKernel : public isothermalCompositionalMultiphaseBaseKernels::PropertyKernelBase< NUM_COMP > -{ -public: - - using Base = isothermalCompositionalMultiphaseBaseKernels::PropertyKernelBase< NUM_COMP >; - using Base::numComp; - - /// Compile time value for the number of phases - static constexpr integer numPhase = NUM_PHASE; - - /** - * @brief Constructor - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] relperm the relperm model - */ - PhaseMobilityKernel( ObjectManagerBase & subRegion, - MultiFluidBase const & fluid, - RelativePermeabilityBase const & relperm ) - : Base(), - m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), - m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ), - m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ), - m_phaseDens( fluid.phaseDensity() ), - m_dPhaseDens( fluid.dPhaseDensity() ), - m_phaseVisc( fluid.phaseViscosity() ), - m_dPhaseVisc( fluid.dPhaseViscosity() ), - m_phaseRelPerm( relperm.phaseRelPerm() ), - m_dPhaseRelPerm_dPhaseVolFrac( relperm.dPhaseRelPerm_dPhaseVolFraction() ), - m_phaseMob( subRegion.getField< fields::flow::phaseMobility >() ), - m_dPhaseMob( subRegion.getField< fields::flow::dPhaseMobility >() ) - {} - - /** - * @brief Compute the phase mobilities in an element - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[in] phaseMobilityKernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void compute( localIndex const ei, - FUNC && phaseMobilityKernelOp = NoOpFunc{} ) const - { - using Deriv = multifluid::DerivativeOffset; - - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const phaseDens = m_phaseDens[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const phaseVisc = m_phaseVisc[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const dPhaseVisc = m_dPhaseVisc[ei][0]; - arraySlice1d< real64 const, relperm::USD_RELPERM - 2 > const phaseRelPerm = m_phaseRelPerm[ei][0]; - arraySlice2d< real64 const, relperm::USD_RELPERM_DS - 2 > const dPhaseRelPerm_dPhaseVolFrac = m_dPhaseRelPerm_dPhaseVolFrac[ei][0]; - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const phaseVolFrac = m_phaseVolFrac[ei]; - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; - arraySlice1d< real64, compflow::USD_PHASE - 1 > const phaseMob = m_phaseMob[ei]; - arraySlice2d< real64, compflow::USD_PHASE_DC - 1 > const dPhaseMob = m_dPhaseMob[ei]; - - real64 dRelPerm_dC[numComp]{}; - real64 dDens_dC[numComp]{}; - real64 dVisc_dC[numComp]{}; - - for( integer ip = 0; ip < numPhase; ++ip ) - { - - // compute the phase mobility only if the phase is present - bool const phaseExists = (phaseVolFrac[ip] > 0); - if( !phaseExists ) - { - phaseMob[ip] = 0.0; - for( integer jc = 0; jc < numComp + 2; ++jc ) - { - dPhaseMob[ip][jc] = 0.0; - } - continue; - } - - real64 const density = phaseDens[ip]; - real64 const dDens_dP = dPhaseDens[ip][Deriv::dP]; - applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], dDens_dC, Deriv::dC ); - - real64 const viscosity = phaseVisc[ip]; - real64 const dVisc_dP = dPhaseVisc[ip][Deriv::dP]; - applyChainRule( numComp, dCompFrac_dCompDens, dPhaseVisc[ip], dVisc_dC, Deriv::dC ); - - real64 const relPerm = phaseRelPerm[ip]; - real64 dRelPerm_dP = 0.0; - for( integer ic = 0; ic < numComp; ++ic ) - { - dRelPerm_dC[ic] = 0.0; - } - - for( integer jp = 0; jp < numPhase; ++jp ) - { - real64 const dRelPerm_dS = dPhaseRelPerm_dPhaseVolFrac[ip][jp]; - dRelPerm_dP += dRelPerm_dS * dPhaseVolFrac[jp][Deriv::dP]; - - for( integer jc = 0; jc < numComp; ++jc ) - { - dRelPerm_dC[jc] += dRelPerm_dS * dPhaseVolFrac[jp][Deriv::dC+jc]; - } - } - - real64 const mobility = relPerm * density / viscosity; - - phaseMob[ip] = mobility; - dPhaseMob[ip][Deriv::dP] = dRelPerm_dP * density / viscosity - + mobility * (dDens_dP / density - dVisc_dP / viscosity); - - // compositional derivatives - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseMob[ip][Deriv::dC+jc] = dRelPerm_dC[jc] * density / viscosity - + mobility * (dDens_dC[jc] / density - dVisc_dC[jc] / viscosity); - } - - // call the lambda in the phase loop to allow the reuse of the relperm, density, viscosity, and mobility - // possible use: assemble the derivatives wrt temperature - phaseMobilityKernelOp( ip, phaseMob[ip], dPhaseMob[ip] ); - } - } - -protected: - - // inputs - - /// Views on the phase volume fractions - arrayView2d< real64 const, compflow::USD_PHASE > m_phaseVolFrac; - arrayView3d< real64 const, compflow::USD_PHASE_DC > m_dPhaseVolFrac; - arrayView3d< real64 const, compflow::USD_COMP_DC > m_dCompFrac_dCompDens; - - /// Views on the phase densities - arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseDens; - arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dPhaseDens; - - /// Views on the phase viscosities - arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseVisc; - arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dPhaseVisc; - - /// Views on the phase relative permeabilities - arrayView3d< real64 const, relperm::USD_RELPERM > m_phaseRelPerm; - arrayView4d< real64 const, relperm::USD_RELPERM_DS > m_dPhaseRelPerm_dPhaseVolFrac; - - // outputs - - /// Views on the phase mobilities - arrayView2d< real64, compflow::USD_PHASE > m_phaseMob; - arrayView3d< real64, compflow::USD_PHASE_DC > m_dPhaseMob; - -}; - -/** - * @class PhaseMobilityKernelFactory - */ -class PhaseMobilityKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] numComp the number of fluid components - * @param[in] numPhase the number of fluid phases - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] relperm the relperm model - */ - template< typename POLICY > - static void - createAndLaunch( integer const numComp, - integer const numPhase, - ObjectManagerBase & subRegion, - MultiFluidBase const & fluid, - RelativePermeabilityBase const & relperm ) - { - if( numPhase == 2 ) - { - isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseMobilityKernel< NUM_COMP, 2 > kernel( subRegion, fluid, relperm ); - PhaseMobilityKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - else if( numPhase == 3 ) - { - isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseMobilityKernel< NUM_COMP, 3 > kernel( subRegion, fluid, relperm ); - PhaseMobilityKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - } -}; - - -/******************************** FaceBasedAssemblyKernel ********************************/ - -/** - * @brief Base class for FaceBasedAssemblyKernel that holds all data not dependent - * on template parameters (like stencil type and number of components/dofs). - */ -class FaceBasedAssemblyKernelBase -{ -public: - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using DofNumberAccessor = ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > >; - - using CompFlowAccessors = - StencilAccessors< fields::ghostRank, - fields::flow::gravityCoefficient, - fields::flow::pressure, - fields::flow::dGlobalCompFraction_dGlobalCompDensity, - fields::flow::phaseVolumeFraction, - fields::flow::dPhaseVolumeFraction, - fields::flow::phaseMobility, - fields::flow::dPhaseMobility >; - using MultiFluidAccessors = - StencilMaterialAccessors< MultiFluidBase, - fields::multifluid::phaseDensity, - fields::multifluid::dPhaseDensity, - fields::multifluid::phaseMassDensity, - fields::multifluid::dPhaseMassDensity, - fields::multifluid::phaseCompFraction, - fields::multifluid::dPhaseCompFraction >; - - using CapPressureAccessors = - StencilMaterialAccessors< CapillaryPressureBase, - fields::cappres::phaseCapPressure, - fields::cappres::dPhaseCapPressure_dPhaseVolFraction >; - - using PermeabilityAccessors = - StencilMaterialAccessors< PermeabilityBase, - fields::permeability::permeability, - fields::permeability::dPerm_dPressure >; - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofNumberAccessor accessor for the dof numbers - * @param[in] compFlowAccessors accessor for wrappers registered by the solver - * @param[in] multiFluidAccessors accessor for wrappers registered by the multifluid model - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - * @param[in] kernelFlags flags packed all together - */ - FaceBasedAssemblyKernelBase( integer const numPhases, - globalIndex const rankOffset, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags ); - -protected: - - /// Number of fluid phases - integer const m_numPhases; - - /// Offset for my MPI rank - globalIndex const m_rankOffset; - - /// Time step size - real64 const m_dt; - - /// Views on dof numbers - ElementViewConst< arrayView1d< globalIndex const > > const m_dofNumber; - - /// Views on ghost rank numbers and gravity coefficients - ElementViewConst< arrayView1d< integer const > > const m_ghostRank; - ElementViewConst< arrayView1d< real64 const > > const m_gravCoef; - - // Primary and secondary variables - - /// Views on pressure - ElementViewConst< arrayView1d< real64 const > > const m_pres; - - /// Views on derivatives of phase volume fractions and comp fractions - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const m_dCompFrac_dCompDens; - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const m_dPhaseVolFrac; - - /// Views on phase component fractions - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const m_phaseCompFrac; - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const m_dPhaseCompFrac; - - // Residual and jacobian - - /// View on the local CRS matrix - CRSMatrixView< real64, globalIndex const > const m_localMatrix; - /// View on the local RHS - arrayView1d< real64 > const m_localRhs; - - BitFlags< FaceBasedAssemblyKernelFlags > const m_kernelFlags; -}; - -/** - * @class FaceBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @brief Define the interface for the assembly kernel in charge of flux terms - */ -template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > -class FaceBasedAssemblyKernel : public FaceBasedAssemblyKernelBase -{ -public: - - /// Compile time value for the number of components - static constexpr integer numComp = NUM_COMP; - - /// Compute time value for the number of degrees of freedom - static constexpr integer numDof = NUM_DOF; - - /// Compute time value for the number of equations (all of them, except the volume balance equation) - static constexpr integer numEqn = NUM_DOF-1; - - /// Maximum number of elements at the face - static constexpr localIndex maxNumElems = STENCILWRAPPER::maxNumPointsInFlux; - - /// Maximum number of connections at the face - static constexpr localIndex maxNumConns = STENCILWRAPPER::maxNumConnections; - - /// Maximum number of points in the stencil - static constexpr localIndex maxStencilSize = STENCILWRAPPER::maxStencilSize; - - /// Number of flux support points (hard-coded for TFPA) - static constexpr integer numFluxSupportPoints = 2; - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dofNumberAccessor - * @param[in] compFlowAccessors - * @param[in] multiFluidAccessors - * @param[in] capPressureAccessors - * @param[in] permeabilityAccessors - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - * @param[in] kernelFlags flags packed together - */ - FaceBasedAssemblyKernel( integer const numPhases, - globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - CapPressureAccessors const & capPressureAccessors, - PermeabilityAccessors const & permeabilityAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags ) - : FaceBasedAssemblyKernelBase( numPhases, - rankOffset, - dofNumberAccessor, - compFlowAccessors, - multiFluidAccessors, - dt, - localMatrix, - localRhs, - kernelFlags ), - m_permeability( permeabilityAccessors.get( fields::permeability::permeability {} ) ), - m_dPerm_dPres( permeabilityAccessors.get( fields::permeability::dPerm_dPressure {} ) ), - m_phaseMob( compFlowAccessors.get( fields::flow::phaseMobility {} ) ), - m_dPhaseMob( compFlowAccessors.get( fields::flow::dPhaseMobility {} ) ), - m_phaseMassDens( multiFluidAccessors.get( fields::multifluid::phaseMassDensity {} ) ), - m_dPhaseMassDens( multiFluidAccessors.get( fields::multifluid::dPhaseMassDensity {} ) ), - m_phaseCapPressure( capPressureAccessors.get( fields::cappres::phaseCapPressure {} ) ), - m_dPhaseCapPressure_dPhaseVolFrac( capPressureAccessors.get( fields::cappres::dPhaseCapPressure_dPhaseVolFraction {} ) ), - m_stencilWrapper( stencilWrapper ), - m_seri( stencilWrapper.getElementRegionIndices() ), - m_sesri( stencilWrapper.getElementSubRegionIndices() ), - m_sei( stencilWrapper.getElementIndices() ) - { } - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - struct StackVariables - { -public: - - /** - * @brief Constructor for the stack variables - * @param[in] size size of the stencil for this connection - * @param[in] numElems number of elements for this connection - */ - GEOS_HOST_DEVICE - StackVariables( localIndex const size, localIndex numElems ) - : stencilSize( size ), - numConnectedElems( numElems ), - dofColIndices( size * numDof ), - localFlux( numElems * numEqn ), - localFluxJacobian( numElems * numEqn, size * numDof ) - {} - - // Stencil information - - /// Stencil size for a given connection - localIndex const stencilSize; - /// Number of elements connected at a given connection - localIndex const numConnectedElems; - - // Transmissibility and derivatives - - /// Transmissibility - real64 transmissibility[maxNumConns][numFluxSupportPoints]{}; - /// Derivatives of transmissibility with respect to pressure - real64 dTrans_dPres[maxNumConns][numFluxSupportPoints]{}; - - // Local degrees of freedom and local residual/jacobian - - /// Indices of the matrix rows/columns corresponding to the dofs in this face - stackArray1d< globalIndex, maxNumElems * numDof > dofColIndices; - - /// Storage for the face local residual vector (all equations except volume balance) - stackArray1d< real64, maxNumElems * numEqn > localFlux; - /// Storage for the face local Jacobian matrix - stackArray2d< real64, maxNumElems * numEqn * maxStencilSize * numDof > localFluxJacobian; - }; - - - /** - * @brief Getter for the stencil size at this connection - * @param[in] iconn the connection index - * @return the size of the stencil at this connection - */ - GEOS_HOST_DEVICE - inline - localIndex stencilSize( localIndex const iconn ) const - { return m_sei[iconn].size(); } - - /** - * @brief Getter for the number of elements at this connection - * @param[in] iconn the connection index - * @return the number of elements at this connection - */ - GEOS_HOST_DEVICE - inline - localIndex numPointsInFlux( localIndex const iconn ) const - { return m_stencilWrapper.numPointsInFlux( iconn ); } - - - /** - * @brief Performs the setup phase for the kernel. - * @param[in] iconn the connection index - * @param[in] stack the stack variables - */ - GEOS_HOST_DEVICE - inline - void setup( localIndex const iconn, - StackVariables & stack ) const - { - // set degrees of freedom indices for this face - for( integer i = 0; i < stack.stencilSize; ++i ) - { - globalIndex const offset = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; - - for( integer jdof = 0; jdof < numDof; ++jdof ) - { - stack.dofColIndices[i * numDof + jdof] = offset + jdof; - } - } - } - - /** - * @brief Compute the local flux contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - inline - void computeFlux( localIndex const iconn, - StackVariables & stack, - FUNC && compFluxKernelOp = NoOpFunc{} ) const - { - // first, compute the transmissibilities at this face - m_stencilWrapper.computeWeights( iconn, - m_permeability, - m_dPerm_dPres, - stack.transmissibility, - stack.dTrans_dPres ); - - - localIndex k[numFluxSupportPoints]; - localIndex connectionIndex = 0; - for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) - { - for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) - { - /// cell indices - localIndex const seri[numFluxSupportPoints] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; - localIndex const sesri[numFluxSupportPoints] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; - localIndex const sei[numFluxSupportPoints] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; - - // clear working arrays - real64 compFlux[numComp]{}; - real64 dCompFlux_dP[numFluxSupportPoints][numComp]{}; - real64 dCompFlux_dC[numFluxSupportPoints][numComp][numComp]{}; - - real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], - stack.transmissibility[connectionIndex][1] }; - - real64 const dTrans_dPres[numFluxSupportPoints] = { stack.dTrans_dPres[connectionIndex][0], - stack.dTrans_dPres[connectionIndex][1] }; - - //***** calculation of flux ***** - // loop over phases, compute and upwind phase flux and sum contributions to each component's flux - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - // create local work arrays - real64 potGrad = 0.0; - real64 phaseFlux = 0.0; - real64 dPhaseFlux_dP[numFluxSupportPoints]{}; - real64 dPhaseFlux_dC[numFluxSupportPoints][numComp]{}; - - localIndex k_up = -1; - - if( m_kernelFlags.isSet( FaceBasedAssemblyKernelFlags::C1PPU )) - { - isothermalCompositionalMultiphaseFVMKernelUtilities::C1PPUPhaseFlux::compute< numComp, numFluxSupportPoints > - ( m_numPhases, - ip, - m_kernelFlags.isSet( FaceBasedAssemblyKernelFlags::CapPressure ), - seri, sesri, sei, - trans, - dTrans_dPres, - m_pres, - m_gravCoef, - m_phaseMob, m_dPhaseMob, - m_dPhaseVolFrac, - m_dCompFrac_dCompDens, - m_phaseMassDens, m_dPhaseMassDens, - m_phaseCapPressure, m_dPhaseCapPressure_dPhaseVolFrac, - k_up, - potGrad, - phaseFlux, - dPhaseFlux_dP, - dPhaseFlux_dC ); - } - else - { - isothermalCompositionalMultiphaseFVMKernelUtilities::PPUPhaseFlux::compute< numComp, numFluxSupportPoints > - ( m_numPhases, - ip, - m_kernelFlags.isSet( FaceBasedAssemblyKernelFlags::CapPressure ), - seri, sesri, sei, - trans, - dTrans_dPres, - m_pres, - m_gravCoef, - m_phaseMob, m_dPhaseMob, - m_dPhaseVolFrac, - m_dCompFrac_dCompDens, - m_phaseMassDens, m_dPhaseMassDens, - m_phaseCapPressure, m_dPhaseCapPressure_dPhaseVolFrac, - k_up, - potGrad, - phaseFlux, - dPhaseFlux_dP, - dPhaseFlux_dC ); - } - - isothermalCompositionalMultiphaseFVMKernelUtilities:: - PhaseComponentFlux::compute< numComp, numFluxSupportPoints > - ( ip, - k_up, - seri, sesri, sei, - m_phaseCompFrac, m_dPhaseCompFrac, - m_dCompFrac_dCompDens, - phaseFlux, dPhaseFlux_dP, dPhaseFlux_dC, - compFlux, dCompFlux_dP, dCompFlux_dC ); - - // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives - // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase - compFluxKernelOp( ip, k, seri, sesri, sei, connectionIndex, - k_up, seri[k_up], sesri[k_up], sei[k_up], potGrad, - phaseFlux, dPhaseFlux_dP, dPhaseFlux_dC ); - - } // loop over phases - - // populate local flux vector and derivatives - for( integer ic = 0; ic < numComp; ++ic ) - { - integer const eqIndex0 = k[0] * numEqn + ic; - integer const eqIndex1 = k[1] * numEqn + ic; - - stack.localFlux[eqIndex0] += m_dt * compFlux[ic]; - stack.localFlux[eqIndex1] -= m_dt * compFlux[ic]; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - localIndex const localDofIndexPres = k[ke] * numDof; - stack.localFluxJacobian[eqIndex0][localDofIndexPres] += m_dt * dCompFlux_dP[ke][ic]; - stack.localFluxJacobian[eqIndex1][localDofIndexPres] -= m_dt * dCompFlux_dP[ke][ic]; - - for( integer jc = 0; jc < numComp; ++jc ) - { - localIndex const localDofIndexComp = localDofIndexPres + jc + 1; - stack.localFluxJacobian[eqIndex0][localDofIndexComp] += m_dt * dCompFlux_dC[ke][ic][jc]; - stack.localFluxJacobian[eqIndex1][localDofIndexComp] -= m_dt * dCompFlux_dC[ke][ic][jc]; - } - } - } - connectionIndex++; - } // loop over k[1] - } // loop over k[0] - - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - inline - void complete( localIndex const iconn, - StackVariables & stack, - FUNC && assemblyKernelOp = NoOpFunc{} ) const - { - using namespace compositionalMultiphaseUtilities; - - if( m_kernelFlags.isSet( FaceBasedAssemblyKernelFlags::TotalMassEquation ) ) - { - // Apply equation/variable change transformation(s) - stackArray1d< real64, maxStencilSize * numDof > work( stack.stencilSize * numDof ); - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numEqn, numDof * stack.stencilSize, stack.numConnectedElems, - stack.localFluxJacobian, work ); - shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numComp, numEqn, stack.numConnectedElems, - stack.localFlux ); - } - - // add contribution to residual and jacobian into: - // - the component mass balance equations (i = 0 to i = numComp-1) - // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels - for( integer i = 0; i < stack.numConnectedElems; ++i ) - { - if( m_ghostRank[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )] < 0 ) - { - globalIndex const globalRow = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; - localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); - GEOS_ASSERT_GE( localRow, 0 ); - GEOS_ASSERT_GT( m_localMatrix.numRows(), localRow + numComp ); - - for( integer ic = 0; ic < numComp; ++ic ) - { - RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[localRow + ic], stack.localFlux[i * numEqn + ic] ); - m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > - ( localRow + ic, - stack.dofColIndices.data(), - stack.localFluxJacobian[i * numEqn + ic].dataIfContiguous(), - stack.stencilSize * numDof ); - } - - // call the lambda to assemble additional terms, such as thermal terms - assemblyKernelOp( i, localRow ); - } - } - } - - /** - * @brief Performs the kernel launch - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] numConnections the number of connections - * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables - */ - template< typename POLICY, typename KERNEL_TYPE > - static void - launch( localIndex const numConnections, - KERNEL_TYPE const & kernelComponent ) - { - GEOS_MARK_FUNCTION; - forAll< POLICY >( numConnections, [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), - kernelComponent.numPointsInFlux( iconn ) ); - - kernelComponent.setup( iconn, stack ); - kernelComponent.computeFlux( iconn, stack ); - kernelComponent.complete( iconn, stack ); - } ); - } - -protected: - - /// Views on permeability - ElementViewConst< arrayView3d< real64 const > > const m_permeability; - ElementViewConst< arrayView3d< real64 const > > const m_dPerm_dPres; - - /// Views on phase mobilities - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_phaseMob; - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const m_dPhaseMob; - - /// Views on phase mass densities - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_phaseMassDens; - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dPhaseMassDens; - - /// Views on phase capillary pressure - ElementViewConst< arrayView3d< real64 const, cappres::USD_CAPPRES > > const m_phaseCapPressure; - ElementViewConst< arrayView4d< real64 const, cappres::USD_CAPPRES_DS > > const m_dPhaseCapPressure_dPhaseVolFrac; - - // Stencil information - - /// Reference to the stencil wrapper - STENCILWRAPPER const m_stencilWrapper; - - /// Connection to element maps - typename STENCILWRAPPER::IndexContainerViewConstType const m_seri; - typename STENCILWRAPPER::IndexContainerViewConstType const m_sesri; - typename STENCILWRAPPER::IndexContainerViewConstType const m_sei; - -}; - -/** - * @class FaceBasedAssemblyKernelFactory - */ -class FaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @param[in] numComps the number of fluid components - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey string to get the element degrees of freedom numbers - * @param[in] hasCapPressure flag specifying whether capillary pressure is used or not - * @param[in] solverName name of the solver (to name accessors) - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY, typename STENCILWRAPPER > - static void - createAndLaunch( integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - string const & dofKey, - integer const hasCapPressure, - integer const useTotalMassEquation, - UpwindingParameters upwindingParams, - string const & solverName, - ElementRegionManager const & elemManager, - STENCILWRAPPER const & stencilWrapper, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) - { - integer constexpr NUM_COMP = NC(); - integer constexpr NUM_DOF = NC() + 1; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags; - if( hasCapPressure ) - kernelFlags.set( FaceBasedAssemblyKernelFlags::CapPressure ); - if( useTotalMassEquation ) - kernelFlags.set( FaceBasedAssemblyKernelFlags::TotalMassEquation ); - if( upwindingParams.upwindingScheme == UpwindingScheme::C1PPU && - isothermalCompositionalMultiphaseFVMKernelUtilities::epsC1PPU > 0 ) - kernelFlags.set( FaceBasedAssemblyKernelFlags::C1PPU ); - - using kernelType = FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); - typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); - typename kernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); - typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); - - kernelType kernel( numPhases, rankOffset, stencilWrapper, dofNumberAccessor, - compFlowAccessors, multiFluidAccessors, capPressureAccessors, permeabilityAccessors, - dt, localMatrix, localRhs, kernelFlags ); - kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); - } ); - } -}; - -/******************************** DiffusionDispersionFaceBasedAssemblyKernel ********************************/ - -/** - * @class DiffusionDispersionFaceBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @brief Define the interface for the assembly kernel in charge of diffusion/dispersion flux terms - */ -template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > -class DiffusionDispersionFaceBasedAssemblyKernel : public FaceBasedAssemblyKernelBase -{ -public: - - /// Compile time value for the number of components - static constexpr integer numComp = NUM_COMP; - - /// Compute time value for the number of degrees of freedom - static constexpr integer numDof = NUM_DOF; - - /// Compute time value for the number of equations (all of them, except the volume balance equation) - static constexpr integer numEqn = NUM_DOF-1; - - /// Maximum number of elements at the face - static constexpr localIndex maxNumElems = STENCILWRAPPER::maxNumPointsInFlux; - - /// Maximum number of connections at the face - static constexpr localIndex maxNumConns = STENCILWRAPPER::maxNumConnections; - - /// Maximum number of points in the stencil - static constexpr localIndex maxStencilSize = STENCILWRAPPER::maxStencilSize; - - /// Number of flux support points (hard-coded for TFPA) - static constexpr integer numFluxSupportPoints = 2; - - using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelBase; - using AbstractBase::m_dPhaseVolFrac; - using AbstractBase::m_kernelFlags; - - using DiffusionAccessors = - StencilMaterialAccessors< DiffusionBase, - fields::diffusion::diffusivity, - fields::diffusion::dDiffusivity_dTemperature, - fields::diffusion::phaseDiffusivityMultiplier >; - - using DispersionAccessors = - StencilMaterialAccessors< DispersionBase, - fields::dispersion::dispersivity >; - - using PorosityAccessors = - StencilMaterialAccessors< PorosityBase, - fields::porosity::referencePorosity >; - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dofNumberAccessor - * @param[in] compFlowAccessors - * @param[in] multiFluidAccessors - * @param[in] diffusionAccessors - * @param[in] dispersionAccessors - * @param[in] porosityAccessors - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - * @param[in] kernelFlags flags packed together - */ - DiffusionDispersionFaceBasedAssemblyKernel( integer const numPhases, - globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - DiffusionAccessors const & diffusionAccessors, - DispersionAccessors const & dispersionAccessors, - PorosityAccessors const & porosityAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags ) - : FaceBasedAssemblyKernelBase( numPhases, - rankOffset, - dofNumberAccessor, - compFlowAccessors, - multiFluidAccessors, - dt, - localMatrix, - localRhs, - kernelFlags ), - m_phaseVolFrac( compFlowAccessors.get( fields::flow::phaseVolumeFraction {} ) ), - m_phaseDens( multiFluidAccessors.get( fields::multifluid::phaseDensity {} ) ), - m_dPhaseDens( multiFluidAccessors.get( fields::multifluid::dPhaseDensity {} ) ), - m_diffusivity( diffusionAccessors.get( fields::diffusion::diffusivity {} ) ), - m_dDiffusivity_dTemp( diffusionAccessors.get( fields::diffusion::dDiffusivity_dTemperature {} ) ), - m_phaseDiffusivityMultiplier( diffusionAccessors.get( fields::diffusion::phaseDiffusivityMultiplier {} ) ), - m_dispersivity( dispersionAccessors.get( fields::dispersion::dispersivity {} ) ), - m_referencePorosity( porosityAccessors.get( fields::porosity::referencePorosity {} ) ), - m_stencilWrapper( stencilWrapper ), - m_seri( stencilWrapper.getElementRegionIndices() ), - m_sesri( stencilWrapper.getElementSubRegionIndices() ), - m_sei( stencilWrapper.getElementIndices() ) - { } - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - struct StackVariables - { -public: - - /** - * @brief Constructor for the stack variables - * @param[in] size size of the stencil for this connection - * @param[in] numElems number of elements for this connection - */ - GEOS_HOST_DEVICE - StackVariables( localIndex const size, localIndex numElems ) - : stencilSize( size ), - numConnectedElems( numElems ), - dofColIndices( size * numDof ), - localFlux( numElems * numEqn ), - localFluxJacobian( numElems * numEqn, size * numDof ) - {} - - // Stencil information - - /// Stencil size for a given connection - localIndex const stencilSize; - /// Number of elements connected at a given connection - localIndex const numConnectedElems; - - /// Transmissibility - real64 transmissibility[maxNumConns][numFluxSupportPoints]{}; - /// Derivatives of transmissibility with respect to pressure - real64 dTrans_dTemp[maxNumConns][numFluxSupportPoints]{}; - - // Local degrees of freedom and local residual/jacobian - - /// Indices of the matrix rows/columns corresponding to the dofs in this face - stackArray1d< globalIndex, maxNumElems * numDof > dofColIndices; - - /// Storage for the face local residual vector (all equations except volume balance) - stackArray1d< real64, maxNumElems * numEqn > localFlux; - /// Storage for the face local Jacobian matrix - stackArray2d< real64, maxNumElems * numEqn * maxStencilSize * numDof > localFluxJacobian; - }; - - - /** - * @brief Getter for the stencil size at this connection - * @param[in] iconn the connection index - * @return the size of the stencil at this connection - */ - GEOS_HOST_DEVICE - inline - localIndex stencilSize( localIndex const iconn ) const - { return m_sei[iconn].size(); } - - /** - * @brief Getter for the number of elements at this connection - * @param[in] iconn the connection index - * @return the number of elements at this connection - */ - GEOS_HOST_DEVICE - inline - localIndex numPointsInFlux( localIndex const iconn ) const - { return m_stencilWrapper.numPointsInFlux( iconn ); } - - - /** - * @brief Performs the setup phase for the kernel. - * @param[in] iconn the connection index - * @param[in] stack the stack variables - */ - GEOS_HOST_DEVICE - inline - void setup( localIndex const iconn, - StackVariables & stack ) const - { - // set degrees of freedom indices for this face - for( integer i = 0; i < stack.stencilSize; ++i ) - { - globalIndex const offset = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; - - for( integer jdof = 0; jdof < numDof; ++jdof ) - { - stack.dofColIndices[i * numDof + jdof] = offset + jdof; - } - } - } - - /** - * @brief Compute the local diffusion flux contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - * @param[in] diffusionFluxKernelOp the function used to customize the computation of the component fluxes - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - inline - void computeDiffusionFlux( localIndex const iconn, - StackVariables & stack, - FUNC && diffusionFluxKernelOp = NoOpFunc{} ) const - { - using Deriv = multifluid::DerivativeOffset; - - // first, compute the transmissibilities at this face - m_stencilWrapper.computeWeights( iconn, - m_diffusivity, - m_dDiffusivity_dTemp, - stack.transmissibility, - stack.dTrans_dTemp ); - - - localIndex k[numFluxSupportPoints]{}; - localIndex connectionIndex = 0; - for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) - { - for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) - { - /// cell indices - localIndex const seri[numFluxSupportPoints] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; - localIndex const sesri[numFluxSupportPoints] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; - localIndex const sei[numFluxSupportPoints] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; - - // clear working arrays - real64 diffusionFlux[numComp]{}; - real64 dDiffusionFlux_dP[numFluxSupportPoints][numComp]{}; - real64 dDiffusionFlux_dC[numFluxSupportPoints][numComp][numComp]{}; - real64 dDens_dC[numComp]{}; - - real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], - stack.transmissibility[connectionIndex][1] }; - - //***** calculation of flux ***** - // loop over phases, compute and upwind phase flux and sum contributions to each component's flux - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - - // loop over components - for( integer ic = 0; ic < numComp; ++ic ) - { - - real64 compFracGrad = 0.0; - real64 dCompFracGrad_dP[numFluxSupportPoints]{}; - real64 dCompFracGrad_dC[numFluxSupportPoints][numComp]{}; - - // compute the component fraction gradient using the diffusion transmissibility - computeCompFractionGradient( ip, ic, - seri, sesri, sei, - trans, - compFracGrad, - dCompFracGrad_dP, - dCompFracGrad_dC ); - - // choose upstream cell for composition upwinding - localIndex const k_up = (compFracGrad >= 0) ? 0 : 1; - - localIndex const er_up = seri[k_up]; - localIndex const esr_up = sesri[k_up]; - localIndex const ei_up = sei[k_up]; - - // computation of the upwinded mass flux - real64 const upwindCoefficient = - m_referencePorosity[er_up][esr_up][ei_up] * - m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * - m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_phaseVolFrac[er_up][esr_up][ei_up][ip]; - diffusionFlux[ic] += upwindCoefficient * compFracGrad; - - // add contributions of the derivatives of component fractions wrt pressure/component fractions - for( integer ke = 0; ke < numFluxSupportPoints; ke++ ) - { - dDiffusionFlux_dP[ke][ic] += upwindCoefficient * dCompFracGrad_dP[ke]; - for( integer jc = 0; jc < numComp; ++jc ) - { - dDiffusionFlux_dC[ke][ic][jc] += upwindCoefficient * dCompFracGrad_dC[ke][jc]; - } - } - - // add contributions of the derivatives of upwind coefficient wrt pressure/component fractions - real64 const dUpwindCoefficient_dP = - m_referencePorosity[er_up][esr_up][ei_up] * - m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * - ( m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dP] * m_phaseVolFrac[er_up][esr_up][ei_up][ip] - + m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_dPhaseVolFrac[er_up][esr_up][ei_up][ip][Deriv::dP] ); - dDiffusionFlux_dP[k_up][ic] += dUpwindCoefficient_dP * compFracGrad; - - applyChainRule( numComp, - m_dCompFrac_dCompDens[er_up][esr_up][ei_up], - m_dPhaseDens[er_up][esr_up][ei_up][0][ip], - dDens_dC, - Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - real64 const dUpwindCoefficient_dC = - m_referencePorosity[er_up][esr_up][ei_up] * - m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * - ( dDens_dC[jc] * m_phaseVolFrac[er_up][esr_up][ei_up][ip] - + m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_dPhaseVolFrac[er_up][esr_up][ei_up][ip][Deriv::dC+jc] ); - dDiffusionFlux_dC[k_up][ic][jc] += dUpwindCoefficient_dC * compFracGrad; - } - - // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives - // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase - diffusionFluxKernelOp( ip, ic, k, seri, sesri, sei, connectionIndex, - k_up, seri[k_up], sesri[k_up], sei[k_up], - compFracGrad, upwindCoefficient ); - - } // loop over components - } // loop over phases - - // add diffusion flux to local flux and local flux jacobian - addToLocalFluxAndJacobian( k, - stack, - diffusionFlux, - dDiffusionFlux_dP, - dDiffusionFlux_dC ); - - connectionIndex++; - } // loop over k[1] - } // loop over k[0] - } - - /** - * @brief Compute the local dispersion flux contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - * @param[in] dispersionFluxKernelOp the function used to customize the computation of the component fluxes - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - inline - void computeDispersionFlux( localIndex const iconn, - StackVariables & stack, - FUNC && dispersionFluxKernelOp = NoOpFunc{} ) const - { - using Deriv = multifluid::DerivativeOffset; - - // first, compute the transmissibilities at this face - // note that the dispersion tensor is lagged in iteration - m_stencilWrapper.computeWeights( iconn, - m_dispersivity, - m_dispersivity, // this is just to pass something, but the resulting derivative won't be used - stack.transmissibility, - stack.dTrans_dTemp ); // will not be used - - - localIndex k[numFluxSupportPoints]{}; - localIndex connectionIndex = 0; - for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) - { - for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) - { - /// cell indices - localIndex const seri[numFluxSupportPoints] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; - localIndex const sesri[numFluxSupportPoints] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; - localIndex const sei[numFluxSupportPoints] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; - - // clear working arrays - real64 dispersionFlux[numComp]{}; - real64 dDispersionFlux_dP[numFluxSupportPoints][numComp]{}; - real64 dDispersionFlux_dC[numFluxSupportPoints][numComp][numComp]{}; - real64 dDens_dC[numComp]{}; - - real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], - stack.transmissibility[connectionIndex][1] }; - - //***** calculation of flux ***** - // loop over phases, compute and upwind phase flux and sum contributions to each component's flux - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - - // loop over components - for( integer ic = 0; ic < numComp; ++ic ) - { - - real64 compFracGrad = 0.0; - real64 dCompFracGrad_dP[numFluxSupportPoints]{}; - real64 dCompFracGrad_dC[numFluxSupportPoints][numComp]{}; - - // compute the component fraction gradient using the dispersion transmissibility - computeCompFractionGradient( ip, ic, - seri, sesri, sei, - trans, - compFracGrad, - dCompFracGrad_dP, - dCompFracGrad_dC ); - - // choose upstream cell for composition upwinding - localIndex const k_up = (compFracGrad >= 0) ? 0 : 1; - - localIndex const er_up = seri[k_up]; - localIndex const esr_up = sesri[k_up]; - localIndex const ei_up = sei[k_up]; - - // computation of the upwinded mass flux - dispersionFlux[ic] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * compFracGrad; - - // add contributions of the derivatives of component fractions wrt pressure/component fractions - for( integer ke = 0; ke < numFluxSupportPoints; ke++ ) - { - dDispersionFlux_dP[ke][ic] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * dCompFracGrad_dP[ke]; - for( integer jc = 0; jc < numComp; ++jc ) - { - dDispersionFlux_dC[ke][ic][jc] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * dCompFracGrad_dC[ke][jc]; - } - } - - // add contributions of the derivatives of upwind coefficient wrt pressure/component fractions - dDispersionFlux_dP[k_up][ic] += m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dP] * compFracGrad; - - applyChainRule( numComp, - m_dCompFrac_dCompDens[er_up][esr_up][ei_up], - m_dPhaseDens[er_up][esr_up][ei_up][0][ip], - dDens_dC, - Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - dDispersionFlux_dC[k_up][ic][jc] += dDens_dC[jc] * compFracGrad; - } - - // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives - // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase - dispersionFluxKernelOp( ip, ic, k, seri, sesri, sei, connectionIndex, - k_up, seri[k_up], sesri[k_up], sei[k_up], - compFracGrad ); - - } // loop over components - } // loop over phases - - // add dispersion flux to local flux and local flux jacobian - addToLocalFluxAndJacobian( k, - stack, - dispersionFlux, - dDispersionFlux_dP, - dDispersionFlux_dC ); - - connectionIndex++; - } // loop over k[1] - } // loop over k[0] - } - - /** - * @brief Compute the component fraction gradient at this interface - * @param[in] ip the phase index - * @param[in] ic the component index - * @param[in] seri the region indices - * @param[in] sesri the subregion indices - * @param[in] sei the element indices - * @param[out] compFracGrad the component fraction gradient - * @param[out] dCompFracGrad_dP the derivatives of the component fraction gradient wrt pressure - * @param[out] dCompFracGrad_dC the derivatives of the component fraction gradient wrt component densities - */ - GEOS_HOST_DEVICE - inline - void computeCompFractionGradient( integer const ip, - integer const ic, - localIndex const (&seri)[numFluxSupportPoints], - localIndex const (&sesri)[numFluxSupportPoints], - localIndex const (&sei)[numFluxSupportPoints], - real64 const (&trans)[numFluxSupportPoints], - real64 & compFracGrad, - real64 (& dCompFracGrad_dP)[numFluxSupportPoints], - real64 (& dCompFracGrad_dC)[numFluxSupportPoints][numComp] ) const - { - using Deriv = multifluid::DerivativeOffset; - - real64 dCompFrac_dC[numComp]{}; - - for( integer i = 0; i < numFluxSupportPoints; i++ ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - compFracGrad += trans[i] * m_phaseCompFrac[er][esr][ei][0][ip][ic]; - dCompFracGrad_dP[i] += trans[i] * m_dPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dP]; - - applyChainRule( numComp, - m_dCompFrac_dCompDens[er][esr][ei], - m_dPhaseCompFrac[er][esr][ei][0][ip][ic], - dCompFrac_dC, - Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - dCompFracGrad_dC[i][jc] += trans[i] * dCompFrac_dC[jc]; - } - } - } - - /** - * @brief Add the local diffusion/dispersion flux contributions to the residual and Jacobian - * @param[in] k the cell indices - * @param[in] stack the stack variables - * @param[in] flux the diffusion/dispersion flux - * @param[in] dFlux_dP the derivative of the diffusion/dispersion flux wrt pressure - * @param[in] dFlux_dC the derivative of the diffusion/dispersion flux wrt compositions - */ - GEOS_HOST_DEVICE - inline - void addToLocalFluxAndJacobian( localIndex const (&k)[numFluxSupportPoints], - StackVariables & stack, - real64 const (&flux)[numComp], - real64 const (&dFlux_dP)[numFluxSupportPoints][numComp], - real64 const (&dFlux_dC)[numFluxSupportPoints][numComp][numComp] ) const - { - // loop over components - for( integer ic = 0; ic < numComp; ++ic ) - { - // finally, increment local flux and local Jacobian - integer const eqIndex0 = k[0] * numEqn + ic; - integer const eqIndex1 = k[1] * numEqn + ic; - - stack.localFlux[eqIndex0] += m_dt * flux[ic]; - stack.localFlux[eqIndex1] -= m_dt * flux[ic]; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - localIndex const localDofIndexPres = k[ke] * numDof; - stack.localFluxJacobian[eqIndex0][localDofIndexPres] += m_dt * dFlux_dP[ke][ic]; - stack.localFluxJacobian[eqIndex1][localDofIndexPres] -= m_dt * dFlux_dP[ke][ic]; - - for( integer jc = 0; jc < numComp; ++jc ) - { - localIndex const localDofIndexComp = localDofIndexPres + jc + 1; - stack.localFluxJacobian[eqIndex0][localDofIndexComp] += m_dt * dFlux_dC[ke][ic][jc]; - stack.localFluxJacobian[eqIndex1][localDofIndexComp] -= m_dt * dFlux_dC[ke][ic][jc]; - } - } - } - } - - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - inline - void complete( localIndex const iconn, - StackVariables & stack, - FUNC && assemblyKernelOp = NoOpFunc{} ) const - { - using namespace compositionalMultiphaseUtilities; - - if( m_kernelFlags.isSet( FaceBasedAssemblyKernelFlags::TotalMassEquation ) ) - { - // Apply equation/variable change transformation(s) - stackArray1d< real64, maxStencilSize * numDof > work( stack.stencilSize * numDof ); - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numEqn, numDof*stack.stencilSize, stack.numConnectedElems, - stack.localFluxJacobian, work ); - shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numComp, numEqn, stack.numConnectedElems, - stack.localFlux ); - } - - // add contribution to residual and jacobian into: - // - the component mass balance equations (i = 0 to i = numComp-1) - // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels - for( integer i = 0; i < stack.numConnectedElems; ++i ) - { - if( m_ghostRank[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )] < 0 ) - { - globalIndex const globalRow = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; - localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); - GEOS_ASSERT_GE( localRow, 0 ); - GEOS_ASSERT_GT( m_localMatrix.numRows(), localRow + numComp ); - - for( integer ic = 0; ic < numComp; ++ic ) - { - RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[localRow + ic], stack.localFlux[i * numEqn + ic] ); - m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > - ( localRow + ic, - stack.dofColIndices.data(), - stack.localFluxJacobian[i * numEqn + ic].dataIfContiguous(), - stack.stencilSize * numDof ); - } - - // call the lambda to assemble additional terms, such as thermal terms - assemblyKernelOp( i, localRow ); - } - } - } - - /** - * @brief Performs the kernel launch - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] numConnections the number of connections - * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables - */ - template< typename POLICY, typename KERNEL_TYPE > - static void - launch( localIndex const numConnections, - integer const hasDiffusion, - integer const hasDispersion, - KERNEL_TYPE const & kernelComponent ) - { - GEOS_MARK_FUNCTION; - forAll< POLICY >( numConnections, [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), - kernelComponent.numPointsInFlux( iconn ) ); - - kernelComponent.setup( iconn, stack ); - if( hasDiffusion ) - { - kernelComponent.computeDiffusionFlux( iconn, stack ); - } - if( hasDispersion ) - { - kernelComponent.computeDispersionFlux( iconn, stack ); - } - kernelComponent.complete( iconn, stack ); - } ); - } - -protected: - - /// Views on phase volume fraction - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_phaseVolFrac; - - /// Views on phase densities - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_phaseDens; - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dPhaseDens; - - /// Views on diffusivity - ElementViewConst< arrayView3d< real64 const > > const m_diffusivity; - ElementViewConst< arrayView3d< real64 const > > const m_dDiffusivity_dTemp; - ElementViewConst< arrayView3d< real64 const > > const m_phaseDiffusivityMultiplier; - - /// Views on dispersivity - ElementViewConst< arrayView3d< real64 const > > const m_dispersivity; - - /// View on the reference porosity - ElementViewConst< arrayView1d< real64 const > > const m_referencePorosity; - - // Stencil information - - /// Reference to the stencil wrapper - STENCILWRAPPER const m_stencilWrapper; - - /// Connection to element maps - typename STENCILWRAPPER::IndexContainerViewConstType const m_seri; - typename STENCILWRAPPER::IndexContainerViewConstType const m_sesri; - typename STENCILWRAPPER::IndexContainerViewConstType const m_sei; - -}; - -/** - * @class DiffusionDispersionFaceBasedAssemblyKernelFactory - */ -class DiffusionDispersionFaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @param[in] numComps the number of fluid components - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey string to get the element degrees of freedom numbers - * @param[in] hasDiffusion flag specifying whether diffusion is used or not - * @param[in] hasDispersion flag specifying whether dispersion is used or not - * @param[in] solverName the name of the solver - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY, typename STENCILWRAPPER > - static void - createAndLaunch( integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - string const & dofKey, - integer const hasDiffusion, - integer const hasDispersion, - integer const useTotalMassEquation, - string const & solverName, - ElementRegionManager const & elemManager, - STENCILWRAPPER const & stencilWrapper, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) - { - integer constexpr NUM_COMP = NC(); - integer constexpr NUM_DOF = NC() + 1; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags; - if( useTotalMassEquation ) - kernelFlags.set( FaceBasedAssemblyKernelFlags::TotalMassEquation ); - - using kernelType = DiffusionDispersionFaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); - typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); - typename kernelType::DiffusionAccessors diffusionAccessors( elemManager, solverName ); - typename kernelType::DispersionAccessors dispersionAccessors( elemManager, solverName ); - typename kernelType::PorosityAccessors porosityAccessors( elemManager, solverName ); - - kernelType kernel( numPhases, rankOffset, stencilWrapper, - dofNumberAccessor, compFlowAccessors, multiFluidAccessors, - diffusionAccessors, dispersionAccessors, porosityAccessors, - dt, localMatrix, localRhs, kernelFlags ); - kernelType::template launch< POLICY >( stencilWrapper.size(), - hasDiffusion, hasDispersion, - kernel ); - } ); - } -}; - - -/******************************** DirichletFaceBasedAssemblyKernel ********************************/ - -/** - * @class DirichFaceBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @tparam FLUIDWRAPPER the type of the fluid wrapper - * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms - */ -template< integer NUM_COMP, integer NUM_DOF, typename FLUIDWRAPPER > -class DirichletFaceBasedAssemblyKernel : public FaceBasedAssemblyKernel< NUM_COMP, - NUM_DOF, - BoundaryStencilWrapper > -{ -public: - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelBase; - using DofNumberAccessor = AbstractBase::DofNumberAccessor; - using CompFlowAccessors = AbstractBase::CompFlowAccessors; - using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; - using CapPressureAccessors = AbstractBase::CapPressureAccessors; - using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; - - using AbstractBase::m_dt; - using AbstractBase::m_numPhases; - using AbstractBase::m_rankOffset; - using AbstractBase::m_dofNumber; - using AbstractBase::m_ghostRank; - using AbstractBase::m_gravCoef; - using AbstractBase::m_pres; - using AbstractBase::m_phaseCompFrac; - using AbstractBase::m_dPhaseCompFrac; - using AbstractBase::m_dCompFrac_dCompDens; - using AbstractBase::m_localMatrix; - using AbstractBase::m_localRhs; - using AbstractBase::m_kernelFlags; - - using Base = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, BoundaryStencilWrapper >; - using Base::numComp; - using Base::numDof; - using Base::numEqn; - using Base::m_stencilWrapper; - using Base::m_phaseMob; - using Base::m_dPhaseMob; - using Base::m_phaseMassDens; - using Base::m_dPhaseMassDens; - using Base::m_permeability; - using Base::m_dPerm_dPres; - using Base::m_seri; - using Base::m_sesri; - using Base::m_sei; - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] faceManager the face manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] fluidWrapper reference to the fluid wrapper - * @param[in] dofNumberAccessor - * @param[in] compFlowAccessors - * @param[in] multiFluidAccessors - * @param[in] capPressureAccessors - * @param[in] permeabilityAccessors - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - * @param[in] kernelFlags flags packed together - */ - DirichletFaceBasedAssemblyKernel( integer const numPhases, - globalIndex const rankOffset, - FaceManager const & faceManager, - BoundaryStencilWrapper const & stencilWrapper, - FLUIDWRAPPER const & fluidWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - CapPressureAccessors const & capPressureAccessors, - PermeabilityAccessors const & permeabilityAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags ) - : Base( numPhases, - rankOffset, - stencilWrapper, - dofNumberAccessor, - compFlowAccessors, - multiFluidAccessors, - capPressureAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs, - kernelFlags ), - m_facePres( faceManager.getField< fields::flow::facePressure >() ), - m_faceTemp( faceManager.getField< fields::flow::faceTemperature >() ), - m_faceCompFrac( faceManager.getField< fields::flow::faceGlobalCompFraction >() ), - m_faceGravCoef( faceManager.getField< fields::flow::gravityCoefficient >() ), - m_fluidWrapper( fluidWrapper ) - {} - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - struct StackVariables - { -public: - - /** - * @brief Constructor for the stack variables - * @param[in] size size of the stencil for this connection - * @param[in] numElems number of elements for this connection - */ - GEOS_HOST_DEVICE - StackVariables( localIndex const GEOS_UNUSED_PARAM( size ), - localIndex GEOS_UNUSED_PARAM( numElems ) ) - {} - - // Transmissibility - real64 transmissibility = 0.0; - - // Component fluxes and derivatives - - /// Component fluxes - real64 compFlux[numComp]{}; - /// Derivatives of component fluxes wrt pressure - real64 dCompFlux_dP[numComp]{}; - /// Derivatives of component fluxes wrt component densities - real64 dCompFlux_dC[numComp][numComp]{}; - - // Local degrees of freedom and local residual/jacobian - - /// Indices of the matrix rows/columns corresponding to the dofs in this face - globalIndex dofColIndices[numDof]{}; - - /// Storage for the face local residual vector - real64 localFlux[numEqn]{}; - /// Storage for the face local Jacobian matrix - real64 localFluxJacobian[numEqn][numDof]{}; - - }; - - - /** - * @brief Performs the setup phase for the kernel. - * @param[in] iconn the connection index - * @param[in] stack the stack variables - */ - GEOS_HOST_DEVICE - void setup( localIndex const iconn, - StackVariables & stack ) const - { - globalIndex const offset = - m_dofNumber[m_seri( iconn, BoundaryStencil::Order::ELEM )][m_sesri( iconn, BoundaryStencil::Order::ELEM )][m_sei( iconn, BoundaryStencil::Order::ELEM )]; - - for( integer jdof = 0; jdof < numDof; ++jdof ) - { - stack.dofColIndices[jdof] = offset + jdof; - } - } - - - /** - * @brief Compute the local Dirichlet face flux contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void computeFlux( localIndex const iconn, - StackVariables & stack, - FUNC && compFluxKernelOp = NoOpFunc{} ) const - { - using Deriv = multifluid::DerivativeOffset; - using Order = BoundaryStencil::Order; - - localIndex const er = m_seri( iconn, Order::ELEM ); - localIndex const esr = m_sesri( iconn, Order::ELEM ); - localIndex const ei = m_sei( iconn, Order::ELEM ); - localIndex const kf = m_sei( iconn, Order::FACE ); - - // Step 1: compute the transmissibility at the boundary face - - real64 dTrans_dPerm[3]{}; - m_stencilWrapper.computeWeights( iconn, - m_permeability, - stack.transmissibility, - dTrans_dPerm ); - real64 const dTrans_dPres = LvArray::tensorOps::AiBi< 3 >( dTrans_dPerm, m_dPerm_dPres[er][esr][ei][0] ); - - // Step 2: compute the fluid properties on the face - // This is needed to get the phase mass density and the phase comp fraction at the face - // Because we approximate the face mobility using the total element mobility - - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, multifluid::LAYOUT_PHASE > facePhaseFrac( 1, 1, m_numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, multifluid::LAYOUT_PHASE > facePhaseDens( 1, 1, m_numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, multifluid::LAYOUT_PHASE > facePhaseMassDens( 1, 1, m_numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, multifluid::LAYOUT_PHASE > facePhaseVisc( 1, 1, m_numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, multifluid::LAYOUT_PHASE > facePhaseEnthalpy( 1, 1, m_numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, multifluid::LAYOUT_PHASE > facePhaseInternalEnergy( 1, 1, m_numPhases ); - StackArray< real64, 4, constitutive::MultiFluidBase::MAX_NUM_PHASES * NUM_COMP, - multifluid::LAYOUT_PHASE_COMP > facePhaseCompFrac( 1, 1, m_numPhases, NUM_COMP ); - real64 faceTotalDens = 0.0; - - MultiFluidBase::KernelWrapper::computeValues( m_fluidWrapper, - m_facePres[kf], - m_faceTemp[kf], - m_faceCompFrac[kf], - facePhaseFrac[0][0], - facePhaseDens[0][0], - facePhaseMassDens[0][0], - facePhaseVisc[0][0], - facePhaseEnthalpy[0][0], - facePhaseInternalEnergy[0][0], - facePhaseCompFrac[0][0], - faceTotalDens ); - - // Step 3: loop over phases, compute and upwind phase flux and sum contributions to each component's flux - - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - - // working variables - real64 dDensMean_dC[numComp]{}; - real64 dF_dC[numComp]{}; - real64 dProp_dC[numComp]{}; - - real64 phaseFlux = 0.0; // for the lambda - real64 dPhaseFlux_dP = 0.0; - real64 dPhaseFlux_dC[numComp]{}; - - - // Step 3.1: compute the average phase mass density at the face - - applyChainRule( numComp, - m_dCompFrac_dCompDens[er][esr][ei], - m_dPhaseMassDens[er][esr][ei][0][ip], - dProp_dC, - Deriv::dC ); - - // average density and derivatives - real64 const densMean = 0.5 * ( m_phaseMassDens[er][esr][ei][0][ip] + facePhaseMassDens[0][0][ip] ); - real64 const dDensMean_dP = 0.5 * m_dPhaseMassDens[er][esr][ei][0][ip][Deriv::dP]; - for( integer jc = 0; jc < numComp; ++jc ) - { - dDensMean_dC[jc] = 0.5 * dProp_dC[jc]; - } - - - // Step 3.2: compute the (TPFA) potential difference at the face - - real64 const gravTimesDz = m_gravCoef[er][esr][ei] - m_faceGravCoef[kf]; - real64 const potDif = m_pres[er][esr][ei] - m_facePres[kf] - densMean * gravTimesDz; - real64 const f = stack.transmissibility * potDif; - real64 const dF_dP = stack.transmissibility * ( 1.0 - dDensMean_dP * gravTimesDz ) + dTrans_dPres * potDif; - for( integer jc = 0; jc < numComp; ++jc ) - { - dF_dC[jc] = -stack.transmissibility * dDensMean_dC[jc] * gravTimesDz; - } - - // Step 3.3: computation of the mobility - // We do that before the if/else statement to be able to pass it to the compFluxOpKernel - - // recomputing the exact mobility at the face would be quite complex, as it would require: - // 1) computing the saturation - // 2) computing the relperm - // 3) computing the mobility as \lambda_p = \rho_p kr_p( S_p ) / \mu_p - // the second step in particular would require yet another dispatch to get the relperm model - // so, for simplicity, we approximate the face mobility as - // \lambda^approx_p = \rho_p S_p / \mu_p - // = \rho_p ( (nu_p / rho_p) * rho_t ) / \mu_p (plugging the expression of saturation) - // = \nu_p * rho_t / \mu_p - // fortunately, we don't need the derivatives - real64 const facePhaseMob = ( facePhaseFrac[0][0][ip] > 0.0 ) - ? facePhaseFrac[0][0][ip] * faceTotalDens / facePhaseVisc[0][0][ip] - : 0.0; - - // *** upwinding *** - // Step 3.4: upwinding based on the sign of the phase potential gradient - // It is easier to hard-code the if/else because it is difficult to address elem and face variables in a uniform way - - if( potDif >= 0 ) // the element is upstream - { - - // compute the phase flux and derivatives using the element mobility - phaseFlux = m_phaseMob[er][esr][ei][ip] * f; - dPhaseFlux_dP = m_phaseMob[er][esr][ei][ip] * dF_dP + m_dPhaseMob[er][esr][ei][ip][Deriv::dP] * f; - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseFlux_dC[jc] = - m_phaseMob[er][esr][ei][ip] * dF_dC[jc] + m_dPhaseMob[er][esr][ei][ip][Deriv::dC+jc] * f; - } - - // slice some constitutive arrays to avoid too much indexing in component loop - arraySlice1d< real64 const, multifluid::USD_PHASE_COMP-3 > phaseCompFracSub = - m_phaseCompFrac[er][esr][ei][0][ip]; - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP_DC-3 > dPhaseCompFracSub = - m_dPhaseCompFrac[er][esr][ei][0][ip]; - - // compute component fluxes and derivatives using element composition - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 const ycp = phaseCompFracSub[ic]; - stack.compFlux[ic] += phaseFlux * ycp; - stack.dCompFlux_dP[ic] += dPhaseFlux_dP * ycp + phaseFlux * dPhaseCompFracSub[ic][Deriv::dP]; - - applyChainRule( numComp, - m_dCompFrac_dCompDens[er][esr][ei], - dPhaseCompFracSub[ic], - dProp_dC, - Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - stack.dCompFlux_dC[ic][jc] += dPhaseFlux_dC[jc] * ycp + phaseFlux * dProp_dC[jc]; - } - } - - } - else // the face is upstream - { - - // compute the phase flux and derivatives using the approximated face mobility - // we only have to take derivatives of the potential gradient in this case - phaseFlux = facePhaseMob * f; - dPhaseFlux_dP = facePhaseMob * dF_dP; - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseFlux_dC[jc] = facePhaseMob * dF_dC[jc]; - } - - // compute component fluxes and derivatives using the face composition - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 const ycp = facePhaseCompFrac[0][0][ip][ic]; - stack.compFlux[ic] += phaseFlux * ycp; - stack.dCompFlux_dP[ic] += dPhaseFlux_dP * ycp; - for( integer jc = 0; jc < numComp; ++jc ) - { - stack.dCompFlux_dC[ic][jc] += dPhaseFlux_dC[jc] * ycp; - } - } - } - - // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives - // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase - compFluxKernelOp( ip, er, esr, ei, kf, f, - facePhaseMob, facePhaseEnthalpy[0][0], facePhaseCompFrac[0][0], - phaseFlux, dPhaseFlux_dP, dPhaseFlux_dC ); - - } - - // *** end of upwinding - - // Step 4: populate local flux vector and derivatives - for( integer ic = 0; ic < numComp; ++ic ) - { - stack.localFlux[ic] = m_dt * stack.compFlux[ic]; - stack.localFluxJacobian[ic][0] = m_dt * stack.dCompFlux_dP[ic]; - for( integer jc = 0; jc < numComp; ++jc ) - { - stack.localFluxJacobian[ic][jc+1] = m_dt * stack.dCompFlux_dC[ic][jc]; - } - } - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void complete( localIndex const iconn, - StackVariables & stack, - FUNC && assemblyKernelOp = NoOpFunc{} ) const - { - using namespace compositionalMultiphaseUtilities; - using Order = BoundaryStencil::Order; - - if( AbstractBase::m_kernelFlags.isSet( FaceBasedAssemblyKernelFlags::TotalMassEquation ) ) - { - // Apply equation/variable change transformation(s) - real64 work[numDof]{}; - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numDof, stack.localFluxJacobian, work ); - shiftElementsAheadByOneAndReplaceFirstElementWithSum( numComp, stack.localFlux ); - } - - // add contribution to residual and jacobian into: - // - the component mass balance equations (i = 0 to i = numComp-1) - // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels - if( m_ghostRank[m_seri( iconn, Order::ELEM )][m_sesri( iconn, Order::ELEM )][m_sei( iconn, Order::ELEM )] < 0 ) - { - globalIndex const globalRow = m_dofNumber[m_seri( iconn, Order::ELEM )][m_sesri( iconn, Order::ELEM )][m_sei( iconn, Order::ELEM )]; - localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); - GEOS_ASSERT_GE( localRow, 0 ); - GEOS_ASSERT_GT( AbstractBase::m_localMatrix.numRows(), localRow + numComp ); - - for( integer ic = 0; ic < numComp; ++ic ) - { - RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + ic], stack.localFlux[ic] ); - AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > - ( localRow + ic, - stack.dofColIndices, - stack.localFluxJacobian[ic], - numDof ); - } - - // call the lambda to assemble additional terms, such as thermal terms - assemblyKernelOp( localRow ); - } - } - -protected: - - /// Views on face pressure, temperature, and composition - arrayView1d< real64 const > const m_facePres; - arrayView1d< real64 const > const m_faceTemp; - arrayView2d< real64 const, compflow::USD_COMP > const m_faceCompFrac; - - /// View on the face gravity coefficient - arrayView1d< real64 const > const m_faceGravCoef; - - /// Reference to the fluid wrapper - FLUIDWRAPPER const m_fluidWrapper; - -}; - - -/** - * @class DirichletFaceBasedAssemblyKernelFactory - */ -class DirichletFaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] numComps the number of fluid components - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey string to get the element degrees of freedom numbers - * @param[in] solverName name of the solver (to name accessors) - * @param[in] faceManager reference to the face manager - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the boundary stencil wrapper - * @param[in] fluidBase the multifluid constitutive model - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY > - static void - createAndLaunch( integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - integer const useTotalMassEquation, - string const & dofKey, - string const & solverName, - FaceManager const & faceManager, - ElementRegionManager const & elemManager, - BoundaryStencilWrapper const & stencilWrapper, - MultiFluidBase & fluidBase, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - constitutive::constitutiveUpdatePassThru( fluidBase, [&]( auto & fluid ) - { - using FluidType = TYPEOFREF( fluid ); - typename FluidType::KernelWrapper const fluidWrapper = fluid.createKernelWrapper(); - - isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) - { - integer constexpr NUM_COMP = NC(); - integer constexpr NUM_DOF = NC() + 1; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - // for now, we neglect capillary pressure in the kernel - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags; - if( useTotalMassEquation ) - kernelFlags.set( FaceBasedAssemblyKernelFlags::TotalMassEquation ); - - using kernelType = DirichletFaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, typename FluidType::KernelWrapper >; - typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); - typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); - typename kernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); - typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); - - kernelType kernel( numPhases, rankOffset, faceManager, stencilWrapper, fluidWrapper, - dofNumberAccessor, compFlowAccessors, multiFluidAccessors, capPressureAccessors, permeabilityAccessors, - dt, localMatrix, localRhs, kernelFlags ); - kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); - } ); - } ); - } -}; - - -/******************************** CFLFluxKernel ********************************/ - -/** - * @brief Functions to compute the (outflux) total volumetric flux needed in the calculation of CFL numbers - */ -struct CFLFluxKernel -{ - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - template< typename VIEWTYPE > - using ElementView = ElementRegionManager::ElementView< VIEWTYPE >; - - using CompFlowAccessors = - StencilAccessors< fields::flow::pressure, - fields::flow::gravityCoefficient, - fields::flow::phaseVolumeFraction, - fields::flow::phaseOutflux, - fields::flow::componentOutflux >; - - using MultiFluidAccessors = - StencilMaterialAccessors< MultiFluidBase, - fields::multifluid::phaseViscosity, - fields::multifluid::phaseDensity, - fields::multifluid::phaseMassDensity, - fields::multifluid::phaseCompFraction >; - - using PermeabilityAccessors = - StencilMaterialAccessors< PermeabilityBase, - fields::permeability::permeability, - fields::permeability::dPerm_dPressure >; - - - using RelPermAccessors = - StencilMaterialAccessors< RelativePermeabilityBase, fields::relperm::phaseRelPerm >; - - template< integer NC, localIndex NUM_ELEMS, localIndex maxStencilSize > - GEOS_HOST_DEVICE - inline - static void - compute( integer const numPhases, - localIndex const stencilSize, - real64 const dt, - arraySlice1d< localIndex const > const seri, - arraySlice1d< localIndex const > const sesri, - arraySlice1d< localIndex const > const sei, - real64 const (&transmissibility)[2], - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, - ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const & phaseRelPerm, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseVisc, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementView< arrayView2d< real64, compflow::USD_PHASE > > const & phaseOutflux, - ElementView< arrayView2d< real64, compflow::USD_COMP > > const & compOutflux ); - - template< integer NC, typename STENCILWRAPPER_TYPE > - static void - launch( integer const numPhases, - real64 const dt, - STENCILWRAPPER_TYPE const & stencil, - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, - ElementViewConst< arrayView3d< real64 const > > const & permeability, - ElementViewConst< arrayView3d< real64 const > > const & dPerm_dPres, - ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const & phaseRelPerm, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseVisc, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementView< arrayView2d< real64, compflow::USD_PHASE > > const & phaseOutflux, - ElementView< arrayView2d< real64, compflow::USD_COMP > > const & compOutflux ); -}; - -/******************************** CFLKernel ********************************/ - -/** - * @brief Functions to compute the CFL number using the phase volumetric outflux and the component mass outflux in each cell - */ -struct CFLKernel -{ - - static constexpr real64 minPhaseMobility = 1e-12; - static constexpr real64 minComponentFraction = 1e-12; - - template< integer NP > - GEOS_HOST_DEVICE - inline - static void - computePhaseCFL( real64 const poreVol, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac, - arraySlice1d< real64 const, relperm::USD_RELPERM - 2 > phaseRelPerm, - arraySlice2d< real64 const, relperm::USD_RELPERM_DS - 2 > dPhaseRelPerm_dPhaseVolFrac, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseVisc, - arraySlice1d< real64 const, compflow::USD_PHASE- 1 > phaseOutflux, - real64 & phaseCFLNumber ); - - template< integer NC > - GEOS_HOST_DEVICE - inline - static void - computeCompCFL( real64 const poreVol, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > compDens, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > compFrac, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > compOutflux, - real64 & compCFLNumber ); - - template< integer NC, integer NP > - static void - launch( localIndex const size, - arrayView1d< real64 const > const & volume, - arrayView2d< real64 const > const & porosity, - arrayView2d< real64 const, compflow::USD_COMP > const & compDens, - arrayView2d< real64 const, compflow::USD_COMP > const & compFrac, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac, - arrayView3d< real64 const, relperm::USD_RELPERM > const & phaseRelPerm, - arrayView4d< real64 const, relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, - arrayView3d< real64 const, multifluid::USD_PHASE > const & phaseVisc, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseOutflux, - arrayView2d< real64 const, compflow::USD_COMP > const & compOutflux, - arrayView1d< real64 > const & phaseCFLNumber, - arrayView1d< real64 > const & compCFLNumber, - real64 & maxPhaseCFLNumber, - real64 & maxCompCFLNumber ); - -}; - -/******************************** AquiferBCKernel ********************************/ - -/** - * @brief Functions to assemble aquifer boundary condition contributions to residual and Jacobian - */ -struct AquiferBCKernel -{ - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using CompFlowAccessors = - StencilAccessors< fields::ghostRank, - fields::flow::pressure, - fields::flow::pressure_n, - fields::flow::gravityCoefficient, - fields::flow::phaseVolumeFraction, - fields::flow::dPhaseVolumeFraction, - fields::flow::dGlobalCompFraction_dGlobalCompDensity >; - - using MultiFluidAccessors = - StencilMaterialAccessors< MultiFluidBase, - fields::multifluid::phaseDensity, - fields::multifluid::dPhaseDensity, - fields::multifluid::phaseCompFraction, - fields::multifluid::dPhaseCompFraction >; - - template< integer NC > - GEOS_HOST_DEVICE - inline - static void - compute( integer const numPhases, - integer const ipWater, - bool const allowAllPhasesIntoAquifer, - real64 const aquiferVolFlux, - real64 const dAquiferVolFlux_dPres, - real64 const aquiferWaterPhaseDens, - arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseDens, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac, - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > phaseCompFrac, - arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens, - real64 const dt, - real64 ( &localFlux )[NC], - real64 ( &localFluxJacobian )[NC][NC+1] ); - - template< integer NC > - static void - launch( integer const numPhases, - integer const ipWater, - bool const allowAllPhasesIntoAquifer, - integer const useTotalMassEquation, - BoundaryStencil const & stencil, - globalIndex const rankOffset, - ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, - AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, - real64 const aquiferWaterPhaseDens, - arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, - ElementViewConst< arrayView1d< integer const > > const & ghostRank, - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & pres_n, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, - real64 const timeAtBeginningOfStep, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ); - -}; - -} // namespace isothermalCompositionalMultiphaseFVMKernels - -} // namespace geos - - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/LogLevelsInfo.hpp b/src/coreComponents/physicsSolvers/fluidFlow/LogLevelsInfo.hpp new file mode 100644 index 00000000000..c42ac620388 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/LogLevelsInfo.hpp @@ -0,0 +1,58 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file LogLevelsInfo.hpp + * This file contains log level informations for flow solvers + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_LOGLEVELSINFO_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_LOGLEVELSINFO_HPP + +#include "common/DataTypes.hpp" + +namespace geos +{ + +namespace logInfo +{ + +/** + * @name Wells LogLevels info structures. They must comply with the `is_log_level_info` trait. + */ +///@{ + +/// @cond DO_NOT_DOCUMENT + +struct CFL +{ + static constexpr int getMinLogLevel() { return 1; } + static constexpr std::string_view getDescription() { return "CFL information"; } +}; + +struct Statistics +{ + static constexpr int getMinLogLevel() { return 1; } + static constexpr std::string_view getDescription() { return "Print statistics"; } +}; + +/// @endcond +///@} + +} + +} + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_LOGLEVELSINFO_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.cpp b/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.cpp index bbfe022fbf6..07c38cd2726 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -23,13 +24,15 @@ #include "discretizationMethods/NumericalMethodsManager.hpp" #include "fieldSpecification/FieldSpecificationManager.hpp" #include "fieldSpecification/SourceFluxBoundaryCondition.hpp" +#include "fieldSpecification/EquilibriumInitialCondition.hpp" +#include "physicsSolvers/fluidFlow/SourceFluxStatistics.hpp" #include "finiteVolume/FiniteVolumeManager.hpp" #include "finiteVolume/FluxApproximationBase.hpp" #include "mesh/DomainPartition.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" -#include "physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBLFields.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBLKernels.hpp" +#include "physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBLFields.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ReactiveCompositionalMultiphaseOBLKernels.hpp" namespace geos @@ -184,10 +187,10 @@ void ReactiveCompositionalMultiphaseOBL::implicitStepComplete( real64 const & ti } ); } -void ReactiveCompositionalMultiphaseOBL::postProcessInput() +void ReactiveCompositionalMultiphaseOBL::postInputInitialization() { // need to override to skip the check for fluidModel, which is enabled in FlowSolverBase - SolverBase::postProcessInput(); + PhysicsSolverBase::postInputInitialization(); GEOS_THROW_IF_GT_MSG( m_maxCompFracChange, 1.0, GEOS_FMT( "{}: The maximum absolute change in component fraction is set to {}, while it must not be greater than 1.0", @@ -365,10 +368,7 @@ real64 ReactiveCompositionalMultiphaseOBL::calculateResidualNorm( real64 const & real64 const residual = m_useDARTSL2Norm ? MpiWrapper::max( localResidualNorm ) : std::sqrt( MpiWrapper::sum( localResidualNorm ) ); - if( getLogLevel() >= 1 && logger::internal::rank==0 ) - { - std::cout << GEOS_FMT( " ( Rflow ) = ( {:4.2e} )", residual ); - } + GEOS_LOG_LEVEL_INFO_RANK_0_NLR( logInfo::Convergence, GEOS_FMT( " ( Rflow ) = ( {:4.2e} )", residual ) ); return residual; } @@ -444,7 +444,7 @@ real64 ReactiveCompositionalMultiphaseOBL::scalingForSystemSolution( DomainParti } ); } ); - return LvArray::math::max( MpiWrapper::min( scalingFactor, MPI_COMM_GEOSX ), m_minScalingFactor ); + return LvArray::math::max( MpiWrapper::min( scalingFactor, MPI_COMM_GEOS ), m_minScalingFactor ); } bool ReactiveCompositionalMultiphaseOBL::checkSystemSolution( DomainPartition & domain, @@ -492,7 +492,7 @@ bool ReactiveCompositionalMultiphaseOBL::checkSystemSolution( DomainPartition & } ); } ); - return MpiWrapper::min( localCheck, MPI_COMM_GEOSX ); + return MpiWrapper::min( localCheck, MPI_COMM_GEOS ); } void ReactiveCompositionalMultiphaseOBL::applySystemSolution( DofManager const & dofManager, @@ -564,7 +564,6 @@ void ReactiveCompositionalMultiphaseOBL::initializePostInitialConditionsPreSubGr DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); - // set mass fraction flag on fluid models forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) @@ -738,7 +737,7 @@ void ReactiveCompositionalMultiphaseOBL::assembleFluxTerms( real64 const dt, { typename TYPEOFREF( stencil ) ::KernelWrapper stencilWrapper = stencil.createKernelWrapper(); - FaceBasedAssemblyKernelFactory:: + FluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numPhases, m_numComponents, m_enableEnergyBalance, @@ -843,8 +842,8 @@ void ReactiveCompositionalMultiphaseOBL::applySourceFluxBC( real64 const time, { globalIndex const numTargetElems = MpiWrapper::sum< globalIndex >( targetSet.size() ); GEOS_LOG_RANK_0( GEOS_FMT( bcLogMessage, - getName(), time+dt, SourceFluxBoundaryCondition::catalogName(), - fs.getName(), setName, subRegion.getName(), fs.getScale(), numTargetElems ) ); + getName(), time+dt, fs.getCatalogName(), fs.getName(), + setName, subRegion.getName(), fs.getScale(), numTargetElems ) ); } if( targetSet.size() == 0 ) @@ -862,6 +861,8 @@ void ReactiveCompositionalMultiphaseOBL::applySourceFluxBC( real64 const time, arrayView1d< real64 > rhsContributionArrayView = rhsContributionArray.toView(); localIndex const rankOffset = dofManager.rankOffset(); + RAJA::ReduceSum< parallelDeviceReduce, real64 > massProd( 0.0 ); + // note that the dofArray will not be used after this step (simpler to use dofNumber instead) fs.computeRhsContribution< FieldSpecificationAdd, parallelDevicePolicy<> >( targetSet.toViewConst(), @@ -891,7 +892,8 @@ void ReactiveCompositionalMultiphaseOBL::applySourceFluxBC( real64 const time, fluidComponentId, dofNumber, rhsContributionArrayView, - localRhs] GEOS_HOST_DEVICE ( localIndex const a ) + localRhs, + massProd] GEOS_HOST_DEVICE ( localIndex const a ) { // we need to filter out ghosts here, because targetSet may contain them localIndex const ei = targetSet[a]; @@ -902,7 +904,18 @@ void ReactiveCompositionalMultiphaseOBL::applySourceFluxBC( real64 const time, // for all "fluid components", we add the value to the component mass balance equation globalIndex const compMassBalanceRow = dofNumber[ei] - rankOffset + fluidComponentId; - localRhs[compMassBalanceRow] += rhsContributionArrayView[a] / sizeScalingFactor; + real64 const rhsValue = rhsContributionArrayView[a] / sizeScalingFactor; + localRhs[compMassBalanceRow] += rhsValue; + massProd += rhsValue; + } ); + + SourceFluxStatsAggregator::forAllFluxStatWrappers( subRegion, fs.getName(), + [&]( SourceFluxStatsAggregator::WrappedStats & wrapper ) + { + // set the new sub-region statistics for this timestep + array1d< real64 > massProdArr{ m_numComponents }; + massProdArr[fluidComponentId] = massProd.get(); + wrapper.gatherTimeStepStats( time, dt, massProdArr.toViewConst(), targetSet.size() ); } ); } ); } ); @@ -945,7 +958,8 @@ bool ReactiveCompositionalMultiphaseOBL::validateDirichletBC( DomainPartition & if( subRegionSetMap.count( setName ) > 0 ) { bcConsistent = false; - GEOS_WARNING( GEOS_FMT( "Conflicting pressure boundary conditions on set {}/{}/{}", regionName, subRegionName, setName ) ); + GEOS_WARNING( BCMessage::pressureConflict( regionName, subRegionName, setName, + fields::flow::pressure::key() ) ); } subRegionSetMap[setName].setNumComp( numCompWithEnergy ); } ); @@ -969,12 +983,14 @@ bool ReactiveCompositionalMultiphaseOBL::validateDirichletBC( DomainPartition & if( subRegionSetMap.count( setName ) == 0 ) { bcConsistent = false; - GEOS_WARNING( GEOS_FMT( "Pressure boundary condition not prescribed on set {}/{}/{}", regionName, subRegionName, setName ) ); + GEOS_WARNING( BCMessage::missingPressure( regionName, subRegionName, setName, + fields::flow::pressure::key() ) ); } if( comp < 0 || comp >= numComp ) { bcConsistent = false; - GEOS_WARNING( GEOS_FMT( "Invalid component index [{}] in composition boundary condition {}", comp, fs.getName() ) ); + GEOS_WARNING( BCMessage::invalidComponentIndex( comp, fs.getName(), + fields::flow::globalCompFraction::key() ) ); return; // can't check next part with invalid component id } @@ -982,7 +998,13 @@ bool ReactiveCompositionalMultiphaseOBL::validateDirichletBC( DomainPartition & if( compMask[comp] ) { bcConsistent = false; - GEOS_WARNING( GEOS_FMT( "Conflicting composition[{}] boundary conditions on set {}/{}/{}", comp, regionName, subRegionName, setName ) ); + fsManager.forSubGroups< EquilibriumInitialCondition >( [&] ( EquilibriumInitialCondition const & bc ) + { + arrayView1d< string const > componentNames = bc.getComponentNames(); + GEOS_WARNING( BCMessage::conflictingComposition( comp, componentNames[comp], + regionName, subRegionName, setName, + fields::flow::globalCompFraction::key() ) ); + } ); } compMask.set( comp ); } ); @@ -1007,7 +1029,8 @@ bool ReactiveCompositionalMultiphaseOBL::validateDirichletBC( DomainPartition & if( subRegionSetMap.count( setName ) == 0 ) { bcConsistent = false; - GEOS_WARNING( GEOS_FMT( "Pressure boundary condition not prescribed on set {}/{}/{}", regionName, subRegionName, setName ) ); + GEOS_WARNING( BCMessage::pressureConflict( regionName, subRegionName, setName, + fields::flow::pressure::key() ) ); } ComponentMask< MAX_NC > & compMask = subRegionSetMap[setName]; @@ -1015,7 +1038,8 @@ bool ReactiveCompositionalMultiphaseOBL::validateDirichletBC( DomainPartition & if( compMask[numComp] ) { bcConsistent = false; - GEOS_WARNING( GEOS_FMT( "Conflicting temperature boundary conditions on set {}/{}/{}", regionName, subRegionName, setName ) ); + GEOS_WARNING( BCMessage::temperatureConflict( regionName, subRegionName, setName, + fields::flow::temperature::key() )); } compMask.set( numComp ); } ); @@ -1029,15 +1053,20 @@ bool ReactiveCompositionalMultiphaseOBL::validateDirichletBC( DomainPartition & for( auto const & setEntry : subRegionEntry.second ) { ComponentMask< MAX_NC > const & compMask = setEntry.second; - for( integer ic = 0; ic < numComp; ++ic ) + fsManager.forSubGroups< EquilibriumInitialCondition >( [&] ( EquilibriumInitialCondition const & fs ) { - if( !compMask[ic] ) + arrayView1d< string const > componentNames = fs.getComponentNames(); + for( int ic = 0; ic < componentNames.size(); ic++ ) { - bcConsistent = false; - GEOS_WARNING( GEOS_FMT( "Boundary condition not applied to composition[{}] on set {}/{}/{}", - ic, regionEntry.first, subRegionEntry.first, setEntry.first ) ); + if( !compMask[ic] ) + { + bcConsistent = false; + GEOS_WARNING( BCMessage::notAppliedOnRegion( ic, componentNames[ic], + regionEntry.first, subRegionEntry.first, setEntry.first, + fields::flow::globalCompFraction::key() ) ); + } } - } + } ); } } } @@ -1082,8 +1111,8 @@ void ReactiveCompositionalMultiphaseOBL::applyDirichletBC( real64 const time, { globalIndex const numTargetElems = MpiWrapper::sum< globalIndex >( targetSet.size() ); GEOS_LOG_RANK_0( GEOS_FMT( bcLogMessage, - getName(), time+dt, FieldSpecificationBase::catalogName(), - fs.getName(), setName, subRegion.getName(), fs.getScale(), numTargetElems ) ); + getName(), time+dt, fs.getCatalogName(), fs.getName(), + setName, subRegion.getName(), fs.getScale(), numTargetElems ) ); } fs.applyFieldValue< FieldSpecificationEqual, parallelDevicePolicy<> >( targetSet, @@ -1122,8 +1151,8 @@ void ReactiveCompositionalMultiphaseOBL::applyDirichletBC( real64 const time, { globalIndex const numTargetElems = MpiWrapper::sum< globalIndex >( targetSet.size() ); GEOS_LOG_RANK_0( GEOS_FMT( bcLogMessage, - getName(), time+dt, FieldSpecificationBase::catalogName(), - fs.getName(), setName, subRegion.getName(), fs.getScale(), numTargetElems ) ); + getName(), time+dt, fs.getCatalogName(), fs.getName(), + setName, subRegion.getName(), fs.getScale(), numTargetElems ) ); } fs.applyFieldValue< FieldSpecificationEqual, parallelDevicePolicy<> >( targetSet, @@ -1353,6 +1382,6 @@ void ReactiveCompositionalMultiphaseOBL::updateState( DomainPartition & domain ) //START_SPHINX_INCLUDE_01 -REGISTER_CATALOG_ENTRY( SolverBase, ReactiveCompositionalMultiphaseOBL, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, ReactiveCompositionalMultiphaseOBL, string const &, Group * const ) //END_SPHINX_INCLUDE_01 }// namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.hpp b/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.hpp index ac2746e8966..b510d9daf42 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -90,7 +91,7 @@ class ReactiveCompositionalMultiphaseOBL : public FlowSolverBase */ static string catalogName() { return "ReactiveCompositionalMultiphaseOBL"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -310,7 +311,7 @@ class ReactiveCompositionalMultiphaseOBL : public FlowSolverBase private: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /// the max number of fluid phases integer m_numPhases; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBLFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBLFields.hpp index 64419e20e78..d83c199f8be 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBLFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBLFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp index 1b344dc0130..98934988d8d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -31,6 +32,7 @@ #include "fieldSpecification/EquilibriumInitialCondition.hpp" #include "fieldSpecification/FieldSpecificationManager.hpp" #include "fieldSpecification/SourceFluxBoundaryCondition.hpp" +#include "physicsSolvers/fluidFlow/SourceFluxStatistics.hpp" #include "finiteVolume/FiniteVolumeManager.hpp" #include "functions/TableFunction.hpp" #include "mainInterface/ProblemManager.hpp" @@ -38,8 +40,13 @@ #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/ThermalSinglePhaseBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/MobilityKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/SolutionScalingKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/StatisticsKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/HydrostaticPressureKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluidUpdateKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/SolidInternalEnergyUpdateKernel.hpp" namespace geos @@ -51,13 +58,19 @@ using namespace singlePhaseBaseKernels; SinglePhaseBase::SinglePhaseBase( const string & name, Group * const parent ): - FlowSolverBase( name, parent ), - m_keepFlowVariablesConstantDuringInitStep( 0 ) + FlowSolverBase( name, parent ) { this->registerWrapper( viewKeyStruct::inputTemperatureString(), &m_inputTemperature ). setApplyDefaultValue( 0.0 ). setInputFlag( InputFlags::OPTIONAL ). setDescription( "Temperature" ); + + this->getWrapper< integer >( string( viewKeyStruct::isThermalString() ) ). + appendDescription( GEOS_FMT( "\nSourceFluxes application if {} is enabled :\n" + "- negative value (injection): the mass balance equation is modified to considered the additional source term,\n" + "- positive value (production): both the mass balance and the energy balance equations are modified to considered the additional source term.\n" + "For the energy balance equation, the mass flux is multipied by the enthalpy in the cell from which the fluid is being produced.", + viewKeyStruct::isThermalString() ) ); } @@ -85,11 +98,21 @@ void SinglePhaseBase::registerDataOnMesh( Group & meshBodies ) subRegion.registerField< mobility >( getName() ); subRegion.registerField< dMobility_dPressure >( getName() ); + subRegion.registerField< fields::flow::mass >( getName() ); + subRegion.registerField< fields::flow::mass_n >( getName() ); + + if( m_isThermal ) { subRegion.registerField< dMobility_dTemperature >( getName() ); } + } ); + elemManager.forElementSubRegions< SurfaceElementSubRegion >( regionNames, + [&]( localIndex const, + SurfaceElementSubRegion & subRegion ) + { + subRegion.registerField< fields::flow::massCreated >( getName() ); } ); FaceManager & faceManager = mesh.getFaceManager(); @@ -167,7 +190,7 @@ void SinglePhaseBase::validateConstitutiveModels( DomainPartition & domain ) con constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) { - string const fluidModelName = castedFluid.catalogName(); + string const fluidModelName = castedFluid.getCatalogName(); GEOS_THROW_IF( m_isThermal && (fluidModelName != "ThermalCompressibleSinglePhaseFluid"), GEOS_FMT( "SingleFluidBase {}: the thermal option is enabled in the solver, but the fluid model {} is not for thermal fluid", getDataContext(), fluid.getDataContext() ), @@ -240,41 +263,92 @@ void SinglePhaseBase::updateFluidModel( ObjectManagerBase & dataGroup ) const constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid ) { typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - thermalSinglePhaseBaseKernels::FluidUpdateKernel::launch( fluidWrapper, pres, temp ); + singlePhaseBaseKernels::FluidUpdateKernel::launch( fluidWrapper, pres, temp ); + } ); +} + +void SinglePhaseBase::updateMass( ElementSubRegionBase & subRegion ) const +{ + GEOS_MARK_FUNCTION; + + arrayView1d< real64 > const mass = subRegion.getField< fields::flow::mass >(); + arrayView1d< real64 > const mass_n = subRegion.getField< fields::flow::mass_n >(); + + CoupledSolidBase const & porousSolid = + getConstitutiveModel< CoupledSolidBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ) ); + arrayView2d< real64 const > const porosity = porousSolid.getPorosity(); + arrayView2d< real64 const > const porosity_n = porousSolid.getPorosity_n(); + + arrayView1d< real64 const > const volume = subRegion.getElementVolume(); + arrayView1d< real64 > const deltaVolume = subRegion.getField< fields::flow::deltaVolume >(); + + SingleFluidBase & fluid = + getConstitutiveModel< SingleFluidBase >( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) ); + arrayView2d< real64 const > const density = fluid.density(); + arrayView2d< real64 const > const density_n = fluid.density_n(); + + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + mass[ei] = porosity[ei][0] * ( volume[ei] + deltaVolume[ei] ) * density[ei][0]; + if( isZero( mass_n[ei] ) ) // this is a hack for hydrofrac cases + mass_n[ei] = porosity_n[ei][0] * volume[ei] * density_n[ei][0]; // initialize newly created element mass + } ); +} + +void SinglePhaseBase::updateEnergy( ElementSubRegionBase & subRegion ) const +{ + GEOS_MARK_FUNCTION; + + arrayView1d< real64 > const energy = subRegion.getField< fields::flow::energy >(); + + CoupledSolidBase const & porousSolid = + getConstitutiveModel< CoupledSolidBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ) ); + arrayView2d< real64 const > const porosity = porousSolid.getPorosity(); + arrayView2d< real64 const > const rockInternalEnergy = porousSolid.getInternalEnergy(); + + arrayView1d< real64 const > const volume = subRegion.getElementVolume(); + arrayView1d< real64 > const deltaVolume = subRegion.getField< fields::flow::deltaVolume >(); + + SingleFluidBase & fluid = + getConstitutiveModel< SingleFluidBase >( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) ); + arrayView2d< real64 const > const density = fluid.density(); + arrayView2d< real64 const > const fluidInternalEnergy = fluid.internalEnergy(); + + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + energy[ei] = ( volume[ei] + deltaVolume[ei] ) * + ( porosity[ei][0] * density[ei][0] * fluidInternalEnergy[ei][0] + ( 1.0 - porosity[ei][0] ) * rockInternalEnergy[ei][0] ); } ); } void SinglePhaseBase::updateSolidInternalEnergyModel( ObjectManagerBase & dataGroup ) const { - arrayView1d< real64 const > const temp = dataGroup.getField< fields::flow::temperature >(); + arrayView1d< real64 const > const temperature = dataGroup.getField< fields::flow::temperature >(); string const & solidInternalEnergyName = dataGroup.getReference< string >( viewKeyStruct::solidInternalEnergyNamesString() ); SolidInternalEnergy & solidInternalEnergy = getConstitutiveModel< SolidInternalEnergy >( dataGroup, solidInternalEnergyName ); SolidInternalEnergy::KernelWrapper solidInternalEnergyWrapper = solidInternalEnergy.createKernelUpdates(); - thermalSinglePhaseBaseKernels::SolidInternalEnergyUpdateKernel::launch< parallelDevicePolicy<> >( dataGroup.size(), solidInternalEnergyWrapper, temp ); + thermalSinglePhaseBaseKernels::SolidInternalEnergyUpdateKernel::launch< parallelDevicePolicy<> >( dataGroup.size(), solidInternalEnergyWrapper, temperature ); } void SinglePhaseBase::updateThermalConductivity( ElementSubRegionBase & subRegion ) const { - //START_SPHINX_INCLUDE_COUPLEDSOLID - CoupledSolidBase const & porousSolid = - getConstitutiveModel< CoupledSolidBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ) ); - //END_SPHINX_INCLUDE_COUPLEDSOLID - - arrayView2d< real64 const > const porosity = porousSolid.getPorosity(); - string const & thermalConductivityName = subRegion.template getReference< string >( viewKeyStruct::thermalConductivityNamesString() ); SinglePhaseThermalConductivityBase const & conductivityMaterial = getConstitutiveModel< SinglePhaseThermalConductivityBase >( subRegion, thermalConductivityName ); - conductivityMaterial.update( porosity ); + + arrayView1d< real64 const > const & temperature = subRegion.template getField< fields::flow::temperature >(); + conductivityMaterial.updateFromTemperature( temperature ); } -void SinglePhaseBase::updateFluidState( ObjectManagerBase & subRegion ) const +real64 SinglePhaseBase::updateFluidState( ElementSubRegionBase & subRegion ) const { updateFluidModel( subRegion ); + updateMass( subRegion ); updateMobility( subRegion ); + return 0.0; } void SinglePhaseBase::updateMobility( ObjectManagerBase & dataGroup ) const @@ -299,16 +373,16 @@ void SinglePhaseBase::updateMobility( ObjectManagerBase & dataGroup ) const ThermalFluidPropViews thermalFluidProps = getThermalFluidProperties( fluid ); - thermalSinglePhaseBaseKernels::MobilityKernel::launch< parallelDevicePolicy<> >( dataGroup.size(), - fluidProps.dens, - fluidProps.dDens_dPres, - thermalFluidProps.dDens_dTemp, - fluidProps.visc, - fluidProps.dVisc_dPres, - thermalFluidProps.dVisc_dTemp, - mob, - dMob_dPres, - dMob_dTemp ); + singlePhaseBaseKernels::MobilityKernel::launch< parallelDevicePolicy<> >( dataGroup.size(), + fluidProps.dens, + fluidProps.dDens_dPres, + thermalFluidProps.dDens_dTemp, + fluidProps.visc, + fluidProps.dVisc_dPres, + thermalFluidProps.dVisc_dTemp, + mob, + dMob_dPres, + dMob_dTemp ); } else { @@ -330,107 +404,12 @@ void SinglePhaseBase::initializePostInitialConditionsPreSubGroups() DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); - - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - FieldIdentifiers fieldsToBeSync; - fieldsToBeSync.addElementFields( { fields::flow::pressure::key() }, - regionNames ); - - CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync, mesh, domain.getNeighbors(), false ); - - // Moved the following part from ImplicitStepSetup to here since it only needs to be initialized once - // They will be updated in applySystemSolution and ImplicitStepComplete, respectively - mesh.getElemManager().forElementSubRegions< CellElementSubRegion, SurfaceElementSubRegion >( regionNames, [&]( localIndex const, - auto & subRegion ) - { - // Compute hydrostatic equilibrium in the regions for which corresponding field specification tag has been specified - computeHydrostaticEquilibrium(); - - // 1. update porosity, permeability, and density/viscosity - // In addition, to avoid multiplying permeability/porosity bay netToGross in the assembly kernel, we do it once and for all here - arrayView1d< real64 const > const netToGross = subRegion.template getField< fields::flow::netToGross >(); - CoupledSolidBase const & porousSolid = - getConstitutiveModel< CoupledSolidBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ) ); - PermeabilityBase const & permeabilityModel = - getConstitutiveModel< PermeabilityBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::permeabilityNamesString() ) ); - permeabilityModel.scaleHorizontalPermeability( netToGross ); - porousSolid.scaleReferencePorosity( netToGross ); - saveConvergedState( subRegion ); // necessary for a meaningful porosity update in sequential schemes - updatePorosityAndPermeability( subRegion ); - - SingleFluidBase const & fluid = - getConstitutiveModel< SingleFluidBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::fluidNamesString() ) ); - updateFluidState( subRegion ); - - // 2. save the initial density (for use in the single-phase poromechanics solver to compute the deltaBodyForce) - fluid.initializeState(); - - // 3. save the initial/old porosity - porousSolid.initializeState(); - - // 4. initialize the rock thermal quantities: conductivity and solid internal energy - if( m_isThermal ) - { - // initialized porosity - arrayView2d< real64 const > const porosity = porousSolid.getPorosity(); - - string const & thermalConductivityName = subRegion.template getReference< string >( viewKeyStruct::thermalConductivityNamesString() ); - SinglePhaseThermalConductivityBase const & conductivityMaterial = - getConstitutiveModel< SinglePhaseThermalConductivityBase >( subRegion, thermalConductivityName ); - conductivityMaterial.initializeRockFluidState( porosity ); - // note that there is nothing to update here because thermal conductivity is explicit for now - - updateSolidInternalEnergyModel( subRegion ); - string const & solidInternalEnergyName = subRegion.template getReference< string >( viewKeyStruct::solidInternalEnergyNamesString() ); - SolidInternalEnergy const & solidInternalEnergyMaterial = - getConstitutiveModel< SolidInternalEnergy >( subRegion, solidInternalEnergyName ); - solidInternalEnergyMaterial.saveConvergedState(); - - } - } ); - - mesh.getElemManager().forElementRegions< SurfaceElementRegion >( regionNames, - [&]( localIndex const, - SurfaceElementRegion & region ) - { - region.forElementSubRegions< FaceElementSubRegion >( [&]( FaceElementSubRegion & subRegion ) - { - ConstitutiveBase & fluid = getConstitutiveModel( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) ); - real64 const defaultDensity = getFluidProperties( fluid ).defaultDensity; - - subRegion.getWrapper< real64_array >( fields::flow::hydraulicAperture::key() ). - setApplyDefaultValue( region.getDefaultAperture() ); - - subRegion.getWrapper< real64_array >( FaceElementSubRegion::viewKeyStruct::creationMassString() ). - setApplyDefaultValue( defaultDensity * region.getDefaultAperture() ); - } ); - } ); - - // Save initial pressure field - mesh.getElemManager().forElementSubRegions( regionNames, [&]( localIndex const, - ElementSubRegionBase & subRegion ) - { - arrayView1d< real64 const > const pres = subRegion.getField< fields::flow::pressure >(); - arrayView1d< real64 > const initPres = subRegion.getField< fields::flow::initialPressure >(); - arrayView1d< real64 const > const & temp = subRegion.template getField< fields::flow::temperature >(); - arrayView1d< real64 > const initTemp = subRegion.template getField< fields::flow::initialTemperature >(); - initPres.setValues< parallelDevicePolicy<> >( pres ); - initTemp.setValues< parallelDevicePolicy<> >( temp ); - } ); - } ); - - // report to the user if some pore volumes are very small - // note: this function is here because: 1) porosity has been initialized and 2) NTG has been applied - validatePoreVolumes( domain ); + FlowSolverBase::initializeState( domain ); } -void SinglePhaseBase::computeHydrostaticEquilibrium() +void SinglePhaseBase::computeHydrostaticEquilibrium( DomainPartition & domain ) { FieldSpecificationManager & fsManager = FieldSpecificationManager::getInstance(); - DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); real64 const gravVector[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3( gravityVector() ); @@ -450,7 +429,7 @@ void SinglePhaseBase::computeHydrostaticEquilibrium() getCatalogName() << " " << getDataContext() << ": the gravity vector specified in this simulation (" << gravVector[0] << " " << gravVector[1] << " " << gravVector[2] << ") is not aligned with the z-axis. \n" - "This is incompatible with the " << EquilibriumInitialCondition::catalogName() << " " << bc.getDataContext() << + "This is incompatible with the " << bc.getCatalogName() << " " << bc.getDataContext() << "used in this simulation. To proceed, you can either: \n" << " - Use a gravityVector aligned with the z-axis, such as (0.0,0.0,-9.81)\n" << " - Remove the hydrostatic equilibrium initial condition from the XML file", @@ -604,6 +583,48 @@ void SinglePhaseBase::computeHydrostaticEquilibrium() } ); } +void SinglePhaseBase::initializeFluidState( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) +{ + mesh.getElemManager().forElementSubRegions< CellElementSubRegion, SurfaceElementSubRegion >( regionNames, [&]( localIndex const, + auto & subRegion ) + { + SingleFluidBase const & fluid = + getConstitutiveModel< SingleFluidBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::fluidNamesString())); + updateFluidState( subRegion ); + + // 2. save the initial density (for use in the single-phase poromechanics solver to compute the deltaBodyForce) + fluid.initializeState(); + + updateMass( subRegion ); + } ); +} + +void SinglePhaseBase::initializeThermalState( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) +{ + mesh.getElemManager().forElementSubRegions< CellElementSubRegion, SurfaceElementSubRegion >( regionNames, [&]( localIndex const, + auto & subRegion ) + { + // initialized porosity + CoupledSolidBase const & porousSolid = + getConstitutiveModel< CoupledSolidBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ) ); + arrayView2d< real64 const > const porosity = porousSolid.getPorosity(); + + string const & thermalConductivityName = subRegion.template getReference< string >( viewKeyStruct::thermalConductivityNamesString()); + SinglePhaseThermalConductivityBase const & conductivityMaterial = + getConstitutiveModel< SinglePhaseThermalConductivityBase >( subRegion, thermalConductivityName ); + conductivityMaterial.initializeRockFluidState( porosity ); + // note that there is nothing to update here because thermal conductivity is explicit for now + + updateSolidInternalEnergyModel( subRegion ); + string const & solidInternalEnergyName = subRegion.template getReference< string >( viewKeyStruct::solidInternalEnergyNamesString()); + SolidInternalEnergy const & solidInternalEnergyMaterial = + getConstitutiveModel< SolidInternalEnergy >( subRegion, solidInternalEnergyName ); + solidInternalEnergyMaterial.saveConvergedState(); + + updateEnergy( subRegion ); + } ); +} + void SinglePhaseBase::implicitStepSetup( real64 const & GEOS_UNUSED_PARAM( time_n ), real64 const & GEOS_UNUSED_PARAM( dt ), DomainPartition & domain ) @@ -628,12 +649,13 @@ void SinglePhaseBase::implicitStepSetup( real64 const & GEOS_UNUSED_PARAM( time_ { updateSolidInternalEnergyModel( subRegion ); updateThermalConductivity( subRegion ); + updateEnergy( subRegion ); } } ); - mesh.getElemManager().forElementSubRegions< FaceElementSubRegion >( regionNames, [&]( localIndex const, - FaceElementSubRegion & subRegion ) + mesh.getElemManager().forElementSubRegions< SurfaceElementSubRegion >( regionNames, [&]( localIndex const, + SurfaceElementSubRegion & subRegion ) { arrayView1d< real64 const > const aper = subRegion.getField< fields::flow::hydraulicAperture >(); arrayView1d< real64 > const aper0 = subRegion.getField< fields::flow::aperture0 >(); @@ -653,6 +675,7 @@ void SinglePhaseBase::implicitStepSetup( real64 const & GEOS_UNUSED_PARAM( time_ fluid.saveConvergedState(); } ); + } ); } @@ -680,12 +703,13 @@ void SinglePhaseBase::implicitStepComplete( real64 const & time, singlePhaseBaseKernels::StatisticsKernel:: saveDeltaPressure( subRegion.size(), pres, initPres, deltaPres ); - arrayView1d< real64 const > const dVol = subRegion.getField< fields::flow::deltaVolume >(); + arrayView1d< real64 > const dVol = subRegion.getField< fields::flow::deltaVolume >(); arrayView1d< real64 > const vol = subRegion.getReference< array1d< real64 > >( CellElementSubRegion::viewKeyStruct::elementVolumeString() ); forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) { vol[ei] += dVol[ei]; + dVol[ei] = 0.0; } ); SingleFluidBase const & fluid = @@ -694,7 +718,7 @@ void SinglePhaseBase::implicitStepComplete( real64 const & time, CoupledSolidBase const & porousSolid = getConstitutiveModel< CoupledSolidBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ) ); - if( m_keepFlowVariablesConstantDuringInitStep ) + if( m_keepVariablesConstantDuringInitStep ) { porousSolid.ignoreConvergedState(); // newPorosity <- porosity_n } @@ -715,12 +739,12 @@ void SinglePhaseBase::implicitStepComplete( real64 const & time, } ); - mesh.getElemManager().forElementSubRegions< FaceElementSubRegion >( regionNames, [&]( localIndex const, - FaceElementSubRegion & subRegion ) + mesh.getElemManager().forElementSubRegions< SurfaceElementSubRegion >( regionNames, [&]( localIndex const, + SurfaceElementSubRegion & subRegion ) { arrayView1d< integer const > const elemGhostRank = subRegion.ghostRank(); arrayView1d< real64 const > const volume = subRegion.getElementVolume(); - arrayView1d< real64 > const creationMass = subRegion.getReference< real64_array >( FaceElementSubRegion::viewKeyStruct::creationMassString() ); + arrayView1d< real64 > const creationMass = subRegion.getField< fields::flow::massCreated >(); SingleFluidBase const & fluid = getConstitutiveModel< SingleFluidBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::fluidNamesString() ) ); @@ -733,7 +757,7 @@ void SinglePhaseBase::implicitStepComplete( real64 const & time, if( volume[ei] * density_n[ei][0] > 1.1 * creationMass[ei] ) { creationMass[ei] *= 0.75; - if( creationMass[ei]<1.0e-20 ) + if( creationMass[ei] < 1.0e-20 ) { creationMass[ei] = 0.0; } @@ -741,7 +765,6 @@ void SinglePhaseBase::implicitStepComplete( real64 const & time, } } ); } ); - } ); } @@ -760,11 +783,22 @@ void SinglePhaseBase::assembleSystem( real64 const GEOS_UNUSED_PARAM( time_n ), localMatrix, localRhs ); - assembleFluxTerms( dt, - domain, - dofManager, - localMatrix, - localRhs ); + if( m_isJumpStabilized ) + { + assembleStabilizedFluxTerms( dt, + domain, + dofManager, + localMatrix, + localRhs ); + } + else + { + assembleFluxTerms( dt, + domain, + dofManager, + localMatrix, + localRhs ); + } } void SinglePhaseBase::assembleAccumulationTerms( DomainPartition & domain, @@ -797,13 +831,13 @@ void SinglePhaseBase::applyBoundaryConditions( real64 time_n, { GEOS_MARK_FUNCTION; - if( m_keepFlowVariablesConstantDuringInitStep ) + if( m_keepVariablesConstantDuringInitStep ) { // this function is going to force the current flow state to be constant during the time step // this is used when the poromechanics solver is performing the stress initialization // TODO: in the future, a dedicated poromechanics kernel should eliminate the flow vars to construct a reduced system // which will remove the need for this brittle passing aroung of flag - keepFlowVariablesConstantDuringInitStep( time_n, dt, dofManager, domain, localMatrix.toViewConstSizes(), localRhs.toView() ); + keepVariablesConstantDuringInitStep( time_n, dt, dofManager, domain, localMatrix.toViewConstSizes(), localRhs.toView() ); } else { @@ -816,20 +850,12 @@ void SinglePhaseBase::applyBoundaryConditions( real64 time_n, namespace { -char const bcLogMessage[] = - "SinglePhaseBase {}: at time {}s, " - "the <{}> boundary condition '{}' is applied to the element set '{}' in subRegion '{}'. " - "\nThe scale of this boundary condition is {} and multiplies the value of the provided function (if any). " - "\nThe total number of target elements (including ghost elements) is {}. " - "\nNote that if this number is equal to zero for all subRegions, the boundary condition will not be applied on this element set."; - void applyAndSpecifyFieldValue( real64 const & time_n, real64 const & dt, MeshLevel & mesh, globalIndex const rankOffset, string const dofKey, - bool const isFirstNonlinearIteration, - string const solverName, + bool const, integer const idof, string const fieldKey, string const boundaryFieldKey, @@ -842,19 +868,11 @@ void applyAndSpecifyFieldValue( real64 const & time_n, mesh, fieldKey, [&]( FieldSpecificationBase const & fs, - string const & setName, + string const &, SortedArrayView< localIndex const > const & lset, ElementSubRegionBase & subRegion, string const & ) { - if( fs.getLogLevel() >= 1 && isFirstNonlinearIteration ) - { - globalIndex const numTargetElems = MpiWrapper::sum< globalIndex >( lset.size() ); - GEOS_LOG_RANK_0( GEOS_FMT( bcLogMessage, - solverName, time_n+dt, FieldSpecificationBase::catalogName(), - fs.getName(), setName, subRegion.getName(), fs.getScale(), numTargetElems ) ); - } - // Specify the bc value of the field fs.applyFieldValue< FieldSpecificationEqual, parallelDevicePolicy<> >( lset, @@ -913,12 +931,12 @@ void SinglePhaseBase::applyDirichletBC( real64 const time_n, MeshLevel & mesh, arrayView1d< string const > const & ) { - applyAndSpecifyFieldValue( time_n, dt, mesh, rankOffset, dofKey, isFirstNonlinearIteration, getName(), + applyAndSpecifyFieldValue( time_n, dt, mesh, rankOffset, dofKey, isFirstNonlinearIteration, 0, fields::flow::pressure::key(), fields::flow::bcPressure::key(), localMatrix, localRhs ); if( m_isThermal ) { - applyAndSpecifyFieldValue( time_n, dt, mesh, rankOffset, dofKey, isFirstNonlinearIteration, getName(), + applyAndSpecifyFieldValue( time_n, dt, mesh, rankOffset, dofKey, isFirstNonlinearIteration, 1, fields::flow::temperature::key(), fields::flow::bcTemperature::key(), localMatrix, localRhs ); } @@ -983,25 +1001,6 @@ void SinglePhaseBase::applySourceFluxBC( real64 const time_n, ElementSubRegionBase & subRegion, string const & ) { - if( fs.getLogLevel() >= 1 && m_nonlinearSolverParameters.m_numNewtonIterations == 0 ) - { - globalIndex const numTargetElems = MpiWrapper::sum< globalIndex >( targetSet.size() ); - GEOS_LOG_RANK_0( GEOS_FMT( bcLogMessage, - getName(), time_n+dt, SourceFluxBoundaryCondition::catalogName(), - fs.getName(), setName, subRegion.getName(), fs.getScale(), numTargetElems ) ); - - if( isThermal ) - { - char const msg[] = "SinglePhaseBase {} with isThermal = 1. At time {}s, " - "the <{}> source flux boundary condition '{}' will be applied with the following behavior" - "\n - negative value (injection): the mass balance equation is modified to considered the additional source term" - "\n - positive value (production): both the mass balance and the energy balance equations are modified to considered the additional source term. " \ - "\n For the energy balance equation, the mass flux is multipied by the enthalpy in the cell from which the fluid is being produced."; - GEOS_LOG_RANK_0( GEOS_FMT( msg, - getName(), time_n+dt, SourceFluxBoundaryCondition::catalogName(), fs.getName() ) ); - } - } - if( targetSet.size() == 0 ) { return; @@ -1026,6 +1025,8 @@ void SinglePhaseBase::applySourceFluxBC( real64 const time_n, arrayView1d< real64 > rhsContributionArrayView = rhsContributionArray.toView(); localIndex const rankOffset = dofManager.rankOffset(); + RAJA::ReduceSum< parallelDeviceReduce, real64 > massProd( 0.0 ); + // note that the dofArray will not be used after this step (simpler to use dofNumber instead) fs.computeRhsContribution< FieldSpecificationAdd, parallelDevicePolicy<> >( targetSet.toViewConst(), @@ -1065,7 +1066,8 @@ void SinglePhaseBase::applySourceFluxBC( real64 const time_n, dEnthalpy_dPressure, rhsContributionArrayView, localRhs, - localMatrix] GEOS_HOST_DEVICE ( localIndex const a ) + localMatrix, + massProd] GEOS_HOST_DEVICE ( localIndex const a ) { // we need to filter out ghosts here, because targetSet may contain them localIndex const ei = targetSet[a]; @@ -1079,7 +1081,8 @@ void SinglePhaseBase::applySourceFluxBC( real64 const time_n, globalIndex const energyRowIndex = massRowIndex + 1; real64 const rhsValue = rhsContributionArrayView[a] / sizeScalingFactor; // scale the contribution by the sizeScalingFactor here! localRhs[massRowIndex] += rhsValue; - //add the value to the energey balance equation if the flux is positive (i.e., it's a producer) + massProd += rhsValue; + //add the value to the energy balance equation if the flux is positive (i.e., it's a producer) if( rhsContributionArrayView[a] > 0.0 ) { globalIndex const pressureDofIndex = dofNumber[ei] - rankOffset; @@ -1105,7 +1108,8 @@ void SinglePhaseBase::applySourceFluxBC( real64 const time_n, ghostRank, dofNumber, rhsContributionArrayView, - localRhs] GEOS_HOST_DEVICE ( localIndex const a ) + localRhs, + massProd] GEOS_HOST_DEVICE ( localIndex const a ) { // we need to filter out ghosts here, because targetSet may contain them localIndex const ei = targetSet[a]; @@ -1116,19 +1120,30 @@ void SinglePhaseBase::applySourceFluxBC( real64 const time_n, // add the value to the mass balance equation globalIndex const rowIndex = dofNumber[ei] - rankOffset; - localRhs[rowIndex] += rhsContributionArrayView[a] / sizeScalingFactor; // scale the contribution by the sizeScalingFactor here! + real64 const rhsValue = rhsContributionArrayView[a] / sizeScalingFactor; + localRhs[rowIndex] += rhsValue; + massProd += rhsValue; } ); } + + SourceFluxStatsAggregator::forAllFluxStatWrappers( subRegion, fs.getName(), + [&]( SourceFluxStatsAggregator::WrappedStats & wrapper ) + { + // set the new sub-region statistics for this timestep + array1d< real64 > massProdArr{ 1 }; + massProdArr[0] = massProd.get(); + wrapper.gatherTimeStepStats( time_n, dt, massProdArr.toViewConst(), targetSet.size() ); + } ); } ); } ); } -void SinglePhaseBase::keepFlowVariablesConstantDuringInitStep( real64 const time, - real64 const dt, - DofManager const & dofManager, - DomainPartition & domain, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) const +void SinglePhaseBase::keepVariablesConstantDuringInitStep( real64 const time, + real64 const dt, + DofManager const & dofManager, + DomainPartition & domain, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) const { GEOS_MARK_FUNCTION; @@ -1206,6 +1221,7 @@ void SinglePhaseBase::updateState( DomainPartition & domain ) if( m_isThermal ) { updateSolidInternalEnergyModel( subRegion ); + updateEnergy( subRegion ); } } ); } ); @@ -1237,6 +1253,7 @@ void SinglePhaseBase::resetStateToBeginningOfStep( DomainPartition & domain ) if( m_isThermal ) { updateSolidInternalEnergyModel( subRegion ); + updateEnergy( subRegion ); } } ); } ); @@ -1265,7 +1282,7 @@ real64 SinglePhaseBase::scalingForSystemSolution( DomainPartition & domain, arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); auto const subRegionData = - singlePhaseBaseKernels::ScalingForSystemSolutionKernel:: + singlePhaseBaseKernels::SolutionScalingKernel:: launch< parallelDevicePolicy<> >( localSolution, rankOffset, dofNumber, ghostRank, m_maxAbsolutePresChange ); scalingFactor = std::min( scalingFactor, subRegionData.first ); @@ -1276,8 +1293,8 @@ real64 SinglePhaseBase::scalingForSystemSolution( DomainPartition & domain, scalingFactor = MpiWrapper::min( scalingFactor ); maxDeltaPres = MpiWrapper::max( maxDeltaPres ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max pressure change: {} Pa (before scaling)", - getName(), fmt::format( "{:.{}f}", maxDeltaPres, 3 ) ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, GEOS_FMT( " {}: Max pressure change = {} Pa (before scaling)", + getName(), fmt::format( "{:.{}f}", maxDeltaPres, 3 ) ) ); return scalingFactor; } @@ -1318,10 +1335,19 @@ bool SinglePhaseBase::checkSystemSolution( DomainPartition & domain, numNegativePressures = MpiWrapper::sum( numNegativePressures ); if( numNegativePressures > 0 ) - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative pressure values: {}, minimum value: {} Pa", - getName(), numNegativePressures, fmt::format( "{:.{}f}", minPressure, 3 ) ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, GEOS_FMT( " {}: Number of negative pressure values: {}, minimum value: {} Pa", + getName(), numNegativePressures, fmt::format( "{:.{}f}", minPressure, 3 ) ) ); return (m_allowNegativePressure || numNegativePressures == 0) ? 1 : 0; } +void SinglePhaseBase::saveConvergedState( ElementSubRegionBase & subRegion ) const +{ + FlowSolverBase::saveConvergedState( subRegion ); + + arrayView1d< real64 const > const mass = subRegion.template getField< fields::flow::mass >(); + arrayView1d< real64 > const mass_n = subRegion.template getField< fields::flow::mass_n >(); + mass_n.setValues< parallelDevicePolicy<> >( mass ); +} + } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.hpp index 56dbab8979e..db72beaa75a 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,8 +21,8 @@ #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEBASE_HPP_ #include "physicsSolvers/fluidFlow/FlowSolverBase.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/ThermalSinglePhaseBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp" #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" #include "constitutive/solid/CoupledSolidBase.hpp" @@ -169,6 +170,22 @@ class SinglePhaseBase : public FlowSolverBase CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) = 0; + /** + * @brief assembles the flux terms for all cells including jump stabilization + * @param time_n previous time value + * @param dt time step + * @param domain the physical domain object + * @param dofManager degree-of-freedom manager associated with the linear system + * @param localMatrix the system matrix + * @param localRhs the system right-hand side vector + */ + virtual void + assembleStabilizedFluxTerms( real64 const dt, + DomainPartition const & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) = 0; + /** * @brief assembles the flux terms for all cells for the poroelastic case * @param time_n previous time value @@ -210,10 +227,6 @@ class SinglePhaseBase : public FlowSolverBase struct viewKeyStruct : FlowSolverBase::viewKeyStruct { static constexpr char const * elemDofFieldString() { return "singlePhaseVariables"; } - - // inputs - static constexpr char const * inputTemperatureString() { return "temperature"; } - static constexpr char const * thermalConductivityNamesString() { return "thermalConductivityNames"; } }; /** @@ -272,10 +285,10 @@ class SinglePhaseBase : public FlowSolverBase /** * @brief Function to update all constitutive state and dependent variables - * @param dataGroup group that contains the fields + * @param subRegion subregion that contains the fields */ - void - updateFluidState( ObjectManagerBase & subRegion ) const; + real64 + updateFluidState( ElementSubRegionBase & subRegion ) const; /** @@ -285,6 +298,20 @@ class SinglePhaseBase : public FlowSolverBase virtual void updateFluidModel( ObjectManagerBase & dataGroup ) const; + /** + * @brief Function to update fluid mass + * @param subRegion subregion that contains the fields + */ + void + updateMass( ElementSubRegionBase & subRegion ) const; + + /** + * @brief Function to update energy + * @param subRegion subregion that contains the fields + */ + void + updateEnergy( ElementSubRegionBase & subRegion ) const; + /** * @brief Update all relevant solid internal energy models using current values of temperature * @param dataGroup the group storing the required fields @@ -308,18 +335,22 @@ class SinglePhaseBase : public FlowSolverBase virtual void initializePostInitialConditionsPreSubGroups() override; + virtual void initializeFluidState( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) override; + + virtual void initializeThermalState( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) override; + /** * @brief Compute the hydrostatic equilibrium using the compositions and temperature input tables */ - void computeHydrostaticEquilibrium(); + virtual void computeHydrostaticEquilibrium( DomainPartition & domain ) override; /** - * @brief Utility function to keep the flow variables during a time step (used in poromechanics simulations) - * @param[in] keepFlowVariablesConstantDuringInitStep flag to tell the solver to freeze its primary variables during a time step - * @detail This function is meant to be called by a specific task before/after the initialization step + * @brief Update the cell-wise pressure gradient */ - void keepFlowVariablesConstantDuringInitStep( bool const keepFlowVariablesConstantDuringInitStep ) - { m_keepFlowVariablesConstantDuringInitStep = keepFlowVariablesConstantDuringInitStep; } + virtual void updatePressureGradient( DomainPartition & domain ) + { + GEOS_UNUSED_VAR( domain ); + } /** * @brief Function to fix the initial state during the initialization step in coupled problems @@ -329,15 +360,15 @@ class SinglePhaseBase : public FlowSolverBase * @param[in] domain the domain * @param[in] localMatrix local system matrix * @param[in] localRhs local system right-hand side vector - * @detail This function is meant to be called when the flag m_keepFlowVariablesConstantDuringInitStep is on + * @detail This function is meant to be called when the flag m_keepVariablesConstantDuringInitStep is on * The main use case is the initialization step in coupled problems during which we solve an elastic problem for a fixed pressure */ - void keepFlowVariablesConstantDuringInitStep( real64 const time, - real64 const dt, - DofManager const & dofManager, - DomainPartition & domain, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) const; + void keepVariablesConstantDuringInitStep( real64 const time, + real64 const dt, + DofManager const & dofManager, + DomainPartition & domain, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) const; protected: @@ -354,6 +385,11 @@ class SinglePhaseBase : public FlowSolverBase virtual void setConstitutiveNamesCallSuper( ElementSubRegionBase & subRegion ) const override; + /** + * @brief Utility function to save the converged state + * @param[in] subRegion the element subRegion + */ + virtual void saveConvergedState( ElementSubRegionBase & subRegion ) const override; /** * @brief Structure holding views into fluid properties used by the base solver. @@ -384,19 +420,13 @@ class SinglePhaseBase : public FlowSolverBase * * This function enables derived solvers to substitute SingleFluidBase for a different, * unrelated fluid class, and customize property extraction. For example, it is used by - * SinglePhaseProppantBase to allow using SlurryFluidBase, which does not inherit from + * SinglePhaseProppantBase to allow using constitutive::SlurryFluidBase, which does not inherit from * SingleFluidBase currently (but this design may need to be revised). */ virtual FluidPropViews getFluidProperties( constitutive::ConstitutiveBase const & fluid ) const; virtual ThermalFluidPropViews getThermalFluidProperties( constitutive::ConstitutiveBase const & fluid ) const; - /// the input temperature - real64 m_inputTemperature; - - /// flag to freeze the initial state during initialization in coupled problems - integer m_keepFlowVariablesConstantDuringInitStep; - private: virtual void setConstitutiveNames( ElementSubRegionBase & subRegion ) const override; @@ -420,7 +450,7 @@ void SinglePhaseBase::accumulationAssemblyLaunch( DofManager const & dofManager, if( m_isThermal ) { thermalSinglePhaseBaseKernels:: - ElementBasedAssemblyKernelFactory:: + AccumulationKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), dofKey, subRegion, @@ -432,7 +462,7 @@ void SinglePhaseBase::accumulationAssemblyLaunch( DofManager const & dofManager, else { singlePhaseBaseKernels:: - ElementBasedAssemblyKernelFactory:: + AccumulationKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), dofKey, subRegion, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp index 6e0bf66f91a..b68848e634f 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBaseKernels.hpp deleted file mode 100644 index 1a53a221166..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBaseKernels.hpp +++ /dev/null @@ -1,934 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file SinglePhaseBaseKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEBASEKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEBASEKERNELS_HPP - -#include "common/DataTypes.hpp" -#include "common/GEOS_RAJA_Interface.hpp" -#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" -#include "constitutive/solid/CoupledSolidBase.hpp" -#include "finiteVolume/FluxApproximationBase.hpp" -#include "linearAlgebra/interfaces/InterfaceTypes.hpp" -#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/SolverBaseKernels.hpp" - -namespace geos -{ - -namespace singlePhaseBaseKernels -{ - -/******************************** MobilityKernel ********************************/ - -struct MobilityKernel -{ - GEOS_HOST_DEVICE - inline - static void - compute( real64 const & dens, - real64 const & dDens_dPres, - real64 const & visc, - real64 const & dVisc_dPres, - real64 & mob, - real64 & dMob_dPres ) - { - mob = dens / visc; - dMob_dPres = dDens_dPres / visc - mob / visc * dVisc_dPres; - } - - GEOS_HOST_DEVICE - inline - static void - compute( real64 const & dens, - real64 const & visc, - real64 & mob ) - { - mob = dens / visc; - } - - template< typename POLICY > - static void launch( localIndex const size, - arrayView2d< real64 const > const & dens, - arrayView2d< real64 const > const & dDens_dPres, - arrayView2d< real64 const > const & visc, - arrayView2d< real64 const > const & dVisc_dPres, - arrayView1d< real64 > const & mob, - arrayView1d< real64 > const & dMob_dPres ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - compute( dens[a][0], - dDens_dPres[a][0], - visc[a][0], - dVisc_dPres[a][0], - mob[a], - dMob_dPres[a] ); - } ); - } - - template< typename POLICY > - static void launch( localIndex const size, - arrayView2d< real64 const > const & dens, - arrayView2d< real64 const > const & visc, - arrayView1d< real64 > const & mob ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - compute( dens[a][0], - visc[a][0], - mob[a] ); - } ); - } -}; - -/******************************** ElementBasedAssemblyKernel ********************************/ - -/** - * @brief Internal struct to provide no-op defaults used in the inclusion - * of lambda functions into kernel component functions. - * @struct NoOpFunc - */ -struct NoOpFunc -{ - template< typename ... Ts > - GEOS_HOST_DEVICE - constexpr void - operator()( Ts && ... ) const {} -}; - -/** - * @class ElementBasedAssemblyKernel - * @brief Define the interface for the assembly kernel in charge of accumulation - */ -template< typename SUBREGION_TYPE, integer NUM_DOF > -class ElementBasedAssemblyKernel -{ - -public: - - /// Compute time value for the number of degrees of freedom - static constexpr integer numDof = NUM_DOF; - - /// Compute time value for the number of equations - static constexpr integer numEqn = NUM_DOF; - - /** - * @brief Constructor - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - ElementBasedAssemblyKernel( globalIndex const rankOffset, - string const dofKey, - SUBREGION_TYPE const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : - m_rankOffset( rankOffset ), - m_dofNumber( subRegion.template getReference< array1d< globalIndex > >( dofKey ) ), - m_elemGhostRank( subRegion.ghostRank() ), - m_volume( subRegion.getElementVolume() ), - m_deltaVolume( subRegion.template getField< fields::flow::deltaVolume >() ), - m_porosity_n( solid.getPorosity_n() ), - m_porosityNew( solid.getPorosity() ), - m_dPoro_dPres( solid.getDporosity_dPressure() ), - m_density_n( fluid.density_n() ), - m_density( fluid.density() ), - m_dDensity_dPres( fluid.dDensity_dPressure() ), - m_localMatrix( localMatrix ), - m_localRhs( localRhs ) - {} - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - struct StackVariables - { -public: - - // Pore volume information - - /// Pore volume at time n+1 - real64 poreVolume = 0.0; - - /// Pore volume at the previous converged time step - real64 poreVolume_n = 0.0; - - /// Derivative of pore volume with respect to pressure - real64 dPoreVolume_dPres = 0.0; - - // Residual information - - /// Index of the local row corresponding to this element - localIndex localRow = -1; - - /// Index of the matrix row/column corresponding to the dof in this element - globalIndex dofIndices[numDof]{}; - - /// Storage for the element local residual vector - real64 localResidual[numEqn]{}; - - /// Storage for the element local Jacobian matrix - real64 localJacobian[numEqn][numDof]{}; - - }; - - /** - * @brief Getter for the ghost rank of an element - * @param[in] ei the element index - * @return the ghost rank of the element - */ - GEOS_HOST_DEVICE - integer elemGhostRank( localIndex const ei ) const - { return m_elemGhostRank( ei ); } - - - /** - * @brief Performs the setup phase for the kernel. - * @param[in] ei the element index - * @param[in] stack the stack variables - */ - GEOS_HOST_DEVICE - void setup( localIndex const ei, - StackVariables & stack ) const - { - // initialize the pore volume - stack.poreVolume = ( m_volume[ei] + m_deltaVolume[ei] ) * m_porosityNew[ei][0]; - stack.poreVolume_n = m_volume[ei] * m_porosity_n[ei][0]; - stack.dPoreVolume_dPres = ( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dPres[ei][0]; - - // set row index and degrees of freedom indices for this element - stack.localRow = m_dofNumber[ei] - m_rankOffset; - for( integer idof = 0; idof < numDof; ++idof ) - { - stack.dofIndices[idof] = m_dofNumber[ei] + idof; - } - } - - /** - * @brief Compute the local accumulation contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[inout] stack the stack variables - * @param[in] kernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void computeAccumulation( localIndex const ei, - StackVariables & stack, - FUNC && kernelOp = NoOpFunc{} ) const - { - // Residual contribution is mass conservation in the cell - stack.localResidual[0] = stack.poreVolume * m_density[ei][0] - stack.poreVolume_n * m_density_n[ei][0]; - - // Derivative of residual wrt to pressure in the cell - stack.localJacobian[0][0] = stack.dPoreVolume_dPres * m_density[ei][0] + m_dDensity_dPres[ei][0] * stack.poreVolume; - - // Customize the kernel with this lambda - kernelOp(); - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void complete( localIndex const GEOS_UNUSED_PARAM( ei ), - StackVariables & stack ) const - { - // add contribution to global residual and jacobian (no need for atomics here) - m_localMatrix.template addToRow< serialAtomic >( stack.localRow, - stack.dofIndices, - stack.localJacobian[0], - numDof ); - m_localRhs[stack.localRow] += stack.localResidual[0]; - - } - - /** - * @brief Performs the kernel launch - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] numElems the number of elements - * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables - */ - template< typename POLICY, typename KERNEL_TYPE > - static void - launch( localIndex const numElems, - KERNEL_TYPE const & kernelComponent ) - { - GEOS_MARK_FUNCTION; - - forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( kernelComponent.elemGhostRank( ei ) >= 0 ) - { - return; - } - - typename KERNEL_TYPE::StackVariables stack; - - kernelComponent.setup( ei, stack ); - kernelComponent.computeAccumulation( ei, stack ); - kernelComponent.complete( ei, stack ); - } ); - } - -protected: - - /// Offset for my MPI rank - globalIndex const m_rankOffset; - - /// View on the dof numbers - arrayView1d< globalIndex const > const m_dofNumber; - - /// View on the ghost ranks - arrayView1d< integer const > const m_elemGhostRank; - - /// View on the element volumes - arrayView1d< real64 const > const m_volume; - arrayView1d< real64 const > const m_deltaVolume; - - /// Views on the porosity - arrayView2d< real64 const > const m_porosity_n; - arrayView2d< real64 const > const m_porosityNew; - arrayView2d< real64 const > const m_dPoro_dPres; - - /// Views on density - arrayView2d< real64 const > const m_density_n; - arrayView2d< real64 const > const m_density; - arrayView2d< real64 const > const m_dDensity_dPres; - - /// View on the local CRS matrix - CRSMatrixView< real64, globalIndex const > const m_localMatrix; - /// View on the local RHS - arrayView1d< real64 > const m_localRhs; - -}; - -/** - * @class SurfaceElementBasedAssemblyKernel - * @brief Define the interface for the assembly kernel in charge of accumulation in SurfaceElementSubRegion - */ -class SurfaceElementBasedAssemblyKernel : public ElementBasedAssemblyKernel< SurfaceElementSubRegion, 1 > -{ - -public: - - using Base = ElementBasedAssemblyKernel< SurfaceElementSubRegion, 1 >; - - /** - * @brief Constructor - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - SurfaceElementBasedAssemblyKernel( globalIndex const rankOffset, - string const dofKey, - SurfaceElementSubRegion const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : Base( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ) -#if ALLOW_CREATION_MASS - , m_creationMass( subRegion.getReference< array1d< real64 > >( SurfaceElementSubRegion::viewKeyStruct::creationMassString() ) ) -#endif - { -#if !defined(ALLOW_CREATION_MASS) - static_assert( true, "must have ALLOW_CREATION_MASS defined" ); -#endif - } - - /** - * @brief Compute the local accumulation contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void computeAccumulation( localIndex const ei, - Base::StackVariables & stack ) const - { - Base::computeAccumulation( ei, stack, [&] () - { -#if ALLOW_CREATION_MASS - if( Base::m_volume[ei] * Base::m_density_n[ei][0] > 1.1 * m_creationMass[ei] ) - { - stack.localResidual[0] += m_creationMass[ei] * 0.25; - } -#endif - } ); - } - -protected: - -#if ALLOW_CREATION_MASS - arrayView1d< real64 const > const m_creationMass; -#endif - -}; - -/** - * @class ElementBasedAssemblyKernelFactory - */ -class ElementBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY > - static void - createAndLaunch( globalIndex const rankOffset, - string const dofKey, - CellElementSubRegion const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - integer constexpr NUM_DOF = 1; - - ElementBasedAssemblyKernel< CellElementSubRegion, NUM_DOF > - kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); - ElementBasedAssemblyKernel< CellElementSubRegion, NUM_DOF >::template launch< POLICY >( subRegion.size(), kernel ); - } - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY > - static void - createAndLaunch( globalIndex const rankOffset, - string const dofKey, - SurfaceElementSubRegion const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - SurfaceElementBasedAssemblyKernel - kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); - SurfaceElementBasedAssemblyKernel::launch< POLICY >( subRegion.size(), kernel ); - } - -}; - -/******************************** ResidualNormKernel ********************************/ - -/** - * @class ResidualNormKernel - */ -class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > -{ -public: - - using Base = solverBaseKernels::ResidualNormKernelBase< 1 >; - using Base::m_minNormalizer; - using Base::m_rankOffset; - using Base::m_localResidual; - using Base::m_dofNumber; - - ResidualNormKernel( globalIndex const rankOffset, - arrayView1d< real64 const > const & localResidual, - arrayView1d< globalIndex const > const & dofNumber, - arrayView1d< localIndex const > const & ghostRank, - ElementSubRegionBase const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - real64 const minNormalizer ) - : Base( rankOffset, - localResidual, - dofNumber, - ghostRank, - minNormalizer ), - m_volume( subRegion.getElementVolume() ), - m_porosity_n( solid.getPorosity_n() ), - m_density_n( fluid.density_n() ) - {} - - GEOS_HOST_DEVICE - virtual void computeLinf( localIndex const ei, - LinfStackVariables & stack ) const override - { - real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_density_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); - real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow] ) / massNormalizer; - if( valMass > stack.localValue[0] ) - { - stack.localValue[0] = valMass; - } - } - - GEOS_HOST_DEVICE - virtual void computeL2( localIndex const ei, - L2StackVariables & stack ) const override - { - real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_density_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); - stack.localValue[0] += m_localResidual[stack.localRow] * m_localResidual[stack.localRow]; - stack.localNormalizer[0] += massNormalizer; - } - - -protected: - - /// View on the volume - arrayView1d< real64 const > const m_volume; - - /// View on porosity at the previous converged time step - arrayView2d< real64 const > const m_porosity_n; - - /// View on total mass/molar density at the previous converged time step - arrayView2d< real64 const > const m_density_n; - -}; - -/** - * @class ResidualNormKernelFactory - */ -class ResidualNormKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] normType the type of norm used (Linf or L2) - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] localResidual the residual vector on my MPI rank - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[out] residualNorm the residual norm on the subRegion - * @param[out] residualNormalizer the residual normalizer on the subRegion - */ - template< typename POLICY > - static void - createAndLaunch( solverBaseKernels::NormType const normType, - globalIndex const rankOffset, - string const dofKey, - arrayView1d< real64 const > const & localResidual, - ElementSubRegionBase const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - real64 const minNormalizer, - real64 (& residualNorm)[1], - real64 (& residualNormalizer)[1] ) - { - arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); - arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); - - ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, subRegion, fluid, solid, minNormalizer ); - if( normType == solverBaseKernels::NormType::Linf ) - { - ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); - } - else // L2 norm - { - ResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); - } - } - -}; - -/******************************** SolutionCheckKernel ********************************/ - -struct SolutionCheckKernel -{ - template< typename POLICY > - static std::pair< integer, real64 > launch( arrayView1d< real64 const > const & localSolution, - globalIndex const rankOffset, - arrayView1d< globalIndex const > const & dofNumber, - arrayView1d< integer const > const & ghostRank, - arrayView1d< real64 const > const & pres, - real64 const scalingFactor ) - { - RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegativePressures( 0 ); - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minPres( 0.0 ); - - forAll< POLICY >( dofNumber.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( ghostRank[ei] < 0 && dofNumber[ei] >= 0 ) - { - localIndex const lid = dofNumber[ei] - rankOffset; - real64 const newPres = pres[ei] + scalingFactor * localSolution[lid]; - - if( newPres < 0.0 ) - { - numNegativePressures += 1; - minPres.min( newPres ); - } - } - - } ); - - return { numNegativePressures.get(), minPres.get() }; - } - -}; - -/******************************** ScalingForSystemSolutionKernel ********************************/ - -struct ScalingForSystemSolutionKernel -{ - template< typename POLICY > - static std::pair< real64, real64 > launch( arrayView1d< real64 const > const & localSolution, - globalIndex const rankOffset, - arrayView1d< globalIndex const > const & dofNumber, - arrayView1d< integer const > const & ghostRank, - real64 const maxAbsolutePresChange ) - { - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > scalingFactor( 1.0 ); - RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaPres( 0.0 ); - - forAll< POLICY >( dofNumber.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) mutable - { - if( ghostRank[ei] < 0 && dofNumber[ei] >= 0 ) - { - localIndex const lid = dofNumber[ei] - rankOffset; - - // compute the change in pressure - real64 const absPresChange = LvArray::math::abs( localSolution[lid] ); - maxDeltaPres.max( absPresChange ); - - // maxAbsolutePresChange <= 0.0 means that scaling is disabled, and we are only collecting maxDeltaPres in this kernel - if( maxAbsolutePresChange > 0.0 && absPresChange > maxAbsolutePresChange ) - { - real64 const presScalingFactor = maxAbsolutePresChange / absPresChange; - scalingFactor.min( presScalingFactor ); - } - } - - } ); - - return { scalingFactor.get(), maxDeltaPres.get() }; - } - -}; - -/******************************** StatisticsKernel ********************************/ - -struct StatisticsKernel -{ - static void - saveDeltaPressure( localIndex const size, - arrayView1d< real64 const > const & pres, - arrayView1d< real64 const > const & initPres, - arrayView1d< real64 > const & deltaPres ) - { - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - deltaPres[ei] = pres[ei] - initPres[ei]; - } ); - } - - static void - launch( localIndex const size, - arrayView1d< integer const > const & elemGhostRank, - arrayView1d< real64 const > const & volume, - arrayView1d< real64 const > const & pres, - arrayView1d< real64 const > const & deltaPres, - arrayView1d< real64 const > const & temp, - arrayView1d< real64 const > const & refPorosity, - arrayView2d< real64 const > const & porosity, - arrayView2d< real64 const > const & density, - real64 & minPres, - real64 & avgPresNumerator, - real64 & maxPres, - real64 & minDeltaPres, - real64 & maxDeltaPres, - real64 & minTemp, - real64 & avgTempNumerator, - real64 & maxTemp, - real64 & totalUncompactedPoreVol, - real64 & totalPoreVol, - real64 & totalMass ) - { - RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinPres( LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgPresNumerator( 0.0 ); - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxPres( -LvArray::NumericLimits< real64 >::max ); - - RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinDeltaPres( LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxDeltaPres( -LvArray::NumericLimits< real64 >::max ); - - RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinTemp( LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgTempNumerator( 0.0 ); - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxTemp( -LvArray::NumericLimits< real64 >::max ); - - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalUncompactedPoreVol( 0.0 ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalPoreVol( 0.0 ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalMass( 0.0 ); - - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( elemGhostRank[ei] >= 0 ) - { - return; - } - - // To match our "reference", we have to use reference porosity here, not the actual porosity when we compute averages - real64 const uncompactedPoreVol = volume[ei] * refPorosity[ei]; - real64 const dynamicPoreVol = volume[ei] * porosity[ei][0]; - - subRegionMinPres.min( pres[ei] ); - subRegionAvgPresNumerator += uncompactedPoreVol * pres[ei]; - subRegionMaxPres.max( pres[ei] ); - - subRegionMinDeltaPres.min( deltaPres[ei] ); - subRegionMaxDeltaPres.max( deltaPres[ei] ); - - subRegionMinTemp.min( temp[ei] ); - subRegionAvgTempNumerator += uncompactedPoreVol * temp[ei]; - subRegionMaxTemp.max( temp[ei] ); - - subRegionTotalUncompactedPoreVol += uncompactedPoreVol; - subRegionTotalPoreVol += dynamicPoreVol; - subRegionTotalMass += dynamicPoreVol * density[ei][0]; - } ); - - minPres = subRegionMinPres.get(); - avgPresNumerator = subRegionAvgPresNumerator.get(); - maxPres = subRegionMaxPres.get(); - - minDeltaPres = subRegionMinDeltaPres.get(); - maxDeltaPres = subRegionMaxDeltaPres.get(); - - minTemp = subRegionMinTemp.get(); - avgTempNumerator = subRegionAvgTempNumerator.get(); - maxTemp = subRegionMaxTemp.get(); - - totalUncompactedPoreVol = subRegionTotalUncompactedPoreVol.get(); - totalPoreVol = subRegionTotalPoreVol.get(); - totalMass = subRegionTotalMass.get(); - } -}; - - -/******************************** HydrostaticPressureKernel ********************************/ - -struct HydrostaticPressureKernel -{ - - template< typename FLUID_WRAPPER > - static bool - computeHydrostaticPressure( integer const maxNumEquilIterations, - real64 const & equilTolerance, - real64 const (&gravVector)[ 3 ], - FLUID_WRAPPER fluidWrapper, - real64 const & refElevation, - real64 const & refPres, - real64 const & refDens, - real64 const & newElevation, - real64 & newPres, - real64 & newDens ) - { - // Step 1: guess the pressure with the refDensity - - real64 const gravCoef = gravVector[2] * ( refElevation - newElevation ); - real64 pres0 = refPres - refDens * gravCoef; - real64 pres1 = 0.0; - - // Step 2: compute the mass density at this elevation using the guess, and update pressure - - real64 dens = 0.0; - real64 visc = 0.0; - constitutive::SingleFluidBaseUpdate::computeValues( fluidWrapper, - pres0, - dens, - visc ); - pres1 = refPres - 0.5 * ( refDens + dens ) * gravCoef; - - // Step 3: fixed-point iteration until convergence - - bool equilHasConverged = false; - for( localIndex eqIter = 0; eqIter < maxNumEquilIterations; ++eqIter ) - { - - // check convergence - equilHasConverged = ( LvArray::math::abs( pres0 - pres1 ) < equilTolerance ); - pres0 = pres1; - - // if converged, move on - if( equilHasConverged ) - { - break; - } - - // compute the density at this elevation using the previous pressure, and compute the new pressure - constitutive::SingleFluidBaseUpdate::computeValues( fluidWrapper, - pres0, - dens, - visc ); - pres1 = refPres - 0.5 * ( refDens + dens ) * gravCoef; - } - - // Step 4: save the hydrostatic pressure and the corresponding density - - newPres = pres1; - newDens = dens; - - return equilHasConverged; - } - - - template< typename FLUID_WRAPPER > - static bool - launch( localIndex const size, - integer const maxNumEquilIterations, - real64 const equilTolerance, - real64 const (&gravVector)[ 3 ], - real64 const & minElevation, - real64 const & elevationIncrement, - real64 const & datumElevation, - real64 const & datumPres, - FLUID_WRAPPER fluidWrapper, - arrayView1d< arrayView1d< real64 > const > elevationValues, - arrayView1d< real64 > pressureValues ) - { - bool hasConverged = true; - - // Step 1: compute the mass density at the datum elevation - - real64 datumDens = 0.0; - real64 datumVisc = 0.0; - - constitutive::SingleFluidBaseUpdate::computeValues( fluidWrapper, - datumPres, - datumDens, - datumVisc ); - - // Step 2: find the closest elevation to datumElevation - - forAll< parallelHostPolicy >( size, [=] ( localIndex const i ) - { - real64 const elevation = minElevation + i * elevationIncrement; - elevationValues[0][i] = elevation; - } ); - integer const iRef = LvArray::sortedArrayManipulation::find( elevationValues[0].begin(), - elevationValues[0].size(), - datumElevation ); - - - // Step 3: compute the mass density and pressure at the reference elevation - - array1d< real64 > dens( pressureValues.size() ); - - bool const hasConvergedRef = - computeHydrostaticPressure( maxNumEquilIterations, - equilTolerance, - gravVector, - fluidWrapper, - datumElevation, - datumPres, - datumDens, - elevationValues[0][iRef], - pressureValues[iRef], - dens[iRef] ); - if( !hasConvergedRef ) - { - return false; - } - - - // Step 4: for each elevation above the reference elevation, compute the pressure - - localIndex const numEntriesAboveRef = size - iRef - 1; - forAll< serialPolicy >( numEntriesAboveRef, [=, &hasConverged] ( localIndex const i ) - { - bool const hasConvergedAboveRef = - computeHydrostaticPressure( maxNumEquilIterations, - equilTolerance, - gravVector, - fluidWrapper, - elevationValues[0][iRef+i], - pressureValues[iRef+i], - dens[iRef+i], - elevationValues[0][iRef+i+1], - pressureValues[iRef+i+1], - dens[iRef+i+1] ); - if( !hasConvergedAboveRef ) - { - hasConverged = false; - } - - - } ); - - // Step 5: for each elevation below the reference elevation, compute the pressure - - localIndex const numEntriesBelowRef = iRef; - forAll< serialPolicy >( numEntriesBelowRef, [=, &hasConverged] ( localIndex const i ) - { - bool const hasConvergedBelowRef = - computeHydrostaticPressure( maxNumEquilIterations, - equilTolerance, - gravVector, - fluidWrapper, - elevationValues[0][iRef-i], - pressureValues[iRef-i], - dens[iRef-i], - elevationValues[0][iRef-i-1], - pressureValues[iRef-i-1], - dens[iRef-i-1] ); - if( !hasConvergedBelowRef ) - { - hasConverged = false; - } - } ); - - return hasConverged; - } -}; - - -} // namespace singlePhaseBaseKernels - -} // namespace geos - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEBASEKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseFVM.cpp index e207d50ad99..cc9cdc6aaf6 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseFVM.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -32,19 +33,21 @@ #include "fieldSpecification/AquiferBoundaryCondition.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/ThermalSinglePhaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/ThermalSinglePhaseFVMKernels.hpp" - -#include "physicsSolvers/fluidFlow/SinglePhaseProppantFluxKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/ResidualNormKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/ThermalFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/DirichletFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/ThermalDirichletFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/StabilizedFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/AquiferBCKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEmbeddedFractures.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEmbeddedFractures.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsConformingFractures.hpp" /** - * @namespace the geosx namespace that encapsulates the majority of the code + * @namespace the geos namespace that encapsulates the majority of the code */ namespace geos { @@ -131,7 +134,7 @@ real64 SinglePhaseFVM< BASE >::calculateResidualNorm( real64 const & GEOS_UNUSED localResidualNorm.resize( numNorm ); localResidualNormalizer.resize( numNorm ); - solverBaseKernels::NormType const normType = BASE::getNonlinearSolverParameters().normType(); + physicsSolverBaseKernels::NormType const normType = BASE::getNonlinearSolverParameters().normType(); globalIndex const rankOffset = dofManager.rankOffset(); string const dofKey = dofManager.getKey( BASE::viewKeyStruct::elemDofFieldString() ); @@ -147,29 +150,17 @@ real64 SinglePhaseFVM< BASE >::calculateResidualNorm( real64 const & GEOS_UNUSED real64 subRegionResidualNorm[numNorm]{}; real64 subRegionResidualNormalizer[numNorm]{}; - string const & fluidName = subRegion.template getReference< string >( BASE::viewKeyStruct::fluidNamesString() ); - SingleFluidBase const & fluid = SolverBase::getConstitutiveModel< SingleFluidBase >( subRegion, fluidName ); - - string const & solidName = subRegion.template getReference< string >( BASE::viewKeyStruct::solidNamesString() ); - CoupledSolidBase const & solid = SolverBase::getConstitutiveModel< CoupledSolidBase >( subRegion, solidName ); - // step 1: compute the norm in the subRegion if( m_isThermal ) { - string const & solidInternalEnergyName = subRegion.template getReference< string >( BASE::viewKeyStruct::solidInternalEnergyNamesString() ); - SolidInternalEnergy const & solidInternalEnergy = SolverBase::getConstitutiveModel< SolidInternalEnergy >( subRegion, solidInternalEnergyName ); - - thermalSinglePhaseBaseKernels:: + singlePhaseBaseKernels:: ResidualNormKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( normType, rankOffset, dofKey, localRhs, subRegion, - fluid, - solid, - solidInternalEnergy, m_nonlinearSolverParameters.m_minNormalizer, subRegionResidualNorm, subRegionResidualNormalizer ); @@ -185,8 +176,6 @@ real64 SinglePhaseFVM< BASE >::calculateResidualNorm( real64 const & GEOS_UNUSED dofKey, localRhs, subRegion, - fluid, - solid, m_nonlinearSolverParameters.m_minNormalizer, subRegionFlowResidualNorm, subRegionFlowResidualNormalizer ); @@ -196,14 +185,14 @@ real64 SinglePhaseFVM< BASE >::calculateResidualNorm( real64 const & GEOS_UNUSED // step 2: first reduction across meshBodies/regions/subRegions - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { - solverBaseKernels::LinfResidualNormHelper:: + physicsSolverBaseKernels::LinfResidualNormHelper:: updateLocalNorm< numNorm >( subRegionResidualNorm, localResidualNorm ); } else { - solverBaseKernels::L2ResidualNormHelper:: + physicsSolverBaseKernels::L2ResidualNormHelper:: updateLocalNorm< numNorm >( subRegionResidualNorm, subRegionResidualNormalizer, localResidualNorm, localResidualNormalizer ); } } ); @@ -216,40 +205,35 @@ real64 SinglePhaseFVM< BASE >::calculateResidualNorm( real64 const & GEOS_UNUSED { array1d< real64 > globalResidualNorm; globalResidualNorm.resize( numNorm ); - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { - solverBaseKernels::LinfResidualNormHelper:: + physicsSolverBaseKernels::LinfResidualNormHelper:: computeGlobalNorm( localResidualNorm, globalResidualNorm ); } else { - solverBaseKernels::L2ResidualNormHelper:: + physicsSolverBaseKernels::L2ResidualNormHelper:: computeGlobalNorm( localResidualNorm, localResidualNormalizer, globalResidualNorm ); } residualNorm = sqrt( globalResidualNorm[0] * globalResidualNorm[0] + globalResidualNorm[1] * globalResidualNorm[1] ); - if( getLogLevel() >= 1 && logger::internal::rank == 0 ) - { - std::cout << GEOS_FMT( " ( R{} ) = ( {:4.2e} ) ( Renergy ) = ( {:4.2e} )", - FlowSolverBase::coupledSolverAttributePrefix(), globalResidualNorm[0], globalResidualNorm[1] ); - } + GEOS_LOG_LEVEL_INFO_RANK_0_NLR( logInfo::Convergence, GEOS_FMT( " ( R{} ) = ( {:4.2e} ) ( Renergy ) = ( {:4.2e} )", + FlowSolverBase::coupledSolverAttributePrefix(), globalResidualNorm[0], globalResidualNorm[1] )); } else { - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { - solverBaseKernels::LinfResidualNormHelper::computeGlobalNorm( localResidualNorm[0], residualNorm ); + physicsSolverBaseKernels::LinfResidualNormHelper::computeGlobalNorm( localResidualNorm[0], residualNorm ); } else { - solverBaseKernels::L2ResidualNormHelper::computeGlobalNorm( localResidualNorm[0], localResidualNormalizer[0], residualNorm ); + physicsSolverBaseKernels::L2ResidualNormHelper::computeGlobalNorm( localResidualNorm[0], localResidualNormalizer[0], residualNorm ); } - if( getLogLevel() >= 1 && logger::internal::rank == 0 ) - { - std::cout << GEOS_FMT( " ( R{} ) = ( {:4.2e} )", FlowSolverBase::coupledSolverAttributePrefix(), residualNorm ); - } + GEOS_LOG_LEVEL_INFO_RANK_0_NLR( logInfo::Convergence, + GEOS_FMT( " ( R{} ) = ( {:4.2e} )", FlowSolverBase::coupledSolverAttributePrefix(), residualNorm )); } return residualNorm; } @@ -307,12 +291,12 @@ void SinglePhaseFVM< BASE >::applySystemSolution( DofManager const & dofManager, } ); } -template< > -void SinglePhaseFVM< SinglePhaseBase >::assembleFluxTerms( real64 const dt, - DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) +template<> +void SinglePhaseFVM<>::assembleFluxTerms( real64 const dt, + DomainPartition const & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; @@ -334,26 +318,26 @@ void SinglePhaseFVM< SinglePhaseBase >::assembleFluxTerms( real64 const dt, if( m_isThermal ) { thermalSinglePhaseFVMKernels:: - FaceBasedAssemblyKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), - dofKey, - getName(), - mesh.getElemManager(), - stencilWrapper, - dt, - localMatrix.toViewConstSizes(), - localRhs.toView() ); + FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), + dofKey, + getName(), + mesh.getElemManager(), + stencilWrapper, + dt, + localMatrix.toViewConstSizes(), + localRhs.toView() ); } else { singlePhaseFVMKernels:: - FaceBasedAssemblyKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), - dofKey, - getName(), - mesh.getElemManager(), - stencilWrapper, - dt, - localMatrix.toViewConstSizes(), - localRhs.toView() ); + FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), + dofKey, + getName(), + mesh.getElemManager(), + stencilWrapper, + dt, + localMatrix.toViewConstSizes(), + localRhs.toView() ); } @@ -363,6 +347,46 @@ void SinglePhaseFVM< SinglePhaseBase >::assembleFluxTerms( real64 const dt, } +template< > +void SinglePhaseFVM< SinglePhaseBase >::assembleStabilizedFluxTerms( real64 const dt, + DomainPartition const & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + GEOS_MARK_FUNCTION; + + NumericalMethodsManager const & numericalMethodManager = domain.getNumericalMethodManager(); + FiniteVolumeManager const & fvManager = numericalMethodManager.getFiniteVolumeManager(); + FluxApproximationBase const & fluxApprox = fvManager.getFluxApproximation( m_discretizationName ); + + string const & dofKey = dofManager.getKey( SinglePhaseBase::viewKeyStruct::elemDofFieldString() ); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & ) + { + fluxApprox.forAllStencils( mesh, [&]( auto & stencil ) + { + typename TYPEOFREF( stencil ) ::KernelWrapper stencilWrapper = stencil.createKernelWrapper(); + + // No thermal support yet + stabilizedSinglePhaseFVMKernels::FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), + dofKey, + getName(), + mesh.getElemManager(), + stencilWrapper, + dt, + localMatrix.toViewConstSizes(), + localRhs.toView() ); + + } ); + } ); + +} + + + template<> void SinglePhaseFVM< SinglePhaseProppantBase >::assembleFluxTerms( real64 const dt, DomainPartition const & domain, @@ -391,9 +415,9 @@ void SinglePhaseFVM< SinglePhaseProppantBase >::assembleFluxTerms( real64 const { typename TYPEOFREF( stencil ) ::KernelWrapper stencilWrapper = stencil.createKernelWrapper(); - typename FaceBasedAssemblyKernelBase::SinglePhaseFlowAccessors flowAccessors( elemManager, getName() ); - typename FaceBasedAssemblyKernelBase::SlurryFluidAccessors fluidAccessors( elemManager, getName() ); - typename FaceBasedAssemblyKernelBase::ProppantPermeabilityAccessors permAccessors( elemManager, getName() ); + typename FluxComputeKernelBase::SinglePhaseFlowAccessors flowAccessors( elemManager, getName() ); + typename FluxComputeKernelBase::SlurryFluidAccessors fluidAccessors( elemManager, getName() ); + typename FluxComputeKernelBase::ProppantPermeabilityAccessors permAccessors( elemManager, getName() ); singlePhaseProppantFluxKernels::FaceElementFluxKernel::launch( stencilWrapper, dt, @@ -417,6 +441,16 @@ void SinglePhaseFVM< SinglePhaseProppantBase >::assembleFluxTerms( real64 const } ); } +template< > +void SinglePhaseFVM< SinglePhaseProppantBase >::assembleStabilizedFluxTerms( real64 const dt, + DomainPartition const & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + GEOS_UNUSED_VAR( dt, domain, dofManager, localMatrix, localRhs ); + GEOS_ERROR( "Stabilized flux not available with this flow solver" ); +} template< typename BASE > void SinglePhaseFVM< BASE >::assembleEDFMFluxTerms( real64 const GEOS_UNUSED_PARAM ( time_n ), @@ -446,26 +480,26 @@ void SinglePhaseFVM< BASE >::assembleEDFMFluxTerms( real64 const GEOS_UNUSED_PAR if( m_isThermal ) { thermalSinglePhaseFVMKernels:: - FaceBasedAssemblyKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), - dofKey, - this->getName(), - mesh.getElemManager(), - stencilWrapper, - dt, - localMatrix.toViewConstSizes(), - localRhs.toView() ); + FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), + dofKey, + this->getName(), + mesh.getElemManager(), + stencilWrapper, + dt, + localMatrix.toViewConstSizes(), + localRhs.toView() ); } else { singlePhaseFVMKernels:: - FaceBasedAssemblyKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), - dofKey, - this->getName(), - mesh.getElemManager(), - stencilWrapper, - dt, - localMatrix.toViewConstSizes(), - localRhs.toView() ); + FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), + dofKey, + this->getName(), + mesh.getElemManager(), + stencilWrapper, + dt, + localMatrix.toViewConstSizes(), + localRhs.toView() ); } } ); @@ -535,26 +569,26 @@ void SinglePhaseFVM< BASE >::assembleHydrofracFluxTerms( real64 const GEOS_UNUSE if( m_isThermal ) { thermalSinglePhaseFVMKernels:: - FaceBasedAssemblyKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), - dofKey, - this->getName(), - mesh.getElemManager(), - stencilWrapper, - dt, - localMatrix.toViewConstSizes(), - localRhs.toView() ); + FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), + dofKey, + this->getName(), + mesh.getElemManager(), + stencilWrapper, + dt, + localMatrix.toViewConstSizes(), + localRhs.toView() ); } else { singlePhaseFVMKernels:: - FaceBasedAssemblyKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), - dofKey, - this->getName(), - mesh.getElemManager(), - stencilWrapper, - dt, - localMatrix.toViewConstSizes(), - localRhs.toView() ); + FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), + dofKey, + this->getName(), + mesh.getElemManager(), + stencilWrapper, + dt, + localMatrix.toViewConstSizes(), + localRhs.toView() ); } } ); @@ -606,7 +640,7 @@ SinglePhaseFVM< BASE >::applyBoundaryConditions( real64 const time_n, GEOS_MARK_FUNCTION; BASE::applyBoundaryConditions( time_n, dt, domain, dofManager, localMatrix, localRhs ); - if( !BASE::m_keepFlowVariablesConstantDuringInitStep ) + if( !BASE::m_keepVariablesConstantDuringInitStep ) { applyFaceDirichletBC( time_n, dt, dofManager, domain, localMatrix, localRhs ); } @@ -671,8 +705,8 @@ void SinglePhaseFVM< BASE >::applyFaceDirichletBC( real64 const time_n, { globalIndex const numTargetFaces = MpiWrapper::sum< globalIndex >( stencil.size() ); GEOS_LOG_RANK_0( GEOS_FMT( faceBcLogMessage, - this->getName(), time_n+dt, FieldSpecificationBase::catalogName(), - fs.getName(), setName, targetGroup.getName(), numTargetFaces ) ); + this->getName(), time_n+dt, fs.getCatalogName(), fs.getName(), + setName, targetGroup.getName(), numTargetFaces ) ); } if( stencil.size() == 0 ) @@ -705,8 +739,8 @@ void SinglePhaseFVM< BASE >::applyFaceDirichletBC( real64 const time_n, { globalIndex const numTargetFaces = MpiWrapper::sum< globalIndex >( stencil.size() ); GEOS_LOG_RANK_0( GEOS_FMT( faceBcLogMessage, - this->getName(), time_n+dt, FieldSpecificationBase::catalogName(), - fs.getName(), setName, targetGroup.getName(), numTargetFaces ) ); + this->getName(), time_n+dt, fs.getCatalogName(), fs.getName(), + setName, targetGroup.getName(), numTargetFaces ) ); } if( stencil.size() == 0 ) @@ -743,7 +777,7 @@ void SinglePhaseFVM< BASE >::applyFaceDirichletBC( real64 const time_n, SingleFluidBase & fluidBase = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); thermalSinglePhaseFVMKernels:: - DirichletFaceBasedAssemblyKernelFactory:: + DirichletFluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), dofKey, this->getName(), @@ -774,8 +808,8 @@ void SinglePhaseFVM< BASE >::applyFaceDirichletBC( real64 const time_n, { globalIndex const numTargetFaces = MpiWrapper::sum< globalIndex >( stencil.size() ); GEOS_LOG_RANK_0( GEOS_FMT( faceBcLogMessage, - this->getName(), time_n+dt, FieldSpecificationBase::catalogName(), - fs.getName(), setName, targetGroup.getName(), numTargetFaces ) ); + this->getName(), time_n+dt, fs.getCatalogName(), fs.getName(), + setName, targetGroup.getName(), numTargetFaces ) ); } if( stencil.size() == 0 ) @@ -804,7 +838,7 @@ void SinglePhaseFVM< BASE >::applyFaceDirichletBC( real64 const time_n, BoundaryStencilWrapper const stencilWrapper = stencil.createKernelWrapper(); singlePhaseFVMKernels:: - DirichletFaceBasedAssemblyKernelFactory:: + DirichletFluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), dofKey, this->getName(), @@ -833,12 +867,12 @@ void SinglePhaseFVM< SinglePhaseProppantBase >::applyAquiferBC( real64 const GEO } template<> -void SinglePhaseFVM< SinglePhaseBase >::applyAquiferBC( real64 const time, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) const +void SinglePhaseFVM<>::applyAquiferBC( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) const { GEOS_MARK_FUNCTION; @@ -859,8 +893,8 @@ void SinglePhaseFVM< SinglePhaseBase >::applyAquiferBC( real64 const time, elemManager.constructArrayViewAccessor< globalIndex, 1 >( elemDofKey ); elemDofNumber.setName( this->getName() + "/accessors/" + elemDofKey ); - typename FaceBasedAssemblyKernelBase::SinglePhaseFlowAccessors flowAccessors( elemManager, this->getName() ); - typename FaceBasedAssemblyKernelBase::SinglePhaseFluidAccessors fluidAccessors( elemManager, this->getName() ); + typename FluxComputeKernelBase::SinglePhaseFlowAccessors flowAccessors( elemManager, this->getName() ); + typename FluxComputeKernelBase::SinglePhaseFluidAccessors fluidAccessors( elemManager, this->getName() ); fsManager.apply< FaceManager, AquiferBoundaryCondition >( time + dt, @@ -904,9 +938,9 @@ void SinglePhaseFVM< SinglePhaseBase >::applyAquiferBC( real64 const time, namespace { -typedef SinglePhaseFVM< SinglePhaseBase > NoProppant; -typedef SinglePhaseFVM< SinglePhaseProppantBase > Proppant; -REGISTER_CATALOG_ENTRY( SolverBase, NoProppant, string const &, Group * const ) -REGISTER_CATALOG_ENTRY( SolverBase, Proppant, string const &, Group * const ) +typedef SinglePhaseFVM< SinglePhaseProppantBase > SinglePhaseFVMProppant; +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhaseFVMProppant, string const &, Group * const ) +typedef SinglePhaseFVM<> SinglePhaseFVM; +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhaseFVM, string const &, Group * const ) } } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseFVM.hpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseFVM.hpp index ef6705b4f5e..49926bcf5a1 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseFVM.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseFVM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -43,7 +44,7 @@ class SinglePhaseFVM : public BASE // have to use this->member etc. using BASE::getLogLevel; - // Aliasing public/protected members/methods of SolverBase so we don't + // Aliasing public/protected members/methods of PhysicsSolverBase so we don't // have to use this->member etc. using BASE::forDiscretizationOnMeshTargets; using BASE::m_cflFactor; @@ -96,24 +97,24 @@ class SinglePhaseFVM : public BASE * @brief name of the node manager in the object catalog * @return string that contains the catalog name to generate a new NodeManager object through the object catalog. */ - template< typename _BASE=BASE > - static - typename std::enable_if< std::is_same< _BASE, SinglePhaseBase >::value, string >::type - catalogName() + static string catalogName() { - return "SinglePhaseFVM"; - } - - template< typename _BASE=BASE > - static - typename std::enable_if< std::is_same< _BASE, SinglePhaseProppantBase >::value, string >::type - catalogName() - { - return "SinglePhaseProppantFVM"; + if constexpr ( std::is_same_v< BASE, SinglePhaseBase > ) + { + return "SinglePhaseFVM"; + } + else if constexpr ( std::is_same_v< BASE, SinglePhaseProppantBase > ) + { + return "SinglePhaseProppantFVM"; + } + else + { + return BASE::catalogName(); + } } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -165,6 +166,12 @@ class SinglePhaseFVM : public BASE arrayView1d< real64 > const & localRhs ) override; virtual void + assembleStabilizedFluxTerms( real64 const dt, + DomainPartition const & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) override; + virtual void assembleEDFMFluxTerms( real64 const time_n, real64 const dt, DomainPartition const & domain, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseFVMKernels.hpp deleted file mode 100644 index c3742dfa748..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseFVMKernels.hpp +++ /dev/null @@ -1,1062 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file SinglePhaseFVMKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEFVMKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEFVMKERNELS_HPP - -#include "common/DataLayouts.hpp" -#include "common/DataTypes.hpp" -#include "common/GEOS_RAJA_Interface.hpp" -#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" -#include "constitutive/fluid/singlefluid/SingleFluidFields.hpp" -#include "constitutive/fluid/singlefluid/SlurryFluidBase.hpp" -#include "constitutive/fluid/singlefluid/SlurryFluidFields.hpp" -#include "constitutive/permeability/PermeabilityBase.hpp" -#include "constitutive/permeability/PermeabilityFields.hpp" -#include "fieldSpecification/AquiferBoundaryCondition.hpp" -#include "finiteVolume/BoundaryStencil.hpp" -#include "finiteVolume/FluxApproximationBase.hpp" -#include "linearAlgebra/interfaces/InterfaceTypes.hpp" -#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" - -namespace geos -{ - -namespace singlePhaseFVMKernels -{ -using namespace constitutive; - -/******************************** FaceBasedAssemblyKernelBase ********************************/ - -/** - * @brief Base class for FaceBasedAssemblyKernel that holds all data not dependent - * on template parameters (like stencil type and number of dofs). - */ -class FaceBasedAssemblyKernelBase -{ -public: - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using DofNumberAccessor = ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > >; - - using SinglePhaseFlowAccessors = - StencilAccessors< fields::ghostRank, - fields::flow::pressure, - fields::flow::pressure_n, - fields::flow::gravityCoefficient, - fields::flow::mobility, - fields::flow::dMobility_dPressure >; - - using SinglePhaseFluidAccessors = - StencilMaterialAccessors< SingleFluidBase, - fields::singlefluid::density, - fields::singlefluid::dDensity_dPressure >; - - using SlurryFluidAccessors = - StencilMaterialAccessors< SlurryFluidBase, - fields::singlefluid::density, - fields::singlefluid::dDensity_dPressure >; - - using PermeabilityAccessors = - StencilMaterialAccessors< PermeabilityBase, - fields::permeability::permeability, - fields::permeability::dPerm_dPressure >; - - using ProppantPermeabilityAccessors = - StencilMaterialAccessors< PermeabilityBase, - fields::permeability::permeability, - fields::permeability::dPerm_dPressure, - fields::permeability::dPerm_dDispJump, - fields::permeability::permeabilityMultiplier >; - - /** - * @brief Constructor for the kernel interface - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofNumberAccessor accessor for the dof numbers - * @param[in] singleFlowAccessors accessor for wrappers registered by the solver - * @param[in] singlePhaseFluidAccessors accessor for wrappers registered by the singlefluid model - * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - FaceBasedAssemblyKernelBase( globalIndex const rankOffset, - DofNumberAccessor const & dofNumberAccessor, - SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, - SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, - PermeabilityAccessors const & permeabilityAccessors, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : m_rankOffset( rankOffset ), - m_dt( dt ), - m_dofNumber( dofNumberAccessor.toNestedViewConst() ), - m_permeability( permeabilityAccessors.get( fields::permeability::permeability {} ) ), - m_dPerm_dPres( permeabilityAccessors.get( fields::permeability::dPerm_dPressure {} ) ), - m_ghostRank( singlePhaseFlowAccessors.get( fields::ghostRank {} ) ), - m_gravCoef( singlePhaseFlowAccessors.get( fields::flow::gravityCoefficient {} ) ), - m_pres( singlePhaseFlowAccessors.get( fields::flow::pressure {} ) ), - m_mob( singlePhaseFlowAccessors.get( fields::flow::mobility {} ) ), - m_dMob_dPres( singlePhaseFlowAccessors.get( fields::flow::dMobility_dPressure {} ) ), - m_dens( singlePhaseFluidAccessors.get( fields::singlefluid::density {} ) ), - m_dDens_dPres( singlePhaseFluidAccessors.get( fields::singlefluid::dDensity_dPressure {} ) ), - m_localMatrix( localMatrix ), - m_localRhs( localRhs ) - {} - -protected: - - /// Offset for my MPI rank - globalIndex const m_rankOffset; - - /// Time step size - real64 const m_dt; - - /// Views on dof numbers - ElementViewConst< arrayView1d< globalIndex const > > const m_dofNumber; - - /// Views on permeability - ElementViewConst< arrayView3d< real64 const > > m_permeability; - ElementViewConst< arrayView3d< real64 const > > m_dPerm_dPres; - - /// Views on ghost rank numbers and gravity coefficients - ElementViewConst< arrayView1d< integer const > > const m_ghostRank; - ElementViewConst< arrayView1d< real64 const > > const m_gravCoef; - - // Primary and secondary variables - /// Views on pressure - ElementViewConst< arrayView1d< real64 const > > const m_pres; - - /// Views on fluid mobility - ElementViewConst< arrayView1d< real64 const > > const m_mob; - ElementViewConst< arrayView1d< real64 const > > const m_dMob_dPres; - - /// Views on fluid density - ElementViewConst< arrayView2d< real64 const > > const m_dens; - ElementViewConst< arrayView2d< real64 const > > const m_dDens_dPres; - - // Residual and jacobian - - /// View on the local CRS matrix - CRSMatrixView< real64, globalIndex const > const m_localMatrix; - /// View on the local RHS - arrayView1d< real64 > const m_localRhs; -}; - -/** - * @class FaceBasedAssemblyKernel - * @tparam NUM_DOF number of degrees of freedom - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @brief Define the interface for the assembly kernel in charge of flux terms - */ -template< integer NUM_EQN, integer NUM_DOF, typename STENCILWRAPPER > -class FaceBasedAssemblyKernel : public FaceBasedAssemblyKernelBase -{ -public: - - /// Compute time value for the number of degrees of freedom - static constexpr integer numDof = NUM_DOF; - - /// Compute time value for the number of equations - static constexpr integer numEqn = NUM_EQN; - - /// Maximum number of elements at the face - static constexpr localIndex maxNumElems = STENCILWRAPPER::maxNumPointsInFlux; - - /// Maximum number of connections at the face - static constexpr localIndex maxNumConns = STENCILWRAPPER::maxNumConnections; - - /// Maximum number of points in the stencil - static constexpr localIndex maxStencilSize = STENCILWRAPPER::maxStencilSize; - - /** - * @brief Constructor for the kernel interface - * @param[in] rankOffset the offset of my MPI rank - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dofNumberAccessor - * @param[in] singlePhaseFlowAccessors - * @param[in] singlePhaseFluidAccessors - * @param[in] permeabilityAccessors - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - FaceBasedAssemblyKernel( globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, - SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, - PermeabilityAccessors const & permeabilityAccessors, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : FaceBasedAssemblyKernelBase( rankOffset, - dofNumberAccessor, - singlePhaseFlowAccessors, - singlePhaseFluidAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs ), - m_stencilWrapper( stencilWrapper ), - m_seri( stencilWrapper.getElementRegionIndices() ), - m_sesri( stencilWrapper.getElementSubRegionIndices() ), - m_sei( stencilWrapper.getElementIndices() ) - {} - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - struct StackVariables - { -public: - - /** - * @brief Constructor for the stack variables - * @param[in] size size of the stencil for this connection - * @param[in] numElems number of elements for this connection - */ - GEOS_HOST_DEVICE - StackVariables( localIndex const size, localIndex numElems ) - : stencilSize( size ), - numFluxElems( numElems ), - dofColIndices( size * numDof ), - localFlux( numElems * numEqn ), - localFluxJacobian( numElems * numEqn, size * numDof ) - {} - - // Stencil information - - /// Stencil size for a given connection - localIndex const stencilSize; - - /// Number of elements for a given connection - localIndex const numFluxElems; - - // Transmissibility and derivatives - - /// Transmissibility - real64 transmissibility[maxNumConns][2]{}; - /// Derivatives of transmissibility with respect to pressure - real64 dTrans_dPres[maxNumConns][2]{}; - - // Local degrees of freedom and local residual/jacobian - - /// Indices of the matrix rows/columns corresponding to the dofs in this face - stackArray1d< globalIndex, maxNumElems * numDof > dofColIndices; - - /// Storage for the face local residual vector (all equations except volume balance) - stackArray1d< real64, maxNumElems * numEqn > localFlux; - /// Storage for the face local Jacobian matrix - stackArray2d< real64, maxNumElems * numEqn * maxStencilSize * numDof > localFluxJacobian; - - }; - - /** - * @brief Getter for the stencil size at this connection - * @param[in] iconn the connection index - * @return the size of the stencil at this connection - */ - GEOS_HOST_DEVICE - localIndex stencilSize( localIndex const iconn ) const - { return m_sei[iconn].size(); } - - /** - * @brief Getter for the number of elements at this connection - * @param[in] iconn the connection index - * @return the number of elements at this connection - */ - GEOS_HOST_DEVICE - localIndex numPointsInFlux( localIndex const iconn ) const - { return m_stencilWrapper.numPointsInFlux( iconn ); } - - /** - * @brief Performs the setup phase for the kernel. - * @param[in] iconn the connection index - * @param[in] stack the stack variables - */ - GEOS_HOST_DEVICE - void setup( localIndex const iconn, - StackVariables & stack ) const - { - // set degrees of freedom indices for this face - for( integer i = 0; i < stack.stencilSize; ++i ) - { - globalIndex const offset = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; - - for( integer jdof = 0; jdof < numDof; ++jdof ) - { - stack.dofColIndices[i * numDof + jdof] = offset + jdof; - } - } - } - - /** - * @brief Compute the local flux contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the computation of the flux - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - * @param[in] NoOpFunc the function used to customize the computation of the flux - */ - template< typename FUNC = singlePhaseBaseKernels::NoOpFunc > - GEOS_HOST_DEVICE - void computeFlux( localIndex const iconn, - StackVariables & stack, - FUNC && kernelOp = singlePhaseBaseKernels::NoOpFunc{} ) const - { - // first, compute the transmissibilities at this face - m_stencilWrapper.computeWeights( iconn, - m_permeability, - m_dPerm_dPres, - stack.transmissibility, - stack.dTrans_dPres ); - - localIndex k[2]; - localIndex connectionIndex = 0; - - for( k[0] = 0; k[0] < stack.numFluxElems; ++k[0] ) - { - for( k[1] = k[0] + 1; k[1] < stack.numFluxElems; ++k[1] ) - { - // clear working arrays - real64 densMean = 0.0; - real64 dDensMean_dP[2]{0.0, 0.0}; - - // create local work arrays - real64 fluxVal = 0.0; - real64 dFlux_dP[2]{0.0, 0.0}; - - real64 const trans[2] = { stack.transmissibility[connectionIndex][0], stack.transmissibility[connectionIndex][1] }; - real64 const dTrans_dP[2] = { stack.dTrans_dPres[connectionIndex][0], stack.dTrans_dPres[connectionIndex][1] }; - - real64 presGrad = 0.0; - real64 dPresGrad_dP[2]{0.0, 0.0}; - - real64 gravHead = 0.0; - real64 dGravHead_dP[2]{0.0, 0.0}; - - localIndex const seri[2] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; - localIndex const sesri[2] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; - localIndex const sei[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; - - // calculate quantities on primary connected cells - for( integer ke = 0; ke < 2; ++ke ) - { - // density - real64 const density = m_dens[seri[ke]][sesri[ke]][sei[ke]][0]; - real64 const dDens_dP = m_dDens_dPres[seri[ke]][sesri[ke]][sei[ke]][0]; - - // average density and derivatives - densMean += 0.5 * density; - dDensMean_dP[ke] = 0.5 * dDens_dP; - } - - //***** calculation of flux ***** - - // compute potential difference - real64 potScale = 0.0; - real64 dPresGrad_dTrans = 0.0; - real64 dGravHead_dTrans = 0.0; - int signPotDiff[2] = {1, -1}; - - for( integer ke = 0; ke < 2; ++ke ) - { - localIndex const er = seri[ke]; - localIndex const esr = sesri[ke]; - localIndex const ei = sei[ke]; - - real64 const pressure = m_pres[er][esr][ei]; - presGrad += trans[ke] * pressure; - dPresGrad_dTrans += signPotDiff[ke] * pressure; - dPresGrad_dP[ke] = trans[ke]; - - real64 const gravD = trans[ke] * m_gravCoef[er][esr][ei]; - real64 const pot = trans[ke] * pressure - densMean * gravD; - - gravHead += densMean * gravD; - dGravHead_dTrans += signPotDiff[ke] * densMean * m_gravCoef[er][esr][ei]; - - for( integer i = 0; i < 2; ++i ) - { - dGravHead_dP[i] += dDensMean_dP[i] * gravD; - } - - potScale = fmax( potScale, fabs( pot ) ); - } - - for( integer ke = 0; ke < 2; ++ke ) - { - dPresGrad_dP[ke] += dTrans_dP[ke] * dPresGrad_dTrans; - dGravHead_dP[ke] += dTrans_dP[ke] * dGravHead_dTrans; - } - - // *** upwinding *** - - // compute potential gradient - real64 const potGrad = presGrad - gravHead; - - // compute upwinding tolerance - real64 constexpr upwRelTol = 1e-8; - real64 const upwAbsTol = fmax( potScale * upwRelTol, LvArray::NumericLimits< real64 >::epsilon ); - - // decide mobility coefficients - smooth variation in [-upwAbsTol; upwAbsTol] - real64 const alpha = ( potGrad + upwAbsTol ) / ( 2 * upwAbsTol ); - - // choose upstream cell - real64 mobility{}; - real64 dMob_dP[2]{}; - if( alpha <= 0.0 || alpha >= 1.0 ) - { - localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) ); - - mobility = m_mob[seri[k_up]][sesri[k_up]][sei[k_up]]; - dMob_dP[k_up] = m_dMob_dPres[seri[k_up]][sesri[k_up]][sei[k_up]]; - } - else - { - real64 const mobWeights[2] = { alpha, 1.0 - alpha }; - for( integer ke = 0; ke < 2; ++ke ) - { - mobility += mobWeights[ke] * m_mob[seri[ke]][sesri[ke]][sei[ke]]; - dMob_dP[ke] = mobWeights[ke] * m_dMob_dPres[seri[ke]][sesri[ke]][sei[ke]]; - } - } - - // pressure gradient depends on all points in the stencil - for( integer ke = 0; ke < 2; ++ke ) - { - dFlux_dP[ke] += dPresGrad_dP[ke]; - } - - // gravitational head depends only on the two cells connected (same as mean density) - for( integer ke = 0; ke < 2; ++ke ) - { - dFlux_dP[ke] -= dGravHead_dP[ke]; - } - - // compute the flux and derivatives using upstream cell mobility - fluxVal = mobility * potGrad; - - for( integer ke = 0; ke < 2; ++ke ) - { - dFlux_dP[ke] *= mobility; - } - - // add contribution from upstream cell mobility derivatives - for( integer ke = 0; ke < 2; ++ke ) - { - dFlux_dP[ke] += dMob_dP[ke] * potGrad; - } - - // populate local flux vector and derivatives - stack.localFlux[k[0]*numEqn] += m_dt * fluxVal; - stack.localFlux[k[1]*numEqn] -= m_dt * fluxVal; - - for( integer ke = 0; ke < 2; ++ke ) - { - localIndex const localDofIndexPres = k[ke] * numDof; - stack.localFluxJacobian[k[0]*numEqn][localDofIndexPres] += m_dt * dFlux_dP[ke]; - stack.localFluxJacobian[k[1]*numEqn][localDofIndexPres] -= m_dt * dFlux_dP[ke]; - } - - // Customize the kernel with this lambda - kernelOp( k, seri, sesri, sei, connectionIndex, alpha, mobility, potGrad, fluxVal, dFlux_dP ); - - connectionIndex++; - } - } - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - template< typename FUNC = singlePhaseBaseKernels::NoOpFunc > - GEOS_HOST_DEVICE - void complete( localIndex const iconn, - StackVariables & stack, - FUNC && kernelOp = singlePhaseBaseKernels::NoOpFunc{} ) const - { - // add contribution to residual and jacobian into: - // - the mass balance equation - // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels - for( integer i = 0; i < stack.numFluxElems; ++i ) - { - if( m_ghostRank[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )] < 0 ) - { - globalIndex const globalRow = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; - localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); - GEOS_ASSERT_GE( localRow, 0 ); - GEOS_ASSERT_GT( m_localMatrix.numRows(), localRow ); - - RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[localRow], stack.localFlux[i * numEqn] ); - m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( localRow, - stack.dofColIndices.data(), - stack.localFluxJacobian[i * numEqn].dataIfContiguous(), - stack.stencilSize * numDof ); - - // call the lambda to assemble additional terms, such as thermal terms - kernelOp( i, localRow ); - } - } - } - - /** - * @brief Performs the kernel launch - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] numConnections the number of connections - * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables - */ - template< typename POLICY, typename KERNEL_TYPE > - static void - launch( localIndex const numConnections, - KERNEL_TYPE const & kernelComponent ) - { - GEOS_MARK_FUNCTION; - - forAll< POLICY >( numConnections, [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), - kernelComponent.numPointsInFlux( iconn ) ); - - kernelComponent.setup( iconn, stack ); - kernelComponent.computeFlux( iconn, stack ); - kernelComponent.complete( iconn, stack ); - } ); - } - - -protected: - - // Stencil information - - /// Reference to the stencil wrapper - STENCILWRAPPER const m_stencilWrapper; - - /// Connection to element maps - typename STENCILWRAPPER::IndexContainerViewConstType const m_seri; - typename STENCILWRAPPER::IndexContainerViewConstType const m_sesri; - typename STENCILWRAPPER::IndexContainerViewConstType const m_sei; -}; - -/** - * @class FaceBasedAssemblyKernelFactory - */ -class FaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey string to get the element degrees of freedom numbers - * @param[in] solverName name of the solver (to name accessors) - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY, typename STENCILWRAPPER > - static void - createAndLaunch( globalIndex const rankOffset, - string const & dofKey, - string const & solverName, - ElementRegionManager const & elemManager, - STENCILWRAPPER const & stencilWrapper, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - integer constexpr NUM_EQN = 1; - integer constexpr NUM_DOF = 1; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - using kernelType = FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; - typename kernelType::SinglePhaseFlowAccessors flowAccessors( elemManager, solverName ); - typename kernelType::SinglePhaseFluidAccessors fluidAccessors( elemManager, solverName ); - typename kernelType::PermeabilityAccessors permAccessors( elemManager, solverName ); - - kernelType kernel( rankOffset, stencilWrapper, dofNumberAccessor, - flowAccessors, fluidAccessors, permAccessors, - dt, localMatrix, localRhs ); - kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); - } -}; - -/******************************** DirichletFaceBasedAssemblyKernel ********************************/ - -/** - * @class DirichFaceBasedAssemblyKernel - * @tparam FLUIDWRAPPER the type of the fluid wrapper - * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms - */ -template< integer NUM_EQN, integer NUM_DOF, typename FLUIDWRAPPER > -class DirichletFaceBasedAssemblyKernel : public FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, - BoundaryStencilWrapper > -{ -public: - - using AbstractBase = singlePhaseFVMKernels::FaceBasedAssemblyKernelBase; - using DofNumberAccessor = AbstractBase::DofNumberAccessor; - using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; - using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; - using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; - - using AbstractBase::m_dt; - using AbstractBase::m_rankOffset; - using AbstractBase::m_dofNumber; - using AbstractBase::m_ghostRank; - using AbstractBase::m_gravCoef; - using AbstractBase::m_pres; - using AbstractBase::m_mob; - using AbstractBase::m_dMob_dPres; - using AbstractBase::m_dens; - using AbstractBase::m_dDens_dPres; - using AbstractBase::m_permeability; - using AbstractBase::m_dPerm_dPres; - - using AbstractBase::m_localMatrix; - using AbstractBase::m_localRhs; - - using Base = singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, - BoundaryStencilWrapper >; - using Base::numDof; - using Base::numEqn; - using Base::m_stencilWrapper; - using Base::m_seri; - using Base::m_sesri; - using Base::m_sei; - - /** - * @brief Constructor for the kernel interface - * @param[in] rankOffset the offset of my MPI rank - * @param[in] faceManager the face manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] fluidWrapper reference to the fluid wrapper - * @param[in] dofNumberAccessor - * @param[in] singlePhaseFlowAccessors - * @param[in] singlePhaseFluidAccessors - * @param[in] permeabilityAccessors - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - DirichletFaceBasedAssemblyKernel( globalIndex const rankOffset, - FaceManager const & faceManager, - BoundaryStencilWrapper const & stencilWrapper, - FLUIDWRAPPER const & fluidWrapper, - DofNumberAccessor const & dofNumberAccessor, - SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, - SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, - PermeabilityAccessors const & permeabilityAccessors, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : Base( rankOffset, - stencilWrapper, - dofNumberAccessor, - singlePhaseFlowAccessors, - singlePhaseFluidAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs ), - m_facePres( faceManager.getField< fields::flow::facePressure >() ), - m_faceGravCoef( faceManager.getField< fields::flow::gravityCoefficient >() ), - m_fluidWrapper( fluidWrapper ) - {} - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - struct StackVariables - { -public: - - /** - * @brief Constructor for the stack variables - * @param[in] size size of the stencil for this connection - * @param[in] numElems number of elements for this connection - */ - GEOS_HOST_DEVICE - StackVariables( localIndex const GEOS_UNUSED_PARAM( size ), - localIndex GEOS_UNUSED_PARAM( numElems ) ) - {} - - /// Transmissibility - real64 transmissibility = 0.0; - - /// Indices of the matrix rows/columns corresponding to the dofs in this face - globalIndex dofColIndices[numDof]{}; - - /// Storage for the face local residual - real64 localFlux[numEqn]{}; - - /// Storage for the face local Jacobian - real64 localFluxJacobian[numEqn][numDof]{}; - - }; - - - /** - * @brief Performs the setup phase for the kernel. - * @param[in] iconn the connection index - * @param[in] stack the stack variables - */ - GEOS_HOST_DEVICE - void setup( localIndex const iconn, - StackVariables & stack ) const - { - globalIndex const offset = - m_dofNumber[m_seri( iconn, BoundaryStencil::Order::ELEM )][m_sesri( iconn, BoundaryStencil::Order::ELEM )][m_sei( iconn, BoundaryStencil::Order::ELEM )]; - - for( integer jdof = 0; jdof < numDof; ++jdof ) - { - stack.dofColIndices[jdof] = offset + jdof; - } - } - - /** - * @brief Compute the local Dirichlet face flux contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes - */ - template< typename FUNC = singlePhaseBaseKernels::NoOpFunc > - GEOS_HOST_DEVICE - void computeFlux( localIndex const iconn, - StackVariables & stack, - FUNC && compFluxKernelOp = singlePhaseBaseKernels::NoOpFunc{} ) const - { - using Order = BoundaryStencil::Order; - localIndex constexpr numElems = BoundaryStencil::maxNumPointsInFlux; - - stackArray1d< real64, numElems > mobility( numElems ); - stackArray1d< real64, numElems > dMobility_dP( numElems ); - - localIndex const er = m_seri( iconn, Order::ELEM ); - localIndex const esr = m_sesri( iconn, Order::ELEM ); - localIndex const ei = m_sei( iconn, Order::ELEM ); - localIndex const kf = m_sei( iconn, Order::FACE ); - - // Get flow quantities on the elem/face - real64 faceDens, faceVisc; - SingleFluidBaseUpdate::computeValues( m_fluidWrapper, m_facePres[kf], faceDens, faceVisc ); - - mobility[Order::ELEM] = m_mob[er][esr][ei]; - singlePhaseBaseKernels::MobilityKernel::compute( faceDens, faceVisc, mobility[Order::FACE] ); - - dMobility_dP[Order::ELEM] = m_dMob_dPres[er][esr][ei]; - dMobility_dP[Order::FACE] = 0.0; - - // Compute average density - real64 const densMean = 0.5 * ( m_dens[er][esr][ei][0] + faceDens ); - real64 const dDens_dP = 0.5 * m_dDens_dPres[er][esr][ei][0]; - - // Evaluate potential difference - real64 const potDif = (m_pres[er][esr][ei] - m_facePres[kf]) - - densMean * (m_gravCoef[er][esr][ei] - m_faceGravCoef[kf]); - real64 const dPotDif_dP = 1.0 - dDens_dP * m_gravCoef[er][esr][ei]; - - real64 dTrans_dPerm[3]; - m_stencilWrapper.computeWeights( iconn, m_permeability, stack.transmissibility, dTrans_dPerm ); - real64 const dTrans_dPres = LvArray::tensorOps::AiBi< 3 >( dTrans_dPerm, m_dPerm_dPres[er][esr][ei][0] ); - - real64 const f = stack.transmissibility * potDif; - real64 const dF_dP = stack.transmissibility * dPotDif_dP + dTrans_dPres * potDif; - - // Upwind mobility - localIndex const k_up = ( potDif >= 0 ) ? Order::ELEM : Order::FACE; - real64 const mobility_up = mobility[k_up]; - real64 const dMobility_dP_up = dMobility_dP[k_up]; - - // call the lambda in the phase loop to allow the reuse of the fluxes and their derivatives - // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase - - compFluxKernelOp( er, esr, ei, kf, f, dF_dP, mobility_up, dMobility_dP_up ); - - // *** end of upwinding - - // Populate local flux vector and derivatives - - stack.localFlux[0] = m_dt * mobility[k_up] * f; - stack.localFluxJacobian[0][0] = m_dt * ( mobility_up * dF_dP + dMobility_dP_up * f ); - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - template< typename FUNC = singlePhaseBaseKernels::NoOpFunc > - GEOS_HOST_DEVICE - void complete( localIndex const iconn, - StackVariables & stack, - FUNC && assemblyKernelOp = singlePhaseBaseKernels::NoOpFunc{} ) const - { - using Order = BoundaryStencil::Order; - - localIndex const er = m_seri( iconn, Order::ELEM ); - localIndex const esr = m_sesri( iconn, Order::ELEM ); - localIndex const ei = m_sei( iconn, Order::ELEM ); - - if( m_ghostRank[er][esr][ei] < 0 ) - { - // Add to global residual/jacobian - globalIndex const dofIndex = m_dofNumber[er][esr][ei]; - localIndex const localRow = LvArray::integerConversion< localIndex >( dofIndex - m_rankOffset ); - - RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow], stack.localFlux[0] ); - - AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > - ( localRow, - stack.dofColIndices, - stack.localFluxJacobian[0], - numDof ); - - assemblyKernelOp( localRow ); - } - } - -protected: - - /// Views on face pressure, temperature, and composition - arrayView1d< real64 const > const m_facePres; - - /// View on the face gravity coefficient - arrayView1d< real64 const > const m_faceGravCoef; - - /// Reference to the fluid wrapper - FLUIDWRAPPER const m_fluidWrapper; - -}; - - -/** - * @class DirichletFaceBasedAssemblyKernelFactory - */ -class DirichletFaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey string to get the element degrees of freedom numbers - * @param[in] solverName name of the solver (to name accessors) - * @param[in] faceManager reference to the face manager - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the boundary stencil wrapper - * @param[in] fluidBase the single phase fluid constitutive model - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY > - static void - createAndLaunch( globalIndex const rankOffset, - string const & dofKey, - string const & solverName, - FaceManager const & faceManager, - ElementRegionManager const & elemManager, - BoundaryStencilWrapper const & stencilWrapper, - SingleFluidBase & fluidBase, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - constitutiveUpdatePassThru( fluidBase, [&]( auto & fluid ) - { - using FluidType = TYPEOFREF( fluid ); - typename FluidType::KernelWrapper fluidWrapper = fluid.createKernelWrapper(); - - integer constexpr NUM_DOF = 1; - integer constexpr NUM_EQN = 1; - using kernelType = DirichletFaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, typename FluidType::KernelWrapper >; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - typename kernelType::SinglePhaseFlowAccessors singlePhaseFlowAccessors( elemManager, solverName ); - typename kernelType::SinglePhaseFluidAccessors singlePhaseFluidAccessors( elemManager, solverName ); - typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); - - kernelType kernel( rankOffset, - faceManager, - stencilWrapper, - fluidWrapper, - dofNumberAccessor, - singlePhaseFlowAccessors, - singlePhaseFluidAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs ); - - kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); - } ); - } - -}; - - -/******************************** AquiferBCKernel ********************************/ - -/** - * @brief Functions to assemble aquifer boundary condition contributions to residual and Jacobian - */ -struct AquiferBCKernel -{ - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - GEOS_HOST_DEVICE - static void - compute( real64 const & aquiferVolFlux, - real64 const & dAquiferVolFlux_dPres, - real64 const & aquiferDens, - real64 const & dens, - real64 const & dDens_dPres, - real64 const & dt, - real64 & localFlux, - real64 & localFluxJacobian ) - { - if( aquiferVolFlux > 0 ) // aquifer is upstream - { - localFlux -= dt * aquiferVolFlux * aquiferDens; - localFluxJacobian -= dt * dAquiferVolFlux_dPres * aquiferDens; - } - else // reservoir is upstream - { - localFlux -= dt * aquiferVolFlux * dens; - localFluxJacobian -= dt * (dAquiferVolFlux_dPres * dens + aquiferVolFlux * dDens_dPres); - } - } - - static void - launch( BoundaryStencil const & stencil, - globalIndex const rankOffset, - ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, - ElementViewConst< arrayView1d< integer const > > const & ghostRank, - AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, - real64 const & aquiferDens, - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & pres_n, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const > > const & dens, - ElementViewConst< arrayView2d< real64 const > > const & dDens_dPres, - real64 const & timeAtBeginningOfStep, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - using Order = BoundaryStencil::Order; - - BoundaryStencil::IndexContainerViewConstType const & seri = stencil.getElementRegionIndices(); - BoundaryStencil::IndexContainerViewConstType const & sesri = stencil.getElementSubRegionIndices(); - BoundaryStencil::IndexContainerViewConstType const & sefi = stencil.getElementIndices(); - BoundaryStencil::WeightContainerViewConstType const & weight = stencil.getWeights(); - - forAll< parallelDevicePolicy<> >( stencil.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - // working variables - real64 localFlux = 0.0; - real64 localFluxJacobian = 0.0; - - localIndex const er = seri( iconn, Order::ELEM ); - localIndex const esr = sesri( iconn, Order::ELEM ); - localIndex const ei = sefi( iconn, Order::ELEM ); - real64 const areaFraction = weight( iconn, Order::ELEM ); - - // compute the aquifer influx rate using the pressure influence function and the aquifer props - real64 dAquiferVolFlux_dPres = 0.0; - real64 const aquiferVolFlux = aquiferBCWrapper.compute( timeAtBeginningOfStep, - dt, - pres[er][esr][ei], - pres_n[er][esr][ei], - gravCoef[er][esr][ei], - areaFraction, - dAquiferVolFlux_dPres ); - - // compute the phase/component aquifer flux - AquiferBCKernel::compute( aquiferVolFlux, - dAquiferVolFlux_dPres, - aquiferDens, - dens[er][esr][ei][0], - dDens_dPres[er][esr][ei][0], - dt, - localFlux, - localFluxJacobian ); - - // Add to residual/jacobian - if( ghostRank[er][esr][ei] < 0 ) - { - globalIndex const globalRow = dofNumber[er][esr][ei]; - localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - rankOffset ); - GEOS_ASSERT_GE( localRow, 0 ); - GEOS_ASSERT_GT( localMatrix.numRows(), localRow ); - - RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[localRow], localFlux ); - localMatrix.addToRow< parallelDeviceAtomic >( localRow, - &dofNumber[er][esr][ei], - &localFluxJacobian, - 1 ); - } - } ); - } - -}; - - -} // namespace singlePhaseFVMKernels - -} // namespace geos - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEFVMKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseHybridFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseHybridFVM.cpp index 24ebda97229..e0b9732cec2 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseHybridFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseHybridFVM.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,20 +19,24 @@ #include "SinglePhaseHybridFVM.hpp" -#include "common/TimingMacros.hpp" #include "constitutive/ConstitutivePassThru.hpp" #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" #include "fieldSpecification/AquiferBoundaryCondition.hpp" #include "fieldSpecification/FieldSpecificationManager.hpp" +#include "discretizationMethods/NumericalMethodsManager.hpp" +#include "finiteVolume/FiniteVolumeManager.hpp" #include "finiteVolume/HybridMimeticDiscretization.hpp" #include "finiteVolume/MimeticInnerProductDispatch.hpp" #include "mainInterface/ProblemManager.hpp" +#include "mesh/DomainPartition.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/SinglePhaseHybridFVMKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/ResidualNormKernel.hpp" /** - * @namespace the geosx namespace that encapsulates the majority of the code + * @namespace the geos namespace that encapsulates the majority of the code */ namespace geos { @@ -56,10 +61,26 @@ SinglePhaseHybridFVM::SinglePhaseHybridFVM( const string & name, void SinglePhaseHybridFVM::registerDataOnMesh( Group & meshBodies ) { + using namespace fields::flow; // 1) Register the cell-centered data SinglePhaseBase::registerDataOnMesh( meshBodies ); + // pressureGradient is specific for HybridFVM + forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + elemManager.forElementSubRegions< ElementSubRegionBase >( regionNames, + [&]( localIndex const, + ElementSubRegionBase & subRegion ) + { + subRegion.registerField< pressureGradient >( getName() ). + reference().resizeDimension< 1 >( 3 ); + } ); + } ); + // 2) Register the face data meshBodies.forSubGroups< MeshBody >( [&] ( MeshBody & meshBody ) { @@ -260,6 +281,19 @@ void SinglePhaseHybridFVM::assembleFluxTerms( real64 const dt, } + +void SinglePhaseHybridFVM::assembleStabilizedFluxTerms( real64 const dt, + DomainPartition const & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + // pressure stabilization not implemented + GEOS_UNUSED_VAR( dt, domain, dofManager, localMatrix, localRhs ); + GEOS_ERROR( "Stabilized flux not available for this flow solver" ); +} + + void SinglePhaseHybridFVM::assembleEDFMFluxTerms( real64 const GEOS_UNUSED_PARAM( time_n ), real64 const dt, DomainPartition const & domain, @@ -306,7 +340,7 @@ void SinglePhaseHybridFVM::applyBoundaryConditions( real64 const time_n, GEOS_MARK_FUNCTION; SinglePhaseBase::applyBoundaryConditions( time_n, dt, domain, dofManager, localMatrix, localRhs ); - if( !m_keepFlowVariablesConstantDuringInitStep ) + if( !m_keepVariablesConstantDuringInitStep ) { applyFaceDirichletBC( time_n, dt, dofManager, domain, localMatrix, localRhs ); } @@ -365,8 +399,8 @@ void SinglePhaseHybridFVM::applyFaceDirichletBC( real64 const time_n, { globalIndex const numTargetFaces = MpiWrapper::sum< globalIndex >( targetSet.size() ); GEOS_LOG_RANK_0( GEOS_FMT( faceBcLogMessage, - this->getName(), time_n+dt, FieldSpecificationBase::catalogName(), - fs.getName(), setName, targetGroup.getName(), numTargetFaces ) ); + this->getName(), time_n+dt, fs.getCatalogName(), fs.getName(), + setName, targetGroup.getName(), numTargetFaces ) ); } // next, we use the field specification functions to apply the boundary conditions to the system @@ -442,7 +476,7 @@ real64 SinglePhaseHybridFVM::calculateResidualNorm( real64 const & GEOS_UNUSED_P real64 localResidualNorm = 0.0; real64 localResidualNormalizer = 0.0; - solverBaseKernels::NormType const normType = getNonlinearSolverParameters().normType(); + physicsSolverBaseKernels::NormType const normType = getNonlinearSolverParameters().normType(); globalIndex const rankOffset = dofManager.rankOffset(); string const elemDofKey = dofManager.getKey( viewKeyStruct::elemDofFieldString() ); @@ -471,9 +505,6 @@ real64 SinglePhaseHybridFVM::calculateResidualNorm( real64 const & GEOS_UNUSED_P defaultViscosity += fluid.defaultViscosity(); subRegionCounter++; - string const & solidName = subRegion.getReference< string >( viewKeyStruct::solidNamesString() ); - CoupledSolidBase const & solid = getConstitutiveModel< CoupledSolidBase >( subRegion, solidName ); - // step 1.1: compute the norm in the subRegion singlePhaseBaseKernels:: @@ -483,15 +514,13 @@ real64 SinglePhaseHybridFVM::calculateResidualNorm( real64 const & GEOS_UNUSED_P elemDofKey, localRhs, subRegion, - fluid, - solid, m_nonlinearSolverParameters.m_minNormalizer, subRegionResidualNorm, subRegionResidualNormalizer ); // step 1.2: reduction across meshBodies/regions/subRegions - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { if( subRegionResidualNorm[0] > localResidualNorm ) { @@ -533,7 +562,7 @@ real64 SinglePhaseHybridFVM::calculateResidualNorm( real64 const & GEOS_UNUSED_P // step 2.2: reduction across meshBodies/regions/subRegions - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { if( faceResidualNorm[0] > localResidualNorm ) { @@ -550,13 +579,13 @@ real64 SinglePhaseHybridFVM::calculateResidualNorm( real64 const & GEOS_UNUSED_P // step 3: second reduction across MPI ranks real64 residualNorm = 0.0; - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { - solverBaseKernels::LinfResidualNormHelper::computeGlobalNorm( localResidualNorm, residualNorm ); + physicsSolverBaseKernels::LinfResidualNormHelper::computeGlobalNorm( localResidualNorm, residualNorm ); } else { - solverBaseKernels::L2ResidualNormHelper::computeGlobalNorm( localResidualNorm, localResidualNormalizer, residualNorm ); + physicsSolverBaseKernels::L2ResidualNormHelper::computeGlobalNorm( localResidualNorm, localResidualNormalizer, residualNorm ); } if( getLogLevel() >= 1 && logger::internal::rank == 0 ) @@ -627,5 +656,22 @@ void SinglePhaseHybridFVM::resetStateToBeginningOfStep( DomainPartition & domain } ); } -REGISTER_CATALOG_ENTRY( SolverBase, SinglePhaseHybridFVM, string const &, Group * const ) +void SinglePhaseHybridFVM::updatePressureGradient( DomainPartition & domain ) +{ + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + FaceManager & faceManager = mesh.getFaceManager(); + + mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, + auto & subRegion ) + { + singlePhaseHybridFVMKernels::AveragePressureGradientKernelFactory::createAndLaunch< parallelHostPolicy >( subRegion, + faceManager ); + } ); + } ); +} + +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhaseHybridFVM, string const &, Group * const ) } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseHybridFVM.hpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseHybridFVM.hpp index 2f124db3319..7a804ccf7ee 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseHybridFVM.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseHybridFVM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,6 @@ #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEHYBRIDFVM_HPP_ #include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseHybridFVMKernels.hpp" namespace geos { @@ -72,7 +72,7 @@ class SinglePhaseHybridFVM : public SinglePhaseBase static string catalogName() { return "SinglePhaseHybridFVM"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -126,6 +126,13 @@ class SinglePhaseHybridFVM : public SinglePhaseBase CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; + virtual void + assembleStabilizedFluxTerms( real64 const dt, + DomainPartition const & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) override; + virtual void assembleEDFMFluxTerms( real64 const time_n, real64 const dt, @@ -157,6 +164,8 @@ class SinglePhaseHybridFVM : public SinglePhaseBase real64 const & dt, DomainPartition & domain ) override; + virtual void updatePressureGradient( DomainPartition & domain ) override final; + /** * @brief Function to perform the application of Dirichlet BCs on faces * @param[in] time_n current time diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantBase.cpp index e74bdc9619a..d5273602f58 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,17 +20,15 @@ #include "SinglePhaseProppantBase.hpp" +#include "mesh/DomainPartition.hpp" #include "constitutive/ConstitutivePassThru.hpp" #include "constitutive/fluid/singlefluid/SlurryFluidSelector.hpp" #include "constitutive/fluid/singlefluid/SingleFluidFields.hpp" -#include "constitutive/fluid/singlefluid/SlurryFluidFields.hpp" -#include "constitutive/permeability/PermeabilityFields.hpp" #include "constitutive/solid/CoupledSolidBase.hpp" #include "constitutive/solid/ProppantSolid.hpp" #include "constitutive/solid/porosity/ProppantPorosity.hpp" -#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/proppantTransport/ProppantTransportFields.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseProppantBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantBaseKernels.hpp" namespace geos { @@ -68,7 +67,7 @@ SinglePhaseProppantBase::~SinglePhaseProppantBase() void SinglePhaseProppantBase::setConstitutiveNames( ElementSubRegionBase & subRegion ) const { string & fluidMaterialName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - fluidMaterialName = SolverBase::getConstitutiveName< SlurryFluidBase >( subRegion ); + fluidMaterialName = PhysicsSolverBase::getConstitutiveName< SlurryFluidBase >( subRegion ); GEOS_ERROR_IF( fluidMaterialName.empty(), GEOS_FMT( "{}: Fluid model not found on subregion {}", getDataContext(), subRegion.getName() ) ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantBase.hpp index 9249d00f4ed..f8d2e5c9a0b 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantBaseKernels.hpp deleted file mode 100644 index 82fd60fd88a..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantBaseKernels.hpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file SinglePhaseProppantBaseKernels.hpp - */ -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEPROPPANTBASEKERNELS_HPP_ -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEPROPPANTBASEKERNELS_HPP_ - -#include "common/DataTypes.hpp" -#include "common/GEOS_RAJA_Interface.hpp" - -namespace geos -{ - -namespace singlePhaseProppantBaseKernels -{ - -/******************************** FluidUpdateKernel ********************************/ - -struct FluidUpdateKernel -{ - template< typename FLUID_WRAPPER > - static void launch( FLUID_WRAPPER const & fluidWrapper, - arrayView1d< real64 const > const & pres, - arrayView1d< real64 const > const & proppantConcentration, - arrayView2d< real64 const > const & componentConcentration, - arrayView2d< real64 const > const & cellBasedFlux, - arrayView1d< integer const > const & isProppantBoundaryElement ) - { - forAll< parallelDevicePolicy<> >( fluidWrapper.numElems(), [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - - for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) - { - - fluidWrapper.update( a, q, - pres[a], - proppantConcentration[a], - componentConcentration[a], - LvArray::tensorOps::l2Norm< 3 >( cellBasedFlux[a] ), - isProppantBoundaryElement[a] ); - } - } ); - } -}; - -} // namespace singlePhaseProppantBaseKernels - -} //namespace geos - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEPROPPANTBASEKERNELS_HPP_ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantFluxKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantFluxKernels.cpp deleted file mode 100644 index 119f5cb3060..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantFluxKernels.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file singlePhaseProppantFluxKernels.cpp - */ - -#include "physicsSolvers/fluidFlow/SinglePhaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/FluxKernelsHelper.hpp" -#include "SinglePhaseProppantFluxKernels.hpp" - -namespace geos -{ - -namespace singlePhaseProppantFluxKernels -{ - -using namespace fluxKernelsHelper; - - -void FaceElementFluxKernel:: - launch( SurfaceElementStencilWrapper const & stencilWrapper, - real64 const dt, - globalIndex const rankOffset, - ElementViewConst< arrayView1d< globalIndex const > > const & pressureDofNumber, - ElementViewConst< arrayView1d< integer const > > const & ghostRank, - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const > > const & dens, - ElementViewConst< arrayView2d< real64 const > > const & dDens_dPres, - ElementViewConst< arrayView1d< real64 const > > const & mob, - ElementViewConst< arrayView1d< real64 const > > const & dMob_dPres, - ElementViewConst< arrayView3d< real64 const > > const & permeability, - ElementViewConst< arrayView3d< real64 const > > const & dPerm_dPres, - ElementViewConst< arrayView4d< real64 const > > const & dPerm_dDispJump, - ElementViewConst< arrayView3d< real64 const > > const & permeabilityMultiplier, - R1Tensor const & gravityVector, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - constexpr localIndex maxNumFluxElems = SurfaceElementStencilWrapper::maxNumPointsInFlux; - constexpr localIndex maxStencilSize = SurfaceElementStencilWrapper::maxStencilSize; - constexpr localIndex maxNumConnections = SurfaceElementStencilWrapper::maxNumConnections; - - typename SurfaceElementStencilWrapper::IndexContainerViewConstType const & seri = stencilWrapper.getElementRegionIndices(); - typename SurfaceElementStencilWrapper::IndexContainerViewConstType const & sesri = stencilWrapper.getElementSubRegionIndices(); - typename SurfaceElementStencilWrapper::IndexContainerViewConstType const & sei = stencilWrapper.getElementIndices(); - - forAll< parallelDevicePolicy<> >( stencilWrapper.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - localIndex const stencilSize = stencilWrapper.stencilSize( iconn ); - localIndex const numFluxElems = stencilWrapper.numPointsInFlux( iconn ); - localIndex const numDofs = stencilSize; // pressures - - // For now, we have to filter out connections for which numElems == 1 in this function and not early on in - // TwoPointFluxApproximation.cpp. - // The reason for keeping the connections numElems == 1 is that the ProppantTransport solver needs these connections to produce correct - // results. - if( numFluxElems > 1 ) - { - - // working arrays - stackArray1d< globalIndex, maxNumFluxElems > dofColIndices( numDofs ); - stackArray1d< localIndex, maxNumFluxElems > localColIndices( numFluxElems ); - - stackArray1d< real64, maxNumFluxElems > localFlux( numFluxElems ); - stackArray2d< real64, maxNumFluxElems * maxStencilSize > localFluxJacobian( numFluxElems, numDofs ); - - // need to store this for later use in determining the dFlux_dU terms when using better permeabilty approximations. - stackArray2d< real64, maxNumFluxElems * maxStencilSize > dFlux_dAper( numFluxElems, stencilSize ); - - // compute transmissibility - real64 transmissibility[maxNumConnections][2]{}; - real64 dTrans_dPres[maxNumConnections][2]{}; - real64 dTrans_dDispJump[maxNumConnections][2][3]{}; - - GEOS_UNUSED_VAR( dPerm_dPres, dPerm_dDispJump ); - stencilWrapper.computeWeights( iconn, - permeability, - permeabilityMultiplier, - gravityVector, - transmissibility ); - - compute( stencilSize, - seri[iconn], - sesri[iconn], - sei[iconn], - transmissibility, - dTrans_dPres, - dTrans_dDispJump, - pres, - gravCoef, - dens, - dDens_dPres, - mob, - dMob_dPres, - dt, - localFlux, - localFluxJacobian, - dFlux_dAper ); - - // extract DOF numbers - for( localIndex i = 0; i < numDofs; ++i ) - { - dofColIndices[i] = pressureDofNumber[seri( iconn, i )][sesri( iconn, i )][sei( iconn, i )]; - localColIndices[i] = sei( iconn, i ); - } - - for( localIndex i = 0; i < numFluxElems; ++i ) - { - if( ghostRank[seri( iconn, i )][sesri( iconn, i )][sei( iconn, i )] < 0 ) - { - globalIndex const globalRow = pressureDofNumber[seri( iconn, i )][sesri( iconn, i )][sei( iconn, i )]; - localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - rankOffset ); - GEOS_ASSERT_GE( localRow, 0 ); - GEOS_ASSERT_GT( localMatrix.numRows(), localRow ); - - RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[localRow], localFlux[i] ); - localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( localRow, - dofColIndices.data(), - localFluxJacobian[i].dataIfContiguous(), - stencilSize ); - - } - } - } - } ); - -} - - -template< localIndex MAX_NUM_CONNECTIONS > -GEOS_HOST_DEVICE -void -FaceElementFluxKernel::compute( localIndex const numFluxElems, - arraySlice1d< localIndex const > const & seri, - arraySlice1d< localIndex const > const & sesri, - arraySlice1d< localIndex const > const & sei, - real64 const (&transmissibility)[MAX_NUM_CONNECTIONS][2], - real64 const (&dTrans_dPres)[MAX_NUM_CONNECTIONS][2], - real64 const (&dTrans_dDispJump)[MAX_NUM_CONNECTIONS][2][3], - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const > > const & dens, - ElementViewConst< arrayView2d< real64 const > > const & dDens_dPres, - ElementViewConst< arrayView1d< real64 const > > const & mob, - ElementViewConst< arrayView1d< real64 const > > const & dMob_dPres, - real64 const dt, - arraySlice1d< real64 > const & flux, - arraySlice2d< real64 > const & fluxJacobian, - arraySlice2d< real64 > const & dFlux_dAperture ) -{ - - localIndex k[2]; - localIndex connectionIndex = 0; - for( k[0]=0; k[0] - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - - /** - * @brief launches the kernel to assemble the flux contributions to the linear system. - * @tparam SurfaceElementStencilWrapper The type of the stencil that is being used. - * @param[in] stencil The stencil object. - * @param[in] dt The timestep for the integration step. - * @param[in] dofNumber The dofNumbers for each element - * @param[in] pres The pressures in each element - * @param[in] gravCoef The factor for gravity calculations (g*H) - * @param[in] dens The material density in each element - * @param[in] dDens_dPres The change in material density for each element - * @param[in] mob The fluid mobility in each element - * @param[in] dMob_dPres The derivative of mobility wrt pressure in each element - * @param[in] permeability - * @param[in] dPerm_dPres The derivative of permeability wrt pressure in each element - * @param[in] permeabilityMultiplier - * @param[in] gravityVector - * @param[out] localMatrix The linear system matrix - * @param[out] localRhs The linear system residual - */ - static void - launch( SurfaceElementStencilWrapper const & stencilWrapper, - real64 const dt, - globalIndex const rankOffset, - ElementViewConst< arrayView1d< globalIndex const > > const & pressureDofNumber, - ElementViewConst< arrayView1d< integer const > > const & ghostRank, - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const > > const & dens, - ElementViewConst< arrayView2d< real64 const > > const & dDens_dPres, - ElementViewConst< arrayView1d< real64 const > > const & mob, - ElementViewConst< arrayView1d< real64 const > > const & dMob_dPres, - ElementViewConst< arrayView3d< real64 const > > const & permeability, - ElementViewConst< arrayView3d< real64 const > > const & dPerm_dPres, - ElementViewConst< arrayView4d< real64 const > > const & dPerm_dDispJump, - ElementViewConst< arrayView3d< real64 const > > const & permeabilityMultiplier, - R1Tensor const & gravityVector, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ); - - - /** - * @brief Compute flux and its derivatives for a given tpfa connector. - * - * - */ - template< localIndex MAX_NUM_CONNECTIONS > - GEOS_HOST_DEVICE - static void - compute( localIndex const numFluxElems, - arraySlice1d< localIndex const > const & seri, - arraySlice1d< localIndex const > const & sesri, - arraySlice1d< localIndex const > const & sei, - real64 const (&transmissibility)[MAX_NUM_CONNECTIONS][2], - real64 const (&dTrans_dPres)[MAX_NUM_CONNECTIONS][2], - real64 const (&dTrans_dDispJump)[MAX_NUM_CONNECTIONS][2][3], - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const > > const & dens, - ElementViewConst< arrayView2d< real64 const > > const & dDens_dPres, - ElementViewConst< arrayView1d< real64 const > > const & mob, - ElementViewConst< arrayView1d< real64 const > > const & dMob_dPres, - real64 const dt, - arraySlice1d< real64 > const & flux, - arraySlice2d< real64 > const & fluxJacobian, - arraySlice2d< real64 > const & dFlux_dAperture ); -}; - - -} // namespace singlePhaseProppantFluxKernels - -} // namespace geos - -#endif //GEOSX_PHYSICSSOLVERS_MULTIPHYSICS_SINGLEPHASEPROPPANTFLUXKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseStatistics.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseStatistics.cpp index c74a9e906b1..26ed404707d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseStatistics.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseStatistics.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,12 +19,14 @@ #include "SinglePhaseStatistics.hpp" +#include "mesh/DomainPartition.hpp" #include "mainInterface/ProblemManager.hpp" #include "physicsSolvers/PhysicsSolverManager.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseBaseKernels.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/StatisticsKernel.hpp" +#include "physicsSolvers/fluidFlow/LogLevelsInfo.hpp" namespace geos { @@ -34,7 +37,9 @@ using namespace dataRepository; SinglePhaseStatistics::SinglePhaseStatistics( const string & name, Group * const parent ): Base( name, parent ) -{} +{ + addLogLevel< logInfo::Statistics >(); +} void SinglePhaseStatistics::registerDataOnMesh( Group & meshBodies ) { @@ -175,7 +180,7 @@ void SinglePhaseStatistics::computeRegionStatistics( real64 const time, subRegionTotalPoreVol, subRegionTotalMass ); - ElementRegionBase & region = elemManager.getRegion( subRegion.getParent().getParent().getName() ); + ElementRegionBase & region = elemManager.getRegion( ElementRegionBase::getParentRegion( subRegion ).getName() ); RegionStatistics & regionStatistics = region.getReference< RegionStatistics >( viewKeyStruct::regionStatisticsString() ); regionStatistics.averagePressure += subRegionAvgPresNumerator; @@ -246,16 +251,23 @@ void SinglePhaseStatistics::computeRegionStatistics( real64 const time, GEOS_WARNING( GEOS_FMT( "{}, {}: Cannot compute average pressure & temperature because region pore volume is zero.", getName(), regionNames[i] ) ); } - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Pressure (min, average, max): {}, {}, {} Pa", - getName(), regionNames[i], time, regionStatistics.minPressure, regionStatistics.averagePressure, regionStatistics.maxPressure ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Delta pressure (min, max): {}, {} Pa", - getName(), regionNames[i], time, regionStatistics.minDeltaPressure, regionStatistics.maxDeltaPressure ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Temperature (min, average, max): {}, {}, {} K", - getName(), regionNames[i], time, regionStatistics.minTemperature, regionStatistics.averageTemperature, regionStatistics.maxTemperature ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Total dynamic pore volume: {} rm^3", - getName(), regionNames[i], time, regionStatistics.totalPoreVolume ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}, {} (time {} s): Total fluid mass: {} kg", - getName(), regionNames[i], time, regionStatistics.totalMass ) ); + string statPrefix = GEOS_FMT( "{}, {} (time {} s):", getName(), regionNames[i], time ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Pressure (min, average, max): {}, {}, {} Pa", + statPrefix, regionStatistics.minPressure, regionStatistics.averagePressure, regionStatistics.maxPressure ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Delta pressure (min, max): {}, {} Pa", + statPrefix, regionStatistics.minDeltaPressure, regionStatistics.maxDeltaPressure ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Temperature (min, average, max): {}, {}, {} K", + statPrefix, regionStatistics.minTemperature, regionStatistics.averageTemperature, + regionStatistics.maxTemperature ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Total dynamic pore volume: {} rm^3", + statPrefix, regionStatistics.totalPoreVolume ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, + GEOS_FMT( "{} Total fluid mass: {} kg", + statPrefix, regionStatistics.totalMass ) ); if( m_writeCSV > 0 && MpiWrapper::commRank() == 0 ) { diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseStatistics.hpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseStatistics.hpp index bfd1360fd92..b7f279c239c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseStatistics.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseStatistics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -62,9 +63,6 @@ class SinglePhaseStatistics : public FieldStatisticsBase< SinglePhaseBase > /**@}*/ -private: - - using Base = FieldStatisticsBase< SinglePhaseBase >; /** * @struct viewKeyStruct holds char strings and viewKeys for fast lookup @@ -105,6 +103,10 @@ class SinglePhaseStatistics : public FieldStatisticsBase< SinglePhaseBase > real64 totalUncompactedPoreVolume; }; +private: + + using Base = FieldStatisticsBase< SinglePhaseBase >; + /** * @brief Compute some statistics on the reservoir (average field pressure, etc) * @param[in] mesh the mesh level object diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SourceFluxStatistics.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SourceFluxStatistics.cpp new file mode 100644 index 00000000000..6c8a1e36cb3 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/SourceFluxStatistics.cpp @@ -0,0 +1,363 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SourceFluxStatistics.cpp + */ + +#include "SourceFluxStatistics.hpp" + +#include "fieldSpecification/SourceFluxBoundaryCondition.hpp" +#include "fieldSpecification/FieldSpecificationManager.hpp" +#include "LvArray/src/tensorOps.hpp" + +namespace geos +{ +using namespace dataRepository; + +SourceFluxStatsAggregator::SourceFluxStatsAggregator( const string & name, + Group * const parent ): + Base( name, parent ) +{ + getWrapperBase( Group::viewKeyStruct::logLevelString() ). + appendDescription( GEOS_FMT( "\n- Log Level 1 outputs the sum of all {0}(s) produced rate & mass,\n" + "- Log Level 2 details values for each {0},\n" + "- Log Level 3 details values for each region.", + SourceFluxBoundaryCondition::catalogName() ) ); + + registerWrapper( viewKeyStruct::fluxNamesString().data(), &m_fluxNames ). + setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ). + setInputFlag( InputFlags::OPTIONAL ). + setSizedFromParent( 0 ). + setDefaultValue( "*" ). + setDescription( GEOS_FMT( "Name(s) array of the {0}(s) for which we want the statistics. " + "Use \"*\" to target all {0}.", + SourceFluxBoundaryCondition::catalogName() ) ); +} + +void SourceFluxStatsAggregator::postInputInitialization() +{ + Base::postInputInitialization(); + + FieldSpecificationManager & fsManager = FieldSpecificationManager::getInstance(); + if( m_fluxNames.size() == 1 && m_fluxNames[0] == "*" ) + { + m_fluxNames.clear(); + fsManager.forSubGroups< SourceFluxBoundaryCondition >( [&]( SourceFluxBoundaryCondition & sourceFlux ) + { + m_fluxNames.emplace_back( string( sourceFlux.getName() ) ); + } ); + GEOS_WARNING_IF( m_fluxNames.empty(), + GEOS_FMT( "{}: No {} was found in {}.", + getDataContext(), SourceFluxBoundaryCondition::catalogName(), + fsManager.getDataContext() ) ); + } + else + { + for( string const & fluxName : m_fluxNames ) + { + GEOS_ERROR_IF( !fsManager.hasGroup< SourceFluxBoundaryCondition >( fluxName ), + GEOS_FMT( "{}: No {} named {} was found in {}.", + getDataContext(), SourceFluxBoundaryCondition::catalogName(), + fluxName, fsManager.getDataContext() ) ); + } + } +} + +Wrapper< SourceFluxStatsAggregator::WrappedStats > & +SourceFluxStatsAggregator::registerWrappedStats( Group & group, + string_view fluxName, + string_view elementSetName ) +{ + string const wrapperName = getStatWrapperName( fluxName ); + Wrapper< WrappedStats > & statsWrapper = group.registerWrapper< WrappedStats >( wrapperName ); + statsWrapper.setRestartFlags( RestartFlags::NO_WRITE ); + statsWrapper.reference().setTarget( getName(), fluxName ); + + writeStatsToCSV( elementSetName, statsWrapper.reference(), true ); + + return statsWrapper; +} +void SourceFluxStatsAggregator::registerDataOnMesh( Group & meshBodies ) +{ + if( m_solver == nullptr ) + { + return; + } + + m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + { + registerWrappedStats( mesh, viewKeyStruct::fluxSetWrapperString(), viewKeyStruct::allRegionWrapperString() ); + + for( string const & fluxName : m_fluxNames ) + { + registerWrappedStats( mesh, fluxName, viewKeyStruct::allRegionWrapperString() ); + + mesh.getElemManager().forElementRegions( [&]( ElementRegionBase & region ) + { + Wrapper< WrappedStats > & regionStatsWrapper = + registerWrappedStats( region, fluxName, region.getName() ); + region.excludeWrappersFromPacking( { regionStatsWrapper.getName() } ); + + region.forElementSubRegions( [&]( ElementSubRegionBase & subRegion ) + { + Wrapper< WrappedStats > & subRegionStatsWrapper = + registerWrappedStats( subRegion, fluxName, subRegion.getName() ); + subRegion.excludeWrappersFromPacking( { subRegionStatsWrapper.getName() } ); + } ); + } ); + } + } ); +} + +void SourceFluxStatsAggregator::writeStatsToLog( integer minLogLevel, + string_view elementSetName, + WrappedStats const & wrappedStats ) +{ + if( getLogLevel() >= minLogLevel && logger::internal::rank == 0 ) + { + GEOS_LOG_RANK( GEOS_FMT( "{} {} (of {}, in {}): Producing on {} elements", + catalogName(), getName(), wrappedStats.getFluxName(), elementSetName, + wrappedStats.stats().m_elementCount ) ); + + // we want to format differently if we have got multiple phases or not + string_view massUnit = units::getSymbol( m_solver->getMassUnit() ); + if( wrappedStats.stats().m_producedMass.size() == 1 ) + { + GEOS_LOG_RANK( GEOS_FMT( "{} {} (of {}, in {}): Produced mass = {} {}", + catalogName(), getName(), wrappedStats.getFluxName(), elementSetName, + wrappedStats.stats().m_producedMass[0], massUnit ) ); + GEOS_LOG_RANK( GEOS_FMT( "{} {} (of {}, in {}): Production rate = {} {}/s", + catalogName(), getName(), wrappedStats.getFluxName(), elementSetName, + wrappedStats.stats().m_productionRate[0], massUnit ) ); + } + else + { + GEOS_LOG_RANK( GEOS_FMT( "{} {} (of {}, in {}): Produced mass = {} {}", + catalogName(), getName(), wrappedStats.getFluxName(), elementSetName, + wrappedStats.stats().m_producedMass, massUnit ) ); + GEOS_LOG_RANK( GEOS_FMT( "{} {} (of {}, in {}): Production rate = {} {}/s", + catalogName(), getName(), wrappedStats.getFluxName(), elementSetName, + wrappedStats.stats().m_productionRate, massUnit ) ); + } + } +} + +void SourceFluxStatsAggregator::writeStatsToCSV( string_view elementSetName, WrappedStats const & stats, + bool writeHeader ) +{ + if( m_writeCSV > 0 && MpiWrapper::commRank() == 0 ) + { + string const fileName = GEOS_FMT( "{}/{}_{}_{}.csv", + m_outputDir, + stats.getAggregatorName(), stats.getFluxName(), elementSetName ); + std::ofstream outputFile( fileName, + writeHeader ? std::ios_base::out : std::ios_base::app ); + if( writeHeader ) + { + outputFile << GEOS_FMT( "Time [s],Element Count,Producted Mass [{0}],Production Rate [{0}/s]", + units::getSymbol( m_solver->getMassUnit() ) ) << std::endl; + } + else + { + outputFile << GEOS_FMT( "{},{},{},{}", + stats.getStatsPeriodStart(), stats.stats().m_elementCount, + stats.stats().m_producedMass, stats.stats().m_productionRate ) << std::endl; + } + outputFile.close(); + } +} + +bool SourceFluxStatsAggregator::execute( real64 const GEOS_UNUSED_PARAM( time_n ), + real64 const GEOS_UNUSED_PARAM( dt ), + integer const GEOS_UNUSED_PARAM( cycleNumber ), + integer const GEOS_UNUSED_PARAM( eventCounter ), + real64 const GEOS_UNUSED_PARAM( eventProgress ), + DomainPartition & domain ) +{ + forMeshLevelStatsWrapper( domain, + [&] ( MeshLevel & meshLevel, WrappedStats & meshLevelStats ) + { + meshLevelStats.stats() = StatData(); + + forAllFluxStatsWrappers( meshLevel, + [&] ( MeshLevel &, WrappedStats & fluxStats ) + { + fluxStats.stats() = StatData(); + + forAllRegionStatsWrappers( meshLevel, fluxStats.getFluxName(), + [&] ( ElementRegionBase & region, WrappedStats & regionStats ) + { + regionStats.stats() = StatData(); + + forAllSubRegionStatsWrappers( region, regionStats.getFluxName(), + [&] ( ElementSubRegionBase &, WrappedStats & subRegionStats ) + { + subRegionStats.finalizePeriod(); + regionStats.stats().combine( subRegionStats.stats() ); + } ); + + fluxStats.stats().combine( regionStats.stats() ); + writeStatsToLog( 3, region.getName(), regionStats ); + writeStatsToCSV( region.getName(), regionStats, false ); + } ); + + meshLevelStats.stats().combine( fluxStats.stats() ); + writeStatsToLog( 2, viewKeyStruct::allRegionWrapperString(), fluxStats ); + writeStatsToCSV( viewKeyStruct::allRegionWrapperString(), fluxStats, false ); + } ); + + writeStatsToLog( 1, viewKeyStruct::allRegionWrapperString(), meshLevelStats ); + writeStatsToCSV( viewKeyStruct::allRegionWrapperString(), meshLevelStats, false ); + } ); + + return false; +} + + + +void SourceFluxStatsAggregator::StatData::allocate( integer phaseCount ) +{ + if( m_producedMass.size() != phaseCount ) + { + m_producedMass.resize( phaseCount ); + m_productionRate.resize( phaseCount ); + } +} +void SourceFluxStatsAggregator::StatData::reset() +{ + for( int ip = 0; ip < getPhaseCount(); ++ip ) + { + m_producedMass[ip] = 0.0; + m_productionRate[ip] = 0.0; + } + m_elementCount = 0; +} +void SourceFluxStatsAggregator::StatData::combine( StatData const & other ) +{ + allocate( other.getPhaseCount() ); + + for( int ip = 0; ip < other.getPhaseCount(); ++ip ) + { + m_producedMass[ip] += other.m_producedMass[ip]; + m_productionRate[ip] += other.m_productionRate[ip]; + } + m_elementCount += other.m_elementCount; +} +void SourceFluxStatsAggregator::StatData::mpiReduce() +{ + for( int ip = 0; ip < getPhaseCount(); ++ip ) + { + m_producedMass[ip] = MpiWrapper::sum( m_producedMass[ip] ); + m_productionRate[ip] = MpiWrapper::sum( m_productionRate[ip] ); + } + m_elementCount = MpiWrapper::sum( m_elementCount ); +} + +void SourceFluxStatsAggregator::WrappedStats::setTarget( string_view aggregatorName, + string_view fluxName ) +{ + m_aggregatorName = aggregatorName; + m_fluxName = fluxName; +} +void SourceFluxStatsAggregator::WrappedStats::gatherTimeStepStats( real64 const currentTime, real64 const dt, + arrayView1d< real64 const > const & producedMass, + integer const elementCount ) +{ + m_periodStats.allocate( producedMass.size() ); + + if( !m_periodStats.m_isGathering ) + { + // if beginning a new period, we must initialize constant values over the period + m_periodStats.m_periodStart = currentTime; + m_periodStats.m_elementCount = elementCount; + m_periodStats.m_isGathering = true; + } + else + { + GEOS_WARNING_IF( currentTime< m_periodStats.m_timeStepStart, GEOS_FMT( "{}: Time seems to have rollback, stats will be wrong.", m_aggregatorName ) ); + if( currentTime > m_periodStats.m_timeStepStart ) + { + // if beginning a new timestep, we must accumulate the stats from previous timesteps (mass & dt) before collecting the new ones + for( int ip = 0; ip < m_periodStats.getPhaseCount(); ++ip ) + { + m_periodStats.m_periodPendingMass[ip] += m_periodStats.m_timeStepMass[ip]; + } + m_periodStats.m_periodPendingDeltaTime += m_periodStats.m_timeStepDeltaTime; + } + } + // current timestep stats to take into account (overriding if not begining a new timestep) + m_periodStats.m_timeStepStart = currentTime; + m_periodStats.m_timeStepDeltaTime = dt; + for( int ip = 0; ip < m_periodStats.getPhaseCount(); ++ip ) + { + m_periodStats.m_timeStepMass = producedMass; + } +} +void SourceFluxStatsAggregator::WrappedStats::finalizePeriod() +{ + // init phase data memory allocation if needed + m_stats.allocate( m_periodStats.getPhaseCount() ); + + // produce the period stats of this rank + m_stats.m_elementCount = m_periodStats.m_elementCount; + m_statsPeriodStart = m_periodStats.m_periodStart; + m_statsPeriodDT = m_periodStats.m_timeStepDeltaTime + m_periodStats.m_periodPendingDeltaTime; + + real64 const timeDivisor = m_statsPeriodDT > 0.0 ? 1.0 / m_statsPeriodDT : 0.0; + for( int ip = 0; ip < m_periodStats.getPhaseCount(); ++ip ) + { + real64 periodMass = m_periodStats.m_timeStepMass[ip] + m_periodStats.m_periodPendingMass[ip]; + m_stats.m_producedMass[ip] = periodMass; + m_stats.m_productionRate[ip] = periodMass * timeDivisor; + } + + // combine period results from all MPI ranks + m_stats.mpiReduce(); + + // start a new timestep + m_periodStats.reset(); +} +void SourceFluxStatsAggregator::WrappedStats::PeriodStats::allocate( integer phaseCount ) +{ + if( m_timeStepMass.size() != phaseCount ) + { + m_timeStepMass.resize( phaseCount ); + m_periodPendingMass.resize( phaseCount ); + } +} +void SourceFluxStatsAggregator::WrappedStats::PeriodStats::reset() +{ + for( int ip = 0; ip < getPhaseCount(); ++ip ) + { + m_timeStepMass[ip] = 0.0; + m_periodPendingMass[ip] = 0.0; + } + m_periodPendingDeltaTime = 0.0; + m_elementCount = 0; + m_timeStepStart = 0.0; + m_timeStepDeltaTime = 0.0; + m_isGathering = false; +} + + +REGISTER_CATALOG_ENTRY( TaskBase, + SourceFluxStatsAggregator, + string const &, + dataRepository::Group * const ) + +} /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SourceFluxStatistics.hpp b/src/coreComponents/physicsSolvers/fluidFlow/SourceFluxStatistics.hpp new file mode 100644 index 00000000000..43dad5d1c3a --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/SourceFluxStatistics.hpp @@ -0,0 +1,421 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SourceFluxStatistics.hpp + */ + +#ifndef SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_SOURCEFLUXSTATISTICS_HPP_ +#define SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_SOURCEFLUXSTATISTICS_HPP_ + +#include "../FieldStatisticsBase.hpp" +#include "FlowSolverBase.hpp" +#include "mesh/DomainPartition.hpp" + + +namespace geos +{ + +/** + * @class SourceFluxStatsAggregator + * + * Task class allowing for the computation of aggregate statistics of SourceFluxBoundaryCondition + */ +class SourceFluxStatsAggregator final : public FieldStatisticsBase< FlowSolverBase > +{ +public: + + /** + * @brief Aggregated flux statistics data. + */ + struct StatData + { + /// Amount of fluid produced by the flux(es). Negative if injecting. One value for each fluid phase. + /// In kg by default, or in mol if useMass = 0 on the solver. + array1d< real64 > m_producedMass; + /// Flux(es) production rate. Negative if injecting. One value for each fluid phase. + /// In kg/s by default, or in mol/s if useMass = 0 on the solver. + array1d< real64 > m_productionRate; + /// Number of elements in which we are producing / injecting + integer m_elementCount = 0; + + /** + * @brief resize the phase data arrays if needed + * @param phaseCount the count of phases + */ + void allocate( integer phaseCount ); + /** + * @brief reset the stats to 0.0 + */ + void reset(); + /** + * @return the phase count for phasic stats + */ + integer getPhaseCount() const + { return m_producedMass.size(); } + /** + * @brief Aggregate the statistics of the instance with those of another one. + * @param other the other stats structure. + */ + void combine( StatData const & other ); + /** + * @brief Aggregate the statistics of the instance with those from all instances from other MPI ranks. + * Must be called only once per timestep. + */ + void mpiReduce(); + }; + /** + * @brief Class that aggregate statistics of a flux over multiple time-steps for a given + * SourceFluxStatsAggregator and a for a given mesh part (i.e. a subregion, a region...). + */ + class WrappedStats + { +public: + /** + * @brief Set the subjects targeted by the stats. + * @param aggregatorName the name of the targeted SourceFluxStatsAggregator + * @param fluxName the name of the targeted SourceFluxBoundaryCondition + */ + void setTarget( string_view aggregatorName, string_view fluxName ); + + /** + * @brief Set the current time step stats. Accumulate the statistics only if the time is strictly + * after the previous time + dt (override the statistics if the current timestep is cut). + * @param currentTime time of the timestep start since simulation starting + * @param dt time delta of the current timestep + * @param producedMass Amount of produced fluid (see StatData::m_producedMass). + * @param elementCount number of cell elements concerned by this instance + */ + void gatherTimeStepStats( real64 currentTime, real64 dt, + arrayView1d< real64 const > const & producedMass, + integer elementCount ); + + /** + * @brief Finalize the period statistics of each timestep gathering and render data over all mpi ranks. + * The result can be read by the data() assessor. + * @note This method must be synchronously called by all MPI ranks. + */ + void finalizePeriod(); + + /** + * @return the reference to the wrapped stats data collected over the last period (one timestep or more), computed by finalizePeriod() + */ + StatData & stats() + { return m_stats; } + + /** + * @return the reference to the wrapped stats data collected over the last period (one timestep or more), computed by finalizePeriod() + */ + StatData const & stats() const + { return m_stats; } + + /** + * @return the start time of the wrapped stats period (in s) + */ + real64 getStatsPeriodStart() const + { return m_statsPeriodStart; } + + /** + * @return the duration of the wrapped stats period (in s) + */ + real64 getStatsPeriodDuration() const + { return m_statsPeriodDT; } + + /** + * @return the name of the SourceFluxStatsAggregator that want to collect data on this instance. + */ + string_view getAggregatorName() const + { return m_aggregatorName; } + + /** + * @return the name of the SourceFluxBoundaryCondition from which we are collecting data on this instance. + */ + string_view getFluxName() const + { return m_fluxName; } +private: + /// stats data collected over the last period (one timestep or more), computed by finalizePeriod() + StatData m_stats; + /// the start time of the wrapped stats period (in s) + real64 m_statsPeriodStart; + /// the duration of the wrapped stats period (in s) + real64 m_statsPeriodDT; + + /** + * @brief This struct is used to accumulate statistics along one or more timesteps. + */ + struct PeriodStats + { + /// Fluid production during current time-step. Same unit as StatData::productedMass. + array1d< real64 > m_timeStepMass; + /// Fluid production during all previous time-step of the current period. Same unit as StatData::productedMass. + array1d< real64 > m_periodPendingMass; + /// time of when the timestep starts (since the simulation start). + real64 m_timeStepStart = 0.0; + /// time that the current timestep is simulating. + real64 m_timeStepDeltaTime = 0.0; + /// start time of the current period. + real64 m_periodStart = 0.0; + /// delta time from all previous time-step of the current period. + real64 m_periodPendingDeltaTime = 0.0; + /// number of cell elements targeted by this instance + integer m_elementCount = 0; + /// Did the period statistics gathering started ? + bool m_isGathering = false; + + /** + * @brief resize the phase data arrays if needed + * @param phaseCount the count of phases + */ + void allocate( integer phaseCount ); + /** + * @brief reset the stats to 0.0 + */ + void reset(); + /** + * @return the phase count for phasic stats + */ + integer getPhaseCount() const + { return m_timeStepMass.size(); } + } m_periodStats; + + /// Name of the SourceFluxStatsAggregator that want to collect data on this instance. + string m_aggregatorName; + /// Name of the SourceFluxBoundaryCondition from which we are collecting data on this instance. + string m_fluxName; + }; + + + /** + * @brief Constructor for the statistics class + * @param[in] name the name of the task coming from the xml + * @param[in] parent the parent group of the task + */ + SourceFluxStatsAggregator( const string & name, + Group * const parent ); + + /** + * @return The catalog name + */ + static string catalogName() { return "SourceFluxStatistics"; } + + /** + * @copydoc ExecutableGroup::execute() + */ + virtual bool execute( real64 const time_n, + real64 const dt, + integer const cycleNumber, + integer const eventCounter, + real64 const eventProgress, + DomainPartition & domain ) override; + + /** + * @brief Apply a functor to WrappedStats that combines all stats for each target solver + * discretization mesh levels. + * @param domain the domain for which we want the statistics + * @param lambda the functor that will be called for each WrappedStats. Takes in parameter the MeshLevel + * reference and the reference to the WrappedStats that combines all stats for the instance. + * @tparam LAMBDA the type of lambda function to call in the function + * @note To be retrieved, the WrappedStats structs must be registered on the container during the + * registerDataOnMesh() call. + */ + template< typename LAMBDA > + void forMeshLevelStatsWrapper( DomainPartition & domain, LAMBDA && lambda ); + /** + * @brief Apply a functor to each WrappedStats that combines the stats over all region for a flux. + * @param meshLevel the mesh level for which we want the statistics. + * @param lambda the functor that will be called for each WrappedStats. Takes in parameter the MeshLevel + * reference and the reference to one of the flux WrappedStats. + * @tparam LAMBDA the type of lambda function to call in the function + * @note To be retrieved, the WrappedStats structs must be registered on the container during the + * registerDataOnMesh() call. + */ + template< typename LAMBDA > + void forAllFluxStatsWrappers( MeshLevel & meshLevel, LAMBDA && lambda ); + /** + * @brief Apply a functor to all simulated region WrappedStats (of the given MeshLevel) that target a + * given flux. + * @param meshLevel the mesh level we want to loop over all its regions. + * @param fluxName the name of the flux from which we want the statistics. + * @param lambda the functor that will be called for each WrappedStats. Takes in parameter the + * ElementRegionBase reference and the reference of its WrappedStats. + * @tparam LAMBDA the type of lambda function to call in the function + * @note To be retrieved, the WrappedStats structs must be registered on the container during the + * registerDataOnMesh() call. + */ + template< typename LAMBDA > + void forAllRegionStatsWrappers( MeshLevel & meshLevel, string_view fluxName, LAMBDA && lambda ); + /** + * @brief Apply a functor to all subregion WrappedStats (of the given region) that target a given flux. + * @param region the region from which we want to execute the lambda for each of its sub-region. + * @param fluxName the name of the flux from which we want the statistics. + * @param lambda the functor that will be called for each WrappedStats. Takes in parameter the + * ElementSubRegionBase reference and the reference of its WrappedStats. + * @tparam LAMBDA the type of lambda function to call in the function + * @note To be retrieved, the WrappedStats structs must be registered on the container during the + * registerDataOnMesh() call. + */ + template< typename LAMBDA > + void forAllSubRegionStatsWrappers( ElementRegionBase & region, string_view fluxName, LAMBDA && lambda ); + + /** + * @brief Apply a functor to all WrappedStats of the given group that target a given flux (and + * potentially multiple SourceFluxStatsAggregator). + * The functor takes in parameter the reference to the currently processed WrappedStats. + * @note To be retrieved, the WrappedStats structs must be registered on the container during the + * registerDataOnMesh() call. + * @tparam LAMBDA the type of lambda function to call in the function + * @param container the container from which we want the statistics. + * @param fluxName the name of the flux from which we want the statistics. + * @param lambda the functor that will be called for each WrappedStats. Takes in parameter the + * reference to the currently processed WrappedStats. + */ + template< typename LAMBDA > + static void forAllFluxStatWrappers( Group & container, string_view fluxName, LAMBDA && lambda ); + + /** + * @return a string used to name the wrapper that is added to each region that is simulated by the solver. + * The string is unique within the region for the SourceFluxBoundaryCondition and the SourceFluxStatsAggregator. + * @param fluxName The name of the flux. For the mesh-level global stats, fluxSetWrapperString() can be used. + */ + inline string getStatWrapperName( string_view fluxName ) const; + + + /** + * @brief View keys + */ + struct viewKeyStruct + { + /// @return The key for setName + constexpr inline static string_view fluxNamesString() { return "fluxNames"; } + /// @return The key for statistics wrapper name that targets all region + constexpr inline static string_view allRegionWrapperString() { return "all_regions"; } + /// @return The key for statistics wrapper name that targets all fluxes of the set + constexpr inline static string_view fluxSetWrapperString() { return "flux_set"; } + }; + + +private: + using Base = FieldStatisticsBase< FlowSolverBase >; + + /// the names of the SourceFlux(s) for which we want the statistics + string_array m_fluxNames; + + /** + * @copydoc Group::registerDataOnMesh(Group &) + */ + void registerDataOnMesh( Group & meshBodies ) override; + + /** + * @copydoc Group::postInputInitialization() + */ + void postInputInitialization() override; + + dataRepository::Wrapper< WrappedStats > & registerWrappedStats( Group & group, + string_view fluxName, + string_view elementSetName ); + + /** + * @brief If requested, output in the log and CSV the given statistics. + * @param minLogLevel the min log level to output any line. + * @param elementSetName the region / sub-subregion name concerned by the statistics. + * @param stats the statistics that must be output in the log. + */ + void writeStatsToLog( integer minLogLevel, string_view elementSetName, WrappedStats const & stats ); + /** + * @brief If CSV is enabled, create or append a new CSV file. + * @param elementSetName the region / sub-subregion name concerned by the statistics. + * @param stats the statistics that must be output in the log. + * @param writeHeader If true, create the CSV with the header. If false, append it with the statistics. + */ + void writeStatsToCSV( string_view elementSetName, WrappedStats const & stats, bool writeHeader ); + +}; + + +template< typename LAMBDA > +void SourceFluxStatsAggregator::forAllFluxStatWrappers( Group & container, + string_view fluxName, + LAMBDA && lambda ) +{ + container.forWrappers< WrappedStats >( [&]( dataRepository::Wrapper< WrappedStats > & statsWrapper ) + { + if( statsWrapper.referenceAsView().getFluxName() == fluxName ) + { + lambda( statsWrapper.reference() ); + } + } ); +} + +template< typename LAMBDA > +void SourceFluxStatsAggregator::forMeshLevelStatsWrapper( DomainPartition & domain, + LAMBDA && lambda ) +{ + m_solver->forDiscretizationOnMeshTargets( domain.getMeshBodies(), + [&] ( string const &, + MeshLevel & meshLevel, + arrayView1d< string const > const & ) + { + string const wrapperName = getStatWrapperName( viewKeyStruct::fluxSetWrapperString() ); + WrappedStats & stats = meshLevel.getWrapper< WrappedStats >( wrapperName ).reference(); + + lambda( meshLevel, stats ); + } ); +} +template< typename LAMBDA > +void SourceFluxStatsAggregator::forAllFluxStatsWrappers( MeshLevel & meshLevel, + LAMBDA && lambda ) +{ + for( string const & fluxName : m_fluxNames ) + { + string const wrapperName = getStatWrapperName( fluxName ); + WrappedStats & stats = meshLevel.getWrapper< WrappedStats >( wrapperName ).reference(); + + lambda( meshLevel, stats ); + } +} +template< typename LAMBDA > +void SourceFluxStatsAggregator::forAllRegionStatsWrappers( MeshLevel & meshLevel, + string_view fluxName, + LAMBDA && lambda ) +{ + string const wrapperName = getStatWrapperName( fluxName ); + meshLevel.getElemManager().forElementRegions( [&]( ElementRegionBase & region ) + { + WrappedStats & stats = region.getWrapper< WrappedStats >( wrapperName ).reference(); + + lambda( region, stats ); + } ); +} +template< typename LAMBDA > +void SourceFluxStatsAggregator::forAllSubRegionStatsWrappers( ElementRegionBase & region, + string_view fluxName, + LAMBDA && lambda ) +{ + string const wrapperName = getStatWrapperName( fluxName ); + region.forElementSubRegions( [&]( ElementSubRegionBase & subRegion ) + { + WrappedStats & stats = subRegion.getWrapper< WrappedStats >( wrapperName ).reference(); + + lambda( subRegion, stats ); + } ); +} + +inline string SourceFluxStatsAggregator::getStatWrapperName( string_view fluxName ) const +{ return GEOS_FMT( "{}_region_stats_for_{}", fluxName, getName() ); } + + +} /* namespace geos */ + +#endif /* SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_SOURCEFLUXSTATISTICS_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/StabilizedCompositionalMultiphaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/StabilizedCompositionalMultiphaseFVMKernels.hpp deleted file mode 100644 index b0d6328732f..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/StabilizedCompositionalMultiphaseFVMKernels.hpp +++ /dev/null @@ -1,377 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file StabilizedCompositionalMultiphaseFVMKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_STABILIZEDCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_STABILIZEDCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP - -#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseFVMKernels.hpp" - -namespace geos -{ - -namespace stabilizedCompositionalMultiphaseFVMKernels -{ - -using namespace constitutive; - - -/******************************** FaceBasedAssemblyKernel ********************************/ - -/** - * @class FaceBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @brief Define the interface for the assembly kernel in charge of flux terms - */ -template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > -class FaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > -{ -public: - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelBase; - using DofNumberAccessor = AbstractBase::DofNumberAccessor; - using CompFlowAccessors = AbstractBase::CompFlowAccessors; - using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; - using CapPressureAccessors = AbstractBase::CapPressureAccessors; - using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; - - using StabCompFlowAccessors = - StencilAccessors< fields::flow::macroElementIndex, - fields::flow::elementStabConstant, - fields::flow::pressure_n >; - - using StabMultiFluidAccessors = - StencilMaterialAccessors< MultiFluidBase, - fields::multifluid::phaseDensity_n, - fields::multifluid::phaseCompFraction_n >; - - using RelPermAccessors = - StencilMaterialAccessors< RelativePermeabilityBase, fields::relperm::phaseRelPerm_n >; - - using AbstractBase::m_dt; - using AbstractBase::m_numPhases; - using AbstractBase::m_kernelFlags; - using AbstractBase::m_rankOffset; - using AbstractBase::m_ghostRank; - using AbstractBase::m_dofNumber; - using AbstractBase::m_gravCoef; - using AbstractBase::m_phaseCompFrac; - using AbstractBase::m_dCompFrac_dCompDens; - using AbstractBase::m_pres; - - using Base = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - using Base::numComp; - using Base::numDof; - using Base::numEqn; - using Base::numFluxSupportPoints; - using Base::maxNumElems; - using Base::maxNumConns; - using Base::maxStencilSize; - using Base::m_phaseMob; - using Base::m_dPhaseMassDens; - using Base::m_stencilWrapper; - using Base::m_seri; - using Base::m_sesri; - using Base::m_sei; - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dofNumberAccessor accessor for the dofs numbers - * @param[in] compFlowAccessor accessor for wrappers registered by the solver - * @param[in] stabCompFlowAccessor accessor for wrappers registered by the solver needed for stabilization - * @param[in] multiFluidAccessor accessor for wrappers registered by the multifluid model - * @param[in] stabMultiFluidAccessor accessor for wrappers registered by the multifluid model needed for stabilization - * @param[in] capPressureAccessors accessor for wrappers registered by the cap pressure model - * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model - * @param[in] relPermAccessors accessor for wrappers registered by the relative permeability model needed for stabilization - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - * @param[in] kernelFlags flags packed together - */ - FaceBasedAssemblyKernel( integer const numPhases, - globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - StabCompFlowAccessors const & stabCompFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - StabMultiFluidAccessors const & stabMultiFluidAccessors, - CapPressureAccessors const & capPressureAccessors, - PermeabilityAccessors const & permeabilityAccessors, - RelPermAccessors const & relPermAccessors, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags ) - : Base( numPhases, - rankOffset, - stencilWrapper, - dofNumberAccessor, - compFlowAccessors, - multiFluidAccessors, - capPressureAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs, - kernelFlags ), - m_pres_n( stabCompFlowAccessors.get( fields::flow::pressure_n {} ) ), - m_phaseDens_n( stabMultiFluidAccessors.get( fields::multifluid::phaseDensity_n {} ) ), - m_phaseCompFrac_n( stabMultiFluidAccessors.get( fields::multifluid::phaseCompFraction_n {} ) ), - m_phaseRelPerm_n( relPermAccessors.get( fields::relperm::phaseRelPerm_n {} ) ), - m_macroElementIndex( stabCompFlowAccessors.get( fields::flow::macroElementIndex {} ) ), - m_elementStabConstant( stabCompFlowAccessors.get( fields::flow::elementStabConstant {} ) ) - {} - - struct StackVariables : public Base::StackVariables - { -public: - - GEOS_HOST_DEVICE - StackVariables( localIndex const size, localIndex numElems ) - : Base::StackVariables( size, numElems ) - {} - - using Base::StackVariables::stencilSize; - using Base::StackVariables::numConnectedElems; - using Base::StackVariables::transmissibility; - using Base::StackVariables::dTrans_dPres; - using Base::StackVariables::dofColIndices; - using Base::StackVariables::localFlux; - using Base::StackVariables::localFluxJacobian; - - /// Stabilization transmissibility - real64 stabTransmissibility[maxNumConns][numFluxSupportPoints]{}; - - }; - - /** - * @brief Compute the local flux contributions to the residual and Jacobian, including stabilization - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void computeFlux( localIndex const iconn, - StackVariables & stack ) const - { - - m_stencilWrapper.computeStabilizationWeights( iconn, - stack.stabTransmissibility ); - - // *********************************************** - // First, we call the base computeFlux to compute: - // 1) compFlux and its derivatives, - // - // We use the lambda below (called **inside** the phase loop of the base computeFlux) to compute stabilization terms - Base::computeFlux( iconn, stack, [&] ( integer const ip, - localIndex const (&k)[2], - localIndex const (&seri)[2], - localIndex const (&sesri)[2], - localIndex const (&sei)[2], - localIndex const connectionIndex, - localIndex const k_up, - localIndex const er_up, - localIndex const esr_up, - localIndex const ei_up, - real64 const potGrad, - real64 const phaseFlux, - real64 const (&dPhaseFlux_dP)[2], - real64 const (&dPhaseFlux_dC)[2][numComp] ) - { - GEOS_UNUSED_VAR( k_up, potGrad, phaseFlux, dPhaseFlux_dP, dPhaseFlux_dC, er_up, esr_up, ei_up ); - - /// stabilization flux and derivatives - real64 stabFlux[numComp]{}; - real64 dStabFlux_dP[numFluxSupportPoints][numComp]{}; - - real64 const stabTrans[numFluxSupportPoints] = { stack.stabTransmissibility[connectionIndex][0], - stack.stabTransmissibility[connectionIndex][1] }; - - // we are in the loop over phases, ip provides the current phase index. - - real64 dPresGradStab = 0.0; - integer stencilMacroElements[numFluxSupportPoints]{}; - - // Step 1: compute the pressure jump at the interface - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - localIndex const er = seri[ke]; - localIndex const esr = sesri[ke]; - localIndex const ei = sei[ke]; - - stencilMacroElements[ke] = m_macroElementIndex[er][esr][ei]; - - // use the jump in *delta* pressure in the stabilization term - dPresGradStab += - m_elementStabConstant[er][esr][ei] * stabTrans[ke] * (m_pres[er][esr][ei] - m_pres_n[er][esr][ei]); - } - - // Step 2: compute the stabilization flux - integer const k_up_stab = (dPresGradStab >= 0) ? 0 : 1; - - localIndex const er_up_stab = seri[k_up_stab]; - localIndex const esr_up_stab = sesri[k_up_stab]; - localIndex const ei_up_stab = sei[k_up_stab]; - - bool const areInSameMacroElement = stencilMacroElements[0] == stencilMacroElements[1]; - bool const isStabilizationActive = stencilMacroElements[0] >= 0 && stencilMacroElements[1] >= 0; - if( isStabilizationActive && areInSameMacroElement ) - { - - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 const laggedUpwindCoef = m_phaseDens_n[er_up_stab][esr_up_stab][ei_up_stab][0][ip] - * m_phaseCompFrac_n[er_up_stab][esr_up_stab][ei_up_stab][0][ip][ic] - * m_phaseRelPerm_n[er_up_stab][esr_up_stab][ei_up_stab][0][ip]; - stabFlux[ic] += dPresGradStab * laggedUpwindCoef; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - real64 const tauStab = m_elementStabConstant[seri[ke]][sesri[ke]][sei[ke]]; - dStabFlux_dP[ke][ic] += tauStab * stabTrans[ke] * laggedUpwindCoef; - } - } - } - - // Step 3: add the stabilization flux and its derivatives to the residual and Jacobian - for( integer ic = 0; ic < numComp; ++ic ) - { - integer const eqIndex0 = k[0] * numEqn + ic; - integer const eqIndex1 = k[1] * numEqn + ic; - - stack.localFlux[eqIndex0] += stabFlux[ic]; - stack.localFlux[eqIndex1] += -stabFlux[ic]; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - localIndex const localDofIndexPres = k[ke] * numDof; - stack.localFluxJacobian[eqIndex0][localDofIndexPres] += dStabFlux_dP[ke][ic]; - stack.localFluxJacobian[eqIndex1][localDofIndexPres] += -dStabFlux_dP[ke][ic]; - } - } - - } ); // end call to Base::computeFlux - - } - -protected: - - /// Views on flow properties at the previous converged time step - ElementViewConst< arrayView1d< real64 const > > const m_pres_n; - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_phaseDens_n; - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const m_phaseCompFrac_n; - ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const m_phaseRelPerm_n; - - /// Views on the macroelement indices and stab constant - ElementViewConst< arrayView1d< integer const > > const m_macroElementIndex; - ElementViewConst< arrayView1d< real64 const > > const m_elementStabConstant; - -}; - -/** - * @class FaceBasedAssemblyKernelFactory - */ -class FaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @param[in] numComps the number of fluid components - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey string to get the element degrees of freedom numbers - * @param[in] hasCapPressure flag specifying whether capillary pressure is used or not - * @param[in] solverName name of the solver (to name accessors) - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY, typename STENCILWRAPPER > - static void - createAndLaunch( integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - string const & dofKey, - integer const hasCapPressure, - integer const useTotalMassEquation, - string const & solverName, - ElementRegionManager const & elemManager, - STENCILWRAPPER const & stencilWrapper, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) - { - integer constexpr NUM_COMP = NC(); - integer constexpr NUM_DOF = NC() + 1; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags; - if( hasCapPressure ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::CapPressure ); - if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::TotalMassEquation ); - - using KERNEL_TYPE = FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - typename KERNEL_TYPE::CompFlowAccessors compFlowAccessors( elemManager, solverName ); - typename KERNEL_TYPE::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); - typename KERNEL_TYPE::StabCompFlowAccessors stabCompFlowAccessors( elemManager, solverName ); - typename KERNEL_TYPE::StabMultiFluidAccessors stabMultiFluidAccessors( elemManager, solverName ); - typename KERNEL_TYPE::CapPressureAccessors capPressureAccessors( elemManager, solverName ); - typename KERNEL_TYPE::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); - typename KERNEL_TYPE::RelPermAccessors relPermAccessors( elemManager, solverName ); - - KERNEL_TYPE kernel( numPhases, rankOffset, stencilWrapper, dofNumberAccessor, - compFlowAccessors, stabCompFlowAccessors, multiFluidAccessors, stabMultiFluidAccessors, - capPressureAccessors, permeabilityAccessors, relPermAccessors, - dt, localMatrix, localRhs, kernelFlags ); - KERNEL_TYPE::template launch< POLICY >( stencilWrapper.size(), kernel ); - } ); - } -}; - -} // namespace stabilizedCompositionalMultiphaseFVMKernels - -} // namespace geos - - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_STABILIZEDCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/StencilAccessors.hpp b/src/coreComponents/physicsSolvers/fluidFlow/StencilAccessors.hpp index 55821d790bc..7b27c5f1788 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/StencilAccessors.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/StencilAccessors.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/fluidFlow/StencilDataCollection.cpp b/src/coreComponents/physicsSolvers/fluidFlow/StencilDataCollection.cpp new file mode 100644 index 00000000000..4b0adc25b20 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/StencilDataCollection.cpp @@ -0,0 +1,297 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StencilDataCollection.cpp + */ + +#include "StencilDataCollection.hpp" + +#include "common/Units.hpp" +#include "finiteVolume/FluxApproximationBase.hpp" +#include "finiteVolume/TwoPointFluxApproximation.hpp" +#include "constitutive/permeability/PermeabilityBase.hpp" +#include "constitutive/permeability/PermeabilityFields.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" +#include "physicsSolvers/PhysicsSolverManager.hpp" +#include "common/format/table/TableFormatter.hpp" + +namespace geos +{ + +using namespace constitutive; +using namespace dataRepository; + + +StencilDataCollection::StencilDataCollection( const string & name, + Group * const parent ): + Base( name, parent ) +{ + enableLogLevelInput(); + getWrapperBase( Group::viewKeyStruct::logLevelString() ). + setDescription( "When higher than 1: Display store events details." ); + + registerWrapper( viewKeyStruct::solverNameString(), &m_solverName ). + setRTTypeName( rtTypes::CustomTypes::groupNameRef ). + setInputFlag( dataRepository::InputFlags::REQUIRED ). + setDescription( "Name of the flow solver, to get the permeabilities." ); + registerWrapper( viewKeyStruct::meshNameString(), &m_meshName ). + setRTTypeName( rtTypes::CustomTypes::groupNameRef ). + setInputFlag( dataRepository::InputFlags::REQUIRED ). + setDescription( "Name of the target " ); + + // registerWrapper( viewKeyStruct::connectionDataString(), &m_currentConnData ); + registerWrapper( viewKeyStruct::cellAGlobalIdString(), &m_cellAGlobalId ); + registerWrapper( viewKeyStruct::cellBGlobalIdString(), &m_cellBGlobalId ); + registerWrapper( viewKeyStruct::transmissibilityABString(), &m_transmissibilityAB ); + registerWrapper( viewKeyStruct::transmissibilityBAString(), &m_transmissibilityBA ); +} + +void StencilDataCollection::postInputInitialization() +{ + Group & problemManager = this->getGroupByPath( "/Problem" ); + + { // find targeted solver + Group & physicsSolverManager = problemManager.getGroup( "Solvers" ); + + m_solver = physicsSolverManager.getGroupPointer< FlowSolverBase >( m_solverName ); + GEOS_THROW_IF( m_solver == nullptr, + GEOS_FMT( "{}: Could not find flow solver named '{}'.", + getDataContext(), + m_solverName ), + InputError ); + } + + { // find mesh & discretization +// DomainPartition & domain = problemManager.getDomainPartition(); + DomainPartition & domain = problemManager.getGroup< DomainPartition >( "domain" ); + + MeshBody const & meshBody = domain.getMeshBody( m_meshName ); + m_meshLevel = &meshBody.getBaseDiscretization(); + + NumericalMethodsManager const & numericalMethodManager = domain.getNumericalMethodManager(); + FiniteVolumeManager const & fvManager = numericalMethodManager.getFiniteVolumeManager(); + try + { + string const discretizationName = m_solver->getDiscretizationName(); + m_discretization = &fvManager.getFluxApproximation( discretizationName ); + } catch( BadTypeError const & e ) + { + // only TPFA is supported for now + GEOS_ERROR( GEOS_FMT( "{}: target discretization is not supported by {} (for now, only '{}' is).", + getDataContext(), catalogName(), TwoPointFluxApproximation::catalogName() ) ); + } + } +} + +void StencilDataCollection::initializePostInitialConditionsPostSubGroups() +{ + // asserting that there is exactly one supported stencil + integer supportedStencilCount = 0; + m_discretization->forStencils< CellElementStencilTPFA >( *m_meshLevel, [&]( auto const & stencil ) + { + globalIndex connCount = stencil.size(); + m_cellAGlobalId.resize( connCount ); + m_cellBGlobalId.resize( connCount ); + m_transmissibilityAB.resize( connCount ); + m_transmissibilityBA.resize( connCount ); + GEOS_LOG_LEVEL_BY_RANK( 1, GEOS_FMT( "{}: initialized {} connection buffer for '{}'.", + getName(), connCount, m_discretization->getName() ) ); + ++supportedStencilCount; + } ); + GEOS_ERROR_IF( supportedStencilCount == 0, GEOS_FMT( "{}: No compatible discretization was found.", getDataContext() ) ); + GEOS_ERROR_IF( supportedStencilCount > 1, GEOS_FMT( "{}: Multiple discretization was found.", getDataContext() ) ); +} + + +bool StencilDataCollection::execute( real64 const GEOS_UNUSED_PARAM( time_n ), + real64 const GEOS_UNUSED_PARAM( dt ), + integer const GEOS_UNUSED_PARAM( cycleNumber ), + integer const GEOS_UNUSED_PARAM( eventCounter ), + real64 const GEOS_UNUSED_PARAM( eventProgress ), + DomainPartition & GEOS_UNUSED_PARAM( domain ) ) +{ + m_discretization->forStencils< CellElementStencilTPFA >( *m_meshLevel, [&]( auto const & stencil ) + { + // gather + auto const stencilWrapper = stencil.createKernelWrapper(); + array1d< KernelConnectionData > const kernelData = gatherConnectionData( stencilWrapper ); + // output + storeConnectionData( m_discretization->getName(), kernelData.toView() ); + } ); + + return false; +} + + +string showKernelDataExtract( arrayView1d< StencilDataCollection::KernelConnectionData > const & kernelData, + globalIndex maxLines = std::numeric_limits< globalIndex >::max() ); + +class StencilDataCollection::Kernel +{ +public: + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using PermeabilityAccessors = StencilMaterialAccessors< PermeabilityBase, + fields::permeability::permeability >; + + + /** + * @brief launch a kernel to compute the element-element connection data using a given StencilWrapper. + * @tparam POLICY the Raja host / device launching policy + * @tparam STENCILWRAPPER_T + * @param connData The buffer where the connection data will be written + * @param stencilWrapper the StencilWrapper to use to compute the element-element connection data + * @param permeability the permeability data that will be used to compute the transmissibility + */ + template< typename POLICY, typename STENCILWRAPPER_T > + static void launch( arrayView1d< StencilDataCollection::KernelConnectionData > const & connData, + STENCILWRAPPER_T const & stencilWrapper, + ElementViewConst< arrayView3d< real64 const > > const & permeability ) + { + using IndexContainerType = typename STENCILWRAPPER_T::IndexContainerViewConstType; + IndexContainerType const & elemRegionIndices = stencilWrapper.getElementRegionIndices(); + IndexContainerType const & elemSubRegionIndices = stencilWrapper.getElementSubRegionIndices(); + IndexContainerType const & elementIndices = stencilWrapper.getElementIndices(); + + forAll< POLICY >( stencilWrapper.size(), [=] GEOS_HOST_DEVICE ( localIndex const iConn ) + { + real64 transmissibility[1][2]; + real64 dummy[1][2]; + + stencilWrapper.computeWeights( iConn, + permeability, + permeability, // we don't need derivatives + transmissibility, + dummy ); // we don't need derivatives + + for( localIndex i = 0; i < 2; ++i ) + { + connData[iConn].m_transmissibility[i] = transmissibility[0][i]; + connData[iConn].m_regionId[i] = elemRegionIndices( iConn, i ); + connData[iConn].m_subRegionId[i] = elemSubRegionIndices( iConn, i ); + connData[iConn].m_elementId[i] = elementIndices( iConn, i ); + } + } ); + connData.move( LvArray::MemorySpace::host ); + } + +private: + Kernel() = delete; +}; + +template< typename STENCILWRAPPER_T > +array1d< StencilDataCollection::KernelConnectionData > +StencilDataCollection::gatherConnectionData( STENCILWRAPPER_T const & stencilWrapper ) const +{ + ElementRegionManager const & elemManager = m_meshLevel->getElemManager(); + + // allocate a large enough buffer to store all connection data + array1d< KernelConnectionData > kernelData{ stencilWrapper.size() }; + typename Kernel::PermeabilityAccessors accessor( elemManager, m_solver->getName() ); + + Kernel::launch< parallelDevicePolicy<> >( kernelData.toView(), stencilWrapper, + accessor.get< fields::permeability::permeability >() ); + + return kernelData; +} + + +StencilDataCollection::ConnectionData +StencilDataCollection::ConnectionData::fromKernel( KernelConnectionData const & kernelData, + LocalToGlobalMap const & localToGlobalMap ) +{ + ConnectionData conn; + for( localIndex i = 0; i < 2; ++i ) + { + conn.m_transmissibility[i] = kernelData.m_transmissibility[i]; + conn.m_globalId[i] = localToGlobalMap[kernelData.m_regionId[i]][kernelData.m_subRegionId[i]][kernelData.m_elementId[i]]; + } + return conn; +} + + +string formatKernelDataExtract( arrayView1d< StencilDataCollection::KernelConnectionData > const & kernelData, + globalIndex maxLines ) +{ + TableData tableData; + auto kernelIterator = kernelData.begin(); + for( int iConn=0; iConn < maxLines && kernelIterator != kernelData.end(); ++iConn, ++kernelIterator ) + { + tableData.addRow( GEOS_FMT( "{} / {}", kernelIterator->m_regionId[0], kernelIterator->m_regionId[1] ), + GEOS_FMT( "{} / {}", kernelIterator->m_subRegionId[0], kernelIterator->m_subRegionId[1] ), + GEOS_FMT( "{} / {}", kernelIterator->m_elementId[0], kernelIterator->m_elementId[1] ), + kernelIterator->m_transmissibility[0], + kernelIterator->m_transmissibility[1] ); + } + TableLayout const tableLayout{ + { "regionId A/B", "subRegionId A/B", "elementId A/B", "transmissibilityAB", "transmissibilityBA" }, + GEOS_FMT( "Kernel data (real row count = {})", kernelData.size() ) + }; + TableTextFormatter const tableFormatter{ tableLayout }; + return tableFormatter.toString( tableData ); +} + +void StencilDataCollection::storeConnectionData( string_view stencilName, + arrayView1d< KernelConnectionData > const & kernelData ) +{ + std::set< ConnectionData > sortedData; + + { // data extraction + ElementRegionManager const & elemManager = m_meshLevel->getElemManager(); + string const & mapVKStr = ObjectManagerBase::viewKeyStruct::localToGlobalMapString(); + LocalToGlobalMap localToGlobalMap = elemManager.constructArrayViewAccessor< globalIndex, 1 >( mapVKStr ); + + std::transform( kernelData.begin(), kernelData.end(), + std::inserter( sortedData, sortedData.end() ), + [&]( auto const & kernelConn ) + { + return ConnectionData::fromKernel( kernelConn, localToGlobalMap ); + } ); + } + + { // data storing + GEOS_ERROR_IF_NE_MSG( size_t( m_cellAGlobalId.size() ), size_t( sortedData.size() ), + GEOS_FMT( "{}: Unexpected stencil size!\n{}", + getDataContext(), formatKernelDataExtract( kernelData, 8 ) ) ); + globalIndex i = 0; + for( ConnectionData const & conn : sortedData ) + { + m_cellAGlobalId[i] = conn.m_globalId[0]; + m_cellBGlobalId[i] = conn.m_globalId[1]; + m_transmissibilityAB[i] = conn.m_transmissibility[0]; + m_transmissibilityBA[i] = conn.m_transmissibility[1]; + ++i; + } + } + + logStoredConnections( stencilName ); +} + +void StencilDataCollection::logStoredConnections( string_view stencilName ) +{ + integer const connCount = MpiWrapper::sum( m_cellAGlobalId.size() ); + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: {} connections stored for '{}'.", + getName(), connCount, stencilName ) ); +} + + +REGISTER_CATALOG_ENTRY( TaskBase, + StencilDataCollection, + string const &, dataRepository::Group * const ) + + +} /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/StencilDataCollection.hpp b/src/coreComponents/physicsSolvers/fluidFlow/StencilDataCollection.hpp new file mode 100644 index 00000000000..b1453803f05 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/StencilDataCollection.hpp @@ -0,0 +1,179 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StencilDataCollection.hpp + */ + +#ifndef SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_CELLTOCELLDATACOLLECTOR_HPP_ +#define SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_CELLTOCELLDATACOLLECTOR_HPP_ + +#include "events/tasks/TaskBase.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBase.hpp" + +namespace geos +{ + +/** + * @class StencilDataCollection + * Task class allowing the ouput of communicating elements data. + * Only current usage is to output the cell-cell transmissibility (= "CellToCellDataCollection"), but we could add more + * implementations to output the transmissibility of boundary or surface connections (or everything that is managed + * by the stencils). + */ +class StencilDataCollection : public TaskBase +{ +public: + + /** + * @brief Constructor for the statistics class + * @param[in] name the name of the task coming from the xml + * @param[in] parent the parent group of the task + */ + StencilDataCollection( const string & name, + dataRepository::Group * const parent ); + + /// Accessor for the catalog name + static string catalogName() { return "CellToCellDataCollection"; } + + /** + * @defgroup Tasks Interface Functions + * + * This function implements the interface defined by the abstract TaskBase class + */ + /**@{*/ + + virtual bool execute( real64 const time_n, + real64 const dt, + integer const cycleNumber, + integer const eventCounter, + real64 const eventProgress, + DomainPartition & domain ) override; + + /**@}*/ + + struct viewKeyStruct + { + static constexpr char const * solverNameString() { return "flowSolverName"; } + static constexpr char const * meshNameString() { return "meshBody"; } + static constexpr char const * cellAGlobalIdString() { return "cellAGlobalId"; } + static constexpr char const * cellBGlobalIdString() { return "cellBGlobalId"; } + static constexpr char const * transmissibilityABString() { return "transmissibilityAB"; } + static constexpr char const * transmissibilityBAString() { return "transmissibilityBA"; } + }; + + class Kernel; + + /** + * @brief Element-element connection data extracted from the kernel. + */ + struct KernelConnectionData + { + real64 m_transmissibility[2]; + localIndex m_regionId[2]; + localIndex m_subRegionId[2]; + localIndex m_elementId[2]; + }; + +private: + + using Base = TaskBase; + using LocalToGlobalMap = ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > >; + + /** + * @brief Element-element connection data to be output by the class. + */ + struct ConnectionData + { + real64 m_transmissibility[2]; + globalIndex m_globalId[2]; + + + /** + * @return Construct a ConnectionData from the given kernel data. + * @param kernelData the kernel extracted data to be converted. + * @param localToGlobalMap the local to global id map, useful to convert the kernel extracted ids of the elements. + */ + static ConnectionData fromKernel( KernelConnectionData const & kernelData, + LocalToGlobalMap const & localToGlobalMap ); + + /** + * @brief minus operator to be able to sort instances before outputing them. + * The sorting is done by the first global id, then by the second global id. + * @param other compared instance + * @return true if this instance is to sort before the other instance. + */ + bool operator<( ConnectionData const & other ) const + { + return m_globalId[0] != other.m_globalId[0] ? + m_globalId[0] < other.m_globalId[0] : + m_globalId[1] < other.m_globalId[1]; + } + }; + + array1d< globalIndex > m_cellAGlobalId; + array1d< globalIndex > m_cellBGlobalId; + array1d< real64 > m_transmissibilityAB; + array1d< real64 > m_transmissibilityBA; + + /// Name of the target mesh body + string m_meshName; + /// Name of the target discretization + string m_solverName; + + /// Pointer to the target flow solver + FlowSolverBase const * m_solver = nullptr; + /// Pointer to the target mesh body + MeshLevel const * m_meshLevel = nullptr; + /// Pointer to the target discretization + FluxApproximationBase const * m_discretization = nullptr; + + + + void postInputInitialization() override; + + /** + * @brief Initialization of the internal buffers, must happen: + * - after FluxApproximationBase::computeCellStencil() + * - before TimeHistoryOutput::initializePostInitialConditionsPostSubGroups() + */ + void initializePostInitialConditionsPostSubGroups() override; + + /** + * @brief gather the element-element connection data of the current timestep using a given StencilWrapper. + * @tparam STENCILWRAPPER_T the type of the StencilWrapper + * @param mesh the mesh for which we want the data + * @param stencilWrapper the StencilWrapper to use to compute the element-element connection data + * @return Return the gathered data in an LvArray + */ + template< typename STENCILWRAPPER_T > + array1d< KernelConnectionData > gatherConnectionData( STENCILWRAPPER_T const & stencilWrapper ) const; + + /** + * @brief Output the element-element connection data of the current timestep. + * @param mesh the specific mesh for which we output the data. We will also need it to convert the ids to global ids. + * @param stencil the specific mesh for which we output the data. + * @param kernelData the connection data, gathered by a kernel. + */ + void storeConnectionData( string_view stencilName, + arrayView1d< KernelConnectionData > const & kernelData ); + + void logStoredConnections( string_view stencilName ); +}; + + +} /* namespace geos */ + +#endif /* SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_CELLTOCELLDATACOLLECTOR_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp deleted file mode 100644 index 0fec20002a4..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp +++ /dev/null @@ -1,1049 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file ThermalCompositionalMultiphaseBaseKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALCOMPOSITIONALMULTIPHASEBASEKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALCOMPOSITIONALMULTIPHASEBASEKERNELS_HPP - -#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp" - -#include "common/Units.hpp" - -namespace geos -{ - -namespace thermalCompositionalMultiphaseBaseKernels -{ - -using namespace constitutive; - - -/******************************** PhaseVolumeFractionKernel ********************************/ - -/** - * @class PhaseVolumeFractionKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_PHASE number of fluid phases - * @brief Define the interface for the property kernel in charge of computing the phase volume fractions - */ -template< integer NUM_COMP, integer NUM_PHASE > -class PhaseVolumeFractionKernel : public isothermalCompositionalMultiphaseBaseKernels::PhaseVolumeFractionKernel< NUM_COMP, NUM_PHASE > -{ -public: - - using Base = isothermalCompositionalMultiphaseBaseKernels::PhaseVolumeFractionKernel< NUM_COMP, NUM_PHASE >; - using Base::m_dPhaseDens; - using Base::m_dPhaseFrac; - using Base::m_dPhaseVolFrac; - - /** - * @brief Constructor - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - */ - PhaseVolumeFractionKernel( ObjectManagerBase & subRegion, - MultiFluidBase const & fluid ) - : Base( subRegion, fluid ) - {} - - /** - * @brief Compute the phase volume fractions in an element - * @param[in] ei the element index - */ - GEOS_HOST_DEVICE - real64 compute( localIndex const ei ) const - { - using Deriv = multifluid::DerivativeOffset; - - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const dPhaseFrac = m_dPhaseFrac[ei][0]; - - arraySlice2d< real64, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; - - // Call the base compute the compute the phase volume fraction - return Base::compute( ei, [&] ( localIndex const ip, - real64 const & phaseVolFrac, - real64 const & phaseDensInv, - real64 const & totalDensity ) - { - // when this lambda is called, we are in the phase loop - // for each phase ip, compute the derivative of phase volume fraction wrt temperature - dPhaseVolFrac[ip][Deriv::dT] = (dPhaseFrac[ip][Deriv::dT] - phaseVolFrac * dPhaseDens[ip][Deriv::dT]) * phaseDensInv; - dPhaseVolFrac[ip][Deriv::dT] *= totalDensity; - } ); - } - -}; - -/** - * @class PhaseVolumeFractionKernelFactory - */ -class PhaseVolumeFractionKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] numComp the number of fluid components - * @param[in] numPhase the number of fluid phases - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - */ - template< typename POLICY > - static real64 - createAndLaunch( integer const numComp, - integer const numPhase, - ObjectManagerBase & subRegion, - MultiFluidBase const & fluid ) - { - real64 maxDeltaPhaseVolFrac = 0.0; - if( numPhase == 2 ) - { - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseVolumeFractionKernel< NUM_COMP, 2 > kernel( subRegion, fluid ); - maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - else if( numPhase == 3 ) - { - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseVolumeFractionKernel< NUM_COMP, 3 > kernel( subRegion, fluid ); - maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - return maxDeltaPhaseVolFrac; - } -}; - - -/******************************** ElementBasedAssemblyKernel ********************************/ - -/** - * @class ElementBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @brief Define the interface for the assembly kernel in charge of thermal accumulation and volume balance - */ -template< localIndex NUM_COMP, localIndex NUM_DOF > -class ElementBasedAssemblyKernel : public isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > -{ -public: - - using Base = isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF >; - using Base::numComp; - using Base::numDof; - using Base::numEqn; - using Base::m_numPhases; - using Base::m_rankOffset; - using Base::m_dofNumber; - using Base::m_elemGhostRank; - using Base::m_volume; - using Base::m_porosity_n; - using Base::m_porosity; - using Base::m_dPoro_dPres; - using Base::m_dCompFrac_dCompDens; - using Base::m_phaseVolFrac_n; - using Base::m_phaseVolFrac; - using Base::m_dPhaseVolFrac; - using Base::m_phaseDens_n; - using Base::m_phaseDens; - using Base::m_dPhaseDens; - using Base::m_phaseCompFrac_n; - using Base::m_phaseCompFrac; - using Base::m_dPhaseCompFrac; - using Base::m_localMatrix; - using Base::m_localRhs; - - /** - * @brief Constructor - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - ElementBasedAssemblyKernel( localIndex const numPhases, - globalIndex const rankOffset, - string const dofKey, - ElementSubRegionBase const & subRegion, - MultiFluidBase const & fluid, - CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > const kernelFlags ) - : Base( numPhases, rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs, kernelFlags ), - m_dPoro_dTemp( solid.getDporosity_dTemperature() ), - m_phaseInternalEnergy_n( fluid.phaseInternalEnergy_n() ), - m_phaseInternalEnergy( fluid.phaseInternalEnergy() ), - m_dPhaseInternalEnergy( fluid.dPhaseInternalEnergy() ), - m_rockInternalEnergy_n( solid.getInternalEnergy_n() ), - m_rockInternalEnergy( solid.getInternalEnergy() ), - m_dRockInternalEnergy_dTemp( solid.getDinternalEnergy_dTemperature() ) - {} - - struct StackVariables : public Base::StackVariables - { -public: - - GEOS_HOST_DEVICE - StackVariables() - : Base::StackVariables() - {} - - using Base::StackVariables::poreVolume; - using Base::StackVariables::poreVolume_n; - using Base::StackVariables::dPoreVolume_dPres; - using Base::StackVariables::localRow; - using Base::StackVariables::dofIndices; - using Base::StackVariables::localResidual; - using Base::StackVariables::localJacobian; - - // derivative of pore volume wrt temperature - real64 dPoreVolume_dTemp = 0.0; - - // Solid energy - - /// Solid energy at time n+1 - real64 solidEnergy = 0.0; - - /// Solid energy at the previous converged time step - real64 solidEnergy_n = 0.0; - - /// Derivative of solid internal energy with respect to pressure - real64 dSolidEnergy_dPres = 0.0; - - /// Derivative of solid internal energy with respect to temperature - real64 dSolidEnergy_dTemp = 0.0; - - }; - - /** - * @brief Performs the setup phase for the kernel. - * @param[in] ei the element index - * @param[in] stack the stack variables - */ - GEOS_HOST_DEVICE - void setup( localIndex const ei, - StackVariables & stack ) const - { - Base::setup( ei, stack ); - - // derivative of pore volume wrt temperature - stack.dPoreVolume_dTemp = m_volume[ei] * m_dPoro_dTemp[ei][0]; - - // initialize the solid volume - real64 const solidVolume = m_volume[ei] * ( 1.0 - m_porosity[ei][0] ); - real64 const solidVolume_n = m_volume[ei] * ( 1.0 - m_porosity_n[ei][0] ); - real64 const dSolidVolume_dPres = -m_volume[ei] * m_dPoro_dPres[ei][0]; - real64 const dSolidVolume_dTemp = -stack.dPoreVolume_dTemp; - - // initialize the solid internal energy - stack.solidEnergy = solidVolume * m_rockInternalEnergy[ei][0]; - stack.solidEnergy_n = solidVolume_n * m_rockInternalEnergy_n[ei][0]; - stack.dSolidEnergy_dPres = dSolidVolume_dPres * m_rockInternalEnergy[ei][0]; - stack.dSolidEnergy_dTemp = solidVolume * m_dRockInternalEnergy_dTemp[ei][0] - + dSolidVolume_dTemp * m_rockInternalEnergy[ei][0]; - } - - /** - * @brief Compute the local accumulation contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void computeAccumulation( localIndex const ei, - StackVariables & stack ) const - { - using Deriv = multifluid::DerivativeOffset; - - Base::computeAccumulation( ei, stack, [&] ( integer const ip, - real64 const & phaseAmount, - real64 const & phaseAmount_n, - real64 const & dPhaseAmount_dP, - real64 const (&dPhaseAmount_dC)[numComp] ) - { - // We are in the loop over phases, ip provides the current phase index. - // We have to do two things: - // 1- Assemble the derivatives of the component mass balance equations with respect to temperature - // 2- Assemble the phase-dependent part of the accumulation term of the energy equation - - real64 dPhaseInternalEnergy_dC[numComp]{}; - - // construct the slices - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseDens = m_phaseDens[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseDens = m_dPhaseDens[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > phaseCompFrac = m_phaseCompFrac[ei][0]; - arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac = m_dPhaseCompFrac[ei][0]; - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseInternalEnergy_n = m_phaseInternalEnergy_n[ei][0]; - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseInternalEnergy = m_phaseInternalEnergy[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseInternalEnergy = m_dPhaseInternalEnergy[ei][0]; - - // Step 1: assemble the derivatives of the component mass balance equations with respect to temperature - - real64 const dPhaseAmount_dT = stack.dPoreVolume_dTemp * phaseVolFrac[ip] * phaseDens[ip] - + stack.poreVolume * (dPhaseVolFrac[ip][Deriv::dT] * phaseDens[ip] + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dT] ); - for( integer ic = 0; ic < numComp; ++ic ) - { - stack.localJacobian[ic][numDof-1] += dPhaseAmount_dT * phaseCompFrac[ip][ic] - + phaseAmount * dPhaseCompFrac[ip][ic][Deriv::dT]; - } - - // Step 2: assemble the phase-dependent part of the accumulation term of the energy equation - - real64 const phaseEnergy = phaseAmount * phaseInternalEnergy[ip]; - real64 const phaseEnergy_n = phaseAmount_n * phaseInternalEnergy_n[ip]; - real64 const dPhaseEnergy_dP = dPhaseAmount_dP * phaseInternalEnergy[ip] - + phaseAmount * dPhaseInternalEnergy[ip][Deriv::dP]; - real64 const dPhaseEnergy_dT = dPhaseAmount_dT * phaseInternalEnergy[ip] - + phaseAmount * dPhaseInternalEnergy[ip][Deriv::dT]; - - // local accumulation - stack.localResidual[numEqn-1] += phaseEnergy - phaseEnergy_n; - - // derivatives w.r.t. pressure and temperature - stack.localJacobian[numEqn-1][0] += dPhaseEnergy_dP; - stack.localJacobian[numEqn-1][numDof-1] += dPhaseEnergy_dT; - - // derivatives w.r.t. component densities - applyChainRule( numComp, dCompFrac_dCompDens, dPhaseInternalEnergy[ip], dPhaseInternalEnergy_dC, Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - stack.localJacobian[numEqn-1][jc + 1] += phaseInternalEnergy[ip] * dPhaseAmount_dC[jc] - + dPhaseInternalEnergy_dC[jc] * phaseAmount; - } - } ); - - // Step 3: assemble the solid part of the accumulation term - - // local accumulation and derivatives w.r.t. pressure and temperature - stack.localResidual[numEqn-1] += stack.solidEnergy - stack.solidEnergy_n; - stack.localJacobian[numEqn-1][0] += stack.dSolidEnergy_dPres; - stack.localJacobian[numEqn-1][numDof-1] += stack.dSolidEnergy_dTemp; - - } - - /** - * @brief Compute the local volume balance contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void computeVolumeBalance( localIndex const ei, - StackVariables & stack ) const - { - using Deriv = multifluid::DerivativeOffset; - - Base::computeVolumeBalance( ei, stack, [&] ( real64 const & oneMinusPhaseVolFraction ) - { - GEOS_UNUSED_VAR( oneMinusPhaseVolFraction ); - - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; - - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - stack.localJacobian[numEqn-2][numDof-1] -= dPhaseVolFrac[ip][Deriv::dT]; - } - } ); - } - - GEOS_HOST_DEVICE - void complete( localIndex const ei, - StackVariables & stack ) const - { - // Step 1: assemble the component mass balance equations and volume balance equations - Base::complete( ei, stack ); - - // Step 2: assemble the energy equation - m_localRhs[stack.localRow + numEqn-1] += stack.localResidual[numEqn-1]; - m_localMatrix.template addToRow< serialAtomic >( stack.localRow + numEqn-1, - stack.dofIndices, - stack.localJacobian[numEqn-1], - numDof ); - } - -protected: - - /// View on derivative of porosity w.r.t temperature - arrayView2d< real64 const > const m_dPoro_dTemp; - - /// Views on phase internal energy - arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseInternalEnergy_n; - arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseInternalEnergy; - arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dPhaseInternalEnergy; - - /// Views on rock internal energy - arrayView2d< real64 const > m_rockInternalEnergy_n; - arrayView2d< real64 const > m_rockInternalEnergy; - arrayView2d< real64 const > m_dRockInternalEnergy_dTemp; - -}; - -/** - * @class ElementBasedAssemblyKernelFactory - */ -class ElementBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] numComps the number of fluid components - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY > - static void - createAndLaunch( localIndex const numComps, - localIndex const numPhases, - globalIndex const rankOffset, - integer const useTotalMassEquation, - string const dofKey, - ElementSubRegionBase const & subRegion, - MultiFluidBase const & fluid, - CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch( numComps, [&] ( auto NC ) - { - localIndex constexpr NUM_COMP = NC(); - localIndex constexpr NUM_DOF = NC()+2; - - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; - if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); - - ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > - kernel( numPhases, rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs, kernelFlags ); - ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF >::template - launch< POLICY, ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > >( subRegion.size(), kernel ); - } ); - } - -}; - -/******************************** FluidUpdateKernel ********************************/ - -struct FluidUpdateKernel -{ - template< typename POLICY, typename FLUID_WRAPPER > - static void - launch( localIndex const size, - FLUID_WRAPPER const & fluidWrapper, - arrayView1d< real64 const > const & pres, - arrayView1d< real64 const > const & temp, - arrayView2d< real64 const, compflow::USD_COMP > const & compFrac ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) - { - fluidWrapper.update( k, q, pres[k], temp[k], compFrac[k] ); - } - } ); - } - - template< typename POLICY, typename FLUID_WRAPPER > - static void - launch( SortedArrayView< localIndex const > const & targetSet, - FLUID_WRAPPER const & fluidWrapper, - arrayView1d< real64 const > const & pres, - arrayView1d< real64 const > const & temp, - arrayView2d< real64 const, compflow::USD_COMP > const & compFrac ) - { - forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - localIndex const k = targetSet[a]; - for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) - { - fluidWrapper.update( k, q, pres[k], temp[k], compFrac[k] ); - } - } ); - } -}; - -/******************************** SolidInternalEnergyUpdateKernel ********************************/ - -struct SolidInternalEnergyUpdateKernel -{ - - template< typename POLICY, typename SOLID_INTERNAL_ENERGY_WRAPPER > - static void - launch( localIndex const size, - SOLID_INTERNAL_ENERGY_WRAPPER const & solidInternalEnergyWrapper, - arrayView1d< real64 const > const & temp ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - solidInternalEnergyWrapper.update( k, temp[k] ); - } ); - } -}; - -/******************************** ScalingForSystemSolutionKernel ********************************/ - -/** - * @class ScalingForSystemSolutionKernel - * @brief Define the kernel for scaling the Newton update - */ -class ScalingForSystemSolutionKernel : public isothermalCompositionalMultiphaseBaseKernels::ScalingForSystemSolutionKernel -{ -public: - - using Base = isothermalCompositionalMultiphaseBaseKernels::ScalingForSystemSolutionKernel; - using Base::m_numComp; - using Base::m_localSolution; - - /** - * @brief Create a new kernel instance - * @param[in] maxRelativePresChange the max allowed relative pressure change - * @param[in] maxRelativeTempChange the max allowed relative temperature change - * @param[in] maxCompFracChange the max allowed comp fraction change - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - * @param[in] pressure the pressure vector - * @param[in] temperature the temperature vector - * @param[in] compDens the component density vector - * @param[in] pressureScalingFactor the pressure local scaling factor - * @param[in] compDensScalingFactor the component density local scaling factor - * @param[in] temperatureFactor the temperature local scaling factor - */ - ScalingForSystemSolutionKernel( real64 const maxRelativePresChange, - real64 const maxAbsolutePresChange, - real64 const maxRelativeTempChange, - real64 const maxCompFracChange, - globalIndex const rankOffset, - integer const numComp, - string const dofKey, - ElementSubRegionBase const & subRegion, - arrayView1d< real64 const > const localSolution, - arrayView1d< real64 const > const pressure, - arrayView1d< real64 const > const temperature, - arrayView2d< real64 const, compflow::USD_COMP > const compDens, - arrayView1d< real64 > pressureScalingFactor, - arrayView1d< real64 > compDensScalingFactor, - arrayView1d< real64 > temperatureScalingFactor ) - : Base( maxRelativePresChange, - maxAbsolutePresChange, - maxCompFracChange, - rankOffset, - numComp, - dofKey, - subRegion, - localSolution, - pressure, - compDens, - pressureScalingFactor, - compDensScalingFactor ), - m_maxRelativeTempChange( maxRelativeTempChange ), - m_temperature( temperature ), - m_temperatureScalingFactor( temperatureScalingFactor ) - {} - - /** - * @brief Compute the local value - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void compute( localIndex const ei, - StackVariables & stack ) const - { - computeScalingFactor( ei, stack ); - } - - /** - * @brief Compute the local value of the scaling factor - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void computeScalingFactor( localIndex const ei, - StackVariables & stack ) const - { - real64 constexpr eps = isothermalCompositionalMultiphaseBaseKernels::minDensForDivision; - Base::computeScalingFactor( ei, stack, [&] () - { - // compute the change in temperature - real64 const temp = m_temperature[ei]; - real64 const absTempChange = LvArray::math::abs( m_localSolution[stack.localRow + m_numComp + 1] ); - if( stack.localMaxDeltaTemp < absTempChange ) - { - stack.localMaxDeltaTemp = absTempChange; - } - - m_temperatureScalingFactor[ei] = 1.0; - - if( temp > eps ) - { - real64 const relativeTempChange = absTempChange / temp; - if( relativeTempChange > m_maxRelativeTempChange ) - { - real64 const tempScalingFactor = m_maxRelativeTempChange / relativeTempChange; - m_temperatureScalingFactor[ei] = tempScalingFactor; - if( stack.localMinVal > tempScalingFactor ) - { - stack.localMinVal = tempScalingFactor; - } - if( stack.localMinTempScalingFactor > tempScalingFactor ) - { - stack.localMinTempScalingFactor = tempScalingFactor; - } - } - } - } ); - } - -protected: - - /// Max allowed changes in primary variables - real64 const m_maxRelativeTempChange; - - /// View on the primary variables - arrayView1d< real64 const > const m_temperature; - - /// View on the scaling factor - arrayView1d< real64 > const m_temperatureScalingFactor; - -}; - -/** - * @class ScalingForSystemSolutionKernelFactory - */ -class ScalingForSystemSolutionKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] maxRelativePresChange the max allowed relative pressure change - * @param[in] maxRelativeTempChange the max allowed relative temperature change - * @param[in] maxCompFracChange the max allowed comp fraction change - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - */ - template< typename POLICY > - static ScalingForSystemSolutionKernel::StackVariables - createAndLaunch( real64 const maxRelativePresChange, - real64 const maxAbsolutePresChange, - real64 const maxRelativeTempChange, - real64 const maxCompFracChange, - globalIndex const rankOffset, - integer const numComp, - string const dofKey, - ElementSubRegionBase & subRegion, - arrayView1d< real64 const > const localSolution ) - { - arrayView1d< real64 const > const pressure = subRegion.getField< fields::flow::pressure >(); - arrayView1d< real64 const > const temperature = subRegion.getField< fields::flow::temperature >(); - arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::flow::globalCompDensity >(); - arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::flow::pressureScalingFactor >(); - arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::flow::temperatureScalingFactor >(); - arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); - ScalingForSystemSolutionKernel kernel( maxRelativePresChange, maxAbsolutePresChange, maxRelativeTempChange, maxCompFracChange, - rankOffset, numComp, dofKey, subRegion, localSolution, - pressure, temperature, compDens, pressureScalingFactor, - temperatureScalingFactor, compDensScalingFactor ); - return thermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernel::launch< POLICY >( subRegion.size(), kernel ); - } - -}; - -/******************************** SolutionCheckKernel ********************************/ - -/** - * @class SolutionCheckKernel - * @brief Define the kernel for checking the updated solution - */ -class SolutionCheckKernel : public isothermalCompositionalMultiphaseBaseKernels::SolutionCheckKernel -{ -public: - - using Base = isothermalCompositionalMultiphaseBaseKernels::SolutionCheckKernel; - using Base::m_numComp; - using Base::m_localSolution; - using Base::m_scalingFactor; - - static real64 constexpr minTemperature = constants::zeroDegreesCelsiusInKelvin; - - /** - * @brief Create a new kernel instance - * @param[in] allowCompDensChopping flag to allow the component density chopping - * @param[in] scalingFactor the scaling factor - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - * @param[in] pressure the pressure vector - * @param[in] temperature the temperature vector - * @param[in] compDens the component density vector - */ - SolutionCheckKernel( integer const allowCompDensChopping, - integer const allowNegativePressure, - CompositionalMultiphaseFVM::ScalingType const scalingType, - real64 const scalingFactor, - globalIndex const rankOffset, - integer const numComp, - string const dofKey, - ElementSubRegionBase const & subRegion, - arrayView1d< real64 const > const localSolution, - arrayView1d< real64 const > const pressure, - arrayView1d< real64 const > const temperature, - arrayView2d< real64 const, compflow::USD_COMP > const compDens, - arrayView1d< real64 > pressureScalingFactor, - arrayView1d< real64 > compDensScalingFactor, - arrayView1d< real64 > temperatureScalingFactor ) - : Base( allowCompDensChopping, - allowNegativePressure, - scalingType, - scalingFactor, - rankOffset, - numComp, - dofKey, - subRegion, - localSolution, - pressure, - compDens, - pressureScalingFactor, - compDensScalingFactor ), - m_temperature( temperature ), - m_temperatureScalingFactor( temperatureScalingFactor ) - {} - - /** - * @brief Compute the local value of the solution check - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void computeSolutionCheck( localIndex const ei, - StackVariables & stack ) const - { - Base::computeSolutionCheck( ei, stack, [&] () - { - bool const localScaling = m_scalingType == CompositionalMultiphaseFVM::ScalingType::Local; - // compute the change in temperature - real64 const newTemp = m_temperature[ei] + (localScaling ? m_temperatureScalingFactor[ei] : m_scalingFactor * m_localSolution[stack.localRow + m_numComp + 1]); - if( newTemp < minTemperature ) - { - stack.localMinVal = 0; - } - } ); - } - -protected: - - /// View on the primary variables - arrayView1d< real64 const > const m_temperature; - - /// View on the scaling factor - arrayView1d< real64 const > const m_temperatureScalingFactor; - -}; - -/** - * @class SolutionCheckKernelFactory - */ -class SolutionCheckKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] maxRelativePresChange the max allowed relative pressure change - * @param[in] maxRelativeTempChange the max allowed relative temperature change - * @param[in] maxCompFracChange the max allowed comp fraction change - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - */ - template< typename POLICY > - static SolutionCheckKernel::StackVariables - createAndLaunch( integer const allowCompDensChopping, - integer const allowNegativePressure, - CompositionalMultiphaseFVM::ScalingType const scalingType, - real64 const scalingFactor, - globalIndex const rankOffset, - integer const numComp, - string const dofKey, - ElementSubRegionBase & subRegion, - arrayView1d< real64 const > const localSolution ) - { - arrayView1d< real64 const > const pressure = - subRegion.getField< fields::flow::pressure >(); - arrayView1d< real64 const > const temperature = - subRegion.getField< fields::flow::temperature >(); - arrayView2d< real64 const, compflow::USD_COMP > const compDens = - subRegion.getField< fields::flow::globalCompDensity >(); - arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::flow::pressureScalingFactor >(); - arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::flow::temperatureScalingFactor >(); - arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); - SolutionCheckKernel kernel( allowCompDensChopping, allowNegativePressure, scalingType, scalingFactor, - rankOffset, numComp, dofKey, subRegion, localSolution, - pressure, temperature, compDens, pressureScalingFactor, temperatureScalingFactor, compDensScalingFactor ); - return SolutionCheckKernel::launch< POLICY >( subRegion.size(), kernel ); - } - -}; - - -/******************************** ResidualNormKernel ********************************/ - -/** - * @class ResidualNormKernel - */ -class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 2 > -{ -public: - - using Base = ResidualNormKernelBase< 2 >; - using Base::m_minNormalizer; - using Base::m_rankOffset; - using Base::m_localResidual; - using Base::m_dofNumber; - - ResidualNormKernel( globalIndex const rankOffset, - arrayView1d< real64 const > const & localResidual, - arrayView1d< globalIndex const > const & dofNumber, - arrayView1d< localIndex const > const & ghostRank, - integer const numComponents, - integer const numPhases, - ElementSubRegionBase const & subRegion, - MultiFluidBase const & fluid, - CoupledSolidBase const & solid, - SolidInternalEnergy const & solidInternalEnergy, - real64 const minNormalizer ) - : Base( rankOffset, - localResidual, - dofNumber, - ghostRank, - minNormalizer ), - m_numComponents( numComponents ), - m_numPhases( numPhases ), - m_volume( subRegion.getElementVolume() ), - m_porosity_n( solid.getPorosity_n() ), - m_phaseVolFrac_n( subRegion.getField< fields::flow::phaseVolumeFraction_n >() ), - m_totalDens_n( fluid.totalDensity_n() ), - m_phaseDens_n( fluid.phaseDensity_n() ), - m_phaseInternalEnergy_n( fluid.phaseInternalEnergy_n() ), - m_solidInternalEnergy_n( solidInternalEnergy.getInternalEnergy_n() ) - {} - - GEOS_HOST_DEVICE - void computeMassEnergyNormalizers( localIndex const ei, - real64 & massNormalizer, - real64 & energyNormalizer ) const - { - massNormalizer = LvArray::math::max( m_minNormalizer, m_totalDens_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); - real64 const poreVolume = m_porosity_n[ei][0] * m_volume[ei]; - energyNormalizer = m_solidInternalEnergy_n[ei][0] * ( 1.0 - m_porosity_n[ei][0] ) * m_volume[ei]; - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - energyNormalizer += m_phaseInternalEnergy_n[ei][0][ip] * m_phaseDens_n[ei][0][ip] * m_phaseVolFrac_n[ei][ip] * poreVolume; - } - // warning: internal energy can be negative - energyNormalizer = LvArray::math::max( m_minNormalizer, LvArray::math::abs( energyNormalizer ) ); - } - - GEOS_HOST_DEVICE - virtual void computeLinf( localIndex const ei, - LinfStackVariables & stack ) const override - { - real64 massNormalizer = 0.0, energyNormalizer = 0.0; - computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); - real64 const volumeNormalizer = LvArray::math::max( m_minNormalizer, m_porosity_n[ei][0] * m_volume[ei] ); - - // step 1: mass residual - - for( integer idof = 0; idof < m_numComponents; ++idof ) - { - real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / massNormalizer; - if( valMass > stack.localValue[0] ) - { - stack.localValue[0] = valMass; - } - } - - // step 2: volume residual - - real64 const valVol = LvArray::math::abs( m_localResidual[stack.localRow + m_numComponents] ) / volumeNormalizer; - if( valVol > stack.localValue[0] ) - { - stack.localValue[0] = valVol; - } - - // step 3: energy residual - - real64 const valEnergy = LvArray::math::abs( m_localResidual[stack.localRow + m_numComponents + 1] ) / energyNormalizer; - if( valEnergy > stack.localValue[1] ) - { - stack.localValue[1] = valEnergy; - } - } - - GEOS_HOST_DEVICE - virtual void computeL2( localIndex const ei, - L2StackVariables & stack ) const override - { - // note: for the L2 norm, we bundle the volume and mass residuals/normalizers - real64 massNormalizer = 0.0, energyNormalizer = 0.0; - computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); - - // step 1: mass residual - - for( integer idof = 0; idof < m_numComponents; ++idof ) - { - stack.localValue[0] += m_localResidual[stack.localRow + idof] * m_localResidual[stack.localRow + idof]; - stack.localNormalizer[0] += massNormalizer; - } - - // step 2: volume residual - - real64 const valVol = m_localResidual[stack.localRow + m_numComponents] * m_totalDens_n[ei][0]; // we need a mass here, hence the - // multiplication - stack.localValue[0] += valVol * valVol; - stack.localNormalizer[0] += massNormalizer; - - // step 3: energy residual - - stack.localValue[1] += m_localResidual[stack.localRow + m_numComponents + 1] * m_localResidual[stack.localRow + m_numComponents + 1]; - stack.localNormalizer[1] += energyNormalizer; - } - -protected: - - /// Number of fluid components - integer const m_numComponents; - - /// Number of fluid phases - integer const m_numPhases; - - /// View on the volume - arrayView1d< real64 const > const m_volume; - - /// View on porosity at the previous converged time step - arrayView2d< real64 const > const m_porosity_n; - - /// View on phase properties at the previous converged time step - arrayView2d< real64 const, compflow::USD_PHASE > const m_phaseVolFrac_n; - arrayView2d< real64 const, multifluid::USD_FLUID > const m_totalDens_n; - arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseDens_n; - arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseInternalEnergy_n; - - /// View on solid properties at the previous converged time step - arrayView2d< real64 const > const m_solidInternalEnergy_n; - -}; - -/** - * @class ResidualNormKernelFactory - */ -class ResidualNormKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] normType the type of norm used (Linf or L2) - * @param[in] numComps the number of fluid components - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] localResidual the residual vector on my MPI rank - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[in] solidInternalEnergy the solid internal energy model - * @param[out] residualNorm the residual norm on the subRegion - * @param[out] residualNormalizer the residual normalizer on the subRegion - */ - template< typename POLICY > - static void - createAndLaunch( solverBaseKernels::NormType const normType, - integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - string const & dofKey, - arrayView1d< real64 const > const & localResidual, - ElementSubRegionBase const & subRegion, - MultiFluidBase const & fluid, - CoupledSolidBase const & solid, - SolidInternalEnergy const & solidInternalEnergy, - real64 const minNormalizer, - real64 (& residualNorm)[2], - real64 (& residualNormalizer)[2] ) - { - arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); - arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); - - ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, - numComps, numPhases, subRegion, fluid, solid, solidInternalEnergy, minNormalizer ); - if( normType == solverBaseKernels::NormType::Linf ) - { - ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); - } - else // L2 norm - { - ResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); - } - - } -}; - - -} // namespace thermalCompositionalMultiphaseBaseKernels - -} // namespace geos - - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALCOMPOSITIONALMULTIPHASEBASEKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseFVMKernels.hpp deleted file mode 100644 index 28bd1d26eb6..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseFVMKernels.hpp +++ /dev/null @@ -1,1442 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file ThermalCompositionalMultiphaseFVMKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP - -#include "constitutive/thermalConductivity/MultiPhaseThermalConductivityBase.hpp" -#include "constitutive/thermalConductivity/ThermalConductivityFields.hpp" -#include "constitutive/thermalConductivity/MultiPhaseThermalConductivityFields.hpp" -#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseFVMKernels.hpp" - -namespace geos -{ - -namespace thermalCompositionalMultiphaseFVMKernels -{ - -using namespace constitutive; - -/******************************** PhaseMobilityKernel ********************************/ - -/** - * @class PhaseMobilityKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_PHASE number of fluid phases - * @brief Define the interface for the property kernel in charge of computing the phase mobilities - */ -template< integer NUM_COMP, integer NUM_PHASE > -class PhaseMobilityKernel : public isothermalCompositionalMultiphaseFVMKernels::PhaseMobilityKernel< NUM_COMP, NUM_PHASE > -{ -public: - - using Base = isothermalCompositionalMultiphaseFVMKernels::PhaseMobilityKernel< NUM_COMP, NUM_PHASE >; - using Base::numPhase; - using Base::m_dPhaseVolFrac; - using Base::m_dPhaseMob; - using Base::m_phaseDens; - using Base::m_dPhaseDens; - using Base::m_phaseVisc; - using Base::m_dPhaseVisc; - using Base::m_dPhaseRelPerm_dPhaseVolFrac; - - /** - * @brief Constructor - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] relperm the relperm model - */ - PhaseMobilityKernel( ObjectManagerBase & subRegion, - MultiFluidBase const & fluid, - RelativePermeabilityBase const & relperm ) - : Base( subRegion, fluid, relperm ) - {} - - /** - * @brief Compute the phase mobilities in an element - * @param[in] ei the element index - */ - GEOS_HOST_DEVICE - inline - void compute( localIndex const ei ) const - { - using Deriv = multifluid::DerivativeOffset; - - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const phaseDens = m_phaseDens[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const phaseVisc = m_phaseVisc[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const dPhaseVisc = m_dPhaseVisc[ei][0]; - arraySlice2d< real64 const, relperm::USD_RELPERM_DS - 2 > const dPhaseRelPerm_dPhaseVolFrac = m_dPhaseRelPerm_dPhaseVolFrac[ei][0]; - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; - - Base::compute( ei, [&] ( localIndex const ip, - real64 const & phaseMob, - arraySlice1d< real64, compflow::USD_PHASE_DC - 2 > const & dPhaseMob ) - { - // Step 1: compute the derivative of relPerm[ip] wrt temperature - real64 dRelPerm_dT = 0.0; - for( integer jp = 0; jp < numPhase; ++jp ) - { - dRelPerm_dT += dPhaseRelPerm_dPhaseVolFrac[ip][jp] * dPhaseVolFrac[jp][Deriv::dT]; - } - - // Step 2: compute the derivative of phaseMob[ip] wrt temperature - dPhaseMob[Deriv::dT] = dRelPerm_dT * phaseDens[ip] / phaseVisc[ip] - + phaseMob * (dPhaseDens[ip][Deriv::dT] / phaseDens[ip] - dPhaseVisc[ip][Deriv::dT] / phaseVisc[ip] ); - } ); - } - -}; - -/** - * @class PhaseMobilityKernelFactory - */ -class PhaseMobilityKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] numComp the number of fluid components - * @param[in] numPhase the number of fluid phases - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] relperm the relperm model - */ - template< typename POLICY > - static void - createAndLaunch( integer const numComp, - integer const numPhase, - ObjectManagerBase & subRegion, - MultiFluidBase const & fluid, - RelativePermeabilityBase const & relperm ) - { - if( numPhase == 2 ) - { - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseMobilityKernel< NUM_COMP, 2 > kernel( subRegion, fluid, relperm ); - PhaseMobilityKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - else if( numPhase == 3 ) - { - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseMobilityKernel< NUM_COMP, 3 > kernel( subRegion, fluid, relperm ); - PhaseMobilityKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - } -}; - - -/******************************** FaceBasedAssemblyKernel ********************************/ - -/** - * @class FaceBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @brief Define the interface for the assembly kernel in charge of flux terms - */ -template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > -class FaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > -{ -public: - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelBase; - using DofNumberAccessor = AbstractBase::DofNumberAccessor; - using CompFlowAccessors = AbstractBase::CompFlowAccessors; - using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; - using CapPressureAccessors = AbstractBase::CapPressureAccessors; - using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; - - using AbstractBase::m_dt; - using AbstractBase::m_numPhases; - using AbstractBase::m_rankOffset; - using AbstractBase::m_dofNumber; - using AbstractBase::m_gravCoef; - using AbstractBase::m_dPhaseVolFrac; - using AbstractBase::m_phaseCompFrac; - using AbstractBase::m_dPhaseCompFrac; - using AbstractBase::m_dCompFrac_dCompDens; - - using Base = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - using Base::numComp; - using Base::numDof; - using Base::numEqn; - using Base::maxNumElems; - using Base::maxNumConns; - using Base::maxStencilSize; - using Base::numFluxSupportPoints; - using Base::m_phaseMob; - using Base::m_dPhaseMob; - using Base::m_dPhaseMassDens; - using Base::m_dPhaseCapPressure_dPhaseVolFrac; - using Base::m_stencilWrapper; - using Base::m_seri; - using Base::m_sesri; - using Base::m_sei; - - using ThermalCompFlowAccessors = - StencilAccessors< fields::flow::temperature >; - - using ThermalMultiFluidAccessors = - StencilMaterialAccessors< MultiFluidBase, - fields::multifluid::phaseEnthalpy, - fields::multifluid::dPhaseEnthalpy >; - - using ThermalConductivityAccessors = - StencilMaterialAccessors< MultiPhaseThermalConductivityBase, - fields::thermalconductivity::effectiveConductivity >; - // for now, we treat thermal conductivity explicitly - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dofNumberAccessor accessor for the dofs numbers - * @param[in] compFlowAccessor accessor for wrappers registered by the solver - * @param[in] thermalCompFlowAccessors accessor for *thermal* wrappers registered by the solver - * @param[in] multiFluidAccessor accessor for wrappers registered by the multifluid model - * @param[in] thermalMultiFluidAccessors accessor for *thermal* wrappers registered by the multifluid model - * @param[in] capPressureAccessors accessor for wrappers registered by the cap pressure model - * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model - * @param[in] thermalConductivityAccessors accessor for wrappers registered by the thermal conductivity model - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - * @param[in] kernelFlags flags packed all together - */ - FaceBasedAssemblyKernel( integer const numPhases, - globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - ThermalCompFlowAccessors const & thermalCompFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - ThermalMultiFluidAccessors const & thermalMultiFluidAccessors, - CapPressureAccessors const & capPressureAccessors, - PermeabilityAccessors const & permeabilityAccessors, - ThermalConductivityAccessors const & thermalConductivityAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags ) - : Base( numPhases, - rankOffset, - stencilWrapper, - dofNumberAccessor, - compFlowAccessors, - multiFluidAccessors, - capPressureAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs, - kernelFlags ), - m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), - m_phaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), - m_dPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ), - m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ) - {} - - struct StackVariables : public Base::StackVariables - { -public: - - GEOS_HOST_DEVICE - StackVariables( localIndex const size, localIndex numElems ) - : Base::StackVariables( size, numElems ) - {} - - using Base::StackVariables::stencilSize; - using Base::StackVariables::numConnectedElems; - using Base::StackVariables::transmissibility; - using Base::StackVariables::dTrans_dPres; - using Base::StackVariables::dofColIndices; - using Base::StackVariables::localFlux; - using Base::StackVariables::localFluxJacobian; - - // Thermal transmissibility (for now, no derivatives) - - real64 thermalTransmissibility[maxNumConns][2]{}; - }; - - /** - * @brief Compute the local flux contributions to the residual and Jacobian - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - inline - void computeFlux( localIndex const iconn, - StackVariables & stack ) const - { - using Deriv = multifluid::DerivativeOffset; - - // *********************************************** - // First, we call the base computeFlux to compute: - // 1) compFlux and its derivatives (including derivatives wrt temperature), - // 2) enthalpy part of convectiveEnergyFlux and its derivatives (including derivatives wrt temperature) - // - // Computing dCompFlux_dT and the enthalpy flux requires quantities already computed in the base computeFlux, - // such as potGrad, phaseFlux, and the indices of the upwind cell - // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables - Base::computeFlux( iconn, stack, [&] ( integer const ip, - localIndex const (&k)[2], - localIndex const (&seri)[2], - localIndex const (&sesri)[2], - localIndex const (&sei)[2], - localIndex const connectionIndex, - localIndex const k_up, - localIndex const er_up, - localIndex const esr_up, - localIndex const ei_up, - real64 const potGrad, - real64 const phaseFlux, - real64 const (&dPhaseFlux_dP)[2], - real64 const (&dPhaseFlux_dC)[2][numComp] ) - { - // We are in the loop over phases, ip provides the current phase index. - - // Step 1: compute the derivatives of the mean density at the interface wrt temperature - - real64 dDensMean_dT[numFluxSupportPoints]{}; - - real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], - stack.transmissibility[connectionIndex][1] }; - - real64 convectiveEnergyFlux = 0.0; - real64 dConvectiveEnergyFlux_dP[numFluxSupportPoints]{}; - real64 dConvectiveEnergyFlux_dT[numFluxSupportPoints]{}; - real64 dConvectiveEnergyFlux_dC[numFluxSupportPoints][numComp]{}; - real64 dCompFlux_dT[numFluxSupportPoints][numComp]{}; - - for( integer i = 0; i < numFluxSupportPoints; ++i ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - real64 const dDens_dT = m_dPhaseMassDens[er][esr][ei][0][ip][Deriv::dT]; - dDensMean_dT[i] = 0.5 * dDens_dT; - } - - // Step 2: compute the derivatives of the phase potential difference wrt temperature - //***** calculation of flux ***** - - real64 dPresGrad_dT[numFluxSupportPoints]{}; - real64 dGravHead_dT[numFluxSupportPoints]{}; - - // compute potential difference MPFA-style - for( integer i = 0; i < numFluxSupportPoints; ++i ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - // Step 2.1: compute derivative of capillary pressure wrt temperature - real64 dCapPressure_dT = 0.0; - if( AbstractBase::m_kernelFlags.isSet( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::CapPressure ) ) - { - for( integer jp = 0; jp < m_numPhases; ++jp ) - { - real64 const dCapPressure_dS = m_dPhaseCapPressure_dPhaseVolFrac[er][esr][ei][0][ip][jp]; - dCapPressure_dT += dCapPressure_dS * m_dPhaseVolFrac[er][esr][ei][jp][Deriv::dT]; - } - } - - // Step 2.2: compute derivative of phase pressure difference wrt temperature - dPresGrad_dT[i] -= trans[i] * dCapPressure_dT; - real64 const gravD = trans[i] * m_gravCoef[er][esr][ei]; - - // Step 2.3: compute derivative of gravity potential difference wrt temperature - for( integer j = 0; j < numFluxSupportPoints; ++j ) - { - dGravHead_dT[j] += dDensMean_dT[j] * gravD; - } - } - - // Step 3: compute the derivatives of the (upwinded) compFlux wrt temperature - // *** upwinding *** - - // note: the upwinding is done in the base class, which is in charge of - // computing the following quantities: potGrad, phaseFlux, k_up, er_up, esr_up, ei_up - - real64 dPhaseFlux_dT[numFluxSupportPoints]{}; - - // Step 3.1: compute the derivative of phase flux wrt temperature - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dPhaseFlux_dT[ke] += dPresGrad_dT[ke]; - } - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dPhaseFlux_dT[ke] -= dGravHead_dT[ke]; - } - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dPhaseFlux_dT[ke] *= m_phaseMob[er_up][esr_up][ei_up][ip]; - } - dPhaseFlux_dT[k_up] += m_dPhaseMob[er_up][esr_up][ei_up][ip][Deriv::dT] * potGrad; - - // Step 3.2: compute the derivative of component flux wrt temperature - - // slice some constitutive arrays to avoid too much indexing in component loop - arraySlice1d< real64 const, multifluid::USD_PHASE_COMP - 3 > phaseCompFracSub = - m_phaseCompFrac[er_up][esr_up][ei_up][0][ip]; - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP_DC - 3 > dPhaseCompFracSub = - m_dPhaseCompFrac[er_up][esr_up][ei_up][0][ip]; - - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 const ycp = phaseCompFracSub[ic]; - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dCompFlux_dT[ke][ic] += dPhaseFlux_dT[ke] * ycp; - } - dCompFlux_dT[k_up][ic] += phaseFlux * dPhaseCompFracSub[ic][Deriv::dT]; - } - - // Step 4: add dCompFlux_dTemp to localFluxJacobian - for( integer ic = 0; ic < numComp; ++ic ) - { - integer const eqIndex0 = k[0]* numEqn + ic; - integer const eqIndex1 = k[1]* numEqn + ic; - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - integer const localDofIndexTemp = k[ke] * numDof + numDof - 1; - stack.localFluxJacobian[eqIndex0][localDofIndexTemp] += m_dt * dCompFlux_dT[ke][ic]; - stack.localFluxJacobian[eqIndex1][localDofIndexTemp] -= m_dt * dCompFlux_dT[ke][ic]; - } - } - - // Step 5: compute the enthalpy flux - real64 const enthalpy = m_phaseEnthalpy[er_up][esr_up][ei_up][0][ip]; - convectiveEnergyFlux += phaseFlux * enthalpy; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dConvectiveEnergyFlux_dP[ke] += dPhaseFlux_dP[ke] * enthalpy; - dConvectiveEnergyFlux_dT[ke] += dPhaseFlux_dT[ke] * enthalpy; - - for( integer jc = 0; jc < numComp; ++jc ) - { - dConvectiveEnergyFlux_dC[ke][jc] += dPhaseFlux_dC[ke][jc] * enthalpy; - } - } - - dConvectiveEnergyFlux_dP[k_up] += phaseFlux * m_dPhaseEnthalpy[er_up][esr_up][ei_up][0][ip][Deriv::dP]; - dConvectiveEnergyFlux_dT[k_up] += phaseFlux * m_dPhaseEnthalpy[er_up][esr_up][ei_up][0][ip][Deriv::dT]; - - real64 dProp_dC[numComp]{}; - applyChainRule( numComp, - m_dCompFrac_dCompDens[er_up][esr_up][ei_up], - m_dPhaseEnthalpy[er_up][esr_up][ei_up][0][ip], - dProp_dC, - Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - dConvectiveEnergyFlux_dC[k_up][jc] += phaseFlux * dProp_dC[jc]; - } - - // Step 6: add convectiveFlux and its derivatives to localFlux and localFluxJacobian - integer const localRowIndexEnergy0 = k[0] * numEqn + numEqn - 1; - integer const localRowIndexEnergy1 = k[1] * numEqn + numEqn - 1; - stack.localFlux[localRowIndexEnergy0] += m_dt * convectiveEnergyFlux; - stack.localFlux[localRowIndexEnergy1] -= m_dt * convectiveEnergyFlux; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - integer const localDofIndexPres = k[ke] * numDof; - stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexPres] += m_dt * dConvectiveEnergyFlux_dP[ke]; - stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexPres] -= m_dt * dConvectiveEnergyFlux_dP[ke]; - integer const localDofIndexTemp = localDofIndexPres + numDof - 1; - stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexTemp] += m_dt * dConvectiveEnergyFlux_dT[ke]; - stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexTemp] -= m_dt * dConvectiveEnergyFlux_dT[ke]; - - for( integer jc = 0; jc < numComp; ++jc ) - { - integer const localDofIndexComp = localDofIndexPres + jc + 1; - stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexComp] += m_dt * dConvectiveEnergyFlux_dC[ke][jc]; - stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexComp] -= m_dt * dConvectiveEnergyFlux_dC[ke][jc]; - } - } - } ); - - // ***************************************************** - // Computation of the conduction term in the energy flux - // Note that the phase enthalpy term in the energy was computed above - // Note that this term is computed using an explicit treatment of conductivity for now - - // Step 1: compute the thermal transmissibilities at this face - // Below, the thermal conductivity used to compute (explicitly) the thermal conducivity - // To avoid modifying the signature of the "computeWeights" function for now, we pass m_thermalConductivity twice - // TODO: modify computeWeights to accomodate explicit coefficients - m_stencilWrapper.computeWeights( iconn, - m_thermalConductivity, - m_thermalConductivity, // we have to pass something here, so we just use thermal conductivity - stack.thermalTransmissibility, - stack.dTrans_dPres ); // again, we have to pass something here, but this is unused for now - - - - localIndex k[2]{}; - localIndex connectionIndex = 0; - - for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) - { - for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) - { - real64 const thermalTrans[2] = { stack.thermalTransmissibility[connectionIndex][0], stack.thermalTransmissibility[connectionIndex][1] }; - localIndex const seri[2] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; - localIndex const sesri[2] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; - localIndex const sei[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; - - real64 conductiveEnergyFlux = 0.0; - real64 dConductiveEnergyFlux_dT[numFluxSupportPoints]{}; - - // Step 2: compute temperature difference at the interface - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - localIndex const er = seri[ke]; - localIndex const esr = sesri[ke]; - localIndex const ei = sei[ke]; - - conductiveEnergyFlux += thermalTrans[ke] * m_temp[er][esr][ei]; - dConductiveEnergyFlux_dT[ke] += thermalTrans[ke]; - } - - // Step 3: add conductiveFlux and its derivatives to localFlux and localFluxJacobian - integer const localRowIndexEnergy0 = k[0] * numEqn + numEqn - 1; - integer const localRowIndexEnergy1 = k[1] * numEqn + numEqn - 1; - stack.localFlux[localRowIndexEnergy0] += m_dt * conductiveEnergyFlux; - stack.localFlux[localRowIndexEnergy1] -= m_dt * conductiveEnergyFlux; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - integer const localDofIndexTemp = k[ke] * numDof + numDof - 1; - stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexTemp] += m_dt * dConductiveEnergyFlux_dT[ke]; - stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexTemp] -= m_dt * dConductiveEnergyFlux_dT[ke]; - } - } - } - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - inline - void complete( localIndex const iconn, - StackVariables & stack ) const - { - // Call Case::complete to assemble the component mass balance equations (i = 0 to i = numDof-2) - // In the lambda, add contribution to residual and jacobian into the energy balance equation - Base::complete( iconn, stack, [&] ( integer const i, - localIndex const localRow ) - { - // beware, there is volume balance eqn in m_localRhs and m_localMatrix! - RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn], stack.localFlux[i * numEqn + numEqn-1] ); - AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > - ( localRow + numEqn, - stack.dofColIndices.data(), - stack.localFluxJacobian[i * numEqn + numEqn-1].dataIfContiguous(), - stack.stencilSize * numDof ); - - } ); - } - -protected: - - /// Views on temperature - ElementViewConst< arrayView1d< real64 const > > const m_temp; - - /// Views on phase enthalpies - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_phaseEnthalpy; - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dPhaseEnthalpy; - - /// View on thermal conductivity - ElementViewConst< arrayView3d< real64 const > > const m_thermalConductivity; - // for now, we treat thermal conductivity explicitly - -}; - -/** - * @class FaceBasedAssemblyKernelFactory - */ -class FaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @param[in] numComps the number of fluid components - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey string to get the element degrees of freedom numbers - * @param[in] hasCapPressure flag specifying whether capillary pressure is used or not - * @param[in] solverName name of the solver (to name accessors) - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY, typename STENCILWRAPPER > - static void - createAndLaunch( integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - string const & dofKey, - integer const hasCapPressure, - integer const useTotalMassEquation, - string const & solverName, - ElementRegionManager const & elemManager, - STENCILWRAPPER const & stencilWrapper, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) - { - integer constexpr NUM_COMP = NC(); - integer constexpr NUM_DOF = NC() + 2; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags; - if( hasCapPressure ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::CapPressure ); - if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::TotalMassEquation ); - - using KernelType = FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - typename KernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); - typename KernelType::ThermalCompFlowAccessors thermalCompFlowAccessors( elemManager, solverName ); - typename KernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); - typename KernelType::ThermalMultiFluidAccessors thermalMultiFluidAccessors( elemManager, solverName ); - typename KernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); - typename KernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); - typename KernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName ); - - KernelType kernel( numPhases, rankOffset, stencilWrapper, dofNumberAccessor, - compFlowAccessors, thermalCompFlowAccessors, multiFluidAccessors, thermalMultiFluidAccessors, - capPressureAccessors, permeabilityAccessors, thermalConductivityAccessors, - dt, localMatrix, localRhs, kernelFlags ); - KernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); - } ); - } -}; - -/******************************** DiffusionDispersionFaceBasedAssemblyKernel ********************************/ - -/** - * @class DiffusionDispersionFaceBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @brief Define the interface for the assembly kernel in charge of diffusion/dispersion flux terms - */ -template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > -class DiffusionDispersionFaceBasedAssemblyKernel : - public isothermalCompositionalMultiphaseFVMKernels::DiffusionDispersionFaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > -{ -public: - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelBase; - using DofNumberAccessor = AbstractBase::DofNumberAccessor; - using CompFlowAccessors = AbstractBase::CompFlowAccessors; - using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; - using AbstractBase::m_dt; - using AbstractBase::m_dPhaseCompFrac; - using AbstractBase::m_dPhaseVolFrac; - - using Base = typename isothermalCompositionalMultiphaseFVMKernels::DiffusionDispersionFaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - using DiffusionAccessors = typename Base::DiffusionAccessors; - using DispersionAccessors = typename Base::DispersionAccessors; - using PorosityAccessors = typename Base::PorosityAccessors; - using Base::numFluxSupportPoints; - using Base::numEqn; - using Base::numComp; - using Base::numDof; - using Base::m_referencePorosity; - using Base::m_phaseVolFrac; - using Base::m_phaseDens; - using Base::m_dPhaseDens; - using Base::m_phaseDiffusivityMultiplier; - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dofNumberAccessor - * @param[in] compFlowAccessors - * @param[in] multiFluidAccessors - * @param[in] diffusionAccessors - * @param[in] dispersionAccessors - * @param[in] porosityAccessors - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - * @param[in] kernelFlags flags packed together - */ - DiffusionDispersionFaceBasedAssemblyKernel( integer const numPhases, - globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - DiffusionAccessors const & diffusionAccessors, - DispersionAccessors const & dispersionAccessors, - PorosityAccessors const & porosityAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags ) - : Base( numPhases, - rankOffset, - stencilWrapper, - dofNumberAccessor, - compFlowAccessors, - multiFluidAccessors, - diffusionAccessors, - dispersionAccessors, - porosityAccessors, - dt, - localMatrix, - localRhs, - kernelFlags ) - {} - - struct StackVariables : public Base::StackVariables - { -public: - - GEOS_HOST_DEVICE - StackVariables( localIndex const size, localIndex numElems ) - : Base::StackVariables( size, numElems ) - {} - - using Base::StackVariables::transmissibility; - using Base::StackVariables::localFlux; - using Base::StackVariables::localFluxJacobian; - - }; - - /** - * @brief Compute the local diffusion flux contributions to the residual and Jacobian - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - inline - void computeDiffusionFlux( localIndex const iconn, - StackVariables & stack ) const - { - using Deriv = multifluid::DerivativeOffset; - - // *********************************************** - // First, we call the base computeFlux to compute the diffusionFlux and its derivatives (including derivatives wrt temperature), - // - // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables - Base::computeDiffusionFlux( iconn, stack, [&] ( integer const ip, - integer const ic, - localIndex const (&k)[2], - localIndex const (&seri)[2], - localIndex const (&sesri)[2], - localIndex const (&sei)[2], - localIndex const connectionIndex, - localIndex const k_up, - localIndex const er_up, - localIndex const esr_up, - localIndex const ei_up, - real64 const compFracGrad, - real64 const upwindCoefficient ) - { - // We are in the loop over phases and components, ip provides the current phase index. - - real64 dCompFracGrad_dT[numFluxSupportPoints]{}; - real64 dDiffusionFlux_dT[numFluxSupportPoints]{}; - - /// compute the TPFA component difference - for( integer i = 0; i < numFluxSupportPoints; i++ ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - dCompFracGrad_dT[i] += stack.transmissibility[connectionIndex][i] * m_dPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dT]; - } - - // add contributions of the derivatives of component fractions wrt pressure/component fractions - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dDiffusionFlux_dT[ke] += upwindCoefficient * dCompFracGrad_dT[ke]; - } - - // add contributions of the derivatives of upwind coefficient wrt temperature - real64 const dUpwindCoefficient_dT = - m_referencePorosity[er_up][esr_up][ei_up] * - m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * - ( m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dT] * m_phaseVolFrac[er_up][esr_up][ei_up][ip] - + m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_dPhaseVolFrac[er_up][esr_up][ei_up][ip][Deriv::dT] ); - dDiffusionFlux_dT[k_up] += dUpwindCoefficient_dT * compFracGrad; - - // finally, increment local flux and local Jacobian - integer const eqIndex0 = k[0] * numEqn + ic; - integer const eqIndex1 = k[1] * numEqn + ic; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - localIndex const localDofIndexTemp = k[ke] * numDof + numComp + 1; - stack.localFluxJacobian[eqIndex0][localDofIndexTemp] += m_dt * dDiffusionFlux_dT[ke]; - stack.localFluxJacobian[eqIndex1][localDofIndexTemp] -= m_dt * dDiffusionFlux_dT[ke]; - } - } ); - } - - /** - * @brief Compute the local dispersion flux contributions to the residual and Jacobian - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - inline - void computeDispersionFlux( localIndex const iconn, - StackVariables & stack ) const - { - using Deriv = multifluid::DerivativeOffset; - - // *********************************************** - // First, we call the base computeFlux to compute the dispersionFlux and its derivatives (including derivatives wrt temperature), - // - // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables - Base::computeDispersionFlux( iconn, stack, [&] ( integer const ip, - integer const ic, - localIndex const (&k)[2], - localIndex const (&seri)[2], - localIndex const (&sesri)[2], - localIndex const (&sei)[2], - localIndex const connectionIndex, - localIndex const k_up, - localIndex const er_up, - localIndex const esr_up, - localIndex const ei_up, - real64 const compFracGrad ) - { - // We are in the loop over phases and components, ip provides the current phase index. - - real64 dCompFracGrad_dT[numFluxSupportPoints]{}; - real64 dDispersionFlux_dT[numFluxSupportPoints]{}; - - /// compute the TPFA component difference - for( integer i = 0; i < numFluxSupportPoints; i++ ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - dCompFracGrad_dT[i] += stack.transmissibility[connectionIndex][i] * m_dPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dT]; - } - - // add contributions of the derivatives of component fractions wrt pressure/component fractions - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dDispersionFlux_dT[ke] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * dCompFracGrad_dT[ke]; - } - - // add contributions of the derivatives of upwind coefficient wrt temperature - dDispersionFlux_dT[k_up] += m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dT] * compFracGrad; - - // finally, increment local flux and local Jacobian - integer const eqIndex0 = k[0] * numEqn + ic; - integer const eqIndex1 = k[1] * numEqn + ic; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - localIndex const localDofIndexTemp = k[ke] * numDof + numComp + 1; - stack.localFluxJacobian[eqIndex0][localDofIndexTemp] += m_dt * dDispersionFlux_dT[ke]; - stack.localFluxJacobian[eqIndex1][localDofIndexTemp] -= m_dt * dDispersionFlux_dT[ke]; - } - } ); - } -}; - -/** - * @class DiffusionDispersionFaceBasedAssemblyKernelFactory - */ -class DiffusionDispersionFaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @param[in] numComps the number of fluid components - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey string to get the element degrees of freedom numbers - * @param[in] hasDiffusion flag specifying whether diffusion is used or not - * @param[in] hasDispersion flag specifying whether dispersion is used or not - * @param[in] solverName the name of the solver - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY, typename STENCILWRAPPER > - static void - createAndLaunch( integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - string const & dofKey, - integer const hasDiffusion, - integer const hasDispersion, - integer const useTotalMassEquation, - string const & solverName, - ElementRegionManager const & elemManager, - STENCILWRAPPER const & stencilWrapper, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) - { - integer constexpr NUM_COMP = NC(); - integer constexpr NUM_DOF = NC() + 2; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags; - if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::TotalMassEquation ); - - using kernelType = DiffusionDispersionFaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); - typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); - typename kernelType::DiffusionAccessors diffusionAccessors( elemManager, solverName ); - typename kernelType::DispersionAccessors dispersionAccessors( elemManager, solverName ); - typename kernelType::PorosityAccessors porosityAccessors( elemManager, solverName ); - - kernelType kernel( numPhases, rankOffset, stencilWrapper, - dofNumberAccessor, compFlowAccessors, multiFluidAccessors, - diffusionAccessors, dispersionAccessors, porosityAccessors, - dt, localMatrix, localRhs, kernelFlags ); - kernelType::template launch< POLICY >( stencilWrapper.size(), - hasDiffusion, hasDispersion, - kernel ); - } ); - } -}; - -/******************************** DirichletFaceBasedAssemblyKernel ********************************/ - -/** - * @class DirichletFaceBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @tparam FLUIDWRAPPER the type of the fluid wrapper - * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms - */ -template< integer NUM_COMP, integer NUM_DOF, typename FLUIDWRAPPER > -class DirichletFaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKernels::DirichletFaceBasedAssemblyKernel< NUM_COMP, - NUM_DOF, - FLUIDWRAPPER > -{ -public: - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelBase; - using DofNumberAccessor = AbstractBase::DofNumberAccessor; - using CompFlowAccessors = AbstractBase::CompFlowAccessors; - using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; - using CapPressureAccessors = AbstractBase::CapPressureAccessors; - using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; - - using AbstractBase::m_dt; - using AbstractBase::m_numPhases; - using AbstractBase::m_rankOffset; - using AbstractBase::m_dofNumber; - using AbstractBase::m_gravCoef; - using AbstractBase::m_phaseCompFrac; - using AbstractBase::m_dPhaseCompFrac; - using AbstractBase::m_dCompFrac_dCompDens; - - using Base = isothermalCompositionalMultiphaseFVMKernels::DirichletFaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, FLUIDWRAPPER >; - using Base::numComp; - using Base::numDof; - using Base::numEqn; - using Base::m_phaseMob; - using Base::m_dPhaseMob; - using Base::m_dPhaseMassDens; - using Base::m_dPhaseCapPressure_dPhaseVolFrac; - using Base::m_stencilWrapper; - using Base::m_seri; - using Base::m_sesri; - using Base::m_sei; - using Base::m_faceTemp; - using Base::m_faceGravCoef; - - - using ThermalCompFlowAccessors = - StencilAccessors< fields::flow::temperature >; - - using ThermalMultiFluidAccessors = - StencilMaterialAccessors< MultiFluidBase, - fields::multifluid::phaseEnthalpy, - fields::multifluid::dPhaseEnthalpy >; - - using ThermalConductivityAccessors = - StencilMaterialAccessors< MultiPhaseThermalConductivityBase, - fields::thermalconductivity::effectiveConductivity >; - // for now, we treat thermal conductivity explicitly - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] faceManager the face manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] fluidWrapper reference to the fluid wrapper - * @param[in] dofNumberAccessor accessor for the dofs numbers - * @param[in] compFlowAccessor accessor for wrappers registered by the solver - * @param[in] thermalCompFlowAccessors accessor for *thermal* wrappers registered by the solver - * @param[in] multiFluidAccessor accessor for wrappers registered by the multifluid model - * @param[in] thermalMultiFluidAccessors accessor for *thermal* wrappers registered by the multifluid model - * @param[in] capPressureAccessors accessor for wrappers registered by the cap pressure model - * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model - * @param[in] thermalConductivityAccessors accessor for wrappers registered by the thermal conductivity model - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - * @param[in] kernelFlags flags packed together - */ - DirichletFaceBasedAssemblyKernel( integer const numPhases, - globalIndex const rankOffset, - FaceManager const & faceManager, - BoundaryStencilWrapper const & stencilWrapper, - FLUIDWRAPPER const & fluidWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - ThermalCompFlowAccessors const & thermalCompFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - ThermalMultiFluidAccessors const & thermalMultiFluidAccessors, - CapPressureAccessors const & capPressureAccessors, - PermeabilityAccessors const & permeabilityAccessors, - ThermalConductivityAccessors const & thermalConductivityAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags ) - : Base( numPhases, - rankOffset, - faceManager, - stencilWrapper, - fluidWrapper, - dofNumberAccessor, - compFlowAccessors, - multiFluidAccessors, - capPressureAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs, - kernelFlags ), - m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), - m_phaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), - m_dPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ), - m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ) - {} - - struct StackVariables : public Base::StackVariables - { -public: - - /** - * @brief Constructor for the stack variables - * @param[in] size size of the stencil for this connection - * @param[in] numElems number of elements for this connection - */ - GEOS_HOST_DEVICE - StackVariables( localIndex const size, localIndex numElems ) - : Base::StackVariables( size, numElems ) - {} - - using Base::StackVariables::transmissibility; - using Base::StackVariables::dofColIndices; - using Base::StackVariables::localFlux; - using Base::StackVariables::localFluxJacobian; - - // Component fluxes and derivatives - - /// Derivatives of component fluxes wrt temperature - real64 dCompFlux_dT[numComp]{}; - - - // Energy fluxes and derivatives - - /// Energy fluxes - real64 energyFlux = 0.0; - /// Derivative of energy fluxes wrt pressure - real64 dEnergyFlux_dP = 0.0; - /// Derivative of energy fluxes wrt temperature - real64 dEnergyFlux_dT = 0.0; - /// Derivatives of energy fluxes wrt component densities - real64 dEnergyFlux_dC[numComp]{}; - - }; - - /** - * @brief Compute the local flux contributions to the residual and Jacobian - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void computeFlux( localIndex const iconn, - StackVariables & stack ) const - { - using Order = BoundaryStencil::Order; - using Deriv = multifluid::DerivativeOffset; - - // *********************************************** - // First, we call the base computeFlux to compute: - // 1) compFlux and its derivatives (including derivatives wrt temperature), - // 2) enthalpy part of energyFlux and its derivatives (including derivatives wrt temperature) - // - // Computing dCompFlux_dT and the enthalpy flux requires quantities already computed in the base computeFlux, - // such as potGrad, phaseFlux, and the indices of the upwind cell - // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables - Base::computeFlux( iconn, stack, [&] ( integer const ip, - localIndex const er, - localIndex const esr, - localIndex const ei, - localIndex const kf, - real64 const f, // potGrad times trans - real64 const facePhaseMob, - arraySlice1d< const real64, multifluid::USD_PHASE - 2 > const & facePhaseEnthalpy, - arraySlice2d< const real64, multifluid::USD_PHASE_COMP-2 > const & facePhaseCompFrac, - real64 const phaseFlux, - real64 const dPhaseFlux_dP, - real64 const (&dPhaseFlux_dC)[numComp] ) - { - // We are in the loop over phases, ip provides the current phase index. - - // Step 1: compute the derivatives of the mean density at the interface wrt temperature - - real64 const dDensMean_dT = 0.5 * m_dPhaseMassDens[er][esr][ei][0][ip][Deriv::dT]; - - // Step 2: compute the derivatives of the phase potential difference wrt temperature - //***** calculation of flux ***** - - real64 const dF_dT = -stack.transmissibility * dDensMean_dT * ( m_gravCoef[er][esr][ei] - m_faceGravCoef[kf] ); - - // Step 3: compute the derivatives of the (upwinded) compFlux wrt temperature - // *** upwinding *** - - // note: the upwinding is done in the base class, which is in charge of - // computing the following quantities: potGrad, phaseFlux - // It is easier to hard-code the if/else because it is difficult to address elem and face variables in a uniform way - - - if( f >= 0 ) // the element is upstream - { - - // Step 3.1.a: compute the derivative of phase flux wrt temperature - real64 const dPhaseFlux_dT = m_phaseMob[er][esr][ei][ip] * dF_dT + m_dPhaseMob[er][esr][ei][ip][Deriv::dT] * f; - - // Step 3.2.a: compute the derivative of component flux wrt temperature - - // slice some constitutive arrays to avoid too much indexing in component loop - arraySlice1d< real64 const, multifluid::USD_PHASE_COMP - 3 > phaseCompFracSub = - m_phaseCompFrac[er][esr][ei][0][ip]; - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP_DC - 3 > dPhaseCompFracSub = - m_dPhaseCompFrac[er][esr][ei][0][ip]; - - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 const ycp = phaseCompFracSub[ic]; - stack.dCompFlux_dT[ic] += dPhaseFlux_dT * ycp + phaseFlux * dPhaseCompFracSub[ic][Deriv::dT]; - } - - // Step 3.3.a: compute the enthalpy flux - - real64 const enthalpy = m_phaseEnthalpy[er][esr][ei][0][ip]; - stack.energyFlux += phaseFlux * enthalpy; - stack.dEnergyFlux_dP += dPhaseFlux_dP * enthalpy + phaseFlux * m_dPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dP]; - stack.dEnergyFlux_dT += dPhaseFlux_dT * enthalpy + phaseFlux * m_dPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dT]; - - real64 dProp_dC[numComp]{}; - applyChainRule( numComp, - m_dCompFrac_dCompDens[er][esr][ei], - m_dPhaseEnthalpy[er][esr][ei][0][ip], - dProp_dC, - Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - stack.dEnergyFlux_dC[jc] += dPhaseFlux_dC[jc] * enthalpy + phaseFlux * dProp_dC[jc]; - } - - } - else // the face is upstream - { - - // Step 3.1.b: compute the derivative of phase flux wrt temperature - real64 const dPhaseFlux_dT = facePhaseMob * dF_dT; - - // Step 3.2.b: compute the derivative of component flux wrt temperature - - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 const ycp = facePhaseCompFrac[ip][ic]; - stack.dCompFlux_dT[ic] += dPhaseFlux_dT * ycp; - } - - // Step 3.3.b: compute the enthalpy flux - - real64 const enthalpy = facePhaseEnthalpy[ip]; - stack.energyFlux += phaseFlux * enthalpy; - stack.dEnergyFlux_dP += dPhaseFlux_dP * enthalpy; - stack.dEnergyFlux_dT += dPhaseFlux_dT * enthalpy; - for( integer jc = 0; jc < numComp; ++jc ) - { - stack.dEnergyFlux_dC[jc] += dPhaseFlux_dC[jc] * enthalpy; - } - - } - - } ); - - // ***************************************************** - // Computation of the conduction term in the energy flux - // Note that the phase enthalpy term in the energy was computed above - // Note that this term is computed using an explicit treatment of conductivity for now - - // Step 1: compute the thermal transmissibilities at this face - // Below, the thermal conductivity used to compute (explicitly) the thermal conducivity - // To avoid modifying the signature of the "computeWeights" function for now, we pass m_thermalConductivity twice - // TODO: modify computeWeights to accomodate explicit coefficients - real64 thermalTrans = 0.0; - real64 dThermalTrans_dPerm[3]{}; // not used - m_stencilWrapper.computeWeights( iconn, - m_thermalConductivity, - thermalTrans, - dThermalTrans_dPerm ); - - // Step 2: compute temperature difference at the interface - stack.energyFlux += thermalTrans - * ( m_temp[m_seri( iconn, Order::ELEM )][m_sesri( iconn, Order::ELEM )][m_sei( iconn, Order::ELEM )] - m_faceTemp[m_sei( iconn, Order::FACE )] ); - stack.dEnergyFlux_dT += thermalTrans; - - - // ********************************************************************************** - // At this point, we have computed the energyFlux and the compFlux for all components - // We have to do two things here: - // 1) Add dCompFlux_dTemp to the localFluxJacobian of the component mass balance equations - // 2) Add energyFlux and its derivatives to the localFlux(Jacobian) of the energy balance equation - - // Step 1: add dCompFlux_dTemp to localFluxJacobian - for( integer ic = 0; ic < numComp; ++ic ) - { - stack.localFluxJacobian[ic][numDof-1] = m_dt * stack.dCompFlux_dT[ic]; - } - - // Step 2: add energyFlux and its derivatives to localFlux and localFluxJacobian - integer const localRowIndexEnergy = numEqn-1; - stack.localFlux[localRowIndexEnergy] = m_dt * stack.energyFlux; - - stack.localFluxJacobian[localRowIndexEnergy][0] = m_dt * stack.dEnergyFlux_dP; - stack.localFluxJacobian[localRowIndexEnergy][numDof-1] = m_dt * stack.dEnergyFlux_dT; - for( integer jc = 0; jc < numComp; ++jc ) - { - stack.localFluxJacobian[localRowIndexEnergy][jc+1] = m_dt * stack.dEnergyFlux_dC[jc]; - } - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void complete( localIndex const iconn, - StackVariables & stack ) const - { - // Call Case::complete to assemble the component mass balance equations (i = 0 to i = numDof-2) - // In the lambda, add contribution to residual and jacobian into the energy balance equation - Base::complete( iconn, stack, [&] ( localIndex const localRow ) - { - // beware, there is volume balance eqn in m_localRhs and m_localMatrix! - RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn], stack.localFlux[numEqn-1] ); - AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > - ( localRow + numEqn, - stack.dofColIndices, - stack.localFluxJacobian[numEqn-1], - numDof ); - - } ); - } - -protected: - - /// Views on temperature - ElementViewConst< arrayView1d< real64 const > > const m_temp; - - /// Views on phase enthalpies - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_phaseEnthalpy; - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dPhaseEnthalpy; - - /// View on thermal conductivity - ElementViewConst< arrayView3d< real64 const > > const m_thermalConductivity; - // for now, we treat thermal conductivity explicitly - -}; - -/** - * @class DirichletFaceBasedAssemblyKernelFactory - */ -class DirichletFaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @param[in] numComps the number of fluid components - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey string to get the element degrees of freedom numbers - * @param[in] solverName name of the solver (to name accessors) - * @param[in] faceManager reference to the face manager - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] fluidBase the multifluid constitutive model - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY, typename STENCILWRAPPER > - static void - createAndLaunch( integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - integer const useTotalMassEquation, - string const & dofKey, - string const & solverName, - FaceManager const & faceManager, - ElementRegionManager const & elemManager, - STENCILWRAPPER const & stencilWrapper, - MultiFluidBase & fluidBase, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - constitutive::constitutiveUpdatePassThru( fluidBase, [&]( auto & fluid ) - { - using FluidType = TYPEOFREF( fluid ); - typename FluidType::KernelWrapper const fluidWrapper = fluid.createKernelWrapper(); - - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) - { - integer constexpr NUM_COMP = NC(); - integer constexpr NUM_DOF = NC() + 2; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - // for now, we neglect capillary pressure in the kernel - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags; - if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::TotalMassEquation ); - - using KernelType = DirichletFaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, typename FluidType::KernelWrapper >; - typename KernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); - typename KernelType::ThermalCompFlowAccessors thermalCompFlowAccessors( elemManager, solverName ); - typename KernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); - typename KernelType::ThermalMultiFluidAccessors thermalMultiFluidAccessors( elemManager, solverName ); - typename KernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); - typename KernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); - typename KernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName ); - - KernelType kernel( numPhases, rankOffset, faceManager, stencilWrapper, fluidWrapper, - dofNumberAccessor, compFlowAccessors, thermalCompFlowAccessors, multiFluidAccessors, thermalMultiFluidAccessors, - capPressureAccessors, permeabilityAccessors, thermalConductivityAccessors, - dt, localMatrix, localRhs, kernelFlags ); - KernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); - } ); - } ); - } -}; - - -} // namespace thermalCompositionalMultiphaseFVMKernels - -} // namespace geos - - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/ThermalSinglePhaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/ThermalSinglePhaseBaseKernels.hpp deleted file mode 100644 index 8db24520903..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/ThermalSinglePhaseBaseKernels.hpp +++ /dev/null @@ -1,643 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file ThermalSinglePhaseBaseKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALSINGLEPHASEBASEKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALSINGLEPHASEBASEKERNELS_HPP - -#include "physicsSolvers/fluidFlow/SinglePhaseBaseKernels.hpp" - -namespace geos -{ - -namespace thermalSinglePhaseBaseKernels -{ - -/******************************** MobilityKernel ********************************/ - -struct MobilityKernel -{ - GEOS_HOST_DEVICE - inline - static void - compute( real64 const & dens, - real64 const & dDens_dPres, - real64 const & dDens_dTemp, - real64 const & visc, - real64 const & dVisc_dPres, - real64 const & dVisc_dTemp, - real64 & mob, - real64 & dMob_dPres, - real64 & dMob_dTemp ) - { - mob = dens / visc; - dMob_dPres = dDens_dPres / visc - mob / visc * dVisc_dPres; - dMob_dTemp = dDens_dTemp / visc - mob / visc * dVisc_dTemp; - } - - GEOS_HOST_DEVICE - inline - static void - compute( real64 const & dens, - real64 const & visc, - real64 & mob ) - { - mob = dens / visc; - } - - template< typename POLICY > - static void launch( localIndex const size, - arrayView2d< real64 const > const & dens, - arrayView2d< real64 const > const & dDens_dPres, - arrayView2d< real64 const > const & dDens_dTemp, - arrayView2d< real64 const > const & visc, - arrayView2d< real64 const > const & dVisc_dPres, - arrayView2d< real64 const > const & dVisc_dTemp, - arrayView1d< real64 > const & mob, - arrayView1d< real64 > const & dMob_dPres, - arrayView1d< real64 > const & dMob_dTemp ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - compute( dens[a][0], - dDens_dPres[a][0], - dDens_dTemp[a][0], - visc[a][0], - dVisc_dPres[a][0], - dVisc_dTemp[a][0], - mob[a], - dMob_dPres[a], - dMob_dTemp[a] ); - } ); - } - - template< typename POLICY > - static void launch( localIndex const size, - arrayView2d< real64 const > const & dens, - arrayView2d< real64 const > const & visc, - arrayView1d< real64 > const & mob ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - compute( dens[a][0], - visc[a][0], - mob[a] ); - } ); - } -}; - -/******************************** ElementBasedAssemblyKernel ********************************/ - -/** - * @class ElementBasedAssemblyKernel - * @brief Define the interface for the assembly kernel in charge of accumulation - */ -template< typename SUBREGION_TYPE, integer NUM_DOF > -class ElementBasedAssemblyKernel : public singlePhaseBaseKernels::ElementBasedAssemblyKernel< SUBREGION_TYPE, NUM_DOF > -{ - -public: - - using Base = singlePhaseBaseKernels::ElementBasedAssemblyKernel< SUBREGION_TYPE, NUM_DOF >; - using Base::numDof; - using Base::numEqn; - using Base::m_rankOffset; - using Base::m_dofNumber; - using Base::m_elemGhostRank; - using Base::m_volume; - using Base::m_deltaVolume; - using Base::m_porosity_n; - using Base::m_porosityNew; - using Base::m_dPoro_dPres; - using Base::m_density_n; - using Base::m_density; - using Base::m_dDensity_dPres; - using Base::m_localMatrix; - using Base::m_localRhs; - - /** - * @brief Constructor - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - ElementBasedAssemblyKernel( globalIndex const rankOffset, - string const dofKey, - SUBREGION_TYPE const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : Base( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ), - m_dDensity_dTemp( fluid.dDensity_dTemperature() ), - m_dPoro_dTemp( solid.getDporosity_dTemperature() ), - m_internalEnergy_n( fluid.internalEnergy_n() ), - m_internalEnergy( fluid.internalEnergy() ), - m_dInternalEnergy_dPres( fluid.dInternalEnergy_dPressure() ), - m_dInternalEnergy_dTemp( fluid.dInternalEnergy_dTemperature() ), - m_rockInternalEnergy_n( solid.getInternalEnergy_n() ), - m_rockInternalEnergy( solid.getInternalEnergy() ), - m_dRockInternalEnergy_dTemp( solid.getDinternalEnergy_dTemperature() ) - {} - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - struct StackVariables : public Base::StackVariables - { -public: - - GEOS_HOST_DEVICE - StackVariables() - : Base::StackVariables() - {} - - using Base::StackVariables::poreVolume; - using Base::StackVariables::poreVolume_n; - using Base::StackVariables::dPoreVolume_dPres; - using Base::StackVariables::localRow; - using Base::StackVariables::dofIndices; - using Base::StackVariables::localResidual; - using Base::StackVariables::localJacobian; - - /// Derivative of pore volume with respect to temperature - real64 dPoreVolume_dTemp = 0.0; - - // Solid energy - - /// Solid energy at time n+1 - real64 solidEnergy = 0.0; - - /// Solid energy at the previous converged time step - real64 solidEnergy_n = 0.0; - - /// Derivative of solid internal energy with respect to pressure - real64 dSolidEnergy_dPres = 0.0; - - /// Derivative of solid internal energy with respect to temperature - real64 dSolidEnergy_dTemp = 0.0; - }; - - - /** - * @brief Performs the setup phase for the kernel. - * @param[in] ei the element index - * @param[in] stack the stack variables - */ - GEOS_HOST_DEVICE - void setup( localIndex const ei, - StackVariables & stack ) const - { - Base::setup( ei, stack ); - - stack.dPoreVolume_dTemp = ( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dTemp[ei][0]; - - // initialize the solid volume - real64 const solidVolume = ( m_volume[ei] + m_deltaVolume[ei] ) * ( 1.0 - m_porosityNew[ei][0] ); - real64 const solidVolume_n = m_volume[ei] * ( 1.0 - m_porosity_n[ei][0] ); - real64 const dSolidVolume_dPres = -( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dPres[ei][0]; - real64 const dSolidVolume_dTemp = -( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dTemp[ei][0]; - - // initialize the solid internal energy - stack.solidEnergy = solidVolume * m_rockInternalEnergy[ei][0]; - stack.solidEnergy_n = solidVolume_n * m_rockInternalEnergy_n[ei][0]; - stack.dSolidEnergy_dPres = dSolidVolume_dPres * m_rockInternalEnergy[ei][0]; - stack.dSolidEnergy_dTemp = solidVolume * m_dRockInternalEnergy_dTemp[ei][0] + dSolidVolume_dTemp * m_rockInternalEnergy[ei][0]; - } - - /** - * @brief Compute the local accumulation contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[inout] stack the stack variables - * @param[in] kernelOp the function used to customize the kernel - */ - GEOS_HOST_DEVICE - void computeAccumulation( localIndex const ei, - StackVariables & stack ) const - { - Base::computeAccumulation( ei, stack, [&] () - { - // Step 1: assemble the derivatives of the mass balance equation w.r.t temperature - stack.localJacobian[0][numDof-1] = stack.poreVolume * m_dDensity_dTemp[ei][0] + stack.dPoreVolume_dTemp * m_density[ei][0]; - - // Step 2: assemble the fluid part of the accumulation term of the energy equation - real64 const fluidEnergy = stack.poreVolume * m_density[ei][0] * m_internalEnergy[ei][0]; - real64 const fluidEnergy_n = stack.poreVolume_n * m_density_n[ei][0] * m_internalEnergy_n[ei][0]; - - real64 const dFluidEnergy_dP = stack.dPoreVolume_dPres * m_density[ei][0] * m_internalEnergy[ei][0] - + stack.poreVolume * m_dDensity_dPres[ei][0] * m_internalEnergy[ei][0] - + stack.poreVolume * m_density[ei][0] * m_dInternalEnergy_dPres[ei][0]; - - real64 const dFluidEnergy_dT = stack.poreVolume * m_dDensity_dTemp[ei][0] * m_internalEnergy[ei][0] - + stack.poreVolume * m_density[ei][0] * m_dInternalEnergy_dTemp[ei][0] - + stack.dPoreVolume_dTemp * m_density[ei][0] * m_internalEnergy[ei][0]; - - // local accumulation - stack.localResidual[numEqn-1] = fluidEnergy - fluidEnergy_n; - - // derivatives w.r.t. pressure and temperature - stack.localJacobian[numEqn-1][0] = dFluidEnergy_dP; - stack.localJacobian[numEqn-1][numDof-1] = dFluidEnergy_dT; - } ); - - // Step 3: assemble the solid part of the accumulation term of the energy equation - stack.localResidual[numEqn-1] += stack.solidEnergy - stack.solidEnergy_n; - stack.localJacobian[numEqn-1][0] += stack.dSolidEnergy_dPres; - stack.localJacobian[numEqn-1][numDof-1] += stack.dSolidEnergy_dTemp; - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void complete( localIndex const ei, - StackVariables & stack ) const - { - // Step 1: assemble the mass balance equation - Base::complete( ei, stack ); - - // Step 2: assemble the energy equation - m_localRhs[stack.localRow + numEqn-1] += stack.localResidual[numEqn-1]; - m_localMatrix.template addToRow< serialAtomic >( stack.localRow + numEqn-1, - stack.dofIndices, - stack.localJacobian[numEqn-1], - numDof ); - - - } - -protected: - - /// View on derivative of fluid density w.r.t temperature - arrayView2d< real64 const > const m_dDensity_dTemp; - - /// View on derivative of porosity w.r.t temperature - arrayView2d< real64 const > const m_dPoro_dTemp; - - /// Views on fluid internal energy - arrayView2d< real64 const > const m_internalEnergy_n; - arrayView2d< real64 const > const m_internalEnergy; - arrayView2d< real64 const > const m_dInternalEnergy_dPres; - arrayView2d< real64 const > const m_dInternalEnergy_dTemp; - - /// Views on rock internal energy - arrayView2d< real64 const > m_rockInternalEnergy_n; - arrayView2d< real64 const > m_rockInternalEnergy; - arrayView2d< real64 const > m_dRockInternalEnergy_dTemp; - -}; - -/** - * @class SurfaceElementBasedAssemblyKernel - * @brief Define the interface for the assembly kernel in charge of accumulation in SurfaceElementSubRegion - */ -class SurfaceElementBasedAssemblyKernel : public ElementBasedAssemblyKernel< SurfaceElementSubRegion, 2 > -{ - -public: - - using Base = ElementBasedAssemblyKernel< SurfaceElementSubRegion, 2 >; - - /** - * @brief Constructor - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - SurfaceElementBasedAssemblyKernel( globalIndex const rankOffset, - string const dofKey, - SurfaceElementSubRegion const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : Base( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ) -#if ALLOW_CREATION_MASS - , m_creationMass( subRegion.getReference< array1d< real64 > >( SurfaceElementSubRegion::viewKeyStruct::creationMassString() ) ) -#endif - { -#if !defined(ALLOW_CREATION_MASS) - static_assert( true, "must have ALLOW_CREATION_MASS defined" ); -#endif - } - - /** - * @brief Compute the local accumulation contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void computeAccumulation( localIndex const ei, - Base::StackVariables & stack ) const - { - Base::computeAccumulation( ei, stack ); - -#if ALLOW_CREATION_MASS - if( Base::m_volume[ei] * Base::m_density_n[ei][0] > 1.1 * m_creationMass[ei] ) - { - stack.localResidual[0] += m_creationMass[ei] * 0.25; - } -#endif - } - -protected: - -#if ALLOW_CREATION_MASS - arrayView1d< real64 const > const m_creationMass; -#endif - -}; - -/** - * @class ElementBasedAssemblyKernelFactory - */ -class ElementBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY > - static void - createAndLaunch( globalIndex const rankOffset, - string const dofKey, - CellElementSubRegion const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - integer constexpr NUM_DOF = 2; - - ElementBasedAssemblyKernel< CellElementSubRegion, NUM_DOF > - kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); - ElementBasedAssemblyKernel< CellElementSubRegion, NUM_DOF >::template - launch< POLICY, ElementBasedAssemblyKernel< CellElementSubRegion, NUM_DOF > >( subRegion.size(), kernel ); - } - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY > - static void - createAndLaunch( globalIndex const rankOffset, - string const dofKey, - SurfaceElementSubRegion const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - SurfaceElementBasedAssemblyKernel - kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); - SurfaceElementBasedAssemblyKernel::launch< POLICY >( subRegion.size(), kernel ); - } - - -}; - - -/******************************** FluidUpdateKernel ********************************/ - -struct FluidUpdateKernel -{ - template< typename FLUID_WRAPPER > - static void launch( FLUID_WRAPPER const & fluidWrapper, - arrayView1d< real64 const > const & pres, - arrayView1d< real64 const > const & temp ) - { - forAll< parallelDevicePolicy<> >( fluidWrapper.numElems(), [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) - { - fluidWrapper.update( k, q, pres[k], temp[k] ); - } - } ); - } -}; - -/******************************** SolidInternalEnergyUpdateKernel ********************************/ - -struct SolidInternalEnergyUpdateKernel -{ - - template< typename POLICY, typename SOLID_INTERNAL_ENERGY_WRAPPER > - static void - launch( localIndex const size, - SOLID_INTERNAL_ENERGY_WRAPPER const & solidInternalEnergyWrapper, - arrayView1d< real64 const > const & temp ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - solidInternalEnergyWrapper.update( k, temp[k] ); - } ); - } -}; - -/******************************** ResidualNormKernel ********************************/ - -/** - * @class ResidualNormKernel - */ -class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 2 > -{ -public: - - using Base = solverBaseKernels::ResidualNormKernelBase< 2 >; - using Base::m_minNormalizer; - using Base::m_rankOffset; - using Base::m_localResidual; - using Base::m_dofNumber; - - ResidualNormKernel( globalIndex const rankOffset, - arrayView1d< real64 const > const & localResidual, - arrayView1d< globalIndex const > const & dofNumber, - arrayView1d< localIndex const > const & ghostRank, - ElementSubRegionBase const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - constitutive::SolidInternalEnergy const & solidInternalEnergy, - real64 const minNormalizer ) - : Base( rankOffset, - localResidual, - dofNumber, - ghostRank, - minNormalizer ), - m_volume( subRegion.getElementVolume() ), - m_porosity_n( solid.getPorosity_n() ), - m_density_n( fluid.density_n() ), - m_fluidInternalEnergy_n( fluid.internalEnergy_n() ), - m_solidInternalEnergy_n( solidInternalEnergy.getInternalEnergy_n() ) - {} - - GEOS_HOST_DEVICE - void computeMassEnergyNormalizers( localIndex const ei, - real64 & massNormalizer, - real64 & energyNormalizer ) const - { - massNormalizer = LvArray::math::max( m_minNormalizer, m_density_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); - energyNormalizer = - LvArray::math::max( m_minNormalizer, - LvArray::math::abs( m_solidInternalEnergy_n[ei][0] * ( 1.0 - m_porosity_n[ei][0] ) * m_volume[ei] - + m_fluidInternalEnergy_n[ei][0] * m_density_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ) ); - } - - GEOS_HOST_DEVICE - virtual void computeLinf( localIndex const ei, - LinfStackVariables & stack ) const override - { - real64 massNormalizer = 0.0, energyNormalizer = 0.0; - computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); - - // step 1: mass residual - - real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow] ) / massNormalizer; - if( valMass > stack.localValue[0] ) - { - stack.localValue[0] = valMass; - } - - // step 2: energy residual - real64 const valEnergy = LvArray::math::abs( m_localResidual[stack.localRow + 1] ) / energyNormalizer; - if( valEnergy > stack.localValue[1] ) - { - stack.localValue[1] = valEnergy; - } - } - - GEOS_HOST_DEVICE - virtual void computeL2( localIndex const ei, - L2StackVariables & stack ) const override - { - real64 massNormalizer = 0.0, energyNormalizer = 0.0; - computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); - - // step 1: mass residual - - stack.localValue[0] += m_localResidual[stack.localRow] * m_localResidual[stack.localRow]; - stack.localNormalizer[0] += massNormalizer; - - // step 2: energy residual - - stack.localValue[1] += m_localResidual[stack.localRow + 1] * m_localResidual[stack.localRow + 1]; - stack.localNormalizer[1] += energyNormalizer; - } - - -protected: - - /// View on the volume - arrayView1d< real64 const > const m_volume; - - /// View on porosity at the previous converged time step - arrayView2d< real64 const > const m_porosity_n; - - /// View on total mass/molar density at the previous converged time step - arrayView2d< real64 const > const m_density_n; - arrayView2d< real64 const > const m_fluidInternalEnergy_n; - - /// View on solid internal energy at the previous converged time step - arrayView2d< real64 const > const m_solidInternalEnergy_n; - -}; - -/** - * @class ResidualNormKernelFactory - */ -class ResidualNormKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] normType the type of norm used (Linf or L2) - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] localResidual the residual vector on my MPI rank - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[in] solidInternalEnergy the solid internal energy model - * @param[out] residualNorm the residual norm on the subRegion - * @param[out] residualNormalizer the residual normalizer on the subRegion - */ - template< typename POLICY > - static void - createAndLaunch( solverBaseKernels::NormType const normType, - globalIndex const rankOffset, - string const & dofKey, - arrayView1d< real64 const > const & localResidual, - ElementSubRegionBase const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - constitutive::SolidInternalEnergy const & solidInternalEnergy, - real64 const minNormalizer, - real64 (& residualNorm)[2], - real64 (& residualNormalizer)[2] ) - { - arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); - arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); - - ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, subRegion, fluid, solid, solidInternalEnergy, minNormalizer ); - if( normType == solverBaseKernels::NormType::Linf ) - { - ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); - } - else // L2 norm - { - ResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); - } - } - -}; - -} // namespace thermalSinglePhaseBaseKernels - -} // namespace geos - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALSINGLEPHASEBASEKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/ThermalSinglePhaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/ThermalSinglePhaseFVMKernels.hpp deleted file mode 100644 index 4f994baa255..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/ThermalSinglePhaseFVMKernels.hpp +++ /dev/null @@ -1,832 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file ThermalSinglePhaseFVMKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALSINGLEPHASEFVMKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALSINGLEPHASEFVMKERNELS_HPP - -#include "constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.hpp" -#include "constitutive/thermalConductivity/ThermalConductivityFields.hpp" -#include "constitutive/thermalConductivity/SinglePhaseThermalConductivityFields.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseFVMKernels.hpp" - -namespace geos -{ - -namespace thermalSinglePhaseFVMKernels -{ -using namespace constitutive; - -/******************************** FaceBasedAssemblyKernel ********************************/ - -/** - * @class FaceBasedAssemblyKernel - * @tparam NUM_DOF number of degrees of freedom - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @brief Define the interface for the assembly kernel in charge of flux terms - */ -template< integer NUM_EQN, integer NUM_DOF, typename STENCILWRAPPER > -class FaceBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER > -{ -public: - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using AbstractBase = singlePhaseFVMKernels::FaceBasedAssemblyKernelBase; - using DofNumberAccessor = AbstractBase::DofNumberAccessor; - using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; - using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; - using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; - - using AbstractBase::m_dt; - using AbstractBase::m_rankOffset; - using AbstractBase::m_dofNumber; - using AbstractBase::m_gravCoef; - using AbstractBase::m_mob; - using AbstractBase::m_dens; - - using Base = singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; - using Base::numDof; - using Base::numEqn; - using Base::maxNumElems; - using Base::maxNumConns; - using Base::maxStencilSize; - using Base::m_stencilWrapper; - using Base::m_seri; - using Base::m_sesri; - using Base::m_sei; - - using ThermalSinglePhaseFlowAccessors = - StencilAccessors< fields::flow::temperature, - fields::flow::dMobility_dTemperature >; - - using ThermalSinglePhaseFluidAccessors = - StencilMaterialAccessors< SingleFluidBase, - fields::singlefluid::dDensity_dTemperature, - fields::singlefluid::enthalpy, - fields::singlefluid::dEnthalpy_dPressure, - fields::singlefluid::dEnthalpy_dTemperature >; - - using ThermalConductivityAccessors = - StencilMaterialAccessors< SinglePhaseThermalConductivityBase, - fields::thermalconductivity::effectiveConductivity >; - - /** - * @brief Constructor for the kernel interface - * @param[in] rankOffset the offset of my MPI rank - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dofNumberAccessor accessor for the dofs numbers - * @param[in] singlePhaseFlowAccessors accessor for wrappers registered by the solver - * @param[in] thermalSinglePhaseFlowAccessors accessor for *thermal* wrappers registered by the solver - * @param[in] singlePhaseFluidAccessors accessor for wrappers registered by the single fluid model - * @param[in] thermalSinglePhaseFluidAccessors accessor for *thermal* wrappers registered by the single fluid model - * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model - * @param[in] thermalConductivityAccessors accessor for wrappers registered by the thermal conductivity model - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - FaceBasedAssemblyKernel( globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, - ThermalSinglePhaseFlowAccessors const & thermalSinglePhaseFlowAccessors, - SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, - ThermalSinglePhaseFluidAccessors const & thermalSinglePhaseFluidAccessors, - PermeabilityAccessors const & permeabilityAccessors, - ThermalConductivityAccessors const & thermalConductivityAccessors, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : Base( rankOffset, - stencilWrapper, - dofNumberAccessor, - singlePhaseFlowAccessors, - singlePhaseFluidAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs ), - m_temp( thermalSinglePhaseFlowAccessors.get( fields::flow::temperature {} ) ), - m_dMob_dTemp( thermalSinglePhaseFlowAccessors.get( fields::flow::dMobility_dTemperature {} ) ), - m_dDens_dTemp( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dDensity_dTemperature {} ) ), - m_enthalpy( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::enthalpy {} ) ), - m_dEnthalpy_dPres( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dEnthalpy_dPressure {} ) ), - m_dEnthalpy_dTemp( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dEnthalpy_dTemperature {} ) ), - m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ) - {} - - struct StackVariables : public Base::StackVariables - { -public: - - GEOS_HOST_DEVICE - StackVariables( localIndex const size, localIndex numElems ) - : Base::StackVariables( size, numElems ), - energyFlux( 0.0 ), - dEnergyFlux_dP( size ), - dEnergyFlux_dT( size ) - {} - - using Base::StackVariables::stencilSize; - using Base::StackVariables::numFluxElems; - using Base::StackVariables::transmissibility; - using Base::StackVariables::dTrans_dPres; - using Base::StackVariables::dofColIndices; - using Base::StackVariables::localFlux; - using Base::StackVariables::localFluxJacobian; - - // Thermal transmissibility (for now, no derivatives) - - real64 thermalTransmissibility[maxNumConns][2]{}; - - // Energy fluxes and derivatives - - /// Energy fluxes - real64 energyFlux; - /// Derivatives of energy fluxes wrt pressure - stackArray1d< real64, maxStencilSize > dEnergyFlux_dP; - /// Derivatives of energy fluxes wrt temperature - stackArray1d< real64, maxStencilSize > dEnergyFlux_dT; - - }; - - /** - * @brief Compute the local flux contributions to the residual and Jacobian - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void computeFlux( localIndex const iconn, - StackVariables & stack ) const - { - // *********************************************** - // First, we call the base computeFlux to compute: - // 1) compFlux and its derivatives (including derivatives wrt temperature), - // 2) enthalpy part of energyFlux and its derivatives (including derivatives wrt temperature) - // - // Computing dFlux_dT and the enthalpy flux requires quantities already computed in the base computeFlux, - // such as potGrad, fluxVal, and the indices of the upwind cell - // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables - Base::computeFlux( iconn, stack, [&] ( localIndex const (&k)[2], - localIndex const (&seri)[2], - localIndex const (&sesri)[2], - localIndex const (&sei)[2], - localIndex const connectionIndex, - real64 const alpha, - real64 const mobility, - real64 const & potGrad, - real64 const & fluxVal, - real64 const (&dFlux_dP)[2] ) - { - // Step 1: compute the derivatives of the mean density at the interface wrt temperature - - real64 dDensMean_dT[2]{0.0, 0.0}; - - real64 const trans[2] = { stack.transmissibility[connectionIndex][0], stack.transmissibility[connectionIndex][1] }; - - for( integer ke = 0; ke < 2; ++ke ) - { - real64 const dDens_dT = m_dDens_dTemp[seri[ke]][sesri[ke]][sei[ke]][0]; - dDensMean_dT[ke] = 0.5 * dDens_dT; - } - - // Step 2: compute the derivatives of the potential difference wrt temperature - //***** calculation of flux ***** - - real64 dGravHead_dT[2]{0.0, 0.0}; - - // compute potential difference - for( integer ke = 0; ke < 2; ++ke ) - { - localIndex const er = seri[ke]; - localIndex const esr = sesri[ke]; - localIndex const ei = sei[ke]; - - // compute derivative of gravity potential difference wrt temperature - real64 const gravD = trans[ke] * m_gravCoef[er][esr][ei]; - - for( integer i = 0; i < 2; ++i ) - { - dGravHead_dT[i] += dDensMean_dT[i] * gravD; - } - } - - // Step 3: compute the derivatives of the (upwinded) compFlux wrt temperature - // *** upwinding *** - - real64 dFlux_dT[2]{0.0, 0.0}; - - // Step 3.1: compute the derivative of flux wrt temperature - for( integer ke = 0; ke < 2; ++ke ) - { - dFlux_dT[ke] -= dGravHead_dT[ke]; - } - - for( integer ke = 0; ke < 2; ++ke ) - { - dFlux_dT[ke] *= mobility; - } - - real64 dMob_dT[2]{}; - - if( alpha <= 0.0 || alpha >= 1.0 ) - { - localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) ); - - dMob_dT[k_up] = m_dMob_dTemp[seri[k_up]][sesri[k_up]][sei[k_up]]; - } - else - { - real64 const mobWeights[2] = { alpha, 1.0 - alpha }; - for( integer ke = 0; ke < 2; ++ke ) - { - dMob_dT[ke] = mobWeights[ke] * m_dMob_dTemp[seri[ke]][sesri[ke]][sei[ke]]; - } - } - - // add contribution from upstream cell mobility derivatives - for( integer ke = 0; ke < 2; ++ke ) - { - dFlux_dT[ke] += dMob_dT[ke] * potGrad; - } - - // add dFlux_dTemp to localFluxJacobian - for( integer ke = 0; ke < 2; ++ke ) - { - localIndex const localDofIndexTemp = k[ke] * numDof + numDof - 1; - stack.localFluxJacobian[k[0]*numEqn][localDofIndexTemp] += m_dt * dFlux_dT[ke]; - stack.localFluxJacobian[k[1]*numEqn][localDofIndexTemp] -= m_dt * dFlux_dT[ke]; - } - - // Step 4: compute the enthalpy flux - real64 enthalpy = 0.0; - real64 dEnthalpy_dP[2]{0.0, 0.0}; - real64 dEnthalpy_dT[2]{0.0, 0.0}; - - if( alpha <= 0.0 || alpha >= 1.0 ) - { - localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) ); - - enthalpy = m_enthalpy[seri[k_up]][sesri[k_up]][sei[k_up]][0]; - dEnthalpy_dP[k_up] = m_dEnthalpy_dPres[seri[k_up]][sesri[k_up]][sei[k_up]][0]; - dEnthalpy_dT[k_up] = m_dEnthalpy_dTemp[seri[k_up]][sesri[k_up]][sei[k_up]][0]; - } - else - { - real64 const mobWeights[2] = { alpha, 1.0 - alpha }; - for( integer ke = 0; ke < 2; ++ke ) - { - enthalpy += mobWeights[ke] * m_enthalpy[seri[ke]][sesri[ke]][sei[ke]][0]; - dEnthalpy_dP[ke] = mobWeights[ke] * m_dEnthalpy_dPres[seri[ke]][sesri[ke]][sei[ke]][0]; - dEnthalpy_dT[ke] = mobWeights[ke] * m_dEnthalpy_dTemp[seri[ke]][sesri[ke]][sei[ke]][0]; - } - } - - stack.energyFlux += fluxVal * enthalpy; - - for( integer ke = 0; ke < 2; ++ke ) - { - stack.dEnergyFlux_dP[ke] += dFlux_dP[ke] * enthalpy; - stack.dEnergyFlux_dT[ke] += dFlux_dT[ke] * enthalpy; - } - - for( integer ke = 0; ke < 2; ++ke ) - { - stack.dEnergyFlux_dP[ke] += fluxVal * dEnthalpy_dP[ke]; - stack.dEnergyFlux_dT[ke] += fluxVal * dEnthalpy_dT[ke]; - } - - } ); - - // ***************************************************** - // Computation of the conduction term in the energy flux - // Note that the enthalpy term in the energy was computed above - // Note that this term is computed using an explicit treatment of conductivity for now - - // Step 1: compute the thermal transmissibilities at this face - // We follow how the thermal compositional multi-phase solver does to update the thermal transmissibility - m_stencilWrapper.computeWeights( iconn, - m_thermalConductivity, - m_thermalConductivity, // we have to pass something here, so we just use thermal conductivity - stack.thermalTransmissibility, - stack.dTrans_dPres ); // again, we have to pass something here, but this is unused for now - - localIndex k[2]; - localIndex connectionIndex = 0; - - for( k[0] = 0; k[0] < stack.numFluxElems; ++k[0] ) - { - for( k[1] = k[0] + 1; k[1] < stack.numFluxElems; ++k[1] ) - { - real64 const thermalTrans[2] = { stack.thermalTransmissibility[connectionIndex][0], stack.thermalTransmissibility[connectionIndex][1] }; - - localIndex const seri[2] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; - localIndex const sesri[2] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; - localIndex const sei[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; - - // Step 2: compute temperature difference at the interface - for( integer ke = 0; ke < 2; ++ke ) - { - localIndex const er = seri[ke]; - localIndex const esr = sesri[ke]; - localIndex const ei = sei[ke]; - - stack.energyFlux += thermalTrans[ke] * m_temp[er][esr][ei]; - stack.dEnergyFlux_dT[ke] += thermalTrans[ke]; - } - - // add energyFlux and its derivatives to localFlux and localFluxJacobian - stack.localFlux[k[0]*numEqn + numEqn - 1] += m_dt * stack.energyFlux; - stack.localFlux[k[1]*numEqn + numEqn - 1] -= m_dt * stack.energyFlux; - - for( integer ke = 0; ke < 2; ++ke ) - { - integer const localDofIndexPres = k[ke] * numDof; - stack.localFluxJacobian[k[0]*numEqn + numEqn - 1][localDofIndexPres] = m_dt * stack.dEnergyFlux_dP[ke]; - stack.localFluxJacobian[k[1]*numEqn + numEqn - 1][localDofIndexPres] = -m_dt * stack.dEnergyFlux_dP[ke]; - integer const localDofIndexTemp = localDofIndexPres + numDof - 1; - stack.localFluxJacobian[k[0]*numEqn + numEqn - 1][localDofIndexTemp] = m_dt * stack.dEnergyFlux_dT[ke]; - stack.localFluxJacobian[k[1]*numEqn + numEqn - 1][localDofIndexTemp] = -m_dt * stack.dEnergyFlux_dT[ke]; - } - - connectionIndex++; - } - } - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void complete( localIndex const iconn, - StackVariables & stack ) const - { - // Call Case::complete to assemble the mass balance equations - // In the lambda, add contribution to residual and jacobian into the energy balance equation - Base::complete( iconn, stack, [&] ( integer const i, - localIndex const localRow ) - { - // The no. of fluxes is equal to the no. of equations in m_localRhs and m_localMatrix - // Different from the one in compositional multi-phase flow, which has a volume balance eqn. - RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn-1], stack.localFlux[i * numEqn + numEqn-1] ); - - AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( localRow + numEqn-1, - stack.dofColIndices.data(), - stack.localFluxJacobian[i * numEqn + numEqn-1].dataIfContiguous(), - stack.stencilSize * numDof ); - - } ); - } - -protected: - - /// Views on temperature - ElementViewConst< arrayView1d< real64 const > > const m_temp; - - /// Views on derivatives of fluid mobilities - ElementViewConst< arrayView1d< real64 const > > const m_dMob_dTemp; - - /// Views on derivatives of fluid densities - ElementViewConst< arrayView2d< real64 const > > const m_dDens_dTemp; - - /// Views on enthalpies - ElementViewConst< arrayView2d< real64 const > > const m_enthalpy; - ElementViewConst< arrayView2d< real64 const > > const m_dEnthalpy_dPres; - ElementViewConst< arrayView2d< real64 const > > const m_dEnthalpy_dTemp; - - /// View on thermal conductivity - ElementViewConst< arrayView3d< real64 const > > m_thermalConductivity; - -}; - -/** - * @class FaceBasedAssemblyKernelFactory - */ -class FaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey string to get the element degrees of freedom numbers - * @param[in] solverName name of the solver (to name accessors) - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY, typename STENCILWRAPPER > - static void - createAndLaunch( globalIndex const rankOffset, - string const & dofKey, - string const & solverName, - ElementRegionManager const & elemManager, - STENCILWRAPPER const & stencilWrapper, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - integer constexpr NUM_DOF = 2; - integer constexpr NUM_EQN = 2; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - using KernelType = FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; - typename KernelType::SinglePhaseFlowAccessors flowAccessors( elemManager, solverName ); - typename KernelType::ThermalSinglePhaseFlowAccessors thermalFlowAccessors( elemManager, solverName ); - typename KernelType::SinglePhaseFluidAccessors fluidAccessors( elemManager, solverName ); - typename KernelType::ThermalSinglePhaseFluidAccessors thermalFluidAccessors( elemManager, solverName ); - typename KernelType::PermeabilityAccessors permAccessors( elemManager, solverName ); - typename KernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName ); - - KernelType kernel( rankOffset, stencilWrapper, dofNumberAccessor, - flowAccessors, thermalFlowAccessors, fluidAccessors, thermalFluidAccessors, - permAccessors, thermalConductivityAccessors, - dt, localMatrix, localRhs ); - KernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); - } -}; - -/******************************** DirichletFaceBasedAssemblyKernel ********************************/ - -/** - * @class DirichFaceBasedAssemblyKernel - * @tparam FLUIDWRAPPER the type of the fluid wrapper - * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms - */ -template< integer NUM_EQN, integer NUM_DOF, typename FLUIDWRAPPER > -class DirichletFaceBasedAssemblyKernel : public singlePhaseFVMKernels::DirichletFaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, FLUIDWRAPPER > -{ -public: - -/** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using AbstractBase = singlePhaseFVMKernels::FaceBasedAssemblyKernelBase; - using DofNumberAccessor = AbstractBase::DofNumberAccessor; - using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; - using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; - using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; - - using AbstractBase::m_dt; - using AbstractBase::m_rankOffset; - using AbstractBase::m_dofNumber; - using AbstractBase::m_ghostRank; - using AbstractBase::m_gravCoef; - using AbstractBase::m_mob; - using AbstractBase::m_pres; - using AbstractBase::m_permeability; - using AbstractBase::m_dPerm_dPres; - - using AbstractBase::m_localMatrix; - using AbstractBase::m_localRhs; - - using Base = singlePhaseFVMKernels::DirichletFaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, FLUIDWRAPPER >; - using Base::numDof; - using Base::numEqn; - using Base::m_stencilWrapper; - using Base::m_seri; - using Base::m_sesri; - using Base::m_sei; - using Base::m_facePres; - using Base::m_faceGravCoef; - - using ThermalSinglePhaseFlowAccessors = - StencilAccessors< fields::flow::temperature, - fields::flow::dMobility_dTemperature >; - - using ThermalSinglePhaseFluidAccessors = - StencilMaterialAccessors< SingleFluidBase, - fields::singlefluid::dDensity_dTemperature, - fields::singlefluid::enthalpy, - fields::singlefluid::dEnthalpy_dPressure, - fields::singlefluid::dEnthalpy_dTemperature >; - - using ThermalConductivityAccessors = - StencilMaterialAccessors< SinglePhaseThermalConductivityBase, - fields::thermalconductivity::effectiveConductivity >; - - /** - * @brief Constructor for the kernel interface - * @param[in] rankOffset the offset of the MPI rank - * @param[in] faceManager the face manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] fluidWrapper reference to the fluid wrapper - * @param[in] dofNumberAccessor the degree of freedom number accessor - * @param[in] singlePhaseFlowAccessors the single phase flow accessor - * @param[in] thermalSinglePhaseFlowAccessors the thermal single phase flow accessor - * @param[in] singlePhaseFluidAccessors the single phase fluid accessor - * @param[in] thermalSinglePhaseFluidAccessors the thermal single phase fluid accessor - * @param[in] permeabilityAccessors the permeability accessor - * @param[in] thermalConductivityAccessors the thermal conductivity accessor - * @param[in] dt the time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - DirichletFaceBasedAssemblyKernel( globalIndex const rankOffset, - FaceManager const & faceManager, - BoundaryStencilWrapper const & stencilWrapper, - FLUIDWRAPPER const & fluidWrapper, - DofNumberAccessor const & dofNumberAccessor, - SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, - ThermalSinglePhaseFlowAccessors const & thermalSinglePhaseFlowAccessors, - SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, - ThermalSinglePhaseFluidAccessors const & thermalSinglePhaseFluidAccessors, - PermeabilityAccessors const & permeabilityAccessors, - ThermalConductivityAccessors const & thermalConductivityAccessors, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - - : Base( rankOffset, - faceManager, - stencilWrapper, - fluidWrapper, - dofNumberAccessor, - singlePhaseFlowAccessors, - singlePhaseFluidAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs ), - m_temp( thermalSinglePhaseFlowAccessors.get( fields::flow::temperature {} ) ), - m_faceTemp( faceManager.getField< fields::flow::faceTemperature >() ), - m_dMob_dTemp( thermalSinglePhaseFlowAccessors.get( fields::flow::dMobility_dTemperature {} ) ), - m_dDens_dTemp( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dDensity_dTemperature {} ) ), - m_enthalpy( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::enthalpy {} ) ), - m_dEnthalpy_dPres( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dEnthalpy_dPressure {} ) ), - m_dEnthalpy_dTemp( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dEnthalpy_dTemperature {} ) ), - m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ) - {} - - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - struct StackVariables : Base::StackVariables - { -public: - - /** - * @brief Constructor for the stack variables - * @param[in] size size of the stencil for this connection - * @param[in] numElems number of elements for this connection - */ - GEOS_HOST_DEVICE - StackVariables( localIndex const size, - localIndex numElems ): - Base::StackVariables( size, - numElems ) - {} - - using Base::StackVariables::localFlux; - using Base::StackVariables::localFluxJacobian; - using Base::StackVariables::dofColIndices; - using Base::StackVariables::transmissibility; - - /// Energy fluxes and derivatives wrt pressure and temperature - real64 energyFlux = 0.0; - real64 dEnergyFlux_dP = 0.0; - real64 dEnergyFlux_dT = 0.0; - }; - - /** - * @brief Compute the local Dirichlet face flux contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes - */ - GEOS_HOST_DEVICE - void computeFlux( localIndex const iconn, - StackVariables & stack ) const - { - Base::computeFlux( iconn, stack, [&] ( localIndex const er, - localIndex const esr, - localIndex const ei, - localIndex const kf, - real64 const & f, - real64 const & dF_dP, - real64 const & mobility_up, - real64 const & dMobility_dP_up ) - { - - // Compute the derivatives of the density wrt temperature - - real64 const dDens_dT = 0.5 * m_dDens_dTemp[er][esr][ei][0]; - - // Compute the derivatives of the phase potential difference wrt temperature - - real64 const dF_dT = -stack.transmissibility * dDens_dT * ( m_gravCoef[er][esr][ei] - m_faceGravCoef[kf] ); - - // Compute the (upwinded) energy flux - - real64 const flux = mobility_up * f; - real64 const enthalpy = m_enthalpy[er][esr][ei][0]; - stack.energyFlux += flux * enthalpy; - - // Compute the derivatives of the (upwinded) energy flux wrt pressure and temperature - - if( f >= 0 ) // the element is upstream - { - real64 const dFlux_dP = mobility_up * dF_dP + dMobility_dP_up * f; - real64 const dFlux_dT = mobility_up * dF_dT + m_dMob_dTemp[er][esr][ei] * f; - - stack.dEnergyFlux_dP += dFlux_dP * enthalpy + flux * m_dEnthalpy_dPres[er][esr][ei][0]; - stack.dEnergyFlux_dT += dFlux_dT * enthalpy + flux * m_dEnthalpy_dTemp[er][esr][ei][0]; - } - else - { - real64 const dFlux_dP = mobility_up * dF_dP; - real64 const dFlux_dT = mobility_up * dF_dT; - - stack.dEnergyFlux_dP += dFlux_dP * enthalpy; - stack.dEnergyFlux_dT += dFlux_dT * enthalpy; - } - - // Contribution of energy conduction through the solid phase - real64 thermalTrans = 0.0; - real64 dThermalTrans_dPerm[3]{}; // not used - m_stencilWrapper.computeWeights( iconn, - m_thermalConductivity, - thermalTrans, - dThermalTrans_dPerm ); - - stack.energyFlux += thermalTrans * ( m_temp[er][esr][ei] - m_faceTemp[kf] ); - stack.dEnergyFlux_dT += thermalTrans; - - // Add energyFlux and its derivatives to localFlux and localFluxJacobian - integer const localRowIndexEnergy = numEqn - 1; - stack.localFlux[localRowIndexEnergy] = m_dt * stack.energyFlux; - - stack.localFluxJacobian[localRowIndexEnergy][0] = m_dt * stack.dEnergyFlux_dP; - stack.localFluxJacobian[localRowIndexEnergy][numDof-1] = m_dt * stack.dEnergyFlux_dT; - } ); - - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void complete( localIndex const iconn, - StackVariables & stack ) const - { - Base::complete( iconn, stack, [&] ( localIndex const localRow ) - { - RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn - 1], stack.localFlux[numEqn-1] ); - - AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > - ( localRow + numEqn - 1, - stack.dofColIndices, - stack.localFluxJacobian[numEqn-1], - numDof ); - } ); - } - -protected: - - /// Views on temperature - ElementViewConst< arrayView1d< real64 const > > const m_temp; - - /// Views on face temperature - arrayView1d< real64 const > const m_faceTemp; - - /// Views on derivatives of fluid mobilities - ElementViewConst< arrayView1d< real64 const > > const m_dMob_dTemp; - - /// Views on derivatives of fluid densities - ElementViewConst< arrayView2d< real64 const > > const m_dDens_dTemp; - - /// Views on enthalpies - ElementViewConst< arrayView2d< real64 const > > const m_enthalpy; - ElementViewConst< arrayView2d< real64 const > > const m_dEnthalpy_dPres; - ElementViewConst< arrayView2d< real64 const > > const m_dEnthalpy_dTemp; - - /// View on thermal conductivity - ElementViewConst< arrayView3d< real64 const > > m_thermalConductivity; - -}; - - -/** - * @class DirichletFaceBasedAssemblyKernelFactory - */ -class DirichletFaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey string to get the element degrees of freedom numbers - * @param[in] solverName name of the solver (to name accessors) - * @param[in] faceManager reference to the face manager - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the boundary stencil wrapper - * @param[in] fluidBase the single phase fluid constitutive model - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY > - static void - createAndLaunch( globalIndex const rankOffset, - string const & dofKey, - string const & solverName, - FaceManager const & faceManager, - ElementRegionManager const & elemManager, - BoundaryStencilWrapper const & stencilWrapper, - SingleFluidBase & fluidBase, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - constitutiveUpdatePassThru( fluidBase, [&]( auto & fluid ) - { - using FluidType = TYPEOFREF( fluid ); - typename FluidType::KernelWrapper fluidWrapper = fluid.createKernelWrapper(); - - integer constexpr NUM_DOF = 2; - integer constexpr NUM_EQN = 2; - - using kernelType = DirichletFaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, typename FluidType::KernelWrapper >; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - typename kernelType::SinglePhaseFlowAccessors singlePhaseFlowAccessors( elemManager, solverName ); - typename kernelType::ThermalSinglePhaseFlowAccessors thermalSinglePhaseFlowAccessors( elemManager, solverName ); - typename kernelType::SinglePhaseFluidAccessors singlePhaseFluidAccessors( elemManager, solverName ); - typename kernelType::ThermalSinglePhaseFluidAccessors thermalSinglePhaseFluidAccessors( elemManager, solverName ); - typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); - typename kernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName ); - - kernelType kernel( rankOffset, - faceManager, - stencilWrapper, - fluidWrapper, - dofNumberAccessor, - singlePhaseFlowAccessors, - thermalSinglePhaseFlowAccessors, - singlePhaseFluidAccessors, - thermalSinglePhaseFluidAccessors, - permeabilityAccessors, - thermalConductivityAccessors, - dt, - localMatrix, - localRhs ); - - kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); - } ); - } - -}; - -} // namespace thermalSinglePhaseFVMKernels - -} // namespace geos - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALSINGLEPHASEFVMKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/docs/CompositionalMultiphaseFlow.rst b/src/coreComponents/physicsSolvers/fluidFlow/docs/CompositionalMultiphaseFlow.rst index 533b01385db..2197a50f5b1 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/docs/CompositionalMultiphaseFlow.rst +++ b/src/coreComponents/physicsSolvers/fluidFlow/docs/CompositionalMultiphaseFlow.rst @@ -182,7 +182,7 @@ Parameters The following attributes are supported: -.. include:: /coreComponents/schema/docs/CompositionalMultiphaseFVM.rst +.. include:: /docs/sphinx/datastructure/CompositionalMultiphaseFVM.rst .. _input_example: diff --git a/src/coreComponents/physicsSolvers/fluidFlow/docs/ProppantTransport.rst b/src/coreComponents/physicsSolvers/fluidFlow/docs/ProppantTransport.rst index 180e9050196..52f681bc6c2 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/docs/ProppantTransport.rst +++ b/src/coreComponents/physicsSolvers/fluidFlow/docs/ProppantTransport.rst @@ -207,7 +207,7 @@ Like any solver, time stepping is driven by events, see :ref:`EventManager`. The following attributes are supported: -.. include:: /coreComponents/schema/docs/ProppantTransport.rst +.. include:: /docs/sphinx/datastructure/ProppantTransport.rst In particular: diff --git a/src/coreComponents/physicsSolvers/fluidFlow/docs/SinglePhaseFlow.rst b/src/coreComponents/physicsSolvers/fluidFlow/docs/SinglePhaseFlow.rst index 9b87049a3c6..3840591994b 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/docs/SinglePhaseFlow.rst +++ b/src/coreComponents/physicsSolvers/fluidFlow/docs/SinglePhaseFlow.rst @@ -90,7 +90,7 @@ Like any solver, time stepping is driven by events, see :ref:`EventManager`. The following attributes are supported: -.. include:: /coreComponents/schema/docs/SinglePhaseFVM.rst +.. include:: /docs/sphinx/datastructure/SinglePhaseFVM.rst In particular: diff --git a/src/coreComponents/physicsSolvers/fluidFlow/HybridFVMHelperKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/HybridFVMHelperKernels.hpp similarity index 82% rename from src/coreComponents/physicsSolvers/fluidFlow/HybridFVMHelperKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/HybridFVMHelperKernels.hpp index 17a6a3765fb..6e4c9d69e23 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/HybridFVMHelperKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/HybridFVMHelperKernels.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -13,15 +14,13 @@ */ /** - * @file CompositionalMultiphaseHybridFVMHelperKernels.hpp + * @file HybridFVMHelperKernels.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_HYBRIDFVMUPWINDINGHELPERKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_HYBRIDFVMUPWINDINGHELPERKERNELS_HPP +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_HYBRIDFVMHELPERKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_HYBRIDFVMHELPERKERNELS_HPP #include "common/DataTypes.hpp" -#include "linearAlgebra/interfaces/InterfaceTypes.hpp" -#include "mesh/MeshLevel.hpp" namespace geos { @@ -90,4 +89,4 @@ struct CellConnectivity } // namespace geos -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASEHYBRIDFVMUPWINDINGHELPERKERNELS_HPP +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_HYBRIDFVMHELPERKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/MinPoreVolumeMaxPorosityKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/MinPoreVolumeMaxPorosityKernel.hpp new file mode 100644 index 00000000000..9add06e9a23 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/MinPoreVolumeMaxPorosityKernel.hpp @@ -0,0 +1,110 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file MinPoreVolumeMaxPorosityKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_MINPOREVOLUMEMAXPOROSITYKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_MINPOREVOLUMEMAXPOROSITYKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "mesh/ElementRegionManager.hpp" + +namespace geos +{ + +namespace flowSolverBaseKernels +{ + +/// Threshold for the min pore volume (below, a warning is issued) +static constexpr real64 poreVolumeThreshold = 1e-4; + +/** + * @struct MinPoreVolumeMaxPorosityKernel + * @brief Kernel to compute the min pore volume and the max porosity in a subRegion + */ +struct MinPoreVolumeMaxPorosityKernel +{ + + /* + * @brief Kernel computing the min pore volume and the max porosity + * @param[in] size the number of elements in the subRegion + * @param[in] ghostRank the ghost ranks + * @param[in] porosity the current element porosity + * @param[in] volume the current element volume + * @param[out] minPoreVolumeInSubRegion the min pore volume + * @param[out] maxPorosityInSubRegion the max porosity + * @param[out] numElemsBelowPoreVolumeThresholdInSubRegion the number of elements below the pore volume threshold + * @param[out] numElemsAbovePorosityThresholdInSubRegion the number of elements with a porosity above 1 + */ + inline static void + computeMinPoreVolumeMaxPorosity( localIndex const size, + arrayView1d< integer const > const & ghostRank, + arrayView2d< real64 const > const & porosity, + arrayView1d< real64 const > const & volume, + real64 & minPoreVolumeInSubRegion, + real64 & maxPorosityInSubRegion, + localIndex & numElemsBelowPoreVolumeThresholdInSubRegion, + localIndex & numElemsAbovePorosityThresholdInSubRegion ) + { + RAJA::ReduceMin< parallelDeviceReduce, real64 > minPoreVolume( LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > maxPorosity( -LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceSum< parallelDeviceReduce, localIndex > numElemsBelowPoreVolumeThreshold( 0.0 ); + RAJA::ReduceSum< parallelDeviceReduce, localIndex > numElemsAbovePorosityThreshold( 0.0 ); + + real64 const pvThreshold = poreVolumeThreshold; + + forAll< parallelDevicePolicy<> >( size, [ghostRank, + porosity, + volume, + pvThreshold, + minPoreVolume, + maxPorosity, + numElemsBelowPoreVolumeThreshold, + numElemsAbovePorosityThreshold] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( ghostRank[ei] >= 0 ) + { + return; + } + + real64 const poreVolume = porosity[ei][0] * volume[ei]; + if( poreVolume < pvThreshold ) + { + numElemsBelowPoreVolumeThreshold += 1; + } + if( porosity[ei][0] > 1 ) + { + numElemsAbovePorosityThreshold += 1; + } + + minPoreVolume.min( poreVolume ); + maxPorosity.max( porosity[ei][0] ); + } ); + + minPoreVolumeInSubRegion = minPoreVolume.get(); + maxPorosityInSubRegion = maxPorosity.get(); + numElemsBelowPoreVolumeThresholdInSubRegion = numElemsBelowPoreVolumeThreshold.get(); + numElemsAbovePorosityThresholdInSubRegion = numElemsAbovePorosityThreshold.get(); + } +}; + +} // namespace flowSolverBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_MINPOREVOLUMEMAXPOROSITYKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/StencilWeightsUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/StencilWeightsUpdateKernel.hpp new file mode 100644 index 00000000000..d8fd200dcb1 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/StencilWeightsUpdateKernel.hpp @@ -0,0 +1,79 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StencilWeightsUpdateKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_STENCILWEIGHTSUPDATEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_STENCILWEIGHTSUPDATEKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "mesh/ElementRegionManager.hpp" + +namespace geos +{ + +namespace flowSolverBaseKernels +{ + +template< typename VIEWTYPE > +using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + +/** + * @brief + * + * @tparam STENCILWRAPPER + */ +template< typename STENCILWRAPPER > +struct stencilWeightsUpdateKernel +{ + /** + * @brief + * + * @param stencilWrappper + * @param hydraulicAperture + */ + inline static void prepareStencilWeights( STENCILWRAPPER & stencilWrapper, + ElementViewConst< arrayView1d< real64 const > > const hydraulicAperture ) + { + forAll< parallelDevicePolicy<> >( stencilWrapper.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + stencilWrapper.removeHydraulicApertureContribution( iconn, hydraulicAperture ); + } ); + } + + /** + * @brief + * + * @param stencilWrappper + * @param hydraulicAperture + */ + inline static void updateStencilWeights( STENCILWRAPPER & stencilWrapper, + ElementViewConst< arrayView1d< real64 const > > const hydraulicAperture ) + { + forAll< parallelDevicePolicy<> >( stencilWrapper.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + stencilWrapper.addHydraulicApertureContribution( iconn, hydraulicAperture ); + } ); + } +}; + +} // namespace flowSolverBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_STENCILWEIGHTSUPDATEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp new file mode 100644 index 00000000000..c88ec507449 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp @@ -0,0 +1,510 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AccumulationKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_ACCUMULATIONKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_ACCUMULATIONKERNEL_HPP + +#include "codingUtilities/Utilities.hpp" +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/solid/CoupledSolidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "mesh/ElementSubRegionBase.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +static constexpr real64 minDensForDivision = 1e-10; + +enum class KernelFlags +{ + SimpleAccumulation = 1 << 0, // 1 + TotalMassEquation = 1 << 1, // 2 + /// Add more flags like that if needed: + // Flag3 = 1 << 2, // 4 + // Flag4 = 1 << 3, // 8 + // Flag5 = 1 << 4, // 16 + // Flag6 = 1 << 5, // 32 + // Flag7 = 1 << 6, // 64 + // Flag8 = 1 << 7 //128 +}; + +/******************************** AccumulationKernel ********************************/ + +/** + * @class AccumulationKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @brief Define the interface for the assembly kernel in charge of accumulation and volume balance + */ +template< integer NUM_COMP, integer NUM_DOF > +class AccumulationKernel +{ +public: + + /// Compile time value for the number of components + static constexpr integer numComp = NUM_COMP; + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = NUM_DOF; + + /// Compute time value for the number of equations + static constexpr integer numEqn = NUM_DOF; + + /** + * @brief Constructor + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + AccumulationKernel( localIndex const numPhases, + globalIndex const rankOffset, + string const dofKey, + ElementSubRegionBase const & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< KernelFlags > const kernelFlags ) + : m_numPhases( numPhases ), + m_rankOffset( rankOffset ), + m_dofNumber( subRegion.getReference< array1d< globalIndex > >( dofKey ) ), + m_elemGhostRank( subRegion.ghostRank() ), + m_volume( subRegion.getElementVolume() ), + m_porosity( solid.getPorosity() ), + m_dPoro_dPres( solid.getDporosity_dPressure() ), + m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ), + m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), + m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ), + m_phaseDens( fluid.phaseDensity() ), + m_dPhaseDens( fluid.dPhaseDensity() ), + m_phaseCompFrac( fluid.phaseCompFraction() ), + m_dPhaseCompFrac( fluid.dPhaseCompFraction() ), + m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ), + m_compAmount_n( subRegion.getField< fields::flow::compAmount_n >() ), + m_localMatrix( localMatrix ), + m_localRhs( localRhs ), + m_kernelFlags( kernelFlags ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables + { +public: + + // Pore volume information (used by both accumulation and volume balance) + + /// Pore volume at time n+1 + real64 poreVolume = 0.0; + + /// Derivative of pore volume with respect to pressure + real64 dPoreVolume_dPres = 0.0; + + // Residual information + + /// Index of the local row corresponding to this element + localIndex localRow = -1; + + /// Indices of the matrix rows/columns corresponding to the dofs in this element + globalIndex dofIndices[numDof]{}; + + /// C-array storage for the element local residual vector (all equations except volume balance) + real64 localResidual[numEqn]{}; + + /// C-array storage for the element local Jacobian matrix (all equations except volume balance, all dofs) + real64 localJacobian[numEqn][numDof]{}; + + }; + + /** + * @brief Getter for the ghost rank of an element + * @param[in] ei the element index + * @return the ghost rank of the element + */ + GEOS_HOST_DEVICE + integer elemGhostRank( localIndex const ei ) const + { return m_elemGhostRank( ei ); } + + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] ei the element index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const ei, + StackVariables & stack ) const + { + // initialize the pore volume + stack.poreVolume = m_volume[ei] * m_porosity[ei][0]; + stack.dPoreVolume_dPres = m_volume[ei] * m_dPoro_dPres[ei][0]; + + // set row index and degrees of freedom indices for this element + stack.localRow = m_dofNumber[ei] - m_rankOffset; + for( integer idof = 0; idof < numDof; ++idof ) + { + stack.dofIndices[idof] = m_dofNumber[ei] + idof; + } + } + + /** + * @brief Compute the local accumulation contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + * @param[in] phaseAmountKernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const ei, + StackVariables & stack, + FUNC && phaseAmountKernelOp = NoOpFunc{} ) const + { + if( m_kernelFlags.isSet( KernelFlags::SimpleAccumulation ) ) + { + // ic - index of component whose conservation equation is assembled + // (i.e. row number in local matrix) + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const compAmount = stack.poreVolume * m_compDens[ei][ic]; + real64 const compAmount_n = m_compAmount_n[ei][ic]; + + stack.localResidual[ic] += compAmount - compAmount_n; + + // Pavel: commented below is some experiment, needs to be re-tested + //real64 const compDens = (ic == 0 && m_compDens[ei][ic] < 1e-6) ? 1e-3 : m_compDens[ei][ic]; + real64 const dCompAmount_dP = stack.dPoreVolume_dPres * m_compDens[ei][ic]; + stack.localJacobian[ic][0] += dCompAmount_dP; + + real64 const dCompAmount_dC = stack.poreVolume; + stack.localJacobian[ic][ic + 1] += dCompAmount_dC; + } + } + else + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + // construct the slices for variables accessed multiple times + arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; + + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; + + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseDens = m_phaseDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > dPhaseDens = m_dPhaseDens[ei][0]; + + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 2 > phaseCompFrac = m_phaseCompFrac[ei][0]; + arraySlice3d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac = m_dPhaseCompFrac[ei][0]; + + // temporary work arrays + real64 dPhaseAmount_dC[numComp]{}; + real64 dPhaseCompFrac_dC[numComp]{}; + + // start with old time step values + for( integer ic = 0; ic < numComp; ++ic ) + { + stack.localResidual[ic] = -m_compAmount_n[ei][ic]; + } + + // sum contributions to component accumulation from each phase + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + real64 const phaseAmount = stack.poreVolume * phaseVolFrac[ip] * phaseDens[ip]; + + real64 const dPhaseAmount_dP = stack.dPoreVolume_dPres * phaseVolFrac[ip] * phaseDens[ip] + + stack.poreVolume * ( dPhaseVolFrac[ip][Deriv::dP] * phaseDens[ip] + + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP] ); + + // assemble density dependence + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], dPhaseAmount_dC, Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseAmount_dC[jc] = dPhaseAmount_dC[jc] * phaseVolFrac[ip] + + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC + jc]; + dPhaseAmount_dC[jc] *= stack.poreVolume; + } + + // ic - index of component whose conservation equation is assembled + // (i.e. row number in local matrix) + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const phaseCompAmount = phaseAmount * phaseCompFrac[ip][ic]; + + real64 const dPhaseCompAmount_dP = dPhaseAmount_dP * phaseCompFrac[ip][ic] + + phaseAmount * dPhaseCompFrac[ip][ic][Deriv::dP]; + + stack.localResidual[ic] += phaseCompAmount; + stack.localJacobian[ic][0] += dPhaseCompAmount_dP; + + // jc - index of component w.r.t. whose compositional var the derivative is being taken + // (i.e. col number in local matrix) + + // assemble phase composition dependence + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseCompFrac[ip][ic], dPhaseCompFrac_dC, Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + real64 const dPhaseCompAmount_dC = dPhaseCompFrac_dC[jc] * phaseAmount + + phaseCompFrac[ip][ic] * dPhaseAmount_dC[jc]; + + stack.localJacobian[ic][jc + 1] += dPhaseCompAmount_dC; + } + } + + // call the lambda in the phase loop to allow the reuse of the phase amounts and their derivatives + // possible use: assemble the derivatives wrt temperature, and the accumulation term of the energy equation for this phase + phaseAmountKernelOp( ip, phaseAmount, dPhaseAmount_dP, dPhaseAmount_dC ); + + } + } + } + + /** + * @brief Compute the local volume balance contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + * @param[in] phaseVolFractionSumKernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeVolumeBalance( localIndex const ei, + StackVariables & stack, + FUNC && phaseVolFractionSumKernelOp = NoOpFunc{} ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; + + real64 oneMinusPhaseVolFracSum = 1.0; + + // sum contributions to component accumulation from each phase + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + oneMinusPhaseVolFracSum -= phaseVolFrac[ip]; + stack.localJacobian[numComp][0] -= dPhaseVolFrac[ip][Deriv::dP]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.localJacobian[numComp][jc+1] -= dPhaseVolFrac[ip][Deriv::dC+jc]; + } + } + + // call the lambda in the phase loop to allow the reuse of the phase amounts and their derivatives + // possible use: assemble the derivatives wrt temperature, and use oneMinusPhaseVolFracSum if poreVolume depends on temperature + phaseVolFractionSumKernelOp( oneMinusPhaseVolFracSum ); + + // scale saturation-based volume balance by pore volume (for better scaling w.r.t. other equations) + stack.localResidual[numComp] = stack.poreVolume * oneMinusPhaseVolFracSum; + for( integer idof = 0; idof < numDof; ++idof ) + { + stack.localJacobian[numComp][idof] *= stack.poreVolume; + } + stack.localJacobian[numComp][0] += stack.dPoreVolume_dPres * oneMinusPhaseVolFracSum; + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void complete( localIndex const GEOS_UNUSED_PARAM( ei ), + StackVariables & stack ) const + { + using namespace compositionalMultiphaseUtilities; + + if( m_kernelFlags.isSet( KernelFlags::TotalMassEquation ) ) + { + // apply equation/variable change transformation to the component mass balance equations + real64 work[numDof]{}; + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numDof, stack.localJacobian, work ); + shiftElementsAheadByOneAndReplaceFirstElementWithSum( numComp, stack.localResidual ); + } + + // add contribution to residual and jacobian into: + // - the component mass balance equations (i = 0 to i = numComp-1) + // - the volume balance equations (i = numComp) + // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels + integer const numRows = numComp+1; + for( integer i = 0; i < numRows; ++i ) + { + m_localRhs[stack.localRow + i] += stack.localResidual[i]; + m_localMatrix.addToRow< serialAtomic >( stack.localRow + i, + stack.dofIndices, + stack.localJacobian[i], + numDof ); + } + } + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElems the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( kernelComponent.elemGhostRank( ei ) >= 0 ) + { + return; + } + + typename KERNEL_TYPE::StackVariables stack; + + kernelComponent.setup( ei, stack ); + kernelComponent.computeAccumulation( ei, stack ); + kernelComponent.computeVolumeBalance( ei, stack ); + kernelComponent.complete( ei, stack ); + } ); + } + +protected: + + /// Number of fluid phases + integer const m_numPhases; + + /// Offset for my MPI rank + globalIndex const m_rankOffset; + + /// View on the dof numbers + arrayView1d< globalIndex const > const m_dofNumber; + + /// View on the ghost ranks + arrayView1d< integer const > const m_elemGhostRank; + + /// View on the element volumes + arrayView1d< real64 const > const m_volume; + + /// Views on the porosity + arrayView2d< real64 const > const m_porosity; + arrayView2d< real64 const > const m_dPoro_dPres; + + /// Views on the derivatives of comp fractions wrt component density + arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dCompFrac_dCompDens; + + /// Views on the phase volume fractions + arrayView2d< real64 const, compflow::USD_PHASE > const m_phaseVolFrac; + arrayView3d< real64 const, compflow::USD_PHASE_DC > const m_dPhaseVolFrac; + + /// Views on the phase densities + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const m_phaseDens; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > const m_dPhaseDens; + + /// Views on the phase component fraction + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > const m_phaseCompFrac; + arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > const m_dPhaseCompFrac; + + // View on component densities + arrayView2d< real64 const, compflow::USD_COMP > m_compDens; + + // View on component amount (mass/moles) from previous time step + arrayView2d< real64 const, compflow::USD_COMP > m_compAmount_n; + + /// View on the local CRS matrix + CRSMatrixView< real64, globalIndex const > const m_localMatrix; + /// View on the local RHS + arrayView1d< real64 > const m_localRhs; + + BitFlags< KernelFlags > const m_kernelFlags; +}; + +/** + * @class AccumulationKernelFactory + */ +class AccumulationKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + integer const useTotalMassEquation, + integer const useSimpleAccumulation, + string const dofKey, + ElementSubRegionBase const & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + internal::kernelLaunchSelectorCompSwitch( numComps, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_DOF = NC()+1; + + BitFlags< KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( KernelFlags::TotalMassEquation ); + if( useSimpleAccumulation ) + kernelFlags.set( KernelFlags::SimpleAccumulation ); + + AccumulationKernel< NUM_COMP, NUM_DOF > kernel( numPhases, rankOffset, dofKey, subRegion, + fluid, solid, localMatrix, localRhs, kernelFlags ); + AccumulationKernel< NUM_COMP, NUM_DOF >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_ACCUMULATIONKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.cpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.cpp new file mode 100644 index 00000000000..9d107531c46 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.cpp @@ -0,0 +1,268 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AquiferBCKernel.cpp + */ + +#include "physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" +#include "finiteVolume/BoundaryStencil.hpp" + +namespace geos +{ +using namespace constitutive; + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/******************************** AquiferBCKernel ********************************/ + +template< integer NC > +GEOS_HOST_DEVICE +void +AquiferBCKernel:: + compute( integer const numPhases, + integer const ipWater, + bool const allowAllPhasesIntoAquifer, + real64 const aquiferVolFlux, + real64 const dAquiferVolFlux_dPres, + real64 const aquiferWaterPhaseDens, + arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, + arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseDens, + arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseDens, + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac, + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac, + arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > phaseCompFrac, + arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac, + arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens, + real64 const dt, + real64 (& localFlux)[NC], + real64 (& localFluxJacobian)[NC][NC+1] ) +{ + using Deriv = multifluid::DerivativeOffset; + + real64 dProp_dC[NC]{}; + real64 dPhaseFlux_dCompDens[NC]{}; + + if( aquiferVolFlux > 0 ) // aquifer is upstream + { + // in this case, we assume that: + // - only the water phase is present in the aquifer + // - the aquifer water phase composition is constant + + for( integer ic = 0; ic < NC; ++ic ) + { + real64 const phaseFlux = aquiferVolFlux * aquiferWaterPhaseDens; + localFlux[ic] -= dt * phaseFlux * aquiferWaterPhaseCompFrac[ic]; + localFluxJacobian[ic][0] -= dt * dAquiferVolFlux_dPres * aquiferWaterPhaseDens * aquiferWaterPhaseCompFrac[ic]; + } + } + else // reservoir is upstream + { + for( integer ip = 0; ip < numPhases; ++ip ) + { + + // Why two options below: + // - The aquifer model assumes single-phase water flow, so ideally, we should only allow water phase flow from the reservoir to the + // aquifer + // - But, if/when the CO2 plume reaches the reservoir cell connected to the aquifer and saturates it, the aquifer flux becomes zero + // if we don't let some CO2 go into the aquifer + + if( ip == ipWater || allowAllPhasesIntoAquifer ) + { + real64 const phaseDensVolFrac = phaseDens[ip] * phaseVolFrac[ip]; + real64 const phaseFlux = aquiferVolFlux * phaseDensVolFrac; + real64 const dPhaseFlux_dPres = dAquiferVolFlux_dPres * phaseDensVolFrac + + aquiferVolFlux * ( dPhaseDens[ip][Deriv::dP] * phaseVolFrac[ip] + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dP] ); + + applyChainRule( NC, dCompFrac_dCompDens, dPhaseDens[ip], dProp_dC, Deriv::dC ); + for( integer ic = 0; ic < NC; ++ic ) + { + dPhaseFlux_dCompDens[ic] = aquiferVolFlux * ( dProp_dC[ic] * phaseVolFrac[ip] + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC+ic] ); + } + + for( integer ic = 0; ic < NC; ++ic ) + { + localFlux[ic] -= dt * phaseFlux * phaseCompFrac[ip][ic]; + localFluxJacobian[ic][0] -= dt * ( dPhaseFlux_dPres * phaseCompFrac[ip][ic] + phaseFlux * dPhaseCompFrac[ip][ic][Deriv::dP] ); + + applyChainRule( NC, dCompFrac_dCompDens, dPhaseCompFrac[ip][ic], dProp_dC, Deriv::dC ); + for( integer jc = 0; jc < NC; ++jc ) + { + localFluxJacobian[ic][jc+1] -= dt * ( dPhaseFlux_dCompDens[jc] * phaseCompFrac[ip][ic] + phaseFlux * dProp_dC[jc] ); + } + } + } + } + } +} + +template< integer NC > +void +AquiferBCKernel:: + launch( integer const numPhases, + integer const ipWater, + bool const allowAllPhasesIntoAquifer, + integer const useTotalMassEquation, + BoundaryStencil const & stencil, + globalIndex const rankOffset, + ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, + AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, + real64 const aquiferWaterPhaseDens, + arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, + ElementViewConst< arrayView1d< integer const > > const & ghostRank, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & presOld, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseDens, + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + real64 const timeAtBeginningOfStep, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + + using namespace compositionalMultiphaseUtilities; + using Order = BoundaryStencil::Order; + + BoundaryStencil::IndexContainerViewConstType const & seri = stencil.getElementRegionIndices(); + BoundaryStencil::IndexContainerViewConstType const & sesri = stencil.getElementSubRegionIndices(); + BoundaryStencil::IndexContainerViewConstType const & sefi = stencil.getElementIndices(); + BoundaryStencil::WeightContainerViewConstType const & weight = stencil.getWeights(); + + forAll< parallelDevicePolicy<> >( stencil.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + constexpr integer NDOF = NC + 1; + + // working arrays + globalIndex dofColIndices[NDOF]{}; + real64 localFlux[NC]{}; + real64 localFluxJacobian[NC][NDOF]{}; + + localIndex const er = seri( iconn, Order::ELEM ); + localIndex const esr = sesri( iconn, Order::ELEM ); + localIndex const ei = sefi( iconn, Order::ELEM ); + real64 const areaFraction = weight( iconn, Order::ELEM ); + + // compute the aquifer influx rate using the pressure influence function and the aquifer props + real64 dAquiferVolFlux_dPres = 0.0; + real64 const aquiferVolFlux = aquiferBCWrapper.compute( timeAtBeginningOfStep, + dt, + pres[er][esr][ei], + presOld[er][esr][ei], + gravCoef[er][esr][ei], + areaFraction, + dAquiferVolFlux_dPres ); + + // compute the phase/component aquifer flux + AquiferBCKernel::compute< NC >( numPhases, + ipWater, + allowAllPhasesIntoAquifer, + aquiferVolFlux, + dAquiferVolFlux_dPres, + aquiferWaterPhaseDens, + aquiferWaterPhaseCompFrac, + phaseDens[er][esr][ei][0], + dPhaseDens[er][esr][ei][0], + phaseVolFrac[er][esr][ei], + dPhaseVolFrac[er][esr][ei], + phaseCompFrac[er][esr][ei][0], + dPhaseCompFrac[er][esr][ei][0], + dCompFrac_dCompDens[er][esr][ei], + dt, + localFlux, + localFluxJacobian ); + + // populate dof indices + globalIndex const offset = dofNumber[er][esr][ei]; + for( integer jdof = 0; jdof < NDOF; ++jdof ) + { + dofColIndices[jdof] = offset + jdof; + } + + if( useTotalMassEquation > 0 ) + { + // Apply equation/variable change transformation(s) + real64 work[NDOF]; + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NDOF, localFluxJacobian, work ); + shiftElementsAheadByOneAndReplaceFirstElementWithSum( NC, localFlux ); + } + + // Add to residual/jacobian + if( ghostRank[er][esr][ei] < 0 ) + { + globalIndex const globalRow = dofNumber[er][esr][ei]; + localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - rankOffset ); + GEOS_ASSERT_GE( localRow, 0 ); + GEOS_ASSERT_GT( localMatrix.numRows(), localRow + NC ); + + for( integer ic = 0; ic < NC; ++ic ) + { + RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[localRow + ic], localFlux[ic] ); + localMatrix.addToRow< parallelDeviceAtomic >( localRow + ic, + dofColIndices, + localFluxJacobian[ic], + NDOF ); + } + } + } ); +} + +#define INST_AquiferBCKernel( NC ) \ + template \ + void AquiferBCKernel:: \ + launch< NC >( integer const numPhases, \ + integer const ipWater, \ + bool const allowAllPhasesIntoAquifer, \ + integer const useTotalMassEquation, \ + BoundaryStencil const & stencil, \ + globalIndex const rankOffset, \ + ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, \ + AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, \ + real64 const aquiferWaterPhaseDens, \ + arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, \ + ElementViewConst< arrayView1d< integer const > > const & ghostRank, \ + ElementViewConst< arrayView1d< real64 const > > const & pres, \ + ElementViewConst< arrayView1d< real64 const > > const & dPres, \ + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, \ + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, \ + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, \ + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, \ + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, \ + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseDens, \ + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, \ + ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, \ + real64 const timeAtBeginningOfStep, \ + real64 const dt, \ + CRSMatrixView< real64, globalIndex const > const & localMatrix, \ + arrayView1d< real64 > const & localRhs ) + +INST_AquiferBCKernel( 1 ); +INST_AquiferBCKernel( 2 ); +INST_AquiferBCKernel( 3 ); +INST_AquiferBCKernel( 4 ); +INST_AquiferBCKernel( 5 ); + +#undef INST_AquiferBCKernel + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.hpp new file mode 100644 index 00000000000..fd97385586e --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.hpp @@ -0,0 +1,131 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AquiferBCKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_AQUIFERBCKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_AQUIFERBCKERNEL_HPP + +#include "codingUtilities/Utilities.hpp" +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "fieldSpecification/AquiferBoundaryCondition.hpp" +#include "finiteVolume/BoundaryStencil.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/******************************** AquiferBCKernel ********************************/ + +/** + * @brief Functions to assemble aquifer boundary condition contributions to residual and Jacobian + */ +struct AquiferBCKernel +{ + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using CompFlowAccessors = + StencilAccessors< fields::ghostRank, + fields::flow::pressure, + fields::flow::pressure_n, + fields::flow::gravityCoefficient, + fields::flow::phaseVolumeFraction, + fields::flow::dPhaseVolumeFraction, + fields::flow::dGlobalCompFraction_dGlobalCompDensity >; + + using MultiFluidAccessors = + StencilMaterialAccessors< constitutive::MultiFluidBase, + fields::multifluid::phaseDensity, + fields::multifluid::dPhaseDensity, + fields::multifluid::phaseCompFraction, + fields::multifluid::dPhaseCompFraction >; + + template< integer NC > + GEOS_HOST_DEVICE + inline + static void + compute( integer const numPhases, + integer const ipWater, + bool const allowAllPhasesIntoAquifer, + real64 const aquiferVolFlux, + real64 const dAquiferVolFlux_dPres, + real64 const aquiferWaterPhaseDens, + arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseDens, + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > dPhaseDens, + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac, + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac, + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 2 > phaseCompFrac, + arraySlice3d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac, + arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens, + real64 const dt, + real64 ( &localFlux )[NC], + real64 ( &localFluxJacobian )[NC][NC+1] ); + + template< integer NC > + static void + launch( integer const numPhases, + integer const ipWater, + bool const allowAllPhasesIntoAquifer, + integer const useTotalMassEquation, + BoundaryStencil const & stencil, + globalIndex const rankOffset, + ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, + AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, + real64 const aquiferWaterPhaseDens, + arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, + ElementViewConst< arrayView1d< integer const > > const & ghostRank, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & pres_n, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + real64 const timeAtBeginningOfStep, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); + +}; + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_AQUIFERBCKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/C1PPUPhaseFlux.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/C1PPUPhaseFlux.hpp new file mode 100644 index 00000000000..6b31d7b9165 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/C1PPUPhaseFlux.hpp @@ -0,0 +1,229 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file C1PPUPhaseFlux.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_C1PPUPHASEFLUX_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_C1PPUPHASEFLUX_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "constitutive/capillaryPressure/layouts.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PotGrad.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PhaseComponentFlux.hpp" + + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernelUtilities +{ + +// TODO make input parameter +static constexpr real64 epsC1PPU = 5000; + +template< typename VIEWTYPE > +using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + +using Deriv = constitutive::multifluid::DerivativeOffset; + +struct C1PPUPhaseFlux +{ + /** + * @brief Form the PhasePotentialUpwind from pressure gradient and gravitational head + * @tparam numComp number of components + * @tparam numFluxSupportPoints number of flux support points + * @param numPhase number of phases + * @param ip phase index + * @param hasCapPressure flag indicating if there is capillary pressure + * @param seri arraySlice of the stencil-implied element region index + * @param sesri arraySlice of the stencil-implied element subregion index + * @param sei arraySlice of the stencil-implied element index + * @param trans transmissibility at the connection + * @param dTrans_dPres derivative of transmissibility wrt pressure + * @param pres pressure + * @param gravCoef gravitational coefficient + * @param phaseMob phase mobility + * @param dPhaseMob derivative of phase mobility wrt pressure, temperature, comp density + * @param dPhaseVolFrac derivative of phase volume fraction wrt pressure, temperature, comp density + * @param dCompFrac_dCompDens derivative of component fraction wrt component density + * @param phaseMassDens phase mass density + * @param dPhaseMassDens derivative of phase mass density wrt pressure, temperature, comp fraction + * @param phaseCapPressure phase capillary pressure + * @param dPhaseCapPressure_dPhaseVolFrac derivative of phase capillary pressure wrt phase volume fraction + * @param k_up uptream index for this phase + * @param potGrad potential gradient for this phase + * @param phaseFlux phase flux + * @param dPhaseFlux_dP derivative of phase flux wrt pressure + * @param dPhaseFlux_dC derivative of phase flux wrt comp density + */ + template< integer numComp, integer numFluxSupportPoints > + GEOS_HOST_DEVICE + static void + compute( integer const numPhase, + integer const ip, + integer const hasCapPressure, + integer const useNewGravity, + localIndex const ( &seri )[numFluxSupportPoints], + localIndex const ( &sesri )[numFluxSupportPoints], + localIndex const ( &sei )[numFluxSupportPoints], + real64 const ( &trans )[2], + real64 const ( &dTrans_dPres )[2], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + localIndex & k_up, + real64 & potGrad, + real64 ( &phaseFlux ), + real64 ( & dPhaseFlux_dP )[numFluxSupportPoints], + real64 ( & dPhaseFlux_dC )[numFluxSupportPoints][numComp], + real64 ( & compFlux )[numComp], + real64 ( & dCompFlux_dP )[numFluxSupportPoints][numComp], + real64 ( & dCompFlux_dC )[numFluxSupportPoints][numComp][numComp] ) + { + real64 dPresGrad_dP[numFluxSupportPoints]{}; + real64 dPresGrad_dC[numFluxSupportPoints][numComp]{}; + real64 dGravHead_dP[numFluxSupportPoints]{}; + real64 dGravHead_dC[numFluxSupportPoints][numComp]{}; + PotGrad::compute< numComp, numFluxSupportPoints >( numPhase, ip, hasCapPressure, useNewGravity, seri, sesri, sei, trans, dTrans_dPres, pres, + gravCoef, phaseVolFrac, dPhaseVolFrac, dCompFrac_dCompDens, phaseMassDens, dPhaseMassDens, + phaseCapPressure, dPhaseCapPressure_dPhaseVolFrac, potGrad, dPresGrad_dP, + dPresGrad_dC, dGravHead_dP, dGravHead_dC ); + + // gravity head + real64 gravHead = 0.0; + for( integer i = 0; i < numFluxSupportPoints; i++ ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + real64 const gravD = trans[i] * gravCoef[er][esr][ei]; + + gravHead += gravD; + } + + // *** upwinding *** + + // phase flux and derivatives + + // assuming TPFA in the code below + + real64 Ttrans = fabs( trans[0] ); + potGrad = potGrad / Ttrans; + + real64 const mobility_i = phaseMob[seri[0]][sesri[0]][sei[0]][ip]; + real64 const mobility_j = phaseMob[seri[1]][sesri[1]][sei[1]][ip]; + + // compute phase flux, see Eqs. (66) and (69) from the reference above + real64 smoEps = epsC1PPU; + if( fabs( gravHead ) <= 1e-20 ) + smoEps = 1000; + real64 const tmpSqrt = sqrt( potGrad * potGrad + smoEps * smoEps ); + real64 const smoMax = 0.5 * (-potGrad + tmpSqrt); + + phaseFlux = Ttrans * ( potGrad * mobility_i - smoMax * (mobility_j - mobility_i) ); + + // derivativess + + // first part, mobility derivative + + // dP + { + real64 const dMob_dP = dPhaseMob[seri[0]][sesri[0]][sei[0]][ip][Deriv::dP]; + dPhaseFlux_dP[0] += Ttrans * potGrad * dMob_dP; + } + + // dC + { + arraySlice1d< real64 const, compflow::USD_PHASE_DC - 2 > + dPhaseMobSub = dPhaseMob[seri[0]][sesri[0]][sei[0]][ip]; + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[0][jc] += Ttrans * potGrad * dPhaseMobSub[Deriv::dC + jc]; + } + } + + real64 const tmpInv = 1.0 / tmpSqrt; + real64 const dSmoMax_x = 0.5 * (1.0 - potGrad * tmpInv); + + // pressure gradient and mobility difference depend on all points in the stencil + real64 const dMobDiff_sign[numFluxSupportPoints] = {-1.0, 1.0}; + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + // dP + + real64 const dPotGrad_dP = dPresGrad_dP[ke] - dGravHead_dP[ke]; + + // first part + dPhaseFlux_dP[ke] += dPotGrad_dP * mobility_i; + + // second part + real64 const dSmoMax_dP = -dPotGrad_dP * dSmoMax_x; + dPhaseFlux_dP[ke] += -dSmoMax_dP * (mobility_j - mobility_i); + + real64 const dMob_dP = dPhaseMob[seri[ke]][sesri[ke]][sei[ke]][ip][Deriv::dP]; + dPhaseFlux_dP[ke] += -Ttrans * smoMax * dMobDiff_sign[ke] * dMob_dP; + + // dC + + arraySlice1d< real64 const, compflow::USD_PHASE_DC - 2 > + dPhaseMobSub = dPhaseMob[seri[ke]][sesri[ke]][sei[ke]][ip]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + real64 const dPotGrad_dC = dPresGrad_dC[ke][jc] - dGravHead_dC[ke][jc]; + + // first part + dPhaseFlux_dC[ke][jc] += dPotGrad_dC * mobility_i; + + // second part + real64 const dSmoMax_dC = -dPotGrad_dC * dSmoMax_x; + dPhaseFlux_dC[ke][jc] += -dSmoMax_dC * (mobility_j - mobility_i); + dPhaseFlux_dC[ke][jc] += -Ttrans * smoMax * dMobDiff_sign[ke] * dPhaseMobSub[Deriv::dC + jc]; + } + } + + potGrad = potGrad * Ttrans; + + // choose upstream cell for composition upwinding + k_up = (phaseFlux >= 0) ? 0 : 1; + + //distribute on phaseComponentFlux here + PhaseComponentFlux::compute( ip, k_up, seri, sesri, sei, phaseCompFrac, dPhaseCompFrac, dCompFrac_dCompDens, phaseFlux + , dPhaseFlux_dP, dPhaseFlux_dC, compFlux, dCompFlux_dP, dCompFlux_dC ); + } +}; + +} // namespace isothermalCompositionalMultiPhaseFVMKernelUtilities + +} // namespace geos + + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_C1PPUPHASEFLUX_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.cpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.cpp new file mode 100644 index 00000000000..0b34792763f --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.cpp @@ -0,0 +1,458 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CFLKernel.cpp + */ + +#include "physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.hpp" +#include "finiteVolume/CellElementStencilTPFA.hpp" +#include "finiteVolume/SurfaceElementStencil.hpp" +#include "finiteVolume/EmbeddedSurfaceToCellStencil.hpp" +#include "finiteVolume/FaceElementToCellStencil.hpp" +#include "CFLKernel.hpp" + +namespace geos +{ +using namespace constitutive; + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/******************************** CFLFluxKernel ********************************/ + +template< integer NC > +GEOS_HOST_DEVICE +inline +void +CFLFluxKernel:: + compute( integer const numPhases, + integer const useNewGravity, + localIndex const stencilSize, + real64 const dt, + arraySlice1d< localIndex const > const seri, + arraySlice1d< localIndex const > const sesri, + arraySlice1d< localIndex const > const sei, + real64 const (&transmissibility)[2], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const & phaseRelPerm, + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseVisc, + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementView< arrayView2d< real64, compflow::USD_PHASE > > const & phaseOutflux, + ElementView< arrayView2d< real64, compflow::USD_COMP > > const & compOutflux ) +{ + // loop over phases, compute and upwind phase flux and sum contributions to each component's flux + for( integer ip = 0; ip < numPhases; ++ip ) + { + + // clear working arrays + real64 densMean{}; + + // create local work arrays + real64 presGrad{}; + real64 gravHead{}; + + // calculate quantities on primary connected cells + calculateMeanDensity( useNewGravity, ip, stencilSize, seri, sesri, sei, phaseVolFrac, phaseMassDens, densMean ); + + //***** calculation of phase volumetric flux ***** + + // compute potential difference MPFA-style + for( localIndex i = 0; i < stencilSize; ++i ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + presGrad += transmissibility[i] * pres[er][esr][ei]; + gravHead += transmissibility[i] * densMean * gravCoef[er][esr][ei]; + } + + // *** upwinding *** + + // compute phase potential gradient + real64 const potGrad = presGrad - gravHead; + + // choose upstream cell + localIndex const k_up = (potGrad >= 0) ? 0 : 1; + + localIndex const er_up = seri[k_up]; + localIndex const esr_up = sesri[k_up]; + localIndex const ei_up = sei[k_up]; + + // compute the phase flux only if the phase is present + bool const phaseExists = (phaseVolFrac[er_up][esr_up][ei_up][ip] > 0); + if( !phaseExists ) + { + continue; + } + + real64 const mobility = phaseRelPerm[er_up][esr_up][ei_up][0][ip] / phaseVisc[er_up][esr_up][ei_up][0][ip]; + + // increment the phase (volumetric) outflux of the upstream cell + real64 const absPhaseFlux = LvArray::math::abs( dt * mobility * potGrad ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &phaseOutflux[er_up][esr_up][ei_up][ip], absPhaseFlux ); + + // increment the component (mass/molar) outflux of the upstream cell + for( integer ic = 0; ic < NC; ++ic ) + { + real64 const absCompFlux = phaseCompFrac[er_up][esr_up][ei_up][0][ip][ic] + * phaseDens[er_up][esr_up][ei_up][0][ip] + * absPhaseFlux; + RAJA::atomicAdd( parallelDeviceAtomic{}, &compOutflux[er_up][esr_up][ei_up][ic], absCompFlux ); + } + } +} + +GEOS_HOST_DEVICE +inline +void +CFLFluxKernel::calculateMeanDensity( integer const useNewGravity, integer const ip, localIndex const stencilSize, + arraySlice1d< localIndex const > const seri, + arraySlice1d< localIndex const > const sesri, + arraySlice1d< localIndex const > const sei, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseMassDens, + real64 & densMean ) +{ + integer denom = 0; + for( localIndex i = 0; i < stencilSize; ++i ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + bool const phaseExists = (phaseVolFrac[er][esr][ei][ip] > 0); + if( useNewGravity && !phaseExists ) + { + continue; + } + + // average density across the face + densMean += phaseMassDens[er][esr][ei][0][ip]; + denom++; + } + if( denom > 1 ) + { + densMean /= denom; + } +} +template< integer NC, typename STENCILWRAPPER_TYPE > +void CFLFluxKernel:: + launch( integer const numPhases, + integer const useNewGravity, + real64 const dt, + STENCILWRAPPER_TYPE const & stencilWrapper, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const > > const & permeability, + ElementViewConst< arrayView3d< real64 const > > const & dPerm_dPres, + ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const & phaseRelPerm, + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseVisc, + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementView< arrayView2d< real64, compflow::USD_PHASE > > const & phaseOutflux, + ElementView< arrayView2d< real64, compflow::USD_COMP > > const & compOutflux ) +{ + typename STENCILWRAPPER_TYPE::IndexContainerViewConstType const & seri = stencilWrapper.getElementRegionIndices(); + typename STENCILWRAPPER_TYPE::IndexContainerViewConstType const & sesri = stencilWrapper.getElementSubRegionIndices(); + typename STENCILWRAPPER_TYPE::IndexContainerViewConstType const & sei = stencilWrapper.getElementIndices(); + + forAll< parallelDevicePolicy<> >( stencilWrapper.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + // compute transmissibility + real64 transmissibility[STENCILWRAPPER_TYPE::maxNumConnections][2]; + real64 dTrans_dPres[STENCILWRAPPER_TYPE::maxNumConnections][2]; + + stencilWrapper.computeWeights( iconn, + permeability, + dPerm_dPres, + transmissibility, + dTrans_dPres ); + + CFLFluxKernel::compute< NC >( numPhases, + useNewGravity, + sei[iconn].size(), + dt, + seri[iconn], + sesri[iconn], + sei[iconn], + transmissibility[0], + pres, + gravCoef, + phaseVolFrac, + phaseRelPerm, + phaseVisc, + phaseDens, + phaseMassDens, + phaseCompFrac, + phaseOutflux, + compOutflux ); + } ); +} + +#define INST_CFLFluxKernel( NC, STENCILWRAPPER_TYPE ) \ + template \ + void CFLFluxKernel:: \ + launch< NC, STENCILWRAPPER_TYPE >( integer const numPhases, \ + integer const useNewGravity, \ + real64 const dt, \ + STENCILWRAPPER_TYPE const & stencil, \ + ElementViewConst< arrayView1d< real64 const > > const & pres, \ + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, \ + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, \ + ElementViewConst< arrayView3d< real64 const > > const & permeability, \ + ElementViewConst< arrayView3d< real64 const > > const & dPerm_dPres, \ + ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const & phaseRelPerm, \ + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseVisc, \ + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, \ + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseMassDens, \ + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, \ + ElementView< arrayView2d< real64, compflow::USD_PHASE > > const & phaseOutflux, \ + ElementView< arrayView2d< real64, compflow::USD_COMP > > const & compOutflux ) + +INST_CFLFluxKernel( 1, CellElementStencilTPFAWrapper ); +INST_CFLFluxKernel( 2, CellElementStencilTPFAWrapper ); +INST_CFLFluxKernel( 3, CellElementStencilTPFAWrapper ); +INST_CFLFluxKernel( 4, CellElementStencilTPFAWrapper ); +INST_CFLFluxKernel( 5, CellElementStencilTPFAWrapper ); + +INST_CFLFluxKernel( 1, SurfaceElementStencilWrapper ); +INST_CFLFluxKernel( 2, SurfaceElementStencilWrapper ); +INST_CFLFluxKernel( 3, SurfaceElementStencilWrapper ); +INST_CFLFluxKernel( 4, SurfaceElementStencilWrapper ); +INST_CFLFluxKernel( 5, SurfaceElementStencilWrapper ); + +INST_CFLFluxKernel( 1, EmbeddedSurfaceToCellStencilWrapper ); +INST_CFLFluxKernel( 2, EmbeddedSurfaceToCellStencilWrapper ); +INST_CFLFluxKernel( 3, EmbeddedSurfaceToCellStencilWrapper ); +INST_CFLFluxKernel( 4, EmbeddedSurfaceToCellStencilWrapper ); +INST_CFLFluxKernel( 5, EmbeddedSurfaceToCellStencilWrapper ); + +INST_CFLFluxKernel( 1, FaceElementToCellStencilWrapper ); +INST_CFLFluxKernel( 2, FaceElementToCellStencilWrapper ); +INST_CFLFluxKernel( 3, FaceElementToCellStencilWrapper ); +INST_CFLFluxKernel( 4, FaceElementToCellStencilWrapper ); +INST_CFLFluxKernel( 5, FaceElementToCellStencilWrapper ); + +#undef INST_CFLFluxKernel + +/******************************** CFLKernel ********************************/ + +template< integer NP > +GEOS_HOST_DEVICE +void +CFLKernel:: + computePhaseCFL( real64 const poreVol, + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac, + arraySlice1d< real64 const, relperm::USD_RELPERM - 2 > phaseRelPerm, + arraySlice2d< real64 const, relperm::USD_RELPERM_DS - 2 > dPhaseRelPerm_dPhaseVolFrac, + arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseVisc, + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseOutflux, + real64 & phaseCFLNumber ) +{ + // first, check which phases are mobile in the cell + real64 mob[NP]{}; + localIndex mobilePhases[NP]{}; + localIndex numMobilePhases = 0; + for( localIndex ip = 0; ip < NP; ++ip ) + { + if( phaseVolFrac[ip] > 0 ) + { + mob[ip] = phaseRelPerm[ip] / phaseVisc[ip]; + if( mob[ip] > minPhaseMobility ) + { + mobilePhases[numMobilePhases] = ip; + numMobilePhases++; + } + } + } + + // then, depending on the regime, apply the appropriate CFL formula + phaseCFLNumber = 0; + + // single-phase flow regime + if( numMobilePhases == 1 ) + { + phaseCFLNumber = phaseOutflux[mobilePhases[0]] / poreVol; + } + // two-phase flow regime + else if( numMobilePhases == 2 ) + { + // from Hui Cao's PhD thesis + localIndex const ip0 = mobilePhases[0]; + localIndex const ip1 = mobilePhases[1]; + real64 const dMob_dVolFrac[2] = { dPhaseRelPerm_dPhaseVolFrac[ip0][ip0] / phaseVisc[ip0], + -dPhaseRelPerm_dPhaseVolFrac[ip1][ip1] / phaseVisc[ip1] }; // using S0 = 1 - S1 + real64 const denom = 1. / ( poreVol * ( mob[ip0] + mob[ip1] ) ); + real64 const coef0 = denom * mob[ip1] / mob[ip0] * dMob_dVolFrac[ip0]; + real64 const coef1 = -denom * mob[ip0] / mob[ip1] * dMob_dVolFrac[ip1]; + + phaseCFLNumber = LvArray::math::abs( coef0*phaseOutflux[ip0] + coef1*phaseOutflux[ip1] ); + } + // three-phase flow regime + else if( numMobilePhases == 3 ) + { + // from Keith Coats, IMPES stability: Selection of stable timesteps (2003) + real64 totalMob = 0.0; + for( integer ip = 0; ip < numMobilePhases; ++ip ) + { + totalMob += mob[ip]; + } + + real64 f[2][2]{}; + for( integer i = 0; i < 2; ++i ) + { + for( integer j = 0; j < 2; ++j ) + { + f[i][j] = ( i == j )*totalMob - mob[i]; + f[i][j] /= (totalMob * mob[j]); + real64 sum = 0; + for( integer k = 0; k < 3; ++k ) + { + sum += dPhaseRelPerm_dPhaseVolFrac[k][j] / phaseVisc[k] + * phaseOutflux[j]; + } + f[i][j] *= sum; + } + } + phaseCFLNumber = f[0][0] + f[1][1]; + phaseCFLNumber += sqrt( phaseCFLNumber*phaseCFLNumber - 4 * ( f[0][0]*f[1][1] - f[1][0]*f[0][1] ) ); + phaseCFLNumber = 0.5 * LvArray::math::abs( phaseCFLNumber ) / poreVol; + } +} + + +template< integer NC > +GEOS_HOST_DEVICE +void +CFLKernel:: + computeCompCFL( real64 const poreVol, + arraySlice1d< real64 const, compflow::USD_COMP - 1 > compDens, + arraySlice1d< real64 const, compflow::USD_COMP - 1 > compFrac, + arraySlice1d< real64 const, compflow::USD_COMP - 1 > compOutflux, + real64 & compCFLNumber ) +{ + + + compCFLNumber = 0.0; + for( integer ic = 0; ic < NC; ++ic ) + { + if( compFrac[ic] > minComponentFraction ) + { + real64 const compMoles = compDens[ic] * poreVol; + real64 const CFL = compOutflux[ic] / compMoles; + if( CFL > compCFLNumber ) + { + compCFLNumber = CFL; + } + } + } +} + +template< integer NC, integer NP > +void +CFLKernel:: + launch( localIndex const size, + arrayView1d< real64 const > const & volume, + arrayView2d< real64 const > const & porosity, + arrayView2d< real64 const, compflow::USD_COMP > const & compDens, + arrayView2d< real64 const, compflow::USD_COMP > const & compFrac, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac, + arrayView3d< real64 const, relperm::USD_RELPERM > const & phaseRelPerm, + arrayView4d< real64 const, relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, + arrayView3d< real64 const, multifluid::USD_PHASE > const & phaseVisc, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseOutflux, + arrayView2d< real64 const, compflow::USD_COMP > const & compOutflux, + arrayView1d< real64 > const & phaseCFLNumber, + arrayView1d< real64 > const & compCFLNumber, + real64 & maxPhaseCFLNumber, + real64 & maxCompCFLNumber ) +{ + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionPhaseCFLNumber( 0.0 ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionCompCFLNumber( 0.0 ); + + forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + real64 const poreVol = volume[ei] * porosity[ei][0]; + + // phase CFL number + real64 cellPhaseCFLNumber = 0.0; + computePhaseCFL< NP >( poreVol, + phaseVolFrac[ei], + phaseRelPerm[ei][0], + dPhaseRelPerm_dPhaseVolFrac[ei][0], + phaseVisc[ei][0], + phaseOutflux[ei], + cellPhaseCFLNumber ); + subRegionPhaseCFLNumber.max( cellPhaseCFLNumber ); + phaseCFLNumber[ei] = cellPhaseCFLNumber; + + // component CFL number + real64 cellCompCFLNumber = 0.0; + computeCompCFL< NC >( poreVol, + compDens[ei], + compFrac[ei], + compOutflux[ei], + cellCompCFLNumber ); + subRegionCompCFLNumber.max( cellCompCFLNumber ); + compCFLNumber[ei] = cellCompCFLNumber; + } ); + + maxPhaseCFLNumber = subRegionPhaseCFLNumber.get(); + maxCompCFLNumber = subRegionCompCFLNumber.get(); +} + +#define INST_CFLKernel( NC, NP ) \ + template \ + void CFLKernel:: \ + launch< NC, NP >( localIndex const size, \ + arrayView1d< real64 const > const & volume, \ + arrayView2d< real64 const > const & porosity, \ + arrayView2d< real64 const, compflow::USD_COMP > const & compDens, \ + arrayView2d< real64 const, compflow::USD_COMP > const & compFrac, \ + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac, \ + arrayView3d< real64 const, relperm::USD_RELPERM > const & phaseRelPerm, \ + arrayView4d< real64 const, relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, \ + arrayView3d< real64 const, multifluid::USD_PHASE > const & phaseVisc, \ + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseOutflux, \ + arrayView2d< real64 const, compflow::USD_COMP > const & compOutflux, \ + arrayView1d< real64 > const & phaseCFLNumber, \ + arrayView1d< real64 > const & compCFLNumber, \ + real64 & maxPhaseCFLNumber, \ + real64 & maxCompCFLNumber ) +INST_CFLKernel( 1, 2 ); +INST_CFLKernel( 2, 2 ); +INST_CFLKernel( 3, 2 ); +INST_CFLKernel( 4, 2 ); +INST_CFLKernel( 5, 2 ); + +INST_CFLKernel( 1, 3 ); +INST_CFLKernel( 2, 3 ); +INST_CFLKernel( 3, 3 ); +INST_CFLKernel( 4, 3 ); +INST_CFLKernel( 5, 3 ); + +#undef INST_CFLKernel + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.hpp new file mode 100644 index 00000000000..a13c9170bc6 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.hpp @@ -0,0 +1,194 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CFLKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_CFLKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_CFLKERNEL_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "constitutive/permeability/PermeabilityBase.hpp" +#include "constitutive/permeability/PermeabilityFields.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityFields.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/******************************** CFLFluxKernel ********************************/ + +/** + * @brief Functions to compute the (outflux) total volumetric flux needed in the calculation of CFL numbers + */ +struct CFLFluxKernel +{ + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + template< typename VIEWTYPE > + using ElementView = ElementRegionManager::ElementView< VIEWTYPE >; + + using CompFlowAccessors = + StencilAccessors< fields::flow::pressure, + fields::flow::gravityCoefficient, + fields::flow::phaseVolumeFraction, + fields::flow::phaseOutflux, + fields::flow::componentOutflux >; + + using MultiFluidAccessors = + StencilMaterialAccessors< constitutive::MultiFluidBase, + fields::multifluid::phaseViscosity, + fields::multifluid::phaseDensity, + fields::multifluid::phaseMassDensity, + fields::multifluid::phaseCompFraction >; + + using PermeabilityAccessors = + StencilMaterialAccessors< constitutive::PermeabilityBase, + fields::permeability::permeability, + fields::permeability::dPerm_dPressure >; + + + using RelPermAccessors = + StencilMaterialAccessors< constitutive::RelativePermeabilityBase, fields::relperm::phaseRelPerm >; + + template< integer NC > + GEOS_HOST_DEVICE inline static void + compute( integer const numPhases, + integer const useNewGravity, + localIndex const stencilSize, + real64 const dt, + arraySlice1d< localIndex const > const seri, + arraySlice1d< localIndex const > const sesri, + arraySlice1d< localIndex const > const sei, + real64 const (&transmissibility)[2], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > > const & phaseRelPerm, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseVisc, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementView< arrayView2d< real64, compflow::USD_PHASE > > const & phaseOutflux, + ElementView< arrayView2d< real64, compflow::USD_COMP > > const & compOutflux ); + + GEOS_HOST_DEVICE inline static void + calculateMeanDensity( integer const useNewGravity, integer const ip, localIndex const stencilSize, + arraySlice1d< localIndex const > const seri, + arraySlice1d< localIndex const > const sesri, + arraySlice1d< localIndex const > const sei, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + real64 & densMean ); + + template< integer NC, typename STENCILWRAPPER_TYPE > + static void + launch( integer const numPhases, + integer const useNewGravity, + real64 const dt, + STENCILWRAPPER_TYPE const & stencil, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const > > const & permeability, + ElementViewConst< arrayView3d< real64 const > > const & dPerm_dPres, + ElementViewConst< arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > > const & phaseRelPerm, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseVisc, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementView< arrayView2d< real64, compflow::USD_PHASE > > const & phaseOutflux, + ElementView< arrayView2d< real64, compflow::USD_COMP > > const & compOutflux ); +}; + +/******************************** CFLKernel ********************************/ + +/** + * @brief Functions to compute the CFL number using the phase volumetric outflux and the component mass outflux in each cell + */ +struct CFLKernel +{ + + static constexpr real64 minPhaseMobility = 1e-12; + static constexpr real64 minComponentFraction = 1e-12; + + template< integer NP > + GEOS_HOST_DEVICE + inline + static void + computePhaseCFL( real64 const poreVol, + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac, + arraySlice1d< real64 const, constitutive::relperm::USD_RELPERM - 2 > phaseRelPerm, + arraySlice2d< real64 const, constitutive::relperm::USD_RELPERM_DS - 2 > dPhaseRelPerm_dPhaseVolFrac, + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseVisc, + arraySlice1d< real64 const, compflow::USD_PHASE- 1 > phaseOutflux, + real64 & phaseCFLNumber ); + + template< integer NC > + GEOS_HOST_DEVICE + inline + static void + computeCompCFL( real64 const poreVol, + arraySlice1d< real64 const, compflow::USD_COMP - 1 > compDens, + arraySlice1d< real64 const, compflow::USD_COMP - 1 > compFrac, + arraySlice1d< real64 const, compflow::USD_COMP - 1 > compOutflux, + real64 & compCFLNumber ); + + template< integer NC, integer NP > + static void + launch( localIndex const size, + arrayView1d< real64 const > const & volume, + arrayView2d< real64 const > const & porosity, + arrayView2d< real64 const, compflow::USD_COMP > const & compDens, + arrayView2d< real64 const, compflow::USD_COMP > const & compFrac, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac, + arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > const & phaseRelPerm, + arrayView4d< real64 const, constitutive::relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseVisc, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseOutflux, + arrayView2d< real64 const, compflow::USD_COMP > const & compOutflux, + arrayView1d< real64 > const & phaseCFLNumber, + arrayView1d< real64 > const & compCFLNumber, + real64 & maxPhaseCFLNumber, + real64 & maxCompCFLNumber ); + +}; + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_CFLKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CapillaryPressureUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CapillaryPressureUpdateKernel.hpp new file mode 100644 index 00000000000..2d182b515cc --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CapillaryPressureUpdateKernel.hpp @@ -0,0 +1,73 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CapillaryPressureUpdateKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_CAPILLARYPRESSUREUPDATEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_CAPILLARYPRESSUREUPDATEKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** CapillaryPressureUpdateKernel ********************************/ + +struct CapillaryPressureUpdateKernel +{ + template< typename POLICY, typename CAPPRES_WRAPPER > + static void + launch( localIndex const size, + CAPPRES_WRAPPER const & capPresWrapper, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + for( localIndex q = 0; q < capPresWrapper.numGauss(); ++q ) + { + capPresWrapper.update( k, q, phaseVolFrac[k] ); + } + } ); + } + + template< typename POLICY, typename CAPPRES_WRAPPER > + static void + launch( SortedArrayView< localIndex const > const & targetSet, + CAPPRES_WRAPPER const & capPresWrapper, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) + { + forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + localIndex const k = targetSet[a]; + for( localIndex q = 0; q < capPresWrapper.numGauss(); ++q ) + { + capPresWrapper.update( k, q, phaseVolFrac[k] ); + } + } ); + } +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_CAPILLARYPRESSUREUPDATEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVMKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.cpp similarity index 99% rename from src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVMKernels.cpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.cpp index 3405e5cdd6d..e5ac3d7e7b8 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVMKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,17 +18,18 @@ */ #include "CompositionalMultiphaseHybridFVMKernels.hpp" -#include "CompositionalMultiphaseUtilities.hpp" #include "finiteVolume/mimeticInnerProducts/MimeticInnerProductBase.hpp" #include "finiteVolume/mimeticInnerProducts/BdVLMInnerProduct.hpp" #include "finiteVolume/mimeticInnerProducts/TPFAInnerProduct.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/HybridFVMHelperKernels.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" +#include "physicsSolvers/fluidFlow/kernels/HybridFVMHelperKernels.hpp" namespace geos { +using namespace constitutive; namespace compositionalMultiphaseHybridFVMKernels { diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp similarity index 91% rename from src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVMKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp index 3c07c9a99bf..dac73b0a0aa 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVMKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -29,9 +30,11 @@ #include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" #include "mesh/ElementRegionManager.hpp" #include "mesh/ObjectManagerBase.hpp" +#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp" #include "physicsSolvers/fluidFlow/StencilAccessors.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp" namespace geos @@ -40,9 +43,6 @@ namespace geos namespace compositionalMultiphaseHybridFVMKernels { -using namespace constitutive; - - // struct to specify local and neighbor derivatives struct Pos { @@ -89,13 +89,13 @@ struct UpwindingHelper static void upwindViscousCoefficient( localIndex const (&localIds)[ 3 ], localIndex const (&neighborIds)[ 3 ], - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseDens, ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, ElementViewConst< arrayView1d< globalIndex const > > const & elemDofNumber, real64 const & oneSidedVolFlux, real64 ( &upwPhaseViscCoef )[ NP ][ NC ], @@ -133,15 +133,15 @@ struct UpwindingHelper upwindBuoyancyCoefficient( localIndex const (&localIds)[ 3 ], localIndex const (&neighborIds)[ 3 ], real64 const & transGravCoef, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, real64 ( &phaseGravTerm )[ NP ][ NP-1 ], real64 ( &dPhaseGravTerm_dPres )[ NP ][ NP-1 ][ 2 ], real64 ( &dPhaseGravTerm_dCompDens )[ NP ][ NP-1 ][ 2 ][ NC ], @@ -169,8 +169,8 @@ struct UpwindingHelper computePhaseGravTerm( localIndex const (&localIds)[ 3 ], localIndex const (&neighborIds)[ 3 ], real64 const & transGravCoef, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, real64 ( &phaseGravTerm )[ NP ][ NP-1 ], real64 ( &dPhaseGravTerm_dPres )[ NP ][ NP-1 ][ 2 ], @@ -285,8 +285,8 @@ struct AssemblerKernelHelper arraySlice1d< localIndex const > const & elemToFaces, real64 const & elemPres, real64 const & elemGravCoef, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & elemPhaseMassDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const & dElemPhaseMassDens, + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const & elemPhaseMassDens, + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const & dElemPhaseMassDens, arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & elemPhaseMob, arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const & dElemPhaseMob, arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const & dElemCompFrac_dCompDens, @@ -336,15 +336,15 @@ struct AssemblerKernelHelper arraySlice1d< localIndex const > const & elemToFaces, real64 const & elemGravCoef, integer const useTotalMassEquation, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, ElementViewConst< arrayView1d< globalIndex const > > const & elemDofNumber, arraySlice2d< real64 const > const & transMatrixGrav, real64 const (&oneSidedVolFlux)[ NF ], @@ -524,15 +524,15 @@ struct AssemblerKernel real64 const & elemPres, real64 const & elemGravCoef, const integer useTotalMassEquation, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, ElementViewConst< arrayView1d< globalIndex const > > const & elemDofNumber, integer const elemGhostRank, globalIndex const rankOffset, @@ -565,7 +565,7 @@ struct FluxKernel fields::flow::dGlobalCompFraction_dGlobalCompDensity >; using MultiFluidAccessors = - StencilMaterialAccessors< MultiFluidBase, + StencilMaterialAccessors< constitutive::MultiFluidBase, fields::multifluid::phaseDensity, fields::multifluid::dPhaseDensity, fields::multifluid::phaseMassDensity, @@ -628,12 +628,12 @@ struct FluxKernel ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseMassDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, ElementViewConst< arrayView1d< globalIndex const > > const & elemDofNumber, globalIndex const rankOffset, real64 const lengthTolerance, @@ -671,8 +671,8 @@ class PhaseMobilityKernel : public isothermalCompositionalMultiphaseBaseKernels: * @param[in] relperm the relperm model */ PhaseMobilityKernel( ObjectManagerBase & subRegion, - MultiFluidBase const & fluid, - RelativePermeabilityBase const & relperm ) + constitutive::MultiFluidBase const & fluid, + constitutive::RelativePermeabilityBase const & relperm ) : Base(), m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ), @@ -696,13 +696,13 @@ class PhaseMobilityKernel : public isothermalCompositionalMultiphaseBaseKernels: void compute( localIndex const ei, FUNC && phaseMobilityKernelOp = NoOpFunc{} ) const { - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const phaseVisc = m_phaseVisc[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const dPhaseVisc = m_dPhaseVisc[ei][0]; - arraySlice1d< real64 const, relperm::USD_RELPERM - 2 > const phaseRelPerm = m_phaseRelPerm[ei][0]; - arraySlice2d< real64 const, relperm::USD_RELPERM_DS - 2 > const dPhaseRelPerm_dPhaseVolFrac = m_dPhaseRelPerm_dPhaseVolFrac[ei][0]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseVisc = m_phaseVisc[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseVisc = m_dPhaseVisc[ei][0]; + arraySlice1d< real64 const, constitutive::relperm::USD_RELPERM - 2 > const phaseRelPerm = m_phaseRelPerm[ei][0]; + arraySlice2d< real64 const, constitutive::relperm::USD_RELPERM_DS - 2 > const dPhaseRelPerm_dPhaseVolFrac = m_dPhaseRelPerm_dPhaseVolFrac[ei][0]; arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const phaseVolFrac = m_phaseVolFrac[ei]; arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; arraySlice1d< real64, compflow::USD_PHASE - 1 > const phaseMob = m_phaseMob[ei]; @@ -777,12 +777,12 @@ class PhaseMobilityKernel : public isothermalCompositionalMultiphaseBaseKernels: arrayView3d< real64 const, compflow::USD_COMP_DC > m_dCompFrac_dCompDens; /// Views on the phase viscosities - arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseVisc; - arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dPhaseVisc; + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseVisc; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseVisc; /// Views on the phase relative permeabilities - arrayView3d< real64 const, relperm::USD_RELPERM > m_phaseRelPerm; - arrayView4d< real64 const, relperm::USD_RELPERM_DS > m_dPhaseRelPerm_dPhaseVolFrac; + arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > m_phaseRelPerm; + arrayView4d< real64 const, constitutive::relperm::USD_RELPERM_DS > m_dPhaseRelPerm_dPhaseVolFrac; // outputs @@ -813,8 +813,8 @@ class PhaseMobilityKernelFactory createAndLaunch( integer const numComp, integer const numPhase, ObjectManagerBase & subRegion, - MultiFluidBase const & fluid, - RelativePermeabilityBase const & relperm ) + constitutive::MultiFluidBase const & fluid, + constitutive::RelativePermeabilityBase const & relperm ) { if( numPhase == 2 ) { @@ -842,11 +842,11 @@ class PhaseMobilityKernelFactory /** * @class ResidualNormKernel */ -class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > +class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 1 > { public: - using Base = solverBaseKernels::ResidualNormKernelBase< 1 >; + using Base = physicsSolverBaseKernels::ResidualNormKernelBase< 1 >; using Base::m_minNormalizer; using Base::m_rankOffset; using Base::m_localResidual; @@ -975,7 +975,7 @@ class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > ElementViewConst< arrayView2d< real64 const > > const m_porosity_n; /// View on total mass/molar density at the previous converged time step - ElementViewConst< arrayView2d< real64 const, multifluid::USD_FLUID > > const m_totalDens_n; + ElementViewConst< arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > > const m_totalDens_n; }; @@ -1003,7 +1003,7 @@ class ResidualNormKernelFactory */ template< typename POLICY > static void - createAndLaunch( solverBaseKernels::NormType const normType, + createAndLaunch( physicsSolverBaseKernels::NormType const normType, globalIndex const rankOffset, string const & dofKey, arrayView1d< real64 const > const & localResidual, @@ -1026,7 +1026,7 @@ class ResidualNormKernelFactory ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, regionFilter, faceManager, flowAccessors, fluidAccessors, poroAccessors, dt, minNormalizer ); - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { ResidualNormKernel::launchLinf< POLICY >( faceManager.size(), kernel, residualNorm ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DiffusionDispersionFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DiffusionDispersionFluxComputeKernel.hpp new file mode 100644 index 00000000000..f4293d5f83d --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DiffusionDispersionFluxComputeKernel.hpp @@ -0,0 +1,774 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file DiffusionDispersionFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DIFFUSIONDISPERSIONFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DIFFUSIONDISPERSIONFLUXCOMPUTEKERNEL_HPP + +#include "codingUtilities/Utilities.hpp" +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/diffusion/DiffusionFields.hpp" +#include "constitutive/diffusion/DiffusionBase.hpp" +#include "constitutive/dispersion/DispersionFields.hpp" +#include "constitutive/dispersion/DispersionBase.hpp" +#include "constitutive/solid/porosity/PorosityBase.hpp" +#include "constitutive/solid/porosity/PorosityFields.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/******************************** DiffusionDispersionFluxComputeKernel ********************************/ + +/** + * @class DiffusionDispersionFluxComputeKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @brief Define the interface for the assembly kernel in charge of diffusion/dispersion flux terms + */ +template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > +class DiffusionDispersionFluxComputeKernel : public FluxComputeKernelBase +{ +public: + + /// Compile time value for the number of components + static constexpr integer numComp = NUM_COMP; + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = NUM_DOF; + + /// Compute time value for the number of equations (all of them, except the volume balance equation) + static constexpr integer numEqn = NUM_DOF-1; + + /// Maximum number of elements at the face + static constexpr localIndex maxNumElems = STENCILWRAPPER::maxNumPointsInFlux; + + /// Maximum number of connections at the face + static constexpr localIndex maxNumConns = STENCILWRAPPER::maxNumConnections; + + /// Maximum number of points in the stencil + static constexpr localIndex maxStencilSize = STENCILWRAPPER::maxStencilSize; + + /// Number of flux support points (hard-coded for TFPA) + static constexpr integer numFluxSupportPoints = 2; + + using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernelBase; + using AbstractBase::m_dPhaseVolFrac; + using AbstractBase::m_kernelFlags; + + using DiffusionAccessors = + StencilMaterialAccessors< constitutive::DiffusionBase, + fields::diffusion::diffusivity, + fields::diffusion::dDiffusivity_dTemperature, + fields::diffusion::phaseDiffusivityMultiplier >; + + using DispersionAccessors = + StencilMaterialAccessors< constitutive::DispersionBase, + fields::dispersion::dispersivity >; + + using PorosityAccessors = + StencilMaterialAccessors< constitutive::PorosityBase, + fields::porosity::referencePorosity >; + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor + * @param[in] compFlowAccessors + * @param[in] multiFluidAccessors + * @param[in] diffusionAccessors + * @param[in] dispersionAccessors + * @param[in] porosityAccessors + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed together + */ + DiffusionDispersionFluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + DiffusionAccessors const & diffusionAccessors, + DispersionAccessors const & dispersionAccessors, + PorosityAccessors const & porosityAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< KernelFlags > kernelFlags ) + : FluxComputeKernelBase( numPhases, + rankOffset, + dofNumberAccessor, + compFlowAccessors, + multiFluidAccessors, + dt, + localMatrix, + localRhs, + kernelFlags ), + m_phaseVolFrac( compFlowAccessors.get( fields::flow::phaseVolumeFraction {} ) ), + m_phaseDens( multiFluidAccessors.get( fields::multifluid::phaseDensity {} ) ), + m_dPhaseDens( multiFluidAccessors.get( fields::multifluid::dPhaseDensity {} ) ), + m_diffusivity( diffusionAccessors.get( fields::diffusion::diffusivity {} ) ), + m_dDiffusivity_dTemp( diffusionAccessors.get( fields::diffusion::dDiffusivity_dTemperature {} ) ), + m_phaseDiffusivityMultiplier( diffusionAccessors.get( fields::diffusion::phaseDiffusivityMultiplier {} ) ), + m_dispersivity( dispersionAccessors.get( fields::dispersion::dispersivity {} ) ), + m_referencePorosity( porosityAccessors.get( fields::porosity::referencePorosity {} ) ), + m_stencilWrapper( stencilWrapper ), + m_seri( stencilWrapper.getElementRegionIndices() ), + m_sesri( stencilWrapper.getElementSubRegionIndices() ), + m_sei( stencilWrapper.getElementIndices() ) + { } + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables + { +public: + + /** + * @brief Constructor for the stack variables + * @param[in] size size of the stencil for this connection + * @param[in] numElems number of elements for this connection + */ + GEOS_HOST_DEVICE + StackVariables( localIndex const size, localIndex numElems ) + : stencilSize( size ), + numConnectedElems( numElems ), + dofColIndices( size * numDof ), + localFlux( numElems * numEqn ), + localFluxJacobian( numElems * numEqn, size * numDof ) + {} + + // Stencil information + + /// Stencil size for a given connection + localIndex const stencilSize; + /// Number of elements connected at a given connection + localIndex const numConnectedElems; + + /// Transmissibility + real64 transmissibility[maxNumConns][numFluxSupportPoints]{}; + /// Derivatives of transmissibility with respect to pressure + real64 dTrans_dTemp[maxNumConns][numFluxSupportPoints]{}; + + // Local degrees of freedom and local residual/jacobian + + /// Indices of the matrix rows/columns corresponding to the dofs in this face + stackArray1d< globalIndex, maxNumElems * numDof > dofColIndices; + + /// Storage for the face local residual vector (all equations except volume balance) + stackArray1d< real64, maxNumElems * numEqn > localFlux; + /// Storage for the face local Jacobian matrix + stackArray2d< real64, maxNumElems * numEqn * maxStencilSize * numDof > localFluxJacobian; + }; + + + /** + * @brief Getter for the stencil size at this connection + * @param[in] iconn the connection index + * @return the size of the stencil at this connection + */ + GEOS_HOST_DEVICE + inline + localIndex stencilSize( localIndex const iconn ) const + { return m_sei[iconn].size(); } + + /** + * @brief Getter for the number of elements at this connection + * @param[in] iconn the connection index + * @return the number of elements at this connection + */ + GEOS_HOST_DEVICE + inline + localIndex numPointsInFlux( localIndex const iconn ) const + { return m_stencilWrapper.numPointsInFlux( iconn ); } + + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] iconn the connection index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + inline + void setup( localIndex const iconn, + StackVariables & stack ) const + { + // set degrees of freedom indices for this face + for( integer i = 0; i < stack.stencilSize; ++i ) + { + globalIndex const offset = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; + + for( integer jdof = 0; jdof < numDof; ++jdof ) + { + stack.dofColIndices[i * numDof + jdof] = offset + jdof; + } + } + } + + /** + * @brief Compute the local diffusion flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + * @param[in] diffusionFluxKernelOp the function used to customize the computation of the component fluxes + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void computeDiffusionFlux( localIndex const iconn, + StackVariables & stack, + FUNC && diffusionFluxKernelOp = NoOpFunc{} ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + // first, compute the transmissibilities at this face + m_stencilWrapper.computeWeights( iconn, + m_diffusivity, + m_dDiffusivity_dTemp, + stack.transmissibility, + stack.dTrans_dTemp ); + + + localIndex k[numFluxSupportPoints]{}; + localIndex connectionIndex = 0; + for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) + { + for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) + { + /// cell indices + localIndex const seri[numFluxSupportPoints] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; + localIndex const sesri[numFluxSupportPoints] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; + localIndex const sei[numFluxSupportPoints] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; + + // clear working arrays + real64 diffusionFlux[numComp]{}; + real64 dDiffusionFlux_dP[numFluxSupportPoints][numComp]{}; + real64 dDiffusionFlux_dC[numFluxSupportPoints][numComp][numComp]{}; + real64 dDens_dC[numComp]{}; + + real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], + stack.transmissibility[connectionIndex][1] }; + + //***** calculation of flux ***** + // loop over phases, compute and upwind phase flux and sum contributions to each component's flux + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + + // loop over components + for( integer ic = 0; ic < numComp; ++ic ) + { + + real64 compFracGrad = 0.0; + real64 dCompFracGrad_dP[numFluxSupportPoints]{}; + real64 dCompFracGrad_dC[numFluxSupportPoints][numComp]{}; + + // compute the component fraction gradient using the diffusion transmissibility + computeCompFractionGradient( ip, ic, + seri, sesri, sei, + trans, + compFracGrad, + dCompFracGrad_dP, + dCompFracGrad_dC ); + + // choose upstream cell for composition upwinding + localIndex const k_up = (compFracGrad >= 0) ? 0 : 1; + + localIndex const er_up = seri[k_up]; + localIndex const esr_up = sesri[k_up]; + localIndex const ei_up = sei[k_up]; + + // computation of the upwinded mass flux + real64 const upwindCoefficient = + m_referencePorosity[er_up][esr_up][ei_up] * + m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * + m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_phaseVolFrac[er_up][esr_up][ei_up][ip]; + diffusionFlux[ic] += upwindCoefficient * compFracGrad; + + // add contributions of the derivatives of component fractions wrt pressure/component fractions + for( integer ke = 0; ke < numFluxSupportPoints; ke++ ) + { + dDiffusionFlux_dP[ke][ic] += upwindCoefficient * dCompFracGrad_dP[ke]; + for( integer jc = 0; jc < numComp; ++jc ) + { + dDiffusionFlux_dC[ke][ic][jc] += upwindCoefficient * dCompFracGrad_dC[ke][jc]; + } + } + + // add contributions of the derivatives of upwind coefficient wrt pressure/component fractions + real64 const dUpwindCoefficient_dP = + m_referencePorosity[er_up][esr_up][ei_up] * + m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * + ( m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dP] * m_phaseVolFrac[er_up][esr_up][ei_up][ip] + + m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_dPhaseVolFrac[er_up][esr_up][ei_up][ip][Deriv::dP] ); + dDiffusionFlux_dP[k_up][ic] += dUpwindCoefficient_dP * compFracGrad; + + applyChainRule( numComp, + m_dCompFrac_dCompDens[er_up][esr_up][ei_up], + m_dPhaseDens[er_up][esr_up][ei_up][0][ip], + dDens_dC, + Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + real64 const dUpwindCoefficient_dC = + m_referencePorosity[er_up][esr_up][ei_up] * + m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * + ( dDens_dC[jc] * m_phaseVolFrac[er_up][esr_up][ei_up][ip] + + m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_dPhaseVolFrac[er_up][esr_up][ei_up][ip][Deriv::dC+jc] ); + dDiffusionFlux_dC[k_up][ic][jc] += dUpwindCoefficient_dC * compFracGrad; + } + + // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives + // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase + diffusionFluxKernelOp( ip, ic, k, seri, sesri, sei, connectionIndex, + k_up, seri[k_up], sesri[k_up], sei[k_up], + compFracGrad, upwindCoefficient ); + + } // loop over components + } // loop over phases + + // add diffusion flux to local flux and local flux jacobian + addToLocalFluxAndJacobian( k, + stack, + diffusionFlux, + dDiffusionFlux_dP, + dDiffusionFlux_dC ); + + connectionIndex++; + } // loop over k[1] + } // loop over k[0] + } + + /** + * @brief Compute the local dispersion flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + * @param[in] dispersionFluxKernelOp the function used to customize the computation of the component fluxes + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void computeDispersionFlux( localIndex const iconn, + StackVariables & stack, + FUNC && dispersionFluxKernelOp = NoOpFunc{} ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + // first, compute the transmissibilities at this face + // note that the dispersion tensor is lagged in iteration + m_stencilWrapper.computeWeights( iconn, + m_dispersivity, + m_dispersivity, // this is just to pass something, but the resulting derivative won't be used + stack.transmissibility, + stack.dTrans_dTemp ); // will not be used + + + localIndex k[numFluxSupportPoints]{}; + localIndex connectionIndex = 0; + for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) + { + for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) + { + /// cell indices + localIndex const seri[numFluxSupportPoints] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; + localIndex const sesri[numFluxSupportPoints] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; + localIndex const sei[numFluxSupportPoints] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; + + // clear working arrays + real64 dispersionFlux[numComp]{}; + real64 dDispersionFlux_dP[numFluxSupportPoints][numComp]{}; + real64 dDispersionFlux_dC[numFluxSupportPoints][numComp][numComp]{}; + real64 dDens_dC[numComp]{}; + + real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], + stack.transmissibility[connectionIndex][1] }; + + //***** calculation of flux ***** + // loop over phases, compute and upwind phase flux and sum contributions to each component's flux + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + + // loop over components + for( integer ic = 0; ic < numComp; ++ic ) + { + + real64 compFracGrad = 0.0; + real64 dCompFracGrad_dP[numFluxSupportPoints]{}; + real64 dCompFracGrad_dC[numFluxSupportPoints][numComp]{}; + + // compute the component fraction gradient using the dispersion transmissibility + computeCompFractionGradient( ip, ic, + seri, sesri, sei, + trans, + compFracGrad, + dCompFracGrad_dP, + dCompFracGrad_dC ); + + // choose upstream cell for composition upwinding + localIndex const k_up = (compFracGrad >= 0) ? 0 : 1; + + localIndex const er_up = seri[k_up]; + localIndex const esr_up = sesri[k_up]; + localIndex const ei_up = sei[k_up]; + + // computation of the upwinded mass flux + dispersionFlux[ic] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * compFracGrad; + + // add contributions of the derivatives of component fractions wrt pressure/component fractions + for( integer ke = 0; ke < numFluxSupportPoints; ke++ ) + { + dDispersionFlux_dP[ke][ic] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * dCompFracGrad_dP[ke]; + for( integer jc = 0; jc < numComp; ++jc ) + { + dDispersionFlux_dC[ke][ic][jc] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * dCompFracGrad_dC[ke][jc]; + } + } + + // add contributions of the derivatives of upwind coefficient wrt pressure/component fractions + dDispersionFlux_dP[k_up][ic] += m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dP] * compFracGrad; + + applyChainRule( numComp, + m_dCompFrac_dCompDens[er_up][esr_up][ei_up], + m_dPhaseDens[er_up][esr_up][ei_up][0][ip], + dDens_dC, + Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + dDispersionFlux_dC[k_up][ic][jc] += dDens_dC[jc] * compFracGrad; + } + + // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives + // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase + dispersionFluxKernelOp( ip, ic, k, seri, sesri, sei, connectionIndex, + k_up, seri[k_up], sesri[k_up], sei[k_up], + compFracGrad ); + + } // loop over components + } // loop over phases + + // add dispersion flux to local flux and local flux jacobian + addToLocalFluxAndJacobian( k, + stack, + dispersionFlux, + dDispersionFlux_dP, + dDispersionFlux_dC ); + + connectionIndex++; + } // loop over k[1] + } // loop over k[0] + } + + /** + * @brief Compute the component fraction gradient at this interface + * @param[in] ip the phase index + * @param[in] ic the component index + * @param[in] seri the region indices + * @param[in] sesri the subregion indices + * @param[in] sei the element indices + * @param[out] compFracGrad the component fraction gradient + * @param[out] dCompFracGrad_dP the derivatives of the component fraction gradient wrt pressure + * @param[out] dCompFracGrad_dC the derivatives of the component fraction gradient wrt component densities + */ + GEOS_HOST_DEVICE + inline + void computeCompFractionGradient( integer const ip, + integer const ic, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&trans)[numFluxSupportPoints], + real64 & compFracGrad, + real64 (& dCompFracGrad_dP)[numFluxSupportPoints], + real64 (& dCompFracGrad_dC)[numFluxSupportPoints][numComp] ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + real64 dCompFrac_dC[numComp]{}; + + for( integer i = 0; i < numFluxSupportPoints; i++ ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + compFracGrad += trans[i] * m_phaseCompFrac[er][esr][ei][0][ip][ic]; + dCompFracGrad_dP[i] += trans[i] * m_dPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dP]; + + applyChainRule( numComp, + m_dCompFrac_dCompDens[er][esr][ei], + m_dPhaseCompFrac[er][esr][ei][0][ip][ic], + dCompFrac_dC, + Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + dCompFracGrad_dC[i][jc] += trans[i] * dCompFrac_dC[jc]; + } + } + } + + /** + * @brief Add the local diffusion/dispersion flux contributions to the residual and Jacobian + * @param[in] k the cell indices + * @param[in] stack the stack variables + * @param[in] flux the diffusion/dispersion flux + * @param[in] dFlux_dP the derivative of the diffusion/dispersion flux wrt pressure + * @param[in] dFlux_dC the derivative of the diffusion/dispersion flux wrt compositions + */ + GEOS_HOST_DEVICE + inline + void addToLocalFluxAndJacobian( localIndex const (&k)[numFluxSupportPoints], + StackVariables & stack, + real64 const (&flux)[numComp], + real64 const (&dFlux_dP)[numFluxSupportPoints][numComp], + real64 const (&dFlux_dC)[numFluxSupportPoints][numComp][numComp] ) const + { + // loop over components + for( integer ic = 0; ic < numComp; ++ic ) + { + // finally, increment local flux and local Jacobian + integer const eqIndex0 = k[0] * numEqn + ic; + integer const eqIndex1 = k[1] * numEqn + ic; + + stack.localFlux[eqIndex0] += m_dt * flux[ic]; + stack.localFlux[eqIndex1] -= m_dt * flux[ic]; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + localIndex const localDofIndexPres = k[ke] * numDof; + stack.localFluxJacobian[eqIndex0][localDofIndexPres] += m_dt * dFlux_dP[ke][ic]; + stack.localFluxJacobian[eqIndex1][localDofIndexPres] -= m_dt * dFlux_dP[ke][ic]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + localIndex const localDofIndexComp = localDofIndexPres + jc + 1; + stack.localFluxJacobian[eqIndex0][localDofIndexComp] += m_dt * dFlux_dC[ke][ic][jc]; + stack.localFluxJacobian[eqIndex1][localDofIndexComp] -= m_dt * dFlux_dC[ke][ic][jc]; + } + } + } + } + + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void complete( localIndex const iconn, + StackVariables & stack, + FUNC && assemblyKernelOp = NoOpFunc{} ) const + { + using namespace compositionalMultiphaseUtilities; + + if( m_kernelFlags.isSet( KernelFlags::TotalMassEquation ) ) + { + // Apply equation/variable change transformation(s) + stackArray1d< real64, maxStencilSize * numDof > work( stack.stencilSize * numDof ); + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numEqn, numDof*stack.stencilSize, stack.numConnectedElems, + stack.localFluxJacobian, work ); + shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numComp, numEqn, stack.numConnectedElems, + stack.localFlux ); + } + + // add contribution to residual and jacobian into: + // - the component mass balance equations (i = 0 to i = numComp-1) + // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels + for( integer i = 0; i < stack.numConnectedElems; ++i ) + { + if( m_ghostRank[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )] < 0 ) + { + globalIndex const globalRow = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; + localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); + GEOS_ASSERT_GE( localRow, 0 ); + GEOS_ASSERT_GT( m_localMatrix.numRows(), localRow + numComp ); + + for( integer ic = 0; ic < numComp; ++ic ) + { + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[localRow + ic], stack.localFlux[i * numEqn + ic] ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > + ( localRow + ic, + stack.dofColIndices.data(), + stack.localFluxJacobian[i * numEqn + ic].dataIfContiguous(), + stack.stencilSize * numDof ); + } + + // call the lambda to assemble additional terms, such as thermal terms + assemblyKernelOp( i, localRow ); + } + } + } + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numConnections the number of connections + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numConnections, + integer const hasDiffusion, + integer const hasDispersion, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numConnections, [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), + kernelComponent.numPointsInFlux( iconn ) ); + + kernelComponent.setup( iconn, stack ); + if( hasDiffusion ) + { + kernelComponent.computeDiffusionFlux( iconn, stack ); + } + if( hasDispersion ) + { + kernelComponent.computeDispersionFlux( iconn, stack ); + } + kernelComponent.complete( iconn, stack ); + } ); + } + +protected: + + /// Views on phase volume fraction + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_phaseVolFrac; + + /// Views on phase densities + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_phaseDens; + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dPhaseDens; + + /// Views on diffusivity + ElementViewConst< arrayView3d< real64 const > > const m_diffusivity; + ElementViewConst< arrayView3d< real64 const > > const m_dDiffusivity_dTemp; + ElementViewConst< arrayView3d< real64 const > > const m_phaseDiffusivityMultiplier; + + /// Views on dispersivity + ElementViewConst< arrayView3d< real64 const > > const m_dispersivity; + + /// View on the reference porosity + ElementViewConst< arrayView1d< real64 const > > const m_referencePorosity; + + // Stencil information + + /// Reference to the stencil wrapper + STENCILWRAPPER const m_stencilWrapper; + + /// Connection to element maps + typename STENCILWRAPPER::IndexContainerViewConstType const m_seri; + typename STENCILWRAPPER::IndexContainerViewConstType const m_sesri; + typename STENCILWRAPPER::IndexContainerViewConstType const m_sei; + +}; + +/** + * @class DiffusionDispersionFluxComputeKernelFactory + */ +class DiffusionDispersionFluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] hasDiffusion flag specifying whether diffusion is used or not + * @param[in] hasDispersion flag specifying whether dispersion is used or not + * @param[in] solverName the name of the solver + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + string const & dofKey, + integer const hasDiffusion, + integer const hasDispersion, + integer const useTotalMassEquation, + string const & solverName, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_DOF = NC() + 1; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + BitFlags< KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( KernelFlags::TotalMassEquation ); + + using kernelType = DiffusionDispersionFluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); + typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); + typename kernelType::DiffusionAccessors diffusionAccessors( elemManager, solverName ); + typename kernelType::DispersionAccessors dispersionAccessors( elemManager, solverName ); + typename kernelType::PorosityAccessors porosityAccessors( elemManager, solverName ); + + kernelType kernel( numPhases, rankOffset, stencilWrapper, + dofNumberAccessor, compFlowAccessors, multiFluidAccessors, + diffusionAccessors, dispersionAccessors, porosityAccessors, + dt, localMatrix, localRhs, kernelFlags ); + kernelType::template launch< POLICY >( stencilWrapper.size(), + hasDiffusion, hasDispersion, + kernel ); + } ); + } +}; + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DIFFUSIONDISPERSIONFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DirichletFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DirichletFluxComputeKernel.hpp new file mode 100644 index 00000000000..a4b00cf8180 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DirichletFluxComputeKernel.hpp @@ -0,0 +1,558 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file DirichletFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DIRICHLETFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DIRICHLETFLUXCOMPUTEKERNEL_HPP + +#include "codingUtilities/Utilities.hpp" +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidSelector.hpp" +#include "finiteVolume/BoundaryStencil.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" + + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/******************************** DirichletFluxComputeKernel ********************************/ + +/** + * @class DirichletFluxComputeKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @tparam FLUIDWRAPPER the type of the fluid wrapper + * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms + */ +template< integer NUM_COMP, integer NUM_DOF, typename FLUIDWRAPPER > +class DirichletFluxComputeKernel : public FluxComputeKernel< NUM_COMP, + NUM_DOF, + BoundaryStencilWrapper > +{ +public: + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using CompFlowAccessors = AbstractBase::CompFlowAccessors; + using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; + using CapPressureAccessors = AbstractBase::CapPressureAccessors; + using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; + + using AbstractBase::m_dt; + using AbstractBase::m_numPhases; + using AbstractBase::m_rankOffset; + using AbstractBase::m_dofNumber; + using AbstractBase::m_ghostRank; + using AbstractBase::m_gravCoef; + using AbstractBase::m_pres; + using AbstractBase::m_phaseCompFrac; + using AbstractBase::m_dPhaseCompFrac; + using AbstractBase::m_dCompFrac_dCompDens; + using AbstractBase::m_localMatrix; + using AbstractBase::m_localRhs; + using AbstractBase::m_kernelFlags; + + using Base = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernel< NUM_COMP, NUM_DOF, BoundaryStencilWrapper >; + using Base::numComp; + using Base::numDof; + using Base::numEqn; + using Base::m_stencilWrapper; + using Base::m_phaseMob; + using Base::m_dPhaseMob; + using Base::m_phaseMassDens; + using Base::m_dPhaseMassDens; + using Base::m_permeability; + using Base::m_dPerm_dPres; + using Base::m_seri; + using Base::m_sesri; + using Base::m_sei; + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] faceManager the face manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] fluidWrapper reference to the fluid wrapper + * @param[in] dofNumberAccessor + * @param[in] compFlowAccessors + * @param[in] multiFluidAccessors + * @param[in] capPressureAccessors + * @param[in] permeabilityAccessors + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed together + */ + DirichletFluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + FaceManager const & faceManager, + BoundaryStencilWrapper const & stencilWrapper, + FLUIDWRAPPER const & fluidWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + CapPressureAccessors const & capPressureAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< KernelFlags > kernelFlags ) + : Base( numPhases, + rankOffset, + stencilWrapper, + dofNumberAccessor, + compFlowAccessors, + multiFluidAccessors, + capPressureAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs, + kernelFlags ), + m_facePres( faceManager.getField< fields::flow::facePressure >() ), + m_faceTemp( faceManager.getField< fields::flow::faceTemperature >() ), + m_faceCompFrac( faceManager.getField< fields::flow::faceGlobalCompFraction >() ), + m_faceGravCoef( faceManager.getField< fields::flow::gravityCoefficient >() ), + m_fluidWrapper( fluidWrapper ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables + { +public: + + /** + * @brief Constructor for the stack variables + * @param[in] size size of the stencil for this connection + * @param[in] numElems number of elements for this connection + */ + GEOS_HOST_DEVICE + StackVariables( localIndex const GEOS_UNUSED_PARAM( size ), + localIndex GEOS_UNUSED_PARAM( numElems )) {} + + // Transmissibility + real64 transmissibility = 0.0; + + // Component fluxes and derivatives + + /// Component fluxes + real64 compFlux[numComp]{}; + /// Derivatives of component fluxes wrt pressure + real64 dCompFlux_dP[numComp]{}; + /// Derivatives of component fluxes wrt component densities + real64 dCompFlux_dC[numComp][numComp]{}; + + // Local degrees of freedom and local residual/jacobian + + /// Indices of the matrix rows/columns corresponding to the dofs in this face + globalIndex dofColIndices[numDof]{}; + + /// Storage for the face local residual vector + real64 localFlux[numEqn]{}; + /// Storage for the face local Jacobian matrix + real64 localFluxJacobian[numEqn][numDof]{}; + + }; + + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] iconn the connection index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const iconn, + StackVariables & stack ) const + { + globalIndex const offset = + m_dofNumber[m_seri( iconn, BoundaryStencil::Order::ELEM )][m_sesri( iconn, BoundaryStencil::Order::ELEM )][m_sei( iconn, BoundaryStencil::Order::ELEM )]; + + for( integer jdof = 0; jdof < numDof; ++jdof ) + { + stack.dofColIndices[jdof] = offset + jdof; + } + } + + + /** + * @brief Compute the local Dirichlet face flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeFlux( localIndex const iconn, + StackVariables & stack, + FUNC && compFluxKernelOp = NoOpFunc{} ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + using Order = BoundaryStencil::Order; + + localIndex const er = m_seri( iconn, Order::ELEM ); + localIndex const esr = m_sesri( iconn, Order::ELEM ); + localIndex const ei = m_sei( iconn, Order::ELEM ); + localIndex const kf = m_sei( iconn, Order::FACE ); + + // Step 1: compute the transmissibility at the boundary face + + real64 dTrans_dPerm[3]{}; + m_stencilWrapper.computeWeights( iconn, + m_permeability, + stack.transmissibility, + dTrans_dPerm ); + real64 const dTrans_dPres = LvArray::tensorOps::AiBi< 3 >( dTrans_dPerm, m_dPerm_dPres[er][esr][ei][0] ); + + // Step 2: compute the fluid properties on the face + // This is needed to get the phase mass density and the phase comp fraction at the face + // Because we approximate the face mobility using the total element mobility + + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseFrac( 1, 1, m_numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseDens( 1, 1, m_numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseMassDens( 1, 1, m_numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseVisc( 1, 1, m_numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseEnthalpy( 1, 1, m_numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseInternalEnergy( 1, 1, m_numPhases ); + StackArray< real64, 4, constitutive::MultiFluidBase::MAX_NUM_PHASES * NUM_COMP, + constitutive::multifluid::LAYOUT_PHASE_COMP > facePhaseCompFrac( 1, 1, m_numPhases, NUM_COMP ); + real64 faceTotalDens = 0.0; + + constitutive::MultiFluidBase::KernelWrapper::computeValues( m_fluidWrapper, + m_facePres[kf], + m_faceTemp[kf], + m_faceCompFrac[kf], + facePhaseFrac[0][0], + facePhaseDens[0][0], + facePhaseMassDens[0][0], + facePhaseVisc[0][0], + facePhaseEnthalpy[0][0], + facePhaseInternalEnergy[0][0], + facePhaseCompFrac[0][0], + faceTotalDens ); + + // Step 3: loop over phases, compute and upwind phase flux and sum contributions to each component's flux + + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + + // working variables + real64 dDensMean_dC[numComp]{}; + real64 dF_dC[numComp]{}; + real64 dProp_dC[numComp]{}; + + real64 phaseFlux = 0.0; // for the lambda + real64 dPhaseFlux_dP = 0.0; + real64 dPhaseFlux_dC[numComp]{}; + + + // Step 3.1: compute the average phase mass density at the face + + applyChainRule( numComp, + m_dCompFrac_dCompDens[er][esr][ei], + m_dPhaseMassDens[er][esr][ei][0][ip], + dProp_dC, + Deriv::dC ); + + // average density and derivatives + real64 const densMean = 0.5 * ( m_phaseMassDens[er][esr][ei][0][ip] + facePhaseMassDens[0][0][ip] ); + real64 const dDensMean_dP = 0.5 * m_dPhaseMassDens[er][esr][ei][0][ip][Deriv::dP]; + for( integer jc = 0; jc < numComp; ++jc ) + { + dDensMean_dC[jc] = 0.5 * dProp_dC[jc]; + } + + + // Step 3.2: compute the (TPFA) potential difference at the face + + real64 const gravTimesDz = m_gravCoef[er][esr][ei] - m_faceGravCoef[kf]; + real64 const potDif = m_pres[er][esr][ei] - m_facePres[kf] - densMean * gravTimesDz; + real64 const f = stack.transmissibility * potDif; + real64 const dF_dP = stack.transmissibility * ( 1.0 - dDensMean_dP * gravTimesDz ) + dTrans_dPres * potDif; + for( integer jc = 0; jc < numComp; ++jc ) + { + dF_dC[jc] = -stack.transmissibility * dDensMean_dC[jc] * gravTimesDz; + } + + // Step 3.3: computation of the mobility + // We do that before the if/else statement to be able to pass it to the compFluxOpKernel + + // recomputing the exact mobility at the face would be quite complex, as it would require: + // 1) computing the saturation + // 2) computing the relperm + // 3) computing the mobility as \lambda_p = \rho_p kr_p( S_p ) / \mu_p + // the second step in particular would require yet another dispatch to get the relperm model + // so, for simplicity, we approximate the face mobility as + // \lambda^approx_p = \rho_p S_p / \mu_p + // = \rho_p ( (nu_p / rho_p) * rho_t ) / \mu_p (plugging the expression of saturation) + // = \nu_p * rho_t / \mu_p + // fortunately, we don't need the derivatives + real64 const facePhaseMob = ( facePhaseFrac[0][0][ip] > 0.0 ) + ? facePhaseFrac[0][0][ip] * faceTotalDens / facePhaseVisc[0][0][ip] + : 0.0; + + // *** upwinding *** + // Step 3.4: upwinding based on the sign of the phase potential gradient + // It is easier to hard-code the if/else because it is difficult to address elem and face variables in a uniform way + + if( potDif >= 0 ) // the element is upstream + { + + // compute the phase flux and derivatives using the element mobility + phaseFlux = m_phaseMob[er][esr][ei][ip] * f; + dPhaseFlux_dP = m_phaseMob[er][esr][ei][ip] * dF_dP + m_dPhaseMob[er][esr][ei][ip][Deriv::dP] * f; + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[jc] = + m_phaseMob[er][esr][ei][ip] * dF_dC[jc] + m_dPhaseMob[er][esr][ei][ip][Deriv::dC+jc] * f; + } + + // slice some constitutive arrays to avoid too much indexing in component loop + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE_COMP-3 > phaseCompFracSub = + m_phaseCompFrac[er][esr][ei][0][ip]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC-3 > dPhaseCompFracSub = + m_dPhaseCompFrac[er][esr][ei][0][ip]; + + // compute component fluxes and derivatives using element composition + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const ycp = phaseCompFracSub[ic]; + stack.compFlux[ic] += phaseFlux * ycp; + stack.dCompFlux_dP[ic] += dPhaseFlux_dP * ycp + phaseFlux * dPhaseCompFracSub[ic][Deriv::dP]; + + applyChainRule( numComp, + m_dCompFrac_dCompDens[er][esr][ei], + dPhaseCompFracSub[ic], + dProp_dC, + Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.dCompFlux_dC[ic][jc] += dPhaseFlux_dC[jc] * ycp + phaseFlux * dProp_dC[jc]; + } + } + + } + else // the face is upstream + { + + // compute the phase flux and derivatives using the approximated face mobility + // we only have to take derivatives of the potential gradient in this case + phaseFlux = facePhaseMob * f; + dPhaseFlux_dP = facePhaseMob * dF_dP; + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[jc] = facePhaseMob * dF_dC[jc]; + } + + // compute component fluxes and derivatives using the face composition + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const ycp = facePhaseCompFrac[0][0][ip][ic]; + stack.compFlux[ic] += phaseFlux * ycp; + stack.dCompFlux_dP[ic] += dPhaseFlux_dP * ycp; + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.dCompFlux_dC[ic][jc] += dPhaseFlux_dC[jc] * ycp; + } + } + } + + // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives + // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase + compFluxKernelOp( ip, er, esr, ei, kf, f, + facePhaseMob, facePhaseEnthalpy[0][0], facePhaseCompFrac[0][0], + phaseFlux, dPhaseFlux_dP, dPhaseFlux_dC ); + + } + + // *** end of upwinding + + // Step 4: populate local flux vector and derivatives + for( integer ic = 0; ic < numComp; ++ic ) + { + stack.localFlux[ic] = m_dt * stack.compFlux[ic]; + stack.localFluxJacobian[ic][0] = m_dt * stack.dCompFlux_dP[ic]; + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.localFluxJacobian[ic][jc+1] = m_dt * stack.dCompFlux_dC[ic][jc]; + } + } + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void complete( localIndex const iconn, + StackVariables & stack, + FUNC && assemblyKernelOp = NoOpFunc{} ) const + { + using namespace compositionalMultiphaseUtilities; + using Order = BoundaryStencil::Order; + + if( AbstractBase::m_kernelFlags.isSet( KernelFlags::TotalMassEquation ) ) + { + // Apply equation/variable change transformation(s) + real64 work[numDof]{}; + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numDof, stack.localFluxJacobian, work ); + shiftElementsAheadByOneAndReplaceFirstElementWithSum( numComp, stack.localFlux ); + } + + // add contribution to residual and jacobian into: + // - the component mass balance equations (i = 0 to i = numComp-1) + // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels + if( m_ghostRank[m_seri( iconn, Order::ELEM )][m_sesri( iconn, Order::ELEM )][m_sei( iconn, Order::ELEM )] < 0 ) + { + globalIndex const globalRow = m_dofNumber[m_seri( iconn, Order::ELEM )][m_sesri( iconn, Order::ELEM )][m_sei( iconn, Order::ELEM )]; + localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); + GEOS_ASSERT_GE( localRow, 0 ); + GEOS_ASSERT_GT( AbstractBase::m_localMatrix.numRows(), localRow + numComp ); + + for( integer ic = 0; ic < numComp; ++ic ) + { + RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + ic], stack.localFlux[ic] ); + AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > + ( localRow + ic, + stack.dofColIndices, + stack.localFluxJacobian[ic], + numDof ); + } + + // call the lambda to assemble additional terms, such as thermal terms + assemblyKernelOp( localRow ); + } + } + +protected: + + /// Views on face pressure, temperature, and composition + arrayView1d< real64 const > const m_facePres; + arrayView1d< real64 const > const m_faceTemp; + arrayView2d< real64 const, compflow::USD_COMP > const m_faceCompFrac; + + /// View on the face gravity coefficient + arrayView1d< real64 const > const m_faceGravCoef; + + /// Reference to the fluid wrapper + FLUIDWRAPPER const m_fluidWrapper; + +}; + + +/** + * @class DirichletFluxComputeKernelFactory + */ +class DirichletFluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] solverName name of the solver (to name accessors) + * @param[in] faceManager reference to the face manager + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the boundary stencil wrapper + * @param[in] fluidBase the multifluid constitutive model + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + integer const useTotalMassEquation, + string const & dofKey, + string const & solverName, + FaceManager const & faceManager, + ElementRegionManager const & elemManager, + BoundaryStencilWrapper const & stencilWrapper, + constitutive::MultiFluidBase & fluidBase, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + constitutive::constitutiveComponentUpdatePassThru( fluidBase, numComps, [&]( auto & fluid, auto NC ) + { + using FluidType = TYPEOFREF( fluid ); + typename FluidType::KernelWrapper const fluidWrapper = fluid.createKernelWrapper(); + + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_DOF = NC() + 1; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + // for now, we neglect capillary pressure in the kernel + BitFlags< KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( KernelFlags::TotalMassEquation ); + + using kernelType = DirichletFluxComputeKernel< NUM_COMP, NUM_DOF, typename FluidType::KernelWrapper >; + typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); + typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); + typename kernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); + typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); + + kernelType kernel( numPhases, rankOffset, faceManager, stencilWrapper, fluidWrapper, + dofNumberAccessor, compFlowAccessors, multiFluidAccessors, capPressureAccessors, permeabilityAccessors, + dt, localMatrix, localRhs, kernelFlags ); + kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); + } ); + } +}; + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DIRICHLETFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DissipationFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DissipationFluxComputeKernel.hpp new file mode 100644 index 00000000000..3d09e878fbf --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DissipationFluxComputeKernel.hpp @@ -0,0 +1,404 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file DissipationFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DISSIPATIONFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DISSIPATIONFLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "constitutive/solid/porosity/PorosityBase.hpp" +#include "constitutive/solid/porosity/PorosityFields.hpp" + +namespace geos +{ + +namespace dissipationCompositionalMultiphaseFVMKernels +{ + +static constexpr integer newtonContinuationCutoffIteration = 5; +static constexpr real64 initialDirectionalCoef = 100; +static constexpr real64 multiplierDirectionalCoef = 1000; + +/******************************** FluxComputeKernel ********************************/ + +/** + * @class FluxComputeKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > +class FluxComputeKernel : public isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > +{ +public: + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using CompFlowAccessors = AbstractBase::CompFlowAccessors; + using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; + using CapPressureAccessors = AbstractBase::CapPressureAccessors; + using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; + + using AbstractBase::m_dt; + using AbstractBase::m_gravCoef; + using AbstractBase::m_dCompFrac_dCompDens; + + using Base = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + using Base::numComp; + using Base::numDof; + using Base::numEqn; + using Base::numFluxSupportPoints; + using Base::m_permeability; + using Base::m_dPerm_dPres; + + using DissCompFlowAccessors = + StencilAccessors< fields::flow::pressure_n, + fields::flow::globalCompDensity, + fields::flow::globalCompFraction, + fields::elementVolume >; + + using PorosityAccessors = + StencilMaterialAccessors< constitutive::PorosityBase, fields::porosity::porosity_n >; + + using Deriv = constitutive::multifluid::DerivativeOffset; + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] hasCapPressure flag specifying whether capillary pressure is used or not + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor accessor for the dofs numbers + * @param[in] compFlowAccessor accessor for wrappers registered by the solver + * @param[in] dissCompFlowAccessor accessor for wrappers registered by the solver needed for dissipation + * @param[in] multiFluidAccessor accessor for wrappers registered by the multifluid model + * @param[in] capPressureAccessors accessor for wrappers registered by the cap pressure model + * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model + * @param[in] porosityAccessors accessor for wrappers registered by the porosity model + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] omega omega coefficient for DBC + * @param[in] curNewton current Newton iteration number + * @param[in] continuation flag indicating if continuation is used or not + * @param[in] miscible flag to trigger some treatment for miscible cases + * @param[in] kappamin minimum value for kappa coefficient in DBC + * @param[in] contMultiplier continuation multiplier factor (should be < 1) + */ + FluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + DissCompFlowAccessors const & dissCompFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + CapPressureAccessors const & capPressureAccessors, + PermeabilityAccessors const & permeabilityAccessors, + PorosityAccessors const & porosityAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags, + real64 const omega, + integer const curNewton, + integer const continuation, + integer const miscible, + real64 const kappamin, + real64 const contMultiplier ) + : Base( numPhases, + rankOffset, + stencilWrapper, + dofNumberAccessor, + compFlowAccessors, + multiFluidAccessors, + capPressureAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs, + kernelFlags ), + m_pres_n( dissCompFlowAccessors.get( fields::flow::pressure_n {} ) ), + m_porosity_n( porosityAccessors.get( fields::porosity::porosity_n {} ) ), + m_volume( dissCompFlowAccessors.get( fields::elementVolume {} ) ), + m_compFrac( dissCompFlowAccessors.get( fields::flow::globalCompFraction {} ) ), + m_omegaDBC( omega ), + m_miscibleDBC( miscible ) + { + /// Step 1. Calculate the continuation parameter based on the current Newton iteration + m_kappaDBC = 1.0; // default value + + if( continuation ) // if continuation is enabled + { + if( curNewton >= newtonContinuationCutoffIteration ) + { + m_kappaDBC = kappamin; + } + else + { + for( int mp = 0; mp < curNewton; mp++ ) + { + m_kappaDBC *= contMultiplier; + } + m_kappaDBC = std::max( m_kappaDBC, kappamin ); + } + } + } + + /** + * @brief Compute the local flux contributions to the residual and Jacobian, including dissipation + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeFlux( localIndex const iconn, + typename Base::StackVariables & stack ) const + { + // *********************************************** + // First, we call the base computeFlux to compute: + // 1) compFlux and its derivatives, + // + // We use the lambda below (called **inside** the phase loop of the base computeFlux) to compute dissipation terms + Base::computeFlux( iconn, stack, [&] ( integer const ip, + integer const GEOS_UNUSED_PARAM( useNewGravity ), + localIndex const (&k)[2], + localIndex const (&seri)[2], + localIndex const (&sesri)[2], + localIndex const (&sei)[2], + localIndex const connectionIndex, + localIndex const k_up, + localIndex const er_up, + localIndex const esr_up, + localIndex const ei_up, + real64 const & potGrad, + real64 const & phaseFlux, + real64 const (&dPhaseFlux_dP)[2], + real64 const (&dPhaseFlux_dC)[2][numComp] ) + { + GEOS_UNUSED_VAR( k_up, potGrad, phaseFlux, dPhaseFlux_dP, dPhaseFlux_dC, er_up, esr_up, ei_up ); + + /// Storing dissipation flux and its derivatives locally + real64 dissFlux[numComp]{}; + real64 dDissFlux_dP[numFluxSupportPoints][numComp]{}; + real64 dDissFlux_dC[numFluxSupportPoints][numComp][numComp]{}; + real64 fluxPointCoef[numFluxSupportPoints] = {1.0, -1.0}; // for gradients + + real64 viscosityMult[3] = {1.0, 1.0, 1.0}; // for viscosity + + /// Step 2. Collect all contributions + real64 poreVolume_n = 0.0; // Pore volume contribution + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + poreVolume_n += m_volume[seri[ke]][sesri[ke]][sei[ke]] * m_porosity_n[seri[ke]][sesri[ke]][sei[ke]][0]; + } + poreVolume_n /= numFluxSupportPoints; + + // potential gradient contribution + // pressure + real64 pressure_gradient = 0; + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + pressure_gradient += fluxPointCoef[ke] * m_pres_n[seri[ke]][sesri[ke]][sei[ke]]; + + real64 const potential_gradient = LvArray::math::abs( pressure_gradient ); + + real64 grad_depth = 0; + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + grad_depth += fluxPointCoef[ke] * m_gravCoef[seri[ke]][sesri[ke]][sei[ke]]; + } + + // bias towards x and y direction for miscible + /* The point of this "directional coefficient" was to add less dissipation flux in the direction of gravity and + more in all other directions. These hard-coded values of 1000 and 100 were picked by some tuning and as + expected are not robust. Further research/testing is needed to generalize this idea. + */ + real64 directional_coef = 1.0; + if( m_miscibleDBC ) + { + directional_coef = initialDirectionalCoef; + if( LvArray::math::abs( grad_depth ) > 0.0 ) + { + real64 const d2 = LvArray::math::abs( grad_depth * grad_depth ); + if( multiplierDirectionalCoef / d2 < initialDirectionalCoef ) + directional_coef = multiplierDirectionalCoef / d2; + } + } + + // multiplier with all contributions + real64 const multiplier = m_kappaDBC * m_omegaDBC / poreVolume_n * m_dt * potential_gradient * directional_coef; + + /// Step 3. Compute the dissipation flux and its derivative + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + real64 const coef = multiplier * viscosityMult[ip] * stack.transmissibility[connectionIndex][ke]; + for( integer ic = 0; ic < numComp; ++ic ) + { + localIndex const er = seri[ke]; + localIndex const esr = sesri[ke]; + localIndex const ei = sei[ke]; + + // composition gradient contribution to the dissipation flux + dissFlux[ic] += coef * m_compFrac[er][esr][ei][ic]; + + dDissFlux_dP[ke][ic] = 0; // no dependency on pressure at n+1, compFrad is global component fraction (z_c) + + for( integer jc = 0; jc < numComp; ++jc ) + { + // composition gradient derivative with respect to component density contribution to the dissipation flux + dDissFlux_dC[ke][ic][jc] += coef * m_dCompFrac_dCompDens[er][esr][ei][ic][jc]; + } + } + } + + /// Step 4: add the dissipation flux and its derivatives to the residual and Jacobian + for( integer ic = 0; ic < numComp; ++ic ) + { + integer const eqIndex0 = k[0] * numEqn + ic; + integer const eqIndex1 = k[1] * numEqn + ic; + + stack.localFlux[eqIndex0] += m_dt * dissFlux[ic]; + stack.localFlux[eqIndex1] -= m_dt * dissFlux[ic]; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + localIndex const localDofIndexPres = k[ke] * numDof; + stack.localFluxJacobian[eqIndex0][localDofIndexPres] += m_dt * dDissFlux_dP[ke][ic]; + stack.localFluxJacobian[eqIndex1][localDofIndexPres] -= m_dt * dDissFlux_dP[ke][ic]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + localIndex const localDofIndexComp = localDofIndexPres + jc + 1; + stack.localFluxJacobian[eqIndex0][localDofIndexComp] += m_dt * dDissFlux_dC[ke][ic][jc]; + stack.localFluxJacobian[eqIndex1][localDofIndexComp] -= m_dt * dDissFlux_dC[ke][ic][jc]; + } + } + } + + } ); // end call to Base::computeFlux + + } + +protected: + + /// Views on flow properties at the previous converged time step + ElementViewConst< arrayView1d< real64 const > > const m_pres_n; + ElementViewConst< arrayView2d< real64 const > > const m_porosity_n; + + ElementViewConst< arrayView1d< real64 const > > const m_volume; + ElementViewConst< arrayView2d< real64 const, compflow::USD_COMP > > const m_compFrac; + + // DBC specific parameters + // input + real64 m_omegaDBC; + integer m_miscibleDBC; + // computed + real64 m_kappaDBC; +}; + +/** + * @class FluxComputeKernelFactory + */ +class FluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] hasCapPressure flag specifying whether capillary pressure is used or not + * @param[in] solverName name of the solver (to name accessors) + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + string const & dofKey, + integer const hasCapPressure, + integer const useTotalMassEquation, + string const & solverName, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + real64 const omega, + integer const curNewton, + integer const continuation, + integer const miscible, + real64 const kappamin, + real64 const contMultiplier ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_DOF = NC() + 1; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags; + if( hasCapPressure ) + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::CapPressure ); + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::TotalMassEquation ); + + using KERNEL_TYPE = FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + typename KERNEL_TYPE::CompFlowAccessors compFlowAccessors( elemManager, solverName ); + typename KERNEL_TYPE::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); + typename KERNEL_TYPE::CapPressureAccessors capPressureAccessors( elemManager, solverName ); + typename KERNEL_TYPE::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); + typename KERNEL_TYPE::PorosityAccessors porosityAccessors( elemManager, solverName ); + typename KERNEL_TYPE::DissCompFlowAccessors dissCompFlowAccessors( elemManager, solverName ); + + KERNEL_TYPE kernel( numPhases, rankOffset, stencilWrapper, dofNumberAccessor, compFlowAccessors, dissCompFlowAccessors, + multiFluidAccessors, capPressureAccessors, permeabilityAccessors, porosityAccessors, + dt, localMatrix, localRhs, kernelFlags, omega, curNewton, continuation, miscible, kappamin, contMultiplier ); + KERNEL_TYPE::template launch< POLICY >( stencilWrapper.size(), kernel ); + } ); + } +}; + +} // namespace DissipationCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DISSIPATIONFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluidUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluidUpdateKernel.hpp new file mode 100644 index 00000000000..f8483ce94c7 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluidUpdateKernel.hpp @@ -0,0 +1,77 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FluidUpdateKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUIDUPDATEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUIDUPDATEKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseBaseKernels +{ + +/******************************** FluidUpdateKernel ********************************/ + +struct FluidUpdateKernel +{ + template< typename POLICY, typename FLUID_WRAPPER > + static void + launch( localIndex const size, + FLUID_WRAPPER const & fluidWrapper, + arrayView1d< real64 const > const & pres, + arrayView1d< real64 const > const & temp, + arrayView2d< real64 const, compflow::USD_COMP > const & compFrac ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) + { + fluidWrapper.update( k, q, pres[k], temp[k], compFrac[k] ); + } + } ); + } + + template< typename POLICY, typename FLUID_WRAPPER > + static void + launch( SortedArrayView< localIndex const > const & targetSet, + FLUID_WRAPPER const & fluidWrapper, + arrayView1d< real64 const > const & pres, + arrayView1d< real64 const > const & temp, + arrayView2d< real64 const, compflow::USD_COMP > const & compFrac ) + { + forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + localIndex const k = targetSet[a]; + for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) + { + fluidWrapper.update( k, q, pres[k], temp[k], compFrac[k] ); + } + } ); + } +}; + +} // namespace thermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALCOMPOSITIONALMULTIPHASEBASEKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernel.hpp new file mode 100644 index 00000000000..83af007a79f --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernel.hpp @@ -0,0 +1,582 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.hpp" + +#include "codingUtilities/Utilities.hpp" +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PPUPhaseFlux.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/C1PPUPhaseFlux.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/IHUPhaseFlux.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/** + * @class FluxComputeKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > +class FluxComputeKernel : public FluxComputeKernelBase +{ +public: + + /// Compile time value for the number of components + static constexpr integer numComp = NUM_COMP; + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = NUM_DOF; + + /// Compute time value for the number of equations (all of them, except the volume balance equation) + static constexpr integer numEqn = NUM_DOF-1; + + /// Maximum number of elements at the face + static constexpr localIndex maxNumElems = STENCILWRAPPER::maxNumPointsInFlux; + + /// Maximum number of connections at the face + static constexpr localIndex maxNumConns = STENCILWRAPPER::maxNumConnections; + + /// Maximum number of points in the stencil + static constexpr localIndex maxStencilSize = STENCILWRAPPER::maxStencilSize; + + /// Number of flux support points (hard-coded for TFPA) + static constexpr integer numFluxSupportPoints = 2; + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor + * @param[in] compFlowAccessors + * @param[in] multiFluidAccessors + * @param[in] capPressureAccessors + * @param[in] permeabilityAccessors + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed together + */ + FluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + CapPressureAccessors const & capPressureAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< KernelFlags > kernelFlags ) + : FluxComputeKernelBase( numPhases, + rankOffset, + dofNumberAccessor, + compFlowAccessors, + multiFluidAccessors, + dt, + localMatrix, + localRhs, + kernelFlags ), + m_permeability( permeabilityAccessors.get( fields::permeability::permeability {} ) ), + m_dPerm_dPres( permeabilityAccessors.get( fields::permeability::dPerm_dPressure {} ) ), + m_phaseMob( compFlowAccessors.get( fields::flow::phaseMobility {} ) ), + m_dPhaseMob( compFlowAccessors.get( fields::flow::dPhaseMobility {} ) ), + m_phaseMassDens( multiFluidAccessors.get( fields::multifluid::phaseMassDensity {} ) ), + m_dPhaseMassDens( multiFluidAccessors.get( fields::multifluid::dPhaseMassDensity {} ) ), + m_phaseCapPressure( capPressureAccessors.get( fields::cappres::phaseCapPressure {} ) ), + m_dPhaseCapPressure_dPhaseVolFrac( capPressureAccessors.get( fields::cappres::dPhaseCapPressure_dPhaseVolFraction {} ) ), + m_stencilWrapper( stencilWrapper ), + m_seri( stencilWrapper.getElementRegionIndices() ), + m_sesri( stencilWrapper.getElementSubRegionIndices() ), + m_sei( stencilWrapper.getElementIndices() ) + { } + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables + { +public: + + /** + * @brief Constructor for the stack variables + * @param[in] size size of the stencil for this connection + * @param[in] numElems number of elements for this connection + */ + GEOS_HOST_DEVICE + StackVariables( localIndex const size, localIndex numElems ) + : stencilSize( size ), + numConnectedElems( numElems ), + dofColIndices( size * numDof ), + localFlux( numElems * numEqn ), + localFluxJacobian( numElems * numEqn, size * numDof ) + {} + + // Stencil information + + /// Stencil size for a given connection + localIndex const stencilSize; + /// Number of elements connected at a given connection + localIndex const numConnectedElems; + + // Transmissibility and derivatives + + /// Transmissibility + real64 transmissibility[maxNumConns][numFluxSupportPoints]{}; + /// Derivatives of transmissibility with respect to pressure + real64 dTrans_dPres[maxNumConns][numFluxSupportPoints]{}; + + // Local degrees of freedom and local residual/jacobian + + /// Indices of the matrix rows/columns corresponding to the dofs in this face + stackArray1d< globalIndex, maxNumElems * numDof > dofColIndices; + + /// Storage for the face local residual vector (all equations except volume balance) + stackArray1d< real64, maxNumElems * numEqn > localFlux; + /// Storage for the face local Jacobian matrix + stackArray2d< real64, maxNumElems * numEqn * maxStencilSize * numDof > localFluxJacobian; + }; + + + /** + * @brief Getter for the stencil size at this connection + * @param[in] iconn the connection index + * @return the size of the stencil at this connection + */ + GEOS_HOST_DEVICE + inline + localIndex stencilSize( localIndex const iconn ) const { return m_sei[iconn].size(); } + + /** + * @brief Getter for the number of elements at this connection + * @param[in] iconn the connection index + * @return the number of elements at this connection + */ + GEOS_HOST_DEVICE + inline + localIndex numPointsInFlux( localIndex const iconn ) const { return m_stencilWrapper.numPointsInFlux( iconn ); } + + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] iconn the connection index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + inline + void setup( localIndex const iconn, + StackVariables & stack ) const + { + // set degrees of freedom indices for this face + for( integer i = 0; i < stack.stencilSize; ++i ) + { + globalIndex const offset = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; + + for( integer jdof = 0; jdof < numDof; ++jdof ) + { + stack.dofColIndices[i * numDof + jdof] = offset + jdof; + } + } + } + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void computeFlux( localIndex const iconn, + StackVariables & stack, + FUNC && compFluxKernelOp = NoOpFunc{} ) const + { + + // first, compute the transmissibilities at this face + m_stencilWrapper.computeWeights( iconn, + m_permeability, + m_dPerm_dPres, + stack.transmissibility, + stack.dTrans_dPres ); + + + localIndex k[numFluxSupportPoints]; + localIndex connectionIndex = 0; + for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) + { + for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) + { + /// cell indices + localIndex const seri[numFluxSupportPoints] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; + localIndex const sesri[numFluxSupportPoints] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; + localIndex const sei[numFluxSupportPoints] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; + + // clear working arrays + real64 compFlux[numComp]{}; + real64 dCompFlux_dP[numFluxSupportPoints][numComp]{}; + real64 dCompFlux_dC[numFluxSupportPoints][numComp][numComp]{}; + + real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], + stack.transmissibility[connectionIndex][1] }; + + real64 const dTrans_dPres[numFluxSupportPoints] = { stack.dTrans_dPres[connectionIndex][0], + stack.dTrans_dPres[connectionIndex][1] }; + + //***** calculation of flux ***** + // loop over phases, compute and upwind phase flux and sum contributions to each component's flux + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + // create local work arrays + real64 potGrad = 0.0; + real64 phaseFlux = 0.0; + real64 dPhaseFlux_dP[numFluxSupportPoints]{}; + real64 dPhaseFlux_dC[numFluxSupportPoints][numComp]{}; + + localIndex k_up = -1; + + if( m_kernelFlags.isSet( KernelFlags::C1PPU ) ) + { + isothermalCompositionalMultiphaseFVMKernelUtilities::C1PPUPhaseFlux::compute< numComp, numFluxSupportPoints > + ( m_numPhases, + ip, + m_kernelFlags.isSet( KernelFlags::CapPressure ), + m_kernelFlags.isSet( KernelFlags::NewGravity ), + seri, sesri, sei, + trans, + dTrans_dPres, + m_pres, + m_gravCoef, + m_phaseMob, m_dPhaseMob, + m_phaseVolFrac, m_dPhaseVolFrac, + m_phaseCompFrac, m_dPhaseCompFrac, + m_dCompFrac_dCompDens, + m_phaseMassDens, m_dPhaseMassDens, + m_phaseCapPressure, m_dPhaseCapPressure_dPhaseVolFrac, + k_up, + potGrad, + phaseFlux, + dPhaseFlux_dP, + dPhaseFlux_dC, + compFlux, + dCompFlux_dP, + dCompFlux_dC ); + } + else if( m_kernelFlags.isSet( KernelFlags::IHU ) ) + { + isothermalCompositionalMultiphaseFVMKernelUtilities::IHUPhaseFlux::compute< numComp, numFluxSupportPoints > + ( m_numPhases, + ip, + m_kernelFlags.isSet( KernelFlags::CapPressure ), + m_kernelFlags.isSet( KernelFlags::NewGravity ), + seri, sesri, sei, + trans, + dTrans_dPres, + m_pres, + m_gravCoef, + m_phaseMob, m_dPhaseMob, + m_phaseVolFrac, m_dPhaseVolFrac, + m_phaseCompFrac, m_dPhaseCompFrac, + m_dCompFrac_dCompDens, + m_phaseMassDens, m_dPhaseMassDens, + m_phaseCapPressure, m_dPhaseCapPressure_dPhaseVolFrac, + k_up, + potGrad, + phaseFlux, + dPhaseFlux_dP, + dPhaseFlux_dC, + compFlux, + dCompFlux_dP, + dCompFlux_dC ); + } + else + { + isothermalCompositionalMultiphaseFVMKernelUtilities::PPUPhaseFlux::compute< numComp, numFluxSupportPoints > + ( m_numPhases, + ip, + m_kernelFlags.isSet( KernelFlags::CapPressure ), + m_kernelFlags.isSet( KernelFlags::NewGravity ), + seri, sesri, sei, + trans, + dTrans_dPres, + m_pres, + m_gravCoef, + m_phaseMob, m_dPhaseMob, + m_phaseVolFrac, m_dPhaseVolFrac, + m_phaseCompFrac, m_dPhaseCompFrac, + m_dCompFrac_dCompDens, + m_phaseMassDens, m_dPhaseMassDens, + m_phaseCapPressure, m_dPhaseCapPressure_dPhaseVolFrac, + k_up, + potGrad, + phaseFlux, + dPhaseFlux_dP, + dPhaseFlux_dC, + compFlux, + dCompFlux_dP, + dCompFlux_dC ); + } + + // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives + // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase + compFluxKernelOp( ip, m_kernelFlags.isSet( KernelFlags::NewGravity ), + k, seri, sesri, sei, connectionIndex, + k_up, seri[k_up], sesri[k_up], sei[k_up], potGrad, + phaseFlux, dPhaseFlux_dP, dPhaseFlux_dC ); + + } // loop over phases + + /// populate local flux vector and derivatives + for( integer ic = 0; ic < numComp; ++ic ) + { + integer const eqIndex0 = k[0] * numEqn + ic; + integer const eqIndex1 = k[1] * numEqn + ic; + + stack.localFlux[eqIndex0] += m_dt * compFlux[ic]; + stack.localFlux[eqIndex1] -= m_dt * compFlux[ic]; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + localIndex const localDofIndexPres = k[ke] * numDof; + stack.localFluxJacobian[eqIndex0][localDofIndexPres] += m_dt * dCompFlux_dP[ke][ic]; + stack.localFluxJacobian[eqIndex1][localDofIndexPres] -= m_dt * dCompFlux_dP[ke][ic]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + localIndex const localDofIndexComp = localDofIndexPres + jc + 1; + stack.localFluxJacobian[eqIndex0][localDofIndexComp] += m_dt * dCompFlux_dC[ke][ic][jc]; + stack.localFluxJacobian[eqIndex1][localDofIndexComp] -= m_dt * dCompFlux_dC[ke][ic][jc]; + } + } + } + connectionIndex++; + } // loop over k[1] + } // loop over k[0] + + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void complete( localIndex const iconn, + StackVariables & stack, + FUNC && assemblyKernelOp = NoOpFunc{} ) const + { + using namespace compositionalMultiphaseUtilities; + + if( m_kernelFlags.isSet( KernelFlags::TotalMassEquation ) ) + { + // Apply equation/variable change transformation(s) + stackArray1d< real64, maxStencilSize * numDof > work( stack.stencilSize * numDof ); + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numEqn, numDof * stack.stencilSize, stack.numConnectedElems, + stack.localFluxJacobian, work ); + shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numComp, numEqn, stack.numConnectedElems, + stack.localFlux ); + } + + // add contribution to residual and jacobian into: + // - the component mass balance equations (i = 0 to i = numComp-1) + // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels + for( integer i = 0; i < stack.numConnectedElems; ++i ) + { + if( m_ghostRank[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )] < 0 ) + { + globalIndex const globalRow = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; + localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); + GEOS_ASSERT_GE( localRow, 0 ); + GEOS_ASSERT_GT( m_localMatrix.numRows(), localRow + numComp ); + + for( integer ic = 0; ic < numComp; ++ic ) + { + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[localRow + ic], + stack.localFlux[i * numEqn + ic] ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > + ( localRow + ic, + stack.dofColIndices.data(), + stack.localFluxJacobian[i * numEqn + ic].dataIfContiguous(), + stack.stencilSize * numDof ); + } + + // call the lambda to assemble additional terms, such as thermal terms + assemblyKernelOp( i, localRow ); + } + } + } + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numConnections the number of connections + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numConnections, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numConnections, [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), + kernelComponent.numPointsInFlux( iconn ) ); + + kernelComponent.setup( iconn, stack ); + kernelComponent.computeFlux( iconn, stack ); + kernelComponent.complete( iconn, stack ); + } ); + } + +protected: + + /// Views on permeability + ElementViewConst< arrayView3d< real64 const > > const m_permeability; + ElementViewConst< arrayView3d< real64 const > > const m_dPerm_dPres; + + /// Views on phase mobilities + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_phaseMob; + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const m_dPhaseMob; + + /// Views on phase mass densities + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_phaseMassDens; + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dPhaseMassDens; + + /// Views on phase capillary pressure + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const m_phaseCapPressure; + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const m_dPhaseCapPressure_dPhaseVolFrac; + + // Stencil information + + /// Reference to the stencil wrapper + STENCILWRAPPER const m_stencilWrapper; + + /// Connection to element maps + typename STENCILWRAPPER::IndexContainerViewConstType const m_seri; + typename STENCILWRAPPER::IndexContainerViewConstType const m_sesri; + typename STENCILWRAPPER::IndexContainerViewConstType const m_sei; + +}; + +/** + * @class FluxComputeKernelFactory + */ +class FluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] hasCapPressure flag specifying whether capillary pressure is used or not + * @param[in] solverName name of the solver (to name accessors) + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + string const & dofKey, + integer const hasCapPressure, + integer const useTotalMassEquation, + integer const useNewGravity, + UpwindingParameters upwindingParams, + string const & solverName, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_DOF = NC() + 1; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + BitFlags< KernelFlags > kernelFlags; + if( hasCapPressure ) + kernelFlags.set( KernelFlags::CapPressure ); + if( useTotalMassEquation ) + kernelFlags.set( KernelFlags::TotalMassEquation ); + if( useNewGravity ) + kernelFlags.set( KernelFlags::NewGravity ); + if( upwindingParams.upwindingScheme == UpwindingScheme::C1PPU && + isothermalCompositionalMultiphaseFVMKernelUtilities::epsC1PPU > 0 ) + kernelFlags.set( KernelFlags::C1PPU ); + else if( upwindingParams.upwindingScheme == UpwindingScheme::IHU ) + kernelFlags.set( KernelFlags::IHU ); + + + using kernelType = FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); + typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); + typename kernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); + typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); + + kernelType kernel( numPhases, rankOffset, stencilWrapper, dofNumberAccessor, + compFlowAccessors, multiFluidAccessors, capPressureAccessors, permeabilityAccessors, + dt, localMatrix, localRhs, kernelFlags ); + kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); + } ); + } +}; + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.cpp new file mode 100644 index 00000000000..a5a01550c52 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.cpp @@ -0,0 +1,65 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FluxComputeKernelBase.cpp + */ + +#include "physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.hpp" + +#include "finiteVolume/CellElementStencilTPFA.hpp" +#include "finiteVolume/SurfaceElementStencil.hpp" +#include "finiteVolume/EmbeddedSurfaceToCellStencil.hpp" +#include "finiteVolume/FaceElementToCellStencil.hpp" +#include "mesh/utilities/MeshMapUtilities.hpp" + +namespace geos +{ +using namespace constitutive; + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/******************************** FluxComputeKernelBase ********************************/ + +FluxComputeKernelBase::FluxComputeKernelBase( integer const numPhases, + globalIndex const rankOffset, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< KernelFlags > kernelFlags ) + : m_numPhases( numPhases ), + m_rankOffset( rankOffset ), + m_dt( dt ), + m_dofNumber( dofNumberAccessor.toNestedViewConst() ), + m_ghostRank( compFlowAccessors.get( fields::ghostRank {} ) ), + m_gravCoef( compFlowAccessors.get( fields::flow::gravityCoefficient {} ) ), + m_pres( compFlowAccessors.get( fields::flow::pressure {} ) ), + m_phaseVolFrac( compFlowAccessors.get( fields::flow::phaseVolumeFraction {} ) ), + m_dPhaseVolFrac( compFlowAccessors.get( fields::flow::dPhaseVolumeFraction {} ) ), + m_dCompFrac_dCompDens( compFlowAccessors.get( fields::flow::dGlobalCompFraction_dGlobalCompDensity {} ) ), + m_phaseCompFrac( multiFluidAccessors.get( fields::multifluid::phaseCompFraction {} ) ), + m_dPhaseCompFrac( multiFluidAccessors.get( fields::multifluid::dPhaseCompFraction {} ) ), + m_localMatrix( localMatrix ), + m_localRhs( localRhs ), + m_kernelFlags( kernelFlags ) +{} + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.hpp new file mode 100644 index 00000000000..ff96044c991 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.hpp @@ -0,0 +1,182 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FluxComputeKernelBase.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUXCOMPUTEKERNELBASE_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUXCOMPUTEKERNELBASE_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/capillaryPressure/CapillaryPressureFields.hpp" +#include "constitutive/capillaryPressure/CapillaryPressureBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "constitutive/permeability/PermeabilityBase.hpp" +#include "constitutive/permeability/PermeabilityFields.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" + + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +enum class KernelFlags +{ + /// Flag to specify whether capillary pressure is used or not + CapPressure = 1 << 0, // 1 + /// Flag indicating whether total mass equation is formed or not + TotalMassEquation = 1 << 1, // 2 + /// Flag indicating whether new gravity treatment is used or not + NewGravity = 1 << 2, // 4 + /// Flag indicating whether C1-PPU is used or not + C1PPU = 1 << 3, // 8 + /// Flag indicating whether IHU is used or not + IHU = 1 << 4 // 16 + /// Add more flags like that if needed: + // Flag6 = 1 << 5, // 32 + // Flag7 = 1 << 6, // 64 + // Flag8 = 1 << 7 //128 +}; + +/******************************** FluxComputeKernelBase ********************************/ + +/** + * @brief Base class for FluxComputeKernel that holds all data not dependent + * on template parameters (like stencil type and number of components/dofs). + */ +class FluxComputeKernelBase +{ +public: + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using DofNumberAccessor = ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > >; + + using CompFlowAccessors = + StencilAccessors< fields::ghostRank, + fields::flow::gravityCoefficient, + fields::flow::pressure, + fields::flow::dGlobalCompFraction_dGlobalCompDensity, + fields::flow::phaseVolumeFraction, + fields::flow::dPhaseVolumeFraction, + fields::flow::phaseMobility, + fields::flow::dPhaseMobility >; + using MultiFluidAccessors = + StencilMaterialAccessors< constitutive::MultiFluidBase, + fields::multifluid::phaseDensity, + fields::multifluid::dPhaseDensity, + fields::multifluid::phaseMassDensity, + fields::multifluid::dPhaseMassDensity, + fields::multifluid::phaseCompFraction, + fields::multifluid::dPhaseCompFraction >; + + using CapPressureAccessors = + StencilMaterialAccessors< constitutive::CapillaryPressureBase, + fields::cappres::phaseCapPressure, + fields::cappres::dPhaseCapPressure_dPhaseVolFraction >; + + using PermeabilityAccessors = + StencilMaterialAccessors< constitutive::PermeabilityBase, + fields::permeability::permeability, + fields::permeability::dPerm_dPressure >; + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofNumberAccessor accessor for the dof numbers + * @param[in] compFlowAccessors accessor for wrappers registered by the solver + * @param[in] multiFluidAccessors accessor for wrappers registered by the multifluid model + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed all together + */ + FluxComputeKernelBase( integer const numPhases, + globalIndex const rankOffset, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< KernelFlags > kernelFlags ); + +protected: + + /// Number of fluid phases + integer const m_numPhases; + + /// Offset for my MPI rank + globalIndex const m_rankOffset; + + /// Time step size + real64 const m_dt; + + /// Views on dof numbers + ElementViewConst< arrayView1d< globalIndex const > > const m_dofNumber; + + /// Views on ghost rank numbers and gravity coefficients + ElementViewConst< arrayView1d< integer const > > const m_ghostRank; + ElementViewConst< arrayView1d< real64 const > > const m_gravCoef; + + // Primary and secondary variables + + /// Views on pressure + ElementViewConst< arrayView1d< real64 const > > const m_pres; + + /// Views on phase volume fractions + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_phaseVolFrac; + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const m_dPhaseVolFrac; + + /// Views on derivatives of comp fractions + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const m_dCompFrac_dCompDens; + + /// Views on phase component fractions + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const m_phaseCompFrac; + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const m_dPhaseCompFrac; + + // Residual and jacobian + + /// View on the local CRS matrix + CRSMatrixView< real64, globalIndex const > const m_localMatrix; + /// View on the local RHS + arrayView1d< real64 > const m_localRhs; + + BitFlags< KernelFlags > const m_kernelFlags; +}; + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUXCOMPUTEKERNELBASE_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/GlobalComponentFractionKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/GlobalComponentFractionKernel.hpp new file mode 100644 index 00000000000..c5317e3a659 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/GlobalComponentFractionKernel.hpp @@ -0,0 +1,144 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file GlobalComponentFractionKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_GLOBALCOMPONENTFRACTIONKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_GLOBALCOMPONENTFRACTIONKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** GlobalComponentFractionKernel ********************************/ + +/** + * @class GlobalComponentFractionKernel + * @tparam NUM_COMP number of fluid components + * @brief Define the interface for the update kernel in charge of computing the phase volume fractions + */ +template< integer NUM_COMP > +class GlobalComponentFractionKernel : public PropertyKernelBase< NUM_COMP > +{ +public: + + using Base = PropertyKernelBase< NUM_COMP >; + using Base::numComp; + + /** + * @brief Constructor + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + GlobalComponentFractionKernel( ObjectManagerBase & subRegion ) + : Base(), + m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ), + m_compFrac( subRegion.getField< fields::flow::globalCompFraction >() ), + m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ) + {} + + /** + * @brief Compute the phase volume fractions in an element + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[in] phaseVolFractionKernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void compute( localIndex const ei, + FUNC && compFractionKernelOp = NoOpFunc{} ) const + { + arraySlice1d< real64 const, compflow::USD_COMP - 1 > const compDens = m_compDens[ei]; + arraySlice1d< real64, compflow::USD_COMP - 1 > const compFrac = m_compFrac[ei]; + arraySlice2d< real64, compflow::USD_COMP_DC - 1 > const dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; + + real64 totalDensity = 0.0; + + for( integer ic = 0; ic < numComp; ++ic ) + { + totalDensity += compDens[ic]; + } + + real64 const totalDensityInv = 1.0 / totalDensity; + + for( integer ic = 0; ic < numComp; ++ic ) + { + compFrac[ic] = compDens[ic] * totalDensityInv; + for( integer jc = 0; jc < numComp; ++jc ) + { + dCompFrac_dCompDens[ic][jc] = -compFrac[ic] * totalDensityInv; + } + dCompFrac_dCompDens[ic][ic] += totalDensityInv; + } + + compFractionKernelOp( compFrac, dCompFrac_dCompDens ); + } + +protected: + + // inputs + + // Views on component densities + arrayView2d< real64 const, compflow::USD_COMP > m_compDens; + + // outputs + + // Views on component fraction + arrayView2d< real64, compflow::USD_COMP > m_compFrac; + arrayView3d< real64, compflow::USD_COMP_DC > m_dCompFrac_dCompDens; + +}; + +/** + * @class GlobalComponentFractionKernelFactory + */ +class GlobalComponentFractionKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComp the number of fluid components + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + ObjectManagerBase & subRegion ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + GlobalComponentFractionKernel< NUM_COMP > kernel( subRegion ); + GlobalComponentFractionKernel< NUM_COMP >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_GLOBALCOMPONENTFRACTIONKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/HydrostaticPressureKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/HydrostaticPressureKernel.hpp new file mode 100644 index 00000000000..a3495e46a94 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/HydrostaticPressureKernel.hpp @@ -0,0 +1,356 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file HydrostaticPressureKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_HYDROSTATICPRESSUREKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_HYDROSTATICPRESSUREKERNEL_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "functions/TableFunction.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** HydrostaticPressureKernel ********************************/ + +struct HydrostaticPressureKernel +{ + + // TODO: this type of constants should be centralized somewhere or provided by fluid model + static real64 constexpr MIN_FOR_PHASE_PRESENCE = 1e-12; + + enum class ReturnType : integer + { + FAILED_TO_CONVERGE = 0, + DETECTED_MULTIPHASE_FLOW = 1, + SUCCESS = 2 + }; + + template< typename FLUID_WRAPPER > + static ReturnType + computeHydrostaticPressure( integer const numComps, + integer const numPhases, + integer const ipInit, + integer const maxNumEquilIterations, + real64 const & equilTolerance, + real64 const (&gravVector)[ 3 ], + FLUID_WRAPPER fluidWrapper, + arrayView1d< TableFunction::KernelWrapper const > compFracTableWrappers, + TableFunction::KernelWrapper tempTableWrapper, + real64 const & refElevation, + real64 const & refPres, + arraySlice1d< real64 const > const & refPhaseMassDens, + real64 const & newElevation, + real64 & newPres, + arraySlice1d< real64 > const & newPhaseMassDens ) + { + // fluid properties at this elevation + StackArray< real64, 2, constitutive::MultiFluidBase::MAX_NUM_COMPONENTS, compflow::LAYOUT_COMP > compFrac( 1, numComps ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseFrac( 1, 1, numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseDens( 1, 1, numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseMassDens( 1, 1, numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseVisc( 1, 1, numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseEnthalpy( 1, 1, numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseInternalEnergy( 1, 1, numPhases ); + StackArray< real64, 4, constitutive::MultiFluidBase::MAX_NUM_PHASES *constitutive::MultiFluidBase::MAX_NUM_COMPONENTS, + constitutive::multifluid::LAYOUT_PHASE_COMP > phaseCompFrac( 1, 1, numPhases, numComps ); + real64 totalDens = 0.0; + + bool isSinglePhaseFlow = true; + + // Step 1: compute the hydrostatic pressure at the current elevation + + real64 const gravCoef = gravVector[2] * ( refElevation - newElevation ); + real64 const temp = tempTableWrapper.compute( &newElevation ); + for( integer ic = 0; ic < numComps; ++ic ) + { + compFrac[0][ic] = compFracTableWrappers[ic].compute( &newElevation ); + } + + // Step 2: guess the pressure with the refPhaseMassDensity + + real64 pres0 = refPres - refPhaseMassDens[ipInit] * gravCoef; + real64 pres1 = 0.0; + + // Step 3: compute the mass density at this elevation using the guess, and update pressure + + constitutive::MultiFluidBase::KernelWrapper::computeValues( fluidWrapper, + pres0, + temp, + compFrac[0], + phaseFrac[0][0], + phaseDens[0][0], + phaseMassDens[0][0], + phaseVisc[0][0], + phaseEnthalpy[0][0], + phaseInternalEnergy[0][0], + phaseCompFrac[0][0], + totalDens ); + pres1 = refPres - 0.5 * ( refPhaseMassDens[ipInit] + phaseMassDens[0][0][ipInit] ) * gravCoef; + + // Step 4: fixed-point iteration until convergence + + bool equilHasConverged = false; + for( integer eqIter = 0; eqIter < maxNumEquilIterations; ++eqIter ) + { + + // check convergence + equilHasConverged = ( LvArray::math::abs( pres0 - pres1 ) < equilTolerance ); + pres0 = pres1; + + // if converged, check number of phases and move on + if( equilHasConverged ) + { + // make sure that the fluid is single-phase, other we have to issue a warning (for now) + // if only one phase is mobile, we are in good shape (unfortunately it is hard to access relperm from here) + localIndex numberOfPhases = 0; + for( integer ip = 0; ip < numPhases; ++ip ) + { + if( phaseFrac[0][0][ip] > MIN_FOR_PHASE_PRESENCE ) + { + numberOfPhases++; + } + } + if( numberOfPhases > 1 ) + { + isSinglePhaseFlow = false; + } + + break; + } + + // compute the mass density at this elevation using the previous pressure, and compute the new pressure + constitutive::MultiFluidBase::KernelWrapper::computeValues( fluidWrapper, + pres0, + temp, + compFrac[0], + phaseFrac[0][0], + phaseDens[0][0], + phaseMassDens[0][0], + phaseVisc[0][0], + phaseEnthalpy[0][0], + phaseInternalEnergy[0][0], + phaseCompFrac[0][0], + totalDens ); + pres1 = refPres - 0.5 * ( refPhaseMassDens[ipInit] + phaseMassDens[0][0][ipInit] ) * gravCoef; + } + + // Step 5: save the hydrostatic pressure and the corresponding density + + newPres = pres1; + for( integer ip = 0; ip < numPhases; ++ip ) + { + newPhaseMassDens[ip] = phaseMassDens[0][0][ip]; + } + + if( !equilHasConverged ) + { + return ReturnType::FAILED_TO_CONVERGE; + } + else if( !isSinglePhaseFlow ) + { + return ReturnType::DETECTED_MULTIPHASE_FLOW; + } + else + { + return ReturnType::SUCCESS; + } + } + + template< typename FLUID_WRAPPER > + static ReturnType + launch( localIndex const size, + integer const numComps, + integer const numPhases, + integer const ipInit, + integer const maxNumEquilIterations, + real64 const equilTolerance, + real64 const (&gravVector)[ 3 ], + real64 const & minElevation, + real64 const & elevationIncrement, + real64 const & datumElevation, + real64 const & datumPres, + FLUID_WRAPPER fluidWrapper, + arrayView1d< TableFunction::KernelWrapper const > compFracTableWrappers, + TableFunction::KernelWrapper tempTableWrapper, + arrayView1d< arrayView1d< real64 > const > elevationValues, + arrayView1d< real64 > pressureValues ) + { + + ReturnType returnVal = ReturnType::SUCCESS; + + // Step 1: compute the phase mass densities at datum + + // datum fluid properties + array2d< real64, compflow::LAYOUT_COMP > datumCompFrac( 1, numComps ); + array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseFrac( 1, 1, numPhases ); + array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseDens( 1, 1, numPhases ); + array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseMassDens( 1, 1, numPhases ); + array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseVisc( 1, 1, numPhases ); + array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseEnthalpy( 1, 1, numPhases ); + array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseInternalEnergy( 1, 1, numPhases ); + array4d< real64, constitutive::multifluid::LAYOUT_PHASE_COMP > datumPhaseCompFrac( 1, 1, numPhases, numComps ); + real64 datumTotalDens = 0.0; + + real64 const datumTemp = tempTableWrapper.compute( &datumElevation ); + for( integer ic = 0; ic < numComps; ++ic ) + { + datumCompFrac[0][ic] = compFracTableWrappers[ic].compute( &datumElevation ); + } + constitutive::MultiFluidBase::KernelWrapper::computeValues( fluidWrapper, + datumPres, + datumTemp, + datumCompFrac[0], + datumPhaseFrac[0][0], + datumPhaseDens[0][0], + datumPhaseMassDens[0][0], + datumPhaseVisc[0][0], + datumPhaseEnthalpy[0][0], + datumPhaseInternalEnergy[0][0], + datumPhaseCompFrac[0][0], + datumTotalDens ); + + // Step 2: find the closest elevation to datumElevation + + forAll< parallelHostPolicy >( size, [=] ( localIndex const i ) + { + real64 const elevation = minElevation + i * elevationIncrement; + elevationValues[0][i] = elevation; + } ); + integer const iRef = LvArray::sortedArrayManipulation::find( elevationValues[0].begin(), + elevationValues[0].size(), + datumElevation ); + + // Step 3: compute the mass density and pressure at the reference elevation + + array2d< real64 > phaseMassDens( pressureValues.size(), numPhases ); + // temporary array without permutation to compile on Lassen + array1d< real64 > datumPhaseMassDensTmp( numPhases ); + for( integer ip = 0; ip < numPhases; ++ip ) + { + datumPhaseMassDensTmp[ip] = datumPhaseMassDens[0][0][ip]; + } + + ReturnType const refReturnVal = + computeHydrostaticPressure( numComps, + numPhases, + ipInit, + maxNumEquilIterations, + equilTolerance, + gravVector, + fluidWrapper, + compFracTableWrappers, + tempTableWrapper, + datumElevation, + datumPres, + datumPhaseMassDensTmp, + elevationValues[0][iRef], + pressureValues[iRef], + phaseMassDens[iRef] ); + if( refReturnVal == ReturnType::FAILED_TO_CONVERGE ) + { + return ReturnType::FAILED_TO_CONVERGE; + } + else if( refReturnVal == ReturnType::DETECTED_MULTIPHASE_FLOW ) + { + returnVal = ReturnType::DETECTED_MULTIPHASE_FLOW; + } + + // Step 4: for each elevation above the reference elevation, compute the pressure + + localIndex const numEntriesAboveRef = size - iRef - 1; + forAll< serialPolicy >( numEntriesAboveRef, [=, &returnVal] ( localIndex const i ) + { + ReturnType const returnValAboveRef = + computeHydrostaticPressure( numComps, + numPhases, + ipInit, + maxNumEquilIterations, + equilTolerance, + gravVector, + fluidWrapper, + compFracTableWrappers, + tempTableWrapper, + elevationValues[0][iRef+i], + pressureValues[iRef+i], + phaseMassDens[iRef+i], + elevationValues[0][iRef+i+1], + pressureValues[iRef+i+1], + phaseMassDens[iRef+i+1] ); + if( returnValAboveRef == ReturnType::FAILED_TO_CONVERGE ) + { + returnVal = ReturnType::FAILED_TO_CONVERGE; + } + else if( ( returnValAboveRef == ReturnType::DETECTED_MULTIPHASE_FLOW ) && + ( returnVal != ReturnType::FAILED_TO_CONVERGE ) ) + { + returnVal = ReturnType::DETECTED_MULTIPHASE_FLOW; + } + + } ); + + // Step 5: for each elevation below the reference elevation, compute the pressure + + localIndex const numEntriesBelowRef = iRef; + forAll< serialPolicy >( numEntriesBelowRef, [=, &returnVal] ( localIndex const i ) + { + ReturnType const returnValBelowRef = + computeHydrostaticPressure( numComps, + numPhases, + ipInit, + maxNumEquilIterations, + equilTolerance, + gravVector, + fluidWrapper, + compFracTableWrappers, + tempTableWrapper, + elevationValues[0][iRef-i], + pressureValues[iRef-i], + phaseMassDens[iRef-i], + elevationValues[0][iRef-i-1], + pressureValues[iRef-i-1], + phaseMassDens[iRef-i-1] ); + if( returnValBelowRef == ReturnType::FAILED_TO_CONVERGE ) + { + returnVal = ReturnType::FAILED_TO_CONVERGE; + } + else if( ( returnValBelowRef == ReturnType::DETECTED_MULTIPHASE_FLOW ) && + ( returnVal != ReturnType::FAILED_TO_CONVERGE ) ) + { + returnVal = ReturnType::DETECTED_MULTIPHASE_FLOW; + } + + } ); + + return returnVal; + } + +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_HYDROSTATICPRESSUREKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/IHUPhaseFlux.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/IHUPhaseFlux.hpp new file mode 100644 index 00000000000..98ee6989a18 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/IHUPhaseFlux.hpp @@ -0,0 +1,2017 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file IHUPhaseFlux.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_IHUPHASEFLUX_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_IHUPHASEFLUX_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "constitutive/capillaryPressure/layouts.hpp" +#include "mesh/ElementRegionManager.hpp" + + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernelUtilities +{ + +template< typename VIEWTYPE > +using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + +using Deriv = constitutive::multifluid::DerivativeOffset; + +/************************* HELPERS ******************/ +namespace UpwindHelpers +{ + +static constexpr double minTotMob = 1e-12; + +template< localIndex numComp, localIndex numFluxSupportPoints, class UPWIND > +GEOS_HOST_DEVICE +static void +upwindMobilityViscous( localIndex const numPhase, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + real64 const totFlux, //in fine should be a ElemnetViewConst once seq form are in place + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + integer const hasCapPressure, + localIndex & upwindDir, + real64 & mobility, + real64( &dMobility_dP), + real64 ( & dMobility_dC)[numComp] + ) +{ + + //reinit + mobility = 0.0; + dMobility_dP = 0.0; + for( localIndex ic = 0; ic < numComp; ++ic ) + { + dMobility_dC[ic] = 0.0; + } + + UPWIND scheme; + scheme.template getUpwindDirectionViscous< numComp, numFluxSupportPoints, UPWIND >( numPhase, + ip, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totFlux, + pres, + gravCoef, + phaseMob, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + upwindDir ); + + localIndex const er_up = seri[upwindDir]; + localIndex const esr_up = sesri[upwindDir]; + localIndex const ei_up = sei[upwindDir]; + + if( std::fabs( phaseMob[er_up][esr_up][ei_up][ip] ) > 1e-20 ) + { + mobility = phaseMob[er_up][esr_up][ei_up][ip]; + dMobility_dP = dPhaseMob[er_up][esr_up][ei_up][ip][Deriv::dP]; + for( localIndex ic = 0; ic < numComp; ++ic ) + { + dMobility_dC[ic] = dPhaseMob[er_up][esr_up][ei_up][ip][Deriv::dC + ic]; + } + } +} + +template< localIndex numComp, localIndex numFluxSupportPoints, class UPWIND > +GEOS_HOST_DEVICE +static void +upwindMobilityGravity( localIndex const numPhase, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + real64 const totFlux, //in fine should be a ElemnetViewConst once seq form are in place + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + integer const hasCapPressure, + integer const useNewGravity, + localIndex & upwindDir, + real64 & mobility, + real64( &dMobility_dP), + real64 ( & dMobility_dC)[numComp] + ) +{ + + //reinit + mobility = 0.0; + dMobility_dP = 0.0; + for( localIndex ic = 0; ic < numComp; ++ic ) + { + dMobility_dC[ic] = 0.0; + } + + UPWIND scheme; + scheme.template getUpwindDirectionGravity< numComp, numFluxSupportPoints, UPWIND >( numPhase, + ip, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totFlux, + pres, + gravCoef, + phaseMob, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + phaseVolFrac, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + useNewGravity, + upwindDir ); + + localIndex const er_up = seri[upwindDir]; + localIndex const esr_up = sesri[upwindDir]; + localIndex const ei_up = sei[upwindDir]; + + if( std::fabs( phaseMob[er_up][esr_up][ei_up][ip] ) > 1e-20 ) + { + mobility = phaseMob[er_up][esr_up][ei_up][ip]; + dMobility_dP = dPhaseMob[er_up][esr_up][ei_up][ip][Deriv::dP]; + for( localIndex ic = 0; ic < numComp; ++ic ) + { + dMobility_dC[ic] = dPhaseMob[er_up][esr_up][ei_up][ip][Deriv::dC + ic]; + } + } +} + +template< localIndex numComp, localIndex numFluxSupportPoints, class UPWIND > +GEOS_HOST_DEVICE +static void +upwindMobilityCapillary( localIndex const numPhase, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + real64 const totFlux, //in fine should be a ElemnetViewConst once seq form are in place + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + integer const hasCapPressure, + localIndex & upwindDir, + real64 & mobility, + real64( &dMobility_dP), + real64 ( & dMobility_dC)[numComp] + ) +{ + + //reinit + mobility = 0.0; + dMobility_dP = 0.0; + for( localIndex ic = 0; ic < numComp; ++ic ) + { + dMobility_dC[ic] = 0.0; + } + + UPWIND scheme; + scheme.template getUpwindDirectionCapillary< numComp, numFluxSupportPoints, UPWIND >( numPhase, + ip, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totFlux, + pres, + gravCoef, + phaseMob, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + upwindDir ); + + localIndex const er_up = seri[upwindDir]; + localIndex const esr_up = sesri[upwindDir]; + localIndex const ei_up = sei[upwindDir]; + + if( std::fabs( phaseMob[er_up][esr_up][ei_up][ip] ) > 1e-20 ) + { + mobility = phaseMob[er_up][esr_up][ei_up][ip]; + dMobility_dP = dPhaseMob[er_up][esr_up][ei_up][ip][Deriv::dP]; + for( localIndex ic = 0; ic < numComp; ++ic ) + { + dMobility_dC[ic] = dPhaseMob[er_up][esr_up][ei_up][ip][Deriv::dC + ic]; + } + } +} + +template< localIndex numComp, localIndex numFluxSupportPoints, class UPWIND > +GEOS_HOST_DEVICE +static void +computeFractionalFlowViscous( localIndex const numPhase, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + localIndex const & k_up_ppu, + real64 const totFlux, + real64 const totMob, + real64 const (&dTotMob_dP)[numFluxSupportPoints], + real64 const (&dTotMob_dC)[numFluxSupportPoints][numComp], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + integer const hasCapPressure, + localIndex & k_up_main, + real64 & fractionalFlow, + real64 ( & dFractionalFlow_dP)[numFluxSupportPoints], + real64 ( & dFractionalFlow_dC)[numFluxSupportPoints][numComp] ) +{ + // get var to memorized the numerator mobility properly upwinded + real64 mainMob{}; + real64 dMMob_dP{}; + real64 dMMob_dC[numComp]{}; + +// real64 totMob{}; +// real64 dTotMob_dP[numFluxSupportPoints]{}; +// real64 dTotMob_dC[numFluxSupportPoints][numComp]{}; + + //reinit + //fractional flow too low to let the upstream phase flow + k_up_main = -1; //to throw error if unmodified + fractionalFlow = 0; + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dFractionalFlow_dP[ke] = 0; + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dFractionalFlow_dC[ke][jc] = 0; + } + } + + localIndex k_up; + real64 mob{}; + real64 dMob_dP{}; + real64 dMob_dC[numComp]{}; + + upwindMobilityViscous< numComp, numFluxSupportPoints, UPWIND >( numPhase, + ip, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totFlux, + pres, + gravCoef, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + phaseMob, + dPhaseMob, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + k_up, + mob, + dMob_dP, + dMob_dC ); + + k_up_main = k_up; + mainMob = mob; + dMMob_dP = dMob_dP; + for( localIndex ic = 0; ic < numComp; ++ic ) + { + dMMob_dC[ic] = dMob_dC[ic]; + } + + //guard against no flow region + if( std::fabs( mainMob ) > 1e-20 ) + { + fractionalFlow = mainMob / LvArray::math::max( totMob, minTotMob ); + dFractionalFlow_dP[k_up_main] = dMMob_dP / LvArray::math::max( totMob, minTotMob ); + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dFractionalFlow_dC[k_up_main][jc] = dMMob_dC[jc] / totMob; + + } + + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dFractionalFlow_dP[ke] -= fractionalFlow * dTotMob_dP[k_up_ppu] / LvArray::math::max( totMob, minTotMob ); + + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dFractionalFlow_dC[ke][jc] -= fractionalFlow * dTotMob_dC[k_up_ppu][jc] / LvArray::math::max( totMob, minTotMob ); + } + } + } +} + + +template< localIndex numComp, localIndex numFluxSupportPoints, class UPWIND > +GEOS_HOST_DEVICE +static void +computeFractionalFlowGravity( localIndex const numPhase, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + localIndex const & k_up_ppu, + real64 const totFlux, + real64 const totMob, + real64 const (&dTotMob_dP)[numFluxSupportPoints], + real64 const (&dTotMob_dC)[numFluxSupportPoints][numComp], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + integer const hasCapPressure, + integer const useNewGravity, + localIndex & k_up_main, + real64 & fractionalFlow, + real64 ( & dFractionalFlow_dP)[numFluxSupportPoints], + real64 ( & dFractionalFlow_dC)[numFluxSupportPoints][numComp] + ) +{ + // get var to memorized the numerator mobility properly upwinded + real64 mainMob{}; + real64 dMMob_dP{}; + real64 dMMob_dC[numComp]{}; + + //reinit + //fractional flow too low to let the upstream phase flow + k_up_main = -1; //to throw error if unmodified + fractionalFlow = 0; + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dFractionalFlow_dP[ke] = 0; + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dFractionalFlow_dC[ke][jc] = 0; + } + } + + + localIndex k_up; + real64 mob{}; + real64 dMob_dP{}; + real64 dMob_dC[numComp]{}; + + upwindMobilityGravity< numComp, numFluxSupportPoints, UPWIND >( numPhase, + ip, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totFlux, + pres, + gravCoef, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + phaseMob, + dPhaseMob, + phaseVolFrac, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + useNewGravity, + k_up, + mob, + dMob_dP, + dMob_dC ); + + k_up_main = k_up; + mainMob = mob; + dMMob_dP = dMob_dP; + for( localIndex ic = 0; ic < numComp; ++ic ) + { + dMMob_dC[ic] = dMob_dC[ic]; + } + + //guard against no flow region + if( std::fabs( mainMob ) > 1e-20 ) + { + fractionalFlow = mainMob / LvArray::math::max( totMob, minTotMob ); + dFractionalFlow_dP[k_up_main] = dMMob_dP / LvArray::math::max( totMob, minTotMob ); + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dFractionalFlow_dC[k_up_main][jc] = dMMob_dC[jc] / totMob; + + } + + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dFractionalFlow_dP[ke] -= fractionalFlow * dTotMob_dP[k_up_ppu] / LvArray::math::max( totMob, minTotMob ); + + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dFractionalFlow_dC[ke][jc] -= fractionalFlow * dTotMob_dC[k_up_ppu][jc] / LvArray::math::max( totMob, minTotMob ); + } + } + } +} + +template< localIndex numComp, localIndex numFluxSupportPoints, class UPWIND > +GEOS_HOST_DEVICE +static void +computeFractionalFlowCapillary( localIndex const numPhase, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + localIndex const & k_up_ppu, + real64 const totFlux, + real64 const totMob, + real64 const (&dTotMob_dP)[numFluxSupportPoints], + real64 const (&dTotMob_dC)[numFluxSupportPoints][numComp], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + integer const hasCapPressure, + localIndex & k_up_main, + real64 & fractionalFlow, + real64 ( & dFractionalFlow_dP)[numFluxSupportPoints], + real64 ( & dFractionalFlow_dC)[numFluxSupportPoints][numComp] + ) +{ + // get var to memorized the numerator mobility properly upwinded + real64 mainMob{}; + real64 dMMob_dP{}; + real64 dMMob_dC[numComp]{}; + + //reinit + //fractional flow too low to let the upstream phase flow + k_up_main = -1; //to throw error if unmodified + fractionalFlow = 0; + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dFractionalFlow_dP[ke] = 0; + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dFractionalFlow_dC[ke][jc] = 0; + } + } + + localIndex k_up; + real64 mob{}; + real64 dMob_dP{}; + real64 dMob_dC[numComp]{}; + + upwindMobilityCapillary< numComp, numFluxSupportPoints, UPWIND >( numPhase, + ip, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totFlux, + pres, + gravCoef, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + phaseMob, + dPhaseMob, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + k_up, + mob, + dMob_dP, + dMob_dC ); + + k_up_main = k_up; + mainMob = mob; + dMMob_dP = dMob_dP; + for( localIndex ic = 0; ic < numComp; ++ic ) + { + dMMob_dC[ic] = dMob_dC[ic]; + } + + //guard against no flow region + if( std::fabs( mainMob ) > 1e-20 ) + { + fractionalFlow = mainMob / LvArray::math::max( totMob, minTotMob ); + dFractionalFlow_dP[k_up_main] = dMMob_dP / LvArray::math::max( totMob, minTotMob ); + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dFractionalFlow_dC[k_up_main][jc] = dMMob_dC[jc] / LvArray::math::max( totMob, minTotMob ); + + } + + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dFractionalFlow_dP[ke] -= fractionalFlow * dTotMob_dP[k_up_ppu] / LvArray::math::max( totMob, minTotMob ); + + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dFractionalFlow_dC[ke][jc] -= fractionalFlow * dTotMob_dC[k_up_ppu][jc] / LvArray::math::max( totMob, minTotMob ); + } + } + } +} + +/** + * @brief Struct defining formation of potential from different Physics (flagged by enum type T) to be used + * in Upwind discretization schemes + * @tparam numComp number of component + * @tparam T the concerned physics (Viscou,Gravity or Capillary) + * @tparam numFluxSupportPoints number of point in the stencil + */ +struct computePotentialViscous +{ + + template< localIndex numComp, localIndex numFluxSupportPoints > + GEOS_HOST_DEVICE + static void compute( localIndex const GEOS_UNUSED_PARAM( numPhase ), + localIndex const GEOS_UNUSED_PARAM( ip ), + localIndex const (&GEOS_UNUSED_PARAM( seri ))[numFluxSupportPoints], + localIndex const (&GEOS_UNUSED_PARAM( sesri ))[numFluxSupportPoints], + localIndex const (&GEOS_UNUSED_PARAM( sei ))[numFluxSupportPoints], + real64 const (&GEOS_UNUSED_PARAM( transmissibility ))[2], + real64 const (&GEOS_UNUSED_PARAM( dTrans_dPres ))[2], + real64 const totFlux, + ElementViewConst< arrayView1d< real64 const > > const & GEOS_UNUSED_PARAM( gravCoef ), + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & + GEOS_UNUSED_PARAM( dCompFrac_dCompDens ), + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & + GEOS_UNUSED_PARAM( phaseMassDens ), + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & + GEOS_UNUSED_PARAM( dPhaseMassDens ), + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & + GEOS_UNUSED_PARAM( dPhaseVolFrac ), + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & + GEOS_UNUSED_PARAM( phaseCapPressure ), + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & + GEOS_UNUSED_PARAM( dPhaseCapPressure_dPhaseVolFrac ), + real64 & pot, + real64( &GEOS_UNUSED_PARAM( dPot_dPres ))[numFluxSupportPoints], + real64( &GEOS_UNUSED_PARAM( dPot_dComp ))[numFluxSupportPoints][numComp], + real64( &GEOS_UNUSED_PARAM( dProp_dComp ))[numComp] ) + { + pot = totFlux; + //could be relevant for symmetry to include derivative + + } +}; + +/*! @copydoc computePotential + */ +struct computePotentialGravity +{ + /*! @copydoc computePotential::compute + * + * @brief specialization for gravitational driving forces which only relies on total flux + */ + template< localIndex numComp, localIndex numFluxSupportPoints > + GEOS_HOST_DEVICE + static void compute( localIndex const GEOS_UNUSED_PARAM( numPhase ), + localIndex const ip, + integer const useNewGravity, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + real64 const GEOS_UNUSED_PARAM( totFlux ), + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & + GEOS_UNUSED_PARAM( dPhaseVolFrac ), + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & + GEOS_UNUSED_PARAM( phaseCapPressure ), + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & + GEOS_UNUSED_PARAM( dPhaseCapPressure_dPhaseVolFrac ), + real64 & pot, + real64 ( & dPot_dPres )[numFluxSupportPoints], + real64 (& dPot_dComp )[numFluxSupportPoints][numComp], + real64 ( & dProp_dComp )[numComp] ) + { + //working arrays + real64 densMean{}; + real64 dDensMean_dPres[numFluxSupportPoints]{}; + real64 dDensMean_dComp[numFluxSupportPoints][numComp]{}; + + //init + pot = 0.0; + for( localIndex i = 0; i < numFluxSupportPoints; ++i ) + { + dPot_dPres[i] = 0.0; + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dPot_dComp[i][jc] = 0.0; + dProp_dComp[jc] = 0.0; + } + } + + calculateMeanDensity( useNewGravity, ip, seri, sesri, sei, phaseVolFrac, dCompFrac_dCompDens, phaseMassDens, dPhaseMassDens, dProp_dComp, + densMean, dDensMean_dPres, dDensMean_dComp ); + + // compute potential difference MPFA-style + for( localIndex i = 0; i < numFluxSupportPoints; ++i ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + real64 const gravD = transmissibility[i] * gravCoef[er][esr][ei]; + real64 const dGravD_dP = dTrans_dPres[i] * gravCoef[er][esr][ei]; + pot += densMean * gravD; + + // need to add contributions from both cells the mean density depends on + for( localIndex j = 0; j < numFluxSupportPoints; ++j ) + { + dPot_dPres[j] += dDensMean_dPres[j] * gravD + densMean * dGravD_dP; + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dPot_dComp[j][jc] += dDensMean_dComp[j][jc] * gravD; + } + } + } + } + + template< localIndex numComp, localIndex numFluxSupportPoints > + GEOS_HOST_DEVICE + static void calculateMeanDensity( integer const useNewGravity, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + real64 (& dProp_dComp)[numComp], + real64 & densMean, real64 (& dDensMean_dPres)[numFluxSupportPoints], real64 (& dDensMean_dComp)[numFluxSupportPoints][numComp] ) + { + integer denom = 0; + for( localIndex i = 0; i < numFluxSupportPoints; ++i ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + bool const phaseExists = (phaseVolFrac[er][esr][ei][ip] > 0); + if( useNewGravity && !phaseExists ) + { + continue; + } + + // density + real64 const density = phaseMassDens[er][esr][ei][0][ip]; + real64 const dDens_dPres = dPhaseMassDens[er][esr][ei][0][ip][Deriv::dP]; + + applyChainRule( numComp, + dCompFrac_dCompDens[er][esr][ei], + dPhaseMassDens[er][esr][ei][0][ip], + dProp_dComp, + Deriv::dC ); + + // average density and derivatives + densMean += density; + dDensMean_dPres[i] = dDens_dPres; + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dDensMean_dComp[i][jc] = dProp_dComp[jc]; + } + denom++; + } + if( denom > 1 ) + { + densMean /= denom; + for( localIndex i = 0; i < numFluxSupportPoints; ++i ) + { + dDensMean_dPres[i] /= denom; + for( integer jc = 0; jc < numComp; ++jc ) + { + dDensMean_dComp[i][jc] /= denom; + } + } + } + } +}; + +/*! @copydoc computePotential + */ +struct computePotentialCapillary +{ + /*! @copydoc computePotential::compute + * + * @brief specialization for capillary driving forces which only relies on total flux + */ + template< localIndex numComp, localIndex numFluxSupportPoints > + GEOS_HOST_DEVICE + static void compute( localIndex const numPhase, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + real64 const GEOS_UNUSED_PARAM( totFlux ), + ElementViewConst< arrayView1d< real64 const > > const & GEOS_UNUSED_PARAM( gravCoef ), + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & + GEOS_UNUSED_PARAM( dCompFrac_dCompDens ), + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & + GEOS_UNUSED_PARAM( phaseMassDens ), + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & + GEOS_UNUSED_PARAM( dPhaseMassDens ), + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + real64 & pot, + real64 ( & dPot_dPres)[numFluxSupportPoints], + real64 (& dPot_dComp)[numFluxSupportPoints][numComp], + real64( &GEOS_UNUSED_PARAM( dProp_dComp ))[numComp] ) + { + + + for( localIndex i = 0; i < numFluxSupportPoints; ++i ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + pot += transmissibility[i] * phaseCapPressure[er][esr][ei][0][ip]; + // need to add contributions from both cells + for( localIndex jp = 0; jp < numPhase; ++jp ) + { + + real64 const dCapPressure_dS = dPhaseCapPressure_dPhaseVolFrac[er][esr][ei][0][ip][jp]; + dPot_dPres[i] += + transmissibility[i] * dCapPressure_dS * dPhaseVolFrac[er][esr][ei][jp][Deriv::dP] + + dTrans_dPres[i] * phaseCapPressure[er][esr][ei][0][jp]; + + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dPot_dComp[i][jc] += transmissibility[i] * dCapPressure_dS * + dPhaseVolFrac[er][esr][ei][jp][Deriv::dC + jc]; + } + } + } + } +}; + +/// Form potential-related parts of fluxes + +template< localIndex numComp, localIndex numFluxSupportPoints, class UPWIND > +GEOS_HOST_DEVICE +static void computePotentialFluxesGravity( localIndex const numPhase, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + localIndex const & k_up_ppu, + real64 const totFlux, + real64 const totMob, + real64 const (&dTotMob_dP)[numFluxSupportPoints], + real64 const (&dTotMob_dC)[numFluxSupportPoints][numComp], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + localIndex const hasCapPressure, + integer const useNewGravity, + localIndex( &k_up), + localIndex (&k_up_o), + real64 & phaseFlux, + real64 (& dPhaseFlux_dP)[numFluxSupportPoints], + real64 ( & dPhaseFlux_dC)[numFluxSupportPoints][numComp] ) +{ + + real64 fflow{}; + real64 dFflow_dP[numFluxSupportPoints]{}; + real64 dFflow_dC[numFluxSupportPoints][numComp]{}; + + real64 pot{}; + real64 dPot_dP[numFluxSupportPoints]{}; + real64 dPot_dC[numFluxSupportPoints][numComp]{}; + real64 dProp_dC[numComp]{}; + + // + UpwindHelpers::computePotentialGravity::compute< numComp, numFluxSupportPoints >( numPhase, + ip, + useNewGravity, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totFlux, + gravCoef, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + phaseVolFrac, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + pot, + dPot_dP, + dPot_dC, + dProp_dC ); + + // and the fractional flow for gravitational part as \lambda_i^{up}/\sum_{numPhase}(\lambda_k^{up}) with up decided upon + // the Upwind strategy + UpwindHelpers::computeFractionalFlowGravity< numComp, numFluxSupportPoints, UPWIND >( numPhase, + ip, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + k_up_ppu, + totFlux, + totMob, + dTotMob_dP, + dTotMob_dC, + pres, + gravCoef, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + phaseMob, + dPhaseMob, + phaseVolFrac, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + useNewGravity, + k_up, + fflow, + dFflow_dP, + dFflow_dC ); + + + for( localIndex jp = 0; jp < numPhase; ++jp ) + { + if( ip != jp ) + { + + real64 potOther{}; + real64 dPotOther_dP[numFluxSupportPoints]{}; + real64 dPotOther_dC[numFluxSupportPoints][numComp]{}; + real64 dPropOther_dC[numComp]{}; + + //Fetch pot for phase j!=i defined as \rho_j g dz/dx + UpwindHelpers::computePotentialGravity::compute< numComp, numFluxSupportPoints >( numPhase, + jp, + useNewGravity, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totFlux, + gravCoef, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + phaseVolFrac, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + potOther, + dPotOther_dP, + dPotOther_dC, + dPropOther_dC ); + + //Eventually get the mobility of the second phase + real64 mobOther{}; + real64 dMobOther_dP{}; + real64 dMobOther_dC[numComp]{}; + + // and the other mobility for gravitational part as \lambda_j^{up} with up decided upon + // the Upwind strategy - Note that it should be the same as the gravitational fractional flow + + UpwindHelpers::upwindMobilityGravity< numComp, numFluxSupportPoints, UPWIND >( numPhase, + jp, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totFlux, + pres, + gravCoef, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + phaseMob, + dPhaseMob, + phaseVolFrac, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + useNewGravity, + k_up_o, + mobOther, + dMobOther_dP, + dMobOther_dC ); + + + // Assembling gravitational flux phase-wise as \phi_{i,g} = \sum_{k\nei} \lambda_k^{up,g} f_k^{up,g} (G_i - G_k) + phaseFlux -= fflow * mobOther * (pot - potOther); + dPhaseFlux_dP[k_up_o] -= fflow * dMobOther_dP * (pot - potOther); + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[k_up_o][jc] -= fflow * dMobOther_dC[jc] * (pot - potOther); + } + + //mob related part of dFflow_dP is only upstream defined but totMob related is defined everywhere + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dPhaseFlux_dP[ke] -= dFflow_dP[ke] * mobOther * (pot - potOther); + + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[ke][jc] -= dFflow_dC[ke][jc] * mobOther * (pot - potOther); + } + } + + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dPhaseFlux_dP[ke] -= fflow * mobOther * (dPot_dP[ke] - dPotOther_dP[ke]); + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[ke][jc] -= fflow * mobOther * (dPot_dC[ke][jc] - dPotOther_dC[ke][jc]); + } + } + } + } + +} + +template< localIndex numComp, localIndex numFluxSupportPoints, class UPWIND > +GEOS_HOST_DEVICE +static void computePotentialFluxesCapillary( localIndex const numPhase, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + localIndex const & k_up_ppu, + real64 const totFlux, + real64 const totMob, + real64 const (&dTotMob_dP)[numFluxSupportPoints], + real64 const (&dTotMob_dC)[numFluxSupportPoints][numComp], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + localIndex const hasCapPressure, + localIndex( &k_up), + localIndex (&k_up_o), + real64 & phaseFlux, + real64 (& dPhaseFlux_dP)[numFluxSupportPoints], + real64 ( & dPhaseFlux_dC)[numFluxSupportPoints][numComp] ) +{ + + real64 fflow{}; + real64 dFflow_dP[numFluxSupportPoints]{}; + real64 dFflow_dC[numFluxSupportPoints][numComp]{}; + + real64 pot{}; + real64 dPot_dP[numFluxSupportPoints]{}; + real64 dPot_dC[numFluxSupportPoints][numComp]{}; + real64 dProp_dC[numComp]{}; + + UpwindHelpers::computePotentialCapillary::compute< numComp, numFluxSupportPoints >( numPhase, + ip, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totFlux, + gravCoef, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + pot, + dPot_dP, + dPot_dC, + dProp_dC ); + + // and the fractional flow for gravitational part as \lambda_i^{up}/\sum_{numPhase}(\lambda_k^{up}) with up decided upon + // the Upwind strategy + UpwindHelpers::computeFractionalFlowCapillary< numComp, numFluxSupportPoints, UPWIND >( numPhase, + ip, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + k_up_ppu, + totFlux, + totMob, + dTotMob_dP, + dTotMob_dC, + pres, + gravCoef, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + phaseMob, + dPhaseMob, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + k_up, + fflow, + dFflow_dP, + dFflow_dC ); + + + for( localIndex jp = 0; jp < numPhase; ++jp ) + { + if( ip != jp ) + { + + real64 potOther{}; + real64 dPotOther_dP[numFluxSupportPoints]{}; + real64 dPotOther_dC[numFluxSupportPoints][numComp]{}; + real64 dPropOther_dC[numComp]{}; + + //Fetch pot for phase j!=i defined as \rho_j g dz/dx + UpwindHelpers::computePotentialCapillary::compute< numComp, numFluxSupportPoints >( numPhase, + jp, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totFlux, + gravCoef, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + potOther, + dPotOther_dP, + dPotOther_dC, + dPropOther_dC ); + + //Eventually get the mobility of the second phase + real64 mobOther{}; + real64 dMobOther_dP{}; + real64 dMobOther_dC[numComp]{}; + + // and the other mobility for gravitational part as \lambda_j^{up} with up decided upon + // the Upwind strategy - Note that it should be the same as the gravitational fractional flow + + UpwindHelpers::upwindMobilityCapillary< numComp, numFluxSupportPoints, UPWIND >( numPhase, + jp, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totFlux, + pres, + gravCoef, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + phaseMob, + dPhaseMob, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + k_up_o, + mobOther, + dMobOther_dP, + dMobOther_dC ); + + + // Assembling gravitational flux phase-wise as \phi_{i,g} = \sum_{k\nei} \lambda_k^{up,g} f_k^{up,g} (G_i - G_k) + phaseFlux -= fflow * mobOther * (pot - potOther); + dPhaseFlux_dP[k_up_o] -= fflow * dMobOther_dP * (pot - potOther); + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[k_up_o][jc] -= fflow * dMobOther_dC[jc] * (pot - potOther); + } + + //mob related part of dFflow_dP is only upstream defined but totMob related is defined everywhere + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dPhaseFlux_dP[ke] -= dFflow_dP[ke] * mobOther * (pot - potOther); + + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[ke][jc] -= dFflow_dC[ke][jc] * mobOther * (pot - potOther); + } + } + + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dPhaseFlux_dP[ke] -= fflow * mobOther * (dPot_dP[ke] - dPotOther_dP[ke]); + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[ke][jc] -= fflow * mobOther * (dPot_dC[ke][jc] - dPotOther_dC[ke][jc]); + } + } + } + } +} + +}//end of struct UpwindHelpers + +/************************* UPWIND ******************/ + +/** + * @brief Template base class for different upwind Scheme + * @tparam T physics concerned by the scheme if specialized + */ +class UpwindScheme +{ + +public: + + //default ctor + UpwindScheme() = default; + + //usual copy ctor + UpwindScheme( UpwindScheme const & scheme ) = default; + + //default move ctor + UpwindScheme( UpwindScheme && ) = default; + + //deleted copy and move assignement + UpwindScheme & operator=( UpwindScheme const & ) = delete; + + UpwindScheme & operator=( UpwindScheme && ) = delete; + + virtual ~UpwindScheme() = default; + + template< localIndex numComp, localIndex numFluxSupportPoints, class UPWIND > + GEOS_HOST_DEVICE + inline + void getUpwindDirectionViscous( localIndex const numPhase, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + real64 const totFlux, //in fine should be a ElemnetViewConst once seq form are in place + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + integer const hasCapPressure, + localIndex & upwindDir + ) + { + real64 pot{}; + + /// each derived concrete class has to define a computePotential method that is calling UpwindScheme::potential method with a specific + /// lamda defining how to get these potentials + UPWIND::template computePotentialViscous< numComp, numFluxSupportPoints >( numPhase, + ip, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totFlux, + pres, + gravCoef, + phaseMob, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + pot ); + + //all definition has been changed to fit pot>0 => first cell is upstream + upwindDir = (pot > 0) ? 0 : 1; + } + + + template< localIndex numComp, localIndex numFluxSupportPoints, class UPWIND > + GEOS_HOST_DEVICE + void getUpwindDirectionGravity( localIndex const numPhase, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + real64 const totFlux, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + integer const hasCapPressure, + integer const useNewGravity, + localIndex & upwindDir + ) + { + real64 pot{}; + + /// each derived concrete class has to define a computePotential method that is calling UpwindScheme::potential method with a specific + /// lamda defining how to get these potentials + UPWIND::template computePotentialGravity< numComp, numFluxSupportPoints >( numPhase, + ip, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totFlux, + pres, + gravCoef, + phaseMob, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + phaseVolFrac, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + useNewGravity, + pot ); + + //all definition has been changed to fit pot>0 => first cell is upstream + upwindDir = (pot >= 0) ? 0 : 1; + } + + + template< localIndex numComp, localIndex numFluxSupportPoints, class UPWIND > + GEOS_HOST_DEVICE + void getUpwindDirectionCapillary( localIndex const numPhase, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + real64 const totFlux, //in fine should be a ElemnetViewConst once seq form are in + // place + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + integer const hasCapPressure, + localIndex & upwindDir + ) + { + real64 pot{}; + + // each derived concrete class has to define a computePotential method that is calling UpwindScheme::potential method with a specific + // lamda defining how to get these potentials + UPWIND::template computePotentialCapillary< numComp, numFluxSupportPoints >( numPhase, + ip, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totFlux, + pres, + gravCoef, + phaseMob, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + pot ); + + //all definition has been changed to fit pot>0 => first cell is upstream + upwindDir = (pot >= 0) ? 0 : 1; + } + + + + // templated way of evaluating the potential (to the exception of viscous one) which relies on + // up-or-downwinded mobility terms pre-multiplying potential differences + template< localIndex numComp, localIndex numFluxSupportPoints, typename LAMBDA > + GEOS_HOST_DEVICE + static void potential( localIndex numPhase, + localIndex ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + real64 & weightedPotential, + LAMBDA && fn ) + { + //getPhase Pot + real64 pot{}; + real64 pot_dP[numFluxSupportPoints]{}; + real64 pot_dC[numFluxSupportPoints][numComp]{}; + real64 dProp_dC[numComp]{}; + + fn( ip, pot, pot_dP, pot_dC, dProp_dC ); + + localIndex const k_up = 0; + localIndex const k_dw = 1; + + //loop other other phases to form + for( localIndex jp = 0; jp < numPhase; ++jp ) + { + if( jp != ip ) + { + localIndex const er_up = seri[k_up]; + localIndex const esr_up = sesri[k_up]; + localIndex const ei_up = sei[k_up]; + + localIndex const er_dw = seri[k_dw]; + localIndex const esr_dw = sesri[k_dw]; + localIndex const ei_dw = sei[k_dw]; + + real64 potOther{}; + real64 potOther_dP[numFluxSupportPoints]{}; + real64 potOther_dC[numFluxSupportPoints][numComp]{}; + real64 dPropOther_dC[numComp]{}; + + fn( jp, potOther, potOther_dP, potOther_dC, dPropOther_dC ); + + real64 const mob_up = phaseMob[er_up][esr_up][ei_up][jp]; + real64 const mob_dw = phaseMob[er_dw][esr_dw][ei_dw][jp]; + + weightedPotential += (pot - potOther >= 0) ? mob_dw * (potOther - pot) : mob_up * (potOther - pot); + + } + } + } + +}; + +/** + * @brief Class describing the Hybrid Upwind scheme as defined in "Consistent upwinding for sequential fully implicit + * multiscale compositional simulation" (Moncorge,2020) + */ +class HybridUpwind : public UpwindScheme +{ + +public: + template< localIndex numComp, localIndex numFluxSupportPoints > + GEOS_HOST_DEVICE + static + void computePotentialViscous( localIndex const numPhase, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + real64 const totalFlux, + ElementViewConst< arrayView1d< real64 const > > const & GEOS_UNUSED_PARAM( pres ), + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & + GEOS_UNUSED_PARAM( phaseMob ), + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + integer const GEOS_UNUSED_PARAM( hasCapPressure ), + real64 & potential + ) + { + real64 dPot_dP[numFluxSupportPoints]{}; + real64 dPot_dC[numFluxSupportPoints][numComp]{}; + real64 dProp_dC[numComp]{}; + + + UpwindHelpers::computePotentialViscous::compute< numComp, numFluxSupportPoints >( + numPhase, + ip, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totalFlux, + gravCoef, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + potential, + dPot_dP, + dPot_dC, + dProp_dC ); + } + + template< localIndex numComp, localIndex numFluxSupportPoints > + GEOS_HOST_DEVICE + static + void computePotentialGravity( localIndex const numPhase, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + real64 const totalFlux, + ElementViewConst< arrayView1d< real64 const > > const & GEOS_UNUSED_PARAM( pres ), + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + integer const GEOS_UNUSED_PARAM( hasCapPressure ), + integer const useNewGravity, + real64 & potential + ) + { + + //Form total velocity + potential = 0; + + //the arg lambda allows us to access some genericity + UpwindScheme::template potential< numComp, numFluxSupportPoints >( numPhase, ip, seri, sesri, sei, + phaseMob, potential, + [&]( localIndex ipp, + real64 & potential_, + real64 (& dPotential_dP_)[numFluxSupportPoints], + real64 (& dPotential_dC_)[numFluxSupportPoints][numComp], + real64 (& dProp_dC)[numComp] ) { + + UpwindHelpers::computePotentialGravity::compute< numComp, numFluxSupportPoints >( + numPhase, + ipp, + useNewGravity, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totalFlux, + gravCoef, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + phaseVolFrac, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + potential_, + dPotential_dP_, + dPotential_dC_, + dProp_dC ); + + } ); + } + + + template< localIndex numComp, localIndex numFluxSupportPoints > + GEOS_HOST_DEVICE + static + void computePotentialCapillary( localIndex const numPhase, + localIndex const ip, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&transmissibility)[2], + real64 const (&dTrans_dPres)[2], + real64 const totalFlux, + ElementViewConst< arrayView1d< real64 const > > const & GEOS_UNUSED_PARAM( pres ), + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & + phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + integer const GEOS_UNUSED_PARAM( hasCapPressure ), + real64 & potential ) + + { + + //Form total velocity + potential = 0; + + //the arg lambda allows us to access some genericity + UpwindScheme::template potential< numComp, numFluxSupportPoints >( numPhase, ip, seri, sesri, sei, + phaseMob, potential, + [&]( localIndex ipp, + real64 & potential_, + real64 (& dPotential_dP_)[numFluxSupportPoints], + real64 (& dPotential_dC_)[numFluxSupportPoints][numComp], + real64 (& dProp_dC)[numComp] ) { + + UpwindHelpers::computePotentialCapillary::compute< numComp, numFluxSupportPoints >( + numPhase, + ipp, + seri, + sesri, + sei, + transmissibility, + dTrans_dPres, + totalFlux, + gravCoef, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + potential_, + dPotential_dP_, + dPotential_dC_, + dProp_dC ); + } ); + } + +}; + +/*** IHU ***/ + +struct IHUPhaseFlux +{ + + using UPWIND_SCHEME = HybridUpwind; + + /** + * @brief Form the Implicit Hybrid Upwind from pressure gradient and gravitational head + * @tparam numComp number of components + * @tparam numFluxSupportPoints number of flux support points + * @param numPhase number of phases + * @param ip phase index + * @param hasCapPressure flag indicating if there is capillary pressure + * @param seri arraySlice of the stencil-implied element region index + * @param sesri arraySlice of the stencil-implied element subregion index + * @param sei arraySlice of the stencil-implied element index + * @param trans transmissibility at the connection + * @param dTrans_dPres derivative of transmissibility wrt pressure + * @param pres pressure + * @param gravCoef gravitational coefficient + * @param phaseMob phase mobility + * @param dPhaseMob derivative of phase mobility wrt pressure, temperature, comp density + * @param dPhaseVolFrac derivative of phase volume fraction wrt pressure, temperature, comp density + * @param dCompFrac_dCompDens derivative of component fraction wrt component density + * @param phaseMassDens phase mass density + * @param dPhaseMassDens derivative of phase mass density wrt pressure, temperature, comp fraction + * @param phaseCapPressure phase capillary pressure + * @param dPhaseCapPressure_dPhaseVolFrac derivative of phase capillary pressure wrt phase volume fraction + * @param k_up uptream index for this phase + * @param potGrad potential gradient for this phase + * @param phaseFlux phase flux + * @param dPhaseFlux_dP derivative of phase flux wrt pressure + * @param dPhaseFlux_dC derivative of phase flux wrt comp density + */ + template< integer numComp, integer numFluxSupportPoints > + GEOS_HOST_DEVICE + static void + compute( integer const numPhase, + integer const ip, + integer const hasCapPressure, + integer const useNewGravity, + localIndex const ( &seri )[numFluxSupportPoints], + localIndex const ( &sesri )[numFluxSupportPoints], + localIndex const ( &sei )[numFluxSupportPoints], + real64 const ( &trans )[2], + real64 const ( &dTrans_dPres )[2], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + localIndex & k_up, + real64 & potGrad, + real64 ( &phaseFlux ), + real64 ( & dPhaseFlux_dP )[numFluxSupportPoints], + real64 ( & dPhaseFlux_dC )[numFluxSupportPoints][numComp], + real64 ( & compFlux )[numComp], + real64 ( & dCompFlux_dP )[numFluxSupportPoints][numComp], + real64 ( & dCompFlux_dC )[numFluxSupportPoints][numComp][numComp] ) + { + + //loop over all phases to form total velocity + real64 totFlux{}; + real64 dTotFlux_dP[numFluxSupportPoints]{}; + real64 dTotFlux_dC[numFluxSupportPoints][numComp]{}; + + //store totMob upwinded by PPU for later schemes + real64 totMob{}; + real64 dTotMob_dP[numFluxSupportPoints]{}; + real64 dTotMob_dC[numFluxSupportPoints][numComp]{}; + localIndex k_up_ppu = -1; + + //unelegant but need dummy when forming PPU total velocity + real64 dummy[numComp]; + real64 dDummy_dP[numFluxSupportPoints][numComp]; + real64 dDummy_dC[numFluxSupportPoints][numComp][numComp]; + + + for( integer jp = 0; jp < numPhase; ++jp ) + { + PPUPhaseFlux::compute( numPhase, jp, hasCapPressure, useNewGravity, + seri, sesri, sei, + trans, dTrans_dPres, + pres, gravCoef, + phaseMob, dPhaseMob, + phaseVolFrac, dPhaseVolFrac, + phaseCompFrac, dPhaseCompFrac, + dCompFrac_dCompDens, + phaseMassDens, dPhaseMassDens, + phaseCapPressure, dPhaseCapPressure_dPhaseVolFrac, + k_up_ppu, potGrad, + phaseFlux, dPhaseFlux_dP, dPhaseFlux_dC, + dummy, dDummy_dP, dDummy_dC ); + + totFlux += phaseFlux; + + phaseFlux = 0.; + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dTotFlux_dP[ke] += dPhaseFlux_dP[ke]; + totMob += phaseMob[seri[ke]][sesri[ke]][sei[ke]][jp]; + dTotMob_dP[ke] += dPhaseMob[seri[ke]][sesri[ke]][sei[ke]][jp][Deriv::dP]; + dPhaseFlux_dP[ke] = 0.; + + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dTotFlux_dC[ke][jc] += dPhaseFlux_dC[ke][jc]; + dTotMob_dC[ke][jc] += dPhaseMob[seri[ke]][sesri[ke]][sei[ke]][jp][Deriv::dC + jc]; + dPhaseFlux_dC[ke][jc] = 0.; + } + } + } + + //fractional flow loop with IHU + //maybe needed to have density out for upwinding + + // choose upstream cell + // create local work arrays + real64 viscousPhaseFlux{}; + real64 dViscousPhaseFlux_dP[numFluxSupportPoints]{}; + real64 dViscousPhaseFlux_dC[numFluxSupportPoints][numComp]{}; + + real64 fractionalFlow{}; + real64 dFractionalFlow_dP[numFluxSupportPoints]{}; + real64 dFractionalFlow_dC[numFluxSupportPoints][numComp]{}; + + // and the fractional flow for viscous part as \lambda_i^{up}/\sum_{NP}(\lambda_j^{up}) with up decided upon + // the Upwind strategy + UpwindHelpers::computeFractionalFlowViscous< numComp, numFluxSupportPoints, + UPWIND_SCHEME >( numPhase, + ip, + seri, + sesri, + sei, + trans, + dTrans_dPres, + k_up_ppu, + totFlux, + totMob, + dTotMob_dP, + dTotMob_dC, + pres, + gravCoef, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + phaseMob, + dPhaseMob, + dPhaseVolFrac, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + k_up, + fractionalFlow, + dFractionalFlow_dP, + dFractionalFlow_dC ); + + + /// Assembling the viscous flux (and derivatives) from fractional flow and total velocity as \phi_{\mu} = f_i^{up,\mu} uT + viscousPhaseFlux = fractionalFlow * totFlux; + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dViscousPhaseFlux_dP[ke] += dFractionalFlow_dP[ke] * totFlux; + + + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dViscousPhaseFlux_dC[ke][jc] += dFractionalFlow_dC[ke][jc] * totFlux; + } + } + + //NON-FIXED UT -- to be canceled out if considered fixed + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dViscousPhaseFlux_dP[ke] += fractionalFlow * dTotFlux_dP[ke]; + + + for( localIndex jc = 0; jc < numComp; ++jc ) + { + dViscousPhaseFlux_dC[ke][jc] += fractionalFlow * dTotFlux_dC[ke][jc]; + } + } + //distribute on phaseComponentFlux here + PhaseComponentFlux::compute( ip, k_up, + seri, sesri, sei, + phaseCompFrac, dPhaseCompFrac, dCompFrac_dCompDens, + viscousPhaseFlux, dViscousPhaseFlux_dP, dViscousPhaseFlux_dC, + compFlux, dCompFlux_dP, dCompFlux_dC ); + + // accumulate in the flux and its derivatives + phaseFlux += viscousPhaseFlux; + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dPhaseFlux_dP[ke] += dViscousPhaseFlux_dP[ke]; + + + for( localIndex ic = 0; ic < numComp; ++ic ) + dPhaseFlux_dC[ke][ic] += dViscousPhaseFlux_dC[ke][ic]; + } + + /// Assembling the gravitational flux (and derivatives) from fractional flow and total velocity as \phi_{g} = f_i^{up,g} uT + localIndex k_up_g = -1; + localIndex k_up_og = -1; + + real64 gravitationalPhaseFlux{}; + real64 gravitationalPhaseFlux_dP[numFluxSupportPoints]{}; + real64 gravitationalPhaseFlux_dC[numFluxSupportPoints][numComp]{}; + + UpwindHelpers::computePotentialFluxesGravity< numComp, + numFluxSupportPoints, UPWIND_SCHEME >( + numPhase, + ip, + seri, + sesri, + sei, + trans, + dTrans_dPres, + k_up_ppu, + totFlux, + totMob, + dTotMob_dP, + dTotMob_dC, + pres, + gravCoef, + phaseMob, + dPhaseMob, + phaseVolFrac, + dPhaseVolFrac, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + useNewGravity, + k_up_g, + k_up_og, + gravitationalPhaseFlux, + gravitationalPhaseFlux_dP, + gravitationalPhaseFlux_dC ); + + + + //distribute on phaseComponentFlux here + PhaseComponentFlux::compute( ip, k_up_g, + seri, sesri, sei, + phaseCompFrac, dPhaseCompFrac, dCompFrac_dCompDens, + gravitationalPhaseFlux, gravitationalPhaseFlux_dP, gravitationalPhaseFlux_dC, + compFlux, dCompFlux_dP, dCompFlux_dC ); + + + //update phaseFlux from gravitational + phaseFlux += gravitationalPhaseFlux; + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dPhaseFlux_dP[ke] += gravitationalPhaseFlux_dP[ke]; + for( localIndex ic = 0; ic < numComp; ++ic ) + dPhaseFlux_dC[ke][ic] += gravitationalPhaseFlux_dC[ke][ic]; + } + + + if( hasCapPressure ) + { + /// Assembling the capillary flux (and derivatives) from fractional flow and total velocity as \phi_{g} = f_i^{up,g} uT + localIndex k_up_pc = -1; + localIndex k_up_opc = -1; + + real64 capillaryPhaseFlux{}; + real64 capillaryPhaseFlux_dP[numFluxSupportPoints]{}; + real64 capillaryPhaseFlux_dC[numFluxSupportPoints][numComp]{}; + + UpwindHelpers::computePotentialFluxesCapillary< numComp, + numFluxSupportPoints, UPWIND_SCHEME >( + numPhase, + ip, + seri, + sesri, + sei, + trans, + dTrans_dPres, + k_up_ppu, + totFlux, + totMob, + dTotMob_dP, + dTotMob_dC, + pres, + gravCoef, + phaseMob, + dPhaseMob, + dPhaseVolFrac, + dCompFrac_dCompDens, + phaseMassDens, + dPhaseMassDens, + phaseCapPressure, + dPhaseCapPressure_dPhaseVolFrac, + hasCapPressure, + k_up_pc, + k_up_opc, + capillaryPhaseFlux, + capillaryPhaseFlux_dP, + capillaryPhaseFlux_dC ); + + //distribute on phaseComponentFlux here + PhaseComponentFlux::compute( ip, k_up_pc, + seri, sesri, sei, + phaseCompFrac, dPhaseCompFrac, dCompFrac_dCompDens, + capillaryPhaseFlux, capillaryPhaseFlux_dP, capillaryPhaseFlux_dC, + compFlux, dCompFlux_dP, dCompFlux_dC ); + + + //update phaseFlux from capillary + phaseFlux += capillaryPhaseFlux; + for( localIndex ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dPhaseFlux_dP[ke] += capillaryPhaseFlux_dP[ke]; + for( localIndex ic = 0; ic < numComp; ++ic ) + dPhaseFlux_dC[ke][ic] += capillaryPhaseFlux_dC[ke][ic]; + + } + + }//end if cappres + + } + +}; + +} // namespace isothermalCompositionalMultiPhaseFVMKernelUtilities + +} // namespace geos + + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_IHUPHASEFLUX_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp new file mode 100644 index 00000000000..3e7370f1c6f --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp @@ -0,0 +1,159 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file KernelLaunchSelector.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_KERNELLAUNCHSELECTOR_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_KERNELLAUNCHSELECTOR_HPP + +#include "physicsSolvers/KernelLaunchSelectors.hpp" +#include "codingUtilities/Utilities.hpp" +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** Kernel launch machinery ********************************/ + +namespace internal +{ + +template< typename T, typename LAMBDA > +void kernelLaunchSelectorCompSwitch( T value, LAMBDA && lambda ) +{ + static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: type should be integral" ); + + switch( value ) + { + case 1: + { lambda( std::integral_constant< T, 1 >() ); return; } + case 2: + { lambda( std::integral_constant< T, 2 >() ); return; } + case 3: + { lambda( std::integral_constant< T, 3 >() ); return; } + case 4: + { lambda( std::integral_constant< T, 4 >() ); return; } + case 5: + { lambda( std::integral_constant< T, 5 >() ); return; } + default: + { GEOS_ERROR( "Unsupported number of components: " << value ); } + } +} + +} // namespace internal + +template< typename KERNELWRAPPER, typename ... ARGS > +void KernelLaunchSelectorCompTherm( integer const numComp, bool const isThermal, ARGS && ... args ) +{ + geos::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal, [&] ( auto NC, auto ISTHERMAL ) + { + KERNELWRAPPER::template launch< NC(), ISTHERMAL() >( std::forward< ARGS >( args )... ); + } ); +} + +template< typename KERNELWRAPPER, typename ... ARGS > +void KernelLaunchSelector1( integer const numComp, ARGS && ... args ) +{ + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC() >( std::forward< ARGS >( args )... ); + } ); +} + +template< typename KERNELWRAPPER, typename ... ARGS > +void KernelLaunchSelector2( integer const numComp, integer const numPhase, ARGS && ... args ) +{ + // Ideally this would be inside the dispatch, but it breaks on Summit with GCC 9.1.0 and CUDA 11.0.3. + if( numPhase == 2 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 2 >( std::forward< ARGS >( args ) ... ); + } ); + } + else if( numPhase == 3 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 3 >( std::forward< ARGS >( args ) ... ); + } ); + } + else + { + GEOS_ERROR( "Unsupported number of phases: " << numPhase ); + } +} + +template< typename KERNELWRAPPER, typename ... ARGS > +void KernelLaunchSelector_NC_NP_THERM( integer const numComp, integer const numPhase, integer const isThermal, ARGS && ... args ) +{ + // Ideally this would be inside the dispatch, but it breaks on Summit with GCC 9.1.0 and CUDA 11.0.3. + if( isThermal ) + { + if( numPhase == 2 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 2, 1 >( std::forward< ARGS >( args ) ... ); + } ); + } + else if( numPhase == 3 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 3, 1 >( std::forward< ARGS >( args ) ... ); + } ); + } + else + { + GEOS_ERROR( "Unsupported number of phases: " << numPhase ); + } + } + else + { + if( numPhase == 2 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 2, 0 >( std::forward< ARGS >( args ) ... ); + } ); + } + else if( numPhase == 3 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 3, 0 >( std::forward< ARGS >( args ) ... ); + } ); + } + else + { + GEOS_ERROR( "Unsupported number of phases: " << numPhase ); + } + } +} + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_KERNELLAUNCHSELECTOR_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PPUPhaseFlux.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PPUPhaseFlux.hpp new file mode 100644 index 00000000000..483e8c4c2ba --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PPUPhaseFlux.hpp @@ -0,0 +1,163 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PPUPhaseFlux.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PPUPHASEFLUX_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PPUPHASEFLUX_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "constitutive/capillaryPressure/layouts.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PotGrad.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PhaseComponentFlux.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernelUtilities +{ + +template< typename VIEWTYPE > +using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + +using Deriv = constitutive::multifluid::DerivativeOffset; + +struct PPUPhaseFlux +{ + /** + * @brief Form the PhasePotentialUpwind from pressure gradient and gravitational head + * @tparam numComp number of components + * @tparam numFluxSupportPoints number of flux support points + * @param numPhase number of phases + * @param ip phase index + * @param hasCapPressure flag indicating if there is capillary pressure + * @param seri arraySlice of the stencil-implied element region index + * @param sesri arraySlice of the stencil-implied element subregion index + * @param sei arraySlice of the stencil-implied element index + * @param trans transmissibility at the connection + * @param dTrans_dPres derivative of transmissibility wrt pressure + * @param pres pressure + * @param gravCoef gravitational coefficient + * @param phaseMob phase mobility + * @param dPhaseMob derivative of phase mobility wrt pressure, temperature, comp density + * @param dPhaseVolFrac derivative of phase volume fraction wrt pressure, temperature, comp density + * @param dCompFrac_dCompDens derivative of component fraction wrt component density + * @param phaseMassDens phase mass density + * @param dPhaseMassDens derivative of phase mass density wrt pressure, temperature, comp fraction + * @param phaseCapPressure phase capillary pressure + * @param dPhaseCapPressure_dPhaseVolFrac derivative of phase capillary pressure wrt phase volume fraction + * @param k_up uptream index for this phase + * @param potGrad potential gradient for this phase + * @param phaseFlux phase flux + * @param dPhaseFlux_dP derivative of phase flux wrt pressure + * @param dPhaseFlux_dC derivative of phase flux wrt comp density + */ + template< integer numComp, integer numFluxSupportPoints > + GEOS_HOST_DEVICE + static void + compute( integer const numPhase, + integer const ip, + integer const hasCapPressure, + integer const useNewGravity, + localIndex const ( &seri )[numFluxSupportPoints], + localIndex const ( &sesri )[numFluxSupportPoints], + localIndex const ( &sei )[numFluxSupportPoints], + real64 const ( &trans )[2], + real64 const ( &dTrans_dPres )[2], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + localIndex & k_up, + real64 & potGrad, + real64 ( &phaseFlux ), + real64 ( & dPhaseFlux_dP )[numFluxSupportPoints], + real64 ( & dPhaseFlux_dC )[numFluxSupportPoints][numComp], + real64 ( & compFlux )[numComp], + real64 ( & dCompFlux_dP )[numFluxSupportPoints][numComp], + real64 ( & dCompFlux_dC )[numFluxSupportPoints][numComp][numComp] ) + { + real64 dPresGrad_dP[numFluxSupportPoints]{}; + real64 dPresGrad_dC[numFluxSupportPoints][numComp]{}; + real64 dGravHead_dP[numFluxSupportPoints]{}; + real64 dGravHead_dC[numFluxSupportPoints][numComp]{}; + PotGrad::compute< numComp, numFluxSupportPoints >( numPhase, ip, hasCapPressure, useNewGravity, seri, sesri, sei, trans, dTrans_dPres, pres, + gravCoef, phaseVolFrac, dPhaseVolFrac, dCompFrac_dCompDens, phaseMassDens, dPhaseMassDens, + phaseCapPressure, dPhaseCapPressure_dPhaseVolFrac, potGrad, dPresGrad_dP, + dPresGrad_dC, dGravHead_dP, dGravHead_dC ); + + // *** upwinding *** + + // choose upstream cell + k_up = (potGrad >= 0) ? 0 : 1; + + localIndex const er_up = seri[k_up]; + localIndex const esr_up = sesri[k_up]; + localIndex const ei_up = sei[k_up]; + + real64 const mobility = phaseMob[er_up][esr_up][ei_up][ip]; + + // pressure gradient depends on all points in the stencil + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dPhaseFlux_dP[ke] += dPresGrad_dP[ke] - dGravHead_dP[ke]; + dPhaseFlux_dP[ke] *= mobility; + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[ke][jc] += dPresGrad_dC[ke][jc] - dGravHead_dC[ke][jc]; + dPhaseFlux_dC[ke][jc] *= mobility; + } + } + // compute phase flux using upwind mobility. + phaseFlux = mobility * potGrad; + + real64 const dMob_dP = dPhaseMob[er_up][esr_up][ei_up][ip][Deriv::dP]; + arraySlice1d< real64 const, compflow::USD_PHASE_DC - 2 > dPhaseMobSub = + dPhaseMob[er_up][esr_up][ei_up][ip]; + + // add contribution from upstream cell mobility derivatives + dPhaseFlux_dP[k_up] += dMob_dP * potGrad; + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[k_up][jc] += dPhaseMobSub[Deriv::dC+jc] * potGrad; + } + + //distribute on phaseComponentFlux here + PhaseComponentFlux::compute( ip, k_up, seri, sesri, sei, phaseCompFrac, dPhaseCompFrac, dCompFrac_dCompDens, phaseFlux + , dPhaseFlux_dP, dPhaseFlux_dC, compFlux, dCompFlux_dP, dCompFlux_dC ); + + } +}; + +} // namespace isothermalCompositionalMultiPhaseFVMKernelUtilities + +} // namespace geos + + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PPUPHASEFLUX_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseComponentFlux.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseComponentFlux.hpp new file mode 100644 index 00000000000..3d7f1cba38b --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseComponentFlux.hpp @@ -0,0 +1,128 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PhaseComponentFlux.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASECOMPONENTFLUX_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASECOMPONENTFLUX_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "mesh/ElementRegionManager.hpp" + + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernelUtilities +{ + +template< typename VIEWTYPE > +using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + +using Deriv = constitutive::multifluid::DerivativeOffset; + +struct PhaseComponentFlux +{ + /** + * @brief Compute the component flux for a given phase + * @tparam numComp number of components + * @tparam numFluxSupportPoints number of flux support points + * @param ip phase index + * @param k_up uptream index for this phase + * @param seri arraySlice of the stencil-implied element region index + * @param sesri arraySlice of the stencil-implied element subregion index + * @param sei arraySlice of the stencil-implied element index + * @param phaseCompFrac phase component fraction + * @param dPhaseCompFrac derivative of phase component fraction wrt pressure, temperature, component fraction + * @param dCompFrac_dCompDens derivative of component fraction wrt component density + * @param phaseFlux phase flux + * @param dPhaseFlux_dP derivative of phase flux wrt pressure + * @param dPhaseFlux_dC derivative of phase flux wrt comp density + * @param compFlux component flux + * @param dCompFlux_dP derivative of phase flux wrt pressure + * @param dCompFlux_dC derivative of phase flux wrt comp density + */ + template< localIndex numComp, localIndex numFluxSupportPoints > + GEOS_HOST_DEVICE + static void + compute( localIndex const ip, + localIndex const k_up, + localIndex const ( &seri )[numFluxSupportPoints], + localIndex const ( &sesri )[numFluxSupportPoints], + localIndex const ( &sei )[numFluxSupportPoints], + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + real64 const & phaseFlux, + real64 const ( &dPhaseFlux_dP )[numFluxSupportPoints], + real64 const ( &dPhaseFlux_dC )[numFluxSupportPoints][numComp], + real64 ( & compFlux )[numComp], + real64 ( & dCompFlux_dP )[numFluxSupportPoints][numComp], + real64 ( & dCompFlux_dC )[numFluxSupportPoints][numComp][numComp] ) + { + localIndex const er_up = seri[k_up]; + localIndex const esr_up = sesri[k_up]; + localIndex const ei_up = sei[k_up]; + + real64 dProp_dC[numComp]{}; + + // slice some constitutive arrays to avoid too much indexing in component loop + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE_COMP-3 > phaseCompFracSub = + phaseCompFrac[er_up][esr_up][ei_up][0][ip]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC-3 > dPhaseCompFracSub = + dPhaseCompFrac[er_up][esr_up][ei_up][0][ip]; + + // compute component fluxes and derivatives using upstream cell composition + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const ycp = phaseCompFracSub[ic]; + compFlux[ic] += phaseFlux * ycp; + + // derivatives stemming from phase flux + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dCompFlux_dP[ke][ic] += dPhaseFlux_dP[ke] * ycp; + for( integer jc = 0; jc < numComp; ++jc ) + { + dCompFlux_dC[ke][ic][jc] += dPhaseFlux_dC[ke][jc] * ycp; + } + } + + // additional derivatives stemming from upstream cell phase composition + dCompFlux_dP[k_up][ic] += phaseFlux * dPhaseCompFracSub[ic][Deriv::dP]; + + // convert derivatives of comp fraction w.r.t. comp fractions to derivatives w.r.t. comp densities + applyChainRule( numComp, + dCompFrac_dCompDens[er_up][esr_up][ei_up], + dPhaseCompFracSub[ic], + dProp_dC, + Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + dCompFlux_dC[k_up][ic][jc] += phaseFlux * dProp_dC[jc]; + } + } + } +}; + +} // namespace isothermalCompositionalMultiPhaseFVMKernelUtilities + +} // namespace geos + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASECOMPONENTFLUX_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseMobilityKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseMobilityKernel.hpp new file mode 100644 index 00000000000..7eb1f79ab2f --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseMobilityKernel.hpp @@ -0,0 +1,241 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PhaseMobilityKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASEMOBILITYKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASEMOBILITYKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/******************************** PhaseMobilityKernel ********************************/ + +/** + * @class PhaseMobilityKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_PHASE number of fluid phases + * @brief Defines the interface for the property kernel in charge of computing the phase mobilities + */ +template< integer NUM_COMP, integer NUM_PHASE > +class PhaseMobilityKernel : public isothermalCompositionalMultiphaseBaseKernels::PropertyKernelBase< NUM_COMP > +{ +public: + + using Base = isothermalCompositionalMultiphaseBaseKernels::PropertyKernelBase< NUM_COMP >; + using Base::numComp; + + /// Compile time value for the number of phases + static constexpr integer numPhase = NUM_PHASE; + + /** + * @brief Constructor + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] relperm the relperm model + */ + PhaseMobilityKernel( ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::RelativePermeabilityBase const & relperm ) + : Base(), + m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), + m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ), + m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ), + m_phaseDens( fluid.phaseDensity() ), + m_dPhaseDens( fluid.dPhaseDensity() ), + m_phaseVisc( fluid.phaseViscosity() ), + m_dPhaseVisc( fluid.dPhaseViscosity() ), + m_phaseRelPerm( relperm.phaseRelPerm() ), + m_dPhaseRelPerm_dPhaseVolFrac( relperm.dPhaseRelPerm_dPhaseVolFraction() ), + m_phaseMob( subRegion.getField< fields::flow::phaseMobility >() ), + m_dPhaseMob( subRegion.getField< fields::flow::dPhaseMobility >() ) + {} + + /** + * @brief Compute the phase mobilities in an element + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[in] phaseMobilityKernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void compute( localIndex const ei, + FUNC && phaseMobilityKernelOp = NoOpFunc{} ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseDens = m_phaseDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseVisc = m_phaseVisc[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseVisc = m_dPhaseVisc[ei][0]; + arraySlice1d< real64 const, constitutive::relperm::USD_RELPERM - 2 > const phaseRelPerm = m_phaseRelPerm[ei][0]; + arraySlice2d< real64 const, constitutive::relperm::USD_RELPERM_DS - 2 > const dPhaseRelPerm_dPhaseVolFrac = m_dPhaseRelPerm_dPhaseVolFrac[ei][0]; + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; + arraySlice1d< real64, compflow::USD_PHASE - 1 > const phaseMob = m_phaseMob[ei]; + arraySlice2d< real64, compflow::USD_PHASE_DC - 1 > const dPhaseMob = m_dPhaseMob[ei]; + + real64 dRelPerm_dC[numComp]{}; + real64 dDens_dC[numComp]{}; + real64 dVisc_dC[numComp]{}; + + for( integer ip = 0; ip < numPhase; ++ip ) + { + + // compute the phase mobility only if the phase is present + bool const phaseExists = (phaseVolFrac[ip] > 0); + if( !phaseExists ) + { + phaseMob[ip] = 0.0; + for( integer jc = 0; jc < numComp + 2; ++jc ) + { + dPhaseMob[ip][jc] = 0.0; + } + continue; + } + + real64 const density = phaseDens[ip]; + real64 const dDens_dP = dPhaseDens[ip][Deriv::dP]; + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], dDens_dC, Deriv::dC ); + + real64 const viscosity = phaseVisc[ip]; + real64 const dVisc_dP = dPhaseVisc[ip][Deriv::dP]; + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseVisc[ip], dVisc_dC, Deriv::dC ); + + real64 const relPerm = phaseRelPerm[ip]; + real64 dRelPerm_dP = 0.0; + for( integer ic = 0; ic < numComp; ++ic ) + { + dRelPerm_dC[ic] = 0.0; + } + + for( integer jp = 0; jp < numPhase; ++jp ) + { + real64 const dRelPerm_dS = dPhaseRelPerm_dPhaseVolFrac[ip][jp]; + dRelPerm_dP += dRelPerm_dS * dPhaseVolFrac[jp][Deriv::dP]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + dRelPerm_dC[jc] += dRelPerm_dS * dPhaseVolFrac[jp][Deriv::dC+jc]; + } + } + + real64 const mobility = relPerm * density / viscosity; + + phaseMob[ip] = mobility; + dPhaseMob[ip][Deriv::dP] = dRelPerm_dP * density / viscosity + + mobility * (dDens_dP / density - dVisc_dP / viscosity); + + // compositional derivatives + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseMob[ip][Deriv::dC+jc] = dRelPerm_dC[jc] * density / viscosity + + mobility * (dDens_dC[jc] / density - dVisc_dC[jc] / viscosity); + } + + // call the lambda in the phase loop to allow the reuse of the relperm, density, viscosity, and mobility + // possible use: assemble the derivatives wrt temperature + phaseMobilityKernelOp( ip, phaseMob[ip], dPhaseMob[ip] ); + } + } + +protected: + + // inputs + + /// Views on the phase volume fractions + arrayView2d< real64 const, compflow::USD_PHASE > m_phaseVolFrac; + arrayView3d< real64 const, compflow::USD_PHASE_DC > m_dPhaseVolFrac; + arrayView3d< real64 const, compflow::USD_COMP_DC > m_dCompFrac_dCompDens; + + /// Views on the phase densities + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseDens; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseDens; + + /// Views on the phase viscosities + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseVisc; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseVisc; + + /// Views on the phase relative permeabilities + arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > m_phaseRelPerm; + arrayView4d< real64 const, constitutive::relperm::USD_RELPERM_DS > m_dPhaseRelPerm_dPhaseVolFrac; + + // outputs + + /// Views on the phase mobilities + arrayView2d< real64, compflow::USD_PHASE > m_phaseMob; + arrayView3d< real64, compflow::USD_PHASE_DC > m_dPhaseMob; + +}; + +/** + * @class PhaseMobilityKernelFactory + */ +class PhaseMobilityKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComp the number of fluid components + * @param[in] numPhase the number of fluid phases + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] relperm the relperm model + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + integer const numPhase, + ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::RelativePermeabilityBase const & relperm ) + { + if( numPhase == 2 ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseMobilityKernel< NUM_COMP, 2 > kernel( subRegion, fluid, relperm ); + PhaseMobilityKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + else if( numPhase == 3 ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseMobilityKernel< NUM_COMP, 3 > kernel( subRegion, fluid, relperm ); + PhaseMobilityKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + } +}; + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASEMOBILITYKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp new file mode 100644 index 00000000000..a693ba124e9 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp @@ -0,0 +1,256 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PhaseVolumeFractionKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASEVOLUMEFRACTIONKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASEVOLUMEFRACTIONKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** PhaseVolumeFractionKernel ********************************/ + +/** + * @class PhaseVolumeFractionKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_PHASE number of fluid phases + * @brief Define the interface for the property kernel in charge of computing the phase volume fractions + */ +template< integer NUM_COMP, integer NUM_PHASE > +class PhaseVolumeFractionKernel : public PropertyKernelBase< NUM_COMP > +{ +public: + + using Base = PropertyKernelBase< NUM_COMP >; + using Base::numComp; + + /// Compile time value for the number of phases + static constexpr integer numPhase = NUM_PHASE; + + /** + * @brief Constructor + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + PhaseVolumeFractionKernel( ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid ) + : Base(), + m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), + m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ), + m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ), + m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ), + m_phaseFrac( fluid.phaseFraction() ), + m_dPhaseFrac( fluid.dPhaseFraction() ), + m_phaseDens( fluid.phaseDensity() ), + m_dPhaseDens( fluid.dPhaseDensity() ) + {} + + /** + * @brief Compute the phase volume fractions in an element + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[in] phaseVolFractionKernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + real64 compute( localIndex const ei, + FUNC && phaseVolFractionKernelOp = NoOpFunc{} ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + arraySlice1d< real64 const, compflow::USD_COMP - 1 > const compDens = m_compDens[ei]; + arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseDens = m_phaseDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseFrac = m_phaseFrac[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseFrac = m_dPhaseFrac[ei][0]; + arraySlice1d< real64, compflow::USD_PHASE - 1 > const phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d< real64, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; + + real64 work[numComp]{}; + + // compute total density from component partial densities + real64 totalDensity = 0.0; + real64 const dTotalDens_dCompDens = 1.0; + for( integer ic = 0; ic < numComp; ++ic ) + { + totalDensity += compDens[ic]; + } + + real64 maxDeltaPhaseVolFrac = 0.0; + + for( integer ip = 0; ip < numPhase; ++ip ) + { + + // set the saturation to zero if the phase is absent + bool const phaseExists = (phaseFrac[ip] > 0); + if( !phaseExists ) + { + phaseVolFrac[ip] = 0.; + for( integer jc = 0; jc < numComp+2; ++jc ) + { + dPhaseVolFrac[ip][jc] = 0.; + } + continue; + } + + // Expression for volume fractions: S_p = (nu_p / rho_p) * rho_t + real64 const phaseDensInv = 1.0 / phaseDens[ip]; + + // store old saturation to compute change later + real64 const satOld = phaseVolFrac[ip]; + + // compute saturation and derivatives except multiplying by the total density + phaseVolFrac[ip] = phaseFrac[ip] * phaseDensInv; + + dPhaseVolFrac[ip][Deriv::dP] = + (dPhaseFrac[ip][Deriv::dP] - phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP]) * phaseDensInv; + + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseVolFrac[ip][Deriv::dC+jc] = + (dPhaseFrac[ip][Deriv::dC+jc] - phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dC+jc]) * phaseDensInv; + } + + // apply chain rule to convert derivatives from global component fractions to densities + applyChainRuleInPlace( numComp, dCompFrac_dCompDens, dPhaseVolFrac[ip], work, Deriv::dC ); + + // call the lambda in the phase loop to allow the reuse of the phaseVolFrac and totalDensity + // possible use: assemble the derivatives wrt temperature + phaseVolFractionKernelOp( ip, phaseVolFrac[ip], phaseDensInv, totalDensity ); + + // now finalize the computation by multiplying by total density + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseVolFrac[ip][Deriv::dC+jc] *= totalDensity; + dPhaseVolFrac[ip][Deriv::dC+jc] += phaseVolFrac[ip] * dTotalDens_dCompDens; + } + + phaseVolFrac[ip] *= totalDensity; + dPhaseVolFrac[ip][Deriv::dP] *= totalDensity; + + real64 const deltaPhaseVolFrac = LvArray::math::abs( phaseVolFrac[ip] - satOld ); + if( maxDeltaPhaseVolFrac < deltaPhaseVolFrac ) + { + maxDeltaPhaseVolFrac = deltaPhaseVolFrac; + } + } + return maxDeltaPhaseVolFrac; + } + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElems the number of elements + * @param[inout] kernelComponent the kernel component providing access to the compute function + */ + template< typename POLICY, typename KERNEL_TYPE > + static real64 + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaPhaseVolFrac( 0.0 ); + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + real64 const deltaPhaseVolFrac = kernelComponent.compute( ei ); + maxDeltaPhaseVolFrac.max( deltaPhaseVolFrac ); + } ); + return maxDeltaPhaseVolFrac.get(); + } + +protected: + + // outputs + + /// Views on phase volume fractions + arrayView2d< real64, compflow::USD_PHASE > m_phaseVolFrac; + arrayView3d< real64, compflow::USD_PHASE_DC > m_dPhaseVolFrac; + + // inputs + + /// Views on component densities + arrayView2d< real64 const, compflow::USD_COMP > m_compDens; + arrayView3d< real64 const, compflow::USD_COMP_DC > m_dCompFrac_dCompDens; + + /// Views on phase fractions + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseFrac; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseFrac; + + /// Views on phase densities + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseDens; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseDens; + +}; + +/** + * @class PhaseVolumeFractionKernelFactory + */ +class PhaseVolumeFractionKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComp the number of fluid components + * @param[in] numPhase the number of fluid phases + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + template< typename POLICY > + static real64 + createAndLaunch( integer const numComp, + integer const numPhase, + ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid ) + { + real64 maxDeltaPhaseVolFrac = 0.0; + if( numPhase == 2 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseVolumeFractionKernel< NUM_COMP, 2 > kernel( subRegion, fluid ); + maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + else if( numPhase == 3 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseVolumeFractionKernel< NUM_COMP, 3 > kernel( subRegion, fluid ); + maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + return maxDeltaPhaseVolFrac; + } +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASEVOLUMEFRACTIONKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PotGrad.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PotGrad.hpp new file mode 100644 index 00000000000..2b4522343e3 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PotGrad.hpp @@ -0,0 +1,225 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PotGrad.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_POTGRAD_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_POTGRAD_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "constitutive/capillaryPressure/layouts.hpp" +#include "mesh/ElementRegionManager.hpp" + + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernelUtilities +{ + +template< typename VIEWTYPE > +using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + +using Deriv = constitutive::multifluid::DerivativeOffset; + +struct PotGrad +{ + template< integer numComp, integer numFluxSupportPoints > + GEOS_HOST_DEVICE + static void + compute ( integer const numPhase, + integer const ip, + integer const hasCapPressure, + integer const useNewGravity, + localIndex const ( &seri )[numFluxSupportPoints], + localIndex const ( &sesri )[numFluxSupportPoints], + localIndex const ( &sei )[numFluxSupportPoints], + real64 const ( &trans )[numFluxSupportPoints], + real64 const ( &dTrans_dPres )[numFluxSupportPoints], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + real64 & potGrad, + real64 ( & dPresGrad_dP )[numFluxSupportPoints], + real64 ( & dPresGrad_dC )[numFluxSupportPoints][numComp], + real64 ( & dGravHead_dP )[numFluxSupportPoints], + real64 ( & dGravHead_dC )[numFluxSupportPoints][numComp] ) + { + // assign derivatives arrays to zero + for( integer i = 0; i < numFluxSupportPoints; ++i ) + { + dPresGrad_dP[i] = 0.0; + dGravHead_dP[i] = 0.0; + for( integer jc = 0; jc < numComp; ++jc ) + { + dPresGrad_dC[i][jc] = 0.0; + dGravHead_dC[i][jc] = 0.0; + } + } + + // create local work arrays + real64 densMean = 0.0; + real64 dDensMean_dP[numFluxSupportPoints]{}; + real64 dDensMean_dC[numFluxSupportPoints][numComp]{}; + + real64 presGrad = 0.0; + real64 gravHead = 0.0; + real64 dCapPressure_dC[numComp]{}; + + calculateMeanDensity( useNewGravity, ip, seri, sesri, sei, phaseVolFrac, dCompFrac_dCompDens, phaseMassDens, dPhaseMassDens, densMean, dDensMean_dP, dDensMean_dC ); + + /// compute the TPFA potential difference + for( integer i = 0; i < numFluxSupportPoints; i++ ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + // capillary pressure + real64 capPressure = 0.0; + real64 dCapPressure_dP = 0.0; + + for( integer ic = 0; ic < numComp; ++ic ) + { + dCapPressure_dC[ic] = 0.0; + } + + if( hasCapPressure ) + { + capPressure = phaseCapPressure[er][esr][ei][0][ip]; + + for( integer jp = 0; jp < numPhase; ++jp ) + { + real64 const dCapPressure_dS = dPhaseCapPressure_dPhaseVolFrac[er][esr][ei][0][ip][jp]; + dCapPressure_dP += dCapPressure_dS * dPhaseVolFrac[er][esr][ei][jp][Deriv::dP]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + dCapPressure_dC[jc] += dCapPressure_dS * dPhaseVolFrac[er][esr][ei][jp][Deriv::dC+jc]; + } + } + } + + presGrad += trans[i] * (pres[er][esr][ei] - capPressure); + dPresGrad_dP[i] += trans[i] * (1 - dCapPressure_dP) + + dTrans_dPres[i] * (pres[er][esr][ei] - capPressure); + for( integer jc = 0; jc < numComp; ++jc ) + { + dPresGrad_dC[i][jc] += -trans[i] * dCapPressure_dC[jc]; + } + + real64 const gravD = trans[i] * gravCoef[er][esr][ei]; + real64 const dGravD_dP = dTrans_dPres[i] * gravCoef[er][esr][ei]; + + // the density used in the potential difference is always a mass density + // unlike the density used in the phase mobility, which is a mass density + // if useMass == 1 and a molar density otherwise + gravHead += densMean * gravD; + + // need to add contributions from both cells the mean density depends on + for( integer j = 0; j < numFluxSupportPoints; ++j ) + { + dGravHead_dP[j] += dDensMean_dP[j] * gravD + dGravD_dP * densMean; + for( integer jc = 0; jc < numComp; ++jc ) + { + dGravHead_dC[j][jc] += dDensMean_dC[j][jc] * gravD; + } + } + } + + // compute phase potential gradient + potGrad = presGrad - gravHead; + + } + + template< integer numComp, integer numFluxSupportPoints > + GEOS_HOST_DEVICE + static void + calculateMeanDensity( integer const useNewGravity, + integer const ip, + localIndex const ( &seri )[numFluxSupportPoints], + localIndex const ( &sesri )[numFluxSupportPoints], + localIndex const ( &sei )[numFluxSupportPoints], + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + real64 & densMean, real64 ( & dDensMean_dP)[numFluxSupportPoints], real64 ( & dDensMean_dC )[numFluxSupportPoints][numComp] ) + { + real64 dDens_dC[numComp]{}; + + integer denom = 0; + for( integer i = 0; i < numFluxSupportPoints; ++i ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + bool const phaseExists = (phaseVolFrac[er][esr][ei][ip] > 0); + if( useNewGravity && !phaseExists ) + { + continue; + } + + // density + real64 const density = phaseMassDens[er][esr][ei][0][ip]; + real64 const dDens_dP = dPhaseMassDens[er][esr][ei][0][ip][Deriv::dP]; + + applyChainRule( numComp, + dCompFrac_dCompDens[er][esr][ei], + dPhaseMassDens[er][esr][ei][0][ip], + dDens_dC, + Deriv::dC ); + + // average density and derivatives + densMean += density; + dDensMean_dP[i] = dDens_dP; + for( integer jc = 0; jc < numComp; ++jc ) + { + dDensMean_dC[i][jc] = dDens_dC[jc]; + } + denom++; + } + if( denom > 1 ) + { + densMean /= denom; + for( integer i = 0; i < numFluxSupportPoints; ++i ) + { + dDensMean_dP[i] /= denom; + for( integer jc = 0; jc < numComp; ++jc ) + { + dDensMean_dC[i][jc] /= denom; + } + } + } + } + +}; + +} // namespace isothermalCompositionalMultiPhaseFVMKernelUtilities + +} // namespace geos + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_POTGRAD_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp new file mode 100644 index 00000000000..ff312c40151 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp @@ -0,0 +1,91 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PropertyKernelBase.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PROPERTYKERNELBASE_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PROPERTYKERNELBASE_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** PropertyKernelBase ********************************/ + +/** + * @class PropertyKernelBase + * @tparam NUM_COMP number of fluid components + * @brief Define the base interface for the property update kernels + */ +template< integer NUM_COMP > +class PropertyKernelBase +{ +public: + + /// Compile time value for the number of components + static constexpr integer numComp = NUM_COMP; + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElems the number of elements + * @param[inout] kernelComponent the kernel component providing access to the compute function + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + kernelComponent.compute( ei ); + } ); + } + + /** + * @brief Performs the kernel launch on a sorted array + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] targetSet the indices of the elements in which we compute the property + * @param[inout] kernelComponent the kernel component providing access to the compute function + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( SortedArrayView< localIndex const > const & targetSet, + KERNEL_TYPE const & kernelComponent ) + { + forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const i ) + { + localIndex const ei = targetSet[ i ]; + kernelComponent.compute( ei ); + } ); + } + +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PROPERTYKERNELBASE_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBLKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ReactiveCompositionalMultiphaseOBLKernels.hpp similarity index 95% rename from src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBLKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ReactiveCompositionalMultiphaseOBLKernels.hpp index 2933bbf9faf..c07fb716b9f 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBLKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ReactiveCompositionalMultiphaseOBLKernels.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -39,8 +40,6 @@ namespace geos namespace reactiveCompositionalMultiphaseOBLKernels { -using namespace constitutive; - static constexpr real64 minValueForDivision = 1e-10; @@ -585,13 +584,13 @@ class ElementBasedAssemblyKernelFactory }; -/******************************** FaceBasedAssemblyKernel ********************************/ +/******************************** FluxComputeKernel ********************************/ /** - * @brief Base class for FaceBasedAssemblyKernel that holds all data not dependent + * @brief Base class for FluxComputeKernel that holds all data not dependent * on template parameters (like stencil type and number of components/dofs). * - * FaceBasedAssemblyKernel is used for flux terms calculation. + * FluxComputeKernel is used for flux terms calculation. * In case mesh geometry/configuration is not changing during simulation, * all connections can be pre-computed, sorted by element, and stored. * Then, ElementBasedAssemblyKernel can be used for flux calculation: every flux will be computed twice, @@ -599,7 +598,7 @@ class ElementBasedAssemblyKernelFactory * and therefore overall performance can significantly improve * */ -class FaceBasedAssemblyKernelBase +class FluxComputeKernelBase { public: @@ -607,7 +606,7 @@ class FaceBasedAssemblyKernelBase static constexpr real64 secondsToDaysMult = 1.0 / (60 * 60 * 24); - // transmissibility in DARTS is the same as in Eclipse (Metric): + // transmissibility in DARTS is Metric: // T = c * (k * A) / d, where c is Darcy constant, k is permeability [mD], A is area [m2] and d is distance [m] // Darcy constant takes care of unit translation (from SI to Metric), it includes conversion of [s]->[day], [cp->Pa * s], [Pa]->[bar] and // [mD->m2]: @@ -642,7 +641,7 @@ class FaceBasedAssemblyKernelBase fields::flow::OBLOperatorDerivatives >; using PermeabilityAccessors = - StencilMaterialAccessors< PermeabilityBase, + StencilMaterialAccessors< constitutive::PermeabilityBase, fields::permeability::permeability, fields::permeability::dPerm_dPressure >; @@ -657,14 +656,14 @@ class FaceBasedAssemblyKernelBase * @param[inout] localMatrix the local CRS matrix * @param[inout] localRhs the local right-hand side vector */ - FaceBasedAssemblyKernelBase( globalIndex const rankOffset, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - PermeabilityAccessors const & permeabilityAccessors, - real64 const & dt, - real64 const & transMultExp, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) + FluxComputeKernelBase( globalIndex const rankOffset, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const & dt, + real64 const & transMultExp, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) : m_rankOffset( rankOffset ), m_dt( dt * secondsToDaysMult ), m_transMultExp ( transMultExp ), @@ -725,7 +724,7 @@ class FaceBasedAssemblyKernelBase }; /** - * @class FaceBasedAssemblyKernel + * @class FluxComputeKernel * @tparam NUM_PHASES number of phases * @tparam NUM_COMPS number of components * @tparam ENABLE_ENERGY flag if energy balance equation is assembled @@ -733,7 +732,7 @@ class FaceBasedAssemblyKernelBase * @brief Compute flux term for an element */ template< integer NUM_PHASES, integer NUM_COMPS, bool ENABLE_ENERGY, typename STENCILWRAPPER > -class FaceBasedAssemblyKernel : public FaceBasedAssemblyKernelBase +class FluxComputeKernel : public FluxComputeKernelBase { public: @@ -791,23 +790,23 @@ class FaceBasedAssemblyKernel : public FaceBasedAssemblyKernelBase * @param[inout] localMatrix the local CRS matrix * @param[inout] localRhs the local right-hand side vector */ - FaceBasedAssemblyKernel( globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - PermeabilityAccessors const & permeabilityAccessors, - real64 const & dt, - real64 const & transMultExp, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : FaceBasedAssemblyKernelBase( rankOffset, - dofNumberAccessor, - compFlowAccessors, - permeabilityAccessors, - dt, - transMultExp, - localMatrix, - localRhs ), + FluxComputeKernel( globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const & dt, + real64 const & transMultExp, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : FluxComputeKernelBase( rankOffset, + dofNumberAccessor, + compFlowAccessors, + permeabilityAccessors, + dt, + transMultExp, + localMatrix, + localRhs ), m_stencilWrapper( stencilWrapper ), m_seri( stencilWrapper.getElementRegionIndices() ), m_sesri( stencilWrapper.getElementSubRegionIndices() ), @@ -1169,9 +1168,9 @@ class FaceBasedAssemblyKernel : public FaceBasedAssemblyKernelBase }; /** - * @class FaceBasedAssemblyKernelFactory + * @class FluxComputeKernelFactory */ -class FaceBasedAssemblyKernelFactory +class FluxComputeKernelFactory { public: @@ -1217,7 +1216,7 @@ class FaceBasedAssemblyKernelFactory elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - using KERNEL_TYPE = FaceBasedAssemblyKernel< NUM_PHASES, NUM_COMPS, ENABLE_ENERGY, STENCILWRAPPER >; + using KERNEL_TYPE = FluxComputeKernel< NUM_PHASES, NUM_COMPS, ENABLE_ENERGY, STENCILWRAPPER >; typename KERNEL_TYPE::CompFlowAccessors compFlowAccessors( elemManager, solverName ); typename KERNEL_TYPE::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/RelativePermeabilityUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/RelativePermeabilityUpdateKernel.hpp new file mode 100644 index 00000000000..05da6a151f4 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/RelativePermeabilityUpdateKernel.hpp @@ -0,0 +1,73 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file RelativePermeabilityUpdateKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_RELATIVEPERMEABILITYUPDATEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_RELATIVEPERMEABILITYUPDATEKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** RelativePermeabilityUpdateKernel ********************************/ + +struct RelativePermeabilityUpdateKernel +{ + template< typename POLICY, typename RELPERM_WRAPPER > + static void + launch( localIndex const size, + RELPERM_WRAPPER const & relPermWrapper, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + for( localIndex q = 0; q < relPermWrapper.numGauss(); ++q ) + { + relPermWrapper.update( k, q, phaseVolFrac[k] ); + } + } ); + } + + template< typename POLICY, typename RELPERM_WRAPPER > + static void + launch( SortedArrayView< localIndex const > const & targetSet, + RELPERM_WRAPPER const & relPermWrapper, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) + { + forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + localIndex const k = targetSet[a]; + for( localIndex q = 0; q < relPermWrapper.numGauss(); ++q ) + { + relPermWrapper.update( k, q, phaseVolFrac[k] ); + } + } ); + } +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_RELATIVEPERMEABILITYUPDATEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ResidualNormKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ResidualNormKernel.hpp new file mode 100644 index 00000000000..3b41be7145b --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ResidualNormKernel.hpp @@ -0,0 +1,191 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ResidualNormKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_RESIDUALNORMKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_RESIDUALNORMKERNEL_HPP + +#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** ResidualNormKernel ********************************/ + +/** + * @class ResidualNormKernel + */ +class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 2 > +{ +public: + + using Base = physicsSolverBaseKernels::ResidualNormKernelBase< 2 >; + using Base::m_minNormalizer; + using Base::m_rankOffset; + using Base::m_localResidual; + using Base::m_dofNumber; + + ResidualNormKernel( globalIndex const rankOffset, + arrayView1d< real64 const > const & localResidual, + arrayView1d< globalIndex const > const & dofNumber, + arrayView1d< localIndex const > const & ghostRank, + integer const numComponents, + ElementSubRegionBase const & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + real64 const minNormalizer ) + : Base( rankOffset, + localResidual, + dofNumber, + ghostRank, + minNormalizer ), + m_numComponents( numComponents ), + m_volume( subRegion.getElementVolume() ), + m_porosity_n( solid.getPorosity_n() ), + m_totalDens_n( fluid.totalDensity_n() ) + {} + + GEOS_HOST_DEVICE + virtual void computeLinf( localIndex const ei, + LinfStackVariables & stack ) const override + { + // this should never be zero if the simulation is set up correctly, but we never know + real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_totalDens_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); + real64 const volumeNormalizer = LvArray::math::max( m_minNormalizer, m_porosity_n[ei][0] * m_volume[ei] ); + + // step 1: mass residuals + + for( integer idof = 0; idof < m_numComponents; ++idof ) + { + real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / massNormalizer; + if( valMass > stack.localValue[0] ) + { + stack.localValue[0] = valMass; + } + } + + // step 2: volume residual + + real64 const valVol = LvArray::math::abs( m_localResidual[stack.localRow + m_numComponents] ) / volumeNormalizer; + if( valVol > stack.localValue[1] ) + { + stack.localValue[1] = valVol; + } + } + + GEOS_HOST_DEVICE + virtual void computeL2( localIndex const ei, + L2StackVariables & stack ) const override + { + // note: for the L2 norm, we bundle the volume and mass residuals/normalizers + + real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_totalDens_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); + + // step 1: mass residuals + + for( integer idof = 0; idof < m_numComponents; ++idof ) + { + stack.localValue[0] += m_localResidual[stack.localRow + idof] * m_localResidual[stack.localRow + idof]; + stack.localNormalizer[0] += massNormalizer; + } + + // step 2: volume residual + + real64 const val = m_localResidual[stack.localRow + m_numComponents] * m_totalDens_n[ei][0]; // we need a mass here, hence the + // multiplication + stack.localValue[1] += val * val; + stack.localNormalizer[1] += massNormalizer; + } + + +protected: + + /// Number of fluid coponents + integer const m_numComponents; + + /// View on the volume + arrayView1d< real64 const > const m_volume; + + /// View on porosity at the previous converged time step + arrayView2d< real64 const > const m_porosity_n; + + /// View on total mass/molar density at the previous converged time step + arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > const m_totalDens_n; + +}; + +/** + * @class ResidualNormKernelFactory + */ +class ResidualNormKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] normType the type of norm used (Linf or L2) + * @param[in] numComps the number of fluid components + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] localResidual the residual vector on my MPI rank + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[out] residualNorm the residual norm on the subRegion + * @param[out] residualNormalizer the residual normalizer on the subRegion + */ + template< typename POLICY > + static void + createAndLaunch( physicsSolverBaseKernels::NormType const normType, + integer const numComps, + globalIndex const rankOffset, + string const dofKey, + arrayView1d< real64 const > const & localResidual, + ElementSubRegionBase const & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + real64 const minNormalizer, + real64 (& residualNorm)[2], + real64 (& residualNormalizer)[2] ) + { + arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + + ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, numComps, subRegion, fluid, solid, minNormalizer ); + if( normType == physicsSolverBaseKernels::NormType::Linf ) + { + ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); + } + else // L2 norm + { + ResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); + } + } + +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_RESIDUALNORMKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolidInternalEnergyUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolidInternalEnergyUpdateKernel.hpp new file mode 100644 index 00000000000..5c534fcc154 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolidInternalEnergyUpdateKernel.hpp @@ -0,0 +1,55 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolidInternalEnergyUpdateKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLIDINTERNALENERGYUPDATEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLIDINTERNALENERGYUPDATEKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseBaseKernels +{ + +/******************************** SolidInternalEnergyUpdateKernel ********************************/ + +struct SolidInternalEnergyUpdateKernel +{ + + template< typename POLICY, typename SOLID_INTERNAL_ENERGY_WRAPPER > + static void + launch( localIndex const size, + SOLID_INTERNAL_ENERGY_WRAPPER const & solidInternalEnergyWrapper, + arrayView1d< real64 const > const & temp ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + solidInternalEnergyWrapper.update( k, temp[k] ); + } ); + } +}; + +} // namespace thermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLIDINTERNALENERGYUPDATEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp new file mode 100644 index 00000000000..5cbf59b932d --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp @@ -0,0 +1,334 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolutionCheckKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONCHECKKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONCHECKKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingAndCheckingKernelBase.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** SolutionCheckKernel ********************************/ + +/** + * @class SolutionCheckKernel + * @brief Define the kernel for checking the updated solution + */ +class SolutionCheckKernel : public SolutionScalingAndCheckingKernelBase< integer > +{ +public: + + using Base = SolutionScalingAndCheckingKernelBase< integer >; + using Base::m_rankOffset; + using Base::m_numComp; + using Base::m_dofNumber; + using Base::m_ghostRank; + using Base::m_localSolution; + using Base::m_pressure; + using Base::m_compDens; + + /** + * @brief Create a new kernel instance + * @param[in] allowCompDensChopping flag to allow the component density chopping + * @param[in] scalingFactor the scaling factor + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + * @param[in] pressure the pressure vector + * @param[in] compDens the component density vector + */ + SolutionCheckKernel( integer const allowCompDensChopping, + integer const allowNegativePressure, + CompositionalMultiphaseFVM::ScalingType const scalingType, + real64 const scalingFactor, + arrayView1d< real64 const > const pressure, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > compDensScalingFactor, + globalIndex const rankOffset, + integer const numComp, + string const dofKey, + ElementSubRegionBase const & subRegion, + arrayView1d< real64 const > const localSolution ) + : Base( rankOffset, + numComp, + dofKey, + subRegion, + localSolution, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor ), + m_allowCompDensChopping( allowCompDensChopping ), + m_allowNegativePressure( allowNegativePressure ), + m_scalingFactor( scalingFactor ), + m_scalingType( scalingType ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables located on the stack + */ + struct StackVariables : public Base::StackVariables + { + GEOS_HOST_DEVICE + StackVariables() + { } + + StackVariables( real64 _localMinVal, + real64 _localMinPres, + real64 _localMinDens, + real64 _localMinTotalDens, + integer _localNumNegPressures, + integer _localNumNegDens, + integer _localNumNegTotalDens ) + : + Base::StackVariables( _localMinVal ), + localMinPres( _localMinPres ), + localMinDens( _localMinDens ), + localMinTotalDens( _localMinTotalDens ), + localNumNegPressures( _localNumNegPressures ), + localNumNegDens( _localNumNegDens ), + localNumNegTotalDens( _localNumNegTotalDens ) + { } + + real64 localMinPres; + real64 localMinDens; + real64 localMinTotalDens; + + integer localNumNegPressures; + integer localNumNegDens; + integer localNumNegTotalDens; + + }; + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElems the number of elements + * @param[inout] kernelComponent the kernel component providing access to the compute function + */ + template< typename POLICY, typename KERNEL_TYPE > + static StackVariables + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + RAJA::ReduceMin< ReducePolicy< POLICY >, integer > globalMinVal( 1 ); + + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minPres( 0.0 ); + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minDens( 0.0 ); + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minTotalDens( 0.0 ); + + RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegPressures( 0 ); + RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegDens( 0 ); + RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegTotalDens( 0 ); + + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( kernelComponent.ghostRank( ei ) >= 0 ) + { + return; + } + + StackVariables stack; + kernelComponent.setup( ei, stack ); + kernelComponent.compute( ei, stack ); + + globalMinVal.min( stack.localMinVal ); + + minPres.min( stack.localMinPres ); + minDens.min( stack.localMinDens ); + minTotalDens.min( stack.localMinTotalDens ); + + numNegPressures += stack.localNumNegPressures; + numNegDens += stack.localNumNegDens; + numNegTotalDens += stack.localNumNegTotalDens; + } ); + + return StackVariables( globalMinVal.get(), + minPres.get(), + minDens.get(), + minTotalDens.get(), + numNegPressures.get(), + numNegDens.get(), + numNegTotalDens.get() ); + } + + GEOS_HOST_DEVICE + void setup( localIndex const ei, + StackVariables & stack ) const + { + Base::setup( ei, stack ); + + stack.localMinPres = 0.0; + stack.localMinDens = 0.0; + stack.localMinTotalDens = 0.0; + + stack.localNumNegPressures = 0; + stack.localNumNegDens = 0; + stack.localNumNegTotalDens = 0; + } + + /** + * @brief Compute the local value + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void compute( localIndex const ei, + StackVariables & stack ) const + { + computeSolutionCheck( ei, stack ); + } + + /** + * @brief Compute the local value of the check + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + * @param[in] kernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeSolutionCheck( localIndex const ei, + StackVariables & stack, + FUNC && kernelOp = NoOpFunc{} ) const + { + bool const localScaling = m_scalingType == CompositionalMultiphaseFVM::ScalingType::Local; + + real64 const newPres = m_pressure[ei] + (localScaling ? m_pressureScalingFactor[ei] : m_scalingFactor) * m_localSolution[stack.localRow]; + if( newPres < 0 ) + { + if( !m_allowNegativePressure ) + { + stack.localMinVal = 0; + } + stack.localNumNegPressures += 1; + if( newPres < stack.localMinPres ) + stack.localMinPres = newPres; + } + + // if component density chopping is not allowed, the time step fails if a component density is negative + // otherwise, we just check that the total density is positive, and negative component densities + // will be chopped (i.e., set to zero) in ApplySystemSolution) + if( !m_allowCompDensChopping ) + { + for( integer ic = 0; ic < m_numComp; ++ic ) + { + real64 const newDens = m_compDens[ei][ic] + (localScaling ? m_compDensScalingFactor[ei] : m_scalingFactor) * m_localSolution[stack.localRow + ic + 1]; + if( newDens < 0 ) + { + stack.localMinVal = 0; + stack.localNumNegDens += 1; + if( newDens < stack.localMinDens ) + stack.localMinDens = newDens; + } + } + } + else + { + real64 totalDens = 0.0; + for( integer ic = 0; ic < m_numComp; ++ic ) + { + real64 const newDens = m_compDens[ei][ic] + (localScaling ? m_compDensScalingFactor[ei] : m_scalingFactor) * m_localSolution[stack.localRow + ic + 1]; + totalDens += ( newDens > 0.0 ) ? newDens : 0.0; + } + if( totalDens < 0 ) + { + stack.localMinVal = 0; + stack.localNumNegTotalDens += 1; + if( totalDens < stack.localMinTotalDens ) + stack.localMinTotalDens = totalDens; + } + } + + kernelOp(); + } + +protected: + + /// flag to allow the component density chopping + integer const m_allowCompDensChopping; + + /// flag to allow negative pressure values + integer const m_allowNegativePressure; + + /// scaling factor + real64 const m_scalingFactor; + + /// scaling type (global or local) + CompositionalMultiphaseFVM::ScalingType const m_scalingType; + +}; + +/** + * @class SolutionCheckKernelFactory + */ +class SolutionCheckKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] allowCompDensChopping flag to allow the component density chopping + * @param[in] scalingFactor the scaling factor + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + */ + template< typename POLICY > + static SolutionCheckKernel::StackVariables + createAndLaunch( integer const allowCompDensChopping, + integer const allowNegativePressure, + CompositionalMultiphaseFVM::ScalingType const scalingType, + real64 const scalingFactor, + arrayView1d< real64 const > const pressure, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > compDensScalingFactor, + globalIndex const rankOffset, + integer const numComp, + string const dofKey, + ElementSubRegionBase & subRegion, + arrayView1d< real64 const > const localSolution ) + { + SolutionCheckKernel kernel( allowCompDensChopping, allowNegativePressure, scalingType, scalingFactor, + pressure, compDens, pressureScalingFactor, compDensScalingFactor, rankOffset, + numComp, dofKey, subRegion, localSolution ); + return SolutionCheckKernel::launch< POLICY >( subRegion.size(), kernel ); + } + +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONCHECKKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingAndCheckingKernelBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingAndCheckingKernelBase.hpp new file mode 100644 index 00000000000..14abec8e0b7 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingAndCheckingKernelBase.hpp @@ -0,0 +1,182 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolutionScalingAndCheckingKernelBase.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONSCALINGANDCHECKINGKERNELBASE_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONSCALINGANDCHECKINGKERNELBASE_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "mesh/ElementSubRegionBase.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/** + * @class SolutionScalingAndCheckingKernelBase + * @brief Define the kernel for scaling the solution and check its validity + */ +template< typename TYPE > +class SolutionScalingAndCheckingKernelBase +{ +public: + + /** + * @brief Create a new kernel instance + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + * @param[in] pressure the pressure vector + * @param[in] compDens the component density vector + * @param[in] pressureScalingFactor the pressure local scaling factor + * @param[in] compDensScalingFactor the component local scaling factor + */ + SolutionScalingAndCheckingKernelBase( globalIndex const rankOffset, + integer const numComp, + string const dofKey, + ElementSubRegionBase const & subRegion, + arrayView1d< real64 const > const localSolution, + arrayView1d< real64 const > const pressure, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > compDensScalingFactor ) + : m_rankOffset( rankOffset ), + m_numComp( numComp ), + m_dofNumber( subRegion.getReference< array1d< globalIndex > >( dofKey ) ), + m_ghostRank( subRegion.ghostRank() ), + m_localSolution( localSolution ), + m_pressure( pressure ), // not passed with fields::flow to be able to reuse this for wells + m_compDens( compDens ), // same here + m_pressureScalingFactor( pressureScalingFactor ), + m_compDensScalingFactor( compDensScalingFactor ) + { } + + /** + * @struct StackVariables + * @brief Kernel variables located on the stack + */ + struct StackVariables + { + GEOS_HOST_DEVICE + StackVariables() + { } + + StackVariables( real64 _localMinVal ) + : + localMinVal( _localMinVal ) + { } + + /// Index of the local row corresponding to this element + localIndex localRow; + + /// The local value + TYPE localMinVal; + }; + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] ei the element index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const ei, + StackVariables & stack ) const + { + stack.localMinVal = 1; + + // set row index and degrees of freedom indices for this element + stack.localRow = m_dofNumber[ei] - m_rankOffset; + } + + /** + * @brief Getter for the ghost rank + * @param[in] i the looping index of the element/node/face + * @return the ghost rank of the element/node/face + */ + GEOS_HOST_DEVICE + integer ghostRank( localIndex const i ) const + { return m_ghostRank( i ); } + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElems the number of elements + * @param[inout] kernelComponent the kernel component providing access to the compute function + */ + template< typename POLICY, typename KERNEL_TYPE > + static TYPE + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + RAJA::ReduceMin< ReducePolicy< POLICY >, TYPE > minVal( 1 ); + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( kernelComponent.ghostRank( ei ) >= 0 ) + { + return; + } + + StackVariables stack; + kernelComponent.setup( ei, stack ); + kernelComponent.compute( ei, stack ); + minVal.min( stack.localMinVal ); + } ); + + return minVal.get(); + } + +protected: + + /// Offset for my MPI rank + globalIndex const m_rankOffset; + + /// Number of components + real64 const m_numComp; + + /// View on the dof numbers + arrayView1d< globalIndex const > const m_dofNumber; + + /// View on the ghost ranks + arrayView1d< integer const > const m_ghostRank; + + /// View on the local residual + arrayView1d< real64 const > const m_localSolution; + + /// View on the primary variables + arrayView1d< real64 const > const m_pressure; + arrayView2d< real64 const, compflow::USD_COMP > const m_compDens; + + /// View on the scaling factors + arrayView1d< real64 > const m_pressureScalingFactor; + arrayView1d< real64 > const m_compDensScalingFactor; + +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONSCALINGANDCHECKINGKERNELBASE_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp new file mode 100644 index 00000000000..316859e9de7 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp @@ -0,0 +1,399 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolutionScalingKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONSCALINGKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONSCALINGKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingAndCheckingKernelBase.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** SolutionScalingKernel ********************************/ + +/** + * @class SolutionScalingKernel + * @brief Define the kernel for scaling the Newton update + */ +class SolutionScalingKernel : public SolutionScalingAndCheckingKernelBase< real64 > +{ +public: + + using Base = SolutionScalingAndCheckingKernelBase< real64 >; + using Base::m_rankOffset; + using Base::m_numComp; + using Base::m_dofNumber; + using Base::m_ghostRank; + using Base::m_localSolution; + using Base::m_pressure; + using Base::m_compDens; + using Base::m_pressureScalingFactor; + using Base::m_compDensScalingFactor; + + /** + * @brief Create a new kernel instance + * @param[in] maxRelativePresChange the max allowed relative pressure change + * @param[in] maxAbsolutePresChange the max allowed absolute pressure change + * @param[in] maxCompFracChange the max allowed comp fraction change + * @param[in] maxRelativeCompDensChange the max allowed comp density change + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + * @param[in] pressure the pressure vector + * @param[in] compDens the component density vector + * @param[in] pressureScalingFactor the pressure local scaling factor + * @param[in] compDensScalingFactor the component density local scaling factor + */ + SolutionScalingKernel( real64 const maxRelativePresChange, + real64 const maxAbsolutePresChange, + real64 const maxCompFracChange, + real64 const maxRelativeCompDensChange, + globalIndex const rankOffset, + integer const numComp, + string const dofKey, + ElementSubRegionBase const & subRegion, + arrayView1d< real64 const > const localSolution, + arrayView1d< real64 const > const pressure, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > compDensScalingFactor ) + : Base( rankOffset, + numComp, + dofKey, + subRegion, + localSolution, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor ), + m_maxRelativePresChange( maxRelativePresChange ), + m_maxAbsolutePresChange( maxAbsolutePresChange ), + m_maxCompFracChange( maxCompFracChange ), + m_maxRelativeCompDensChange( maxRelativeCompDensChange ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables located on the stack + */ + struct StackVariables : public Base::StackVariables + { + GEOS_HOST_DEVICE + StackVariables() + { } + + StackVariables( real64 _localMinVal, + real64 _localMaxDeltaPres, + localIndex _localMaxDeltaPresLoc, + real64 _localMaxDeltaTemp, + localIndex _localMaxDeltaTempLoc, + real64 _localMaxDeltaCompDens, + localIndex _localMaxDeltaCompDensLoc, + real64 _localMinPresScalingFactor, + real64 _localMinTempScalingFactor, + real64 _localMinCompDensScalingFactor ) + : + Base::StackVariables( _localMinVal ), + localMaxDeltaPres( _localMaxDeltaPres ), + localMaxDeltaPresLoc( _localMaxDeltaPresLoc ), + localMaxDeltaTemp( _localMaxDeltaTemp ), + localMaxDeltaTempLoc( _localMaxDeltaTempLoc ), + localMaxDeltaCompDens( _localMaxDeltaCompDens ), + localMaxDeltaCompDensLoc( _localMaxDeltaCompDensLoc ), + localMinPresScalingFactor( _localMinPresScalingFactor ), + localMinTempScalingFactor( _localMinTempScalingFactor ), + localMinCompDensScalingFactor( _localMinCompDensScalingFactor ) + { } + + real64 localMaxDeltaPres; + localIndex localMaxDeltaPresLoc; + real64 localMaxDeltaTemp; + localIndex localMaxDeltaTempLoc; + real64 localMaxDeltaCompDens; + localIndex localMaxDeltaCompDensLoc; + + real64 localMinPresScalingFactor; + real64 localMinTempScalingFactor; + real64 localMinCompDensScalingFactor; + + }; + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElems the number of elements + * @param[inout] kernelComponent the kernel component providing access to the compute function + */ + template< typename POLICY, typename KERNEL_TYPE > + static StackVariables + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > globalScalingFactor( 1.0 ); + + RAJA::ReduceMaxLoc< ReducePolicy< POLICY >, real64 > maxDeltaPres( std::numeric_limits< real64 >::min(), -1 ); + RAJA::ReduceMaxLoc< ReducePolicy< POLICY >, real64 > maxDeltaTemp( std::numeric_limits< real64 >::min(), -1 ); + RAJA::ReduceMaxLoc< ReducePolicy< POLICY >, real64 > maxDeltaCompDens( std::numeric_limits< real64 >::min(), -1 ); + + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minPresScalingFactor( 1.0 ); + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minTempScalingFactor( 1.0 ); + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minCompDensScalingFactor( 1.0 ); + + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( kernelComponent.ghostRank( ei ) >= 0 ) + { + return; + } + + StackVariables stack; + kernelComponent.setup( ei, stack ); + kernelComponent.compute( ei, stack ); + + globalScalingFactor.min( stack.localMinVal ); + + maxDeltaPres.maxloc( stack.localMaxDeltaPres, ei ); + maxDeltaTemp.maxloc( stack.localMaxDeltaTemp, ei ); + maxDeltaCompDens.maxloc( stack.localMaxDeltaCompDens, ei ); + + minPresScalingFactor.min( stack.localMinPresScalingFactor ); + minTempScalingFactor.min( stack.localMinTempScalingFactor ); + minCompDensScalingFactor.min( stack.localMinCompDensScalingFactor ); + } ); + + return StackVariables( globalScalingFactor.get(), + maxDeltaPres.get(), + maxDeltaPres.getLoc(), + maxDeltaTemp.get(), + maxDeltaTemp.getLoc(), + maxDeltaCompDens.get(), + maxDeltaCompDens.getLoc(), + minPresScalingFactor.get(), + minTempScalingFactor.get(), + minCompDensScalingFactor.get() ); + } + + GEOS_HOST_DEVICE + void setup( localIndex const ei, + StackVariables & stack ) const + { + Base::setup( ei, stack ); + + stack.localMaxDeltaPres = 0.0; + stack.localMaxDeltaPresLoc = -1; + stack.localMaxDeltaTemp = 0.0; + stack.localMaxDeltaTempLoc = -1; + stack.localMaxDeltaCompDens = 0.0; + stack.localMaxDeltaCompDensLoc =-1; + + stack.localMinPresScalingFactor = 1.0; + stack.localMinTempScalingFactor = 1.0; + stack.localMinCompDensScalingFactor = 1.0; + } + + /** + * @brief Compute the local value + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void compute( localIndex const ei, + StackVariables & stack ) const + { + computeScalingFactor( ei, stack ); + } + + /** + * @brief Compute the local value of the scaling factor + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + * @param[in] kernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeScalingFactor( localIndex const ei, + StackVariables & stack, + FUNC && kernelOp = NoOpFunc{} ) const + { + real64 constexpr eps = minDensForDivision; + + // compute the change in pressure + real64 const pres = m_pressure[ei]; + real64 const absPresChange = LvArray::math::abs( m_localSolution[stack.localRow] ); + if( stack.localMaxDeltaPres < absPresChange ) + { + stack.localMaxDeltaPres = absPresChange; + } + + // compute pressure scaling factor + real64 presScalingFactor = 1.0; + // when enabled, absolute change scaling has a priority over relative change + if( m_maxAbsolutePresChange > 0.0 ) // maxAbsolutePresChange <= 0.0 means that absolute scaling is disabled + { + if( absPresChange > m_maxAbsolutePresChange ) + { + presScalingFactor = m_maxAbsolutePresChange / absPresChange; + } + } + else if( pres > eps ) + { + real64 const relativePresChange = absPresChange / pres; + if( relativePresChange > m_maxRelativePresChange ) + { + presScalingFactor = m_maxRelativePresChange / relativePresChange; + } + } + m_pressureScalingFactor[ei] = presScalingFactor; + if( stack.localMinVal > presScalingFactor ) + { + stack.localMinVal = presScalingFactor; + } + if( stack.localMinPresScalingFactor > presScalingFactor ) + { + stack.localMinPresScalingFactor = presScalingFactor; + } + + real64 prevTotalDens = 0; + for( integer ic = 0; ic < m_numComp; ++ic ) + { + prevTotalDens += m_compDens[ei][ic]; + } + + m_compDensScalingFactor[ei] = 1.0; + + // compute the change in component densities and component fractions + for( integer ic = 0; ic < m_numComp; ++ic ) + { + // compute scaling factor based on relative change in component densities + real64 const absCompDensChange = LvArray::math::abs( m_localSolution[stack.localRow + ic + 1] ); + if( stack.localMaxDeltaCompDens < absCompDensChange ) + { + stack.localMaxDeltaCompDens = absCompDensChange; + } + + // This actually checks the change in component fraction, using a lagged total density + // Indeed we can rewrite the following check as: + // | prevCompDens / prevTotalDens - newCompDens / prevTotalDens | > maxCompFracChange + // Note that the total density in the second term is lagged (i.e, we use prevTotalDens) + // because I found it more robust than using directly newTotalDens (which can vary also + // wildly when the compDens change is large) + real64 const maxAbsCompDensChange = m_maxCompFracChange * prevTotalDens; + if( absCompDensChange > maxAbsCompDensChange && absCompDensChange > eps ) + { + real64 const compScalingFactor = maxAbsCompDensChange / absCompDensChange; + m_compDensScalingFactor[ei] = LvArray::math::min( m_compDensScalingFactor[ei], compScalingFactor ); + if( stack.localMinVal > compScalingFactor ) + { + stack.localMinVal = compScalingFactor; + } + if( stack.localMinCompDensScalingFactor > compScalingFactor ) + { + stack.localMinCompDensScalingFactor = compScalingFactor; + } + } + + // switch from relative to absolute when value is < 1.0 + real64 const maxRelCompDensChange = m_maxRelativeCompDensChange * LvArray::math::max( m_compDens[ei][ic], 1.0 ); + if( absCompDensChange > maxRelCompDensChange && absCompDensChange > eps ) + { + real64 const compScalingFactor = maxRelCompDensChange / absCompDensChange; + m_compDensScalingFactor[ei] = LvArray::math::min( m_compDensScalingFactor[ei], compScalingFactor ); + if( stack.localMinVal > compScalingFactor ) + { + stack.localMinVal = compScalingFactor; + } + if( stack.localMinCompDensScalingFactor > compScalingFactor ) + { + stack.localMinCompDensScalingFactor = compScalingFactor; + } + } + } + + // compute the scaling factor for other vars, such as temperature + kernelOp(); + } + +protected: + + /// Max allowed changes in primary variables + real64 const m_maxRelativePresChange; + real64 const m_maxAbsolutePresChange; + real64 const m_maxCompFracChange; + real64 const m_maxRelativeCompDensChange; + +}; + +/** + * @class SolutionScalingKernelFactory + */ +class SolutionScalingKernelFactory +{ +public: + + /* + * @brief Create and launch the kernel computing the scaling factor + * @tparam POLICY the kernel policy + * @param[in] maxRelativePresChange the max allowed relative pressure change + * @param[in] maxAbsolutePresChange the max allowed absolute pressure change + * @param[in] maxCompFracChange the max allowed comp fraction change + * @param[in] maxRelativeCompDensChange the max allowed comp density change + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + * @return the scaling factor + */ + template< typename POLICY > + static SolutionScalingKernel::StackVariables + createAndLaunch( real64 const maxRelativePresChange, + real64 const maxAbsolutePresChange, + real64 const maxCompFracChange, + real64 const maxRelativeCompDensChange, + arrayView1d< real64 const > const pressure, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > compDensScalingFactor, + globalIndex const rankOffset, + integer const numComp, + string const dofKey, + ElementSubRegionBase & subRegion, + arrayView1d< real64 const > const localSolution ) + { + SolutionScalingKernel kernel( maxRelativePresChange, maxAbsolutePresChange, maxCompFracChange, maxRelativeCompDensChange, rankOffset, + numComp, dofKey, subRegion, localSolution, pressure, compDens, pressureScalingFactor, compDensScalingFactor ); + return SolutionScalingKernel::launch< POLICY >( subRegion.size(), kernel ); + } +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONSCALINGKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StabilizedFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StabilizedFluxComputeKernel.hpp new file mode 100644 index 00000000000..eb679f2942c --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StabilizedFluxComputeKernel.hpp @@ -0,0 +1,378 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StabilizedFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_STABILIZEDFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_STABILIZEDFLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernel.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityFields.hpp" + +namespace geos +{ + +namespace stabilizedCompositionalMultiphaseFVMKernels +{ + +/******************************** FluxComputeKernel ********************************/ + +/** + * @class FluxComputeKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > +class FluxComputeKernel : public isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > +{ +public: + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using CompFlowAccessors = AbstractBase::CompFlowAccessors; + using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; + using CapPressureAccessors = AbstractBase::CapPressureAccessors; + using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; + + using StabCompFlowAccessors = + StencilAccessors< fields::flow::macroElementIndex, + fields::flow::elementStabConstant, + fields::flow::pressure_n >; + + using StabMultiFluidAccessors = + StencilMaterialAccessors< constitutive::MultiFluidBase, + fields::multifluid::phaseDensity_n, + fields::multifluid::phaseCompFraction_n >; + + using RelPermAccessors = + StencilMaterialAccessors< constitutive::RelativePermeabilityBase, fields::relperm::phaseRelPerm_n >; + + using AbstractBase::m_dt; + using AbstractBase::m_numPhases; + using AbstractBase::m_kernelFlags; + using AbstractBase::m_rankOffset; + using AbstractBase::m_ghostRank; + using AbstractBase::m_dofNumber; + using AbstractBase::m_gravCoef; + using AbstractBase::m_phaseCompFrac; + using AbstractBase::m_dCompFrac_dCompDens; + using AbstractBase::m_pres; + + using Base = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + using Base::numComp; + using Base::numDof; + using Base::numEqn; + using Base::numFluxSupportPoints; + using Base::maxNumElems; + using Base::maxNumConns; + using Base::maxStencilSize; + using Base::m_phaseMob; + using Base::m_dPhaseMassDens; + using Base::m_stencilWrapper; + using Base::m_seri; + using Base::m_sesri; + using Base::m_sei; + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor accessor for the dofs numbers + * @param[in] compFlowAccessor accessor for wrappers registered by the solver + * @param[in] stabCompFlowAccessor accessor for wrappers registered by the solver needed for stabilization + * @param[in] multiFluidAccessor accessor for wrappers registered by the multifluid model + * @param[in] stabMultiFluidAccessor accessor for wrappers registered by the multifluid model needed for stabilization + * @param[in] capPressureAccessors accessor for wrappers registered by the cap pressure model + * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model + * @param[in] relPermAccessors accessor for wrappers registered by the relative permeability model needed for stabilization + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed together + */ + FluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + StabCompFlowAccessors const & stabCompFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + StabMultiFluidAccessors const & stabMultiFluidAccessors, + CapPressureAccessors const & capPressureAccessors, + PermeabilityAccessors const & permeabilityAccessors, + RelPermAccessors const & relPermAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags ) + : Base( numPhases, + rankOffset, + stencilWrapper, + dofNumberAccessor, + compFlowAccessors, + multiFluidAccessors, + capPressureAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs, + kernelFlags ), + m_pres_n( stabCompFlowAccessors.get( fields::flow::pressure_n {} ) ), + m_phaseDens_n( stabMultiFluidAccessors.get( fields::multifluid::phaseDensity_n {} ) ), + m_phaseCompFrac_n( stabMultiFluidAccessors.get( fields::multifluid::phaseCompFraction_n {} ) ), + m_phaseRelPerm_n( relPermAccessors.get( fields::relperm::phaseRelPerm_n {} ) ), + m_macroElementIndex( stabCompFlowAccessors.get( fields::flow::macroElementIndex {} ) ), + m_elementStabConstant( stabCompFlowAccessors.get( fields::flow::elementStabConstant {} ) ) + {} + + struct StackVariables : public Base::StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables( localIndex const size, localIndex numElems ) + : Base::StackVariables( size, numElems ) + {} + + using Base::StackVariables::stencilSize; + using Base::StackVariables::numConnectedElems; + using Base::StackVariables::transmissibility; + using Base::StackVariables::dTrans_dPres; + using Base::StackVariables::dofColIndices; + using Base::StackVariables::localFlux; + using Base::StackVariables::localFluxJacobian; + + /// Stabilization transmissibility + real64 stabTransmissibility[maxNumConns][numFluxSupportPoints]{}; + + }; + + /** + * @brief Compute the local flux contributions to the residual and Jacobian, including stabilization + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeFlux( localIndex const iconn, + StackVariables & stack ) const + { + + m_stencilWrapper.computeStabilizationWeights( iconn, + stack.stabTransmissibility ); + + // *********************************************** + // First, we call the base computeFlux to compute: + // 1) compFlux and its derivatives, + // + // We use the lambda below (called **inside** the phase loop of the base computeFlux) to compute stabilization terms + Base::computeFlux( iconn, stack, [&] ( integer const ip, + integer const GEOS_UNUSED_PARAM( useNewGravity ), + localIndex const (&k)[2], + localIndex const (&seri)[2], + localIndex const (&sesri)[2], + localIndex const (&sei)[2], + localIndex const connectionIndex, + localIndex const k_up, + localIndex const er_up, + localIndex const esr_up, + localIndex const ei_up, + real64 const potGrad, + real64 const phaseFlux, + real64 const (&dPhaseFlux_dP)[2], + real64 const (&dPhaseFlux_dC)[2][numComp] ) + { + GEOS_UNUSED_VAR( k_up, potGrad, phaseFlux, dPhaseFlux_dP, dPhaseFlux_dC, er_up, esr_up, ei_up ); + + /// stabilization flux and derivatives + real64 stabFlux[numComp]{}; + real64 dStabFlux_dP[numFluxSupportPoints][numComp]{}; + + real64 const stabTrans[numFluxSupportPoints] = { stack.stabTransmissibility[connectionIndex][0], + stack.stabTransmissibility[connectionIndex][1] }; + + // we are in the loop over phases, ip provides the current phase index. + + real64 dPresGradStab = 0.0; + integer stencilMacroElements[numFluxSupportPoints]{}; + + // Step 1: compute the pressure jump at the interface + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + localIndex const er = seri[ke]; + localIndex const esr = sesri[ke]; + localIndex const ei = sei[ke]; + + stencilMacroElements[ke] = m_macroElementIndex[er][esr][ei]; + + // use the jump in *delta* pressure in the stabilization term + dPresGradStab += + m_elementStabConstant[er][esr][ei] * stabTrans[ke] * (m_pres[er][esr][ei] - m_pres_n[er][esr][ei]); + } + + // Step 2: compute the stabilization flux + integer const k_up_stab = (dPresGradStab >= 0) ? 0 : 1; + + localIndex const er_up_stab = seri[k_up_stab]; + localIndex const esr_up_stab = sesri[k_up_stab]; + localIndex const ei_up_stab = sei[k_up_stab]; + + bool const areInSameMacroElement = stencilMacroElements[0] == stencilMacroElements[1]; + bool const isStabilizationActive = stencilMacroElements[0] >= 0 && stencilMacroElements[1] >= 0; + if( isStabilizationActive && areInSameMacroElement ) + { + + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const laggedUpwindCoef = m_phaseDens_n[er_up_stab][esr_up_stab][ei_up_stab][0][ip] + * m_phaseCompFrac_n[er_up_stab][esr_up_stab][ei_up_stab][0][ip][ic] + * m_phaseRelPerm_n[er_up_stab][esr_up_stab][ei_up_stab][0][ip]; + stabFlux[ic] += dPresGradStab * laggedUpwindCoef; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + real64 const tauStab = m_elementStabConstant[seri[ke]][sesri[ke]][sei[ke]]; + dStabFlux_dP[ke][ic] += tauStab * stabTrans[ke] * laggedUpwindCoef; + } + } + } + + // Step 3: add the stabilization flux and its derivatives to the residual and Jacobian + for( integer ic = 0; ic < numComp; ++ic ) + { + integer const eqIndex0 = k[0] * numEqn + ic; + integer const eqIndex1 = k[1] * numEqn + ic; + + stack.localFlux[eqIndex0] += stabFlux[ic]; + stack.localFlux[eqIndex1] += -stabFlux[ic]; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + localIndex const localDofIndexPres = k[ke] * numDof; + stack.localFluxJacobian[eqIndex0][localDofIndexPres] += dStabFlux_dP[ke][ic]; + stack.localFluxJacobian[eqIndex1][localDofIndexPres] += -dStabFlux_dP[ke][ic]; + } + } + + } ); // end call to Base::computeFlux + + } + +protected: + + /// Views on flow properties at the previous converged time step + ElementViewConst< arrayView1d< real64 const > > const m_pres_n; + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_phaseDens_n; + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const m_phaseCompFrac_n; + ElementViewConst< arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > > const m_phaseRelPerm_n; + + /// Views on the macroelement indices and stab constant + ElementViewConst< arrayView1d< integer const > > const m_macroElementIndex; + ElementViewConst< arrayView1d< real64 const > > const m_elementStabConstant; + +}; + +/** + * @class FluxComputeKernelFactory + */ +class FluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] hasCapPressure flag specifying whether capillary pressure is used or not + * @param[in] solverName name of the solver (to name accessors) + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + string const & dofKey, + integer const hasCapPressure, + integer const useTotalMassEquation, + string const & solverName, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_DOF = NC() + 1; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags; + if( hasCapPressure ) + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::CapPressure ); + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::TotalMassEquation ); + + using KERNEL_TYPE = FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + typename KERNEL_TYPE::CompFlowAccessors compFlowAccessors( elemManager, solverName ); + typename KERNEL_TYPE::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); + typename KERNEL_TYPE::StabCompFlowAccessors stabCompFlowAccessors( elemManager, solverName ); + typename KERNEL_TYPE::StabMultiFluidAccessors stabMultiFluidAccessors( elemManager, solverName ); + typename KERNEL_TYPE::CapPressureAccessors capPressureAccessors( elemManager, solverName ); + typename KERNEL_TYPE::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); + typename KERNEL_TYPE::RelPermAccessors relPermAccessors( elemManager, solverName ); + + KERNEL_TYPE kernel( numPhases, rankOffset, stencilWrapper, dofNumberAccessor, + compFlowAccessors, stabCompFlowAccessors, multiFluidAccessors, stabMultiFluidAccessors, + capPressureAccessors, permeabilityAccessors, relPermAccessors, + dt, localMatrix, localRhs, kernelFlags ); + KERNEL_TYPE::template launch< POLICY >( stencilWrapper.size(), kernel ); + } ); + } +}; + +} // namespace stabilizedCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_STABILIZEDFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp new file mode 100644 index 00000000000..af2cec319f2 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp @@ -0,0 +1,194 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StatisticsKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_STATISTICSKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_STATISTICSKERNEL_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/relativePermeability/layouts.hpp" + + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** StatisticsKernel ********************************/ + +struct StatisticsKernel +{ + template< typename POLICY > + static void + saveDeltaPressure( localIndex const size, + arrayView1d< real64 const > const & pres, + arrayView1d< real64 const > const & initPres, + arrayView1d< real64 > const & deltaPres ) + { + forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + deltaPres[ei] = pres[ei] - initPres[ei]; + } ); + } + + template< typename POLICY > + static void + launch( localIndex const size, + integer const numComps, + integer const numPhases, + real64 const relpermThreshold, + arrayView1d< integer const > const & elemGhostRank, + arrayView1d< real64 const > const & volume, + arrayView1d< real64 const > const & pres, + arrayView1d< real64 const > const & deltaPres, + arrayView1d< real64 const > const & temp, + arrayView1d< real64 const > const & refPorosity, + arrayView2d< real64 const > const & porosity, + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseDensity, + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > const & phaseCompFraction, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac, + arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > const & phaseTrappedVolFrac, + arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > const & phaseRelperm, + real64 & minPres, + real64 & avgPresNumerator, + real64 & maxPres, + real64 & minDeltaPres, + real64 & maxDeltaPres, + real64 & minTemp, + real64 & avgTempNumerator, + real64 & maxTemp, + real64 & totalUncompactedPoreVol, + arrayView1d< real64 > const & phaseDynamicPoreVol, + arrayView1d< real64 > const & phaseMass, + arrayView1d< real64 > const & trappedPhaseMass, + arrayView1d< real64 > const & immobilePhaseMass, + arrayView2d< real64 > const & dissolvedComponentMass ) + { + RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinPres( LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgPresNumerator( 0.0 ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxPres( -LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinDeltaPres( LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxDeltaPres( -LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinTemp( LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgTempNumerator( 0.0 ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxTemp( 0.0 ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalUncompactedPoreVol( 0.0 ); + + // For this arrays phaseDynamicPoreVol, phaseMass, dissolvedComponentMass, + // using an array of ReduceSum leads to a formal parameter overflow in CUDA. + // As a workaround, we use a slice with RAJA::atomicAdd instead + + forAll< parallelDevicePolicy<> >( size, [numComps, + numPhases, + relpermThreshold, + elemGhostRank, + volume, + refPorosity, + porosity, + pres, + deltaPres, + temp, + phaseDensity, + phaseVolFrac, + phaseTrappedVolFrac, + phaseRelperm, + phaseCompFraction, + subRegionMinPres, + subRegionAvgPresNumerator, + subRegionMaxPres, + subRegionMinDeltaPres, + subRegionMaxDeltaPres, + subRegionMinTemp, + subRegionAvgTempNumerator, + subRegionMaxTemp, + subRegionTotalUncompactedPoreVol, + phaseDynamicPoreVol, + phaseMass, + trappedPhaseMass, + immobilePhaseMass, + dissolvedComponentMass] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( elemGhostRank[ei] >= 0 ) + { + return; + } + + // To match our "reference", we have to use reference porosity here, not the actual porosity when we compute averages + real64 const uncompactedPoreVol = volume[ei] * refPorosity[ei]; + real64 const dynamicPoreVol = volume[ei] * porosity[ei][0]; + + subRegionMinPres.min( pres[ei] ); + subRegionAvgPresNumerator += uncompactedPoreVol * pres[ei]; + subRegionMaxPres.max( pres[ei] ); + + subRegionMaxDeltaPres.max( deltaPres[ei] ); + subRegionMinDeltaPres.min( deltaPres[ei] ); + + subRegionMinTemp.min( temp[ei] ); + subRegionAvgTempNumerator += uncompactedPoreVol * temp[ei]; + subRegionMaxTemp.max( temp[ei] ); + subRegionTotalUncompactedPoreVol += uncompactedPoreVol; + for( integer ip = 0; ip < numPhases; ++ip ) + { + real64 const elemPhaseVolume = dynamicPoreVol * phaseVolFrac[ei][ip]; + real64 const elemPhaseMass = phaseDensity[ei][0][ip] * elemPhaseVolume; + real64 const elemTrappedPhaseMass = phaseDensity[ei][0][ip] * dynamicPoreVol * phaseTrappedVolFrac[ei][0][ip]; + // RAJA::atomicAdd used here because we do not use ReduceSum here (for the reason explained above) + RAJA::atomicAdd( parallelDeviceAtomic{}, &phaseDynamicPoreVol[ip], elemPhaseVolume ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &phaseMass[ip], elemPhaseMass ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &trappedPhaseMass[ip], elemTrappedPhaseMass ); + if( phaseRelperm[ei][0][ip] < relpermThreshold ) + { + RAJA::atomicAdd( parallelDeviceAtomic{}, &immobilePhaseMass[ip], elemPhaseMass ); + } + for( integer ic = 0; ic < numComps; ++ic ) + { + // RAJA::atomicAdd used here because we do not use ReduceSum here (for the reason explained above) + RAJA::atomicAdd( parallelDeviceAtomic{}, &dissolvedComponentMass[ip][ic], phaseCompFraction[ei][0][ip][ic] * elemPhaseMass ); + } + } + + } ); + + minPres = subRegionMinPres.get(); + avgPresNumerator = subRegionAvgPresNumerator.get(); + maxPres = subRegionMaxPres.get(); + minDeltaPres = subRegionMinDeltaPres.get(); + maxDeltaPres = subRegionMaxDeltaPres.get(); + minTemp = subRegionMinTemp.get(); + avgTempNumerator = subRegionAvgTempNumerator.get(); + maxTemp = subRegionMaxTemp.get(); + totalUncompactedPoreVol = subRegionTotalUncompactedPoreVol.get(); + + // dummy loop to bring data back to the CPU + forAll< serialPolicy >( 1, [phaseDynamicPoreVol, phaseMass, trappedPhaseMass, immobilePhaseMass, dissolvedComponentMass] ( localIndex const ) + { + GEOS_UNUSED_VAR( phaseDynamicPoreVol, phaseMass, trappedPhaseMass, immobilePhaseMass, dissolvedComponentMass ); + } ); + } +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_STATISTICSKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalAccumulationKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalAccumulationKernel.hpp new file mode 100644 index 00000000000..58d6aa12cf4 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalAccumulationKernel.hpp @@ -0,0 +1,345 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalAccumulationKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALACCUMULATIONKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALACCUMULATIONKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseBaseKernels +{ + +/******************************** AccumulationKernel ********************************/ + +/** + * @class AccumulationKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @brief Define the interface for the assembly kernel in charge of thermal accumulation and volume balance + */ +template< localIndex NUM_COMP, localIndex NUM_DOF > +class AccumulationKernel : public isothermalCompositionalMultiphaseBaseKernels::AccumulationKernel< NUM_COMP, NUM_DOF > +{ +public: + + using Base = isothermalCompositionalMultiphaseBaseKernels::AccumulationKernel< NUM_COMP, NUM_DOF >; + using Base::numComp; + using Base::numDof; + using Base::numEqn; + using Base::m_numPhases; + using Base::m_rankOffset; + using Base::m_dofNumber; + using Base::m_elemGhostRank; + using Base::m_volume; + using Base::m_porosity; + using Base::m_dPoro_dPres; + using Base::m_dCompFrac_dCompDens; + using Base::m_phaseVolFrac; + using Base::m_dPhaseVolFrac; + using Base::m_phaseDens; + using Base::m_dPhaseDens; + using Base::m_phaseCompFrac; + using Base::m_dPhaseCompFrac; + using Base::m_localMatrix; + using Base::m_localRhs; + + /** + * @brief Constructor + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + AccumulationKernel( localIndex const numPhases, + globalIndex const rankOffset, + string const dofKey, + ElementSubRegionBase const & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > const kernelFlags ) + : Base( numPhases, rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs, kernelFlags ), + m_dPoro_dTemp( solid.getDporosity_dTemperature() ), + m_phaseInternalEnergy( fluid.phaseInternalEnergy() ), + m_dPhaseInternalEnergy( fluid.dPhaseInternalEnergy() ), + m_rockInternalEnergy( solid.getInternalEnergy() ), + m_dRockInternalEnergy_dTemp( solid.getDinternalEnergy_dTemperature() ), + m_energy_n( subRegion.getField< fields::flow::energy_n >() ) + {} + + struct StackVariables : public Base::StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables() + : Base::StackVariables() + {} + + using Base::StackVariables::localRow; + using Base::StackVariables::dofIndices; + using Base::StackVariables::localResidual; + using Base::StackVariables::localJacobian; + + // derivative of pore volume wrt temperature + real64 dPoreVolume_dTemp = 0.0; + + // Solid energy + + /// Solid energy at time n+1 + real64 solidEnergy = 0.0; + + /// Derivative of solid internal energy with respect to pressure + real64 dSolidEnergy_dPres = 0.0; + + /// Derivative of solid internal energy with respect to temperature + real64 dSolidEnergy_dTemp = 0.0; + + }; + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] ei the element index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const ei, + StackVariables & stack ) const + { + Base::setup( ei, stack ); + + // derivative of pore volume wrt temperature + stack.dPoreVolume_dTemp = m_volume[ei] * m_dPoro_dTemp[ei][0]; + + // initialize the solid volume + real64 const solidVolume = m_volume[ei] * ( 1.0 - m_porosity[ei][0] ); + real64 const dSolidVolume_dPres = -m_volume[ei] * m_dPoro_dPres[ei][0]; + real64 const dSolidVolume_dTemp = -stack.dPoreVolume_dTemp; + + // initialize the solid internal energy + stack.solidEnergy = solidVolume * m_rockInternalEnergy[ei][0]; + stack.dSolidEnergy_dPres = dSolidVolume_dPres * m_rockInternalEnergy[ei][0]; + stack.dSolidEnergy_dTemp = solidVolume * m_dRockInternalEnergy_dTemp[ei][0] + + dSolidVolume_dTemp * m_rockInternalEnergy[ei][0]; + } + + /** + * @brief Compute the local accumulation contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const ei, + StackVariables & stack ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + // start with old time step value + stack.localResidual[numEqn-1] = -m_energy_n[ei]; + + Base::computeAccumulation( ei, stack, [&] ( integer const ip, + real64 const & phaseAmount, + real64 const & dPhaseAmount_dP, + real64 const (&dPhaseAmount_dC)[numComp] ) + { + // We are in the loop over phases, ip provides the current phase index. + // We have to do two things: + // 1- Assemble the derivatives of the component mass balance equations with respect to temperature + // 2- Assemble the phase-dependent part of the accumulation term of the energy equation + + real64 dPhaseInternalEnergy_dC[numComp]{}; + + // construct the slices + arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseDens = m_phaseDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > dPhaseDens = m_dPhaseDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 2 > phaseCompFrac = m_phaseCompFrac[ei][0]; + arraySlice3d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac = m_dPhaseCompFrac[ei][0]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseInternalEnergy = m_phaseInternalEnergy[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > dPhaseInternalEnergy = m_dPhaseInternalEnergy[ei][0]; + + // Step 1: assemble the derivatives of the component mass balance equations with respect to temperature + + real64 const dPhaseAmount_dT = stack.dPoreVolume_dTemp * phaseVolFrac[ip] * phaseDens[ip] + + stack.poreVolume * (dPhaseVolFrac[ip][Deriv::dT] * phaseDens[ip] + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dT] ); + for( integer ic = 0; ic < numComp; ++ic ) + { + stack.localJacobian[ic][numDof-1] += dPhaseAmount_dT * phaseCompFrac[ip][ic] + + phaseAmount * dPhaseCompFrac[ip][ic][Deriv::dT]; + } + + // Step 2: assemble the phase-dependent part of the accumulation term of the energy equation + + real64 const phaseEnergy = phaseAmount * phaseInternalEnergy[ip]; + real64 const dPhaseEnergy_dP = dPhaseAmount_dP * phaseInternalEnergy[ip] + + phaseAmount * dPhaseInternalEnergy[ip][Deriv::dP]; + real64 const dPhaseEnergy_dT = dPhaseAmount_dT * phaseInternalEnergy[ip] + + phaseAmount * dPhaseInternalEnergy[ip][Deriv::dT]; + + // local accumulation + stack.localResidual[numEqn-1] += phaseEnergy; + + // derivatives w.r.t. pressure and temperature + stack.localJacobian[numEqn-1][0] += dPhaseEnergy_dP; + stack.localJacobian[numEqn-1][numDof-1] += dPhaseEnergy_dT; + + // derivatives w.r.t. component densities + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseInternalEnergy[ip], dPhaseInternalEnergy_dC, Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.localJacobian[numEqn-1][jc + 1] += phaseInternalEnergy[ip] * dPhaseAmount_dC[jc] + + dPhaseInternalEnergy_dC[jc] * phaseAmount; + } + } ); + + // Step 3: assemble the solid part of the accumulation term + + // local accumulation and derivatives w.r.t. pressure and temperature + stack.localResidual[numEqn-1] += stack.solidEnergy; + stack.localJacobian[numEqn-1][0] += stack.dSolidEnergy_dPres; + stack.localJacobian[numEqn-1][numDof-1] += stack.dSolidEnergy_dTemp; + + } + + /** + * @brief Compute the local volume balance contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeVolumeBalance( localIndex const ei, + StackVariables & stack ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + Base::computeVolumeBalance( ei, stack, [&] ( real64 const & oneMinusPhaseVolFraction ) + { + GEOS_UNUSED_VAR( oneMinusPhaseVolFraction ); + + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; + + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + stack.localJacobian[numEqn-2][numDof-1] -= dPhaseVolFrac[ip][Deriv::dT]; + } + } ); + } + + GEOS_HOST_DEVICE + void complete( localIndex const ei, + StackVariables & stack ) const + { + // Step 1: assemble the component mass balance equations and volume balance equations + Base::complete( ei, stack ); + + // Step 2: assemble the energy equation + m_localRhs[stack.localRow + numEqn-1] += stack.localResidual[numEqn-1]; + m_localMatrix.template addToRow< serialAtomic >( stack.localRow + numEqn-1, + stack.dofIndices, + stack.localJacobian[numEqn-1], + numDof ); + } + +protected: + + /// View on derivative of porosity w.r.t temperature + arrayView2d< real64 const > const m_dPoro_dTemp; + + /// Views on phase internal energy + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseInternalEnergy; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseInternalEnergy; + + /// Views on rock internal energy + arrayView2d< real64 const > m_rockInternalEnergy; + arrayView2d< real64 const > m_dRockInternalEnergy_dTemp; + + /// Views on energy + arrayView1d< real64 const > m_energy_n; + +}; + +/** + * @class AccumulationKernelFactory + */ +class AccumulationKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( localIndex const numComps, + localIndex const numPhases, + globalIndex const rankOffset, + integer const useTotalMassEquation, + string const dofKey, + ElementSubRegionBase const & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComps, [&] ( auto NC ) + { + localIndex constexpr NUM_COMP = NC(); + localIndex constexpr NUM_DOF = NC()+2; + + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ); + + AccumulationKernel< NUM_COMP, NUM_DOF > kernel( numPhases, rankOffset, dofKey, subRegion, + fluid, solid, localMatrix, localRhs, kernelFlags ); + AccumulationKernel< NUM_COMP, NUM_DOF >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + +}; + +} // namespace thermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALACCUMULATIONKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalDiffusionDispersionFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalDiffusionDispersionFluxComputeKernel.hpp new file mode 100644 index 00000000000..957d98bee43 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalDiffusionDispersionFluxComputeKernel.hpp @@ -0,0 +1,352 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalDiffusionDispersionFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALDIFFUSIONDISPERSIONFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALDIFFUSIONDISPERSIONFLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/DiffusionDispersionFluxComputeKernel.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseFVMKernels +{ + +/******************************** DiffusionDispersionFluxComputeKernel ********************************/ + +/** + * @class DiffusionDispersionFluxComputeKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @brief Define the interface for the assembly kernel in charge of diffusion/dispersion flux terms + */ +template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > +class DiffusionDispersionFluxComputeKernel : + public isothermalCompositionalMultiphaseFVMKernels::DiffusionDispersionFluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > +{ +public: + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using CompFlowAccessors = AbstractBase::CompFlowAccessors; + using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; + using AbstractBase::m_dt; + using AbstractBase::m_dPhaseCompFrac; + using AbstractBase::m_dPhaseVolFrac; + + using Base = typename isothermalCompositionalMultiphaseFVMKernels::DiffusionDispersionFluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + using DiffusionAccessors = typename Base::DiffusionAccessors; + using DispersionAccessors = typename Base::DispersionAccessors; + using PorosityAccessors = typename Base::PorosityAccessors; + using Base::numFluxSupportPoints; + using Base::numEqn; + using Base::numComp; + using Base::numDof; + using Base::m_referencePorosity; + using Base::m_phaseVolFrac; + using Base::m_phaseDens; + using Base::m_dPhaseDens; + using Base::m_phaseDiffusivityMultiplier; + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor + * @param[in] compFlowAccessors + * @param[in] multiFluidAccessors + * @param[in] diffusionAccessors + * @param[in] dispersionAccessors + * @param[in] porosityAccessors + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed together + */ + DiffusionDispersionFluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + DiffusionAccessors const & diffusionAccessors, + DispersionAccessors const & dispersionAccessors, + PorosityAccessors const & porosityAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags ) + : Base( numPhases, + rankOffset, + stencilWrapper, + dofNumberAccessor, + compFlowAccessors, + multiFluidAccessors, + diffusionAccessors, + dispersionAccessors, + porosityAccessors, + dt, + localMatrix, + localRhs, + kernelFlags ) + {} + + struct StackVariables : public Base::StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables( localIndex const size, localIndex numElems ) + : Base::StackVariables( size, numElems ) + {} + + using Base::StackVariables::transmissibility; + using Base::StackVariables::localFlux; + using Base::StackVariables::localFluxJacobian; + + }; + + /** + * @brief Compute the local diffusion flux contributions to the residual and Jacobian + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + inline + void computeDiffusionFlux( localIndex const iconn, + StackVariables & stack ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + // *********************************************** + // First, we call the base computeFlux to compute the diffusionFlux and its derivatives (including derivatives wrt temperature), + // + // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables + Base::computeDiffusionFlux( iconn, stack, [&] ( integer const ip, + integer const ic, + localIndex const (&k)[2], + localIndex const (&seri)[2], + localIndex const (&sesri)[2], + localIndex const (&sei)[2], + localIndex const connectionIndex, + localIndex const k_up, + localIndex const er_up, + localIndex const esr_up, + localIndex const ei_up, + real64 const compFracGrad, + real64 const upwindCoefficient ) + { + // We are in the loop over phases and components, ip provides the current phase index. + + real64 dCompFracGrad_dT[numFluxSupportPoints]{}; + real64 dDiffusionFlux_dT[numFluxSupportPoints]{}; + + /// compute the TPFA component difference + for( integer i = 0; i < numFluxSupportPoints; i++ ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + dCompFracGrad_dT[i] += stack.transmissibility[connectionIndex][i] * m_dPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dT]; + } + + // add contributions of the derivatives of component fractions wrt pressure/component fractions + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dDiffusionFlux_dT[ke] += upwindCoefficient * dCompFracGrad_dT[ke]; + } + + // add contributions of the derivatives of upwind coefficient wrt temperature + real64 const dUpwindCoefficient_dT = + m_referencePorosity[er_up][esr_up][ei_up] * + m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * + ( m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dT] * m_phaseVolFrac[er_up][esr_up][ei_up][ip] + + m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_dPhaseVolFrac[er_up][esr_up][ei_up][ip][Deriv::dT] ); + dDiffusionFlux_dT[k_up] += dUpwindCoefficient_dT * compFracGrad; + + // finally, increment local flux and local Jacobian + integer const eqIndex0 = k[0] * numEqn + ic; + integer const eqIndex1 = k[1] * numEqn + ic; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + localIndex const localDofIndexTemp = k[ke] * numDof + numComp + 1; + stack.localFluxJacobian[eqIndex0][localDofIndexTemp] += m_dt * dDiffusionFlux_dT[ke]; + stack.localFluxJacobian[eqIndex1][localDofIndexTemp] -= m_dt * dDiffusionFlux_dT[ke]; + } + } ); + } + + /** + * @brief Compute the local dispersion flux contributions to the residual and Jacobian + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + inline + void computeDispersionFlux( localIndex const iconn, + StackVariables & stack ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + // *********************************************** + // First, we call the base computeFlux to compute the dispersionFlux and its derivatives (including derivatives wrt temperature), + // + // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables + Base::computeDispersionFlux( iconn, stack, [&] ( integer const ip, + integer const ic, + localIndex const (&k)[2], + localIndex const (&seri)[2], + localIndex const (&sesri)[2], + localIndex const (&sei)[2], + localIndex const connectionIndex, + localIndex const k_up, + localIndex const er_up, + localIndex const esr_up, + localIndex const ei_up, + real64 const compFracGrad ) + { + // We are in the loop over phases and components, ip provides the current phase index. + + real64 dCompFracGrad_dT[numFluxSupportPoints]{}; + real64 dDispersionFlux_dT[numFluxSupportPoints]{}; + + /// compute the TPFA component difference + for( integer i = 0; i < numFluxSupportPoints; i++ ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + dCompFracGrad_dT[i] += stack.transmissibility[connectionIndex][i] * m_dPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dT]; + } + + // add contributions of the derivatives of component fractions wrt pressure/component fractions + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dDispersionFlux_dT[ke] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * dCompFracGrad_dT[ke]; + } + + // add contributions of the derivatives of upwind coefficient wrt temperature + dDispersionFlux_dT[k_up] += m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dT] * compFracGrad; + + // finally, increment local flux and local Jacobian + integer const eqIndex0 = k[0] * numEqn + ic; + integer const eqIndex1 = k[1] * numEqn + ic; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + localIndex const localDofIndexTemp = k[ke] * numDof + numComp + 1; + stack.localFluxJacobian[eqIndex0][localDofIndexTemp] += m_dt * dDispersionFlux_dT[ke]; + stack.localFluxJacobian[eqIndex1][localDofIndexTemp] -= m_dt * dDispersionFlux_dT[ke]; + } + } ); + } +}; + +/** + * @class DiffusionDispersionFluxComputeKernelFactory + */ +class DiffusionDispersionFluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] hasDiffusion flag specifying whether diffusion is used or not + * @param[in] hasDispersion flag specifying whether dispersion is used or not + * @param[in] solverName the name of the solver + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + string const & dofKey, + integer const hasDiffusion, + integer const hasDispersion, + integer const useTotalMassEquation, + string const & solverName, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_DOF = NC() + 2; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::TotalMassEquation ); + + using kernelType = DiffusionDispersionFluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); + typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); + typename kernelType::DiffusionAccessors diffusionAccessors( elemManager, solverName ); + typename kernelType::DispersionAccessors dispersionAccessors( elemManager, solverName ); + typename kernelType::PorosityAccessors porosityAccessors( elemManager, solverName ); + + kernelType kernel( numPhases, rankOffset, stencilWrapper, + dofNumberAccessor, compFlowAccessors, multiFluidAccessors, + diffusionAccessors, dispersionAccessors, porosityAccessors, + dt, localMatrix, localRhs, kernelFlags ); + kernelType::template launch< POLICY >( stencilWrapper.size(), + hasDiffusion, hasDispersion, + kernel ); + } ); + } +}; + +} // namespace thermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALDIFFUSIONDISPERSIONFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalDirichletFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalDirichletFluxComputeKernel.hpp new file mode 100644 index 00000000000..5df89fc5e3e --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalDirichletFluxComputeKernel.hpp @@ -0,0 +1,484 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalDirichletFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/DirichletFluxComputeKernel.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "constitutive/thermalConductivity/MultiPhaseThermalConductivityBase.hpp" +#include "constitutive/thermalConductivity/ThermalConductivityFields.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseFVMKernels +{ + +/******************************** DirichletFluxComputeKernel ********************************/ + +/** + * @class DirichletFluxComputeKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @tparam FLUIDWRAPPER the type of the fluid wrapper + * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms + */ +template< integer NUM_COMP, integer NUM_DOF, typename FLUIDWRAPPER > +class DirichletFluxComputeKernel : public isothermalCompositionalMultiphaseFVMKernels::DirichletFluxComputeKernel< NUM_COMP, + NUM_DOF, + FLUIDWRAPPER > +{ +public: + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using CompFlowAccessors = AbstractBase::CompFlowAccessors; + using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; + using CapPressureAccessors = AbstractBase::CapPressureAccessors; + using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; + + using AbstractBase::m_dt; + using AbstractBase::m_numPhases; + using AbstractBase::m_rankOffset; + using AbstractBase::m_dofNumber; + using AbstractBase::m_gravCoef; + using AbstractBase::m_phaseCompFrac; + using AbstractBase::m_dPhaseCompFrac; + using AbstractBase::m_dCompFrac_dCompDens; + + using Base = isothermalCompositionalMultiphaseFVMKernels::DirichletFluxComputeKernel< NUM_COMP, NUM_DOF, FLUIDWRAPPER >; + using Base::numComp; + using Base::numDof; + using Base::numEqn; + using Base::m_phaseMob; + using Base::m_dPhaseMob; + using Base::m_dPhaseMassDens; + using Base::m_stencilWrapper; + using Base::m_seri; + using Base::m_sesri; + using Base::m_sei; + using Base::m_faceTemp; + using Base::m_faceGravCoef; + + + using ThermalCompFlowAccessors = + StencilAccessors< fields::flow::temperature >; + + using ThermalMultiFluidAccessors = + StencilMaterialAccessors< constitutive::MultiFluidBase, + fields::multifluid::phaseEnthalpy, + fields::multifluid::dPhaseEnthalpy >; + + using ThermalConductivityAccessors = + StencilMaterialAccessors< constitutive::MultiPhaseThermalConductivityBase, + fields::thermalconductivity::effectiveConductivity >; + // for now, we treat thermal conductivity explicitly + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] faceManager the face manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] fluidWrapper reference to the fluid wrapper + * @param[in] dofNumberAccessor accessor for the dofs numbers + * @param[in] compFlowAccessor accessor for wrappers registered by the solver + * @param[in] thermalCompFlowAccessors accessor for *thermal* wrappers registered by the solver + * @param[in] multiFluidAccessor accessor for wrappers registered by the multifluid model + * @param[in] thermalMultiFluidAccessors accessor for *thermal* wrappers registered by the multifluid model + * @param[in] capPressureAccessors accessor for wrappers registered by the cap pressure model + * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model + * @param[in] thermalConductivityAccessors accessor for wrappers registered by the thermal conductivity model + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed together + */ + DirichletFluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + FaceManager const & faceManager, + BoundaryStencilWrapper const & stencilWrapper, + FLUIDWRAPPER const & fluidWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + ThermalCompFlowAccessors const & thermalCompFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + ThermalMultiFluidAccessors const & thermalMultiFluidAccessors, + CapPressureAccessors const & capPressureAccessors, + PermeabilityAccessors const & permeabilityAccessors, + ThermalConductivityAccessors const & thermalConductivityAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags ) + : Base( numPhases, + rankOffset, + faceManager, + stencilWrapper, + fluidWrapper, + dofNumberAccessor, + compFlowAccessors, + multiFluidAccessors, + capPressureAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs, + kernelFlags ), + m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), + m_phaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), + m_dPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ), + m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ) + {} + + struct StackVariables : public Base::StackVariables + { +public: + + /** + * @brief Constructor for the stack variables + * @param[in] size size of the stencil for this connection + * @param[in] numElems number of elements for this connection + */ + GEOS_HOST_DEVICE + StackVariables( localIndex const size, localIndex numElems ) + : Base::StackVariables( size, numElems ) + {} + + using Base::StackVariables::transmissibility; + using Base::StackVariables::dofColIndices; + using Base::StackVariables::localFlux; + using Base::StackVariables::localFluxJacobian; + + // Component fluxes and derivatives + + /// Derivatives of component fluxes wrt temperature + real64 dCompFlux_dT[numComp]{}; + + + // Energy fluxes and derivatives + + /// Energy fluxes + real64 energyFlux = 0.0; + /// Derivative of energy fluxes wrt pressure + real64 dEnergyFlux_dP = 0.0; + /// Derivative of energy fluxes wrt temperature + real64 dEnergyFlux_dT = 0.0; + /// Derivatives of energy fluxes wrt component densities + real64 dEnergyFlux_dC[numComp]{}; + + }; + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeFlux( localIndex const iconn, + StackVariables & stack ) const + { + using Order = BoundaryStencil::Order; + using Deriv = constitutive::multifluid::DerivativeOffset; + + // *********************************************** + // First, we call the base computeFlux to compute: + // 1) compFlux and its derivatives (including derivatives wrt temperature), + // 2) enthalpy part of energyFlux and its derivatives (including derivatives wrt temperature) + // + // Computing dCompFlux_dT and the enthalpy flux requires quantities already computed in the base computeFlux, + // such as potGrad, phaseFlux, and the indices of the upwind cell + // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables + Base::computeFlux( iconn, stack, [&] ( integer const ip, + localIndex const er, + localIndex const esr, + localIndex const ei, + localIndex const kf, + real64 const f, // potGrad times trans + real64 const facePhaseMob, + arraySlice1d< const real64, constitutive::multifluid::USD_PHASE - 2 > const & facePhaseEnthalpy, + arraySlice2d< const real64, constitutive::multifluid::USD_PHASE_COMP-2 > const & facePhaseCompFrac, + real64 const phaseFlux, + real64 const dPhaseFlux_dP, + real64 const (&dPhaseFlux_dC)[numComp] ) + { + // We are in the loop over phases, ip provides the current phase index. + + // Step 1: compute the derivatives of the mean density at the interface wrt temperature + + real64 const dDensMean_dT = 0.5 * m_dPhaseMassDens[er][esr][ei][0][ip][Deriv::dT]; + + // Step 2: compute the derivatives of the phase potential difference wrt temperature + //***** calculation of flux ***** + + real64 const dF_dT = -stack.transmissibility * dDensMean_dT * ( m_gravCoef[er][esr][ei] - m_faceGravCoef[kf] ); + + // Step 3: compute the derivatives of the (upwinded) compFlux wrt temperature + // *** upwinding *** + + // note: the upwinding is done in the base class, which is in charge of + // computing the following quantities: potGrad, phaseFlux + // It is easier to hard-code the if/else because it is difficult to address elem and face variables in a uniform way + + + if( f >= 0 ) // the element is upstream + { + + // Step 3.1.a: compute the derivative of phase flux wrt temperature + real64 const dPhaseFlux_dT = m_phaseMob[er][esr][ei][ip] * dF_dT + m_dPhaseMob[er][esr][ei][ip][Deriv::dT] * f; + + // Step 3.2.a: compute the derivative of component flux wrt temperature + + // slice some constitutive arrays to avoid too much indexing in component loop + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 3 > phaseCompFracSub = + m_phaseCompFrac[er][esr][ei][0][ip]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 3 > dPhaseCompFracSub = + m_dPhaseCompFrac[er][esr][ei][0][ip]; + + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const ycp = phaseCompFracSub[ic]; + stack.dCompFlux_dT[ic] += dPhaseFlux_dT * ycp + phaseFlux * dPhaseCompFracSub[ic][Deriv::dT]; + } + + // Step 3.3.a: compute the enthalpy flux + + real64 const enthalpy = m_phaseEnthalpy[er][esr][ei][0][ip]; + stack.energyFlux += phaseFlux * enthalpy; + stack.dEnergyFlux_dP += dPhaseFlux_dP * enthalpy + phaseFlux * m_dPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dP]; + stack.dEnergyFlux_dT += dPhaseFlux_dT * enthalpy + phaseFlux * m_dPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dT]; + + real64 dProp_dC[numComp]{}; + applyChainRule( numComp, + m_dCompFrac_dCompDens[er][esr][ei], + m_dPhaseEnthalpy[er][esr][ei][0][ip], + dProp_dC, + Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.dEnergyFlux_dC[jc] += dPhaseFlux_dC[jc] * enthalpy + phaseFlux * dProp_dC[jc]; + } + + } + else // the face is upstream + { + + // Step 3.1.b: compute the derivative of phase flux wrt temperature + real64 const dPhaseFlux_dT = facePhaseMob * dF_dT; + + // Step 3.2.b: compute the derivative of component flux wrt temperature + + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const ycp = facePhaseCompFrac[ip][ic]; + stack.dCompFlux_dT[ic] += dPhaseFlux_dT * ycp; + } + + // Step 3.3.b: compute the enthalpy flux + + real64 const enthalpy = facePhaseEnthalpy[ip]; + stack.energyFlux += phaseFlux * enthalpy; + stack.dEnergyFlux_dP += dPhaseFlux_dP * enthalpy; + stack.dEnergyFlux_dT += dPhaseFlux_dT * enthalpy; + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.dEnergyFlux_dC[jc] += dPhaseFlux_dC[jc] * enthalpy; + } + + } + + } ); + + // ***************************************************** + // Computation of the conduction term in the energy flux + // Note that the phase enthalpy term in the energy was computed above + // Note that this term is computed using an explicit treatment of conductivity for now + + // Step 1: compute the thermal transmissibilities at this face + // Below, the thermal conductivity used to compute (explicitly) the thermal conducivity + // To avoid modifying the signature of the "computeWeights" function for now, we pass m_thermalConductivity twice + // TODO: modify computeWeights to accomodate explicit coefficients + real64 thermalTrans = 0.0; + real64 dThermalTrans_dPerm[3]{}; // not used + m_stencilWrapper.computeWeights( iconn, + m_thermalConductivity, + thermalTrans, + dThermalTrans_dPerm ); + + // Step 2: compute temperature difference at the interface + stack.energyFlux += thermalTrans + * ( m_temp[m_seri( iconn, Order::ELEM )][m_sesri( iconn, Order::ELEM )][m_sei( iconn, Order::ELEM )] - m_faceTemp[m_sei( iconn, Order::FACE )] ); + stack.dEnergyFlux_dT += thermalTrans; + + + // ********************************************************************************** + // At this point, we have computed the energyFlux and the compFlux for all components + // We have to do two things here: + // 1) Add dCompFlux_dTemp to the localFluxJacobian of the component mass balance equations + // 2) Add energyFlux and its derivatives to the localFlux(Jacobian) of the energy balance equation + + // Step 1: add dCompFlux_dTemp to localFluxJacobian + for( integer ic = 0; ic < numComp; ++ic ) + { + stack.localFluxJacobian[ic][numDof-1] = m_dt * stack.dCompFlux_dT[ic]; + } + + // Step 2: add energyFlux and its derivatives to localFlux and localFluxJacobian + integer const localRowIndexEnergy = numEqn-1; + stack.localFlux[localRowIndexEnergy] = m_dt * stack.energyFlux; + + stack.localFluxJacobian[localRowIndexEnergy][0] = m_dt * stack.dEnergyFlux_dP; + stack.localFluxJacobian[localRowIndexEnergy][numDof-1] = m_dt * stack.dEnergyFlux_dT; + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.localFluxJacobian[localRowIndexEnergy][jc+1] = m_dt * stack.dEnergyFlux_dC[jc]; + } + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void complete( localIndex const iconn, + StackVariables & stack ) const + { + // Call Case::complete to assemble the component mass balance equations (i = 0 to i = numDof-2) + // In the lambda, add contribution to residual and jacobian into the energy balance equation + Base::complete( iconn, stack, [&] ( localIndex const localRow ) + { + // beware, there is volume balance eqn in m_localRhs and m_localMatrix! + RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn], stack.localFlux[numEqn-1] ); + AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > + ( localRow + numEqn, + stack.dofColIndices, + stack.localFluxJacobian[numEqn-1], + numDof ); + + } ); + } + +protected: + + /// Views on temperature + ElementViewConst< arrayView1d< real64 const > > const m_temp; + + /// Views on phase enthalpies + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_phaseEnthalpy; + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dPhaseEnthalpy; + + /// View on thermal conductivity + ElementViewConst< arrayView3d< real64 const > > const m_thermalConductivity; + // for now, we treat thermal conductivity explicitly + +}; + +/** + * @class DirichletFluxComputeKernelFactory + */ +class DirichletFluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] solverName name of the solver (to name accessors) + * @param[in] faceManager reference to the face manager + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] fluidBase the multifluid constitutive model + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + integer const useTotalMassEquation, + string const & dofKey, + string const & solverName, + FaceManager const & faceManager, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + constitutive::MultiFluidBase & fluidBase, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + constitutive::constitutiveComponentUpdatePassThru< true >( fluidBase, numComps, [&]( auto & fluid, auto NC ) + { + using FluidType = TYPEOFREF( fluid ); + typename FluidType::KernelWrapper const fluidWrapper = fluid.createKernelWrapper(); + + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_DOF = NC() + 2; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + // for now, we neglect capillary pressure in the kernel + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::TotalMassEquation ); + + using KernelType = DirichletFluxComputeKernel< NUM_COMP, NUM_DOF, typename FluidType::KernelWrapper >; + typename KernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); + typename KernelType::ThermalCompFlowAccessors thermalCompFlowAccessors( elemManager, solverName ); + typename KernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); + typename KernelType::ThermalMultiFluidAccessors thermalMultiFluidAccessors( elemManager, solverName ); + typename KernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); + typename KernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); + typename KernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName ); + + KernelType kernel( numPhases, rankOffset, faceManager, stencilWrapper, fluidWrapper, + dofNumberAccessor, compFlowAccessors, thermalCompFlowAccessors, multiFluidAccessors, thermalMultiFluidAccessors, + capPressureAccessors, permeabilityAccessors, thermalConductivityAccessors, + dt, localMatrix, localRhs, kernelFlags ); + KernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); + } ); + } +}; + +} // namespace thermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalFluxComputeKernel.hpp new file mode 100644 index 00000000000..519b1a538bb --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalFluxComputeKernel.hpp @@ -0,0 +1,573 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALFLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernel.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "constitutive/thermalConductivity/MultiPhaseThermalConductivityBase.hpp" +#include "constitutive/thermalConductivity/ThermalConductivityFields.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseFVMKernels +{ + +/******************************** FluxComputeKernel ********************************/ + +/** + * @class FluxComputeKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > +class FluxComputeKernel : public isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > +{ +public: + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using CompFlowAccessors = AbstractBase::CompFlowAccessors; + using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; + using CapPressureAccessors = AbstractBase::CapPressureAccessors; + using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; + + using AbstractBase::m_dt; + using AbstractBase::m_numPhases; + using AbstractBase::m_rankOffset; + using AbstractBase::m_dofNumber; + using AbstractBase::m_gravCoef; + using AbstractBase::m_phaseVolFrac; + using AbstractBase::m_dPhaseVolFrac; + using AbstractBase::m_phaseCompFrac; + using AbstractBase::m_dPhaseCompFrac; + using AbstractBase::m_dCompFrac_dCompDens; + + using Base = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + using Base::numComp; + using Base::numDof; + using Base::numEqn; + using Base::maxNumElems; + using Base::maxNumConns; + using Base::maxStencilSize; + using Base::numFluxSupportPoints; + using Base::m_phaseMob; + using Base::m_dPhaseMob; + using Base::m_dPhaseMassDens; + using Base::m_dPhaseCapPressure_dPhaseVolFrac; + using Base::m_stencilWrapper; + using Base::m_seri; + using Base::m_sesri; + using Base::m_sei; + + using ThermalCompFlowAccessors = + StencilAccessors< fields::flow::temperature >; + + using ThermalMultiFluidAccessors = + StencilMaterialAccessors< constitutive::MultiFluidBase, + fields::multifluid::phaseEnthalpy, + fields::multifluid::dPhaseEnthalpy >; + + using ThermalConductivityAccessors = + StencilMaterialAccessors< constitutive::MultiPhaseThermalConductivityBase, + fields::thermalconductivity::effectiveConductivity >; + // for now, we treat thermal conductivity explicitly + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor accessor for the dofs numbers + * @param[in] compFlowAccessor accessor for wrappers registered by the solver + * @param[in] thermalCompFlowAccessors accessor for *thermal* wrappers registered by the solver + * @param[in] multiFluidAccessor accessor for wrappers registered by the multifluid model + * @param[in] thermalMultiFluidAccessors accessor for *thermal* wrappers registered by the multifluid model + * @param[in] capPressureAccessors accessor for wrappers registered by the cap pressure model + * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model + * @param[in] thermalConductivityAccessors accessor for wrappers registered by the thermal conductivity model + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed all together + */ + FluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + ThermalCompFlowAccessors const & thermalCompFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + ThermalMultiFluidAccessors const & thermalMultiFluidAccessors, + CapPressureAccessors const & capPressureAccessors, + PermeabilityAccessors const & permeabilityAccessors, + ThermalConductivityAccessors const & thermalConductivityAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags ) + : Base( numPhases, + rankOffset, + stencilWrapper, + dofNumberAccessor, + compFlowAccessors, + multiFluidAccessors, + capPressureAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs, + kernelFlags ), + m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), + m_phaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), + m_dPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ), + m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ) + {} + + struct StackVariables : public Base::StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables( localIndex const size, localIndex numElems ) + : Base::StackVariables( size, numElems ) + {} + + using Base::StackVariables::stencilSize; + using Base::StackVariables::numConnectedElems; + using Base::StackVariables::transmissibility; + using Base::StackVariables::dTrans_dPres; + using Base::StackVariables::dofColIndices; + using Base::StackVariables::localFlux; + using Base::StackVariables::localFluxJacobian; + + // Thermal transmissibility (for now, no derivatives) + + real64 thermalTransmissibility[maxNumConns][2]{}; + }; + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + inline + void computeFlux( localIndex const iconn, + StackVariables & stack ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + // *********************************************** + // First, we call the base computeFlux to compute: + // 1) compFlux and its derivatives (including derivatives wrt temperature), + // 2) enthalpy part of convectiveEnergyFlux and its derivatives (including derivatives wrt temperature) + // + // Computing dCompFlux_dT and the enthalpy flux requires quantities already computed in the base computeFlux, + // such as potGrad, phaseFlux, and the indices of the upwind cell + // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables + Base::computeFlux( iconn, stack, [&] ( integer const ip, + integer const useNewGravity, + localIndex const (&k)[2], + localIndex const (&seri)[2], + localIndex const (&sesri)[2], + localIndex const (&sei)[2], + localIndex const connectionIndex, + localIndex const k_up, + localIndex const er_up, + localIndex const esr_up, + localIndex const ei_up, + real64 const potGrad, + real64 const phaseFlux, + real64 const (&dPhaseFlux_dP)[2], + real64 const (&dPhaseFlux_dC)[2][numComp] ) + { + // We are in the loop over phases, ip provides the current phase index. + + // Step 1: compute the derivatives of the mean density at the interface wrt temperature + + real64 dDensMean_dT[numFluxSupportPoints]{}; + + real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], + stack.transmissibility[connectionIndex][1] }; + + real64 convectiveEnergyFlux = 0.0; + real64 dConvectiveEnergyFlux_dP[numFluxSupportPoints]{}; + real64 dConvectiveEnergyFlux_dT[numFluxSupportPoints]{}; + real64 dConvectiveEnergyFlux_dC[numFluxSupportPoints][numComp]{}; + real64 dCompFlux_dT[numFluxSupportPoints][numComp]{}; + + integer denom = 0; + for( integer i = 0; i < numFluxSupportPoints; ++i ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + bool const phaseExists = (m_phaseVolFrac[er_up][esr_up][ei_up][ip] > 0); + if( useNewGravity && !phaseExists ) + { + continue; + } + + dDensMean_dT[i] = m_dPhaseMassDens[er][esr][ei][0][ip][Deriv::dT]; + denom++; + } + if( denom > 1 ) + { + for( integer i = 0; i < numFluxSupportPoints; ++i ) + { + dDensMean_dT[i] /= denom; + } + } + + // Step 2: compute the derivatives of the phase potential difference wrt temperature + //***** calculation of flux ***** + + real64 dPresGrad_dT[numFluxSupportPoints]{}; + real64 dGravHead_dT[numFluxSupportPoints]{}; + + // compute potential difference MPFA-style + for( integer i = 0; i < numFluxSupportPoints; ++i ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + // Step 2.1: compute derivative of capillary pressure wrt temperature + real64 dCapPressure_dT = 0.0; + if( AbstractBase::m_kernelFlags.isSet( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::CapPressure ) ) + { + for( integer jp = 0; jp < m_numPhases; ++jp ) + { + real64 const dCapPressure_dS = m_dPhaseCapPressure_dPhaseVolFrac[er][esr][ei][0][ip][jp]; + dCapPressure_dT += dCapPressure_dS * m_dPhaseVolFrac[er][esr][ei][jp][Deriv::dT]; + } + } + + // Step 2.2: compute derivative of phase pressure difference wrt temperature + dPresGrad_dT[i] -= trans[i] * dCapPressure_dT; + real64 const gravD = trans[i] * m_gravCoef[er][esr][ei]; + + // Step 2.3: compute derivative of gravity potential difference wrt temperature + for( integer j = 0; j < numFluxSupportPoints; ++j ) + { + dGravHead_dT[j] += dDensMean_dT[j] * gravD; + } + } + + // Step 3: compute the derivatives of the (upwinded) compFlux wrt temperature + // *** upwinding *** + + // note: the upwinding is done in the base class, which is in charge of + // computing the following quantities: potGrad, phaseFlux, k_up, er_up, esr_up, ei_up + + real64 dPhaseFlux_dT[numFluxSupportPoints]{}; + + // Step 3.1: compute the derivative of phase flux wrt temperature + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dPhaseFlux_dT[ke] += dPresGrad_dT[ke]; + } + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dPhaseFlux_dT[ke] -= dGravHead_dT[ke]; + } + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dPhaseFlux_dT[ke] *= m_phaseMob[er_up][esr_up][ei_up][ip]; + } + dPhaseFlux_dT[k_up] += m_dPhaseMob[er_up][esr_up][ei_up][ip][Deriv::dT] * potGrad; + + // Step 3.2: compute the derivative of component flux wrt temperature + + // slice some constitutive arrays to avoid too much indexing in component loop + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 3 > phaseCompFracSub = + m_phaseCompFrac[er_up][esr_up][ei_up][0][ip]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 3 > dPhaseCompFracSub = + m_dPhaseCompFrac[er_up][esr_up][ei_up][0][ip]; + + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const ycp = phaseCompFracSub[ic]; + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dCompFlux_dT[ke][ic] += dPhaseFlux_dT[ke] * ycp; + } + dCompFlux_dT[k_up][ic] += phaseFlux * dPhaseCompFracSub[ic][Deriv::dT]; + } + + // Step 4: add dCompFlux_dTemp to localFluxJacobian + for( integer ic = 0; ic < numComp; ++ic ) + { + integer const eqIndex0 = k[0]* numEqn + ic; + integer const eqIndex1 = k[1]* numEqn + ic; + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + integer const localDofIndexTemp = k[ke] * numDof + numDof - 1; + stack.localFluxJacobian[eqIndex0][localDofIndexTemp] += m_dt * dCompFlux_dT[ke][ic]; + stack.localFluxJacobian[eqIndex1][localDofIndexTemp] -= m_dt * dCompFlux_dT[ke][ic]; + } + } + + // Step 5: compute the enthalpy flux + real64 const enthalpy = m_phaseEnthalpy[er_up][esr_up][ei_up][0][ip]; + convectiveEnergyFlux += phaseFlux * enthalpy; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dConvectiveEnergyFlux_dP[ke] += dPhaseFlux_dP[ke] * enthalpy; + dConvectiveEnergyFlux_dT[ke] += dPhaseFlux_dT[ke] * enthalpy; + + for( integer jc = 0; jc < numComp; ++jc ) + { + dConvectiveEnergyFlux_dC[ke][jc] += dPhaseFlux_dC[ke][jc] * enthalpy; + } + } + + dConvectiveEnergyFlux_dP[k_up] += phaseFlux * m_dPhaseEnthalpy[er_up][esr_up][ei_up][0][ip][Deriv::dP]; + dConvectiveEnergyFlux_dT[k_up] += phaseFlux * m_dPhaseEnthalpy[er_up][esr_up][ei_up][0][ip][Deriv::dT]; + + real64 dProp_dC[numComp]{}; + applyChainRule( numComp, + m_dCompFrac_dCompDens[er_up][esr_up][ei_up], + m_dPhaseEnthalpy[er_up][esr_up][ei_up][0][ip], + dProp_dC, + Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + dConvectiveEnergyFlux_dC[k_up][jc] += phaseFlux * dProp_dC[jc]; + } + + // Step 6: add convectiveFlux and its derivatives to localFlux and localFluxJacobian + integer const localRowIndexEnergy0 = k[0] * numEqn + numEqn - 1; + integer const localRowIndexEnergy1 = k[1] * numEqn + numEqn - 1; + stack.localFlux[localRowIndexEnergy0] += m_dt * convectiveEnergyFlux; + stack.localFlux[localRowIndexEnergy1] -= m_dt * convectiveEnergyFlux; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + integer const localDofIndexPres = k[ke] * numDof; + stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexPres] += m_dt * dConvectiveEnergyFlux_dP[ke]; + stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexPres] -= m_dt * dConvectiveEnergyFlux_dP[ke]; + integer const localDofIndexTemp = localDofIndexPres + numDof - 1; + stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexTemp] += m_dt * dConvectiveEnergyFlux_dT[ke]; + stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexTemp] -= m_dt * dConvectiveEnergyFlux_dT[ke]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + integer const localDofIndexComp = localDofIndexPres + jc + 1; + stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexComp] += m_dt * dConvectiveEnergyFlux_dC[ke][jc]; + stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexComp] -= m_dt * dConvectiveEnergyFlux_dC[ke][jc]; + } + } + } ); + + // ***************************************************** + // Computation of the conduction term in the energy flux + // Note that the phase enthalpy term in the energy was computed above + // Note that this term is computed using an explicit treatment of conductivity for now + + // Step 1: compute the thermal transmissibilities at this face + // Below, the thermal conductivity used to compute (explicitly) the thermal conducivity + // To avoid modifying the signature of the "computeWeights" function for now, we pass m_thermalConductivity twice + // TODO: modify computeWeights to accomodate explicit coefficients + m_stencilWrapper.computeWeights( iconn, + m_thermalConductivity, + m_thermalConductivity, // we have to pass something here, so we just use thermal conductivity + stack.thermalTransmissibility, + stack.dTrans_dPres ); // again, we have to pass something here, but this is unused for now + + + + localIndex k[2]{}; + localIndex connectionIndex = 0; + + for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) + { + for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) + { + real64 const thermalTrans[2] = { stack.thermalTransmissibility[connectionIndex][0], stack.thermalTransmissibility[connectionIndex][1] }; + localIndex const seri[2] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; + localIndex const sesri[2] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; + localIndex const sei[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; + + real64 conductiveEnergyFlux = 0.0; + real64 dConductiveEnergyFlux_dT[numFluxSupportPoints]{}; + + // Step 2: compute temperature difference at the interface + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + localIndex const er = seri[ke]; + localIndex const esr = sesri[ke]; + localIndex const ei = sei[ke]; + + conductiveEnergyFlux += thermalTrans[ke] * m_temp[er][esr][ei]; + dConductiveEnergyFlux_dT[ke] += thermalTrans[ke]; + } + + // Step 3: add conductiveFlux and its derivatives to localFlux and localFluxJacobian + integer const localRowIndexEnergy0 = k[0] * numEqn + numEqn - 1; + integer const localRowIndexEnergy1 = k[1] * numEqn + numEqn - 1; + stack.localFlux[localRowIndexEnergy0] += m_dt * conductiveEnergyFlux; + stack.localFlux[localRowIndexEnergy1] -= m_dt * conductiveEnergyFlux; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + integer const localDofIndexTemp = k[ke] * numDof + numDof - 1; + stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexTemp] += m_dt * dConductiveEnergyFlux_dT[ke]; + stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexTemp] -= m_dt * dConductiveEnergyFlux_dT[ke]; + } + } + } + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + inline + void complete( localIndex const iconn, + StackVariables & stack ) const + { + // Call Case::complete to assemble the component mass balance equations (i = 0 to i = numDof-2) + // In the lambda, add contribution to residual and jacobian into the energy balance equation + Base::complete( iconn, stack, [&] ( integer const i, + localIndex const localRow ) + { + // beware, there is volume balance eqn in m_localRhs and m_localMatrix! + RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn], stack.localFlux[i * numEqn + numEqn-1] ); + AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > + ( localRow + numEqn, + stack.dofColIndices.data(), + stack.localFluxJacobian[i * numEqn + numEqn-1].dataIfContiguous(), + stack.stencilSize * numDof ); + + } ); + } + +protected: + + /// Views on temperature + ElementViewConst< arrayView1d< real64 const > > const m_temp; + + /// Views on phase enthalpies + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_phaseEnthalpy; + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dPhaseEnthalpy; + + /// View on thermal conductivity + ElementViewConst< arrayView3d< real64 const > > const m_thermalConductivity; + // for now, we treat thermal conductivity explicitly + +}; + +/** + * @class FluxComputeKernelFactory + */ +class FluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] hasCapPressure flag specifying whether capillary pressure is used or not + * @param[in] solverName name of the solver (to name accessors) + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + string const & dofKey, + integer const hasCapPressure, + integer const useTotalMassEquation, + string const & solverName, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_DOF = NC() + 2; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags; + if( hasCapPressure ) + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::CapPressure ); + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::TotalMassEquation ); + + using KernelType = FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + typename KernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); + typename KernelType::ThermalCompFlowAccessors thermalCompFlowAccessors( elemManager, solverName ); + typename KernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); + typename KernelType::ThermalMultiFluidAccessors thermalMultiFluidAccessors( elemManager, solverName ); + typename KernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); + typename KernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); + typename KernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName ); + + KernelType kernel( numPhases, rankOffset, stencilWrapper, dofNumberAccessor, + compFlowAccessors, thermalCompFlowAccessors, multiFluidAccessors, thermalMultiFluidAccessors, + capPressureAccessors, permeabilityAccessors, thermalConductivityAccessors, + dt, localMatrix, localRhs, kernelFlags ); + KernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); + } ); + } +}; + +} // namespace thermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseMobilityKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseMobilityKernel.hpp new file mode 100644 index 00000000000..796e59bee30 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseMobilityKernel.hpp @@ -0,0 +1,154 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalPhaseMobilityKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALPHASEMOBILITYKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALPHASEMOBILITYKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/PhaseMobilityKernel.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseFVMKernels +{ + +/******************************** PhaseMobilityKernel ********************************/ + +/** + * @class PhaseMobilityKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_PHASE number of fluid phases + * @brief Define the interface for the property kernel in charge of computing the phase mobilities + */ +template< integer NUM_COMP, integer NUM_PHASE > +class PhaseMobilityKernel : public isothermalCompositionalMultiphaseFVMKernels::PhaseMobilityKernel< NUM_COMP, NUM_PHASE > +{ +public: + + using Base = isothermalCompositionalMultiphaseFVMKernels::PhaseMobilityKernel< NUM_COMP, NUM_PHASE >; + using Base::numPhase; + using Base::m_dPhaseVolFrac; + using Base::m_dPhaseMob; + using Base::m_phaseDens; + using Base::m_dPhaseDens; + using Base::m_phaseVisc; + using Base::m_dPhaseVisc; + using Base::m_dPhaseRelPerm_dPhaseVolFrac; + + /** + * @brief Constructor + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] relperm the relperm model + */ + PhaseMobilityKernel( ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::RelativePermeabilityBase const & relperm ) + : Base( subRegion, fluid, relperm ) + {} + + /** + * @brief Compute the phase mobilities in an element + * @param[in] ei the element index + */ + GEOS_HOST_DEVICE + inline + void compute( localIndex const ei ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseDens = m_phaseDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseVisc = m_phaseVisc[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseVisc = m_dPhaseVisc[ei][0]; + arraySlice2d< real64 const, constitutive::relperm::USD_RELPERM_DS - 2 > const dPhaseRelPerm_dPhaseVolFrac = m_dPhaseRelPerm_dPhaseVolFrac[ei][0]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; + + Base::compute( ei, [&] ( localIndex const ip, + real64 const & phaseMob, + arraySlice1d< real64, compflow::USD_PHASE_DC - 2 > const & dPhaseMob ) + { + // Step 1: compute the derivative of relPerm[ip] wrt temperature + real64 dRelPerm_dT = 0.0; + for( integer jp = 0; jp < numPhase; ++jp ) + { + dRelPerm_dT += dPhaseRelPerm_dPhaseVolFrac[ip][jp] * dPhaseVolFrac[jp][Deriv::dT]; + } + + // Step 2: compute the derivative of phaseMob[ip] wrt temperature + dPhaseMob[Deriv::dT] = dRelPerm_dT * phaseDens[ip] / phaseVisc[ip] + + phaseMob * (dPhaseDens[ip][Deriv::dT] / phaseDens[ip] - dPhaseVisc[ip][Deriv::dT] / phaseVisc[ip] ); + } ); + } + +}; + +/** + * @class PhaseMobilityKernelFactory + */ +class PhaseMobilityKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComp the number of fluid components + * @param[in] numPhase the number of fluid phases + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] relperm the relperm model + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + integer const numPhase, + ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::RelativePermeabilityBase const & relperm ) + { + if( numPhase == 2 ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseMobilityKernel< NUM_COMP, 2 > kernel( subRegion, fluid, relperm ); + PhaseMobilityKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + else if( numPhase == 3 ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseMobilityKernel< NUM_COMP, 3 > kernel( subRegion, fluid, relperm ); + PhaseMobilityKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + } +}; + +} // namespace thermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALPHASEMOBILITYKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp new file mode 100644 index 00000000000..3c4ed036b3b --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp @@ -0,0 +1,140 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalPhaseVolumeFractionKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALPHASEVOLUMEFRACTIONKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALPHASEVOLUMEFRACTIONKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseBaseKernels +{ + +/******************************** PhaseVolumeFractionKernel ********************************/ + +/** + * @class PhaseVolumeFractionKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_PHASE number of fluid phases + * @brief Define the interface for the property kernel in charge of computing the phase volume fractions + */ +template< integer NUM_COMP, integer NUM_PHASE > +class PhaseVolumeFractionKernel : public isothermalCompositionalMultiphaseBaseKernels::PhaseVolumeFractionKernel< NUM_COMP, NUM_PHASE > +{ +public: + + using Base = isothermalCompositionalMultiphaseBaseKernels::PhaseVolumeFractionKernel< NUM_COMP, NUM_PHASE >; + using Base::m_dPhaseDens; + using Base::m_dPhaseFrac; + using Base::m_dPhaseVolFrac; + + /** + * @brief Constructor + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + PhaseVolumeFractionKernel( ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid ) + : Base( subRegion, fluid ) + {} + + /** + * @brief Compute the phase volume fractions in an element + * @param[in] ei the element index + */ + GEOS_HOST_DEVICE + real64 compute( localIndex const ei ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseFrac = m_dPhaseFrac[ei][0]; + + arraySlice2d< real64, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; + + // Call the base compute the compute the phase volume fraction + return Base::compute( ei, [&] ( localIndex const ip, + real64 const & phaseVolFrac, + real64 const & phaseDensInv, + real64 const & totalDensity ) + { + // when this lambda is called, we are in the phase loop + // for each phase ip, compute the derivative of phase volume fraction wrt temperature + dPhaseVolFrac[ip][Deriv::dT] = (dPhaseFrac[ip][Deriv::dT] - phaseVolFrac * dPhaseDens[ip][Deriv::dT]) * phaseDensInv; + dPhaseVolFrac[ip][Deriv::dT] *= totalDensity; + } ); + } + +}; + +/** + * @class PhaseVolumeFractionKernelFactory + */ +class PhaseVolumeFractionKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComp the number of fluid components + * @param[in] numPhase the number of fluid phases + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + template< typename POLICY > + static real64 + createAndLaunch( integer const numComp, + integer const numPhase, + ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid ) + { + real64 maxDeltaPhaseVolFrac = 0.0; + if( numPhase == 2 ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseVolumeFractionKernel< NUM_COMP, 2 > kernel( subRegion, fluid ); + maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + else if( numPhase == 3 ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseVolumeFractionKernel< NUM_COMP, 3 > kernel( subRegion, fluid ); + maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + return maxDeltaPhaseVolFrac; + } +}; + +} // namespace thermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALPHASEVOLUMEFRACTIONKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalResidualNormKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalResidualNormKernel.hpp new file mode 100644 index 00000000000..6b60c11b66f --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalResidualNormKernel.hpp @@ -0,0 +1,241 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalResidualNormKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALRESIDUALNORMKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALRESIDUALNORMKERNEL_HPP + +#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseBaseKernels +{ + +/******************************** ResidualNormKernel ********************************/ + +/** + * @class ResidualNormKernel + */ +class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 3 > +{ +public: + + using Base = ResidualNormKernelBase< 3 >; + using Base::m_minNormalizer; + using Base::m_rankOffset; + using Base::m_localResidual; + using Base::m_dofNumber; + + ResidualNormKernel( globalIndex const rankOffset, + arrayView1d< real64 const > const & localResidual, + arrayView1d< globalIndex const > const & dofNumber, + arrayView1d< localIndex const > const & ghostRank, + integer const numComponents, + integer const numPhases, + ElementSubRegionBase const & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + constitutive::SolidInternalEnergy const & solidInternalEnergy, + real64 const minNormalizer ) + : Base( rankOffset, + localResidual, + dofNumber, + ghostRank, + minNormalizer ), + m_numComponents( numComponents ), + m_numPhases( numPhases ), + m_volume( subRegion.getElementVolume() ), + m_porosity_n( solid.getPorosity_n() ), + m_phaseVolFrac_n( subRegion.getField< fields::flow::phaseVolumeFraction_n >() ), + m_totalDens_n( fluid.totalDensity_n() ), + m_phaseDens_n( fluid.phaseDensity_n() ), + m_phaseInternalEnergy_n( fluid.phaseInternalEnergy_n() ), + m_solidInternalEnergy_n( solidInternalEnergy.getInternalEnergy_n() ) + {} + + GEOS_HOST_DEVICE + void computeMassEnergyNormalizers( localIndex const ei, + real64 & massNormalizer, + real64 & energyNormalizer ) const + { + massNormalizer = LvArray::math::max( m_minNormalizer, m_totalDens_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); + real64 const poreVolume = m_porosity_n[ei][0] * m_volume[ei]; + energyNormalizer = m_solidInternalEnergy_n[ei][0] * ( 1.0 - m_porosity_n[ei][0] ) * m_volume[ei]; + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + energyNormalizer += m_phaseInternalEnergy_n[ei][0][ip] * m_phaseDens_n[ei][0][ip] * m_phaseVolFrac_n[ei][ip] * poreVolume; + } + // warning: internal energy can be negative + energyNormalizer = LvArray::math::max( m_minNormalizer, LvArray::math::abs( energyNormalizer ) ); + } + + GEOS_HOST_DEVICE + virtual void computeLinf( localIndex const ei, + LinfStackVariables & stack ) const override + { + real64 massNormalizer = 0.0, energyNormalizer = 0.0; + computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); + real64 const volumeNormalizer = LvArray::math::max( m_minNormalizer, m_porosity_n[ei][0] * m_volume[ei] ); + + // step 1: mass residual + + for( integer idof = 0; idof < m_numComponents; ++idof ) + { + real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / massNormalizer; + if( valMass > stack.localValue[0] ) + { + stack.localValue[0] = valMass; + } + } + + // step 2: volume residual + + real64 const valVol = LvArray::math::abs( m_localResidual[stack.localRow + m_numComponents] ) / volumeNormalizer; + if( valVol > stack.localValue[1] ) + { + stack.localValue[1] = valVol; + } + + // step 3: energy residual + + real64 const valEnergy = LvArray::math::abs( m_localResidual[stack.localRow + m_numComponents + 1] ) / energyNormalizer; + if( valEnergy > stack.localValue[2] ) + { + stack.localValue[2] = valEnergy; + } + } + + GEOS_HOST_DEVICE + virtual void computeL2( localIndex const ei, + L2StackVariables & stack ) const override + { + // note: for the L2 norm, we bundle the volume and mass residuals/normalizers + real64 massNormalizer = 0.0, energyNormalizer = 0.0; + computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); + + // step 1: mass residual + + for( integer idof = 0; idof < m_numComponents; ++idof ) + { + stack.localValue[0] += m_localResidual[stack.localRow + idof] * m_localResidual[stack.localRow + idof]; + stack.localNormalizer[0] += massNormalizer; + } + + // step 2: volume residual + + real64 const valVol = m_localResidual[stack.localRow + m_numComponents] * m_totalDens_n[ei][0]; // we need a mass here, hence the + // multiplication + stack.localValue[1] += valVol * valVol; + stack.localNormalizer[1] += massNormalizer; + + // step 3: energy residual + + stack.localValue[2] += m_localResidual[stack.localRow + m_numComponents + 1] * m_localResidual[stack.localRow + m_numComponents + 1]; + stack.localNormalizer[2] += energyNormalizer; + } + +protected: + + /// Number of fluid components + integer const m_numComponents; + + /// Number of fluid phases + integer const m_numPhases; + + /// View on the volume + arrayView1d< real64 const > const m_volume; + + /// View on porosity at the previous converged time step + arrayView2d< real64 const > const m_porosity_n; + + /// View on phase properties at the previous converged time step + arrayView2d< real64 const, compflow::USD_PHASE > const m_phaseVolFrac_n; + arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > const m_totalDens_n; + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const m_phaseDens_n; + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const m_phaseInternalEnergy_n; + + /// View on solid properties at the previous converged time step + arrayView2d< real64 const > const m_solidInternalEnergy_n; + +}; + +/** + * @class ResidualNormKernelFactory + */ +class ResidualNormKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] normType the type of norm used (Linf or L2) + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] localResidual the residual vector on my MPI rank + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[in] solidInternalEnergy the solid internal energy model + * @param[out] residualNorm the residual norm on the subRegion + * @param[out] residualNormalizer the residual normalizer on the subRegion + */ + template< typename POLICY > + static void + createAndLaunch( physicsSolverBaseKernels::NormType const normType, + integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + string const & dofKey, + arrayView1d< real64 const > const & localResidual, + ElementSubRegionBase const & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + constitutive::SolidInternalEnergy const & solidInternalEnergy, + real64 const minNormalizer, + real64 (& residualNorm)[3], + real64 (& residualNormalizer)[3] ) + { + arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + + ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, + numComps, numPhases, subRegion, fluid, solid, solidInternalEnergy, minNormalizer ); + if( normType == physicsSolverBaseKernels::NormType::Linf ) + { + ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); + } + else // L2 norm + { + ResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); + } + + } +}; + + +} // namespace thermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALRESIDUALNORMKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp new file mode 100644 index 00000000000..35c969bb891 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp @@ -0,0 +1,181 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalSolutionCheckKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALSOLUTIONCHECKKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALSOLUTIONCHECKKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseBaseKernels +{ + +/******************************** SolutionCheckKernel ********************************/ + +/** + * @class SolutionCheckKernel + * @brief Define the kernel for checking the updated solution + */ +class SolutionCheckKernel : public isothermalCompositionalMultiphaseBaseKernels::SolutionCheckKernel +{ +public: + + using Base = isothermalCompositionalMultiphaseBaseKernels::SolutionCheckKernel; + using Base::m_numComp; + using Base::m_localSolution; + using Base::m_scalingFactor; + + static real64 constexpr minTemperature = constants::zeroDegreesCelsiusInKelvin; + + /** + * @brief Create a new kernel instance + * @param[in] allowCompDensChopping flag to allow the component density chopping + * @param[in] scalingFactor the scaling factor + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + * @param[in] pressure the pressure vector + * @param[in] temperature the temperature vector + * @param[in] compDens the component density vector + */ + SolutionCheckKernel( integer const allowCompDensChopping, + integer const allowNegativePressure, + CompositionalMultiphaseFVM::ScalingType const scalingType, + real64 const scalingFactor, + arrayView1d< real64 const > const pressure, + arrayView1d< real64 const > const temperature, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > compDensScalingFactor, + arrayView1d< real64 > temperatureScalingFactor, + globalIndex const rankOffset, + integer const numComp, + string const dofKey, + ElementSubRegionBase const & subRegion, + arrayView1d< real64 const > const localSolution, + integer const temperatureOffset ) + : Base( allowCompDensChopping, + allowNegativePressure, + scalingType, + scalingFactor, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor, + rankOffset, + numComp, + dofKey, + subRegion, + localSolution ), + m_temperature( temperature ), + m_temperatureScalingFactor( temperatureScalingFactor ), + m_temperatureOffset( temperatureOffset ) + {} + + /** + * @brief Compute the local value of the solution check + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeSolutionCheck( localIndex const ei, + StackVariables & stack ) const + { + Base::computeSolutionCheck( ei, stack, [&] () + { + bool const localScaling = m_scalingType == CompositionalMultiphaseFVM::ScalingType::Local; + // compute the change in temperature + real64 const newTemp = m_temperature[ei] + (localScaling ? m_temperatureScalingFactor[ei] : m_scalingFactor * m_localSolution[stack.localRow + m_temperatureOffset]); + if( newTemp < minTemperature ) + { + stack.localMinVal = 0; + } + } ); + } + +protected: + + /// View on the primary variables + arrayView1d< real64 const > const m_temperature; + + /// View on the scaling factor + arrayView1d< real64 const > const m_temperatureScalingFactor; + + /// Offset to temperature variable + integer m_temperatureOffset; + +}; + +/** + * @class SolutionCheckKernelFactory + */ +class SolutionCheckKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] maxRelativePresChange the max allowed relative pressure change + * @param[in] maxRelativeTempChange the max allowed relative temperature change + * @param[in] maxCompFracChange the max allowed comp fraction change + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + */ + template< typename POLICY > + static SolutionCheckKernel::StackVariables + createAndLaunch( integer const allowCompDensChopping, + integer const allowNegativePressure, + CompositionalMultiphaseFVM::ScalingType const scalingType, + real64 const scalingFactor, + arrayView1d< real64 const > const pressure, + arrayView1d< real64 const > const temperature, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > temperatureScalingFactor, + arrayView1d< real64 > compDensScalingFactor, + globalIndex const rankOffset, + integer const numComp, + string const dofKey, + ElementSubRegionBase & subRegion, + arrayView1d< real64 const > const localSolution, + integer temperatureOffset ) + { + SolutionCheckKernel kernel( allowCompDensChopping, allowNegativePressure, scalingType, scalingFactor, + pressure, temperature, compDens, pressureScalingFactor, compDensScalingFactor, temperatureScalingFactor, + rankOffset, numComp, dofKey, subRegion, localSolution, + temperatureOffset ); + return SolutionCheckKernel::launch< POLICY >( subRegion.size(), kernel ); + } + +}; + +} // namespace thermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALSOLUTIONCHECKKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionScalingKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionScalingKernel.hpp new file mode 100644 index 00000000000..1a4a2b4c782 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionScalingKernel.hpp @@ -0,0 +1,226 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalSolutionScalingKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALSOLUTIONSCALINGKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALSOLUTIONSCALINGKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseBaseKernels +{ + +/******************************** SolutionScalingKernel ********************************/ + +/** + * @class SolutionScalingKernel + * @brief Define the kernel for scaling the Newton update + */ +class SolutionScalingKernel : public isothermalCompositionalMultiphaseBaseKernels::SolutionScalingKernel +{ +public: + + using Base = isothermalCompositionalMultiphaseBaseKernels::SolutionScalingKernel; + using Base::m_numComp; + using Base::m_localSolution; + + /** + * @brief Create a new kernel instance + * @param[in] maxRelativePresChange the max allowed relative pressure change + * @param[in] maxAbsolutePresChange the max allowed absolute pressure change + * @param[in] maxRelativeTempChange the max allowed relative temperature change + * @param[in] maxCompFracChange the max allowed comp fraction change + * @param[in] maxRelativeCompDensChange the max allowed comp density change + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + * @param[in] pressure the pressure vector + * @param[in] temperature the temperature vector + * @param[in] compDens the component density vector + * @param[in] pressureScalingFactor the pressure local scaling factor + * @param[in] compDensScalingFactor the component density local scaling factor + * @param[in] temperatureFactor the temperature local scaling factor + */ + SolutionScalingKernel( real64 const maxRelativePresChange, + real64 const maxAbsolutePresChange, + real64 const maxRelativeTempChange, + real64 const maxCompFracChange, + real64 const maxRelativeCompDensChange, + globalIndex const rankOffset, + integer const numComp, + string const dofKey, + ElementSubRegionBase const & subRegion, + arrayView1d< real64 const > const localSolution, + arrayView1d< real64 const > const pressure, + arrayView1d< real64 const > const temperature, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > compDensScalingFactor, + arrayView1d< real64 > temperatureScalingFactor, + integer const temperatureOffset ) + : Base( maxRelativePresChange, + maxAbsolutePresChange, + maxCompFracChange, + maxRelativeCompDensChange, + rankOffset, + numComp, + dofKey, + subRegion, + localSolution, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor ), + m_maxRelativeTempChange( maxRelativeTempChange ), + m_temperature( temperature ), + m_temperatureScalingFactor( temperatureScalingFactor ), + m_temperatureOffset( temperatureOffset ) + {} + + /** + * @brief Compute the local value + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void compute( localIndex const ei, + StackVariables & stack ) const + { + computeScalingFactor( ei, stack ); + } + + /** + * @brief Compute the local value of the scaling factor + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeScalingFactor( localIndex const ei, + StackVariables & stack ) const + { + real64 constexpr eps = isothermalCompositionalMultiphaseBaseKernels::minDensForDivision; + Base::computeScalingFactor( ei, stack, [&] () + { + // compute the change in temperature + real64 const temp = m_temperature[ei]; + real64 const absTempChange = LvArray::math::abs( m_localSolution[stack.localRow + m_temperatureOffset] ); + if( stack.localMaxDeltaTemp < absTempChange ) + { + stack.localMaxDeltaTemp = absTempChange; + } + + m_temperatureScalingFactor[ei] = 1.0; + + if( temp > eps ) + { + real64 const relativeTempChange = absTempChange / temp; + if( relativeTempChange > m_maxRelativeTempChange ) + { + real64 const tempScalingFactor = m_maxRelativeTempChange / relativeTempChange; + m_temperatureScalingFactor[ei] = tempScalingFactor; + if( stack.localMinVal > tempScalingFactor ) + { + stack.localMinVal = tempScalingFactor; + } + if( stack.localMinTempScalingFactor > tempScalingFactor ) + { + stack.localMinTempScalingFactor = tempScalingFactor; + } + } + } + } ); + } + +protected: + + /// Max allowed changes in primary variables + real64 const m_maxRelativeTempChange; + + /// View on the primary variables + arrayView1d< real64 const > const m_temperature; + + /// View on the scaling factor + arrayView1d< real64 > const m_temperatureScalingFactor; + + /// Temperature offset in solution array + integer const m_temperatureOffset; +}; + +/** + * @class SolutionScalingKernelFactory + */ +class SolutionScalingKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] maxRelativePresChange the max allowed relative pressure change + * @param[in] maxAbsolutePresChange the max allowed absolute pressure change + * @param[in] maxRelativeTempChange the max allowed relative temperature change + * @param[in] maxCompFracChange the max allowed comp fraction change + * @param[in] maxRelativeCompdensChange the max allowed relative component density change + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + */ + template< typename POLICY > + static SolutionScalingKernel::StackVariables + createAndLaunch( real64 const maxRelativePresChange, + real64 const maxAbsolutePresChange, + real64 const maxRelativeTempChange, + real64 const maxCompFracChange, + real64 const maxRelativeCompDensChange, + arrayView1d< real64 const > const pressure, + arrayView1d< real64 const > const temperature, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > compDensScalingFactor, + arrayView1d< real64 > temperatureScalingFactor, + globalIndex const rankOffset, + integer const numComp, + string const dofKey, + ElementSubRegionBase & subRegion, + arrayView1d< real64 const > const localSolution, + integer const temperatureOffset ) + { + SolutionScalingKernel kernel( maxRelativePresChange, maxAbsolutePresChange, maxRelativeTempChange, + maxCompFracChange, maxRelativeCompDensChange, + rankOffset, numComp, dofKey, subRegion, localSolution, + pressure, temperature, compDens, pressureScalingFactor, + compDensScalingFactor, temperatureScalingFactor, temperatureOffset ); + return thermalCompositionalMultiphaseBaseKernels:: + SolutionScalingKernel::launch< POLICY >( subRegion.size(), kernel ); + } + +}; + +} // namespace thermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALSOLUTIONSCALINGKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp new file mode 100644 index 00000000000..c2e2845ff74 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp @@ -0,0 +1,361 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AccumulationKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_ACCUMULATIONKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_ACCUMULATIONKERNELS_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" +#include "constitutive/solid/CoupledSolidBase.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "codingUtilities/Utilities.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** AccumulationKernel ********************************/ + +/** + * @class AccumulationKernel + * @brief Define the interface for the assembly kernel in charge of accumulation + */ +template< typename SUBREGION_TYPE, integer NUM_DOF > +class AccumulationKernel +{ + +public: + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = NUM_DOF; + + /// Compute time value for the number of equations + static constexpr integer numEqn = NUM_DOF; + + /** + * @brief Constructor + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + AccumulationKernel( globalIndex const rankOffset, + string const dofKey, + SUBREGION_TYPE const & subRegion, + constitutive::SingleFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : + m_rankOffset( rankOffset ), + m_dofNumber( subRegion.template getReference< array1d< globalIndex > >( dofKey ) ), + m_elemGhostRank( subRegion.ghostRank() ), + m_volume( subRegion.getElementVolume() ), + m_deltaVolume( subRegion.template getField< fields::flow::deltaVolume >() ), + m_porosity( solid.getPorosity() ), + m_dPoro_dPres( solid.getDporosity_dPressure() ), + m_density( fluid.density() ), + m_dDensity_dPres( fluid.dDensity_dPressure() ), + m_mass_n( subRegion.template getField< fields::flow::mass_n >() ), + m_localMatrix( localMatrix ), + m_localRhs( localRhs ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables + { +public: + + // Pore volume information + + /// Pore volume at time n+1 + real64 poreVolume = 0.0; + + /// Derivative of pore volume with respect to pressure + real64 dPoreVolume_dPres = 0.0; + + // Residual information + + /// Index of the local row corresponding to this element + localIndex localRow = -1; + + /// Index of the matrix row/column corresponding to the dof in this element + globalIndex dofIndices[numDof]{}; + + /// Storage for the element local residual vector + real64 localResidual[numEqn]{}; + + /// Storage for the element local Jacobian matrix + real64 localJacobian[numEqn][numDof]{}; + + }; + + /** + * @brief Getter for the ghost rank of an element + * @param[in] ei the element index + * @return the ghost rank of the element + */ + GEOS_HOST_DEVICE + integer elemGhostRank( localIndex const ei ) const + { return m_elemGhostRank( ei ); } + + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] ei the element index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const ei, + StackVariables & stack ) const + { + // initialize the pore volume + stack.poreVolume = ( m_volume[ei] + m_deltaVolume[ei] ) * m_porosity[ei][0]; + stack.dPoreVolume_dPres = ( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dPres[ei][0]; + + // set row index and degrees of freedom indices for this element + stack.localRow = m_dofNumber[ei] - m_rankOffset; + for( integer idof = 0; idof < numDof; ++idof ) + { + stack.dofIndices[idof] = m_dofNumber[ei] + idof; + } + } + + /** + * @brief Compute the local accumulation contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + * @param[in] kernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const ei, + StackVariables & stack, + FUNC && kernelOp = NoOpFunc{} ) const + { + // Residual contribution is mass conservation in the cell + stack.localResidual[0] = stack.poreVolume * m_density[ei][0] - m_mass_n[ei]; + + // Derivative of residual wrt to pressure in the cell + stack.localJacobian[0][0] = stack.dPoreVolume_dPres * m_density[ei][0] + m_dDensity_dPres[ei][0] * stack.poreVolume; + + // Customize the kernel with this lambda + kernelOp(); + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void complete( localIndex const GEOS_UNUSED_PARAM( ei ), + StackVariables & stack ) const + { + // add contribution to global residual and jacobian (no need for atomics here) + m_localMatrix.template addToRow< serialAtomic >( stack.localRow, + stack.dofIndices, + stack.localJacobian[0], + numDof ); + m_localRhs[stack.localRow] += stack.localResidual[0]; + + } + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElems the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( kernelComponent.elemGhostRank( ei ) >= 0 ) + { + return; + } + + typename KERNEL_TYPE::StackVariables stack; + + kernelComponent.setup( ei, stack ); + kernelComponent.computeAccumulation( ei, stack ); + kernelComponent.complete( ei, stack ); + } ); + } + +protected: + + /// Offset for my MPI rank + globalIndex const m_rankOffset; + + /// View on the dof numbers + arrayView1d< globalIndex const > const m_dofNumber; + + /// View on the ghost ranks + arrayView1d< integer const > const m_elemGhostRank; + + /// View on the element volumes + arrayView1d< real64 const > const m_volume; + arrayView1d< real64 const > const m_deltaVolume; + + /// Views on the porosity + arrayView2d< real64 const > const m_porosity; + arrayView2d< real64 const > const m_dPoro_dPres; + + /// Views on density + arrayView2d< real64 const > const m_density; + arrayView2d< real64 const > const m_dDensity_dPres; + + /// View on mass + arrayView1d< real64 const > const m_mass_n; + + /// View on the local CRS matrix + CRSMatrixView< real64, globalIndex const > const m_localMatrix; + /// View on the local RHS + arrayView1d< real64 > const m_localRhs; + +}; + +/** + * @class SurfaceElementAccumulationKernel + * @brief Define the interface for the assembly kernel in charge of accumulation in SurfaceElementSubRegion + */ +class SurfaceElementAccumulationKernel : public AccumulationKernel< SurfaceElementSubRegion, 1 > +{ + +public: + + using Base = AccumulationKernel< SurfaceElementSubRegion, 1 >; + + /** + * @brief Constructor + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + SurfaceElementAccumulationKernel( globalIndex const rankOffset, + string const dofKey, + SurfaceElementSubRegion const & subRegion, + constitutive::SingleFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : Base( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ) + , m_creationMass( subRegion.getField< fields::flow::massCreated >() ) + {} + + /** + * @brief Compute the local accumulation contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const ei, + Base::StackVariables & stack ) const + { + Base::computeAccumulation( ei, stack, [&] () + { + if( Base::m_mass_n[ei] > 1.1 * m_creationMass[ei] ) + { + stack.localResidual[0] += m_creationMass[ei] * 0.25; + } + } ); + } + +protected: + + arrayView1d< real64 const > const m_creationMass; + +}; + +/** + * @class AccumulationKernelFactory + */ +class AccumulationKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename SUBREGION_TYPE > + static void + createAndLaunch( globalIndex const rankOffset, + string const dofKey, + SUBREGION_TYPE const & subRegion, + constitutive::SingleFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + if constexpr ( std::is_base_of_v< CellElementSubRegion, SUBREGION_TYPE > ) + { + integer constexpr NUM_DOF = 1; + AccumulationKernel< CellElementSubRegion, NUM_DOF > kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); + AccumulationKernel< CellElementSubRegion, NUM_DOF >::template launch< POLICY >( subRegion.size(), kernel ); + } + else if constexpr ( std::is_base_of_v< SurfaceElementSubRegion, SUBREGION_TYPE > ) + { + SurfaceElementAccumulationKernel kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); + SurfaceElementAccumulationKernel::launch< POLICY >( subRegion.size(), kernel ); + } + else + { + GEOS_UNUSED_VAR( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); + GEOS_ERROR( "Unsupported subregion type: " << typeid(SUBREGION_TYPE).name() ); + } + } + +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_ACCUMULATIONKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AquiferBCKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AquiferBCKernel.hpp new file mode 100644 index 00000000000..c35ec2cfbc7 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AquiferBCKernel.hpp @@ -0,0 +1,152 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AquiferBCKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_AQUIFERBCKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_AQUIFERBCKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "fieldSpecification/AquiferBoundaryCondition.hpp" +#include "finiteVolume/BoundaryStencil.hpp" + +namespace geos +{ + +namespace singlePhaseFVMKernels +{ + +/******************************** AquiferBCKernel ********************************/ + +/** + * @brief Functions to assemble aquifer boundary condition contributions to residual and Jacobian + */ +struct AquiferBCKernel +{ + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + GEOS_HOST_DEVICE + static void + compute( real64 const & aquiferVolFlux, + real64 const & dAquiferVolFlux_dPres, + real64 const & aquiferDens, + real64 const & dens, + real64 const & dDens_dPres, + real64 const & dt, + real64 & localFlux, + real64 & localFluxJacobian ) + { + if( aquiferVolFlux > 0 ) // aquifer is upstream + { + localFlux -= dt * aquiferVolFlux * aquiferDens; + localFluxJacobian -= dt * dAquiferVolFlux_dPres * aquiferDens; + } + else // reservoir is upstream + { + localFlux -= dt * aquiferVolFlux * dens; + localFluxJacobian -= dt * (dAquiferVolFlux_dPres * dens + aquiferVolFlux * dDens_dPres); + } + } + + static void + launch( BoundaryStencil const & stencil, + globalIndex const rankOffset, + ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, + ElementViewConst< arrayView1d< integer const > > const & ghostRank, + AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, + real64 const & aquiferDens, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & pres_n, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const > > const & dens, + ElementViewConst< arrayView2d< real64 const > > const & dDens_dPres, + real64 const & timeAtBeginningOfStep, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + using Order = BoundaryStencil::Order; + + BoundaryStencil::IndexContainerViewConstType const & seri = stencil.getElementRegionIndices(); + BoundaryStencil::IndexContainerViewConstType const & sesri = stencil.getElementSubRegionIndices(); + BoundaryStencil::IndexContainerViewConstType const & sefi = stencil.getElementIndices(); + BoundaryStencil::WeightContainerViewConstType const & weight = stencil.getWeights(); + + forAll< parallelDevicePolicy<> >( stencil.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + // working variables + real64 localFlux = 0.0; + real64 localFluxJacobian = 0.0; + + localIndex const er = seri( iconn, Order::ELEM ); + localIndex const esr = sesri( iconn, Order::ELEM ); + localIndex const ei = sefi( iconn, Order::ELEM ); + real64 const areaFraction = weight( iconn, Order::ELEM ); + + // compute the aquifer influx rate using the pressure influence function and the aquifer props + real64 dAquiferVolFlux_dPres = 0.0; + real64 const aquiferVolFlux = aquiferBCWrapper.compute( timeAtBeginningOfStep, + dt, + pres[er][esr][ei], + pres_n[er][esr][ei], + gravCoef[er][esr][ei], + areaFraction, + dAquiferVolFlux_dPres ); + + // compute the phase/component aquifer flux + AquiferBCKernel::compute( aquiferVolFlux, + dAquiferVolFlux_dPres, + aquiferDens, + dens[er][esr][ei][0], + dDens_dPres[er][esr][ei][0], + dt, + localFlux, + localFluxJacobian ); + + // Add to residual/jacobian + if( ghostRank[er][esr][ei] < 0 ) + { + globalIndex const globalRow = dofNumber[er][esr][ei]; + localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - rankOffset ); + GEOS_ASSERT_GE( localRow, 0 ); + GEOS_ASSERT_GT( localMatrix.numRows(), localRow ); + + RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[localRow], localFlux ); + localMatrix.addToRow< parallelDeviceAtomic >( localRow, + &dofNumber[er][esr][ei], + &localFluxJacobian, + 1 ); + } + } ); + } + +}; + +} // namespace singlePhaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_AQUIFERBCKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/DirichletFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/DirichletFluxComputeKernel.hpp new file mode 100644 index 00000000000..e5c45309b0d --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/DirichletFluxComputeKernel.hpp @@ -0,0 +1,362 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file DirichletFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_DIRICHLETFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_DIRICHLETFLUXCOMPUTEKERNEL_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" +#include "finiteVolume/BoundaryStencil.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/MobilityKernel.hpp" +#include "codingUtilities/Utilities.hpp" + +namespace geos +{ + +namespace singlePhaseFVMKernels +{ + +/******************************** DirichletFluxComputeKernel ********************************/ + +/** + * @class DirichletFluxComputeKernel + * @tparam FLUIDWRAPPER the type of the fluid wrapper + * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms + */ +template< integer NUM_EQN, integer NUM_DOF, typename FLUIDWRAPPER > +class DirichletFluxComputeKernel : public FluxComputeKernel< NUM_EQN, NUM_DOF, + BoundaryStencilWrapper > +{ +public: + + using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; + using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; + using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; + using AbstractBase::m_dt; + using AbstractBase::m_rankOffset; + using AbstractBase::m_dofNumber; + using AbstractBase::m_ghostRank; + using AbstractBase::m_gravCoef; + using AbstractBase::m_pres; + using AbstractBase::m_mob; + using AbstractBase::m_dMob_dPres; + using AbstractBase::m_dens; + using AbstractBase::m_dDens_dPres; + using AbstractBase::m_permeability; + using AbstractBase::m_dPerm_dPres; + using AbstractBase::m_localMatrix; + using AbstractBase::m_localRhs; + + using Base = singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, + BoundaryStencilWrapper >; + using Base::numDof; + using Base::numEqn; + using Base::m_stencilWrapper; + using Base::m_seri; + using Base::m_sesri; + using Base::m_sei; + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] faceManager the face manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] fluidWrapper reference to the fluid wrapper + * @param[in] dofNumberAccessor + * @param[in] singlePhaseFlowAccessors + * @param[in] singlePhaseFluidAccessors + * @param[in] permeabilityAccessors + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + DirichletFluxComputeKernel( globalIndex const rankOffset, + FaceManager const & faceManager, + BoundaryStencilWrapper const & stencilWrapper, + FLUIDWRAPPER const & fluidWrapper, + DofNumberAccessor const & dofNumberAccessor, + SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, + SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : Base( rankOffset, + stencilWrapper, + dofNumberAccessor, + singlePhaseFlowAccessors, + singlePhaseFluidAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs ), + m_facePres( faceManager.getField< fields::flow::facePressure >() ), + m_faceGravCoef( faceManager.getField< fields::flow::gravityCoefficient >() ), + m_fluidWrapper( fluidWrapper ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables + { +public: + + /** + * @brief Constructor for the stack variables + * @param[in] size size of the stencil for this connection + * @param[in] numElems number of elements for this connection + */ + GEOS_HOST_DEVICE + StackVariables( localIndex const GEOS_UNUSED_PARAM( size ), + localIndex GEOS_UNUSED_PARAM( numElems ) ) + {} + + /// Transmissibility + real64 transmissibility = 0.0; + + /// Indices of the matrix rows/columns corresponding to the dofs in this face + globalIndex dofColIndices[numDof]{}; + + /// Storage for the face local residual + real64 localFlux[numEqn]{}; + + /// Storage for the face local Jacobian + real64 localFluxJacobian[numEqn][numDof]{}; + + }; + + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] iconn the connection index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const iconn, + StackVariables & stack ) const + { + globalIndex const offset = + m_dofNumber[m_seri( iconn, BoundaryStencil::Order::ELEM )][m_sesri( iconn, BoundaryStencil::Order::ELEM )][m_sei( iconn, BoundaryStencil::Order::ELEM )]; + + for( integer jdof = 0; jdof < numDof; ++jdof ) + { + stack.dofColIndices[jdof] = offset + jdof; + } + } + + /** + * @brief Compute the local Dirichlet face flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeFlux( localIndex const iconn, + StackVariables & stack, + FUNC && compFluxKernelOp = NoOpFunc{} ) const + { + using Order = BoundaryStencil::Order; + localIndex constexpr numElems = BoundaryStencil::maxNumPointsInFlux; + + stackArray1d< real64, numElems > mobility( numElems ); + stackArray1d< real64, numElems > dMobility_dP( numElems ); + + localIndex const er = m_seri( iconn, Order::ELEM ); + localIndex const esr = m_sesri( iconn, Order::ELEM ); + localIndex const ei = m_sei( iconn, Order::ELEM ); + localIndex const kf = m_sei( iconn, Order::FACE ); + + // Get flow quantities on the elem/face + real64 faceDens, faceVisc; + constitutive::SingleFluidBaseUpdate::computeValues( m_fluidWrapper, m_facePres[kf], faceDens, faceVisc ); + + mobility[Order::ELEM] = m_mob[er][esr][ei]; + singlePhaseBaseKernels::MobilityKernel::compute( faceDens, faceVisc, mobility[Order::FACE] ); + + dMobility_dP[Order::ELEM] = m_dMob_dPres[er][esr][ei]; + dMobility_dP[Order::FACE] = 0.0; + + // Compute average density + real64 const densMean = 0.5 * ( m_dens[er][esr][ei][0] + faceDens ); + real64 const dDens_dP = 0.5 * m_dDens_dPres[er][esr][ei][0]; + + // Evaluate potential difference + real64 const potDif = (m_pres[er][esr][ei] - m_facePres[kf]) + - densMean * (m_gravCoef[er][esr][ei] - m_faceGravCoef[kf]); + real64 const dPotDif_dP = 1.0 - dDens_dP * m_gravCoef[er][esr][ei]; + + real64 dTrans_dPerm[3]; + m_stencilWrapper.computeWeights( iconn, m_permeability, stack.transmissibility, dTrans_dPerm ); + real64 const dTrans_dPres = LvArray::tensorOps::AiBi< 3 >( dTrans_dPerm, m_dPerm_dPres[er][esr][ei][0] ); + + real64 const f = stack.transmissibility * potDif; + real64 const dF_dP = stack.transmissibility * dPotDif_dP + dTrans_dPres * potDif; + + // Upwind mobility + localIndex const k_up = ( potDif >= 0 ) ? Order::ELEM : Order::FACE; + real64 const mobility_up = mobility[k_up]; + real64 const dMobility_dP_up = dMobility_dP[k_up]; + + // call the lambda in the phase loop to allow the reuse of the fluxes and their derivatives + // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase + + compFluxKernelOp( er, esr, ei, kf, f, dF_dP, mobility_up, dMobility_dP_up ); + + // *** end of upwinding + + // Populate local flux vector and derivatives + + stack.localFlux[0] = m_dt * mobility[k_up] * f; + stack.localFluxJacobian[0][0] = m_dt * ( mobility_up * dF_dP + dMobility_dP_up * f ); + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void complete( localIndex const iconn, + StackVariables & stack, + FUNC && assemblyKernelOp = NoOpFunc{} ) const + { + using Order = BoundaryStencil::Order; + + localIndex const er = m_seri( iconn, Order::ELEM ); + localIndex const esr = m_sesri( iconn, Order::ELEM ); + localIndex const ei = m_sei( iconn, Order::ELEM ); + + if( m_ghostRank[er][esr][ei] < 0 ) + { + // Add to global residual/jacobian + globalIndex const dofIndex = m_dofNumber[er][esr][ei]; + localIndex const localRow = LvArray::integerConversion< localIndex >( dofIndex - m_rankOffset ); + + RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow], stack.localFlux[0] ); + + AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > + ( localRow, + stack.dofColIndices, + stack.localFluxJacobian[0], + numDof ); + + assemblyKernelOp( localRow ); + } + } + +protected: + + /// Views on face pressure, temperature, and composition + arrayView1d< real64 const > const m_facePres; + + /// View on the face gravity coefficient + arrayView1d< real64 const > const m_faceGravCoef; + + /// Reference to the fluid wrapper + FLUIDWRAPPER const m_fluidWrapper; + +}; + + +/** + * @class DirichletFluxComputeKernelFactory + */ +class DirichletFluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] solverName name of the solver (to name accessors) + * @param[in] faceManager reference to the face manager + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the boundary stencil wrapper + * @param[in] fluidBase the single phase fluid constitutive model + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( globalIndex const rankOffset, + string const & dofKey, + string const & solverName, + FaceManager const & faceManager, + ElementRegionManager const & elemManager, + BoundaryStencilWrapper const & stencilWrapper, + constitutive::SingleFluidBase & fluidBase, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + constitutiveUpdatePassThru( fluidBase, [&]( auto & fluid ) + { + using FluidType = TYPEOFREF( fluid ); + typename FluidType::KernelWrapper fluidWrapper = fluid.createKernelWrapper(); + + integer constexpr NUM_DOF = 1; + integer constexpr NUM_EQN = 1; + using kernelType = DirichletFluxComputeKernel< NUM_EQN, NUM_DOF, typename FluidType::KernelWrapper >; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + typename kernelType::SinglePhaseFlowAccessors singlePhaseFlowAccessors( elemManager, solverName ); + typename kernelType::SinglePhaseFluidAccessors singlePhaseFluidAccessors( elemManager, solverName ); + typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); + + kernelType kernel( rankOffset, + faceManager, + stencilWrapper, + fluidWrapper, + dofNumberAccessor, + singlePhaseFlowAccessors, + singlePhaseFluidAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs ); + + kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); + } ); + } + +}; + +} // namespace singlePhaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_DIRICHLETFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluidUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluidUpdateKernel.hpp new file mode 100644 index 00000000000..dbf86d97295 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluidUpdateKernel.hpp @@ -0,0 +1,55 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FluidUpdateKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUIDUPDATEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUIDUPDATEKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** FluidUpdateKernel ********************************/ + +struct FluidUpdateKernel +{ + template< typename FLUID_WRAPPER > + static void launch( FLUID_WRAPPER const & fluidWrapper, + arrayView1d< real64 const > const & pres, + arrayView1d< real64 const > const & temp ) + { + forAll< parallelDevicePolicy<> >( fluidWrapper.numElems(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) + { + fluidWrapper.update( k, q, pres[k], temp[k] ); + } + } ); + } +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUIDUPDATEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp new file mode 100644 index 00000000000..05034149bb7 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp @@ -0,0 +1,383 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernelBase.hpp" + + +namespace geos +{ + +namespace singlePhaseFVMKernels +{ + +/** + * @class FluxComputeKernel + * @tparam NUM_DOF number of degrees of freedom + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NUM_EQN, integer NUM_DOF, typename STENCILWRAPPER > +class FluxComputeKernel : public FluxComputeKernelBase +{ +public: + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = NUM_DOF; + + /// Compute time value for the number of equations + static constexpr integer numEqn = NUM_EQN; + + /// Maximum number of elements at the face + static constexpr localIndex maxNumElems = STENCILWRAPPER::maxNumPointsInFlux; + + /// Maximum number of connections at the face + static constexpr localIndex maxNumConns = STENCILWRAPPER::maxNumConnections; + + /// Maximum number of points in the stencil + static constexpr localIndex maxStencilSize = STENCILWRAPPER::maxStencilSize; + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor + * @param[in] singlePhaseFlowAccessors + * @param[in] singlePhaseFluidAccessors + * @param[in] permeabilityAccessors + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + FluxComputeKernel( globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, + SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : FluxComputeKernelBase( rankOffset, + dofNumberAccessor, + singlePhaseFlowAccessors, + singlePhaseFluidAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs ), + m_stencilWrapper( stencilWrapper ), + m_seri( stencilWrapper.getElementRegionIndices() ), + m_sesri( stencilWrapper.getElementSubRegionIndices() ), + m_sei( stencilWrapper.getElementIndices() ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables + { +public: + + /** + * @brief Constructor for the stack variables + * @param[in] size size of the stencil for this connection + * @param[in] numElems number of elements for this connection + */ + GEOS_HOST_DEVICE + StackVariables( localIndex const size, localIndex numElems ) + : stencilSize( size ), + numFluxElems( numElems ), + dofColIndices( size * numDof ), + localFlux( numElems * numEqn ), + localFluxJacobian( numElems * numEqn, size * numDof ) + {} + + // Stencil information + + /// Stencil size for a given connection + localIndex const stencilSize; + + /// Number of elements for a given connection + localIndex const numFluxElems; + + // Transmissibility and derivatives + + /// Transmissibility + real64 transmissibility[maxNumConns][2]{}; + /// Derivatives of transmissibility with respect to pressure + real64 dTrans_dPres[maxNumConns][2]{}; + + // Local degrees of freedom and local residual/jacobian + + /// Indices of the matrix rows/columns corresponding to the dofs in this face + stackArray1d< globalIndex, maxNumElems * numDof > dofColIndices; + + /// Storage for the face local residual vector (all equations except volume balance) + stackArray1d< real64, maxNumElems * numEqn > localFlux; + /// Storage for the face local Jacobian matrix + stackArray2d< real64, maxNumElems * numEqn * maxStencilSize * numDof > localFluxJacobian; + + }; + + /** + * @brief Getter for the stencil size at this connection + * @param[in] iconn the connection index + * @return the size of the stencil at this connection + */ + GEOS_HOST_DEVICE + localIndex stencilSize( localIndex const iconn ) const + { return m_sei[iconn].size(); } + + /** + * @brief Getter for the number of elements at this connection + * @param[in] iconn the connection index + * @return the number of elements at this connection + */ + GEOS_HOST_DEVICE + localIndex numPointsInFlux( localIndex const iconn ) const + { return m_stencilWrapper.numPointsInFlux( iconn ); } + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] iconn the connection index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const iconn, + StackVariables & stack ) const + { + // set degrees of freedom indices for this face + for( integer i = 0; i < stack.stencilSize; ++i ) + { + globalIndex const offset = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; + + for( integer jdof = 0; jdof < numDof; ++jdof ) + { + stack.dofColIndices[i * numDof + jdof] = offset + jdof; + } + } + } + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the flux + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + * @param[in] NoOpFunc the function used to customize the computation of the flux + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeFlux( localIndex const iconn, + StackVariables & stack, + FUNC && kernelOp = NoOpFunc{} ) const + { + // first, compute the transmissibilities at this face + m_stencilWrapper.computeWeights( iconn, + m_permeability, + m_dPerm_dPres, + stack.transmissibility, + stack.dTrans_dPres ); + + localIndex k[2]; + localIndex connectionIndex = 0; + + for( k[0] = 0; k[0] < stack.numFluxElems; ++k[0] ) + { + for( k[1] = k[0] + 1; k[1] < stack.numFluxElems; ++k[1] ) + { + real64 fluxVal = 0.0; + real64 dFlux_dTrans = 0.0; + real64 alpha = 0.0; + real64 mobility = 0.0; + real64 potGrad = 0.0; + real64 trans[2] = { stack.transmissibility[connectionIndex][0], stack.transmissibility[connectionIndex][1] }; + real64 dTrans[2] = { stack.dTrans_dPres[connectionIndex][0], stack.dTrans_dPres[connectionIndex][1] }; + real64 dFlux_dP[2] = {0.0, 0.0}; + localIndex const regionIndex[2] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; + localIndex const subRegionIndex[2] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; + localIndex const elementIndex[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; + + singlePhaseFluxKernelsHelper::computeSinglePhaseFlux( regionIndex, subRegionIndex, elementIndex, + trans, + dTrans, + m_pres, + m_gravCoef, + m_dens, + m_dDens_dPres, + m_mob, + m_dMob_dPres, + alpha, + mobility, + potGrad, + fluxVal, + dFlux_dP, + dFlux_dTrans ); + + // populate local flux vector and derivatives + stack.localFlux[k[0]*numEqn] += m_dt * fluxVal; + stack.localFlux[k[1]*numEqn] -= m_dt * fluxVal; + + for( integer ke = 0; ke < 2; ++ke ) + { + localIndex const localDofIndexPres = k[ke] * numDof; + stack.localFluxJacobian[k[0]*numEqn][localDofIndexPres] += m_dt * dFlux_dP[ke]; + stack.localFluxJacobian[k[1]*numEqn][localDofIndexPres] -= m_dt * dFlux_dP[ke]; + } + + // Customize the kernel with this lambda + kernelOp( k, regionIndex, subRegionIndex, elementIndex, connectionIndex, alpha, mobility, potGrad, fluxVal, dFlux_dP ); + + connectionIndex++; + } + } + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void complete( localIndex const iconn, + StackVariables & stack, + FUNC && kernelOp = NoOpFunc{} ) const + { + // add contribution to residual and jacobian into: + // - the mass balance equation + // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels + for( integer i = 0; i < stack.numFluxElems; ++i ) + { + if( m_ghostRank[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )] < 0 ) + { + globalIndex const globalRow = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; + localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); + GEOS_ASSERT_GE( localRow, 0 ); + GEOS_ASSERT_GT( m_localMatrix.numRows(), localRow ); + + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[localRow], stack.localFlux[i * numEqn] ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( localRow, + stack.dofColIndices.data(), + stack.localFluxJacobian[i * numEqn].dataIfContiguous(), + stack.stencilSize * numDof ); + + // call the lambda to assemble additional terms, such as thermal terms + kernelOp( i, localRow ); + } + } + } + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numConnections the number of connections + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numConnections, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + + forAll< POLICY >( numConnections, [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), + kernelComponent.numPointsInFlux( iconn ) ); + + kernelComponent.setup( iconn, stack ); + kernelComponent.computeFlux( iconn, stack ); + kernelComponent.complete( iconn, stack ); + } ); + } + + +protected: + + // Stencil information + + /// Reference to the stencil wrapper + STENCILWRAPPER const m_stencilWrapper; + + /// Connection to element maps + typename STENCILWRAPPER::IndexContainerViewConstType const m_seri; + typename STENCILWRAPPER::IndexContainerViewConstType const m_sesri; + typename STENCILWRAPPER::IndexContainerViewConstType const m_sei; +}; + +/** + * @class FluxComputeKernelFactory + */ +class FluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] solverName name of the solver (to name accessors) + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( globalIndex const rankOffset, + string const & dofKey, + string const & solverName, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + integer constexpr NUM_EQN = 1; + integer constexpr NUM_DOF = 1; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + using kernelType = FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; + typename kernelType::SinglePhaseFlowAccessors flowAccessors( elemManager, solverName ); + typename kernelType::SinglePhaseFluidAccessors fluidAccessors( elemManager, solverName ); + typename kernelType::PermeabilityAccessors permAccessors( elemManager, solverName ); + + kernelType kernel( rankOffset, stencilWrapper, dofNumberAccessor, + flowAccessors, fluidAccessors, permAccessors, + dt, localMatrix, localRhs ); + kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); + } +}; + +} // namespace singlePhaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernelBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernelBase.hpp new file mode 100644 index 00000000000..15c528a8f60 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernelBase.hpp @@ -0,0 +1,173 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FluxComputeKernelBase.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXCOMPUTEKERNELBASE_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXCOMPUTEKERNELBASE_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" +#include "constitutive/fluid/singlefluid/SingleFluidFields.hpp" +#include "constitutive/fluid/singlefluid/SlurryFluidBase.hpp" +#include "constitutive/fluid/singlefluid/SlurryFluidFields.hpp" +#include "constitutive/permeability/PermeabilityBase.hpp" +#include "constitutive/permeability/PermeabilityFields.hpp" +#include "linearAlgebra/interfaces/InterfaceTypes.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp" + +namespace geos +{ + +namespace singlePhaseFVMKernels +{ + +/******************************** FluxComputeKernelBase ********************************/ + +/** + * @brief Base class for FluxComputeKernel that holds all data not dependent + * on template parameters (like stencil type and number of dofs). + */ +class FluxComputeKernelBase +{ +public: + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using DofNumberAccessor = ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > >; + + using SinglePhaseFlowAccessors = + StencilAccessors< fields::ghostRank, + fields::flow::pressure, + fields::flow::pressure_n, + fields::flow::gravityCoefficient, + fields::flow::mobility, + fields::flow::dMobility_dPressure >; + + using SinglePhaseFluidAccessors = + StencilMaterialAccessors< constitutive::SingleFluidBase, + fields::singlefluid::density, + fields::singlefluid::dDensity_dPressure >; + + using SlurryFluidAccessors = + StencilMaterialAccessors< constitutive::SlurryFluidBase, + fields::singlefluid::density, + fields::singlefluid::dDensity_dPressure >; + + using PermeabilityAccessors = + StencilMaterialAccessors< constitutive::PermeabilityBase, + fields::permeability::permeability, + fields::permeability::dPerm_dPressure >; + + using ProppantPermeabilityAccessors = + StencilMaterialAccessors< constitutive::PermeabilityBase, + fields::permeability::permeability, + fields::permeability::dPerm_dPressure, + fields::permeability::dPerm_dDispJump, + fields::permeability::permeabilityMultiplier >; + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofNumberAccessor accessor for the dof numbers + * @param[in] singleFlowAccessors accessor for wrappers registered by the solver + * @param[in] singlePhaseFluidAccessors accessor for wrappers registered by the singlefluid model + * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + FluxComputeKernelBase( globalIndex const rankOffset, + DofNumberAccessor const & dofNumberAccessor, + SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, + SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : m_rankOffset( rankOffset ), + m_dt( dt ), + m_dofNumber( dofNumberAccessor.toNestedViewConst() ), + m_permeability( permeabilityAccessors.get( fields::permeability::permeability {} ) ), + m_dPerm_dPres( permeabilityAccessors.get( fields::permeability::dPerm_dPressure {} ) ), + m_ghostRank( singlePhaseFlowAccessors.get( fields::ghostRank {} ) ), + m_gravCoef( singlePhaseFlowAccessors.get( fields::flow::gravityCoefficient {} ) ), + m_pres( singlePhaseFlowAccessors.get( fields::flow::pressure {} ) ), + m_mob( singlePhaseFlowAccessors.get( fields::flow::mobility {} ) ), + m_dMob_dPres( singlePhaseFlowAccessors.get( fields::flow::dMobility_dPressure {} ) ), + m_dens( singlePhaseFluidAccessors.get( fields::singlefluid::density {} ) ), + m_dDens_dPres( singlePhaseFluidAccessors.get( fields::singlefluid::dDensity_dPressure {} ) ), + m_localMatrix( localMatrix ), + m_localRhs( localRhs ) + {} + +protected: + + /// Offset for my MPI rank + globalIndex const m_rankOffset; + + /// Time step size + real64 const m_dt; + + /// Views on dof numbers + ElementViewConst< arrayView1d< globalIndex const > > const m_dofNumber; + + /// Views on permeability + ElementViewConst< arrayView3d< real64 const > > m_permeability; + ElementViewConst< arrayView3d< real64 const > > m_dPerm_dPres; + + /// Views on ghost rank numbers and gravity coefficients + ElementViewConst< arrayView1d< integer const > > const m_ghostRank; + ElementViewConst< arrayView1d< real64 const > > const m_gravCoef; + + // Primary and secondary variables + /// Views on pressure + ElementViewConst< arrayView1d< real64 const > > const m_pres; + + /// Views on fluid mobility + ElementViewConst< arrayView1d< real64 const > > const m_mob; + ElementViewConst< arrayView1d< real64 const > > const m_dMob_dPres; + + /// Views on fluid density + ElementViewConst< arrayView2d< real64 const > > const m_dens; + ElementViewConst< arrayView2d< real64 const > > const m_dDens_dPres; + + // Residual and jacobian + + /// View on the local CRS matrix + CRSMatrixView< real64, globalIndex const > const m_localMatrix; + /// View on the local RHS + arrayView1d< real64 > const m_localRhs; +}; + +} // namespace singlePhaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXCOMPUTEKERNELBASE_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp new file mode 100644 index 00000000000..814eb7e6234 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp @@ -0,0 +1,292 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FluxKernelsHelper.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXKERNELSHELPER_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXKERNELSHELPER_HPP + +#include "common/DataTypes.hpp" +#include "mesh/ElementRegionManager.hpp" + +namespace geos +{ + +namespace singlePhaseFluxKernelsHelper +{ + +/** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ +template< typename VIEWTYPE > +using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + +GEOS_HOST_DEVICE +inline +void computeSinglePhaseFlux( localIndex const ( &seri )[2], + localIndex const ( &sesri )[2], + localIndex const ( &sei )[2], + real64 const ( &transmissibility )[2], + real64 const ( &dTrans_dPres )[2], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const > > const & dens, + ElementViewConst< arrayView2d< real64 const > > const & dDens_dPres, + ElementViewConst< arrayView1d< real64 const > > const & mob, + ElementViewConst< arrayView1d< real64 const > > const & dMob_dPres, + real64 & alpha, + real64 & mobility, + real64 & potGrad, + real64 & fluxVal, + real64 ( & dFlux_dP )[2], + real64 & dFlux_dTrans ) +{ + // average density + real64 densMean = 0.0; + real64 dDensMean_dP[2]; + + for( localIndex ke = 0; ke < 2; ++ke ) + { + densMean += 0.5 * dens[seri[ke]][sesri[ke]][sei[ke]][0]; + dDensMean_dP[ke] = 0.5 * dDens_dPres[seri[ke]][sesri[ke]][sei[ke]][0]; + } + + // compute potential difference + real64 dpotGrad_dTrans = 0.0; + real64 sumWeightGrav = 0.0; + real64 potScale = 0.0; + int signpotGradf[2] = {1, -1}; + + for( localIndex ke = 0; ke < 2; ++ke ) + { + localIndex const er = seri[ke]; + localIndex const esr = sesri[ke]; + localIndex const ei = sei[ke]; + + real64 const pressure = pres[er][esr][ei]; + real64 const gravD = gravCoef[er][esr][ei]; + real64 const pot = transmissibility[ke] * ( pressure - densMean * gravD ); + + potGrad += pot; + dpotGrad_dTrans += signpotGradf[ke] * ( pressure - densMean * gravD ); + sumWeightGrav += transmissibility[ke] * gravD; + + potScale = fmax( potScale, fabs( pot ) ); + } + + // compute upwinding tolerance + real64 constexpr upwRelTol = 1e-8; + real64 const upwAbsTol = fmax( potScale * upwRelTol, LvArray::NumericLimits< real64 >::epsilon ); + + // decide mobility coefficients - smooth variation in [-upwAbsTol; upwAbsTol] + alpha = ( potGrad + upwAbsTol ) / ( 2 * upwAbsTol ); + + real64 dMobility_dP[2]{}; + if( alpha <= 0.0 || alpha >= 1.0 ) + { + // happy path: single upwind direction + localIndex const ke = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) ); + mobility = mob[seri[ke]][sesri[ke]][sei[ke]]; + dMobility_dP[ke] = dMob_dPres[seri[ke]][sesri[ke]][sei[ke]]; + } + else + { + // sad path: weighted averaging + real64 const mobWeights[2] = { alpha, 1.0 - alpha }; + for( localIndex ke = 0; ke < 2; ++ke ) + { + mobility += mobWeights[ke] * mob[seri[ke]][sesri[ke]][sei[ke]]; + dMobility_dP[ke] = mobWeights[ke] * dMob_dPres[seri[ke]][sesri[ke]][sei[ke]]; + } + } + + // compute the final flux and derivative w.r.t transmissibility + fluxVal = mobility * potGrad; + + dFlux_dTrans = mobility * dpotGrad_dTrans; + + for( localIndex ke = 0; ke < 2; ++ke ) + { + dFlux_dP[ke] = mobility * ( transmissibility[ke] - dDensMean_dP[ke] * sumWeightGrav ) + + dMobility_dP[ke] * potGrad + dFlux_dTrans * dTrans_dPres[ke]; + } + +} + + +template< typename ENERGYFLUX_DERIVATIVE_TYPE > +GEOS_HOST_DEVICE +void computeEnthalpyFlux( localIndex const ( &seri )[2], + localIndex const ( &sesri )[2], + localIndex const ( &sei )[2], + real64 const ( &transmissibility )[2], + ElementViewConst< arrayView2d< real64 const > > const & enthalpy, + ElementViewConst< arrayView2d< real64 const > > const & dEnthalpy_dPressure, + ElementViewConst< arrayView2d< real64 const > > const & dEnthalpy_dTemperature, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const > > const & dDens_dTemp, + ElementViewConst< arrayView1d< real64 const > > const & dMob_dTemp, + real64 const & alpha, + real64 const & mobility, + real64 const & potGrad, + real64 const & massFlux, + real64 const & dMassFlux_dTrans, + real64 const ( &dMassFlux_dP )[2], + real64 ( & dMassFlux_dT )[2], + real64 & energyFlux, + real64 & dEnergyFlux_dTrans, + ENERGYFLUX_DERIVATIVE_TYPE & dEnergyFlux_dP, + ENERGYFLUX_DERIVATIVE_TYPE & dEnergyFlux_dT ) +{ + // Step 1: compute the derivatives of the mean density at the interface wrt temperature + + real64 dDensMean_dT[2]{0.0, 0.0}; + + for( integer ke = 0; ke < 2; ++ke ) + { + real64 const dDens_dT = dDens_dTemp[seri[ke]][sesri[ke]][sei[ke]][0]; + dDensMean_dT[ke] = 0.5 * dDens_dT; + } + + // Step 2: compute the derivatives of the potential difference wrt temperature + //***** calculation of flux ***** + + real64 dGravHead_dT[2]{0.0, 0.0}; + + // compute potential difference + for( integer ke = 0; ke < 2; ++ke ) + { + localIndex const er = seri[ke]; + localIndex const esr = sesri[ke]; + localIndex const ei = sei[ke]; + + // compute derivative of gravity potential difference wrt temperature + real64 const gravD = transmissibility[ke] * gravCoef[er][esr][ei]; + + for( integer i = 0; i < 2; ++i ) + { + dGravHead_dT[i] += dDensMean_dT[i] * gravD; + } + } + + // Step 3: compute the derivatives of the (upwinded) compFlux wrt temperature + // *** upwinding *** + + // Step 3.1: compute the derivative of the mass flux wrt temperature + for( integer ke = 0; ke < 2; ++ke ) + { + dMassFlux_dT[ke] -= dGravHead_dT[ke]; + } + + for( integer ke = 0; ke < 2; ++ke ) + { + dMassFlux_dT[ke] *= mobility; + } + + real64 dMob_dT[2]{}; + + if( alpha <= 0.0 || alpha >= 1.0 ) + { + localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) ); + + dMob_dT[k_up] = dMob_dTemp[seri[k_up]][sesri[k_up]][sei[k_up]]; + } + else + { + real64 const mobWeights[2] = { alpha, 1.0 - alpha }; + for( integer ke = 0; ke < 2; ++ke ) + { + dMob_dT[ke] = mobWeights[ke] * dMob_dTemp[seri[ke]][sesri[ke]][sei[ke]]; + } + } + + // add contribution from upstream cell mobility derivatives + for( integer ke = 0; ke < 2; ++ke ) + { + dMassFlux_dT[ke] += dMob_dT[ke] * potGrad; + } + + // Step 4: compute the enthalpy flux + real64 enthalpyTimesMobWeight = 0.0; + real64 dEnthalpy_dP[2]{0.0, 0.0}; + real64 dEnthalpy_dT[2]{0.0, 0.0}; + + if( alpha <= 0.0 || alpha >= 1.0 ) + { + localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) ); + + enthalpyTimesMobWeight = enthalpy[seri[k_up]][sesri[k_up]][sei[k_up]][0]; + dEnthalpy_dP[k_up] = dEnthalpy_dPressure[seri[k_up]][sesri[k_up]][sei[k_up]][0]; + dEnthalpy_dT[k_up] = dEnthalpy_dTemperature[seri[k_up]][sesri[k_up]][sei[k_up]][0]; + } + else + { + real64 const mobWeights[2] = { alpha, 1.0 - alpha }; + for( integer ke = 0; ke < 2; ++ke ) + { + enthalpyTimesMobWeight += mobWeights[ke] * enthalpy[seri[ke]][sesri[ke]][sei[ke]][0]; + dEnthalpy_dP[ke] = mobWeights[ke] * dEnthalpy_dPressure[seri[ke]][sesri[ke]][sei[ke]][0]; + dEnthalpy_dT[ke] = mobWeights[ke] * dEnthalpy_dTemperature[seri[ke]][sesri[ke]][sei[ke]][0]; + } + } + + energyFlux += massFlux * enthalpyTimesMobWeight; + dEnergyFlux_dTrans = enthalpyTimesMobWeight * dMassFlux_dTrans; + + for( integer ke = 0; ke < 2; ++ke ) + { + dEnergyFlux_dP[ke] += dMassFlux_dP[ke] * enthalpyTimesMobWeight; + dEnergyFlux_dT[ke] += dMassFlux_dT[ke] * enthalpyTimesMobWeight; + } + + for( integer ke = 0; ke < 2; ++ke ) + { + dEnergyFlux_dP[ke] += massFlux * dEnthalpy_dP[ke]; + dEnergyFlux_dT[ke] += massFlux * dEnthalpy_dT[ke]; + } +} + + +template< typename ENERGYFLUX_DERIVATIVE_TYPE > +GEOS_HOST_DEVICE +void computeConductiveFlux( localIndex const ( &seri )[2], + localIndex const ( &sesri )[2], + localIndex const ( &sei )[2], + ElementViewConst< arrayView1d< real64 const > > const & temperature, + real64 const ( &thermalTrans )[2], + real64 & energyFlux, + ENERGYFLUX_DERIVATIVE_TYPE & dEnergyFlux_dT ) +{ + for( integer ke = 0; ke < 2; ++ke ) + { + localIndex const er = seri[ke]; + localIndex const esr = sesri[ke]; + localIndex const ei = sei[ke]; + + energyFlux += thermalTrans[ke] * temperature[er][esr][ei]; + dEnergyFlux_dT[ke] += thermalTrans[ke]; + } +} + +} // namespace singlePhaseFluxKernelsHelper + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXKERNELSHELPER_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/HydrostaticPressureKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/HydrostaticPressureKernel.hpp new file mode 100644 index 00000000000..6a4e5bab264 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/HydrostaticPressureKernel.hpp @@ -0,0 +1,213 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file HydrostaticPressureKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_HYDROSTATICPRESSUREKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_HYDROSTATICPRESSUREKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** HydrostaticPressureKernel ********************************/ + +struct HydrostaticPressureKernel +{ + + template< typename FLUID_WRAPPER > + static bool + computeHydrostaticPressure( integer const maxNumEquilIterations, + real64 const & equilTolerance, + real64 const (&gravVector)[ 3 ], + FLUID_WRAPPER fluidWrapper, + real64 const & refElevation, + real64 const & refPres, + real64 const & refDens, + real64 const & newElevation, + real64 & newPres, + real64 & newDens ) + { + // Step 1: guess the pressure with the refDensity + + real64 const gravCoef = gravVector[2] * ( refElevation - newElevation ); + real64 pres0 = refPres - refDens * gravCoef; + real64 pres1 = 0.0; + + // Step 2: compute the mass density at this elevation using the guess, and update pressure + + real64 dens = 0.0; + real64 visc = 0.0; + constitutive::SingleFluidBaseUpdate::computeValues( fluidWrapper, + pres0, + dens, + visc ); + pres1 = refPres - 0.5 * ( refDens + dens ) * gravCoef; + + // Step 3: fixed-point iteration until convergence + + bool equilHasConverged = false; + for( localIndex eqIter = 0; eqIter < maxNumEquilIterations; ++eqIter ) + { + + // check convergence + equilHasConverged = ( LvArray::math::abs( pres0 - pres1 ) < equilTolerance ); + pres0 = pres1; + + // if converged, move on + if( equilHasConverged ) + { + break; + } + + // compute the density at this elevation using the previous pressure, and compute the new pressure + constitutive::SingleFluidBaseUpdate::computeValues( fluidWrapper, + pres0, + dens, + visc ); + pres1 = refPres - 0.5 * ( refDens + dens ) * gravCoef; + } + + // Step 4: save the hydrostatic pressure and the corresponding density + + newPres = pres1; + newDens = dens; + + return equilHasConverged; + } + + + template< typename FLUID_WRAPPER > + static bool + launch( localIndex const size, + integer const maxNumEquilIterations, + real64 const equilTolerance, + real64 const (&gravVector)[ 3 ], + real64 const & minElevation, + real64 const & elevationIncrement, + real64 const & datumElevation, + real64 const & datumPres, + FLUID_WRAPPER fluidWrapper, + arrayView1d< arrayView1d< real64 > const > elevationValues, + arrayView1d< real64 > pressureValues ) + { + bool hasConverged = true; + + // Step 1: compute the mass density at the datum elevation + + real64 datumDens = 0.0; + real64 datumVisc = 0.0; + + constitutive::SingleFluidBaseUpdate::computeValues( fluidWrapper, + datumPres, + datumDens, + datumVisc ); + + // Step 2: find the closest elevation to datumElevation + + forAll< parallelHostPolicy >( size, [=] ( localIndex const i ) + { + real64 const elevation = minElevation + i * elevationIncrement; + elevationValues[0][i] = elevation; + } ); + integer const iRef = LvArray::sortedArrayManipulation::find( elevationValues[0].begin(), + elevationValues[0].size(), + datumElevation ); + + + // Step 3: compute the mass density and pressure at the reference elevation + + array1d< real64 > dens( pressureValues.size() ); + + bool const hasConvergedRef = + computeHydrostaticPressure( maxNumEquilIterations, + equilTolerance, + gravVector, + fluidWrapper, + datumElevation, + datumPres, + datumDens, + elevationValues[0][iRef], + pressureValues[iRef], + dens[iRef] ); + if( !hasConvergedRef ) + { + return false; + } + + + // Step 4: for each elevation above the reference elevation, compute the pressure + + localIndex const numEntriesAboveRef = size - iRef - 1; + forAll< serialPolicy >( numEntriesAboveRef, [=, &hasConverged] ( localIndex const i ) + { + bool const hasConvergedAboveRef = + computeHydrostaticPressure( maxNumEquilIterations, + equilTolerance, + gravVector, + fluidWrapper, + elevationValues[0][iRef+i], + pressureValues[iRef+i], + dens[iRef+i], + elevationValues[0][iRef+i+1], + pressureValues[iRef+i+1], + dens[iRef+i+1] ); + if( !hasConvergedAboveRef ) + { + hasConverged = false; + } + + + } ); + + // Step 5: for each elevation below the reference elevation, compute the pressure + + localIndex const numEntriesBelowRef = iRef; + forAll< serialPolicy >( numEntriesBelowRef, [=, &hasConverged] ( localIndex const i ) + { + bool const hasConvergedBelowRef = + computeHydrostaticPressure( maxNumEquilIterations, + equilTolerance, + gravVector, + fluidWrapper, + elevationValues[0][iRef-i], + pressureValues[iRef-i], + dens[iRef-i], + elevationValues[0][iRef-i-1], + pressureValues[iRef-i-1], + dens[iRef-i-1] ); + if( !hasConvergedBelowRef ) + { + hasConverged = false; + } + } ); + + return hasConverged; + } +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_HYDROSTATICPRESSUREKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/MobilityKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/MobilityKernel.hpp new file mode 100644 index 00000000000..6f55e13e545 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/MobilityKernel.hpp @@ -0,0 +1,149 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file MobilityKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_MOBILITYKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_MOBILITYKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** MobilityKernel ********************************/ + +struct MobilityKernel +{ + // Isothermal version + GEOS_HOST_DEVICE + inline + static void + compute( real64 const & dens, + real64 const & dDens_dPres, + real64 const & visc, + real64 const & dVisc_dPres, + real64 & mob, + real64 & dMob_dPres ) + { + mob = dens / visc; + dMob_dPres = dDens_dPres / visc - mob / visc * dVisc_dPres; + } + +// Thermal version + GEOS_HOST_DEVICE + inline + static void + compute( real64 const & dens, + real64 const & dDens_dPres, + real64 const & dDens_dTemp, + real64 const & visc, + real64 const & dVisc_dPres, + real64 const & dVisc_dTemp, + real64 & mob, + real64 & dMob_dPres, + real64 & dMob_dTemp ) + { + mob = dens / visc; + dMob_dPres = dDens_dPres / visc - mob / visc * dVisc_dPres; + dMob_dTemp = dDens_dTemp / visc - mob / visc * dVisc_dTemp; + } + +// Value-only (no derivatives) version + GEOS_HOST_DEVICE + inline + static void + compute( real64 const & dens, + real64 const & visc, + real64 & mob ) + { + mob = dens / visc; + } + + // Isothermal version + template< typename POLICY > + static void launch( localIndex const size, + arrayView2d< real64 const > const & dens, + arrayView2d< real64 const > const & dDens_dPres, + arrayView2d< real64 const > const & visc, + arrayView2d< real64 const > const & dVisc_dPres, + arrayView1d< real64 > const & mob, + arrayView1d< real64 > const & dMob_dPres ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + compute( dens[a][0], + dDens_dPres[a][0], + visc[a][0], + dVisc_dPres[a][0], + mob[a], + dMob_dPres[a] ); + } ); + } + + // Thermal version + template< typename POLICY > + static void launch( localIndex const size, + arrayView2d< real64 const > const & dens, + arrayView2d< real64 const > const & dDens_dPres, + arrayView2d< real64 const > const & dDens_dTemp, + arrayView2d< real64 const > const & visc, + arrayView2d< real64 const > const & dVisc_dPres, + arrayView2d< real64 const > const & dVisc_dTemp, + arrayView1d< real64 > const & mob, + arrayView1d< real64 > const & dMob_dPres, + arrayView1d< real64 > const & dMob_dTemp ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + compute( dens[a][0], + dDens_dPres[a][0], + dDens_dTemp[a][0], + visc[a][0], + dVisc_dPres[a][0], + dVisc_dTemp[a][0], + mob[a], + dMob_dPres[a], + dMob_dTemp[a] ); + } ); + } + +// Value-only (no derivatives) version + template< typename POLICY > + static void launch( localIndex const size, + arrayView2d< real64 const > const & dens, + arrayView2d< real64 const > const & visc, + arrayView1d< real64 > const & mob ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + compute( dens[a][0], + visc[a][0], + mob[a] ); + } ); + } +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_MOBILITYKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ResidualNormKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ResidualNormKernel.hpp new file mode 100644 index 00000000000..9360af72ea9 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ResidualNormKernel.hpp @@ -0,0 +1,268 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ResidualNormKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_RESIDUALNORMKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_RESIDUALNORMKERNEL_HPP + +#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** ResidualNormKernel ********************************/ + +/** + * @class IsothermalResidualNormKernel + */ +class IsothermalResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 1 > +{ +public: + + using Base = physicsSolverBaseKernels::ResidualNormKernelBase< 1 >; + using Base::m_minNormalizer; + using Base::m_rankOffset; + using Base::m_localResidual; + using Base::m_dofNumber; + + IsothermalResidualNormKernel( globalIndex const rankOffset, + arrayView1d< real64 const > const & localResidual, + arrayView1d< globalIndex const > const & dofNumber, + arrayView1d< localIndex const > const & ghostRank, + ElementSubRegionBase const & subRegion, + real64 const minNormalizer ) + : Base( rankOffset, + localResidual, + dofNumber, + ghostRank, + minNormalizer ), + m_mass_n( subRegion.template getField< fields::flow::mass_n >() ) + {} + + GEOS_HOST_DEVICE + virtual void computeLinf( localIndex const ei, + LinfStackVariables & stack ) const override + { + real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_mass_n[ei] ); + real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow] ) / massNormalizer; + if( valMass > stack.localValue[0] ) + { + stack.localValue[0] = valMass; + } + } + + GEOS_HOST_DEVICE + virtual void computeL2( localIndex const ei, + L2StackVariables & stack ) const override + { + real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_mass_n[ei] ); + stack.localValue[0] += m_localResidual[stack.localRow] * m_localResidual[stack.localRow]; + stack.localNormalizer[0] += massNormalizer; + } + + +protected: + + /// View on mass at the previous converged time step + arrayView1d< real64 const > const m_mass_n; + +}; + +/** + * @class ThermalResidualNormKernel + */ +class ThermalResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 2 > +{ +public: + + using Base = physicsSolverBaseKernels::ResidualNormKernelBase< 2 >; + using Base::m_minNormalizer; + using Base::m_rankOffset; + using Base::m_localResidual; + using Base::m_dofNumber; + + ThermalResidualNormKernel( globalIndex const rankOffset, + arrayView1d< real64 const > const & localResidual, + arrayView1d< globalIndex const > const & dofNumber, + arrayView1d< localIndex const > const & ghostRank, + ElementSubRegionBase const & subRegion, + real64 const minNormalizer ) + : Base( rankOffset, + localResidual, + dofNumber, + ghostRank, + minNormalizer ), + m_mass_n( subRegion.template getField< fields::flow::mass_n >() ), + m_energy_n( subRegion.template getField< fields::flow::energy_n >() ) + {} + + GEOS_HOST_DEVICE + void computeMassEnergyNormalizers( localIndex const ei, + real64 & massNormalizer, + real64 & energyNormalizer ) const + { + massNormalizer = LvArray::math::max( m_minNormalizer, m_mass_n[ei] ); + energyNormalizer = LvArray::math::max( m_minNormalizer, LvArray::math::abs( m_energy_n[ei] ) ); // energy can be negative + } + + GEOS_HOST_DEVICE + virtual void computeLinf( localIndex const ei, + LinfStackVariables & stack ) const override + { + real64 massNormalizer = 0.0, energyNormalizer = 0.0; + computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); + + // step 1: mass residual + + real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow] ) / massNormalizer; + if( valMass > stack.localValue[0] ) + { + stack.localValue[0] = valMass; + } + + // step 2: energy residual + real64 const valEnergy = LvArray::math::abs( m_localResidual[stack.localRow + 1] ) / energyNormalizer; + if( valEnergy > stack.localValue[1] ) + { + stack.localValue[1] = valEnergy; + } + } + + GEOS_HOST_DEVICE + virtual void computeL2( localIndex const ei, + L2StackVariables & stack ) const override + { + real64 massNormalizer = 0.0, energyNormalizer = 0.0; + computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); + + // step 1: mass residual + + stack.localValue[0] += m_localResidual[stack.localRow] * m_localResidual[stack.localRow]; + stack.localNormalizer[0] += massNormalizer; + + // step 2: energy residual + + stack.localValue[1] += m_localResidual[stack.localRow + 1] * m_localResidual[stack.localRow + 1]; + stack.localNormalizer[1] += energyNormalizer; + } + + +protected: + + /// View on mass at the previous converged time step + arrayView1d< real64 const > const m_mass_n; + + /// View on energy at the previous converged time step + arrayView1d< real64 const > const m_energy_n; + +}; + +/** + * @class ResidualNormKernelFactory + */ +class ResidualNormKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch (isothermal version) + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] normType the type of norm used (Linf or L2) + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] localResidual the residual vector on my MPI rank + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[out] residualNorm the residual norm on the subRegion + * @param[out] residualNormalizer the residual normalizer on the subRegion + */ + template< typename POLICY > + static void + createAndLaunch( physicsSolverBaseKernels::NormType const normType, + globalIndex const rankOffset, + string const dofKey, + arrayView1d< real64 const > const & localResidual, + ElementSubRegionBase const & subRegion, + real64 const minNormalizer, + real64 (& residualNorm)[1], + real64 (& residualNormalizer)[1] ) + { + arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + + IsothermalResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, subRegion, minNormalizer ); + if( normType == physicsSolverBaseKernels::NormType::Linf ) + { + IsothermalResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); + } + else // L2 norm + { + IsothermalResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); + } + } + + /** + * @brief Create a new kernel and launch (thermal version) + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] normType the type of norm used (Linf or L2) + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] localResidual the residual vector on my MPI rank + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[in] solidInternalEnergy the solid internal energy model + * @param[out] residualNorm the residual norm on the subRegion + * @param[out] residualNormalizer the residual normalizer on the subRegion + */ + template< typename POLICY > + static void + createAndLaunch( physicsSolverBaseKernels::NormType const normType, + globalIndex const rankOffset, + string const & dofKey, + arrayView1d< real64 const > const & localResidual, + ElementSubRegionBase const & subRegion, + real64 const minNormalizer, + real64 (& residualNorm)[2], + real64 (& residualNormalizer)[2] ) + { + arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + + ThermalResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, subRegion, minNormalizer ); + if( normType == physicsSolverBaseKernels::NormType::Linf ) + { + ThermalResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); + } + else // L2 norm + { + ThermalResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); + } + } + +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_RESIDUALNORMKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseHybridFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SinglePhaseHybridFVMKernels.hpp similarity index 87% rename from src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseHybridFVMKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SinglePhaseHybridFVMKernels.hpp index 4c6bc274f4c..2898e11a3a3 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseHybridFVMKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SinglePhaseHybridFVMKernels.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,8 +17,8 @@ * @file SinglePhaseHybridFVMKernels.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEHYBRIDFVMKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEHYBRIDFVMKERNELS_HPP +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_HYBRIDFVMKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_HYBRIDFVMKERNELS_HPP #include "common/DataTypes.hpp" #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" @@ -30,19 +31,22 @@ #include "finiteVolume/mimeticInnerProducts/QuasiTPFAInnerProduct.hpp" #include "finiteVolume/mimeticInnerProducts/QuasiRTInnerProduct.hpp" #include "finiteVolume/mimeticInnerProducts/SimpleInnerProduct.hpp" +#include "linearAlgebra/interfaces/InterfaceTypes.hpp" +#include "denseLinearAlgebra/interfaces/blaslapack/BlasLapackLA.hpp" #include "mesh/MeshLevel.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/HybridFVMHelperKernels.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseBaseKernels.hpp" #include "physicsSolvers/fluidFlow/StencilAccessors.hpp" -#include "physicsSolvers/SolverBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/HybridFVMHelperKernels.hpp" +#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" +#include "codingUtilities/Utilities.hpp" namespace geos { namespace singlePhaseHybridFVMKernels { +/******************************** AssemblerKernelHelper ********************************/ /******************************** Kernel switches ********************************/ namespace internal @@ -81,6 +85,133 @@ void kernelLaunchSelectorFaceSwitch( T value, LAMBDA && lambda ) } // namespace internal +/******************************** AveragePressureGradientKernel ********************************/ + +template< integer NUM_FACES > +class AveragePressureGradientKernel +{ +public: + AveragePressureGradientKernel( CellElementSubRegion & subRegion, + FaceManager const & faceManager ) + : + // get the face-centered pressures + m_facePressure( faceManager.getField< fields::flow::facePressure >() ), + m_faceCenter( faceManager.faceCenter() ), + m_pres( subRegion.template getField< fields::flow::pressure >() ), + m_elemCenter( subRegion.getElementCenter() ), + m_elemsToFaces( subRegion.faceList() ), + m_presGradient( subRegion.template getField< fields::flow::pressureGradient >() ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables + { + + GEOS_HOST_DEVICE + StackVariables(): + coordinates( NUM_FACES+1, 4 ), + pressures( NUM_FACES+1 ), + presGradientLocal( 4 ) + {} + + stackArray2d< real64, (NUM_FACES + 1) * 4 > coordinates; + stackArray1d< real64, NUM_FACES + 1 > pressures; + stackArray1d< real64, 4 > presGradientLocal; + }; + + + inline + void compute( localIndex const elemIndex, + StackVariables stack ) const + { + + for( integer dim=0; dim<3; ++dim ) + { + stack.coordinates( 0, dim ) = m_elemCenter( elemIndex, dim ); + } + stack.coordinates( 0, 3 ) = 1.0; + stack.pressures[0] = m_pres[elemIndex]; + + for( integer fi=0; fi + static void + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + + forAll< POLICY >( numElems, [=] ( localIndex const ei ) + { + typename KERNEL_TYPE::StackVariables stack; + kernelComponent.compute( ei, stack ); + } ); + } + +private: + /// face pressure + arrayView1d< real64 const > const m_facePressure; + + /// the face center coordinates + arrayView2d< real64 const > const m_faceCenter; + + /// the cell-centered pressures + arrayView1d< real64 const > const m_pres; + + /// the cell center coordinates + arrayView2d< real64 const > const m_elemCenter; + + /// the elements to faces map + arrayView2d< localIndex const > const m_elemsToFaces; + + /// pressure gradient in the cell + arrayView2d< real64 > const m_presGradient; + +}; + +class AveragePressureGradientKernelFactory +{ +public: + + template< typename POLICY > + static void createAndLaunch( CellElementSubRegion & subRegion, + FaceManager const & faceManager ) + { + internal::kernelLaunchSelectorFaceSwitch( subRegion.numFacesPerElement(), [&] ( auto NUM_FACES ) + { + AveragePressureGradientKernel< NUM_FACES > kernel( subRegion, faceManager ); + AveragePressureGradientKernel< NUM_FACES >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } +}; + + /******************************** ElementBasedAssemblyKernel ********************************/ /** @@ -348,11 +479,11 @@ class ElementBasedAssemblyKernel * @param[inout] stack the stack variables * @param[in] kernelOp the function used to customize the kernel */ - template< typename FUNC = singlePhaseBaseKernels::NoOpFunc > + template< typename FUNC = NoOpFunc > GEOS_HOST_DEVICE void compute( localIndex const ei, StackVariables & stack, - FUNC && kernelOp = singlePhaseBaseKernels::NoOpFunc{} ) const + FUNC && kernelOp = NoOpFunc{} ) const { GEOS_UNUSED_VAR( ei, stack, kernelOp ); @@ -616,11 +747,11 @@ class ElementBasedAssemblyKernelFactory /** * @class ResidualNormKernel */ -class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > +class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 1 > { public: - using Base = solverBaseKernels::ResidualNormKernelBase< 1 >; + using Base = physicsSolverBaseKernels::ResidualNormKernelBase< 1 >; using Base::m_minNormalizer; using Base::m_rankOffset; using Base::m_localResidual; @@ -787,7 +918,7 @@ class ResidualNormKernelFactory */ template< typename POLICY > static void - createAndLaunch( solverBaseKernels::NormType const normType, + createAndLaunch( physicsSolverBaseKernels::NormType const normType, globalIndex const rankOffset, string const & dofKey, arrayView1d< real64 const > const & localResidual, @@ -811,7 +942,7 @@ class ResidualNormKernelFactory ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, regionFilter, faceManager, flowAccessors, fluidAccessors, poroAccessors, defaultViscosity, dt, minNormalizer ); - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { ResidualNormKernel::launchLinf< POLICY >( faceManager.size(), kernel, residualNorm ); } @@ -827,4 +958,4 @@ class ResidualNormKernelFactory } // namespace geos -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEHYBRIDFVMKERNELS_HPP +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_HYBRIDFVMKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolidInternalEnergyUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolidInternalEnergyUpdateKernel.hpp new file mode 100644 index 00000000000..f1b0942ea16 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolidInternalEnergyUpdateKernel.hpp @@ -0,0 +1,54 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolidInternalEnergyUpdateKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SOLIDINTERNALENERGYUPDATEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SOLIDINTERNALENERGYUPDATEKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace thermalSinglePhaseBaseKernels +{ + +/******************************** SolidInternalEnergyUpdateKernel ********************************/ + +struct SolidInternalEnergyUpdateKernel +{ + + template< typename POLICY, typename SOLID_INTERNAL_ENERGY_WRAPPER > + static void + launch( localIndex const size, + SOLID_INTERNAL_ENERGY_WRAPPER const & solidInternalEnergyWrapper, + arrayView1d< real64 const > const & temp ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + solidInternalEnergyWrapper.update( k, temp[k] ); + } ); + } +}; + +} // namespace thermalSinglePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SOLIDINTERNALENERGYUPDATEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp new file mode 100644 index 00000000000..24529dda836 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp @@ -0,0 +1,72 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolutionCheckKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_SOLUTIONCHECKKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_SOLUTIONCHECKKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** SolutionCheckKernel ********************************/ + +struct SolutionCheckKernel +{ + template< typename POLICY > + static std::pair< integer, real64 > launch( arrayView1d< real64 const > const & localSolution, + globalIndex const rankOffset, + arrayView1d< globalIndex const > const & dofNumber, + arrayView1d< integer const > const & ghostRank, + arrayView1d< real64 const > const & pres, + real64 const scalingFactor ) + { + RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegativePressures( 0 ); + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minPres( 0.0 ); + + forAll< POLICY >( dofNumber.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( ghostRank[ei] < 0 && dofNumber[ei] >= 0 ) + { + localIndex const lid = dofNumber[ei] - rankOffset; + real64 const newPres = pres[ei] + scalingFactor * localSolution[lid]; + + if( newPres < 0.0 ) + { + numNegativePressures += 1; + minPres.min( newPres ); + } + } + + } ); + + return { numNegativePressures.get(), minPres.get() }; + } + +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_SOLUTIONCHECKKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionScalingKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionScalingKernel.hpp new file mode 100644 index 00000000000..fe0572da818 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionScalingKernel.hpp @@ -0,0 +1,75 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolutionScalingKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_SOLUTIONSCALINGKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_SOLUTIONSCALINGKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** SolutionScalingKernel ********************************/ + +struct SolutionScalingKernel +{ + template< typename POLICY > + static std::pair< real64, real64 > launch( arrayView1d< real64 const > const & localSolution, + globalIndex const rankOffset, + arrayView1d< globalIndex const > const & dofNumber, + arrayView1d< integer const > const & ghostRank, + real64 const maxAbsolutePresChange ) + { + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > scalingFactor( 1.0 ); + RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaPres( 0.0 ); + + forAll< POLICY >( dofNumber.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) mutable + { + if( ghostRank[ei] < 0 && dofNumber[ei] >= 0 ) + { + localIndex const lid = dofNumber[ei] - rankOffset; + + // compute the change in pressure + real64 const absPresChange = LvArray::math::abs( localSolution[lid] ); + maxDeltaPres.max( absPresChange ); + + // maxAbsolutePresChange <= 0.0 means that scaling is disabled, and we are only collecting maxDeltaPres in this kernel + if( maxAbsolutePresChange > 0.0 && absPresChange > maxAbsolutePresChange ) + { + real64 const presScalingFactor = maxAbsolutePresChange / absPresChange; + scalingFactor.min( presScalingFactor ); + } + } + + } ); + + return { scalingFactor.get(), maxDeltaPres.get() }; + } + +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_SOLUTIONSCALINGKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/StabilizedFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/StabilizedFluxComputeKernel.hpp new file mode 100644 index 00000000000..02bc73de112 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/StabilizedFluxComputeKernel.hpp @@ -0,0 +1,308 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StabilizedFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_STABILIZEDFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_STABILIZEDFLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp" + +namespace geos +{ + +namespace stabilizedSinglePhaseFVMKernels +{ + +/******************************** FluxComputeKernel ********************************/ + +/** + * @class FluxComputeKernel + * @tparam NUM_DOF number of degrees of freedom + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NUM_EQN, integer NUM_DOF, typename STENCILWRAPPER > +class FluxComputeKernel : public singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER > +{ +public: + + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; + using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; + using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; + + using StabSinglePhaseFlowAccessors = + StencilAccessors< fields::flow::macroElementIndex, + fields::flow::elementStabConstant, + fields::flow::pressure_n >; + + using StabSinglePhaseFluidAccessors = + StencilMaterialAccessors< constitutive::SingleFluidBase, + fields::singlefluid::density_n >; + + using AbstractBase::m_dt; + using AbstractBase::m_rankOffset; + using AbstractBase::m_ghostRank; + using AbstractBase::m_dofNumber; + using AbstractBase::m_gravCoef; + using AbstractBase::m_pres; + + using Base = singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; + using Base::numDof; + using Base::numEqn; + using Base::maxNumElems; + using Base::maxNumConns; + using Base::maxStencilSize; + using Base::m_stencilWrapper; + using Base::m_seri; + using Base::m_sesri; + using Base::m_sei; + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor accessor for the dofs numbers + * @param[in] singlePhaseFlowAccessor accessor for wrappers registered by the solver + * @param[in] stabSinglePhaseFlowAccessor accessor for wrappers registered by the solver needed for stabilization + * @param[in] singlePhaseFluidAccessor accessor for wrappers registered by the single fluid model + * @param[in] stabSinglePhaseFluidAccessor accessor for wrappers registered by the single fluid model needed for stabilization + * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + FluxComputeKernel( globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, + StabSinglePhaseFlowAccessors const & stabSinglePhaseFlowAccessors, + SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, + StabSinglePhaseFluidAccessors const & stabSinglePhaseFluidAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : Base( rankOffset, + stencilWrapper, + dofNumberAccessor, + singlePhaseFlowAccessors, + singlePhaseFluidAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs ), + m_pres_n( stabSinglePhaseFlowAccessors.get( fields::flow::pressure_n {} ) ), + m_dens_n( stabSinglePhaseFluidAccessors.get( fields::singlefluid::density_n {} ) ), + m_macroElementIndex( stabSinglePhaseFlowAccessors.get( fields::flow::macroElementIndex {} ) ), + m_elementStabConstant( stabSinglePhaseFlowAccessors.get( fields::flow::elementStabConstant {} ) ) + {} + + struct StackVariables : public Base::StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables( localIndex const size, localIndex numElems ) + : Base::StackVariables( size, numElems ) + {} + + using Base::StackVariables::stencilSize; + using Base::StackVariables::numFluxElems; + using Base::StackVariables::transmissibility; + using Base::StackVariables::dTrans_dPres; + using Base::StackVariables::dofColIndices; + using Base::StackVariables::localFlux; + using Base::StackVariables::localFluxJacobian; + + /// Stabilization transmissibility + real64 stabTransmissibility[maxNumConns][2]{}; + + }; + + /** + * @brief Compute the local flux contributions to the residual and Jacobian, including stabilization + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeFlux( localIndex const iconn, + StackVariables & stack ) const + { + + m_stencilWrapper.computeStabilizationWeights( iconn, + stack.stabTransmissibility ); + + // *********************************************** + // We call the base computeFlux, + // + // We use the lambda below to compute stabilization terms + Base::computeFlux( iconn, stack, [&] ( localIndex const (&k)[2], + localIndex const (&seri)[2], + localIndex const (&sesri)[2], + localIndex const (&sei)[2], + localIndex const connectionIndex, + real64 const alpha, + real64 const mobility, + real64 const potGrad, + real64 const fluxVal, + real64 const (&dFlux_dP)[2] ) + { + + GEOS_UNUSED_VAR( alpha, mobility, potGrad, fluxVal, dFlux_dP ); + + /// stabilization flux and derivatives + real64 stabFlux{}; + real64 dStabFlux_dP[2]{}; + + real64 const stabTrans[2] = { stack.stabTransmissibility[connectionIndex][0], + stack.stabTransmissibility[connectionIndex][1] }; + + + real64 dPresGradStab = 0.0; + integer stencilMacroElements[2]{}; + + // Step 1: compute the pressure jump at the interface + for( integer ke = 0; ke < stack.numFluxElems; ++ke ) + { + localIndex const er = seri[ke]; + localIndex const esr = sesri[ke]; + localIndex const ei = sei[ke]; + + stencilMacroElements[ke] = m_macroElementIndex[er][esr][ei]; + + // use the jump in *delta* pressure in the stabilization term + dPresGradStab += m_elementStabConstant[er][esr][ei] * stabTrans[ke] * (m_pres[er][esr][ei] - m_pres_n[er][esr][ei]); + } + + // Step 2: compute the stabilization flux + integer const k_up_stab = (dPresGradStab >= 0) ? 0 : 1; + + localIndex const er_up_stab = seri[k_up_stab]; + localIndex const esr_up_stab = sesri[k_up_stab]; + localIndex const ei_up_stab = sei[k_up_stab]; + + bool const areInSameMacroElement = stencilMacroElements[0] == stencilMacroElements[1]; + bool const isStabilizationActive = stencilMacroElements[0] >= 0 && stencilMacroElements[1] >= 0; + if( isStabilizationActive && areInSameMacroElement ) + { + + real64 const laggedUpwindCoef = m_dens_n[er_up_stab][esr_up_stab][ei_up_stab][0]; + stabFlux += dPresGradStab * laggedUpwindCoef; + + for( integer ke = 0; ke < stack.numFluxElems; ++ke ) + { + real64 const tauStab = m_elementStabConstant[seri[ke]][sesri[ke]][sei[ke]]; + dStabFlux_dP[ke] += tauStab * stabTrans[ke] * laggedUpwindCoef; + } + } + + // Step 3: add the stabilization flux and its derivatives to the residual and Jacobian + integer const eqIndex0 = k[0] * numEqn; + integer const eqIndex1 = k[1] * numEqn; + + stack.localFlux[eqIndex0] += stabFlux; + stack.localFlux[eqIndex1] += -stabFlux; + + for( integer ke = 0; ke < stack.numFluxElems; ++ke ) + { + localIndex const localDofIndexPres = k[ke] * numDof; + stack.localFluxJacobian[eqIndex0][localDofIndexPres] += dStabFlux_dP[ke]; + stack.localFluxJacobian[eqIndex1][localDofIndexPres] += -dStabFlux_dP[ke]; + } + + } ); // end call to Base::computeFlux + + } + +protected: + + /// Views on flow properties at the previous converged time step + ElementViewConst< arrayView1d< real64 const > > const m_pres_n; + ElementViewConst< arrayView2d< real64 const > > const m_dens_n; + + /// Views on the macroelement indices and stab constant + ElementViewConst< arrayView1d< integer const > > const m_macroElementIndex; + ElementViewConst< arrayView1d< real64 const > > const m_elementStabConstant; + +}; + +/** + * @class FluxComputeKernelFactory + */ +class FluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] solverName name of the solver (to name accessors) + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( globalIndex const rankOffset, + string const & dofKey, + string const & solverName, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + + integer constexpr NUM_EQN = 1; + integer constexpr NUM_DOF = 1; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + using KERNEL_TYPE = FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; + typename KERNEL_TYPE::SinglePhaseFlowAccessors singlePhaseFlowAccessors( elemManager, solverName ); + typename KERNEL_TYPE::SinglePhaseFluidAccessors singlePhaseFluidAccessors( elemManager, solverName ); + typename KERNEL_TYPE::StabSinglePhaseFlowAccessors stabSinglePhaseFlowAccessors( elemManager, solverName ); + typename KERNEL_TYPE::StabSinglePhaseFluidAccessors stabSinglePhaseFluidAccessors( elemManager, solverName ); + typename KERNEL_TYPE::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); + + KERNEL_TYPE kernel( rankOffset, stencilWrapper, dofNumberAccessor, + singlePhaseFlowAccessors, stabSinglePhaseFlowAccessors, singlePhaseFluidAccessors, stabSinglePhaseFluidAccessors, + permeabilityAccessors, + dt, localMatrix, localRhs ); + KERNEL_TYPE::template launch< POLICY >( stencilWrapper.size(), kernel ); + } +}; + +} // namespace stabilizedSinglePhaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_STABILIZEDFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/StatisticsKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/StatisticsKernel.hpp new file mode 100644 index 00000000000..c99e4c17971 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/StatisticsKernel.hpp @@ -0,0 +1,133 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StatisticsKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_STATISTICSKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_STATISTICSKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** StatisticsKernel ********************************/ + +struct StatisticsKernel +{ + static void + saveDeltaPressure( localIndex const size, + arrayView1d< real64 const > const & pres, + arrayView1d< real64 const > const & initPres, + arrayView1d< real64 > const & deltaPres ) + { + forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + deltaPres[ei] = pres[ei] - initPres[ei]; + } ); + } + + static void + launch( localIndex const size, + arrayView1d< integer const > const & elemGhostRank, + arrayView1d< real64 const > const & volume, + arrayView1d< real64 const > const & pres, + arrayView1d< real64 const > const & deltaPres, + arrayView1d< real64 const > const & temp, + arrayView1d< real64 const > const & refPorosity, + arrayView2d< real64 const > const & porosity, + arrayView2d< real64 const > const & density, + real64 & minPres, + real64 & avgPresNumerator, + real64 & maxPres, + real64 & minDeltaPres, + real64 & maxDeltaPres, + real64 & minTemp, + real64 & avgTempNumerator, + real64 & maxTemp, + real64 & totalUncompactedPoreVol, + real64 & totalPoreVol, + real64 & totalMass ) + { + RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinPres( LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgPresNumerator( 0.0 ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxPres( -LvArray::NumericLimits< real64 >::max ); + + RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinDeltaPres( LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxDeltaPres( -LvArray::NumericLimits< real64 >::max ); + + RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinTemp( LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgTempNumerator( 0.0 ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxTemp( -LvArray::NumericLimits< real64 >::max ); + + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalUncompactedPoreVol( 0.0 ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalPoreVol( 0.0 ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalMass( 0.0 ); + + forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( elemGhostRank[ei] >= 0 ) + { + return; + } + + // To match our "reference", we have to use reference porosity here, not the actual porosity when we compute averages + real64 const uncompactedPoreVol = volume[ei] * refPorosity[ei]; + real64 const dynamicPoreVol = volume[ei] * porosity[ei][0]; + + subRegionMinPres.min( pres[ei] ); + subRegionAvgPresNumerator += uncompactedPoreVol * pres[ei]; + subRegionMaxPres.max( pres[ei] ); + + subRegionMinDeltaPres.min( deltaPres[ei] ); + subRegionMaxDeltaPres.max( deltaPres[ei] ); + + subRegionMinTemp.min( temp[ei] ); + subRegionAvgTempNumerator += uncompactedPoreVol * temp[ei]; + subRegionMaxTemp.max( temp[ei] ); + + subRegionTotalUncompactedPoreVol += uncompactedPoreVol; + subRegionTotalPoreVol += dynamicPoreVol; + subRegionTotalMass += dynamicPoreVol * density[ei][0]; + } ); + + minPres = subRegionMinPres.get(); + avgPresNumerator = subRegionAvgPresNumerator.get(); + maxPres = subRegionMaxPres.get(); + + minDeltaPres = subRegionMinDeltaPres.get(); + maxDeltaPres = subRegionMaxDeltaPres.get(); + + minTemp = subRegionMinTemp.get(); + avgTempNumerator = subRegionAvgTempNumerator.get(); + maxTemp = subRegionMaxTemp.get(); + + totalUncompactedPoreVol = subRegionTotalUncompactedPoreVol.get(); + totalPoreVol = subRegionTotalPoreVol.get(); + totalMass = subRegionTotalMass.get(); + } +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_STATISTICSKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp new file mode 100644 index 00000000000..2cba35dac4f --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp @@ -0,0 +1,338 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalAccumulationKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALACCUMULATIONKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALACCUMULATIONKERNELS_HPP + +#include "physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp" + +namespace geos +{ + +namespace thermalSinglePhaseBaseKernels +{ + +/******************************** AccumulationKernel ********************************/ + +/** + * @class AccumulationKernel + * @brief Define the interface for the assembly kernel in charge of accumulation + */ +template< typename SUBREGION_TYPE, integer NUM_DOF > +class AccumulationKernel : public singlePhaseBaseKernels::AccumulationKernel< SUBREGION_TYPE, NUM_DOF > +{ + +public: + + using Base = singlePhaseBaseKernels::AccumulationKernel< SUBREGION_TYPE, NUM_DOF >; + using Base::numDof; + using Base::numEqn; + using Base::m_rankOffset; + using Base::m_dofNumber; + using Base::m_elemGhostRank; + using Base::m_volume; + using Base::m_deltaVolume; + using Base::m_porosity; + using Base::m_dPoro_dPres; + using Base::m_density; + using Base::m_dDensity_dPres; + using Base::m_localMatrix; + using Base::m_localRhs; + + /** + * @brief Constructor + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + AccumulationKernel( globalIndex const rankOffset, + string const dofKey, + SUBREGION_TYPE const & subRegion, + constitutive::SingleFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : Base( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ), + m_dDensity_dTemp( fluid.dDensity_dTemperature() ), + m_dPoro_dTemp( solid.getDporosity_dTemperature() ), + m_internalEnergy( fluid.internalEnergy() ), + m_dInternalEnergy_dPres( fluid.dInternalEnergy_dPressure() ), + m_dInternalEnergy_dTemp( fluid.dInternalEnergy_dTemperature() ), + m_rockInternalEnergy( solid.getInternalEnergy() ), + m_dRockInternalEnergy_dTemp( solid.getDinternalEnergy_dTemperature() ), + m_energy_n( subRegion.template getField< fields::flow::energy_n >() ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables : public Base::StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables() + : Base::StackVariables() + {} + + using Base::StackVariables::poreVolume; + using Base::StackVariables::dPoreVolume_dPres; + using Base::StackVariables::localRow; + using Base::StackVariables::dofIndices; + using Base::StackVariables::localResidual; + using Base::StackVariables::localJacobian; + + /// Derivative of pore volume with respect to temperature + real64 dPoreVolume_dTemp = 0.0; + + // Solid energy + + /// Solid energy at time n+1 + real64 solidEnergy = 0.0; + + /// Derivative of solid internal energy with respect to pressure + real64 dSolidEnergy_dPres = 0.0; + + /// Derivative of solid internal energy with respect to temperature + real64 dSolidEnergy_dTemp = 0.0; + }; + + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] ei the element index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const ei, + StackVariables & stack ) const + { + Base::setup( ei, stack ); + + stack.dPoreVolume_dTemp = ( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dTemp[ei][0]; + + // initialize the solid volume + real64 const solidVolume = ( m_volume[ei] + m_deltaVolume[ei] ) * ( 1.0 - m_porosity[ei][0] ); + real64 const dSolidVolume_dPres = -( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dPres[ei][0]; + real64 const dSolidVolume_dTemp = -( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dTemp[ei][0]; + + // initialize the solid internal energy + stack.solidEnergy = solidVolume * m_rockInternalEnergy[ei][0]; + stack.dSolidEnergy_dPres = dSolidVolume_dPres * m_rockInternalEnergy[ei][0]; + stack.dSolidEnergy_dTemp = solidVolume * m_dRockInternalEnergy_dTemp[ei][0] + dSolidVolume_dTemp * m_rockInternalEnergy[ei][0]; + } + + /** + * @brief Compute the local accumulation contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + * @param[in] kernelOp the function used to customize the kernel + */ + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const ei, + StackVariables & stack ) const + { + stack.localResidual[numEqn-1] = -m_energy_n[ei]; + + Base::computeAccumulation( ei, stack, [&] () + { + // Step 1: assemble the derivatives of the mass balance equation w.r.t temperature + stack.localJacobian[0][numDof-1] = stack.poreVolume * m_dDensity_dTemp[ei][0] + stack.dPoreVolume_dTemp * m_density[ei][0]; + + // Step 2: assemble the fluid part of the accumulation term of the energy equation + real64 const fluidEnergy = stack.poreVolume * m_density[ei][0] * m_internalEnergy[ei][0]; + + real64 const dFluidEnergy_dP = stack.dPoreVolume_dPres * m_density[ei][0] * m_internalEnergy[ei][0] + + stack.poreVolume * m_dDensity_dPres[ei][0] * m_internalEnergy[ei][0] + + stack.poreVolume * m_density[ei][0] * m_dInternalEnergy_dPres[ei][0]; + + real64 const dFluidEnergy_dT = stack.poreVolume * m_dDensity_dTemp[ei][0] * m_internalEnergy[ei][0] + + stack.poreVolume * m_density[ei][0] * m_dInternalEnergy_dTemp[ei][0] + + stack.dPoreVolume_dTemp * m_density[ei][0] * m_internalEnergy[ei][0]; + + // local accumulation + stack.localResidual[numEqn-1] += fluidEnergy; + + // derivatives w.r.t. pressure and temperature + stack.localJacobian[numEqn-1][0] = dFluidEnergy_dP; + stack.localJacobian[numEqn-1][numDof-1] = dFluidEnergy_dT; + } ); + + // Step 3: assemble the solid part of the accumulation term of the energy equation + stack.localResidual[numEqn-1] += stack.solidEnergy; + stack.localJacobian[numEqn-1][0] += stack.dSolidEnergy_dPres; + stack.localJacobian[numEqn-1][numDof-1] += stack.dSolidEnergy_dTemp; + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void complete( localIndex const ei, + StackVariables & stack ) const + { + // Step 1: assemble the mass balance equation + Base::complete( ei, stack ); + + // Step 2: assemble the energy equation + m_localRhs[stack.localRow + numEqn-1] += stack.localResidual[numEqn-1]; + m_localMatrix.template addToRow< serialAtomic >( stack.localRow + numEqn-1, + stack.dofIndices, + stack.localJacobian[numEqn-1], + numDof ); + } + +protected: + + /// View on derivative of fluid density w.r.t temperature + arrayView2d< real64 const > const m_dDensity_dTemp; + + /// View on derivative of porosity w.r.t temperature + arrayView2d< real64 const > const m_dPoro_dTemp; + + /// Views on fluid internal energy + arrayView2d< real64 const > const m_internalEnergy; + arrayView2d< real64 const > const m_dInternalEnergy_dPres; + arrayView2d< real64 const > const m_dInternalEnergy_dTemp; + + /// Views on rock internal energy + arrayView2d< real64 const > const m_rockInternalEnergy; + arrayView2d< real64 const > const m_dRockInternalEnergy_dTemp; + + /// View on energy + arrayView1d< real64 const > const m_energy_n; + +}; + +/** + * @class SurfaceElementAccumulationKernel + * @brief Define the interface for the assembly kernel in charge of accumulation in SurfaceElementSubRegion + */ +class SurfaceElementAccumulationKernel : public AccumulationKernel< SurfaceElementSubRegion, 2 > +{ + +public: + + using Base = AccumulationKernel< SurfaceElementSubRegion, 2 >; + + /** + * @brief Constructor + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + SurfaceElementAccumulationKernel( globalIndex const rankOffset, + string const dofKey, + SurfaceElementSubRegion const & subRegion, + constitutive::SingleFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : Base( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ), + m_creationMass( subRegion.getField< fields::flow::massCreated >() ) + {} + + /** + * @brief Compute the local accumulation contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const ei, + Base::StackVariables & stack ) const + { + Base::computeAccumulation( ei, stack ); + if( Base::m_mass_n[ei] > 1.1 * m_creationMass[ei] ) + { + stack.localResidual[0] += m_creationMass[ei] * 0.25; + } + } + +protected: + + arrayView1d< real64 const > const m_creationMass; + +}; + +/** + * @class AccumulationKernelFactory + */ +class AccumulationKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename SUBREGION_TYPE > + static void + createAndLaunch( globalIndex const rankOffset, + string const dofKey, + SUBREGION_TYPE const & subRegion, + constitutive::SingleFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + if constexpr ( std::is_base_of_v< CellElementSubRegion, SUBREGION_TYPE > ) + { + integer constexpr NUM_DOF = 2; + AccumulationKernel< CellElementSubRegion, NUM_DOF > kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); + AccumulationKernel< CellElementSubRegion, NUM_DOF >::template launch< POLICY >( subRegion.size(), kernel ); + } + else if constexpr ( std::is_base_of_v< SurfaceElementSubRegion, SUBREGION_TYPE > ) + { + SurfaceElementAccumulationKernel kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); + SurfaceElementAccumulationKernel::launch< POLICY >( subRegion.size(), kernel ); + } + else + { + GEOS_UNUSED_VAR( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); + GEOS_ERROR( "Unsupported subregion type: " << typeid(SUBREGION_TYPE).name() ); + } + } + +}; + +} // namespace thermalSinglePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALACCUMULATIONKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalDirichletFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalDirichletFluxComputeKernel.hpp new file mode 100644 index 00000000000..5ab2f2959b0 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalDirichletFluxComputeKernel.hpp @@ -0,0 +1,393 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalDirichletFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp" + +#include "constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.hpp" +#include "constitutive/thermalConductivity/ThermalConductivityFields.hpp" + +namespace geos +{ + +namespace thermalSinglePhaseFVMKernels +{ + +/******************************** DirichletFluxComputeKernel ********************************/ + +/** + * @class DirichletFluxComputeKernel + * @tparam FLUIDWRAPPER the type of the fluid wrapper + * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms + */ +template< integer NUM_EQN, integer NUM_DOF, typename FLUIDWRAPPER > +class DirichletFluxComputeKernel : public singlePhaseFVMKernels::DirichletFluxComputeKernel< NUM_EQN, NUM_DOF, FLUIDWRAPPER > +{ +public: + +/** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; + using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; + using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; + + using AbstractBase::m_dt; + using AbstractBase::m_rankOffset; + using AbstractBase::m_dofNumber; + using AbstractBase::m_ghostRank; + using AbstractBase::m_gravCoef; + using AbstractBase::m_mob; + using AbstractBase::m_pres; + using AbstractBase::m_permeability; + using AbstractBase::m_dPerm_dPres; + + using AbstractBase::m_localMatrix; + using AbstractBase::m_localRhs; + + using Base = singlePhaseFVMKernels::DirichletFluxComputeKernel< NUM_EQN, NUM_DOF, FLUIDWRAPPER >; + using Base::numDof; + using Base::numEqn; + using Base::m_stencilWrapper; + using Base::m_seri; + using Base::m_sesri; + using Base::m_sei; + using Base::m_facePres; + using Base::m_faceGravCoef; + + using ThermalSinglePhaseFlowAccessors = + StencilAccessors< fields::flow::temperature, + fields::flow::dMobility_dTemperature >; + + using ThermalSinglePhaseFluidAccessors = + StencilMaterialAccessors< constitutive::SingleFluidBase, + fields::singlefluid::dDensity_dTemperature, + fields::singlefluid::enthalpy, + fields::singlefluid::dEnthalpy_dPressure, + fields::singlefluid::dEnthalpy_dTemperature >; + + using ThermalConductivityAccessors = + StencilMaterialAccessors< constitutive::SinglePhaseThermalConductivityBase, + fields::thermalconductivity::effectiveConductivity, + fields::thermalconductivity::dEffectiveConductivity_dT >; + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of the MPI rank + * @param[in] faceManager the face manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] fluidWrapper reference to the fluid wrapper + * @param[in] dofNumberAccessor the degree of freedom number accessor + * @param[in] singlePhaseFlowAccessors the single phase flow accessor + * @param[in] thermalSinglePhaseFlowAccessors the thermal single phase flow accessor + * @param[in] singlePhaseFluidAccessors the single phase fluid accessor + * @param[in] thermalSinglePhaseFluidAccessors the thermal single phase fluid accessor + * @param[in] permeabilityAccessors the permeability accessor + * @param[in] thermalConductivityAccessors the thermal conductivity accessor + * @param[in] dt the time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + DirichletFluxComputeKernel( globalIndex const rankOffset, + FaceManager const & faceManager, + BoundaryStencilWrapper const & stencilWrapper, + FLUIDWRAPPER const & fluidWrapper, + DofNumberAccessor const & dofNumberAccessor, + SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, + ThermalSinglePhaseFlowAccessors const & thermalSinglePhaseFlowAccessors, + SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, + ThermalSinglePhaseFluidAccessors const & thermalSinglePhaseFluidAccessors, + PermeabilityAccessors const & permeabilityAccessors, + ThermalConductivityAccessors const & thermalConductivityAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + + : Base( rankOffset, + faceManager, + stencilWrapper, + fluidWrapper, + dofNumberAccessor, + singlePhaseFlowAccessors, + singlePhaseFluidAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs ), + m_temp( thermalSinglePhaseFlowAccessors.get( fields::flow::temperature {} ) ), + m_faceTemp( faceManager.getField< fields::flow::faceTemperature >() ), + m_dMob_dTemp( thermalSinglePhaseFlowAccessors.get( fields::flow::dMobility_dTemperature {} ) ), + m_dDens_dTemp( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dDensity_dTemperature {} ) ), + m_enthalpy( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::enthalpy {} ) ), + m_dEnthalpy_dPres( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dEnthalpy_dPressure {} ) ), + m_dEnthalpy_dTemp( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dEnthalpy_dTemperature {} ) ), + m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ), + m_dThermalCond_dT( thermalConductivityAccessors.get( fields::thermalconductivity::dEffectiveConductivity_dT {} ) ) + {} + + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables : Base::StackVariables + { +public: + + /** + * @brief Constructor for the stack variables + * @param[in] size size of the stencil for this connection + * @param[in] numElems number of elements for this connection + */ + GEOS_HOST_DEVICE + StackVariables( localIndex const size, + localIndex numElems ): + Base::StackVariables( size, + numElems ) + {} + + using Base::StackVariables::localFlux; + using Base::StackVariables::localFluxJacobian; + using Base::StackVariables::dofColIndices; + using Base::StackVariables::transmissibility; + + /// Energy fluxes and derivatives wrt pressure and temperature + real64 energyFlux = 0.0; + real64 dEnergyFlux_dP = 0.0; + real64 dEnergyFlux_dT = 0.0; + }; + + /** + * @brief Compute the local Dirichlet face flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes + */ + GEOS_HOST_DEVICE + void computeFlux( localIndex const iconn, + StackVariables & stack ) const + { + Base::computeFlux( iconn, stack, [&] ( localIndex const er, + localIndex const esr, + localIndex const ei, + localIndex const kf, + real64 const & f, + real64 const & dF_dP, + real64 const & mobility_up, + real64 const & dMobility_dP_up ) + { + + // Compute the derivatives of the density wrt temperature + + real64 const dDens_dT = 0.5 * m_dDens_dTemp[er][esr][ei][0]; + + // Compute the derivatives of the phase potential difference wrt temperature + + real64 const dF_dT = -stack.transmissibility * dDens_dT * ( m_gravCoef[er][esr][ei] - m_faceGravCoef[kf] ); + + // Compute the (upwinded) energy flux + + real64 const flux = mobility_up * f; + real64 const enthalpy = m_enthalpy[er][esr][ei][0]; + stack.energyFlux += flux * enthalpy; + + // Compute the derivatives of the (upwinded) energy flux wrt pressure and temperature + + if( f >= 0 ) // the element is upstream + { + real64 const dFlux_dP = mobility_up * dF_dP + dMobility_dP_up * f; + real64 const dFlux_dT = mobility_up * dF_dT + m_dMob_dTemp[er][esr][ei] * f; + + stack.dEnergyFlux_dP += dFlux_dP * enthalpy + flux * m_dEnthalpy_dPres[er][esr][ei][0]; + stack.dEnergyFlux_dT += dFlux_dT * enthalpy + flux * m_dEnthalpy_dTemp[er][esr][ei][0]; + } + else + { + real64 const dFlux_dP = mobility_up * dF_dP; + real64 const dFlux_dT = mobility_up * dF_dT; + + stack.dEnergyFlux_dP += dFlux_dP * enthalpy; + stack.dEnergyFlux_dT += dFlux_dT * enthalpy; + } + + // Contribution of energy conduction through the solid phase + real64 thermalTrans = 0.0; + real64 dThermalTrans_dThermalCond[3]{}; + m_stencilWrapper.computeWeights( iconn, + m_thermalConductivity, + thermalTrans, + dThermalTrans_dThermalCond ); + + real64 const dThermalTrans_dT = LvArray::tensorOps::AiBi< 3 >( dThermalTrans_dThermalCond, m_dThermalCond_dT[er][esr][ei][0] ); + + real64 const deltaT = m_temp[er][esr][ei] - m_faceTemp[kf]; + stack.energyFlux += thermalTrans * deltaT; + stack.dEnergyFlux_dT += thermalTrans + dThermalTrans_dT * deltaT; + + // Add energyFlux and its derivatives to localFlux and localFluxJacobian + integer const localRowIndexEnergy = numEqn - 1; + stack.localFlux[localRowIndexEnergy] = m_dt * stack.energyFlux; + + stack.localFluxJacobian[localRowIndexEnergy][0] = m_dt * stack.dEnergyFlux_dP; + stack.localFluxJacobian[localRowIndexEnergy][numDof-1] = m_dt * stack.dEnergyFlux_dT; + } ); + + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void complete( localIndex const iconn, + StackVariables & stack ) const + { + Base::complete( iconn, stack, [&] ( localIndex const localRow ) + { + RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn - 1], stack.localFlux[numEqn-1] ); + + AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > + ( localRow + numEqn - 1, + stack.dofColIndices, + stack.localFluxJacobian[numEqn-1], + numDof ); + } ); + } + +protected: + + /// Views on temperature + ElementViewConst< arrayView1d< real64 const > > const m_temp; + + /// Views on face temperature + arrayView1d< real64 const > const m_faceTemp; + + /// Views on derivatives of fluid mobilities + ElementViewConst< arrayView1d< real64 const > > const m_dMob_dTemp; + + /// Views on derivatives of fluid densities + ElementViewConst< arrayView2d< real64 const > > const m_dDens_dTemp; + + /// Views on enthalpies + ElementViewConst< arrayView2d< real64 const > > const m_enthalpy; + ElementViewConst< arrayView2d< real64 const > > const m_dEnthalpy_dPres; + ElementViewConst< arrayView2d< real64 const > > const m_dEnthalpy_dTemp; + + /// View on thermal conductivity + ElementViewConst< arrayView3d< real64 const > > m_thermalConductivity; + + /// View on derivatives of thermal conductivity w.r.t. temperature + ElementViewConst< arrayView3d< real64 const > > m_dThermalCond_dT; + +}; + +/** + * @class DirichletFluxComputeKernelFactory + */ +class DirichletFluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] solverName name of the solver (to name accessors) + * @param[in] faceManager reference to the face manager + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the boundary stencil wrapper + * @param[in] fluidBase the single phase fluid constitutive model + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( globalIndex const rankOffset, + string const & dofKey, + string const & solverName, + FaceManager const & faceManager, + ElementRegionManager const & elemManager, + BoundaryStencilWrapper const & stencilWrapper, + constitutive::SingleFluidBase & fluidBase, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + constitutiveUpdatePassThru( fluidBase, [&]( auto & fluid ) + { + using FluidType = TYPEOFREF( fluid ); + typename FluidType::KernelWrapper fluidWrapper = fluid.createKernelWrapper(); + + integer constexpr NUM_DOF = 2; + integer constexpr NUM_EQN = 2; + + using kernelType = DirichletFluxComputeKernel< NUM_EQN, NUM_DOF, typename FluidType::KernelWrapper >; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + typename kernelType::SinglePhaseFlowAccessors singlePhaseFlowAccessors( elemManager, solverName ); + typename kernelType::ThermalSinglePhaseFlowAccessors thermalSinglePhaseFlowAccessors( elemManager, solverName ); + typename kernelType::SinglePhaseFluidAccessors singlePhaseFluidAccessors( elemManager, solverName ); + typename kernelType::ThermalSinglePhaseFluidAccessors thermalSinglePhaseFluidAccessors( elemManager, solverName ); + typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); + typename kernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName ); + + kernelType kernel( rankOffset, + faceManager, + stencilWrapper, + fluidWrapper, + dofNumberAccessor, + singlePhaseFlowAccessors, + thermalSinglePhaseFlowAccessors, + singlePhaseFluidAccessors, + thermalSinglePhaseFluidAccessors, + permeabilityAccessors, + thermalConductivityAccessors, + dt, + localMatrix, + localRhs ); + + kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); + } ); + } + +}; + +} // namespace thermalSinglePhaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalFluxComputeKernel.hpp new file mode 100644 index 00000000000..4dd02b5d35f --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalFluxComputeKernel.hpp @@ -0,0 +1,492 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALFLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp" + +#include "constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.hpp" +#include "constitutive/thermalConductivity/ThermalConductivityFields.hpp" + +namespace geos +{ + +namespace thermalSinglePhaseFVMKernels +{ +/******************************** FluxComputeKernel ********************************/ + +/** + * @class FluxComputeKernel + * @tparam NUM_DOF number of degrees of freedom + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NUM_EQN, integer NUM_DOF, typename STENCILWRAPPER > +class FluxComputeKernel : public singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER > +{ +public: + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; + using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; + using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; + + using AbstractBase::m_dt; + using AbstractBase::m_rankOffset; + using AbstractBase::m_dofNumber; + using AbstractBase::m_gravCoef; + using AbstractBase::m_mob; + using AbstractBase::m_dens; + + using Base = singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; + using Base::numDof; + using Base::numEqn; + using Base::maxNumElems; + using Base::maxNumConns; + using Base::maxStencilSize; + using Base::m_stencilWrapper; + using Base::m_seri; + using Base::m_sesri; + using Base::m_sei; + + using ThermalSinglePhaseFlowAccessors = + StencilAccessors< fields::flow::temperature, + fields::flow::dMobility_dTemperature >; + + using ThermalSinglePhaseFluidAccessors = + StencilMaterialAccessors< constitutive::SingleFluidBase, + fields::singlefluid::dDensity_dTemperature, + fields::singlefluid::enthalpy, + fields::singlefluid::dEnthalpy_dPressure, + fields::singlefluid::dEnthalpy_dTemperature >; + + using ThermalConductivityAccessors = + StencilMaterialAccessors< constitutive::SinglePhaseThermalConductivityBase, + fields::thermalconductivity::effectiveConductivity, + fields::thermalconductivity::dEffectiveConductivity_dT >; + + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor accessor for the dofs numbers + * @param[in] singlePhaseFlowAccessors accessor for wrappers registered by the solver + * @param[in] thermalSinglePhaseFlowAccessors accessor for *thermal* wrappers registered by the solver + * @param[in] singlePhaseFluidAccessors accessor for wrappers registered by the single fluid model + * @param[in] thermalSinglePhaseFluidAccessors accessor for *thermal* wrappers registered by the single fluid model + * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model + * @param[in] thermalConductivityAccessors accessor for wrappers registered by the thermal conductivity model + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + FluxComputeKernel( globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, + ThermalSinglePhaseFlowAccessors const & thermalSinglePhaseFlowAccessors, + SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, + ThermalSinglePhaseFluidAccessors const & thermalSinglePhaseFluidAccessors, + PermeabilityAccessors const & permeabilityAccessors, + ThermalConductivityAccessors const & thermalConductivityAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : Base( rankOffset, + stencilWrapper, + dofNumberAccessor, + singlePhaseFlowAccessors, + singlePhaseFluidAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs ), + m_temp( thermalSinglePhaseFlowAccessors.get( fields::flow::temperature {} ) ), + m_dMob_dTemp( thermalSinglePhaseFlowAccessors.get( fields::flow::dMobility_dTemperature {} ) ), + m_dDens_dTemp( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dDensity_dTemperature {} ) ), + m_enthalpy( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::enthalpy {} ) ), + m_dEnthalpy_dPres( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dEnthalpy_dPressure {} ) ), + m_dEnthalpy_dTemp( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dEnthalpy_dTemperature {} ) ), + m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ), + m_dThermalCond_dT( thermalConductivityAccessors.get( fields::thermalconductivity::dEffectiveConductivity_dT {} ) ) + {} + + struct StackVariables : public Base::StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables( localIndex const size, localIndex numElems ) + : Base::StackVariables( size, numElems ), + energyFlux( 0.0 ), + dEnergyFlux_dP( size ), + dEnergyFlux_dT( size ) + {} + + using Base::StackVariables::stencilSize; + using Base::StackVariables::numFluxElems; + using Base::StackVariables::transmissibility; + using Base::StackVariables::dTrans_dPres; + using Base::StackVariables::dofColIndices; + using Base::StackVariables::localFlux; + using Base::StackVariables::localFluxJacobian; + + // Thermal transmissibility + real64 thermalTransmissibility[maxNumConns][2]{}; + + /// Derivatives of thermal transmissibility with respect to temperature + real64 dThermalTrans_dT[maxNumConns][2]{}; + + // Energy fluxes and derivatives + + /// Energy fluxes + real64 energyFlux; + /// Derivatives of energy fluxes wrt pressure + stackArray1d< real64, maxStencilSize > dEnergyFlux_dP; + /// Derivatives of energy fluxes wrt temperature + stackArray1d< real64, maxStencilSize > dEnergyFlux_dT; + + }; + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeFlux( localIndex const iconn, + StackVariables & stack ) const + { + // *********************************************** + // First, we call the base computeFlux to compute: + // 1) compFlux and its derivatives (including derivatives wrt temperature), + // 2) enthalpy part of energyFlux and its derivatives (including derivatives wrt temperature) + // + // Computing dFlux_dT and the enthalpy flux requires quantities already computed in the base computeFlux, + // such as potGrad, fluxVal, and the indices of the upwind cell + // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables + Base::computeFlux( iconn, stack, [&] ( localIndex const (&k)[2], + localIndex const (&seri)[2], + localIndex const (&sesri)[2], + localIndex const (&sei)[2], + localIndex const connectionIndex, + real64 const alpha, + real64 const mobility, + real64 const & potGrad, + real64 const & fluxVal, + real64 const (&dFlux_dP)[2] ) + { + // Step 1: compute the derivatives of the mean density at the interface wrt temperature + + real64 dDensMean_dT[2]{0.0, 0.0}; + + real64 const trans[2] = { stack.transmissibility[connectionIndex][0], stack.transmissibility[connectionIndex][1] }; + + for( integer ke = 0; ke < 2; ++ke ) + { + real64 const dDens_dT = m_dDens_dTemp[seri[ke]][sesri[ke]][sei[ke]][0]; + dDensMean_dT[ke] = 0.5 * dDens_dT; + } + + // Step 2: compute the derivatives of the potential difference wrt temperature + //***** calculation of flux ***** + + real64 dGravHead_dT[2]{0.0, 0.0}; + + // compute potential difference + for( integer ke = 0; ke < 2; ++ke ) + { + localIndex const er = seri[ke]; + localIndex const esr = sesri[ke]; + localIndex const ei = sei[ke]; + + // compute derivative of gravity potential difference wrt temperature + real64 const gravD = trans[ke] * m_gravCoef[er][esr][ei]; + + for( integer i = 0; i < 2; ++i ) + { + dGravHead_dT[i] += dDensMean_dT[i] * gravD; + } + } + + // Step 3: compute the derivatives of the (upwinded) compFlux wrt temperature + // *** upwinding *** + + real64 dFlux_dT[2]{0.0, 0.0}; + + // Step 3.1: compute the derivative of flux wrt temperature + for( integer ke = 0; ke < 2; ++ke ) + { + dFlux_dT[ke] -= dGravHead_dT[ke]; + } + + for( integer ke = 0; ke < 2; ++ke ) + { + dFlux_dT[ke] *= mobility; + } + + real64 dMob_dT[2]{}; + + if( alpha <= 0.0 || alpha >= 1.0 ) + { + localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) ); + + dMob_dT[k_up] = m_dMob_dTemp[seri[k_up]][sesri[k_up]][sei[k_up]]; + } + else + { + real64 const mobWeights[2] = { alpha, 1.0 - alpha }; + for( integer ke = 0; ke < 2; ++ke ) + { + dMob_dT[ke] = mobWeights[ke] * m_dMob_dTemp[seri[ke]][sesri[ke]][sei[ke]]; + } + } + + // add contribution from upstream cell mobility derivatives + for( integer ke = 0; ke < 2; ++ke ) + { + dFlux_dT[ke] += dMob_dT[ke] * potGrad; + } + + // add dFlux_dTemp to localFluxJacobian + for( integer ke = 0; ke < 2; ++ke ) + { + localIndex const localDofIndexTemp = k[ke] * numDof + numDof - 1; + stack.localFluxJacobian[k[0]*numEqn][localDofIndexTemp] += m_dt * dFlux_dT[ke]; + stack.localFluxJacobian[k[1]*numEqn][localDofIndexTemp] -= m_dt * dFlux_dT[ke]; + } + + // Step 4: compute the enthalpy flux + real64 enthalpy = 0.0; + real64 dEnthalpy_dP[2]{0.0, 0.0}; + real64 dEnthalpy_dT[2]{0.0, 0.0}; + + if( alpha <= 0.0 || alpha >= 1.0 ) + { + localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) ); + + enthalpy = m_enthalpy[seri[k_up]][sesri[k_up]][sei[k_up]][0]; + dEnthalpy_dP[k_up] = m_dEnthalpy_dPres[seri[k_up]][sesri[k_up]][sei[k_up]][0]; + dEnthalpy_dT[k_up] = m_dEnthalpy_dTemp[seri[k_up]][sesri[k_up]][sei[k_up]][0]; + } + else + { + real64 const mobWeights[2] = { alpha, 1.0 - alpha }; + for( integer ke = 0; ke < 2; ++ke ) + { + enthalpy += mobWeights[ke] * m_enthalpy[seri[ke]][sesri[ke]][sei[ke]][0]; + dEnthalpy_dP[ke] = mobWeights[ke] * m_dEnthalpy_dPres[seri[ke]][sesri[ke]][sei[ke]][0]; + dEnthalpy_dT[ke] = mobWeights[ke] * m_dEnthalpy_dTemp[seri[ke]][sesri[ke]][sei[ke]][0]; + } + } + + stack.energyFlux += fluxVal * enthalpy; + + for( integer ke = 0; ke < 2; ++ke ) + { + stack.dEnergyFlux_dP[ke] += dFlux_dP[ke] * enthalpy; + stack.dEnergyFlux_dT[ke] += dFlux_dT[ke] * enthalpy; + } + + for( integer ke = 0; ke < 2; ++ke ) + { + stack.dEnergyFlux_dP[ke] += fluxVal * dEnthalpy_dP[ke]; + stack.dEnergyFlux_dT[ke] += fluxVal * dEnthalpy_dT[ke]; + } + + } ); + + // ***************************************************** + // Computation of the conduction term in the energy flux + // Note that the enthalpy term in the energy was computed above + // Note that this term is computed using an explicit treatment of conductivity for now + + // Step 1: compute the thermal transmissibilities at this face + // We follow how the thermal compositional multi-phase solver does to update the thermal transmissibility + m_stencilWrapper.computeWeights( iconn, + m_thermalConductivity, + m_dThermalCond_dT, + stack.thermalTransmissibility, + stack.dThermalTrans_dT ); + + localIndex k[2]; + localIndex connectionIndex = 0; + + for( k[0] = 0; k[0] < stack.numFluxElems; ++k[0] ) + { + for( k[1] = k[0] + 1; k[1] < stack.numFluxElems; ++k[1] ) + { + real64 const thermalTrans[2] = { stack.thermalTransmissibility[connectionIndex][0], stack.thermalTransmissibility[connectionIndex][1] }; + real64 const dThermalTrans_dT[2] = { stack.dThermalTrans_dT[connectionIndex][0], stack.dThermalTrans_dT[connectionIndex][1] }; + + localIndex const seri[2] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; + localIndex const sesri[2] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; + localIndex const sei[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; + + // Step 2: compute temperature difference at the interface + for( integer ke = 0; ke < 2; ++ke ) + { + localIndex const er = seri[ke]; + localIndex const esr = sesri[ke]; + localIndex const ei = sei[ke]; + + stack.energyFlux += thermalTrans[ke] * m_temp[er][esr][ei]; + stack.dEnergyFlux_dT[ke] += thermalTrans[ke] + dThermalTrans_dT[ke] * m_temp[er][esr][ei]; + } + + // add energyFlux and its derivatives to localFlux and localFluxJacobian + stack.localFlux[k[0]*numEqn + numEqn - 1] += m_dt * stack.energyFlux; + stack.localFlux[k[1]*numEqn + numEqn - 1] -= m_dt * stack.energyFlux; + + for( integer ke = 0; ke < 2; ++ke ) + { + integer const localDofIndexPres = k[ke] * numDof; + stack.localFluxJacobian[k[0]*numEqn + numEqn - 1][localDofIndexPres] = m_dt * stack.dEnergyFlux_dP[ke]; + stack.localFluxJacobian[k[1]*numEqn + numEqn - 1][localDofIndexPres] = -m_dt * stack.dEnergyFlux_dP[ke]; + integer const localDofIndexTemp = localDofIndexPres + numDof - 1; + stack.localFluxJacobian[k[0]*numEqn + numEqn - 1][localDofIndexTemp] = m_dt * stack.dEnergyFlux_dT[ke]; + stack.localFluxJacobian[k[1]*numEqn + numEqn - 1][localDofIndexTemp] = -m_dt * stack.dEnergyFlux_dT[ke]; + } + + connectionIndex++; + } + } + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void complete( localIndex const iconn, + StackVariables & stack ) const + { + // Call Case::complete to assemble the mass balance equations + // In the lambda, add contribution to residual and jacobian into the energy balance equation + Base::complete( iconn, stack, [&] ( integer const i, + localIndex const localRow ) + { + // The no. of fluxes is equal to the no. of equations in m_localRhs and m_localMatrix + // Different from the one in compositional multi-phase flow, which has a volume balance eqn. + RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn-1], stack.localFlux[i * numEqn + numEqn-1] ); + + AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( localRow + numEqn-1, + stack.dofColIndices.data(), + stack.localFluxJacobian[i * numEqn + numEqn-1].dataIfContiguous(), + stack.stencilSize * numDof ); + + } ); + } + +protected: + + /// Views on temperature + ElementViewConst< arrayView1d< real64 const > > const m_temp; + + /// Views on derivatives of fluid mobilities + ElementViewConst< arrayView1d< real64 const > > const m_dMob_dTemp; + + /// Views on derivatives of fluid densities + ElementViewConst< arrayView2d< real64 const > > const m_dDens_dTemp; + + /// Views on enthalpies + ElementViewConst< arrayView2d< real64 const > > const m_enthalpy; + ElementViewConst< arrayView2d< real64 const > > const m_dEnthalpy_dPres; + ElementViewConst< arrayView2d< real64 const > > const m_dEnthalpy_dTemp; + + /// View on thermal conductivity + ElementViewConst< arrayView3d< real64 const > > m_thermalConductivity; + + /// View on derivatives of thermal conductivity w.r.t. temperature + ElementViewConst< arrayView3d< real64 const > > m_dThermalCond_dT; + +}; + +/** + * @class FluxComputeKernelFactory + */ +class FluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] solverName name of the solver (to name accessors) + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( globalIndex const rankOffset, + string const & dofKey, + string const & solverName, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + integer constexpr NUM_DOF = 2; + integer constexpr NUM_EQN = 2; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + using KernelType = FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; + typename KernelType::SinglePhaseFlowAccessors flowAccessors( elemManager, solverName ); + typename KernelType::ThermalSinglePhaseFlowAccessors thermalFlowAccessors( elemManager, solverName ); + typename KernelType::SinglePhaseFluidAccessors fluidAccessors( elemManager, solverName ); + typename KernelType::ThermalSinglePhaseFluidAccessors thermalFluidAccessors( elemManager, solverName ); + typename KernelType::PermeabilityAccessors permAccessors( elemManager, solverName ); + typename KernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName ); + + KernelType kernel( rankOffset, stencilWrapper, dofNumberAccessor, + flowAccessors, thermalFlowAccessors, fluidAccessors, thermalFluidAccessors, + permAccessors, thermalConductivityAccessors, + dt, localMatrix, localRhs ); + KernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); + } +}; + +} // namespace thermalSinglePhaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantBaseKernels.hpp new file mode 100644 index 00000000000..f18d8befbf9 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantBaseKernels.hpp @@ -0,0 +1,64 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SinglePhaseProppantBaseKernels.hpp + */ +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_PROPPANTBASEKERNELS_HPP_ +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_PROPPANTBASEKERNELS_HPP_ + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace singlePhaseProppantBaseKernels +{ + +/******************************** FluidUpdateKernel ********************************/ + +struct FluidUpdateKernel +{ + template< typename FLUID_WRAPPER > + static void launch( FLUID_WRAPPER const & fluidWrapper, + arrayView1d< real64 const > const & pres, + arrayView1d< real64 const > const & proppantConcentration, + arrayView2d< real64 const > const & componentConcentration, + arrayView2d< real64 const > const & cellBasedFlux, + arrayView1d< integer const > const & isProppantBoundaryElement ) + { + forAll< parallelDevicePolicy<> >( fluidWrapper.numElems(), [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + + for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) + { + + fluidWrapper.update( a, q, + pres[a], + proppantConcentration[a], + componentConcentration[a], + LvArray::tensorOps::l2Norm< 3 >( cellBasedFlux[a] ), + isProppantBoundaryElement[a] ); + } + } ); + } +}; + +} // namespace singlePhaseProppantBaseKernels + +} //namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_PROPPANTBASEKERNELS_HPP_ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.cpp new file mode 100644 index 00000000000..9843c0fc5ab --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.cpp @@ -0,0 +1,226 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ProppantFluxKernels.cpp + */ + +#include "ProppantFluxKernels.hpp" + +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp" + +namespace geos +{ + +namespace singlePhaseProppantFluxKernels +{ + +using namespace singlePhaseFluxKernelsHelper; + + +void FaceElementFluxKernel:: + launch( SurfaceElementStencilWrapper const & stencilWrapper, + real64 const dt, + globalIndex const rankOffset, + ElementViewConst< arrayView1d< globalIndex const > > const & pressureDofNumber, + ElementViewConst< arrayView1d< integer const > > const & ghostRank, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const > > const & dens, + ElementViewConst< arrayView2d< real64 const > > const & dDens_dPres, + ElementViewConst< arrayView1d< real64 const > > const & mob, + ElementViewConst< arrayView1d< real64 const > > const & dMob_dPres, + ElementViewConst< arrayView3d< real64 const > > const & permeability, + ElementViewConst< arrayView3d< real64 const > > const & dPerm_dPres, + ElementViewConst< arrayView4d< real64 const > > const & dPerm_dDispJump, + ElementViewConst< arrayView3d< real64 const > > const & permeabilityMultiplier, + R1Tensor const & gravityVector, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + constexpr localIndex maxNumFluxElems = SurfaceElementStencilWrapper::maxNumPointsInFlux; + constexpr localIndex maxStencilSize = SurfaceElementStencilWrapper::maxStencilSize; + constexpr localIndex maxNumConnections = SurfaceElementStencilWrapper::maxNumConnections; + + typename SurfaceElementStencilWrapper::IndexContainerViewConstType const & seri = stencilWrapper.getElementRegionIndices(); + typename SurfaceElementStencilWrapper::IndexContainerViewConstType const & sesri = stencilWrapper.getElementSubRegionIndices(); + typename SurfaceElementStencilWrapper::IndexContainerViewConstType const & sei = stencilWrapper.getElementIndices(); + + forAll< parallelDevicePolicy<> >( stencilWrapper.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + localIndex const stencilSize = stencilWrapper.stencilSize( iconn ); + localIndex const numFluxElems = stencilWrapper.numPointsInFlux( iconn ); + localIndex const numDofs = stencilSize; // pressures + + // For now, we have to filter out connections for which numElems == 1 in this function and not early on in + // TwoPointFluxApproximation.cpp. + // The reason for keeping the connections numElems == 1 is that the ProppantTransport solver needs these connections to produce correct + // results. + if( numFluxElems > 1 ) + { + + // working arrays + stackArray1d< globalIndex, maxNumFluxElems > dofColIndices( numDofs ); + stackArray1d< localIndex, maxNumFluxElems > localColIndices( numFluxElems ); + + stackArray1d< real64, maxNumFluxElems > localFlux( numFluxElems ); + stackArray2d< real64, maxNumFluxElems * maxStencilSize > localFluxJacobian( numFluxElems, numDofs ); + + // need to store this for later use in determining the dFlux_dU terms when using better permeabilty approximations. + stackArray2d< real64, maxNumFluxElems * maxStencilSize > dFlux_dAper( numFluxElems, stencilSize ); + + // compute transmissibility + real64 transmissibility[maxNumConnections][2]{}; + real64 dTrans_dPres[maxNumConnections][2]{}; + real64 dTrans_dDispJump[maxNumConnections][2][3]{}; + + GEOS_UNUSED_VAR( dPerm_dPres, dPerm_dDispJump ); + stencilWrapper.computeWeights( iconn, + permeability, + permeabilityMultiplier, + gravityVector, + transmissibility ); + + compute( stencilSize, + seri[iconn], + sesri[iconn], + sei[iconn], + transmissibility, + dTrans_dPres, + dTrans_dDispJump, + pres, + gravCoef, + dens, + dDens_dPres, + mob, + dMob_dPres, + dt, + localFlux, + localFluxJacobian, + dFlux_dAper ); + + // extract DOF numbers + for( localIndex i = 0; i < numDofs; ++i ) + { + dofColIndices[i] = pressureDofNumber[seri( iconn, i )][sesri( iconn, i )][sei( iconn, i )]; + localColIndices[i] = sei( iconn, i ); + } + + for( localIndex i = 0; i < numFluxElems; ++i ) + { + if( ghostRank[seri( iconn, i )][sesri( iconn, i )][sei( iconn, i )] < 0 ) + { + globalIndex const globalRow = pressureDofNumber[seri( iconn, i )][sesri( iconn, i )][sei( iconn, i )]; + localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - rankOffset ); + GEOS_ASSERT_GE( localRow, 0 ); + GEOS_ASSERT_GT( localMatrix.numRows(), localRow ); + + RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[localRow], localFlux[i] ); + localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( localRow, + dofColIndices.data(), + localFluxJacobian[i].dataIfContiguous(), + stencilSize ); + + } + } + } + } ); + +} + + +template< localIndex MAX_NUM_CONNECTIONS > +GEOS_HOST_DEVICE +void +FaceElementFluxKernel::compute( localIndex const numFluxElems, + arraySlice1d< localIndex const > const & seri, + arraySlice1d< localIndex const > const & sesri, + arraySlice1d< localIndex const > const & sei, + real64 const (&transmissibility)[MAX_NUM_CONNECTIONS][2], + real64 const (&dTrans_dPres)[MAX_NUM_CONNECTIONS][2], + real64 const (&dTrans_dDispJump)[MAX_NUM_CONNECTIONS][2][3], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const > > const & dens, + ElementViewConst< arrayView2d< real64 const > > const & dDens_dPres, + ElementViewConst< arrayView1d< real64 const > > const & mob, + ElementViewConst< arrayView1d< real64 const > > const & dMob_dPres, + real64 const dt, + arraySlice1d< real64 > const & flux, + arraySlice2d< real64 > const & fluxJacobian, + arraySlice2d< real64 > const & dFlux_dAperture ) +{ + + localIndex k[2]; + localIndex connectionIndex = 0; + for( k[0]=0; k[0] + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + + /** + * @brief launches the kernel to assemble the flux contributions to the linear system. + * @tparam SurfaceElementStencilWrapper The type of the stencil that is being used. + * @param[in] stencil The stencil object. + * @param[in] dt The timestep for the integration step. + * @param[in] dofNumber The dofNumbers for each element + * @param[in] pres The pressures in each element + * @param[in] gravCoef The factor for gravity calculations (g*H) + * @param[in] dens The material density in each element + * @param[in] dDens_dPres The change in material density for each element + * @param[in] mob The fluid mobility in each element + * @param[in] dMob_dPres The derivative of mobility wrt pressure in each element + * @param[in] permeability + * @param[in] dPerm_dPres The derivative of permeability wrt pressure in each element + * @param[in] permeabilityMultiplier + * @param[in] gravityVector + * @param[out] localMatrix The linear system matrix + * @param[out] localRhs The linear system residual + */ + static void + launch( SurfaceElementStencilWrapper const & stencilWrapper, + real64 const dt, + globalIndex const rankOffset, + ElementViewConst< arrayView1d< globalIndex const > > const & pressureDofNumber, + ElementViewConst< arrayView1d< integer const > > const & ghostRank, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const > > const & dens, + ElementViewConst< arrayView2d< real64 const > > const & dDens_dPres, + ElementViewConst< arrayView1d< real64 const > > const & mob, + ElementViewConst< arrayView1d< real64 const > > const & dMob_dPres, + ElementViewConst< arrayView3d< real64 const > > const & permeability, + ElementViewConst< arrayView3d< real64 const > > const & dPerm_dPres, + ElementViewConst< arrayView4d< real64 const > > const & dPerm_dDispJump, + ElementViewConst< arrayView3d< real64 const > > const & permeabilityMultiplier, + R1Tensor const & gravityVector, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); + + + /** + * @brief Compute flux and its derivatives for a given tpfa connector. + * + * + */ + template< localIndex MAX_NUM_CONNECTIONS > + GEOS_HOST_DEVICE + static void + compute( localIndex const numFluxElems, + arraySlice1d< localIndex const > const & seri, + arraySlice1d< localIndex const > const & sesri, + arraySlice1d< localIndex const > const & sei, + real64 const (&transmissibility)[MAX_NUM_CONNECTIONS][2], + real64 const (&dTrans_dPres)[MAX_NUM_CONNECTIONS][2], + real64 const (&dTrans_dDispJump)[MAX_NUM_CONNECTIONS][2][3], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const > > const & dens, + ElementViewConst< arrayView2d< real64 const > > const & dDens_dPres, + ElementViewConst< arrayView1d< real64 const > > const & mob, + ElementViewConst< arrayView1d< real64 const > > const & dMob_dPres, + real64 const dt, + arraySlice1d< real64 > const & flux, + arraySlice2d< real64 > const & fluxJacobian, + arraySlice2d< real64 > const & dFlux_dAperture ); +}; + + +} // namespace singlePhaseProppantFluxKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_MULTIPHYSICS_SINGLEPHASEPROPPANTFLUXKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransport.cpp b/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransport.cpp index be24ccd834d..798286fc9e0 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransport.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransport.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -35,9 +36,11 @@ #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/proppantTransport/ProppantTransportFields.hpp" #include "physicsSolvers/fluidFlow/proppantTransport/ProppantTransportKernels.hpp" +#include "mesh/MeshFields.hpp" + /** - * @namespace the geosx namespace that encapsulates the majority of the code + * @namespace the geos namespace that encapsulates the majority of the code */ namespace geos { @@ -80,9 +83,9 @@ ProppantTransport::ProppantTransport( const string & name, } -void ProppantTransport::postProcessInput() +void ProppantTransport::postInputInitialization() { - FlowSolverBase::postProcessInput(); + FlowSolverBase::postInputInitialization(); } void ProppantTransport::registerDataOnMesh( Group & meshBodies ) @@ -286,7 +289,7 @@ void ProppantTransport::updateProppantMobility( ObjectManagerBase & dataGroup ) GEOS_MARK_FUNCTION; arrayView1d< real64 const > const conc = dataGroup.getField< fields::proppant::proppantConcentration >(); - arrayView1d< real64 const > const aperture = dataGroup.getReference< array1d< real64 > >( FaceElementSubRegion::viewKeyStruct::elementApertureString() ); + arrayView1d< real64 const > const aperture = dataGroup.getReference< array1d< real64 > >( fields::elementAperture::key() ); arrayView1d< integer > const isProppantMobile = dataGroup.getField< fields::proppant::isProppantMobile >(); real64 const minAperture = m_minAperture; @@ -832,7 +835,7 @@ ProppantTransport::calculateResidualNorm( real64 const & GEOS_UNUSED_PARAM( time real64 localResidualNorm = 0.0; real64 localResidualNormalizer = 0.0; - solverBaseKernels::NormType const normType = getNonlinearSolverParameters().normType(); + physicsSolverBaseKernels::NormType const normType = getNonlinearSolverParameters().normType(); localIndex const rankOffset = dofManager.rankOffset(); string const dofKey = dofManager.getKey( fields::proppant::proppantConcentration::key() ); @@ -864,7 +867,7 @@ ProppantTransport::calculateResidualNorm( real64 const & GEOS_UNUSED_PARAM( time // step 2: first reduction across meshBodies/regions/subRegions - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { if( subRegionResidualNorm[0] > localResidualNorm ) { @@ -882,13 +885,13 @@ ProppantTransport::calculateResidualNorm( real64 const & GEOS_UNUSED_PARAM( time // step 3: second reduction across MPI ranks real64 residualNorm = 0.0; - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { - solverBaseKernels::LinfResidualNormHelper::computeGlobalNorm( localResidualNorm, residualNorm ); + physicsSolverBaseKernels::LinfResidualNormHelper::computeGlobalNorm( localResidualNorm, residualNorm ); } else { - solverBaseKernels::L2ResidualNormHelper::computeGlobalNorm( localResidualNorm, localResidualNormalizer, residualNorm ); + physicsSolverBaseKernels::L2ResidualNormHelper::computeGlobalNorm( localResidualNorm, localResidualNormalizer, residualNorm ); } if( getLogLevel() >= 1 && logger::internal::rank == 0 ) @@ -1054,7 +1057,7 @@ void ProppantTransport::updateProppantPackVolume( real64 const GEOS_UNUSED_PARAM elemManager.constructViewAccessor< array1d< real64 >, arrayView1d< real64 > >( fields::proppant::proppantLiftFlux::key() ); ElementRegionManager::ElementViewAccessor< arrayView1d< real64 const > > const - aperture = elemManager.constructArrayViewAccessor< real64, 1 >( FaceElementSubRegion::viewKeyStruct::elementApertureString() ); + aperture = elemManager.constructArrayViewAccessor< real64, 1 >( fields::elementAperture::key() ); typename ProppantPackVolumeKernel::FlowAccessors flowAccessors( elemManager, getName() ); typename ProppantPackVolumeKernel::SlurryFluidAccessors slurryFluidAccessors( elemManager, getName() ); @@ -1138,5 +1141,5 @@ void ProppantTransport::updateProppantPackVolume( real64 const GEOS_UNUSED_PARAM } -REGISTER_CATALOG_ENTRY( SolverBase, ProppantTransport, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, ProppantTransport, string const &, Group * const ) } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransport.hpp b/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransport.hpp index a1386b39381..3332d1e6a41 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransport.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransport.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -81,7 +82,7 @@ class ProppantTransport : public FlowSolverBase */ static string catalogName() { return "ProppantTransport"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -216,7 +217,7 @@ class ProppantTransport : public FlowSolverBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; private: diff --git a/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransportFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransportFields.hpp index ad416b39534..b96b212fe71 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransportFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransportFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransportKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransportKernels.cpp index 2c21074f9d0..c74004bafb4 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransportKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransportKernels.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransportKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransportKernels.hpp index c1da68e00a0..f857e3f6bba 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransportKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/proppantTransport/ProppantTransportKernels.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -32,15 +33,13 @@ #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/proppantTransport/ProppantTransportFields.hpp" #include "physicsSolvers/fluidFlow/StencilAccessors.hpp" -#include "physicsSolvers/SolverBaseKernels.hpp" +#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" namespace geos { namespace proppantTransportKernels { -using namespace constitutive; - /******************************** FluidUpdateKernel ********************************/ struct FluidUpdateKernel @@ -190,7 +189,7 @@ struct FluxKernel fields::elementAperture >; using ParticleFluidAccessors = - StencilMaterialAccessors< ParticleFluidBase, + StencilMaterialAccessors< constitutive::ParticleFluidBase, fields::particlefluid::settlingFactor, fields::particlefluid::dSettlingFactor_dPressure, fields::particlefluid::dSettlingFactor_dProppantConcentration, @@ -199,7 +198,7 @@ struct FluxKernel fields::particlefluid::dCollisionFactor_dProppantConcentration >; using SlurryFluidAccessors = - StencilMaterialAccessors< SlurryFluidBase, + StencilMaterialAccessors< constitutive::SlurryFluidBase, fields::singlefluid::density, fields::singlefluid::dDensity_dPressure, fields::slurryfluid::dDensity_dProppantConcentration, @@ -216,12 +215,12 @@ struct FluxKernel fields::slurryfluid::dFluidDensity_dComponentConcentration >; using CellBasedFluxSlurryFluidAccessors = - StencilMaterialAccessors< SlurryFluidBase, + StencilMaterialAccessors< constitutive::SlurryFluidBase, fields::singlefluid::density, fields::singlefluid::viscosity >; using PermeabilityAccessors = - StencilMaterialAccessors< PermeabilityBase, + StencilMaterialAccessors< constitutive::PermeabilityBase, fields::permeability::permeability, fields::permeability::permeabilityMultiplier >; @@ -361,10 +360,10 @@ struct ProppantPackVolumeKernel fields::proppant::isProppantBoundary >; using ParticleFluidAccessors = - StencilMaterialAccessors< ParticleFluidBase, fields::particlefluid::settlingFactor >; + StencilMaterialAccessors< constitutive::ParticleFluidBase, fields::particlefluid::settlingFactor >; using SlurryFluidAccessors = - StencilMaterialAccessors< SlurryFluidBase, + StencilMaterialAccessors< constitutive::SlurryFluidBase, fields::singlefluid::density, fields::slurryfluid::fluidDensity, fields::slurryfluid::fluidViscosity >; @@ -460,11 +459,11 @@ struct ProppantPackVolumeKernel /** * @class ResidualNormKernel */ -class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > +class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 1 > { public: - using Base = solverBaseKernels::ResidualNormKernelBase< 1 >; + using Base = physicsSolverBaseKernels::ResidualNormKernelBase< 1 >; using Base::m_minNormalizer; using Base::m_rankOffset; using Base::m_localResidual; @@ -544,7 +543,7 @@ class ResidualNormKernelFactory */ template< typename POLICY > static void - createAndLaunch( solverBaseKernels::NormType const normType, + createAndLaunch( physicsSolverBaseKernels::NormType const normType, integer const numComp, globalIndex const rankOffset, string const & dofKey, @@ -559,7 +558,7 @@ class ResidualNormKernelFactory ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, numComp, subRegion, minNormalizer ); - if( normType == solverBaseKernels::NormType::Linf ) + if( normType == physicsSolverBaseKernels::NormType::Linf ) { ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 6620d93c277..1f13044d87d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,7 +19,6 @@ #include "CompositionalMultiphaseWell.hpp" - #include "codingUtilities/Utilities.hpp" #include "common/DataTypes.hpp" #include "common/FieldSpecificationOps.hpp" @@ -34,13 +34,22 @@ #include "mesh/PerforationFields.hpp" #include "mesh/WellElementSubRegion.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" -#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" -#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" -#include "physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/wells/WellFields.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" +#include "physicsSolvers/fluidFlow/wells/LogLevelsInfo.hpp" +#include "physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp" +#include "physicsSolvers/fluidFlow/wells/kernels/ThermalCompositionalMultiphaseWellKernels.hpp" +#include "physicsSolvers/fluidFlow/wells/kernels/PerforationFluxKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionScalingKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/GlobalComponentFractionKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/FluidUpdateKernel.hpp" #if defined( __INTEL_COMPILER ) #pragma GCC optimize "O0" @@ -51,14 +60,11 @@ namespace geos using namespace dataRepository; using namespace constitutive; -using namespace compositionalMultiphaseWellKernels; CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name, Group * const parent ) : WellSolverBase( name, parent ), - m_numPhases( 0 ), - m_numComponents( 0 ), m_useMass( false ), m_useTotalMassEquation( 1 ), m_maxCompFracChange( 1.0 ), @@ -73,8 +79,8 @@ CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name, setInputFlag( InputFlags::OPTIONAL ). setDescription( "Use mass formulation instead of molar" ); - this->registerWrapper( viewKeyStruct::useMassFlagString(), &m_useTotalMassEquation ). - setApplyDefaultValue( 0 ). + this->registerWrapper( viewKeyStruct::useTotalMassEquationString(), &m_useTotalMassEquation ). + setApplyDefaultValue( 1 ). setInputFlag( InputFlags::OPTIONAL ). setDescription( "Use total mass equation" ); @@ -84,6 +90,12 @@ CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name, setApplyDefaultValue( 1.0 ). setDescription( "Maximum (absolute) change in a component fraction between two Newton iterations" ); + this->registerWrapper( viewKeyStruct::maxRelativeCompDensChangeString(), &m_maxRelativeCompDensChange ). + setSizedFromParent( 0 ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( LvArray::NumericLimits< real64 >::max/1.0e100 ). // disabled by default + setDescription( "Maximum (relative) change in a component density between two Newton iterations" ); + this->registerWrapper( viewKeyStruct::maxRelativePresChangeString(), &m_maxRelativePresChange ). setSizedFromParent( 0 ). setInputFlag( InputFlags::OPTIONAL ). @@ -96,6 +108,12 @@ CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name, setApplyDefaultValue( -1.0 ). // disabled by default setDescription( "Maximum (absolute) pressure change in a Newton iteration" ); + this->registerWrapper( viewKeyStruct::maxRelativeTempChangeString(), &m_maxRelativeTempChange ). + setSizedFromParent( 0 ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( 1.0 ). + setDescription( "Maximum (relative) change in temperature between two Newton iterations " ); + this->registerWrapper( viewKeyStruct::allowLocalCompDensChoppingString(), &m_allowCompDensChopping ). setSizedFromParent( 0 ). setInputFlag( InputFlags::OPTIONAL ). @@ -103,9 +121,9 @@ CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name, setDescription( "Flag indicating whether local (cell-wise) chopping of negative compositions is allowed" ); } -void CompositionalMultiphaseWell::postProcessInput() +void CompositionalMultiphaseWell::postInputInitialization() { - WellSolverBase::postProcessInput(); + WellSolverBase::postInputInitialization(); GEOS_ERROR_IF_GT_MSG( m_maxCompFracChange, 1.0, getWrapperDataContext( viewKeyStruct::maxCompFracChangeString() ) << @@ -114,6 +132,9 @@ void CompositionalMultiphaseWell::postProcessInput() getWrapperDataContext( viewKeyStruct::maxCompFracChangeString() ) << ": The maximum absolute change in component fraction must larger or equal to 0.0" ); + GEOS_ERROR_IF_LE_MSG( m_maxRelativeCompDensChange, 0.0, + getWrapperDataContext( viewKeyStruct::maxRelativeCompDensChangeString() ) << + ": The maximum relative change in component density must be larger than 0.0" ); } void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) @@ -146,8 +167,9 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) m_numPhases = fluid0.numFluidPhases(); m_numComponents = fluid0.numFluidComponents(); } - m_numDofPerWellElement = m_numComponents + 2; // 1 pressure + NC compositions + 1 connectionRate - m_numDofPerResElement = m_numComponents + 1; // 1 pressure + NC compositions + m_numDofPerWellElement = isThermal() ? m_numComponents + 3 : m_numComponents + 2; // 1 pressure + NC compositions + 1 connectionRate + + // temp if thermal + m_numDofPerResElement = isThermal() ? m_numComponents + 2 : m_numComponents + 1; // 1 pressure + NC compositions + temp if thermal // loop over the wells forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, @@ -162,15 +184,11 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) WellElementSubRegion & subRegion ) { string const & fluidName = getConstitutiveName< MultiFluidBase >( subRegion ); + GEOS_ERROR_IF( fluidName.empty(), GEOS_FMT( "{}: Fluid model not found on subregion {}", + getDataContext(), subRegion.getName() ) ); MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - subRegion.registerField< fields::well::pressure >( getName() ); - subRegion.registerField< fields::well::pressure_n >( getName() ); - - subRegion.registerField< fields::well::temperature >( getName() ); - subRegion.registerField< fields::well::temperature_n >( getName() ); - // The resizing of the arrays needs to happen here, before the call to initializePreSubGroups, // to make sure that the dimensions are properly set before the timeHistoryOutput starts its initialization. @@ -195,9 +213,8 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) reference().resizeDimension< 1, 2 >( m_numPhases, m_numComponents + 2 ); // dP, dT, dC subRegion.registerField< fields::well::totalMassDensity >( getName() ); - subRegion.registerField< fields::well::dTotalMassDensity_dPressure >( getName() ); - subRegion.registerField< fields::well::dTotalMassDensity_dGlobalCompDensity >( getName() ). - reference().resizeDimension< 1 >( m_numComponents ); + subRegion.registerField< fields::well::dTotalMassDensity >( getName() ). + reference().resizeDimension< 1 >( m_numComponents +2 ); // dP, dT, dC subRegion.registerField< fields::well::phaseVolumeFraction_n >( getName() ). reference().resizeDimension< 1 >( m_numPhases ); @@ -209,45 +226,39 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) PerforationData & perforationData = *subRegion.getPerforationData(); perforationData.registerField< fields::well::compPerforationRate >( getName() ). reference().resizeDimension< 1 >( m_numComponents ); - perforationData.registerField< fields::well::dCompPerforationRate_dPres >( getName() ). - reference().resizeDimension< 1, 2 >( 2, m_numComponents ); - perforationData.registerField< fields::well::dCompPerforationRate_dComp >( getName() ). - reference().resizeDimension< 1, 2, 3 >( 2, m_numComponents, m_numComponents ); + + perforationData.registerField< fields::well::dCompPerforationRate >( getName() ).reference().resizeDimension< 1, 2, 3 >( 2, m_numComponents, m_numComponents+ 2 ); + if( fluid.isThermal() ) + { + perforationData.registerField< fields::well::energyPerforationFlux >( getName() ); + perforationData.registerField< fields::well::dEnergyPerforationFlux >( getName() ). + reference().resizeDimension< 1, 2 >( 2, m_numComponents+2 ); + } WellControls & wellControls = getWellControls( subRegion ); wellControls.registerWrapper< real64 >( viewKeyStruct::currentBHPString() ); - wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentBHP_dPresString() ). - setRestartFlags( RestartFlags::NO_WRITE ); - wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentBHP_dCompDensString() ). - setRestartFlags( RestartFlags::NO_WRITE ). + + wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentBHPString() ). setSizedFromParent( 0 ). - reference().resizeDimension< 0 >( m_numComponents ); + reference().resizeDimension< 0 >( m_numComponents + 2 ); // dP, dT, dC + wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::currentPhaseVolRateString() ). setSizedFromParent( 0 ). reference().resizeDimension< 0 >( m_numPhases ); - wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentPhaseVolRate_dPresString() ). - setRestartFlags( RestartFlags::NO_WRITE ). - setSizedFromParent( 0 ). - reference().resizeDimension< 0 >( m_numPhases ); - wellControls.registerWrapper< array2d< real64 > >( viewKeyStruct::dCurrentPhaseVolRate_dCompDensString() ). - setRestartFlags( RestartFlags::NO_WRITE ). - setSizedFromParent( 0 ). - reference().resizeDimension< 0, 1 >( m_numPhases, m_numComponents ); - wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentPhaseVolRate_dRateString() ). - setRestartFlags( RestartFlags::NO_WRITE ). + + wellControls.registerWrapper< array2d< real64 > >( viewKeyStruct::dCurrentPhaseVolRateString() ). setSizedFromParent( 0 ). - reference().resizeDimension< 0 >( m_numPhases ); + reference().resizeDimension< 0, 1 >( m_numPhases, m_numComponents + 3 ); // dP, dT, dC, dQ + + wellControls.registerWrapper< real64 >( viewKeyStruct::massDensityString() ); wellControls.registerWrapper< real64 >( viewKeyStruct::currentTotalVolRateString() ); - wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentTotalVolRate_dPresString() ). - setRestartFlags( RestartFlags::NO_WRITE ); - wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentTotalVolRate_dCompDensString() ). - setRestartFlags( RestartFlags::NO_WRITE ). + wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentTotalVolRateString() ). setSizedFromParent( 0 ). - reference().resizeDimension< 0 >( m_numComponents ); - wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentTotalVolRate_dRateString() ). - setRestartFlags( RestartFlags::NO_WRITE ); + reference().resizeDimension< 0 >( m_numComponents + 3 ); // dP, dT, dC dQ + + wellControls.registerWrapper< real64 >( viewKeyStruct::massDensityString() ); // write rates output header // the rank that owns the reference well element is responsible @@ -496,28 +507,17 @@ void CompositionalMultiphaseWell::initializePostSubGroups() MeshLevel & mesh, arrayView1d< string const > const & regionNames ) { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion & subRegion ) { - string & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - fluidName = getConstitutiveName< MultiFluidBase >( subRegion ); - GEOS_THROW_IF( fluidName.empty(), - GEOS_FMT( "{}: Fluid model not found on subregion {}", - getDataContext(), subRegion.getName() ), - InputError ); - string & relPermName = subRegion.getReference< string >( viewKeyStruct::relPermNamesString() ); relPermName = getConstitutiveName< RelativePermeabilityBase >( subRegion ); GEOS_THROW_IF( relPermName.empty(), - GEOS_FMT( "{}: Fluid model not found on subregion {}", + GEOS_FMT( "{}: Relative permeability not found on subregion {}", getDataContext(), subRegion.getName() ), InputError ); validateInjectionStreams( subRegion ); - - validateWellConstraints( 0, 0, subRegion ); - } ); } ); } @@ -563,17 +563,21 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & { return; } + using Deriv = multifluid::DerivativeOffset; integer const numComp = m_numComponents; localIndex const iwelemRef = subRegion.getTopWellElementIndex(); + string & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + fluidName = getConstitutiveName< MultiFluidBase >( subRegion ); + MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); + integer isThermal = fluid.isThermal(); // subRegion data arrayView1d< real64 const > const & pres = subRegion.getField< fields::well::pressure >(); arrayView1d< real64 > const & totalMassDens = subRegion.getField< fields::well::totalMassDensity >(); - arrayView1d< real64 > const & dTotalMassDens_dPres = subRegion.getField< fields::well::dTotalMassDensity_dPressure >(); - arrayView2d< real64, compflow::USD_FLUID_DC > const & dTotalMassDens_dCompDens = subRegion.getField< fields::well::dTotalMassDensity_dGlobalCompDensity >(); + arrayView2d< real64, compflow::USD_FLUID_DC > const & dTotalMassDens = subRegion.getField< fields::well::dTotalMassDensity >(); arrayView1d< real64 const > const wellElemGravCoef = subRegion.getField< fields::well::gravityCoefficient >(); @@ -586,36 +590,41 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & real64 & currentBHP = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() ); - real64 & dCurrentBHP_dPres = - wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHP_dPresString() ); - arrayView1d< real64 > const & dCurrentBHP_dCompDens = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHP_dCompDensString() ); - - // bring everything back to host, capture the scalars by reference - forAll< serialPolicy >( 1, [&numComp, - pres, - totalMassDens, - dTotalMassDens_dPres, - dTotalMassDens_dCompDens, - wellElemGravCoef, - ¤tBHP, - &dCurrentBHP_dPres, - dCurrentBHP_dCompDens, - &iwelemRef, - &refGravCoef] ( localIndex const ) + arrayView1d< real64 > const & dCurrentBHP = + wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHPString() ); + + geos::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal, [&] ( auto NC, auto ISTHERMAL ) { - real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef]; - currentBHP = pres[iwelemRef] + totalMassDens[iwelemRef] * diffGravCoef; - dCurrentBHP_dPres = 1 + dTotalMassDens_dPres[iwelemRef] * diffGravCoef; - for( integer ic = 0; ic < numComp; ++ic ) + integer constexpr IS_THERMAL = ISTHERMAL(); + GEOS_UNUSED_VAR( NC ); + // bring everything back to host, capture the scalars by reference + forAll< serialPolicy >( 1, [&numComp, + pres, + totalMassDens, + dTotalMassDens, + wellElemGravCoef, + ¤tBHP, + &dCurrentBHP, + &iwelemRef, + &refGravCoef] ( localIndex const ) { - dCurrentBHP_dCompDens[ic] = dTotalMassDens_dCompDens[iwelemRef][ic] * diffGravCoef; - } + real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef]; + currentBHP = pres[iwelemRef] + totalMassDens[iwelemRef] * diffGravCoef; + dCurrentBHP[Deriv::dP] = 1 + dTotalMassDens[iwelemRef][Deriv::dP] * diffGravCoef; + for( integer ic = 0; ic < numComp; ++ic ) + { + dCurrentBHP[Deriv::dC+ic] = dTotalMassDens[iwelemRef][Deriv::dC+ic] * diffGravCoef; + } + if constexpr ( IS_THERMAL ) + { + dCurrentBHP[Deriv::dT] = dTotalMassDens[iwelemRef][Deriv::dT] * diffGravCoef; + } + } ); } ); if( logLevel >= 2 ) { - GEOS_LOG_RANK( GEOS_FMT( "{}: BHP (at the specified reference elevation): {} Pa", + GEOS_LOG_RANK( GEOS_FMT( "{}: BHP (at the specified reference elevation) = {} Pa", wellControlsName, currentBHP ) ); } @@ -649,7 +658,7 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - + integer isThermal = fluid.isThermal(); arrayView3d< real64 const, multifluid::USD_PHASE > const & phaseFrac = fluid.phaseFraction(); arrayView4d< real64 const, multifluid::USD_PHASE_DC > const & dPhaseFrac = fluid.dPhaseFraction(); @@ -672,165 +681,170 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg arrayView1d< real64 > const & currentPhaseVolRate = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ); - arrayView1d< real64 > const & dCurrentPhaseVolRate_dPres = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dPresString() ); - arrayView2d< real64 > const & dCurrentPhaseVolRate_dCompDens = - wellControls.getReference< array2d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dCompDensString() ); - arrayView1d< real64 > const & dCurrentPhaseVolRate_dRate = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dRateString() ); + arrayView2d< real64 > const & dCurrentPhaseVolRate = + wellControls.getReference< array2d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRateString() ); real64 & currentTotalVolRate = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() ); - real64 & dCurrentTotalVolRate_dPres = - wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dPresString() ); - arrayView1d< real64 > const & dCurrentTotalVolRate_dCompDens = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dCompDensString() ); - real64 & dCurrentTotalVolRate_dRate = - wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dRateString() ); + arrayView1d< real64 > const & dCurrentTotalVolRate = + wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRateString() ); + real64 & massDensity = + wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::massDensityString() ); constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) { typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - - // bring everything back to host, capture the scalars by reference - forAll< serialPolicy >( 1, [&numComp, - &numPhase, - fluidWrapper, - pres, - temp, - compFrac, - dCompFrac_dCompDens, - connRate, - totalDens, - dTotalDens, - phaseDens, - dPhaseDens, - phaseFrac, - dPhaseFrac, - &useSurfaceConditions, - &surfacePres, - &surfaceTemp, - ¤tTotalVolRate, - &dCurrentTotalVolRate_dPres, - dCurrentTotalVolRate_dCompDens, - &dCurrentTotalVolRate_dRate, - currentPhaseVolRate, - dCurrentPhaseVolRate_dPres, - dCurrentPhaseVolRate_dCompDens, - dCurrentPhaseVolRate_dRate, - &iwelemRef, - &logLevel, - &wellControlsName, - &massUnit] ( localIndex const ) + geos::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal, [&] ( auto NC, auto ISTHERMAL ) { - GEOS_UNUSED_VAR( massUnit ); - using Deriv = multifluid::DerivativeOffset; - - stackArray1d< real64, maxNumComp > work( numComp ); - - // Step 1: evaluate the phase and total density in the reference element - - // We need to evaluate the density as follows: - // - Surface conditions: using the surface pressure provided by the user - // - Reservoir conditions: using the pressure in the top element - if( useSurfaceConditions ) + integer constexpr NUM_COMP = NC(); + integer constexpr IS_THERMAL = ISTHERMAL(); + using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NUM_COMP, IS_THERMAL >; + // bring everything back to host, capture the scalars by reference + forAll< serialPolicy >( 1, [&numComp, + &numPhase, + fluidWrapper, + pres, + temp, + compFrac, + dCompFrac_dCompDens, + connRate, + totalDens, + dTotalDens, + phaseDens, + dPhaseDens, + phaseFrac, + dPhaseFrac, + &useSurfaceConditions, + &surfacePres, + &surfaceTemp, + ¤tTotalVolRate, + dCurrentTotalVolRate, + currentPhaseVolRate, + dCurrentPhaseVolRate, + &iwelemRef, + &logLevel, + &wellControlsName, + &massUnit, + &massDensity] ( localIndex const ) { - // we need to compute the surface density - fluidWrapper.update( iwelemRef, 0, surfacePres, surfaceTemp, compFrac[iwelemRef] ); - if( logLevel >= 2 ) + GEOS_UNUSED_VAR( massUnit ); + using Deriv = multifluid::DerivativeOffset; + stackArray1d< real64, maxNumComp > work( numComp ); + // Step 1: evaluate the phase and total density in the reference element + + // We need to evaluate the density as follows: + // - Surface conditions: using the surface pressure provided by the user + // - Reservoir conditions: using the pressure in the top element + if( useSurfaceConditions ) { - GEOS_LOG_RANK( GEOS_FMT( "{}: surface density computed with P_surface = {} Pa and T_surface = {} K", - wellControlsName, surfacePres, surfaceTemp ) ); + // we need to compute the surface density + fluidWrapper.update( iwelemRef, 0, surfacePres, surfaceTemp, compFrac[iwelemRef] ); + if( logLevel >= 2 ) + { + GEOS_LOG_RANK( GEOS_FMT( "{}: surface density computed with P_surface = {} Pa and T_surface = {} K", + wellControlsName, surfacePres, surfaceTemp ) ); #ifdef GEOS_USE_HIP - GEOS_UNUSED_VAR( wellControlsName ); + GEOS_UNUSED_VAR( wellControlsName ); #endif + } + } + else + { + real64 const refPres = pres[iwelemRef]; + fluidWrapper.update( iwelemRef, 0, refPres, temp[iwelemRef], compFrac[iwelemRef] ); } - } - else - { - real64 const refPres = pres[iwelemRef]; - fluidWrapper.update( iwelemRef, 0, refPres, temp[iwelemRef], compFrac[iwelemRef] ); - } - - // Step 2: update the total volume rate - - real64 const currentTotalRate = connRate[iwelemRef]; - - // Step 2.1: compute the inverse of the total density and derivatives - - real64 const totalDensInv = 1.0 / totalDens[iwelemRef][0]; - real64 const dTotalDensInv_dPres = -dTotalDens[iwelemRef][0][Deriv::dP] * totalDensInv * totalDensInv; - stackArray1d< real64, maxNumComp > dTotalDensInv_dCompDens( numComp ); - for( integer ic = 0; ic < numComp; ++ic ) - { - dTotalDensInv_dCompDens[ic] = -dTotalDens[iwelemRef][0][Deriv::dC+ic] * totalDensInv * totalDensInv; - } - applyChainRuleInPlace( numComp, dCompFrac_dCompDens[iwelemRef], dTotalDensInv_dCompDens, work.data() ); - - // Step 2.2: divide the total mass/molar rate by the total density to get the total volumetric rate - currentTotalVolRate = currentTotalRate * totalDensInv; - dCurrentTotalVolRate_dPres = ( useSurfaceConditions == 0 ) * currentTotalRate * dTotalDensInv_dPres; - dCurrentTotalVolRate_dRate = totalDensInv; - for( integer ic = 0; ic < numComp; ++ic ) - { - dCurrentTotalVolRate_dCompDens[ic] = currentTotalRate * dTotalDensInv_dCompDens[ic]; - } - if( logLevel >= 2 && useSurfaceConditions ) - { - GEOS_LOG_RANK( GEOS_FMT( "{}: The total fluid density at surface conditions is {} {}/sm3. \n" - "The total rate is {} {}/s, which corresponds to a total surface volumetric rate of {} sm3/s", - wellControlsName, totalDens[iwelemRef][0], massUnit, - currentTotalRate, massUnit, currentTotalVolRate ) ); - } + // Step 2: update the total volume rate - // Step 3: update the phase volume rate - for( integer ip = 0; ip < numPhase; ++ip ) - { + real64 const currentTotalRate = connRate[iwelemRef]; - // Step 3.1: compute the inverse of the (phase density * phase fraction) and derivatives + // Step 2.1: compute the inverse of the total density and derivatives + massDensity = totalDens[iwelemRef][0]; + real64 const totalDensInv = 1.0 / totalDens[iwelemRef][0]; - // skip the rest of this function if phase ip is absent - bool const phaseExists = (phaseFrac[iwelemRef][0][ip] > 0); - if( !phaseExists ) + stackArray1d< real64, maxNumComp > dTotalDensInv_dCompDens( numComp ); + for( integer ic = 0; ic < numComp; ++ic ) { - continue; + dTotalDensInv_dCompDens[ic] = -dTotalDens[iwelemRef][0][Deriv::dC+ic] * totalDensInv * totalDensInv; + } + applyChainRuleInPlace( numComp, dCompFrac_dCompDens[iwelemRef], dTotalDensInv_dCompDens, work.data() ); + + // Step 2.2: divide the total mass/molar rate by the total density to get the total volumetric rate + currentTotalVolRate = currentTotalRate * totalDensInv; + // Compute derivatives dP dT + real64 const dTotalDensInv_dPres = -dTotalDens[iwelemRef][0][Deriv::dP] * totalDensInv * totalDensInv; + dCurrentTotalVolRate[COFFSET_WJ::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dTotalDensInv_dPres; + if constexpr ( IS_THERMAL ) + { + dCurrentTotalVolRate[COFFSET_WJ::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * -dTotalDens[iwelemRef][0][Deriv::dT] * totalDensInv * totalDensInv; } - real64 const phaseDensInv = 1.0 / phaseDens[iwelemRef][0][ip]; - real64 const phaseFracTimesPhaseDensInv = phaseFrac[iwelemRef][0][ip] * phaseDensInv; - real64 const dPhaseFracTimesPhaseDensInv_dPres = dPhaseFrac[iwelemRef][0][ip][Deriv::dP] * phaseDensInv - - dPhaseDens[iwelemRef][0][ip][Deriv::dP] * phaseFracTimesPhaseDensInv * phaseDensInv; - - - // Step 3.2: divide the total mass/molar rate by the (phase density * phase fraction) to get the phase volumetric rate - currentPhaseVolRate[ip] = currentTotalRate * phaseFracTimesPhaseDensInv; - dCurrentPhaseVolRate_dPres[ip] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dPres; - dCurrentPhaseVolRate_dRate[ip] = phaseFracTimesPhaseDensInv; + dCurrentTotalVolRate[COFFSET_WJ::dQ] = totalDensInv; for( integer ic = 0; ic < numComp; ++ic ) { - dCurrentPhaseVolRate_dCompDens[ip][ic] = -phaseFracTimesPhaseDensInv * dPhaseDens[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv; - dCurrentPhaseVolRate_dCompDens[ip][ic] += dPhaseFrac[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv; - dCurrentPhaseVolRate_dCompDens[ip][ic] *= currentTotalRate; + dCurrentTotalVolRate[COFFSET_WJ::dC+ic] = currentTotalRate * dTotalDensInv_dCompDens[ic]; } - applyChainRuleInPlace( numComp, dCompFrac_dCompDens[iwelemRef], dCurrentPhaseVolRate_dCompDens[ip], work.data() ); if( logLevel >= 2 && useSurfaceConditions ) { - GEOS_LOG_RANK( GEOS_FMT( "{}: The density of phase {} at surface conditions is {} {}/sm3. \n" - "The phase surface volumetric rate is {} sm3/s", - wellControlsName, ip, phaseDens[iwelemRef][0][ip], massUnit, currentPhaseVolRate[ip] ) ); + GEOS_LOG_RANK( GEOS_FMT( "{}: total fluid density at surface conditions = {} {}/sm3, total rate = {} {}/s, total surface volumetric rate = {} sm3/s", + wellControlsName, totalDens[iwelemRef][0], massUnit, currentTotalRate, massUnit, currentTotalVolRate ) ); } - } + + // Step 3: update the phase volume rate + for( integer ip = 0; ip < numPhase; ++ip ) + { + + // Step 3.1: compute the inverse of the (phase density * phase fraction) and derivatives + + // skip the rest of this function if phase ip is absent + bool const phaseExists = (phaseFrac[iwelemRef][0][ip] > 0); + if( !phaseExists ) + { + continue; + } + + real64 const phaseDensInv = 1.0 / phaseDens[iwelemRef][0][ip]; + real64 const phaseFracTimesPhaseDensInv = phaseFrac[iwelemRef][0][ip] * phaseDensInv; + real64 const dPhaseFracTimesPhaseDensInv_dPres = dPhaseFrac[iwelemRef][0][ip][Deriv::dP] * phaseDensInv + - dPhaseDens[iwelemRef][0][ip][Deriv::dP] * phaseFracTimesPhaseDensInv * phaseDensInv; + + + // Step 3.2: divide the total mass/molar rate by the (phase density * phase fraction) to get the phase volumetric rate + currentPhaseVolRate[ip] = currentTotalRate * phaseFracTimesPhaseDensInv; + dCurrentPhaseVolRate[ip][COFFSET_WJ::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dPres; + dCurrentPhaseVolRate[ip][COFFSET_WJ::dQ] = phaseFracTimesPhaseDensInv; + if constexpr (IS_THERMAL ) + { + real64 const dPhaseFracTimesPhaseDensInv_dTemp = dPhaseFrac[iwelemRef][0][ip][Deriv::dT] * phaseDensInv + - dPhaseDens[iwelemRef][0][ip][Deriv::dT] * phaseFracTimesPhaseDensInv * phaseDensInv; + dCurrentPhaseVolRate[ip][COFFSET_WJ::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dTemp; + } + + for( integer ic = 0; ic < numComp; ++ic ) + { + dCurrentPhaseVolRate[ip][COFFSET_WJ::dC+ic] = -phaseFracTimesPhaseDensInv * dPhaseDens[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv; + dCurrentPhaseVolRate[ip][COFFSET_WJ::dC+ic] += dPhaseFrac[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv; + dCurrentPhaseVolRate[ip][COFFSET_WJ::dC+ic] *= currentTotalRate; + } + applyChainRuleInPlace( numComp, dCompFrac_dCompDens[iwelemRef], &dCurrentPhaseVolRate[ip][COFFSET_WJ::dC], work.data() ); + + if( logLevel >= 2 && useSurfaceConditions ) + { + GEOS_LOG_RANK( GEOS_FMT( "{}: density of phase {} at surface conditions = {} {}/sm3, phase surface volumetric rate = {} sm3/s", + wellControlsName, ip, phaseDens[iwelemRef][0][ip], massUnit, currentPhaseVolRate[ip] ) ); + } + } + } ); } ); } ); } + void CompositionalMultiphaseWell::updateFluidModel( WellElementSubRegion & subRegion ) { GEOS_MARK_FUNCTION; - arrayView1d< real64 const > const & pres = subRegion.getField< fields::well::pressure >(); arrayView1d< real64 const > const & temp = subRegion.getField< fields::well::temperature >(); arrayView2d< real64 const, compflow::USD_COMP > const & compFrac = subRegion.getField< fields::well::globalCompFraction >(); @@ -843,7 +857,6 @@ void CompositionalMultiphaseWell::updateFluidModel( WellElementSubRegion & subRe using FluidType = TYPEOFREF( castedFluid ); using ExecPolicy = typename FluidType::exec_policy; typename FluidType::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - thermalCompositionalMultiphaseBaseKernels:: FluidUpdateKernel:: launch< ExecPolicy >( subRegion.size(), @@ -852,21 +865,32 @@ void CompositionalMultiphaseWell::updateFluidModel( WellElementSubRegion & subRe temp, compFrac ); } ); + } -void CompositionalMultiphaseWell::updatePhaseVolumeFraction( WellElementSubRegion & subRegion ) const +real64 CompositionalMultiphaseWell::updatePhaseVolumeFraction( WellElementSubRegion & subRegion ) const { GEOS_MARK_FUNCTION; string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - isothermalCompositionalMultiphaseBaseKernels:: - PhaseVolumeFractionKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( m_numComponents, - m_numPhases, - subRegion, - fluid ); + real64 maxDeltaPhaseVolFrac = + m_isThermal ? + thermalCompositionalMultiphaseBaseKernels:: + PhaseVolumeFractionKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_numComponents, + m_numPhases, + subRegion, + fluid ) +: isothermalCompositionalMultiphaseBaseKernels:: + PhaseVolumeFractionKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_numComponents, + m_numPhases, + subRegion, + fluid ); + + return maxDeltaPhaseVolFrac; } void CompositionalMultiphaseWell::updateTotalMassDensity( WellElementSubRegion & subRegion ) const @@ -875,15 +899,46 @@ void CompositionalMultiphaseWell::updateTotalMassDensity( WellElementSubRegion & string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - - TotalMassDensityKernelFactory:: + fluid.isThermal() ? + thermalCompositionalMultiphaseWellKernels:: + TotalMassDensityKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_numComponents, + m_numPhases, + subRegion, + fluid ) + : + compositionalMultiphaseWellKernels:: + TotalMassDensityKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, subRegion, fluid ); + } -void CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) +void CompositionalMultiphaseWell::updateState( DomainPartition & domain ) +{ + GEOS_MARK_FUNCTION; + + real64 maxPhaseVolFrac = 0.0; + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + real64 const maxRegionPhaseVolFrac = updateSubRegionState( subRegion ); + maxPhaseVolFrac = LvArray::math::max( maxRegionPhaseVolFrac, maxPhaseVolFrac ); + } ); + } ); + maxPhaseVolFrac = MpiWrapper::max( maxPhaseVolFrac ); + + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max well phase volume fraction change = {}", getName(), fmt::format( "{:.{}f}", maxPhaseVolFrac, 4 ) ) ); + +} + +real64 CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) { // update properties updateGlobalComponentFraction( subRegion ); @@ -893,17 +948,16 @@ void CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & s updateVolRatesForConstraint( subRegion ); // update densities, phase fractions, phase volume fractions - updateFluidModel( subRegion ); - updatePhaseVolumeFraction( subRegion ); - updateTotalMassDensity( subRegion ); + updateFluidModel( subRegion ); // Calculate fluid properties; + real64 maxPhaseVolChange = updatePhaseVolumeFraction( subRegion ); + updateTotalMassDensity( subRegion ); // update the current BHP pressure updateBHPForConstraint( subRegion ); - - // note: the perforation rates are updated separately + return maxPhaseVolChange; } -void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain ) +void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain, real64 const & time_n, real64 const & dt ) { GEOS_MARK_FUNCTION; @@ -920,278 +974,265 @@ void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain ) { ElementRegionManager & elemManager = mesh.getElemManager(); - PresTempCompFracInitializationKernel::CompFlowAccessors resCompFlowAccessors( mesh.getElemManager(), flowSolver.getName() ); - PresTempCompFracInitializationKernel::MultiFluidAccessors resMultiFluidAccessors( mesh.getElemManager(), flowSolver.getName() ); + compositionalMultiphaseWellKernels::PresTempCompFracInitializationKernel::CompFlowAccessors + resCompFlowAccessors( mesh.getElemManager(), flowSolver.getName() ); + compositionalMultiphaseWellKernels::PresTempCompFracInitializationKernel::MultiFluidAccessors + resMultiFluidAccessors( mesh.getElemManager(), flowSolver.getName() ); elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion & subRegion ) { WellControls const & wellControls = getWellControls( subRegion ); - PerforationData const & perforationData = *subRegion.getPerforationData(); - - // get well primary variables on well elements - arrayView1d< real64 > const & wellElemPressure = subRegion.getField< fields::well::pressure >(); - arrayView1d< real64 > const & wellElemTemp = subRegion.getField< fields::well::temperature >(); - arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = subRegion.getField< fields::well::globalCompDensity >(); - arrayView1d< real64 > const & connRate = subRegion.getField< fields::well::mixtureConnectionRate >(); - - // get the info stored on well elements - arrayView2d< real64, compflow::USD_COMP > const & wellElemCompFrac = subRegion.getField< fields::well::globalCompFraction >(); - arrayView1d< real64 const > const & wellElemGravCoef = subRegion.getField< fields::well::gravityCoefficient >(); - - // get the element region, subregion, index - arrayView1d< localIndex const > const resElementRegion = perforationData.getField< fields::perforation::reservoirElementRegion >(); - arrayView1d< localIndex const > const resElementSubRegion = perforationData.getField< fields::perforation::reservoirElementSubRegion >(); - arrayView1d< localIndex const > const resElementIndex = perforationData.getField< fields::perforation::reservoirElementIndex >(); - - arrayView1d< real64 const > const & perfGravCoef = perforationData.getField< fields::well::gravityCoefficient >(); - - // 1) Loop over all perforations to compute an average mixture density and component fraction - // 2) Initialize the reference pressure - // 3) Estimate the pressures in the well elements using the average density - PresTempCompFracInitializationKernel:: - launch( perforationData.size(), - subRegion.size(), - numComp, - numPhase, - perforationData.getNumPerforationsGlobal(), - wellControls, - 0.0, // initialization done at t = 0 - resCompFlowAccessors.get( fields::flow::pressure{} ), - resCompFlowAccessors.get( fields::flow::temperature{} ), - resCompFlowAccessors.get( fields::flow::globalCompDensity{} ), - resCompFlowAccessors.get( fields::flow::phaseVolumeFraction{} ), - resMultiFluidAccessors.get( fields::multifluid::phaseMassDensity{} ), - resElementRegion, - resElementSubRegion, - resElementIndex, - perfGravCoef, - wellElemGravCoef, - wellElemPressure, - wellElemTemp, - wellElemCompFrac ); - - // get well secondary variables on well elements - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - MultiFluidBase & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens = fluid.phaseDensity(); - arrayView2d< real64 const, multifluid::USD_FLUID > const & wellElemTotalDens = fluid.totalDensity(); - // 4) Back calculate component densities - constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) + if( time_n <= 0.0 || + ( !wellControls.isWellOpen( time_n ) && wellControls.isWellOpen( time_n + dt ) ) ) { - typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - thermalCompositionalMultiphaseBaseKernels:: - FluidUpdateKernel:: - launch< serialPolicy >( subRegion.size(), - fluidWrapper, - wellElemPressure, - wellElemTemp, - wellElemCompFrac ); - } ); + PerforationData const & perforationData = *subRegion.getPerforationData(); - CompDensInitializationKernel::launch( subRegion.size(), - numComp, - wellElemCompFrac, - wellElemTotalDens, - wellElemCompDens ); + // get well primary variables on well elements + arrayView1d< real64 > const & wellElemPressure = subRegion.getField< fields::well::pressure >(); + arrayView1d< real64 > const & wellElemTemp = subRegion.getField< fields::well::temperature >(); + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = subRegion.getField< fields::well::globalCompDensity >(); + arrayView1d< real64 > const & connRate = subRegion.getField< fields::well::mixtureConnectionRate >(); - // 5) Recompute the pressure-dependent properties - updateSubRegionState( subRegion ); + // get the info stored on well elements + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompFrac = subRegion.getField< fields::well::globalCompFraction >(); + arrayView1d< real64 const > const & wellElemGravCoef = subRegion.getField< fields::well::gravityCoefficient >(); - // 6) Estimate the well rates - // TODO: initialize rates using perforation rates - compositionalMultiphaseWellKernels:: - RateInitializationKernel:: - launch( subRegion.size(), - m_targetPhaseIndex, - wellControls, - 0.0, // initialization done at t = 0 - wellElemPhaseDens, - wellElemTotalDens, - connRate ); + // get the element region, subregion, index + arrayView1d< localIndex const > const resElementRegion = perforationData.getField< fields::perforation::reservoirElementRegion >(); + arrayView1d< localIndex const > const resElementSubRegion = perforationData.getField< fields::perforation::reservoirElementSubRegion >(); + arrayView1d< localIndex const > const resElementIndex = perforationData.getField< fields::perforation::reservoirElementIndex >(); + + arrayView1d< real64 const > const & perfGravCoef = perforationData.getField< fields::well::gravityCoefficient >(); + + // 1) Loop over all perforations to compute an average mixture density and component fraction + // 2) Initialize the reference pressure + // 3) Estimate the pressures in the well elements using the average density + compositionalMultiphaseWellKernels:: + PresTempCompFracInitializationKernel:: + launch( perforationData.size(), + subRegion.size(), + numComp, + numPhase, + perforationData.getNumPerforationsGlobal(), + wellControls, + 0.0, // initialization done at t = 0 + resCompFlowAccessors.get( fields::flow::pressure{} ), + resCompFlowAccessors.get( fields::flow::temperature{} ), + resCompFlowAccessors.get( fields::flow::globalCompDensity{} ), + resCompFlowAccessors.get( fields::flow::phaseVolumeFraction{} ), + resMultiFluidAccessors.get( fields::multifluid::phaseMassDensity{} ), + resElementRegion, + resElementSubRegion, + resElementIndex, + perfGravCoef, + wellElemGravCoef, + wellElemPressure, + wellElemTemp, + wellElemCompFrac ); + + // get well secondary variables on well elements + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + MultiFluidBase & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens = fluid.phaseDensity(); + arrayView2d< real64 const, multifluid::USD_FLUID > const & wellElemTotalDens = fluid.totalDensity(); + + // 4) Back calculate component densities + constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) + { + typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); + + thermalCompositionalMultiphaseBaseKernels:: + FluidUpdateKernel:: + launch< serialPolicy >( subRegion.size(), + fluidWrapper, + wellElemPressure, + wellElemTemp, + wellElemCompFrac ); + } ); + + compositionalMultiphaseWellKernels:: + CompDensInitializationKernel::launch( subRegion.size(), + numComp, + wellElemCompFrac, + wellElemTotalDens, + wellElemCompDens ); + + // 5) Recompute the pressure-dependent properties + updateSubRegionState( subRegion ); + + // 6) Estimate the well rates + // TODO: initialize rates using perforation rates + compositionalMultiphaseWellKernels:: + RateInitializationKernel:: + launch( subRegion.size(), + m_targetPhaseIndex, + wellControls, + 0.0, // initialization done at t = 0 + wellElemPhaseDens, + wellElemTotalDens, + connRate ); + } } ); } ); } -void CompositionalMultiphaseWell::assembleFluxTerms( real64 const dt, - DomainPartition const & domain, +void CompositionalMultiphaseWell::assembleFluxTerms( real64 const & time, + real64 const & dt, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; - // loop over the wells - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) - { - ElementRegionManager const & elemManager = mesh.getElemManager(); - elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion const & subRegion ) + string const wellDofKey = dofManager.getKey( wellElementDofName()); + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) { - WellControls const & wellControls = getWellControls( subRegion ); - - // get a reference to the degree-of-freedom numbers - string const wellDofKey = dofManager.getKey( wellElementDofName() ); - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< localIndex const > const & nextWellElemIndex = - subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() ); + WellControls const & well_controls = getWellControls( subRegion ); + if( well_controls.isWellOpen( time + dt ) && !m_keepVariablesConstantDuringInitStep ) + { + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + int numComponents = fluid.numFluidComponents(); - // get a reference to the primary variables on well elements - arrayView1d< real64 const > const & connRate = subRegion.getField< fields::well::mixtureConnectionRate >(); - - // get the info stored on well elements - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac = subRegion.getField< fields::well::globalCompFraction >(); - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens = subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >(); - - isothermalCompositionalMultiphaseBaseKernels:: - KernelLaunchSelector1< FluxKernel >( numFluidComponents(), - subRegion.size(), - dofManager.rankOffset(), - m_useTotalMassEquation, - wellControls, - wellElemDofNumber, - nextWellElemIndex, - connRate, - wellElemCompFrac, - dWellElemCompFrac_dCompDens, - dt, - localMatrix, - localRhs ); + if( isThermal() ) + { + thermalCompositionalMultiphaseWellKernels:: + FaceBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + dt, + dofManager.rankOffset(), + m_useTotalMassEquation, + wellDofKey, + well_controls, + subRegion, + fluid, + localMatrix, + localRhs ); + } + else + { + compositionalMultiphaseWellKernels:: + FaceBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + dt, + dofManager.rankOffset(), + m_useTotalMassEquation, + wellDofKey, + well_controls, + subRegion, + localMatrix, + localRhs ); + } + } } ); } ); + } -void CompositionalMultiphaseWell::assembleAccumulationTerms( DomainPartition const & domain, +void CompositionalMultiphaseWell::assembleAccumulationTerms( real64 const & time, + real64 const & dt, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; - + GEOS_UNUSED_VAR( time ); + GEOS_UNUSED_VAR( dt ); string const wellDofKey = dofManager.getKey( wellElementDofName() ); - - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { - - ElementRegionManager const & elemManager = mesh.getElemManager(); - - elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion const & subRegion ) + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) { + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + int numPhases = fluid.numFluidPhases(); + int numComponents = fluid.numFluidComponents(); + WellControls const & wellControls = getWellControls( subRegion ); + if( wellControls.isWellOpen( time+ dt ) && !m_keepVariablesConstantDuringInitStep ) + { + if( isThermal() ) + { - // get the degrees of freedom and ghosting info - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank(); - - // get the properties on the well element - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac = - subRegion.getField< fields::well::phaseVolumeFraction >(); - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac = - subRegion.getField< fields::well::dPhaseVolumeFraction >(); - - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens = - subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >(); - - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac_n = - subRegion.getField< fields::well::phaseVolumeFraction_n >(); - - arrayView1d< real64 const > const & wellElemVolume = subRegion.getElementVolume(); + thermalCompositionalMultiphaseWellKernels:: + ElementBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + numPhases, + wellControls.isProducer(), + dofManager.rankOffset(), + m_useTotalMassEquation, + wellDofKey, + subRegion, + fluid, + localMatrix, + localRhs ); + } + else + { + compositionalMultiphaseWellKernels:: + ElementBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + numPhases, + wellControls.isProducer(), + dofManager.rankOffset(), + m_useTotalMassEquation, + wellDofKey, + subRegion, + fluid, + localMatrix, + localRhs ); + } + } + else + { + //wellControls.setWellOpen(false); + // get the degrees of freedom and ghosting info + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank(); + localIndex rank_offset = dofManager.rankOffset(); + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( wellElemGhostRank[ei] < 0 ) + { + globalIndex const dofIndex = wellElemDofNumber[ei]; + localIndex const localRow = dofIndex - rank_offset; - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens = fluid.phaseDensity(); - arrayView4d< real64 const, multifluid::USD_PHASE_DC > const & dWellElemPhaseDens = fluid.dPhaseDensity(); - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac = fluid.phaseCompFraction(); - arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > const & dWellElemPhaseCompFrac = fluid.dPhaseCompFraction(); - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens_n = fluid.phaseDensity_n(); - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac_n = fluid.phaseCompFraction_n(); - - isothermalCompositionalMultiphaseBaseKernels:: - KernelLaunchSelector1< AccumulationKernel >( numFluidComponents(), - subRegion.size(), - numFluidPhases(), - dofManager.rankOffset(), - m_useTotalMassEquation, - wellElemDofNumber, - wellElemGhostRank, - wellElemVolume, - wellElemPhaseVolFrac, - dWellElemPhaseVolFrac, - dWellElemCompFrac_dCompDens, - wellElemPhaseDens, - dWellElemPhaseDens, - wellElemPhaseCompFrac, - dWellElemPhaseCompFrac, - wellElemPhaseVolFrac_n, - wellElemPhaseDens_n, - wellElemPhaseCompFrac_n, - localMatrix, - localRhs ); + real64 unity = 1.0; + for( integer i=0; i < m_numDofPerWellElement; i++ ) + { + globalIndex const rindex = localRow+i; + globalIndex const cindex =dofIndex + i; + localMatrix.template addToRow< serialAtomic >( rindex, + &cindex, + &unity, + 1 ); + localRhs[rindex] = 0.0; + } + } + } ); + } } ); } ); -} - - -void CompositionalMultiphaseWell::assembleVolumeBalanceTerms( DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - GEOS_MARK_FUNCTION; - - string const wellDofKey = dofManager.getKey( wellElementDofName() ); - - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) - { - ElementRegionManager const & elemManager = mesh.getElemManager(); - elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion const & subRegion ) - { - // get the degrees of freedom and ghosting info - arrayView1d< globalIndex const > const & wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank(); - - // get the properties on the well element - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac = - subRegion.getField< fields::well::phaseVolumeFraction >(); - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac = - subRegion.getField< fields::well::dPhaseVolumeFraction >(); - - arrayView1d< real64 const > const & wellElemVolume = - subRegion.getReference< array1d< real64 > >( ElementSubRegionBase::viewKeyStruct::elementVolumeString() ); - - isothermalCompositionalMultiphaseBaseKernels:: - KernelLaunchSelector1< VolumeBalanceKernel >( numFluidComponents(), - subRegion.size(), - numFluidPhases(), - dofManager.rankOffset(), - wellElemDofNumber, - wellElemGhostRank, - wellElemPhaseVolFrac, - dWellElemPhaseVolFrac, - wellElemVolume, - localMatrix, - localRhs ); - } ); - } ); } @@ -1204,7 +1245,17 @@ CompositionalMultiphaseWell::calculateResidualNorm( real64 const & time_n, { GEOS_MARK_FUNCTION; - real64 localResidualNorm = 0.0; + integer numNorm = 1; // mass balance + array1d< real64 > localResidualNorm; + array1d< real64 > localResidualNormalizer; + + if( isThermal() ) + { + numNorm = 2; // mass balance and energy balance + } + localResidualNorm.resize( numNorm ); + localResidualNormalizer.resize( numNorm ); + globalIndex const rankOffset = dofManager.rankOffset(); string const wellDofKey = dofManager.getKey( wellElementDofName() ); @@ -1221,7 +1272,7 @@ CompositionalMultiphaseWell::calculateResidualNorm( real64 const & time_n, [&]( localIndex const, WellElementSubRegion const & subRegion ) { - real64 subRegionResidualNorm[1]{}; + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); @@ -1230,40 +1281,87 @@ CompositionalMultiphaseWell::calculateResidualNorm( real64 const & time_n, // step 1: compute the norm in the subRegion - ResidualNormKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( m_numComponents, - numDofPerWellElement(), - m_targetPhaseIndex, - rankOffset, - wellDofKey, - localRhs, - subRegion, - fluid, - wellControls, - time_n + dt, - dt, - m_nonlinearSolverParameters.m_minNormalizer, - subRegionResidualNorm ); - - // step 2: reduction across meshBodies/regions/subRegions - - if( subRegionResidualNorm[0] > localResidualNorm ) + if( isThermal() ) { - localResidualNorm = subRegionResidualNorm[0]; + real64 subRegionResidualNorm[2]{}; + + thermalCompositionalMultiphaseWellKernels::ResidualNormKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_numComponents, + m_targetPhaseIndex, + rankOffset, + wellDofKey, + localRhs, + subRegion, + fluid, + wellControls, + time_n + dt, + dt, + m_nonlinearSolverParameters.m_minNormalizer, + subRegionResidualNorm ); + // step 2: reduction across meshBodies/regions/subRegions + + for( integer i=0; i localResidualNorm[i] ) + { + localResidualNorm[i] = subRegionResidualNorm[i]; + } + } + } + else + { + real64 subRegionResidualNorm[1]{}; + compositionalMultiphaseWellKernels::ResidualNormKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_numComponents, + numDofPerWellElement(), + m_targetPhaseIndex, + rankOffset, + wellDofKey, + localRhs, + subRegion, + fluid, + wellControls, + time_n + dt, + dt, + m_nonlinearSolverParameters.m_minNormalizer, + subRegionResidualNorm ); + + + // step 2: reduction across meshBodies/regions/subRegions + + if( subRegionResidualNorm[0] > localResidualNorm[0] ) + { + localResidualNorm[0] = subRegionResidualNorm[0]; + } + } } ); } ); // step 3: second reduction across MPI ranks - - real64 const residualNorm = MpiWrapper::max( localResidualNorm ); - - if( getLogLevel() >= 1 && logger::internal::rank == 0 ) + real64 resNorm=localResidualNorm[0]; + if( isThermal() ) { - std::cout << GEOS_FMT( " ( R{} ) = ( {:4.2e} )", coupledSolverAttributePrefix(), residualNorm ); + real64 globalResidualNorm[2]{}; + globalResidualNorm[0] = MpiWrapper::max( localResidualNorm[0] ); + globalResidualNorm[1] = MpiWrapper::max( localResidualNorm[1] ); + resNorm=sqrt( globalResidualNorm[0] * globalResidualNorm[0] + globalResidualNorm[1] * globalResidualNorm[1] ); + if( getLogLevel() >= 1 && logger::internal::rank == 0 ) + { + std::cout << GEOS_FMT( " ( R{} ) = ( {:4.2e} ) ( Renergy ) = ( {:4.2e} )", + coupledSolverAttributePrefix(), globalResidualNorm[0], globalResidualNorm[1] ); + } + } + else + { + resNorm= MpiWrapper::max( resNorm ); + if( getLogLevel() >= 1 && logger::internal::rank == 0 ) + { + std::cout << GEOS_FMT( " ( R{} ) = ( {:4.2e} )", coupledSolverAttributePrefix(), resNorm ); + } } - return residualNorm; + return resNorm; } real64 @@ -1276,33 +1374,104 @@ CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain, string const wellDofKey = dofManager.getKey( wellElementDofName() ); real64 scalingFactor = 1.0; - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + real64 maxDeltaPres = 0.0, maxDeltaCompDens = 0.0, maxDeltaTemp = 0.0; + real64 minPresScalingFactor = 1.0, minCompDensScalingFactor = 1.0, minTempScalingFactor = 1.0; + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { - mesh.getElemManager().forElementSubRegions< ElementSubRegionBase >( regionNames, - [&]( localIndex const, - ElementSubRegionBase & subRegion ) + mesh.getElemManager().forElementSubRegions( regionNames, + [&]( localIndex const, + ElementSubRegionBase & subRegion ) { - // check that pressure and component densities are non-negative + arrayView1d< real64 const > const pressure = subRegion.getField< fields::well::pressure >(); + arrayView1d< real64 const > const temperature = subRegion.getField< fields::well::temperature >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::well::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::well::pressureScalingFactor >(); + arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::well::temperatureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::well::globalCompDensityScalingFactor >(); + const integer temperatureOffset = m_numComponents+2; auto const subRegionData = - compositionalMultiphaseWellKernels:: - ScalingForSystemSolutionKernelFactory:: + m_isThermal + ? thermalCompositionalMultiphaseBaseKernels:: + SolutionScalingKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, + m_maxAbsolutePresChange, + m_maxRelativeTempChange, + m_maxCompFracChange, + m_maxRelativeCompDensChange, + pressure, + temperature, + compDens, + pressureScalingFactor, + compDensScalingFactor, + temperatureScalingFactor, + dofManager.rankOffset(), + m_numComponents, + wellDofKey, + subRegion, + localSolution, + temperatureOffset ) + : isothermalCompositionalMultiphaseBaseKernels:: + SolutionScalingKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, m_maxAbsolutePresChange, m_maxCompFracChange, + m_maxRelativeCompDensChange, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor, dofManager.rankOffset(), m_numComponents, wellDofKey, subRegion, localSolution ); + scalingFactor = std::min( subRegionData.localMinVal, scalingFactor ); - } ); + maxDeltaPres = std::max( maxDeltaPres, subRegionData.localMaxDeltaPres ); + maxDeltaCompDens = std::max( maxDeltaCompDens, subRegionData.localMaxDeltaCompDens ); + maxDeltaTemp = std::max( maxDeltaTemp, subRegionData.localMaxDeltaTemp ); + minPresScalingFactor = std::min( minPresScalingFactor, subRegionData.localMinPresScalingFactor ); + minCompDensScalingFactor = std::min( minCompDensScalingFactor, subRegionData.localMinCompDensScalingFactor ); + minTempScalingFactor = std::min( minTempScalingFactor, subRegionData.localMinTempScalingFactor ); + } ); } ); - return LvArray::math::max( MpiWrapper::min( scalingFactor ), m_minScalingFactor ); + scalingFactor = MpiWrapper::min( scalingFactor ); + maxDeltaPres = MpiWrapper::max( maxDeltaPres ); + maxDeltaCompDens = MpiWrapper::max( maxDeltaCompDens ); + minPresScalingFactor = MpiWrapper::min( minPresScalingFactor ); + minCompDensScalingFactor = MpiWrapper::min( minCompDensScalingFactor ); + + string const massUnit = m_useMass ? "kg/m3" : "mol/m3"; + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max well pressure change: {} Pa (before scaling)", + getName(), GEOS_FMT( "{:.{}f}", maxDeltaPres, 3 ) ) ); + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max well component density change: {} {} (before scaling)", + getName(), GEOS_FMT( "{:.{}f}", maxDeltaCompDens, 3 ), massUnit ) ); + + if( m_isThermal ) + { + maxDeltaTemp = MpiWrapper::max( maxDeltaTemp ); + minTempScalingFactor = MpiWrapper::min( minTempScalingFactor ); + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max well temperature change: {} K (before scaling)", + getName(), GEOS_FMT( "{:.{}f}", maxDeltaTemp, 3 ) ) ); + } + + + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min well pressure scaling factor: {}", getName(), minPresScalingFactor ) ); + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min well component density scaling factor: {}", getName(), minCompDensScalingFactor ) ); + if( m_isThermal ) + { + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min well temperature scaling factor: {}", getName(), minTempScalingFactor ) ); + } + + + return LvArray::math::max( scalingFactor, m_minScalingFactor ); + } bool @@ -1315,143 +1484,217 @@ CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain, string const wellDofKey = dofManager.getKey( wellElementDofName() ); integer localCheck = 1; - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + if( 0 ) { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion & subRegion ) - { - auto const subRegionData = - compositionalMultiphaseWellKernels:: - SolutionCheckKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, - CompositionalMultiphaseFVM::ScalingType::Global, - scalingFactor, - dofManager.rankOffset(), - m_numComponents, - wellDofKey, - subRegion, - localSolution ); - if( !subRegionData.localMinVal ) + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) { - GEOS_LOG_LEVEL( 1, "Solution is invalid in well " << subRegion.getName() - << " (either a negative pressure or a negative component density was found)." ); - } + arrayView1d< real64 const > const pressure = + subRegion.getField< fields::well::pressure >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = + subRegion.getField< fields::well::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::well::pressureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::well::globalCompDensityScalingFactor >(); + + auto const subRegionData = + compositionalMultiphaseWellKernels:: + SolutionCheckKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, + CompositionalMultiphaseFVM::ScalingType::Global, + scalingFactor, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor, + dofManager.rankOffset(), + m_numComponents, + wellDofKey, + subRegion, + localSolution ); + + if( !subRegionData.localMinVal ) + { + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, + GEOS_FMT( "Solution is invalid in well {} (either a negative pressure or a negative component density was found)", subRegion.getName()) ); + } - localCheck = std::min( localCheck, subRegionData.localMinVal ); + localCheck = std::min( localCheck, subRegionData.localMinVal ); + } ); } ); - } ); + } + else + { + + real64 minPres = 0.0, minDens = 0.0, minTotalDens = 0.0; + integer numNegPres = 0, numNegDens = 0, numNegTotalDens = 0; + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions( regionNames, + [&]( localIndex const, + ElementSubRegionBase & subRegion ) + { + //integer const m_allowCompDensChopping(true); + integer const m_allowNegativePressure( false ); + CompositionalMultiphaseFVM::ScalingType const m_scalingType( CompositionalMultiphaseFVM::ScalingType::Global ); + arrayView1d< real64 const > const pressure = + subRegion.getField< fields::well::pressure >(); + arrayView1d< real64 const > const temperature = + subRegion.getField< fields::well::temperature >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = + subRegion.getField< fields::well::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::well::pressureScalingFactor >(); + arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::well::temperatureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::well::globalCompDensityScalingFactor >(); + + // check that pressure and component densities are non-negative + // for thermal, check that temperature is above 273.15 K + const integer temperatureOffset = m_numComponents+2; + auto const subRegionData = + m_isThermal + ? thermalCompositionalMultiphaseBaseKernels:: + SolutionCheckKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, + m_allowNegativePressure, + m_scalingType, + scalingFactor, + pressure, + temperature, + compDens, + pressureScalingFactor, + temperatureScalingFactor, + compDensScalingFactor, + dofManager.rankOffset(), + m_numComponents, + wellDofKey, + subRegion, + localSolution, + temperatureOffset ) + : isothermalCompositionalMultiphaseBaseKernels:: + SolutionCheckKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, + m_allowNegativePressure, + m_scalingType, + scalingFactor, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor, + dofManager.rankOffset(), + m_numComponents, + wellDofKey, + subRegion, + localSolution ); + + localCheck = std::min( localCheck, subRegionData.localMinVal ); + + minPres = std::min( minPres, subRegionData.localMinPres ); + minDens = std::min( minDens, subRegionData.localMinDens ); + minTotalDens = std::min( minTotalDens, subRegionData.localMinTotalDens ); + numNegPres += subRegionData.localNumNegPressures; + numNegDens += subRegionData.localNumNegDens; + numNegTotalDens += subRegionData.localNumNegTotalDens; + } ); + } ); + + minPres = MpiWrapper::min( minPres ); + minDens = MpiWrapper::min( minDens ); + minTotalDens = MpiWrapper::min( minTotalDens ); + numNegPres = MpiWrapper::sum( numNegPres ); + numNegDens = MpiWrapper::sum( numNegDens ); + numNegTotalDens = MpiWrapper::sum( numNegTotalDens ); + + if( numNegPres > 0 ) + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative well pressure values: {}, minimum value: {} Pa", + getName(), numNegPres, fmt::format( "{:.{}f}", minPres, 3 ) ) ); + string const massUnit = m_useMass ? "kg/m3" : "mol/m3"; + if( numNegDens > 0 ) + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative well component density values: {}, minimum value: {} {} ", + getName(), numNegDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); + if( minTotalDens > 0 ) + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative total well density values: {}, minimum value: {} {} ", + getName(), minTotalDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); + + } return MpiWrapper::min( localCheck ); } -void CompositionalMultiphaseWell::computePerforationRates( DomainPartition & domain ) +void CompositionalMultiphaseWell::computePerforationRates( real64 const & time_n, real64 const & dt, DomainPartition & domain ) { GEOS_MARK_FUNCTION; - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + forDiscretizationOnMeshTargets ( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { // TODO: change the way we access the flowSolver here CompositionalMultiphaseBase const & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() ); - PerforationKernel::CompFlowAccessors resCompFlowAccessors( mesh.getElemManager(), flowSolver.getName() ); - PerforationKernel::MultiFluidAccessors resMultiFluidAccessors( mesh.getElemManager(), flowSolver.getName() ); - PerforationKernel::RelPermAccessors resRelPermAccessors( mesh.getElemManager(), flowSolver.getName() ); + ElementRegionManager & elemManager = mesh.getElemManager(); - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, - WellElementSubRegion & subRegion ) + elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, + WellElementSubRegion & subRegion ) { - - WellControls const & wellControls = getWellControls( subRegion ); - bool const disableReservoirToWellFlow = wellControls.isInjector() and !wellControls.isCrossflowEnabled(); - PerforationData * const perforationData = subRegion.getPerforationData(); + WellControls const & wellControls = getWellControls( subRegion ); + if( wellControls.isWellOpen( time_n + dt ) && !m_keepVariablesConstantDuringInitStep ) + { - // get depth - arrayView1d< real64 const > const & wellElemGravCoef = subRegion.getField< fields::well::gravityCoefficient >(); - - // get well primary variables on well elements - arrayView1d< real64 const > const & wellElemPres = - subRegion.getField< fields::well::pressure >(); - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompDens = - subRegion.getField< fields::well::globalCompDensity >(); + bool const disableReservoirToWellFlow = wellControls.isInjector() and !wellControls.isCrossflowEnabled(); - arrayView1d< real64 const > const & wellElemTotalMassDens = - subRegion.getField< fields::well::totalMassDensity >(); - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres = - subRegion.getField< fields::well::dTotalMassDensity_dPressure >(); - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens = - subRegion.getField< fields::well::dTotalMassDensity_dGlobalCompDensity >(); - - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac = - subRegion.getField< fields::well::globalCompFraction >(); - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens = - subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >(); - - // get well variables on perforations - arrayView1d< real64 const > const & perfGravCoef = - perforationData->getField< fields::well::gravityCoefficient >(); - arrayView1d< localIndex const > const perfWellElemIndex = - perforationData->getField< fields::perforation::wellElementIndex >(); - arrayView1d< real64 const > const perfTrans = - perforationData->getField< fields::perforation::wellTransmissibility >(); - - arrayView2d< real64 > const & compPerfRate = - perforationData->getField< fields::well::compPerforationRate >(); - arrayView3d< real64 > const & dCompPerfRate_dPres = - perforationData->getField< fields::well::dCompPerforationRate_dPres >(); - arrayView4d< real64 > const & dCompPerfRate_dComp = - perforationData->getField< fields::well::dCompPerforationRate_dComp >(); - - // get the element region, subregion, index - arrayView1d< localIndex const > const resElementRegion = - perforationData->getField< fields::perforation::reservoirElementRegion >(); - arrayView1d< localIndex const > const resElementSubRegion = - perforationData->getField< fields::perforation::reservoirElementSubRegion >(); - arrayView1d< localIndex const > const resElementIndex = - perforationData->getField< fields::perforation::reservoirElementIndex >(); - - isothermalCompositionalMultiphaseBaseKernels:: - KernelLaunchSelector2< PerforationKernel >( numFluidComponents(), - numFluidPhases(), - perforationData->size(), - disableReservoirToWellFlow, - resCompFlowAccessors.get( fields::flow::pressure{} ), - resCompFlowAccessors.get( fields::flow::phaseVolumeFraction{} ), - resCompFlowAccessors.get( fields::flow::dPhaseVolumeFraction{} ), - resCompFlowAccessors.get( fields::flow::dGlobalCompFraction_dGlobalCompDensity{} ), - resMultiFluidAccessors.get( fields::multifluid::phaseDensity{} ), - resMultiFluidAccessors.get( fields::multifluid::dPhaseDensity{} ), - resMultiFluidAccessors.get( fields::multifluid::phaseViscosity{} ), - resMultiFluidAccessors.get( fields::multifluid::dPhaseViscosity{} ), - resMultiFluidAccessors.get( fields::multifluid::phaseCompFraction{} ), - resMultiFluidAccessors.get( fields::multifluid::dPhaseCompFraction{} ), - resRelPermAccessors.get( fields::relperm::phaseRelPerm{} ), - resRelPermAccessors.get( fields::relperm::dPhaseRelPerm_dPhaseVolFraction{} ), - wellElemGravCoef, - wellElemPres, - wellElemCompDens, - wellElemTotalMassDens, - dWellElemTotalMassDens_dPres, - dWellElemTotalMassDens_dCompDens, - wellElemCompFrac, - dWellElemCompFrac_dCompDens, - perfGravCoef, - perfWellElemIndex, - perfTrans, - resElementRegion, - resElementSubRegion, - resElementIndex, - compPerfRate, - dCompPerfRate_dPres, - dCompPerfRate_dComp ); + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + bool isThermal = fluid.isThermal(); + if( isThermal ) + { + thermalPerforationFluxKernels:: + PerforationFluxKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_numComponents, + m_numPhases, + flowSolver.getName(), + perforationData, + subRegion, + fluid, + elemManager, + disableReservoirToWellFlow ); + } + else + { + isothermalPerforationFluxKernels:: + PerforationFluxKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_numComponents, + m_numPhases, + flowSolver.getName(), + perforationData, + subRegion, + elemManager, + disableReservoirToWellFlow ); + } + } + else + { + // Zero completion flow rate + arrayView2d< real64 > const compPerfRate = perforationData->getField< fields::well::compPerforationRate >(); + for( integer iperf=0; iperfsize(); iperf++ ) + { + for( integer ic = 0; ic < m_numComponents; ++ic ) + { + compPerfRate[iperf][ic] = 0.0; + } + } + } } ); + } ); } @@ -1464,26 +1707,42 @@ CompositionalMultiphaseWell::applySystemSolution( DofManager const & dofManager, real64 const dt, DomainPartition & domain ) { + + + DofManager::CompMask pressureMask( m_numDofPerWellElement, 0, 1 ); + DofManager::CompMask componentMask( m_numDofPerWellElement, 1, numFluidComponents()+1 ); + DofManager::CompMask connRateMask( m_numDofPerWellElement, numFluidComponents()+1, numFluidComponents()+2 ); GEOS_UNUSED_VAR( dt ); // update all the fields using the global damping coefficients dofManager.addVectorToField( localSolution, wellElementDofName(), fields::well::pressure::key(), scalingFactor, - { m_numDofPerWellElement, 0, 1 } ); + pressureMask ); dofManager.addVectorToField( localSolution, wellElementDofName(), fields::well::globalCompDensity::key(), scalingFactor, - { m_numDofPerWellElement, 1, m_numDofPerWellElement - 1 } ); + componentMask ); dofManager.addVectorToField( localSolution, wellElementDofName(), fields::well::mixtureConnectionRate::key(), scalingFactor, - { m_numDofPerWellElement, m_numDofPerWellElement - 1, m_numDofPerWellElement } ); + connRateMask ); + + if( isThermal() ) + { + DofManager::CompMask temperatureMask( m_numDofPerWellElement, numFluidComponents()+2, numFluidComponents()+3 ); + + dofManager.addVectorToField( localSolution, + wellElementDofName(), + fields::well::temperature::key(), + scalingFactor, + temperatureMask ); + } // if component density chopping is allowed, some component densities may be negative after the update // these negative component densities are set to zero in this function if( m_allowCompDensChopping ) @@ -1497,17 +1756,28 @@ CompositionalMultiphaseWell::applySystemSolution( DofManager const & dofManager, { // synchronize FieldIdentifiers fieldsToBeSync; - - fieldsToBeSync.addElementFields( { fields::well::pressure::key(), - fields::well::globalCompDensity::key(), - fields::well::mixtureConnectionRate::key() }, - regionNames ); - + if( isThermal() ) + { + fieldsToBeSync.addElementFields( { fields::well::pressure::key(), + fields::well::globalCompDensity::key(), + fields::well::mixtureConnectionRate::key(), + fields::well::temperature::key() }, + regionNames ); + } + else + { + fieldsToBeSync.addElementFields( { fields::well::pressure::key(), + fields::well::globalCompDensity::key(), + fields::well::mixtureConnectionRate::key() }, + regionNames ); + } CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync, mesh, domain.getNeighbors(), true ); } ); + + } void CompositionalMultiphaseWell::chopNegativeDensities( DomainPartition & domain ) @@ -1571,6 +1841,15 @@ void CompositionalMultiphaseWell::resetStateToBeginningOfStep( DomainPartition & subRegion.getField< fields::well::pressure_n >(); wellElemPressure.setValues< parallelDevicePolicy<> >( wellElemPressure_n ); + if( isThermal() ) + { + // get a reference to the primary variables on well elements + arrayView1d< real64 > const & wellElemTemperature = + subRegion.getField< fields::well::temperature >(); + arrayView1d< real64 const > const & wellElemTemperature_n = + subRegion.getField< fields::well::temperature_n >(); + wellElemTemperature.setValues< parallelDevicePolicy<> >( wellElemTemperature_n ); + } arrayView2d< real64, compflow::USD_COMP > const & wellElemGlobalCompDensity = subRegion.getField< fields::well::globalCompDensity >(); arrayView2d< real64 const, compflow::USD_COMP > const & wellElemGlobalCompDensity_n = @@ -1597,9 +1876,9 @@ void CompositionalMultiphaseWell::assemblePressureRelations( real64 const & time { GEOS_MARK_FUNCTION; - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) + forDiscretizationOnMeshTargets ( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) { ElementRegionManager const & elemManager = mesh.getElemManager(); @@ -1611,170 +1890,83 @@ void CompositionalMultiphaseWell::assemblePressureRelations( real64 const & time WellControls & wellControls = getWellControls( subRegion ); - // get the degrees of freedom, depth info, next welem index - string const wellDofKey = dofManager.getKey( wellElementDofName() ); - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< real64 const > const & wellElemGravCoef = - subRegion.getField< fields::well::gravityCoefficient >(); - arrayView1d< localIndex const > const & nextWellElemIndex = - subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() ); - - // get primary variables on well elements - arrayView1d< real64 const > const & wellElemPres = - subRegion.getField< fields::well::pressure >(); - - // get total mass density on well elements (for potential calculations) - arrayView1d< real64 const > const & wellElemTotalMassDens = - subRegion.getField< fields::well::totalMassDensity >(); - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres = - subRegion.getField< fields::well::dTotalMassDensity_dPressure >(); - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens = - subRegion.getField< fields::well::dTotalMassDensity_dGlobalCompDensity >(); - - - bool controlHasSwitched = false; - isothermalCompositionalMultiphaseBaseKernels:: - KernelLaunchSelector1< PressureRelationKernel >( numFluidComponents(), - subRegion.size(), - dofManager.rankOffset(), - subRegion.isLocallyOwned(), - subRegion.getTopWellElementIndex(), - m_targetPhaseIndex, - wellControls, - time_n + dt, // controls evaluated with BHP/rate of the end of step - wellElemDofNumber, - wellElemGravCoef, - nextWellElemIndex, - wellElemPres, - wellElemTotalMassDens, - dWellElemTotalMassDens_dPres, - dWellElemTotalMassDens_dCompDens, - controlHasSwitched, - localMatrix, - localRhs ); - - if( controlHasSwitched ) + if( wellControls.isWellOpen( time_n + dt ) && !m_keepVariablesConstantDuringInitStep ) { - // TODO: move the switch logic into wellControls - // TODO: implement a more general switch when more then two constraints per well type are allowed + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + bool isThermal = fluid.isThermal(); + // get the degrees of freedom, depth info, next welem index + string const wellDofKey = dofManager.getKey( wellElementDofName() ); + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + arrayView1d< real64 const > const & wellElemGravCoef = + subRegion.getField< fields::well::gravityCoefficient >(); + arrayView1d< localIndex const > const & nextWellElemIndex = + subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() ); + + // get primary variables on well elements + arrayView1d< real64 const > const & wellElemPres = + subRegion.getField< fields::well::pressure >(); + + // get total mass density on well elements (for potential calculations) + arrayView1d< real64 const > const & wellElemTotalMassDens = + subRegion.getField< fields::well::totalMassDensity >(); + arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens = + subRegion.getField< fields::well::dTotalMassDensity >(); + + bool controlHasSwitched = false; + isothermalCompositionalMultiphaseBaseKernels:: + KernelLaunchSelectorCompTherm< compositionalMultiphaseWellKernels::PressureRelationKernel > + ( numFluidComponents(), + isThermal, + subRegion.size(), + dofManager.rankOffset(), + subRegion.isLocallyOwned(), + subRegion.getTopWellElementIndex(), + m_targetPhaseIndex, + wellControls, + time_n + dt, // controls evaluated with BHP/rate of the end of step + wellElemDofNumber, + wellElemGravCoef, + nextWellElemIndex, + wellElemPres, + wellElemTotalMassDens, + dWellElemTotalMassDens, + controlHasSwitched, + localMatrix, + localRhs ); + + if( controlHasSwitched ) + { + // TODO: move the switch logic into wellControls + // TODO: implement a more general switch when more then two constraints per well type are allowed - real64 const timeAtEndOfStep = time_n + dt; + real64 const timeAtEndOfStep = time_n + dt; - if( wellControls.getControl() == WellControls::Control::BHP ) - { - if( wellControls.isProducer() ) + if( wellControls.getControl() == WellControls::Control::BHP ) { - wellControls.switchToPhaseRateControl( wellControls.getTargetPhaseRate( timeAtEndOfStep ) ); - GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() - << " from BHP constraint to phase volumetric rate constraint" ); + if( wellControls.isProducer() ) + { + wellControls.switchToPhaseRateControl( wellControls.getTargetPhaseRate( timeAtEndOfStep ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::WellControl, + GEOS_FMT( "Control switch for well {} from BHP constraint to phase volumetric rate constraint", subRegion.getName() ) ); + } + else + { + wellControls.switchToTotalRateControl( wellControls.getTargetTotalRate( timeAtEndOfStep ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::WellControl, + GEOS_FMT( "Control switch for well {} from BHP constraint to total volumetric rate constraint", subRegion.getName()) ); + } } else { - wellControls.switchToTotalRateControl( wellControls.getTargetTotalRate( timeAtEndOfStep ) ); - GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() - << " from BHP constraint to total volumetric rate constraint" ); + wellControls.switchToBHPControl( wellControls.getTargetBHP( timeAtEndOfStep ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::WellControl, + GEOS_FMT( "Control switch for well {} from rate constraint to BHP constraint", subRegion.getName() ) ); } } - else - { - wellControls.switchToBHPControl( wellControls.getTargetBHP( timeAtEndOfStep ) ); - GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() - << " from rate constraint to BHP constraint" ); - } - } - } ); - } ); -} - -void CompositionalMultiphaseWell::shutDownWell( real64 const time_n, - real64 const dt, - DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - GEOS_MARK_FUNCTION; - - string const wellDofKey = dofManager.getKey( wellElementDofName() ); - - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) - { - - ElementRegionManager const & elemManager = mesh.getElemManager(); - - elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion const & subRegion ) - { - - // if the well is open, we don't have to do anything, so we just return - WellControls const & wellControls = getWellControls( subRegion ); - if( wellControls.isWellOpen( time_n + dt ) ) - { - return; } - globalIndex const rankOffset = dofManager.rankOffset(); - - arrayView1d< integer const > const ghostRank = - subRegion.getReference< array1d< integer > >( ObjectManagerBase::viewKeyStruct::ghostRankString() ); - arrayView1d< globalIndex const > const dofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - - arrayView1d< real64 const > const pres = - subRegion.getField< fields::well::pressure >(); - arrayView2d< real64 const, compflow::USD_COMP > const compDens = - subRegion.getField< fields::well::globalCompDensity >(); - arrayView1d< real64 const > const connRate = - subRegion.getField< fields::well::mixtureConnectionRate >(); - - integer const numComp = m_numComponents; - - forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( ghostRank[ei] >= 0 ) - { - return; - } - - globalIndex const dofIndex = dofNumber[ei]; - localIndex const localRow = dofIndex - rankOffset; - real64 rhsValue; - - // 4.1. Apply pressure value to the matrix/rhs - FieldSpecificationEqual::SpecifyFieldValue( dofIndex, - rankOffset, - localMatrix, - rhsValue, - pres[ei], // freeze the current pressure value - pres[ei] ); - localRhs[localRow] = rhsValue; - - // 4.2. For each component, apply target global density value - for( integer ic = 0; ic < numComp; ++ic ) - { - FieldSpecificationEqual::SpecifyFieldValue( dofIndex + ic + 1, - rankOffset, - localMatrix, - rhsValue, - compDens[ei][ic], // freeze the current component density values - compDens[ei][ic] ); - localRhs[localRow + ic + 1] = rhsValue; - } - - // 4.3. Apply rate value to the matrix/rhs - FieldSpecificationEqual::SpecifyFieldValue( dofIndex + numComp + 1, - rankOffset, - localMatrix, - rhsValue, - connRate[ei], // freeze the current pressure value - connRate[ei] ); - localRhs[localRow + numComp + 1] = rhsValue; - - } ); } ); } ); } @@ -1796,15 +1988,27 @@ void CompositionalMultiphaseWell::implicitStepSetup( real64 const & time_n, [&]( localIndex const, WellElementSubRegion & subRegion ) { + // get a reference to the primary variables on well elements arrayView1d< real64 const > const & wellElemPressure = subRegion.getField< fields::well::pressure >(); + arrayView2d< real64 const, compflow::USD_COMP > const & wellElemGlobalCompDensity = + subRegion.getField< fields::well::globalCompDensity >(); + arrayView1d< real64 const > const & wellElemTemperature = + subRegion.getField< fields::well::temperature >(); + arrayView1d< real64 > const & wellElemPressure_n = subRegion.getField< fields::well::pressure_n >(); wellElemPressure_n.setValues< parallelDevicePolicy<> >( wellElemPressure ); - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemGlobalCompDensity = - subRegion.getField< fields::well::globalCompDensity >(); + if( isThermal() ) + { + + arrayView1d< real64 > const & wellElemTemperature_n = + subRegion.getField< fields::well::temperature_n >(); + wellElemTemperature_n.setValues< parallelDevicePolicy<> >( wellElemTemperature ); + } + arrayView2d< real64, compflow::USD_COMP > const & wellElemGlobalCompDensity_n = subRegion.getField< fields::well::globalCompDensity_n >(); wellElemGlobalCompDensity_n.setValues< parallelDevicePolicy<> >( wellElemGlobalCompDensity ); @@ -1950,5 +2154,5 @@ void CompositionalMultiphaseWell::printRates( real64 const & time_n, } ); } -REGISTER_CATALOG_ENTRY( SolverBase, CompositionalMultiphaseWell, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, CompositionalMultiphaseWell, string const &, Group * const ) } // namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index e0b95e4799b..aa70d4f4507 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,10 +20,7 @@ #ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_COMPOSITIONALMULTIPHASEWELL_HPP_ #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_COMPOSITIONALMULTIPHASEWELL_HPP_ -#include "constitutive/fluid/multifluid/Layouts.hpp" -#include "constitutive/relativePermeability/layouts.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBase.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" namespace geos @@ -77,7 +75,7 @@ class CompositionalMultiphaseWell : public WellSolverBase */ static string catalogName() { return "CompositionalMultiphaseWell"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -164,7 +162,7 @@ class CompositionalMultiphaseWell : public WellSolverBase * @param subRegion the well subregion containing all the primary and dependent fields * @param targetIndex the targetIndex of the subRegion */ - void updatePhaseVolumeFraction( WellElementSubRegion & subRegion ) const; + real64 updatePhaseVolumeFraction( WellElementSubRegion & subRegion ) const; /** * @brief Recompute total mass densities from mass density and phase volume fractions @@ -176,13 +174,16 @@ class CompositionalMultiphaseWell : public WellSolverBase * @brief Recompute the perforation rates for all the wells * @param domain the domain containing the mesh and fields */ - virtual void computePerforationRates( DomainPartition & domain ) override; + virtual void computePerforationRates( real64 const & time_n, + real64 const & dt, DomainPartition & domain ) override; /** * @brief Recompute all dependent quantities from primary variables (including constitutive models) * @param subRegion the well subregion containing all the primary and dependent fields */ - virtual void updateSubRegionState( WellElementSubRegion & subRegion ) override; + virtual void updateState( DomainPartition & domain ) override; + + virtual real64 updateSubRegionState( WellElementSubRegion & subRegion ) override; virtual string wellElementDofName() const override { return viewKeyStruct::dofFieldString(); } @@ -192,6 +193,8 @@ class CompositionalMultiphaseWell : public WellSolverBase virtual localIndex numFluidPhases() const override { return m_numPhases; } + integer useTotalMassEquation() const { return m_useTotalMassEquation; } + /** * @brief assembles the flux terms for all connections between well elements * @param time_n previous time value @@ -201,12 +204,13 @@ class CompositionalMultiphaseWell : public WellSolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - virtual void assembleFluxTerms( real64 const dt, - DomainPartition const & domain, + + virtual void assembleFluxTerms( real64 const & time_n, + real64 const & dt, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; - + arrayView1d< real64 > const & localRhs )override; /** * @brief assembles the accumulation term for all the well elements * @param domain the physical domain object @@ -214,23 +218,13 @@ class CompositionalMultiphaseWell : public WellSolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - virtual void assembleAccumulationTerms( DomainPartition const & domain, + virtual void assembleAccumulationTerms( real64 const & time_n, + real64 const & dt, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; - /** - * @brief assembles the volume balance terms for all well elements - * @param domain the physical domain object - * @param dofManager degree-of-freedom manager associated with the linear system - * @param matrix the system matrix - * @param rhs the system right-hand side vector - */ - virtual void assembleVolumeBalanceTerms( DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; - /** * @brief assembles the pressure relations at all connections between well elements except at the well head * @param time_n time at the beginning of the time step @@ -247,22 +241,6 @@ class CompositionalMultiphaseWell : public WellSolverBase CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; - /** - * @brief apply a special treatment to the wells that are shut - * @param time_n the time at the previous converged time step - * @param dt the time step size - * @param domain the physical domain object - * @param dofManager degree-of-freedom manager associated with the linear system - * @param matrix the system matrix - * @param rhs the system right-hand side vector - */ - virtual void shutDownWell( real64 const time_n, - real64 const dt, - DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; - /** * @brief Sets all the negative component densities (if any) to zero. * @param domain the physical domain object @@ -289,17 +267,25 @@ class CompositionalMultiphaseWell : public WellSolverBase static constexpr char const * maxAbsolutePresChangeString() { return "maxAbsolutePressureChange"; } + static constexpr char const * maxRelativeCompDensChangeString() { return "maxRelativeCompDensChange"; } + + static constexpr char const * maxRelativeTempChangeString() { return "maxRelativeTemperatureChange"; } + static constexpr char const * allowLocalCompDensChoppingString() { return CompositionalMultiphaseBase::viewKeyStruct::allowLocalCompDensChoppingString(); } // control data (not registered on the mesh) + static constexpr char const * massDensityString() { return "massDensity";} + static constexpr char const * currentBHPString() { return "currentBHP"; } + static constexpr char const * dCurrentBHPString() { return "dCurrentBHP"; } static constexpr char const * dCurrentBHP_dPresString() { return "dCurrentBHP_dPres"; } - static constexpr char const * dCurrentBHP_dCompDensString() { return "dCurrentBHP_dCompDens"; } static constexpr char const * currentPhaseVolRateString() { return "currentPhaseVolumetricRate"; } + static constexpr char const * dCurrentPhaseVolRateString() { return "dCurrentPhaseVolumetricRate"; } + static constexpr char const * dCurrentPhaseVolRate_dPresString() { return "dCurrentPhaseVolumetricRate_dPres"; } @@ -308,6 +294,7 @@ class CompositionalMultiphaseWell : public WellSolverBase static constexpr char const * dCurrentPhaseVolRate_dRateString() { return "dCurrentPhaseVolumetricRate_dRate"; } static constexpr char const * currentTotalVolRateString() { return "currentTotalVolumetricRate"; } + static constexpr char const * dCurrentTotalVolRateString() { return "dCurrentTotalVolumetricRate"; } static constexpr char const * dCurrentTotalVolRate_dPresString() { return "dCurrentTotalVolumetricRate_dPres"; } @@ -319,7 +306,7 @@ class CompositionalMultiphaseWell : public WellSolverBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void initializePostSubGroups() override; @@ -354,9 +341,9 @@ class CompositionalMultiphaseWell : public WellSolverBase * @param dt the time step dt * @param subRegion the well subRegion */ - void validateWellConstraints( real64 const & time_n, - real64 const & dt, - WellElementSubRegion const & subRegion ); + virtual void validateWellConstraints( real64 const & time_n, + real64 const & dt, + WellElementSubRegion const & subRegion ) override; void printRates( real64 const & time_n, real64 const & dt, @@ -368,15 +355,11 @@ class CompositionalMultiphaseWell : public WellSolverBase * @brief Initialize all the primary and secondary variables in all the wells * @param domain the domain containing the well manager to access individual wells */ - void initializeWells( DomainPartition & domain ) override; + void initializeWells( DomainPartition & domain, real64 const & time_n, real64 const & dt ) override; virtual void setConstitutiveNames( ElementSubRegionBase & subRegion ) const override; - /// the max number of fluid phases - integer m_numPhases; - /// the number of fluid components - integer m_numComponents; /// flag indicating whether mass or molar formulation should be used integer m_useMass; @@ -396,6 +379,12 @@ class CompositionalMultiphaseWell : public WellSolverBase /// maximum (absolute) change in pressure between two Newton iterations real64 m_maxAbsolutePresChange; + /// maximum (relative) change in component density between two Newton iterations + real64 m_maxRelativeCompDensChange; + + /// maximum (relative) change in temperature in a Newton iteration + real64 m_maxRelativeTempChange; + /// minimum value of the scaling factor obtained by enforcing maxCompFracChange real64 m_minScalingFactor; @@ -405,8 +394,7 @@ class CompositionalMultiphaseWell : public WellSolverBase /// index of the target phase, used to impose the phase rate constraint localIndex m_targetPhaseIndex; - /// name of the fluid constitutive model used as a reference for component/phase description - string m_referenceFluidModelName; + }; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp index 4caa44d670b..3ca423cd7ac 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -121,21 +122,14 @@ DECLARE_FIELD( totalMassDensity, WRITE_AND_READ, "Total mass density" ); -DECLARE_FIELD( dTotalMassDensity_dPressure, - "dTotalMassDensity_dPressure", - array1d< real64 >, - 0, - NOPLOT, - NO_WRITE, - "Derivative of total mass density with respect to pressure" ); - -DECLARE_FIELD( dTotalMassDensity_dGlobalCompDensity, - "dTotalMassDensity_dComp", // to avoid a rebaseline +DECLARE_FIELD( dTotalMassDensity, + "dTotalMassDensity", array2dLayoutFluid_dC, 0, NOPLOT, NO_WRITE, - "Derivative of total mass density with respect to global component density" ); + "Derivative of total mass density with respect to pressure, temperature, and global component density" ); + DECLARE_FIELD( compPerforationRate, "compPerforationRate", @@ -145,21 +139,15 @@ DECLARE_FIELD( compPerforationRate, WRITE_AND_READ, "Component perforation rate" ); -DECLARE_FIELD( dCompPerforationRate_dPres, - "dCompPerforationRate_dPres", - array3d< real64 >, - 0, - NOPLOT, - NO_WRITE, - "Derivative of component perforation rate with respect to pressure" ); - -DECLARE_FIELD( dCompPerforationRate_dComp, - "dCompPerforationRate_dComp", +DECLARE_FIELD( dCompPerforationRate, + "dCompPerforationRate", array4d< real64 >, 0, NOPLOT, NO_WRITE, - "Derivative of component perforation rate with respect to global component density" ); + "Derivative of component perforation rate with respect to pressure temperature and global component density" ); + + DECLARE_FIELD( globalCompDensityScalingFactor, "globalCompDensityScalingFactor", @@ -169,6 +157,7 @@ DECLARE_FIELD( globalCompDensityScalingFactor, NO_WRITE, "Scaling factors for global component densities" ); + } } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp deleted file mode 100644 index 70a8e51721d..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp +++ /dev/null @@ -1,1783 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file CompositionalMultiphaseWellKernels.cpp - */ - -#include "CompositionalMultiphaseWellKernels.hpp" - -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" -// TODO: move keys to WellControls -#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp" - -namespace geos -{ - -namespace compositionalMultiphaseWellKernels -{ - -/******************************** ControlEquationHelper ********************************/ - -GEOS_HOST_DEVICE -inline -void -ControlEquationHelper:: - switchControl( bool const isProducer, - WellControls::Control const & currentControl, - integer const phasePhaseIndex, - real64 const & targetBHP, - real64 const & targetPhaseRate, - real64 const & targetTotalRate, - real64 const & currentBHP, - arrayView1d< real64 const > const & currentPhaseVolRate, - real64 const & currentTotalVolRate, - WellControls::Control & newControl ) -{ - // if isViable is true at the end of the following checks, no need to switch - bool controlIsViable = false; - - // The limiting flow rates are treated as upper limits, while the pressure limits - // are treated as lower limits in production wells and upper limits in injectors. - // The well changes its mode of control whenever the existing control mode would - // violate one of these limits. - - // Currently, the available constraints are: - // - Producer: BHP, PHASEVOLRATE - // - Injector: BHP, TOTALVOLRATE - - // TODO: support GRAT, WRAT, LIQUID for producers and check if any of the active constraint is violated - - // BHP control - if( currentControl == WellControls::Control::BHP ) - { - // the control is viable if the reference oil rate is below the max rate for producers - if( isProducer ) - { - controlIsViable = ( LvArray::math::abs( currentPhaseVolRate[phasePhaseIndex] ) <= LvArray::math::abs( targetPhaseRate ) ); - } - // the control is viable if the reference total rate is below the max rate for injectors - else - { - controlIsViable = ( LvArray::math::abs( currentTotalVolRate ) <= LvArray::math::abs( targetTotalRate ) ); - } - } - else // rate control - { - // the control is viable if the reference pressure is below/above the max/min pressure - if( isProducer ) - { - // targetBHP specifies a min pressure here - controlIsViable = ( currentBHP >= targetBHP ); - } - else - { - // targetBHP specifies a max pressure here - controlIsViable = ( currentBHP <= targetBHP ); - } - } - - if( controlIsViable ) - { - newControl = currentControl; - } - else - { - if( isProducer ) - { - newControl = ( currentControl == WellControls::Control::BHP ) - ? WellControls::Control::PHASEVOLRATE - : WellControls::Control::BHP; - } - else - { - newControl = ( currentControl == WellControls::Control::BHP ) - ? WellControls::Control::TOTALVOLRATE - : WellControls::Control::BHP; - } - } -} - -template< integer NC > -GEOS_HOST_DEVICE -inline -void -ControlEquationHelper:: - compute( globalIndex const rankOffset, - WellControls::Control const currentControl, - integer const targetPhaseIndex, - real64 const & targetBHP, - real64 const & targetPhaseRate, - real64 const & targetTotalRate, - real64 const & currentBHP, - real64 const & dCurrentBHP_dPres, - arrayView1d< real64 const > const & dCurrentBHP_dCompDens, - arrayView1d< real64 const > const & currentPhaseVolRate, - arrayView1d< real64 const > const & dCurrentPhaseVolRate_dPres, - arrayView2d< real64 const > const & dCurrentPhaseVolRate_dCompDens, - arrayView1d< real64 const > const & dCurrentPhaseVolRate_dRate, - real64 const & currentTotalVolRate, - real64 const & dCurrentTotalVolRate_dPres, - arrayView1d< real64 const > const & dCurrentTotalVolRate_dCompDens, - real64 const & dCurrentTotalVolRate_dRate, - globalIndex const dofNumber, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - localIndex const eqnRowIndex = dofNumber + ROFFSET::CONTROL - rankOffset; - globalIndex const presDofColIndex = dofNumber + COFFSET::DPRES; - globalIndex const rateDofColIndex = dofNumber + COFFSET::DCOMP + NC; - - globalIndex compDofColIndices[NC]{}; - for( integer ic = 0; ic < NC; ++ic ) - { - compDofColIndices[ ic ] = presDofColIndex + ic + 1; - } - - real64 controlEqn = 0; - real64 dControlEqn_dPres = 0; - real64 dControlEqn_dRate = 0; - real64 dControlEqn_dComp[NC]{}; - - // Note: We assume in the computation of currentBHP that the reference elevation - // is in the top well element. This is enforced by a check in the solver. - // If we wanted to allow the reference elevation to be outside the top - // well element, it would make more sense to check the BHP constraint in - // the well element that contains the reference elevation. - - // BHP control - if( currentControl == WellControls::Control::BHP ) - { - // control equation is a difference between current BHP and target BHP - controlEqn = currentBHP - targetBHP; - dControlEqn_dPres = dCurrentBHP_dPres; - for( integer ic = 0; ic < NC; ++ic ) - { - dControlEqn_dComp[ic] = dCurrentBHP_dCompDens[ic]; - } - } - // Oil volumetric rate control - else if( currentControl == WellControls::Control::PHASEVOLRATE ) - { - controlEqn = currentPhaseVolRate[targetPhaseIndex] - targetPhaseRate; - dControlEqn_dPres = dCurrentPhaseVolRate_dPres[targetPhaseIndex]; - dControlEqn_dRate = dCurrentPhaseVolRate_dRate[targetPhaseIndex]; - for( integer ic = 0; ic < NC; ++ic ) - { - dControlEqn_dComp[ic] = dCurrentPhaseVolRate_dCompDens[targetPhaseIndex][ic]; - } - } - // Total volumetric rate control - else if( currentControl == WellControls::Control::TOTALVOLRATE ) - { - controlEqn = currentTotalVolRate - targetTotalRate; - dControlEqn_dPres = dCurrentTotalVolRate_dPres; - dControlEqn_dRate = dCurrentTotalVolRate_dRate; - for( integer ic = 0; ic < NC; ++ic ) - { - dControlEqn_dComp[ic] = dCurrentTotalVolRate_dCompDens[ic]; - } - } - else - { - GEOS_ERROR( "This constraint is not supported in CompositionalMultiphaseWell" ); - } - localRhs[eqnRowIndex] += controlEqn; - localMatrix.addToRow< serialAtomic >( eqnRowIndex, - &presDofColIndex, - &dControlEqn_dPres, - 1 ); - localMatrix.addToRow< serialAtomic >( eqnRowIndex, - &rateDofColIndex, - &dControlEqn_dRate, - 1 ); - localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( eqnRowIndex, - compDofColIndices, - dControlEqn_dComp, - NC ); -} - -/******************************** FluxKernel ********************************/ - -template< integer NC > -GEOS_HOST_DEVICE -void -FluxKernel:: - computeExit( real64 const & dt, - real64 const ( &compFlux )[NC], - real64 const ( &dCompFlux_dRate )[NC], - real64 const ( &dCompFlux_dPresUp )[NC], - real64 const ( &dCompFlux_dCompDensUp )[NC][NC], - real64 ( & oneSidedFlux )[NC], - real64 ( & oneSidedFluxJacobian_dRate )[NC][1], - real64 ( & oneSidedFluxJacobian_dPresCompUp )[NC][NC + 1] ) -{ - for( integer ic = 0; ic < NC; ++ic ) - { - oneSidedFlux[ic] = -dt * compFlux[ic]; - - // derivative with respect to rate - oneSidedFluxJacobian_dRate[ic][0] = -dt * dCompFlux_dRate[ic]; - - // derivative with respect to upstream pressure - oneSidedFluxJacobian_dPresCompUp[ic][0] = -dt * dCompFlux_dPresUp[ic]; - - // derivatives with respect to upstream component densities - for( integer jdof = 0; jdof < NC; ++jdof ) - { - oneSidedFluxJacobian_dPresCompUp[ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; - } - } -} - -template< integer NC > -GEOS_HOST_DEVICE -void -FluxKernel:: - compute( real64 const & dt, - real64 const ( &compFlux )[NC], - real64 const ( &dCompFlux_dRate )[NC], - real64 const ( &dCompFlux_dPresUp )[NC], - real64 const ( &dCompFlux_dCompDensUp )[NC][NC], - real64 ( & localFlux )[2*NC], - real64 ( & localFluxJacobian_dRate )[2*NC][1], - real64 ( & localFluxJacobian_dPresCompUp )[2*NC][NC + 1] ) -{ - // flux terms - for( integer ic = 0; ic < NC; ++ic ) - { - localFlux[TAG::NEXT *NC+ic] = dt * compFlux[ic]; - localFlux[TAG::CURRENT *NC+ic] = -dt * compFlux[ic]; - - // derivative with respect to rate - localFluxJacobian_dRate[TAG::NEXT *NC+ic][0] = dt * dCompFlux_dRate[ic]; - localFluxJacobian_dRate[TAG::CURRENT *NC+ic][0] = -dt * dCompFlux_dRate[ic]; - - // derivative with respect to upstream pressure - localFluxJacobian_dPresCompUp[TAG::NEXT *NC+ic][0] = dt * dCompFlux_dPresUp[ic]; - localFluxJacobian_dPresCompUp[TAG::CURRENT *NC+ic][0] = -dt * dCompFlux_dPresUp[ic]; - - // derivatives with respect to upstream component densities - for( integer jdof = 0; jdof < NC; ++jdof ) - { - localFluxJacobian_dPresCompUp[TAG::NEXT *NC+ic][jdof+1] = dt * dCompFlux_dCompDensUp[ic][jdof]; - localFluxJacobian_dPresCompUp[TAG::CURRENT *NC+ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; - } - } -} - -template< integer NC > -void -FluxKernel:: - launch( localIndex const size, - globalIndex const rankOffset, - integer const useTotalMassEquation, - WellControls const & wellControls, - arrayView1d< globalIndex const > const & wellElemDofNumber, - arrayView1d< localIndex const > const & nextWellElemIndex, - arrayView1d< real64 const > const & connRate, - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - using namespace compositionalMultiphaseUtilities; - - bool const isProducer = wellControls.isProducer(); - arrayView1d< real64 const > const & injection = wellControls.getInjectionStream(); - - // loop over the well elements to compute the fluxes between elements - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) - { - // create local work arrays - real64 compFracUp[NC]{}; - real64 dCompFrac_dCompDensUp[NC][NC]{}; - - real64 compFlux[NC]{}; - real64 dCompFlux_dRate[NC]{}; - real64 dCompFlux_dPresUp[NC]{}; - real64 dCompFlux_dCompDensUp[NC][NC]{}; - - // Step 1) decide the upwind well element - - /* currentConnRate < 0 flow from iwelem to iwelemNext - * currentConnRate > 0 flow from iwelemNext to iwelem - * With this convention, currentConnRate < 0 at the last connection for a producer - * currentConnRate > 0 at the last connection for a injector - */ - - localIndex const iwelemNext = nextWellElemIndex[iwelem]; - real64 const currentConnRate = connRate[iwelem]; - localIndex iwelemUp = -1; - - if( iwelemNext < 0 && !isProducer ) // exit connection, injector - { - // we still need to define iwelemUp for Jacobian assembly - iwelemUp = iwelem; - - // just copy the injection stream into compFrac - for( integer ic = 0; ic < NC; ++ic ) - { - compFracUp[ic] = injection[ic]; - for( integer jc = 0; jc < NC; ++jc ) - { - dCompFrac_dCompDensUp[ic][jc] = 0.0; - } - } - } - else - { - // first set iwelemUp to the upstream cell - if( ( iwelemNext < 0 && isProducer ) // exit connection, producer - || currentConnRate < 0 ) // not an exit connection, iwelem is upstream - { - iwelemUp = iwelem; - } - else // not an exit connection, iwelemNext is upstream - { - iwelemUp = iwelemNext; - } - - // copy the vars of iwelemUp into compFrac - for( integer ic = 0; ic < NC; ++ic ) - { - compFracUp[ic] = wellElemCompFrac[iwelemUp][ic]; - for( integer jc = 0; jc < NC; ++jc ) - { - dCompFrac_dCompDensUp[ic][jc] = dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; - } - } - } - - // Step 2) compute upstream transport coefficient - - for( integer ic = 0; ic < NC; ++ic ) - { - compFlux[ic] = compFracUp[ic] * currentConnRate; - dCompFlux_dRate[ic] = compFracUp[ic]; - dCompFlux_dPresUp[ic] = 0.0; // none of these quantities depend on pressure - for( integer jc = 0; jc < NC; ++jc ) - { - dCompFlux_dCompDensUp[ic][jc] = dCompFrac_dCompDensUp[ic][jc] * currentConnRate; - } - } - - globalIndex const offsetUp = wellElemDofNumber[iwelemUp]; - globalIndex const offsetCurrent = wellElemDofNumber[iwelem]; - - if( iwelemNext < 0 ) // exit connection - { - // for this case, we only need NC mass conservation equations - // so we do not use the arrays initialized before the loop - real64 oneSidedFlux[NC]{}; - real64 oneSidedFluxJacobian_dRate[NC][1]{}; - real64 oneSidedFluxJacobian_dPresCompUp[NC][NC+1]{}; - - computeExit< NC >( dt, - compFlux, - dCompFlux_dRate, - dCompFlux_dPresUp, - dCompFlux_dCompDensUp, - oneSidedFlux, - oneSidedFluxJacobian_dRate, - oneSidedFluxJacobian_dPresCompUp ); - - - globalIndex oneSidedEqnRowIndices[NC]{}; - globalIndex oneSidedDofColIndices_dPresCompUp[NC+1]{}; - globalIndex oneSidedDofColIndices_dRate = 0; - - // jacobian indices - for( integer ic = 0; ic < NC; ++ic ) - { - // mass balance equations for all components - oneSidedEqnRowIndices[ic] = offsetUp + ROFFSET::MASSBAL + ic - rankOffset; - } - - // in the dof ordering used in this class, there are 1 pressure dofs - // and NC compDens dofs before the rate dof in this block - localIndex const dRateColOffset = COFFSET::DCOMP + NC; - oneSidedDofColIndices_dRate = offsetCurrent + dRateColOffset; - - for( integer jdof = 0; jdof < NC+1; ++jdof ) - { - // dofs are the **upstream** pressure and component densities - oneSidedDofColIndices_dPresCompUp[jdof] = offsetUp + COFFSET::DPRES + jdof; - } - - if( useTotalMassEquation > 0 ) - { - // Apply equation/variable change transformation(s) - real64 work[NC + 1]{}; - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, 1, oneSidedFluxJacobian_dRate, work ); - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC + 1, oneSidedFluxJacobian_dPresCompUp, work ); - shiftElementsAheadByOneAndReplaceFirstElementWithSum( NC, oneSidedFlux ); - } - - for( integer i = 0; i < NC; ++i ) - { - if( oneSidedEqnRowIndices[i] >= 0 && oneSidedEqnRowIndices[i] < localMatrix.numRows() ) - { - localMatrix.addToRow< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], - &oneSidedDofColIndices_dRate, - oneSidedFluxJacobian_dRate[i], - 1 ); - localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], - oneSidedDofColIndices_dPresCompUp, - oneSidedFluxJacobian_dPresCompUp[i], - NC+1 ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[oneSidedEqnRowIndices[i]], oneSidedFlux[i] ); - } - } - } - else // not an exit connection - { - real64 localFlux[2*NC]{}; - real64 localFluxJacobian_dRate[2*NC][1]{}; - real64 localFluxJacobian_dPresCompUp[2*NC][NC+1]{}; - - compute< NC >( dt, - compFlux, - dCompFlux_dRate, - dCompFlux_dPresUp, - dCompFlux_dCompDensUp, - localFlux, - localFluxJacobian_dRate, - localFluxJacobian_dPresCompUp ); - - - globalIndex eqnRowIndices[2*NC]{}; - globalIndex dofColIndices_dPresCompUp[NC+1]{}; - globalIndex dofColIndices_dRate = 0; - - globalIndex const offsetNext = wellElemDofNumber[iwelemNext]; - - // jacobian indices - for( integer ic = 0; ic < NC; ++ic ) - { - // mass balance equations for all components - eqnRowIndices[TAG::NEXT *NC+ic] = offsetNext + ROFFSET::MASSBAL + ic - rankOffset; - eqnRowIndices[TAG::CURRENT *NC+ic] = offsetCurrent + ROFFSET::MASSBAL + ic - rankOffset; - } - - // in the dof ordering used in this class, there are 1 pressure dofs - // and NC compDens dofs before the rate dof in this block - localIndex const dRateColOffset = COFFSET::DCOMP + NC; - dofColIndices_dRate = offsetCurrent + dRateColOffset; - - for( integer jdof = 0; jdof < NC+1; ++jdof ) - { - // dofs are the **upstream** pressure and component densities - dofColIndices_dPresCompUp[jdof] = offsetUp + COFFSET::DPRES + jdof; - } - - if( useTotalMassEquation > 0 ) - { - // Apply equation/variable change transformation(s) - real64 work[NC + 1]{}; - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, 1, 2, localFluxJacobian_dRate, work ); - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, NC + 1, 2, localFluxJacobian_dPresCompUp, work ); - shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( NC, NC, 2, localFlux ); - } - - for( integer i = 0; i < 2*NC; ++i ) - { - if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < localMatrix.numRows() ) - { - localMatrix.addToRow< parallelDeviceAtomic >( eqnRowIndices[i], - &dofColIndices_dRate, - localFluxJacobian_dRate[i], - 1 ); - localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], - dofColIndices_dPresCompUp, - localFluxJacobian_dPresCompUp[i], - NC+1 ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[eqnRowIndices[i]], localFlux[i] ); - } - } - } - } ); -} - -#define INST_FluxKernel( NC ) \ - template \ - void FluxKernel:: \ - launch< NC >( localIndex const size, \ - globalIndex const rankOffset, \ - integer const useTotalMassEquation, \ - WellControls const & wellControls, \ - arrayView1d< globalIndex const > const & wellElemDofNumber, \ - arrayView1d< localIndex const > const & nextWellElemIndex, \ - arrayView1d< real64 const > const & connRate, \ - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, \ - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, \ - real64 const & dt, \ - CRSMatrixView< real64, globalIndex const > const & localMatrix, \ - arrayView1d< real64 > const & localRhs ) - -INST_FluxKernel( 1 ); -INST_FluxKernel( 2 ); -INST_FluxKernel( 3 ); -INST_FluxKernel( 4 ); -INST_FluxKernel( 5 ); - -/******************************** PressureRelationKernel ********************************/ - -template< integer NC > -GEOS_HOST_DEVICE -void -PressureRelationKernel:: - compute( real64 const & gravCoef, - real64 const & gravCoefNext, - real64 const & pres, - real64 const & presNext, - real64 const & totalMassDens, - real64 const & totalMassDensNext, - real64 const & dTotalMassDens_dPres, - real64 const & dTotalMassDens_dPresNext, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDens, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDensNext, - real64 & localPresRel, - real64 ( & localPresRelJacobian )[2*(NC+1)] ) -{ - // local working variables and arrays - real64 dAvgMassDens_dCompCurrent[NC]{}; - real64 dAvgMassDens_dCompNext[NC]{}; - - // compute the average density at the interface between well elements - real64 const avgMassDens = 0.5 * ( totalMassDensNext + totalMassDens ); - real64 const dAvgMassDens_dPresNext = 0.5 * dTotalMassDens_dPresNext; - real64 const dAvgMassDens_dPresCurrent = 0.5 * dTotalMassDens_dPres; - for( integer ic = 0; ic < NC; ++ic ) - { - dAvgMassDens_dCompNext[ic] = 0.5 * dTotalMassDens_dCompDensNext[ic]; - dAvgMassDens_dCompCurrent[ic] = 0.5 * dTotalMassDens_dCompDens[ic]; - } - - // compute depth diff times acceleration - real64 const gravD = gravCoefNext - gravCoef; - - // TODO: add friction and acceleration terms - - localPresRel = ( presNext - pres - avgMassDens * gravD ); - localPresRelJacobian[TAG::NEXT *(NC+1)] = ( 1 - dAvgMassDens_dPresNext * gravD ); - localPresRelJacobian[TAG::CURRENT *(NC+1)] = ( -1 - dAvgMassDens_dPresCurrent * gravD ); - - for( integer ic = 0; ic < NC; ++ic ) - { - localPresRelJacobian[TAG::NEXT *(NC+1) + ic+1] = -dAvgMassDens_dCompNext[ic] * gravD; - localPresRelJacobian[TAG::CURRENT *(NC+1) + ic+1] = -dAvgMassDens_dCompCurrent[ic] * gravD; - } -} - -template< integer NC > -void -PressureRelationKernel:: - launch( localIndex const size, - globalIndex const rankOffset, - bool const isLocallyOwned, - localIndex const iwelemControl, - integer const targetPhaseIndex, - WellControls const & wellControls, - real64 const & timeAtEndOfStep, - arrayView1d< globalIndex const > const & wellElemDofNumber, - arrayView1d< real64 const > const & wellElemGravCoef, - arrayView1d< localIndex const > const & nextWellElemIndex, - arrayView1d< real64 const > const & wellElemPressure, - arrayView1d< real64 const > const & wellElemTotalMassDens, - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, - bool & controlHasSwitched, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - - // static well control data - bool const isProducer = wellControls.isProducer(); - WellControls::Control const currentControl = wellControls.getControl(); - real64 const targetBHP = wellControls.getTargetBHP( timeAtEndOfStep ); - real64 const targetTotalRate = wellControls.getTargetTotalRate( timeAtEndOfStep ); - real64 const targetPhaseRate = wellControls.getTargetPhaseRate( timeAtEndOfStep ); - - // dynamic well control data - real64 const & currentBHP = - wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() ); - real64 const & dCurrentBHP_dPres = - wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHP_dPresString() ); - arrayView1d< real64 const > const & dCurrentBHP_dCompDens = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHP_dCompDensString() ); - - arrayView1d< real64 const > const & currentPhaseVolRate = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ); - arrayView1d< real64 const > const & dCurrentPhaseVolRate_dPres = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dPresString() ); - arrayView2d< real64 const > const & dCurrentPhaseVolRate_dCompDens = - wellControls.getReference< array2d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dCompDensString() ); - arrayView1d< real64 const > const & dCurrentPhaseVolRate_dRate = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dRateString() ); - - real64 const & currentTotalVolRate = - wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() ); - real64 const & dCurrentTotalVolRate_dPres = - wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dPresString() ); - arrayView1d< real64 const > const & dCurrentTotalVolRate_dCompDens = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dCompDensString() ); - real64 const & dCurrentTotalVolRate_dRate = - wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dRateString() ); - - RAJA::ReduceMax< parallelDeviceReduce, localIndex > switchControl( 0 ); - - // loop over the well elements to compute the pressure relations between well elements - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) - { - localIndex const iwelemNext = nextWellElemIndex[iwelem]; - - if( iwelemNext < 0 && isLocallyOwned ) // if iwelemNext < 0, form control equation - { - WellControls::Control newControl = currentControl; - ControlEquationHelper::switchControl( isProducer, - currentControl, - targetPhaseIndex, - targetBHP, - targetPhaseRate, - targetTotalRate, - currentBHP, - currentPhaseVolRate, - currentTotalVolRate, - newControl ); - if( currentControl != newControl ) - { - switchControl.max( 1 ); - } - - ControlEquationHelper::compute< NC >( rankOffset, - newControl, - targetPhaseIndex, - targetBHP, - targetPhaseRate, - targetTotalRate, - currentBHP, - dCurrentBHP_dPres, - dCurrentBHP_dCompDens, - currentPhaseVolRate, - dCurrentPhaseVolRate_dPres, - dCurrentPhaseVolRate_dCompDens, - dCurrentPhaseVolRate_dRate, - currentTotalVolRate, - dCurrentTotalVolRate_dPres, - dCurrentTotalVolRate_dCompDens, - dCurrentTotalVolRate_dRate, - wellElemDofNumber[iwelemControl], - localMatrix, - localRhs ); - - // TODO: for consistency, we should assemble here, not in compute... - - } - else if( iwelemNext >= 0 ) // if iwelemNext >= 0, form momentum equation - { - - real64 localPresRel = 0; - real64 localPresRelJacobian[2*(NC+1)]{}; - - compute< NC >( wellElemGravCoef[iwelem], - wellElemGravCoef[iwelemNext], - wellElemPressure[iwelem], - wellElemPressure[iwelemNext], - wellElemTotalMassDens[iwelem], - wellElemTotalMassDens[iwelemNext], - dWellElemTotalMassDens_dPres[iwelem], - dWellElemTotalMassDens_dPres[iwelemNext], - dWellElemTotalMassDens_dCompDens[iwelem], - dWellElemTotalMassDens_dCompDens[iwelemNext], - localPresRel, - localPresRelJacobian ); - - - // local working variables and arrays - globalIndex dofColIndices[2*(NC+1)]; - - globalIndex const eqnRowIndex = wellElemDofNumber[iwelem] + ROFFSET::CONTROL - rankOffset; - dofColIndices[TAG::NEXT *(NC+1)] = wellElemDofNumber[iwelemNext] + COFFSET::DPRES; - dofColIndices[TAG::CURRENT *(NC+1)] = wellElemDofNumber[iwelem] + COFFSET::DPRES; - - for( integer ic = 0; ic < NC; ++ic ) - { - dofColIndices[TAG::NEXT *(NC+1) + ic+1] = wellElemDofNumber[iwelemNext] + COFFSET::DCOMP + ic; - dofColIndices[TAG::CURRENT *(NC+1) + ic+1] = wellElemDofNumber[iwelem] + COFFSET::DCOMP + ic; - } - - if( eqnRowIndex >= 0 && eqnRowIndex < localMatrix.numRows() ) - { - localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndex, - dofColIndices, - localPresRelJacobian, - 2 * (NC+1) ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[eqnRowIndex], localPresRel ); - } - } - } ); - controlHasSwitched = ( switchControl.get() == 1 ); -} - -#define INST_PressureRelationKernel( NC ) \ - template \ - void PressureRelationKernel:: \ - launch< NC >( localIndex const size, \ - globalIndex const rankOffset, \ - bool const isLocallyOwned, \ - localIndex const iwelemControl, \ - integer const targetPhaseIndex, \ - WellControls const & wellControls, \ - real64 const & timeAtEndOfStep, \ - arrayView1d< globalIndex const > const & wellElemDofNumber, \ - arrayView1d< real64 const > const & wellElemGravCoef, \ - arrayView1d< localIndex const > const & nextWellElemIndex, \ - arrayView1d< real64 const > const & wellElemPressure, \ - arrayView1d< real64 const > const & wellElemTotalMassDens, \ - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, \ - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, \ - bool & controlHasSwitched, \ - CRSMatrixView< real64, globalIndex const > const & localMatrix, \ - arrayView1d< real64 > const & localRhs ) - -INST_PressureRelationKernel( 1 ); -INST_PressureRelationKernel( 2 ); -INST_PressureRelationKernel( 3 ); -INST_PressureRelationKernel( 4 ); -INST_PressureRelationKernel( 5 ); - - -/******************************** PerforationKernel ********************************/ - -template< integer NC, integer NP > -GEOS_HOST_DEVICE -void -PerforationKernel:: - compute( bool const & disableReservoirToWellFlow, - real64 const & resPres, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & resPhaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const & dResPhaseVolFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const & dResCompFrac_dCompDens, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & resPhaseDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const & dResPhaseDens, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & resPhaseVisc, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const & dResPhaseVisc, - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > const & resPhaseCompFrac, - arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > const & dResPhaseCompFrac, - arraySlice1d< real64 const, relperm::USD_RELPERM - 2 > const & resPhaseRelPerm, - arraySlice2d< real64 const, relperm::USD_RELPERM_DS - 2 > const & dResPhaseRelPerm_dPhaseVolFrac, - real64 const & wellElemGravCoef, - real64 const & wellElemPres, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & wellElemCompDens, - real64 const & wellElemTotalMassDens, - real64 const & dWellElemTotalMassDens_dPres, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dWellElemTotalMassDens_dCompDens, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & wellElemCompFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const & dWellElemCompFrac_dCompDens, - real64 const & perfGravCoef, - real64 const & trans, - arraySlice1d< real64 > const & compPerfRate, - arraySlice2d< real64 > const & dCompPerfRate_dPres, - arraySlice3d< real64 > const & dCompPerfRate_dComp ) -{ - using Deriv = multifluid::DerivativeOffset; - - // local working variables and arrays - real64 pres[2]{}; - real64 dPres_dP[2]{}; - real64 dPres_dC[2][NC]{}; - real64 dFlux_dP[2]{}; - real64 dFlux_dC[2][NC]{}; - real64 dMult_dP[2]{}; - real64 dMult_dC[2][NC]{}; - real64 dPotDiff_dP[2]{}; - real64 dPotDiff_dC[2][NC]{}; - real64 multiplier[2]{}; - - real64 dResTotalMob_dC[NC]{}; - real64 dDens_dC[NC]{}; - real64 dVisc_dC[NC]{}; - real64 dRelPerm_dC[NC]{}; - real64 dMob_dC[NC]{}; - real64 dCompFrac_dCompDens[NC]{}; - - - // Step 1: reset the perforation rates - - for( integer ic = 0; ic < NC; ++ic ) - { - compPerfRate[ic] = 0.0; - for( integer ke = 0; ke < 2; ++ke ) - { - dCompPerfRate_dPres[ke][ic] = 0.0; - for( integer jc = 0; jc < NC; ++jc ) - { - dCompPerfRate_dComp[ke][ic][jc] = 0.0; - } - } - } - - - // Step 2: copy the variables from the reservoir and well element - - // a) get reservoir variables - - pres[TAG::RES] = resPres; - dPres_dP[TAG::RES] = 1.0; - multiplier[TAG::RES] = 1.0; - - // Here in the absence of a buoyancy term we assume that the reservoir cell is perforated at its center - // TODO: add a buoyancy term for the reservoir side here - - - // b) get well variables - - pres[TAG::WELL] = wellElemPres; - dPres_dP[TAG::WELL] = 1.0; - multiplier[TAG::WELL] = -1.0; - - real64 const gravD = ( perfGravCoef - wellElemGravCoef ); - - pres[TAG::WELL] += wellElemTotalMassDens * gravD; - dPres_dP[TAG::WELL] += dWellElemTotalMassDens_dPres * gravD; - for( integer ic = 0; ic < NC; ++ic ) - { - dPres_dC[TAG::WELL][ic] += dWellElemTotalMassDens_dCompDens[ic] * gravD; - } - - - // Step 3: compute potential difference - - real64 potDiff = 0.0; - for( integer i = 0; i < 2; ++i ) - { - potDiff += multiplier[i] * trans * pres[i]; - dPotDiff_dP[i] += multiplier[i] * trans * dPres_dP[i]; - - for( integer ic = 0; ic < NC; ++ic ) - { - dPotDiff_dC[i][ic] += multiplier[i] * trans * dPres_dC[i][ic]; - } - } - - - // Step 4: upwinding based on the flow direction - - real64 flux = 0.0; - if( potDiff >= 0 ) // ** reservoir cell is upstream ** - { - - // loop over phases, compute and upwind phase flux - // and sum contributions to each component's perforation rate - for( integer ip = 0; ip < NP; ++ip ) - { - - // skip the rest of the calculation if the phase is absent - // or if crossflow is disabled for injectors - bool const phaseExists = (resPhaseVolFrac[ip] > 0); - if( !phaseExists || disableReservoirToWellFlow ) - { - continue; - } - - // here, we have to recompute the reservoir phase mobility (not including density) - - // density - real64 const resDens = resPhaseDens[ip]; - real64 const dResDens_dP = dResPhaseDens[ip][Deriv::dP]; - applyChainRule( NC, dResCompFrac_dCompDens, - dResPhaseDens[ip], - dDens_dC, - Deriv::dC ); - - // viscosity - real64 const resVisc = resPhaseVisc[ip]; - real64 const dResVisc_dP = dResPhaseVisc[ip][Deriv::dP]; - applyChainRule( NC, dResCompFrac_dCompDens, - dResPhaseVisc[ip], - dVisc_dC, - Deriv::dC ); - - // relative permeability - real64 const resRelPerm = resPhaseRelPerm[ip]; - real64 dResRelPerm_dP = 0.0; - for( integer jc = 0; jc < NC; ++jc ) - { - dRelPerm_dC[jc] = 0; - } - - for( integer jp = 0; jp < NP; ++jp ) - { - real64 const dResRelPerm_dS = dResPhaseRelPerm_dPhaseVolFrac[ip][jp]; - dResRelPerm_dP += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dP]; - - for( integer jc = 0; jc < NC; ++jc ) - { - dRelPerm_dC[jc] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dC+jc]; - } - } - - // compute the reservoir phase mobility, including phase density - real64 const resPhaseMob = resDens * resRelPerm / resVisc; - real64 const dResPhaseMob_dPres = dResRelPerm_dP * resDens / resVisc - + resPhaseMob * (dResDens_dP / resDens - dResVisc_dP / resVisc); - for( integer jc = 0; jc < NC; ++jc ) - { - dMob_dC[jc] = dRelPerm_dC[jc] * resDens / resVisc - + resPhaseMob * (dDens_dC[jc] / resDens - dVisc_dC[jc] / resVisc); - } - - // compute the phase flux and derivatives using upstream cell mobility - flux = resPhaseMob * potDiff; - dFlux_dP[TAG::RES] = dResPhaseMob_dPres * potDiff + resPhaseMob * dPotDiff_dP[TAG::RES]; - dFlux_dP[TAG::WELL] = resPhaseMob * dPotDiff_dP[TAG::WELL]; - - for( integer ic = 0; ic < NC; ++ic ) - { - dFlux_dC[TAG::RES][ic] = dMob_dC[ic] * potDiff + resPhaseMob * dPotDiff_dC[TAG::RES][ic]; - dFlux_dC[TAG::WELL][ic] = resPhaseMob * dPotDiff_dC[TAG::WELL][ic]; - } - - // increment component fluxes - for( integer ic = 0; ic < NC; ++ic ) - { - compPerfRate[ic] += flux * resPhaseCompFrac[ip][ic]; - - dCompPerfRate_dPres[TAG::RES][ic] += resPhaseCompFrac[ip][ic] * dFlux_dP[TAG::RES]; - dCompPerfRate_dPres[TAG::RES][ic] += dResPhaseCompFrac[ip][ic][Deriv::dP] * flux; - dCompPerfRate_dPres[TAG::WELL][ic] += resPhaseCompFrac[ip][ic] * dFlux_dP[TAG::WELL]; - - applyChainRule( NC, - dResCompFrac_dCompDens, - dResPhaseCompFrac[ip][ic], - dCompFrac_dCompDens, - Deriv::dC ); - - for( integer jc = 0; jc < NC; ++jc ) - { - dCompPerfRate_dComp[TAG::RES][ic][jc] += dFlux_dC[TAG::RES][jc] * resPhaseCompFrac[ip][ic]; - dCompPerfRate_dComp[TAG::RES][ic][jc] += flux * dCompFrac_dCompDens[jc]; - dCompPerfRate_dComp[TAG::WELL][ic][jc] += dFlux_dC[TAG::WELL][jc] * resPhaseCompFrac[ip][ic]; - } - } - } - } - else // ** well is upstream ** - { - - real64 resTotalMob = 0.0; - real64 dResTotalMob_dP = 0.0; - - // we re-compute here the total mass (when useMass == 1) or molar (when useMass == 0) density - real64 wellElemTotalDens = 0; - for( integer ic = 0; ic < NC; ++ic ) - { - wellElemTotalDens += wellElemCompDens[ic]; - } - - // first, compute the reservoir total mobility (excluding phase density) - for( integer ip = 0; ip < NP; ++ip ) - { - - // skip the rest of the calculation if the phase is absent - bool const phaseExists = (resPhaseVolFrac[ip] > 0); - if( !phaseExists ) - { - continue; - } - - // viscosity - real64 const resVisc = resPhaseVisc[ip]; - real64 const dResVisc_dP = dResPhaseVisc[ip][Deriv::dP]; - applyChainRule( NC, dResCompFrac_dCompDens, - dResPhaseVisc[ip], - dVisc_dC, - Deriv::dC ); - - // relative permeability - real64 const resRelPerm = resPhaseRelPerm[ip]; - real64 dResRelPerm_dP = 0.0; - for( integer jc = 0; jc < NC; ++jc ) - { - dRelPerm_dC[jc] = 0; - } - - for( integer jp = 0; jp < NP; ++jp ) - { - real64 const dResRelPerm_dS = dResPhaseRelPerm_dPhaseVolFrac[ip][jp]; - dResRelPerm_dP += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dP]; - - for( integer jc = 0; jc < NC; ++jc ) - { - dRelPerm_dC[jc] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dC+jc]; - } - } - - // increment total mobility - resTotalMob += resRelPerm / resVisc; - dResTotalMob_dP += ( dResRelPerm_dP * resVisc - resRelPerm * dResVisc_dP ) - / ( resVisc * resVisc ); - for( integer ic = 0; ic < NC; ++ic ) - { - dResTotalMob_dC[ic] += ( dRelPerm_dC[ic] * resVisc - resRelPerm * dVisc_dC[ic] ) - / ( resVisc * resVisc ); - } - } - - // compute a potdiff multiplier = wellElemTotalDens * resTotalMob - // wellElemTotalDens is a mass density if useMass == 1 and a molar density otherwise - real64 const mult = wellElemTotalDens * resTotalMob; - dMult_dP[TAG::RES] = wellElemTotalDens * dResTotalMob_dP; - dMult_dP[TAG::WELL] = 0.0; // because totalDens does not depend on pressure - - for( integer ic = 0; ic < NC; ++ic ) - { - dMult_dC[TAG::RES][ic] = wellElemTotalDens * dResTotalMob_dC[ic]; - dMult_dC[TAG::WELL][ic] = resTotalMob; - } - - // compute the volumetric flux and derivatives using upstream cell mobility - flux = mult * potDiff; - dFlux_dP[TAG::RES] = dMult_dP[TAG::RES] * potDiff + mult * dPotDiff_dP[TAG::RES]; - dFlux_dP[TAG::WELL] = dMult_dP[TAG::WELL] * potDiff + mult * dPotDiff_dP[TAG::WELL]; - - for( integer ic = 0; ic < NC; ++ic ) - { - dFlux_dC[TAG::RES][ic] = dMult_dC[TAG::RES][ic] * potDiff + mult * dPotDiff_dC[TAG::RES][ic]; - dFlux_dC[TAG::WELL][ic] = dMult_dC[TAG::WELL][ic] * potDiff + mult * dPotDiff_dC[TAG::WELL][ic]; - } - - // compute component fluxes - for( integer ic = 0; ic < NC; ++ic ) - { - compPerfRate[ic] += wellElemCompFrac[ic] * flux; - dCompPerfRate_dPres[TAG::RES][ic] = wellElemCompFrac[ic] * dFlux_dP[TAG::RES]; - dCompPerfRate_dPres[TAG::WELL][ic] = wellElemCompFrac[ic] * dFlux_dP[TAG::WELL]; - - for( integer jc = 0; jc < NC; ++jc ) - { - dCompPerfRate_dComp[TAG::RES][ic][jc] += wellElemCompFrac[ic] * dFlux_dC[TAG::RES][jc]; - dCompPerfRate_dComp[TAG::WELL][ic][jc] += wellElemCompFrac[ic] * dFlux_dC[TAG::WELL][jc]; - dCompPerfRate_dComp[TAG::WELL][ic][jc] += dWellElemCompFrac_dCompDens[ic][jc] * flux; - } - } - } -} - -template< integer NC, integer NP > -void -PerforationKernel:: - launch( localIndex const size, - bool const disableReservoirToWellFlow, - ElementViewConst< arrayView1d< real64 const > > const & resPres, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & resPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dResPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dResCompFrac_dCompDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & resPhaseDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dResPhaseDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & resPhaseVisc, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dResPhaseVisc, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & resPhaseCompFrac, - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dResPhaseCompFrac, - ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const & resPhaseRelPerm, - ElementViewConst< arrayView4d< real64 const, relperm::USD_RELPERM_DS > > const & dResPhaseRelPerm_dPhaseVolFrac, - arrayView1d< real64 const > const & wellElemGravCoef, - arrayView1d< real64 const > const & wellElemPres, - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompDens, - arrayView1d< real64 const > const & wellElemTotalMassDens, - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, - arrayView1d< real64 const > const & perfGravCoef, - arrayView1d< localIndex const > const & perfWellElemIndex, - arrayView1d< real64 const > const & perfTrans, - arrayView1d< localIndex const > const & resElementRegion, - arrayView1d< localIndex const > const & resElementSubRegion, - arrayView1d< localIndex const > const & resElementIndex, - arrayView2d< real64 > const & compPerfRate, - arrayView3d< real64 > const & dCompPerfRate_dPres, - arrayView4d< real64 > const & dCompPerfRate_dComp ) -{ - - // loop over the perforations to compute the perforation rates - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const iperf ) - { - - // get the index of the reservoir elem - localIndex const er = resElementRegion[iperf]; - localIndex const esr = resElementSubRegion[iperf]; - localIndex const ei = resElementIndex[iperf]; - - // get the index of the well elem - localIndex const iwelem = perfWellElemIndex[iperf]; - - compute< NC, NP >( disableReservoirToWellFlow, - resPres[er][esr][ei], - resPhaseVolFrac[er][esr][ei], - dResPhaseVolFrac[er][esr][ei], - dResCompFrac_dCompDens[er][esr][ei], - resPhaseDens[er][esr][ei][0], - dResPhaseDens[er][esr][ei][0], - resPhaseVisc[er][esr][ei][0], - dResPhaseVisc[er][esr][ei][0], - resPhaseCompFrac[er][esr][ei][0], - dResPhaseCompFrac[er][esr][ei][0], - resPhaseRelPerm[er][esr][ei][0], - dResPhaseRelPerm_dPhaseVolFrac[er][esr][ei][0], - wellElemGravCoef[iwelem], - wellElemPres[iwelem], - wellElemCompDens[iwelem], - wellElemTotalMassDens[iwelem], - dWellElemTotalMassDens_dPres[iwelem], - dWellElemTotalMassDens_dCompDens[iwelem], - wellElemCompFrac[iwelem], - dWellElemCompFrac_dCompDens[iwelem], - perfGravCoef[iperf], - perfTrans[iperf], - compPerfRate[iperf], - dCompPerfRate_dPres[iperf], - dCompPerfRate_dComp[iperf] ); - - } ); -} - -#define INST_PerforationKernel( NC, NP ) \ - template \ - void PerforationKernel:: \ - launch< NC, NP >( localIndex const size, \ - bool const disableReservoirToWellFlow, \ - ElementViewConst< arrayView1d< real64 const > > const & resPres, \ - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & resPhaseVolFrac, \ - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dResPhaseVolFrac, \ - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dResCompFrac_dCompDens, \ - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & resPhaseDens, \ - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dResPhaseDens, \ - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & resPhaseVisc, \ - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dResPhaseVisc, \ - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & resPhaseCompFrac, \ - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dResPhaseCompFrac, \ - ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const & resPhaseRelPerm, \ - ElementViewConst< arrayView4d< real64 const, relperm::USD_RELPERM_DS > > const & dResPhaseRelPerm_dPhaseVolFrac, \ - arrayView1d< real64 const > const & wellElemGravCoef, \ - arrayView1d< real64 const > const & wellElemPres, \ - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompDens, \ - arrayView1d< real64 const > const & wellElemTotalMassDens, \ - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, \ - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, \ - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, \ - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, \ - arrayView1d< real64 const > const & perfGravCoef, \ - arrayView1d< localIndex const > const & perfWellElemIndex, \ - arrayView1d< real64 const > const & perfTrans, \ - arrayView1d< localIndex const > const & resElementRegion, \ - arrayView1d< localIndex const > const & resElementSubRegion, \ - arrayView1d< localIndex const > const & resElementIndex, \ - arrayView2d< real64 > const & compPerfRate, \ - arrayView3d< real64 > const & dCompPerfRate_dPres, \ - arrayView4d< real64 > const & dCompPerfRate_dComp ) - -INST_PerforationKernel( 1, 2 ); -INST_PerforationKernel( 2, 2 ); -INST_PerforationKernel( 3, 2 ); -INST_PerforationKernel( 4, 2 ); -INST_PerforationKernel( 5, 2 ); -INST_PerforationKernel( 1, 3 ); -INST_PerforationKernel( 2, 3 ); -INST_PerforationKernel( 3, 3 ); -INST_PerforationKernel( 4, 3 ); -INST_PerforationKernel( 5, 3 ); - -/******************************** AccumulationKernel ********************************/ - -template< integer NC > -GEOS_HOST_DEVICE -void -AccumulationKernel:: - compute( integer const numPhases, - real64 const & volume, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const & dPhaseVolFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const & dCompFrac_dCompDens, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & phaseDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const & dPhaseDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > const & phaseCompFrac, - arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > const & dPhaseCompFrac, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFrac_n, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & phaseDens_n, - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > const & phaseCompFrac_n, - real64 ( & localAccum )[NC], - real64 ( & localAccumJacobian )[NC][NC + 1] ) -{ - using Deriv = multifluid::DerivativeOffset; - - // temporary work arrays - real64 dPhaseAmount_dC[NC]{}; - real64 dPhaseCompFrac_dC[NC]{}; - - // reset the local values - for( integer i = 0; i < NC; ++i ) - { - localAccum[i] = 0.0; - for( integer j = 0; j < NC+1; ++j ) - { - localAccumJacobian[i][j] = 0.0; - } - } - - // sum contributions to component accumulation from each phase - for( integer ip = 0; ip < numPhases; ++ip ) - { - real64 const phaseAmountNew = volume * phaseVolFrac[ip] * phaseDens[ip]; - real64 const phaseAmount_n = volume * phaseVolFrac_n[ip] * phaseDens_n[ip]; - - real64 const dPhaseAmount_dP = volume * ( dPhaseVolFrac[ip][Deriv::dP] * phaseDens[ip] - + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP] ); - - // assemble density dependence - applyChainRule( NC, dCompFrac_dCompDens, dPhaseDens[ip], dPhaseAmount_dC, Deriv::dC ); - for( integer jc = 0; jc < NC; ++jc ) - { - dPhaseAmount_dC[jc] = dPhaseAmount_dC[jc] * phaseVolFrac[ip] - + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC+jc]; - dPhaseAmount_dC[jc] *= volume; - } - - // ic - index of component whose conservation equation is assembled - // (i.e. row number in local matrix) - for( integer ic = 0; ic < NC; ++ic ) - { - real64 const phaseCompAmountNew = phaseAmountNew * phaseCompFrac[ip][ic]; - real64 const phaseCompAmount_n = phaseAmount_n * phaseCompFrac_n[ip][ic]; - - real64 const dPhaseCompAmount_dP = dPhaseAmount_dP * phaseCompFrac[ip][ic] - + phaseAmountNew * dPhaseCompFrac[ip][ic][Deriv::dP]; - - localAccum[ic] += phaseCompAmountNew - phaseCompAmount_n; - localAccumJacobian[ic][0] += dPhaseCompAmount_dP; - - // jc - index of component w.r.t. whose compositional var the derivative is being taken - // (i.e. col number in local matrix) - - // assemble phase composition dependence - applyChainRule( NC, dCompFrac_dCompDens, dPhaseCompFrac[ip][ic], dPhaseCompFrac_dC, Deriv::dC ); - for( integer jc = 0; jc < NC; ++jc ) - { - real64 const dPhaseCompAmount_dC = dPhaseCompFrac_dC[jc] * phaseAmountNew - + phaseCompFrac[ip][ic] * dPhaseAmount_dC[jc]; - localAccumJacobian[ic][jc + 1] += dPhaseCompAmount_dC; - } - } - } -} - -template< integer NC > -void -AccumulationKernel:: - launch( localIndex const size, - integer const numPhases, - globalIndex const rankOffset, - integer const useTotalMassEquation, - arrayView1d< globalIndex const > const & wellElemDofNumber, - arrayView1d< integer const > const & wellElemGhostRank, - arrayView1d< real64 const > const & wellElemVolume, - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac, - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac, - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens, - arrayView4d< real64 const, multifluid::USD_PHASE_DC > const & dWellElemPhaseDens, - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac, - arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > const & dWellElemPhaseCompFrac, - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac_n, - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens_n, - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac_n, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - - using namespace compositionalMultiphaseUtilities; - - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) - { - - if( wellElemGhostRank[iwelem] >= 0 ) - { - return; - } - - real64 localAccum[NC]{}; - real64 localAccumJacobian[NC][NC+1]{}; - - compute< NC >( numPhases, - wellElemVolume[iwelem], - wellElemPhaseVolFrac[iwelem], - dWellElemPhaseVolFrac[iwelem], - dWellElemCompFrac_dCompDens[iwelem], - wellElemPhaseDens[iwelem][0], - dWellElemPhaseDens[iwelem][0], - wellElemPhaseCompFrac[iwelem][0], - dWellElemPhaseCompFrac[iwelem][0], - wellElemPhaseVolFrac_n[iwelem], - wellElemPhaseDens_n[iwelem][0], - wellElemPhaseCompFrac_n[iwelem][0], - localAccum, - localAccumJacobian ); - - // set the equation row indices to be the mass balance equations for all components - localIndex eqnRowIndices[NC]{}; - for( integer ic = 0; ic < NC; ++ic ) - { - eqnRowIndices[ic] = wellElemDofNumber[iwelem] + ROFFSET::MASSBAL + ic - rankOffset; - } - - // set DOF col indices for this block - globalIndex dofColIndices[NC+1]{}; - for( integer idof = 0; idof < NC+1; ++idof ) - { - dofColIndices[idof] = wellElemDofNumber[iwelem] + COFFSET::DPRES + idof; - } - - if( useTotalMassEquation > 0 ) - { - // Apply equation/variable change transformation(s) - real64 work[NC + 1]; - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC + 1, localAccumJacobian, work ); - shiftElementsAheadByOneAndReplaceFirstElementWithSum( NC, localAccum ); - } - - // add contribution to residual and jacobian - for( integer ic = 0; ic < NC; ++ic ) - { - localRhs[eqnRowIndices[ic]] += localAccum[ic]; - localMatrix.addToRow< serialAtomic >( eqnRowIndices[ic], - dofColIndices, - localAccumJacobian[ic], - NC+1 ); - } - } ); -} - -#define INST_AccumulationKernel( NC ) \ - template \ - void AccumulationKernel:: \ - launch< NC >( localIndex const size, \ - integer const numPhases, \ - globalIndex const rankOffset, \ - integer const useTotalMassEquation, \ - arrayView1d< globalIndex const > const & wellElemDofNumber, \ - arrayView1d< integer const > const & wellElemGhostRank, \ - arrayView1d< real64 const > const & wellElemVolume, \ - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac, \ - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac, \ - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, \ - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens, \ - arrayView4d< real64 const, multifluid::USD_PHASE_DC > const & dWellElemPhaseDens, \ - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac, \ - arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > const & dWellElemPhaseCompFrac, \ - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac_n, \ - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens_n, \ - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac_n, \ - CRSMatrixView< real64, globalIndex const > const & localMatrix, \ - arrayView1d< real64 > const & localRhs ) - -INST_AccumulationKernel( 1 ); -INST_AccumulationKernel( 2 ); -INST_AccumulationKernel( 3 ); -INST_AccumulationKernel( 4 ); -INST_AccumulationKernel( 5 ); - -/******************************** VolumeBalanceKernel ********************************/ - -template< integer NC > -GEOS_HOST_DEVICE -void -VolumeBalanceKernel:: - compute( integer const numPhases, - real64 const & volume, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const & dPhaseVolFrac, - real64 & localVolBalance, - real64 ( & localVolBalanceJacobian )[NC+1] ) -{ - using Deriv = multifluid::DerivativeOffset; - - localVolBalance = 1.0; - for( integer ic = 0; ic < NC+1; ++ic ) - { - localVolBalanceJacobian[ic] = 0.0; - } - - // sum contributions to component accumulation from each phase - for( integer ip = 0; ip < numPhases; ++ip ) - { - localVolBalance -= phaseVolFrac[ip]; - localVolBalanceJacobian[0] -= dPhaseVolFrac[ip][Deriv::dP]; - - for( integer jc = 0; jc < NC; ++jc ) - { - localVolBalanceJacobian[jc + 1] -= dPhaseVolFrac[ip][Deriv::dC+jc]; - } - } - - // scale saturation-based volume balance by pore volume (for better scaling w.r.t. other equations) - for( integer idof = 0; idof < NC+1; ++idof ) - { - localVolBalanceJacobian[idof] *= volume; - } - localVolBalance *= volume; -} - -template< integer NC > -void -VolumeBalanceKernel:: - launch( localIndex const size, - integer const numPhases, - globalIndex const rankOffset, - arrayView1d< globalIndex const > const & wellElemDofNumber, - arrayView1d< integer const > const & wellElemGhostRank, - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac, - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac, - arrayView1d< real64 const > const & wellElemVolume, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) - { - - if( wellElemGhostRank[iwelem] >= 0 ) - { - return; - } - - real64 localVolBalance = 1.0; - real64 localVolBalanceJacobian[NC+1]{}; - - compute< NC >( numPhases, - wellElemVolume[iwelem], - wellElemPhaseVolFrac[iwelem], - dWellElemPhaseVolFrac[iwelem], - localVolBalance, - localVolBalanceJacobian ); - - // get equation/dof indices - localIndex const localVolBalanceEqnIndex = wellElemDofNumber[iwelem] - rankOffset + ROFFSET::MASSBAL + NC; - globalIndex localVolBalanceDOF[NC+1]{}; - for( integer jdof = 0; jdof < NC+1; ++jdof ) - { - localVolBalanceDOF[jdof] = wellElemDofNumber[iwelem] + COFFSET::DPRES + jdof; - } - - localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( localVolBalanceEqnIndex, - localVolBalanceDOF, - localVolBalanceJacobian, - NC+1 ); - localRhs[localVolBalanceEqnIndex] += localVolBalance; - } ); -} - -#define INST_VolumeBalanceKernel( NC ) \ - template \ - void VolumeBalanceKernel:: \ - launch< NC >( localIndex const size, \ - integer const numPhases, \ - globalIndex const rankOffset, \ - arrayView1d< globalIndex const > const & wellElemDofNumber, \ - arrayView1d< integer const > const & wellElemGhostRank, \ - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac, \ - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac, \ - arrayView1d< real64 const > const & wellElemVolume, \ - CRSMatrixView< real64, globalIndex const > const & localMatrix, \ - arrayView1d< real64 > const & localRhs ) - -INST_VolumeBalanceKernel( 1 ); -INST_VolumeBalanceKernel( 2 ); -INST_VolumeBalanceKernel( 3 ); -INST_VolumeBalanceKernel( 4 ); -INST_VolumeBalanceKernel( 5 ); - -/******************************** PresTempCompFracInitializationKernel ********************************/ - -void -PresTempCompFracInitializationKernel:: - launch( localIndex const perforationSize, - localIndex const subRegionSize, - integer const numComps, - integer const numPhases, - localIndex const numPerforations, - WellControls const & wellControls, - real64 const & currentTime, - ElementViewConst< arrayView1d< real64 const > > const & resPres, - ElementViewConst< arrayView1d< real64 const > > const & resTemp, - ElementViewConst< arrayView2d< real64 const, compflow::USD_COMP > > const & resCompDens, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & resPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & resPhaseMassDens, - arrayView1d< localIndex const > const & resElementRegion, - arrayView1d< localIndex const > const & resElementSubRegion, - arrayView1d< localIndex const > const & resElementIndex, - arrayView1d< real64 const > const & perfGravCoef, - arrayView1d< real64 const > const & wellElemGravCoef, - arrayView1d< real64 > const & wellElemPres, - arrayView1d< real64 > const & wellElemTemp, - arrayView2d< real64, compflow::USD_COMP > const & wellElemCompFrac ) -{ - integer constexpr MAX_NUM_COMP = constitutive::MultiFluidBase::MAX_NUM_COMPONENTS; - - real64 const targetBHP = wellControls.getTargetBHP( currentTime ); - real64 const refWellElemGravCoef = wellControls.getReferenceGravityCoef(); - real64 const initialPresCoef = wellControls.getInitialPressureCoefficient(); - WellControls::Control const currentControl = wellControls.getControl(); - bool const isProducer = wellControls.isProducer(); - - - - // Step 1: we loop over all the perforations on this rank to compute the following quantities: - // - Sum of total mass densities over the perforated reservoir elements - // - Sum of the temperatures over the perforated reservoir elements - // - Sum of the component fractions over the perforated reservoir elements - // In passing, we save the min gravCoef difference between the reference depth and the perforation depth - // Note that we use gravCoef instead of depth for the (unlikely) case in which the gravityVector is not aligned with z - - RAJA::ReduceSum< parallelDeviceReduce, real64 > sumTotalMassDens( 0 ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > sumTemp( 0 ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > sumCompFrac[MAX_NUM_COMP]{}; - RAJA::ReduceMin< parallelDeviceReduce, real64 > localMinGravCoefDiff( 1e9 ); - - forAll< parallelDevicePolicy<> >( perforationSize, [=] GEOS_HOST_DEVICE ( localIndex const iperf ) - { - // get the reservoir (sub)region and element indices - localIndex const er = resElementRegion[iperf]; - localIndex const esr = resElementSubRegion[iperf]; - localIndex const ei = resElementIndex[iperf]; - - // save the min gravCoef difference between the reference depth and the perforation depth (times g) - localMinGravCoefDiff.min( LvArray::math::abs( refWellElemGravCoef - perfGravCoef[iperf] ) ); - - // increment the temperature - sumTemp += resTemp[er][esr][ei]; - - // increment the total mass density - for( integer ip = 0; ip < numPhases; ++ip ) - { - sumTotalMassDens += resPhaseVolFrac[er][esr][ei][ip] * resPhaseMassDens[er][esr][ei][0][ip]; - } - - // increment the component fractions - real64 perfTotalDens = 0.0; - for( integer ic = 0; ic < numComps; ++ic ) - { - perfTotalDens += resCompDens[er][esr][ei][ic]; - } - for( integer ic = 0; ic < numComps; ++ic ) - { - sumCompFrac[ic] += resCompDens[er][esr][ei][ic] / perfTotalDens; - } - } ); - real64 const minGravCoefDiff = MpiWrapper::min( localMinGravCoefDiff.get() ); - - - - // Step 2: we assign average quantities over the well (i.e., over all the ranks) - // For composition and temperature, we make a distinction between injection and production - - // for total mass density, we always use the values of the perforated reservoir elements, even for injectors - real64 const avgTotalMassDens = MpiWrapper::sum( sumTotalMassDens.get() ) / numPerforations; - - stackArray1d< real64, MAX_NUM_COMP > avgCompFrac( numComps ); - real64 avgTemp = 0; - - // for a producer, we use the temperature and component fractions from the reservoir - if( isProducer ) - { - // use average temperature from reservoir - avgTemp = MpiWrapper::sum( sumTemp.get() ) / numPerforations; - - // use average comp frac from reservoir - for( integer ic = 0; ic < numComps; ++ic ) - { - avgCompFrac[ic] = MpiWrapper::sum( sumCompFrac[ic].get() ) / numPerforations; - } - } - // for an injector, we use the injection stream values - else - { - // use temperature from injection stream - avgTemp = wellControls.getInjectionTemperature(); - - // use comp frac from injection stream - for( integer ic = 0; ic < numComps; ++ic ) - { - avgCompFrac[ic] = wellControls.getInjectionStream()[ic]; - } - } - - - - // Step 3: we compute the approximate pressure at the reference depth - // We make a distinction between pressure-controlled wells and rate-controlled wells - - real64 refPres = 0.0; - - // if the well is controlled by pressure, initialize the reference pressure at the target pressure - if( currentControl == WellControls::Control::BHP ) - { - refPres = targetBHP; - } - // if the well is controlled by rate, initialize the reference pressure using the pressure at the closest perforation - else - { - RAJA::ReduceMin< parallelDeviceReduce, real64 > localRefPres( 1e9 ); - real64 const alpha = ( isProducer ) ? 1 - initialPresCoef : 1 + initialPresCoef; - - forAll< parallelDevicePolicy<> >( perforationSize, [=] GEOS_HOST_DEVICE ( localIndex const iperf ) - { - // get the reservoir (sub)region and element indices - localIndex const er = resElementRegion[iperf]; - localIndex const esr = resElementSubRegion[iperf]; - localIndex const ei = resElementIndex[iperf]; - - // get the perforation pressure and save the estimated reference pressure - real64 const gravCoefDiff = LvArray::math::abs( refWellElemGravCoef - perfGravCoef[iperf] ); - if( isZero( gravCoefDiff - minGravCoefDiff ) ) - { - localRefPres.min( alpha * resPres[er][esr][ei] + avgTotalMassDens * ( refWellElemGravCoef - perfGravCoef[iperf] ) ); - } - } ); - refPres = MpiWrapper::min( localRefPres.get() ); - } - - - - // Step 4: we are ready to assign the primary variables on the well elements: - // - pressure: hydrostatic pressure using our crude approximation of the total mass density - // - temperature: uniform, using the average temperature computed above - // - component fraction: uniform, using the average component fraction computed above - - RAJA::ReduceMax< parallelDeviceReduce, integer > foundNegativeTemp( 0 ); - RAJA::ReduceMax< parallelDeviceReduce, integer > foundNegativePres( 0 ); - RAJA::ReduceMax< parallelDeviceReduce, integer > foundInconsistentCompFrac( 0 ); - - - forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) - { - wellElemPres[iwelem] = refPres + avgTotalMassDens * ( wellElemGravCoef[iwelem] - refWellElemGravCoef ); - wellElemTemp[iwelem] = avgTemp; - - real64 sumCompFracForCheck = 0.0; - for( integer ic = 0; ic < numComps; ++ic ) - { - wellElemCompFrac[iwelem][ic] = avgCompFrac[ic]; - sumCompFracForCheck += wellElemCompFrac[iwelem][ic]; - } - - if( wellElemPres[iwelem] <= 0 ) - { - foundNegativePres.max( 1 ); - } - if( wellElemTemp[iwelem] <= 0 ) - { - foundNegativeTemp.max( 1 ); - } - if( !isZero( sumCompFracForCheck - 1.0 ) ) - { - foundInconsistentCompFrac.max( 1 ); - } - - } ); - - - GEOS_THROW_IF( foundNegativePres.get() == 1, - wellControls.getDataContext() << "Invalid well initialization, negative pressure was found.", - InputError ); - GEOS_THROW_IF( foundNegativeTemp.get() == 1, - wellControls.getDataContext() << "Invalid well initialization, negative temperature was found.", - InputError ); - GEOS_THROW_IF( foundInconsistentCompFrac.get() == 1, - wellControls.getDataContext() << "Invalid well initialization, inconsistent component fractions were found.", - InputError ); - - -} - -/******************************** CompDensInitializationKernel ********************************/ - -void -CompDensInitializationKernel:: - launch( localIndex const subRegionSize, - integer const numComponents, - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, - arrayView2d< real64 const, multifluid::USD_FLUID > const & wellElemTotalDens, - arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens ) -{ - forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) - { - for( integer ic = 0; ic < numComponents; ++ic ) - { - wellElemCompDens[iwelem][ic] = wellElemCompFrac[iwelem][ic] * wellElemTotalDens[iwelem][0]; - } - } ); -} - -/******************************** RateInitializationKernel ********************************/ - -void -RateInitializationKernel:: - launch( localIndex const subRegionSize, - integer const targetPhaseIndex, - WellControls const & wellControls, - real64 const & currentTime, - arrayView3d< real64 const, multifluid::USD_PHASE > const & phaseDens, - arrayView2d< real64 const, multifluid::USD_FLUID > const & totalDens, - arrayView1d< real64 > const & connRate ) -{ - WellControls::Control const control = wellControls.getControl(); - bool const isProducer = wellControls.isProducer(); - real64 const targetTotalRate = wellControls.getTargetTotalRate( currentTime ); - real64 const targetPhaseRate = wellControls.getTargetPhaseRate( currentTime ); - - // Estimate the connection rates - forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) - { - if( control == WellControls::Control::BHP ) - { - // if BHP constraint set rate below the absolute max rate - // with the appropriate sign (negative for prod, positive for inj) - if( isProducer ) - { - connRate[iwelem] = LvArray::math::max( 0.1 * targetPhaseRate * phaseDens[iwelem][0][targetPhaseIndex], -1e3 ); - } - else - { - connRate[iwelem] = LvArray::math::min( 0.1 * targetTotalRate * totalDens[iwelem][0], 1e3 ); - } - } - else - { - if( isProducer ) - { - connRate[iwelem] = targetPhaseRate * phaseDens[iwelem][0][targetPhaseIndex]; - } - else - { - connRate[iwelem] = targetTotalRate * totalDens[iwelem][0]; - } - } - } ); -} - - -} // end namespace compositionalMultiphaseWellKernels - -} // end namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp deleted file mode 100644 index ea06e3ae2ad..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ /dev/null @@ -1,980 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file CompositionalMultiphaseWellKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_COMPOSITIONALMULTIPHASEWELLKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_COMPOSITIONALMULTIPHASEWELLKERNELS_HPP - -#include "codingUtilities/Utilities.hpp" -#include "common/DataTypes.hpp" -#include "common/GEOS_RAJA_Interface.hpp" -#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" -#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" -#include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" -#include "constitutive/relativePermeability/RelativePermeabilityFields.hpp" -#include "mesh/ElementRegionManager.hpp" -#include "mesh/ObjectManagerBase.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" -#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" -#include "physicsSolvers/fluidFlow/wells/WellControls.hpp" -#include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" - -namespace geos -{ - -namespace compositionalMultiphaseWellKernels -{ - -using namespace constitutive; - -static constexpr real64 minDensForDivision = 1e-10; - -// tag to access well and reservoir elements in perforation rates computation -struct SubRegionTag -{ - static constexpr integer RES = 0; - static constexpr integer WELL = 1; -}; - -// tag to access the next and current well elements of a connection -struct ElemTag -{ - static constexpr integer CURRENT = 0; - static constexpr integer NEXT = 1; -}; - -// define the column offset of the derivatives -struct ColOffset -{ - static constexpr integer DPRES = 0; - static constexpr integer DCOMP = 1; -}; - -// define the row offset of the residual equations -struct RowOffset -{ - static constexpr integer CONTROL = 0; - static constexpr integer MASSBAL = 1; -}; - -/******************************** ControlEquationHelper ********************************/ - -struct ControlEquationHelper -{ - - using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; - using COFFSET = compositionalMultiphaseWellKernels::ColOffset; - - GEOS_HOST_DEVICE - inline - static - void - switchControl( bool const isProducer, - WellControls::Control const & currentControl, - integer const phasePhaseIndex, - real64 const & targetBHP, - real64 const & targetPhaseRate, - real64 const & targetTotalRate, - real64 const & currentBHP, - arrayView1d< real64 const > const & currentPhaseVolRate, - real64 const & currentTotalVolRate, - WellControls::Control & newControl ); - - template< integer NC > - GEOS_HOST_DEVICE - inline - static void - compute( globalIndex const rankOffset, - WellControls::Control const currentControl, - integer const targetPhaseIndex, - real64 const & targetBHP, - real64 const & targetPhaseRate, - real64 const & targetTotalRate, - real64 const & currentBHP, - real64 const & dCurrentBHP_dPres, - arrayView1d< real64 const > const & dCurrentBHP_dCompDens, - arrayView1d< real64 const > const & currentPhaseVolRate, - arrayView1d< real64 const > const & dCurrentPhaseVolRate_dPres, - arrayView2d< real64 const > const & dCurrentPhaseVolRate_dCompDens, - arrayView1d< real64 const > const & dCurrentPhaseVolRate_dRate, - real64 const & currentTotalVolRate, - real64 const & dCurrentTotalVolRate_dPres, - arrayView1d< real64 const > const & dCurrentTotalVolRate_dCompDens, - real64 const & dCurrentTotalVolRate_dRate, - globalIndex const dofNumber, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ); - -}; - -/******************************** FluxKernel ********************************/ - -struct FluxKernel -{ - - using TAG = compositionalMultiphaseWellKernels::ElemTag; - using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; - using COFFSET = compositionalMultiphaseWellKernels::ColOffset; - - template< integer NC > - GEOS_HOST_DEVICE - inline - static void - computeExit( real64 const & dt, - real64 const ( &compFlux )[NC], - real64 const ( &dCompFlux_dRate )[NC], - real64 const ( &dCompFlux_dPresUp )[NC], - real64 const ( &dCompFlux_dCompDensUp )[NC][NC], - real64 ( &oneSidedFlux )[NC], - real64 ( &oneSidedFluxJacobian_dRate )[NC][1], - real64 ( &oneSidedFluxJacobian_dPresCompUp )[NC][NC + 1] ); - - template< integer NC > - GEOS_HOST_DEVICE - inline - static void - compute( real64 const & dt, - real64 const ( &compFlux )[NC], - real64 const ( &dCompFlux_dRate )[NC], - real64 const ( &dCompFlux_dPresUp )[NC], - real64 const ( &dCompFlux_dCompDensUp )[NC][NC], - real64 ( &localFlux )[2*NC], - real64 ( &localFluxJacobian_dRate )[2*NC][1], - real64 ( &localFluxJacobian_dPresCompUp )[2*NC][NC + 1] ); - - template< integer NC > - static void - launch( localIndex const size, - globalIndex const rankOffset, - integer const useTotalMassEquation, - WellControls const & wellControls, - arrayView1d< globalIndex const > const & wellElemDofNumber, - arrayView1d< localIndex const > const & nextWellElemIndex, - arrayView1d< real64 const > const & connRate, - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ); - -}; - -/******************************** PressureRelationKernel ********************************/ - -struct PressureRelationKernel -{ - - using TAG = compositionalMultiphaseWellKernels::ElemTag; - using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; - using COFFSET = compositionalMultiphaseWellKernels::ColOffset; - - template< integer NC > - GEOS_HOST_DEVICE - inline - static void - compute( real64 const & gravCoef, - real64 const & gravCoefNext, - real64 const & pres, - real64 const & presNext, - real64 const & totalMassDens, - real64 const & totalMassDensNext, - real64 const & dTotalMassDens_dPres, - real64 const & dTotalMassDens_dPresNext, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDens, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDensNext, - real64 & localPresRel, - real64 ( &localPresRelJacobian )[2*(NC+1)] ); - - template< integer NC > - static void - launch( localIndex const size, - globalIndex const rankOffset, - bool const isLocallyOwned, - localIndex const iwelemControl, - integer const targetPhaseIndex, - WellControls const & wellControls, - real64 const & timeAtEndOfStep, - arrayView1d< globalIndex const > const & wellElemDofNumber, - arrayView1d< real64 const > const & wellElemGravCoef, - arrayView1d< localIndex const > const & nextWellElemIndex, - arrayView1d< real64 const > const & wellElemPressure, - arrayView1d< real64 const > const & wellElemTotalMassDens, - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, - bool & controlHasSwitched, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ); - -}; - -/******************************** PerforationKernel ********************************/ - -struct PerforationKernel -{ - - using TAG = compositionalMultiphaseWellKernels::SubRegionTag; - - using CompFlowAccessors = - StencilAccessors< fields::flow::pressure, - fields::flow::phaseVolumeFraction, - fields::flow::dPhaseVolumeFraction, - fields::flow::dGlobalCompFraction_dGlobalCompDensity >; - - using MultiFluidAccessors = - StencilMaterialAccessors< MultiFluidBase, - fields::multifluid::phaseDensity, - fields::multifluid::dPhaseDensity, - fields::multifluid::phaseViscosity, - fields::multifluid::dPhaseViscosity, - fields::multifluid::phaseCompFraction, - fields::multifluid::dPhaseCompFraction >; - - using RelPermAccessors = - StencilMaterialAccessors< RelativePermeabilityBase, - fields::relperm::phaseRelPerm, - fields::relperm::dPhaseRelPerm_dPhaseVolFraction >; - - - /** - * @brief The type for element-based non-constitutive data parameters. - * Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - - template< integer NC, integer NP > - GEOS_HOST_DEVICE - inline - static void - compute( bool const & disableReservoirToWellFlow, - real64 const & resPres, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & resPhaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const & dResPhaseVolFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const & dResCompFrac_dCompDens, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & resPhaseDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const & dResPhaseDens, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & resPhaseVisc, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const & dResPhaseVisc, - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > const & resPhaseCompFrac, - arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > const & dResPhaseCompFrac, - arraySlice1d< real64 const, relperm::USD_RELPERM - 2 > const & resPhaseRelPerm, - arraySlice2d< real64 const, relperm::USD_RELPERM_DS - 2 > const & dResPhaseRelPerm_dPhaseVolFrac, - real64 const & wellElemGravCoef, - real64 const & wellElemPres, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & wellElemCompDens, - real64 const & wellElemTotalMassDens, - real64 const & dWellElemTotalMassDens_dPres, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dWellElemTotalMassDens_dCompDens, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & wellElemCompFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const & dWellElemCompFrac_dCompDens, - real64 const & perfGravCoef, - real64 const & trans, - arraySlice1d< real64 > const & compPerfRate, - arraySlice2d< real64 > const & dCompPerfRate_dPres, - arraySlice3d< real64 > const & dCompPerfRate_dComp ); - - template< integer NC, integer NP > - static void - launch( localIndex const size, - bool const disableReservoirToWellFlow, - ElementViewConst< arrayView1d< real64 const > > const & resPres, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & resPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dResPhaseVolFrac_dComp, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dResCompFrac_dCompDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & resPhaseDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dResPhaseDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & resPhaseVisc, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dResPhaseVisc, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & resPhaseCompFrac, - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dResPhaseCompFrac, - ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const & resPhaseRelPerm, - ElementViewConst< arrayView4d< real64 const, relperm::USD_RELPERM_DS > > const & dResPhaseRelPerm_dPhaseVolFrac, - arrayView1d< real64 const > const & wellElemGravCoef, - arrayView1d< real64 const > const & wellElemPres, - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompDens, - arrayView1d< real64 const > const & wellElemTotalMassDens, - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, - arrayView1d< real64 const > const & perfGravCoef, - arrayView1d< localIndex const > const & perfWellElemIndex, - arrayView1d< real64 const > const & perfTrans, - arrayView1d< localIndex const > const & resElementRegion, - arrayView1d< localIndex const > const & resElementSubRegion, - arrayView1d< localIndex const > const & resElementIndex, - arrayView2d< real64 > const & compPerfRate, - arrayView3d< real64 > const & dCompPerfRate_dPres, - arrayView4d< real64 > const & dCompPerfRate_dComp ); - -}; - -/******************************** AccumulationKernel ********************************/ - -struct AccumulationKernel -{ - - using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; - using COFFSET = compositionalMultiphaseWellKernels::ColOffset; - - template< integer NC > - GEOS_HOST_DEVICE - inline - static void - compute( integer const numPhases, - real64 const & volume, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const & dPhaseVolFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const & dCompFrac_dCompDens, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & phaseDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const & dPhaseDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > const & phaseCompFrac, - arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > const & dPhaseCompFrac, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFrac_n, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & phaseDens_n, - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > const & phaseCompFrac_n, - real64 ( &localAccum )[NC], - real64 ( &localAccumJacobian )[NC][NC + 1] ); - - template< integer NC > - static void - launch( localIndex const size, - integer const numPhases, - globalIndex const rankOffset, - integer const useTotalMassEquation, - arrayView1d< globalIndex const > const & wellElemDofNumber, - arrayView1d< integer const > const & wellElemGhostRank, - arrayView1d< real64 const > const & wellElemVolume, - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac, - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac, - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens, - arrayView4d< real64 const, multifluid::USD_PHASE_DC > const & dWellElemPhaseDens, - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac, - arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > const & dWellElemPhaseCompFrac, - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac_n, - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens_n, - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac_n, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ); - -}; - -/******************************** VolumeBalanceKernel ********************************/ - -struct VolumeBalanceKernel -{ - - using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; - using COFFSET = compositionalMultiphaseWellKernels::ColOffset; - - template< integer NC > - GEOS_HOST_DEVICE - inline - static void - compute( integer const numPhases, - real64 const & volume, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const & dPhaseVolFrac, - real64 & localVolBalance, - real64 ( &localVolBalanceJacobian )[NC+1] ); - - template< integer NC > - static void - launch( localIndex const size, - integer const numPhases, - globalIndex const rankOffset, - arrayView1d< globalIndex const > const & wellElemDofNumber, - arrayView1d< integer const > const & wellElemGhostRank, - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac, - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac, - arrayView1d< real64 const > const & wellElemVolume, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ); - -}; - -/******************************** PresTempCompFracInitializationKernel ********************************/ - -struct PresTempCompFracInitializationKernel -{ - - using CompFlowAccessors = - StencilAccessors< fields::flow::pressure, - fields::flow::temperature, - fields::flow::globalCompDensity, - fields::flow::phaseVolumeFraction >; - - using MultiFluidAccessors = - StencilMaterialAccessors< MultiFluidBase, - fields::multifluid::phaseMassDensity >; - - - /** - * @brief The type for element-based non-constitutive data parameters. - * Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - static void - launch( localIndex const perforationSize, - localIndex const subRegionSize, - integer const numComponents, - integer const numPhases, - localIndex const numPerforations, - WellControls const & wellControls, - real64 const & currentTime, - ElementViewConst< arrayView1d< real64 const > > const & resPres, - ElementViewConst< arrayView1d< real64 const > > const & resTemp, - ElementViewConst< arrayView2d< real64 const, compflow::USD_COMP > > const & resCompDens, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & resPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & resPhaseMassDens, - arrayView1d< localIndex const > const & resElementRegion, - arrayView1d< localIndex const > const & resElementSubRegion, - arrayView1d< localIndex const > const & resElementIndex, - arrayView1d< real64 const > const & perfGravCoef, - arrayView1d< real64 const > const & wellElemGravCoef, - arrayView1d< real64 > const & wellElemPres, - arrayView1d< real64 > const & wellElemTemp, - arrayView2d< real64, compflow::USD_COMP > const & wellElemCompFrac ); - -}; - -/******************************** CompDensInitializationKernel ********************************/ - -struct CompDensInitializationKernel -{ - - static void - launch( localIndex const subRegionSize, - integer const numComponents, - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, - arrayView2d< real64 const, multifluid::USD_FLUID > const & wellElemTotalDens, - arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens ); - -}; - -/******************************** RateInitializationKernel ********************************/ - -struct RateInitializationKernel -{ - - static void - launch( localIndex const subRegionSize, - integer const targetPhaseIndex, - WellControls const & wellControls, - real64 const & currentTime, - arrayView3d< real64 const, multifluid::USD_PHASE > const & phaseDens, - arrayView2d< real64 const, multifluid::USD_FLUID > const & totalDens, - arrayView1d< real64 > const & connRate ); - -}; - - -/******************************** TotalMassDensityKernel ****************************/ - -/** - * @class TotalMassDensityKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_PHASE number of fluid phases - * @brief Define the interface for the property kernel in charge of computing the total mass density - */ -template< integer NUM_COMP, integer NUM_PHASE > -class TotalMassDensityKernel : public isothermalCompositionalMultiphaseBaseKernels::PropertyKernelBase< NUM_COMP > -{ -public: - - using Base = isothermalCompositionalMultiphaseBaseKernels::PropertyKernelBase< NUM_COMP >; - using Base::numComp; - - /// Compile time value for the number of phases - static constexpr integer numPhase = NUM_PHASE; - - /** - * @brief Constructor - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - */ - TotalMassDensityKernel( ObjectManagerBase & subRegion, - MultiFluidBase const & fluid ) - : Base(), - m_phaseVolFrac( subRegion.getField< fields::well::phaseVolumeFraction >() ), - m_dPhaseVolFrac( subRegion.getField< fields::well::dPhaseVolumeFraction >() ), - m_dCompFrac_dCompDens( subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >() ), - m_phaseMassDens( fluid.phaseMassDensity() ), - m_dPhaseMassDens( fluid.dPhaseMassDensity() ), - m_totalMassDens( subRegion.getField< fields::well::totalMassDensity >() ), - m_dTotalMassDens_dPres( subRegion.getField< fields::well::dTotalMassDensity_dPressure >() ), - m_dTotalMassDens_dCompDens( subRegion.getField< fields::well::dTotalMassDensity_dGlobalCompDensity >() ) - {} - - /** - * @brief Compute the total mass density in an element - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[in] totalMassDensityKernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - inline - void compute( localIndex const ei, - FUNC && totalMassDensityKernelOp = NoOpFunc{} ) const - { - using Deriv = multifluid::DerivativeOffset; - - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseMassDens = m_phaseMassDens[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseMassDens = m_dPhaseMassDens[ei][0]; - real64 & totalMassDens = m_totalMassDens[ei]; - real64 & dTotalMassDens_dPres = m_dTotalMassDens_dPres[ei]; - arraySlice1d< real64, compflow::USD_FLUID_DC - 1 > dTotalMassDens_dCompDens = m_dTotalMassDens_dCompDens[ei]; - - real64 dMassDens_dC[numComp]{}; - - totalMassDens = 0.0; - dTotalMassDens_dPres = 0.0; - for( integer ic = 0; ic < numComp; ++ic ) - { - dTotalMassDens_dCompDens[ic] = 0.0; - } - - for( integer ip = 0; ip < numPhase; ++ip ) - { - totalMassDens += phaseVolFrac[ip] * phaseMassDens[ip]; - dTotalMassDens_dPres += dPhaseVolFrac[ip][Deriv::dP] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dP]; - - applyChainRule( numComp, dCompFrac_dCompDens, dPhaseMassDens[ip], dMassDens_dC, Deriv::dC ); - for( integer ic = 0; ic < numComp; ++ic ) - { - dTotalMassDens_dCompDens[ic] += dPhaseVolFrac[ip][Deriv::dC+ic] * phaseMassDens[ip] - + phaseVolFrac[ip] * dMassDens_dC[ic]; - } - - totalMassDensityKernelOp( ip, totalMassDens, dTotalMassDens_dPres, dTotalMassDens_dCompDens ); - } - - } - -protected: - - // inputs - - /// Views on phase volume fractions - arrayView2d< real64 const, compflow::USD_PHASE > m_phaseVolFrac; - arrayView3d< real64 const, compflow::USD_PHASE_DC > m_dPhaseVolFrac; - arrayView3d< real64 const, compflow::USD_COMP_DC > m_dCompFrac_dCompDens; - - /// Views on phase mass densities - arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseMassDens; - arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dPhaseMassDens; - - // outputs - - /// Views on total mass densities - arrayView1d< real64 > m_totalMassDens; - arrayView1d< real64 > m_dTotalMassDens_dPres; - arrayView2d< real64, compflow::USD_FLUID_DC > m_dTotalMassDens_dCompDens; - -}; - -/** - * @class TotalMassDensityKernelFactory - */ -class TotalMassDensityKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] numComp the number of fluid components - * @param[in] numPhase the number of fluid phases - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - */ - template< typename POLICY > - static void - createAndLaunch( integer const numComp, - integer const numPhase, - ObjectManagerBase & subRegion, - MultiFluidBase const & fluid ) - { - if( numPhase == 2 ) - { - isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - TotalMassDensityKernel< NUM_COMP, 2 > kernel( subRegion, fluid ); - TotalMassDensityKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - else if( numPhase == 3 ) - { - isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - TotalMassDensityKernel< NUM_COMP, 3 > kernel( subRegion, fluid ); - TotalMassDensityKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - } -}; - - -/******************************** ResidualNormKernel ********************************/ - -/** - * @class ResidualNormKernel - */ -class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > -{ -public: - - using Base = solverBaseKernels::ResidualNormKernelBase< 1 >; - using Base::m_minNormalizer; - using Base::m_rankOffset; - using Base::m_localResidual; - using Base::m_dofNumber; - - ResidualNormKernel( globalIndex const rankOffset, - arrayView1d< real64 const > const & localResidual, - arrayView1d< globalIndex const > const & dofNumber, - arrayView1d< localIndex const > const & ghostRank, - integer const numComp, - integer const numDof, - integer const targetPhaseIndex, - WellElementSubRegion const & subRegion, - MultiFluidBase const & fluid, - WellControls const & wellControls, - real64 const timeAtEndOfStep, - real64 const dt, - real64 const minNormalizer ) - : Base( rankOffset, - localResidual, - dofNumber, - ghostRank, - minNormalizer ), - m_numComp( numComp ), - m_numDof( numDof ), - m_targetPhaseIndex( targetPhaseIndex ), - m_dt( dt ), - m_isLocallyOwned( subRegion.isLocallyOwned() ), - m_iwelemControl( subRegion.getTopWellElementIndex() ), - m_isProducer( wellControls.isProducer() ), - m_currentControl( wellControls.getControl() ), - m_targetBHP( wellControls.getTargetBHP( timeAtEndOfStep ) ), - m_targetTotalRate( wellControls.getTargetTotalRate( timeAtEndOfStep ) ), - m_targetPhaseRate( wellControls.getTargetPhaseRate( timeAtEndOfStep ) ), - m_volume( subRegion.getElementVolume() ), - m_phaseDens_n( fluid.phaseDensity_n() ), - m_totalDens_n( fluid.totalDensity_n() ) - {} - - GEOS_HOST_DEVICE - virtual void computeLinf( localIndex const iwelem, - LinfStackVariables & stack ) const override - { - using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; - - real64 normalizer = 0.0; - for( integer idof = 0; idof < m_numDof; ++idof ) - { - - // Step 1: compute a normalizer for the control or pressure equation - - // for the control equation, we distinguish two cases - if( idof == ROFFSET::CONTROL ) - { - - // for the top well element, normalize using the current control - if( m_isLocallyOwned && iwelem == m_iwelemControl ) - { - if( m_currentControl == WellControls::Control::BHP ) - { - // the residual entry is in pressure units - normalizer = m_targetBHP; - } - else if( m_currentControl == WellControls::Control::TOTALVOLRATE ) - { - // the residual entry is in volume / time units - normalizer = LvArray::math::max( LvArray::math::abs( m_targetTotalRate ), m_minNormalizer ); - } - else if( m_currentControl == WellControls::Control::PHASEVOLRATE ) - { - // the residual entry is in volume / time units - normalizer = LvArray::math::max( LvArray::math::abs( m_targetPhaseRate ), m_minNormalizer ); - } - } - // for the pressure difference equation, always normalize by the BHP - else - { - normalizer = m_targetBHP; - } - } - // Step 2: compute a normalizer for the mass balance equations - else if( idof >= ROFFSET::MASSBAL && idof < ROFFSET::MASSBAL + m_numComp ) - { - if( m_isProducer ) // only PHASEVOLRATE is supported for now - { - // the residual is in mass units - normalizer = m_dt * LvArray::math::abs( m_targetPhaseRate ) * m_phaseDens_n[iwelem][0][m_targetPhaseIndex]; - } - else // Type::INJECTOR, only TOTALVOLRATE is supported for now - { - // the residual is in mass units - normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ) * m_totalDens_n[iwelem][0]; - } - - // to make sure that everything still works well if the rate is zero, we add this check - normalizer = LvArray::math::max( normalizer, m_volume[iwelem] * m_totalDens_n[iwelem][0] ); - } - // Step 3: compute a normalizer for the volume balance equations - else - { - if( m_isProducer ) // only PHASEVOLRATE is supported for now - { - // the residual is in volume units - normalizer = m_dt * LvArray::math::abs( m_targetPhaseRate ); - } - else // Type::INJECTOR, only TOTALVOLRATE is supported for now - { - normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ); - } - - // to make sure that everything still works well if the rate is zero, we add this check - normalizer = LvArray::math::max( normalizer, m_volume[iwelem] ); - } - normalizer = LvArray::math::max( m_minNormalizer, normalizer ); - - // Step 4: compute the contribution to the residual - real64 const val = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / normalizer; - if( val > stack.localValue[0] ) - { - stack.localValue[0] = val; - } - } - } - - GEOS_HOST_DEVICE - virtual void computeL2( localIndex const iwelem, - L2StackVariables & stack ) const override - { - GEOS_UNUSED_VAR( iwelem, stack ); - GEOS_ERROR( "The L2 norm is not implemented for CompositionalMultiphaseWell" ); - } - - -protected: - - /// Number of fluid components - integer const m_numComp; - - /// Number of dof per well element - integer const m_numDof; - - /// Index of the target phase - integer const m_targetPhaseIndex; - - /// Time step size - real64 const m_dt; - - /// Flag indicating whether the well is locally owned or not - bool const m_isLocallyOwned; - - /// Index of the element where the control is enforced - localIndex const m_iwelemControl; - - /// Flag indicating whether the well is a producer or an injector - bool const m_isProducer; - - /// Controls - WellControls::Control const m_currentControl; - real64 const m_targetBHP; - real64 const m_targetTotalRate; - real64 const m_targetPhaseRate; - - /// View on the volume - arrayView1d< real64 const > const m_volume; - - /// View on phase/total density at the previous converged time step - arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseDens_n; - arrayView2d< real64 const, multifluid::USD_FLUID > const m_totalDens_n; - -}; - -/** - * @class ResidualNormKernelFactory - */ -class ResidualNormKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] numComp number of fluid components - * @param[in] numDof number of dofs per well element - * @param[in] targetPhaseIndex the index of the target phase (for phase volume control) - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] localResidual the residual vector on my MPI rank - * @param[in] subRegion the well element subregion - * @param[in] fluid the fluid model - * @param[in] wellControls the controls - * @param[in] timeAtEndOfStep the time at the end of the step (time_n + dt) - * @param[in] dt the time step size - * @param[out] residualNorm the residual norm on the subRegion - */ - template< typename POLICY > - static void - createAndLaunch( integer const numComp, - integer const numDof, - integer const targetPhaseIndex, - globalIndex const rankOffset, - string const & dofKey, - arrayView1d< real64 const > const & localResidual, - WellElementSubRegion const & subRegion, - MultiFluidBase const & fluid, - WellControls const & wellControls, - real64 const timeAtEndOfStep, - real64 const dt, - real64 const minNormalizer, - real64 (& residualNorm)[1] ) - { - arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); - arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); - - ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, - numComp, numDof, targetPhaseIndex, subRegion, fluid, wellControls, timeAtEndOfStep, dt, minNormalizer ); - ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); - } - -}; - -/******************************** ScalingForSystemSolutionKernel ********************************/ - -/** - * @class ScalingForSystemSolutionKernelFactory - */ -class ScalingForSystemSolutionKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] maxRelativePresChange the max allowed relative pressure change - * @param[in] maxCompFracChange the max allowed comp fraction change - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - */ - template< typename POLICY > - static isothermalCompositionalMultiphaseBaseKernels::ScalingForSystemSolutionKernel::StackVariables - createAndLaunch( real64 const maxRelativePresChange, - real64 const maxAbsolutePresChange, - real64 const maxCompFracChange, - globalIndex const rankOffset, - integer const numComp, - string const dofKey, - ElementSubRegionBase & subRegion, - arrayView1d< real64 const > const localSolution ) - { - arrayView1d< real64 const > const pressure = - subRegion.getField< fields::well::pressure >(); - arrayView2d< real64 const, compflow::USD_COMP > const compDens = - subRegion.getField< fields::well::globalCompDensity >(); - arrayView1d< real64 > pressureScalingFactor = - subRegion.getField< fields::well::pressureScalingFactor >(); - arrayView1d< real64 > compDensScalingFactor = - subRegion.getField< fields::well::globalCompDensityScalingFactor >(); - isothermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernel kernel( maxRelativePresChange, maxAbsolutePresChange, maxCompFracChange, rankOffset, - numComp, dofKey, subRegion, localSolution, pressure, compDens, pressureScalingFactor, compDensScalingFactor ); - return isothermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernel:: - launch< POLICY >( subRegion.size(), kernel ); - } - -}; - -/******************************** SolutionCheckKernel ********************************/ - -/** - * @class SolutionCheckKernelFactory - */ -class SolutionCheckKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] allowCompDensChopping flag to allow the component density chopping - * @param[in] scalingFactor the scaling factor - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - */ - template< typename POLICY > - static isothermalCompositionalMultiphaseBaseKernels::SolutionCheckKernel::StackVariables - createAndLaunch( integer const allowCompDensChopping, - CompositionalMultiphaseFVM::ScalingType const scalingType, - real64 const scalingFactor, - globalIndex const rankOffset, - integer const numComp, - string const dofKey, - ElementSubRegionBase & subRegion, - arrayView1d< real64 const > const localSolution ) - { - arrayView1d< real64 const > const pressure = subRegion.getField< fields::well::pressure >(); - arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::well::globalCompDensity >(); - arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::well::pressureScalingFactor >(); - arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::well::globalCompDensityScalingFactor >(); - isothermalCompositionalMultiphaseBaseKernels:: - SolutionCheckKernel kernel( allowCompDensChopping, 0, scalingType, scalingFactor, rankOffset, // no negative pressure - numComp, dofKey, subRegion, localSolution, pressure, compDens, pressureScalingFactor, compDensScalingFactor ); - return isothermalCompositionalMultiphaseBaseKernels:: - SolutionCheckKernel:: - launch< POLICY >( subRegion.size(), kernel ); - } - -}; - - -} // end namespace compositionalMultiphaseWellKernels - -} // end namespace geos - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_COMPOSITIONALMULTIPHASEWELLKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/LogLevelsInfo.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/LogLevelsInfo.hpp new file mode 100644 index 00000000000..43120e4b77b --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/LogLevelsInfo.hpp @@ -0,0 +1,58 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file LogLevelsInfo.hpp + * This file contains log level informations for wells + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_LOGLEVELSINFO_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_LOGLEVELSINFO_HPP + +#include "common/DataTypes.hpp" + +namespace geos +{ + +namespace logInfo +{ + +/** + * @name Wells LogLevels info structures. They must comply with the `is_log_level_info` trait. + */ +///@{ + +/// @cond DO_NOT_DOCUMENT + +struct WellControl +{ + static constexpr int getMinLogLevel() { return 1; } + static constexpr std::string_view getDescription() { return "Well control information"; } +}; + +struct Crossflow +{ + static constexpr int getMinLogLevel() { return 1; } + static constexpr std::string_view getDescription() { return "Crossflow information"; } +}; + +/// @endcond +///@} + +} + +} + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_LOGLEVELSINFO_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index a1f1777c5e3..75797a3490c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -29,11 +30,15 @@ #include "mesh/WellElementSubRegion.hpp" #include "mesh/PerforationFields.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" +#include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp" -#include "physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" +#include "physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluidUpdateKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp" +#include "physicsSolvers/fluidFlow/wells/LogLevelsInfo.hpp" namespace geos { @@ -48,6 +53,13 @@ SinglePhaseWell::SinglePhaseWell( const string & name, { m_numDofPerWellElement = 2; m_numDofPerResElement = 1; + m_numPhases = 1; + m_numComponents = 1; + + this->registerWrapper( FlowSolverBase::viewKeyStruct::allowNegativePressureString(), &m_allowNegativePressure ). + setApplyDefaultValue( 1 ). // negative pressure is allowed by default + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Flag indicating if negative pressure is allowed" ); } void SinglePhaseWell::registerDataOnMesh( Group & meshBodies ) @@ -66,12 +78,10 @@ void SinglePhaseWell::registerDataOnMesh( Group & meshBodies ) [&]( localIndex const, WellElementSubRegion & subRegion ) { - subRegion.registerField< fields::well::pressure_n >( getName() ); - subRegion.registerField< fields::well::pressure >( getName() ). - setRestartFlags( RestartFlags::WRITE_AND_READ ); - - subRegion.registerField< fields::well::temperature_n >( getName() ); - subRegion.registerField< fields::well::temperature >( getName() ); + string & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + fluidName = getConstitutiveName< SingleFluidBase >( subRegion ); + GEOS_ERROR_IF( fluidName.empty(), GEOS_FMT( "{}: Fluid model not found on subregion {}", + getDataContext(), subRegion.getName() ) ); subRegion.registerField< fields::well::connectionRate_n >( getName() ); subRegion.registerField< fields::well::connectionRate >( getName() ); @@ -101,31 +111,6 @@ void SinglePhaseWell::registerDataOnMesh( Group & meshBodies ) outputFile << "Time [s],BHP [Pa],Total rate [kg/s],Total " << conditionKey << " volumetric rate ["<( viewKeyStruct::fluidNamesString() ); - fluidName = getConstitutiveName< SingleFluidBase >( subRegion ); - GEOS_ERROR_IF( fluidName.empty(), GEOS_FMT( "{}: Fluid model not found on subregion {}", - getDataContext(), subRegion.getName() ) ); - - } ); - } ); -} - -void SinglePhaseWell::initializePostSubGroups() -{ - - WellSolverBase::initializePostSubGroups(); - DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - ElementRegionManager & elemManager = mesh.getElemManager(); - elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion & subRegion ) - { - validateWellConstraints( 0, 0, subRegion ); } ); } ); } @@ -137,7 +122,7 @@ string SinglePhaseWell::resElementDofName() const void SinglePhaseWell::validateWellConstraints( real64 const & time_n, real64 const & dt, - WellElementSubRegion const & subRegion ) const + WellElementSubRegion const & subRegion ) { WellControls const & wellControls = getWellControls( subRegion ); WellControls::Control const currentControl = wellControls.getControl(); @@ -213,7 +198,7 @@ void SinglePhaseWell::updateBHPForConstraint( WellElementSubRegion & subRegion ) if( logLevel >= 2 ) { - GEOS_LOG_RANK( GEOS_FMT( "{}: The BHP (at the specified reference elevation) is {} Pa", + GEOS_LOG_RANK( GEOS_FMT( "{}: The BHP (at the specified reference elevation) = {} Pa", wellControlsName, currentBHP ) ); } @@ -309,10 +294,8 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi if( logLevel >= 2 && useSurfaceConditions ) { - GEOS_LOG_RANK( GEOS_FMT( "{}: The total fluid density at surface conditions is {} kg/sm3. \n" - "The total rate is {} kg/s, which corresponds to a total surface volumetric rate of {} sm3/s", - wellControlsName, dens[iwelemRef][0], - connRate[iwelemRef], currentVolRate ) ); + GEOS_LOG_RANK( GEOS_FMT( "{}: total fluid density at surface conditions = {} kg/sm3, total rate = {} kg/s, total surface volumetric rate = {} sm3/s", + wellControlsName, dens[iwelemRef][0], connRate[iwelemRef], currentVolRate ) ); } } ); } ); @@ -331,11 +314,11 @@ void SinglePhaseWell::updateFluidModel( WellElementSubRegion & subRegion ) const constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid ) { typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - thermalSinglePhaseBaseKernels::FluidUpdateKernel::launch( fluidWrapper, pres, temp ); + singlePhaseBaseKernels::FluidUpdateKernel::launch( fluidWrapper, pres, temp ); } ); } -void SinglePhaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) +real64 SinglePhaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) { // update volumetric rates for the well constraints // Warning! This must be called before updating the fluid model @@ -348,12 +331,21 @@ void SinglePhaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) updateBHPForConstraint( subRegion ); // note: the perforation rates are updated separately + return 0.0; // change in phasevolume fraction doesnt apply } -void SinglePhaseWell::initializeWells( DomainPartition & domain ) +void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & time_n, real64 const & dt ) { GEOS_MARK_FUNCTION; - + GEOS_UNUSED_VAR( time_n ); + GEOS_UNUSED_VAR( dt ); + // different functionality than for compositional + // compositional has better treatment of well initialization in cases where well starts later in sim + // logic will be incorporated into single phase in different push + if( time_n > 0 ) + { + return; + } // loop over the wells forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & meshLevel, @@ -402,7 +394,7 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain ) subRegion.size(), perforationData.getNumPerforationsGlobal(), wellControls, - 0.0, // initialization done at t = 0 + 0.0, // initialization done at t = 0 resSinglePhaseFlowAccessors.get( fields::flow::pressure{} ), resSingleFluidAccessors.get( fields::singlefluid::density{} ), resElementRegion, @@ -424,7 +416,7 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain ) // 5) Estimate the well rates RateInitializationKernel::launch( subRegion.size(), wellControls, - 0.0, // initialization done at t = 0 + 0.0, // initialization done at t = 0 wellElemDens, connRate ); @@ -433,14 +425,16 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain ) } ); } -void SinglePhaseWell::assembleFluxTerms( real64 const dt, - DomainPartition const & domain, +void SinglePhaseWell::assembleFluxTerms( real64 const & time_n, + real64 const & dt, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; - + GEOS_UNUSED_VAR( time_n ); + GEOS_UNUSED_VAR( dt ); // loop over the wells forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, @@ -527,7 +521,7 @@ void SinglePhaseWell::assemblePressureRelations( real64 const & time_n, subRegion.isLocallyOwned(), subRegion.getTopWellElementIndex(), wellControls, - time_n + dt, // controls evaluated with BHP/rate of the end of the time interval + time_n + dt, // controls evaluated with BHP/rate of the end of the time interval wellElemDofNumber, wellElemGravCoef, nextWellElemIndex, @@ -547,14 +541,12 @@ void SinglePhaseWell::assemblePressureRelations( real64 const & time_n, if( wellControls.getControl() == WellControls::Control::BHP ) { wellControls.switchToTotalRateControl( wellControls.getTargetTotalRate( timeAtEndOfStep ) ); - GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() - << " from BHP constraint to rate constraint" ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::WellControl, GEOS_FMT( "Control switch for well {} from BHP constraint to rate constraint", subRegion.getName()) ); } else { wellControls.switchToBHPControl( wellControls.getTargetBHP( timeAtEndOfStep ) ); - GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() - << " from rate constraint to BHP constraint" ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::WellControl, GEOS_FMT( "Control switch for well {} from rate constraint to BHP constraint", subRegion.getName()) ); } } @@ -562,13 +554,16 @@ void SinglePhaseWell::assemblePressureRelations( real64 const & time_n, } ); } -void SinglePhaseWell::assembleAccumulationTerms( DomainPartition const & domain, +void SinglePhaseWell::assembleAccumulationTerms( real64 const & time_n, + real64 const & dt, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; - + GEOS_UNUSED_VAR( time_n ); + GEOS_UNUSED_VAR( dt ); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel const & mesh, arrayView1d< string const > const & regionNames ) @@ -607,7 +602,8 @@ void SinglePhaseWell::assembleAccumulationTerms( DomainPartition const & domain, } ); } ); - + // then assemble the volume balance equations + assembleVolumeBalanceTerms( domain, dofManager, localMatrix, localRhs ); } void SinglePhaseWell::assembleVolumeBalanceTerms( DomainPartition const & GEOS_UNUSED_PARAM( domain ), @@ -618,87 +614,12 @@ void SinglePhaseWell::assembleVolumeBalanceTerms( DomainPartition const & GEOS_U // not implemented for single phase flow } -void SinglePhaseWell::shutDownWell( real64 const time_n, - real64 const dt, - DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - GEOS_MARK_FUNCTION; - - string const wellDofKey = dofManager.getKey( wellElementDofName() ); - - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) - { - - ElementRegionManager const & elemManager = mesh.getElemManager(); - - elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion const & subRegion ) - { - - // if the well is open, we don't have to do anything, so we just return - WellControls const & wellControls = getWellControls( subRegion ); - if( wellControls.isWellOpen( time_n + dt ) ) - { - return; - } - - globalIndex const rankOffset = dofManager.rankOffset(); - - arrayView1d< integer const > const ghostRank = - subRegion.getReference< array1d< integer > >( ObjectManagerBase::viewKeyStruct::ghostRankString() ); - arrayView1d< globalIndex const > const dofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - - arrayView1d< real64 const > const pres = - subRegion.getField< fields::well::pressure >(); - arrayView1d< real64 const > const connRate = - subRegion.getField< fields::well::connectionRate >(); - - forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( ghostRank[ei] >= 0 ) - { - return; - } - - globalIndex const dofIndex = dofNumber[ei]; - localIndex const localRow = dofIndex - rankOffset; - real64 rhsValue; - - // 4.1. Apply pressure value to the matrix/rhs - FieldSpecificationEqual::SpecifyFieldValue( dofIndex, - rankOffset, - localMatrix, - rhsValue, - pres[ei], // freeze the current pressure value - pres[ei] ); - localRhs[localRow] = rhsValue; - - // 4.2. Apply rate value to the matrix/rhs - FieldSpecificationEqual::SpecifyFieldValue( dofIndex + 1, - rankOffset, - localMatrix, - rhsValue, - connRate[ei], // freeze the current pressure value - connRate[ei] ); - localRhs[localRow + 1] = rhsValue; - - } ); - } ); - } ); -} - - -void SinglePhaseWell::computePerforationRates( DomainPartition & domain ) +void SinglePhaseWell::computePerforationRates( real64 const & time_n, + real64 const & dt, DomainPartition & domain ) { GEOS_MARK_FUNCTION; - + GEOS_UNUSED_VAR( time_n ); + GEOS_UNUSED_VAR( dt ); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) @@ -852,8 +773,9 @@ bool SinglePhaseWell::checkSystemSolution( DomainPartition & domain, { GEOS_MARK_FUNCTION; - localIndex localCheck = 1; string const wellDofKey = dofManager.getKey( wellElementDofName() ); + integer numNegativePressures = 0; + real64 minPressure = 0.0; forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel const & mesh, @@ -867,33 +789,32 @@ bool SinglePhaseWell::checkSystemSolution( DomainPartition & domain, WellElementSubRegion const & subRegion ) { + globalIndex const rankOffset = dofManager.rankOffset(); // get the degree of freedom numbers on well elements - arrayView1d< globalIndex const > const & wellElemDofNumber = + arrayView1d< globalIndex const > const & dofNumber = subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank(); + arrayView1d< integer const > const & ghostRank = subRegion.ghostRank(); // get a reference to the primary variables on well elements - arrayView1d< real64 const > const & wellElemPressure = + arrayView1d< real64 const > const & pres = subRegion.getField< fields::well::pressure >(); - // here we can reuse the flow solver kernel checking that pressures are positive - localIndex const subRegionSolutionCheck = - singlePhaseWellKernels:: - SolutionCheckKernel::launch< parallelDevicePolicy<> >( localSolution, - dofManager.rankOffset(), - wellElemDofNumber, - wellElemGhostRank, - wellElemPressure, - scalingFactor ); - - if( subRegionSolutionCheck == 0 ) - { - localCheck = 0; - } + auto const statistics = + singlePhaseBaseKernels::SolutionCheckKernel:: + launch< parallelDevicePolicy<> >( localSolution, rankOffset, dofNumber, ghostRank, pres, scalingFactor ); + + numNegativePressures += statistics.first; + minPressure = std::min( minPressure, statistics.second ); } ); } ); - return MpiWrapper::min( localCheck ); + numNegativePressures = MpiWrapper::sum( numNegativePressures ); + + if( numNegativePressures > 0 ) + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative pressure values: {}, minimum value: {} Pa", + getName(), numNegativePressures, fmt::format( "{:.{}f}", minPressure, 3 ) ) ); + + return (m_allowNegativePressure || numNegativePressures == 0) ? 1 : 0; } void @@ -1103,5 +1024,5 @@ void SinglePhaseWell::printRates( real64 const & time_n, } ); } -REGISTER_CATALOG_ENTRY( SolverBase, SinglePhaseWell, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhaseWell, string const &, Group * const ) }// namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp index 9df8cfcec0f..a27be685524 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,8 +21,6 @@ #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_SINGLEPHASEWELL_HPP_ #include "WellSolverBase.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" namespace geos { @@ -81,7 +80,7 @@ class SinglePhaseWell : public WellSolverBase */ static string catalogName() { return "SinglePhaseWell"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -159,13 +158,14 @@ class SinglePhaseWell : public WellSolverBase * @brief Recompute the perforation rates for all the wells * @param domain the domain containing the mesh and fields */ - virtual void computePerforationRates( DomainPartition & domain ) override; + virtual void computePerforationRates( real64 const & time_n, + real64 const & dt, DomainPartition & domain ) override; /** * @brief Recompute all dependent quantities from primary variables (including constitutive models) on the well * @param subRegion the well subRegion containing the well elements and their associated fields */ - virtual void updateSubRegionState( WellElementSubRegion & subRegion ) override; + virtual real64 updateSubRegionState( WellElementSubRegion & subRegion ) override; /** * @brief assembles the flux terms for all connections between well elements @@ -176,11 +176,12 @@ class SinglePhaseWell : public WellSolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - void assembleFluxTerms( real64 const dt, - DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; + virtual void assembleFluxTerms( real64 const & time_n, + real64 const & dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) override; /** * @brief assembles the accumulation term for all the well elements @@ -189,10 +190,11 @@ class SinglePhaseWell : public WellSolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - void assembleAccumulationTerms( DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; + virtual void assembleAccumulationTerms( real64 const & time_n, + real64 const & dt, DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) override; /** * @brief assembles the volume balance terms for all well elements @@ -201,10 +203,10 @@ class SinglePhaseWell : public WellSolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - virtual void assembleVolumeBalanceTerms( DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; + void assembleVolumeBalanceTerms( DomainPartition const & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); /** * @brief assembles the pressure relations at all connections between well elements except at the well head @@ -222,23 +224,6 @@ class SinglePhaseWell : public WellSolverBase CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; - /* - * @brief apply a special treatment to the wells that are shut - * @param time_n the time at the previous converged time step - * @param dt the time step size - * @param domain the physical domain object - * @param dofManager degree-of-freedom manager associated with the linear system - * @param matrix the system matrix - * @param rhs the system right-hand side vector - */ - virtual void shutDownWell( real64 const time_n, - real64 const dt, - DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; - - struct viewKeyStruct : WellSolverBase::viewKeyStruct { static constexpr char const * dofFieldString() { return "singlePhaseWellVars"; } @@ -255,19 +240,20 @@ class SinglePhaseWell : public WellSolverBase protected: - virtual void initializePostSubGroups() override; - void printRates( real64 const & time_n, real64 const & dt, DomainPartition & domain ) override; + /// flag if negative pressure is allowed + integer m_allowNegativePressure; + private: /** * @brief Initialize all the primary and secondary variables in all the wells * @param domain the domain containing the well manager to access individual wells */ - void initializeWells( DomainPartition & domain ) override; + void initializeWells( DomainPartition & domain, real64 const & time_n, real64 const & dt ) override; /** * @brief Make sure that the well constraints are compatible @@ -275,9 +261,9 @@ class SinglePhaseWell : public WellSolverBase * @param dt the time step dt * @param subRegion the well subRegion */ - void validateWellConstraints( real64 const & time_n, - real64 const & dt, - WellElementSubRegion const & subRegion ) const; + virtual void validateWellConstraints( real64 const & time_n, + real64 const & dt, + WellElementSubRegion const & subRegion ) override; }; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp index e3c2063e21a..773a7e3be60 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstants.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstants.hpp index 410a1439d5a..58b8b421c3a 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstants.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstants.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp index 147f7027661..7ce65b6cbec 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,6 +21,8 @@ #include "WellConstants.hpp" #include "dataRepository/InputFlags.hpp" #include "functions/FunctionManager.hpp" +#include "physicsSolvers/fluidFlow/wells/LogLevelsInfo.hpp" + namespace geos { @@ -36,6 +39,7 @@ WellControls::WellControls( string const & name, Group * const parent ) m_targetBHP( 0.0 ), m_targetTotalRate( 0.0 ), m_targetPhaseRate( 0.0 ), + m_targetMassRate( 0.0 ), m_useSurfaceConditions( 0 ), m_surfacePres( 0.0 ), m_surfaceTemp( 0.0 ), @@ -79,6 +83,11 @@ WellControls::WellControls( string const & name, Group * const parent ) setInputFlag( InputFlags::OPTIONAL ). setDescription( "Target phase volumetric rate (if useSurfaceConditions: [surface m^3/s]; else [reservoir m^3/s])" ); + registerWrapper( viewKeyStruct::targetMassRateString(), &m_targetMassRate ). + setDefaultValue( 0.0 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Target Mass Rate rate ( [kg^3/s])" ); + registerWrapper( viewKeyStruct::targetPhaseNameString(), &m_targetPhaseName ). setRTTypeName( rtTypes::CustomTypes::groupNameRef ). setDefaultValue( "" ). @@ -146,6 +155,11 @@ WellControls::WellControls( string const & name, Group * const parent ) setInputFlag( InputFlags::OPTIONAL ). setDescription( "Name of the phase rate table when the rate is a time dependent function" ); + registerWrapper( viewKeyStruct::targetMassRateTableNameString(), &m_targetMassRateTableName ). + setRTTypeName( rtTypes::CustomTypes::groupNameRef ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Name of the mass rate table when the rate is a time dependent function" ); + registerWrapper( viewKeyStruct::statusTableNameString(), &m_statusTableName ). setRTTypeName( rtTypes::CustomTypes::groupNameRef ). setInputFlag( InputFlags::OPTIONAL ). @@ -175,6 +189,12 @@ void WellControls::switchToPhaseRateControl( real64 const & val ) m_targetPhaseRate = val; } +void WellControls::switchToMassRateControl( real64 const & val ) +{ + m_currentControl = Control::MASSRATE; + m_targetMassRate = val; +} + namespace { @@ -198,7 +218,7 @@ TableFunction * createWellTable( string const & tableName, } -void WellControls::postProcessInput() +void WellControls::postInputInitialization() { // 0) Assign the value of the current well control // When the simulation starts from a restart file, we don't want to use the inputControl, @@ -228,6 +248,10 @@ void WellControls::postProcessInput() getWrapperDataContext( viewKeyStruct::targetPhaseRateString() ) << ": Target oil rate is negative", InputError ); + GEOS_THROW_IF( m_targetMassRate < 0, + getWrapperDataContext( viewKeyStruct::targetMassRateString() ) << ": Target mass rate is negative", + InputError ); + GEOS_THROW_IF( (m_injectionStream.empty() && m_injectionTemperature >= 0) || (!m_injectionStream.empty() && m_injectionTemperature < 0), "WellControls " << getDataContext() << ": Both " @@ -267,14 +291,18 @@ void WellControls::postProcessInput() // 4) check that at least one rate constraint has been defined GEOS_THROW_IF( ((m_targetPhaseRate <= 0.0 && m_targetPhaseRateTableName.empty()) && + (m_targetMassRate <= 0.0 && m_targetMassRateTableName.empty()) && (m_targetTotalRate <= 0.0 && m_targetTotalRateTableName.empty())), - "WellControls " << getDataContext() << ": You need to specify a phase rate constraint or a total rate constraint. \n" << + "WellControls " << getDataContext() << ": You need to specify a phase, mass, or total rate constraint. \n" << "The phase rate constraint can be specified using " << "either " << viewKeyStruct::targetPhaseRateString() << " or " << viewKeyStruct::targetPhaseRateTableNameString() << ".\n" << "The total rate constraint can be specified using " << "either " << viewKeyStruct::targetTotalRateString() << - " or " << viewKeyStruct::targetTotalRateTableNameString(), + " or " << viewKeyStruct::targetTotalRateTableNameString()<< + "The mass rate constraint can be specified using " << + "either " << viewKeyStruct::targetMassRateString() << + " or " << viewKeyStruct::targetMassRateTableNameString(), InputError ); // 5) check whether redundant information has been provided @@ -293,6 +321,15 @@ void WellControls::postProcessInput() " The keywords " << viewKeyStruct::targetBHPString() << " and " << viewKeyStruct::targetBHPTableNameString() << " cannot be specified together", InputError ); + GEOS_THROW_IF( ((m_targetMassRate > 0.0 && !m_targetMassRateTableName.empty())), + "WellControls " << getDataContext() << ": You have provided redundant information for well mass rate." << + " The keywords " << viewKeyStruct::targetMassRateString() << " and " << viewKeyStruct::targetMassRateTableNameString() << " cannot be specified together", + InputError ); + + GEOS_THROW_IF( ((m_targetMassRate > 0.0 && m_useSurfaceConditions==0)), + "WellControls " << getDataContext() << ": Option only valid if useSurfaceConditions set to 1", + InputError ); + // 6.1) If the well is under BHP control then the BHP must be specified. // Otherwise the BHP will be set to a default value. if( m_currentControl == Control::BHP ) @@ -305,8 +342,8 @@ void WellControls::postProcessInput() else if( m_targetBHP <= 0.0 && m_targetBHPTableName.empty() ) { m_targetBHP = isProducer() ? WellConstants::defaultProducerBHP : WellConstants::defaultInjectorBHP; - GEOS_LOG_LEVEL_RANK_0( 1, "WellControls " << getDataContext() << ": Setting " << viewKeyStruct::targetBHPString() << " to default value " - << m_targetBHP << "." ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::WellControl, + GEOS_FMT( "WellControls {}: Setting {} to default value {}", getDataContext(), viewKeyStruct::targetBHPString(), m_targetBHP )); } // 6.2) Check incoherent information @@ -317,6 +354,12 @@ void WellControls::postProcessInput() << EnumStrings< Control >::toString( Control::TOTALVOLRATE ), InputError ); + // An injector must be controlled by TotalVolRate + GEOS_THROW_IF( (isProducer() && (m_inputControl == Control::MASSRATE)), + "WellControls " << getDataContext() << ": You have to control an injector with " + << EnumStrings< Control >::toString( Control::MASSRATE ), + InputError ); + // 7) Make sure that the flag disabling crossflow is not used for producers GEOS_THROW_IF( isProducer() && m_isCrossflowEnabled == 0, getWrapperDataContext( viewKeyStruct::enableCrossflowString() ) << @@ -342,7 +385,7 @@ void WellControls::postProcessInput() m_targetBHPTable = &(functionManager.getGroup< TableFunction const >( m_targetBHPTableName )); GEOS_THROW_IF( m_targetBHPTable->getInterpolationMethod() != TableFunction::InterpolationType::Lower, - "WellControls " << getDataContext() << ": The interpolation method for the time-dependent rate table " + "WellControls " << getDataContext() << ": The interpolation method for the time-dependent BHP table " << m_targetBHPTable->getName() << " should be TableFunction::InterpolationType::Lower", InputError ); } @@ -359,7 +402,7 @@ void WellControls::postProcessInput() m_targetTotalRateTable = &(functionManager.getGroup< TableFunction const >( m_targetTotalRateTableName )); GEOS_THROW_IF( m_targetTotalRateTable->getInterpolationMethod() != TableFunction::InterpolationType::Lower, - "WellControls " << getDataContext() << ": The interpolation method for the time-dependent rate table " + "WellControls " << getDataContext() << ": The interpolation method for the time-dependent total rate table " << m_targetTotalRateTable->getName() << " should be TableFunction::InterpolationType::Lower", InputError ); } @@ -376,11 +419,26 @@ void WellControls::postProcessInput() m_targetPhaseRateTable = &(functionManager.getGroup< TableFunction const >( m_targetPhaseRateTableName )); GEOS_THROW_IF( m_targetPhaseRateTable->getInterpolationMethod() != TableFunction::InterpolationType::Lower, - "WellControls " << getDataContext() << ": The interpolation method for the time-dependent rate table " + "WellControls " << getDataContext() << ": The interpolation method for the time-dependent phase rate table " << m_targetPhaseRateTable->getName() << " should be TableFunction::InterpolationType::Lower", InputError ); } + // Create time-dependent mass rate table + if( m_targetMassRateTableName.empty() ) + { + m_targetMassRateTableName = getName()+"_ConstantMassRate_table"; + m_targetMassRateTable = createWellTable( m_targetMassRateTableName, m_targetMassRate ); + } + else + { + FunctionManager & functionManager = FunctionManager::getInstance(); + m_targetMassRateTable = &(functionManager.getGroup< TableFunction const >( m_targetMassRateTableName )); + GEOS_THROW_IF( m_targetMassRateTable->getInterpolationMethod() != TableFunction::InterpolationType::Lower, + "WellControls " << getDataContext() << ": The interpolation method for the time-dependent mass rate table " + << m_targetMassRateTable->getName() << " should be TableFunction::InterpolationType::Lower", + InputError ); + } // 12) Create the time-dependent well status table if( m_statusTableName.empty()) { @@ -399,8 +457,8 @@ void WellControls::postProcessInput() m_statusTable = &(functionManager.getGroup< TableFunction const >( m_statusTableName )); GEOS_THROW_IF( m_statusTable->getInterpolationMethod() != TableFunction::InterpolationType::Lower, - "WellControls " << getDataContext() << ": The interpolation method for the time-dependent rate table " - << m_targetPhaseRateTable->getName() << " should be TableFunction::InterpolationType::Lower", + "WellControls " << getDataContext() << ": The interpolation method for the time-dependent status table " + << m_statusTable->getName() << " should be TableFunction::InterpolationType::Lower", InputError ); } } @@ -408,7 +466,8 @@ void WellControls::postProcessInput() bool WellControls::isWellOpen( real64 const & currentTime ) const { bool isOpen = true; - if( isZero( getTargetTotalRate( currentTime ) ) && isZero( getTargetPhaseRate( currentTime ) ) ) + if( isZero( getTargetTotalRate( currentTime ) ) && isZero( getTargetPhaseRate( currentTime ) ) + && isZero( getTargetMassRate( currentTime ) )) { isOpen = false; } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp index 78f1524e518..3335b7d98dc 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLCONTROLS_HPP #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLCONTROLS_HPP -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include "dataRepository/Group.hpp" #include "functions/TableFunction.hpp" @@ -61,7 +62,8 @@ class WellControls : public dataRepository::Group BHP, /**< The well operates at a specified bottom hole pressure (BHP) */ PHASEVOLRATE, /**< The well operates at a specified phase volumetric flow rate */ TOTALVOLRATE, /**< The well operates at a specified total volumetric flow rate */ - UNINITIALIZED, /**< This is the current well control before postProcessInput (needed to restart from file properly) */ + MASSRATE, /**evaluate( ¤tTime ); + } + + /** * @brief Const accessor for the composition of the injection stream * @return a global component fraction vector @@ -276,6 +294,8 @@ class WellControls : public dataRepository::Group static constexpr char const * targetPhaseRateString() { return "targetPhaseRate"; } /// String key for the well target phase name static constexpr char const * targetPhaseNameString() { return "targetPhaseName"; } + /// String key for the well target phase name + static constexpr char const * targetMassRateString() { return "targetMassRate"; } /// String key for the well injection stream static constexpr char const * injectionStreamString() { return "injectionStream"; } /// String key for the well injection temperature @@ -290,6 +310,8 @@ class WellControls : public dataRepository::Group static constexpr char const * targetTotalRateTableNameString() { return "targetTotalRateTableName"; } /// string key for phase rate table name static constexpr char const * targetPhaseRateTableNameString() { return "targetPhaseRateTableName"; } + /// string key for mass rate table name + static constexpr char const * targetMassRateTableNameString() { return "targetMassRateTableName"; } /// string key for BHP table name static constexpr char const * targetBHPTableNameString() { return "targetBHPTableName"; } /// string key for status table name @@ -305,7 +327,7 @@ class WellControls : public dataRepository::Group protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; private: @@ -336,6 +358,9 @@ class WellControls : public dataRepository::Group /// Name of the targeted phase string m_targetPhaseName; + /// Target MassRate + real64 m_targetMassRate; + /// Vector with global component fractions at the injector array1d< real64 > m_injectionStream; @@ -357,6 +382,9 @@ class WellControls : public dataRepository::Group /// Phase rate table name string m_targetPhaseRateTableName; + /// Mass rate table name + string m_targetMassRateTableName; + /// BHP table name string m_targetBHPTableName; @@ -378,6 +406,9 @@ class WellControls : public dataRepository::Group /// Phase rate table TableFunction const * m_targetPhaseRateTable; + /// Mass rate table + TableFunction const * m_targetMassRateTable; + /// BHP table TableFunction const * m_targetBHPTable; @@ -393,6 +424,7 @@ ENUM_STRINGS( WellControls::Control, "BHP", "phaseVolRate", "totalVolRate", + "massRate", "uninitialized" ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellFields.hpp new file mode 100644 index 00000000000..e24c0d3293d --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellFields.hpp @@ -0,0 +1,60 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file WellFields.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLFIELDS_HPP_ +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLFIELDS_HPP_ + +#include "common/DataLayouts.hpp" +#include "mesh/MeshFields.hpp" + +namespace geos +{ +/** + * A scope for field traits. + */ +namespace fields +{ + +namespace well +{ + +DECLARE_FIELD( energyPerforationFlux, + "energyPerforationFlux", + array1d< real64 >, + 0, + NOPLOT, + WRITE_AND_READ, + "Energy perforation flux" ); + +DECLARE_FIELD( dEnergyPerforationFlux, + "dEnergyPerforationFlux", + array3d< real64 >, + 0, + NOPLOT, + NO_WRITE, + "Derivative of energy perforation flux with respect to pressure temperature and global component density" ); + + +} + +} + +} + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLFIELDS_HPP_ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index a25112cd74a..e7496035ec6 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -26,6 +27,8 @@ #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/wells/LogLevelsInfo.hpp" +#include "physicsSolvers/fluidFlow/wells/kernels/ThermalCompositionalMultiphaseWellKernels.hpp" #include "fileIO/Outputs/OutputBase.hpp" namespace geos @@ -36,11 +39,20 @@ using namespace constitutive; WellSolverBase::WellSolverBase( string const & name, Group * const parent ) - : SolverBase( name, parent ), + : PhysicsSolverBase( name, parent ), + m_numPhases( 0 ), + m_numComponents( 0 ), m_numDofPerWellElement( 0 ), m_numDofPerResElement( 0 ), - m_ratesOutputDir( joinPath( OutputBase::getOutputDirectory(), name + "_rates" ) ) + m_isThermal( 0 ), + m_ratesOutputDir( joinPath( OutputBase::getOutputDirectory(), name + "_rates" ) ), + m_keepVariablesConstantDuringInitStep( 0 ) { + registerWrapper( viewKeyStruct::isThermalString(), &m_isThermal ). + setApplyDefaultValue( 0 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Flag indicating whether the problem is thermal or not." ); + this->getWrapper< string >( viewKeyStruct::discretizationString() ). setInputFlag( InputFlags::FALSE ); @@ -48,11 +60,14 @@ WellSolverBase::WellSolverBase( string const & name, setApplyDefaultValue( 0 ). setInputFlag( dataRepository::InputFlags::OPTIONAL ). setDescription( "Write rates into a CSV file" ); + + addLogLevel< logInfo::WellControl >(); + addLogLevel< logInfo::Crossflow >(); } -Group * WellSolverBase::createChild( string const & childKey, string const & childName ) +Group *WellSolverBase::createChild( string const & childKey, string const & childName ) { - Group * rval = nullptr; + Group *rval = nullptr; if( childKey == keys::wellControls ) { @@ -60,7 +75,7 @@ Group * WellSolverBase::createChild( string const & childKey, string const & chi } else { - SolverBase::createChild( childKey, childName ); + PhysicsSolverBase::createChild( childKey, childName ); } return rval; } @@ -70,12 +85,16 @@ void WellSolverBase::expandObjectCatalogs() createChild( keys::wellControls, keys::wellControls ); } - WellSolverBase::~WellSolverBase() = default; -void WellSolverBase::postProcessInput() +void WellSolverBase::postInputInitialization() { - SolverBase::postProcessInput(); + PhysicsSolverBase::postInputInitialization(); + + // 1. Set key dimensions of the problem + m_numDofPerWellElement = m_isThermal ? m_numComponents + 2 : m_numComponents + 1; // 1 pressure connectionRate + temp if thermal + m_numDofPerResElement = m_isThermal ? m_numComponents + 1: m_numComponents; // 1 pressure + temp if thermal + // create dir for rates output if( m_writeCSV > 0 ) @@ -91,9 +110,9 @@ void WellSolverBase::postProcessInput() void WellSolverBase::registerDataOnMesh( Group & meshBodies ) { - SolverBase::registerDataOnMesh( meshBodies ); - + PhysicsSolverBase::registerDataOnMesh( meshBodies ); + // loop over the wells forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, MeshLevel & meshLevel, arrayView1d< string const > const & regionNames ) @@ -104,6 +123,14 @@ void WellSolverBase::registerDataOnMesh( Group & meshBodies ) [&]( localIndex const, WellElementSubRegion & subRegion ) { + subRegion.registerField< fields::well::pressure >( getName() ); + subRegion.registerField< fields::well::pressure_n >( getName() ); + + subRegion.registerField< fields::well::temperature >( getName() ); + if( isThermal() ) + { + subRegion.registerField< fields::well::temperature_n >( getName() ); + } subRegion.registerField< fields::well::gravityCoefficient >( getName() ); @@ -118,9 +145,26 @@ void WellSolverBase::registerDataOnMesh( Group & meshBodies ) } ); } +void WellSolverBase::initializePostSubGroups() +{ + DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + validateWellConstraints( 0, 0, subRegion ); + } ); + } ); +} + void WellSolverBase::setConstitutiveNamesCallSuper( ElementSubRegionBase & subRegion ) const { - SolverBase::setConstitutiveNamesCallSuper( subRegion ); + PhysicsSolverBase::setConstitutiveNamesCallSuper( subRegion ); subRegion.registerWrapper< string >( viewKeyStruct::fluidNamesString() ). setPlotLevel( PlotLevel::NOPLOT ). setRestartFlags( RestartFlags::NO_WRITE ). @@ -131,9 +175,9 @@ void WellSolverBase::setupDofs( DomainPartition const & domain, DofManager & dofManager ) const { map< std::pair< string, string >, array1d< string > > meshTargets; - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshBodyName, - MeshLevel const & meshLevel, - arrayView1d< string const > const & regionNames ) + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const & meshBodyName, + MeshLevel const & meshLevel, + arrayView1d< string const > const & regionNames ) { array1d< string > regions; ElementRegionManager const & elementRegionManager = meshLevel.getElemManager(); @@ -158,14 +202,26 @@ void WellSolverBase::setupDofs( DomainPartition const & domain, } void WellSolverBase::implicitStepSetup( real64 const & time_n, - real64 const & GEOS_UNUSED_PARAM( dt ), + real64 const & dt, DomainPartition & domain ) { // Initialize the primary and secondary variables for the first time step - if( time_n <= 0.0 ) + + initializeWells( domain, time_n, dt ); +} + +void WellSolverBase::updateState( DomainPartition & domain ) +{ + GEOS_MARK_FUNCTION; + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { - initializeWells( domain ); - } + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, + WellElementSubRegion & subRegion ) + { updateSubRegionState( subRegion ); } ); + } ); } void WellSolverBase::assembleSystem( real64 const time, @@ -175,57 +231,36 @@ void WellSolverBase::assembleSystem( real64 const time, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - // assemble the accumulation term in the mass balance equations - assembleAccumulationTerms( domain, dofManager, localMatrix, localRhs ); + string const wellDofKey = dofManager.getKey( wellElementDofName()); - // then assemble the flux terms in the mass balance equations - assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); - - // then assemble the volume balance equations - assembleVolumeBalanceTerms( domain, dofManager, localMatrix, localRhs ); + // assemble the accumulation term in the mass balance equations + assembleAccumulationTerms( time, dt, domain, dofManager, localMatrix, localRhs ); // then assemble the pressure relations between well elements assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); - // then compute the perforation rates (later assembled by the coupled solver) - computePerforationRates( domain ); - - // then apply a special treatment to the wells that are shut - shutDownWell( time, dt, domain, dofManager, localMatrix, localRhs ); -} - -void WellSolverBase::updateState( DomainPartition & domain ) -{ - GEOS_MARK_FUNCTION; + computePerforationRates( time, dt, domain ); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, - WellElementSubRegion & subRegion ) - { - updateSubRegionState( subRegion ); - } ); - } ); + // then assemble the flux terms in the mass balance equations + // get a reference to the degree-of-freedom numbers + // then assemble the flux terms in the mass balance equations + assembleFluxTerms( time, dt, domain, dofManager, localMatrix, localRhs ); } void WellSolverBase::initializePostInitialConditionsPreSubGroups() { - SolverBase::initializePostInitialConditionsPreSubGroups(); + PhysicsSolverBase::initializePostInitialConditionsPreSubGroups(); DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); // make sure that nextWellElementIndex is up-to-date (will be used in well initialization and assembly) - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion & subRegion ) - { - subRegion.reconstructLocalConnectivity(); - } ); + { subRegion.reconstructLocalConnectivity(); } ); } ); // Precompute solver-specific constant data (e.g. gravity-coefficient) @@ -235,9 +270,9 @@ void WellSolverBase::initializePostInitialConditionsPreSubGroups() void WellSolverBase::precomputeData( DomainPartition & domain ) { R1Tensor const gravVector = gravityVector(); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion & subRegion ) @@ -265,16 +300,19 @@ void WellSolverBase::precomputeData( DomainPartition & domain ) } ); // set the reference well element where the BHP control is applied - wellControls.setReferenceGravityCoef( refElev * gravVector[ 2 ] ); - + wellControls.setReferenceGravityCoef( refElev * gravVector[2] ); } ); } ); } WellControls & WellSolverBase::getWellControls( WellElementSubRegion const & subRegion ) -{ return this->getGroup< WellControls >( subRegion.getWellControlsName() ); } +{ + return this->getGroup< WellControls >( subRegion.getWellControlsName()); +} WellControls const & WellSolverBase::getWellControls( WellElementSubRegion const & subRegion ) const -{ return this->getGroup< WellControls >( subRegion.getWellControlsName() ); } +{ + return this->getGroup< WellControls >( subRegion.getWellControlsName()); +} } // namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index 6f53122b71e..a02af416759 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,7 @@ #ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLSOLVERBASE_HPP_ #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLSOLVERBASE_HPP_ -#include "physicsSolvers/SolverBase.hpp" +#include "physicsSolvers/PhysicsSolverBase.hpp" namespace geos { @@ -34,7 +35,7 @@ class WellElementSubRegion; * Base class for well solvers. * Provides some common features */ -class WellSolverBase : public SolverBase +class WellSolverBase : public PhysicsSolverBase { public: @@ -97,6 +98,12 @@ class WellSolverBase : public SolverBase */ localIndex numDofPerResElement() const { return m_numDofPerResElement; } + /** + * @brief getter for iso/thermal switch + * @return True if thermal + */ + integer isThermal() const { return m_isThermal; } + /** * @brief get the name of DOF defined on well elements * @return name of the DOF field used by derived solver type @@ -190,8 +197,9 @@ class WellSolverBase : public SolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - virtual void assembleFluxTerms( real64 const dt, - DomainPartition const & domain, + virtual void assembleFluxTerms( real64 const & time_n, + real64 const & dt, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) = 0; @@ -203,23 +211,13 @@ class WellSolverBase : public SolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - virtual void assembleAccumulationTerms( DomainPartition const & domain, + virtual void assembleAccumulationTerms( real64 const & time_n, + real64 const & dt, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) = 0; - /** - * @brief assembles the volume balance terms for all well elements - * @param domain the physical domain object - * @param dofManager degree-of-freedom manager associated with the linear system - * @param matrix the system matrix - * @param rhs the system right-hand side vector - */ - virtual void assembleVolumeBalanceTerms( DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) = 0; - /** * @brief assembles the pressure relations at all connections between well elements except at the well head * @param time_n time at the beginning of the time step @@ -236,22 +234,6 @@ class WellSolverBase : public SolverBase CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) = 0; - /** - * @brief apply a special treatment to the wells that are shut - * @param time_n the time at the previous converged time step - * @param dt the time step size - * @param domain the physical domain object - * @param dofManager degree-of-freedom manager associated with the linear system - * @param matrix the system matrix - * @param rhs the system right-hand side vector - */ - virtual void shutDownWell( real64 const time_n, - real64 const dt, - DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) = 0; - /** * @brief Recompute all dependent quantities from primary variables (including constitutive models) * @param domain the domain containing the mesh and fields @@ -262,17 +244,28 @@ class WellSolverBase : public SolverBase * @brief Recompute all dependent quantities from primary variables (including constitutive models) * @param subRegion the well subRegion containing the well elements and their associated fields */ - virtual void updateSubRegionState( WellElementSubRegion & subRegion ) = 0; + virtual real64 updateSubRegionState( WellElementSubRegion & subRegion ) = 0; /** * @brief Recompute the perforation rates for all the wells * @param domain the domain containing the mesh and fields */ - virtual void computePerforationRates( DomainPartition & domain ) = 0; + virtual void computePerforationRates( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) = 0; - struct viewKeyStruct : SolverBase::viewKeyStruct + /** + * @brief Utility function to keep the well variables during a time step (used in poromechanics simulations) + * @param[in] keepVariablesConstantDuringInitStep flag to tell the solver to freeze its primary variables during a time step + * @detail This function is meant to be called by a specific task before/after the initialization step + */ + void setKeepVariablesConstantDuringInitStep( bool const keepVariablesConstantDuringInitStep ) + { m_keepVariablesConstantDuringInitStep = keepVariablesConstantDuringInitStep; } + + struct viewKeyStruct : PhysicsSolverBase::viewKeyStruct { static constexpr char const * fluidNamesString() { return "fluidNames"; } + static constexpr char const * isThermalString() { return "isThermal"; } static constexpr char const * writeCSVFlagString() { return "writeCSV"; } }; @@ -289,15 +282,27 @@ class WellSolverBase : public SolverBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void initializePostInitialConditionsPreSubGroups() override; + virtual void initializePostSubGroups() override; + /** * @brief Initialize all the primary and secondary variables in all the wells * @param domain the domain containing the well manager to access individual wells */ - virtual void initializeWells( DomainPartition & domain ) = 0; + virtual void initializeWells( DomainPartition & domain, real64 const & time_n, real64 const & dt ) = 0; + + /** + * @brief Make sure that the well constraints are compatible + * @param time_n the time at the beginning of the time step + * @param dt the time step dt + * @param subRegion the well subRegion + */ + virtual void validateWellConstraints( real64 const & time_n, + real64 const & dt, + WellElementSubRegion const & subRegion ) = 0; virtual void printRates( real64 const & time_n, real64 const & dt, @@ -306,15 +311,30 @@ class WellSolverBase : public SolverBase /// name of the flow solver string m_flowSolverName; + /// the max number of fluid phases + integer m_numPhases; + + /// the number of fluid components + integer m_numComponents; + /// the number of Degrees of Freedom per well element integer m_numDofPerWellElement; /// the number of Degrees of Freedom per reservoir element integer m_numDofPerResElement; + /// flag indicating whether thermal formulation is used + integer m_isThermal; + + /// rates output integer m_writeCSV; string const m_ratesOutputDir; + /// flag to freeze the initial state during initialization in coupled problems + integer m_keepVariablesConstantDuringInitStep; + + /// name of the fluid constitutive model used as a reference for component/phase description + string m_referenceFluidModelName; }; } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp index ad9a099508e..b9dfebc799b 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -49,7 +50,7 @@ DECLARE_FIELD( pressure_n, "Pressure at the previous converged time step" ); DECLARE_FIELD( temperature, - "wellTemperature", + "temperature", array1d< real64 >, 0, LEVEL_0, @@ -57,7 +58,7 @@ DECLARE_FIELD( temperature, "Temperature" ); DECLARE_FIELD( temperature_n, - "wellTemperature_n", + "temperature_n", array1d< real64 >, 0, NOPLOT, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellTags.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellTags.hpp new file mode 100644 index 00000000000..b96fa2d0618 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellTags.hpp @@ -0,0 +1,111 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file WellTags.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLTAGS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLTAGS_HPP + + +namespace geos +{ + +namespace wellTags +{ + +static constexpr real64 minDensForDivision = 1e-10; + +// tag to access well and reservoir elements in perforation rates computation +struct SubRegionTag +{ + static constexpr integer RES = 0; + static constexpr integer WELL = 1; +}; + +// tag to access the next and current well elements of a connection +struct ElemTag +{ + static constexpr integer CURRENT = 0; + static constexpr integer NEXT = 1; +}; + +// define the column offset of the derivatives +struct ColOffset +{ + static constexpr integer DPRES = 0; + static constexpr integer DCOMP = 1; +}; + +template< integer NC, integer IS_THERMAL > +struct ColOffset_WellJac; + +template< integer NC > +struct ColOffset_WellJac< NC, 0 > +{ + static constexpr integer dP = 0; + static constexpr integer dC = 1; + static constexpr integer dQ = dC + NC; + static integer constexpr nDer = dQ + 1; + +}; + +template< integer NC > +struct ColOffset_WellJac< NC, 1 > +{ + static constexpr integer dP = 0; + static constexpr integer dC = 1; + static constexpr integer dQ = dC + NC; + static constexpr integer dT = dQ+1; + /// number of derivatives + static integer constexpr nDer = dT + 1; +}; + +// define the row offset of the residual equations +struct RowOffset +{ + static constexpr integer CONTROL = 0; + static constexpr integer MASSBAL = 1; +}; + +template< integer NC, integer IS_THERMAL > +struct RowOffset_WellJac; + +template< integer NC > +struct RowOffset_WellJac< NC, 0 > +{ + static constexpr integer CONTROL = 0; + static constexpr integer MASSBAL = 1; + static constexpr integer VOLBAL = MASSBAL + NC; + static constexpr integer nEqn = VOLBAL+1; +}; + +template< integer NC > +struct RowOffset_WellJac< NC, 1 > +{ + static constexpr integer CONTROL = 0; + static constexpr integer MASSBAL = 1; + static constexpr integer VOLBAL = MASSBAL + NC; + static constexpr integer ENERGYBAL = VOLBAL+1; + static constexpr integer nEqn = ENERGYBAL+1; + +}; + +} // end namespace wellTags + +} // end namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLTAGS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/docs/CompositionalMultiphaseWell.rst b/src/coreComponents/physicsSolvers/fluidFlow/wells/docs/CompositionalMultiphaseWell.rst index b78c7b6583b..dccbaa36cff 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/docs/CompositionalMultiphaseWell.rst +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/docs/CompositionalMultiphaseWell.rst @@ -127,7 +127,7 @@ Parameters The following attributes are supported: -.. include:: /coreComponents/schema/docs/CompositionalMultiphaseWell.rst +.. include:: /docs/sphinx/datastructure/CompositionalMultiphaseWell.rst .. _well_input_example: diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.cpp new file mode 100644 index 00000000000..42ec6911080 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.cpp @@ -0,0 +1,759 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CompositionalMultiphaseWellKernels.cpp + */ + +#include "CompositionalMultiphaseWellKernels.hpp" + +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" +// TODO: move keys to WellControls +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp" + +namespace geos +{ + +using namespace constitutive; +namespace compositionalMultiphaseWellKernels +{ + +/******************************** ControlEquationHelper ********************************/ + +GEOS_HOST_DEVICE +inline +void +ControlEquationHelper:: + switchControl( bool const isProducer, + WellControls::Control const & currentControl, + integer const phasePhaseIndex, + real64 const & targetBHP, + real64 const & targetPhaseRate, + real64 const & targetTotalRate, + real64 const & targetMassRate, + real64 const & currentBHP, + arrayView1d< real64 const > const & currentPhaseVolRate, + real64 const & currentTotalVolRate, + WellControls::Control & newControl ) +{ + // if isViable is true at the end of the following checks, no need to switch + bool controlIsViable = false; + + // The limiting flow rates are treated as upper limits, while the pressure limits + // are treated as lower limits in production wells and upper limits in injectors. + // The well changes its mode of control whenever the existing control mode would + // violate one of these limits. + + // Currently, the available constraints are: + // - Producer: BHP, PHASEVOLRATE + // - Injector: BHP, TOTALVOLRATE + + // TODO: support GRAT, WRAT, LIQUID for producers and check if any of the active constraint is violated + + // BHP control + if( currentControl == WellControls::Control::BHP ) + { + // the control is viable if the reference oil rate is below the max rate for producers + if( isProducer ) + { + controlIsViable = ( LvArray::math::abs( currentPhaseVolRate[phasePhaseIndex] ) <= LvArray::math::abs( targetPhaseRate ) ); + } + // the control is viable if the reference total rate is below the max rate for injectors + else + { + controlIsViable = ( LvArray::math::abs( currentTotalVolRate ) <= LvArray::math::abs( targetTotalRate ) ); + } + } + else // rate control + { + // the control is viable if the reference pressure is below/above the max/min pressure + if( isProducer ) + { + // targetBHP specifies a min pressure here + controlIsViable = ( currentBHP >= targetBHP ); + } + else + { + // targetBHP specifies a max pressure here + controlIsViable = ( currentBHP <= targetBHP ); + } + } + + if( controlIsViable ) + { + newControl = currentControl; + } + else + { + if( isProducer ) + { + newControl = ( currentControl == WellControls::Control::BHP ) + ? WellControls::Control::PHASEVOLRATE + : WellControls::Control::BHP; + } + else + { + if( isZero( targetMassRate ) ) + { + newControl = ( currentControl == WellControls::Control::BHP ) + ? WellControls::Control::TOTALVOLRATE + : WellControls::Control::BHP; + } + else + { + newControl = ( currentControl == WellControls::Control::BHP ) + ? WellControls::Control::MASSRATE + : WellControls::Control::BHP; + } + } + } +} + +template< integer NC, integer IS_THERMAL > +GEOS_HOST_DEVICE +inline +void +ControlEquationHelper:: + compute( globalIndex const rankOffset, + WellControls::Control const currentControl, + integer const targetPhaseIndex, + real64 const & targetBHP, + real64 const & targetPhaseRate, + real64 const & targetTotalRate, + real64 const & targetMassRate, + real64 const & currentBHP, + arrayView1d< real64 const > const & dCurrentBHP, + arrayView1d< real64 const > const & currentPhaseVolRate, + arrayView2d< real64 const > const & dCurrentPhaseVolRate, + + real64 const & currentTotalVolRate, + arrayView1d< real64 const > const & dCurrentTotalVolRate, + real64 const & massDensity, + globalIndex const dofNumber, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + + using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; + using Deriv = multifluid::DerivativeOffset; + + localIndex const eqnRowIndex = dofNumber + ROFFSET::CONTROL - rankOffset; + globalIndex dofColIndices[COFFSET_WJ::nDer]{}; + for( integer ic = 0; ic < COFFSET_WJ::nDer; ++ic ) + { + dofColIndices[ ic ] = dofNumber + ic; + } + + real64 controlEqn = 0; + real64 dControlEqn[NC+2+IS_THERMAL]{}; + + // Note: We assume in the computation of currentBHP that the reference elevation + // is in the top well element. This is enforced by a check in the solver. + // If we wanted to allow the reference elevation to be outside the top + // well element, it would make more sense to check the BHP constraint in + // the well element that contains the reference elevation. + + // BHP control + if( currentControl == WellControls::Control::BHP ) + { + // control equation is a difference between current BHP and target BHP + controlEqn = currentBHP - targetBHP; + dControlEqn[COFFSET_WJ::dP] = dCurrentBHP[Deriv::dP]; + for( integer ic = 0; ic < NC; ++ic ) + { + dControlEqn[COFFSET_WJ::dC+ic] = dCurrentBHP[Deriv::dC+ic]; + } + if constexpr ( IS_THERMAL ) + + dControlEqn[COFFSET_WJ::dT] = dCurrentBHP[Deriv::dT]; + + } + // Oil volumetric rate control + else if( currentControl == WellControls::Control::PHASEVOLRATE ) + { + controlEqn = currentPhaseVolRate[targetPhaseIndex] - targetPhaseRate; + dControlEqn[COFFSET_WJ::dP] = dCurrentPhaseVolRate[targetPhaseIndex][COFFSET_WJ::dP]; + dControlEqn[COFFSET_WJ::dQ] = dCurrentPhaseVolRate[targetPhaseIndex][COFFSET_WJ::dQ]; + for( integer ic = 0; ic < NC; ++ic ) + { + dControlEqn[COFFSET_WJ::dC+ic] = dCurrentPhaseVolRate[targetPhaseIndex][COFFSET_WJ::dC+ic]; + } + if constexpr ( IS_THERMAL ) + dControlEqn[COFFSET_WJ::dT] = dCurrentBHP[Deriv::dT]; + } + // Total volumetric rate control + else if( currentControl == WellControls::Control::TOTALVOLRATE ) + { + controlEqn = currentTotalVolRate - targetTotalRate; + dControlEqn[COFFSET_WJ::dP] = dCurrentTotalVolRate[COFFSET_WJ::dP]; + dControlEqn[COFFSET_WJ::dQ] = dCurrentTotalVolRate[COFFSET_WJ::dQ]; + for( integer ic = 0; ic < NC; ++ic ) + { + dControlEqn[COFFSET_WJ::dC+ic] = dCurrentTotalVolRate[COFFSET_WJ::dC+ic]; + } + if constexpr ( IS_THERMAL ) + dControlEqn[COFFSET_WJ::dT] = dCurrentTotalVolRate[COFFSET_WJ::dT]; + } + // Total mass rate control + else if( currentControl == WellControls::Control::MASSRATE ) + { + controlEqn = massDensity*currentTotalVolRate - targetMassRate; + dControlEqn[COFFSET_WJ::dP] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dP]; + dControlEqn[COFFSET_WJ::dQ] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dQ]; + for( integer ic = 0; ic < NC; ++ic ) + { + dControlEqn[COFFSET_WJ::dC+ic] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dC+ic]; + } + if constexpr ( IS_THERMAL ) + dControlEqn[COFFSET_WJ::dT] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dT]; + } + // Total mass rate control + else if( currentControl == WellControls::Control::MASSRATE ) + { + controlEqn = massDensity*currentTotalVolRate - targetMassRate; + dControlEqn[COFFSET_WJ::dP] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dP]; + dControlEqn[COFFSET_WJ::dQ] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dQ]; + for( integer ic = 0; ic < NC; ++ic ) + { + dControlEqn[COFFSET_WJ::dC+ic] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dC+ic]; + } + } + else + { + GEOS_ERROR( "This constraint is not supported in CompositionalMultiphaseWell" ); + } + localRhs[eqnRowIndex] += controlEqn; + + localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( eqnRowIndex, + dofColIndices, + dControlEqn, + COFFSET_WJ::nDer ); + + +} + +/******************************** PressureRelationKernel ********************************/ + +template< integer NC, integer IS_THERMAL > +GEOS_HOST_DEVICE +void +PressureRelationKernel:: + compute( real64 const & gravCoef, + real64 const & gravCoefNext, + real64 const & pres, + real64 const & presNext, + real64 const & totalMassDens, + real64 const & totalMassDensNext, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDensNext, + real64 & localPresRel, + real64 ( & localPresRelJacobian )[2*(NC+1 + IS_THERMAL)] ) +{ + // local working variables and arrays + real64 dAvgMassDens_dCompCurrent[NC]{}; + real64 dAvgMassDens_dCompNext[NC]{}; + + // compute the average density at the interface between well elements + real64 const avgMassDens = 0.5 * ( totalMassDensNext + totalMassDens ); + real64 const dAvgMassDens_dPresNext = 0.5 * dTotalMassDensNext[Deriv::dP]; + real64 const dAvgMassDens_dPresCurrent = 0.5 * dTotalMassDens[Deriv::dP]; + for( integer ic = 0; ic < NC; ++ic ) + { + dAvgMassDens_dCompNext[ic] = 0.5 * dTotalMassDensNext[Deriv::dC+ic]; + dAvgMassDens_dCompCurrent[ic] = 0.5 * dTotalMassDens[Deriv::dC+ic]; + } + + // compute depth diff times acceleration + real64 const gravD = gravCoefNext - gravCoef; + + // TODO: add friction and acceleration terms + + localPresRel = ( presNext - pres - avgMassDens * gravD ); + + // localPresRelJacbain contains dP, dC and potentially dT derivatives for neighboring well elements + // TAG::NEXT is 1, CURRENT is 0 , not sure why indexes are setup as below + localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL)] = ( 1 - dAvgMassDens_dPresNext * gravD ); + localPresRelJacobian[TAG::CURRENT *(NC+1+IS_THERMAL)] = ( -1 - dAvgMassDens_dPresCurrent * gravD ); + + for( integer ic = 0; ic < NC; ++ic ) + { + localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL) + ic+1] = -dAvgMassDens_dCompNext[ic] * gravD; + localPresRelJacobian[TAG::CURRENT *(NC+1+IS_THERMAL) + ic+1] = -dAvgMassDens_dCompCurrent[ic] * gravD; + } + if constexpr ( IS_THERMAL ) + { + localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL)+NC+1] = 0.5 * dTotalMassDensNext[Deriv::dT]; + localPresRelJacobian[TAG::CURRENT *(NC+1+IS_THERMAL)+NC+1] = 0.5 * dTotalMassDens[Deriv::dT]; + } +} + +template< integer NC, integer IS_THERMAL > +void +PressureRelationKernel:: + launch( localIndex const size, + globalIndex const rankOffset, + bool const isLocallyOwned, + localIndex const iwelemControl, + integer const targetPhaseIndex, + WellControls const & wellControls, + real64 const & timeAtEndOfStep, + arrayView1d< globalIndex const > const & wellElemDofNumber, + arrayView1d< real64 const > const & wellElemGravCoef, + arrayView1d< localIndex const > const & nextWellElemIndex, + arrayView1d< real64 const > const & wellElemPressure, + arrayView1d< real64 const > const & wellElemTotalMassDens, + arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, + bool & controlHasSwitched, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; + // static well control data + bool const isProducer = wellControls.isProducer(); + WellControls::Control const currentControl = wellControls.getControl(); + real64 const targetBHP = wellControls.getTargetBHP( timeAtEndOfStep ); + real64 const targetTotalRate = wellControls.getTargetTotalRate( timeAtEndOfStep ); + real64 const targetPhaseRate = wellControls.getTargetPhaseRate( timeAtEndOfStep ); + real64 const targetMassRate = wellControls.getTargetMassRate( timeAtEndOfStep ); + + // dynamic well control data + real64 const & currentBHP = + wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() ); + arrayView1d< real64 const > const & dCurrentBHP = + wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHPString() ); + + arrayView1d< real64 const > const & currentPhaseVolRate = + wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ); + arrayView2d< real64 const > const & dCurrentPhaseVolRate = + wellControls.getReference< array2d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRateString() ); + + real64 const & currentTotalVolRate = + wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() ); + arrayView1d< real64 const > const & dCurrentTotalVolRate = + wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRateString() ); + + real64 const & massDensity = + wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::massDensityString() ); + + RAJA::ReduceMax< parallelDeviceReduce, localIndex > switchControl( 0 ); + + // loop over the well elements to compute the pressure relations between well elements + forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) + { + localIndex const iwelemNext = nextWellElemIndex[iwelem]; + + if( iwelemNext < 0 && isLocallyOwned ) // if iwelemNext < 0, form control equation + { + WellControls::Control newControl = currentControl; + ControlEquationHelper::switchControl( isProducer, + currentControl, + targetPhaseIndex, + targetBHP, + targetPhaseRate, + targetTotalRate, + targetMassRate, + currentBHP, + currentPhaseVolRate, + currentTotalVolRate, + newControl ); + if( currentControl != newControl ) + { + switchControl.max( 1 ); + } + ControlEquationHelper::compute< NC, IS_THERMAL >( rankOffset, + newControl, + targetPhaseIndex, + targetBHP, + targetPhaseRate, + targetTotalRate, + targetMassRate, + currentBHP, + dCurrentBHP, + currentPhaseVolRate, + dCurrentPhaseVolRate, + currentTotalVolRate, + dCurrentTotalVolRate, + massDensity, + wellElemDofNumber[iwelemControl], + localMatrix, + localRhs ); + // TODO: for consistency, we should assemble here, not in compute... + + } + else if( iwelemNext >= 0 ) // if iwelemNext >= 0, form momentum equation + { + + real64 localPresRel = 0; + real64 localPresRelJacobian[2*(NC+1+IS_THERMAL)]{}; + + compute< NC, IS_THERMAL >( + wellElemGravCoef[iwelem], + wellElemGravCoef[iwelemNext], + wellElemPressure[iwelem], + wellElemPressure[iwelemNext], + wellElemTotalMassDens[iwelem], + wellElemTotalMassDens[iwelemNext], + dWellElemTotalMassDens[iwelem], + dWellElemTotalMassDens[iwelemNext], + localPresRel, + localPresRelJacobian ); + + + // local working variables and arrays + globalIndex dofColIndices[2*(NC+1+IS_THERMAL)]; + + globalIndex const eqnRowIndex = wellElemDofNumber[iwelem] + ROFFSET::CONTROL - rankOffset; + dofColIndices[TAG::NEXT *(NC+1+IS_THERMAL)] = wellElemDofNumber[iwelemNext] + COFFSET_WJ::dP; + dofColIndices[TAG::CURRENT *(NC+1+IS_THERMAL)] = wellElemDofNumber[iwelem] + COFFSET_WJ::dP; + + for( integer ic = 0; ic < NC; ++ic ) + { + dofColIndices[TAG::NEXT *(NC+1+IS_THERMAL) + ic+1] = wellElemDofNumber[iwelemNext] + COFFSET_WJ::dC + ic; + dofColIndices[TAG::CURRENT *(NC+1+IS_THERMAL) + ic+1] = wellElemDofNumber[iwelem] + COFFSET_WJ::dC + ic; + } + if constexpr ( IS_THERMAL ) + { + dofColIndices[TAG::NEXT *(NC+1+IS_THERMAL)+NC+1] = wellElemDofNumber[iwelemNext] + COFFSET_WJ::dT; + dofColIndices[TAG::CURRENT *(NC+1+IS_THERMAL)+NC+1] = wellElemDofNumber[iwelem] + COFFSET_WJ::dT; + } + if( eqnRowIndex >= 0 && eqnRowIndex < localMatrix.numRows() ) + { + localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndex, + dofColIndices, + localPresRelJacobian, + 2 * (NC+1+IS_THERMAL) ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[eqnRowIndex], localPresRel ); + } + } + } ); + controlHasSwitched = ( switchControl.get() == 1 ); +} + +#define INST_PressureRelationKernel( NC, IS_THERMAL ) \ + template \ + void PressureRelationKernel:: \ + launch< NC, IS_THERMAL >( localIndex const size, \ + globalIndex const rankOffset, \ + bool const isLocallyOwned, \ + localIndex const iwelemControl, \ + integer const targetPhaseIndex, \ + WellControls const & wellControls, \ + real64 const & timeAtEndOfStep, \ + arrayView1d< globalIndex const > const & wellElemDofNumber, \ + arrayView1d< real64 const > const & wellElemGravCoef, \ + arrayView1d< localIndex const > const & nextWellElemIndex, \ + arrayView1d< real64 const > const & wellElemPressure, \ + arrayView1d< real64 const > const & wellElemTotalMassDens, \ + arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, \ + bool & controlHasSwitched, \ + CRSMatrixView< real64, globalIndex const > const & localMatrix, \ + arrayView1d< real64 > const & localRhs ) + +INST_PressureRelationKernel( 1, 0 ); +INST_PressureRelationKernel( 1, 1 ); +INST_PressureRelationKernel( 2, 0 ); +INST_PressureRelationKernel( 2, 1 ); +INST_PressureRelationKernel( 3, 0 ); +INST_PressureRelationKernel( 3, 1 ); +INST_PressureRelationKernel( 4, 0 ); +INST_PressureRelationKernel( 4, 1 ); +INST_PressureRelationKernel( 5, 0 ); +INST_PressureRelationKernel( 5, 1 ); + +void +PresTempCompFracInitializationKernel:: + launch( localIndex const perforationSize, + localIndex const subRegionSize, + integer const numComps, + integer const numPhases, + localIndex const numPerforations, + WellControls const & wellControls, + real64 const & currentTime, + ElementViewConst< arrayView1d< real64 const > > const & resPres, + ElementViewConst< arrayView1d< real64 const > > const & resTemp, + ElementViewConst< arrayView2d< real64 const, compflow::USD_COMP > > const & resCompDens, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & resPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & resPhaseMassDens, + arrayView1d< localIndex const > const & resElementRegion, + arrayView1d< localIndex const > const & resElementSubRegion, + arrayView1d< localIndex const > const & resElementIndex, + arrayView1d< real64 const > const & perfGravCoef, + arrayView1d< real64 const > const & wellElemGravCoef, + arrayView1d< real64 > const & wellElemPres, + arrayView1d< real64 > const & wellElemTemp, + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompFrac ) +{ + integer constexpr MAX_NUM_COMP = constitutive::MultiFluidBase::MAX_NUM_COMPONENTS; + + real64 const targetBHP = wellControls.getTargetBHP( currentTime ); + real64 const refWellElemGravCoef = wellControls.getReferenceGravityCoef(); + real64 const initialPresCoef = wellControls.getInitialPressureCoefficient(); + WellControls::Control const currentControl = wellControls.getControl(); + bool const isProducer = wellControls.isProducer(); + + + + // Step 1: we loop over all the perforations on this rank to compute the following quantities: + // - Sum of total mass densities over the perforated reservoir elements + // - Sum of the temperatures over the perforated reservoir elements + // - Sum of the component fractions over the perforated reservoir elements + // In passing, we save the min gravCoef difference between the reference depth and the perforation depth + // Note that we use gravCoef instead of depth for the (unlikely) case in which the gravityVector is not aligned with z + + RAJA::ReduceSum< parallelDeviceReduce, real64 > sumTotalMassDens( 0 ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > sumTemp( 0 ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > sumCompFrac[MAX_NUM_COMP]{}; + RAJA::ReduceMin< parallelDeviceReduce, real64 > localMinGravCoefDiff( 1e9 ); + + forAll< parallelDevicePolicy<> >( perforationSize, [=] GEOS_HOST_DEVICE ( localIndex const iperf ) + { + // get the reservoir (sub)region and element indices + localIndex const er = resElementRegion[iperf]; + localIndex const esr = resElementSubRegion[iperf]; + localIndex const ei = resElementIndex[iperf]; + + // save the min gravCoef difference between the reference depth and the perforation depth (times g) + localMinGravCoefDiff.min( LvArray::math::abs( refWellElemGravCoef - perfGravCoef[iperf] ) ); + + // increment the temperature + sumTemp += resTemp[er][esr][ei]; + + // increment the total mass density + for( integer ip = 0; ip < numPhases; ++ip ) + { + sumTotalMassDens += resPhaseVolFrac[er][esr][ei][ip] * resPhaseMassDens[er][esr][ei][0][ip]; + } + + // increment the component fractions + real64 perfTotalDens = 0.0; + for( integer ic = 0; ic < numComps; ++ic ) + { + perfTotalDens += resCompDens[er][esr][ei][ic]; + } + for( integer ic = 0; ic < numComps; ++ic ) + { + sumCompFrac[ic] += resCompDens[er][esr][ei][ic] / perfTotalDens; + } + } ); + real64 const minGravCoefDiff = MpiWrapper::min( localMinGravCoefDiff.get() ); + + + + // Step 2: we assign average quantities over the well (i.e., over all the ranks) + // For composition and temperature, we make a distinction between injection and production + + // for total mass density, we always use the values of the perforated reservoir elements, even for injectors + real64 const avgTotalMassDens = MpiWrapper::sum( sumTotalMassDens.get() ) / numPerforations; + + stackArray1d< real64, MAX_NUM_COMP > avgCompFrac( numComps ); + real64 avgTemp = 0; + + // for a producer, we use the temperature and component fractions from the reservoir + if( isProducer ) + { + // use average temperature from reservoir + avgTemp = MpiWrapper::sum( sumTemp.get() ) / numPerforations; + + // use average comp frac from reservoir + for( integer ic = 0; ic < numComps; ++ic ) + { + avgCompFrac[ic] = MpiWrapper::sum( sumCompFrac[ic].get() ) / numPerforations; + } + } + // for an injector, we use the injection stream values + else + { + // use temperature from injection stream + avgTemp = wellControls.getInjectionTemperature(); + + // use comp frac from injection stream + for( integer ic = 0; ic < numComps; ++ic ) + { + avgCompFrac[ic] = wellControls.getInjectionStream()[ic]; + } + } + + + + // Step 3: we compute the approximate pressure at the reference depth + // We make a distinction between pressure-controlled wells and rate-controlled wells + + real64 refPres = 0.0; + + // if the well is controlled by pressure, initialize the reference pressure at the target pressure + if( currentControl == WellControls::Control::BHP ) + { + refPres = targetBHP; + } + // if the well is controlled by rate, initialize the reference pressure using the pressure at the closest perforation + else + { + RAJA::ReduceMin< parallelDeviceReduce, real64 > localRefPres( 1e9 ); + real64 const alpha = ( isProducer ) ? 1 - initialPresCoef : 1 + initialPresCoef; + + forAll< parallelDevicePolicy<> >( perforationSize, [=] GEOS_HOST_DEVICE ( localIndex const iperf ) + { + // get the reservoir (sub)region and element indices + localIndex const er = resElementRegion[iperf]; + localIndex const esr = resElementSubRegion[iperf]; + localIndex const ei = resElementIndex[iperf]; + + // get the perforation pressure and save the estimated reference pressure + real64 const gravCoefDiff = LvArray::math::abs( refWellElemGravCoef - perfGravCoef[iperf] ); + if( isZero( gravCoefDiff - minGravCoefDiff ) ) + { + localRefPres.min( alpha * resPres[er][esr][ei] + avgTotalMassDens * ( refWellElemGravCoef - perfGravCoef[iperf] ) ); + } + } ); + refPres = MpiWrapper::min( localRefPres.get() ); + } + + + + // Step 4: we are ready to assign the primary variables on the well elements: + // - pressure: hydrostatic pressure using our crude approximation of the total mass density + // - temperature: uniform, using the average temperature computed above + // - component fraction: uniform, using the average component fraction computed above + + RAJA::ReduceMax< parallelDeviceReduce, integer > foundNegativeTemp( 0 ); + RAJA::ReduceMax< parallelDeviceReduce, integer > foundNegativePres( 0 ); + RAJA::ReduceMax< parallelDeviceReduce, integer > foundInconsistentCompFrac( 0 ); + + + forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) + { + wellElemPres[iwelem] = refPres + avgTotalMassDens * ( wellElemGravCoef[iwelem] - refWellElemGravCoef ); + wellElemTemp[iwelem] = avgTemp; + + real64 sumCompFracForCheck = 0.0; + for( integer ic = 0; ic < numComps; ++ic ) + { + wellElemCompFrac[iwelem][ic] = avgCompFrac[ic]; + sumCompFracForCheck += wellElemCompFrac[iwelem][ic]; + } + + if( wellElemPres[iwelem] <= 0 ) + { + foundNegativePres.max( 1 ); + } + if( wellElemTemp[iwelem] <= 0 ) + { + foundNegativeTemp.max( 1 ); + } + if( !isZero( sumCompFracForCheck - 1.0, constitutive::MultiFluidConstants::minForSpeciesPresence ) ) + { + foundInconsistentCompFrac.max( 1 ); + } + + } ); + + + GEOS_THROW_IF( foundNegativePres.get() == 1, + wellControls.getDataContext() << "Invalid well initialization, negative pressure was found.", + InputError ); + GEOS_THROW_IF( foundNegativeTemp.get() == 1, + wellControls.getDataContext() << "Invalid well initialization, negative temperature was found.", + InputError ); + GEOS_THROW_IF( foundInconsistentCompFrac.get() == 1, + wellControls.getDataContext() << "Invalid well initialization, inconsistent component fractions were found.", + InputError ); + + +} + +/******************************** CompDensInitializationKernel ********************************/ + +void +CompDensInitializationKernel:: + launch( localIndex const subRegionSize, + integer const numComponents, + arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, + arrayView2d< real64 const, multifluid::USD_FLUID > const & wellElemTotalDens, + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens ) +{ + forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) + { + for( integer ic = 0; ic < numComponents; ++ic ) + { + wellElemCompDens[iwelem][ic] = wellElemCompFrac[iwelem][ic] * wellElemTotalDens[iwelem][0]; + } + } ); +} + +/******************************** RateInitializationKernel ********************************/ + +void +RateInitializationKernel:: + launch( localIndex const subRegionSize, + integer const targetPhaseIndex, + WellControls const & wellControls, + real64 const & currentTime, + arrayView3d< real64 const, multifluid::USD_PHASE > const & phaseDens, + arrayView2d< real64 const, multifluid::USD_FLUID > const & totalDens, + arrayView1d< real64 > const & connRate ) +{ + WellControls::Control const control = wellControls.getControl(); + bool const isProducer = wellControls.isProducer(); + real64 const targetTotalRate = wellControls.getTargetTotalRate( currentTime ); + real64 const targetPhaseRate = wellControls.getTargetPhaseRate( currentTime ); + real64 const targetMassRate = wellControls.getTargetMassRate( currentTime ); + + // Estimate the connection rates + forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) + { + if( control == WellControls::Control::BHP ) + { + // if BHP constraint set rate below the absolute max rate + // with the appropriate sign (negative for prod, positive for inj) + if( isProducer ) + { + connRate[iwelem] = LvArray::math::max( 0.1 * targetPhaseRate * phaseDens[iwelem][0][targetPhaseIndex], -1e3 ); + } + else + { + if( isZero( targetMassRate ) ) + { + connRate[iwelem] = LvArray::math::min( 0.1 * targetTotalRate * totalDens[iwelem][0], 1e3 ); + } + else + { + connRate[iwelem] = targetMassRate; + } + + } + } + else if( control == WellControls::Control::MASSRATE ) + { + connRate[iwelem] = targetMassRate; + connRate[iwelem] = targetMassRate* totalDens[iwelem][0]; + } + else + { + if( isProducer ) + { + connRate[iwelem] = targetPhaseRate * phaseDens[iwelem][0][targetPhaseIndex]; + } + else + { + connRate[iwelem] = targetTotalRate * totalDens[iwelem][0]; + } + } + } ); +} + + +} // end namespace compositionalMultiphaseWellKernels + +} // end namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp new file mode 100644 index 00000000000..41d63148bfb --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp @@ -0,0 +1,1919 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CompositionalMultiphaseWellKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_COMPOSITIONALMULTIPHASEWELLKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_COMPOSITIONALMULTIPHASEWELLKERNELS_HPP + +#include "codingUtilities/Utilities.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityFields.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "mesh/ObjectManagerBase.hpp" +#include "physicsSolvers/KernelLaunchSelectors.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" +#include "physicsSolvers/fluidFlow/wells/WellControls.hpp" +#include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" + +namespace geos +{ + + +namespace compositionalMultiphaseWellKernels +{ + +static constexpr real64 minDensForDivision = 1e-10; + +// tag to access well and reservoir elements in perforation rates computation +struct SubRegionTag +{ + static constexpr integer RES = 0; + static constexpr integer WELL = 1; +}; + +// tag to access the next and current well elements of a connection +struct ElemTag +{ + static constexpr integer CURRENT = 0; + static constexpr integer NEXT = 1; +}; + +// define the column offset of the derivatives +struct ColOffset +{ + static constexpr integer DPRES = 0; + static constexpr integer DCOMP = 1; +}; + +template< integer NC, integer IS_THERMAL > +struct ColOffset_WellJac; + +template< integer NC > +struct ColOffset_WellJac< NC, 0 > +{ + static constexpr integer dP = 0; + static constexpr integer dC = 1; + static constexpr integer dQ = dC + NC; + static integer constexpr nDer = dQ + 1; + +}; + +template< integer NC > +struct ColOffset_WellJac< NC, 1 > +{ + static constexpr integer dP = 0; + static constexpr integer dC = 1; + static constexpr integer dQ = dC + NC; + static constexpr integer dT = dQ+1; +/// number of derivatives + static integer constexpr nDer = dT + 1; +}; + +// define the row offset of the residual equations +struct RowOffset +{ + static constexpr integer CONTROL = 0; + static constexpr integer MASSBAL = 1; +}; + +template< integer NC, integer IS_THERMAL > +struct RowOffset_WellJac; + +template< integer NC > +struct RowOffset_WellJac< NC, 0 > +{ + static constexpr integer CONTROL = 0; + static constexpr integer MASSBAL = 1; + static constexpr integer VOLBAL = MASSBAL + NC; + static constexpr integer nEqn = VOLBAL+1; +}; + +template< integer NC > +struct RowOffset_WellJac< NC, 1 > +{ + static constexpr integer CONTROL = 0; + static constexpr integer MASSBAL = 1; + static constexpr integer VOLBAL = MASSBAL + NC; + static constexpr integer ENERGYBAL = VOLBAL+1; + static constexpr integer nEqn = ENERGYBAL+1; + +}; +/******************************** ControlEquationHelper ********************************/ +struct ControlEquationHelper +{ + using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; + using COFFSET = compositionalMultiphaseWellKernels::ColOffset; + + GEOS_HOST_DEVICE + inline + static + void + switchControl( bool const isProducer, + WellControls::Control const & currentControl, + integer const phasePhaseIndex, + real64 const & targetBHP, + real64 const & targetPhaseRate, + real64 const & targetTotalRate, + real64 const & targetMassRate, + real64 const & currentBHP, + arrayView1d< real64 const > const & currentPhaseVolRate, + real64 const & currentTotalVolRate, + WellControls::Control & newControl ); + + template< integer NC, integer IS_THERMAL > + GEOS_HOST_DEVICE + inline + static void + compute( globalIndex const rankOffset, + WellControls::Control const currentControl, + integer const targetPhaseIndex, + real64 const & targetBHP, + real64 const & targetPhaseRate, + real64 const & targetTotalRate, + real64 const & targetMassRate, + real64 const & currentBHP, + arrayView1d< real64 const > const & dCurrentBHP, + arrayView1d< real64 const > const & currentPhaseVolRate, + arrayView2d< real64 const > const & dCurrentPhaseVolRate, + real64 const & currentTotalVolRate, + arrayView1d< real64 const > const & dCurrentTotalVolRate, + real64 const & massDensity, + globalIndex const dofNumber, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); + +}; + +/******************************** PressureRelationKernel ********************************/ + +struct PressureRelationKernel +{ + using Deriv = constitutive::multifluid::DerivativeOffset; + using TAG = compositionalMultiphaseWellKernels::ElemTag; + using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; + using COFFSET = compositionalMultiphaseWellKernels::ColOffset; + + template< integer NC, integer IS_THERMAL > + GEOS_HOST_DEVICE + inline + static void + compute( real64 const & gravCoef, + real64 const & gravCoefNext, + real64 const & pres, + real64 const & presNext, + real64 const & totalMassDens, + real64 const & totalMassDensNext, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDensNext, + real64 & localPresRel, + real64 ( &localPresRelJacobian )[2*(NC+1+IS_THERMAL)] ); + + template< integer NC, integer IS_THERMAL > + static void + launch( localIndex const size, + globalIndex const rankOffset, + bool const isLocallyOwned, + localIndex const iwelemControl, + integer const targetPhaseIndex, + WellControls const & wellControls, + real64 const & timeAtEndOfStep, + arrayView1d< globalIndex const > const & wellElemDofNumber, + arrayView1d< real64 const > const & wellElemGravCoef, + arrayView1d< localIndex const > const & nextWellElemIndex, + arrayView1d< real64 const > const & wellElemPressure, + arrayView1d< real64 const > const & wellElemTotalMassDens, + arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, + bool & controlHasSwitched, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); + +}; + +/******************************** VolumeBalanceKernel ********************************/ + +struct VolumeBalanceKernel +{ + + using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; + using COFFSET = compositionalMultiphaseWellKernels::ColOffset; + + template< integer NC > + GEOS_HOST_DEVICE + inline + static void + compute( integer const numPhases, + real64 const & volume, + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFrac, + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const & dPhaseVolFrac, + real64 & localVolBalance, + real64 ( &localVolBalanceJacobian )[NC+1] ); + + template< integer NC > + static void + launch( localIndex const size, + integer const numPhases, + globalIndex const rankOffset, + arrayView1d< globalIndex const > const & wellElemDofNumber, + arrayView1d< integer const > const & wellElemGhostRank, + arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac, + arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac, + arrayView1d< real64 const > const & wellElemVolume, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); + +}; + +/******************************** PresTempCompFracInitializationKernel ********************************/ + +struct PresTempCompFracInitializationKernel +{ + + using CompFlowAccessors = + StencilAccessors< fields::flow::pressure, + fields::flow::temperature, + fields::flow::globalCompDensity, + fields::flow::phaseVolumeFraction >; + + using MultiFluidAccessors = + StencilMaterialAccessors< constitutive::MultiFluidBase, + fields::multifluid::phaseMassDensity >; + + + /** + * @brief The type for element-based non-constitutive data parameters. + * Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + static void + launch( localIndex const perforationSize, + localIndex const subRegionSize, + integer const numComponents, + integer const numPhases, + localIndex const numPerforations, + WellControls const & wellControls, + real64 const & currentTime, + ElementViewConst< arrayView1d< real64 const > > const & resPres, + ElementViewConst< arrayView1d< real64 const > > const & resTemp, + ElementViewConst< arrayView2d< real64 const, compflow::USD_COMP > > const & resCompDens, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & resPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & resPhaseMassDens, + arrayView1d< localIndex const > const & resElementRegion, + arrayView1d< localIndex const > const & resElementSubRegion, + arrayView1d< localIndex const > const & resElementIndex, + arrayView1d< real64 const > const & perfGravCoef, + arrayView1d< real64 const > const & wellElemGravCoef, + arrayView1d< real64 > const & wellElemPres, + arrayView1d< real64 > const & wellElemTemp, + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompFrac ); + +}; + +/******************************** CompDensInitializationKernel ********************************/ + +struct CompDensInitializationKernel +{ + + static void + launch( localIndex const subRegionSize, + integer const numComponents, + arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, + arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > const & wellElemTotalDens, + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens ); + +}; + +/******************************** RateInitializationKernel ********************************/ + +struct RateInitializationKernel +{ + + static void + launch( localIndex const subRegionSize, + integer const targetPhaseIndex, + WellControls const & wellControls, + real64 const & currentTime, + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseDens, + arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > const & totalDens, + arrayView1d< real64 > const & connRate ); + +}; + + +/******************************** TotalMassDensityKernel ****************************/ + +/** + * @class TotalMassDensityKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_PHASE number of fluid phases + * @brief Define the interface for the property kernel in charge of computing the total mass density + */ +template< integer NUM_COMP, integer NUM_PHASE > +class TotalMassDensityKernel : public isothermalCompositionalMultiphaseBaseKernels::PropertyKernelBase< NUM_COMP > +{ +public: + + using Base = isothermalCompositionalMultiphaseBaseKernels::PropertyKernelBase< NUM_COMP >; + using Base::numComp; + + /// Compile time value for the number of phases + static constexpr integer numPhase = NUM_PHASE; + + /** + * @brief Constructor + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + TotalMassDensityKernel( ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid ) + : Base(), + m_phaseVolFrac( subRegion.getField< fields::well::phaseVolumeFraction >() ), + m_dPhaseVolFrac( subRegion.getField< fields::well::dPhaseVolumeFraction >() ), + m_dCompFrac_dCompDens( subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >() ), + m_phaseMassDens( fluid.phaseMassDensity() ), + m_dPhaseMassDens( fluid.dPhaseMassDensity() ), + m_totalMassDens( subRegion.getField< fields::well::totalMassDensity >() ), + m_dTotalMassDens( subRegion.getField< fields::well::dTotalMassDensity >() ) + {} + + /** + * @brief Compute the total mass density in an element + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[in] totalMassDensityKernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void compute( localIndex const ei, + FUNC && totalMassDensityKernelOp = NoOpFunc{} ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; + arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseMassDens = m_phaseMassDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > dPhaseMassDens = m_dPhaseMassDens[ei][0]; + real64 & totalMassDens = m_totalMassDens[ei]; + arraySlice1d< real64, compflow::USD_FLUID_DC - 1 > dTotalMassDens = m_dTotalMassDens[ei]; + + real64 dMassDens_dC[numComp]{}; + + totalMassDens = 0.0; + + dTotalMassDens[Deriv::dP]=0.0; + for( integer ic = 0; ic < numComp; ++ic ) + { + dTotalMassDens[Deriv::dC+ic]=0.0; + } + + for( integer ip = 0; ip < numPhase; ++ip ) + { + totalMassDens += phaseVolFrac[ip] * phaseMassDens[ip]; + dTotalMassDens[Deriv::dP] += dPhaseVolFrac[ip][Deriv::dP] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dP]; + + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseMassDens[ip], dMassDens_dC, Deriv::dC ); + for( integer ic = 0; ic < numComp; ++ic ) + { + dTotalMassDens[Deriv::dC+ic] += dPhaseVolFrac[ip][Deriv::dC+ic] * phaseMassDens[ip] + + phaseVolFrac[ip] * dMassDens_dC[ic]; + } + + totalMassDensityKernelOp( ip ); //, phaseVolFrac, dTotalMassDens_dPres, dTotalMassDens_dCompDens ); + } + + } + +protected: + + // inputs + + /// Views on phase volume fractions + arrayView2d< real64 const, compflow::USD_PHASE > m_phaseVolFrac; + arrayView3d< real64 const, compflow::USD_PHASE_DC > m_dPhaseVolFrac; + arrayView3d< real64 const, compflow::USD_COMP_DC > m_dCompFrac_dCompDens; + + /// Views on phase mass densities + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseMassDens; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseMassDens; + + // outputs + + /// Views on total mass densities + arrayView1d< real64 > m_totalMassDens; + arrayView2d< real64, compflow::USD_FLUID_DC > m_dTotalMassDens; + + +}; + +/** + * @class TotalMassDensityKernelFactory + */ +class TotalMassDensityKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComp the number of fluid components + * @param[in] numPhase the number of fluid phases + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + integer const numPhase, + ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid ) + { + if( numPhase == 2 ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + TotalMassDensityKernel< NUM_COMP, 2 > kernel( subRegion, fluid ); + TotalMassDensityKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + else if( numPhase == 3 ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + TotalMassDensityKernel< NUM_COMP, 3 > kernel( subRegion, fluid ); + TotalMassDensityKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + } +}; + + +/******************************** ResidualNormKernel ********************************/ + +/** + * @class ResidualNormKernel + */ +class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 1 > +{ +public: + + using Base = physicsSolverBaseKernels::ResidualNormKernelBase< 1 >; + using Base::m_minNormalizer; + using Base::m_rankOffset; + using Base::m_localResidual; + using Base::m_dofNumber; + + ResidualNormKernel( globalIndex const rankOffset, + arrayView1d< real64 const > const & localResidual, + arrayView1d< globalIndex const > const & dofNumber, + arrayView1d< localIndex const > const & ghostRank, + integer const numComp, + integer const numDof, + integer const targetPhaseIndex, + WellElementSubRegion const & subRegion, + constitutive::MultiFluidBase const & fluid, + WellControls const & wellControls, + real64 const timeAtEndOfStep, + real64 const dt, + real64 const minNormalizer ) + : Base( rankOffset, + localResidual, + dofNumber, + ghostRank, + minNormalizer ), + m_numComp( numComp ), + m_numDof( numDof ), + m_targetPhaseIndex( targetPhaseIndex ), + m_dt( dt ), + m_isLocallyOwned( subRegion.isLocallyOwned() ), + m_iwelemControl( subRegion.getTopWellElementIndex() ), + m_isProducer( wellControls.isProducer() ), + m_currentControl( wellControls.getControl() ), + m_targetBHP( wellControls.getTargetBHP( timeAtEndOfStep ) ), + m_targetTotalRate( wellControls.getTargetTotalRate( timeAtEndOfStep ) ), + m_targetPhaseRate( wellControls.getTargetPhaseRate( timeAtEndOfStep ) ), + m_targetMassRate( wellControls.getTargetMassRate( timeAtEndOfStep ) ), + m_volume( subRegion.getElementVolume() ), + m_phaseDens_n( fluid.phaseDensity_n() ), + m_totalDens_n( fluid.totalDensity_n() ) + {} + + GEOS_HOST_DEVICE + virtual void computeLinf( localIndex const iwelem, + LinfStackVariables & stack ) const override + { + using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; + + real64 normalizer = 0.0; + for( integer idof = 0; idof < m_numDof; ++idof ) + { + + // Step 1: compute a normalizer for the control or pressure equation + + // for the control equation, we distinguish two cases + if( idof == ROFFSET::CONTROL ) + { + + // for the top well element, normalize using the current control + if( m_isLocallyOwned && iwelem == m_iwelemControl ) + { + if( m_currentControl == WellControls::Control::BHP ) + { + // the residual entry is in pressure units + normalizer = m_targetBHP; + } + else if( m_currentControl == WellControls::Control::TOTALVOLRATE ) + { + // the residual entry is in volume / time units + normalizer = LvArray::math::max( LvArray::math::abs( m_targetTotalRate ), m_minNormalizer ); + } + else if( m_currentControl == WellControls::Control::PHASEVOLRATE ) + { + // the residual entry is in volume / time units + normalizer = LvArray::math::max( LvArray::math::abs( m_targetPhaseRate ), m_minNormalizer ); + } + else if( m_currentControl == WellControls::Control::MASSRATE ) + { + // the residual entry is in volume / time units + normalizer = LvArray::math::max( LvArray::math::abs( m_targetMassRate ), m_minNormalizer ); + } + } + // for the pressure difference equation, always normalize by the BHP + else + { + normalizer = m_targetBHP; + } + } + // Step 2: compute a normalizer for the mass balance equations + else if( idof >= ROFFSET::MASSBAL && idof < ROFFSET::MASSBAL + m_numComp ) + { + if( m_isProducer ) // only PHASEVOLRATE is supported for now + { + // the residual is in mass units + normalizer = m_dt * LvArray::math::abs( m_targetPhaseRate ) * m_phaseDens_n[iwelem][0][m_targetPhaseIndex]; + } + else // Type::INJECTOR, only TOTALVOLRATE is supported for now + { + if( m_currentControl == WellControls::Control::MASSRATE ) + { + normalizer = m_dt * LvArray::math::abs( m_targetMassRate ); + } + else + { + // the residual is in mass units + normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ) * m_totalDens_n[iwelem][0]; + } + + } + + // to make sure that everything still works well if the rate is zero, we add this check + normalizer = LvArray::math::max( normalizer, m_volume[iwelem] * m_totalDens_n[iwelem][0] ); + } + // Step 3: compute a normalizer for the volume balance equations + else if( idof == ROFFSET::MASSBAL + m_numComp ) + { + if( m_isProducer ) // only PHASEVOLRATE is supported for now + { + // the residual is in volume units + normalizer = m_dt * LvArray::math::abs( m_targetPhaseRate ); + } + else // Type::INJECTOR, only TOTALVOLRATE is supported for now + { + if( m_currentControl == WellControls::Control::MASSRATE ) + { + normalizer = m_dt * LvArray::math::abs( m_targetMassRate/ m_totalDens_n[iwelem][0] ); + } + else + { + normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ); + } + + } + + } + + // to make sure that everything still works well if the rate is zero, we add this check + normalizer = LvArray::math::max( normalizer, m_volume[iwelem] ); + + // Step 4: compute the contribution to the residual + real64 const val = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / normalizer; + if( val > stack.localValue[0] ) + { + stack.localValue[0] = val; + } + } + } + + GEOS_HOST_DEVICE + virtual void computeL2( localIndex const iwelem, + L2StackVariables & stack ) const override + { + GEOS_UNUSED_VAR( iwelem, stack ); + GEOS_ERROR( "The L2 norm is not implemented for CompositionalMultiphaseWell" ); + } + + +protected: + + /// Number of fluid components + integer const m_numComp; + + /// Number of dof per well element + integer const m_numDof; + + /// Index of the target phase + integer const m_targetPhaseIndex; + + /// Time step size + real64 const m_dt; + + /// Flag indicating whether the well is locally owned or not + bool const m_isLocallyOwned; + + /// Index of the element where the control is enforced + localIndex const m_iwelemControl; + + /// Flag indicating whether the well is a producer or an injector + bool const m_isProducer; + + /// Controls + WellControls::Control const m_currentControl; + real64 const m_targetBHP; + real64 const m_targetTotalRate; + real64 const m_targetPhaseRate; + real64 const m_targetMassRate; + + /// View on the volume + arrayView1d< real64 const > const m_volume; + + /// View on phase/total density at the previous converged time step + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const m_phaseDens_n; + arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > const m_totalDens_n; + +}; + +/** + * @class ResidualNormKernelFactory + */ +class ResidualNormKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComp number of fluid components + * @param[in] numDof number of dofs per well element + * @param[in] targetPhaseIndex the index of the target phase (for phase volume control) + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] localResidual the residual vector on my MPI rank + * @param[in] subRegion the well element subregion + * @param[in] fluid the fluid model + * @param[in] wellControls the controls + * @param[in] timeAtEndOfStep the time at the end of the step (time_n + dt) + * @param[in] dt the time step size + * @param[out] residualNorm the residual norm on the subRegion + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + integer const numDof, + integer const targetPhaseIndex, + globalIndex const rankOffset, + string const & dofKey, + arrayView1d< real64 const > const & localResidual, + WellElementSubRegion const & subRegion, + constitutive::MultiFluidBase const & fluid, + WellControls const & wellControls, + real64 const timeAtEndOfStep, + real64 const dt, + real64 const minNormalizer, + real64 (& residualNorm)[1] ) + { + arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + + ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, + numComp, numDof, targetPhaseIndex, subRegion, fluid, wellControls, timeAtEndOfStep, dt, minNormalizer ); + ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); + } + +}; + +/******************************** SolutionScalingKernel ********************************/ + +/** + * @class SolutionScalingKernelFactory + */ +class SolutionScalingKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] maxRelativePresChange the max allowed relative pressure change + * @param[in] maxAbsolutePresChange the max allowed absolute pressure change + * @param[in] maxCompFracChange the max allowed comp fraction change + * @param[in] maxRelativeCompDensChange the max allowed relative comp density change + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + */ + template< typename POLICY > + static isothermalCompositionalMultiphaseBaseKernels::SolutionScalingKernel::StackVariables + createAndLaunch( real64 const maxRelativePresChange, + real64 const maxAbsolutePresChange, + real64 const maxCompFracChange, + real64 const maxRelativeCompDensChange, + globalIndex const rankOffset, + integer const numComp, + string const dofKey, + ElementSubRegionBase & subRegion, + arrayView1d< real64 const > const localSolution ) + { + arrayView1d< real64 const > const pressure = + subRegion.getField< fields::well::pressure >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = + subRegion.getField< fields::well::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = + subRegion.getField< fields::well::pressureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = + subRegion.getField< fields::well::globalCompDensityScalingFactor >(); + isothermalCompositionalMultiphaseBaseKernels:: + SolutionScalingKernel kernel( maxRelativePresChange, maxAbsolutePresChange, maxCompFracChange, maxRelativeCompDensChange, rankOffset, + numComp, dofKey, subRegion, localSolution, pressure, compDens, pressureScalingFactor, compDensScalingFactor ); + return isothermalCompositionalMultiphaseBaseKernels:: + SolutionScalingKernel:: + launch< POLICY >( subRegion.size(), kernel ); + } + +}; + +/******************************** SolutionCheckKernel ********************************/ + +/** + * @class SolutionCheckKernelFactory + */ +class SolutionCheckKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] allowCompDensChopping flag to allow the component density chopping + * @param[in] scalingFactor the scaling factor + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + */ + template< typename POLICY > + static isothermalCompositionalMultiphaseBaseKernels::SolutionCheckKernel::StackVariables + createAndLaunch( integer const allowCompDensChopping, + CompositionalMultiphaseFVM::ScalingType const scalingType, + real64 const scalingFactor, + arrayView1d< real64 const > const pressure, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > compDensScalingFactor, + globalIndex const rankOffset, + integer const numComp, + string const dofKey, + ElementSubRegionBase & subRegion, + arrayView1d< real64 const > const localSolution ) + { + + isothermalCompositionalMultiphaseBaseKernels:: + SolutionCheckKernel kernel( allowCompDensChopping, 0, scalingType, scalingFactor, + pressure, compDens, pressureScalingFactor, compDensScalingFactor, rankOffset, + numComp, dofKey, subRegion, localSolution ); + return isothermalCompositionalMultiphaseBaseKernels:: + SolutionCheckKernel:: + launch< POLICY >( subRegion.size(), kernel ); + } + +}; + +/******************************** ElementBasedAssemblyKernel ********************************/ + +/** + * @class ElementBasedAssemblyKernel + * @tparam NUM_COMP number of fluid components + * @tparam IS_THERMAL thermal switch + * @brief Define the interface for the assembly kernel in charge of accumulation and volume balance + */ +template< integer NUM_COMP, integer IS_THERMAL > +class ElementBasedAssemblyKernel +{ +public: + using COFFSET = compositionalMultiphaseWellKernels::ColOffset; + using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; + + // Well jacobian column and row indicies + // tjb - change NUM_DOF to IS_THERMAL + using FLUID_PROP_COFFSET = constitutive::multifluid::DerivativeOffsetC< NUM_COMP, IS_THERMAL >; + using WJ_COFFSET = compositionalMultiphaseWellKernels::ColOffset_WellJac< NUM_COMP, IS_THERMAL >; + using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NUM_COMP, IS_THERMAL >; + /// Compile time value for the number of components + static constexpr integer numComp = NUM_COMP; + + /// Number of Dof's set in this kernal - no dQ in accum + static constexpr integer numDof = NUM_COMP + 1 + IS_THERMAL; + + /// Compute time value for the number of equations mass bal + vol bal + energy bal + static constexpr integer numEqn = NUM_COMP + 1 + IS_THERMAL; + + + /** + * @brief Constructor + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + ElementBasedAssemblyKernel( localIndex const numPhases, + integer const isProducer, + globalIndex const rankOffset, + string const dofKey, + WellElementSubRegion const & subRegion, + constitutive::MultiFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > const kernelFlags ) + : m_numPhases( numPhases ), + m_isProducer( isProducer ), + m_rankOffset( rankOffset ), + m_iwelemControl( subRegion.getTopWellElementIndex() ), + m_dofNumber( subRegion.getReference< array1d< globalIndex > >( dofKey ) ), + m_elemGhostRank( subRegion.ghostRank() ), + m_volume( subRegion.getElementVolume() ), + m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ), + m_phaseVolFrac_n( subRegion.getField< fields::flow::phaseVolumeFraction_n >() ), + m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), + m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ), + m_phaseDens_n( fluid.phaseDensity_n() ), + m_phaseDens( fluid.phaseDensity() ), + m_dPhaseDens( fluid.dPhaseDensity() ), + m_phaseCompFrac_n( fluid.phaseCompFraction_n() ), + m_phaseCompFrac( fluid.phaseCompFraction() ), + m_dPhaseCompFrac( fluid.dPhaseCompFraction() ), + m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ), + m_compDens_n( subRegion.getField< fields::flow::globalCompDensity_n >() ), + m_localMatrix( localMatrix ), + m_localRhs( localRhs ), + m_kernelFlags( kernelFlags ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables + { +public: + + // volume information (used by both accumulation and volume balance) + real64 volume = 0.0; + + // Residual information + + /// Index of the local row corresponding to this element + localIndex localRow = -1; + + /// Indices of the matrix rows/columns corresponding to the dofs in this element + globalIndex dofIndices[numDof]{}; // NC compdens + P + thermal + globalIndex eqnRowIndices[numDof]{}; + globalIndex dofColIndices[numDof]{}; + + /// C-array storage for the element local residual vector (all equations except constraint and momentum) + real64 localResidual[numEqn]{}; + + /// C-array storage for the element local Jacobian matrix (all equations except constraint and momentum) + real64 localJacobian[numEqn][numDof]{}; + + }; + + /** + * @brief Getter for the ghost rank of an element + * @param[in] ei the element index + * @return the ghost rank of the element + */ + GEOS_HOST_DEVICE + integer elemGhostRank( localIndex const ei ) const + { return m_elemGhostRank( ei ); } + + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] ei the element index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const ei, + StackVariables & stack ) const + { + // initialize the volume + stack.volume = m_volume[ei]; + + // Note row/col indices needed to be consistent with layout of stack.localJacobian + // Setup row equation indices for this element ( mass + vol + thermal if valid) + + // 1) Mass Balance + for( integer ic = 0; ic < numComp; ++ic ) + { + stack.eqnRowIndices[ic] = m_dofNumber[ei] + WJ_ROFFSET::MASSBAL + ic - m_rankOffset; + } +// 2) Volume Balance + stack.eqnRowIndices[numComp] = m_dofNumber[ei] + WJ_ROFFSET::VOLBAL - m_rankOffset; + // 3) Energy Balance + if constexpr ( IS_THERMAL ) + { + stack.eqnRowIndices[numComp+1] = m_dofNumber[ei] + WJ_ROFFSET::ENERGYBAL - m_rankOffset; + } + // Setup equation column indices for this element ( P + COMPDENS + THERMAL if valid) + stack.dofColIndices[0] = m_dofNumber[ei] + WJ_COFFSET::dP; + for( integer ic = 0; ic < numComp; ++ic ) + { + stack.dofColIndices[ic+1] = m_dofNumber[ei] + WJ_COFFSET::dC+ic; + } + if constexpr ( IS_THERMAL ) + { + stack.dofColIndices[numComp+1] = m_dofNumber[ei] + WJ_COFFSET::dT; + } + if( 1 ) + for( integer jc = 0; jc < numEqn; ++jc ) + { + stack.localResidual[jc] = 0.0; + for( integer ic = 0; ic < numDof; ++ic ) + { + stack.localJacobian[jc][ic] = 0.0; + } + + } + + } + + /** + * @brief Compute the local accumulation contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + * @param[in] phaseAmountKernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const ei, + StackVariables & stack, + FUNC && phaseAmountKernelOp = NoOpFunc{} ) const + { + + using Deriv = constitutive::multifluid::DerivativeOffset; + + // construct the slices for variables accessed multiple times + arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; + + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac_n = m_phaseVolFrac_n[ei]; + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; + + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseDens_n = m_phaseDens_n[ei][0]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseDens = m_phaseDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > dPhaseDens = m_dPhaseDens[ei][0]; + + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 2 > phaseCompFrac_n = m_phaseCompFrac_n[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 2 > phaseCompFrac = m_phaseCompFrac[ei][0]; + arraySlice3d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac = m_dPhaseCompFrac[ei][0]; + + // temporary work arrays + real64 dPhaseAmount[FLUID_PROP_COFFSET::nDer]{}; + real64 dPhaseAmount_dC[numComp]{}; + real64 dPhaseCompFrac_dC[numComp]{}; + + // sum contributions to component accumulation from each phase + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + real64 const phaseAmount = stack.volume * phaseVolFrac[ip] * phaseDens[ip]; + real64 const phaseAmount_n = stack.volume * phaseVolFrac_n[ip] * phaseDens_n[ip]; + //remove tjb + real64 const dPhaseAmount_dP = stack.volume * ( dPhaseVolFrac[ip][Deriv::dP] * phaseDens[ip] + + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP] ); + dPhaseAmount[FLUID_PROP_COFFSET::dP]=stack.volume * ( dPhaseVolFrac[ip][Deriv::dP] * phaseDens[ip] + + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP] ); + + // assemble density dependence + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], dPhaseAmount_dC, Deriv::dC ); + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], &dPhaseAmount[FLUID_PROP_COFFSET::dC], Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseAmount_dC[jc] = dPhaseAmount_dC[jc] * phaseVolFrac[ip] + + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC+jc]; + dPhaseAmount_dC[jc] *= stack.volume; + dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] = dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] * phaseVolFrac[ip] + + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC+jc]; + dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] *= stack.volume; + } +// tjb- remove when safe + for( integer ic = 0; ic < numComp; ic++ ) + { + assert( fabs( dPhaseAmount[FLUID_PROP_COFFSET::dC+ic] -dPhaseAmount_dC[ic] ) < FLT_EPSILON ); + + } + // ic - index of component whose conservation equation is assembled + // (i.e. row number in local matrix) + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const phaseCompAmount = phaseAmount * phaseCompFrac[ip][ic]; + real64 const phaseCompAmount_n = phaseAmount_n * phaseCompFrac_n[ip][ic]; + + real64 const dPhaseCompAmount_dP = dPhaseAmount_dP * phaseCompFrac[ip][ic] + + phaseAmount * dPhaseCompFrac[ip][ic][Deriv::dP]; + + stack.localResidual[ic] += phaseCompAmount - phaseCompAmount_n; + stack.localJacobian[ic][0] += dPhaseCompAmount_dP; + + // jc - index of component w.r.t. whose compositional var the derivative is being taken + // (i.e. col number in local matrix) + + // assemble phase composition dependence + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseCompFrac[ip][ic], dPhaseCompFrac_dC, Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + real64 const dPhaseCompAmount_dC = dPhaseCompFrac_dC[jc] * phaseAmount + + phaseCompFrac[ip][ic] * dPhaseAmount[FLUID_PROP_COFFSET::dC+jc]; + + stack.localJacobian[ic][jc + 1] += dPhaseCompAmount_dC; + } + } + if constexpr ( IS_THERMAL ) + { + dPhaseAmount[FLUID_PROP_COFFSET::dT] = stack.volume * (dPhaseVolFrac[ip][Deriv::dT] * phaseDens[ip] + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dT] ); + for( integer ic = 0; ic < numComp; ++ic ) + { + // assemble the derivatives of the component mass balance equations with respect to temperature + stack.localJacobian[ic][numComp+1] += dPhaseAmount[FLUID_PROP_COFFSET::dT] * phaseCompFrac[ip][ic] + + phaseAmount * dPhaseCompFrac[ip][ic][Deriv::dT]; + } + } + // call the lambda in the phase loop to allow the reuse of the phase amounts and their derivatives + // possible use: assemble accumulation term of the energy equation for this phase + phaseAmountKernelOp( ip, phaseAmount, phaseAmount_n, dPhaseAmount ); + + } + + // check zero diagonal (works only in debug) + /* + for( integer ic = 0; ic < numComp; ++ic ) + { + GEOS_ASSERT_MSG ( LvArray::math::abs( stack.localJacobian[ic][ic] ) > minDensForDivision, + GEOS_FMT( "Zero diagonal in Jacobian: equation {}, value = {}", ic, stack.localJacobian[ic][ic] ) ); + } + */ + } + + + /** + * @brief Compute the local volume balance contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + * @param[in] phaseVolFractionSumKernelOp the function used to customize the kernel + */ + + GEOS_HOST_DEVICE + void computeVolumeBalance( localIndex const ei, + StackVariables & stack ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; + + real64 oneMinusPhaseVolFracSum = 1.0; + + // sum contributions to component accumulation from each phase +// Note localJacobian stores equation balances in order of component/vol/enerqy + // These are mapped to solver orderings with indicies setup in stack variables + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + oneMinusPhaseVolFracSum -= phaseVolFrac[ip]; + stack.localJacobian[numComp][0] -= dPhaseVolFrac[ip][Deriv::dP]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.localJacobian[numComp][jc+1] -= dPhaseVolFrac[ip][Deriv::dC+jc]; + } + + if constexpr ( IS_THERMAL) + { + stack.localJacobian[numComp][numComp+1] -= dPhaseVolFrac[ip][Deriv::dT]; + } + + } + // scale saturation-based volume balance by pore volume (for better scaling w.r.t. other equations) + stack.localResidual[numComp] = stack.volume * oneMinusPhaseVolFracSum; + for( integer idof = 0; idof < numComp+1+IS_THERMAL; ++idof ) + { + stack.localJacobian[numComp][idof] *= stack.volume; + } + + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void complete( localIndex const ei, //GEOS_UNUSED_PARAM( ei ), + StackVariables & stack ) const + { + using namespace compositionalMultiphaseUtilities; + + integer const numRows = numComp+1+ IS_THERMAL; + + if constexpr ( IS_THERMAL) + { + if( ei == m_iwelemControl && !m_isProducer ) + { + // For top segment energy balance eqn replaced with T(n+1) - T = 0 + // No other energy balance derivatives + // Assumption is global index == 0 is top segment with fixed temp BC + + for( integer i=0; i < numComp+1+IS_THERMAL; i++ ) + { + stack.localJacobian[numRows-1][i] = 0.0; + } + // constant Temperature + for( integer i=0; i < numComp+1+IS_THERMAL; i++ ) + stack.localJacobian[i][numRows-1] = 0.0; + stack.localJacobian[numRows-1][numRows-1] = 1.0; + + stack.localResidual[numRows-1]=0.0; + } + } + + if( m_kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ) ) + { + // apply equation/variable change transformation to the component mass balance equations + real64 work[numComp + 1 + IS_THERMAL]{}; + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numComp+1+ IS_THERMAL, stack.localJacobian, work ); + shiftElementsAheadByOneAndReplaceFirstElementWithSum( numComp, stack.localResidual ); + } + + // add contribution to residual and jacobian into: + // - the component mass balance equations (i = 0 to i = numComp-1) + // - the volume balance equations (i = numComp) + // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels + + for( integer i = 0; i < numRows; ++i ) + { + m_localRhs[stack.eqnRowIndices[i]] += stack.localResidual[i]; + m_localMatrix.addToRow< serialAtomic >( stack.eqnRowIndices[i], + stack.dofColIndices, + stack.localJacobian[i], + numComp+1+ IS_THERMAL ); + } + + } + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElems the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( kernelComponent.elemGhostRank( ei ) >= 0 ) + { + return; + } + + typename KERNEL_TYPE::StackVariables stack; + + kernelComponent.setup( ei, stack ); + kernelComponent.computeAccumulation( ei, stack ); + kernelComponent.computeVolumeBalance( ei, stack ); + kernelComponent.complete( ei, stack ); + } ); + } + +protected: + + /// Number of fluid phases + integer const m_numPhases; + + /// Well type + integer const m_isProducer; + + /// Offset for my MPI rank + globalIndex const m_rankOffset; + + /// Index of the element where the control is enforced + localIndex const m_iwelemControl; + + /// View on the dof numbers + arrayView1d< globalIndex const > const m_dofNumber; + + /// View on the ghost ranks + arrayView1d< integer const > const m_elemGhostRank; + + /// View on the element volumes + arrayView1d< real64 const > const m_volume; + + /// Views on the porosity + arrayView2d< real64 const > const m_porosity_n; + arrayView2d< real64 const > const m_porosity; + arrayView2d< real64 const > const m_dPoro_dPres; + + /// Views on the derivatives of comp fractions wrt component density + arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dCompFrac_dCompDens; + + /// Views on the phase volume fractions + arrayView2d< real64 const, compflow::USD_PHASE > const m_phaseVolFrac_n; + arrayView2d< real64 const, compflow::USD_PHASE > const m_phaseVolFrac; + arrayView3d< real64 const, compflow::USD_PHASE_DC > const m_dPhaseVolFrac; + + /// Views on the phase densities + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const m_phaseDens_n; + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const m_phaseDens; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > const m_dPhaseDens; + + /// Views on the phase component fraction + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > const m_phaseCompFrac_n; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > const m_phaseCompFrac; + arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > const m_dPhaseCompFrac; + + // Views on component densities + arrayView2d< real64 const, compflow::USD_COMP > m_compDens; + arrayView2d< real64 const, compflow::USD_COMP > m_compDens_n; + + /// View on the local CRS matrix + CRSMatrixView< real64, globalIndex const > const m_localMatrix; + /// View on the local RHS + arrayView1d< real64 > const m_localRhs; + + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > const m_kernelFlags; +}; + + +/** + * @class ElementBasedAssemblyKernelFactory + */ +class ElementBasedAssemblyKernelFactory +{ +public: + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( localIndex const numComps, + localIndex const numPhases, + integer const isProducer, + globalIndex const rankOffset, + integer const useTotalMassEquation, + string const dofKey, + WellElementSubRegion const & subRegion, + constitutive::MultiFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + geos::internal::kernelLaunchSelectorCompThermSwitch( numComps, 0, [&]( auto NC, auto IS_THERMAL ) + { + localIndex constexpr NUM_COMP = NC(); + + integer constexpr istherm = IS_THERMAL(); + + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ); + + ElementBasedAssemblyKernel< NUM_COMP, istherm > + kernel( numPhases, isProducer, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ); + ElementBasedAssemblyKernel< NUM_COMP, istherm >::template + launch< POLICY, ElementBasedAssemblyKernel< NUM_COMP, istherm > >( subRegion.size(), kernel ); + } ); + } +}; +/** + * @class FaceBasedAssemblyKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @brief Define the interface for the assembly kernel in charge of flux terms + */ + + +template< integer NC, integer IS_THERMAL > +class FaceBasedAssemblyKernel +{ +public: + + using COFFSET = compositionalMultiphaseWellKernels::ColOffset; + using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; + using TAG = compositionalMultiphaseWellKernels::ElemTag; + + using FLUID_PROP_COFFSET = constitutive::multifluid::DerivativeOffsetC< NC, IS_THERMAL >; + using WJ_COFFSET = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; + using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >; + + using CP_Deriv = constitutive::multifluid::DerivativeOffsetC< NC, IS_THERMAL >; + /// Compile time value for the number of components + static constexpr integer numComp = NC; + + /// Number of Dof's set in this kernal + static constexpr integer numDof = WJ_COFFSET::nDer; + + /// Compile time value for the number of equations except rate, momentum, energy + static constexpr integer numEqn = NC; + + static constexpr integer maxNumElems = 2; + static constexpr integer maxStencilSize = 2; + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor + * @param[in] compFlowAccessors + * @param[in] multiFluidAccessors + * @param[in] capPressureAccessors + * @param[in] permeabilityAccessors + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed together + */ + FaceBasedAssemblyKernel( real64 const dt, + globalIndex const rankOffset, + string const wellDofKey, + WellControls const & wellControls, + WellElementSubRegion const & subRegion, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags ) + : + m_dt( dt ), + m_rankOffset( rankOffset ), + m_wellElemDofNumber ( subRegion.getReference< array1d< globalIndex > >( wellDofKey ) ), + m_nextWellElemIndex ( subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString()) ), + m_connRate ( subRegion.getField< fields::well::mixtureConnectionRate >() ), + m_wellElemCompFrac ( subRegion.getField< fields::well::globalCompFraction >() ), + m_dWellElemCompFrac_dCompDens ( subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >() ), + m_localMatrix( localMatrix ), + m_localRhs ( localRhs ), + m_useTotalMassEquation ( kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ) ), + m_isProducer ( wellControls.isProducer() ), + m_injection ( wellControls.getInjectionStream() ) + {} + + struct StackVariables + { +public: + + /** + * @brief Constructor for the stack variables + * @param[in] size size of the stencil for this connection + * @param[in] numElems number of elements for this connection + */ + GEOS_HOST_DEVICE + StackVariables( localIndex const size ) + : stencilSize( size ), + numConnectedElems( 2 ), + dofColIndices( size * numDof ) + {} + + // Stencil information + localIndex const stencilSize; + /// Number of elements connected at a given connection + localIndex numConnectedElems; + + + // edge indexes + localIndex iwelemUp; + localIndex iwelemNext; + localIndex iwelemCurrent; + globalIndex offsetUp; + globalIndex offsetCurrent; + globalIndex offsetNext; + // Local degrees of freedom and local residual/jacobian + + /// Indices of the matrix rows/columns corresponding to the dofs in this face + stackArray1d< globalIndex, maxNumElems * numDof > dofColIndices; + + /// Storage for the face local residual vector (all mass bal equations) + stackArray1d< real64, maxNumElems * numEqn > localFlux; + /// Storage for the face local Jacobian matrix dC dP dT + stackArray2d< real64, maxNumElems * numEqn * maxStencilSize * CP_Deriv::nDer > localFluxJacobian; + /// Storage for the face local Jacobian matrix dQ only + stackArray2d< real64, maxNumElems * numEqn * maxStencilSize > localFluxJacobian_dQ; + }; + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] iconn the connection index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + inline + void setup( localIndex const iconn, + StackVariables & stack ) const + { + stack.numConnectedElems=2; + if( m_nextWellElemIndex[iconn] <0 ) + { + stack.numConnectedElems = 1; + } + stack.localFlux.resize( stack.numConnectedElems*numEqn ); + stack.localFluxJacobian.resize( stack.numConnectedElems * numEqn, stack.stencilSize * numDof ); + stack.localFluxJacobian_dQ.resize( stack.numConnectedElems * numEqn, 1 ); + + } + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] iconn the connection index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + inline + void complete( localIndex const iconn, + StackVariables & stack ) const + { + GEOS_UNUSED_VAR( iconn ); + using namespace compositionalMultiphaseUtilities; + if( stack.numConnectedElems ==1 ) + { + // Setup Jacobian global row indicies + // equations for COMPONENT + ENERGY balances + globalIndex oneSidedEqnRowIndices[numEqn]{}; + for( integer ic = 0; ic < NC; ++ic ) + { + oneSidedEqnRowIndices[ic] = stack.offsetUp + WJ_ROFFSET::MASSBAL + ic - m_rankOffset; + } + + // Setup Jacobian global col indicies ( Mapping from local jac order to well jac order) + globalIndex oneSidedDofColIndices_dPresCompTempUp[CP_Deriv::nDer]{}; + globalIndex oneSidedDofColIndices_dRate = stack.offsetCurrent + WJ_COFFSET::dQ; + // Note localFluxJacobian cols are stored using CP_Deriv order (dP dC or dP dT dC) + int ioff=0; + oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dP; + + if constexpr ( IS_THERMAL ) + { + oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dT; + } + for( integer jdof = 0; jdof < NC; ++jdof ) + { + oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dC+ jdof; + } + if( m_useTotalMassEquation > 0 ) + { + // Apply equation/variable change transformation(s) + real64 work[CP_Deriv::nDer]{}; + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numEqn, 1, stack.localFluxJacobian_dQ, work ); + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numEqn, CP_Deriv::nDer, stack.localFluxJacobian, work ); + shiftElementsAheadByOneAndReplaceFirstElementWithSum( numEqn, stack.localFlux ); + } + for( integer i = 0; i < numEqn; ++i ) + { + if( oneSidedEqnRowIndices[i] >= 0 && oneSidedEqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.addToRow< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], + &oneSidedDofColIndices_dRate, + stack.localFluxJacobian_dQ[i], + 1 ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], + oneSidedDofColIndices_dPresCompTempUp, + stack.localFluxJacobian[i], + CP_Deriv::nDer ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[oneSidedEqnRowIndices[i]], stack.localFlux[i] ); + } + } + } + else + { + // Setup Jacobian global row indicies + // equations for COMPONENT + ENERGY balances + globalIndex eqnRowIndices[2*numEqn]{}; + + for( integer ic = 0; ic < NC; ++ic ) + { + // mass balance equations for all components + eqnRowIndices[TAG::NEXT *numEqn+ic] = stack.offsetNext + WJ_ROFFSET::MASSBAL + ic - m_rankOffset; + eqnRowIndices[TAG::CURRENT *numEqn+ic] = stack.offsetCurrent + WJ_ROFFSET::MASSBAL + ic - m_rankOffset; + } + + // Setup Jacobian global col indicies ( Mapping from local jac order to well jac order) + globalIndex dofColIndices_dPresCompUp[CP_Deriv::nDer]{}; + globalIndex dofColIndices_dRate = stack.offsetCurrent + WJ_COFFSET::dQ; + + int ioff=0; + // Indice storage order reflects local jac col storage order CP::Deriv order P T DENS + dofColIndices_dPresCompUp[ioff++] = stack.offsetUp + WJ_COFFSET::dP; + + if constexpr ( IS_THERMAL ) + { + dofColIndices_dPresCompUp[ioff++] = stack.offsetUp + WJ_COFFSET::dT; + } + for( integer jdof = 0; jdof < NC; ++jdof ) + { + dofColIndices_dPresCompUp[ioff++] = stack.offsetUp + WJ_COFFSET::dC+ jdof; + } + + + if( m_useTotalMassEquation > 0 ) + { + // Apply equation/variable change transformation(s) + real64 work[CP_Deriv::nDer]{}; + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numEqn, numEqn, 1, 2, stack.localFluxJacobian_dQ, work ); + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numEqn, numEqn, CP_Deriv::nDer, 2, stack.localFluxJacobian, work ); + shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numEqn, numEqn, 2, stack.localFlux ); + } + // Note this updates diag and offdiag + for( integer i = 0; i < 2*NC; ++i ) + { + if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.addToRow< parallelDeviceAtomic >( eqnRowIndices[i], + &dofColIndices_dRate, + stack.localFluxJacobian_dQ[i], + 1 ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], + dofColIndices_dPresCompUp, + stack.localFluxJacobian[i], + CP_Deriv::nDer ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], stack.localFlux[i] ); + + } + } + } + } + + GEOS_HOST_DEVICE + inline + void + computeExit( real64 const & dt, + real64 const ( &compFlux )[NC ], + StackVariables & stack, + real64 ( & dCompFlux)[NC][numDof] ) const + { + for( integer ic = 0; ic < NC; ++ic ) + { + stack.localFlux[ic] = -dt * compFlux[ic]; + // derivative with respect to rate + stack.localFluxJacobian_dQ[ic][0] = -dt * dCompFlux[ic][WJ_COFFSET::dQ]; + // derivative with respect to upstream pressure + stack.localFluxJacobian[ic][CP_Deriv::dP] = -dt * dCompFlux[ic][WJ_COFFSET::dP]; + // derivatives with respect to upstream component densities + for( integer jdof = 0; jdof < NC; ++jdof ) + { + stack.localFluxJacobian[ic][CP_Deriv::dC+jdof] = -dt * dCompFlux[ic][WJ_COFFSET::dC+jdof]; + } + if constexpr ( IS_THERMAL ) + { + stack.localFluxJacobian[ic][CP_Deriv::dT] = -dt * dCompFlux[ic][WJ_COFFSET::dT]; + } + } + } + + GEOS_HOST_DEVICE + inline + void + compute( real64 const & dt, + real64 const ( &compFlux )[NC ], + StackVariables & stack, + real64 ( & dCompFlux)[(NC )][numDof] ) const + { + // flux terms + for( integer ic = 0; ic < NC; ++ic ) + { + stack.localFlux[TAG::NEXT * NC +ic] = dt * compFlux[ic]; + stack.localFlux[TAG::CURRENT * NC +ic] = -dt * compFlux[ic]; + // derivative with respect to rate + stack.localFluxJacobian_dQ[TAG::NEXT * NC+ ic][0] = dt * dCompFlux[ic][WJ_COFFSET::dQ]; + stack.localFluxJacobian_dQ[TAG::CURRENT * NC + +ic][0] = -dt * dCompFlux[ic][WJ_COFFSET::dQ]; + + // derivative with respect to upstream pressure + stack.localFluxJacobian[TAG::NEXT * NC +ic][CP_Deriv::dP] = dt * dCompFlux[ic][WJ_COFFSET::dP]; + stack.localFluxJacobian[TAG::CURRENT * NC+ ic][CP_Deriv::dP] = -dt * dCompFlux[ic][WJ_COFFSET::dP]; + + if constexpr ( IS_THERMAL ) + { + stack.localFluxJacobian[TAG::NEXT * NC +ic][CP_Deriv::dT] = dt * dCompFlux[ic][WJ_COFFSET::dT]; + stack.localFluxJacobian[TAG::CURRENT * NC +ic][CP_Deriv::dT] = -dt * dCompFlux[ic][WJ_COFFSET::dT]; + } + + // derivatives with respect to upstream component densities + for( integer jdof = 0; jdof < NC; ++jdof ) + { + stack.localFluxJacobian[TAG::NEXT * NC +ic][CP_Deriv::dC+jdof] = dt * dCompFlux[ic][WJ_COFFSET::dC+jdof]; + stack.localFluxJacobian[TAG::CURRENT * NC +ic][CP_Deriv::dC+jdof] = -dt * dCompFlux[ic][WJ_COFFSET::dC+jdof]; + } + } + } + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes + * @param[in] ie the element index + * @param[inout] stack the stack variables + * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void computeFlux( localIndex const iwelem, + StackVariables & stack, + FUNC && compFluxKernelOp = NoOpFunc{} ) const + { + + using namespace compositionalMultiphaseUtilities; + + // create local work arrays + real64 compFracUp[NC]{}; + real64 compFlux[NC]{}; + real64 dComp[NC][NC]; + real64 dCompFlux[NC][numDof]{}; + for( integer ic = 0; ic < NC; ++ic ) + { + for( integer jc = 0; jc < NC; ++jc ) + { + dComp[ic][jc]=0.0; + } + } + // Step 1) decide the upwind well element + + /* currentConnRate < 0 flow from iwelem to iwelemNext + * currentConnRate > 0 flow from iwelemNext to iwelem + * With this convention, currentConnRate < 0 at the last connection for a producer + * currentConnRate > 0 at the last connection for a injector + */ + + localIndex const iwelemNext = m_nextWellElemIndex[iwelem]; + real64 const currentConnRate = m_connRate[iwelem]; + localIndex iwelemUp = -1; + + if( iwelemNext < 0 && !m_isProducer ) // exit connection, injector + { + // we still need to define iwelemUp for Jacobian assembly + iwelemUp = iwelem; + + // just copy the injection stream into compFrac + for( integer ic = 0; ic < NC; ++ic ) + { + compFracUp[ic] = m_injection[ic]; + for( integer jc = 0; jc < NC; ++jc ) + { + dComp[ic][jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; + } + for( integer jc = 0; jc < NC; ++jc ) + { + dCompFlux[ic][WJ_COFFSET::dC+jc] = 0.0; + } + } + } + else + { + // first set iwelemUp to the upstream cell + if( ( iwelemNext < 0 && m_isProducer ) // exit connection, producer + || currentConnRate < 0 ) // not an exit connection, iwelem is upstream + { + iwelemUp = iwelem; + } + else // not an exit connection, iwelemNext is upstream + { + iwelemUp = iwelemNext; + } + + // copy the vars of iwelemUp into compFrac + for( integer ic = 0; ic < NC; ++ic ) + { + compFracUp[ic] = m_wellElemCompFrac[iwelemUp][ic]; + for( integer jc = 0; jc < NC; ++jc ) + { + dCompFlux[ic][WJ_COFFSET::dC+jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; + dComp[ic][jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; + } + } + } + + // Step 2) compute upstream transport coefficient + + for( integer ic = 0; ic < NC; ++ic ) + { + compFlux[ic] = compFracUp[ic] * currentConnRate; + dCompFlux[ic][WJ_COFFSET::dQ] = compFracUp[ic]; + // none of these quantities depend on pressure + dCompFlux[ic][WJ_COFFSET::dP] = 0.0; + if constexpr ( IS_THERMAL ) + { + dCompFlux[ic][WJ_COFFSET::dT] = 0.0; + } + for( integer jc = 0; jc < NC; ++jc ) + { + dCompFlux[ic][WJ_COFFSET::dC+jc] = dCompFlux[ic][WJ_COFFSET::dC+jc] * currentConnRate; + } + } + + stack.offsetUp = m_wellElemDofNumber[iwelemUp]; + stack.iwelemUp = iwelemUp; + stack.offsetCurrent = m_wellElemDofNumber[iwelem]; + stack.iwelemCurrent= iwelem; + + + if( iwelemNext < 0 ) // exit connection + { + // for this case, we only need NC mass conservation equations + computeExit ( m_dt, + compFlux, + stack, + dCompFlux ); + + } + else // not an exit connection + { + compute( m_dt, + compFlux, + stack, + dCompFlux + ); + stack.offsetNext = m_wellElemDofNumber[iwelemNext]; + } + stack.iwelemNext = iwelemNext; + compFluxKernelOp( iwelemNext, iwelemUp, currentConnRate, dComp ); + } + + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElements the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElements, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const ie ) + { + typename KERNEL_TYPE::StackVariables stack( 1 ); + + kernelComponent.setup( ie, stack ); + kernelComponent.computeFlux( ie, stack ); + kernelComponent.complete( ie, stack ); + } ); + } + +protected: + /// Time step size + real64 const m_dt; + /// Rank offset for calculating row/col Jacobian indices + integer const m_rankOffset; + + /// Reference to the degree-of-freedom numbers + arrayView1d< globalIndex const > const m_wellElemDofNumber; + /// Next element index, needed since iterating over element nodes, not edges + arrayView1d< localIndex const > const m_nextWellElemIndex; + + /// Connection rate + arrayView1d< real64 const > const m_connRate; + + + /// Element component fraction + arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompFrac; + /// Element component fraction derivatives + arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dWellElemCompFrac_dCompDens; + + /// View on the local CRS matrix + CRSMatrixView< real64, globalIndex const > const m_localMatrix; + /// View on the local RHS + arrayView1d< real64 > const m_localRhs; + + /// Kernel option flag + integer const m_useTotalMassEquation; + + /// Well type + bool const m_isProducer; + + /// Injection stream composition + arrayView1d< real64 const > const m_injection; + + +}; + +/** + * @class FaceBasedAssemblyKernelFactory + */ +class FaceBasedAssemblyKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] dt time step size + * @param[in] rankOffset the offset of my MPI rank + * @param[in] useTotalMassEquation flag specifying whether to replace one component bal eqn with total mass eqn + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] wellControls object holding well control/constraint information + * @param[in] subregion well subregion + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComps, + real64 const dt, + globalIndex const rankOffset, + integer const useTotalMassEquation, + string const dofKey, + WellControls const & wellControls, + WellElementSubRegion const & subRegion, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + + + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ); + + using kernelType = FaceBasedAssemblyKernel< NUM_COMP, 0 >; + + + kernelType kernel( dt, rankOffset, dofKey, wellControls, subRegion, localMatrix, localRhs, kernelFlags ); + kernelType::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } +}; +} // end namespace compositionalMultiphaseWellKernels + +} // end namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_COMPOSITIONALMULTIPHASEWELLKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/PerforationFluxKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/PerforationFluxKernels.hpp new file mode 100644 index 00000000000..fff9e893cf0 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/PerforationFluxKernels.hpp @@ -0,0 +1,880 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PerforationFluxKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_PERFORATIONFLUXLKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_PERFORATIONFLUXLKERNELS_HPP + +#include "codingUtilities/Utilities.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityFields.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "mesh/ObjectManagerBase.hpp" +#include "physicsSolvers/KernelLaunchSelectors.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" +#include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/wells/WellTags.hpp" +#include "physicsSolvers/fluidFlow/wells/WellFields.hpp" + + +namespace geos +{ + +struct NoOpStuct +{ + NoOpStuct(){} +}; + +namespace isothermalPerforationFluxKernels +{ + + + +/******************************** PerforationFluxKernel ********************************/ + +template< integer NC, integer NP, integer IS_THERMAL > +class PerforationFluxKernel +{ +public: + /// Compile time value for the number of components + static constexpr integer numComp = NC; + + /// Compile time value for the number of phases + static constexpr integer numPhase = NP; + + /// Compile time value for thermal option + static constexpr integer isThermal = IS_THERMAL; + + using TAG = wellTags::SubRegionTag; + + using CompFlowAccessors = + StencilAccessors< fields::flow::pressure, + fields::flow::phaseVolumeFraction, + fields::flow::dPhaseVolumeFraction, + fields::flow::dGlobalCompFraction_dGlobalCompDensity >; + + using MultiFluidAccessors = + StencilMaterialAccessors< constitutive::MultiFluidBase, + fields::multifluid::phaseDensity, + fields::multifluid::dPhaseDensity, + fields::multifluid::phaseViscosity, + fields::multifluid::dPhaseViscosity, + fields::multifluid::phaseCompFraction, + fields::multifluid::dPhaseCompFraction >; + + using RelPermAccessors = + StencilMaterialAccessors< constitutive::RelativePermeabilityBase, + fields::relperm::phaseRelPerm, + fields::relperm::dPhaseRelPerm_dPhaseVolFraction >; + + + /** + * @brief The type for element-based non-constitutive data parameters. + * Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + PerforationFluxKernel ( PerforationData * const perforationData, + ElementSubRegionBase const & subRegion, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + RelPermAccessors const & relPermAccessors, + bool const disableReservoirToWellFlow ): + m_resPres( compFlowAccessors.get( fields::flow::pressure {} )), + m_resPhaseVolFrac( compFlowAccessors.get( fields::flow::phaseVolumeFraction {} )), + m_dResPhaseVolFrac( compFlowAccessors.get( fields::flow::dPhaseVolumeFraction {} )), + m_dResCompFrac_dCompDens( compFlowAccessors.get( fields::flow::dGlobalCompFraction_dGlobalCompDensity {} )), + m_resPhaseDens( multiFluidAccessors.get( fields::multifluid::phaseDensity {} )), + m_dResPhaseDens( multiFluidAccessors.get( fields::multifluid::dPhaseDensity {} )), + m_resPhaseVisc( multiFluidAccessors.get( fields::multifluid::phaseViscosity {} )), + m_dResPhaseVisc( multiFluidAccessors.get( fields::multifluid::dPhaseViscosity {} )), + m_resPhaseCompFrac( multiFluidAccessors.get( fields::multifluid::phaseCompFraction {} )), + m_dResPhaseCompFrac( multiFluidAccessors.get( fields::multifluid::dPhaseCompFraction {} )), + m_resPhaseRelPerm( relPermAccessors.get( fields::relperm::phaseRelPerm {} )), + m_dResPhaseRelPerm_dPhaseVolFrac( relPermAccessors.get( fields::relperm::dPhaseRelPerm_dPhaseVolFraction {} )), + m_wellElemGravCoef( subRegion.getField< fields::well::gravityCoefficient >()), + m_wellElemPres( subRegion.getField< fields::well::pressure >()), + m_wellElemCompDens( subRegion.getField< fields::well::globalCompDensity >()), + m_wellElemTotalMassDens( subRegion.getField< fields::well::totalMassDensity >()), + m_dWellElemTotalMassDens( subRegion.getField< fields::well::dTotalMassDensity >()), + m_wellElemCompFrac( subRegion.getField< fields::well::globalCompFraction >()), + m_dWellElemCompFrac_dCompDens( subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >()), + m_perfGravCoef( perforationData->getField< fields::well::gravityCoefficient >()), + m_perfWellElemIndex( perforationData->getField< fields::perforation::wellElementIndex >()), + m_perfTrans( perforationData->getField< fields::perforation::wellTransmissibility >()), + m_resElementRegion( perforationData->getField< fields::perforation::reservoirElementRegion >()), + m_resElementSubRegion( perforationData->getField< fields::perforation::reservoirElementSubRegion >()), + m_resElementIndex( perforationData->getField< fields::perforation::reservoirElementIndex >()), + m_compPerfRate( perforationData->getField< fields::well::compPerforationRate >()), + m_dCompPerfRate( perforationData->getField< fields::well::dCompPerforationRate >()), + m_disableReservoirToWellFlow( disableReservoirToWellFlow ) + {} + + struct StackVariables + { +public: + /** + * @brief Constructor for the stack variables + */ + + GEOS_HOST_DEVICE + StackVariables() {} + + }; + + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void + computeFlux( localIndex const iperf, FUNC && fluxKernelOp= NoOpFunc {} ) const + { + // get the index of the reservoir elem + localIndex const er = m_resElementRegion[iperf]; + localIndex const esr = m_resElementSubRegion[iperf]; + localIndex const ei = m_resElementIndex[iperf]; + + // get the index of the well elem + localIndex const iwelem = m_perfWellElemIndex[iperf]; + + using Deriv = constitutive::multifluid::DerivativeOffset; + using CP_Deriv = constitutive::multifluid::DerivativeOffsetC< NC, IS_THERMAL >; + + // local working variables and arrays + real64 pres[2]{}; + real64 multiplier[2]{}; + + // local working variables - compact + // All derivative quantiites generated are stored in arrays using CP_Deriv offsets + // The input well/reservoir quantites use the Deriv offsets + // The arrays using the deriv offsets have extra column for dT in isothermal cases + + real64 dPres[2][CP_Deriv::nDer]{}; + real64 dFlux[2][CP_Deriv::nDer]{}; + real64 dMob[CP_Deriv::nDer]{}; + real64 dPotDiff[2][CP_Deriv::nDer]{}; + real64 dCompFrac[CP_Deriv::nDer]{}; + + // Step 1: reset the perforation rates + for( integer ic = 0; ic < NC; ++ic ) + { + m_compPerfRate[iperf][ic] = 0.0; + for( integer ke = 0; ke < 2; ++ke ) + { + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + m_dCompPerfRate[iperf][ke][ic][jc] = 0.0; + } + } + } + + // Step 2: copy the variables from the reservoir and well element + + // a) get reservoir variables + + pres[TAG::RES] = m_resPres[er][esr][ei]; + dPres[TAG::RES][CP_Deriv::dP] = 1.0; + multiplier[TAG::RES] = 1.0; + + // Here in the absence of a buoyancy term we assume that the reservoir cell is perforated at its center + // TODO: add a buoyancy term for the reservoir side here + + + // b) get well variables + + pres[TAG::WELL] = m_wellElemPres[iwelem]; + dPres[TAG::WELL][CP_Deriv::dP] = 1.0; + multiplier[TAG::WELL] = -1.0; + + real64 const gravD = ( m_perfGravCoef[iperf] - m_wellElemGravCoef[iwelem] ); + + pres[TAG::WELL] += m_wellElemTotalMassDens[iwelem] * gravD; + // Note LHS uses CP_Deriv while RHS uses Deriv !!! + dPres[TAG::WELL][CP_Deriv::dP] += m_dWellElemTotalMassDens[iwelem][Deriv::dP] * gravD; + if constexpr ( IS_THERMAL ) + { + dPres[TAG::WELL][CP_Deriv::dT] += m_dWellElemTotalMassDens[iwelem][Deriv::dT] * gravD; + } + for( integer ic = 0; ic < NC; ++ic ) + { + dPres[TAG::WELL][CP_Deriv::dC+ic] += m_dWellElemTotalMassDens[iwelem][Deriv::dC+ic] * gravD; + } + + // Step 3: compute potential difference + + real64 potDiff = 0.0; + for( integer i = 0; i < 2; ++i ) + { + potDiff += multiplier[i] * m_perfTrans[iperf] * pres[i]; + // LHS & RHS both use CP_Deriv + for( integer ic = 0; ic < CP_Deriv::nDer; ++ic ) + { + dPotDiff[i][ic] += multiplier[i] * m_perfTrans[iperf] * dPres[i][ic]; + } + } + // Step 4: upwinding based on the flow direction + + real64 flux = 0.0; + if( potDiff >= 0 ) // ** reservoir cell is upstream ** + { + + // loop over phases, compute and upwind phase flux + // and sum contributions to each component's perforation rate + for( integer ip = 0; ip < NP; ++ip ) + { + // skip the rest of the calculation if the phase is absent + // or if crossflow is disabled for injectors + bool const phaseExists = (m_resPhaseVolFrac[er][esr][ei][ip] > 0); + if( !phaseExists || m_disableReservoirToWellFlow ) + { + continue; + } + + // here, we have to recompute the reservoir phase mobility (not including density) + + // density + real64 const resDens = m_resPhaseDens[er][esr][ei][0][ip]; + real64 dDens[CP_Deriv::nDer]{}; + + dDens[CP_Deriv::dP] = m_dResPhaseDens[er][esr][ei][0][ip][Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dDens[CP_Deriv::dT] = m_dResPhaseDens[er][esr][ei][0][ip][Deriv::dT]; + } + applyChainRule( NC, m_dResCompFrac_dCompDens[er][esr][ei], + m_dResPhaseDens[er][esr][ei][0][ip], + &dDens[CP_Deriv::dC], + Deriv::dC ); + // viscosity + real64 const resVisc = m_resPhaseVisc[er][esr][ei][0][ip]; + real64 dVisc[CP_Deriv::nDer]{}; + dVisc[CP_Deriv::dP] = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dVisc[CP_Deriv::dT] = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dT]; + } + + applyChainRule( NC, m_dResCompFrac_dCompDens[er][esr][ei], + m_dResPhaseVisc[er][esr][ei][0][ip], + &dVisc[CP_Deriv::dC], + Deriv::dC ); + + // relative permeability + real64 const resRelPerm = m_resPhaseRelPerm[er][esr][ei][0][ip]; + real64 dRelPerm[CP_Deriv::nDer]{}; + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dRelPerm[jc]=0; + } + for( integer jp = 0; jp < NP; ++jp ) + { + real64 const dResRelPerm_dS = m_dResPhaseRelPerm_dPhaseVolFrac[er][esr][ei][0][ip][jp]; + dRelPerm[CP_Deriv::dP] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dRelPerm[CP_Deriv::dT] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dT]; + } + for( integer jc = 0; jc < NC; ++jc ) + { + dRelPerm[CP_Deriv::dC+jc] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dC+jc]; + } + } + + // compute the reservoir phase mobility, including phase density + real64 const resPhaseMob = resDens * resRelPerm / resVisc; + + // Handles all dependencies + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dMob[jc] = dRelPerm[jc] * resDens / resVisc + + resPhaseMob * (dDens[jc] / resDens - dVisc[jc] / resVisc); + } + // compute the phase flux and derivatives using upstream cell mobility + flux = resPhaseMob * potDiff; + // Handles all dependencies + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dFlux[TAG::RES][jc] = dMob[jc] * potDiff + resPhaseMob * dPotDiff[TAG::RES][jc]; + dFlux[TAG::WELL][jc] = resPhaseMob * dPotDiff[TAG::WELL][jc]; + } + + // increment component fluxes + for( integer ic = 0; ic < NC; ++ic ) + { + // Note this needs to be uncommented out + m_compPerfRate[iperf][ic] += flux * m_resPhaseCompFrac[er][esr][ei][0][ip][ic]; + dCompFrac[CP_Deriv::dP] = m_dResPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dP]; + if constexpr (IS_THERMAL) + { + dCompFrac[CP_Deriv::dT] = m_dResPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dT]; + } + + applyChainRule( NC, + m_dResCompFrac_dCompDens[er][esr][ei], + m_dResPhaseCompFrac[er][esr][ei][0][ip][ic], + &dCompFrac[CP_Deriv::dC], + Deriv::dC ); + + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + m_dCompPerfRate[iperf][TAG::RES][ic][jc] += dFlux[TAG::RES][jc] * m_resPhaseCompFrac[er][esr][ei][0][ip][ic]; + m_dCompPerfRate[iperf][TAG::RES][ic][jc] += flux * dCompFrac[jc]; + m_dCompPerfRate[iperf][TAG::WELL][ic][jc] += dFlux[TAG::WELL][jc] * m_resPhaseCompFrac[er][esr][ei][0][ip][ic]; + } + } + if constexpr ( IS_THERMAL ) + { + fluxKernelOp( iwelem, er, esr, ei, ip, potDiff, flux, dFlux ); + } + + } // end resevoir is upstream phase loop + + } + else // ** well is upstream ** + { + + real64 resTotalMob = 0.0; + + // we re-compute here the total mass (when useMass == 1) or molar (when useMass == 0) density + real64 wellElemTotalDens = 0; + for( integer ic = 0; ic < NC; ++ic ) + { + wellElemTotalDens += m_wellElemCompDens[iwelem][ic]; + } + + // first, compute the reservoir total mobility (excluding phase density) + for( integer ip = 0; ip < NP; ++ip ) + { + + // skip the rest of the calculation if the phase is absent + bool const phaseExists = (m_resPhaseVolFrac[er][esr][ei][ip] > 0); + if( !phaseExists ) + { + continue; + } + + // viscosity + real64 const resVisc = m_resPhaseVisc[er][esr][ei][0][ip]; + real64 dVisc[CP_Deriv::nDer]{}; + dVisc[CP_Deriv::dP] = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dVisc[CP_Deriv::dT] = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dT]; + } + + applyChainRule( NC, m_dResCompFrac_dCompDens[er][esr][ei], + m_dResPhaseVisc[er][esr][ei][0][ip], + &dVisc[CP_Deriv::dC], + Deriv::dC ); + + + // relative permeability + real64 const resRelPerm = m_resPhaseRelPerm[er][esr][ei][0][ip]; + real64 dRelPerm[CP_Deriv::nDer]{}; + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dRelPerm[jc]=0; + } + for( integer jp = 0; jp < NP; ++jp ) + { + real64 const dResRelPerm_dS = m_dResPhaseRelPerm_dPhaseVolFrac[er][esr][ei][0][ip][jp]; + dRelPerm[CP_Deriv::dP] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dRelPerm[CP_Deriv::dT] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dT]; + } + for( integer jc = 0; jc < NC; ++jc ) + { + dRelPerm[CP_Deriv::dC+jc] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dC+jc]; + } + } + // increment total mobility + resTotalMob += resRelPerm / resVisc; + // Handles all dependencies + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dMob[jc] += (dRelPerm[jc] *resVisc - resRelPerm * dVisc[jc] ) + / ( resVisc * resVisc); + } + } // end well is upstream phase loop + + // compute a potdiff multiplier = wellElemTotalDens * resTotalMob + // wellElemTotalDens is a mass density if useMass == 1 and a molar density otherwise + real64 const mult = wellElemTotalDens * resTotalMob; + + real64 dMult[2][CP_Deriv::nDer]{}; + dMult[TAG::WELL][CP_Deriv::dP] = 0.0; + if constexpr ( IS_THERMAL ) + { + dMult[TAG::WELL][CP_Deriv::dT] = 0.0; + } + for( integer ic = 0; ic < NC; ++ic ) + { + dMult[TAG::WELL][CP_Deriv::dC+ic] = resTotalMob; + } + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dMult[TAG::RES][jc] = wellElemTotalDens * dMob[jc]; + } + + + // compute the volumetric flux and derivatives using upstream cell mobility + flux = mult * potDiff; + + for( integer ic = 0; ic < CP_Deriv::nDer; ++ic ) + { + dFlux[TAG::RES][ic] = dMult[TAG::RES][ic] * potDiff + mult * dPotDiff[TAG::RES][ic]; + dFlux[TAG::WELL][ic] = dMult[TAG::WELL][ic] * potDiff + mult * dPotDiff[TAG::WELL][ic]; + } + // compute component fluxes + for( integer ic = 0; ic < NC; ++ic ) + { + m_compPerfRate[iperf][ic] += m_wellElemCompFrac[iwelem][ic] * flux; + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + m_dCompPerfRate[iperf][TAG::RES][ic][jc] = m_wellElemCompFrac[iwelem][ic] * dFlux[TAG::RES][jc]; + } + } + for( integer ic = 0; ic < NC; ++ic ) + { + m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dP] = m_wellElemCompFrac[iwelem][ic] * dFlux[TAG::WELL][CP_Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dT] = m_wellElemCompFrac[iwelem][ic] * dFlux[TAG::WELL][CP_Deriv::dT]; + } + for( integer jc = 0; jc < NC; ++jc ) + { + m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dC+jc] += m_wellElemCompFrac[iwelem][ic] * dFlux[TAG::WELL][CP_Deriv::dC+jc]; + m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dC+jc] += m_dWellElemCompFrac_dCompDens[iwelem][ic][jc] * flux; + } + } + if constexpr ( IS_THERMAL ) + { + fluxKernelOp( iwelem, er, esr, ei, -1, potDiff, flux, dFlux ); + } + } // end upstream + } + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElements the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElements, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const iperf ) + { + + kernelComponent.computeFlux( iperf ); + + } ); + } + + + StackVariables m_stackVariables; + +protected: + ElementViewConst< arrayView1d< real64 const > > const m_resPres; + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_resPhaseVolFrac; + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const m_dResPhaseVolFrac; + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const m_dResCompFrac_dCompDens; + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_resPhaseDens; + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dResPhaseDens; + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_resPhaseVisc; + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dResPhaseVisc; + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const m_resPhaseCompFrac; + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const m_dResPhaseCompFrac; + ElementViewConst< arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > > const m_resPhaseRelPerm; + ElementViewConst< arrayView4d< real64 const, constitutive::relperm::USD_RELPERM_DS > > const m_dResPhaseRelPerm_dPhaseVolFrac; + arrayView1d< real64 const > const m_wellElemGravCoef; + arrayView1d< real64 const > const m_wellElemPres; + arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompDens; + arrayView1d< real64 const > const m_wellElemTotalMassDens; + arrayView2d< real64 const, compflow::USD_FLUID_DC > const m_dWellElemTotalMassDens; + arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompFrac; + arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dWellElemCompFrac_dCompDens; + arrayView1d< real64 const > const m_perfGravCoef; + arrayView1d< localIndex const > const m_perfWellElemIndex; + arrayView1d< real64 const > const m_perfTrans; + arrayView1d< localIndex const > const m_resElementRegion; + arrayView1d< localIndex const > const m_resElementSubRegion; + arrayView1d< localIndex const > const m_resElementIndex; + arrayView2d< real64 > const m_compPerfRate; + arrayView4d< real64 > const m_dCompPerfRate; + arrayView3d< real64 > const m_dCompPerfRate_dPres; + arrayView4d< real64 > const m_dCompPerfRate_dComp; + + bool const m_disableReservoirToWellFlow; + + +}; + +/** + * @class PerforationKernelFactory + */ +class PerforationFluxKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] dt time step size + * @param[in] rankOffset the offset of my MPI rank + * @param[in] useTotalMassEquation flag specifying whether to replace one component bal eqn with total mass eqn + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] wellControls object holding well control/constraint information + * @param[in] subregion well subregion + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + integer const numPhases, + string const flowSolverName, + PerforationData * const perforationData, + ElementSubRegionBase const & subRegion, + ElementRegionManager & elemManager, + integer const disableReservoirToWellFlow ) + { + geos::internal::kernelLaunchSelectorCompPhaseSwitch( numComp, numPhases, [&]( auto NC, auto NP ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_PHASE = NP(); + integer constexpr IS_THERMAL = 0; + + using kernelType = PerforationFluxKernel< NUM_COMP, NUM_PHASE, IS_THERMAL >; + typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, flowSolverName ); + typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, flowSolverName ); + typename kernelType::RelPermAccessors relPermAccessors( elemManager, flowSolverName ); + + kernelType kernel( perforationData, subRegion, compFlowAccessors, multiFluidAccessors, relPermAccessors, disableReservoirToWellFlow ); + kernelType::template launch< POLICY >( perforationData->size(), kernel ); + } ); + } +}; + +} // end namespace isothermalPerforationFluxKernels + +namespace thermalPerforationFluxKernels +{ + +using namespace constitutive; + +/******************************** PerforationFluxKernel ********************************/ + +template< integer NC, integer NP, integer IS_THERMAL > +class PerforationFluxKernel : public isothermalPerforationFluxKernels::PerforationFluxKernel< NC, NP, IS_THERMAL > +{ +public: + + using Base = isothermalPerforationFluxKernels::PerforationFluxKernel< NC, NP, IS_THERMAL >; + //using AbstractBase::m_dPhaseVolFrac; + using Base::m_resPhaseCompFrac; + using Base::m_dResCompFrac_dCompDens; + using Base::m_dWellElemCompFrac_dCompDens; + //using AbstractBase::m_dPhaseCompFrac; + //using AbstractBase::m_dCompFrac_dCompDens; + /// Compile time value for the number of components + static constexpr integer numComp = NC; + + /// Compile time value for the number of phases + static constexpr integer numPhase = NP; + + /// Compile time value for thermal option + static constexpr integer isThermal = IS_THERMAL; + + using TAG = typename Base::TAG; + using CompFlowAccessors = typename Base::CompFlowAccessors; + using MultiFluidAccessors = typename Base::MultiFluidAccessors; + using RelPermAccessors = typename Base::RelPermAccessors; + + + using ThermalCompFlowAccessors = + StencilAccessors< fields::flow::temperature >; + + using ThermalMultiFluidAccessors = + StencilMaterialAccessors< MultiFluidBase, + fields::multifluid::phaseEnthalpy, + fields::multifluid::dPhaseEnthalpy >; + + //using ThermalConductivityAccessors = + // StencilMaterialAccessors< MultiPhaseThermalConductivityBase, + // fields::thermalconductivity::effectiveConductivity >; + + /** + * @brief The type for element-based non-constitutive data parameters. + * Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + PerforationFluxKernel ( PerforationData * const perforationData, + ElementSubRegionBase const & subRegion, + MultiFluidBase const & fluid, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + RelPermAccessors const & relPermAccessors, + bool const disableReservoirToWellFlow, + ThermalCompFlowAccessors const & thermalCompFlowAccessors, + ThermalMultiFluidAccessors const & thermalMultiFluidAccessors ) + : Base( perforationData, + subRegion, + compFlowAccessors, + multiFluidAccessors, + relPermAccessors, + disableReservoirToWellFlow ), + m_wellElemPhaseFrac( fluid.phaseFraction() ), + m_dPhaseFrac( fluid.dPhaseFraction() ), + m_wellElemPhaseEnthalpy( fluid.phaseEnthalpy()), + m_dWellElemPhaseEnthalpy( fluid.dPhaseEnthalpy()), + m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()), + m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()), + m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), + m_resPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), + m_dResPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ) + + {} + + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void + computeFlux( localIndex const iperf ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + using CP_Deriv =constitutive::multifluid::DerivativeOffsetC< NC, IS_THERMAL >; + // initialize outputs + m_energyPerfFlux[iperf]=0; + for( integer ke = 0; ke < 2; ++ke ) + { + for( integer i = 0; i < CP_Deriv::nDer; ++i ) + { + m_dEnergyPerfFlux[iperf][ke][i]=0; + } + } + + Base::computeFlux ( iperf, [&]( localIndex const iwelem, localIndex const er, localIndex const esr, localIndex const ei, localIndex const ip, + real64 const potDiff, real64 const flux, real64 const (&dFlux)[2][CP_Deriv::nDer] ) + { + if( potDiff >= 0 ) // ** reservoir cell is upstream ** + { + + real64 const res_enthalpy = m_resPhaseEnthalpy[er][esr][ei][0][ip]; + + m_energyPerfFlux[iperf] += flux * res_enthalpy; + + // energy equation derivatives WRT res P & T + m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dP] += dFlux[TAG::RES][CP_Deriv::dP] * res_enthalpy + + flux * m_dResPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dP]; + m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dT] += dFlux[TAG::RES][CP_Deriv::dT] * res_enthalpy + + flux * m_dResPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dT]; + // energy equation derivatives WRT well P + m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * res_enthalpy; + m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * res_enthalpy; + + + // energy equation derivatives WRT reservoir dens + real64 dProp_dC[numComp]{}; + applyChainRule( NC, + m_dResCompFrac_dCompDens[er][esr][ei], + m_dResPhaseEnthalpy[er][esr][ei][0][ip], + dProp_dC, + Deriv::dC ); + + for( integer jc = 0; jc < NC; ++jc ) + { + m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dC+jc] += flux * dProp_dC[jc]; + } + } + else // ** reservoir cell is downstream + { + for( integer iphase = 0; iphase < NP; ++iphase ) + { + bool const phaseExists = m_wellElemPhaseFrac[iwelem][0][iphase] > 0.0; + if( !phaseExists ) + continue; + double pflux = m_wellElemPhaseFrac[iwelem][0][iphase]*flux; + real64 const wellelem_enthalpy = m_wellElemPhaseEnthalpy[iwelem][0][iphase]; + m_energyPerfFlux[iperf] += pflux * wellelem_enthalpy; + + // energy equation derivatives WRT res P & T + m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dP] += dFlux[TAG::RES][CP_Deriv::dP] * wellelem_enthalpy; + m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dT] += dFlux[TAG::RES][CP_Deriv::dT] * wellelem_enthalpy; + + m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * wellelem_enthalpy + + pflux * m_dWellElemPhaseEnthalpy[iwelem][0][iphase][Deriv::dP] + + pflux * wellelem_enthalpy * m_dPhaseFrac[iwelem][0][iphase][Deriv::dP]; + m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * wellelem_enthalpy + + pflux * m_dWellElemPhaseEnthalpy[iwelem][0][iphase][Deriv::dT] + + pflux * wellelem_enthalpy * m_dPhaseFrac[iwelem][0][iphase][Deriv::dT]; + + //energy e + real64 dPVF_dC[numComp]{}; + applyChainRule( NC, + m_dWellElemCompFrac_dCompDens[iwelem], + m_dPhaseFrac[iwelem][0][iphase], + dPVF_dC, + Deriv::dC ); + for( integer ic=0; ic + static void + launch( localIndex const numElements, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const iperf ) + { + kernelComponent.computeFlux( iperf ); + + } ); + } + +protected: + + /// Views on well element properties + /// Element phase fraction + arrayView3d< real64 const, multifluid::USD_PHASE > const m_wellElemPhaseFrac; + arrayView4d< real64 const, multifluid::USD_PHASE_DC > const m_dPhaseFrac; + arrayView3d< real64 const, multifluid::USD_PHASE > const m_wellElemPhaseEnthalpy; + arrayView4d< real64 const, multifluid::USD_PHASE_DC > const m_dWellElemPhaseEnthalpy; + + /// Views on energy flux + arrayView1d< real64 > const m_energyPerfFlux; + arrayView3d< real64 > const m_dEnergyPerfFlux; + + /// Views on temperature + ElementViewConst< arrayView1d< real64 const > > const m_temp; + + /// Views on phase enthalpies + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_resPhaseEnthalpy; + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dResPhaseEnthalpy; + + +}; + +/** + * @class PerforationKernelFactory + */ +class PerforationFluxKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] dt time step size + * @param[in] rankOffset the offset of my MPI rank + * @param[in] useTotalMassEquation flag specifying whether to replace one component bal eqn with total mass eqn + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] wellControls object holding well control/constraint information + * @param[in] subregion well subregion + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + integer const numPhases, + string const flowSolverName, + PerforationData * const perforationData, + ElementSubRegionBase const & subRegion, + MultiFluidBase const & fluid, + ElementRegionManager & elemManager, + integer const disableReservoirToWellFlow ) + { + geos::internal::kernelLaunchSelectorCompPhaseSwitch( numComp, numPhases, [&]( auto NC, auto NP ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_PHASE = NP(); + integer constexpr IS_THERMAL = 1; + + using kernelType = PerforationFluxKernel< NUM_COMP, NUM_PHASE, IS_THERMAL >; + typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, flowSolverName ); + typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, flowSolverName ); + typename kernelType::RelPermAccessors relPermAccessors( elemManager, flowSolverName ); + typename kernelType::ThermalCompFlowAccessors thermalCompFlowAccessors( elemManager, flowSolverName ); + typename kernelType::ThermalMultiFluidAccessors thermalMultiFluidAccessors( elemManager, flowSolverName ); + + kernelType kernel( perforationData, subRegion, fluid, compFlowAccessors, multiFluidAccessors, + relPermAccessors, disableReservoirToWellFlow, + thermalCompFlowAccessors, + thermalMultiFluidAccessors ); + kernelType::template launch< POLICY >( perforationData->size(), kernel ); + } ); + } +}; + +} // end namespace thermalPerforationFluxKernels + +} // end namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_PERFORATIONFLUXLKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.cpp similarity index 98% rename from src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.cpp rename to src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.cpp index 68c108e9d6a..e3dae7a4616 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,7 @@ #include "SinglePhaseWellKernels.hpp" // TODO: move keys to WellControls -#include "SinglePhaseWell.hpp" +#include "physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp" namespace geos { diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp similarity index 92% rename from src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp index f54b0bfd8bd..8269b9f3cce 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -27,7 +28,7 @@ #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/StencilAccessors.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" -#include "physicsSolvers/SolverBaseKernels.hpp" +#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" namespace geos { @@ -309,11 +310,11 @@ struct RateInitializationKernel /** * @class ResidualNormKernel */ -class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > +class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 1 > { public: - using Base = solverBaseKernels::ResidualNormKernelBase< 1 >; + using Base = physicsSolverBaseKernels::ResidualNormKernelBase< 1 >; using Base::m_minNormalizer; using Base::m_rankOffset; using Base::m_localResidual; @@ -468,38 +469,6 @@ class ResidualNormKernelFactory }; -/******************************** SolutionCheckKernel ********************************/ - -struct SolutionCheckKernel -{ - template< typename POLICY > - static localIndex - launch( arrayView1d< real64 const > const & localSolution, - globalIndex const rankOffset, - arrayView1d< globalIndex const > const & presDofNumber, - arrayView1d< integer const > const & ghostRank, - arrayView1d< real64 const > const & pres, - real64 const scalingFactor ) - { - RAJA::ReduceMin< ReducePolicy< POLICY >, localIndex > minVal( 1 ); - - forAll< POLICY >( presDofNumber.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( ghostRank[ei] < 0 && presDofNumber[ei] >= 0 ) - { - localIndex const lid = presDofNumber[ei] - rankOffset; - real64 const newPres = pres[ei] + scalingFactor * localSolution[lid]; - - if( newPres < 0.0 ) - { - minVal.min( 0 ); - } - } - } ); - return minVal.get(); - } -}; - } // end namespace singlePhaseWellKernels } // end namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalCompositionalMultiphaseWellKernels.hpp new file mode 100644 index 00000000000..e7beb347528 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalCompositionalMultiphaseWellKernels.hpp @@ -0,0 +1,1123 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalCompositionalMultiphaseWellKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_THERMALCOMPOSITIONALMULTIPHASEWELLKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_THERMALCOMPOSITIONALMULTIPHASEWELLKERNELS_HPP + +#include "physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp" +#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseWellKernels +{ + +using namespace constitutive; + +/******************************** TotalMassDensityKernel ****************************/ + +/** + * @class TotalMassDensityKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_PHASE number of fluid phases + * @brief Define the interface for the property kernel in charge of computing the total mass density + */ +template< integer NUM_COMP, integer NUM_PHASE > +class TotalMassDensityKernel : public compositionalMultiphaseWellKernels::TotalMassDensityKernel< NUM_COMP, NUM_PHASE > +{ +public: + using Base = compositionalMultiphaseWellKernels::TotalMassDensityKernel< NUM_COMP, NUM_PHASE >; + using Base::m_dCompFrac_dCompDens; + using Base::m_dPhaseMassDens; + using Base::m_dPhaseVolFrac; + using Base::m_dTotalMassDens; + using Base::m_phaseMassDens; + using Base::m_phaseVolFrac; + using Base::m_totalMassDens; + using Base::numComp; + using Base::numPhase; + + /** + * @brief Constructor + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + TotalMassDensityKernel( ObjectManagerBase & subRegion, + MultiFluidBase const & fluid ) + : Base( subRegion, fluid ) + {} + + /** + * @brief Compute the total mass density in an element + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[in] totalMassDensityKernelOp the function used to customize the kernel + */ + GEOS_HOST_DEVICE inline void compute( localIndex const ei ) const + { + using Deriv = multifluid::DerivativeOffset; + + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; + arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseMassDens = m_phaseMassDens[ei][0]; + arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseMassDens = m_dPhaseMassDens[ei][0]; + + real64 & dTotalMassDens_dT = m_dTotalMassDens[ei][Deriv::dT]; + + // Call the base compute the compute the total mass density and derivatives + return Base::compute( ei, [&]( localIndex const ip ) + { + dTotalMassDens_dT += dPhaseVolFrac[ip][Deriv::dT] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dT]; + } ); + } + +protected: + // outputs + arrayView1d< real64 > m_dTotalMassDens_dTemp; +}; + +/** + * @class TotalMassDensityKernelFactory + */ +class TotalMassDensityKernelFactory +{ +public: + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComp the number of fluid components + * @param[in] numPhase the number of fluid phases + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + integer const numPhase, + ObjectManagerBase & subRegion, + MultiFluidBase const & fluid ) + { + if( numPhase == 2 ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + TotalMassDensityKernel< NUM_COMP, 2 > kernel( subRegion, fluid ); + TotalMassDensityKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + else if( numPhase == 3 ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + TotalMassDensityKernel< NUM_COMP, 3 > kernel( subRegion, fluid ); + TotalMassDensityKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + } +}; + +/******************************** ResidualNormKernel ********************************/ + +/** + * @class ResidualNormKernel + */ +template< localIndex NUM_COMP > +class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 2 > +{ +public: + + /// Compile time value for the number of components + static constexpr integer numComp = NUM_COMP; + + + using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NUM_COMP, 1 >; + + using Base = physicsSolverBaseKernels::ResidualNormKernelBase< 2 >; + using Base::m_minNormalizer; + using Base::m_rankOffset; + using Base::m_localResidual; + using Base::m_dofNumber; + + ResidualNormKernel( globalIndex const rankOffset, + arrayView1d< real64 const > const & localResidual, + arrayView1d< globalIndex const > const & dofNumber, + arrayView1d< localIndex const > const & ghostRank, + integer const targetPhaseIndex, + WellElementSubRegion const & subRegion, + MultiFluidBase const & fluid, + WellControls const & wellControls, + real64 const timeAtEndOfStep, + real64 const dt, + real64 const minNormalizer ) + : Base( rankOffset, + localResidual, + dofNumber, + ghostRank, + minNormalizer ), + m_numPhases( fluid.numFluidPhases()), + m_targetPhaseIndex( targetPhaseIndex ), + m_dt( dt ), + m_isLocallyOwned( subRegion.isLocallyOwned() ), + m_iwelemControl( subRegion.getTopWellElementIndex() ), + m_isProducer( wellControls.isProducer() ), + m_currentControl( wellControls.getControl() ), + m_targetBHP( wellControls.getTargetBHP( timeAtEndOfStep ) ), + m_targetTotalRate( wellControls.getTargetTotalRate( timeAtEndOfStep ) ), + m_targetPhaseRate( wellControls.getTargetPhaseRate( timeAtEndOfStep ) ), + m_targetMassRate( wellControls.getTargetMassRate( timeAtEndOfStep ) ), + m_volume( subRegion.getElementVolume() ), + m_phaseDens_n( fluid.phaseDensity_n() ), + m_totalDens_n( fluid.totalDensity_n() ), + m_phaseVolFraction_n( subRegion.getField< fields::well::phaseVolumeFraction_n >()), + m_phaseInternalEnergy_n( fluid.phaseInternalEnergy_n() ) + {} + + + GEOS_HOST_DEVICE + void computeMassEnergyNormalizers( localIndex const iwelem, + real64 & massNormalizer, + real64 & energyNormalizer ) const + { + massNormalizer = LvArray::math::max( m_minNormalizer, m_totalDens_n[iwelem][0] * m_volume[iwelem] ); + + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + energyNormalizer += m_phaseInternalEnergy_n[iwelem][0][ip] * m_phaseDens_n[iwelem][0][ip] * m_phaseVolFraction_n[iwelem][ip] * m_volume[iwelem]; + } + // warning: internal energy can be negative + energyNormalizer = LvArray::math::max( m_minNormalizer, LvArray::math::abs( energyNormalizer ) ); + } + + GEOS_HOST_DEVICE + virtual void computeLinf( localIndex const iwelem, + LinfStackVariables & stack ) const override + { + real64 normalizer = 0.0; + for( integer idof = 0; idof < WJ_ROFFSET::nEqn; ++idof ) + { + + // Step 1: compute a normalizer for the control or pressure equation + + // for the control equation, we distinguish two cases + if( idof == WJ_ROFFSET::CONTROL ) + { + + // for the top well element, normalize using the current control + if( m_isLocallyOwned && iwelem == m_iwelemControl ) + { + if( m_currentControl == WellControls::Control::BHP ) + { + // the residual entry is in pressure units + normalizer = m_targetBHP; + } + else if( m_currentControl == WellControls::Control::TOTALVOLRATE ) + { + // the residual entry is in volume / time units + normalizer = LvArray::math::max( LvArray::math::abs( m_targetTotalRate ), m_minNormalizer ); + } + else if( m_currentControl == WellControls::Control::PHASEVOLRATE ) + { + // the residual entry is in volume / time units + normalizer = LvArray::math::max( LvArray::math::abs( m_targetPhaseRate ), m_minNormalizer ); + } + else if( m_currentControl == WellControls::Control::MASSRATE ) + { + // the residual entry is in volume / time units + normalizer = LvArray::math::max( LvArray::math::abs( m_targetMassRate ), m_minNormalizer ); + } + } + // for the pressure difference equation, always normalize by the BHP + else + { + normalizer = m_targetBHP; + } + } + // Step 2: compute a normalizer for the mass balance equations + else if( idof >= WJ_ROFFSET::MASSBAL && idof < WJ_ROFFSET::MASSBAL + numComp ) + { + if( m_isProducer ) // only PHASEVOLRATE is supported for now + { + // the residual is in mass units + normalizer = m_dt * LvArray::math::abs( m_targetPhaseRate ) * m_phaseDens_n[iwelem][0][m_targetPhaseIndex]; + } + else // Type::INJECTOR, only TOTALVOLRATE is supported for now + { + if( m_currentControl == WellControls::Control::MASSRATE ) + { + normalizer = m_dt * LvArray::math::abs( m_targetMassRate ); + } + else + { + // the residual is in mass units + normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ) * m_totalDens_n[iwelem][0]; + } + + } + + // to make sure that everything still works well if the rate is zero, we add this check + normalizer = LvArray::math::max( normalizer, m_volume[iwelem] * m_totalDens_n[iwelem][0] ); + } + // Step 3: compute a normalizer for the volume balance equations + else if( idof == WJ_ROFFSET::VOLBAL ) + { + if( m_isProducer ) // only PHASEVOLRATE is supported for now + { + // the residual is in volume units + normalizer = m_dt * LvArray::math::abs( m_targetPhaseRate ); + } + else // Type::INJECTOR, only TOTALVOLRATE is supported for now + { + if( m_currentControl == WellControls::Control::MASSRATE ) + { + normalizer = m_dt * LvArray::math::abs( m_targetMassRate/ m_totalDens_n[iwelem][0] ); + } + else + { + normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ); + } + + } + // to make sure that everything still works well if the rate is zero, we add this check + normalizer = LvArray::math::max( normalizer, m_volume[iwelem] ); + } + // step 3: energy residual + if( idof == WJ_ROFFSET::ENERGYBAL ) + { + real64 massNormalizer = 0.0, energyNormalizer = 0.0; + computeMassEnergyNormalizers( iwelem, massNormalizer, energyNormalizer ); + real64 const valEnergy = LvArray::math::abs( m_localResidual[stack.localRow + WJ_ROFFSET::ENERGYBAL] ) / energyNormalizer; + if( valEnergy > stack.localValue[1] ) + { + stack.localValue[1] = valEnergy; + } + + } + else + { + normalizer = LvArray::math::max( m_minNormalizer, normalizer ); + // Step 4: compute the contribution to the residual + real64 const val = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / normalizer; + if( val > stack.localValue[0] ) + { + stack.localValue[0] = val; + } + } + } + } + + GEOS_HOST_DEVICE + virtual void computeL2( localIndex const iwelem, + L2StackVariables & stack ) const override + { + GEOS_UNUSED_VAR( iwelem, stack ); + GEOS_ERROR( "The L2 norm is not implemented for CompositionalMultiphaseWell" ); + } + + +protected: + + /// Number of fluid phases + integer const m_numPhases; + + /// Index of the target phase + integer const m_targetPhaseIndex; + + /// Time step size + real64 const m_dt; + + /// Flag indicating whether the well is locally owned or not + bool const m_isLocallyOwned; + + /// Index of the element where the control is enforced + localIndex const m_iwelemControl; + + /// Flag indicating whether the well is a producer or an injector + bool const m_isProducer; + + /// Controls + WellControls::Control const m_currentControl; + real64 const m_targetBHP; + real64 const m_targetTotalRate; + real64 const m_targetPhaseRate; + real64 const m_targetMassRate; + + /// View on the volume + arrayView1d< real64 const > const m_volume; + + /// View on phase/total density at the previous converged time step + arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseDens_n; + arrayView2d< real64 const, multifluid::USD_FLUID > const m_totalDens_n; + arrayView2d< real64 const, compflow::USD_PHASE > const m_phaseVolFraction_n; + arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseInternalEnergy_n; + +}; + +/* + *@class ResidualNormKernelFactory + */ +class ResidualNormKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComp number of fluid components + * @param[in] numDof number of dofs per well element + * @param[in] targetPhaseIndex the index of the target phase (for phase volume control) + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] localResidual the residual vector on my MPI rank + * @param[in] subRegion the well element subregion + * @param[in] fluid the fluid model + * @param[in] wellControls the controls + * @param[in] timeAtEndOfStep the time at the end of the step (time_n + dt) + * @param[in] dt the time step size + * @param[out] residualNorm the residual norm on the subRegion + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + integer const targetPhaseIndex, + globalIndex const rankOffset, + string const & dofKey, + arrayView1d< real64 const > const & localResidual, + WellElementSubRegion const & subRegion, + MultiFluidBase const & fluid, + WellControls const & wellControls, + real64 const timeAtEndOfStep, + real64 const dt, + real64 const minNormalizer, + real64 (& residualNorm)[2] ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch ( numComp, [&]( auto NC ) + { + + integer constexpr NUM_COMP = NC(); + using kernelType = ResidualNormKernel< NUM_COMP >; + arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + + kernelType kernel( rankOffset, localResidual, dofNumber, ghostRank, + targetPhaseIndex, subRegion, fluid, wellControls, timeAtEndOfStep, dt, minNormalizer ); + kernelType::template launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); + } ); + } + +}; + +/******************************** ElementBasedAssemblyKernel ********************************/ + +/** + * @class ElementBasedAssemblyKernel + * @tparam NUM_COMP number of fluid components + * @tparam IS_THERMAL thermal flag + * @brief Define the interface for the assembly kernel in charge of thermal accumulation and volume balance + */ +template< localIndex NUM_COMP > +class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::ElementBasedAssemblyKernel< NUM_COMP, 1 > +{ +public: + using Base = compositionalMultiphaseWellKernels::ElementBasedAssemblyKernel< NUM_COMP, 1 >; + using Base::m_dCompFrac_dCompDens; + using Base::m_dofNumber; + using Base::m_dPhaseCompFrac; + using Base::m_dPhaseDens; + using Base::m_dPhaseVolFrac; + using Base::m_dPoro_dPres; + using Base::m_elemGhostRank; + using Base::m_localMatrix; + using Base::m_localRhs; + using Base::m_numPhases; + using Base::m_phaseCompFrac; + using Base::m_phaseCompFrac_n; + using Base::m_phaseDens; + using Base::m_phaseDens_n; + using Base::m_phaseVolFrac; + using Base::m_phaseVolFrac_n; + using Base::m_porosity; + using Base::m_porosity_n; + using Base::m_rankOffset; + using Base::m_volume; + using Base::numComp; + using Base::numDof; + using Base::numEqn; + + using FLUID_PROP_COFFSET = multifluid::DerivativeOffsetC< NUM_COMP, 1 >; + + + /** + * @brief Constructor + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + ElementBasedAssemblyKernel( localIndex const numPhases, + integer const isProducer, + globalIndex const rankOffset, + string const dofKey, + WellElementSubRegion const & subRegion, + MultiFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > const kernelFlags ) + : Base( numPhases, isProducer, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ), + m_phaseInternalEnergy_n( fluid.phaseInternalEnergy_n()), + m_phaseInternalEnergy( fluid.phaseInternalEnergy()), + m_dPhaseInternalEnergy( fluid.dPhaseInternalEnergy()) + {} + + struct StackVariables : public Base::StackVariables + { +public: + GEOS_HOST_DEVICE + StackVariables() + : Base::StackVariables() + {} + using Base::StackVariables::eqnRowIndices; + using Base::StackVariables::dofColIndices; + using Base::StackVariables::localJacobian; + using Base::StackVariables::localResidual; + using Base::StackVariables::localRow; + using Base::StackVariables::volume; + + + + }; + /** + * @brief Performs the setup phase for the kernel. + * @param[in] ei the element index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const ei, + StackVariables & stack ) const + { + Base::setup( ei, stack ); + + + + } + + /** + * @brief Compute the local accumulation contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const ei, + StackVariables & stack ) const + { + using Deriv = multifluid::DerivativeOffset; + + Base::computeAccumulation( ei, stack, [&]( integer const ip + , real64 const & phaseAmount + , real64 const & phaseAmount_n + , real64 const (&dPhaseAmount)[FLUID_PROP_COFFSET::nDer] ) + { + // We are in the loop over phases, ip provides the current phase index. + // We have to do two things: + // 1- Assemble the derivatives of the component mass balance equations with respect to temperature + // 2- Assemble the phase-dependent part of the accumulation term of the energy equation + + real64 dPhaseInternalEnergy_dC[numComp]{}; + + // construct the slices + arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; + arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseInternalEnergy_n = m_phaseInternalEnergy_n[ei][0]; + arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseInternalEnergy = m_phaseInternalEnergy[ei][0]; + arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseInternalEnergy = m_dPhaseInternalEnergy[ei][0]; + + // Step 1: assemble the phase-dependent part of the accumulation term of the energy equation + + real64 const phaseEnergy = phaseAmount * phaseInternalEnergy[ip]; + real64 const phaseEnergy_n = phaseAmount_n * phaseInternalEnergy_n[ip]; + real64 const dPhaseEnergy_dP = dPhaseAmount[FLUID_PROP_COFFSET::dP] * phaseInternalEnergy[ip] + + phaseAmount * dPhaseInternalEnergy[ip][Deriv::dP]; + real64 const dPhaseEnergy_dT = dPhaseAmount[FLUID_PROP_COFFSET::dT] * phaseInternalEnergy[ip] + + phaseAmount * dPhaseInternalEnergy[ip][Deriv::dT]; + // local accumulation + stack.localResidual[numEqn-1] += phaseEnergy - phaseEnergy_n; + + // derivatives w.r.t. pressure and temperature + stack.localJacobian[numEqn-1][0] += dPhaseEnergy_dP; + stack.localJacobian[numEqn-1][numDof-1] += dPhaseEnergy_dT; + + // derivatives w.r.t. component densities + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseInternalEnergy[ip], dPhaseInternalEnergy_dC, Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.localJacobian[numEqn-1][jc + 1] += phaseInternalEnergy[ip] * dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] + + dPhaseInternalEnergy_dC[jc] * phaseAmount; + } + } ); + + + } + + /** + * @brief Compute the local volume balance contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeVolumeBalance( localIndex const ei, + StackVariables & stack ) const + { + Base::computeVolumeBalance( ei, stack ); + + } + + GEOS_HOST_DEVICE + void complete( localIndex const ei, + StackVariables & stack ) const + { + // Assemble the component mass balance equations and volume balance equations + // Energy balance equation updates to solver matrices included in Base class + Base::complete( ei, stack ); + + } + +protected: + /// View on derivative of porosity w.r.t temperature + arrayView2d< real64 const > const m_dPoro_dTemp; + + /// Views on phase internal energy + arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseInternalEnergy_n; + arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseInternalEnergy; + arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dPhaseInternalEnergy; + +}; + +/** + * @class ElementBasedAssemblyKernelFactory + */ +class ElementBasedAssemblyKernelFactory +{ +public: + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( localIndex const numComps, + localIndex const numPhases, + integer const isProducer, + globalIndex const rankOffset, + integer const useTotalMassEquation, + string const dofKey, + WellElementSubRegion const & subRegion, + MultiFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + localIndex constexpr NUM_COMP = NC(); + + + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ); + + ElementBasedAssemblyKernel< NUM_COMP > + kernel( numPhases, isProducer, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ); + ElementBasedAssemblyKernel< NUM_COMP >::template + launch< POLICY, ElementBasedAssemblyKernel< NUM_COMP > >( subRegion.size(), kernel ); + } ); + } +}; +/** + * @class FaceBasedAssemblyKernel + * @tparam NUM_COMP number of fluid components + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NC > +class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceBasedAssemblyKernel< NC, 1 > +{ +public: + static constexpr integer IS_THERMAL = 1; + using Base = compositionalMultiphaseWellKernels::FaceBasedAssemblyKernel< NC, IS_THERMAL >; + + // Well jacobian column and row indicies + using WJ_COFFSET = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; + using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >; + + using CP_Deriv = multifluid::DerivativeOffsetC< NC, IS_THERMAL >; + + using TAG = compositionalMultiphaseWellKernels::ElemTag; + + + using Base::m_isProducer; + using Base::m_dt; + using Base::m_localRhs; + using Base::m_localMatrix; + using Base::m_rankOffset; + using Base::maxNumElems; + using Base::maxStencilSize; + using Base::m_useTotalMassEquation; + + /// Compile time value for the number of components + static constexpr integer numComp = NC; + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = WJ_COFFSET::nDer; + +/// Compile time value for the number of equations except volume and momentum + static constexpr integer numEqn = WJ_ROFFSET::nEqn - 2; + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor + * @param[in] compFlowAccessors + * @param[in] multiFluidAccessors + * @param[in] capPressureAccessors + * @param[in] permeabilityAccessors + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed together + */ + FaceBasedAssemblyKernel( real64 const dt, + globalIndex const rankOffset, + string const wellDofKey, + WellControls const & wellControls, + WellElementSubRegion const & subRegion, + MultiFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags ) + : Base( dt + , rankOffset + , wellDofKey + , wellControls + , subRegion + , localMatrix + , localRhs + , kernelFlags ), + m_numPhases ( fluid.numFluidPhases()), + m_globalWellElementIndex( subRegion.getGlobalWellElementIndex() ), + m_phaseFraction( fluid.phaseFraction()), + m_dPhaseFraction( fluid.dPhaseFraction()), + m_phaseEnthalpy( fluid.phaseEnthalpy()), + m_dPhaseEnthalpy( fluid.dPhaseEnthalpy()) + { } + + struct StackVariables : public Base::StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables( localIndex const size ) + : Base::StackVariables( size ) + {} + + /// Storage for the face local residual vector (energy equation) + stackArray1d< real64, maxNumElems > localEnergyFlux; + /// Storage for the face local energy Jacobian matrix dC dP dT + stackArray2d< real64, maxNumElems * maxStencilSize * CP_Deriv::nDer > localEnergyFluxJacobian; + /// Storage for the face local Jacobian matrix dQ only + stackArray2d< real64, maxNumElems * maxStencilSize > localEnergyFluxJacobian_dQ; + }; + + GEOS_HOST_DEVICE + inline + void setup( localIndex const iwelem, StackVariables & stack ) const + { + Base::setup ( iwelem, stack ); + stack.localEnergyFlux.resize( stack.numConnectedElems ); + stack.localEnergyFluxJacobian.resize( stack.numConnectedElems, stack.stencilSize * numDof ); + stack.localEnergyFluxJacobian_dQ.resize( stack.numConnectedElems, 1 ); + for( integer i=0; i= 0 && oneSidedEqnRowIndices < m_localMatrix.numRows() ) + { + + if( !m_isProducer && m_globalWellElementIndex[iwelem] == 0 ) + { + // For top segment energy balance eqn replaced with T(n+1) - T = 0 + // No other energy balance derivatives + // Assumption is global index == 0 is top segment with fixed temp BC + for( integer i=0; i< CP_Deriv::nDer; i++ ) + { + stack.localEnergyFluxJacobian[0][i] = 0.0; + } + stack.localEnergyFluxJacobian_dQ[0][0]=0; + stack.localEnergyFlux[0]=0; + } + + + // Setup Jacobian global col indicies ( Mapping from local jac order to well jac order) + globalIndex oneSidedDofColIndices_dRate = stack.offsetCurrent + WJ_COFFSET::dQ; + globalIndex oneSidedDofColIndices_dPresCompTempUp[CP_Deriv::nDer]{}; + + int ioff=0; + oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dP; + oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dT; + for( integer jdof = 0; jdof < NC; ++jdof ) + { + oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dC+ jdof; + } + + m_localMatrix.template addToRow< parallelDeviceAtomic >( oneSidedEqnRowIndices, + &oneSidedDofColIndices_dRate, + stack.localEnergyFluxJacobian_dQ[0], + 1 ); + m_localMatrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( oneSidedEqnRowIndices, + oneSidedDofColIndices_dPresCompTempUp, + stack.localEnergyFluxJacobian[0], + CP_Deriv::nDer ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[oneSidedEqnRowIndices], stack.localEnergyFlux[0] ); + } + } + else // if ( stack.numConnectedElems == 2 ) + { + globalIndex row_current = stack.offsetCurrent + WJ_ROFFSET::ENERGYBAL - m_rankOffset; + globalIndex row_next = stack.offsetNext + WJ_ROFFSET::ENERGYBAL - m_rankOffset; + + if( !m_isProducer ) + { + if( row_next >= 0 && row_next < m_localMatrix.numRows() ) + { + if( m_globalWellElementIndex[stack.iwelemNext] == 0 ) + { + for( integer i=0; i= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.template addToRow< parallelDeviceAtomic >( eqnRowIndices[i], + &dofColIndices_dRate, + stack.localEnergyFluxJacobian_dQ[i], + 1 ); + m_localMatrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], + dofColIndices, + stack.localEnergyFluxJacobian[i], + CP_Deriv::nDer ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], stack.localEnergyFlux[i] ); + } + } + } + + } + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes + * @param[in] ie the element index + * @param[inout] stack the stack variables + * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes + */ + + GEOS_HOST_DEVICE + inline + void computeFlux( localIndex const iwelem, StackVariables & stack ) const + { + Base::computeFlux ( iwelem, stack, [&] ( localIndex const & iwelemNext + , localIndex const & iwelemUp + , real64 const & currentConnRate + , real64 const (&dCompFrac_dCompDens)[NC][NC] ) + { + + if( iwelemNext < 0 && !m_isProducer ) // exit connection, injector + { + real64 eflux=0; + real64 eflux_dq=0; + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + eflux += m_phaseEnthalpy[iwelemUp][0][ip]* m_phaseFraction[iwelemUp][0][ip]; + eflux_dq += m_phaseEnthalpy[iwelemUp][0][ip] * m_phaseFraction[iwelemUp][0][ip]; + + stack.localEnergyFluxJacobian[0] [CP_Deriv::dP] += m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][CP_Deriv::dP] + + m_dPhaseEnthalpy[iwelemUp][0][ip][CP_Deriv::dP]*m_phaseFraction[iwelemUp][0][ip]; + stack.localEnergyFluxJacobian[0] [CP_Deriv::dT] += m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][CP_Deriv::dT] + + m_dPhaseEnthalpy[iwelemUp][0][ip][CP_Deriv::dT]*m_phaseFraction[iwelemUp][0][ip]; + + real64 dProp1_dC[numComp]{}; + applyChainRule( numComp, dCompFrac_dCompDens, m_dPhaseEnthalpy[iwelemUp][0][ip], dProp1_dC, CP_Deriv::dC ); + real64 dProp2_dC[numComp]{}; + applyChainRule( numComp, dCompFrac_dCompDens, m_dPhaseFraction[iwelemUp][0][ip], dProp2_dC, CP_Deriv::dC ); + for( integer dof=0; dof < numComp; dof++ ) + { + stack.localEnergyFluxJacobian[0] [CP_Deriv::dC+dof] += m_phaseEnthalpy[iwelemUp][0][ip]*dProp2_dC[dof] + + dProp1_dC[dof]*m_phaseFraction[iwelemUp][0][ip]; + } + } + for( integer dof=0; dof < CP_Deriv::nDer; dof++ ) + { + stack.localEnergyFluxJacobian[0] [dof] *= -m_dt*currentConnRate; + } + // Energy equation + stack.localEnergyFlux[0] = -m_dt * eflux * currentConnRate; + stack.localEnergyFluxJacobian_dQ[0][0] = -m_dt * eflux_dq; + } + else if( ( iwelemNext < 0 && m_isProducer ) || currentConnRate < 0 ) // exit connection, producer + { + real64 eflux=0; + real64 eflux_dq=0; + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + eflux += m_phaseEnthalpy[iwelemUp][0][ip]* m_phaseFraction[iwelemUp][0][ip]; + eflux_dq += m_phaseEnthalpy[iwelemUp][0][ip] * m_phaseFraction[iwelemUp][0][ip]; + stack.localEnergyFluxJacobian[0] [CP_Deriv::dP] += m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][CP_Deriv::dP] + + m_dPhaseEnthalpy[iwelemUp][0][ip][CP_Deriv::dP]*m_phaseFraction[iwelemUp][0][ip]; + stack.localEnergyFluxJacobian[0] [CP_Deriv::dT] += m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][CP_Deriv::dT] + + m_dPhaseEnthalpy[iwelemUp][0][ip][CP_Deriv::dT]*m_phaseFraction[iwelemUp][0][ip]; + + real64 dProp1_dC[numComp]{}; + applyChainRule( numComp, dCompFrac_dCompDens, m_dPhaseEnthalpy[iwelemUp][0][ip], dProp1_dC, CP_Deriv::dC ); + real64 dProp2_dC[numComp]{}; + applyChainRule( numComp, dCompFrac_dCompDens, m_dPhaseFraction[iwelemUp][0][ip], dProp2_dC, CP_Deriv::dC ); + for( integer dof=0; dof < numComp; dof++ ) + { + stack.localEnergyFluxJacobian[0] [CP_Deriv::dC+dof] += m_phaseEnthalpy[iwelemUp][0][ip]*dProp2_dC[dof] + + dProp1_dC[dof]*m_phaseFraction[iwelemUp][0][ip]; + } + + } + + for( integer dof=0; dof < CP_Deriv::nDer; dof++ ) + { + stack.localEnergyFluxJacobian[0][dof] *= -m_dt*currentConnRate; + } + stack.localEnergyFlux[0] = -m_dt * eflux * currentConnRate; + stack.localEnergyFluxJacobian_dQ[0][0] = -m_dt*eflux_dq; + } + else + { + real64 eflux=0; + real64 eflux_dq=0; + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + eflux += m_phaseEnthalpy[iwelemUp][0][ip]* m_phaseFraction[iwelemUp][0][ip]; + eflux_dq += m_phaseEnthalpy[iwelemUp][0][ip] * m_phaseFraction[iwelemUp][0][ip]; + + real64 dprop_dp = m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][CP_Deriv::dP] + + m_dPhaseEnthalpy[iwelemUp][0][ip][CP_Deriv::dP]*m_phaseFraction[iwelemUp][0][ip]; + real64 dprop_dt = m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][CP_Deriv::dT] + + m_dPhaseEnthalpy[iwelemUp][0][ip][CP_Deriv::dT]*m_phaseFraction[iwelemUp][0][ip]; + + stack.localEnergyFluxJacobian[TAG::NEXT ] [CP_Deriv::dP] += dprop_dp; + stack.localEnergyFluxJacobian[TAG::NEXT] [CP_Deriv::dT] += dprop_dt; + + stack.localEnergyFluxJacobian[TAG::CURRENT ] [CP_Deriv::dP] += dprop_dp; + stack.localEnergyFluxJacobian[TAG::CURRENT] [CP_Deriv::dT] += dprop_dt; + + real64 dPE_dC[numComp]{}; + applyChainRule( numComp, dCompFrac_dCompDens, m_dPhaseEnthalpy[iwelemUp][0][ip], dPE_dC, CP_Deriv::dC ); + real64 dPF_dC[numComp]{}; + applyChainRule( numComp, dCompFrac_dCompDens, m_dPhaseFraction[iwelemUp][0][ip], dPF_dC, CP_Deriv::dC ); + + for( integer dof=0; dof < numComp; dof++ ) + { + stack.localEnergyFluxJacobian[TAG::NEXT ][CP_Deriv::dC+dof] += m_phaseEnthalpy[iwelemUp][0][ip]*dPF_dC[dof] + +dPE_dC[dof]*m_phaseFraction[iwelemUp][0][ip]; + stack.localEnergyFluxJacobian[TAG::CURRENT ][CP_Deriv::dC+dof] += m_phaseEnthalpy[iwelemUp][0][ip]*dPF_dC[dof] + +dPE_dC[dof]*m_phaseFraction[iwelemUp][0][ip]; + } + } + stack.localEnergyFlux[TAG::NEXT ] = m_dt * eflux * currentConnRate; + stack.localEnergyFlux[TAG::CURRENT ] = -m_dt * eflux * currentConnRate; + stack.localEnergyFluxJacobian_dQ [TAG::NEXT ][0] = m_dt * eflux_dq; + stack.localEnergyFluxJacobian_dQ [TAG::CURRENT][0] = -m_dt * eflux_dq; + for( integer dof=0; dof < CP_Deriv::nDer; dof++ ) + { + stack.localEnergyFluxJacobian[TAG::NEXT ][dof] *= m_dt*currentConnRate; + stack.localEnergyFluxJacobian[TAG::CURRENT ][dof] *= -m_dt*currentConnRate; + } + } + + } ); + + } + + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElements the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack + * variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElements, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const ie ) + { + typename KERNEL_TYPE::StackVariables stack( 1 ); + + kernelComponent.setup( ie, stack ); + kernelComponent.computeFlux( ie, stack ); + kernelComponent.complete( ie, stack ); + } ); + } + +protected: + /// Number of phases + integer const m_numPhases; + + /// Global index of local element + arrayView1d< globalIndex const > m_globalWellElementIndex; + + /// Element phase fraction + arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseFraction; + arrayView4d< real64 const, multifluid::USD_PHASE_DC > const m_dPhaseFraction; + + /// Views on phase enthalpy + arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseEnthalpy; + arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dPhaseEnthalpy; + + +}; + +/** + * @class FaceBasedAssemblyKernelFactory + */ +class FaceBasedAssemblyKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] dt time step size + * @param[in] rankOffset the offset of my MPI rank + * @param[in] useTotalMassEquation flag specifying whether to replace one component bal eqn with total mass eqn + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] wellControls object holding well control/constraint information + * @param[in] subregion well subregion + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComps, + real64 const dt, + globalIndex const rankOffset, + integer const useTotalMassEquation, + string const dofKey, + WellControls const & wellControls, + WellElementSubRegion const & subRegion, + MultiFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + + + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ); + + + using kernelType = FaceBasedAssemblyKernel< NUM_COMP >; + + + kernelType kernel( dt, rankOffset, dofKey, wellControls, subRegion, fluid, localMatrix, localRhs, kernelFlags ); + kernelType::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } +}; + +} // end namespace thermalCompositionalMultiphaseWellKernels + +} // end namespace geos + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_THERMALCOMPOSITIONALMULTIPHASEWELLKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalSinglePhaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalSinglePhaseWellKernels.hpp new file mode 100644 index 00000000000..74a8c1f7414 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalSinglePhaseWellKernels.hpp @@ -0,0 +1,247 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SinglePhaseWellKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_THERMALSINGLEPHASEWELLKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_THERMALSINGLEPHASEWELLKERNELS_HPP + +#include "constitutive/fluid/singlefluid/SingleFluidFields.hpp" +#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" +#include "physicsSolvers/fluidFlow/wells/WellControls.hpp" +#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" + +namespace geos +{ + +namespace thermalSinglePhaseWellKernels +{ + + + +/******************************** ElementBasedAssemblyKernel ********************************/ + +/** + * @class ElementBasedAssemblyKernel + * @tparam NUM_DOF number of degrees of freedom + * @brief Define the interface for the assembly kernel in charge of accumulation and volume balance + */ +template< integer NUM_DOF > +class ElementBasedAssemblyKernel : public singlePhaseWellKernels::ElementBasedAssemblyKernel< NUM_DOF > +{ +public: + using Base = singlePhaseWellKernels::ElementBasedAssemblyKernel< NUM_DOF >; + using Base::m_rankOffset; + using Base::m_wellElemDofNumber; + using Base::m_elemGhostRank; + using Base::m_wellElemVolume; + using Base::m_wellElemDensity; + using Base::m_wellElemDensity_n; + using Base::m_dWellElemDensity_dPressure; + using Base::m_localMatrix; + using Base::m_localRhs; + using ROFFSET = singlePhaseWellKernels::RowOffset; + using COFFSET = singlePhaseWellKernels::ColOffset; + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = NUM_DOF; + + /// Compute time value for the number of equations + static constexpr integer numEqn = NUM_DOF; + + /** + * @brief Constructor + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + ElementBasedAssemblyKernel( globalIndex const rankOffset, + string const dofKey, + ElementSubRegionBase const & subRegion, + constitutive::SingleFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : Base( rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs ), + m_dWellElemDensity_dTemperature( fluid.dDensity_dTemperature() ), + m_internalEnergy( fluid.internalEnergy() ), + m_internalEnergy_n( fluid.internalEnergy_n() ), + m_dInternalEnergy_dPres( fluid.dInternalEnergy_dPressure() ), + m_dInternalEnergy_dTemp( fluid.dInternalEnergy_dTemperature() ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables : public Base::StackVariables + { +public: + GEOS_HOST_DEVICE + StackVariables() + : Base::StackVariables() + {} + using Base::StackVariables::eqnRowIndices; + using Base::StackVariables::dofColIndices; + using Base::StackVariables::localJacobian; + using Base::StackVariables::localResidual; + using Base::StackVariables::localRow; + using Base::StackVariables::volume; + using Base::StackVariables::density; + using Base::StackVariables::density_n; + using Base::StackVariables::dDensity_dPres; + + }; + /** + * @brief Getter for the ghost rank of an element + * @param[in] ei the element index + * @return the ghost rank of the element + */ + GEOS_HOST_DEVICE + integer elemGhostRank( localIndex const ei ) const + { return m_elemGhostRank( ei ); } + + + + /** + * @brief Compute the local accumulation contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + * @param[in] phaseAmountKernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const iwelem, + StackVariables & stack ) const + { + Base::computeAccumulation( iwelem, stack, [&]( ) + { + + // Step 1: assemble the derivatives of the mass balance equation w.r.t temperature + stack.localJacobian[0][numDof-1] = stack.volume * m_dWellElemDensity_dTemperature[iwelem][0]; + + // Step 2: assemble the fluid part of the accumulation term of the energy equation + real64 const fluidEnergy = stack.volume * stack.density * m_internalEnergy[iwelem][0]; + real64 const fluidEnergy_n = stack.volume * stack.density_n * m_internalEnergy_n[iwelem][0]; + + real64 const dFluidEnergy_dP = stack.volume * stack.dDensity_dPres * m_internalEnergy[iwelem][0] + + stack.volume * stack.density * m_dInternalEnergy_dPres[iwelem][0]; + + + real64 const dFluidEnergy_dT = stack.volume * m_dWellElemDensity_dTemperature[iwelem][0] * m_internalEnergy[iwelem][0] + + stack.volume * stack.density * m_dInternalEnergy_dTemp[iwelem][0]; + + // local accumulation + stack.localResidual[numEqn-1] = fluidEnergy - fluidEnergy_n; + + // derivatives w.r.t. pressure and temperature + stack.localJacobian[numEqn-1][0] = dFluidEnergy_dP; + stack.localJacobian[numEqn-1][numDof-1] = dFluidEnergy_dT; + } ); + } + + + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElems the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) + { + if( kernelComponent.elemGhostRank( iwelem ) >= 0 ) + { + return; + } + typename KERNEL_TYPE::StackVariables stack; + kernelComponent.setup( iwelem, stack ); + kernelComponent.computeAccumulation( iwelem, stack ); + kernelComponent.complete( iwelem, stack ); + + } ); + } + +protected: + + /// View on derivative of fluid density w.r.t temperature + arrayView2d< real64 const > const m_dWellElemDensity_dTemperature; + + /// Views on fluid internal energy + arrayView2d< real64 const > const m_internalEnergy; + arrayView2d< real64 const > const m_internalEnergy_n; + arrayView2d< real64 const > const m_dInternalEnergy_dPres; + arrayView2d< real64 const > const m_dInternalEnergy_dTemp; + +}; + + +/** + * @class ElementBasedAssemblyKernelFactory + */ +class ElementBasedAssemblyKernelFactory +{ +public: + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( globalIndex const rankOffset, + string const dofKey, + ElementSubRegionBase const & subRegion, + constitutive::SingleFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + integer constexpr NUM_DOF = 2; + ElementBasedAssemblyKernel< NUM_DOF > + kernel( rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs ); + ElementBasedAssemblyKernel< NUM_DOF >::template + launch< POLICY, ElementBasedAssemblyKernel< NUM_DOF > >( subRegion.size(), kernel ); + + } +}; +} // end namespace singlePhaseWellKernels + +} // end namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_SINGLEPHASEWELLKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/inducedSeismicity/CMakeLists.txt b/src/coreComponents/physicsSolvers/inducedSeismicity/CMakeLists.txt new file mode 100644 index 00000000000..c8f23c55323 --- /dev/null +++ b/src/coreComponents/physicsSolvers/inducedSeismicity/CMakeLists.txt @@ -0,0 +1,19 @@ +# Specify solver headers +set( physicsSolvers_headers + ${physicsSolvers_headers} + inducedSeismicity/inducedSeismicityFields.hpp + inducedSeismicity/rateAndStateFields.hpp + inducedSeismicity/QuasiDynamicEQ.hpp + inducedSeismicity/QuasiDynamicEQRK32.hpp + inducedSeismicity/SeismicityRate.hpp + inducedSeismicity/kernels/RateAndStateKernels.hpp + inducedSeismicity/kernels/SeismicityRateKernels.hpp + PARENT_SCOPE ) + +# Specify solver sources +set( physicsSolvers_sources + ${physicsSolvers_sources} + inducedSeismicity/QuasiDynamicEQ.cpp + inducedSeismicity/QuasiDynamicEQRK32.cpp + inducedSeismicity/SeismicityRate.cpp + PARENT_SCOPE ) diff --git a/src/coreComponents/physicsSolvers/inducedSeismicity/QuasiDynamicEQ.cpp b/src/coreComponents/physicsSolvers/inducedSeismicity/QuasiDynamicEQ.cpp new file mode 100644 index 00000000000..3ddf5fc1494 --- /dev/null +++ b/src/coreComponents/physicsSolvers/inducedSeismicity/QuasiDynamicEQ.cpp @@ -0,0 +1,287 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file QuasiDynamicEQ.cpp + */ + +#include "QuasiDynamicEQ.hpp" + +#include "dataRepository/InputFlags.hpp" +#include "mesh/DomainPartition.hpp" +#include "kernels/RateAndStateKernels.hpp" +#include "rateAndStateFields.hpp" +#include "physicsSolvers/contact/ContactFields.hpp" +#include "fieldSpecification/FieldSpecificationManager.hpp" + +namespace geos +{ + +using namespace dataRepository; +using namespace fields; +using namespace constitutive; +using namespace rateAndStateKernels; + +QuasiDynamicEQ::QuasiDynamicEQ( const string & name, + Group * const parent ): + PhysicsSolverBase( name, parent ), + m_stressSolver( nullptr ), + m_stressSolverName( "SpringSlider" ), + m_shearImpedance( 0.0 ), + m_targetSlipIncrement( 1.0e-7 ) +{ + this->registerWrapper( viewKeyStruct::shearImpedanceString(), &m_shearImpedance ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Shear impedance." ); + + this->registerWrapper( viewKeyStruct::stressSolverNameString(), &m_stressSolverName ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Name of solver for computing stress. If empty, the spring-slider model is run." ); + + this->registerWrapper( viewKeyStruct::targetSlipIncrementString(), &m_targetSlipIncrement ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( 1.0e-7 ). + setDescription( "Target slip incrmeent for timestep size selction" ); +} + +void QuasiDynamicEQ::postInputInitialization() +{ + + // Initialize member stress solver as specified in XML input + if( !m_stressSolverName.empty() ) + { + m_stressSolver = &this->getParent().getGroup< PhysicsSolverBase >( m_stressSolverName ); + } + + PhysicsSolverBase::postInputInitialization(); +} + +QuasiDynamicEQ::~QuasiDynamicEQ() +{ + // TODO Auto-generated destructor stub +} + +void QuasiDynamicEQ::registerDataOnMesh( Group & meshBodies ) +{ + PhysicsSolverBase::registerDataOnMesh( meshBodies ); + + forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + + elemManager.forElementSubRegions< SurfaceElementSubRegion >( regionNames, + [&]( localIndex const, + SurfaceElementSubRegion & subRegion ) + { + // Scalar functions on fault + subRegion.registerField< rateAndState::stateVariable >( getName() ); + subRegion.registerField< rateAndState::stateVariable_n >( getName() ); + subRegion.registerField< rateAndState::slipRate >( getName() ); + + // Tangent (2-component) functions on fault + string const labels2Comp[2] = {"tangent1", "tangent2" }; + subRegion.registerField< rateAndState::slipVelocity >( getName() ). + setDimLabels( 1, labels2Comp ).reference().resizeDimension< 1 >( 2 ); + subRegion.registerField< rateAndState::deltaSlip >( getName() ). + setDimLabels( 1, labels2Comp ).reference().resizeDimension< 1 >( 2 ); + + if( !subRegion.hasWrapper( contact::dispJump::key() )) + { + // 3-component functions on fault + string const labels3Comp[3] = { "normal", "tangent1", "tangent2" }; + subRegion.registerField< contact::dispJump >( getName() ). + setDimLabels( 1, labels3Comp ). + reference().resizeDimension< 1 >( 3 ); + subRegion.registerField< contact::traction >( getName() ). + setDimLabels( 1, labels3Comp ). + reference().resizeDimension< 1 >( 3 ); + + subRegion.registerWrapper< string >( viewKeyStruct::frictionLawNameString() ). + setPlotLevel( PlotLevel::NOPLOT ). + setRestartFlags( RestartFlags::NO_WRITE ). + setSizedFromParent( 0 ); + + string & frictionLawName = subRegion.getReference< string >( viewKeyStruct::frictionLawNameString() ); + frictionLawName =PhysicsSolverBase::getConstitutiveName< FrictionBase >( subRegion ); + GEOS_ERROR_IF( frictionLawName.empty(), GEOS_FMT( "{}: FrictionBase model not found on subregion {}", + getDataContext(), subRegion.getDataContext() ) ); + } + } ); + } ); +} + +real64 QuasiDynamicEQ::solverStep( real64 const & time_n, + real64 const & dt, + int const cycleNumber, + DomainPartition & domain ) +{ + if( cycleNumber == 0 ) + { + /// Apply initial conditions to the Fault + FieldSpecificationManager & fieldSpecificationManager = FieldSpecificationManager::getInstance(); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + + { + fieldSpecificationManager.applyInitialConditions( mesh ); + } ); + } + + /// 1. Compute shear and normal tractions + GEOS_LOG_LEVEL_RANK_0( 1, "Stress solver" ); + + real64 const dtStress = updateStresses( time_n, dt, cycleNumber, domain ); + + /// 2. Solve for slip rate and state variable and, compute slip + GEOS_LOG_LEVEL_RANK_0( 1, "Rate and State solver" ); + integer const maxIterNewton = m_nonlinearSolverParameters.m_maxIterNewton; + real64 const newtonTol = m_nonlinearSolverParameters.m_newtonTol; + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + + { + mesh.getElemManager().forElementSubRegions< SurfaceElementSubRegion >( regionNames, + [&]( localIndex const, + SurfaceElementSubRegion & subRegion ) + { + // solve rate and state equations. + createAndLaunch< ImplicitFixedStressRateAndStateKernel, parallelDevicePolicy<> >( subRegion, viewKeyStruct::frictionLawNameString(), m_shearImpedance, maxIterNewton, newtonTol, time_n, + dtStress ); + // save old state + saveOldStateAndUpdateSlip( subRegion, dtStress ); + } ); + } ); + + // return time step size achieved by stress solver + return dtStress; +} + +real64 QuasiDynamicEQ::updateStresses( real64 const & time_n, + real64 const & dt, + const int cycleNumber, + DomainPartition & domain ) const +{ + // Call member variable stress solver to update the stress state + if( m_stressSolver ) + { + // 1. Solve the momentum balance + real64 const dtStress = m_stressSolver->solverStep( time_n, dt, cycleNumber, domain ); + + return dtStress; + } + else + { + // Spring-slider shear traction computation + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + + { + mesh.getElemManager().forElementSubRegions< SurfaceElementSubRegion >( regionNames, + [&]( localIndex const, + SurfaceElementSubRegion & subRegion ) + { + + arrayView2d< real64 const > const deltaSlip = subRegion.getField< rateAndState::deltaSlip >(); + arrayView2d< real64 > const traction = subRegion.getField< fields::contact::traction >(); + + string const & fricitonLawName = subRegion.template getReference< string >( viewKeyStruct::frictionLawNameString() ); + RateAndStateFriction const & frictionLaw = getConstitutiveModel< RateAndStateFriction >( subRegion, fricitonLawName ); + + RateAndStateFriction::KernelWrapper frictionKernelWrapper = frictionLaw.createKernelUpdates(); + + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + SpringSliderParameters springSliderParameters = SpringSliderParameters( traction[k][0], + frictionKernelWrapper.getACoefficient( k ), + frictionKernelWrapper.getBCoefficient( k ), + frictionKernelWrapper.getDcCoefficient( k ) ); + + + traction[k][1] = traction[k][1] + springSliderParameters.tauRate * dt + - springSliderParameters.springStiffness * deltaSlip[k][0]; + traction[k][2] = traction[k][2] + springSliderParameters.tauRate * dt + - springSliderParameters.springStiffness * deltaSlip[k][1]; + } ); + } ); + } ); + return dt; + } +} + +void QuasiDynamicEQ::saveOldStateAndUpdateSlip( ElementSubRegionBase & subRegion, real64 const dt ) const +{ + arrayView1d< real64 > const stateVariable = subRegion.getField< rateAndState::stateVariable >(); + arrayView1d< real64 > const stateVariable_n = subRegion.getField< rateAndState::stateVariable_n >(); + arrayView2d< real64 > const slipVelocity = subRegion.getField< rateAndState::slipVelocity >(); + arrayView2d< real64 > const deltaSlip = subRegion.getField< rateAndState::deltaSlip >(); + + arrayView2d< real64 > const dispJump = subRegion.getField< contact::dispJump >(); + + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + stateVariable_n[k] = stateVariable[k]; + deltaSlip[k][0] = slipVelocity[k][0] * dt; + deltaSlip[k][1] = slipVelocity[k][1] * dt; + // Update tangential components of the displacement jump + dispJump[k][1] = dispJump[k][1] + slipVelocity[k][0] * dt; + dispJump[k][2] = dispJump[k][2] + slipVelocity[k][1] * dt; + } ); +} + +real64 QuasiDynamicEQ::setNextDt( real64 const & currentDt, DomainPartition & domain ) +{ + GEOS_UNUSED_VAR( currentDt ); + + real64 maxSlipRate = 0.0; + // Spring-slider shear traction computation + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) + + { + real64 maxSlipRateOnThisRank = 0.0; + mesh.getElemManager().forElementSubRegions< SurfaceElementSubRegion >( regionNames, + [&]( localIndex const, + SurfaceElementSubRegion const & subRegion ) + { + arrayView1d< real64 const > const slipRate = subRegion.getField< rateAndState::slipRate >(); + + RAJA::ReduceMax< parallelDeviceReduce, real64 > maximumSlipRateOnThisRegion( 0.0 ); + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + maximumSlipRateOnThisRegion.max( slipRate[k] ); + } ); + if( maximumSlipRateOnThisRegion.get() > maxSlipRateOnThisRank ) + maxSlipRateOnThisRank = maximumSlipRateOnThisRegion.get(); + } ); + maxSlipRate = MpiWrapper::max( maxSlipRateOnThisRank ); + } ); + + real64 const nextDt = m_targetSlipIncrement / maxSlipRate; + + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "The next dt will be {:.2e} s", nextDt )); + + return nextDt; +} + +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, QuasiDynamicEQ, string const &, dataRepository::Group * const ) + +} // namespace geos diff --git a/src/coreComponents/physicsSolvers/inducedSeismicity/QuasiDynamicEQ.hpp b/src/coreComponents/physicsSolvers/inducedSeismicity/QuasiDynamicEQ.hpp new file mode 100644 index 00000000000..6d85175d3c7 --- /dev/null +++ b/src/coreComponents/physicsSolvers/inducedSeismicity/QuasiDynamicEQ.hpp @@ -0,0 +1,135 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#ifndef GEOS_PHYSICSSOLVERS_INDUCED_QUASIDYNAMICEQ_HPP +#define GEOS_PHYSICSSOLVERS_INDUCED_QUASIDYNAMICEQ_HPP + +#include "physicsSolvers/PhysicsSolverBase.hpp" + +namespace geos +{ + +class QuasiDynamicEQ : public PhysicsSolverBase +{ +public: + /// The default nullary constructor is disabled to avoid compiler auto-generation: + QuasiDynamicEQ() = delete; + + /// The constructor needs a user-defined "name" and a parent Group (to place this instance in the tree structure of classes) + QuasiDynamicEQ( const string & name, + Group * const parent ); + + /// Destructor + virtual ~QuasiDynamicEQ() override; + + static string catalogName() { return "QuasiDynamicEQ"; } + + /** + * @return Get the final class Catalog name + */ + virtual string getCatalogName() const override { return catalogName(); } + + /// This method ties properties with their supporting mesh + virtual void registerDataOnMesh( Group & meshBodies ) override; + + struct viewKeyStruct : public PhysicsSolverBase::viewKeyStruct + { + /// stress solver name + constexpr static char const * stressSolverNameString() { return "stressSolverName"; } + /// Friction law name string + constexpr static char const * frictionLawNameString() { return "frictionLawName"; } + /// Friction law name string + constexpr static char const * shearImpedanceString() { return "shearImpedance"; } + /// target slip increment + constexpr static char const * targetSlipIncrementString() { return "targetSlipIncrement"; } + }; + + virtual real64 solverStep( real64 const & time_n, + real64 const & dt, + integer const cycleNumber, + DomainPartition & domain ) override final; + + virtual real64 setNextDt( real64 const & currentDt, + DomainPartition & domain ) override final; + + real64 updateStresses( real64 const & time_n, + real64 const & dt, + const int cycleNumber, + DomainPartition & domain ) const; + + /** + * @brief save the old state + * @param subRegion + */ + void saveOldStateAndUpdateSlip( ElementSubRegionBase & subRegion, real64 const dt ) const; + + +private: + + + + virtual void postInputInitialization() override; + + + + /// pointer to stress solver + PhysicsSolverBase * m_stressSolver; + + /// stress solver name + string m_stressSolverName; + + /// shear impedance + real64 m_shearImpedance; + + /// target slip rate + real64 m_targetSlipIncrement; + + class SpringSliderParameters + { +public: + + GEOS_HOST_DEVICE + SpringSliderParameters( real64 const normalTraction, real64 const a, real64 const b, real64 const Dc ): + tauRate( 1e-4 ), + springStiffness( 0.0 ) + { + real64 const criticalStiffness = normalTraction * (b - a) / Dc; + springStiffness = 0.9 * criticalStiffness; + } + + /// Default copy constructor + SpringSliderParameters( SpringSliderParameters const & ) = default; + + /// Default move constructor + SpringSliderParameters( SpringSliderParameters && ) = default; + + /// Deleted default constructor + SpringSliderParameters() = delete; + + /// Deleted copy assignment operator + SpringSliderParameters & operator=( SpringSliderParameters const & ) = delete; + + /// Deleted move assignment operator + SpringSliderParameters & operator=( SpringSliderParameters && ) = delete; + + real64 tauRate; + + real64 springStiffness; + }; +}; + +} /* namespace geos */ + +#endif /* GEOS_PHYSICSSOLVERS_INDUCED_QUASIDYNAMICEQ_HPP */ diff --git a/src/coreComponents/physicsSolvers/inducedSeismicity/QuasiDynamicEQRK32.cpp b/src/coreComponents/physicsSolvers/inducedSeismicity/QuasiDynamicEQRK32.cpp new file mode 100644 index 00000000000..28ff8f5ff14 --- /dev/null +++ b/src/coreComponents/physicsSolvers/inducedSeismicity/QuasiDynamicEQRK32.cpp @@ -0,0 +1,478 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file QuasiDynamicEQRK32.cpp + */ + +#include "QuasiDynamicEQRK32.hpp" + +#include "dataRepository/InputFlags.hpp" +#include "mesh/DomainPartition.hpp" +#include "kernels/RateAndStateKernels.hpp" +#include "rateAndStateFields.hpp" +#include "physicsSolvers/contact/ContactFields.hpp" +#include "fieldSpecification/FieldSpecificationManager.hpp" + +namespace geos +{ + +using namespace dataRepository; +using namespace fields; +using namespace constitutive; +using namespace rateAndStateKernels; + +QuasiDynamicEQRK32::QuasiDynamicEQRK32( const string & name, + Group * const parent ): + PhysicsSolverBase( name, parent ), + m_stressSolver( nullptr ), + m_stressSolverName( "SpringSlider" ), + m_shearImpedance( 0.0 ), + m_butcherTable( BogackiShampine32Table()), // TODO: The butcher table should be specified in the XML input. + m_successfulStep( false ), + m_controller( PIDController( { 1.0/18.0, 1.0/9.0, 1.0/18.0 }, + 1.0e-6, 1.0e-6, 0.81 )) // TODO: The control parameters should be specified in the XML input +{ + this->registerWrapper( viewKeyStruct::shearImpedanceString(), &m_shearImpedance ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Shear impedance." ); + + this->registerWrapper( viewKeyStruct::stressSolverNameString(), &m_stressSolverName ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Name of solver for computing stress. If empty, the spring-slider model is run." ); +} + +void QuasiDynamicEQRK32::postInputInitialization() +{ + + // Initialize member stress solver as specified in XML input + if( !m_stressSolverName.empty() ) + { + m_stressSolver = &this->getParent().getGroup< PhysicsSolverBase >( m_stressSolverName ); + } + + PhysicsSolverBase::postInputInitialization(); +} + +QuasiDynamicEQRK32::~QuasiDynamicEQRK32() +{ + // TODO Auto-generated destructor stub +} + + +void QuasiDynamicEQRK32::registerDataOnMesh( Group & meshBodies ) +{ + PhysicsSolverBase::registerDataOnMesh( meshBodies ); + + forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + + elemManager.forElementSubRegions< SurfaceElementSubRegion >( regionNames, + [&]( localIndex const, + SurfaceElementSubRegion & subRegion ) + { + // Scalar functions on fault + subRegion.registerField< rateAndState::stateVariable >( getName() ); + subRegion.registerField< rateAndState::stateVariable_n >( getName() ); + subRegion.registerField< rateAndState::slipRate >( getName() ); + + // Tangent (2-component) functions on fault + string const labels2Comp[2] = {"tangent1", "tangent2" }; + subRegion.registerField< rateAndState::slipVelocity >( getName() ). + setDimLabels( 1, labels2Comp ).reference().resizeDimension< 1 >( 2 ); + subRegion.registerField< rateAndState::slipVelocity_n >( getName() ). + setDimLabels( 1, labels2Comp ).reference().resizeDimension< 1 >( 2 ); + subRegion.registerField< rateAndState::deltaSlip >( getName() ). + setDimLabels( 1, labels2Comp ).reference().resizeDimension< 1 >( 2 ); + subRegion.registerField< rateAndState::deltaSlip_n >( getName() ). + setDimLabels( 1, labels2Comp ).reference().resizeDimension< 1 >( 2 ); + + // Runge-Kutta stage rates and error + integer const numRKComponents = 3; + subRegion.registerField< rateAndState::rungeKuttaStageRates >( getName() ).reference().resizeDimension< 1, 2 >( m_butcherTable.numStages, numRKComponents ); + subRegion.registerField< rateAndState::error >( getName() ).reference().resizeDimension< 1 >( numRKComponents ); + + + if( !subRegion.hasWrapper( contact::dispJump::key() )) + { + // 3-component functions on fault + string const labels3Comp[3] = { "normal", "tangent1", "tangent2" }; + subRegion.registerField< contact::dispJump >( getName() ). + setDimLabels( 1, labels3Comp ). + reference().resizeDimension< 1 >( 3 ); + subRegion.registerField< contact::dispJump_n >( getName() ). + setDimLabels( 1, labels3Comp ). + reference().resizeDimension< 1 >( 3 ); + subRegion.registerField< contact::traction >( getName() ). + setDimLabels( 1, labels3Comp ). + reference().resizeDimension< 1 >( 3 ); + subRegion.registerField< contact::traction_n >( getName() ). + setDimLabels( 1, labels3Comp ). + reference().resizeDimension< 1 >( 3 ); + + subRegion.registerWrapper< string >( viewKeyStruct::frictionLawNameString() ). + setPlotLevel( PlotLevel::NOPLOT ). + setRestartFlags( RestartFlags::NO_WRITE ). + setSizedFromParent( 0 ); + + string & frictionLawName = subRegion.getReference< string >( viewKeyStruct::frictionLawNameString() ); + frictionLawName = PhysicsSolverBase::getConstitutiveName< FrictionBase >( subRegion ); + GEOS_ERROR_IF( frictionLawName.empty(), GEOS_FMT( "{}: FrictionBase model not found on subregion {}", + getDataContext(), subRegion.getDataContext() ) ); + } + } ); + } ); +} + +real64 QuasiDynamicEQRK32::solverStep( real64 const & time_n, + real64 const & dt, + int const cycleNumber, + DomainPartition & domain ) +{ + if( cycleNumber == 0 ) + { + /// Apply initial conditions to the Fault + FieldSpecificationManager & fieldSpecificationManager = FieldSpecificationManager::getInstance(); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + + { + fieldSpecificationManager.applyInitialConditions( mesh ); + + } ); + saveState( domain ); + } + + real64 dtAdaptive = dt; + + GEOS_LOG_LEVEL_RANK_0( 1, "Begin adaptive time step" ); + while( true ) // Adaptive time step loop. Performs a Runge-Kutta time stepping with error control on state and slip + { + real64 dtStress; GEOS_UNUSED_VAR( dtStress ); + + // Initial Runge-Kutta stage + stepRateStateODEInitialSubstage( dtAdaptive, domain ); + real64 dtStage = m_butcherTable.c[1]*dtAdaptive; + dtStress = updateStresses( time_n, dtStage, cycleNumber, domain ); + updateSlipVelocity( time_n, dtStage, domain ); + + // Remaining stages + for( integer stageIndex = 1; stageIndex < m_butcherTable.numStages-1; stageIndex++ ) + { + stepRateStateODESubstage( stageIndex, dtAdaptive, domain ); + dtStage = m_butcherTable.c[stageIndex+1]*dtAdaptive; + dtStress = updateStresses( time_n, dtStage, cycleNumber, domain ); + updateSlipVelocity( time_n, dtStage, domain ); + } + + stepRateStateODEAndComputeError( dtAdaptive, domain ); + // Update timestep based on the time step error + real64 const dtNext = setNextDt( dtAdaptive, domain ); + if( m_successfulStep ) // set in setNextDt + { + // Compute stresses, and slip velocity and save results at updated time, + if( !m_butcherTable.FSAL ) + { + dtStress = updateStresses( time_n, dtAdaptive, cycleNumber, domain ); + updateSlipVelocity( time_n, dtAdaptive, domain ); + } + saveState( domain ); + // update the time step and exit the adaptive time step loop + dtAdaptive = dtNext; + break; + } + else + { + // Retry with updated time step + dtAdaptive = dtNext; + } + } + // return time step size achieved by stress solver + return dtAdaptive; +} + +void QuasiDynamicEQRK32::stepRateStateODEInitialSubstage( real64 const dt, DomainPartition & domain ) const +{ + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + + { + mesh.getElemManager().forElementSubRegions< SurfaceElementSubRegion >( regionNames, + [&]( localIndex const, + SurfaceElementSubRegion & subRegion ) + { + + string const & fricitonLawName = subRegion.template getReference< string >( viewKeyStruct::frictionLawNameString() ); + RateAndStateFriction const & frictionLaw = getConstitutiveModel< RateAndStateFriction >( subRegion, fricitonLawName ); + rateAndStateKernels::EmbeddedRungeKuttaKernel rkKernel( subRegion, frictionLaw, m_butcherTable ); + arrayView3d< real64 > const rkStageRates = subRegion.getField< rateAndState::rungeKuttaStageRates >(); + + if( m_butcherTable.FSAL && m_successfulStep ) + { + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + rkKernel.updateStageRatesFSAL( k ); + rkKernel.updateStageValues( k, 1, dt ); + } ); + } + else + { + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + rkKernel.initialize( k ); + rkKernel.updateStageRates( k, 0 ); + rkKernel.updateStageValues( k, 1, dt ); + } ); + } + } ); + } ); +} + +void QuasiDynamicEQRK32::stepRateStateODESubstage( integer const stageIndex, + real64 const dt, + DomainPartition & domain ) const +{ + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + + { + mesh.getElemManager().forElementSubRegions< SurfaceElementSubRegion >( regionNames, + [&]( localIndex const, + SurfaceElementSubRegion & subRegion ) + { + + string const & fricitonLawName = subRegion.template getReference< string >( viewKeyStruct::frictionLawNameString() ); + RateAndStateFriction const & frictionLaw = getConstitutiveModel< RateAndStateFriction >( subRegion, fricitonLawName ); + rateAndStateKernels::EmbeddedRungeKuttaKernel rkKernel( subRegion, frictionLaw, m_butcherTable ); + arrayView3d< real64 > const rkStageRates = subRegion.getField< rateAndState::rungeKuttaStageRates >(); + + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + rkKernel.updateStageRates( k, stageIndex ); + rkKernel.updateStageValues( k, stageIndex+1, dt ); + } ); + } ); + } ); +} + +void QuasiDynamicEQRK32::stepRateStateODEAndComputeError( real64 const dt, DomainPartition & domain ) const +{ + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + + { + mesh.getElemManager().forElementSubRegions< SurfaceElementSubRegion >( regionNames, + [&]( localIndex const, + SurfaceElementSubRegion & subRegion ) + { + + string const & fricitonLawName = subRegion.template getReference< string >( viewKeyStruct::frictionLawNameString() ); + RateAndStateFriction const & frictionLaw = getConstitutiveModel< RateAndStateFriction >( subRegion, fricitonLawName ); + rateAndStateKernels::EmbeddedRungeKuttaKernel rkKernel( subRegion, frictionLaw, m_butcherTable ); + arrayView3d< real64 > const rkStageRates = subRegion.getField< rateAndState::rungeKuttaStageRates >(); + if( m_butcherTable.FSAL ) + { + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + // Perform last stage rate update + rkKernel.updateStageRates( k, m_butcherTable.numStages-1 ); + // Update solution to final time and compute errors + rkKernel.updateSolutionAndLocalErrorFSAL( k, dt, m_controller.absTol, m_controller.relTol ); + } ); + } + else + { + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + // Perform last stage rate update + rkKernel.updateStageRates( k, m_butcherTable.numStages-1 ); + // Update solution to final time and compute errors + rkKernel.updateSolutionAndLocalError( k, dt, m_controller.absTol, m_controller.relTol ); + } ); + } + } ); + } ); +} + +real64 QuasiDynamicEQRK32::updateStresses( real64 const & time_n, + real64 const & dt, + const int cycleNumber, + DomainPartition & domain ) const +{ + GEOS_LOG_LEVEL_RANK_0( 1, "Stress solver" ); + // Call member variable stress solver to update the stress state + if( m_stressSolver ) + { + // 1. Solve the momentum balance + real64 const dtStress = m_stressSolver->solverStep( time_n, dt, cycleNumber, domain ); + + return dtStress; + } + else + { + // Spring-slider shear traction computation + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + + { + mesh.getElemManager().forElementSubRegions< SurfaceElementSubRegion >( regionNames, + [&]( localIndex const, + SurfaceElementSubRegion & subRegion ) + { + + arrayView2d< real64 const > const deltaSlip = subRegion.getField< rateAndState::deltaSlip >(); + arrayView2d< real64 > const traction = subRegion.getField< fields::contact::traction >(); + arrayView2d< real64 const > const traction_n = subRegion.getField< fields::contact::traction_n >(); + + string const & fricitonLawName = subRegion.template getReference< string >( viewKeyStruct::frictionLawNameString() ); + RateAndStateFriction const & frictionLaw = getConstitutiveModel< RateAndStateFriction >( subRegion, fricitonLawName ); + + RateAndStateFriction::KernelWrapper frictionKernelWrapper = frictionLaw.createKernelUpdates(); + + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + SpringSliderParameters springSliderParameters = SpringSliderParameters( traction[k][0], + frictionKernelWrapper.getACoefficient( k ), + frictionKernelWrapper.getBCoefficient( k ), + frictionKernelWrapper.getDcCoefficient( k ) ); + + + traction[k][1] = traction_n[k][1] + springSliderParameters.tauRate * dt + - springSliderParameters.springStiffness * deltaSlip[k][0]; + traction[k][2] = traction_n[k][2] + springSliderParameters.tauRate * dt + - springSliderParameters.springStiffness * deltaSlip[k][1]; + } ); + } ); + } ); + return dt; + } +} + +void QuasiDynamicEQRK32::updateSlipVelocity( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) const +{ + GEOS_LOG_LEVEL_RANK_0( 1, "Rate and State solver" ); + integer const maxIterNewton = m_nonlinearSolverParameters.m_maxIterNewton; + real64 const newtonTol = m_nonlinearSolverParameters.m_newtonTol; + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + + { + mesh.getElemManager().forElementSubRegions< SurfaceElementSubRegion >( regionNames, + [&]( localIndex const, + SurfaceElementSubRegion & subRegion ) + { + // solve rate and state equations. + rateAndStateKernels::createAndLaunch< rateAndStateKernels::ExplicitRateAndStateKernel, parallelDevicePolicy<> >( subRegion, viewKeyStruct::frictionLawNameString(), m_shearImpedance, + maxIterNewton, newtonTol, time_n, dt ); + } ); + } ); +} + +void QuasiDynamicEQRK32::saveState( DomainPartition & domain ) const +{ + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + + { + mesh.getElemManager().forElementSubRegions< SurfaceElementSubRegion >( regionNames, + [&]( localIndex const, + SurfaceElementSubRegion & subRegion ) + { + arrayView1d< real64 const > const stateVariable = subRegion.getField< rateAndState::stateVariable >(); + arrayView2d< real64 const > const slipVelocity = subRegion.getField< rateAndState::slipVelocity >(); + arrayView2d< real64 const > const deltaSlip = subRegion.getField< rateAndState::deltaSlip >(); + arrayView2d< real64 const > const dispJump = subRegion.getField< contact::dispJump >(); + arrayView2d< real64 const > const traction = subRegion.getField< contact::traction >(); + + arrayView1d< real64 > const stateVariable_n = subRegion.getField< rateAndState::stateVariable_n >(); + arrayView2d< real64 > const slipVelocity_n = subRegion.getField< rateAndState::slipVelocity_n >(); + arrayView2d< real64 > const deltaSlip_n = subRegion.getField< rateAndState::deltaSlip >(); + arrayView2d< real64 > const dispJump_n = subRegion.getField< contact::dispJump_n >(); + arrayView2d< real64 > const traction_n = subRegion.getField< contact::traction_n >(); + + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + stateVariable_n[k] = stateVariable[k]; + LvArray::tensorOps::copy< 2 >( deltaSlip_n[k], deltaSlip[k] ); + LvArray::tensorOps::copy< 2 >( slipVelocity_n[k], slipVelocity[k] ); + LvArray::tensorOps::copy< 3 >( dispJump_n[k], dispJump[k] ); + LvArray::tensorOps::copy< 3 >( traction_n[k], traction[k] ); + } ); + } ); + } ); +} + +real64 QuasiDynamicEQRK32::setNextDt( real64 const & currentDt, DomainPartition & domain ) +{ + + // Spring-slider shear traction computation + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) + + { + mesh.getElemManager().forElementSubRegions< SurfaceElementSubRegion >( regionNames, + [&]( localIndex const, + SurfaceElementSubRegion const & subRegion ) + { + arrayView2d< real64 const > const error = subRegion.getField< rateAndState::error >(); + + RAJA::ReduceSum< parallelDeviceReduce, real64 > scaledl2ErrorSquared( 0.0 ); + integer const N = subRegion.size(); + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + scaledl2ErrorSquared += LvArray::tensorOps::l2NormSquared< 3 >( error[k] ); + } ); + m_controller.errors[0] = LvArray::math::sqrt( MpiWrapper::sum( scaledl2ErrorSquared.get() / (3.0*N) )); + } ); + } ); + + // Compute update factor to currentDt using PID error controller + limiter + real64 const dtFactor = m_controller.computeUpdateFactor( m_butcherTable.algHighOrder, m_butcherTable.algLowOrder ); + real64 const nextDt = dtFactor*currentDt; + // Check if step was acceptable + m_successfulStep = (dtFactor >= m_controller.acceptSafety) ? true : false; + if( m_successfulStep ) + { + m_controller.errors[2] = m_controller.errors[1]; + m_controller.errors[1] = m_controller.errors[0]; + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "Adaptive time step successful. The next dt will be {:.2e} s", nextDt )); + } + else + { + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "Adaptive time step failed. The next dt will be {:.2e} s", nextDt )); + } + + return nextDt; +} + +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, QuasiDynamicEQRK32, string const &, dataRepository::Group * const ) + +} // namespace geos diff --git a/src/coreComponents/physicsSolvers/inducedSeismicity/QuasiDynamicEQRK32.hpp b/src/coreComponents/physicsSolvers/inducedSeismicity/QuasiDynamicEQRK32.hpp new file mode 100644 index 00000000000..bcb3dd8a72a --- /dev/null +++ b/src/coreComponents/physicsSolvers/inducedSeismicity/QuasiDynamicEQRK32.hpp @@ -0,0 +1,235 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#ifndef GEOS_PHYSICSSOLVERS_INDUCED_QUASIDYNAMICEQRK32_HPP +#define GEOS_PHYSICSSOLVERS_INDUCED_QUASIDYNAMICEQRK32_HPP + +#include "physicsSolvers/PhysicsSolverBase.hpp" +#include "kernels/RateAndStateKernels.hpp" + +namespace geos +{ + +class QuasiDynamicEQRK32 : public PhysicsSolverBase +{ +public: + /// The default nullary constructor is disabled to avoid compiler auto-generation: + QuasiDynamicEQRK32() = delete; + + /// The constructor needs a user-defined "name" and a parent Group (to place this instance in the tree structure of classes) + QuasiDynamicEQRK32( const string & name, + Group * const parent ); + + /// Destructor + virtual ~QuasiDynamicEQRK32() override; + + static string catalogName() { return "QuasiDynamicEQRK32"; } + + /** + * @return Get the final class Catalog name + */ + virtual string getCatalogName() const override { return catalogName(); } + + /// This method ties properties with their supporting mesh + virtual void registerDataOnMesh( Group & meshBodies ) override; + + struct viewKeyStruct : public PhysicsSolverBase::viewKeyStruct + { + /// stress solver name + constexpr static char const * stressSolverNameString() { return "stressSolverName"; } + /// Friction law name string + constexpr static char const * frictionLawNameString() { return "frictionLawName"; } + /// Friction law name string + constexpr static char const * shearImpedanceString() { return "shearImpedance"; } + /// target slip increment + constexpr static char const * timeStepTol() { return "timeStepTol"; } + }; + + virtual real64 solverStep( real64 const & time_n, + real64 const & dt, + integer const cycleNumber, + DomainPartition & domain ) override final; + + + virtual real64 setNextDt( real64 const & currentDt, + DomainPartition & domain ) override final; + + /** + * @brief Computes stage rates for the initial Runge-Kutta substage and updates slip and state + * @param dt + * @param domain + */ + void stepRateStateODEInitialSubstage( real64 const dt, DomainPartition & domain ) const; + + /** + * @brief Computes stage rates at the Runge-Kutta substage specified by stageIndex and updates slip and state + * @param stageIndex + * @param dt + * @param domain + */ + void stepRateStateODESubstage( integer const stageIndex, + real64 const dt, + DomainPartition & domain ) const; + + /** + * @brief Updates slip and state to t + dt and approximates the error + * @param dt + * @param domain + */ + void stepRateStateODEAndComputeError( real64 const dt, DomainPartition & domain ) const; + + real64 updateStresses( real64 const & time_n, + real64 const & dt, + const int cycleNumber, + DomainPartition & domain ) const; + + /** + * @brief Updates rate-and-state slip velocity + * @param domain + */ + void updateSlipVelocity( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) const; + + /** + * @brief save the current state + * @param domain + */ + void saveState( DomainPartition & domain ) const; + +private: + + virtual void postInputInitialization() override; + + + /// pointer to stress solver + PhysicsSolverBase * m_stressSolver; + + /// stress solver name + string m_stressSolverName; + + /// shear impedance + real64 m_shearImpedance; + + /// Runge-Kutta Butcher table (specifies the embedded RK method) + // TODO: The specific type should not be hardcoded! + // Should be possible to change RK-method based on the table. + rateAndStateKernels::BogackiShampine32Table m_butcherTable; + + bool m_successfulStep; // Flag indicating if the adative time step was accepted + + /** + * @brief Proportional-integral-derivative controller used for updating time step + * based error estimate in the current and previous time steps. + */ + class PIDController + { +public: + + GEOS_HOST_DEVICE + PIDController( std::array< const real64, 3 > const & cparams, + const real64 atol, + const real64 rtol, + const real64 safety ): + controlParameters{ cparams }, + absTol( atol ), + relTol( rtol ), + acceptSafety( safety ), + errors{ {0.0, 0.0, 0.0} } + {} + + /// Default copy constructor + PIDController( PIDController const & ) = default; + + /// Default move constructor + PIDController( PIDController && ) = default; + + /// Deleted default constructor + PIDController() = delete; + + /// Deleted copy assignment operator + PIDController & operator=( PIDController const & ) = delete; + + /// Deleted move assignment operator + PIDController & operator=( PIDController && ) = delete; + + /// Parameters for the PID error controller + const std::array< const real64, 3 > controlParameters; // Controller parameters + + real64 const absTol; // absolut tolerence + + real64 const relTol; // relative tolerence + + real64 const acceptSafety; // Acceptance safety + + std::array< real64, 3 > errors; // Errors for current and two previous updates + // stored as [n+1, n, n-1] + + real64 computeUpdateFactor( integer const algHighOrder, integer const algLowOrder ) + { + // PID error controller + limiter + real64 const k = LvArray::math::min( algHighOrder, algLowOrder ) + 1.0; + real64 const eps0 = 1.0/(errors[0] + std::numeric_limits< real64 >::epsilon()); // n + 1 + real64 const eps1 = 1.0/(errors[1] + std::numeric_limits< real64 >::epsilon()); // n + real64 const eps2 = 1.0/(errors[2] + std::numeric_limits< real64 >::epsilon()); // n-1 + // Compute update factor eps0^(beta0/k)*eps1^(beta1/k)*eps2^(beta2/k) where + // beta0 - beta2 are the control parameters. Also apply limiter to smoothen changes. + // Limiter is 1.0 + atan(x - 1.0). Here use atan(x) = atan2(x, 1.0). + return 1.0 + LvArray::math::atan2( pow( eps0, controlParameters[0] / k ) * + pow( eps1, controlParameters[1] / k ) * + pow( eps2, controlParameters[2] / k ) - 1.0, 1.0 ); + } + }; + + PIDController m_controller; + + + class SpringSliderParameters + { +public: + + GEOS_HOST_DEVICE + SpringSliderParameters( real64 const normalTraction, real64 const a, real64 const b, real64 const Dc ): + tauRate( 1e-4 ), + springStiffness( 0.0 ) + { + real64 const criticalStiffness = normalTraction * (b - a) / Dc; + springStiffness = 0.9 * criticalStiffness; + } + + /// Default copy constructor + SpringSliderParameters( SpringSliderParameters const & ) = default; + + /// Default move constructor + SpringSliderParameters( SpringSliderParameters && ) = default; + + /// Deleted default constructor + SpringSliderParameters() = delete; + + /// Deleted copy assignment operator + SpringSliderParameters & operator=( SpringSliderParameters const & ) = delete; + + /// Deleted move assignment operator + SpringSliderParameters & operator=( SpringSliderParameters && ) = delete; + + real64 tauRate; + + real64 springStiffness; + }; +}; + +} /* namespace geos */ + +#endif /* GEOS_PHYSICSSOLVERS_INDUCED_QUASIDYNAMICEQRK32_HPP */ diff --git a/src/coreComponents/physicsSolvers/inducedSeismicity/SeismicityRate.cpp b/src/coreComponents/physicsSolvers/inducedSeismicity/SeismicityRate.cpp new file mode 100644 index 00000000000..8409180dfba --- /dev/null +++ b/src/coreComponents/physicsSolvers/inducedSeismicity/SeismicityRate.cpp @@ -0,0 +1,421 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SeismicityRate.cpp + */ + +#include "SeismicityRate.hpp" + +#include "dataRepository/InputFlags.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mesh/DomainPartition.hpp" +#include "mesh/mpiCommunications/CommunicationTools.hpp" +#include "physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp" +#include "kernels/SeismicityRateKernels.hpp" +#include "physicsSolvers/inducedSeismicity/inducedSeismicityFields.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" + +#include "fieldSpecification/FieldSpecificationManager.hpp" + + +namespace geos +{ + +using namespace dataRepository; +using namespace fields; +using namespace constitutive; + +SeismicityRate::SeismicityRate( const string & name, + Group * const parent ): + PhysicsSolverBase( name, parent ), + m_stressSolver( nullptr ) +{ + this->registerWrapper( viewKeyStruct::directEffectString(), &m_directEffect ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Rate-and-state friction direct effect parameter." ); + + this->registerWrapper( viewKeyStruct::backgroundStressingRateString(), &m_backgroundStressingRate ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Background stressing rate (Pa/s)." ); + + this->registerWrapper( viewKeyStruct::stressSolverNameString(), &m_stressSolverName ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Name of solver for computing stress" ); + + this->registerWrapper( viewKeyStruct::faultNormalDirectionString(), &m_faultNormalDirection ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Fault normal direction" ); + + this->registerWrapper( viewKeyStruct::faultShearDirectionString(), &m_faultShearDirection ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Fault shear direction" ); + + this->getWrapper< string >( viewKeyStruct::discretizationString() ). + setInputFlag( InputFlags::FALSE ); +} + +void SeismicityRate::postInputInitialization() +{ + // Check orthogonality of user-specified faults + if( std::abs( LvArray::tensorOps::AiBi< 3 >( m_faultNormalDirection, m_faultShearDirection )) > 1e-8 ) + { + GEOS_ERROR( "Fault normal and fault shear directions must be orthogonal" ); + } + // If user has specified faults, normalize them to be unit vectors + else if( LvArray::tensorOps::l2Norm< 3 >( m_faultNormalDirection ) > 1e-8 ) + { + LvArray::tensorOps::normalize< 3 >( m_faultNormalDirection ); + LvArray::tensorOps::normalize< 3 >( m_faultShearDirection ); + } + + // Initialize member stress solver as specified in XML input + if( !m_stressSolverName.empty() ) + { + m_stressSolver = &this->getParent().getGroup< PhysicsSolverBase >( m_stressSolverName ); + } + + PhysicsSolverBase::postInputInitialization(); +} + +SeismicityRate::~SeismicityRate() +{ + // TODO Auto-generated destructor stub +} + +void SeismicityRate::registerDataOnMesh( Group & meshBodies ) +{ + PhysicsSolverBase::registerDataOnMesh( meshBodies ); + + forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + + elemManager.forElementSubRegions< ElementSubRegionBase >( regionNames, + [&]( localIndex const, + ElementSubRegionBase & subRegion ) + { + subRegion.registerField< inducedSeismicity::initialProjectedNormalTraction >( getName() ); + + subRegion.registerField< inducedSeismicity::initialProjectedShearTraction >( getName() ); + + subRegion.registerField< inducedSeismicity::projectedNormalTraction >( getName() ); + + subRegion.registerField< inducedSeismicity::projectedNormalTraction_n >( getName() ); + + subRegion.registerField< inducedSeismicity::projectedShearTraction >( getName() ); + + subRegion.registerField< inducedSeismicity::projectedShearTraction_n >( getName() ); + + subRegion.registerField< inducedSeismicity::seismicityRate >( getName() ); + + subRegion.registerField< inducedSeismicity::logDenom >( getName() ); + } ); + } ); +} + +void SeismicityRate::updateFaultTraction( ElementSubRegionBase & subRegion ) const +{ + // Retrieve field variables + arrayView1d< real64 > const sig = subRegion.getField< inducedSeismicity::projectedNormalTraction >(); + arrayView1d< real64 > const tau = subRegion.getField< inducedSeismicity::projectedShearTraction >(); + + // Retrieve stress state computed by m_stressSolver, called in solverStep + string const & solidModelName = subRegion.getReference< string >( SolidMechanicsLagrangianFEM::viewKeyStruct::solidMaterialNamesString()); + SolidBase const & solidModel = getConstitutiveModel< SolidBase >( subRegion, solidModelName ); + arrayView3d< real64 const, solid::STRESS_USD > const stress = solidModel.getStress(); + + // Construct Voigt notation projection tensor (dyadic product of fault normal and shear vectors) + // for when multiplying in inner dot product with symmetric stress tensor + real64 faultNormalProjectionTensor[6]{}; + real64 faultShearProjectionTensor[6]{}; + constructFaultStressProjectionTensors( faultNormalProjectionTensor, faultShearProjectionTensor ); + + // loop over all elements and compute unweighted average across all nodes + // as average stress state acting over the cell ceneter + // TODO: APPLY WEIGHTS TO AVERAGE TO ACCOUNT FOR ELEMENT SHAPE + forAll< parallelDevicePolicy<> >( sig.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + // Compute average stress state + real64 meanStress[ 6 ]{}; + for( int q = 0; q < stress.size( 1 ); q++ ) + { + LvArray::tensorOps::add< 6 >( meanStress, stress[k][q] ); + } + LvArray::tensorOps::scale< 6 >( meanStress, 1./stress.size( 1 )); + + // Project average stress state to fault + sig[k] = LvArray::tensorOps::AiBi< 6 >( meanStress, faultNormalProjectionTensor ); + tau[k] = LvArray::tensorOps::AiBi< 6 >( meanStress, faultShearProjectionTensor ); + } ); + + // For poroelastic models, we must calculate the total stress before computing the effective stresses + // on the fault. This requires retrieving both the pressure field and the Biot coefficient. We first check + // to see if a flow solver exists, retrive the pressure field, then pass the porous model through the lambda + // cast to access the Biot coefficient. Finally, effective stresses on the fault are calculated. + if( subRegion.hasWrapper( FlowSolverBase::viewKeyStruct::fluidNamesString() ) ) + { + arrayView1d< real64 const > const pres = subRegion.getField< flow::pressure >(); + + string const & porousSolidModelName = subRegion.getReference< string >( FlowSolverBase::viewKeyStruct::solidNamesString() ); + CoupledSolidBase & porousSolid = getConstitutiveModel< CoupledSolidBase >( subRegion, porousSolidModelName ); + constitutive::ConstitutivePassThru< CoupledSolidBase >::execute( porousSolid, [&] ( auto & castedPorousSolid ) + { + // Initialize biotCoefficient as const arrayView before passing it through the lambda cast + arrayView1d< real64 const > const biotCoefficient = castedPorousSolid.getBiotCoefficient(); + + // To calculate the action of the total stress on the fault from our previous calculations, + // we need to project the action of the pore pressure on the stress tensor onto the fault + computeTotalStressOnFault( biotCoefficient, + pres, + faultNormalProjectionTensor, + faultShearProjectionTensor, + sig, + tau ); + } ); + } +} + +void SeismicityRate::computeTotalStressOnFault( arrayView1d< real64 const > const & biotCoefficient, + arrayView1d< real64 const > const & pres, + real64 const (&faultNormalProjectionTensor)[6], + real64 const (&faultShearProjectionTensor)[6], + arrayView1d< real64 > const & sig, + arrayView1d< real64 > const & tau ) const +{ + // To calculate the action of the total stress on the fault from our previous calculations, + // we need to project the action of the pore pressure on the stress tensor onto the fault + forAll< parallelDevicePolicy<> >( sig.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + // Form pressure as tensor + real64 pressureTensor[ 6 ]{}; + LvArray::tensorOps::symAddIdentity< 3 >( pressureTensor, -biotCoefficient[k]*pres[k] ); + + // Project pressure tensor onto fault orientations + real64 const pressureOnFaultNormal = LvArray::tensorOps::AiBi< 6 >( pressureTensor, faultNormalProjectionTensor ); + real64 const pressureOnFaultShear = LvArray::tensorOps::AiBi< 6 >( pressureTensor, faultShearProjectionTensor ); + + // Calculate total stress on the faults + sig[k] += pressureOnFaultNormal; + tau[k] += pressureOnFaultShear; + } ); + +} + +void SeismicityRate::initializeFaultTraction( real64 const time_n, integer const cycleNumber, DomainPartition & domain ) const +{ + // Only call initialization step before stress solver has been called for first time step + if( cycleNumber == 0 ) + { + // Call solverStep of stress solver with dt=0 to initialize stresses in the matrix + + updateStresses( time_n, 0.0, cycleNumber, domain ); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + + { + mesh.getElemManager().forElementSubRegions( regionNames, + [&]( localIndex const, + ElementSubRegionBase & subRegion ) + { + + saveOldState( subRegion ); + + // Retrieve field variables + arrayView1d< real64 const > const sig = subRegion.getField< inducedSeismicity::projectedNormalTraction >(); + arrayView1d< real64 const > const tau = subRegion.getField< inducedSeismicity::projectedShearTraction >(); + + arrayView1d< real64 > const sig_i = subRegion.getField< inducedSeismicity::initialProjectedNormalTraction >(); + arrayView1d< real64 > const tau_i = subRegion.getField< inducedSeismicity::initialProjectedShearTraction >(); + + forAll< parallelDevicePolicy<> >( sig.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + // Set initial stress conditions on faults + sig_i[k] = sig[k]; + tau_i[k] = tau[k]; + } ); + } ); + } ); + } +} + +void SeismicityRate::constructFaultStressProjectionTensors( real64 (& faultNormalProjectionTensor)[6], + real64 (& faultShearProjectionTensor)[6] ) const +{ + faultNormalProjectionTensor[0] = m_faultNormalDirection[0]*m_faultNormalDirection[0]; + faultNormalProjectionTensor[1] = m_faultNormalDirection[1]*m_faultNormalDirection[1]; + faultNormalProjectionTensor[2] = m_faultNormalDirection[2]*m_faultNormalDirection[2]; + faultNormalProjectionTensor[3] = 2*m_faultNormalDirection[1]*m_faultNormalDirection[2]; + faultNormalProjectionTensor[4] = 2*m_faultNormalDirection[0]*m_faultNormalDirection[2]; + faultNormalProjectionTensor[5] = 2*m_faultNormalDirection[0]*m_faultNormalDirection[1]; + + faultShearProjectionTensor[0] = m_faultShearDirection[0]*m_faultNormalDirection[0]; + faultShearProjectionTensor[1] = m_faultShearDirection[1]*m_faultNormalDirection[1]; + faultShearProjectionTensor[2] = m_faultShearDirection[2]*m_faultNormalDirection[2]; + faultShearProjectionTensor[3] = m_faultShearDirection[1]*m_faultNormalDirection[2] + m_faultShearDirection[2]*m_faultNormalDirection[1]; + faultShearProjectionTensor[4] = m_faultShearDirection[0]*m_faultNormalDirection[2] + m_faultShearDirection[2]*m_faultNormalDirection[0]; + faultShearProjectionTensor[5] = m_faultShearDirection[0]*m_faultNormalDirection[1] + m_faultShearDirection[1]*m_faultNormalDirection[0]; +} + +real64 SeismicityRate::solverStep( real64 const & time_n, + real64 const & dt, + const int cycleNumber, + DomainPartition & domain ) +{ + // Save initial stress state on pre-defined fault orientations to field variables + if( cycleNumber == 0 ) + { + initializeFaultTraction( time_n, cycleNumber, domain ); + } + + real64 const dtStress = updateStresses( time_n, dt, cycleNumber, domain ); + + // Loop over subRegions to solve for seismicity rate + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + + { + mesh.getElemManager().forElementSubRegions( regionNames, + [&]( localIndex const, + ElementSubRegionBase & subRegion ) + { + // solve for the seismicity rate given new stresses on faults + integralSolverStep( time_n, dtStress, subRegion ); + + // save old state + saveOldState( subRegion ); + } ); + } ); + + // return time step size achieved by stress solver + return dtStress; +} + +real64 SeismicityRate::updateStresses( real64 const & time_n, + real64 const & dt, + const int cycleNumber, + DomainPartition & domain ) const +{ + // Call member variable stress solver to update the stress state + if( m_stressSolver ) + { + + // 1. Solve the momentum balance + real64 const dtStress = m_stressSolver->solverStep( time_n, dt, cycleNumber, domain ); + + // 2. Loop over subRegions to update stress on faults + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + + { + mesh.getElemManager().forElementSubRegions( regionNames, + [&]( localIndex const, + ElementSubRegionBase & subRegion ) + { + updateFaultTraction( subRegion ); + } ); + } ); + return dtStress; + } + else + { + char const bcLogMessage[] = + "SeismicityRate {}: at time {}s, " + "the <{}> boundary condition '{}' is applied to the element set '{}' in subRegion '{}'. " + "\nThe scale of this boundary condition is {} and multiplies the value of the provided function (if any). " + "\nThe total number of target elements (including ghost elements) is {}. " + "\nNote that if this number is equal to zero for all subRegions, the boundary condition will not be applied on this element set."; + + forDiscretizationOnMeshTargets ( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + { + + FieldSpecificationManager & fsManager = FieldSpecificationManager::getInstance(); + + std::vector< string > const keys = { inducedSeismicity::projectedNormalTraction::key(), + inducedSeismicity::projectedShearTraction::key() }; + + for( auto const & key : keys ) + { + fsManager.apply< ElementSubRegionBase >( time_n + dt, + mesh, + key, + [&]( FieldSpecificationBase const & fs, + string const & setName, + SortedArrayView< localIndex const > const & lset, + ElementSubRegionBase & subRegion, + string const & ) + { + if( fs.getLogLevel() >= 1 ) + { + globalIndex const numTargetElems = MpiWrapper::sum< globalIndex >( lset.size() ); + GEOS_LOG_RANK_0( GEOS_FMT( bcLogMessage, + this->getName(), time_n+dt, FieldSpecificationBase::catalogName(), + fs.getName(), setName, subRegion.getName(), fs.getScale(), numTargetElems ) ); + } + + // Specify the bc value of the field + fs.applyFieldValue< FieldSpecificationEqual, + parallelDevicePolicy<> >( lset, + time_n + dt, + subRegion, + key ); + } ); + } + } ); + } + return dt; +} + +void SeismicityRate::saveOldState( ElementSubRegionBase & subRegion ) const +{ + // Retrieve field variables + arrayView1d< real64 > const sig = subRegion.getField< inducedSeismicity::projectedNormalTraction >(); + arrayView1d< real64 > const sig_n = subRegion.getField< inducedSeismicity::projectedNormalTraction_n >(); + arrayView1d< real64 > const tau = subRegion.getField< inducedSeismicity::projectedShearTraction >(); + arrayView1d< real64 > const tau_n = subRegion.getField< inducedSeismicity::projectedShearTraction_n >(); + + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + // update projected stresses from previou step + sig_n[k] = sig[k]; + tau_n[k] = tau[k]; + } ); +} + +// Solve integral solution to ODE +void SeismicityRate::integralSolverStep( real64 const & time_n, + real64 const & dt, + ElementSubRegionBase & subRegion ) +{ + if( subRegion.hasWrapper( FlowSolverBase::viewKeyStruct::fluidNamesString() ) ) + { + seismicityRateKernels::createAndLaunch< parallelDevicePolicy<>, true >( subRegion, time_n, dt, m_directEffect, m_backgroundStressingRate ); + } + else + { + seismicityRateKernels::createAndLaunch< parallelDevicePolicy<>, false >( subRegion, time_n, dt, m_directEffect, m_backgroundStressingRate ); + } +} + +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SeismicityRate, string const &, dataRepository::Group * const ) +} // namespace geos diff --git a/src/coreComponents/physicsSolvers/inducedSeismicity/SeismicityRate.hpp b/src/coreComponents/physicsSolvers/inducedSeismicity/SeismicityRate.hpp new file mode 100644 index 00000000000..67cce07e74f --- /dev/null +++ b/src/coreComponents/physicsSolvers/inducedSeismicity/SeismicityRate.hpp @@ -0,0 +1,156 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#ifndef GEOS_PHYSICSSOLVERS_INDUCED_SEISMICITY_SEISMICITYRATE_HPP +#define GEOS_PHYSICSSOLVERS_INDUCED_SEISMICITY_SEISMICITYRATE_HPP + +#include "physicsSolvers/PhysicsSolverBase.hpp" + +namespace geos +{ + +class SeismicityRate : public PhysicsSolverBase +{ +public: + /// The default nullary constructor is disabled to avoid compiler auto-generation: + SeismicityRate() = delete; + + /// The constructor needs a user-defined "name" and a parent Group (to place this instance in the tree structure of classes) + SeismicityRate( const string & name, + Group * const parent ); + + /// Destructor + virtual ~SeismicityRate() override; + + static string catalogName() { return "SeismicityRate"; } + + /** + * @return Get the final class Catalog name + */ + virtual string getCatalogName() const override { return catalogName(); } + + /// This method ties properties with their supporting mesh + virtual void registerDataOnMesh( Group & meshBodies ) override; + + struct viewKeyStruct : public PhysicsSolverBase::viewKeyStruct + { + static constexpr char const * stressSolverNameString() { return "stressSolverName"; } + static constexpr char const * initialFaultNormalTractionString() { return "initialFaultNormalTraction"; } + static constexpr char const * initialFaultShearTractionString() { return "initialFaultShearTraction"; } + static constexpr char const * faultNormalDirectionString() { return "faultNormalDirection"; } + static constexpr char const * faultShearDirectionString() { return "faultShearDirection"; } + static constexpr char const * directEffectString() { return "directEffect"; } + static constexpr char const * backgroundStressingRateString() { return "backgroundStressingRate"; } + }; + + virtual real64 solverStep( real64 const & time_n, + real64 const & dt, + integer const cycleNumber, + DomainPartition & domain ) override final; + + /** + * @brief single step advance in computing the seismicity rate based on + * stress history according to closed form integral solution (Heimisson & Segall, 2018) + * to the ODE formulated by Dieterich, 1994 + * @param time_n time at previous converged step + * @param dt time step size + * @param subRegion ElementSubRegionBase to compute the solution in + */ + void integralSolverStep( real64 const & time_n, + real64 const & dt, + ElementSubRegionBase & subRegion ); + + /** + * @brief called in SolverStep after member stress solver is called to + * project the stress state to pre-defined fault orientations + * @param subRegion The ElementSubRegionBase that will have the stress information + */ + void updateFaultTraction( ElementSubRegionBase & subRegion ) const; + + /** + * @brief save the old state + * @param subRegion + */ + void saveOldState( ElementSubRegionBase & subRegion ) const; + + /** + * @brief + * @param biotCoefficient + * @param pres + * @param sig + * @param tau + */ + void computeTotalStressOnFault( arrayView1d< real64 const > const & biotCoefficient, + arrayView1d< real64 const > const & pres, + real64 const (&faultNormalProjectionTensor)[6], + real64 const (&faultShearProjectionTensor)[6], + arrayView1d< real64 > const & sig, + arrayView1d< real64 > const & tau ) const; + + /** + * @brief called in SolverStep before member stress solver is called to + * project the initial stress state to pre-defined fault orientations, + * only when cycleNumber == 0 + * @param cycleNumber current cycle number + * @param domain The DomainPartition of the problem + */ + void initializeFaultTraction( real64 const time_n, + integer const cycleNumber, + DomainPartition & domain ) const; + + +protected: + + /** + * @brief update the stresses either by asking the stressSolver or by applying b.c. + * @param time_n the current time + * @param dt the current time step + * @param cycleNumber the cycle number + * @param domain the DomainPartion group + */ + real64 updateStresses( real64 const & time_n, + real64 const & dt, + const int cycleNumber, + DomainPartition & domain ) const; + + + + void constructFaultStressProjectionTensors( real64 ( &faultNormalProjectionTensor )[6], + real64 ( &faultShearProjectionTensor )[6] ) const; + + virtual void postInputInitialization() override; + + /// pointer to stress solver + PhysicsSolverBase *m_stressSolver; + + /// stress solver name string + string m_stressSolverName; + + /// fault orientation: normal direction + R1Tensor m_faultNormalDirection; + + /// fault orientation: shear direction + R1Tensor m_faultShearDirection; + + /// direct effect coefficient + real64 m_directEffect; + + /// bacground stressing rate + real64 m_backgroundStressingRate; +}; + +} /* namespace geos */ + +#endif /* GEOS_PHYSICSSOLVERS_INDUCED_SEISMICITY_SEISMICITYRATE_HPP */ diff --git a/src/coreComponents/physicsSolvers/inducedSeismicity/inducedSeismicityFields.hpp b/src/coreComponents/physicsSolvers/inducedSeismicity/inducedSeismicityFields.hpp new file mode 100644 index 00000000000..ac9af24c68b --- /dev/null +++ b/src/coreComponents/physicsSolvers/inducedSeismicity/inducedSeismicityFields.hpp @@ -0,0 +1,104 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file inducedSeismicityFields.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_INDUCEDSEISMICITY_INDUCEDSEISMICITYFIELDS_HPP_ +#define GEOS_PHYSICSSOLVERS_INDUCEDSEISMICITY_INDUCEDSEISMICITYFIELDS_HPP_ + +#include "common/DataLayouts.hpp" +#include "mesh/MeshFields.hpp" + +namespace geos +{ + +namespace fields +{ + +namespace inducedSeismicity +{ + +DECLARE_FIELD( initialProjectedNormalTraction, + "initialProjectedNormalTraction", + array1d< real64 >, + 0, + LEVEL_0, + WRITE_AND_READ, + "Initial meanNormal stress acting on the fault" ); + +DECLARE_FIELD( projectedNormalTraction, + "projectedNormalTraction", + array1d< real64 >, + 0, + LEVEL_0, + WRITE_AND_READ, + "meanNormal stress acting on the fault" ); + +DECLARE_FIELD( projectedNormalTraction_n, + "projectedNormalTraction_n", + array1d< real64 >, + 0, + LEVEL_1, + WRITE_AND_READ, + "meanNormal stress acting on the fault at the previous converged time step" ); + +DECLARE_FIELD( initialProjectedShearTraction, + "initialProjectedShearTraction", + array1d< real64 >, + 0, + LEVEL_0, + WRITE_AND_READ, + "Initial meanShear stress acting on the fault" ); + +DECLARE_FIELD( projectedShearTraction, + "projectedShearTraction", + array1d< real64 >, + 0, + LEVEL_0, + WRITE_AND_READ, + "meanShear stress acting on the fault" ); + +DECLARE_FIELD( projectedShearTraction_n, + "projectedShearTraction_n", + array1d< real64 >, + 0, + LEVEL_1, + WRITE_AND_READ, + "meanShear stress acting on the fault at the previous converged time step" ); + +DECLARE_FIELD( seismicityRate, + "seismicityRate", + array1d< real64 >, + 1.0, + LEVEL_0, + WRITE_AND_READ, + "Seismicity rate" ); + +DECLARE_FIELD( logDenom, + "logDenom", + array1d< real64 >, + 0, + LEVEL_2, + WRITE_AND_READ, + "Log of the denominator of the integral form of the seismicity rate" ); +} + +} + +} + +#endif // GEOS_PHYSICSSOLVERS_INDUCEDSEISMICITY_INDUCEDSEISMICITYFIELDS_HPP_ diff --git a/src/coreComponents/physicsSolvers/inducedSeismicity/kernels/RateAndStateKernels.hpp b/src/coreComponents/physicsSolvers/inducedSeismicity/kernels/RateAndStateKernels.hpp new file mode 100644 index 00000000000..d91dff75ef6 --- /dev/null +++ b/src/coreComponents/physicsSolvers/inducedSeismicity/kernels/RateAndStateKernels.hpp @@ -0,0 +1,582 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#ifndef GEOS_PHYSICSSOLVERS_RATEANDSTATEKERNELS_HPP_ +#define GEOS_PHYSICSSOLVERS_RATEANDSTATEKERNELS_HPP_ + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/contact/RateAndStateFriction.hpp" +#include "physicsSolvers/inducedSeismicity/rateAndStateFields.hpp" +#include "denseLinearAlgebra/denseLASolvers.hpp" + +namespace geos +{ + +namespace rateAndStateKernels +{ + +// TBD: Pass the kernel and add getters for relevant fields to make this function general purpose and avoid +// wrappers? +GEOS_HOST_DEVICE +static void projectSlipRateBase( localIndex const k, + real64 const frictionCoefficient, + real64 const shearImpedance, + arrayView2d< real64 const > const traction, + arrayView1d< real64 const > const slipRate, + arrayView2d< real64 > const slipVelocity ) +{ + // Project slip rate onto shear traction to get slip velocity components + real64 const frictionForce = traction[k][0] * frictionCoefficient; + real64 const projectionScaling = 1.0 / ( shearImpedance + frictionForce / slipRate[k] ); + slipVelocity[k][0] = projectionScaling * traction[k][1]; + slipVelocity[k][1] = projectionScaling * traction[k][2]; +} + +/** + * @class ImplicitFixedStressRateAndStateKernel + * + * @brief + * + * @details + */ +class ImplicitFixedStressRateAndStateKernel +{ +public: + + ImplicitFixedStressRateAndStateKernel( SurfaceElementSubRegion & subRegion, + constitutive::RateAndStateFriction const & frictionLaw, + real64 const shearImpedance ): + m_slipRate( subRegion.getField< fields::rateAndState::slipRate >() ), + m_stateVariable( subRegion.getField< fields::rateAndState::stateVariable >() ), + m_stateVariable_n( subRegion.getField< fields::rateAndState::stateVariable_n >() ), + m_traction( subRegion.getField< fields::contact::traction >() ), + m_slipVelocity( subRegion.getField< fields::rateAndState::slipVelocity >() ), + m_shearImpedance( shearImpedance ), + m_frictionLaw( frictionLaw.createKernelUpdates() ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables located on the stack + */ + struct StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables( ) + {} + + real64 jacobian[2][2]{}; + + real64 rhs[2]{}; + + }; + + GEOS_HOST_DEVICE + void setup( localIndex const k, + real64 const dt, + StackVariables & stack ) const + { + real64 const normalTraction = m_traction[k][0]; + real64 const shearTractionMagnitude = LvArray::math::sqrt( m_traction[k][1] * m_traction[k][1] + m_traction[k][2] * m_traction[k][2] ); + // Eq 1: Scalar force balance for slipRate and shear traction magnitude + stack.rhs[0] = shearTractionMagnitude - m_shearImpedance * m_slipRate[k] + - normalTraction * m_frictionLaw.frictionCoefficient( k, m_slipRate[k], m_stateVariable[k] ); + real64 const dFriction[2] = { -normalTraction * m_frictionLaw.dFrictionCoefficient_dStateVariable( k, m_slipRate[k], m_stateVariable[k] ), + -m_shearImpedance - normalTraction * m_frictionLaw.dFrictionCoefficient_dSlipRate( k, m_slipRate[k], m_stateVariable[k] ) }; + + // Eq 2: slip law + stack.rhs[1] = (m_stateVariable[k] - m_stateVariable_n[k]) / dt - m_frictionLaw.stateEvolution( k, m_slipRate[k], m_stateVariable[k] ); + real64 const dStateEvolutionLaw[2] = { 1 / dt - m_frictionLaw.dStateEvolution_dStateVariable( k, m_slipRate[k], m_stateVariable[k] ), + -m_frictionLaw.dStateEvolution_dSlipRate( k, m_slipRate[k], m_stateVariable[k] ) }; + + // Assemble Jacobian matrix + stack.jacobian[0][0] = dFriction[0]; // derivative of Eq 1 w.r.t. stateVariable + stack.jacobian[0][1] = dFriction[1]; // derivative of Eq 1 w.r.t. slipRate + stack.jacobian[1][0] = dStateEvolutionLaw[0]; // derivative of Eq 2 w.r.t. stateVariable + stack.jacobian[1][1] = dStateEvolutionLaw[1]; // derivative of Eq 2 w.r.t. slipRate + } + + GEOS_HOST_DEVICE + void solve( localIndex const k, + StackVariables & stack ) const + { + /// Solve 2x2 system + real64 solution[2] = {0.0, 0.0}; + denseLinearAlgebra::solve< 2 >( stack.jacobian, stack.rhs, solution ); + + // Update variables + m_stateVariable[k] -= solution[0]; + m_slipRate[k] -= solution[1]; + } + + GEOS_HOST_DEVICE + void projectSlipRate( localIndex const k ) const + { + real64 const frictionCoefficient = m_frictionLaw.frictionCoefficient( k, m_slipRate[k], m_stateVariable[k] ); + projectSlipRateBase( k, frictionCoefficient, m_shearImpedance, m_traction, m_slipRate, m_slipVelocity ); + } + + GEOS_HOST_DEVICE + camp::tuple< int, real64 > checkConvergence( StackVariables const & stack, + real64 const tol ) const + { + real64 const residualNorm = LvArray::tensorOps::l2Norm< 2 >( stack.rhs ); + int const converged = residualNorm < tol ? 1 : 0; + camp::tuple< int, real64 > result { converged, residualNorm }; + return result; + } + +private: + + arrayView1d< real64 > const m_slipRate; + + arrayView1d< real64 > const m_stateVariable; + + arrayView1d< real64 const > const m_stateVariable_n; + + arrayView2d< real64 const > const m_traction; + + arrayView2d< real64 > const m_slipVelocity; + + real64 const m_shearImpedance; + + constitutive::RateAndStateFriction::KernelWrapper m_frictionLaw; + +}; + +/** + * @class ExplicitRateAndStateKernel + * + * @brief + * + * @details + */ +class ExplicitRateAndStateKernel +{ +public: + + ExplicitRateAndStateKernel( SurfaceElementSubRegion & subRegion, + constitutive::RateAndStateFriction const & frictionLaw, + real64 const shearImpedance ): + m_slipRate( subRegion.getField< fields::rateAndState::slipRate >() ), + m_stateVariable( subRegion.getField< fields::rateAndState::stateVariable >() ), + m_traction( subRegion.getField< fields::contact::traction >() ), + m_slipVelocity( subRegion.getField< fields::rateAndState::slipVelocity >() ), + m_shearImpedance( shearImpedance ), + m_frictionLaw( frictionLaw.createKernelUpdates() ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables located on the stack + */ + struct StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables( ) + {} + + real64 jacobian; + real64 rhs; + + }; + + GEOS_HOST_DEVICE + void setup( localIndex const k, + real64 const dt, + StackVariables & stack ) const + { + GEOS_UNUSED_VAR( dt ); + real64 const normalTraction = m_traction[k][0]; + real64 const shearTractionMagnitude = LvArray::math::sqrt( m_traction[k][1] * m_traction[k][1] + m_traction[k][2] * m_traction[k][2] ); + + // Slip rate is bracketed between [0, shear traction magnitude / shear impedance] + // If slip rate is outside the bracket, re-initialize to the middle value + real64 const upperBound = shearTractionMagnitude/m_shearImpedance; + real64 const bracketedSlipRate = m_slipRate[k] > upperBound ? 0.5*upperBound : m_slipRate[k]; + + stack.rhs = shearTractionMagnitude - m_shearImpedance *bracketedSlipRate - normalTraction * m_frictionLaw.frictionCoefficient( k, bracketedSlipRate, m_stateVariable[k] ); + stack.jacobian = -m_shearImpedance - normalTraction * m_frictionLaw.dFrictionCoefficient_dSlipRate( k, bracketedSlipRate, m_stateVariable[k] ); + } + + GEOS_HOST_DEVICE + void solve( localIndex const k, + StackVariables & stack ) const + { + m_slipRate[k] -= stack.rhs/stack.jacobian; + + // Slip rate is bracketed between [0, shear traction magnitude / shear impedance] + // Check that the update did not end outside of the bracket. + real64 const shearTractionMagnitude = LvArray::math::sqrt( m_traction[k][1] * m_traction[k][1] + m_traction[k][2] * m_traction[k][2] ); + real64 const upperBound = shearTractionMagnitude/m_shearImpedance; + if( m_slipRate[k] > upperBound ) m_slipRate[k] = 0.5*upperBound; + + } + + + GEOS_HOST_DEVICE + camp::tuple< int, real64 > checkConvergence( StackVariables const & stack, + real64 const tol ) const + { + real64 const residualNorm = LvArray::math::abs( stack.rhs ); + int const converged = residualNorm < tol ? 1 : 0; + camp::tuple< int, real64 > result { converged, residualNorm }; + return result; + } + + GEOS_HOST_DEVICE + void projectSlipRate( localIndex const k ) const + { + real64 const frictionCoefficient = m_frictionLaw.frictionCoefficient( k, m_slipRate[k], m_stateVariable[k] ); + projectSlipRateBase( k, frictionCoefficient, m_shearImpedance, m_traction, m_slipRate, m_slipVelocity ); + } + +private: + + arrayView1d< real64 > const m_slipRate; + + arrayView1d< real64 > const m_stateVariable; + + arrayView2d< real64 const > const m_traction; + + arrayView2d< real64 > const m_slipVelocity; + + real64 const m_shearImpedance; + + constitutive::RateAndStateFriction::KernelWrapper m_frictionLaw; + +}; + + +/** + * @brief Performs the kernel launch + * @tparam KernelType The Rate-and-state kernel to launch + * @tparam POLICY the policy used in the RAJA kernels + */ +template< typename KernelType, typename POLICY > +static void +createAndLaunch( SurfaceElementSubRegion & subRegion, + string const & frictionLawNameKey, + real64 const shearImpedance, + integer const maxIterNewton, + real64 const newtonTol, + real64 const time_n, + real64 const dt ) +{ + GEOS_MARK_FUNCTION; + + GEOS_UNUSED_VAR( time_n ); + + string const & frictionaLawName = subRegion.getReference< string >( frictionLawNameKey ); + constitutive::RateAndStateFriction const & frictionLaw = subRegion.getConstitutiveModel< constitutive::RateAndStateFriction >( frictionaLawName ); + KernelType kernel( subRegion, frictionLaw, shearImpedance ); + + // Newton loop (outside of the kernel launch) + bool allConverged = false; + for( integer iter = 0; iter < maxIterNewton; iter++ ) + { + RAJA::ReduceMin< parallelDeviceReduce, int > converged( 1 ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > residualNorm( 0.0 ); + forAll< POLICY >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + typename KernelType::StackVariables stack; + kernel.setup( k, dt, stack ); + kernel.solve( k, stack ); + auto const [elementConverged, elementResidualNorm] = kernel.checkConvergence( stack, newtonTol ); + converged.min( elementConverged ); + residualNorm.max( elementResidualNorm ); + } ); + + real64 const maxResidualNorm = MpiWrapper::max( residualNorm.get() ); + GEOS_LOG_RANK_0( GEOS_FMT( "-----iter {} : residual = {:.10e} ", iter, maxResidualNorm ) ); + + if( converged.get() ) + { + allConverged = true; + break; + } + } + if( !allConverged ) + { + GEOS_ERROR( " Failed to converge" ); + } + forAll< POLICY >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + kernel.projectSlipRate( k ); + } ); +} + +/** + * @brief Butcher table for embedded RK3(2) method using Kuttas third order + * method for the high-order update, and an explicit trapezoidal rule + * based on the first and third stage rates for the low-order update. + */ +struct Kutta32Table +{ + integer constexpr static algHighOrder = 3; // High-order update order + integer constexpr static algLowOrder = 2; // Low-order update order + integer constexpr static numStages = 3; // Number of stages + real64 const a[2][2] = { { 1.0/2.0, 0.0 }, // Coefficients for stage value updates + { -1.0, 2.0 } }; // (lower-triangular part of table). + real64 const c[3] = { 0.0, 1.0/2.0, 1.0 }; // Coefficients for time increments of substages + real64 const b[3] = { 1.0/6.0, 4.0/6.0, 1.0/6.0 }; // Quadrature weights used to step the solution to next time + real64 const bStar[3] = { 1.0/2.0, 0.0, 1.0/2.0 }; // Quadrature weights used for low-order comparision solution + real64 constexpr static FSAL = false; // Not first same as last +}; + +/** + * @brief Butcher table for the BogackiShampine 3(2) method. + */ +struct BogackiShampine32Table +{ + integer constexpr static algHighOrder = 3; // High-order update order + integer constexpr static algLowOrder = 2; // Low-order update order + integer constexpr static numStages = 4; // Number of stages + real64 const a[3][3] = { { 1.0/2.0, 0.0, 0.0 }, // Coefficients for stage value updates + { 0.0, 3.0/4.0, 0.0 }, // (lower-triangular part of table). + { 2.0/9.0, 1.0/3.0, 4.0/9.0 } }; + real64 const c[4] = { 0.0, 1.0/2.0, 3.0/4.0, 1.0 }; // Coefficients for time increments of substages + real64 const b[4] = { 2.0/9.0, 1.0/3.0, 4.0/9.0, 0.0 }; // Quadrature weights used to step the solution to next time + real64 const bStar[4] = { 7.0/24.0, 1.0/4.0, 1.0/3.0, 1.0/8.0}; // Quadrature weights used for low-order comparision solution + bool constexpr static FSAL = true; // First same as last (can reuse the last stage rate in next + // update) +}; + +/** + * @brief Runge-Kutta method used to time integrate slip and state. Uses of a high order + * update used to integrate the solutions, and a lower order update to estimate the error + * in the time step. + * + * @tparam Butcher table defining the Runge-Kutta method. + */ +template< typename TABLE_TYPE > class EmbeddedRungeKuttaKernel +{ + +public: + EmbeddedRungeKuttaKernel( SurfaceElementSubRegion & subRegion, + constitutive::RateAndStateFriction const & frictionLaw, + TABLE_TYPE butcherTable ): + m_stateVariable( subRegion.getField< fields::rateAndState::stateVariable >() ), + m_stateVariable_n( subRegion.getField< fields::rateAndState::stateVariable_n >() ), + m_slipRate( subRegion.getField< fields::rateAndState::slipRate >() ), + m_slipVelocity( subRegion.getField< fields::rateAndState::slipVelocity >() ), + m_slipVelocity_n( subRegion.getField< fields::rateAndState::slipVelocity_n >() ), + m_deltaSlip( subRegion.getField< fields::rateAndState::deltaSlip >() ), + m_deltaSlip_n( subRegion.getField< fields::rateAndState::deltaSlip_n >() ), + m_dispJump( subRegion.getField< fields::contact::dispJump >() ), + m_dispJump_n( subRegion.getField< fields::contact::dispJump_n >() ), + m_error( subRegion.getField< fields::rateAndState::error >() ), + m_stageRates( subRegion.getField< fields::rateAndState::rungeKuttaStageRates >() ), + m_frictionLaw( frictionLaw.createKernelUpdates() ), + m_butcherTable( butcherTable ) + {} + + /** + * @brief Initialize slip and state buffers + */ + GEOS_HOST_DEVICE + void initialize( localIndex const k ) const + { + LvArray::tensorOps::copy< 2 >( m_slipVelocity[k], m_slipVelocity_n[k] ); + m_slipRate[k] = LvArray::tensorOps::l2Norm< 2 >( m_slipVelocity_n[k] ); + m_stateVariable[k] = m_stateVariable_n[k]; + } + + /** + * @brief Re-uses the last stage rate from the previous time step as the first + * in the next update. Only valid for FSAL (first-same-as-last) Runge-Kutta methods. + */ + GEOS_HOST_DEVICE + void updateStageRatesFSAL( localIndex const k ) const + { + LvArray::tensorOps::copy< 3 >( m_stageRates[k][0], m_stageRates[k][m_butcherTable.numStages-1] ); + } + + /** + * @brief Updates the stage rates rates (the right-hand-side of the ODEs for slip and state) + */ + GEOS_HOST_DEVICE + void updateStageRates( localIndex const k, integer const stageIndex ) const + { + m_stageRates[k][stageIndex][0] = m_slipVelocity[k][0]; + m_stageRates[k][stageIndex][1] = m_slipVelocity[k][1]; + m_stageRates[k][stageIndex][2] = m_frictionLaw.stateEvolution( k, m_slipRate[k], m_stateVariable[k] ); + } + + /** + * @brief Update stage values (slip, state and displacement jump) to a Runge-Kutta substage. + */ + GEOS_HOST_DEVICE + void updateStageValues( localIndex const k, integer const stageIndex, real64 const dt ) const + { + + real64 stateVariableIncrement = 0.0; + real64 deltaSlipIncrement[2] = {0.0, 0.0}; + + for( integer i = 0; i < stageIndex; i++ ) + { + deltaSlipIncrement[0] += m_butcherTable.a[stageIndex-1][i] * m_stageRates[k][i][0]; + deltaSlipIncrement[1] += m_butcherTable.a[stageIndex-1][i] * m_stageRates[k][i][1]; + stateVariableIncrement += m_butcherTable.a[stageIndex-1][i] * m_stageRates[k][i][2]; + } + m_deltaSlip[k][0] = m_deltaSlip_n[k][0] + dt*deltaSlipIncrement[0]; + m_deltaSlip[k][1] = m_deltaSlip_n[k][1] + dt*deltaSlipIncrement[1]; + m_stateVariable[k] = m_stateVariable_n[k] + dt*stateVariableIncrement; + + m_dispJump[k][1] = m_dispJump_n[k][1] + m_deltaSlip[k][0]; + m_dispJump[k][2] = m_dispJump_n[k][2] + m_deltaSlip[k][1]; + } + + /** + * @brief Updates slip, state and displacement jump to the next time computes error the local error + * in the time step + */ + GEOS_HOST_DEVICE + void updateSolutionAndLocalError( localIndex const k, real64 const dt, real64 const absTol, real64 const relTol ) const + { + + real64 deltaSlipIncrement[2] = {0.0, 0.0}; + real64 deltaSlipIncrementLowOrder[2] = {0.0, 0.0}; + + real64 stateVariableIncrement = 0.0; + real64 stateVariableIncrementLowOrder = 0.0; + + for( localIndex i = 0; i < m_butcherTable.numStages; i++ ) + { + + // High order update of solution + deltaSlipIncrement[0] += m_butcherTable.b[i] * m_stageRates[k][i][0]; + deltaSlipIncrement[1] += m_butcherTable.b[i] * m_stageRates[k][i][1]; + stateVariableIncrement += m_butcherTable.b[i] * m_stageRates[k][i][2]; + + // Low order update for error + deltaSlipIncrementLowOrder[0] += m_butcherTable.bStar[i] * m_stageRates[k][i][0]; + deltaSlipIncrementLowOrder[1] += m_butcherTable.bStar[i] * m_stageRates[k][i][1]; + stateVariableIncrementLowOrder += m_butcherTable.bStar[i] * m_stageRates[k][i][2]; + } + + m_deltaSlip[k][0] = m_deltaSlip_n[k][0] + dt * deltaSlipIncrement[0]; + m_deltaSlip[k][1] = m_deltaSlip_n[k][1] + dt * deltaSlipIncrement[1]; + m_stateVariable[k] = m_stateVariable_n[k] + dt * stateVariableIncrement; + + real64 const deltaSlipLowOrder[2] = {m_deltaSlip_n[k][0] + dt * deltaSlipIncrementLowOrder[0], + m_deltaSlip_n[k][1] + dt * deltaSlipIncrementLowOrder[1]}; + real64 const stateVariableLowOrder = m_stateVariable_n[k] + dt * stateVariableIncrementLowOrder; + + m_dispJump[k][1] = m_dispJump_n[k][1] + m_deltaSlip[k][0]; + m_dispJump[k][2] = m_dispJump_n[k][2] + m_deltaSlip[k][1]; + + // Compute error + m_error[k][0] = computeError( m_deltaSlip[k][0], deltaSlipLowOrder[0], absTol, relTol ); + m_error[k][1] = computeError( m_deltaSlip[k][1], deltaSlipLowOrder[1], absTol, relTol ); + m_error[k][2] = computeError( m_stateVariable[k], stateVariableLowOrder, absTol, relTol ); + } + + /** + * @brief Updates slip, state and displacement jump to the next time computes error the local error + * in the time step. Uses the FSAL (first-same-as-last) property. + */ + GEOS_HOST_DEVICE + void updateSolutionAndLocalErrorFSAL( localIndex const k, real64 const dt, real64 const absTol, real64 const relTol ) const + { + + real64 deltaSlipIncrementLowOrder[2] = {0.0, 0.0}; + real64 stateVariableIncrementLowOrder = 0.0; + + for( localIndex i = 0; i < m_butcherTable.numStages; i++ ) + { + // In FSAL algorithms the last RK substage update coincides with the + // high-order update. Only need to compute increments for the the + // low-order updates for error computation. + deltaSlipIncrementLowOrder[0] += m_butcherTable.bStar[i] * m_stageRates[k][i][0]; + deltaSlipIncrementLowOrder[1] += m_butcherTable.bStar[i] * m_stageRates[k][i][1]; + stateVariableIncrementLowOrder += m_butcherTable.bStar[i] * m_stageRates[k][i][2]; + } + + real64 const deltaSlipLowOrder[2] = {m_deltaSlip_n[k][0] + dt * deltaSlipIncrementLowOrder[0], + m_deltaSlip_n[k][1] + dt * deltaSlipIncrementLowOrder[1]}; + real64 const stateVariableLowOrder = m_stateVariable_n[k] + dt * stateVariableIncrementLowOrder; + + m_dispJump[k][1] = m_dispJump_n[k][1] + m_deltaSlip[k][0]; + m_dispJump[k][2] = m_dispJump_n[k][2] + m_deltaSlip[k][1]; + + // Compute error + m_error[k][0] = computeError( m_deltaSlip[k][0], deltaSlipLowOrder[0], absTol, relTol ); + m_error[k][1] = computeError( m_deltaSlip[k][1], deltaSlipLowOrder[1], absTol, relTol ); + m_error[k][2] = computeError( m_stateVariable[k], stateVariableLowOrder, absTol, relTol ); + } + + /** + * @brief Computes the relative error scaled by error tolerances + */ + GEOS_HOST_DEVICE + real64 computeError( real64 const highOrderApprox, real64 const lowOrderApprox, real64 const absTol, real64 const relTol ) const + { + return (highOrderApprox - lowOrderApprox) / + ( absTol + relTol * LvArray::math::max( LvArray::math::abs( highOrderApprox ), LvArray::math::abs( lowOrderApprox ) )); + } + +private: + + /// Current state variable + arrayView1d< real64 > const m_stateVariable; + + /// State variable at t = t_n + arrayView1d< real64 > const m_stateVariable_n; + + /// Current slip rate (magnitude of slip velocity) + arrayView1d< real64 > const m_slipRate; + + /// Current slip velocity + arrayView2d< real64 > const m_slipVelocity; + + /// Slip velocity at time t_n + arrayView2d< real64 > const m_slipVelocity_n; + + /// Current slip change + arrayView2d< real64 > const m_deltaSlip; + + /// Slip change at time t_n + arrayView2d< real64 > const m_deltaSlip_n; + + /// Current displacment jump + arrayView2d< real64 > const m_dispJump; + + /// Displacment jump at time t_n + arrayView2d< real64 > const m_dispJump_n; + + /// Local error for each solution component stored as slip1, slip2, state + arrayView2d< real64 > const m_error; + + /// Stage rates for each solution component stored as slip1, slip2, state + arrayView3d< real64 > const m_stageRates; + + /// Friction law used for rate-and-state updates + constitutive::RateAndStateFriction::KernelWrapper m_frictionLaw; + + /// Butcher table used for explicit time stepping of slip and state + TABLE_TYPE m_butcherTable; +}; + +} /* namespace rateAndStateKernels */ + +} /* namespace geos */ + +#endif /* GEOS_PHYSICSSOLVERS_RATEANDSTATEKERNELS_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/inducedSeismicity/kernels/SeismicityRateKernels.hpp b/src/coreComponents/physicsSolvers/inducedSeismicity/kernels/SeismicityRateKernels.hpp new file mode 100644 index 00000000000..63ca4bdee7a --- /dev/null +++ b/src/coreComponents/physicsSolvers/inducedSeismicity/kernels/SeismicityRateKernels.hpp @@ -0,0 +1,203 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#ifndef GEOS_PHYSICSSOLVERS_SEISMICITYRATEKERNELS_HPP_ +#define GEOS_PHYSICSSOLVERS_SEISMICITYRATEKERNELS_HPP_ + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "physicsSolvers/inducedSeismicity/inducedSeismicityFields.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" + +namespace geos +{ + +namespace seismicityRateKernels +{ +/** + * @class DieterichSeismicityRate + * + * @brief Solving the ODE for seismicity rate from Dieterich, 1994 + * + * @details This solver finds a solution R(x, t) - the seismicity rate - to the ordinary differential equation (ODE) + * formulated by Dieterich, 1994 given a certain stressing history. The stressing history can consist + * of mechanical stresses and pore pressure. The solver class includes a member variable + * pointing to the stress solver that is specified in the XML file. SolverStep for the + * stress solver is then called in the SolverStep function for the seismicity rate, to take + * the updated stress history as the input. + * + * Solving the ODE is currently implemented by computing the closed-form integral solution + * to the ODE which involves numerical calculation of an integral of a stress functional. + * We initially solve for the log of the seismicity rate in order to avoid overflow that + * typically occurs in the exponential of the stress history. + */ +class SeismicityRateKernel +{ +public: + + SeismicityRateKernel( ElementSubRegionBase & subRegion ): + m_R( subRegion.getField< fields::inducedSeismicity::seismicityRate >() ), + m_logDenom( subRegion.getField< fields::inducedSeismicity::logDenom >() ), + m_sigma_0( subRegion.getField< fields::inducedSeismicity::initialProjectedNormalTraction >() ), + m_sigma_n( subRegion.getField< fields::inducedSeismicity::projectedNormalTraction_n >() ), + m_sigma( subRegion.getField< fields::inducedSeismicity::projectedNormalTraction >() ), + m_tau_0( subRegion.getField< fields::inducedSeismicity::initialProjectedShearTraction >() ), + m_tau_n( subRegion.getField< fields::inducedSeismicity::projectedShearTraction_n >() ), + m_tau( subRegion.getField< fields::inducedSeismicity::projectedShearTraction >() ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables located on the stack + */ + struct StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables( real64 const directEffect, + real64 const backgroundStressingRate ): + directEffectValue( directEffect ), + backgroundStressingRateValue( backgroundStressingRate ), + effectiveNormalTraction_0( 0.0 ), + effectiveNormalTraction_n( 0.0 ), + effectiveNormalTraction( 0.0 ) + {} + + real64 const directEffectValue; + + real64 const backgroundStressingRateValue; + + real64 effectiveNormalTraction_0; + + real64 effectiveNormalTraction_n; + + real64 effectiveNormalTraction; + }; + + GEOS_HOST_DEVICE + void setup( localIndex const k, + StackVariables & stack ) const + { + stack.effectiveNormalTraction_0 = -m_sigma_0[k]; + stack.effectiveNormalTraction_n = -m_sigma_n[k]; + stack.effectiveNormalTraction = -m_sigma[k]; + } + + GEOS_HOST_DEVICE + void computeSeismicityRate( localIndex const k, + real64 const & time_n, + real64 const & dt, + StackVariables & stack ) const + { + + // arguments of stress exponential at current and previous time step + real64 const g = ( LvArray::math::abs( m_tau[k] ) + stack.backgroundStressingRateValue*(time_n+dt) ) / ( stack.directEffectValue*stack.effectiveNormalTraction ) - + LvArray::math::abs( m_tau_0[k] ) / (stack.directEffectValue * stack.effectiveNormalTraction_0 ); + + real64 const g_n = ( LvArray::math::abs( m_tau_n[k] ) + stack.backgroundStressingRateValue*time_n ) / ( stack.directEffectValue*stack.effectiveNormalTraction_n ) - + LvArray::math::abs( m_tau_0[k] ) / (stack.directEffectValue*stack.effectiveNormalTraction_0); + + // Compute the difference of the log of the denominator of closed for integral solution. + // This avoids directly computing the exponential of the current stress state which is more prone to overflow. + m_logDenom[k] += + LvArray::math::log( 1 + dt/(2*(stack.directEffectValue*stack.effectiveNormalTraction_0/stack.backgroundStressingRateValue) ) * + ( LvArray::math::exp( g - m_logDenom[k] ) + LvArray::math::exp( g_n - m_logDenom[k] ) )); + + // Convert log seismicity rate to raw value + m_R[k] = LvArray::math::exp( g - m_logDenom[k] ); + } + +protected: + + arrayView1d< real64 > m_R; + + arrayView1d< real64 > m_logDenom; + + arrayView1d< real64 const > m_sigma_0; + + arrayView1d< real64 const > m_sigma_n; + + arrayView1d< real64 const > m_sigma; + + arrayView1d< real64 const > m_tau_0; + + arrayView1d< real64 const > m_tau_n; + + arrayView1d< real64 const > m_tau; +}; + + +class SeismicityRateKernelPoroelastic : public SeismicityRateKernel +{ + +public: + + SeismicityRateKernelPoroelastic( ElementSubRegionBase & subRegion ): + SeismicityRateKernel( subRegion ), + m_pressure_0( subRegion.getField< fields::flow::initialPressure >() ), + m_pressure_n( subRegion.getField< fields::flow::pressure_n >() ), + m_pressure( subRegion.getField< fields::flow::pressure >() ) + {} + + GEOS_HOST_DEVICE + void setup( localIndex const k, + StackVariables & stack ) const + { + stack.effectiveNormalTraction_0 = -m_sigma_0[k] - m_pressure_0[k]; + stack.effectiveNormalTraction_n = -m_sigma_n[k] - m_pressure_n[k]; + stack.effectiveNormalTraction = -m_sigma[k] - m_pressure[k]; + } + +private: + + arrayView1d< real64 const > m_pressure_0; + + arrayView1d< real64 const > m_pressure_n; + + arrayView1d< real64 const > m_pressure; +}; + + +/** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + */ +template< typename POLICY, bool ISPORO > +static void +createAndLaunch( ElementSubRegionBase & subRegion, + real64 const time_n, + real64 const dt, + real64 const directEffectValue, + real64 const backgroundStressingRateValue ) +{ + GEOS_MARK_FUNCTION; + + using kernelType = std::conditional_t< ISPORO, SeismicityRateKernelPoroelastic, SeismicityRateKernel >; + kernelType kernel( subRegion ); + + forAll< POLICY >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + typename kernelType::StackVariables stack( directEffectValue, backgroundStressingRateValue ); + kernel.setup( k, stack ); + kernel.computeSeismicityRate( k, time_n, dt, stack ); + } ); +} + +} /* namespace seismicityRateKernels */ + +}/* namespace geos */ + +#endif /* GEOS_PHYSICSSOLVERS_SEISMICITYRATEKERNELS_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/inducedSeismicity/rateAndStateFields.hpp b/src/coreComponents/physicsSolvers/inducedSeismicity/rateAndStateFields.hpp new file mode 100644 index 00000000000..e060dceb28a --- /dev/null +++ b/src/coreComponents/physicsSolvers/inducedSeismicity/rateAndStateFields.hpp @@ -0,0 +1,116 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file rateAndStateFields.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_INDUCEDSEISMICITY_RATEANDSTATEFIELDS_HPP_ +#define GEOS_PHYSICSSOLVERS_INDUCEDSEISMICITY_RATEANDSTATEFIELDS_HPP_ + +#include "common/DataLayouts.hpp" +#include "mesh/MeshFields.hpp" + +namespace geos +{ + +namespace fields +{ + +namespace rateAndState +{ + +DECLARE_FIELD( slipRate, + "slipRate", + array1d< real64 >, + 1.0e-6, + NOPLOT, + WRITE_AND_READ, + "Slip rate" ); + +DECLARE_FIELD( slipVelocity, + "slipVelocity", + array2d< real64 >, + 0.70710678118e-6, + LEVEL_0, + WRITE_AND_READ, + "Slip velocity" ); + +DECLARE_FIELD( slipVelocity_n, + "slipVelocity_n", + array2d< real64 >, + 0.70710678118e-6, + NOPLOT, + WRITE_AND_READ, + "Slip velocity at previous time step" ); + +DECLARE_FIELD( stateVariable, + "stateVariable", + array1d< real64 >, + 0.6, + LEVEL_0, + WRITE_AND_READ, + "Rate- and state-dependent friction state variable" ); + +DECLARE_FIELD( stateVariable_n, + "stateVariable_n", + array1d< real64 >, + 0.6, + NOPLOT, + WRITE_AND_READ, + "Initial rate- and state-dependent friction state variable at this time step" ); + + +DECLARE_FIELD( deltaSlip, + "deltaSlip", + array2d< real64 >, + 0.0, + LEVEL_0, + WRITE_AND_READ, + "Slip increment" ); + +DECLARE_FIELD( deltaSlip_n, + "deltaSlip_n", + array2d< real64 >, + 0.0, + NOPLOT, + WRITE_AND_READ, + "Initial slip increment at this time step" ); + + +DECLARE_FIELD( rungeKuttaStageRates, + "rungeKuttaStageRates", + array3d< real64 >, + 0.0, + NOPLOT, + WRITE_AND_READ, + "Runge-Kutta stage rates for rate-and-state variables" ); + + +DECLARE_FIELD( error, + "error", + array2d< real64 >, + 0.0, + LEVEL_0, + WRITE_AND_READ, + "Error for rate-and-state fields" ); + +} + +} + +} + +#endif // GEOS_PHYSICSSOLVERS_INDUCEDSEISMICITY_INDUCEDSEISMICITYFIELDS_HPP_ diff --git a/src/coreComponents/physicsSolvers/multiphysics/CMakeLists.txt b/src/coreComponents/physicsSolvers/multiphysics/CMakeLists.txt new file mode 100644 index 00000000000..89a34cbc276 --- /dev/null +++ b/src/coreComponents/physicsSolvers/multiphysics/CMakeLists.txt @@ -0,0 +1,57 @@ +# Specify solver headers +set( physicsSolvers_headers + ${physicsSolvers_headers} + multiphysics/CompositionalMultiphaseReservoirAndWells.hpp + multiphysics/CoupledReservoirAndWellsBase.hpp + multiphysics/CoupledSolver.hpp + multiphysics/PoromechanicsSolver.hpp + multiphysics/FlowProppantTransportSolver.hpp + multiphysics/HydrofractureSolver.hpp + multiphysics/HydrofractureSolverKernels.hpp + multiphysics/MultiphasePoromechanics.hpp + multiphysics/PhaseFieldFractureSolver.hpp + multiphysics/PoromechanicsInitialization.hpp + multiphysics/PoromechanicsFields.hpp + multiphysics/PoromechanicsInitialization.hpp + multiphysics/LogLevelsInfo.hpp + multiphysics/poromechanicsKernels/MultiphasePoromechanics.hpp + multiphysics/poromechanicsKernels/MultiphasePoromechanics_impl.hpp + multiphysics/poromechanicsKernels/PoromechanicsBase.hpp + multiphysics/poromechanicsKernels/SinglePhasePoromechanics.hpp + multiphysics/poromechanicsKernels/SinglePhasePoromechanics_impl.hpp + multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp + multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM.hpp + multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM_impl.hpp + multiphysics/poromechanicsKernels/SinglePhasePoromechanicsFractures.hpp + multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEmbeddedFractures.hpp + multiphysics/poromechanicsKernels/ThermalMultiphasePoromechanics.hpp + multiphysics/poromechanicsKernels/ThermalMultiphasePoromechanics_impl.hpp + multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanics.hpp + multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanics_impl.hpp + multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEFEM.hpp + multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEFEM_impl.hpp + multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsConformingFractures.hpp + multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEmbeddedFractures.hpp + multiphysics/SinglePhasePoromechanics.hpp + multiphysics/SinglePhasePoromechanicsEmbeddedFractures.hpp + multiphysics/SinglePhasePoromechanicsConformingFractures.hpp + multiphysics/SinglePhaseReservoirAndWells.hpp + PARENT_SCOPE ) + +# Specify solver sources +set( physicsSolvers_sources + ${physicsSolvers_sources} + multiphysics/CompositionalMultiphaseReservoirAndWells.cpp + multiphysics/CoupledReservoirAndWellsBase.cpp + multiphysics/FlowProppantTransportSolver.cpp + multiphysics/HydrofractureSolver.cpp + multiphysics/MultiphasePoromechanics.cpp + multiphysics/PhaseFieldFractureSolver.cpp + multiphysics/PoromechanicsInitialization.cpp + multiphysics/SinglePhasePoromechanics.cpp + multiphysics/SinglePhasePoromechanicsEmbeddedFractures.cpp + multiphysics/SinglePhasePoromechanicsConformingFractures.cpp + multiphysics/SinglePhaseReservoirAndWells.cpp + PARENT_SCOPE ) + +#include( multiphysics/poromechanicsKernels/PoromechanicsKernels.cmake) diff --git a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp index ef75ab18317..ea2c6f34b3e 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,71 +21,44 @@ #include "CompositionalMultiphaseReservoirAndWells.hpp" #include "common/TimingMacros.hpp" +#include "dataRepository/LogLevelsInfo.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "mesh/PerforationFields.hpp" +#include "physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" -#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" +#include "physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp" +#include "physicsSolvers/fluidFlow/wells/LogLevelsInfo.hpp" #include "physicsSolvers/multiphysics/MultiphasePoromechanics.hpp" + namespace geos { using namespace dataRepository; using namespace constitutive; -namespace -{ - -// This is meant to be specialized to work, see below -template< typename COMPOSITIONAL_RESERVOIR_SOLVER > class - CompositionalCatalogNames {}; - -// Class specialization for a RESERVOIR_SOLVER set to CompositionalMultiphaseFlow -template<> class CompositionalCatalogNames< CompositionalMultiphaseBase > -{ -public: - // TODO: find a way to use the catalog name here - static string name() { return "CompositionalMultiphaseReservoir"; } -}; -// Class specialization for a RESERVOIR_SOLVER set to MultiphasePoromechanics -template<> class CompositionalCatalogNames< MultiphasePoromechanics< CompositionalMultiphaseBase > > -{ -public: - static string name() { return MultiphasePoromechanics< CompositionalMultiphaseBase >::catalogName()+"Reservoir"; } -}; - -} - -// provide a definition for catalogName() -template< typename COMPOSITIONAL_RESERVOIR_SOLVER > -string -CompositionalMultiphaseReservoirAndWells< COMPOSITIONAL_RESERVOIR_SOLVER >:: -catalogName() -{ - return CompositionalCatalogNames< COMPOSITIONAL_RESERVOIR_SOLVER >::name(); -} - - -template< typename COMPOSITIONAL_RESERVOIR_SOLVER > -CompositionalMultiphaseReservoirAndWells< COMPOSITIONAL_RESERVOIR_SOLVER >:: +template< typename RESERVOIR_SOLVER > +CompositionalMultiphaseReservoirAndWells< RESERVOIR_SOLVER >:: CompositionalMultiphaseReservoirAndWells( const string & name, Group * const parent ) : Base( name, parent ) -{} +{ + Base::template addLogLevel< logInfo::Crossflow >(); +} -template< typename COMPOSITIONAL_RESERVOIR_SOLVER > -CompositionalMultiphaseReservoirAndWells< COMPOSITIONAL_RESERVOIR_SOLVER >:: +template< typename RESERVOIR_SOLVER > +CompositionalMultiphaseReservoirAndWells< RESERVOIR_SOLVER >:: ~CompositionalMultiphaseReservoirAndWells() {} template<> CompositionalMultiphaseBase * -CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase >:: +CompositionalMultiphaseReservoirAndWells<>:: flowSolver() const { return this->reservoirSolver(); @@ -92,7 +66,7 @@ flowSolver() const template<> CompositionalMultiphaseBase * -CompositionalMultiphaseReservoirAndWells< MultiphasePoromechanics< CompositionalMultiphaseBase > >:: +CompositionalMultiphaseReservoirAndWells< MultiphasePoromechanics<> >:: flowSolver() const { return this->reservoirSolver()->flowSolver(); @@ -100,37 +74,73 @@ flowSolver() const template<> void -CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase >:: +CompositionalMultiphaseReservoirAndWells<>:: setMGRStrategy() { - if( flowSolver()->getLinearSolverParameters().mgr.strategy == LinearSolverParameters::MGR::StrategyType::compositionalMultiphaseFVM ) + LinearSolverParameters & linearSolverParameters = m_linearSolverParameters.get(); + + if( linearSolverParameters.preconditionerType != LinearSolverParameters::PreconditionerType::mgr ) + return; + + linearSolverParameters.mgr.separateComponents = true; + linearSolverParameters.dofsPerNode = 3; + + if( dynamic_cast< CompositionalMultiphaseHybridFVM * >( this->flowSolver() ) ) { - m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::compositionalMultiphaseReservoirFVM; + if( isThermal() ) + { + GEOS_ERROR( GEOS_FMT( "{}: MGR strategy is not implemented for thermal {}/{}", + this->getName(), this->getCatalogName(), this->flowSolver()->getCatalogName())); + } + else + { + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::compositionalMultiphaseReservoirHybridFVM; + } } else { - m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::compositionalMultiphaseReservoirHybridFVM; + if( isThermal() ) + { + m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::thermalCompositionalMultiphaseReservoirFVM; + } + else + { + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::compositionalMultiphaseReservoirFVM; + } } + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: MGR strategy set to {}", getName(), + EnumStrings< LinearSolverParameters::MGR::StrategyType >::toString( linearSolverParameters.mgr.strategy ))); } template<> void -CompositionalMultiphaseReservoirAndWells< MultiphasePoromechanics< CompositionalMultiphaseBase > >:: +CompositionalMultiphaseReservoirAndWells< MultiphasePoromechanics<> >:: setMGRStrategy() { - if( flowSolver()->getLinearSolverParameters().mgr.strategy == LinearSolverParameters::MGR::StrategyType::compositionalMultiphaseHybridFVM ) + LinearSolverParameters & linearSolverParameters = m_linearSolverParameters.get(); + + if( linearSolverParameters.preconditionerType != LinearSolverParameters::PreconditionerType::mgr ) + return; + + linearSolverParameters.mgr.separateComponents = true; + linearSolverParameters.dofsPerNode = 3; + + if( dynamic_cast< CompositionalMultiphaseHybridFVM * >( this->flowSolver() ) ) { - GEOS_LOG_RANK_0( "The MGR strategy for hybrid FVM is not implemented" ); + GEOS_ERROR( GEOS_FMT( "{}: MGR strategy is not implemented for {}/{}", + this->getName(), this->getCatalogName(), this->flowSolver()->getCatalogName() ) ); } else { - m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::multiphasePoromechanicsReservoirFVM; + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::multiphasePoromechanicsReservoirFVM; } + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: MGR strategy set to {}", getName(), + EnumStrings< LinearSolverParameters::MGR::StrategyType >::toString( linearSolverParameters.mgr.strategy ))); } -template< typename COMPOSITIONAL_RESERVOIR_SOLVER > +template< typename RESERVOIR_SOLVER > void -CompositionalMultiphaseReservoirAndWells< COMPOSITIONAL_RESERVOIR_SOLVER >:: +CompositionalMultiphaseReservoirAndWells< RESERVOIR_SOLVER >:: initializePreSubGroups() { Base::initializePreSubGroups(); @@ -147,18 +157,9 @@ initializePreSubGroups() InputError ); } -template< typename COMPOSITIONAL_RESERVOIR_SOLVER > -void -CompositionalMultiphaseReservoirAndWells< COMPOSITIONAL_RESERVOIR_SOLVER >:: -initializePostInitialConditionsPreSubGroups() -{ - Base::initializePostInitialConditionsPreSubGroups(); - setMGRStrategy(); -} - -template< typename COMPOSITIONAL_RESERVOIR_SOLVER > +template< typename RESERVOIR_SOLVER > void -CompositionalMultiphaseReservoirAndWells< COMPOSITIONAL_RESERVOIR_SOLVER >:: +CompositionalMultiphaseReservoirAndWells< RESERVOIR_SOLVER >:: addCouplingSparsityPattern( DomainPartition const & domain, DofManager const & dofManager, SparsityPatternView< globalIndex > const & pattern ) const @@ -171,7 +172,7 @@ addCouplingSparsityPattern( DomainPartition const & domain, { ElementRegionManager const & elemManager = mesh.getElemManager(); - // TODO: remove this and just call SolverBase::setupSystem when DofManager can handle the coupling + // TODO: remove this and just call PhysicsSolverBase::setupSystem when DofManager can handle the coupling // Populate off-diagonal sparsity between well and reservoir @@ -179,7 +180,7 @@ addCouplingSparsityPattern( DomainPartition const & domain, integer const wellNDOF = Base::wellSolver()->numDofPerWellElement(); integer constexpr maxNumComp = MultiFluidBase::MAX_NUM_COMPONENTS; - integer constexpr maxNumDof = maxNumComp + 1; + integer constexpr maxNumDof = maxNumComp + 2; string const wellDofKey = dofManager.getKey( Base::wellSolver()->wellElementDofName() ); string const resDofKey = dofManager.getKey( Base::wellSolver()->resElementDofName() ); @@ -263,9 +264,9 @@ addCouplingSparsityPattern( DomainPartition const & domain, } ); } -template< typename COMPOSITIONAL_RESERVOIR_SOLVER > +template< typename RESERVOIR_SOLVER > void -CompositionalMultiphaseReservoirAndWells< COMPOSITIONAL_RESERVOIR_SOLVER >:: +CompositionalMultiphaseReservoirAndWells< RESERVOIR_SOLVER >:: assembleCouplingTerms( real64 const time_n, real64 const dt, DomainPartition const & domain, @@ -275,10 +276,6 @@ assembleCouplingTerms( real64 const time_n, { using namespace compositionalMultiphaseUtilities; - using TAG = compositionalMultiphaseWellKernels::SubRegionTag; - using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; - using COFFSET = compositionalMultiphaseWellKernels::ColOffset; - GEOS_THROW_IF( !Base::m_isWellTransmissibilityComputed, GEOS_FMT( "{} {}: The well transmissibility has not been computed yet", this->getCatalogName(), this->getName() ), @@ -292,11 +289,7 @@ assembleCouplingTerms( real64 const time_n, ElementRegionManager const & elemManager = mesh.getElemManager(); - integer constexpr MAX_NUM_COMP = MultiFluidBase::MAX_NUM_COMPONENTS; - integer constexpr MAX_NUM_DOF = MAX_NUM_COMP + 1; - integer const numComps = Base::wellSolver()->numFluidComponents(); - integer const resNumDofs = Base::wellSolver()->numDofPerResElement(); string const resDofKey = dofManager.getKey( Base::wellSolver()->resElementDofName() ); ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > const resDofNumberAccessor = @@ -308,6 +301,8 @@ assembleCouplingTerms( real64 const time_n, elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion const & subRegion ) { + string const & fluidName = this->flowSolver()->template getConstitutiveName< MultiFluidBase >( subRegion ); + MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); // if the well is shut, we neglect reservoir-well flow that may occur despite the zero rate // therefore, we do not want to compute perforation rates and we simply assume they are zero @@ -321,149 +316,81 @@ assembleCouplingTerms( real64 const time_n, return; } - areWellsShut = 0; - PerforationData const * const perforationData = subRegion.getPerforationData(); // get the degrees of freedom string const wellDofKey = dofManager.getKey( Base::wellSolver()->wellElementDofName() ); - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - - // get well variables on perforations - arrayView2d< real64 const > const & compPerfRate = - perforationData->getField< fields::well::compPerforationRate >(); - arrayView3d< real64 const > const & dCompPerfRate_dPres = - perforationData->getField< fields::well::dCompPerforationRate_dPres >(); - arrayView4d< real64 const > const & dCompPerfRate_dComp = - perforationData->getField< fields::well::dCompPerforationRate_dComp >(); - - arrayView1d< localIndex const > const & perfWellElemIndex = - perforationData->getField< fields::perforation::wellElementIndex >(); - - // get the element region, subregion, index - arrayView1d< localIndex const > const & resElementRegion = - perforationData->getField< fields::perforation::reservoirElementRegion >(); - arrayView1d< localIndex const > const & resElementSubRegion = - perforationData->getField< fields::perforation::reservoirElementSubRegion >(); - arrayView1d< localIndex const > const & resElementIndex = - perforationData->getField< fields::perforation::reservoirElementIndex >(); - - bool const useTotalMassEquation = this->flowSolver()->useTotalMassEquation() > 0; - - RAJA::ReduceSum< parallelDeviceReduce, integer > numCrossflowPerforations( 0 ); + areWellsShut = 0; - // loop over the perforations and add the rates to the residual and jacobian - forAll< parallelDevicePolicy<> >( perforationData->size(), [=] GEOS_HOST_DEVICE ( localIndex const iperf ) + integer useTotalMassEquation=Base::wellSolver()->useTotalMassEquation(); + integer numCrossflowPerforations=0; + if( isThermal ( ) ) { - // local working variables and arrays - stackArray1d< localIndex, 2 * MAX_NUM_COMP > eqnRowIndices( 2 * numComps ); - stackArray1d< globalIndex, 2 * MAX_NUM_DOF > dofColIndices( 2 * resNumDofs ); - - stackArray1d< real64, 2 * MAX_NUM_COMP > localPerf( 2 * numComps ); - stackArray2d< real64, 2 * MAX_NUM_COMP * 2 * MAX_NUM_DOF > localPerfJacobian( 2 * numComps, 2 * resNumDofs ); - - // get the reservoir (sub)region and element indices - localIndex const er = resElementRegion[iperf]; - localIndex const esr = resElementSubRegion[iperf]; - localIndex const ei = resElementIndex[iperf]; - - // get the well element index for this perforation - localIndex const iwelem = perfWellElemIndex[iperf]; - globalIndex const resOffset = resDofNumber[er][esr][ei]; - globalIndex const wellElemOffset = wellElemDofNumber[iwelem]; - - for( integer ic = 0; ic < numComps; ++ic ) - { - eqnRowIndices[TAG::RES * numComps + ic] = LvArray::integerConversion< localIndex >( resOffset - rankOffset ) + ic; - eqnRowIndices[TAG::WELL * numComps + ic] = LvArray::integerConversion< localIndex >( wellElemOffset - rankOffset ) + ROFFSET::MASSBAL + ic; - } - for( integer jdof = 0; jdof < resNumDofs; ++jdof ) - { - dofColIndices[TAG::RES * resNumDofs + jdof] = resOffset + jdof; - dofColIndices[TAG::WELL * resNumDofs + jdof] = wellElemOffset + COFFSET::DPRES + jdof; - } - - // populate local flux vector and derivatives - for( integer ic = 0; ic < numComps; ++ic ) - { - localPerf[TAG::RES * numComps + ic] = dt * compPerfRate[iperf][ic]; - localPerf[TAG::WELL * numComps + ic] = -dt * compPerfRate[iperf][ic]; - - if( detectCrossflow ) - { - if( compPerfRate[iperf][ic] > LvArray::NumericLimits< real64 >::epsilon ) - { - numCrossflowPerforations += 1; - } - } - - for( integer ke = 0; ke < 2; ++ke ) - { - localIndex const localDofIndexPres = ke * resNumDofs; - localPerfJacobian[TAG::RES * numComps + ic][localDofIndexPres] = dt * dCompPerfRate_dPres[iperf][ke][ic]; - localPerfJacobian[TAG::WELL * numComps + ic][localDofIndexPres] = -dt * dCompPerfRate_dPres[iperf][ke][ic]; - - for( integer jc = 0; jc < numComps; ++jc ) - { - localIndex const localDofIndexComp = localDofIndexPres + jc + 1; - localPerfJacobian[TAG::RES * numComps + ic][localDofIndexComp] = dt * dCompPerfRate_dComp[iperf][ke][ic][jc]; - localPerfJacobian[TAG::WELL * numComps + ic][localDofIndexComp] = -dt * dCompPerfRate_dComp[iperf][ke][ic][jc]; - } - } - } - - if( useTotalMassEquation ) - { - // Apply equation/variable change transformation(s) - stackArray1d< real64, 2 * MAX_NUM_DOF > work( 2 * resNumDofs ); - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComps, numComps, resNumDofs * 2, 2, localPerfJacobian, work ); - shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numComps, numComps, 2, localPerf ); - } - - for( localIndex i = 0; i < localPerf.size(); ++i ) - { - if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < localMatrix.numRows() ) - { - localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], - dofColIndices.data(), - localPerfJacobian[i].dataIfContiguous(), - 2 * resNumDofs ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[eqnRowIndices[i]], localPerf[i] ); - } - } - } ); - + coupledReservoirAndWellKernels:: + ThermalCompositionalMultiPhaseFluxKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComps, + wellControls.isProducer(), + dt, + rankOffset, + wellDofKey, + subRegion, + resDofNumber, + perforationData, + fluid, + useTotalMassEquation, + detectCrossflow, + numCrossflowPerforations, + localRhs, + localMatrix ); + } + else + { + coupledReservoirAndWellKernels:: + IsothermalCompositionalMultiPhaseFluxKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComps, + dt, + rankOffset, + wellDofKey, + subRegion, + resDofNumber, + perforationData, + fluid, + useTotalMassEquation, + detectCrossflow, + numCrossflowPerforations, + localRhs, + localMatrix ); + } - if( detectCrossflow ) // check to avoid communications if not needed + if( detectCrossflow ) // check to avoid communications if not needed { - globalIndex const totalNumCrossflowPerforations = MpiWrapper::sum( numCrossflowPerforations.get() ); + globalIndex const totalNumCrossflowPerforations = MpiWrapper::sum( numCrossflowPerforations ); if( totalNumCrossflowPerforations > 0 ) { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "CompositionalMultiphaseReservoir '{}': Warning! Crossflow detected at {} perforations in well {}" - "To disable crossflow for injectors, you can use the field '{}' in the WellControls '{}' section", - this->getName(), totalNumCrossflowPerforations, subRegion.getName(), - WellControls::viewKeyStruct::enableCrossflowString(), wellControls.getName() ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Crossflow, GEOS_FMT( "CompositionalMultiphaseReservoir '{}': Warning! Crossflow detected at {} perforations in well {}" + "To disable crossflow for injectors, you can use the field '{}' in the WellControls '{}' section", + this->getName(), totalNumCrossflowPerforations, subRegion.getName(), + WellControls::viewKeyStruct::enableCrossflowString(), wellControls.getName() )); } } - } ); - // update dynamically the MGR recipe to optimize the linear solve if all wells are shut - areWellsShut = MpiWrapper::min( areWellsShut ); - m_linearSolverParameters.get().mgr.areWellsShut = areWellsShut; + // update dynamically the MGR recipe to optimize the linear solve if all wells are shut + areWellsShut = MpiWrapper::min( areWellsShut ); + m_linearSolverParameters.get().mgr.areWellsShut = areWellsShut; + } ); } ); } -template class CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase >; -template class CompositionalMultiphaseReservoirAndWells< MultiphasePoromechanics< CompositionalMultiphaseBase > >; +template class CompositionalMultiphaseReservoirAndWells<>; +template class CompositionalMultiphaseReservoirAndWells< MultiphasePoromechanics<> >; namespace { -typedef CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > CompositionalMultiphaseFlowAndWells; -typedef CompositionalMultiphaseReservoirAndWells< MultiphasePoromechanics< CompositionalMultiphaseBase > > CompositionalMultiphasePoromechanicsAndWells; -REGISTER_CATALOG_ENTRY( SolverBase, CompositionalMultiphaseFlowAndWells, string const &, Group * const ) -REGISTER_CATALOG_ENTRY( SolverBase, CompositionalMultiphasePoromechanicsAndWells, string const &, Group * const ) +typedef CompositionalMultiphaseReservoirAndWells<> CompositionalMultiphaseFlowAndWells; +typedef CompositionalMultiphaseReservoirAndWells< MultiphasePoromechanics<> > CompositionalMultiphasePoromechanicsAndWells; +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, CompositionalMultiphaseFlowAndWells, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, CompositionalMultiphasePoromechanicsAndWells, string const &, Group * const ) } } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp index 108dfed9d80..0ceee38fdfe 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,18 +22,20 @@ #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_COMPOSITIONALMULTIPHASERESERVOIRANDWELLS_HPP_ #include "physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp" namespace geos { -template< typename COMPOSITIONAL_RESERVOIR_SOLVER > -class CompositionalMultiphaseReservoirAndWells : public CoupledReservoirAndWellsBase< COMPOSITIONAL_RESERVOIR_SOLVER, +/// @tparam RESERVOIR_SOLVER compositional flow or compositional poromechanics solver +template< typename RESERVOIR_SOLVER = CompositionalMultiphaseBase > +class CompositionalMultiphaseReservoirAndWells : public CoupledReservoirAndWellsBase< RESERVOIR_SOLVER, CompositionalMultiphaseWell > { public: - using Base = CoupledReservoirAndWellsBase< COMPOSITIONAL_RESERVOIR_SOLVER, + using Base = CoupledReservoirAndWellsBase< RESERVOIR_SOLVER, CompositionalMultiphaseWell >; using Base::getLogLevel; using Base::m_solvers; @@ -55,9 +58,20 @@ class CompositionalMultiphaseReservoirAndWells : public CoupledReservoirAndWells * @brief name of the node manager in the object catalog * @return string that contains the catalog name to generate a new NodeManager object through the object catalog. */ - static string catalogName(); + static string catalogName() + { + if constexpr (std::is_same_v< RESERVOIR_SOLVER, CompositionalMultiphaseBase > ) // special case + { + return "CompositionalMultiphaseReservoir"; + } + else // default + { + return RESERVOIR_SOLVER::catalogName() + "Reservoir"; + } + } + /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -71,55 +85,22 @@ class CompositionalMultiphaseReservoirAndWells : public CoupledReservoirAndWells DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; - - void - assembleFluxTerms( real64 const dt, - DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) const - { flowSolver()->assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); } - void - assembleStabilizedFluxTerms( real64 const dt, - DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) const - { flowSolver()->assembleStabilizedFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); } - - void keepFlowVariablesConstantDuringInitStep( bool const keepFlowVariablesConstantDuringInitStep ) - { flowSolver()->keepFlowVariablesConstantDuringInitStep( keepFlowVariablesConstantDuringInitStep ); } - - real64 updateFluidState( ObjectManagerBase & subRegion ) const - { return flowSolver()->updateFluidState( subRegion ); } - void updatePorosityAndPermeability( CellElementSubRegion & subRegion ) const - { flowSolver()->updatePorosityAndPermeability( subRegion ); } - void updateSolidInternalEnergyModel( ObjectManagerBase & dataGroup ) const - { flowSolver()->updateSolidInternalEnergyModel( dataGroup ); } - - integer & isThermal() { return flowSolver()->isThermal(); } + integer isThermal() { return flowSolver()->isThermal(); } integer useSimpleAccumulation() const { return flowSolver()->useSimpleAccumulation(); } integer useTotalMassEquation() const { return flowSolver()->useTotalMassEquation(); } integer numFluidPhases() { return flowSolver()->numFluidPhases(); } integer numFluidComponents() { return flowSolver()->numFluidComponents(); } - void enableFixedStressPoromechanicsUpdate() - { flowSolver()->enableFixedStressPoromechanicsUpdate(); } - - virtual void saveSequentialIterationState( DomainPartition & domain ) const override final { flowSolver()->saveSequentialIterationState( domain ); } - protected: virtual void initializePreSubGroups() override; - virtual void initializePostInitialConditionsPreSubGroups() override; + virtual void setMGRStrategy() override; private: CompositionalMultiphaseBase * flowSolver() const; - void setMGRStrategy(); - }; } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp new file mode 100644 index 00000000000..5fdb80fdf62 --- /dev/null +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp @@ -0,0 +1,593 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalCompositionalMultiphaseWellKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_MULTIPHYSICS_COUPLEDRESERVOIRANDWELLS_HPP +#define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_COUPLEDRESERVOIRANDWELLS_HPP + + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" +#include "physicsSolvers/fluidFlow/wells/WellTags.hpp" +#include "physicsSolvers/fluidFlow/wells/WellFields.hpp" +namespace geos +{ + +namespace coupledReservoirAndWellKernels +{ + +using namespace constitutive; + +/** + * @class FaceBasedAssemblyKernel + * @tparam NUM_COMP number of fluid components + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NC, integer IS_THERMAL > +class IsothermalCompositionalMultiPhaseFluxKernel +{ +public: + + /// Compile time value for the number of components + static constexpr integer numComp = NC; + static constexpr integer resNumDOF = NC+1+IS_THERMAL; + + // Well jacobian column and row indicies + using WJ_COFFSET = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; + using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >; + + using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; + using COFFSET = compositionalMultiphaseWellKernels::ColOffset; + + using CP_Deriv = multifluid::DerivativeOffsetC< NC, IS_THERMAL >; + + using TAG = compositionalMultiphaseWellKernels::SubRegionTag; + + + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = WJ_COFFSET::nDer; + + /// Compile time value for the number of equations except volume and momentum + static constexpr integer numEqn = WJ_ROFFSET::nEqn - 2; + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor + * @param[in] compFlowAccessors + * @param[in] multiFluidAccessors + * @param[in] capPressureAccessors + * @param[in] permeabilityAccessors + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed together + */ + IsothermalCompositionalMultiPhaseFluxKernel( real64 const dt, + globalIndex const rankOffset, + string const wellDofKey, + WellElementSubRegion const & subRegion, + ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, + PerforationData const * const perforationData, + MultiFluidBase const & fluid, + + arrayView1d< real64 > const & localRhs, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + bool const & detectCrossflow, + integer & numCrossFlowPerforations, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags ) + : + m_dt( dt ), + m_numPhases ( fluid.numFluidPhases()), + m_rankOffset( rankOffset ), + m_compPerfRate( perforationData->getField< fields::well::compPerforationRate >() ), + m_dCompPerfRate( perforationData->getField< fields::well::dCompPerforationRate >() ), + m_perfWellElemIndex( perforationData->getField< fields::perforation::wellElementIndex >() ), + m_wellElemDofNumber( subRegion.getReference< array1d< globalIndex > >( wellDofKey ) ), + m_resElemDofNumber( resDofNumber ), + m_resElementRegion( perforationData->getField< fields::perforation::reservoirElementRegion >() ), + m_resElementSubRegion( perforationData->getField< fields::perforation::reservoirElementSubRegion >() ), + m_resElementIndex( perforationData->getField< fields::perforation::reservoirElementIndex >() ), + m_localRhs( localRhs ), + m_localMatrix( localMatrix ), + m_detectCrossflow( detectCrossflow ), + m_numCrossFlowPerforations( numCrossFlowPerforations ), + m_useTotalMassEquation ( kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ) ) + { } + + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes + * @param[in] ie the element index + * @param[inout] stack the stack variables + * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes + */ + + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void computeFlux( localIndex const iperf, + FUNC && compFluxKernelOp = NoOpFunc{} ) const + { + + using namespace compositionalMultiphaseUtilities; + // local working variables and arrays + stackArray1d< localIndex, 2* numComp > eqnRowIndices( 2 * numComp ); + stackArray1d< globalIndex, 2*resNumDOF > dofColIndices( 2 * resNumDOF ); + + stackArray1d< real64, 2 * numComp > localPerf( 2 * numComp ); + stackArray2d< real64, 2 * resNumDOF * 2 * numComp > localPerfJacobian( 2 * numComp, 2 * resNumDOF ); + + // get the reservoir (sub)region and element indices + localIndex const er = m_resElementRegion[iperf]; + localIndex const esr = m_resElementSubRegion[iperf]; + localIndex const ei = m_resElementIndex[iperf]; + + // get the well element index for this perforation + localIndex const iwelem = m_perfWellElemIndex[iperf]; + globalIndex const resOffset = m_resElemDofNumber[er][esr][ei]; + globalIndex const wellElemOffset = m_wellElemDofNumber[iwelem]; + + for( integer ic = 0; ic < numComp; ++ic ) + { + eqnRowIndices[TAG::RES * numComp + ic] = LvArray::integerConversion< localIndex >( resOffset - m_rankOffset ) + ic; + eqnRowIndices[TAG::WELL * numComp + ic] = LvArray::integerConversion< localIndex >( wellElemOffset - m_rankOffset ) + WJ_ROFFSET::MASSBAL + ic; + } + // Note res and well have same col lineup for P and compdens + for( integer jdof = 0; jdof < NC+1; ++jdof ) + { + dofColIndices[TAG::RES * resNumDOF + jdof] = resOffset + jdof; + dofColIndices[TAG::WELL * resNumDOF + jdof] = wellElemOffset + WJ_COFFSET::dP + jdof; + } + // For temp its different + if constexpr ( IS_THERMAL ) + { + dofColIndices[TAG::RES * resNumDOF + NC+1 ] = resOffset + NC+1; + dofColIndices[TAG::WELL * resNumDOF + NC+1 ] = wellElemOffset + WJ_COFFSET::dT; + } + // populate local flux vector and derivatives + for( integer ic = 0; ic < numComp; ++ic ) + { + localPerf[TAG::RES * numComp + ic] = m_dt * m_compPerfRate[iperf][ic]; + localPerf[TAG::WELL * numComp + ic] = -m_dt * m_compPerfRate[iperf][ic]; + + if( m_detectCrossflow ) + { + if( m_compPerfRate[iperf][ic] > LvArray::NumericLimits< real64 >::epsilon ) + { + m_numCrossFlowPerforations += 1; + } + } + for( integer ke = 0; ke < 2; ++ke ) + { + localIndex localDofIndexPres = ke * resNumDOF; + + localPerfJacobian[TAG::RES * numComp + ic][localDofIndexPres] = m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dP]; + localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexPres] = -m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dP]; + for( integer jc = 0; jc < numComp; ++jc ) + { + localIndex const localDofIndexComp = localDofIndexPres + jc + 1; + + localPerfJacobian[TAG::RES * numComp + ic][localDofIndexComp] = m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc]; + localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexComp] = -m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc]; + } + if constexpr ( IS_THERMAL ) + { + localIndex localDofIndexTemp = localDofIndexPres + NC + 1; + localPerfJacobian[TAG::RES * numComp + ic][localDofIndexTemp] = m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dT]; + localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexTemp] = -m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dT]; + } + } + } + + if( m_useTotalMassEquation ) + { + // Apply equation/variable change transformation(s) + stackArray1d< real64, 2 * resNumDOF > work( 2 * resNumDOF ); + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numComp, resNumDOF * 2, 2, localPerfJacobian, work ); + shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numComp, numComp, 2, localPerf ); + } + + for( localIndex i = 0; i < localPerf.size(); ++i ) + { + if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], + dofColIndices.data(), + localPerfJacobian[i].dataIfContiguous(), + 2 * resNumDOF ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localPerf[i] ); + } + } + compFluxKernelOp( resOffset, wellElemOffset, dofColIndices, iwelem ); + + } + + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElements the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack + * variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElements, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const ie ) + { + kernelComponent.computeFlux( ie ); + + } ); + } + +protected: + + /// Time step size + real64 const m_dt; + + /// Number of phases + integer const m_numPhases; + + globalIndex const m_rankOffset; + // Perfoation variables + arrayView2d< real64 const > const m_compPerfRate; + arrayView4d< real64 const > const m_dCompPerfRate; + arrayView1d< localIndex const > const m_perfWellElemIndex; + + // Element region, subregion, index + arrayView1d< globalIndex const > const m_wellElemDofNumber; + ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const m_resElemDofNumber; + arrayView1d< localIndex const > const m_resElementRegion; + arrayView1d< localIndex const > const m_resElementSubRegion; + arrayView1d< localIndex const > const m_resElementIndex; + + // RHS and Jacobian + arrayView1d< real64 > const m_localRhs; + CRSMatrixView< real64, globalIndex const > m_localMatrix; + + bool const m_detectCrossflow; + integer & m_numCrossFlowPerforations; + integer const m_useTotalMassEquation; +}; + +/** + * @class FaceBasedAssemblyKernelFactory + */ +class IsothermalCompositionalMultiPhaseFluxKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] dt time step size + * @param[in] rankOffset the offset of my MPI rank + * @param[in] useTotalMassEquation flag specifying whether to replace one component bal eqn with total mass eqn + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] wellControls object holding well control/constraint information + * @param[in] subregion well subregion + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComps, + real64 const dt, + globalIndex const rankOffset, + string const wellDofKey, + WellElementSubRegion const & subRegion, + ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, + PerforationData const * const perforationData, + MultiFluidBase const & fluid, + integer const & useTotalMassEquation, + bool const & detectCrossflow, + integer & numCrossFlowPerforations, + arrayView1d< real64 > const & localRhs, + CRSMatrixView< real64, globalIndex const > const & localMatrix + ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + + + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ); + + + using kernelType = IsothermalCompositionalMultiPhaseFluxKernel< NUM_COMP, 0 >; + + + kernelType kernel( dt, rankOffset, wellDofKey, subRegion, resDofNumber, perforationData, fluid, localRhs, localMatrix, detectCrossflow, numCrossFlowPerforations, kernelFlags ); + kernelType::template launch< POLICY >( perforationData->size(), kernel ); + } ); + + } +}; + + +/** + * @class FaceBasedAssemblyKernel + * @tparam NUM_COMP number of fluid components + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NC, integer IS_THERMAL > +class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalMultiPhaseFluxKernel< NC, IS_THERMAL > +{ +public: + using Base = IsothermalCompositionalMultiPhaseFluxKernel< NC, IS_THERMAL >; + /// Compile time value for the number of components + static constexpr integer numComp = NC; + static constexpr integer resNumDOF = NC+1+IS_THERMAL; + + // Well jacobian column and row indicies + using WJ_COFFSET = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; + using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >; + + using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; + using COFFSET = compositionalMultiphaseWellKernels::ColOffset; + + using CP_Deriv = multifluid::DerivativeOffsetC< NC, IS_THERMAL >; + + using TAG = compositionalMultiphaseWellKernels::SubRegionTag; + + using Base::m_dt; + using Base::m_localRhs; + using Base::m_localMatrix; + using Base::m_rankOffset; + + + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = WJ_COFFSET::nDer; + + /// Compile time value for the number of equations except volume and momentum + static constexpr integer numEqn = WJ_ROFFSET::nEqn - 2; + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor + * @param[in] compFlowAccessors + * @param[in] multiFluidAccessors + * @param[in] capPressureAccessors + * @param[in] permeabilityAccessors + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed together + */ + ThermalCompositionalMultiPhaseFluxKernel( real64 const dt, + integer const isProducer, + globalIndex const rankOffset, + string const wellDofKey, + WellElementSubRegion const & subRegion, + ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, + PerforationData const * const perforationData, + MultiFluidBase const & fluid, + arrayView1d< real64 > const & localRhs, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + bool const & detectCrossflow, + integer & numCrossFlowPerforations, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags ) + : Base( dt, + rankOffset, + wellDofKey, + subRegion, + resDofNumber, + perforationData, + fluid, + localRhs, + localMatrix, + detectCrossflow, + numCrossFlowPerforations, + kernelFlags ), + m_isProducer( isProducer ), + m_globalWellElementIndex( subRegion.getGlobalWellElementIndex() ), + m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()), + m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()) + + { } + + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes + * @param[in] ie the element index + * @param[inout] stack the stack variables + * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes + */ + + GEOS_HOST_DEVICE + inline + void computeFlux( localIndex const iperf ) const + { + Base::computeFlux( iperf, [&] ( globalIndex const & resOffset, + globalIndex const & wellElemOffset, + stackArray1d< globalIndex, 2*resNumDOF > & dofColIndices, + localIndex const iwelem ) + { + // No energy equation if top element and Injector + // Top element defined by global index == 0 + // Assumption is global index == 0 is top segment with fixed temp BC + if( !m_isProducer ) + { + if( m_globalWellElementIndex[iwelem] == 0 ) + return; + } + // local working variables and arrays + stackArray1d< localIndex, 2* numComp > eqnRowIndices( 2 ); + + stackArray1d< real64, 2 * numComp > localPerf( 2 ); + stackArray2d< real64, 2 * resNumDOF * 2 * numComp > localPerfJacobian( 2, 2 * resNumDOF ); + + + // equantion offsets - note res and well have different equation lineups + eqnRowIndices[TAG::RES ] = LvArray::integerConversion< localIndex >( resOffset - m_rankOffset ) + NC + 1; + eqnRowIndices[TAG::WELL ] = LvArray::integerConversion< localIndex >( wellElemOffset - m_rankOffset ) + WJ_ROFFSET::ENERGYBAL; + + // populate local flux vector and derivatives + localPerf[TAG::RES ] = m_dt * m_energyPerfFlux[iperf]; + localPerf[TAG::WELL ] = -m_dt * m_energyPerfFlux[iperf]; + + for( integer ke = 0; ke < 2; ++ke ) + { + localIndex localDofIndexPres = ke * resNumDOF; + localPerfJacobian[TAG::RES ][localDofIndexPres] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dP]; + localPerfJacobian[TAG::WELL ][localDofIndexPres] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dP]; + + // populate local flux vector and derivatives + for( integer ic = 0; ic < numComp; ++ic ) + { + localIndex const localDofIndexComp = localDofIndexPres + ic + 1; + localPerfJacobian[TAG::RES ][localDofIndexComp] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dC+ic]; + localPerfJacobian[TAG::WELL][localDofIndexComp] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dC+ic]; + } + localPerfJacobian[TAG::RES ][localDofIndexPres+NC+1] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dT]; + localPerfJacobian[TAG::WELL][localDofIndexPres+NC+1] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dT]; + } + + + for( localIndex i = 0; i < localPerf.size(); ++i ) + { + if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], + dofColIndices.data(), + localPerfJacobian[i].dataIfContiguous(), + 2 * resNumDOF ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localPerf[i] ); + } + } + } ); + + + } + + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElements the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack + * variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElements, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const ie ) + { + kernelComponent.computeFlux( ie ); + + } ); + } + +protected: + + /// Well type + integer const m_isProducer; + + /// Global index of local element + arrayView1d< globalIndex const > m_globalWellElementIndex; + + /// Views on energy flux + arrayView1d< real64 const > const m_energyPerfFlux; + arrayView3d< real64 const > const m_dEnergyPerfFlux; +}; + +/** + * @class ThermalCompositionalMultiPhaseFluxKernelFactory + */ +class ThermalCompositionalMultiPhaseFluxKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] dt time step size + * @param[in] rankOffset the offset of my MPI rank + * @param[in] useTotalMassEquation flag specifying whether to replace one component bal eqn with total mass eqn + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] wellControls object holding well control/constraint information + * @param[in] subregion well subregion + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComps, + integer const isProducer, + real64 const dt, + globalIndex const rankOffset, + string const wellDofKey, + WellElementSubRegion const & subRegion, + ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, + PerforationData const * const perforationData, + MultiFluidBase const & fluid, + integer const & useTotalMassEquation, + bool const & detectCrossflow, + integer & numCrossFlowPerforations, + arrayView1d< real64 > const & localRhs, + CRSMatrixView< real64, globalIndex const > const & localMatrix + ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + + + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ); + + + using kernelType = ThermalCompositionalMultiPhaseFluxKernel< NUM_COMP, 1 >; + + + kernelType kernel( dt, isProducer, rankOffset, wellDofKey, subRegion, resDofNumber, perforationData, fluid, localRhs, localMatrix, detectCrossflow, numCrossFlowPerforations, kernelFlags ); + kernelType::template launch< POLICY >( perforationData->size(), kernel ); + } ); + + } +}; + +} // end namespace coupledReservoirAndWellKernels + +} // end namespace geos + +#endif // GEOS_PHYSICSSOLVERS_MULTIPHYSICS_COUPLEDRESERVOIRANDWELLS_HPP diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.cpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.cpp index 1ca8d0b1385..631a5ee6cd3 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -26,7 +27,7 @@ namespace coupledReservoirAndWellsInternal { void -addCouplingNumNonzeros( SolverBase const * const solver, +addCouplingNumNonzeros( PhysicsSolverBase const * const solver, DomainPartition & domain, DofManager & dofManager, arrayView1d< localIndex > const & rowLengths, @@ -110,14 +111,14 @@ addCouplingNumNonzeros( SolverBase const * const solver, } ); } -bool validateWellPerforations( SolverBase const * const reservoirSolver, +bool validateWellPerforations( PhysicsSolverBase const * const reservoirSolver, WellSolverBase const * const wellSolver, DomainPartition const & domain ) { std::pair< string, string > badPerforation; arrayView1d< string const > const flowTargetRegionNames = - reservoirSolver->getReference< array1d< string > >( SolverBase::viewKeyStruct::targetRegionsString() ); + reservoirSolver->getReference< array1d< string > >( PhysicsSolverBase::viewKeyStruct::targetRegionsString() ); wellSolver->forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel const & meshLevel, diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.hpp index e08ccb8ea4a..c40265648f1 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -26,6 +27,7 @@ #include "constitutive/permeability/PermeabilityFields.hpp" #include "constitutive/permeability/PermeabilityBase.hpp" #include "mesh/PerforationFields.hpp" +#include "mesh/DomainPartition.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBase.hpp" @@ -46,7 +48,7 @@ namespace coupledReservoirAndWellsInternal * @param wellElemDofName name of the well element dofs */ void -addCouplingNumNonzeros( SolverBase const * const solver, +addCouplingNumNonzeros( PhysicsSolverBase const * const solver, DomainPartition & domain, DofManager & dofManager, arrayView1d< localIndex > const & rowLengths, @@ -62,7 +64,7 @@ addCouplingNumNonzeros( SolverBase const * const solver, * @param wellSolver the well solver * @param domain the physical domain object */ -bool validateWellPerforations( SolverBase const * const reservoirSolver, +bool validateWellPerforations( PhysicsSolverBase const * const reservoirSolver, WellSolverBase const * const wellSolver, DomainPartition const & domain ); @@ -126,7 +128,8 @@ class CoupledReservoirAndWellsBase : public CoupledSolver< RESERVOIR_SOLVER, WEL { GEOS_MARK_FUNCTION; - GEOS_UNUSED_VAR( setSparsity ); + // call reservoir solver setup (needed in case of SinglePhasePoromechanicsConformingFractures) + reservoirSolver()->setupSystem( domain, dofManager, localMatrix, rhs, solution, setSparsity ); dofManager.setDomain( domain ); @@ -166,10 +169,10 @@ class CoupledReservoirAndWellsBase : public CoupledSolver< RESERVOIR_SOLVER, WEL localMatrix.setName( this->getName() + "/localMatrix" ); rhs.setName( this->getName() + "/rhs" ); - rhs.create( dofManager.numLocalDofs(), MPI_COMM_GEOSX ); + rhs.create( dofManager.numLocalDofs(), MPI_COMM_GEOS ); solution.setName( this->getName() + "/solution" ); - solution.create( dofManager.numLocalDofs(), MPI_COMM_GEOSX ); + solution.create( dofManager.numLocalDofs(), MPI_COMM_GEOS ); } /**@}*/ @@ -198,10 +201,18 @@ class CoupledReservoirAndWellsBase : public CoupledSolver< RESERVOIR_SOLVER, WEL // Validate well perforations: Ensure that each perforation is in a region targeted by the solver if( !validateWellPerforations( domain )) { - return; + GEOS_ERROR( GEOS_FMT( "{}: well perforations validation failed, bad perforations found", this->getName())); } } + virtual void + postInputInitialization() override + { + Base::postInputInitialization(); + + setMGRStrategy(); + } + virtual void implicitStepSetup( real64 const & time_n, real64 const & dt, @@ -220,6 +231,46 @@ class CoupledReservoirAndWellsBase : public CoupledSolver< RESERVOIR_SOLVER, WEL } } + void + assembleFluxTerms( real64 const dt, + DomainPartition const & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) const + { reservoirSolver()->assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); } + + void + assembleStabilizedFluxTerms( real64 const dt, + DomainPartition const & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) const + { reservoirSolver()->assembleStabilizedFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); } + + real64 updateFluidState( ElementSubRegionBase & subRegion ) const + { return reservoirSolver()->updateFluidState( subRegion ); } + void updatePorosityAndPermeability( CellElementSubRegion & subRegion ) const + { reservoirSolver()->updatePorosityAndPermeability( subRegion ); } + void updateSolidInternalEnergyModel( ObjectManagerBase & dataGroup ) const + { reservoirSolver()->updateSolidInternalEnergyModel( dataGroup ); } + + integer & isThermal() { return reservoirSolver()->isThermal(); } + + void enableJumpStabilization() + { reservoirSolver()->enableJumpStabilization(); } + + void enableFixedStressPoromechanicsUpdate() + { reservoirSolver()->enableFixedStressPoromechanicsUpdate(); } + + void setKeepVariablesConstantDuringInitStep( bool const keepVariablesConstantDuringInitStep ) + { + reservoirSolver()->setKeepVariablesConstantDuringInitStep( keepVariablesConstantDuringInitStep ); + wellSolver()->setKeepVariablesConstantDuringInitStep( keepVariablesConstantDuringInitStep ); + } + + virtual void saveSequentialIterationState( DomainPartition & domain ) override + { reservoirSolver()->saveSequentialIterationState( domain ); } + protected: /** @@ -255,6 +306,12 @@ class CoupledReservoirAndWellsBase : public CoupledSolver< RESERVOIR_SOLVER, WEL DofManager const & dofManager, SparsityPatternView< globalIndex > const & pattern ) const = 0; + virtual void setMGRStrategy() + { + if( this->m_linearSolverParameters.get().preconditionerType == LinearSolverParameters::PreconditionerType::mgr ) + GEOS_ERROR( GEOS_FMT( "{}: MGR strategy is not implemented for {}", this->getName(), this->getCatalogName())); + } + /// Flag to determine whether the well transmissibility needs to be computed bool m_isWellTransmissibilityComputed; @@ -324,12 +381,12 @@ class CoupledReservoirAndWellsBase : public CoupledSolver< RESERVOIR_SOLVER, WEL forAll< serialPolicy >( perforationData.size(), [=] ( localIndex const iperf ) { GEOS_UNUSED_VAR( iperf ); // unused if geos_error_if is nulld - GEOS_LOG_RANK( GEOS_FMT( "Perforation at ({},{},{}); perforated element center: ({},{},{}); transmissibility: {} Pa.s.rm^3/s/Pa", - perfLocation[iperf][0], perfLocation[iperf][1], perfLocation[iperf][2], + GEOS_LOG_RANK( GEOS_FMT( "{}: perforation at ({},{},{}), perforated element center = ({},{},{}), transmissibility = {} [{}]", + this->getName(), perfLocation[iperf][0], perfLocation[iperf][1], perfLocation[iperf][2], elemCenter[resElemRegion[iperf]][resElemSubRegion[iperf]][resElemIndex[iperf]][0], elemCenter[resElemRegion[iperf]][resElemSubRegion[iperf]][resElemIndex[iperf]][1], elemCenter[resElemRegion[iperf]][resElemSubRegion[iperf]][resElemIndex[iperf]][2], - perfTrans[iperf] ) ); + perfTrans[iperf], getSymbol( units::Transmissibility ) ) ); } ); } } ); diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledSolver.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledSolver.hpp index 61b69720a39..8517edb3dfe 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CoupledSolver.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledSolver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,8 @@ #ifndef GEOS_PHYSICSSOLVERS_MULTIPHYSICS_COUPLEDSOLVER_HPP_ #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_COUPLEDSOLVER_HPP_ -#include "physicsSolvers/SolverBase.hpp" +#include "physicsSolvers/PhysicsSolverBase.hpp" +#include "physicsSolvers/multiphysics/LogLevelsInfo.hpp" #include @@ -28,7 +30,7 @@ namespace geos { template< typename ... SOLVERS > -class CoupledSolver : public SolverBase +class CoupledSolver : public PhysicsSolverBase { public: @@ -40,7 +42,7 @@ class CoupledSolver : public SolverBase */ CoupledSolver( const string & name, Group * const parent ) - : SolverBase( name, parent ) + : PhysicsSolverBase( name, parent ) { forEachArgInTuple( m_solvers, [&]( auto solver, auto idx ) { @@ -52,8 +54,10 @@ class CoupledSolver : public SolverBase setDescription( "Name of the " + SolverType::coupledSolverAttributePrefix() + " solver used by the coupled solver" ); } ); - this->getWrapper< string >( SolverBase::viewKeyStruct::discretizationString() ). + this->getWrapper< string >( PhysicsSolverBase::viewKeyStruct::discretizationString() ). setInputFlag( dataRepository::InputFlags::FALSE ); + + addLogLevel< logInfo::Coupling >(); } /// deleted copy constructor @@ -87,7 +91,7 @@ class CoupledSolver : public SolverBase getDataContext(), solverName, solverType ), InputError ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: found {} solver named {}", getName(), solver->catalogName(), solverName ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Coupling, GEOS_FMT( "{}: found {} solver named {}", getName(), solver->getCatalogName(), solverName ) ); } ); } @@ -161,6 +165,7 @@ class CoupledSolver : public SolverBase } ); } + // general version of assembleSystem function, keep in mind many solvers will override it virtual void assembleSystem( real64 const time_n, real64 const dt, @@ -171,18 +176,13 @@ class CoupledSolver : public SolverBase { /// Fully-coupled assembly. - // 1. we sync the nonlinear convergence history. The coupled solver parameters are the one being - // used. We want to propagate the info to subsolvers. It can be important for solvers that - // have special treatment for specific iterations. - synchronizeNonLinearParameters(); - - // 2. Assemble matrix blocks of each individual solver + // 1. Assemble matrix blocks of each individual solver forEachArgInTuple( m_solvers, [&]( auto & solver, auto ) { solver->assembleSystem( time_n, dt, domain, dofManager, localMatrix, localRhs ); } ); - // 3. Assemble coupling blocks + // 2. Assemble coupling blocks assembleCouplingTerms( time_n, dt, domain, dofManager, localMatrix, localRhs ); } @@ -285,6 +285,10 @@ class CoupledSolver : public SolverBase forEachArgInTuple( m_solvers, [&]( auto & solver, auto ) { bool const validSinglePhysicsSolution = solver->checkSystemSolution( domain, dofManager, localSolution, scalingFactor ); + if( !validSinglePhysicsSolution ) + { + GEOS_LOG_RANK_0( GEOS_FMT( " {}/{}: Solution check failed. Newton loop terminated.", getName(), solver->getName()) ); + } validSolution = validSolution && validSinglePhysicsSolution; } ); return validSolution; @@ -320,7 +324,7 @@ class CoupledSolver : public SolverBase virtual real64 setNextDtBasedOnNewtonIter( real64 const & currentDt ) override { - real64 nextDt = SolverBase::setNextDtBasedOnNewtonIter( currentDt ); + real64 nextDt = PhysicsSolverBase::setNextDtBasedOnNewtonIter( currentDt ); forEachArgInTuple( m_solvers, [&]( auto & solver, auto ) { real64 const singlePhysicsNextDt = @@ -340,7 +344,7 @@ class CoupledSolver : public SolverBase { solver->cleanup( time_n, cycleNumber, eventCounter, eventProgress, domain ); } ); - SolverBase::cleanup( time_n, cycleNumber, eventCounter, eventProgress, domain ); + PhysicsSolverBase::cleanup( time_n, cycleNumber, eventCounter, eventProgress, domain ); } /**@}*/ @@ -355,14 +359,42 @@ class CoupledSolver : public SolverBase return isConverged; } - virtual void saveSequentialIterationState( DomainPartition & domain ) const override + virtual bool updateConfiguration( DomainPartition & domain ) override + { + bool result = true; + forEachArgInTuple( m_solvers, [&]( auto & solver, auto ) + { + result &= solver->updateConfiguration( domain ); + } ); + return result; + } + + virtual void outputConfigurationStatistics( DomainPartition const & domain ) const override + { + forEachArgInTuple( m_solvers, [&]( auto & solver, auto ) + { + solver->outputConfigurationStatistics( domain ); + } ); + } + + virtual void resetConfigurationToBeginningOfStep( DomainPartition & domain ) override { forEachArgInTuple( m_solvers, [&]( auto & solver, auto ) { - solver->saveSequentialIterationState( domain ); + solver->resetConfigurationToBeginningOfStep( domain ); } ); } + virtual bool resetConfigurationToDefault( DomainPartition & domain ) const override + { + bool result = true; + forEachArgInTuple( m_solvers, [&]( auto & solver, auto ) + { + result &= solver->resetConfigurationToDefault( domain ); + } ); + return result; + } + protected: /** @@ -379,7 +411,7 @@ class CoupledSolver : public SolverBase int const cycleNumber, DomainPartition & domain ) { - return SolverBase::solverStep( time_n, dt, cycleNumber, domain ); + return PhysicsSolverBase::solverStep( time_n, dt, cycleNumber, domain ); } /** @@ -441,9 +473,9 @@ class CoupledSolver : public SolverBase resetStateToBeginningOfStep( domain ); integer & iter = solverParams.m_numNewtonIterations; - iter = 0; + /// Sequential coupling loop - while( iter < solverParams.m_maxIterNewton ) + for( iter = 0; iter < solverParams.m_maxIterNewton; iter++ ) { // Increment the solver statistics for reporting purposes // Pass a "0" as argument (0 linear iteration) to skip the output of linear iteration stats at the end @@ -454,12 +486,15 @@ class CoupledSolver : public SolverBase // Solve the subproblems nonlinearly forEachArgInTuple( m_solvers, [&]( auto & solver, auto idx ) { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " Iteration {:2}: {}", iter + 1, solver->getName() ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::NonlinearSolver, GEOS_FMT( " Iteration {:2}: {}", iter + 1, solver->getName() ) ); real64 solverDt = solver->nonlinearImplicitStep( time_n, stepDt, cycleNumber, domain ); + // save fields (e.g. pressure and temperature) after inner solve + solver->saveSequentialIterationState( domain ); + mapSolutionBetweenSolvers( domain, idx() ); if( solverDt < stepDt ) // subsolver had to cut the time step @@ -475,11 +510,10 @@ class CoupledSolver : public SolverBase stepDt, domain ); - // save fields (e.g. pressure and temperature) at the end of this iteration - saveSequentialIterationState( domain ); - if( isConverged ) { + // we still want to count current iteration + ++iter; // exit outer loop break; } @@ -487,8 +521,6 @@ class CoupledSolver : public SolverBase { finishSequentialIteration( iter, domain ); } - - ++iter; } if( isConverged ) @@ -505,7 +537,7 @@ class CoupledSolver : public SolverBase { // cut timestep, go back to beginning of step and restart the Newton loop stepDt *= dtCutFactor; - GEOS_LOG_LEVEL_RANK_0 ( 1, GEOS_FMT( "New dt = {}", stepDt ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( "New dt = {}", stepDt ) ); // notify the solver statistics counter that this is a time step cut m_solverStatistics.logTimeStepCut(); @@ -547,21 +579,21 @@ class CoupledSolver : public SolverBase GEOS_UNUSED_VAR( domain, solverType ); } - bool checkSequentialConvergence( int const & iter, - real64 const & time_n, - real64 const & dt, - DomainPartition & domain ) + virtual bool checkSequentialConvergence( int const & iter, + real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) { NonlinearSolverParameters const & params = getNonlinearSolverParameters(); bool isConverged = true; if( params.m_subcyclingOption == 0 ) { - GEOS_LOG_LEVEL_RANK_0( 1, "***** Single Pass solver, no subcycling *****" ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Convergence, "***** Single Pass solver, no subcycling *****" ); } else { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " Iteration {:2}: outer-loop convergence check", iter + 1 ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Convergence, GEOS_FMT( " Iteration {:2}: outer-loop convergence check", iter + 1 ) ); if( params.sequentialConvergenceCriterion() == NonlinearSolverParameters::SequentialConvergenceCriterion::ResidualNorm ) { @@ -602,7 +634,7 @@ class CoupledSolver : public SolverBase // finally, we perform the convergence check on the multiphysics residual residualNorm = sqrt( residualNorm ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " ( R ) = ( {:4.2e} )", residualNorm ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Convergence, GEOS_FMT( " ( R ) = ( {:4.2e} )", residualNorm ) ); isConverged = ( residualNorm < params.m_newtonTol ); } @@ -629,14 +661,14 @@ class CoupledSolver : public SolverBase if( isConverged ) { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "***** The iterative coupling has converged in {} iteration(s) *****", iter + 1 ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Convergence, GEOS_FMT( "***** The iterative coupling has converged in {} iteration(s) *****", iter + 1 ) ); } } return isConverged; } virtual void - postProcessInput() override + postInputInitialization() override { setSubSolvers(); @@ -644,13 +676,18 @@ class CoupledSolver : public SolverBase bool const usesLineSearch = getNonlinearSolverParameters().m_lineSearchAction != NonlinearSolverParameters::LineSearchAction::None; GEOS_THROW_IF( isSequential && usesLineSearch, GEOS_FMT( "{}: line search is not supported by the coupled solver when {} is set to `{}`. Please set {} to `{}` to remove this error", - getWrapperDataContext( NonlinearSolverParameters::viewKeysStruct::couplingTypeString() ), + getNonlinearSolverParameters().getWrapperDataContext( NonlinearSolverParameters::viewKeysStruct::couplingTypeString() ), NonlinearSolverParameters::viewKeysStruct::couplingTypeString(), EnumStrings< NonlinearSolverParameters::CouplingType >::toString( NonlinearSolverParameters::CouplingType::Sequential ), NonlinearSolverParameters::viewKeysStruct::lineSearchActionString(), EnumStrings< NonlinearSolverParameters::LineSearchAction >::toString( NonlinearSolverParameters::LineSearchAction::None ) ), InputError ); + if( !isSequential ) + { + synchronizeNonlinearSolverParameters(); + } + if( m_nonlinearSolverParameters.m_nonlinearAccelerationType != NonlinearSolverParameters::NonlinearAccelerationType::None ) validateNonlinearAcceleration(); } @@ -664,12 +701,12 @@ class CoupledSolver : public SolverBase InputError ); } - void - synchronizeNonLinearParameters() + virtual void + synchronizeNonlinearSolverParameters() override { forEachArgInTuple( m_solvers, [&]( auto & solver, auto ) { - solver->getNonlinearSolverParameters() = m_nonlinearSolverParameters; + solver->getNonlinearSolverParameters() = getNonlinearSolverParameters(); } ); } diff --git a/src/coreComponents/physicsSolvers/multiphysics/FlowProppantTransportSolver.cpp b/src/coreComponents/physicsSolvers/multiphysics/FlowProppantTransportSolver.cpp index 17ee134ba24..fe329e26569 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/FlowProppantTransportSolver.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/FlowProppantTransportSolver.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -101,7 +102,7 @@ real64 FlowProppantTransportSolver::sequentiallyCoupledSolverStep( real64 const resetStateToBeginningOfStep( domain ); } - GEOS_LOG_LEVEL_RANK_0( 1, " Iteration: " << iter+1 << ", FlowSolver: " ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::NonlinearSolver, GEOS_FMT( " Iteration: {}, FlowSolver: ", iter+1 ) ); dtReturnTemporary = flowSolver()->nonlinearImplicitStep( time_n, dtReturn, cycleNumber, domain ); @@ -116,11 +117,11 @@ real64 FlowProppantTransportSolver::sequentiallyCoupledSolverStep( real64 const if( fluidNonLinearParams.m_numNewtonIterations <= this->m_nonlinearSolverParameters.m_minIterNewton && iter > 0 ) { m_solverStatistics.logNonlinearIteration(); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "***** The iterative coupling has converged in {} iterations *****", iter ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Convergence, GEOS_FMT( "***** The iterative coupling has converged in {} iterations *****", iter ) ); break; } - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " Iteration: {}, Proppant Solver: ", iter+1 ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::NonlinearSolver, GEOS_FMT( " Iteration: {}, Proppant Solver: ", iter+1 ) ); dtReturnTemporary = proppantTransportSolver()->nonlinearImplicitStep( time_n, dtReturn, cycleNumber, domain ); @@ -139,6 +140,6 @@ real64 FlowProppantTransportSolver::sequentiallyCoupledSolverStep( real64 const return dtReturn; } -REGISTER_CATALOG_ENTRY( SolverBase, FlowProppantTransportSolver, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, FlowProppantTransportSolver, string const &, Group * const ) } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/multiphysics/FlowProppantTransportSolver.hpp b/src/coreComponents/physicsSolvers/multiphysics/FlowProppantTransportSolver.hpp index 91539a4b814..9b14cea8309 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/FlowProppantTransportSolver.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/FlowProppantTransportSolver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -62,7 +63,7 @@ class FlowProppantTransportSolver : public CoupledSolver< ProppantTransport, */ static string catalogName() { return "FlowProppantTransport"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } diff --git a/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.cpp b/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.cpp index 46d83cd528c..c11d99f3fad 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOS Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,16 +17,20 @@ * @file HydrofractureSolver.cpp */ - #include "HydrofractureSolver.hpp" -#include "constitutive/contact/ContactSelector.hpp" +#include "constitutive/contact/HydraulicApertureRelationSelector.hpp" #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" +#include "constitutive/fluid/singlefluid/SingleFluidFields.hpp" #include "physicsSolvers/multiphysics/HydrofractureSolverKernels.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsFields.hpp" #include "physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp" #include "physicsSolvers/multiphysics/MultiphasePoromechanics.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" +#include "physicsSolvers/surfaceGeneration/LogLevelsInfo.hpp" +#include "dataRepository/LogLevelsInfo.hpp" +#include "mesh/MeshFields.hpp" +#include "finiteVolume/FluxApproximationBase.hpp" namespace geos { @@ -34,59 +39,21 @@ using namespace constitutive; using namespace dataRepository; using namespace fields; - -namespace -{ - -// This is meant to be specialized to work, see below -template< typename POROMECHANICS_SOLVER > class - HydrofractureSolverCatalogNames {}; - -// Class specialization for a POROMECHANICS_SOLVER set to SinglePhasePoromechanics -template<> class HydrofractureSolverCatalogNames< SinglePhasePoromechanics< SinglePhaseBase > > -{ -public: - static string name() { return "Hydrofracture"; } -}; - -// Class specialization for a POROMECHANICS_SOLVER set to MultiphasePoromechanics -template<> class HydrofractureSolverCatalogNames< MultiphasePoromechanics< CompositionalMultiphaseBase > > -{ -public: - static string name() { return "MultiphaseHydrofracture"; } -}; -} - -// provide a definition for catalogName() -template< typename POROMECHANICS_SOLVER > -string -HydrofractureSolver< POROMECHANICS_SOLVER >:: -catalogName() -{ - return HydrofractureSolverCatalogNames< POROMECHANICS_SOLVER >::name(); -} - - template< typename POROMECHANICS_SOLVER > HydrofractureSolver< POROMECHANICS_SOLVER >::HydrofractureSolver( const string & name, Group * const parent ) : Base( name, parent ), - m_contactRelationName(), m_surfaceGeneratorName(), m_surfaceGenerator( nullptr ), m_maxNumResolves( 10 ), - m_isMatrixPoroelastic() + m_isMatrixPoroelastic(), + m_newFractureInitializationType() { registerWrapper( viewKeyStruct::surfaceGeneratorNameString(), &m_surfaceGeneratorName ). setRTTypeName( rtTypes::CustomTypes::groupNameRef ). setInputFlag( InputFlags::REQUIRED ). setDescription( "Name of the surface generator to use in the hydrofracture solver" ); - registerWrapper( viewKeyStruct::contactRelationNameString(), &m_contactRelationName ). - setRTTypeName( rtTypes::CustomTypes::groupNameRef ). - setInputFlag( InputFlags::REQUIRED ). - setDescription( "Name of contact relation to enforce constraints on fracture boundary." ); - registerWrapper( viewKeyStruct::maxNumResolvesString(), &m_maxNumResolves ). setApplyDefaultValue( 10 ). setInputFlag( InputFlags::OPTIONAL ). @@ -96,18 +63,41 @@ HydrofractureSolver< POROMECHANICS_SOLVER >::HydrofractureSolver( const string & setApplyDefaultValue( 0 ). setInputFlag( InputFlags::OPTIONAL ); + /// GEOS mainly initializes pressure in the new fracture elements. + registerWrapper( viewKeyStruct::newFractureInitializationTypeString(), &m_newFractureInitializationType ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( InitializationType::Pressure ). + setDescription( "Type of new fracture element initialization. Can be Pressure or Displacement. " ); + registerWrapper( viewKeyStruct::useQuasiNewtonString(), &m_useQuasiNewton ). setApplyDefaultValue( 0 ). setInputFlag( InputFlags::OPTIONAL ); + Base::template addLogLevel< logInfo::SurfaceGenerator >(); + + registerWrapper( viewKeyStruct::isLaggingFractureStencilWeightsUpdateString(), &m_isLaggingFractureStencilWeightsUpdate ). + setApplyDefaultValue( 0 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Flag to determine whether or not to apply lagging update for the fracture stencil weights. " ); + m_numResolves[0] = 0; +} - // This may need to be different depending on whether poroelasticity is on or not. - m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::hydrofracture; - m_linearSolverParameters.get().mgr.separateComponents = false; - m_linearSolverParameters.get().mgr.displacementFieldName = solidMechanics::totalDisplacement::key(); - m_linearSolverParameters.get().dofsPerNode = 3; +template< typename POROMECHANICS_SOLVER > +void HydrofractureSolver< POROMECHANICS_SOLVER >::setMGRStrategy() +{ + LinearSolverParameters & linearSolverParameters = this->m_linearSolverParameters.get(); + + if( linearSolverParameters.preconditionerType != LinearSolverParameters::PreconditionerType::mgr ) + return; + linearSolverParameters.mgr.separateComponents = true; + linearSolverParameters.dofsPerNode = 3; + + // This may need to be different depending on whether poroelasticity is on or not. + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::hydrofracture; + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: MGR strategy set to {}", this->getName(), + EnumStrings< LinearSolverParameters::MGR::StrategyType >::toString( linearSolverParameters.mgr.strategy ))); } template< typename POROMECHANICS_SOLVER > @@ -115,7 +105,7 @@ void HydrofractureSolver< POROMECHANICS_SOLVER >::registerDataOnMesh( dataReposi { Base::registerDataOnMesh( meshBodies ); -#ifdef GEOSX_USE_SEPARATION_COEFFICIENT +#ifdef GEOS_USE_SEPARATION_COEFFICIENT meshBodies.forSubGroups< MeshBody >( [&] ( MeshBody & meshBody ) { MeshLevel & meshLevel = *meshBody.getBaseDiscretization(); @@ -137,6 +127,11 @@ void HydrofractureSolver< POROMECHANICS_SOLVER >::registerDataOnMesh( dataReposi } ); } ); #endif + + if( m_isLaggingFractureStencilWeightsUpdate ) + { + flowSolver()->enableLaggingFractureStencilWeightsUpdate(); + } } template< typename POROMECHANICS_SOLVER > @@ -147,7 +142,7 @@ void HydrofractureSolver< POROMECHANICS_SOLVER >::implicitStepSetup( real64 cons Base::implicitStepSetup( time_n, dt, domain ); updateHydraulicApertureAndFracturePermeability( domain ); -#ifdef GEOSX_USE_SEPARATION_COEFFICIENT +#ifdef GEOS_USE_SEPARATION_COEFFICIENT MeshLevel & mesh = domain.getMeshBody( 0 ).getBaseDiscretization(); mesh.getElemManager().forElementRegions< SurfaceElementRegion >( [&]( SurfaceElementRegion & faceElemRegion ) @@ -169,13 +164,18 @@ void HydrofractureSolver< POROMECHANICS_SOLVER >::implicitStepSetup( real64 cons } template< typename POROMECHANICS_SOLVER > -void HydrofractureSolver< POROMECHANICS_SOLVER >::postProcessInput() +void HydrofractureSolver< POROMECHANICS_SOLVER >::postInputInitialization() { - Base::postProcessInput(); + Base::postInputInitialization(); + + setMGRStrategy(); static const std::set< integer > binaryOptions = { 0, 1 }; GEOS_ERROR_IF( binaryOptions.count( m_isMatrixPoroelastic ) == 0, viewKeyStruct::isMatrixPoroelasticString() << " option can be either 0 (false) or 1 (true)" ); + GEOS_ERROR_IF( m_newFractureInitializationType != InitializationType::Pressure && m_newFractureInitializationType != InitializationType::Displacement, + viewKeyStruct::newFractureInitializationTypeString() << " option can be either Pressure or Displacement" ); + m_surfaceGenerator = &this->getParent().template getGroup< SurfaceGenerator >( m_surfaceGeneratorName ); flowSolver()->allowNegativePressure(); @@ -189,6 +189,11 @@ real64 HydrofractureSolver< POROMECHANICS_SOLVER >::fullyCoupledSolverStep( real int const cycleNumber, DomainPartition & domain ) { + if( cycleNumber == 0 && time_n <= 0 ) + { + initializeNewFractureFields( domain ); + } + real64 dtReturn = dt; implicitStepSetup( time_n, dt, domain ); @@ -219,8 +224,7 @@ real64 HydrofractureSolver< POROMECHANICS_SOLVER >::fullyCoupledSolverStep( real // currently the only method is implicit time integration dtReturn = nonlinearImplicitStep( time_n, dt, cycleNumber, domain ); - - if( m_surfaceGenerator->solverStep( time_n, dt, cycleNumber, domain ) > 0 ) + if( !this->m_performStressInitialization && m_surfaceGenerator->solverStep( time_n, dt, cycleNumber, domain ) > 0 ) { locallyFractured = 1; } @@ -228,7 +232,7 @@ real64 HydrofractureSolver< POROMECHANICS_SOLVER >::fullyCoupledSolverStep( real &globallyFractured, 1, MPI_MAX, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); if( globallyFractured == 0 ) { @@ -236,11 +240,14 @@ real64 HydrofractureSolver< POROMECHANICS_SOLVER >::fullyCoupledSolverStep( real } else { + // We initialize the fields for new fracture cells + initializeNewFractureFields( domain ); + FieldIdentifiers fieldsToBeSync; fieldsToBeSync.addElementFields( { flow::pressure::key(), flow::pressure_n::key(), - SurfaceElementSubRegion::viewKeyStruct::elementApertureString() }, + fields::elementAperture::key() }, { m_surfaceGenerator->getFractureRegionName() } ); fieldsToBeSync.addFields( FieldLocation::Node, @@ -290,19 +297,20 @@ void HydrofractureSolver< POROMECHANICS_SOLVER >::updateHydraulicApertureAndFrac elemManager.forElementSubRegions< FaceElementSubRegion >( [&]( FaceElementSubRegion & subRegion ) { - ContactBase const & contact = this->template getConstitutiveModel< ContactBase >( subRegion, m_contactRelationName ); + string const & hydraulicApertureRelationName = subRegion.template getReference< string >( viewKeyStruct::hydraulicApertureRelationNameString() ); + HydraulicApertureBase const & hydraulicApertureModel = this->template getConstitutiveModel< HydraulicApertureBase >( subRegion, hydraulicApertureRelationName ); arrayView1d< real64 > const aperture = subRegion.getElementAperture(); arrayView1d< real64 > const hydraulicAperture = subRegion.getField< flow::hydraulicAperture >(); arrayView1d< real64 const > const volume = subRegion.getElementVolume(); arrayView1d< real64 > const deltaVolume = subRegion.getField< flow::deltaVolume >(); arrayView1d< real64 const > const area = subRegion.getElementArea(); - ArrayOfArraysView< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); + arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); string const porousSolidName = subRegion.template getReference< string >( FlowSolverBase::viewKeyStruct::solidNamesString() ); CoupledSolidBase const & porousSolid = subRegion.template getConstitutiveModel< CoupledSolidBase >( porousSolidName ); -#ifdef GEOSX_USE_SEPARATION_COEFFICIENT +#ifdef GEOS_USE_SEPARATION_COEFFICIENT arrayView1d< real64 const > const & apertureF = subRegion.getReference< array1d< real64 > >( viewKeyStruct::apertureAtFailureString() ); @@ -318,14 +326,14 @@ void HydrofractureSolver< POROMECHANICS_SOLVER >::updateHydraulicApertureAndFrac { typename TYPEOFREF( castedPorousSolid ) ::KernelWrapper porousMaterialWrapper = castedPorousSolid.createKernelUpdates(); - constitutiveUpdatePassThru( contact, [&] ( auto & castedContact ) + constitutiveUpdatePassThru( hydraulicApertureModel, [&] ( auto & castedHydraulicApertureModel ) { - using ContactType = TYPEOFREF( castedContact ); - typename ContactType::KernelWrapper contactWrapper = castedContact.createKernelWrapper(); + using HydraulicApertureModelType = TYPEOFREF( castedHydraulicApertureModel ); + typename HydraulicApertureModelType::KernelWrapper hydraulicApertureWrapper = castedHydraulicApertureModel.createKernelWrapper(); auto const statistics = hydrofractureSolverKernels::DeformationUpdateKernel ::launch< parallelDevicePolicy<> >( subRegion.size(), - contactWrapper, + hydraulicApertureWrapper, porousMaterialWrapper, u, faceNormal, @@ -336,7 +344,7 @@ void HydrofractureSolver< POROMECHANICS_SOLVER >::updateHydraulicApertureAndFrac deltaVolume, aperture, hydraulicAperture -#ifdef GEOSX_USE_SEPARATION_COEFFICIENT +#ifdef GEOS_USE_SEPARATION_COEFFICIENT , apertureF, separationCoeff, @@ -370,13 +378,12 @@ void HydrofractureSolver< POROMECHANICS_SOLVER >::updateHydraulicApertureAndFrac minHydraulicAperture = MpiWrapper::min( minHydraulicAperture ); maxHydraulicAperture = MpiWrapper::max( maxHydraulicAperture ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max aperture change: {} m, max hydraulic aperture change: {} m", - this->getName(), fmt::format( "{:.{}f}", maxApertureChange, 6 ), fmt::format( "{:.{}f}", maxHydraulicApertureChange, 6 ) ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min aperture: {} m, max aperture: {} m", - this->getName(), fmt::format( "{:.{}f}", minAperture, 6 ), fmt::format( "{:.{}f}", maxAperture, 6 ) ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min hydraulic aperture: {} m, max hydraulic aperture: {} m", - this->getName(), fmt::format( "{:.{}f}", minHydraulicAperture, 6 ), fmt::format( "{:.{}f}", maxHydraulicAperture, 6 ) ) ); - + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, GEOS_FMT( " {}: Max aperture change: {} m, max hydraulic aperture change: {} m", + this->getName(), fmt::format( "{:.{}f}", maxApertureChange, 6 ), fmt::format( "{:.{}f}", maxHydraulicApertureChange, 6 ) ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, GEOS_FMT( " {}: Min aperture: {} m, max aperture: {} m", + this->getName(), fmt::format( "{:.{}f}", minAperture, 6 ), fmt::format( "{:.{}f}", maxAperture, 6 ) ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, GEOS_FMT( " {}: Min hydraulic aperture: {} m, max hydraulic aperture: {} m", + this->getName(), fmt::format( "{:.{}f}", minHydraulicAperture, 6 ), fmt::format( "{:.{}f}", maxHydraulicAperture, 6 ) ) ); } template< typename POROMECHANICS_SOLVER > void HydrofractureSolver< POROMECHANICS_SOLVER >::setupCoupling( DomainPartition const & domain, @@ -472,10 +479,10 @@ void HydrofractureSolver< POROMECHANICS_SOLVER >::setupSystem( DomainPartition & localMatrix.setName( this->getName() + "/matrix" ); rhs.setName( this->getName() + "/rhs" ); - rhs.create( numLocalRows, MPI_COMM_GEOSX ); + rhs.create( numLocalRows, MPI_COMM_GEOS ); solution.setName( this->getName() + "/solution" ); - solution.create( numLocalRows, MPI_COMM_GEOSX ); + solution.create( numLocalRows, MPI_COMM_GEOS ); setUpDflux_dApertureMatrix( domain, dofManager, localMatrix ); } @@ -712,16 +719,12 @@ assembleForceResidualDerivativeWrtPressure( DomainPartition & domain, { arrayView1d< real64 const > const & fluidPressure = subRegion.getField< flow::pressure >(); arrayView1d< real64 const > const & area = subRegion.getElementArea(); - ArrayOfArraysView< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); + arrayView2d< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); // if matching on lassen/crusher, move to device policy using execPolicy = serialPolicy; forAll< execPolicy >( subRegion.size(), [=] ( localIndex const kfe ) { - if( elemsToFaces.sizeOfArray( kfe ) != 2 ) - { - return; - } constexpr int kfSign[2] = { -1, 1 }; @@ -811,7 +814,8 @@ assembleFluidMassResidualDerivativeWrtDisplacement( DomainPartition const & doma [&]( localIndex const, FaceElementSubRegion const & subRegion ) { - ContactBase const & contact = this->template getConstitutiveModel< ContactBase >( subRegion, m_contactRelationName ); + string const & hydraulicApertureRelationName = subRegion.template getReference< string >( viewKeyStruct::hydraulicApertureRelationNameString() ); + HydraulicApertureBase const & hydraulicApertureModel = this->template getConstitutiveModel< HydraulicApertureBase >( subRegion, hydraulicApertureRelationName ); string const & fluidName = subRegion.getReference< string >( FlowSolverBase::viewKeyStruct::fluidNamesString() ); SingleFluidBase const & fluid = this->template getConstitutiveModel< SingleFluidBase >( subRegion, fluidName ); @@ -824,20 +828,20 @@ assembleFluidMassResidualDerivativeWrtDisplacement( DomainPartition const & doma arrayView1d< real64 const > const aperture = subRegion.getElementAperture(); arrayView1d< real64 const > const area = subRegion.getElementArea(); - ArrayOfArraysView< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); + arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); ArrayOfArraysView< localIndex const > const faceToNodeMap = faceManager.nodeList().toViewConst(); arrayView2d< real64 const > const faceNormal = faceManager.faceNormal(); - constitutiveUpdatePassThru( contact, [&] ( auto & castedContact ) + constitutiveUpdatePassThru( hydraulicApertureModel, [&] ( auto & castedHydraulicApertureModel ) { - using ContactType = TYPEOFREF( castedContact ); - typename ContactType::KernelWrapper contactWrapper = castedContact.createKernelWrapper(); + using HydraulicApertureModelType = TYPEOFREF( castedHydraulicApertureModel ); + typename HydraulicApertureModelType::KernelWrapper hydraulicApertureWrapper = castedHydraulicApertureModel.createKernelWrapper(); hydrofractureSolverKernels::FluidMassResidualDerivativeAssemblyKernel:: launch< parallelDevicePolicy<> >( subRegion.size(), rankOffset, - contactWrapper, + hydraulicApertureWrapper, m_useQuasiNewton, elemsToFaces, faceToNodeMap, @@ -862,13 +866,19 @@ void HydrofractureSolver< POROMECHANICS_SOLVER >::updateState( DomainPartition & Base::updateState( domain ); - // remove the contribution of the hydraulic aperture from the stencil weights - flowSolver()->prepareStencilWeights( domain ); + if( !m_isLaggingFractureStencilWeightsUpdate ) + { + // remove the contribution of the hydraulic aperture from the stencil weights + flowSolver()->prepareStencilWeights( domain ); + } updateHydraulicApertureAndFracturePermeability( domain ); - // update the stencil weights using the updated hydraulic aperture - flowSolver()->updateStencilWeights( domain ); + if( !m_isLaggingFractureStencilWeightsUpdate ) + { + // update the stencil weights using the updated hydraulic aperture + flowSolver()->updateStencilWeights( domain ); + } forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & mesh, @@ -886,6 +896,30 @@ void HydrofractureSolver< POROMECHANICS_SOLVER >::updateState( DomainPartition & } ); } +template< typename POROMECHANICS_SOLVER > +void HydrofractureSolver< POROMECHANICS_SOLVER >::implicitStepComplete( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) +{ + Base::implicitStepComplete( time_n, dt, domain ); + + if( m_isLaggingFractureStencilWeightsUpdate ) + { + // remove the contribution of the hydraulic aperture from the stencil weights + flowSolver()->prepareStencilWeights( domain ); + + // update the stencil weights using the updated hydraulic aperture + flowSolver()->updateStencilWeights( domain ); + } +} + +template< typename POROMECHANICS_SOLVER > +void HydrofractureSolver< POROMECHANICS_SOLVER >::resetStateToBeginningOfStep( DomainPartition & domain ) +{ + Base::resetStateToBeginningOfStep( domain ); + updateState( domain ); +} + template< typename POROMECHANICS_SOLVER > real64 HydrofractureSolver< POROMECHANICS_SOLVER >::setNextDt( real64 const & currentDt, DomainPartition & domain ) @@ -902,7 +936,6 @@ real64 HydrofractureSolver< POROMECHANICS_SOLVER >::setNextDt( real64 const & cu nextDt = m_surfaceGenerator->getTimestepRequest() < 1e99 ? m_surfaceGenerator->getTimestepRequest() : currentDt; } - GEOS_LOG_LEVEL_RANK_0( 3, this->getName() << ": nextDt request is " << nextDt ); return nextDt; } template< typename POROMECHANICS_SOLVER > @@ -971,12 +1004,189 @@ void HydrofractureSolver< POROMECHANICS_SOLVER >::setUpDflux_dApertureMatrix( Do } ); } +template< typename POROMECHANICS_SOLVER > +void HydrofractureSolver< POROMECHANICS_SOLVER >::initializeNewFractureFields( DomainPartition & domain ) +{ + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & meshLevel, + arrayView1d< string const > const & regionNames ) + { + ElementRegionManager & elemManager = meshLevel.getElemManager(); + NodeManager & nodeManager = meshLevel.getNodeManager(); + FaceManager const & faceManager = meshLevel.getFaceManager(); + ArrayOfArraysView< localIndex const > const faceToNodesMap = faceManager.nodeList().toViewConst(); + arrayView2d< real64 const > faceNormal = faceManager.faceNormal(); + + solidMechanics::arrayView2dLayoutIncrDisplacement const incrementalDisplacement = + nodeManager.getField< fields::solidMechanics::incrementalDisplacement >(); + solidMechanics::arrayView2dLayoutTotalDisplacement const totalDisplacement = + nodeManager.getField< fields::solidMechanics::totalDisplacement >(); + + elemManager.forElementRegions< SurfaceElementRegion >( regionNames, + [=] ( localIndex const, + SurfaceElementRegion & region ) + { + real64 const defaultAperture = region.getDefaultAperture(); + region.forElementSubRegions< FaceElementSubRegion >( [=]( FaceElementSubRegion & subRegion ) + { + ArrayOfArraysView< localIndex const > const facesToEdges = subRegion.edgeList().toViewConst(); + ArrayOfArraysView< localIndex const > const & fractureConnectorsToFaceElements = subRegion.m_2dFaceTo2dElems.toViewConst(); + map< localIndex, localIndex > const & edgesToConnectorEdges = subRegion.m_edgesTo2dFaces; + + arrayView2d< localIndex const > const faceMap = subRegion.faceList().toViewConst(); + + arrayView1d< real64 > const fluidPressure_n = subRegion.getField< fields::flow::pressure_n >(); + arrayView1d< real64 > const fluidPressure = subRegion.getField< fields::flow::pressure >(); + string const & fluidName = subRegion.getReference< string >( FlowSolverBase::viewKeyStruct::fluidNamesString() ); + SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); + real64 const defaultDensity = fluid.defaultDensity(); + arrayView1d< real64 > const massCreated = subRegion.getField< fields::flow::massCreated >(); + + + arrayView1d< real64 > const aperture = subRegion.getField< fields::elementAperture >(); + arrayView1d< real64 > const elementArea = subRegion.getElementArea(); + + // Get the list of newFractureElements + SortedArrayView< localIndex const > const newFractureElements = subRegion.m_newFaceElements.toViewConst(); + + #ifdef GEOS_USE_SEPARATION_COEFFICIENT + arrayView1d< real64 > const apertureF = subRegion.getReference< array1d< real64 > >( "apertureAtFailure" ); + #endif + + // arrayView1d< real64 > const dens = subRegion.getReference< array1d< real64 > >( "density_n" ); // change it to make aperture + // zero + + forAll< serialPolicy >( newFractureElements.size(), [&] ( localIndex const k ) + { + localIndex const newElemIndex = newFractureElements[k]; + real64 initialPressure = 1.0e99; + real64 initialAperture = 1.0e99; + #ifdef GEOS_USE_SEPARATION_COEFFICIENT + apertureF[newElemIndex] = aperture[newElemIndex]; + #endif + if( m_newFractureInitializationType == InitializationType::Displacement ) + { + aperture[newElemIndex] = 1.0e99; + } + arraySlice1d< localIndex const > const faceToEdges = facesToEdges[newElemIndex]; + + for( localIndex ke=0; ke 1.0e98? 0.0:initialPressure; + fluidPressure_n[newElemIndex] = fluidPressure[newElemIndex]; + massCreated[newElemIndex] = defaultDensity * defaultAperture * elementArea[newElemIndex]; + } + else if( m_newFractureInitializationType == InitializationType::Displacement ) + { + // Set the aperture/fluid pressure for the new face element to be the minimum + // of the existing value, smallest aperture/pressure from a connected face element. + // aperture[newElemIndex] = std::min(aperture[newElemIndex], initialAperture); + + localIndex const faceIndex0 = faceMap[newElemIndex][0]; + localIndex const faceIndex1 = faceMap[newElemIndex][1]; + + localIndex const numNodesPerFace = faceToNodesMap.sizeOfArray( faceIndex0 ); + + bool zeroDisp = true; + + for( localIndex a=0; a( totalDisplacement[node0] ) ) > 1.0e-99 && + LvArray::math::abs( LvArray::tensorOps::l2Norm< 3 >( totalDisplacement[node1] ) ) > 1.0e-99 ) + { + zeroDisp = false; + } + } + if( zeroDisp ) + { + aperture[newElemIndex] = 0; + } + } + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::SurfaceGenerator, + GEOS_FMT( "New elem index = {:4d} , init aper = {:4.2e}, init press = {:4.2e} ", + newElemIndex, aperture[newElemIndex], fluidPressure[newElemIndex] ) ); + } ); + + if( m_newFractureInitializationType == InitializationType::Displacement ) + { + SortedArray< localIndex > touchedNodes; + forAll< serialPolicy >( newFractureElements.size(), [ newFractureElements + , aperture + , faceMap + , faceNormal + , faceToNodesMap + , &touchedNodes + , incrementalDisplacement + , totalDisplacement ]( localIndex const k ) + { + localIndex const newElemIndex = newFractureElements[k]; + + if( aperture[newElemIndex] < 1e98 ) + { + localIndex const faceIndex0 = faceMap( newElemIndex, 0 ); + localIndex const faceIndex1 = faceMap( newElemIndex, 1 ); + localIndex const numNodesPerFace = faceToNodesMap.sizeOfArray( faceIndex0 ); + + real64 newDisp[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3( faceNormal[ faceIndex0 ] ); + LvArray::tensorOps::scale< 3 >( newDisp, -aperture[newElemIndex] ); + for( localIndex a=0; a( incrementalDisplacement[node0], newDisp ); + LvArray::tensorOps::add< 3 >( totalDisplacement[node0], newDisp ); + LvArray::tensorOps::subtract< 3 >( incrementalDisplacement[node1], newDisp ); + LvArray::tensorOps::subtract< 3 >( totalDisplacement[node1], newDisp ); + } + } + } + } ); + } + + subRegion.m_recalculateConnectionsFor2dFaces.clear(); + subRegion.m_newFaceElements.clear(); + } ); + } ); + } ); +} + namespace { -typedef HydrofractureSolver< SinglePhasePoromechanics< SinglePhaseBase > > SinglePhaseHydrofracture; -// typedef HydrofractureSolver< MultiphasePoromechanics< CompositionalMultiphaseBase > > MultiphaseHydrofracture; -REGISTER_CATALOG_ENTRY( SolverBase, SinglePhaseHydrofracture, string const &, Group * const ) -// REGISTER_CATALOG_ENTRY( SolverBase, MultiphaseHydrofracture, string const &, Group * const ) +typedef HydrofractureSolver<> SinglePhaseHydrofracture; +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhaseHydrofracture, string const &, Group * const ) +// typedef HydrofractureSolver< MultiphasePoromechanics<> > MultiphaseHydrofracture; +// REGISTER_CATALOG_ENTRY( PhysicsSolverBase, MultiphaseHydrofracture, string const &, Group * const ) } } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.hpp b/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.hpp index 9ee4adcdd04..05a96830440 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -23,13 +24,14 @@ #include "physicsSolvers/surfaceGeneration/SurfaceGenerator.hpp" #include "physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" +#include "dataRepository/LogLevelsInfo.hpp" namespace geos { using dataRepository::Group; -template< typename POROMECHANICS_SOLVER = SinglePhasePoromechanics< SinglePhaseBase > > +template< typename POROMECHANICS_SOLVER = SinglePhasePoromechanics<> > class HydrofractureSolver : public POROMECHANICS_SOLVER { public: @@ -55,6 +57,7 @@ class HydrofractureSolver : public POROMECHANICS_SOLVER using Base::flowSolver; using Base::solidMechanicsSolver; using Base::assembleElementBasedTerms; + using Base::resetStateToBeginningOfStep; /** @@ -68,9 +71,21 @@ class HydrofractureSolver : public POROMECHANICS_SOLVER /// Destructor for the class ~HydrofractureSolver() override {} - static string catalogName(); + static string catalogName() + { + // single phase + if constexpr ( std::is_same_v< POROMECHANICS_SOLVER, SinglePhasePoromechanics< SinglePhaseBase > > ) + { + return "Hydrofracture"; + } +// // multi phase (TODO) +// else if constexpr ( std::is_same_v< POROMECHANICS_SOLVER, MultiphasePoromechanics< CompositionalMultiphaseBase > > ) +// { +// return "MultiphaseHydrofracture"; +// } + } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -112,6 +127,12 @@ class HydrofractureSolver : public POROMECHANICS_SOLVER virtual void updateState( DomainPartition & domain ) override final; + virtual void implicitStepComplete( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) override final; + + virtual void resetStateToBeginningOfStep( DomainPartition & domain ) override final; + /**@}*/ void updateHydraulicApertureAndFracturePermeability( DomainPartition & domain ); @@ -138,19 +159,27 @@ class HydrofractureSolver : public POROMECHANICS_SOLVER return m_derivativeFluxResidual_dAperture->toViewConst(); } - struct viewKeyStruct : Base::viewKeyStruct + enum class InitializationType : integer { - constexpr static char const * contactRelationNameString() { return "contactRelationName"; } + Pressure, + Displacement, + }; + struct viewKeyStruct : Base::viewKeyStruct + { constexpr static char const * surfaceGeneratorNameString() { return "surfaceGeneratorName"; } constexpr static char const * maxNumResolvesString() { return "maxNumResolves"; } constexpr static char const * isMatrixPoroelasticString() { return "isMatrixPoroelastic"; } + constexpr static char const * newFractureInitializationTypeString() { return "newFractureInitializationType"; } + constexpr static char const * useQuasiNewtonString() { return "useQuasiNewton"; } -#ifdef GEOSX_USE_SEPARATION_COEFFICIENT + constexpr static char const * isLaggingFractureStencilWeightsUpdateString() { return "isLaggingFractureStencilWeightsUpdate"; } + +#ifdef GEOS_USE_SEPARATION_COEFFICIENT constexpr static char const * separationCoeff0String() { return "separationCoeff0"; } constexpr static char const * apertureAtFailureString() { return "apertureAtFailure"; } #endif @@ -158,7 +187,7 @@ class HydrofractureSolver : public POROMECHANICS_SOLVER protected: - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; /** * @Brief add the nnz induced by the flux-aperture coupling @@ -186,6 +215,7 @@ class HydrofractureSolver : public POROMECHANICS_SOLVER DofManager const & dofManager, CRSMatrix< real64, globalIndex > & localMatrix ); + virtual void setMGRStrategy() override; private: @@ -194,6 +224,13 @@ class HydrofractureSolver : public POROMECHANICS_SOLVER int const cycleNumber, DomainPartition & domain ) override final; + + /** + * @brief Initialize fields on the newly created elements of the fracture. + * @param domain the physical domain object + */ + void initializeNewFractureFields( DomainPartition & domain ); + // name of the contact relation string m_contactRelationName; @@ -211,10 +248,20 @@ class HydrofractureSolver : public POROMECHANICS_SOLVER integer m_isMatrixPoroelastic; + // flag to determine which initialization type to use for the new fracture cell + InitializationType m_newFractureInitializationType; + integer m_useQuasiNewton; // use Quasi-Newton (see https://arxiv.org/abs/2111.00264) + // flag to determine whether or not to apply lagging update for the fracture stencil weights + integer m_isLaggingFractureStencilWeightsUpdate; + }; +ENUM_STRINGS( HydrofractureSolver< SinglePhasePoromechanics< SinglePhaseBase > >::InitializationType, + "Pressure", + "Displacement" ); + } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolverKernels.hpp b/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolverKernels.hpp index fe23b8b491f..86630e16ead 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolverKernels.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolverKernels.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -31,21 +32,21 @@ namespace hydrofractureSolverKernels struct DeformationUpdateKernel { - template< typename POLICY, typename CONTACT_WRAPPER, typename POROUS_WRAPPER > + template< typename POLICY, typename HYDRAULICAPERTURE_WRAPPER, typename POROUS_WRAPPER > static std::tuple< double, double, double, double, double, double > launch( localIndex const size, - CONTACT_WRAPPER const & contactWrapper, + HYDRAULICAPERTURE_WRAPPER const & hydraulicApertureWrapper, POROUS_WRAPPER const & porousMaterialWrapper, arrayView2d< real64 const, nodes::TOTAL_DISPLACEMENT_USD > const & u, arrayView2d< real64 const > const & faceNormal, ArrayOfArraysView< localIndex const > const & faceToNodeMap, - ArrayOfArraysView< localIndex const > const & elemsToFaces, + arrayView2d< localIndex const > const & elemsToFaces, arrayView1d< real64 const > const & area, arrayView1d< real64 const > const & volume, arrayView1d< real64 > const & deltaVolume, arrayView1d< real64 > const & aperture, arrayView1d< real64 > const & hydraulicAperture -#ifdef GEOSX_USE_SEPARATION_COEFFICIENT +#ifdef GEOS_USE_SEPARATION_COEFFICIENT , arrayView1d< real64 const > const & apertureAtFailure, arrayView1d< real64 > const & separationCoeff, @@ -65,8 +66,6 @@ struct DeformationUpdateKernel forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const kfe ) mutable { - if( elemsToFaces.sizeOfArray( kfe ) != 2 ) - { return; } localIndex const kf0 = elemsToFaces[kfe][0]; localIndex const kf1 = elemsToFaces[kfe][1]; @@ -85,8 +84,14 @@ struct DeformationUpdateKernel minAperture.min( aperture[kfe] ); maxAperture.max( aperture[kfe] ); - real64 dHydraulicAperture_dNormalJump = 0; - real64 const newHydraulicAperture = contactWrapper.computeHydraulicAperture( aperture[kfe], dHydraulicAperture_dNormalJump ); + real64 normalTraction = 0.0; /// TODO: must be changed to use actual traction + real64 dHydraulicAperture_dNormalTraction = 0.0; + real64 dHydraulicAperture_dNormalJump = 0.0; + real64 const newHydraulicAperture = hydraulicApertureWrapper.computeHydraulicAperture( aperture[kfe], + normalTraction, + dHydraulicAperture_dNormalJump, + dHydraulicAperture_dNormalTraction ); + maxHydraulicApertureChange.max( std::fabs( newHydraulicAperture - hydraulicAperture[kfe] )); real64 const oldHydraulicAperture = hydraulicAperture[kfe]; hydraulicAperture[kfe] = newHydraulicAperture; @@ -101,7 +106,7 @@ struct DeformationUpdateKernel dHydraulicAperture_dNormalJump, jump, traction ); -#ifdef GEOSX_USE_SEPARATION_COEFFICIENT +#ifdef GEOS_USE_SEPARATION_COEFFICIENT real64 const s = aperture[kfe] / apertureAtFailure[kfe]; if( separationCoeff0[kfe]<1.0 && s>separationCoeff0[kfe] ) { @@ -126,11 +131,11 @@ struct DeformationUpdateKernel struct FluidMassResidualDerivativeAssemblyKernel { - template< typename CONTACT_WRAPPER > + template< typename HYDRAULICAPERTURE_WRAPPER > GEOS_HOST_DEVICE inline static void - computeAccumulationDerivative( CONTACT_WRAPPER const & contactWrapper, + computeAccumulationDerivative( HYDRAULICAPERTURE_WRAPPER const & hydraulicApertureWrapper, localIndex const numNodesPerFace, arraySlice1d< localIndex const > const elemsToFaces, ArrayOfArraysView< localIndex const > const faceToNodeMap, @@ -142,8 +147,13 @@ struct FluidMassResidualDerivativeAssemblyKernel globalIndex (& nodeDOF)[8 * 3], arraySlice1d< real64 > const dRdU ) { - real64 dHydraulicAperture_dNormalJump = 0; - real64 const hydraulicAperture = contactWrapper.computeHydraulicAperture( aperture, dHydraulicAperture_dNormalJump ); + real64 dHydraulicAperture_dNormalJump = 0.0; + real64 dHydraulicAperture_dTraction = 0.0; + real64 fractureTraction = 0.0; + real64 const hydraulicAperture = hydraulicApertureWrapper.computeHydraulicAperture( aperture, + fractureTraction, + dHydraulicAperture_dNormalJump, + dHydraulicAperture_dTraction ); GEOS_UNUSED_VAR( hydraulicAperture ); constexpr integer kfSign[2] = { -1, 1 }; @@ -172,7 +182,7 @@ struct FluidMassResidualDerivativeAssemblyKernel localIndex const numNodesPerFace, arraySlice1d< localIndex const > const & columns, arraySlice1d< real64 const > const & values, - ArrayOfArraysView< localIndex const > const elemsToFaces, + arrayView2d< localIndex const > const elemsToFaces, ArrayOfArraysView< localIndex const > const faceToNodeMap, arrayView1d< globalIndex const > const dispDofNumber, real64 const (&Nbar)[ 3 ], @@ -200,13 +210,13 @@ struct FluidMassResidualDerivativeAssemblyKernel } } - template< typename POLICY, typename CONTACT_WRAPPER > + template< typename POLICY, typename HYDRAULICAPERTURE_WRAPPER > static void launch( localIndex const size, globalIndex const rankOffset, - CONTACT_WRAPPER const & contactWrapper, + HYDRAULICAPERTURE_WRAPPER const & hydraulicApertureWrapper, integer const useQuasiNewton, - ArrayOfArraysView< localIndex const > const elemsToFaces, + arrayView2d< localIndex const > const elemsToFaces, ArrayOfArraysView< localIndex const > const faceToNodeMap, arrayView2d< real64 const > const faceNormal, arrayView1d< real64 const > const area, @@ -229,7 +239,7 @@ struct FluidMassResidualDerivativeAssemblyKernel globalIndex nodeDOF[8 * 3]; stackArray1d< real64, 24 > dRdU( 2 * numNodesPerFace * 3 ); // - computeAccumulationDerivative( contactWrapper, + computeAccumulationDerivative( hydraulicApertureWrapper, numNodesPerFace, elemsToFaces[ei], faceToNodeMap, diff --git a/src/coreComponents/physicsSolvers/multiphysics/LogLevelsInfo.hpp b/src/coreComponents/physicsSolvers/multiphysics/LogLevelsInfo.hpp new file mode 100644 index 00000000000..e87c0615e53 --- /dev/null +++ b/src/coreComponents/physicsSolvers/multiphysics/LogLevelsInfo.hpp @@ -0,0 +1,52 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file LogLevelsInfo.hpp + * This file contains log level informations for coupled multiphysics solvers + */ + +#ifndef GEOS_PHYSICSSOLVERS_MULTIPHYSICS_LOGLEVELSINFO_HPP +#define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_LOGLEVELSINFO_HPP + +#include "common/DataTypes.hpp" + +namespace geos +{ + +namespace logInfo +{ + +/** + * @name Wells LogLevels info structures. They must comply with the `is_log_level_info` trait. + */ +///@{ + +/// @cond DO_NOT_DOCUMENT + +struct Coupling +{ + static constexpr int getMinLogLevel() { return 1; } + static constexpr std::string_view getDescription() { return "Coupling information"; } +}; + +/// @endcond +///@} + +} + +} + +#endif // GEOS_PHYSICSSOLVERS_MULTIPHYSICS_LOGLEVELSINFO_HPP diff --git a/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.cpp b/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.cpp index ac12d92bbf7..6b01f872f5c 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,20 +17,23 @@ * @file MultiphasePoromechanics.cpp */ -#define GEOSX_DISPATCH_VEM /// enables VEM in FiniteElementDispatch +#define GEOS_DISPATCH_VEM /// enables VEM in FiniteElementDispatch #include "MultiphasePoromechanics.hpp" +#include "dataRepository/LogLevelsInfo.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "constitutive/solid/PorousSolid.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/MultiphasePoromechanics.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/ThermalMultiphasePoromechanics.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsFields.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp" #include "physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainQuasiStatic.hpp" +//#include "physicsSolvers/contact/SolidMechanicsLagrangeContact.hpp" +//#include "physicsSolvers/contact/SolidMechanicsEmbeddedFractures.hpp" namespace geos { @@ -39,121 +43,79 @@ using namespace constitutive; using namespace fields; using namespace stabilization; -namespace -{ +template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > +MultiphasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::MultiphasePoromechanics( const string & name, + Group * const parent ) + : Base( name, parent ) +{} -// This is meant to be specialized to work, see below -template< typename FLOW_SOLVER > class - MultiphaseCatalogNames {}; -// Class specialization for a FLOW_SOLVER set to CompositionalMultiphaseBase -template<> class MultiphaseCatalogNames< CompositionalMultiphaseBase > -{ -public: - static string name() { return "MultiphasePoromechanics"; } -}; -// Class specialization for a FLOW_SOLVER set to CompositionalMultiphaseReservoirAndWells -template<> class MultiphaseCatalogNames< CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > > +template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > +void MultiphasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::postInputInitialization() { -public: - static string name() { return CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase >::catalogName() + "Poromechanics"; } -}; -} + Base::postInputInitialization(); -// provide a definition for catalogName() -template< typename FLOW_SOLVER > -string -MultiphasePoromechanics< FLOW_SOLVER >:: -catalogName() -{ - return MultiphaseCatalogNames< FLOW_SOLVER >::name(); + setMGRStrategy(); } -template< typename FLOW_SOLVER > -MultiphasePoromechanics< FLOW_SOLVER >::MultiphasePoromechanics( const string & name, - Group * const parent ) - : Base( name, parent ) +template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > +void MultiphasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::setupCoupling( DomainPartition const & GEOS_UNUSED_PARAM( domain ), + DofManager & dofManager ) const { - this->registerWrapper( viewKeyStruct::stabilizationTypeString(), &m_stabilizationType ). - setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Stabilization type. Options are:\n" + - toString( StabilizationType::None ) + " - Add no stabilization to mass equation,\n" + - toString( StabilizationType::Global ) + " - Add stabilization to all faces,\n" + - toString( StabilizationType::Local ) + " - Add stabilization only to interiors of macro elements." ); - - this->registerWrapper( viewKeyStruct::stabilizationRegionNamesString(), &m_stabilizationRegionNames ). - setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ). - setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Regions where stabilization is applied." ); - - this->registerWrapper( viewKeyStruct::stabilizationMultiplierString(), &m_stabilizationMultiplier ). - setApplyDefaultValue( 1.0 ). - setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Constant multiplier of stabilization strength." ); - - LinearSolverParameters & linearSolverParameters = this->m_linearSolverParameters.get(); - linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::multiphasePoromechanics; - linearSolverParameters.mgr.separateComponents = true; - linearSolverParameters.mgr.displacementFieldName = solidMechanics::totalDisplacement::key(); - linearSolverParameters.dofsPerNode = 3; + dofManager.addCoupling( solidMechanics::totalDisplacement::key(), + CompositionalMultiphaseBase::viewKeyStruct::elemDofFieldString(), + DofManager::Connector::Elem ); } -template< typename FLOW_SOLVER > -void MultiphasePoromechanics< FLOW_SOLVER >::postProcessInput() +template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > +void MultiphasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::assembleSystem( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) { - Base::postProcessInput(); - - GEOS_ERROR_IF( this->flowSolver()->catalogName() == "CompositionalMultiphaseReservoir" && - this->getNonlinearSolverParameters().couplingType() != NonlinearSolverParameters::CouplingType::Sequential, - GEOS_FMT( "{}: {} solver is only designed to work for {} = {}", - this->getDataContext(), catalogName(), NonlinearSolverParameters::viewKeysStruct::couplingTypeString(), - EnumStrings< NonlinearSolverParameters::CouplingType >::toString( NonlinearSolverParameters::CouplingType::Sequential ) - )); -} + GEOS_MARK_FUNCTION; -template< typename FLOW_SOLVER > -void MultiphasePoromechanics< FLOW_SOLVER >::registerDataOnMesh( Group & meshBodies ) -{ - Base::registerDataOnMesh( meshBodies ); + // Steps 1 and 2: compute element-based terms (mechanics and local flow terms) + assembleElementBasedTerms( time, + dt, + domain, + dofManager, + localMatrix, + localRhs ); + + // step 3: compute the fluxes (face-based contributions) if( m_stabilizationType == StabilizationType::Global || m_stabilizationType == StabilizationType::Local ) { - this->template forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - ElementRegionManager & elemManager = mesh.getElemManager(); - - elemManager.forElementSubRegions< ElementSubRegionBase >( regionNames, - [&]( localIndex const, - ElementSubRegionBase & subRegion ) - { - subRegion.registerField< fields::flow::macroElementIndex >( this->getName() ); - subRegion.registerField< fields::flow::elementStabConstant >( this->getName() ); - } ); - } ); + this->flowSolver()->assembleStabilizedFluxTerms( dt, + domain, + dofManager, + localMatrix, + localRhs ); + } + else + { + this->flowSolver()->assembleFluxTerms( dt, + domain, + dofManager, + localMatrix, + localRhs ); } } -template< typename FLOW_SOLVER > -void MultiphasePoromechanics< FLOW_SOLVER >::setupCoupling( DomainPartition const & GEOS_UNUSED_PARAM( domain ), - DofManager & dofManager ) const -{ - dofManager.addCoupling( solidMechanics::totalDisplacement::key(), - CompositionalMultiphaseBase::viewKeyStruct::elemDofFieldString(), - DofManager::Connector::Elem ); -} - -template< typename FLOW_SOLVER > -void MultiphasePoromechanics< FLOW_SOLVER >::assembleSystem( real64 const time, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) +template<> +void MultiphasePoromechanics< CompositionalMultiphaseReservoirAndWells<>, SolidMechanicsLagrangianFEM >::assembleSystem( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; + // Steps 1 and 2: compute element-based terms (mechanics and local flow terms) assembleElementBasedTerms( time, dt, domain, @@ -166,7 +128,6 @@ void MultiphasePoromechanics< FLOW_SOLVER >::assembleSystem( real64 const time, if( m_stabilizationType == StabilizationType::Global || m_stabilizationType == StabilizationType::Local ) { - updateStabilizationParameters( domain ); this->flowSolver()->assembleStabilizedFluxTerms( dt, domain, dofManager, @@ -181,15 +142,20 @@ void MultiphasePoromechanics< FLOW_SOLVER >::assembleSystem( real64 const time, localMatrix, localRhs ); } + + // step 4: assemble well contributions + + this->flowSolver()->wellSolver()->assembleSystem( time, dt, domain, dofManager, localMatrix, localRhs ); + this->flowSolver()->assembleCouplingTerms( time, dt, domain, dofManager, localMatrix, localRhs ); } -template< typename FLOW_SOLVER > -void MultiphasePoromechanics< FLOW_SOLVER >::assembleElementBasedTerms( real64 const time_n, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) +template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > +void MultiphasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::assembleElementBasedTerms( real64 const time_n, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) { GEOS_UNUSED_VAR( time_n ); GEOS_UNUSED_VAR( dt ); @@ -212,37 +178,39 @@ void MultiphasePoromechanics< FLOW_SOLVER >::assembleElementBasedTerms( real64 c if( this->m_isThermal ) { poromechanicsMaxForce = - assemblyLaunch< constitutive::PorousSolid< ElasticIsotropic >, // TODO: change once there is a cmake solution - thermalPoromechanicsKernels::ThermalMultiphasePoromechanicsKernelFactory >( mesh, - dofManager, - regionNames, - viewKeyStruct::porousMaterialNamesString(), - localMatrix, - localRhs, - dt, - flowDofKey, - this->flowSolver()->numFluidComponents(), - this->flowSolver()->numFluidPhases(), - this->flowSolver()->useTotalMassEquation(), - FlowSolverBase::viewKeyStruct::fluidNamesString() ); + this->template assemblyLaunch< constitutive::PorousSolidBase, + thermalPoromechanicsKernels::ThermalMultiphasePoromechanicsKernelFactory >( mesh, + dofManager, + regionNames, + Base::viewKeyStruct::porousMaterialNamesString(), + localMatrix, + localRhs, + dt, + flowDofKey, + this->flowSolver()->numFluidComponents(), + this->flowSolver()->numFluidPhases(), + this->flowSolver()->useTotalMassEquation(), + this->m_performStressInitialization, + FlowSolverBase::viewKeyStruct::fluidNamesString() ); } else { poromechanicsMaxForce = - assemblyLaunch< constitutive::PorousSolidBase, - poromechanicsKernels::MultiphasePoromechanicsKernelFactory >( mesh, - dofManager, - regionNames, - viewKeyStruct::porousMaterialNamesString(), - localMatrix, - localRhs, - dt, - flowDofKey, - this->flowSolver()->numFluidComponents(), - this->flowSolver()->numFluidPhases(), - this->flowSolver()->useSimpleAccumulation(), - this->flowSolver()->useTotalMassEquation(), - FlowSolverBase::viewKeyStruct::fluidNamesString() ); + this->template assemblyLaunch< constitutive::PorousSolidBase, + poromechanicsKernels::MultiphasePoromechanicsKernelFactory >( mesh, + dofManager, + regionNames, + Base::viewKeyStruct::porousMaterialNamesString(), + localMatrix, + localRhs, + dt, + flowDofKey, + this->flowSolver()->numFluidComponents(), + this->flowSolver()->numFluidPhases(), + this->flowSolver()->useSimpleAccumulation(), + this->flowSolver()->useTotalMassEquation(), + this->m_performStressInitialization, + FlowSolverBase::viewKeyStruct::fluidNamesString() ); } } ); @@ -272,14 +240,14 @@ void MultiphasePoromechanics< FLOW_SOLVER >::assembleElementBasedTerms( real64 c } mechanicsMaxForce = - assemblyLaunch< constitutive::SolidBase, - solidMechanicsLagrangianFEMKernels::QuasiStaticFactory >( mesh, - dofManager, - filteredRegionNames.toViewConst(), - SolidMechanicsLagrangianFEM::viewKeyStruct::solidMaterialNamesString(), - localMatrix, - localRhs, - dt ); + this->template assemblyLaunch< constitutive::SolidBase, + solidMechanicsLagrangianFEMKernels::QuasiStaticFactory >( mesh, + dofManager, + filteredRegionNames.toViewConst(), + SolidMechanicsLagrangianFEM::viewKeyStruct::solidMaterialNamesString(), + localMatrix, + localRhs, + dt ); } ); @@ -287,47 +255,17 @@ void MultiphasePoromechanics< FLOW_SOLVER >::assembleElementBasedTerms( real64 c this->solidMechanicsSolver()->getMaxForce() = LvArray::math::max( mechanicsMaxForce, poromechanicsMaxForce ); } -template< typename FLOW_SOLVER > -void MultiphasePoromechanics< FLOW_SOLVER >::updateState( DomainPartition & domain ) -{ - GEOS_MARK_FUNCTION; - - real64 maxDeltaPhaseVolFrac = 0.0; - this->template forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - ElementRegionManager & elemManager = mesh.getElemManager(); - elemManager.forElementSubRegions< CellElementSubRegion >( regionNames, - [&]( localIndex const, - CellElementSubRegion & subRegion ) - { - real64 const deltaPhaseVolFrac = this->flowSolver()->updateFluidState( subRegion ); - maxDeltaPhaseVolFrac = LvArray::math::max( maxDeltaPhaseVolFrac, deltaPhaseVolFrac ); - if( this->m_isThermal ) - { - this->flowSolver()->updateSolidInternalEnergyModel( subRegion ); - } - } ); - } ); - - maxDeltaPhaseVolFrac = MpiWrapper::max( maxDeltaPhaseVolFrac ); - - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max phase volume fraction change = {}", - this->getName(), GEOS_FMT( "{:.{}f}", maxDeltaPhaseVolFrac, 4 ) ) ); -} - -template< typename FLOW_SOLVER > -void MultiphasePoromechanics< FLOW_SOLVER >::initializePostInitialConditionsPreSubGroups() +template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > +void MultiphasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::initializePostInitialConditionsPreSubGroups() { Base::initializePostInitialConditionsPreSubGroups(); arrayView1d< string const > const & poromechanicsTargetRegionNames = - this->template getReference< array1d< string > >( SolverBase::viewKeyStruct::targetRegionsString() ); + this->template getReference< array1d< string > >( PhysicsSolverBase::viewKeyStruct::targetRegionsString() ); arrayView1d< string const > const & solidMechanicsTargetRegionNames = - this->solidMechanicsSolver()->template getReference< array1d< string > >( SolverBase::viewKeyStruct::targetRegionsString() ); + this->solidMechanicsSolver()->template getReference< array1d< string > >( PhysicsSolverBase::viewKeyStruct::targetRegionsString() ); arrayView1d< string const > const & flowTargetRegionNames = - this->flowSolver()->template getReference< array1d< string > >( SolverBase::viewKeyStruct::targetRegionsString() ); + this->flowSolver()->template getReference< array1d< string > >( PhysicsSolverBase::viewKeyStruct::targetRegionsString() ); for( integer i = 0; i < poromechanicsTargetRegionNames.size(); ++i ) { GEOS_THROW_IF( std::find( solidMechanicsTargetRegionNames.begin(), solidMechanicsTargetRegionNames.end(), @@ -343,117 +281,96 @@ void MultiphasePoromechanics< FLOW_SOLVER >::initializePostInitialConditionsPreS getCatalogName(), this->getDataContext(), poromechanicsTargetRegionNames[i], this->flowSolver()->getDataContext() ), InputError ); } - - if( this->m_isThermal ) - { - this->m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::thermalMultiphasePoromechanics; - } } -template< typename FLOW_SOLVER > -void MultiphasePoromechanics< FLOW_SOLVER >::initializePreSubGroups() +template<> +void MultiphasePoromechanics<>::setMGRStrategy() { - Base::initializePreSubGroups(); + LinearSolverParameters & linearSolverParameters = this->m_linearSolverParameters.get(); - GEOS_THROW_IF( m_stabilizationType == StabilizationType::Local, - this->getWrapperDataContext( viewKeyStruct::stabilizationTypeString() ) << - ": Local stabilization has been disabled temporarily", - InputError ); -} + if( linearSolverParameters.preconditionerType != LinearSolverParameters::PreconditionerType::mgr ) + return; -template< typename FLOW_SOLVER > -void MultiphasePoromechanics< FLOW_SOLVER >::updateStabilizationParameters( DomainPartition & domain ) const -{ - // Step 1: we loop over the regions where stabilization is active and collect their name + linearSolverParameters.mgr.separateComponents = true; + linearSolverParameters.dofsPerNode = 3; - set< string > regionFilter; - for( string const & regionName : m_stabilizationRegionNames ) + if( dynamic_cast< CompositionalMultiphaseHybridFVM * >( this->flowSolver() ) ) { - regionFilter.insert( regionName ); + GEOS_ERROR( GEOS_FMT( "{}: MGR strategy is not implemented for {}/{}", + this->getName(), this->getCatalogName(), this->flowSolver()->getCatalogName())); } - - // Step 2: loop over the target regions of the solver, and tag the elements belonging to stabilization regions - this->template forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & targetRegionNames ) + else { - // keep only the target regions that are in the filter - array1d< string > filteredTargetRegionNames; - filteredTargetRegionNames.reserve( targetRegionNames.size() ); - - for( string const & targetRegionName : targetRegionNames ) + if( this->m_isThermal ) { - if( regionFilter.count( targetRegionName ) ) - { - filteredTargetRegionNames.emplace_back( targetRegionName ); - } + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::thermalMultiphasePoromechanics; } - - // loop over the elements and update the stabilization constant - mesh.getElemManager().forElementSubRegions( filteredTargetRegionNames.toViewConst(), [&]( localIndex const, - ElementSubRegionBase & subRegion ) - + else { - arrayView1d< integer > const macroElementIndex = subRegion.getField< fields::flow::macroElementIndex >(); - arrayView1d< real64 > const elementStabConstant = subRegion.getField< fields::flow::elementStabConstant >(); - - geos::constitutive::CoupledSolidBase const & porousSolid = - this->template getConstitutiveModel< geos::constitutive::CoupledSolidBase >( subRegion, subRegion.getReference< string >( viewKeyStruct::porousMaterialNamesString() ) ); + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::multiphasePoromechanics; + } + } + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: MGR strategy set to {}", getName(), + EnumStrings< LinearSolverParameters::MGR::StrategyType >::toString( linearSolverParameters.mgr.strategy ))); +} - arrayView1d< real64 const > const bulkModulus = porousSolid.getBulkModulus(); - arrayView1d< real64 const > const shearModulus = porousSolid.getShearModulus(); - arrayView1d< real64 const > const biotCoefficient = porousSolid.getBiotCoefficient(); +template<> +void MultiphasePoromechanics< CompositionalMultiphaseReservoirAndWells<>, SolidMechanicsLagrangianFEM >::setMGRStrategy() +{ + // same as CompositionalMultiphaseReservoirAndWells< MultiphasePoromechanics<> >::setMGRStrategy - real64 const stabilizationMultiplier = m_stabilizationMultiplier; + LinearSolverParameters & linearSolverParameters = m_linearSolverParameters.get(); - forAll< parallelDevicePolicy<> >( subRegion.size(), [bulkModulus, - shearModulus, - biotCoefficient, - stabilizationMultiplier, - macroElementIndex, - elementStabConstant] GEOS_HOST_DEVICE ( localIndex const ei ) - { - real64 const bM = bulkModulus[ei]; - real64 const sM = shearModulus[ei]; - real64 const bC = biotCoefficient[ei]; + if( linearSolverParameters.preconditionerType != LinearSolverParameters::PreconditionerType::mgr ) + return; - macroElementIndex[ei] = 1; - elementStabConstant[ei] = stabilizationMultiplier * 9.0 * (bC * bC) / (32.0 * (10.0 * sM / 3.0 + bM)); + linearSolverParameters.mgr.separateComponents = true; + linearSolverParameters.dofsPerNode = 3; - } ); - } ); - } ); + if( dynamic_cast< CompositionalMultiphaseHybridFVM * >( this->flowSolver() ) ) + { + GEOS_ERROR( GEOS_FMT( "{}: MGR strategy is not implemented for {}/{}", + this->getName(), this->getCatalogName(), this->flowSolver()->getCatalogName() ) ); + } + else + { + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::multiphasePoromechanicsReservoirFVM; + } + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: MGR strategy set to {}", getName(), + EnumStrings< LinearSolverParameters::MGR::StrategyType >::toString( linearSolverParameters.mgr.strategy ))); } -template< typename FLOW_SOLVER > -void MultiphasePoromechanics< FLOW_SOLVER >::updateBulkDensity( ElementSubRegionBase & subRegion ) +template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > +void MultiphasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::updateBulkDensity( ElementSubRegionBase & subRegion ) { // get the fluid model (to access fluid density) string const fluidName = subRegion.getReference< string >( FlowSolverBase::viewKeyStruct::fluidNamesString() ); MultiFluidBase const & fluid = this->template getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); // get the solid model (to access porosity and solid density) - string const solidName = subRegion.getReference< string >( viewKeyStruct::porousMaterialNamesString() ); + string const solidName = subRegion.getReference< string >( Base::viewKeyStruct::porousMaterialNamesString() ); CoupledSolidBase const & solid = this->template getConstitutiveModel< CoupledSolidBase >( subRegion, solidName ); // update the bulk density poromechanicsKernels:: MultiphaseBulkDensityKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( this->flowSolver()->numFluidPhases(), + createAndLaunch< parallelDevicePolicy<> >( this->flowSolver()->numFluidComponents(), fluid, solid, subRegion ); } -template class MultiphasePoromechanics< CompositionalMultiphaseBase >; -template class MultiphasePoromechanics< CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > >; +template class MultiphasePoromechanics<>; +//template class MultiphasePoromechanics< CompositionalMultiphaseBase, SolidMechanicsLagrangeContact >; +//template class MultiphasePoromechanics< CompositionalMultiphaseBase, SolidMechanicsEmbeddedFractures >; +template class MultiphasePoromechanics< CompositionalMultiphaseReservoirAndWells<> >; namespace { -typedef MultiphasePoromechanics< CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > > MultiphaseReservoirPoromechanics; -REGISTER_CATALOG_ENTRY( SolverBase, MultiphaseReservoirPoromechanics, string const &, Group * const ) -typedef MultiphasePoromechanics< CompositionalMultiphaseBase > MultiphasePoromechanics; -REGISTER_CATALOG_ENTRY( SolverBase, MultiphasePoromechanics, string const &, Group * const ) +typedef MultiphasePoromechanics< CompositionalMultiphaseReservoirAndWells<> > MultiphaseReservoirPoromechanics; +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, MultiphaseReservoirPoromechanics, string const &, Group * const ) +typedef MultiphasePoromechanics<> MultiphasePoromechanics; +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, MultiphasePoromechanics, string const &, Group * const ) } } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.hpp b/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.hpp index 0d0835869cb..30259c11b43 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,37 +22,26 @@ #include "physicsSolvers/multiphysics/PoromechanicsSolver.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" - +#include "physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp" namespace geos { -namespace stabilization -{ -enum class StabilizationType : integer -{ - None, - Global, - Local, -}; - -ENUM_STRINGS( StabilizationType, - "None", - "Global", - "Local" ); -} - -template< typename FLOW_SOLVER > -class MultiphasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER > +template< typename FLOW_SOLVER = CompositionalMultiphaseBase, typename MECHANICS_SOLVER = SolidMechanicsLagrangianFEM > +class MultiphasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER, MECHANICS_SOLVER > { public: - using Base = PoromechanicsSolver< FLOW_SOLVER >; + using Base = PoromechanicsSolver< FLOW_SOLVER, MECHANICS_SOLVER >; using Base::m_solvers; using Base::m_dofManager; using Base::m_localMatrix; using Base::m_rhs; using Base::m_solution; + using Base::m_stabilizationType; + using Base::m_stabilizationRegionNames; + using Base::m_stabilizationMultiplier; + using Base::getLogLevel; /** * @brief main constructor for MultiphasePoromechanics Objects @@ -68,9 +58,20 @@ class MultiphasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER > * @brief name of the node manager in the object catalog * @return string that contains the catalog name to generate a new MultiphasePoromechanics object through the object catalog. */ - static string catalogName(); + static string catalogName() + { + if constexpr ( std::is_same_v< FLOW_SOLVER, CompositionalMultiphaseBase > ) // special case + { + return "MultiphasePoromechanics"; + } + else // default + { + return FLOW_SOLVER::catalogName() + "Poromechanics"; + } + } + /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -81,9 +82,7 @@ class MultiphasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER > */ /**@{*/ - virtual void postProcessInput() override; - - virtual void registerDataOnMesh( dataRepository::Group & meshBodies ) override; + virtual void postInputInitialization() override; virtual void setupCoupling( DomainPartition const & domain, DofManager & dofManager ) const override; @@ -102,35 +101,17 @@ class MultiphasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER > CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ); - virtual void updateState( DomainPartition & domain ) override; - /**@}*/ - /* - * @brief Utility function to update the stabilization parameters at each time step - * @param[in] domain the domain partition - */ - void updateStabilizationParameters( DomainPartition & domain ) const; - protected: virtual void initializePostInitialConditionsPreSubGroups() override; - virtual void initializePreSubGroups() override; - - struct viewKeyStruct : Base::viewKeyStruct + virtual void setMGRStrategy() { - /// Type of stabilization used in the simulation - constexpr static char const * stabilizationTypeString() { return "stabilizationType"; } - - /// Names of the regions where the stabilization is applied - constexpr static char const * stabilizationRegionNamesString() { return "stabilizationRegionNames"; } - - /// Multiplier on stabilization - constexpr static char const * stabilizationMultiplierString() { return "stabilizationMultiplier"; } - }; - -private: + if( this->m_linearSolverParameters.get().preconditionerType == LinearSolverParameters::PreconditionerType::mgr ) + GEOS_ERROR( GEOS_FMT( "{}: MGR strategy is not implemented for {}", this->getName(), this->getCatalogName())); + } /** * @brief Helper function to recompute the bulk density @@ -138,70 +119,8 @@ class MultiphasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER > */ virtual void updateBulkDensity( ElementSubRegionBase & subRegion ) override; - template< typename CONSTITUTIVE_BASE, - typename KERNEL_WRAPPER, - typename ... PARAMS > - real64 assemblyLaunch( MeshLevel & mesh, - DofManager const & dofManager, - arrayView1d< string const > const & regionNames, - string const & materialNamesString, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - real64 const dt, - PARAMS && ... params ); - - /// Type of stabilization used in the simulation - stabilization::StabilizationType m_stabilizationType; - - /// Names of the regions where the stabilization is applied - array1d< string > m_stabilizationRegionNames; - - /// Multiplier on stabilization constant - real64 m_stabilizationMultiplier; - }; -template< typename FLOW_SOLVER > -template< typename CONSTITUTIVE_BASE, - typename KERNEL_WRAPPER, - typename ... PARAMS > -real64 MultiphasePoromechanics< FLOW_SOLVER >::assemblyLaunch( MeshLevel & mesh, - DofManager const & dofManager, - arrayView1d< string const > const & regionNames, - string const & materialNamesString, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - real64 const dt, - PARAMS && ... params ) -{ - GEOS_MARK_FUNCTION; - - NodeManager const & nodeManager = mesh.getNodeManager(); - - string const dofKey = dofManager.getKey( fields::solidMechanics::totalDisplacement::key() ); - arrayView1d< globalIndex const > const & dofNumber = nodeManager.getReference< globalIndex_array >( dofKey ); - - real64 const gravityVectorData[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3( SolverBase::gravityVector() ); - - KERNEL_WRAPPER kernelWrapper( dofNumber, - dofManager.rankOffset(), - localMatrix, - localRhs, - dt, - gravityVectorData, - std::forward< PARAMS >( params )... ); - - return finiteElement:: - regionBasedKernelApplication< parallelDevicePolicy< >, - CONSTITUTIVE_BASE, - CellElementSubRegion >( mesh, - regionNames, - this->solidMechanicsSolver()->getDiscretizationName(), - materialNamesString, - kernelWrapper ); -} - - } /* namespace geos */ #endif /* GEOS_PHYSICSSOLVERS_MULTIPHYSICS_MULTIPHASEPOROMECHANICS_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.cpp b/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.cpp index 33eb3bcd9de..c9fe35f6145 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -43,9 +44,9 @@ PhaseFieldFractureSolver::~PhaseFieldFractureSolver() // TODO Auto-generated destructor stub } -void PhaseFieldFractureSolver::postProcessInput() +void PhaseFieldFractureSolver::postInputInitialization() { - Base::postProcessInput(); + Base::postInputInitialization(); GEOS_WARNING_IF( getNonlinearSolverParameters().m_couplingType == NonlinearSolverParameters::CouplingType::FullyImplicit, "FullyImplicit coupling not implemented for this solver. A sequential coupling approach will be used." ); getNonlinearSolverParameters().m_couplingType = NonlinearSolverParameters::CouplingType::Sequential; @@ -106,6 +107,6 @@ void PhaseFieldFractureSolver::mapSolutionBetweenSolvers( DomainPartition & doma } } -REGISTER_CATALOG_ENTRY( SolverBase, PhaseFieldFractureSolver, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, PhaseFieldFractureSolver, string const &, Group * const ) } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.hpp b/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.hpp index 40e34b47102..a1aae598694 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -52,7 +53,7 @@ class PhaseFieldFractureSolver : public CoupledSolver< SolidMechanicsLagrangianF return "PhaseFieldFracture"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -65,7 +66,7 @@ class PhaseFieldFractureSolver : public CoupledSolver< SolidMechanicsLagrangianF Damage = 1 }; - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; /** * @brief accessor for the pointer to the solid mechanics solver diff --git a/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsFields.hpp b/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsFields.hpp index d6f02ff4d06..d3dec017bc4 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsFields.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsInitialization.cpp b/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsInitialization.cpp index cb0e6541120..02fa02be59b 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsInitialization.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsInitialization.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,66 +19,31 @@ #include "PoromechanicsInitialization.hpp" +#include "events/tasks/TasksManager.hpp" #include "physicsSolvers/PhysicsSolverManager.hpp" +#include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" +#include "physicsSolvers/solidMechanics/SolidMechanicsStatistics.hpp" #include "physicsSolvers/multiphysics/MultiphasePoromechanics.hpp" #include "physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp" -#include "mainInterface/ProblemManager.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" +#include "physicsSolvers/multiphysics/SinglePhasePoromechanicsConformingFractures.hpp" +#include "physicsSolvers/multiphysics/SinglePhasePoromechanicsEmbeddedFractures.hpp" +#include "physicsSolvers/multiphysics/HydrofractureSolver.hpp" #include "physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.hpp" #include "physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp" +#include "physicsSolvers/multiphysics/LogLevelsInfo.hpp" namespace geos { using namespace dataRepository; -namespace -{ - -// This is meant to be specialized to work, see below -template< typename POROMECHANICS_SOLVER > class - PoromechanicsCatalogNames {}; - -// Class specializations for a POROMECHANICS_SOLVER set to SinglePhasePoromechanics -template<> class PoromechanicsCatalogNames< SinglePhasePoromechanics< SinglePhaseBase > > -{ -public: - static string name() { return SinglePhasePoromechanics< SinglePhaseBase >::catalogName() + "Initialization"; } -}; -template<> class PoromechanicsCatalogNames< SinglePhasePoromechanics< SinglePhaseReservoirAndWells< SinglePhaseBase > > > -{ -public: - static string name() { return SinglePhasePoromechanics< SinglePhaseReservoirAndWells< SinglePhaseBase > >::catalogName() + "Initialization"; } -}; -// Class specializations for a POROMECHANICS_SOLVER set to MultiphasePoromechanics -template<> class PoromechanicsCatalogNames< MultiphasePoromechanics< CompositionalMultiphaseBase > > -{ -public: - static string name() { return MultiphasePoromechanics< CompositionalMultiphaseBase >::catalogName() + "Initialization"; } -}; -template<> class PoromechanicsCatalogNames< MultiphasePoromechanics< CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > > > -{ -public: - static string name() { return MultiphasePoromechanics< CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > >::catalogName() + "Initialization"; } -}; - -} - -// provide a definition for catalogName() -template< typename POROMECHANICS_SOLVER > -string -PoromechanicsInitialization< POROMECHANICS_SOLVER >:: -catalogName() -{ - return PoromechanicsCatalogNames< POROMECHANICS_SOLVER >::name(); -} - template< typename POROMECHANICS_SOLVER > PoromechanicsInitialization< POROMECHANICS_SOLVER >:: PoromechanicsInitialization( const string & name, Group * const parent ): TaskBase( name, parent ), m_poromechanicsSolverName(), + m_solidMechanicsStatistics(), m_solidMechanicsStateResetTask( name, parent ) { enableLogLevelInput(); @@ -87,10 +53,13 @@ PoromechanicsInitialization( const string & name, setInputFlag( InputFlags::REQUIRED ). setDescription( "Name of the poromechanics solver" ); - registerWrapper( viewKeyStruct::performStressInitializationString(), &m_performStressInitialization ). - setApplyDefaultValue( true ). - setInputFlag( InputFlags::REQUIRED ). - setDescription( "Flag to indicate that the solver is going to perform stress initialization" ); + registerWrapper( viewKeyStruct::solidMechanicsStatisticsNameString(), &m_solidMechanicsStatisticsName ). + setRTTypeName( rtTypes::CustomTypes::groupNameRef ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( "" ). + setDescription( "Name of the solid mechanics statistics" ); + + addLogLevel< logInfo::Initialization >(); } template< typename POROMECHANICS_SOLVER > @@ -99,22 +68,36 @@ PoromechanicsInitialization< POROMECHANICS_SOLVER >::~PoromechanicsInitializatio template< typename POROMECHANICS_SOLVER > void PoromechanicsInitialization< POROMECHANICS_SOLVER >:: -postProcessInput() +postInputInitialization() { - ProblemManager & problemManager = this->getGroupByPath< ProblemManager >( "/Problem" ); - PhysicsSolverManager & physicsSolverManager = problemManager.getPhysicsSolverManager(); + Group & problemManager = this->getGroupByPath( "/Problem" ); + Group & physicsSolverManager = problemManager.getGroup( "Solvers" ); GEOS_THROW_IF( !physicsSolverManager.hasGroup( m_poromechanicsSolverName ), - GEOS_FMT( "{}: physics solver named {} not found", + GEOS_FMT( "{}: {} solver named {} not found", getWrapperDataContext( viewKeyStruct::poromechanicsSolverNameString() ), + POROMECHANICS_SOLVER::catalogName(), m_poromechanicsSolverName ), InputError ); m_poromechanicsSolver = &physicsSolverManager.getGroup< POROMECHANICS_SOLVER >( m_poromechanicsSolverName ); + if( !m_solidMechanicsStatisticsName.empty()) + { + TasksManager & tasksManager = problemManager.getGroup< TasksManager >( "Tasks" ); + + GEOS_THROW_IF( !tasksManager.hasGroup( m_solidMechanicsStatisticsName ), + GEOS_FMT( "{}: statistics task named {} not found", + getWrapperDataContext( viewKeyStruct::solidMechanicsStatisticsNameString() ), + m_solidMechanicsStatisticsName ), + InputError ); + + m_solidMechanicsStatistics = &tasksManager.getGroup< SolidMechanicsStatistics >( m_solidMechanicsStatisticsName ); + } + m_solidMechanicsStateResetTask.setLogLevel( getLogLevel()); m_solidMechanicsStateResetTask.m_solidSolverName = m_poromechanicsSolver->solidMechanicsSolver()->getName(); - m_solidMechanicsStateResetTask.postProcessInput(); + m_solidMechanicsStateResetTask.postInputInitialization(); } template< typename POROMECHANICS_SOLVER > @@ -127,17 +110,21 @@ execute( real64 const time_n, real64 const eventProgress, DomainPartition & domain ) { - if( m_performStressInitialization ) - { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "Task `{}`: at time {}s, physics solver `{}` is set to perform stress initialization during the next time step(s)", - getName(), time_n, m_poromechanicsSolverName ) ); - m_poromechanicsSolver->setStressInitialization( true ); - } - else + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Initialization, GEOS_FMT( "Task `{}`: at time {}s, physics solver `{}` is set to perform stress initialization during the next time step(s)", + getName(), time_n, m_poromechanicsSolverName ) ); + m_poromechanicsSolver->setStressInitialization( true ); + + m_solidMechanicsStateResetTask.execute( time_n, dt, cycleNumber, eventCounter, eventProgress, domain ); + + m_poromechanicsSolver->execute( time_n, dt, cycleNumber, eventCounter, eventProgress, domain ); + + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Initialization, GEOS_FMT( "Task `{}`: at time {}s, physics solver `{}` has completed stress initialization", + getName(), time_n + dt, m_poromechanicsSolverName ) ); + m_poromechanicsSolver->setStressInitialization( false ); + + if( m_solidMechanicsStatistics != nullptr ) { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "Task `{}`: at time {}s, physics solver `{}` has completed stress initialization", - getName(), time_n, m_poromechanicsSolverName ) ); - m_poromechanicsSolver->setStressInitialization( false ); + m_solidMechanicsStatistics->execute( time_n, dt, cycleNumber, eventCounter, eventProgress, domain ); } m_solidMechanicsStateResetTask.execute( time_n, dt, cycleNumber, eventCounter, eventProgress, domain ); @@ -148,14 +135,22 @@ execute( real64 const time_n, namespace { -typedef PoromechanicsInitialization< MultiphasePoromechanics< CompositionalMultiphaseBase > > MultiphasePoromechanicsInitialization; -typedef PoromechanicsInitialization< MultiphasePoromechanics< CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > > > MultiphaseReservoirPoromechanicsInitialization; -typedef PoromechanicsInitialization< SinglePhasePoromechanics< SinglePhaseBase > > SinglePhasePoromechanicsInitialization; -typedef PoromechanicsInitialization< SinglePhasePoromechanics< SinglePhaseReservoirAndWells< SinglePhaseBase > > > SinglePhaseReservoirPoromechanicsInitialization; +typedef PoromechanicsInitialization< MultiphasePoromechanics<> > MultiphasePoromechanicsInitialization; +typedef PoromechanicsInitialization< MultiphasePoromechanics< CompositionalMultiphaseReservoirAndWells<> > > MultiphaseReservoirPoromechanicsInitialization; +typedef PoromechanicsInitialization< SinglePhasePoromechanics<> > SinglePhasePoromechanicsInitialization; +typedef PoromechanicsInitialization< SinglePhasePoromechanicsConformingFractures<> > SinglePhasePoromechanicsConformingFracturesInitialization; +typedef PoromechanicsInitialization< SinglePhasePoromechanicsConformingFractures< SinglePhaseReservoirAndWells<> > > SinglePhaseReservoirPoromechanicsConformingFracturesInitialization; +typedef PoromechanicsInitialization< SinglePhasePoromechanicsEmbeddedFractures > SinglePhasePoromechanicsEmbeddedFracturesInitialization; +typedef PoromechanicsInitialization< SinglePhasePoromechanics< SinglePhaseReservoirAndWells<> > > SinglePhaseReservoirPoromechanicsInitialization; +typedef PoromechanicsInitialization< HydrofractureSolver< SinglePhasePoromechanics<> > > HydrofractureInitialization; REGISTER_CATALOG_ENTRY( TaskBase, MultiphasePoromechanicsInitialization, string const &, Group * const ) REGISTER_CATALOG_ENTRY( TaskBase, MultiphaseReservoirPoromechanicsInitialization, string const &, Group * const ) REGISTER_CATALOG_ENTRY( TaskBase, SinglePhasePoromechanicsInitialization, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( TaskBase, SinglePhasePoromechanicsConformingFracturesInitialization, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( TaskBase, SinglePhaseReservoirPoromechanicsConformingFracturesInitialization, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( TaskBase, SinglePhasePoromechanicsEmbeddedFracturesInitialization, string const &, Group * const ) REGISTER_CATALOG_ENTRY( TaskBase, SinglePhaseReservoirPoromechanicsInitialization, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( TaskBase, HydrofractureInitialization, string const &, Group * const ) } } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsInitialization.hpp b/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsInitialization.hpp index 22f971dcdb3..60e8535a2b7 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsInitialization.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsInitialization.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -24,6 +25,7 @@ namespace geos { +class SolidMechanicsStatistics; /** * @class PoromechanicsInitialization @@ -53,7 +55,10 @@ class PoromechanicsInitialization : public TaskBase ~PoromechanicsInitialization() override; /// Accessor for the catalog name - static string catalogName(); + static string catalogName() + { + return POROMECHANICS_SOLVER::catalogName() + "Initialization"; + } /** * @defgroup Tasks Interface Functions @@ -80,21 +85,25 @@ class PoromechanicsInitialization : public TaskBase { /// String for the poromechanics solver name constexpr static char const * poromechanicsSolverNameString() { return "poromechanicsSolverName"; } - /// String for the solver configuration - constexpr static char const * performStressInitializationString() { return "performStressInitialization"; } + /// String for the solid mechanics statistics name + constexpr static char const * solidMechanicsStatisticsNameString() { return "solidMechanicsStatisticsName"; } }; + void postInputInitialization() override; - void postProcessInput() override; +// void registerDataOnMesh( Group & meshBodies ) override; /// Name of the poromechanics solver string m_poromechanicsSolverName; - /// Pointer to the multiphase poromechanics solver + /// Name of the solid mechanics statistics + string m_solidMechanicsStatisticsName; + + /// Pointer to the poromechanics solver POROMECHANICS_SOLVER * m_poromechanicsSolver; - /// Flag to indicate that the solver is going to perform stress initialization - integer m_performStressInitialization; + /// Pointer to the solid mechanics statistics + SolidMechanicsStatistics * m_solidMechanicsStatistics; SolidMechanicsStateReset m_solidMechanicsStateResetTask; diff --git a/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsSolver.hpp b/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsSolver.hpp index 73dae9d74c9..62a772e0278 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsSolver.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsSolver.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,17 +21,36 @@ #ifndef GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSSOLVER_HPP_ #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSSOLVER_HPP_ +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/multiphysics/CoupledSolver.hpp" #include "physicsSolvers/multiphysics/PoromechanicsFields.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp" #include "constitutive/solid/CoupledSolidBase.hpp" #include "constitutive/solid/PorousSolid.hpp" +#include "constitutive/contact/HydraulicApertureBase.hpp" +#include "mesh/DomainPartition.hpp" #include "mesh/utilities/AverageOverQuadraturePointsKernel.hpp" #include "codingUtilities/Utilities.hpp" namespace geos { +namespace stabilization +{ +enum class StabilizationType : integer +{ + None, + Global, + Local, +}; + +ENUM_STRINGS( StabilizationType, + "None", + "Global", + "Local" ); +} + + template< typename FLOW_SOLVER, typename MECHANICS_SOLVER = SolidMechanicsLagrangianFEM > class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER > { @@ -71,6 +91,23 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER setApplyDefaultValue( false ). setInputFlag( dataRepository::InputFlags::FALSE ). setDescription( "Flag to indicate that the solver is going to perform stress initialization" ); + + this->registerWrapper( viewKeyStruct::stabilizationTypeString(), &m_stabilizationType ). + setInputFlag( dataRepository::InputFlags::OPTIONAL ). + setDescription( "StabilizationType. Options are:\n" + + toString( stabilization::StabilizationType::None ) + "- Add no stabilization to mass equation \n" + + toString( stabilization::StabilizationType::Global ) + "- Add jump stabilization to all faces \n" + + toString( stabilization::StabilizationType::Local ) + "- Add jump stabilization on interior of macro elements" ); + + this->registerWrapper( viewKeyStruct::stabilizationRegionNamesString(), &m_stabilizationRegionNames ). + setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ). + setInputFlag( dataRepository::InputFlags::OPTIONAL ). + setDescription( "Regions where stabilization is applied." ); + + this->registerWrapper( viewKeyStruct::stabilizationMultiplierString(), &m_stabilizationMultiplier ). + setApplyDefaultValue( 1.0 ). + setInputFlag( dataRepository::InputFlags::OPTIONAL ). + setDescription( "Constant multiplier of stabilization strength" ); } virtual void initializePostInitialConditionsPreSubGroups() override @@ -83,10 +120,32 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER InputError ); } + virtual void setConstitutiveNamesCallSuper( ElementSubRegionBase & subRegion ) const override final + { + if( dynamic_cast< SurfaceElementSubRegion * >( &subRegion ) ) + { + subRegion.registerWrapper< string >( viewKeyStruct::hydraulicApertureRelationNameString() ). + setPlotLevel( dataRepository::PlotLevel::NOPLOT ). + setRestartFlags( dataRepository::RestartFlags::NO_WRITE ). + setSizedFromParent( 0 ); + + string & hydraulicApertureModelName = subRegion.getReference< string >( viewKeyStruct::hydraulicApertureRelationNameString() ); + hydraulicApertureModelName = PhysicsSolverBase::getConstitutiveName< constitutive::HydraulicApertureBase >( subRegion ); + GEOS_ERROR_IF( hydraulicApertureModelName.empty(), GEOS_FMT( "{}: HydraulicApertureBase model not found on subregion {}", + this->getDataContext(), subRegion.getDataContext() ) ); + } + + } + virtual void initializePreSubGroups() override { Base::initializePreSubGroups(); + GEOS_THROW_IF( m_stabilizationType == stabilization::StabilizationType::Local, + this->getWrapperDataContext( viewKeyStruct::stabilizationTypeString() ) << + ": Local stabilization has been temporarily disabled", + InputError ); + DomainPartition & domain = this->template getGroupByPath< DomainPartition >( "/Problem/domain" ); this->template forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, @@ -94,7 +153,7 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER arrayView1d< string const > const & regionNames ) { ElementRegionManager & elementRegionManager = mesh.getElemManager(); - elementRegionManager.forElementSubRegions< ElementSubRegionBase >( regionNames, + elementRegionManager.forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, ElementSubRegionBase & subRegion ) { @@ -109,11 +168,9 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER porosityModelName = this->template getConstitutiveName< constitutive::PorosityBase >( subRegion ); GEOS_THROW_IF( porosityModelName.empty(), GEOS_FMT( "{} {} : Porosity model not found on subregion {}", - this->catalogName(), this->getDataContext().toString(), subRegion.getName() ), + this->getCatalogName(), this->getDataContext().toString(), subRegion.getName() ), InputError ); - - if( subRegion.hasField< fields::poromechanics::bulkDensity >() ) { // get the solid model to know the number of quadrature points and resize the bulk density @@ -126,7 +183,7 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER virtual void registerDataOnMesh( dataRepository::Group & meshBodies ) override { - SolverBase::registerDataOnMesh( meshBodies ); + PhysicsSolverBase::registerDataOnMesh( meshBodies ); if( this->getNonlinearSolverParameters().m_couplingType == NonlinearSolverParameters::CouplingType::Sequential ) { @@ -136,13 +193,18 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER flowSolver()->enableFixedStressPoromechanicsUpdate(); } - SolverBase::forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + if( m_stabilizationType == stabilization::StabilizationType::Global || m_stabilizationType == stabilization::StabilizationType::Local ) + { + flowSolver()->enableJumpStabilization(); + } + + PhysicsSolverBase::forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { ElementRegionManager & elemManager = mesh.getElemManager(); - elemManager.forElementSubRegions< ElementSubRegionBase >( regionNames, + elemManager.forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, ElementSubRegionBase & subRegion ) { @@ -163,6 +225,12 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER // ideally we would resize it here as well, but the solid model name is not available yet (see below) subRegion.registerField< fields::poromechanics::bulkDensity >( this->getName() ); } + + if( m_stabilizationType == stabilization::StabilizationType::Global || m_stabilizationType == stabilization::StabilizationType::Local ) + { + subRegion.registerField< fields::flow::macroElementIndex >( this->getName()); + subRegion.registerField< fields::flow::elementStabConstant >( this->getName()); + } } ); } ); } @@ -171,7 +239,13 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER real64 const & dt, DomainPartition & domain ) override { - flowSolver()->keepFlowVariablesConstantDuringInitStep( m_performStressInitialization ); + flowSolver()->setKeepVariablesConstantDuringInitStep( m_performStressInitialization ); + + if( this->m_stabilizationType == stabilization::StabilizationType::Global || this->m_stabilizationType == stabilization::StabilizationType::Local ) + { + this->updateStabilizationParameters( domain ); + } + Base::implicitStepSetup( time_n, dt, domain ); } @@ -183,10 +257,28 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER // that's the reason why this function is here and not in CoupledSolvers.hpp solidMechanicsSolver()->setupDofs( domain, dofManager ); flowSolver()->setupDofs( domain, dofManager ); - this->setupCoupling( domain, dofManager ); } + virtual bool checkSequentialConvergence( int const & iter, + real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) override + { + // always force outer loop for initialization + auto & subcycling = this->getNonlinearSolverParameters().m_subcyclingOption; + auto const subcycling_orig = subcycling; + if( m_performStressInitialization ) + subcycling = 1; + + bool isConverged = Base::checkSequentialConvergence( iter, time_n, dt, domain ); + + // restore original + subcycling = subcycling_orig; + + return isConverged; + } + /** * @brief accessor for the pointer to the solid mechanics solver * @return a pointer to the solid mechanics solver @@ -224,24 +316,138 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER /// Flag to indicate that the solver is going to perform stress initialization constexpr static char const * performStressInitializationString() { return "performStressInitialization"; } + + /// Type of pressure stabilization + constexpr static char const * stabilizationTypeString() {return "stabilizationType"; } + + /// Name of regions on which stabilization applied + constexpr static const char * stabilizationRegionNamesString() {return "stabilizationRegionNames"; } + + /// Multiplier on stabilization strength + constexpr static const char * stabilizationMultiplierString() {return "stabilizationMultiplier"; } + + /// Name of the hydraulicApertureRelationName + static constexpr char const * hydraulicApertureRelationNameString() {return "hydraulicApertureRelationName"; } + }; + void updateStabilizationParameters( DomainPartition & domain ) const + { + // Step 1: we loop over the regions where stabilization is active and collect their name + set< string > regionFilter; + for( string const & regionName : m_stabilizationRegionNames ) + { + regionFilter.insert( regionName ); + } + + // Step 2: loop over target regions of solver, and tag the elements belonging to the stabilization regions + this->template forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & targetRegionNames ) + { + //keep only target regions in filter + array1d< string > filteredTargetRegionNames; + filteredTargetRegionNames.reserve( targetRegionNames.size() ); + + for( string const & targetRegionName : targetRegionNames ) + { + if( regionFilter.count( targetRegionName ) ) + { + filteredTargetRegionNames.emplace_back( targetRegionName ); + } + } + + // Loop over elements and update stabilization constant + mesh.getElemManager().forElementSubRegions( filteredTargetRegionNames.toViewConst(), [&]( localIndex const, + ElementSubRegionBase & subRegion ) + { + arrayView1d< integer > const macroElementIndex = subRegion.getField< fields::flow::macroElementIndex >(); + arrayView1d< real64 > const elementStabConstant = subRegion.getField< fields::flow::elementStabConstant >(); + + geos::constitutive::CoupledSolidBase const & porousSolid = + this->template getConstitutiveModel< geos::constitutive::CoupledSolidBase >( subRegion, subRegion.getReference< string >( viewKeyStruct::porousMaterialNamesString() ) ); + + arrayView1d< real64 const > const bulkModulus = porousSolid.getBulkModulus(); + arrayView1d< real64 const > const shearModulus = porousSolid.getShearModulus(); + arrayView1d< real64 const > const biotCoefficient = porousSolid.getBiotCoefficient(); + + real64 const stabilizationMultiplier = m_stabilizationMultiplier; + + forAll< parallelDevicePolicy<> >( subRegion.size(), [bulkModulus, + shearModulus, + biotCoefficient, + stabilizationMultiplier, + macroElementIndex, + elementStabConstant] GEOS_HOST_DEVICE ( localIndex const ei ) + + { + real64 const bM = bulkModulus[ei]; + real64 const sM = shearModulus[ei]; + real64 const bC = biotCoefficient[ei]; + + macroElementIndex[ei] = 1; + elementStabConstant[ei] = stabilizationMultiplier * 9.0 * (bC * bC) / (32.0 * (10.0 * sM / 3.0 + bM)); + } ); + } ); + } ); + + } + protected: + template< typename CONSTITUTIVE_BASE, + typename KERNEL_WRAPPER, + typename ... PARAMS > + real64 assemblyLaunch( MeshLevel & mesh, + DofManager const & dofManager, + arrayView1d< string const > const & regionNames, + string const & materialNamesString, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + real64 const dt, + PARAMS && ... params ) + { + GEOS_MARK_FUNCTION; + + NodeManager const & nodeManager = mesh.getNodeManager(); + + string const dofKey = dofManager.getKey( fields::solidMechanics::totalDisplacement::key() ); + arrayView1d< globalIndex const > const & dofNumber = nodeManager.getReference< globalIndex_array >( dofKey ); + + real64 const gravityVectorData[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3( PhysicsSolverBase::gravityVector() ); + + KERNEL_WRAPPER kernelWrapper( dofNumber, + dofManager.rankOffset(), + localMatrix, + localRhs, + dt, + gravityVectorData, + std::forward< PARAMS >( params )... ); + + return finiteElement:: + regionBasedKernelApplication< parallelDevicePolicy< >, + CONSTITUTIVE_BASE, + CellElementSubRegion >( mesh, + regionNames, + this->solidMechanicsSolver()->getDiscretizationName(), + materialNamesString, + kernelWrapper ); + } + /* Implementation of Nonlinear Acceleration (Aitken) of averageMeanTotalStressIncrement */ void recordAverageMeanTotalStressIncrement( DomainPartition & domain, array1d< real64 > & averageMeanTotalStressIncrement ) { averageMeanTotalStressIncrement.resize( 0 ); - SolverBase::forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) { + PhysicsSolverBase::forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, auto & subRegion ) { // get the solid model (to access stress increment) string const solidName = subRegion.template getReference< string >( "porousMaterialNames" ); - constitutive::CoupledSolidBase & solid = SolverBase::getConstitutiveModel< constitutive::CoupledSolidBase >( + constitutive::CoupledSolidBase & solid = PhysicsSolverBase::getConstitutiveModel< constitutive::CoupledSolidBase >( subRegion, solidName ); arrayView1d< const real64 > const & averageMeanTotalStressIncrement_k = solid.getAverageMeanTotalStressIncrement_k(); @@ -257,14 +463,14 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER array1d< real64 > & averageMeanTotalStressIncrement ) { integer i = 0; - SolverBase::forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) { + PhysicsSolverBase::forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, auto & subRegion ) { // get the solid model (to access stress increment) string const solidName = subRegion.template getReference< string >( "porousMaterialNames" ); - constitutive::CoupledSolidBase & solid = SolverBase::getConstitutiveModel< constitutive::CoupledSolidBase >( + constitutive::CoupledSolidBase & solid = PhysicsSolverBase::getConstitutiveModel< constitutive::CoupledSolidBase >( subRegion, solidName ); auto & porosityModel = dynamic_cast< constitutive::BiotPorosity const & >( solid.getBasePorosityModel()); arrayView1d< real64 > const & averageMeanTotalStressIncrement_k = solid.getAverageMeanTotalStressIncrement_k(); @@ -371,7 +577,8 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER } /// After the solid mechanics solver - if( solverType == static_cast< integer >( SolverType::SolidMechanics ) ) + if( solverType == static_cast< integer >( SolverType::SolidMechanics ) + && !m_performStressInitialization ) // do not update during poromechanics initialization { // compute the average of the mean total stress increment over quadrature points averageMeanTotalStressIncrement( domain ); @@ -387,6 +594,8 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER // update the porosity after a change in displacement (after mechanics solve) // or a change in pressure/temperature (after a flow solve) flowSolver()->updatePorosityAndPermeability( subRegion ); + // update bulk density to reflect porosity change into mechanics + updateBulkDensity( subRegion ); } ); } ); } @@ -448,7 +657,7 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER virtual void validateNonlinearAcceleration() override { - if( MpiWrapper::commSize( MPI_COMM_GEOSX ) > 1 ) + if( MpiWrapper::commSize( MPI_COMM_GEOS ) > 1 ) { GEOS_ERROR( "Nonlinear acceleration is not implemented for MPI runs" ); } @@ -460,6 +669,15 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER /// Flag to indicate that the solver is going to perform stress initialization integer m_performStressInitialization; + /// Type of stabilization used + stabilization::StabilizationType m_stabilizationType; + + /// Names of regions where stabilization applied + array1d< string > m_stabilizationRegionNames; + + /// Stabilization Multiplier + real64 m_stabilizationMultiplier; + /// Member variables needed for Nonlinear Acceleration ( Aitken ). Naming convention follows ( Jiang & Tchelepi, 2019 ) array1d< real64 > m_s0; // Accelerated averageMeanTotalStresIncrement @ outer iteration v ( two iterations ago ) array1d< real64 > m_s1; // Accelerated averageMeanTotalStresIncrement @ outer iteration v + 1 ( previous iteration ) diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.cpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.cpp index d21eef612ae..0bfa9146a27 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,7 +17,7 @@ * @file SinglePhasePoromechanics.cpp */ -#define GEOSX_DISPATCH_VEM /// enables VEM in FiniteElementDispatch +#define GEOS_DISPATCH_VEM /// enables VEM in FiniteElementDispatch #include "SinglePhasePoromechanics.hpp" @@ -24,8 +25,6 @@ #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" #include "linearAlgebra/solvers/BlockPreconditioner.hpp" #include "linearAlgebra/solvers/SeparateComponentPreconditioner.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" -#include "physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanics.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanics.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsFields.hpp" @@ -33,6 +32,7 @@ #include "physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainQuasiStatic.hpp" #include "physicsSolvers/contact/SolidMechanicsLagrangeContact.hpp" #include "physicsSolvers/contact/SolidMechanicsEmbeddedFractures.hpp" +#include "physicsSolvers/fluidFlow/SinglePhaseHybridFVM.hpp" namespace geos { @@ -40,60 +40,20 @@ namespace geos using namespace constitutive; using namespace dataRepository; using namespace fields; - -namespace -{ - -// This is meant to be specialized to work, see below -template< typename FLOW_SOLVER > class - SinglePhaseCatalogNames {}; - -// Class specialization for a FLOW_SOLVER set to SinglePhaseFlow -template<> class SinglePhaseCatalogNames< SinglePhaseBase > -{ -public: - static string name() { return "SinglePhasePoromechanics"; } -}; -// Class specialization for a FLOW_SOLVER set to SinglePhaseReservoirAndWells -template<> class SinglePhaseCatalogNames< SinglePhaseReservoirAndWells< SinglePhaseBase > > -{ -public: - static string name() { return SinglePhaseReservoirAndWells< SinglePhaseBase >::catalogName() + "Poromechanics"; } -}; -} - -// provide a definition for catalogName() -template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > -string -SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >:: -catalogName() -{ - return SinglePhaseCatalogNames< FLOW_SOLVER >::name(); -} +using namespace stabilization; template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::SinglePhasePoromechanics( const string & name, Group * const parent ) : Base( name, parent ) -{ - LinearSolverParameters & linearSolverParameters = this->m_linearSolverParameters.get(); - linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::singlePhasePoromechanics; - linearSolverParameters.mgr.separateComponents = true; - linearSolverParameters.mgr.displacementFieldName = solidMechanics::totalDisplacement::key(); - linearSolverParameters.dofsPerNode = 3; -} +{} template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > -void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::postProcessInput() +void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::postInputInitialization() { - Base::postProcessInput(); - - GEOS_ERROR_IF( this->flowSolver()->catalogName() == "SinglePhaseReservoir" && - this->getNonlinearSolverParameters().couplingType() != NonlinearSolverParameters::CouplingType::Sequential, - GEOS_FMT( "{}: {} solver is only designed to work for {} = {}", - this->getName(), catalogName(), NonlinearSolverParameters::viewKeysStruct::couplingTypeString(), - EnumStrings< NonlinearSolverParameters::CouplingType >::toString( NonlinearSolverParameters::CouplingType::Sequential ) - )); + Base::postInputInitialization(); + + setMGRStrategy(); } template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > @@ -119,7 +79,7 @@ void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::setupSystem( Dom } // setup monolithic coupled system - SolverBase::setupSystem( domain, dofManager, localMatrix, rhs, solution, setSparsity ); + PhysicsSolverBase::setupSystem( domain, dofManager, localMatrix, rhs, solution, setSparsity ); if( !this->m_precond && this->m_linearSolverParameters.get().solverType != LinearSolverParameters::SolverType::direct ) { @@ -133,9 +93,9 @@ void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::initializePostIn Base::initializePostInitialConditionsPreSubGroups(); arrayView1d< string const > const & poromechanicsTargetRegionNames = - this->template getReference< array1d< string > >( SolverBase::viewKeyStruct::targetRegionsString() ); + this->template getReference< array1d< string > >( PhysicsSolverBase::viewKeyStruct::targetRegionsString() ); arrayView1d< string const > const & flowTargetRegionNames = - this->flowSolver()->template getReference< array1d< string > >( SolverBase::viewKeyStruct::targetRegionsString() ); + this->flowSolver()->template getReference< array1d< string > >( PhysicsSolverBase::viewKeyStruct::targetRegionsString() ); for( integer i = 0; i < poromechanicsTargetRegionNames.size(); ++i ) { GEOS_THROW_IF( std::find( flowTargetRegionNames.begin(), flowTargetRegionNames.end(), poromechanicsTargetRegionNames[i] ) @@ -144,18 +104,70 @@ void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::initializePostIn getCatalogName(), this->getDataContext(), poromechanicsTargetRegionNames[i], this->flowSolver()->getDataContext() ), InputError ); } +} + +template<> +void SinglePhasePoromechanics<>::setMGRStrategy() +{ + LinearSolverParameters & linearSolverParameters = this->m_linearSolverParameters.get(); + + if( linearSolverParameters.preconditionerType != LinearSolverParameters::PreconditionerType::mgr ) + return; - if( this->m_isThermal ) + linearSolverParameters.mgr.separateComponents = true; + linearSolverParameters.dofsPerNode = 3; + + if( dynamic_cast< SinglePhaseHybridFVM * >( this->flowSolver() ) ) { - this->m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::thermalSinglePhasePoromechanics; + if( this->m_isThermal ) + { + GEOS_ERROR( GEOS_FMT( "{}: MGR strategy is not implemented for thermal {}/{}", + this->getName(), this->getCatalogName(), this->flowSolver()->getCatalogName() )); + } + else + { + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::hybridSinglePhasePoromechanics; + } } else { - if( this->flowSolver()->getLinearSolverParameters().mgr.strategy == LinearSolverParameters::MGR::StrategyType::singlePhaseHybridFVM ) + if( this->m_isThermal ) { - this->m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::hybridSinglePhasePoromechanics; + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::thermalSinglePhasePoromechanics; + } + else + { + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::singlePhasePoromechanics; } } + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: MGR strategy set to {}", getName(), + EnumStrings< LinearSolverParameters::MGR::StrategyType >::toString( linearSolverParameters.mgr.strategy ))); +} + +template<> +void SinglePhasePoromechanics< SinglePhaseReservoirAndWells<>, SolidMechanicsLagrangianFEM >::setMGRStrategy() +{ + // same as SinglePhaseReservoirAndWells< SinglePhasePoromechanics<> >::setMGRStrategy + + LinearSolverParameters & linearSolverParameters = m_linearSolverParameters.get(); + + if( linearSolverParameters.preconditionerType != LinearSolverParameters::PreconditionerType::mgr ) + return; + + linearSolverParameters.mgr.separateComponents = true; + linearSolverParameters.dofsPerNode = 3; + + if( dynamic_cast< SinglePhaseHybridFVM * >( this->flowSolver() ) ) + { + GEOS_ERROR( GEOS_FMT( "{}: MGR strategy is not implemented for poromechanics {}/{}", + this->getName(), this->getCatalogName(), this->flowSolver()->getCatalogName())); + } + else + { + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::singlePhasePoromechanicsReservoirFVM; + } + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: MGR strategy set to {}", this->getName(), + EnumStrings< LinearSolverParameters::MGR::StrategyType >::toString( linearSolverParameters.mgr.strategy ))); } template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > @@ -177,12 +189,64 @@ void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::assembleSystem( localRhs ); // Step 3: compute the fluxes (face-based contributions) - this->flowSolver()->assembleFluxTerms( dt, - domain, - dofManager, - localMatrix, - localRhs ); + if( m_stabilizationType == StabilizationType::Global || m_stabilizationType == StabilizationType::Local ) + { + this->flowSolver()->assembleStabilizedFluxTerms( dt, + domain, + dofManager, + localMatrix, + localRhs ); + } + else + { + this->flowSolver()->assembleFluxTerms( dt, + domain, + dofManager, + localMatrix, + localRhs ); + } +} +template<> +void SinglePhasePoromechanics< SinglePhaseReservoirAndWells<>, SolidMechanicsLagrangianFEM >::assembleSystem( real64 const time_n, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + GEOS_MARK_FUNCTION; + + // Steps 1 and 2: compute element-based terms (mechanics and local flow terms) + assembleElementBasedTerms( time_n, + dt, + domain, + dofManager, + localMatrix, + localRhs ); + + // Step 3: compute the fluxes (face-based contributions) + if( m_stabilizationType == StabilizationType::Global || m_stabilizationType == StabilizationType::Local ) + { + this->flowSolver()->assembleStabilizedFluxTerms( dt, + domain, + dofManager, + localMatrix, + localRhs ); + } + else + { + this->flowSolver()->assembleFluxTerms( dt, + domain, + dofManager, + localMatrix, + localRhs ); + } + + // step 4: assemble well contributions + + this->flowSolver()->wellSolver()->assembleSystem( time_n, dt, domain, dofManager, localMatrix, localRhs ); + this->flowSolver()->assembleCouplingTerms( time_n, dt, domain, dofManager, localMatrix, localRhs ); } template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > @@ -214,30 +278,32 @@ void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::assembleElementB if( this->m_isThermal ) { poromechanicsMaxForce = - assemblyLaunch< constitutive::PorousSolid< ElasticIsotropic >, // TODO: change once there is a cmake solution - thermalPoromechanicsKernels::ThermalSinglePhasePoromechanicsKernelFactory >( mesh, - dofManager, - regionNames, - viewKeyStruct::porousMaterialNamesString(), - localMatrix, - localRhs, - dt, - flowDofKey, - FlowSolverBase::viewKeyStruct::fluidNamesString() ); + this->template assemblyLaunch< constitutive::PorousSolidBase, + thermalPoromechanicsKernels::ThermalSinglePhasePoromechanicsKernelFactory >( mesh, + dofManager, + regionNames, + viewKeyStruct::porousMaterialNamesString(), + localMatrix, + localRhs, + dt, + flowDofKey, + this->m_performStressInitialization, + FlowSolverBase::viewKeyStruct::fluidNamesString() ); } else { poromechanicsMaxForce = - assemblyLaunch< constitutive::PorousSolidBase, - poromechanicsKernels::SinglePhasePoromechanicsKernelFactory >( mesh, - dofManager, - regionNames, - viewKeyStruct::porousMaterialNamesString(), - localMatrix, - localRhs, - dt, - flowDofKey, - FlowSolverBase::viewKeyStruct::fluidNamesString() ); + this->template assemblyLaunch< constitutive::PorousSolidBase, + poromechanicsKernels::SinglePhasePoromechanicsKernelFactory >( mesh, + dofManager, + regionNames, + viewKeyStruct::porousMaterialNamesString(), + localMatrix, + localRhs, + dt, + flowDofKey, + this->m_performStressInitialization, + FlowSolverBase::viewKeyStruct::fluidNamesString() ); } } ); @@ -266,16 +332,17 @@ void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::assembleElementB } mechanicsMaxForce = - assemblyLaunch< constitutive::SolidBase, - solidMechanicsLagrangianFEMKernels::QuasiStaticFactory >( mesh, - dofManager, - filteredRegionNames.toViewConst(), - SolidMechanicsLagrangianFEM::viewKeyStruct::solidMaterialNamesString(), - localMatrix, - localRhs, - dt ); + this->template assemblyLaunch< constitutive::SolidBase, + solidMechanicsLagrangianFEMKernels::QuasiStaticFactory >( mesh, + dofManager, + filteredRegionNames.toViewConst(), + SolidMechanicsLagrangianFEM::viewKeyStruct::solidMaterialNamesString(), + localMatrix, + localRhs, + dt ); } ); + this->solidMechanicsSolver()->applyContactConstraint( dofManager, domain, localMatrix, localRhs ); this->solidMechanicsSolver()->getMaxForce() = LvArray::math::max( mechanicsMaxForce, poromechanicsMaxForce ); } @@ -307,31 +374,6 @@ void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::createPreconditi } } -template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > -void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::updateState( DomainPartition & domain ) -{ - GEOS_MARK_FUNCTION; - - this->template forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - - ElementRegionManager & elemManager = mesh.getElemManager(); - - elemManager.forElementSubRegions< CellElementSubRegion >( regionNames, - [&]( localIndex const, - CellElementSubRegion & subRegion ) - { - this->flowSolver()->updateFluidState( subRegion ); - if( this->m_isThermal ) - { - this->flowSolver()->updateSolidInternalEnergyModel( subRegion ); - } - } ); - } ); -} - template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::updateBulkDensity( ElementSubRegionBase & subRegion ) { @@ -351,17 +393,19 @@ void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::updateBulkDensit subRegion ); } -template class SinglePhasePoromechanics< SinglePhaseBase >; +template class SinglePhasePoromechanics<>; template class SinglePhasePoromechanics< SinglePhaseBase, SolidMechanicsLagrangeContact >; template class SinglePhasePoromechanics< SinglePhaseBase, SolidMechanicsEmbeddedFractures >; -template class SinglePhasePoromechanics< SinglePhaseReservoirAndWells< SinglePhaseBase > >; +template class SinglePhasePoromechanics< SinglePhaseReservoirAndWells<> >; +template class SinglePhasePoromechanics< SinglePhaseReservoirAndWells<>, SolidMechanicsLagrangeContact >; +//template class SinglePhasePoromechanics< SinglePhaseReservoirAndWells<>, SolidMechanicsEmbeddedFractures >; namespace { -typedef SinglePhasePoromechanics< SinglePhaseReservoirAndWells< SinglePhaseBase > > SinglePhaseReservoirPoromechanics; -REGISTER_CATALOG_ENTRY( SolverBase, SinglePhaseReservoirPoromechanics, string const &, Group * const ) -typedef SinglePhasePoromechanics< SinglePhaseBase > SinglePhasePoromechanics; -REGISTER_CATALOG_ENTRY( SolverBase, SinglePhasePoromechanics, string const &, Group * const ) +typedef SinglePhasePoromechanics< SinglePhaseReservoirAndWells<> > SinglePhaseReservoirPoromechanics; +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhaseReservoirPoromechanics, string const &, Group * const ) +typedef SinglePhasePoromechanics<> SinglePhasePoromechanics; +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhasePoromechanics, string const &, Group * const ) } } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp index 58077a81cfe..e742fb9715b 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,12 +21,13 @@ #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_SINGLEPHASEPOROMECHANICS_HPP_ #include "physicsSolvers/multiphysics/PoromechanicsSolver.hpp" - +#include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" +#include "physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.hpp" namespace geos { -template< typename FLOW_SOLVER, typename MECHANICS_SOLVER = SolidMechanicsLagrangianFEM > +template< typename FLOW_SOLVER = SinglePhaseBase, typename MECHANICS_SOLVER = SolidMechanicsLagrangianFEM > class SinglePhasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER, MECHANICS_SOLVER > { public: @@ -36,6 +38,9 @@ class SinglePhasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER, MECHAN using Base::m_localMatrix; using Base::m_rhs; using Base::m_solution; + using Base::m_stabilizationType; + using Base::m_stabilizationRegionNames; + using Base::m_stabilizationMultiplier; /** * @brief main constructor for SinglePhasePoromechanics objects @@ -52,9 +57,20 @@ class SinglePhasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER, MECHAN * @brief name of the node manager in the object catalog * @return string that contains the catalog name to generate a new SinglePhasePoromechanics object through the object catalog. */ - static string catalogName(); + static string catalogName() + { + if constexpr ( std::is_same_v< FLOW_SOLVER, SinglePhaseBase > ) // special case + { + return "SinglePhasePoromechanics"; + } + else // default + { + return FLOW_SOLVER::catalogName() + "Poromechanics"; + } + } + /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -65,7 +81,7 @@ class SinglePhasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER, MECHAN */ /**@{*/ - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void setupCoupling( DomainPartition const & domain, DofManager & dofManager ) const override; @@ -91,8 +107,6 @@ class SinglePhasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER, MECHAN CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ); - virtual void updateState( DomainPartition & domain ) override; - /**@}*/ struct viewKeyStruct : Base::viewKeyStruct @@ -104,19 +118,11 @@ class SinglePhasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER, MECHAN virtual void initializePostInitialConditionsPreSubGroups() override; - template< typename CONSTITUTIVE_BASE, - typename KERNEL_WRAPPER, - typename ... PARAMS > - real64 assemblyLaunch( MeshLevel & mesh, - DofManager const & dofManager, - arrayView1d< string const > const & regionNames, - string const & materialNamesString, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - real64 const dt, - PARAMS && ... params ); - -private: + virtual void setMGRStrategy() + { + if( this->m_linearSolverParameters.get().preconditionerType == LinearSolverParameters::PreconditionerType::mgr ) + GEOS_ERROR( GEOS_FMT( "{}: MGR strategy is not implemented for {}", this->getName(), this->getCatalogName())); + } /** * @brief Helper function to recompute the bulk density @@ -128,47 +134,6 @@ class SinglePhasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER, MECHAN }; -template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > -template< typename CONSTITUTIVE_BASE, - typename KERNEL_WRAPPER, - typename ... PARAMS > -real64 SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::assemblyLaunch( MeshLevel & mesh, - DofManager const & dofManager, - arrayView1d< string const > const & regionNames, - string const & materialNamesString, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - real64 const dt, - PARAMS && ... params ) -{ - GEOS_MARK_FUNCTION; - - NodeManager const & nodeManager = mesh.getNodeManager(); - - string const dofKey = dofManager.getKey( fields::solidMechanics::totalDisplacement::key() ); - arrayView1d< globalIndex const > const & dofNumber = nodeManager.getReference< globalIndex_array >( dofKey ); - - real64 const gravityVectorData[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3( SolverBase::gravityVector() ); - - KERNEL_WRAPPER kernelWrapper( dofNumber, - dofManager.rankOffset(), - localMatrix, - localRhs, - dt, - gravityVectorData, - std::forward< PARAMS >( params )... ); - - return finiteElement:: - regionBasedKernelApplication< parallelDevicePolicy< >, - CONSTITUTIVE_BASE, - CellElementSubRegion >( mesh, - regionNames, - this->solidMechanicsSolver()->getDiscretizationName(), - materialNamesString, - kernelWrapper ); -} - - } /* namespace geos */ #endif /* GEOS_PHYSICSSOLVERS_MULTIPHYSICS_SINGLEPHASEPOROMECHANICS_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsConformingFractures.cpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsConformingFractures.cpp index 86d04ed2cf1..51fef65a2de 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsConformingFractures.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsConformingFractures.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,8 +19,10 @@ #include "SinglePhasePoromechanicsConformingFractures.hpp" +#include "dataRepository/LogLevelsInfo.hpp" #include "constitutive/solid/PorousSolid.hpp" #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" +#include "constitutive/contact/HydraulicApertureRelationSelector.hpp" #include "linearAlgebra/solvers/BlockPreconditioner.hpp" #include "linearAlgebra/solvers/SeparateComponentPreconditioner.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" @@ -28,6 +31,7 @@ #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsFractures.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsFields.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp" +#include "finiteVolume/FluxApproximationBase.hpp" namespace geos { @@ -36,19 +40,31 @@ using namespace constitutive; using namespace dataRepository; using namespace fields; -SinglePhasePoromechanicsConformingFractures::SinglePhasePoromechanicsConformingFractures( const string & name, - Group * const parent ) +template< typename FLOW_SOLVER > +SinglePhasePoromechanicsConformingFractures< FLOW_SOLVER >::SinglePhasePoromechanicsConformingFractures( const string & name, + Group * const parent ) : Base( name, parent ) +{} + +template<> +void SinglePhasePoromechanicsConformingFractures<>::setMGRStrategy() { - LinearSolverParameters & params = m_linearSolverParameters.get(); - params.mgr.strategy = LinearSolverParameters::MGR::StrategyType::singlePhasePoromechanicsConformingFractures; - params.mgr.separateComponents = false; - params.mgr.displacementFieldName = solidMechanics::totalDisplacement::key(); - params.dofsPerNode = 3; + LinearSolverParameters & linearSolverParameters = this->m_linearSolverParameters.get(); + + if( linearSolverParameters.preconditionerType != LinearSolverParameters::PreconditionerType::mgr ) + return; + + linearSolverParameters.mgr.separateComponents = true; + linearSolverParameters.dofsPerNode = 3; + + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::singlePhasePoromechanicsConformingFractures; + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: MGR strategy set to {}", getName(), + EnumStrings< LinearSolverParameters::MGR::StrategyType >::toString( linearSolverParameters.mgr.strategy ))); } -void SinglePhasePoromechanicsConformingFractures::setupCoupling( DomainPartition const & domain, - DofManager & dofManager ) const +template< typename FLOW_SOLVER > +void SinglePhasePoromechanicsConformingFractures< FLOW_SOLVER >::setupCoupling( DomainPartition const & domain, + DofManager & dofManager ) const { /// We need to add 2 coupling terms: // 1. Poromechanical coupling in the bulk @@ -60,22 +76,13 @@ void SinglePhasePoromechanicsConformingFractures::setupCoupling( DomainPartition DofManager::Connector::Elem ); } -bool SinglePhasePoromechanicsConformingFractures::updateConfiguration( DomainPartition & domain ) -{ - return solidMechanicsSolver()->updateConfiguration( domain ); -} - -bool SinglePhasePoromechanicsConformingFractures::resetConfigurationToDefault( DomainPartition & domain ) const -{ - return solidMechanicsSolver()->resetConfigurationToDefault( domain ); -} - -void SinglePhasePoromechanicsConformingFractures::setupSystem( DomainPartition & domain, - DofManager & dofManager, - CRSMatrix< real64, globalIndex > & localMatrix, - ParallelVector & rhs, - ParallelVector & solution, - bool const setSparsity ) +template< typename FLOW_SOLVER > +void SinglePhasePoromechanicsConformingFractures< FLOW_SOLVER >::setupSystem( DomainPartition & domain, + DofManager & dofManager, + CRSMatrix< real64, globalIndex > & localMatrix, + ParallelVector & rhs, + ParallelVector & solution, + bool const setSparsity ) { GEOS_MARK_FUNCTION; @@ -83,14 +90,9 @@ void SinglePhasePoromechanicsConformingFractures::setupSystem( DomainPartition & /// 1. Add all coupling terms handled directly by the DofManager dofManager.setDomain( domain ); - setupDofs( domain, dofManager ); + this->setupDofs( domain, dofManager ); dofManager.reorderByRank(); - if( getLogLevel() > 2 ) - { - dofManager.printFieldInfo(); - } - /// 2. Add coupling terms not added by the DofManager. localIndex const numLocalRows = dofManager.numLocalDofs(); @@ -127,10 +129,10 @@ void SinglePhasePoromechanicsConformingFractures::setupSystem( DomainPartition & localMatrix.assimilate< parallelDevicePolicy<> >( std::move( pattern ) ); rhs.setName( this->getName() + "/rhs" ); - rhs.create( numLocalRows, MPI_COMM_GEOSX ); + rhs.create( numLocalRows, MPI_COMM_GEOS ); solution.setName( this->getName() + "/solution" ); - solution.create( numLocalRows, MPI_COMM_GEOSX ); + solution.create( numLocalRows, MPI_COMM_GEOS ); setUpDflux_dApertureMatrix( domain, dofManager, localMatrix ); @@ -140,19 +142,18 @@ void SinglePhasePoromechanicsConformingFractures::setupSystem( DomainPartition & // } } -void SinglePhasePoromechanicsConformingFractures::assembleSystem( real64 const time_n, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) +template< typename FLOW_SOLVER > +void SinglePhasePoromechanicsConformingFractures< FLOW_SOLVER >::assembleSystem( real64 const time_n, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; - solidMechanicsSolver()->synchronizeFractureState( domain ); - - synchronizeNonLinearParameters(); + this->solidMechanicsSolver()->synchronizeFractureState( domain ); assembleElementBasedContributions( time_n, dt, @@ -162,13 +163,13 @@ void SinglePhasePoromechanicsConformingFractures::assembleSystem( real64 const t localRhs ); // Assemble fluxes 3D/2D and get dFluidResidualDAperture - flowSolver()->assembleHydrofracFluxTerms( time_n, - dt, - domain, - dofManager, - localMatrix, - localRhs, - getDerivativeFluxResidual_dNormalJump() ); + this->flowSolver()->assembleHydrofracFluxTerms( time_n, + dt, + domain, + dofManager, + localMatrix, + localRhs, + getDerivativeFluxResidual_dNormalJump() ); // This step must occur after the fluxes are assembled because that's when DerivativeFluxResidual_dAperture is filled. assembleCouplingTerms( time_n, @@ -179,49 +180,48 @@ void SinglePhasePoromechanicsConformingFractures::assembleSystem( real64 const t localRhs ); } -void SinglePhasePoromechanicsConformingFractures::assembleElementBasedContributions( real64 const time_n, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) +template< typename FLOW_SOLVER > +void SinglePhasePoromechanicsConformingFractures< FLOW_SOLVER >::assembleElementBasedContributions( real64 const time_n, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) { GEOS_UNUSED_VAR( time_n, dt ); /// 3. assemble Force Residual w.r.t. pressure and Flow mass residual w.r.t. displacement Base::assembleElementBasedTerms( time_n, dt, domain, dofManager, localMatrix, localRhs ); - this->solidMechanicsSolver()->getMaxForce() = 0.0; - /// TODO: this is to be consistent with old version but it should be changed. We likely want to scale the residual for contact the same - /// way we scale the mechanics one. // Flow accumulation for fractures - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + this->forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { mesh.getElemManager().forElementSubRegions< FaceElementSubRegion >( regionNames, [&]( localIndex const, FaceElementSubRegion const & subRegion ) { - flowSolver()->accumulationAssemblyLaunch( dofManager, subRegion, localMatrix, localRhs ); + this->flowSolver()->accumulationAssemblyLaunch( dofManager, subRegion, localMatrix, localRhs ); } ); } ); - solidMechanicsSolver()->assembleContact( domain, dofManager, localMatrix, localRhs ); + this->solidMechanicsSolver()->assembleContact( domain, dofManager, localMatrix, localRhs ); } -void SinglePhasePoromechanicsConformingFractures::assembleCouplingTerms( real64 const time_n, - real64 const dt, - DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) +template< typename FLOW_SOLVER > +void SinglePhasePoromechanicsConformingFractures< FLOW_SOLVER >::assembleCouplingTerms( real64 const time_n, + real64 const dt, + DomainPartition const & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) { GEOS_UNUSED_VAR( time_n, dt ); // These 2 steps need to occur after the fluxes are assembled because that's when DerivativeFluxResidual_dAperture is filled. - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) + this->forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) { /// 3. assemble Force Residual w.r.t. pressure and Flow mass residual w.r.t. displacement assembleForceResidualDerivativeWrtPressure( mesh, regionNames, dofManager, localMatrix, localRhs ); @@ -229,14 +229,15 @@ void SinglePhasePoromechanicsConformingFractures::assembleCouplingTerms( real64 } ); } -void SinglePhasePoromechanicsConformingFractures:: - setUpDflux_dApertureMatrix( DomainPartition & domain, - DofManager const & GEOS_UNUSED_PARAM( dofManager ), - CRSMatrix< real64, globalIndex > & localMatrix ) +template< typename FLOW_SOLVER > +void SinglePhasePoromechanicsConformingFractures< FLOW_SOLVER >:: +setUpDflux_dApertureMatrix( DomainPartition & domain, + DofManager const & GEOS_UNUSED_PARAM( dofManager ), + CRSMatrix< real64, globalIndex > & localMatrix ) { - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) + this->forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) { std::unique_ptr< CRSMatrix< real64, localIndex > > & derivativeFluxResidual_dAperture = this->getRefDerivativeFluxResidual_dAperture(); @@ -267,7 +268,7 @@ void SinglePhasePoromechanicsConformingFractures:: NumericalMethodsManager const & numericalMethodManager = domain.getNumericalMethodManager(); FiniteVolumeManager const & fvManager = numericalMethodManager.getFiniteVolumeManager(); - FluxApproximationBase const & fluxApprox = fvManager.getFluxApproximation( flowSolver()->getDiscretizationName() ); + FluxApproximationBase const & fluxApprox = fvManager.getFluxApproximation( this->flowSolver()->getDiscretizationName() ); fluxApprox.forStencils< SurfaceElementStencil >( mesh, [&]( SurfaceElementStencil const & stencil ) { @@ -288,16 +289,17 @@ void SinglePhasePoromechanicsConformingFractures:: } ); } -void SinglePhasePoromechanicsConformingFractures:: - addTransmissibilityCouplingNNZ( DomainPartition const & domain, - DofManager const & dofManager, - arrayView1d< localIndex > const & rowLengths ) const +template< typename FLOW_SOLVER > +void SinglePhasePoromechanicsConformingFractures< FLOW_SOLVER >:: +addTransmissibilityCouplingNNZ( DomainPartition const & domain, + DofManager const & dofManager, + arrayView1d< localIndex > const & rowLengths ) const { GEOS_MARK_FUNCTION; - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, // meshBodyName, - MeshLevel const & mesh, - arrayView1d< string const > const & ) // regionNames + this->forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, // meshBodyName, + MeshLevel const & mesh, + arrayView1d< string const > const & ) // regionNames { ElementRegionManager const & elemManager = mesh.getElemManager(); @@ -307,7 +309,7 @@ void SinglePhasePoromechanicsConformingFractures:: NumericalMethodsManager const & numericalMethodManager = domain.getNumericalMethodManager(); FiniteVolumeManager const & fvManager = numericalMethodManager.getFiniteVolumeManager(); - FluxApproximationBase const & stabilizationMethod = fvManager.getFluxApproximation( solidMechanicsSolver()->getStabilizationName() ); + FluxApproximationBase const & stabilizationMethod = fvManager.getFluxApproximation( this->solidMechanicsSolver()->getStabilizationName() ); stabilizationMethod.forStencils< SurfaceElementStencil >( mesh, [&]( SurfaceElementStencil const & stencil ) { @@ -350,16 +352,17 @@ void SinglePhasePoromechanicsConformingFractures:: } ); } -void SinglePhasePoromechanicsConformingFractures:: - addTransmissibilityCouplingPattern( DomainPartition const & domain, - DofManager const & dofManager, - SparsityPatternView< globalIndex > const & pattern ) const +template< typename FLOW_SOLVER > +void SinglePhasePoromechanicsConformingFractures< FLOW_SOLVER >:: +addTransmissibilityCouplingPattern( DomainPartition const & domain, + DofManager const & dofManager, + SparsityPatternView< globalIndex > const & pattern ) const { GEOS_MARK_FUNCTION; - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & ) + this->forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & ) { FaceManager const & faceManager = mesh.getFaceManager(); NodeManager const & nodeManager = mesh.getNodeManager(); @@ -375,26 +378,24 @@ void SinglePhasePoromechanicsConformingFractures:: // Get the finite volume method used to compute the stabilization NumericalMethodsManager const & numericalMethodManager = domain.getNumericalMethodManager(); FiniteVolumeManager const & fvManager = numericalMethodManager.getFiniteVolumeManager(); - FluxApproximationBase const & stabilizationMethod = fvManager.getFluxApproximation( solidMechanicsSolver()->getStabilizationName() ); + FluxApproximationBase const & fvDiscretization = fvManager.getFluxApproximation( this->flowSolver()->getDiscretizationName() ); SurfaceElementRegion const & fractureRegion = - elemManager.getRegion< SurfaceElementRegion >( solidMechanicsSolver()->getUniqueFractureRegionName() ); + elemManager.getRegion< SurfaceElementRegion >( this->solidMechanicsSolver()->getUniqueFractureRegionName() ); FaceElementSubRegion const & fractureSubRegion = fractureRegion.getUniqueSubRegion< FaceElementSubRegion >(); GEOS_ERROR_IF( !fractureSubRegion.hasWrapper( flow::pressure::key() ), - getDataContext() << ": The fracture subregion must contain pressure field." ); + this->getDataContext() << ": The fracture subregion must contain pressure field." ); - ArrayOfArraysView< localIndex const > const elem2dToFaces = fractureSubRegion.faceList().toViewConst(); + arrayView2d< localIndex const > const elem2dToFaces = fractureSubRegion.faceList().toViewConst(); arrayView1d< globalIndex const > const & presDofNumber = fractureSubRegion.getReference< globalIndex_array >( presDofKey ); globalIndex const rankOffset = dofManager.rankOffset(); - ArrayOfArraysView< localIndex const > const & elemsToFaces = fractureSubRegion.faceList().toViewConst(); - - stabilizationMethod.forStencils< SurfaceElementStencil >( mesh, [&]( SurfaceElementStencil const & stencil ) + fvDiscretization.forStencils< SurfaceElementStencil >( mesh, [&]( SurfaceElementStencil const & stencil ) { forAll< serialPolicy >( stencil.size(), [=] ( localIndex const iconn ) { @@ -409,20 +410,20 @@ void SinglePhasePoromechanicsConformingFractures:: for( localIndex kf = 0; kf < 2; ++kf ) { // Set row DOF index - globalIndex const rowIndex = presDofNumber[sei[iconn][1-kf]] - rankOffset; + // Note that the 1-kf index is intentional, as this is coupling the pressure of one face cell + // to the nodes of the adjacent cell + localIndex const rowIndex = presDofNumber[sei[iconn][1-kf]] - rankOffset; - if( rowIndex > 0 && rowIndex < pattern.numRows() ) + if( rowIndex >= 0 && rowIndex < pattern.numRows() ) { // Get fracture, face and region/subregion/element indices (for elements on both sides) - localIndex fractureIndex = sei[iconn][kf]; + localIndex const fractureIndex = sei[iconn][kf]; // Get the number of nodes - localIndex const numNodesPerFace = faceToNodeMap.sizeOfArray( elemsToFaces[fractureIndex][0] ); + localIndex const numNodesPerFace = faceToNodeMap.sizeOfArray( elem2dToFaces[fractureIndex][0] ); // Loop over the two sides of each fracture element - GEOS_ERROR_IF( elem2dToFaces.sizeOfArray( fractureIndex ) != 2, - "Fracture face " << fractureIndex << " has to be shared by two cells." ); for( localIndex kf1 = 0; kf1 < 2; ++kf1 ) { localIndex const faceIndex = elem2dToFaces[fractureIndex][kf1]; @@ -445,21 +446,27 @@ void SinglePhasePoromechanicsConformingFractures:: } ); } -void SinglePhasePoromechanicsConformingFractures:: - assembleForceResidualDerivativeWrtPressure( MeshLevel const & mesh, - arrayView1d< string const > const & regionNames, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) +template< typename FLOW_SOLVER > +void SinglePhasePoromechanicsConformingFractures< FLOW_SOLVER >:: +assembleForceResidualDerivativeWrtPressure( MeshLevel const & mesh, + arrayView1d< string const > const & regionNames, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; FaceManager const & faceManager = mesh.getFaceManager(); NodeManager const & nodeManager = mesh.getNodeManager(); + EdgeManager const & edgeManager = mesh.getEdgeManager(); ElementRegionManager const & elemManager = mesh.getElemManager(); ArrayOfArraysView< localIndex const > const & faceToNodeMap = faceManager.nodeList().toViewConst(); + ArrayOfArraysView< localIndex const > const faceToEdgeMap = faceManager.edgeList().toViewConst(); + arrayView2d< localIndex const > const & edgeToNodeMap = edgeManager.nodeList().toViewConst(); + arrayView2d< real64 const > faceCenters = faceManager.faceCenter(); arrayView2d< real64 const > const & faceNormal = faceManager.faceNormal(); + arrayView1d< real64 const > faceAreas = faceManager.faceArea(); string const & dispDofKey = dofManager.getKey( solidMechanics::totalDisplacement::key() ); string const & presDofKey = dofManager.getKey( m_pressureKey ); @@ -478,7 +485,7 @@ void SinglePhasePoromechanicsConformingFractures:: arrayView1d< globalIndex const > const & presDofNumber = subRegion.getReference< globalIndex_array >( presDofKey ); arrayView1d< real64 const > const & pressure = subRegion.getReference< array1d< real64 > >( flow::pressure::key() ); - ArrayOfArraysView< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); + arrayView2d< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); forAll< serialPolicy >( subRegion.size(), [=]( localIndex const kfe ) { @@ -490,10 +497,9 @@ void SinglePhasePoromechanicsConformingFractures:: Nbar[ 1 ] = faceNormal[elemsToFaces[kfe][0]][1] - faceNormal[elemsToFaces[kfe][1]][1]; Nbar[ 2 ] = faceNormal[elemsToFaces[kfe][0]][2] - faceNormal[elemsToFaces[kfe][1]][2]; LvArray::tensorOps::normalize< 3 >( Nbar ); - - globalIndex rowDOF[12]; - real64 nodeRHS[12]; - stackArray1d< real64, 12 > dRdP( 3*numNodesPerFace ); + globalIndex rowDOF[3 * m_maxFaceNodes]; // this needs to be changed when dealing with arbitrary element types + real64 nodeRHS[3 * m_maxFaceNodes]; + stackArray1d< real64, 3 * m_maxFaceNodes > dRdP( 3*m_maxFaceNodes ); globalIndex colDOF[1]; colDOF[0] = presDofNumber[kfe]; @@ -501,14 +507,21 @@ void SinglePhasePoromechanicsConformingFractures:: { localIndex const faceIndex = elemsToFaces[kfe][kf]; + // Compute local area contribution for each node + stackArray1d< real64, FaceManager::maxFaceNodes() > nodalArea; + this->solidMechanicsSolver()->computeFaceNodalArea( elemsToFaces[kfe][kf], + nodePosition, + faceToNodeMap, + faceToEdgeMap, + edgeToNodeMap, + faceCenters, + faceNormal, + faceAreas, + nodalArea ); for( localIndex a=0; a nodalArea; - solidMechanicsSolver()->computeFaceNodalArea( nodePosition, faceToNodeMap, elemsToFaces[kfe][kf], nodalArea ); - real64 const nodalForceMag = -( pressure[kfe] ) * nodalArea[a]; - array1d< real64 > globalNodalForce( 3 ); + real64 globalNodalForce[ 3 ]; LvArray::tensorOps::scaledCopy< 3 >( globalNodalForce, Nbar, nodalForceMag ); for( localIndex i=0; i<3; ++i ) @@ -540,21 +553,27 @@ void SinglePhasePoromechanicsConformingFractures:: } ); } -void SinglePhasePoromechanicsConformingFractures:: - assembleFluidMassResidualDerivativeWrtDisplacement( MeshLevel const & mesh, - arrayView1d< string const > const & regionNames, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) +template< typename FLOW_SOLVER > +void SinglePhasePoromechanicsConformingFractures< FLOW_SOLVER >:: +assembleFluidMassResidualDerivativeWrtDisplacement( MeshLevel const & mesh, + arrayView1d< string const > const & regionNames, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) { GEOS_MARK_FUNCTION; FaceManager const & faceManager = mesh.getFaceManager(); NodeManager const & nodeManager = mesh.getNodeManager(); + EdgeManager const & edgeManager = mesh.getEdgeManager(); ElementRegionManager const & elemManager = mesh.getElemManager(); - arrayView2d< real64 const > const & faceNormal = faceManager.faceNormal(); ArrayOfArraysView< localIndex const > const & faceToNodeMap = faceManager.nodeList().toViewConst(); + ArrayOfArraysView< localIndex const > const faceToEdgeMap = faceManager.edgeList().toViewConst(); + arrayView2d< localIndex const > const & edgeToNodeMap = edgeManager.nodeList().toViewConst(); + arrayView2d< real64 const > faceCenters = faceManager.faceCenter(); + arrayView2d< real64 const > const & faceNormal = faceManager.faceNormal(); + arrayView1d< real64 const > faceAreas = faceManager.faceArea(); CRSMatrixView< real64 const, localIndex const > const & dFluxResidual_dNormalJump = getDerivativeFluxResidual_dNormalJump().toViewConst(); @@ -575,12 +594,12 @@ void SinglePhasePoromechanicsConformingFractures:: { string const & fluidName = subRegion.getReference< string >( FlowSolverBase::viewKeyStruct::fluidNamesString() ); - SingleFluidBase const & fluid = getConstitutiveModel< SingleFluidBase >( subRegion, fluidName ); + SingleFluidBase const & fluid = this->template getConstitutiveModel< SingleFluidBase >( subRegion, fluidName ); arrayView2d< real64 const > const & density = fluid.density(); arrayView1d< globalIndex const > const & presDofNumber = subRegion.getReference< array1d< globalIndex > >( presDofKey ); - ArrayOfArraysView< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); + arrayView2d< localIndex const > const & elemsToFaces = subRegion.faceList().toViewConst(); arrayView1d< real64 const > const & area = subRegion.getElementArea().toViewConst(); arrayView1d< integer const > const & fractureState = subRegion.getField< fields::contact::fractureState >(); @@ -589,7 +608,7 @@ void SinglePhasePoromechanicsConformingFractures:: { localIndex const kf0 = elemsToFaces[kfe][0], kf1 = elemsToFaces[kfe][1]; localIndex const numNodesPerFace = faceToNodeMap.sizeOfArray( kf0 ); - globalIndex nodeDOF[24]; + globalIndex nodeDOF[2*3*m_maxFaceNodes]; globalIndex elemDOF[1]; elemDOF[0] = presDofNumber[kfe]; @@ -599,7 +618,7 @@ void SinglePhasePoromechanicsConformingFractures:: Nbar[ 2 ] = faceNormal[kf0][2] - faceNormal[kf1][2]; LvArray::tensorOps::normalize< 3 >( Nbar ); - stackArray1d< real64, 2*3*4 > dRdU( 2*3*numNodesPerFace ); + stackArray1d< real64, 2*3*m_maxFaceNodes > dRdU( 2*3*m_maxFaceNodes ); bool const isFractureOpen = ( fractureState[kfe] == fields::contact::FractureState::Open ); @@ -609,8 +628,16 @@ void SinglePhasePoromechanicsConformingFractures:: for( localIndex kf=0; kf<2; ++kf ) { // Compute local area contribution for each node - array1d< real64 > nodalArea; - solidMechanicsSolver()->computeFaceNodalArea( nodePosition, faceToNodeMap, elemsToFaces[kfe][kf], nodalArea ); + stackArray1d< real64, FaceManager::maxFaceNodes() > nodalArea; + this->solidMechanicsSolver()->computeFaceNodalArea( elemsToFaces[kfe][kf], + nodePosition, + faceToNodeMap, + faceToEdgeMap, + edgeToNodeMap, + faceCenters, + faceNormal, + faceAreas, + nodalArea ); // TODO: move to something like this plus a static method. // localIndex const numNodesPerFace = faceToNodeMap.sizeOfArray( elemsToFaces[kfe][kf] ); @@ -631,7 +658,7 @@ void SinglePhasePoromechanicsConformingFractures:: localIndex const localRow = LvArray::integerConversion< localIndex >( elemDOF[0] - rankOffset ); - if( localRow > 0 && localRow < localMatrix.numRows() ) + if( localRow >= 0 && localRow < localMatrix.numRows() ) { localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( localRow, @@ -659,9 +686,17 @@ void SinglePhasePoromechanicsConformingFractures:: for( localIndex kf=0; kf<2; ++kf ) { - // Compute local area contribution for each node - array1d< real64 > nodalArea; - solidMechanicsSolver()->computeFaceNodalArea( nodePosition, faceToNodeMap, elemsToFaces[kfe2][kf], nodalArea ); + //TODO: We should avoid allocating LvArrays inside kernel + stackArray1d< real64, FaceManager::maxFaceNodes() > nodalArea; + this->solidMechanicsSolver()->computeFaceNodalArea( elemsToFaces[kfe2][kf], + nodePosition, + faceToNodeMap, + faceToEdgeMap, + edgeToNodeMap, + faceCenters, + faceNormal, + faceAreas, + nodalArea ); for( localIndex a=0; a( elemDOF[0] - rankOffset ); - if( localRow > 0 && localRow < localMatrix.numRows() ) + if( localRow >= 0 && localRow < localMatrix.numRows() ) { localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( localRow, nodeDOF, @@ -692,29 +727,31 @@ void SinglePhasePoromechanicsConformingFractures:: } ); } -void SinglePhasePoromechanicsConformingFractures::updateState( DomainPartition & domain ) +template< typename FLOW_SOLVER > +void SinglePhasePoromechanicsConformingFractures< FLOW_SOLVER >::updateState( DomainPartition & domain ) { GEOS_MARK_FUNCTION; // call base poromechanics update Base::updateState( domain ); // need to call solid mechanics update separately to compute face displacement jump - solidMechanicsSolver()->updateState( domain ); + this->solidMechanicsSolver()->updateState( domain ); // remove the contribution of the hydraulic aperture from the stencil weights - flowSolver()->prepareStencilWeights( domain ); + this->flowSolver()->prepareStencilWeights( domain ); updateHydraulicApertureAndFracturePermeability( domain ); // update the stencil weights using the updated hydraulic aperture - flowSolver()->updateStencilWeights( domain ); + this->flowSolver()->updateStencilWeights( domain ); } -void SinglePhasePoromechanicsConformingFractures::updateHydraulicApertureAndFracturePermeability( DomainPartition & domain ) +template< typename FLOW_SOLVER > +void SinglePhasePoromechanicsConformingFractures< FLOW_SOLVER >::updateHydraulicApertureAndFracturePermeability( DomainPartition & domain ) { - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + this->forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { ElementRegionManager & elemManager = mesh.getElemManager(); @@ -728,7 +765,6 @@ void SinglePhasePoromechanicsConformingFractures::updateHydraulicApertureAndFrac arrayView2d< real64 const > const fractureTraction = subRegion.getField< fields::contact::traction >(); arrayView1d< real64 const > const pressure = subRegion.getField< fields::flow::pressure >(); arrayView1d< real64 const > const oldHydraulicAperture = subRegion.getField< fields::flow::aperture0 >(); - arrayView1d< real64 const > const minimumHydraulicAperture = subRegion.getField< flow::minimumHydraulicAperture >(); arrayView1d< real64 > const aperture = subRegion.getElementAperture(); arrayView1d< real64 > const hydraulicAperture = subRegion.getField< flow::hydraulicAperture >(); @@ -737,36 +773,47 @@ void SinglePhasePoromechanicsConformingFractures::updateHydraulicApertureAndFrac string const porousSolidName = subRegion.getReference< string >( FlowSolverBase::viewKeyStruct::solidNamesString() ); CoupledSolidBase & porousSolid = subRegion.getConstitutiveModel< CoupledSolidBase >( porousSolidName ); - constitutive::ConstitutivePassThru< CompressibleSolidBase >::execute( porousSolid, [=, &subRegion] ( auto & castedPorousSolid ) - { + string const & hydraulicApertureRelationName = subRegion.template getReference< string >( viewKeyStruct::hydraulicApertureRelationNameString() ); + HydraulicApertureBase const & hydraulicApertureModel = this->template getConstitutiveModel< HydraulicApertureBase >( subRegion, hydraulicApertureRelationName ); - typename TYPEOFREF( castedPorousSolid ) ::KernelWrapper porousMaterialWrapper = castedPorousSolid.createKernelUpdates(); - - poromechanicsFracturesKernels::StateUpdateKernel:: - launch< parallelDevicePolicy<> >( subRegion.size(), - porousMaterialWrapper, - dispJump, - pressure, - area, - volume, - deltaVolume, - aperture, - minimumHydraulicAperture, - oldHydraulicAperture, - hydraulicAperture, - fractureTraction ); + constitutiveUpdatePassThru( hydraulicApertureModel, [&] ( auto & castedHydraulicAperture ) + { + using HydraulicApertureType = TYPEOFREF( castedHydraulicAperture ); + typename HydraulicApertureType::KernelWrapper hydraulicApertureWrapper = castedHydraulicAperture.createKernelWrapper(); + constitutive::ConstitutivePassThru< CompressibleSolidBase >::execute( porousSolid, [=, &subRegion] ( auto & castedPorousSolid ) + { + typename TYPEOFREF( castedPorousSolid ) ::KernelWrapper porousMaterialWrapper = castedPorousSolid.createKernelUpdates(); + + poromechanicsFracturesKernels::StateUpdateKernel:: + launch< parallelDevicePolicy<> >( subRegion.size(), + porousMaterialWrapper, + hydraulicApertureWrapper, + dispJump, + pressure, + area, + volume, + deltaVolume, + aperture, + oldHydraulicAperture, + hydraulicAperture, + fractureTraction ); + + } ); } ); } ); } ); } +template class SinglePhasePoromechanicsConformingFractures<>; +template class SinglePhasePoromechanicsConformingFractures< SinglePhaseReservoirAndWells<> >; -void SinglePhasePoromechanicsConformingFractures::outputConfigurationStatistics( DomainPartition const & domain ) const +namespace { - solidMechanicsSolver()->outputConfigurationStatistics( domain ); +typedef SinglePhasePoromechanicsConformingFractures< SinglePhaseReservoirAndWells<> > SinglePhaseReservoirPoromechanicsConformingFractures; +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhaseReservoirPoromechanicsConformingFractures, string const &, Group * const ) +typedef SinglePhasePoromechanicsConformingFractures<> SinglePhasePoromechanicsConformingFractures; +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhasePoromechanicsConformingFractures, string const &, Group * const ) } -REGISTER_CATALOG_ENTRY( SolverBase, SinglePhasePoromechanicsConformingFractures, string const &, Group * const ) - } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsConformingFractures.hpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsConformingFractures.hpp index 06ed8c35d55..0e657441f11 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsConformingFractures.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsConformingFractures.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -23,15 +24,17 @@ #include "physicsSolvers/multiphysics/CoupledSolver.hpp" #include "physicsSolvers/contact/SolidMechanicsLagrangeContact.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" +#include "dataRepository/Group.hpp" namespace geos { -class SinglePhasePoromechanicsConformingFractures : public SinglePhasePoromechanics< SinglePhaseBase, SolidMechanicsLagrangeContact > +template< typename FLOW_SOLVER = SinglePhaseBase > +class SinglePhasePoromechanicsConformingFractures : public SinglePhasePoromechanics< FLOW_SOLVER, SolidMechanicsLagrangeContact > { public: - using Base = SinglePhasePoromechanics< SinglePhaseBase, SolidMechanicsLagrangeContact >; + using Base = SinglePhasePoromechanics< FLOW_SOLVER, SolidMechanicsLagrangeContact >; using Base::m_solvers; using Base::m_dofManager; using Base::m_localMatrix; @@ -47,7 +50,7 @@ class SinglePhasePoromechanicsConformingFractures : public SinglePhasePoromechan * @param parent the parent group of this instantiation of SinglePhasePoromechanicsConformingFractures */ SinglePhasePoromechanicsConformingFractures( const string & name, - Group * const parent ); + dataRepository::Group * const parent ); /// Destructor for the class ~SinglePhasePoromechanicsConformingFractures() override {} @@ -57,9 +60,20 @@ class SinglePhasePoromechanicsConformingFractures : public SinglePhasePoromechan * @return string that contains the catalog name to generate a new SinglePhasePoromechanicsConformingFractures object through the object * catalog. */ - static string catalogName() { return "SinglePhasePoromechanicsConformingFractures"; } + static string catalogName() + { + if constexpr ( std::is_same_v< FLOW_SOLVER, SinglePhaseBase > ) + { + return "SinglePhasePoromechanicsConformingFractures"; + } + else + { + return FLOW_SOLVER::catalogName() + "PoromechanicsConformingFractures"; + } + } + /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -89,16 +103,21 @@ class SinglePhasePoromechanicsConformingFractures : public SinglePhasePoromechan virtual void updateState( DomainPartition & domain ) override final; - bool resetConfigurationToDefault( DomainPartition & domain ) const override final; - - bool updateConfiguration( DomainPartition & domain ) override final; - - void outputConfigurationStatistics( DomainPartition const & domain ) const override final; + virtual void setMGRStrategy() override + { + if( this->m_linearSolverParameters.get().preconditionerType == LinearSolverParameters::PreconditionerType::mgr ) + GEOS_ERROR( GEOS_FMT( "{}: MGR strategy is not implemented for {}", this->getName(), this->getCatalogName())); + } /**@}*/ private: + struct viewKeyStruct : public Base::viewKeyStruct + {}; + + static const localIndex m_maxFaceNodes=11; // Maximum number of nodes on a contact face + void assembleElementBasedContributions( real64 const time_n, real64 const dt, DomainPartition & domain, @@ -163,7 +182,6 @@ class SinglePhasePoromechanicsConformingFractures : public SinglePhasePoromechan */ void updateHydraulicApertureAndFracturePermeability( DomainPartition & domain ); - std::unique_ptr< CRSMatrix< real64, localIndex > > & getRefDerivativeFluxResidual_dAperture() { return m_derivativeFluxResidual_dAperture; diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsEmbeddedFractures.cpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsEmbeddedFractures.cpp index 5d890ad3003..6c6e2be5bc4 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsEmbeddedFractures.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsEmbeddedFractures.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,9 +18,9 @@ */ #include "SinglePhasePoromechanicsEmbeddedFractures.hpp" -#include "constitutive/contact/ContactSelector.hpp" +#include "constitutive/contact/HydraulicApertureRelationSelector.hpp" #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" -#include "physicsSolvers/contact/SolidMechanicsEFEMKernelsHelper.hpp" +#include "physicsSolvers/contact/kernels/SolidMechanicsEFEMKernelsHelper.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanics.hpp" @@ -27,6 +28,7 @@ #include "physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEFEM.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsFields.hpp" +#include "finiteVolume/FluxApproximationBase.hpp" namespace geos @@ -39,20 +41,39 @@ using namespace fields; SinglePhasePoromechanicsEmbeddedFractures::SinglePhasePoromechanicsEmbeddedFractures( const std::string & name, Group * const parent ): SinglePhasePoromechanics( name, parent ) -{ - LinearSolverParameters & params = m_linearSolverParameters.get(); - params.mgr.strategy = LinearSolverParameters::MGR::StrategyType::singlePhasePoromechanicsEmbeddedFractures; - params.mgr.separateComponents = false; - params.mgr.displacementFieldName = solidMechanics::totalDisplacement::key(); - params.dofsPerNode = 3; -} +{} SinglePhasePoromechanicsEmbeddedFractures::~SinglePhasePoromechanicsEmbeddedFractures() {} +void SinglePhasePoromechanicsEmbeddedFractures::setMGRStrategy() +{ + LinearSolverParameters & linearSolverParameters = m_linearSolverParameters.get(); + + if( linearSolverParameters.preconditionerType != LinearSolverParameters::PreconditionerType::mgr ) + return; + + linearSolverParameters.mgr.separateComponents = true; + linearSolverParameters.dofsPerNode = 3; + + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::singlePhasePoromechanicsEmbeddedFractures; + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: MGR strategy set to {}", getName(), + EnumStrings< LinearSolverParameters::MGR::StrategyType >::toString( linearSolverParameters.mgr.strategy ))); +} + +void SinglePhasePoromechanicsEmbeddedFractures::postInputInitialization() +{ + Base::postInputInitialization(); + + GEOS_ERROR_IF( solidMechanicsSolver()->useStaticCondensation(), + GEOS_FMT( "{}: {} = 1 in {} solver named {} is not supported for {}", + this->getName(), SolidMechanicsEmbeddedFractures::viewKeyStruct::useStaticCondensationString(), + solidMechanicsSolver()->getCatalogName(), solidMechanicsSolver()->getName(), getCatalogName() )); +} + void SinglePhasePoromechanicsEmbeddedFractures::registerDataOnMesh( dataRepository::Group & meshBodies ) { - SinglePhasePoromechanics::registerDataOnMesh( meshBodies ); + Base::registerDataOnMesh( meshBodies ); forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, MeshLevel & mesh, @@ -69,7 +90,7 @@ void SinglePhasePoromechanicsEmbeddedFractures::registerDataOnMesh( dataReposito void SinglePhasePoromechanicsEmbeddedFractures::initializePostInitialConditionsPreSubGroups() { - SinglePhasePoromechanics::initializePostInitialConditionsPreSubGroups(); + Base::initializePostInitialConditionsPreSubGroups(); updateState( this->getGroupByPath< DomainPartition >( "/Problem/domain" ) ); } @@ -158,10 +179,10 @@ void SinglePhasePoromechanicsEmbeddedFractures::setupSystem( DomainPartition & d localMatrix.assimilate< parallelDevicePolicy<> >( std::move( pattern ) ); rhs.setName( this->getName() + "/rhs" ); - rhs.create( dofManager.numLocalDofs(), MPI_COMM_GEOSX ); + rhs.create( dofManager.numLocalDofs(), MPI_COMM_GEOS ); solution.setName( this->getName() + "/solution" ); - solution.create( dofManager.numLocalDofs(), MPI_COMM_GEOSX ); + solution.create( dofManager.numLocalDofs(), MPI_COMM_GEOS ); } void SinglePhasePoromechanicsEmbeddedFractures::addCouplingNumNonzeros( DomainPartition & domain, @@ -406,7 +427,7 @@ void SinglePhasePoromechanicsEmbeddedFractures::assembleSystem( real64 const tim thermoPoromechanicsEFEMKernels::ThermalSinglePhasePoromechanicsEFEMKernelFactory >( mesh, dofManager, regionNames, - SinglePhasePoromechanics::viewKeyStruct::porousMaterialNamesString(), + Base::viewKeyStruct::porousMaterialNamesString(), localMatrix, localRhs, dt ); @@ -419,7 +440,7 @@ void SinglePhasePoromechanicsEmbeddedFractures::assembleSystem( real64 const tim poromechanicsEFEMKernels::SinglePhaseKernelFactory >( mesh, dofManager, regionNames, - SinglePhasePoromechanics::viewKeyStruct::porousMaterialNamesString(), + Base::viewKeyStruct::porousMaterialNamesString(), localMatrix, localRhs, dt ); @@ -438,84 +459,12 @@ void SinglePhasePoromechanicsEmbeddedFractures::assembleSystem( real64 const tim } -void SinglePhasePoromechanicsEmbeddedFractures::applyBoundaryConditions( real64 const time_n, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - solidMechanicsSolver()->applyBoundaryConditions( time_n, dt, - domain, - dofManager, - localMatrix, - localRhs ); - - flowSolver()->applyBoundaryConditions( time_n, dt, - domain, - dofManager, - localMatrix, - localRhs ); -} - -void SinglePhasePoromechanicsEmbeddedFractures::implicitStepSetup( real64 const & time_n, - real64 const & dt, - DomainPartition & domain ) -{ - flowSolver()->implicitStepSetup( time_n, dt, domain ); - solidMechanicsSolver()->implicitStepSetup( time_n, dt, domain ); -} - -void SinglePhasePoromechanicsEmbeddedFractures::implicitStepComplete( real64 const & time_n, - real64 const & dt, - DomainPartition & domain ) -{ - solidMechanicsSolver()->implicitStepComplete( time_n, dt, domain ); - flowSolver()->implicitStepComplete( time_n, dt, domain ); -} - -void SinglePhasePoromechanicsEmbeddedFractures::resetStateToBeginningOfStep( DomainPartition & domain ) -{ - flowSolver()->resetStateToBeginningOfStep( domain ); - solidMechanicsSolver()->resetStateToBeginningOfStep( domain ); -} - - -real64 SinglePhasePoromechanicsEmbeddedFractures::calculateResidualNorm( real64 const & time_n, - real64 const & dt, - DomainPartition const & domain, - DofManager const & dofManager, - arrayView1d< real64 const > const & localRhs ) -{ - // compute norm of momentum balance residual equations - real64 const momentumResidualNorm = solidMechanicsSolver()->calculateResidualNorm( time_n, dt, domain, dofManager, localRhs ); - - // compute norm of mass balance residual equations - real64 const massResidualNorm = flowSolver()->calculateResidualNorm( time_n, dt, domain, dofManager, localRhs ); - - real64 const residual = sqrt( momentumResidualNorm * momentumResidualNorm + massResidualNorm * massResidualNorm ); - - return residual; -} - -void SinglePhasePoromechanicsEmbeddedFractures::applySystemSolution( DofManager const & dofManager, - arrayView1d< real64 const > const & localSolution, - real64 const scalingFactor, - real64 const dt, - DomainPartition & domain ) -{ - // update displacement and jump - solidMechanicsSolver()->applySystemSolution( dofManager, localSolution, scalingFactor, dt, domain ); - // update pressure field - flowSolver()->applySystemSolution( dofManager, localSolution, scalingFactor, dt, domain ); -} - void SinglePhasePoromechanicsEmbeddedFractures::updateState( DomainPartition & domain ) { GEOS_MARK_FUNCTION; /// 1. update the reservoir - SinglePhasePoromechanics::updateState( domain ); + Base::updateState( domain ); // remove the contribution of the hydraulic aperture from the stencil weights flowSolver()->prepareStencilWeights( domain ); @@ -550,40 +499,42 @@ void SinglePhasePoromechanicsEmbeddedFractures::updateState( DomainPartition & d arrayView1d< real64 const > const area = subRegion.getElementArea().toViewConst(); - arrayView2d< real64 > const & fractureTraction = subRegion.template getField< fields::contact::traction >(); - - arrayView1d< real64 > const & dTdpf = subRegion.template getField< fields::contact::dTraction_dPressure >(); + arrayView2d< real64 > const & fractureContactTraction = subRegion.template getField< fields::contact::traction >(); arrayView1d< real64 const > const & pressure = subRegion.template getField< fields::flow::pressure >(); - string const & contactRelationName = subRegion.template getReference< string >( ContactSolverBase::viewKeyStruct::contactRelationNameString() ); - ContactBase const & contact = getConstitutiveModel< ContactBase >( subRegion, contactRelationName ); - - ContactBase::KernelWrapper contactWrapper = contact.createKernelWrapper(); + string const & hydraulicApertureRelationName = subRegion.template getReference< string >( viewKeyStruct::hydraulicApertureRelationNameString() ); + HydraulicApertureBase const & hydraulicApertureModel = this->template getConstitutiveModel< HydraulicApertureBase >( subRegion, hydraulicApertureRelationName ); string const porousSolidName = subRegion.template getReference< string >( FlowSolverBase::viewKeyStruct::solidNamesString() ); CoupledSolidBase & porousSolid = subRegion.template getConstitutiveModel< CoupledSolidBase >( porousSolidName ); - constitutive::ConstitutivePassThru< CompressibleSolidBase >::execute( porousSolid, [=, &subRegion] ( auto & castedPorousSolid ) + constitutive::ConstitutivePassThru< CompressibleSolidBase >::execute( porousSolid, [=, &subRegion, &hydraulicApertureModel] ( auto & castedPorousSolid ) { typename TYPEOFREF( castedPorousSolid ) ::KernelWrapper porousMaterialWrapper = castedPorousSolid.createKernelUpdates(); - poromechanicsEFEMKernels::StateUpdateKernel:: - launch< parallelDevicePolicy<> >( subRegion.size(), - contactWrapper, - porousMaterialWrapper, - dispJump, - pressure, - area, - volume, - deltaVolume, - aperture, - oldHydraulicAperture, - hydraulicAperture, - fractureTraction, - dTdpf ); + constitutiveUpdatePassThru( hydraulicApertureModel, [=, &subRegion] ( auto & castedHydraulicApertureModel ) + { + using HydraulicApertureModelType = TYPEOFREF( castedHydraulicApertureModel ); + typename HydraulicApertureModelType::KernelWrapper hydraulicApertureModelWrapper = castedHydraulicApertureModel.createKernelWrapper(); + + poromechanicsEFEMKernels::StateUpdateKernel:: + launch< parallelDevicePolicy<> >( subRegion.size(), + hydraulicApertureModelWrapper, + porousMaterialWrapper, + dispJump, + pressure, + area, + volume, + deltaVolume, + aperture, + oldHydraulicAperture, + hydraulicAperture, + fractureContactTraction ); + + } ); } ); // update the stencil weights using the updated hydraulic aperture @@ -601,6 +552,6 @@ void SinglePhasePoromechanicsEmbeddedFractures::updateState( DomainPartition & d } ); } -REGISTER_CATALOG_ENTRY( SolverBase, SinglePhasePoromechanicsEmbeddedFractures, std::string const &, Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhasePoromechanicsEmbeddedFractures, std::string const &, Group * const ) } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsEmbeddedFractures.hpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsEmbeddedFractures.hpp index e34b3289a7a..95c3e7b7f82 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsEmbeddedFractures.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsEmbeddedFractures.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -29,6 +30,9 @@ namespace geos class SinglePhasePoromechanicsEmbeddedFractures : public SinglePhasePoromechanics< SinglePhaseBase, SolidMechanicsEmbeddedFractures > { public: + + using Base = SinglePhasePoromechanics< SinglePhaseBase, SolidMechanicsEmbeddedFractures >; + SinglePhasePoromechanicsEmbeddedFractures( const std::string & name, Group * const parent ); ~SinglePhasePoromechanicsEmbeddedFractures() override; @@ -38,9 +42,9 @@ class SinglePhasePoromechanicsEmbeddedFractures : public SinglePhasePoromechanic * @return string that contains the catalog name to generate a new SinglePhasePoromechanicsEmbeddedFractures object through the object * catalog. */ - static string catalogName() { return "SinglePhasePoromechanicsEmbeddedFractures"; } + static string catalogName() { return Base::catalogName() + "EmbeddedFractures"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -57,11 +61,6 @@ class SinglePhasePoromechanicsEmbeddedFractures : public SinglePhasePoromechanic setupDofs( DomainPartition const & domain, DofManager & dofManager ) const override; - virtual void - implicitStepSetup( real64 const & time_n, - real64 const & dt, - DomainPartition & domain ) override final; - virtual void assembleSystem( real64 const time, real64 const dt, @@ -70,36 +69,6 @@ class SinglePhasePoromechanicsEmbeddedFractures : public SinglePhasePoromechanic CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; - virtual void - applyBoundaryConditions( real64 const time_n, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; - - virtual real64 - calculateResidualNorm( real64 const & time_n, - real64 const & dt, - DomainPartition const & domain, - DofManager const & dofManager, - arrayView1d< real64 const > const & localRhs ) override; - - virtual void - applySystemSolution( DofManager const & dofManager, - arrayView1d< real64 const > const & localSolution, - real64 const scalingFactor, - real64 const dt, - DomainPartition & domain ) override; - - virtual void - implicitStepComplete( real64 const & time_n, - real64 const & dt, - DomainPartition & domain ) override final; - - virtual void - resetStateToBeginningOfStep( DomainPartition & domain ) override; - /** * @Brief add extra nnz to each row induced by the coupling * @param domain the physical domain object @@ -132,8 +101,12 @@ class SinglePhasePoromechanicsEmbeddedFractures : public SinglePhasePoromechanic protected: + virtual void postInputInitialization() override final; + virtual void initializePostInitialConditionsPreSubGroups() override final; + virtual void setMGRStrategy() override; + private: template< typename CONSTITUTIVE_BASE, @@ -185,6 +158,7 @@ real64 SinglePhasePoromechanicsEmbeddedFractures::assemblyLaunch( MeshLevel & me dt, gravityVectorData, flowDofKey, + m_performStressInitialization, FlowSolverBase::viewKeyStruct::fluidNamesString() ); real64 const maxForce = diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp index 871982d3787..f83652d7455 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,11 +22,14 @@ #include "common/TimingMacros.hpp" #include "mesh/PerforationFields.hpp" +#include "physicsSolvers/KernelLaunchSelectors.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseFVM.hpp" +#include "physicsSolvers/fluidFlow/SinglePhaseHybridFVM.hpp" #include "physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp" -#include "physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" +#include "physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp" #include "physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp" +#include "physicsSolvers/multiphysics/SinglePhasePoromechanicsConformingFractures.hpp" namespace geos { @@ -33,60 +37,29 @@ namespace geos using namespace dataRepository; using namespace constitutive; -namespace -{ - -// This is meant to be specialized to work, see below -template< typename SINGLEPHASE_RESERVOIR_SOLVER > class - SinglePhaseCatalogNames {}; - -// Class specialization for a RESERVOIR_SOLVER set to SinglePhaseFlow -template<> class SinglePhaseCatalogNames< SinglePhaseBase > -{ -public: - // TODO: find a way to use the catalog name here - static string name() { return "SinglePhaseReservoir"; } -}; -// Class specialization for a RESERVOIR_SOLVER set to SinglePhasePoromechanics -template<> class SinglePhaseCatalogNames< SinglePhasePoromechanics< SinglePhaseBase > > -{ -public: - static string name() { return SinglePhasePoromechanics< SinglePhaseBase >::catalogName()+"Reservoir"; } -}; -} - -// provide a definition for catalogName() -template< typename SINGLEPHASE_RESERVOIR_SOLVER > -string -SinglePhaseReservoirAndWells< SINGLEPHASE_RESERVOIR_SOLVER >:: -catalogName() -{ - return SinglePhaseCatalogNames< SINGLEPHASE_RESERVOIR_SOLVER >::name(); -} - -template< typename SINGLEPHASE_RESERVOIR_SOLVER > -SinglePhaseReservoirAndWells< SINGLEPHASE_RESERVOIR_SOLVER >:: +template< typename RESERVOIR_SOLVER > +SinglePhaseReservoirAndWells< RESERVOIR_SOLVER >:: SinglePhaseReservoirAndWells( const string & name, Group * const parent ) : Base( name, parent ) {} -template< typename SINGLEPHASE_RESERVOIR_SOLVER > -SinglePhaseReservoirAndWells< SINGLEPHASE_RESERVOIR_SOLVER >:: +template< typename RESERVOIR_SOLVER > +SinglePhaseReservoirAndWells< RESERVOIR_SOLVER >:: ~SinglePhaseReservoirAndWells() {} template<> SinglePhaseBase * -SinglePhaseReservoirAndWells< SinglePhaseBase >:: +SinglePhaseReservoirAndWells<>:: flowSolver() const { return this->reservoirSolver(); } -template<> +template< typename POROMECHANICS_SOLVER > SinglePhaseBase * -SinglePhaseReservoirAndWells< SinglePhasePoromechanics< SinglePhaseBase > >:: +SinglePhaseReservoirAndWells< POROMECHANICS_SOLVER >:: flowSolver() const { return this->reservoirSolver()->flowSolver(); @@ -94,37 +67,58 @@ flowSolver() const template<> void -SinglePhaseReservoirAndWells< SinglePhaseBase >:: +SinglePhaseReservoirAndWells<>:: setMGRStrategy() { - if( flowSolver()->getLinearSolverParameters().mgr.strategy == LinearSolverParameters::MGR::StrategyType::singlePhaseReservoirHybridFVM ) + LinearSolverParameters & linearSolverParameters = m_linearSolverParameters.get(); + + if( linearSolverParameters.preconditionerType != LinearSolverParameters::PreconditionerType::mgr ) + return; + + linearSolverParameters.mgr.separateComponents = true; + linearSolverParameters.dofsPerNode = 3; + + if( dynamic_cast< SinglePhaseHybridFVM * >( this->flowSolver() ) ) { - m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::singlePhaseReservoirHybridFVM; + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::singlePhaseReservoirHybridFVM; } else { - m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::singlePhaseReservoirFVM; + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::singlePhaseReservoirFVM; } + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: MGR strategy set to {}", getName(), + EnumStrings< LinearSolverParameters::MGR::StrategyType >::toString( linearSolverParameters.mgr.strategy ))); } template<> void -SinglePhaseReservoirAndWells< SinglePhasePoromechanics< SinglePhaseBase > >:: +SinglePhaseReservoirAndWells< SinglePhasePoromechanics<> >:: setMGRStrategy() { - if( flowSolver()->getLinearSolverParameters().mgr.strategy == LinearSolverParameters::MGR::StrategyType::singlePhaseReservoirHybridFVM ) + LinearSolverParameters & linearSolverParameters = m_linearSolverParameters.get(); + + if( linearSolverParameters.preconditionerType != LinearSolverParameters::PreconditionerType::mgr ) + return; + + linearSolverParameters.mgr.separateComponents = true; + linearSolverParameters.dofsPerNode = 3; + + if( dynamic_cast< SinglePhaseHybridFVM * >( this->flowSolver() ) ) { - GEOS_LOG_RANK_0( "The MGR strategy for hybrid FVM is not implemented" ); + GEOS_ERROR( GEOS_FMT( "{}: MGR strategy is not implemented for poromechanics {}/{}", + this->getName(), this->getCatalogName(), this->flowSolver()->getCatalogName())); } else { - m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::singlePhasePoromechanicsReservoirFVM; + linearSolverParameters.mgr.strategy = LinearSolverParameters::MGR::StrategyType::singlePhasePoromechanicsReservoirFVM; } + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{}: MGR strategy set to {}", this->getName(), + EnumStrings< LinearSolverParameters::MGR::StrategyType >::toString( linearSolverParameters.mgr.strategy ))); } -template< typename SINGLEPHASE_RESERVOIR_SOLVER > +template< typename RESERVOIR_SOLVER > void -SinglePhaseReservoirAndWells< SINGLEPHASE_RESERVOIR_SOLVER >:: +SinglePhaseReservoirAndWells< RESERVOIR_SOLVER >:: initializePreSubGroups() { Base::initializePreSubGroups(); @@ -132,18 +126,9 @@ initializePreSubGroups() Base::wellSolver()->setFlowSolverName( flowSolver->getName() ); } -template< typename SINGLEPHASE_RESERVOIR_SOLVER > +template< typename RESERVOIR_SOLVER > void -SinglePhaseReservoirAndWells< SINGLEPHASE_RESERVOIR_SOLVER >:: -initializePostInitialConditionsPreSubGroups() -{ - Base::initializePostInitialConditionsPreSubGroups(); - setMGRStrategy(); -} - -template< typename SINGLEPHASE_RESERVOIR_SOLVER > -void -SinglePhaseReservoirAndWells< SINGLEPHASE_RESERVOIR_SOLVER >:: +SinglePhaseReservoirAndWells< RESERVOIR_SOLVER >:: addCouplingSparsityPattern( DomainPartition const & domain, DofManager const & dofManager, SparsityPatternView< globalIndex > const & pattern ) const @@ -156,87 +141,89 @@ addCouplingSparsityPattern( DomainPartition const & domain, { ElementRegionManager const & elemManager = mesh.getElemManager(); - // TODO: remove this and just call SolverBase::setupSystem when DofManager can handle the coupling + // TODO: remove this and just call PhysicsSolverBase::setupSystem when DofManager can handle the coupling // Populate off-diagonal sparsity between well and reservoir string const resDofKey = dofManager.getKey( Base::wellSolver()->resElementDofName() ); string const wellDofKey = dofManager.getKey( Base::wellSolver()->wellElementDofName() ); - + integer isThermal = Base::wellSolver()->isThermal(); integer const wellNDOF = Base::wellSolver()->numDofPerWellElement(); ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > const & resDofNumber = elemManager.constructArrayViewAccessor< globalIndex, 1 >( resDofKey ); globalIndex const rankOffset = dofManager.rankOffset(); - - elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, - WellElementSubRegion const & subRegion ) - { - PerforationData const * const perforationData = subRegion.getPerforationData(); - - // get the well degrees of freedom and ghosting info - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - - // get the well element indices corresponding to each perforation - arrayView1d< localIndex const > const & perfWellElemIndex = - perforationData->getField< fields::perforation::wellElementIndex >(); - - // get the element region, subregion, index - arrayView1d< localIndex const > const & resElementRegion = - perforationData->getField< fields::perforation::reservoirElementRegion >(); - arrayView1d< localIndex const > const & resElementSubRegion = - perforationData->getField< fields::perforation::reservoirElementSubRegion >(); - arrayView1d< localIndex const > const & resElementIndex = - perforationData->getField< fields::perforation::reservoirElementIndex >(); - - // Insert the entries corresponding to reservoir-well perforations - // This will fill J_WR, and J_RW - forAll< serialPolicy >( perforationData->size(), [=] ( localIndex const iperf ) + geos::internal::kernelLaunchSelectorThermalSwitch( isThermal, [&] ( auto ISTHERMAL ) { + integer constexpr IS_THERMAL = ISTHERMAL(); + elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, + WellElementSubRegion const & subRegion ) { - // Get the reservoir (sub)region and element indices - localIndex const er = resElementRegion[iperf]; - localIndex const esr = resElementSubRegion[iperf]; - localIndex const ei = resElementIndex[iperf]; - localIndex const iwelem = perfWellElemIndex[iperf]; + PerforationData const * const perforationData = subRegion.getPerforationData(); + + // get the well degrees of freedom and ghosting info + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + + // get the well element indices corresponding to each perforation + arrayView1d< localIndex const > const & perfWellElemIndex = + perforationData->getField< fields::perforation::wellElementIndex >(); + + // get the element region, subregion, index + arrayView1d< localIndex const > const & resElementRegion = + perforationData->getField< fields::perforation::reservoirElementRegion >(); + arrayView1d< localIndex const > const & resElementSubRegion = + perforationData->getField< fields::perforation::reservoirElementSubRegion >(); + arrayView1d< localIndex const > const & resElementIndex = + perforationData->getField< fields::perforation::reservoirElementIndex >(); + + // Insert the entries corresponding to reservoir-well perforations + // This will fill J_WR, and J_RW + forAll< serialPolicy >( perforationData->size(), [=] ( localIndex const iperf ) + { + // Get the reservoir (sub)region and element indices + localIndex const er = resElementRegion[iperf]; + localIndex const esr = resElementSubRegion[iperf]; + localIndex const ei = resElementIndex[iperf]; + localIndex const iwelem = perfWellElemIndex[iperf]; - globalIndex const eqnRowIndexRes = resDofNumber[er][esr][ei] - rankOffset; - globalIndex const dofColIndexRes = resDofNumber[er][esr][ei]; + globalIndex const eqnRowIndexRes = resDofNumber[er][esr][ei] - rankOffset; + globalIndex const dofColIndexRes = resDofNumber[er][esr][ei]; - // working arrays - stackArray1d< globalIndex, 2 > eqnRowIndicesWell( wellNDOF ); - stackArray1d< globalIndex, 2 > dofColIndicesWell( wellNDOF ); + // working arrays - tjb previously dim was 2 + stackArray1d< globalIndex, 2+IS_THERMAL > eqnRowIndicesWell( wellNDOF ); + stackArray1d< globalIndex, 2+IS_THERMAL > dofColIndicesWell( wellNDOF ); - for( integer idof = 0; idof < wellNDOF; ++idof ) - { - eqnRowIndicesWell[idof] = wellElemDofNumber[iwelem] + idof - rankOffset; - dofColIndicesWell[idof] = wellElemDofNumber[iwelem] + idof; - } + for( integer idof = 0; idof < wellNDOF; ++idof ) + { + eqnRowIndicesWell[idof] = wellElemDofNumber[iwelem] + idof - rankOffset; + dofColIndicesWell[idof] = wellElemDofNumber[iwelem] + idof; + } - if( eqnRowIndexRes >= 0 && eqnRowIndexRes < pattern.numRows() ) - { - for( localIndex j = 0; j < dofColIndicesWell.size(); ++j ) + if( eqnRowIndexRes >= 0 && eqnRowIndexRes < pattern.numRows() ) { - pattern.insertNonZero( eqnRowIndexRes, dofColIndicesWell[j] ); + for( localIndex j = 0; j < dofColIndicesWell.size(); ++j ) + { + pattern.insertNonZero( eqnRowIndexRes, dofColIndicesWell[j] ); + } } - } - for( localIndex i = 0; i < eqnRowIndicesWell.size(); ++i ) - { - if( eqnRowIndicesWell[i] >= 0 && eqnRowIndicesWell[i] < pattern.numRows() ) + for( localIndex i = 0; i < eqnRowIndicesWell.size(); ++i ) { - pattern.insertNonZero( eqnRowIndicesWell[i], dofColIndexRes ); + if( eqnRowIndicesWell[i] >= 0 && eqnRowIndicesWell[i] < pattern.numRows() ) + { + pattern.insertNonZero( eqnRowIndicesWell[i], dofColIndexRes ); + } } - } + } ); } ); } ); } ); } -template< typename SINGLEPHASE_RESERVOIR_SOLVER > +template< typename RESERVOIR_SOLVER > void -SinglePhaseReservoirAndWells< SINGLEPHASE_RESERVOIR_SOLVER >:: +SinglePhaseReservoirAndWells< RESERVOIR_SOLVER >:: assembleCouplingTerms( real64 const time_n, real64 const dt, DomainPartition const & domain, @@ -367,15 +354,18 @@ assembleCouplingTerms( real64 const time_n, } -template class SinglePhaseReservoirAndWells< SinglePhaseBase >; -template class SinglePhaseReservoirAndWells< SinglePhasePoromechanics< SinglePhaseBase > >; +template class SinglePhaseReservoirAndWells<>; +template class SinglePhaseReservoirAndWells< SinglePhasePoromechanics<> >; +template class SinglePhaseReservoirAndWells< SinglePhasePoromechanicsConformingFractures<> >; namespace { -typedef SinglePhaseReservoirAndWells< SinglePhaseBase > SinglePhaseFlowAndWells; -typedef SinglePhaseReservoirAndWells< SinglePhasePoromechanics< SinglePhaseBase > > SinglePhasePoromechanicsAndWells; -REGISTER_CATALOG_ENTRY( SolverBase, SinglePhaseFlowAndWells, string const &, Group * const ) -REGISTER_CATALOG_ENTRY( SolverBase, SinglePhasePoromechanicsAndWells, string const &, Group * const ) +typedef SinglePhaseReservoirAndWells<> SinglePhaseFlowAndWells; +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhaseFlowAndWells, string const &, Group * const ) +typedef SinglePhaseReservoirAndWells< SinglePhasePoromechanics<> > SinglePhasePoromechanicsAndWells; +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhasePoromechanicsAndWells, string const &, Group * const ) +typedef SinglePhaseReservoirAndWells< SinglePhasePoromechanicsConformingFractures<> > SinglePhasePoromechanicsConformingFracturesAndWells; +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhasePoromechanicsConformingFracturesAndWells, string const &, Group * const ) } } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.hpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.hpp index ef7315a6c95..6ce8df9632c 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,18 +22,20 @@ #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_SINGLEPHASERESERVOIRANDWELLS_HPP_ #include "physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.hpp" +#include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" #include "physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp" namespace geos { -template< typename SINGLEPHASE_RESERVOIR_SOLVER > -class SinglePhaseReservoirAndWells : public CoupledReservoirAndWellsBase< SINGLEPHASE_RESERVOIR_SOLVER, +/// @tparam RESERVOIR_SOLVER single-phase flow or single-phase poromechanics solver +template< typename RESERVOIR_SOLVER = SinglePhaseBase > +class SinglePhaseReservoirAndWells : public CoupledReservoirAndWellsBase< RESERVOIR_SOLVER, SinglePhaseWell > { public: - using Base = CoupledReservoirAndWellsBase< SINGLEPHASE_RESERVOIR_SOLVER, + using Base = CoupledReservoirAndWellsBase< RESERVOIR_SOLVER, SinglePhaseWell >; using Base::m_solvers; using Base::m_linearSolverParameters; @@ -54,9 +57,20 @@ class SinglePhaseReservoirAndWells : public CoupledReservoirAndWellsBase< SINGLE * @brief name of the node manager in the object catalog * @return string that contains the catalog name to generate a new NodeManager object through the object catalog. */ - static string catalogName(); + static string catalogName() + { + if constexpr (std::is_same_v< RESERVOIR_SOLVER, SinglePhaseBase > ) // special case + { + return "SinglePhaseReservoir"; + } + else // default + { + return RESERVOIR_SOLVER::catalogName() + "Reservoir"; + } + } + /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -72,41 +86,41 @@ class SinglePhaseReservoirAndWells : public CoupledReservoirAndWellsBase< SINGLE arrayView1d< real64 > const & localRhs ) override; void - assembleFluxTerms( real64 const dt, - DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) const - { flowSolver()->assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); } - - void keepFlowVariablesConstantDuringInitStep( bool const keepFlowVariablesConstantDuringInitStep ) - { flowSolver()->keepFlowVariablesConstantDuringInitStep( keepFlowVariablesConstantDuringInitStep ); } - - void updateFluidState( ObjectManagerBase & subRegion ) const - { flowSolver()->updateFluidState( subRegion ); } - void updatePorosityAndPermeability( CellElementSubRegion & subRegion ) const - { flowSolver()->updatePorosityAndPermeability( subRegion ); } - void updateSolidInternalEnergyModel( ObjectManagerBase & dataGroup ) const - { flowSolver()->updateSolidInternalEnergyModel( dataGroup ); } - - integer & isThermal() { return flowSolver()->isThermal(); } - - void enableFixedStressPoromechanicsUpdate() { flowSolver()->enableFixedStressPoromechanicsUpdate(); } - - virtual void saveSequentialIterationState( DomainPartition & domain ) const override { flowSolver()->saveSequentialIterationState( domain ); } + assembleHydrofracFluxTerms( real64 const time_n, + real64 const dt, + DomainPartition const & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + CRSMatrixView< real64, localIndex const > const & dR_dAper ) + { flowSolver()->assembleHydrofracFluxTerms( time_n, dt, domain, dofManager, localMatrix, localRhs, dR_dAper ); } + + template< typename SUBREGION_TYPE > + void accumulationAssemblyLaunch( DofManager const & dofManager, + SUBREGION_TYPE const & subRegion, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { flowSolver()->accumulationAssemblyLaunch( dofManager, subRegion, localMatrix, localRhs ); } + + void prepareStencilWeights( DomainPartition & domain ) const + { flowSolver()->prepareStencilWeights( domain ); } + void updateStencilWeights( DomainPartition & domain ) const + { flowSolver()->updateStencilWeights( domain ); } protected: virtual void initializePreSubGroups() override; - virtual void initializePostInitialConditionsPreSubGroups() override; + virtual void setMGRStrategy() override + { + if( this->m_linearSolverParameters.get().preconditionerType == LinearSolverParameters::PreconditionerType::mgr ) + GEOS_ERROR( GEOS_FMT( "{}: MGR strategy is not implemented for {}", this->getName(), this->getCatalogName())); + } private: SinglePhaseBase * flowSolver() const; - void setMGRStrategy(); - }; } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/multiphysics/docs/Initialization.rst b/src/coreComponents/physicsSolvers/multiphysics/docs/Initialization.rst new file mode 100644 index 00000000000..a80e5152f58 --- /dev/null +++ b/src/coreComponents/physicsSolvers/multiphysics/docs/Initialization.rst @@ -0,0 +1,14 @@ +.. _PoromechanicalInitialization: + +Poromechanical Models Intialization +=========================================== + +This section demonstrates the intializaton of poromechanical models in GEOS. + + +.. toctree:: + :maxdepth: 1 + + gravityInducedStressInitialization/Example + + userTableStressInitialization/Example diff --git a/src/coreComponents/physicsSolvers/multiphysics/docs/Poromechanics.rst b/src/coreComponents/physicsSolvers/multiphysics/docs/Poromechanics.rst index f745e30e86b..28579e26852 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/docs/Poromechanics.rst +++ b/src/coreComponents/physicsSolvers/multiphysics/docs/Poromechanics.rst @@ -48,7 +48,7 @@ In the main solver, it requires the specification of solidSolverName, flowSolver The following attributes are supported: -.. include:: /coreComponents/schema/docs/SinglePhasePoromechanics.rst +.. include:: /docs/sphinx/datastructure/SinglePhasePoromechanics.rst * ``couplingTypeOption``: defines the coupling scheme. diff --git a/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/Example.rst b/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/Example.rst new file mode 100644 index 00000000000..14eb7d136f3 --- /dev/null +++ b/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/Example.rst @@ -0,0 +1,232 @@ +.. _gravityinducedhydrostaticinitialization: + + +################################################################################# + Model Initialization: Hydrostatic and Mechanical Equilibrium +################################################################################# + + +**Context** + +Prior to simulating underground operations, it is necessary to run a few steps of a fully coupled geomechanical simulation to reach the equilibrium state. In this example, we perform a gravity-only stress initialization for a reservoir with a hydrostatic in-situ pressure. The problem is solved using a single-phase poromechanics solver (see :ref:`PoroelasticSolver`) and the HydrostaticEquilibrium initialization procedure (see :ref:`EquilibriumInitialCondition`) in GEOS to predict the initial state of stress with depth in the reservoir, subject to the reservoir rock properties and the prevailing hydrostatic pressure condition. This way, the poromechanical model is initialized at mechanical equilibrium and all displacements are set to zero after initialization. We verify numerical results obtained by GEOS against an analytical equation (Eaton's equation). + + +**Input file** + +The xml input files for the test case are located at: + +.. code-block:: console + + inputFiles/initialization/gravityInducedStress_initialization_base.xml + inputFiles/initialization/gravityInducedStress_initialization_benchmark.xml + + +A Python script for post-processing the simulation results is provided: + +.. code-block:: console + + src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/gravityInitializationFigure.py + + +------------------------------------------------------------------ +Description of the Case +------------------------------------------------------------------ + +We model the in-situ state of stress of a subsurface reservoir subject to a gravity-only induced stress and hydrostatic in-situ pressure condition. The domain is homogenous, isotropic and isothermal. The domain is subject to roller boundary conditions on lateral surfaces and at the base of the model, while the top of the model is a free surface. + +.. _problemSketch1InitializationTest: +.. figure:: sketch_of_problem.png + :align: center + :width: 300 + :figclass: align-center + + Sketch of the problem + + +We set up and solve a PoroMechanics model to obtain the gradient of total stresses (principal stress components) across the domain due to gravity effects and hydrostatic pressure only. These numerical predictions are compared with the analytical solutions derived from `Eaton et al. (1969, 1975) `__ + + + +For this example, we focus on the ``Mesh``, +the ``Constitutive``, and the ``FieldSpecifications`` tags. + + +------------------------------------------------------------------ +Mesh +------------------------------------------------------------------ + +The following figure shows the mesh used for solving this poromechanical problem: + +.. _problemSketch2InitializationTest: +.. figure:: mesh.png + :align: center + :width: 500 + :figclass: align-center + + Generated mesh + + +The mesh was created with the internal mesh generator and parametrized in the ``InternalMesh`` XML tag. +It contains 20x20x40 eight-node brick elements in the x, y, and z directions respectively. +Such eight-node hexahedral elements are defined as ``C3D8`` elementTypes, and their collection forms a mesh +with one group of cell blocks named here ``cellBlockNames``. + + +.. literalinclude:: ../../../../../../inputFiles/initialization/gravityInducedStress_initialization_benchmark.xml + :language: xml + :start-after: + :end-before: + + +------------------------ +Poro-Mechanics Solver +------------------------ + +For the initialization test, a hydrostatic pore pressure is imposed on the system. This is done using the Hydrostatic Equilibrium tag under Field Specifications. We then define a poro-mechanics solver called here poroSolve. +This solid mechanics solver (see :ref:`SolidMechanicsLagrangianFEM`) called ``lagSolve`` is based on the Lagrangian finite element formulation. +The problem is run as ``QuasiStatic`` without considering inertial effects. +The computational domain is discretized by ``FE1``, defined in the ``NumericalMethods`` section. +We use the ``targetRegions`` attribute to define the regions where the poromechanics solver is applied. +Since we only have one cellBlockName type called ``Domain``, the poromechanics solver is applied to every element of the model. +The flow solver for this problem (see :ref:`SinglePhaseFlow`) called ``SinglePhaseFlow`` is discretized by ``fluidTPFA``, defined in the ``NumericalMethods`` section. + +.. literalinclude:: ../../../../../../inputFiles/initialization/gravityInducedStress_initialization_base.xml + :language: xml + :start-after: + :end-before: + +.. literalinclude:: ../../../../../../inputFiles/initialization/gravityInducedStress_initialization_base.xml + :language: xml + :start-after: + :end-before: + + +------------------------------ +Constitutive Laws +------------------------------ + +A homogeneous domain with one solid material is assumed, and its mechanical and fluid properties are specified in the ``Constitutive`` section: + +.. literalinclude:: ../../../../../../inputFiles/initialization/gravityInducedStress_initialization_base.xml + :language: xml + :start-after: + :end-before: + + +As shown above, in the ``CellElementRegion`` section, +``rock`` is the solid material in the computational domain and ``water`` is the fluid material. +Here, Porous Elastic Isotropic model ``PorousElasticIsotropic`` is used to simulate the elastic behavior of ``rock``. +As for the solid material parameters, ``defaultDensity``, ``defaultPoissonRatio``, ``defaultYoungModulus``, ``grainBulkModulus``, ``defaultReferencePorosity``, and ``permeabilityComponents`` denote the rock density, Poisson ratio, Young modulus, grain bulk modulus, porosity, and permeability components respectively. In additon, the fluid property (``water``) of density, viscosity, compressibility and viscosibility are specified with ``defaultDensity``, ``defaultViscosity``, ``compressibility``, and ``viscosibility``. +All properties are specified in the International System of Units. + + +------------------------------ +Stress Initialization Function +------------------------------ + +In the ``Tasks`` section, ``SinglePhasePoromechanicsInitialization`` tasks are defined to initialize the model by calling the poro-mechanics solver ``poroSolve``. This task is used to determine stress gradients through designated densities and established constitutive relationships to maintain mechanical equilibrium and reset all initial displacements to zero following the initialization process. + +.. literalinclude:: ../../../../../../inputFiles/initialization/gravityInducedStress_initialization_base.xml + :language: xml + :start-after: + :end-before: + +The initialization is triggered into action using the ``Event`` management section, where the ``soloEvent`` function calls the task at the target time (in this case -1e10s). + +.. literalinclude:: ../../../../../../inputFiles/initialization/gravityInducedStress_initialization_benchmark.xml + :language: xml + :start-after: + :end-before: + +The ``PeriodicEvent`` function is used here to define recurring tasks that progress for a stipulated time during the simuation. We also use it in this example to save the vtkOuput results. + +.. literalinclude:: ../../../../../../inputFiles/initialization/gravityInducedStress_initialization_base.xml + :language: xml + :start-after: + :end-before: + +We use Paraview to extract the data from the vtkOutput files at the initialization time, and then use a Python script to read and plot the stress and pressure gradients for verification and visualization. + + + +----------------------------------- +Initial and Boundary Conditions +----------------------------------- + +The next step is to specify fields, including: + + - The initial value (hydrostatic equilibrium), + - The boundary conditions (the displacement control of the outer boundaries have to be set). + +In this problem, all outer boundaries of the domain are subject to roller constraints except the top of the model, left as a free surface. + +These boundary conditions are set up through the ``FieldSpecifications`` section. + +.. literalinclude:: ../../../../../../inputFiles/initialization/gravityInducedStress_initialization_base.xml + :language: xml + :start-after: + :end-before: + + +The parameters used in the simulation are summarized in the following table. + ++------------------+-------------------------+------------------+--------------------+ +| Symbol | Parameter | Unit | Value | ++==================+=========================+==================+====================+ +| :math:`E` | Young Modulus | [MPa] | 100 | ++------------------+-------------------------+------------------+--------------------+ +| :math:`v` | Poisson Ratio | [-] | 0.25 | ++------------------+-------------------------+------------------+--------------------+ +| :math:`\rho_b` | Bulk Density | [kg/m\ :sup:`3`] | 2500 | ++------------------+-------------------------+------------------+--------------------+ +| :math:`\phi` | Porosity | [-] | 0.375 | ++------------------+-------------------------+------------------+--------------------+ +| :math:`K_s` | Grain Bulk Modulus | [Pa] | 10\ :sup:`27` | ++------------------+-------------------------+------------------+--------------------+ +| :math:`\kappa` | Permeability | [m\ :sup:`2`] | 10\ :sup:`-12` | ++------------------+-------------------------+------------------+--------------------+ +| :math:`\rho_f` | Fluid Density | [kg/m\ :sup:`3`] | 1000 | ++------------------+-------------------------+------------------+--------------------+ +| :math:`c_f` | Fluid compressibility | [Pa\ :sup:`-1`] | 4.4x10\ :sup:`-10` | ++------------------+-------------------------+------------------+--------------------+ +| :math:`\mu` | Fluid viscosity | [Pa s] | 10\ :sup:`-3` | ++------------------+-------------------------+------------------+--------------------+ + + +--------------------------------- +Inspecting Results +--------------------------------- + +In the example, we request vtk output files for time-series (time history). We use paraview to visualize the outcome at the time 0s. +The following figure shows the final gradient of pressure and of the effective vertical stress after initialization is completed. + +.. _problemInitializationPressure: +.. figure:: pressure_field.png + :align: center + :width: 500 + :figclass: align-center + + Simulation result of pressure + +.. _problemInitializationStressZZ: +.. figure:: effective_SZZ.png + :align: center + :width: 500 + :figclass: align-center + + Simulation result of effective vertical stress + + +The figure below shows the comparison between the total stress computed by GEOS(marks) and with an analytical solutions (solid lines). Note that, because of the use of an isotropic model, the minimum and maximul horizontal stresses are equal. + +.. plot:: coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/gravityInitializationFigure.py + + +------------------------------------------------------------------ +To go further +------------------------------------------------------------------ + + +**Feedback on this example** + +For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. diff --git a/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/effective_SZZ.png b/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/effective_SZZ.png new file mode 100644 index 00000000000..1bd5ed57fe6 Binary files /dev/null and b/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/effective_SZZ.png differ diff --git a/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/gravityInitializationFigure.py b/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/gravityInitializationFigure.py new file mode 100644 index 00000000000..17d26c5174f --- /dev/null +++ b/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/gravityInitializationFigure.py @@ -0,0 +1,155 @@ +import matplotlib +import matplotlib.pyplot as plt +import numpy as np +import h5py +import xml.etree.ElementTree as ElementTree +import math +from math import sin,cos,tan,exp,atan,asin +import csv +import os +import argparse + + +def getHydromechanicalParametersFromXML(xmlFilePath): + tree = ElementTree.parse(xmlFilePath) + + param1 = tree.find('Constitutive/ElasticIsotropic') + param2 = tree.find('Constitutive/BiotPorosity') + param3 = tree.find('Constitutive/CompressibleSinglePhaseFluid') + + hydromechanicalParameters = dict.fromkeys([ + "bulkModulus", "shearModulus", "youngModulus", "poissonRatio", "rockDensity", "poissonRatio", "biotCoefficient", "porosity", "fluidDensity", "traction"]) + + hydromechanicalParameters["rockDensity"] = float(param1.get("defaultDensity")) + hydromechanicalParameters["poissonRatio"] = float(param1.get("defaultPoissonRatio")) + hydromechanicalParameters["youngModulus"] = float(param1.get("defaultYoungModulus")) + + E = hydromechanicalParameters["youngModulus"] + nu = hydromechanicalParameters["poissonRatio"] + K = E / (3 * (1 - 2 * nu)) + G = E / (2 * (1 + nu)) + + hydromechanicalParameters["poissonRatio"] = nu + hydromechanicalParameters["bulkModulus"] = K + hydromechanicalParameters["shearModulus"] = G + + Ks = float(param2.get("defaultGrainBulkModulus")) + hydromechanicalParameters["biotCoefficient"] = 1.0 - K / Ks + + hydromechanicalParameters["porosity"] = float(param2.get("defaultReferencePorosity")) + + hydromechanicalParameters["fluidDensity"] = float(param3.get("defaultDensity")) + + param4 = tree.findall('FieldSpecifications/Traction') + found_stress = False + for elem in param4: + if elem.get("name") == "tractionTop" and elem.get("tractionType") == "normal": + traction = float(elem.get("scale")) * (-1) + found_stress = True + if found_stress: break + + return hydromechanicalParameters + + +def main(): + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + + # File path + outputDir = args.outputDir + geosDir = args.geosDir + xmlFile1Path = geosDir + "/inputFiles/initialization/gravityInducedStress_initialization_base.xml" + xmlFile2Path = geosDir + "/inputFiles/initialization/gravityInducedStress_initialization_benchmark.xml" + + hydromechanicalParameters = getHydromechanicalParametersFromXML(xmlFile1Path) + + BiotCoefficient = hydromechanicalParameters["biotCoefficient"] + nu = hydromechanicalParameters["poissonRatio"] + rhoF = hydromechanicalParameters["fluidDensity"] + rhoR = hydromechanicalParameters["rockDensity"] + phi = hydromechanicalParameters["porosity"] + rhoB = (1-phi)*rhoR + phi*rhoF + + traction = hydromechanicalParameters["traction"] + gravity = 9.81 + + # rename this file to the name of your Paraview output file + file = open(outputDir + "/simulation_result_0.csv") + csvreader = csv.reader(file) + header = next(csvreader) + header_index = {column_name: index for index, column_name in enumerate(header)} + + rows = [] + for row in csvreader: + rows.append(row) + file.close() + + zloc_index = header_index["elementCenter:2"] + pressure_index = header_index["pressure"] + tsxx_index = header_index["rockSolid_stress:0"] # the solidModelName="rockSolid" has been defined in the gravityInducedStress_initialization_base.xml file, please change if you have a different solidModelName + tsyy_index = header_index["rockSolid_stress:1"] + tszz_index = header_index["rockSolid_stress:2"] + + + rows = np.array(rows) + zloc_0 = np.empty(len(rows[:,1])) + pressure_0 = np.empty(len(rows[:,1])) + tsxx_0 = np.empty(len(rows[:,1])) + tsyy_0 = np.empty(len(rows[:,1])) + tszz_0 = np.empty(len(rows[:,1])) + for i in range(0,len(rows[:,1])): + zloc_0[i]=-(float(rows[i,zloc_index])) + pressure_0[i]=float(rows[i,pressure_index]) + tsxx_0[i]=-(float(rows[i,tsxx_index])-BiotCoefficient*pressure_0[i])/1.0e6 + tsyy_0[i]=-(float(rows[i,tsyy_index])-BiotCoefficient*pressure_0[i])/1.0e6 + tszz_0[i]=-(float(rows[i,tszz_index])-BiotCoefficient*pressure_0[i])/1.0e6 + + + z_analytical= np.linspace(0, 1000, 100) + pp_analytical= rhoF*gravity*z_analytical/1.0e6 + szz_analtyical= rhoB*gravity*z_analytical/1.0e6 + + sxx_analtyical=nu/(1-nu)*(szz_analtyical-BiotCoefficient*pp_analytical)+BiotCoefficient*pp_analytical + + fsize = 20 + msize = 12 + lw = 6 + mew = 2 + malpha = 0.6 + lalpha = 0.8 + N1=1 + + fig = plt.figure(figsize=(10,8)) + cmap = plt.get_cmap("tab10") + + + plt.plot(tsxx_0[::N1], zloc_0[::N1], 'o', color=cmap(0), markersize=msize, alpha=malpha, mec=cmap(0), fillstyle='none', mew=mew, label= 'Sxx_Total_GEOS') + plt.plot(sxx_analtyical, z_analytical, lw=lw, alpha=0.8, color='orange', linestyle= ':', label='Sxx_Total_Analytical') + plt.plot(tsyy_0[::N1], zloc_0[::N1], 's', color=cmap(1), markersize=msize, alpha=malpha, mec=cmap(1), fillstyle='none', mew=mew, label= 'Syy_Total_GEOS') + plt.plot(tszz_0[::N1], zloc_0[::N1], 'd', color=cmap(2), markersize=msize, alpha=malpha, mec=cmap(2), fillstyle='none', mew=mew, label= 'Szz_Total_GEOS') + plt.plot(szz_analtyical, z_analytical, lw=lw, alpha=0.8, color='g', linestyle= ':', label='Szz_Total_Analytical') + plt.plot(pressure_0[::N1]/1.0e6, zloc_0[::N1], 'x', color=cmap(3), markersize=msize, alpha=malpha, mec=cmap(3), fillstyle='none', mew=mew, label= 'Pore Pressure_GEOS') + plt.plot(pp_analytical, z_analytical, lw=lw, alpha=0.8, color='r', linestyle= ':', label='Pore Pressure_Analytical') + plt.xlabel('Total Stresses [MPa]', size=fsize, weight="bold") + plt.ylabel('Depth [m]', size=fsize, weight="bold") + plt.legend(loc='upper right',fontsize=fsize*0.5) + plt.grid(True) + ax = plt.gca() + ax.xaxis.set_tick_params(labelsize=fsize) + ax.yaxis.set_tick_params(labelsize=fsize) + ax.invert_yaxis() + + plt.show() + + +if __name__ == "__main__": + main() + diff --git a/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/mesh.png b/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/mesh.png new file mode 100644 index 00000000000..16e043636c3 Binary files /dev/null and b/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/mesh.png differ diff --git a/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/pressure_field.png b/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/pressure_field.png new file mode 100644 index 00000000000..f8a23bc4d31 Binary files /dev/null and b/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/pressure_field.png differ diff --git a/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/simulation_result_0.csv b/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/simulation_result_0.csv new file mode 100644 index 00000000000..76f10c48621 --- /dev/null +++ b/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/simulation_result_0.csv @@ -0,0 +1,1002 @@ +"elementCenter:0","elementCenter:1","elementCenter:2","pressure","rockSolid_stress:0","rockSolid_stress:1","rockSolid_stress:2","rockSolid_stress:3","rockSolid_stress:4","rockSolid_stress:5","Points:0","Points:1","Points:2" +525,525,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-1.1991e-09,-1.1232e-09,9.354e-09,500,500,-1000 +525,525,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-1.1991e-09,-1.1232e-09,9.354e-09,500,500,-999 +525,525,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-1.1991e-09,-1.1232e-09,9.354e-09,500,500,-998 +525,525,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-1.1991e-09,-1.1232e-09,9.354e-09,500,500,-997 +525,525,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-1.1991e-09,-1.1232e-09,9.354e-09,500,500,-996 +525,525,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-1.1991e-09,-1.1232e-09,9.354e-09,500,500,-995 +525,525,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-1.1991e-09,-1.1232e-09,9.354e-09,500,500,-994 +525,525,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-1.1991e-09,-1.1232e-09,9.354e-09,500,500,-993 +525,525,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-1.1991e-09,-1.1232e-09,9.354e-09,500,500,-992 +525,525,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-1.1991e-09,-1.1232e-09,9.354e-09,500,500,-991 +525,525,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-1.1991e-09,-1.1232e-09,9.354e-09,500,500,-990 +525,525,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-1.1991e-09,-1.1232e-09,9.354e-09,500,500,-989 +525,525,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-1.1991e-09,-1.1232e-09,9.354e-09,500,500,-988 +525,525,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-1.1991e-09,-1.1232e-09,9.354e-09,500,500,-987 +525,525,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-1.1991e-09,-1.1232e-09,9.354e-09,500,500,-986 +525,475,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-5.6053e-10,-1.7456e-09,7.6652e-09,500,500,-985 +525,475,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-5.6053e-10,-1.7456e-09,7.6652e-09,500,500,-984 +525,475,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-5.6053e-10,-1.7456e-09,7.6652e-09,500,500,-983 +525,475,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-5.6053e-10,-1.7456e-09,7.6652e-09,500,500,-982 +525,475,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-5.6053e-10,-1.7456e-09,7.6652e-09,500,500,-981 +525,475,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-5.6053e-10,-1.7456e-09,7.6652e-09,500,500,-980 +525,475,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-5.6053e-10,-1.7456e-09,7.6652e-09,500,500,-979 +525,475,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-5.6053e-10,-1.7456e-09,7.6652e-09,500,500,-978 +525,475,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-5.6053e-10,-1.7456e-09,7.6652e-09,500,500,-977 +525,475,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-5.6053e-10,-1.7456e-09,7.6652e-09,500,500,-976 +525,475,-987.5,9.7081e+06,-3.023e+06,-3.023e+06,-9.069e+06,-5.6053e-10,-1.7456e-09,7.6652e-09,500,500,-975 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-974 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-973 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-972 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-971 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-970 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-969 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-968 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-967 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-966 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-965 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-964 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-963 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-962 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-961 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-960 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-959 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-958 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-957 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-956 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-955 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-954 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-953 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-952 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-951 +525,475,-962.5,9.4618e+06,-2.9466e+06,-2.9466e+06,-8.8397e+06,-1.0896e-08,-8.1315e-10,7.7823e-09,500,500,-950 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-949 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-948 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-947 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-946 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-945 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-944 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-943 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-942 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-941 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-940 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-939 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-938 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-937 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-936 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-935 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-934 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-933 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-932 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-931 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-930 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-929 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-928 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-927 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-926 +525,475,-937.5,9.2155e+06,-2.8701e+06,-2.8701e+06,-8.6104e+06,-4.1503e-09,1.586e-08,7.7569e-09,500,500,-925 +525,475,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-1.1501e-08,-5.6552e-09,7.2616e-09,500,500,-924 +525,475,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-1.1501e-08,-5.6552e-09,7.2616e-09,500,500,-923 +525,475,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-1.1501e-08,-5.6552e-09,7.2616e-09,500,500,-922 +525,475,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-1.1501e-08,-5.6552e-09,7.2616e-09,500,500,-921 +525,475,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-1.1501e-08,-5.6552e-09,7.2616e-09,500,500,-920 +525,475,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-1.1501e-08,-5.6552e-09,7.2616e-09,500,500,-919 +525,475,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-1.1501e-08,-5.6552e-09,7.2616e-09,500,500,-918 +525,475,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-1.1501e-08,-5.6552e-09,7.2616e-09,500,500,-917 +525,475,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-1.1501e-08,-5.6552e-09,7.2616e-09,500,500,-916 +525,475,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-1.1501e-08,-5.6552e-09,7.2616e-09,500,500,-915 +525,475,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-1.1501e-08,-5.6552e-09,7.2616e-09,500,500,-914 +525,475,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-1.1501e-08,-5.6552e-09,7.2616e-09,500,500,-913 +525,475,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-1.1501e-08,-5.6552e-09,7.2616e-09,500,500,-912 +525,525,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-8.8688e-09,-6.1626e-09,1.1097e-08,500,500,-911 +525,525,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-8.8688e-09,-6.1626e-09,1.1097e-08,500,500,-910 +525,525,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-8.8688e-09,-6.1626e-09,1.1097e-08,500,500,-909 +525,525,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-8.8688e-09,-6.1626e-09,1.1097e-08,500,500,-908 +525,525,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-8.8688e-09,-6.1626e-09,1.1097e-08,500,500,-907 +525,525,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-8.8688e-09,-6.1626e-09,1.1097e-08,500,500,-906 +525,525,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-8.8688e-09,-6.1626e-09,1.1097e-08,500,500,-905 +525,525,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-8.8688e-09,-6.1626e-09,1.1097e-08,500,500,-904 +525,525,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-8.8688e-09,-6.1626e-09,1.1097e-08,500,500,-903 +525,525,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-8.8688e-09,-6.1626e-09,1.1097e-08,500,500,-902 +525,525,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-8.8688e-09,-6.1626e-09,1.1097e-08,500,500,-901 +525,525,-912.5,8.9693e+06,-2.7937e+06,-2.7937e+06,-8.3811e+06,-8.8688e-09,-6.1626e-09,1.1097e-08,500,500,-900 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-899 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-898 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-897 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-896 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-895 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-894 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-893 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-892 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-891 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-890 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-889 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-888 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-887 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-886 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-885 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-884 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-883 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-882 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-881 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-880 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-879 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-878 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-877 +525,525,-887.5,8.7231e+06,-2.7173e+06,-2.7173e+06,-8.1518e+06,-2.4893e-09,-6.2797e-09,1.0626e-08,500,500,-876 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-875 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-874 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-873 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-872 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-871 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-870 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-869 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-868 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-867 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-866 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-865 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-864 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-863 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-862 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-861 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-860 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-859 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-858 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-857 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-856 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-855 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-854 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-853 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-852 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-851 +525,525,-862.5,8.4769e+06,-2.6408e+06,-2.6408e+06,-7.9224e+06,-2.5917e-08,-2.7981e-08,1.011e-08,500,500,-850 +525,525,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-1.9889e-08,-1.5031e-08,9.5237e-09,500,500,-849 +525,525,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-1.9889e-08,-1.5031e-08,9.5237e-09,500,500,-848 +525,525,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-1.9889e-08,-1.5031e-08,9.5237e-09,500,500,-847 +525,525,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-1.9889e-08,-1.5031e-08,9.5237e-09,500,500,-846 +525,525,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-1.9889e-08,-1.5031e-08,9.5237e-09,500,500,-845 +525,525,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-1.9889e-08,-1.5031e-08,9.5237e-09,500,500,-844 +525,525,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-1.9889e-08,-1.5031e-08,9.5237e-09,500,500,-843 +525,525,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-1.9889e-08,-1.5031e-08,9.5237e-09,500,500,-842 +525,525,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-1.9889e-08,-1.5031e-08,9.5237e-09,500,500,-841 +525,525,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-1.9889e-08,-1.5031e-08,9.5237e-09,500,500,-840 +525,525,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-1.9889e-08,-1.5031e-08,9.5237e-09,500,500,-839 +525,525,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-1.9889e-08,-1.5031e-08,9.5237e-09,500,500,-838 +525,475,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-2.021e-08,-1.8614e-08,7.1723e-09,500,500,-837 +525,475,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-2.021e-08,-1.8614e-08,7.1723e-09,500,500,-836 +525,475,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-2.021e-08,-1.8614e-08,7.1723e-09,500,500,-835 +525,475,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-2.021e-08,-1.8614e-08,7.1723e-09,500,500,-834 +525,475,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-2.021e-08,-1.8614e-08,7.1723e-09,500,500,-833 +525,475,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-2.021e-08,-1.8614e-08,7.1723e-09,500,500,-832 +525,475,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-2.021e-08,-1.8614e-08,7.1723e-09,500,500,-831 +525,475,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-2.021e-08,-1.8614e-08,7.1723e-09,500,500,-830 +525,475,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-2.021e-08,-1.8614e-08,7.1723e-09,500,500,-829 +525,475,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-2.021e-08,-1.8614e-08,7.1723e-09,500,500,-828 +525,475,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-2.021e-08,-1.8614e-08,7.1723e-09,500,500,-827 +525,475,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-2.021e-08,-1.8614e-08,7.1723e-09,500,500,-826 +525,475,-837.5,8.2307e+06,-2.5644e+06,-2.5644e+06,-7.6931e+06,-2.021e-08,-1.8614e-08,7.1723e-09,500,500,-825 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-824 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-823 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-822 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-821 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-820 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-819 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-818 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-817 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-816 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-815 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-814 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-813 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-812 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-811 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-810 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-809 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-808 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-807 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-806 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-805 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-804 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-803 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-802 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-801 +525,475,-812.5,7.9846e+06,-2.4879e+06,-2.4879e+06,-7.4637e+06,-2.2916e-08,-2.1406e-08,6.9877e-09,500,500,-800 +525,475,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-2.0244e-08,-1.1675e-08,7.6617e-09,500,500,-799 +525,475,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-2.0244e-08,-1.1675e-08,7.6617e-09,500,500,-798 +525,475,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-2.0244e-08,-1.1675e-08,7.6617e-09,500,500,-797 +525,475,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-2.0244e-08,-1.1675e-08,7.6617e-09,500,500,-796 +525,475,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-2.0244e-08,-1.1675e-08,7.6617e-09,500,500,-795 +525,475,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-2.0244e-08,-1.1675e-08,7.6617e-09,500,500,-794 +525,475,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-2.0244e-08,-1.1675e-08,7.6617e-09,500,500,-793 +525,475,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-2.0244e-08,-1.1675e-08,7.6617e-09,500,500,-792 +525,475,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-2.0244e-08,-1.1675e-08,7.6617e-09,500,500,-791 +525,475,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-2.0244e-08,-1.1675e-08,7.6617e-09,500,500,-790 +525,475,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-2.0244e-08,-1.1675e-08,7.6617e-09,500,500,-789 +525,475,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-2.0244e-08,-1.1675e-08,7.6617e-09,500,500,-788 +525,475,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-2.0244e-08,-1.1675e-08,7.6617e-09,500,500,-787 +525,525,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-1.8987e-08,-8.4655e-09,9.1127e-09,500,500,-786 +525,525,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-1.8987e-08,-8.4655e-09,9.1127e-09,500,500,-785 +525,525,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-1.8987e-08,-8.4655e-09,9.1127e-09,500,500,-784 +525,525,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-1.8987e-08,-8.4655e-09,9.1127e-09,500,500,-783 +525,525,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-1.8987e-08,-8.4655e-09,9.1127e-09,500,500,-782 +525,525,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-1.8987e-08,-8.4655e-09,9.1127e-09,500,500,-781 +525,525,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-1.8987e-08,-8.4655e-09,9.1127e-09,500,500,-780 +525,525,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-1.8987e-08,-8.4655e-09,9.1127e-09,500,500,-779 +525,525,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-1.8987e-08,-8.4655e-09,9.1127e-09,500,500,-778 +525,525,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-1.8987e-08,-8.4655e-09,9.1127e-09,500,500,-777 +525,525,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-1.8987e-08,-8.4655e-09,9.1127e-09,500,500,-776 +525,525,-787.5,7.7385e+06,-2.4114e+06,-2.4114e+06,-7.2343e+06,-1.8987e-08,-8.4655e-09,9.1127e-09,500,500,-775 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-774 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-773 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-772 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-771 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-770 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-769 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-768 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-767 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-766 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-765 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-764 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-763 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-762 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-761 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-760 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-759 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-758 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-757 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-756 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-755 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-754 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-753 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-752 +525,525,-762.5,7.4924e+06,-2.335e+06,-2.335e+06,-7.0049e+06,-2.5787e-08,-3.2986e-08,1.1376e-08,500,500,-751 +525,525,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.3592e-08,-3.3602e-08,1.2525e-08,500,500,-750 +525,525,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.3592e-08,-3.3602e-08,1.2525e-08,500,500,-749 +525,525,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.3592e-08,-3.3602e-08,1.2525e-08,500,500,-748 +525,525,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.3592e-08,-3.3602e-08,1.2525e-08,500,500,-747 +525,525,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.3592e-08,-3.3602e-08,1.2525e-08,500,500,-746 +525,525,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.3592e-08,-3.3602e-08,1.2525e-08,500,500,-745 +525,525,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.3592e-08,-3.3602e-08,1.2525e-08,500,500,-744 +525,525,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.3592e-08,-3.3602e-08,1.2525e-08,500,500,-743 +525,525,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.3592e-08,-3.3602e-08,1.2525e-08,500,500,-742 +525,525,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.3592e-08,-3.3602e-08,1.2525e-08,500,500,-741 +525,525,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.3592e-08,-3.3602e-08,1.2525e-08,500,500,-740 +525,525,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.3592e-08,-3.3602e-08,1.2525e-08,500,500,-739 +525,525,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.3592e-08,-3.3602e-08,1.2525e-08,500,500,-738 +525,525,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.3592e-08,-3.3602e-08,1.2525e-08,500,500,-737 +525,525,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.3592e-08,-3.3602e-08,1.2525e-08,500,500,-736 +525,475,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.9716e-08,-3.78e-08,6.2774e-09,500,500,-735 +525,475,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.9716e-08,-3.78e-08,6.2774e-09,500,500,-734 +525,475,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.9716e-08,-3.78e-08,6.2774e-09,500,500,-733 +525,475,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.9716e-08,-3.78e-08,6.2774e-09,500,500,-732 +525,475,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.9716e-08,-3.78e-08,6.2774e-09,500,500,-731 +525,475,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.9716e-08,-3.78e-08,6.2774e-09,500,500,-730 +525,475,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.9716e-08,-3.78e-08,6.2774e-09,500,500,-729 +525,475,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.9716e-08,-3.78e-08,6.2774e-09,500,500,-728 +525,475,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.9716e-08,-3.78e-08,6.2774e-09,500,500,-727 +525,475,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.9716e-08,-3.78e-08,6.2774e-09,500,500,-726 +525,475,-737.5,7.2464e+06,-2.2585e+06,-2.2585e+06,-6.7755e+06,-2.9716e-08,-3.78e-08,6.2774e-09,500,500,-725 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-724 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-723 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-722 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-721 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-720 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-719 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-718 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-717 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-716 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-715 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-714 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-713 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-712 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-711 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-710 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-709 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-708 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-707 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-706 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-705 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-704 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-703 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-702 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-701 +525,475,-712.5,7.0004e+06,-2.182e+06,-2.182e+06,-6.5461e+06,-3.2734e-08,-4.0593e-08,7.9573e-09,500,500,-700 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-699 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-698 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-697 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-696 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-695 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-694 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-693 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-692 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-691 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-690 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-689 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-688 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-687 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-686 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-685 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-684 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-683 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-682 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-681 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-680 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-679 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-678 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-677 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-676 +525,475,-687.5,6.7544e+06,-2.1055e+06,-2.1055e+06,-6.3166e+06,-2.6333e-08,-5.3447e-08,8.153e-09,500,500,-675 +525,475,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.2499e-08,-5.2094e-08,9.2601e-09,500,500,-674 +525,475,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.2499e-08,-5.2094e-08,9.2601e-09,500,500,-673 +525,475,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.2499e-08,-5.2094e-08,9.2601e-09,500,500,-672 +525,475,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.2499e-08,-5.2094e-08,9.2601e-09,500,500,-671 +525,475,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.2499e-08,-5.2094e-08,9.2601e-09,500,500,-670 +525,475,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.2499e-08,-5.2094e-08,9.2601e-09,500,500,-669 +525,475,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.2499e-08,-5.2094e-08,9.2601e-09,500,500,-668 +525,475,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.2499e-08,-5.2094e-08,9.2601e-09,500,500,-667 +525,475,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.2499e-08,-5.2094e-08,9.2601e-09,500,500,-666 +525,475,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.2499e-08,-5.2094e-08,9.2601e-09,500,500,-665 +525,475,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.2499e-08,-5.2094e-08,9.2601e-09,500,500,-664 +525,475,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.2499e-08,-5.2094e-08,9.2601e-09,500,500,-663 +525,475,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.2499e-08,-5.2094e-08,9.2601e-09,500,500,-662 +525,525,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.8345e-08,-4.7393e-08,1.6922e-08,500,500,-661 +525,525,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.8345e-08,-4.7393e-08,1.6922e-08,500,500,-660 +525,525,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.8345e-08,-4.7393e-08,1.6922e-08,500,500,-659 +525,525,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.8345e-08,-4.7393e-08,1.6922e-08,500,500,-658 +525,525,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.8345e-08,-4.7393e-08,1.6922e-08,500,500,-657 +525,525,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.8345e-08,-4.7393e-08,1.6922e-08,500,500,-656 +525,525,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.8345e-08,-4.7393e-08,1.6922e-08,500,500,-655 +525,525,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.8345e-08,-4.7393e-08,1.6922e-08,500,500,-654 +525,525,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.8345e-08,-4.7393e-08,1.6922e-08,500,500,-653 +525,525,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.8345e-08,-4.7393e-08,1.6922e-08,500,500,-652 +525,525,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.8345e-08,-4.7393e-08,1.6922e-08,500,500,-651 +525,525,-662.5,6.5084e+06,-2.029e+06,-2.029e+06,-6.0871e+06,-2.8345e-08,-4.7393e-08,1.6922e-08,500,500,-650 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-649 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-648 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-647 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-646 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-645 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-644 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-643 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-642 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-641 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-640 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-639 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-638 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-637 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-636 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-635 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-634 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-633 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-632 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-631 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-630 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-629 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-628 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-627 +525,525,-637.5,6.2625e+06,-1.9525e+06,-1.9525e+06,-5.8576e+06,-2.6992e-08,-5.0203e-08,1.7557e-08,500,500,-626 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-625 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-624 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-623 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-622 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-621 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-620 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-619 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-618 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-617 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-616 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-615 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-614 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-613 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-612 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-611 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-610 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-609 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-608 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-607 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-606 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-605 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-604 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-603 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-602 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-601 +525,525,-612.5,6.0166e+06,-1.876e+06,-1.876e+06,-5.6281e+06,-3.2491e-08,-6.9944e-08,1.5866e-08,500,500,-600 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-599 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-598 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-597 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-596 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-595 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-594 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-593 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-592 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-591 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-590 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-589 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-588 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-587 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-586 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-585 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-584 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-583 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-582 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-581 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-580 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-579 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-578 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-577 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-576 +525,525,-587.5,5.7707e+06,-1.7995e+06,-1.7995e+06,-5.3986e+06,-3.0479e-08,-7.7507e-08,1.647e-08,500,500,-575 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-574 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-573 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-572 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-571 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-570 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-569 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-568 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-567 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-566 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-565 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-564 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-563 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-562 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-561 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-560 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-559 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-558 +525,525,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.3775e-08,-8.8349e-08,1.9547e-08,500,500,-557 +525,475,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.6325e-08,-9.338e-08,1.7773e-08,500,500,-556 +525,475,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.6325e-08,-9.338e-08,1.7773e-08,500,500,-555 +525,475,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.6325e-08,-9.338e-08,1.7773e-08,500,500,-554 +525,475,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.6325e-08,-9.338e-08,1.7773e-08,500,500,-553 +525,475,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.6325e-08,-9.338e-08,1.7773e-08,500,500,-552 +525,475,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.6325e-08,-9.338e-08,1.7773e-08,500,500,-551 +525,475,-562.5,5.5248e+06,-1.723e+06,-1.723e+06,-5.1691e+06,-3.6325e-08,-9.338e-08,1.7773e-08,500,500,-550 +525,475,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.0922e-08,-8.9685e-08,1.9473e-08,500,500,-549 +525,475,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.0922e-08,-8.9685e-08,1.9473e-08,500,500,-548 +525,475,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.0922e-08,-8.9685e-08,1.9473e-08,500,500,-547 +525,475,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.0922e-08,-8.9685e-08,1.9473e-08,500,500,-546 +525,475,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.0922e-08,-8.9685e-08,1.9473e-08,500,500,-545 +525,475,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.0922e-08,-8.9685e-08,1.9473e-08,500,500,-544 +525,475,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.0922e-08,-8.9685e-08,1.9473e-08,500,500,-543 +525,475,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.0922e-08,-8.9685e-08,1.9473e-08,500,500,-542 +525,475,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.0922e-08,-8.9685e-08,1.9473e-08,500,500,-541 +525,475,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.0922e-08,-8.9685e-08,1.9473e-08,500,500,-540 +525,475,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.0922e-08,-8.9685e-08,1.9473e-08,500,500,-539 +525,475,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.0922e-08,-8.9685e-08,1.9473e-08,500,500,-538 +525,475,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.0922e-08,-8.9685e-08,1.9473e-08,500,500,-537 +525,525,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.2483e-08,-8.8263e-08,2.2753e-08,500,500,-536 +525,525,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.2483e-08,-8.8263e-08,2.2753e-08,500,500,-535 +525,525,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.2483e-08,-8.8263e-08,2.2753e-08,500,500,-534 +525,525,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.2483e-08,-8.8263e-08,2.2753e-08,500,500,-533 +525,525,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.2483e-08,-8.8263e-08,2.2753e-08,500,500,-532 +525,525,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.2483e-08,-8.8263e-08,2.2753e-08,500,500,-531 +525,525,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.2483e-08,-8.8263e-08,2.2753e-08,500,500,-530 +525,525,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.2483e-08,-8.8263e-08,2.2753e-08,500,500,-529 +525,525,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.2483e-08,-8.8263e-08,2.2753e-08,500,500,-528 +525,525,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.2483e-08,-8.8263e-08,2.2753e-08,500,500,-527 +525,525,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.2483e-08,-8.8263e-08,2.2753e-08,500,500,-526 +525,525,-537.5,5.279e+06,-1.6465e+06,-1.6465e+06,-4.9395e+06,-4.2483e-08,-8.8263e-08,2.2753e-08,500,500,-525 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-524 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-523 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-522 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-521 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-520 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-519 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-518 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-517 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-516 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-515 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-514 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-513 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-512 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-511 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-510 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-509 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-508 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-507 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-506 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-505 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-504 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-503 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-502 +525,525,-512.5,5.0332e+06,-1.57e+06,-1.57e+06,-4.7099e+06,-4.6282e-08,-8.5001e-08,2.4689e-08,500,500,-501 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-500 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-499 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-498 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-497 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-496 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-495 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-494 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-493 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-492 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-491 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-490 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-489 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-488 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-487 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-486 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-485 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-484 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-483 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-482 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-481 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-480 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-479 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-478 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-477 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-476 +525,525,-487.5,4.7874e+06,-1.4934e+06,-1.4934e+06,-4.4803e+06,-4.859e-08,-8.3197e-08,2.5083e-08,500,500,-475 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-474 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-473 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-472 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-471 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-470 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-469 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-468 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-467 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-466 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-465 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-464 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-463 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-462 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-461 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-460 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-459 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-458 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-457 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-456 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-455 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-454 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-453 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-452 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-451 +525,525,-462.5,4.5417e+06,-1.4169e+06,-1.4169e+06,-4.2507e+06,-5.4505e-08,-8.2e-08,2.7127e-08,500,500,-450 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-449 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-448 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-447 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-446 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-445 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-444 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-443 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-442 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-441 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-440 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-439 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-438 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-437 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-436 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-435 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-434 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-433 +525,525,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-4.7306e-08,-7.7143e-08,2.8496e-08,500,500,-432 +525,475,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-2.9143e-08,-6.2086e-08,2.9651e-08,500,500,-431 +525,475,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-2.9143e-08,-6.2086e-08,2.9651e-08,500,500,-430 +525,475,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-2.9143e-08,-6.2086e-08,2.9651e-08,500,500,-429 +525,475,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-2.9143e-08,-6.2086e-08,2.9651e-08,500,500,-428 +525,475,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-2.9143e-08,-6.2086e-08,2.9651e-08,500,500,-427 +525,475,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-2.9143e-08,-6.2086e-08,2.9651e-08,500,500,-426 +525,475,-437.5,4.2959e+06,-1.3404e+06,-1.3404e+06,-4.0211e+06,-2.9143e-08,-6.2086e-08,2.9651e-08,500,500,-425 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-424 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-423 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-422 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-421 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-420 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-419 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-418 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-417 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-416 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-415 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-414 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-413 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-412 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-411 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-410 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-409 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-408 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-407 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-406 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-405 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-404 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-403 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-402 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-401 +525,475,-412.5,4.0502e+06,-1.2638e+06,-1.2638e+06,-3.7915e+06,-3.8719e-08,-6.8279e-08,3.0795e-08,500,500,-400 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-399 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-398 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-397 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-396 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-395 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-394 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-393 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-392 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-391 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-390 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-389 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-388 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-387 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-386 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-385 +525,475,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-3.8407e-08,-6.7273e-08,3.1651e-08,500,500,-384 +525,525,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-4.9197e-08,-6.9927e-08,2.468e-08,500,500,-383 +525,525,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-4.9197e-08,-6.9927e-08,2.468e-08,500,500,-382 +525,525,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-4.9197e-08,-6.9927e-08,2.468e-08,500,500,-381 +525,525,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-4.9197e-08,-6.9927e-08,2.468e-08,500,500,-380 +525,525,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-4.9197e-08,-6.9927e-08,2.468e-08,500,500,-379 +525,525,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-4.9197e-08,-6.9927e-08,2.468e-08,500,500,-378 +525,525,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-4.9197e-08,-6.9927e-08,2.468e-08,500,500,-377 +525,525,-387.5,3.8046e+06,-1.1873e+06,-1.1873e+06,-3.5618e+06,-4.9197e-08,-6.9927e-08,2.468e-08,500,500,-376 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-375 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-374 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-373 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-372 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-371 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-370 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-369 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-368 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-367 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-366 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-365 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-364 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-363 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-362 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-361 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-360 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-359 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-358 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-357 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-356 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-355 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-354 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-353 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-352 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-351 +525,525,-362.5,3.5589e+06,-1.1107e+06,-1.1107e+06,-3.3321e+06,-4.7306e-08,-6.4879e-08,2.9061e-08,500,500,-350 +525,525,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-4.2969e-08,-6.9684e-08,3.4663e-08,500,500,-349 +525,525,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-4.2969e-08,-6.9684e-08,3.4663e-08,500,500,-348 +525,525,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-4.2969e-08,-6.9684e-08,3.4663e-08,500,500,-347 +525,525,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-4.2969e-08,-6.9684e-08,3.4663e-08,500,500,-346 +525,525,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-4.2969e-08,-6.9684e-08,3.4663e-08,500,500,-345 +525,525,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-4.2969e-08,-6.9684e-08,3.4663e-08,500,500,-344 +525,525,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-4.2969e-08,-6.9684e-08,3.4663e-08,500,500,-343 +525,525,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-4.2969e-08,-6.9684e-08,3.4663e-08,500,500,-342 +525,525,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-4.2969e-08,-6.9684e-08,3.4663e-08,500,500,-341 +525,525,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-4.2969e-08,-6.9684e-08,3.4663e-08,500,500,-340 +525,525,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-4.2969e-08,-6.9684e-08,3.4663e-08,500,500,-339 +525,525,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-4.2969e-08,-6.9684e-08,3.4663e-08,500,500,-338 +525,475,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-5.1886e-08,-7.1349e-08,2.4023e-08,500,500,-337 +525,475,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-5.1886e-08,-7.1349e-08,2.4023e-08,500,500,-336 +525,475,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-5.1886e-08,-7.1349e-08,2.4023e-08,500,500,-335 +525,475,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-5.1886e-08,-7.1349e-08,2.4023e-08,500,500,-334 +525,475,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-5.1886e-08,-7.1349e-08,2.4023e-08,500,500,-333 +525,475,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-5.1886e-08,-7.1349e-08,2.4023e-08,500,500,-332 +525,475,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-5.1886e-08,-7.1349e-08,2.4023e-08,500,500,-331 +525,475,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-5.1886e-08,-7.1349e-08,2.4023e-08,500,500,-330 +525,475,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-5.1886e-08,-7.1349e-08,2.4023e-08,500,500,-329 +525,475,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-5.1886e-08,-7.1349e-08,2.4023e-08,500,500,-328 +525,475,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-5.1886e-08,-7.1349e-08,2.4023e-08,500,500,-327 +525,475,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-5.1886e-08,-7.1349e-08,2.4023e-08,500,500,-326 +525,475,-337.5,3.3133e+06,-1.0341e+06,-1.0341e+06,-3.1024e+06,-5.1886e-08,-7.1349e-08,2.4023e-08,500,500,-325 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-324 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-323 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-322 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-321 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-320 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-319 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-318 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-317 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-316 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-315 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-314 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-313 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-312 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-311 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-310 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-309 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-308 +525,475,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-6.2797e-08,-7.6363e-08,2.071e-08,500,500,-307 +525,525,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-4.0003e-08,-6.5711e-08,3.2505e-08,500,500,-306 +525,525,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-4.0003e-08,-6.5711e-08,3.2505e-08,500,500,-305 +525,525,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-4.0003e-08,-6.5711e-08,3.2505e-08,500,500,-304 +525,525,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-4.0003e-08,-6.5711e-08,3.2505e-08,500,500,-303 +525,525,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-4.0003e-08,-6.5711e-08,3.2505e-08,500,500,-302 +525,525,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-4.0003e-08,-6.5711e-08,3.2505e-08,500,500,-301 +525,525,-312.5,3.0677e+06,-9.5758e+05,-9.5758e+05,-2.8727e+06,-4.0003e-08,-6.5711e-08,3.2505e-08,500,500,-300 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-299 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-298 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-297 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-296 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-295 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-294 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-293 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-292 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-291 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-290 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-289 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-288 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-287 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-286 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-285 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-284 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-283 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-282 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-281 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-280 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-279 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-278 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-277 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-276 +525,525,-287.5,2.8221e+06,-8.81e+05,-8.81e+05,-2.643e+06,-4.7427e-08,-6.5087e-08,2.1632e-08,500,500,-275 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-274 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-273 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-272 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-271 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-270 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-269 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-268 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-267 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-266 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-265 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-264 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-263 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-262 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-261 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-260 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-259 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-258 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-257 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-256 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-255 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-254 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-253 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-252 +525,525,-262.5,2.5766e+06,-8.0442e+05,-8.0442e+05,-2.4133e+06,-5.4921e-08,-6.134e-08,1.3059e-08,500,500,-251 +525,525,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.9674e-08,-5.2597e-08,1.5083e-08,500,500,-250 +525,525,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.9674e-08,-5.2597e-08,1.5083e-08,500,500,-249 +525,525,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.9674e-08,-5.2597e-08,1.5083e-08,500,500,-248 +525,525,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.9674e-08,-5.2597e-08,1.5083e-08,500,500,-247 +525,525,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.9674e-08,-5.2597e-08,1.5083e-08,500,500,-246 +525,525,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.9674e-08,-5.2597e-08,1.5083e-08,500,500,-245 +525,525,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.9674e-08,-5.2597e-08,1.5083e-08,500,500,-244 +525,525,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.9674e-08,-5.2597e-08,1.5083e-08,500,500,-243 +525,525,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.9674e-08,-5.2597e-08,1.5083e-08,500,500,-242 +525,525,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.9674e-08,-5.2597e-08,1.5083e-08,500,500,-241 +525,525,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.9674e-08,-5.2597e-08,1.5083e-08,500,500,-240 +525,525,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.9674e-08,-5.2597e-08,1.5083e-08,500,500,-239 +525,525,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.9674e-08,-5.2597e-08,1.5083e-08,500,500,-238 +525,525,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.9674e-08,-5.2597e-08,1.5083e-08,500,500,-237 +525,525,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.9674e-08,-5.2597e-08,1.5083e-08,500,500,-236 +525,475,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.7176e-08,-7.5634e-08,1.9129e-08,500,500,-235 +525,475,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.7176e-08,-7.5634e-08,1.9129e-08,500,500,-234 +525,475,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.7176e-08,-7.5634e-08,1.9129e-08,500,500,-233 +525,475,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.7176e-08,-7.5634e-08,1.9129e-08,500,500,-232 +525,475,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.7176e-08,-7.5634e-08,1.9129e-08,500,500,-231 +525,475,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.7176e-08,-7.5634e-08,1.9129e-08,500,500,-230 +525,475,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.7176e-08,-7.5634e-08,1.9129e-08,500,500,-229 +525,475,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.7176e-08,-7.5634e-08,1.9129e-08,500,500,-228 +525,475,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.7176e-08,-7.5634e-08,1.9129e-08,500,500,-227 +525,475,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.7176e-08,-7.5634e-08,1.9129e-08,500,500,-226 +525,475,-237.5,2.3311e+06,-7.2784e+05,-7.2784e+05,-2.1835e+06,-5.7176e-08,-7.5634e-08,1.9129e-08,500,500,-225 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-224 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-223 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-222 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-221 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-220 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-219 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-218 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-217 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-216 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-215 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-214 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-213 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-212 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-211 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-210 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-209 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-208 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-207 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-206 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-205 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-204 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-203 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-202 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-201 +525,475,-212.5,2.0856e+06,-6.5125e+05,-6.5125e+05,-1.9537e+06,-4.8121e-08,-6.4219e-08,2.1104e-08,500,500,-200 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-199 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-198 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-197 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-196 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-195 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-194 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-193 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-192 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-191 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-190 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-189 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-188 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-187 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-186 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-185 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-184 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-183 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-182 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-181 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-180 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-179 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-178 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-177 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-176 +525,475,-187.5,1.8401e+06,-5.7465e+05,-5.7465e+05,-1.7239e+06,-4.8052e-08,-5.2736e-08,2.2656e-08,500,500,-175 +525,475,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-4.6733e-08,-5.2215e-08,1.9757e-08,500,500,-174 +525,475,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-4.6733e-08,-5.2215e-08,1.9757e-08,500,500,-173 +525,475,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-4.6733e-08,-5.2215e-08,1.9757e-08,500,500,-172 +525,475,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-4.6733e-08,-5.2215e-08,1.9757e-08,500,500,-171 +525,475,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-4.6733e-08,-5.2215e-08,1.9757e-08,500,500,-170 +525,475,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-4.6733e-08,-5.2215e-08,1.9757e-08,500,500,-169 +525,475,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-4.6733e-08,-5.2215e-08,1.9757e-08,500,500,-168 +525,475,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-4.6733e-08,-5.2215e-08,1.9757e-08,500,500,-167 +525,475,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-4.6733e-08,-5.2215e-08,1.9757e-08,500,500,-166 +525,475,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-4.6733e-08,-5.2215e-08,1.9757e-08,500,500,-165 +525,475,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-4.6733e-08,-5.2215e-08,1.9757e-08,500,500,-164 +525,475,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-4.6733e-08,-5.2215e-08,1.9757e-08,500,500,-163 +525,475,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-4.6733e-08,-5.2215e-08,1.9757e-08,500,500,-162 +525,525,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-6.1583e-08,-3.6741e-08,1.6738e-08,500,500,-161 +525,525,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-6.1583e-08,-3.6741e-08,1.6738e-08,500,500,-160 +525,525,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-6.1583e-08,-3.6741e-08,1.6738e-08,500,500,-159 +525,525,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-6.1583e-08,-3.6741e-08,1.6738e-08,500,500,-158 +525,525,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-6.1583e-08,-3.6741e-08,1.6738e-08,500,500,-157 +525,525,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-6.1583e-08,-3.6741e-08,1.6738e-08,500,500,-156 +525,525,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-6.1583e-08,-3.6741e-08,1.6738e-08,500,500,-155 +525,525,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-6.1583e-08,-3.6741e-08,1.6738e-08,500,500,-154 +525,525,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-6.1583e-08,-3.6741e-08,1.6738e-08,500,500,-153 +525,525,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-6.1583e-08,-3.6741e-08,1.6738e-08,500,500,-152 +525,525,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-6.1583e-08,-3.6741e-08,1.6738e-08,500,500,-151 +525,525,-162.5,1.5947e+06,-4.9805e+05,-4.9805e+05,-1.4941e+06,-6.1583e-08,-3.6741e-08,1.6738e-08,500,500,-150 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-149 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-148 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-147 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-146 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-145 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-144 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-143 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-142 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-141 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-140 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-139 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-138 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-137 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-136 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-135 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-134 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-133 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-132 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-131 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-130 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-129 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-128 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-127 +525,525,-137.5,1.3493e+06,-4.2144e+05,-4.2144e+05,-1.2643e+06,-4.9162e-08,-3.3654e-08,1.4931e-08,500,500,-126 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-125 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-124 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-123 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-122 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-121 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-120 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-119 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-118 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-117 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-116 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-115 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-114 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-113 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-112 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-111 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-110 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-109 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-108 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-107 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-106 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-105 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-104 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-103 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-102 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-101 +525,525,-112.5,1.1039e+06,-3.4483e+05,-3.4483e+05,-1.0345e+06,-3.8719e-08,-2.6229e-08,1.699e-08,500,500,-100 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-99 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-98 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-97 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-96 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-95 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-94 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-93 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-92 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-91 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-90 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-89 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-88 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-87 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-86 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-85 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-84 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-83 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-82 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-81 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-80 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-79 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-78 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-77 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-76 +525,525,-87.5,8.5854e+05,-2.6821e+05,-2.6821e+05,-8.0463e+05,-3.5562e-08,-7.841e-09,1.8485e-08,500,500,-75 +525,525,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.2717e-08,-3.4348e-09,1.3681e-08,500,500,-74 +525,525,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.2717e-08,-3.4348e-09,1.3681e-08,500,500,-73 +525,525,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.2717e-08,-3.4348e-09,1.3681e-08,500,500,-72 +525,525,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.2717e-08,-3.4348e-09,1.3681e-08,500,500,-71 +525,525,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.2717e-08,-3.4348e-09,1.3681e-08,500,500,-70 +525,525,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.2717e-08,-3.4348e-09,1.3681e-08,500,500,-69 +525,525,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.2717e-08,-3.4348e-09,1.3681e-08,500,500,-68 +525,525,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.2717e-08,-3.4348e-09,1.3681e-08,500,500,-67 +525,525,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.2717e-08,-3.4348e-09,1.3681e-08,500,500,-66 +525,525,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.2717e-08,-3.4348e-09,1.3681e-08,500,500,-65 +525,525,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.2717e-08,-3.4348e-09,1.3681e-08,500,500,-64 +525,525,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.2717e-08,-3.4348e-09,1.3681e-08,500,500,-63 +525,475,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.629e-08,-1.8839e-08,1.0223e-08,500,500,-62 +525,475,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.629e-08,-1.8839e-08,1.0223e-08,500,500,-61 +525,475,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.629e-08,-1.8839e-08,1.0223e-08,500,500,-60 +525,475,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.629e-08,-1.8839e-08,1.0223e-08,500,500,-59 +525,475,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.629e-08,-1.8839e-08,1.0223e-08,500,500,-58 +525,475,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.629e-08,-1.8839e-08,1.0223e-08,500,500,-57 +525,475,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.629e-08,-1.8839e-08,1.0223e-08,500,500,-56 +525,475,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.629e-08,-1.8839e-08,1.0223e-08,500,500,-55 +525,475,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.629e-08,-1.8839e-08,1.0223e-08,500,500,-54 +525,475,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.629e-08,-1.8839e-08,1.0223e-08,500,500,-53 +525,475,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.629e-08,-1.8839e-08,1.0223e-08,500,500,-52 +525,475,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.629e-08,-1.8839e-08,1.0223e-08,500,500,-51 +525,475,-62.5,6.1321e+05,-1.9158e+05,-1.9158e+05,-5.7475e+05,-3.629e-08,-1.8839e-08,1.0223e-08,500,500,-50 +525,475,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-3.3827e-08,-1.648e-08,8.0362e-09,500,500,-49 +525,475,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-3.3827e-08,-1.648e-08,8.0362e-09,500,500,-48 +525,475,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-3.3827e-08,-1.648e-08,8.0362e-09,500,500,-47 +525,475,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-3.3827e-08,-1.648e-08,8.0362e-09,500,500,-46 +525,475,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-3.3827e-08,-1.648e-08,8.0362e-09,500,500,-45 +525,475,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-3.3827e-08,-1.648e-08,8.0362e-09,500,500,-44 +525,475,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-3.3827e-08,-1.648e-08,8.0362e-09,500,500,-43 +525,475,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-3.3827e-08,-1.648e-08,8.0362e-09,500,500,-42 +525,475,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-3.3827e-08,-1.648e-08,8.0362e-09,500,500,-41 +525,475,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-3.3827e-08,-1.648e-08,8.0362e-09,500,500,-40 +525,475,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-3.3827e-08,-1.648e-08,8.0362e-09,500,500,-39 +525,475,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-3.3827e-08,-1.648e-08,8.0362e-09,500,500,-38 +525,475,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-3.3827e-08,-1.648e-08,8.0362e-09,500,500,-37 +525,475,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-3.3827e-08,-1.648e-08,8.0362e-09,500,500,-36 +525,525,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-1.8111e-08,-1.3427e-08,7.6771e-09,500,500,-35 +525,525,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-1.8111e-08,-1.3427e-08,7.6771e-09,500,500,-34 +525,525,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-1.8111e-08,-1.3427e-08,7.6771e-09,500,500,-33 +525,525,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-1.8111e-08,-1.3427e-08,7.6771e-09,500,500,-32 +525,525,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-1.8111e-08,-1.3427e-08,7.6771e-09,500,500,-31 +525,525,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-1.8111e-08,-1.3427e-08,7.6771e-09,500,500,-30 +525,525,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-1.8111e-08,-1.3427e-08,7.6771e-09,500,500,-29 +525,525,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-1.8111e-08,-1.3427e-08,7.6771e-09,500,500,-28 +525,525,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-1.8111e-08,-1.3427e-08,7.6771e-09,500,500,-27 +525,525,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-1.8111e-08,-1.3427e-08,7.6771e-09,500,500,-26 +525,525,-37.5,3.679e+05,-1.1496e+05,-1.1496e+05,-3.4487e+05,-1.8111e-08,-1.3427e-08,7.6771e-09,500,500,-25 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-24 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-23 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-22 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-21 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-20 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-19 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-18 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-17 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-16 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-15 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-14 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-13 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-12 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-11 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-10 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-9 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-8 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-7 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-6 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-5 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-4 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-3 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-2 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,-1 +525,525,-12.5,1.2263e+05,-38320,-38320,-1.1496e+05,-3.1919e-09,-9.1593e-09,6.9718e-09,500,500,0 diff --git a/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/sketch_of_problem.png b/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/sketch_of_problem.png new file mode 100644 index 00000000000..e878da52b4b Binary files /dev/null and b/src/coreComponents/physicsSolvers/multiphysics/docs/gravityInducedStressInitialization/sketch_of_problem.png differ diff --git a/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/Example.rst b/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/Example.rst new file mode 100644 index 00000000000..6ec3b78de4f --- /dev/null +++ b/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/Example.rst @@ -0,0 +1,116 @@ +.. _userdefinedstressinitialization: + + +################################################################################# + Model Initialization: User Defined Tables +################################################################################# + + +**Context** + +This example uses the same reservoir model as the gravity-induced hydrostatic stress initialization case (see :ref:`gravityinducedhydrostaticinitialization`). Instead of using the gravity based equilibrium initialization procedure, we collect the interpretated stress and pore pressure gradients for a reservoir and then request the simulator to perform an initialization with the provided pressure and stresses in every element in the model. The problem is solved by using the single-phase poromechanics solver (see :ref:`PoroelasticSolver`) in GEOS. + +**Input file** + +The xml input files for the test case are located at: + +.. code-block:: console + + inputFiles/initialization/userdefinedStress_initialization_base.xml + inputFiles/initialization/userdefinedStress_initialization_benchmark.xml + + +This example also uses a set of table files located at: + +.. code-block:: console + + inputFiles/initialization/userTables/ + + +Last, a Python script for post-processing the results is provided: + +.. code-block:: console + + src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/tableInitializationFigure.py + + +------------------------------------- +Stress Initialization Table Functions +------------------------------------- + +The major distinction between this "user-defined" initialization and the "gravity-based" initialization is that in the user-defined case, the user provides the following additional information: + + - The distribution of effective stresses and pore pressure across the domain, with their gradients assumed constant along the depth in this example. We use a table function (see :ref:`FunctionManager`) to specify pressure and stress conditions throughout the area. + + +This is shown in the following tags under the ``FieldSpecifications`` section below + +.. literalinclude:: ../../../../../../inputFiles/initialization/userdefinedStress_initialization_base.xml + :language: xml + :start-after: + :end-before: + +The tables for ``sigma_xx``, ``sigma_yy``, ``sigma_zz`` and ``init_pressure`` are listed under the ``Functions`` section as shown below. + +.. literalinclude:: ../../../../../../inputFiles/initialization/userdefinedStress_initialization_base.xml + :language: xml + :start-after: + :end-before: + +The required input files: x.csv, y.csv, z.csv, effectiveSigma_xx.csv, effectiveSigma_yy.csv, effectiveSigma_zz.csv, and porePressure.csv are generated based on the expected stress-gradients in the model. + +A Python script to generate these files is provided: + +.. code-block:: console + + src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/genetrateTable.py + +In addition to generating the files listed above, the script prints out the corresponding fluid density and rock density based on the model parameters provided. These values are then input into the ``defaultDensity`` parameter of the ``CompressibleSinglePhaseFluid`` and ``ElasticIsotropic`` tags respectively, as shown below: + +.. literalinclude:: ../../../../../../inputFiles/initialization/userdefinedStress_initialization_base.xml + :language: xml + :start-after: + :end-before: + +.. literalinclude:: ../../../../../../inputFiles/initialization/userdefinedStress_initialization_base.xml + :language: xml + :start-after: + :end-before: + + +--------------------------------- +Inspecting Results +--------------------------------- + +In the example, we request vtk output files for time-series (time history). We use paraview to visualize the outcome at the time 0s. +The following figure shows the final gradient of pressure and of the effective vertical stress after initialization is completed. + +.. _problemInitializationPres: +.. figure:: pressure_field.png + :align: center + :width: 500 + :figclass: align-center + + Simulation result of pressure + +.. _problemInitializationSZZ: +.. figure:: stressZZ_field.png + :align: center + :width: 500 + :figclass: align-center + + Simulation result of effective vertical stress + +The figure below shows the comparisons between the numerical predictions (marks) and the corresponding user-provided stress gradients. Note that anisotropic horizontal stresses are obtained through this intialization procedure; however, mechanical equilibrium might not be guaranteed, especially for the heterogeneous models. + +.. plot:: coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/tableInitializationFigure.py + + +------------------------------------------------------------------ +To go further +------------------------------------------------------------------ + + +**Feedback on this example** + +For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. diff --git a/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/generateTable.py b/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/generateTable.py new file mode 100644 index 00000000000..c8e8eb08ff2 --- /dev/null +++ b/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/generateTable.py @@ -0,0 +1,49 @@ +import math +import numpy as np + + +model_top = 0.0 # in m +model_base = -1000.0 # in m +num_Points = 2 +z_table = np.linspace(model_base, model_top, num_Points) +pp_gradient = 0.1 # in MPa/m +sigma_xx_gradient = 0.17 # in MPa/m +sigma_yy_gradient = 0.27 # in MPa/m +sigma_zz_gradient = 0.24 # in MPa/m + + + +PoissonRatio = 0.25 +YoungModulus = 100e6 # in Pa +grainBulkModulus = 1e27 # in #Pa +bulkModulus = YoungModulus/3.0/(1.0-2.0*PoissonRatio) # in Pa +BiotCoefficient = 1.0-bulkModulus/grainBulkModulus +porosity = 0.375 +Gravity = 9.81 + + +pp_table = abs(z_table)*pp_gradient*100000 +fluidDensity = pp_gradient*100000/Gravity +effectiveSigma_xx_table = z_table*sigma_xx_gradient*100000 + BiotCoefficient*pp_table +effectiveSigma_yy_table = z_table*sigma_yy_gradient*100000 + BiotCoefficient*pp_table +effectiveSigma_zz_table = z_table*sigma_zz_gradient*100000 + BiotCoefficient*pp_table + +bulkDensity = sigma_zz_gradient*100000/Gravity +rockDensity = (bulkDensity - porosity*fluidDensity)/(1.0-porosity) +print(f'Fluid Density = {fluidDensity} kg/m3, Rock Density = {rockDensity} kg/m3') + +np.savetxt('porePressure.csv', pp_table, fmt='%1.2f', delimiter=',') + +np.savetxt('effectiveSigma_xx.csv', effectiveSigma_xx_table, fmt='%1.2f', delimiter=',') + +np.savetxt('effectiveSigma_yy.csv', effectiveSigma_yy_table, fmt='%1.2f', delimiter=',') + +np.savetxt('effectiveSigma_zz.csv', effectiveSigma_zz_table, fmt='%1.2f', delimiter=',') + +x_table = np.linspace(0.0, 0.0, 1) +np.savetxt('x.csv', x_table, fmt='%1.2f', delimiter=',') + +y_table = np.linspace(0.0, 0.0, 1) +np.savetxt('y.csv', x_table, fmt='%1.2f', delimiter=',') + +np.savetxt('z.csv', z_table, fmt='%1.2f', delimiter=',') diff --git a/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/pressure_field.png b/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/pressure_field.png new file mode 100644 index 00000000000..9145f77b897 Binary files /dev/null and b/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/pressure_field.png differ diff --git a/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/simulation_result_0.csv b/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/simulation_result_0.csv new file mode 100644 index 00000000000..837edf3cc67 --- /dev/null +++ b/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/simulation_result_0.csv @@ -0,0 +1,1002 @@ +"elementCenter:0","elementCenter:1","elementCenter:2","pressure","rockSolid_stress:0","rockSolid_stress:1","rockSolid_stress:2","rockSolid_stress:3","rockSolid_stress:4","rockSolid_stress:5","Points:0","Points:1","Points:2" +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-1000 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-999 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-998 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-997 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-996 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-995 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-994 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-993 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-992 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-991 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-990 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-989 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-988 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-987 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-986 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-985 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-984 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-983 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-982 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-981 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-980 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-979 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-978 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-977 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-976 +525,525,-987.5,9.875e+06,-6.8917e+06,-1.6767e+07,-1.3763e+07,2.231e-09,-1.1239e-09,4.8216e-09,500,500,-975 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-974 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-973 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-972 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-971 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-970 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-969 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-968 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-967 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-966 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-965 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-964 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-963 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-962 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-961 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-960 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-959 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-958 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-957 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-956 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-955 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-954 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-953 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-952 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-951 +525,525,-962.5,9.625e+06,-6.7171e+06,-1.6342e+07,-1.3414e+07,-1.4554e-08,4.3977e-09,4.9082e-09,500,500,-950 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-949 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-948 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-947 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-946 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-945 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-944 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-943 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-942 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-941 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-940 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-939 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-938 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-937 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-936 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-935 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-934 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-933 +525,525,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,8.0922e-09,2.9974e-08,5.203e-09,500,500,-932 +525,475,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,7.4834e-09,3.0448e-08,3.7313e-09,500,500,-931 +525,475,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,7.4834e-09,3.0448e-08,3.7313e-09,500,500,-930 +525,475,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,7.4834e-09,3.0448e-08,3.7313e-09,500,500,-929 +525,475,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,7.4834e-09,3.0448e-08,3.7313e-09,500,500,-928 +525,475,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,7.4834e-09,3.0448e-08,3.7313e-09,500,500,-927 +525,475,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,7.4834e-09,3.0448e-08,3.7313e-09,500,500,-926 +525,475,-937.5,9.375e+06,-6.5426e+06,-1.5918e+07,-1.3065e+07,7.4834e-09,3.0448e-08,3.7313e-09,500,500,-925 +525,475,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,2.3555e-09,4.198e-09,3.9418e-09,500,500,-924 +525,475,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,2.3555e-09,4.198e-09,3.9418e-09,500,500,-923 +525,475,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,2.3555e-09,4.198e-09,3.9418e-09,500,500,-922 +525,475,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,2.3555e-09,4.198e-09,3.9418e-09,500,500,-921 +525,475,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,2.3555e-09,4.198e-09,3.9418e-09,500,500,-920 +525,475,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,2.3555e-09,4.198e-09,3.9418e-09,500,500,-919 +525,475,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,2.3555e-09,4.198e-09,3.9418e-09,500,500,-918 +525,475,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,2.3555e-09,4.198e-09,3.9418e-09,500,500,-917 +525,475,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,2.3555e-09,4.198e-09,3.9418e-09,500,500,-916 +525,475,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,2.3555e-09,4.198e-09,3.9418e-09,500,500,-915 +525,475,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,2.3555e-09,4.198e-09,3.9418e-09,500,500,-914 +525,475,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,2.3555e-09,4.198e-09,3.9418e-09,500,500,-913 +525,475,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,2.3555e-09,4.198e-09,3.9418e-09,500,500,-912 +525,525,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,1.7691e-09,3.352e-09,5.2129e-09,500,500,-911 +525,525,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,1.7691e-09,3.352e-09,5.2129e-09,500,500,-910 +525,525,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,1.7691e-09,3.352e-09,5.2129e-09,500,500,-909 +525,525,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,1.7691e-09,3.352e-09,5.2129e-09,500,500,-908 +525,525,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,1.7691e-09,3.352e-09,5.2129e-09,500,500,-907 +525,525,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,1.7691e-09,3.352e-09,5.2129e-09,500,500,-906 +525,525,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,1.7691e-09,3.352e-09,5.2129e-09,500,500,-905 +525,525,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,1.7691e-09,3.352e-09,5.2129e-09,500,500,-904 +525,525,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,1.7691e-09,3.352e-09,5.2129e-09,500,500,-903 +525,525,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,1.7691e-09,3.352e-09,5.2129e-09,500,500,-902 +525,525,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,1.7691e-09,3.352e-09,5.2129e-09,500,500,-901 +525,525,-912.5,9.125e+06,-6.3681e+06,-1.5493e+07,-1.2717e+07,1.7691e-09,3.352e-09,5.2129e-09,500,500,-900 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-899 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-898 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-897 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-896 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-895 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-894 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-893 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-892 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-891 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-890 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-889 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-888 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-887 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-886 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-885 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-884 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-883 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-882 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-881 +525,525,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6027e-08,6.0936e-09,4.9075e-09,500,500,-880 +525,475,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6876e-08,6.3486e-09,3.6317e-09,500,500,-879 +525,475,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6876e-08,6.3486e-09,3.6317e-09,500,500,-878 +525,475,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6876e-08,6.3486e-09,3.6317e-09,500,500,-877 +525,475,-887.5,8.875e+06,-6.1935e+06,-1.5069e+07,-1.2368e+07,1.6876e-08,6.3486e-09,3.6317e-09,500,500,-876 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-875 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-874 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-873 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-872 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-871 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-870 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-869 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-868 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-867 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-866 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-865 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-864 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-863 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-862 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-861 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-860 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-859 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-858 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-857 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-856 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-855 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-854 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-853 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-852 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-851 +525,525,-862.5,8.625e+06,-6.019e+06,-1.4644e+07,-1.202e+07,-2.2885e-08,-2.095e-08,4.3994e-09,500,500,-850 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-849 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-848 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-847 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-846 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-845 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-844 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-843 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-842 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-841 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-840 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-839 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-838 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-837 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-836 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-835 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-834 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-833 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-832 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-831 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-830 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-829 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-828 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-827 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-826 +525,525,-837.5,8.375e+06,-5.8445e+06,-1.422e+07,-1.1671e+07,2.533e-10,-2.026e-09,3.9873e-09,500,500,-825 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-824 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-823 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-822 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-821 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-820 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-819 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-818 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-817 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-816 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-815 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-814 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-813 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-812 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-811 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-810 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-809 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-808 +525,525,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,1.4824e-09,1.3732e-09,3.8487e-09,500,500,-807 +525,475,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,2.5881e-09,1.2905e-09,3.5733e-09,500,500,-806 +525,475,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,2.5881e-09,1.2905e-09,3.5733e-09,500,500,-805 +525,475,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,2.5881e-09,1.2905e-09,3.5733e-09,500,500,-804 +525,475,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,2.5881e-09,1.2905e-09,3.5733e-09,500,500,-803 +525,475,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,2.5881e-09,1.2905e-09,3.5733e-09,500,500,-802 +525,475,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,2.5881e-09,1.2905e-09,3.5733e-09,500,500,-801 +525,475,-812.5,8.125e+06,-5.67e+06,-1.3795e+07,-1.1322e+07,2.5881e-09,1.2905e-09,3.5733e-09,500,500,-800 +525,475,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.2955e-09,1.8767e-08,3.2627e-09,500,500,-799 +525,475,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.2955e-09,1.8767e-08,3.2627e-09,500,500,-798 +525,475,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.2955e-09,1.8767e-08,3.2627e-09,500,500,-797 +525,475,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.2955e-09,1.8767e-08,3.2627e-09,500,500,-796 +525,475,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.2955e-09,1.8767e-08,3.2627e-09,500,500,-795 +525,475,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.2955e-09,1.8767e-08,3.2627e-09,500,500,-794 +525,475,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.2955e-09,1.8767e-08,3.2627e-09,500,500,-793 +525,475,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.2955e-09,1.8767e-08,3.2627e-09,500,500,-792 +525,475,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.2955e-09,1.8767e-08,3.2627e-09,500,500,-791 +525,475,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.2955e-09,1.8767e-08,3.2627e-09,500,500,-790 +525,475,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.2955e-09,1.8767e-08,3.2627e-09,500,500,-789 +525,475,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.2955e-09,1.8767e-08,3.2627e-09,500,500,-788 +525,475,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.2955e-09,1.8767e-08,3.2627e-09,500,500,-787 +525,525,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.1293e-09,1.8739e-08,3.8989e-09,500,500,-786 +525,525,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.1293e-09,1.8739e-08,3.8989e-09,500,500,-785 +525,525,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.1293e-09,1.8739e-08,3.8989e-09,500,500,-784 +525,525,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.1293e-09,1.8739e-08,3.8989e-09,500,500,-783 +525,525,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.1293e-09,1.8739e-08,3.8989e-09,500,500,-782 +525,525,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.1293e-09,1.8739e-08,3.8989e-09,500,500,-781 +525,525,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.1293e-09,1.8739e-08,3.8989e-09,500,500,-780 +525,525,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.1293e-09,1.8739e-08,3.8989e-09,500,500,-779 +525,525,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.1293e-09,1.8739e-08,3.8989e-09,500,500,-778 +525,525,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.1293e-09,1.8739e-08,3.8989e-09,500,500,-777 +525,525,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.1293e-09,1.8739e-08,3.8989e-09,500,500,-776 +525,525,-787.5,7.875e+06,-5.4955e+06,-1.337e+07,-1.0974e+07,9.1293e-09,1.8739e-08,3.8989e-09,500,500,-775 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-774 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-773 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-772 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-771 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-770 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-769 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-768 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-767 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-766 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-765 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-764 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-763 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-762 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-761 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-760 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-759 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-758 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-757 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-756 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-755 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-754 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-753 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-752 +525,525,-762.5,7.625e+06,-5.321e+06,-1.2946e+07,-1.0625e+07,-7.4289e-09,-7.4071e-09,3.9814e-09,500,500,-751 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-750 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-749 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-748 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-747 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-746 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-745 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-744 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-743 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-742 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-741 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-740 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-739 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-738 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-737 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-736 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-735 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-734 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-733 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-732 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-731 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-730 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-729 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-728 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-727 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-726 +525,525,-737.5,7.375e+06,-5.1465e+06,-1.2521e+07,-1.0277e+07,-5.2577e-09,-3.0772e-09,3.7433e-09,500,500,-725 +525,525,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2317e-08,6.709e-09,3.617e-09,500,500,-724 +525,525,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2317e-08,6.709e-09,3.617e-09,500,500,-723 +525,525,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2317e-08,6.709e-09,3.617e-09,500,500,-722 +525,525,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2317e-08,6.709e-09,3.617e-09,500,500,-721 +525,525,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2317e-08,6.709e-09,3.617e-09,500,500,-720 +525,525,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2317e-08,6.709e-09,3.617e-09,500,500,-719 +525,525,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2317e-08,6.709e-09,3.617e-09,500,500,-718 +525,525,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2317e-08,6.709e-09,3.617e-09,500,500,-717 +525,525,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2317e-08,6.709e-09,3.617e-09,500,500,-716 +525,525,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2317e-08,6.709e-09,3.617e-09,500,500,-715 +525,525,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2317e-08,6.709e-09,3.617e-09,500,500,-714 +525,525,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2317e-08,6.709e-09,3.617e-09,500,500,-713 +525,475,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2673e-08,8.1302e-09,2.7197e-09,500,500,-712 +525,475,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2673e-08,8.1302e-09,2.7197e-09,500,500,-711 +525,475,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2673e-08,8.1302e-09,2.7197e-09,500,500,-710 +525,475,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2673e-08,8.1302e-09,2.7197e-09,500,500,-709 +525,475,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2673e-08,8.1302e-09,2.7197e-09,500,500,-708 +525,475,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2673e-08,8.1302e-09,2.7197e-09,500,500,-707 +525,475,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2673e-08,8.1302e-09,2.7197e-09,500,500,-706 +525,475,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2673e-08,8.1302e-09,2.7197e-09,500,500,-705 +525,475,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2673e-08,8.1302e-09,2.7197e-09,500,500,-704 +525,475,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2673e-08,8.1302e-09,2.7197e-09,500,500,-703 +525,475,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2673e-08,8.1302e-09,2.7197e-09,500,500,-702 +525,475,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2673e-08,8.1302e-09,2.7197e-09,500,500,-701 +525,475,-712.5,7.125e+06,-4.9719e+06,-1.2097e+07,-9.9283e+06,-1.2673e-08,8.1302e-09,2.7197e-09,500,500,-700 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-699 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-698 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-697 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-696 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-695 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-694 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-693 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-692 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-691 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-690 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-689 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-688 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-687 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-686 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-685 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-684 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-683 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-682 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-681 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-680 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-679 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-678 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-677 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-676 +525,475,-687.5,6.875e+06,-4.7974e+06,-1.1672e+07,-9.5798e+06,-7.8735e-09,-2.8248e-09,2.8188e-09,500,500,-675 +525,475,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,3.2449e-09,7.996e-11,2.6142e-09,500,500,-674 +525,475,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,3.2449e-09,7.996e-11,2.6142e-09,500,500,-673 +525,475,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,3.2449e-09,7.996e-11,2.6142e-09,500,500,-672 +525,475,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,3.2449e-09,7.996e-11,2.6142e-09,500,500,-671 +525,475,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,3.2449e-09,7.996e-11,2.6142e-09,500,500,-670 +525,475,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,3.2449e-09,7.996e-11,2.6142e-09,500,500,-669 +525,475,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,3.2449e-09,7.996e-11,2.6142e-09,500,500,-668 +525,475,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,3.2449e-09,7.996e-11,2.6142e-09,500,500,-667 +525,475,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,3.2449e-09,7.996e-11,2.6142e-09,500,500,-666 +525,475,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,3.2449e-09,7.996e-11,2.6142e-09,500,500,-665 +525,475,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,3.2449e-09,7.996e-11,2.6142e-09,500,500,-664 +525,475,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,3.2449e-09,7.996e-11,2.6142e-09,500,500,-663 +525,475,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,3.2449e-09,7.996e-11,2.6142e-09,500,500,-662 +525,525,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,2.8008e-09,-1.5585e-11,3.0555e-09,500,500,-661 +525,525,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,2.8008e-09,-1.5585e-11,3.0555e-09,500,500,-660 +525,525,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,2.8008e-09,-1.5585e-11,3.0555e-09,500,500,-659 +525,525,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,2.8008e-09,-1.5585e-11,3.0555e-09,500,500,-658 +525,525,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,2.8008e-09,-1.5585e-11,3.0555e-09,500,500,-657 +525,525,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,2.8008e-09,-1.5585e-11,3.0555e-09,500,500,-656 +525,525,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,2.8008e-09,-1.5585e-11,3.0555e-09,500,500,-655 +525,525,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,2.8008e-09,-1.5585e-11,3.0555e-09,500,500,-654 +525,525,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,2.8008e-09,-1.5585e-11,3.0555e-09,500,500,-653 +525,525,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,2.8008e-09,-1.5585e-11,3.0555e-09,500,500,-652 +525,525,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,2.8008e-09,-1.5585e-11,3.0555e-09,500,500,-651 +525,525,-662.5,6.625e+06,-4.623e+06,-1.1248e+07,-9.2314e+06,2.8008e-09,-1.5585e-11,3.0555e-09,500,500,-650 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-649 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-648 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-647 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-646 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-645 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-644 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-643 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-642 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-641 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-640 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-639 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-638 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-637 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-636 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-635 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-634 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-633 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-632 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-631 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-630 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-629 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-628 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-627 +525,525,-637.5,6.375e+06,-4.4485e+06,-1.0823e+07,-8.8829e+06,8.6973e-09,1.137e-08,2.5422e-09,500,500,-626 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-625 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-624 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-623 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-622 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-621 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-620 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-619 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-618 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-617 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-616 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-615 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-614 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-613 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-612 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-611 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-610 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-609 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-608 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-607 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-606 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-605 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-604 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-603 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-602 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-601 +525,525,-612.5,6.125e+06,-4.274e+06,-1.0399e+07,-8.5344e+06,-7.1658e-09,1.2119e-09,2.4478e-09,500,500,-600 +525,525,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,5.7147e-09,5.744e-09,2.6549e-09,500,500,-599 +525,525,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,5.7147e-09,5.744e-09,2.6549e-09,500,500,-598 +525,525,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,5.7147e-09,5.744e-09,2.6549e-09,500,500,-597 +525,525,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,5.7147e-09,5.744e-09,2.6549e-09,500,500,-596 +525,525,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,5.7147e-09,5.744e-09,2.6549e-09,500,500,-595 +525,525,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,5.7147e-09,5.744e-09,2.6549e-09,500,500,-594 +525,525,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,5.7147e-09,5.744e-09,2.6549e-09,500,500,-593 +525,525,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,5.7147e-09,5.744e-09,2.6549e-09,500,500,-592 +525,525,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,5.7147e-09,5.744e-09,2.6549e-09,500,500,-591 +525,525,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,5.7147e-09,5.744e-09,2.6549e-09,500,500,-590 +525,525,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,5.7147e-09,5.744e-09,2.6549e-09,500,500,-589 +525,525,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,5.7147e-09,5.744e-09,2.6549e-09,500,500,-588 +525,475,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,6.0238e-09,5.5572e-09,1.1504e-09,500,500,-587 +525,475,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,6.0238e-09,5.5572e-09,1.1504e-09,500,500,-586 +525,475,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,6.0238e-09,5.5572e-09,1.1504e-09,500,500,-585 +525,475,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,6.0238e-09,5.5572e-09,1.1504e-09,500,500,-584 +525,475,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,6.0238e-09,5.5572e-09,1.1504e-09,500,500,-583 +525,475,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,6.0238e-09,5.5572e-09,1.1504e-09,500,500,-582 +525,475,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,6.0238e-09,5.5572e-09,1.1504e-09,500,500,-581 +525,475,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,6.0238e-09,5.5572e-09,1.1504e-09,500,500,-580 +525,475,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,6.0238e-09,5.5572e-09,1.1504e-09,500,500,-579 +525,475,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,6.0238e-09,5.5572e-09,1.1504e-09,500,500,-578 +525,475,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,6.0238e-09,5.5572e-09,1.1504e-09,500,500,-577 +525,475,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,6.0238e-09,5.5572e-09,1.1504e-09,500,500,-576 +525,475,-587.5,5.875e+06,-4.0995e+06,-9.9745e+06,-8.1859e+06,6.0238e-09,5.5572e-09,1.1504e-09,500,500,-575 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-574 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-573 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-572 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-571 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-570 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-569 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-568 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-567 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-566 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-565 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-564 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-563 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-562 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-561 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-560 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-559 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-558 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-557 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-556 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-555 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-554 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-553 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-552 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-551 +525,475,-562.5,5.625e+06,-3.925e+06,-9.55e+06,-7.8375e+06,5.6524e-09,-2.5183e-09,1.1073e-09,500,500,-550 +525,475,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2223e-09,-4.6824e-09,1.507e-09,500,500,-549 +525,475,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2223e-09,-4.6824e-09,1.507e-09,500,500,-548 +525,475,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2223e-09,-4.6824e-09,1.507e-09,500,500,-547 +525,475,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2223e-09,-4.6824e-09,1.507e-09,500,500,-546 +525,475,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2223e-09,-4.6824e-09,1.507e-09,500,500,-545 +525,475,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2223e-09,-4.6824e-09,1.507e-09,500,500,-544 +525,475,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2223e-09,-4.6824e-09,1.507e-09,500,500,-543 +525,475,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2223e-09,-4.6824e-09,1.507e-09,500,500,-542 +525,475,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2223e-09,-4.6824e-09,1.507e-09,500,500,-541 +525,475,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2223e-09,-4.6824e-09,1.507e-09,500,500,-540 +525,475,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2223e-09,-4.6824e-09,1.507e-09,500,500,-539 +525,475,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2223e-09,-4.6824e-09,1.507e-09,500,500,-538 +525,475,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2223e-09,-4.6824e-09,1.507e-09,500,500,-537 +525,525,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2087e-09,-4.6421e-09,2.4099e-09,500,500,-536 +525,525,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2087e-09,-4.6421e-09,2.4099e-09,500,500,-535 +525,525,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2087e-09,-4.6421e-09,2.4099e-09,500,500,-534 +525,525,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2087e-09,-4.6421e-09,2.4099e-09,500,500,-533 +525,525,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2087e-09,-4.6421e-09,2.4099e-09,500,500,-532 +525,525,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2087e-09,-4.6421e-09,2.4099e-09,500,500,-531 +525,525,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2087e-09,-4.6421e-09,2.4099e-09,500,500,-530 +525,525,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2087e-09,-4.6421e-09,2.4099e-09,500,500,-529 +525,525,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2087e-09,-4.6421e-09,2.4099e-09,500,500,-528 +525,525,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2087e-09,-4.6421e-09,2.4099e-09,500,500,-527 +525,525,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2087e-09,-4.6421e-09,2.4099e-09,500,500,-526 +525,525,-537.5,5.375e+06,-3.7505e+06,-9.1255e+06,-7.489e+06,2.2087e-09,-4.6421e-09,2.4099e-09,500,500,-525 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-524 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-523 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-522 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-521 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-520 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-519 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-518 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-517 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-516 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-515 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-514 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-513 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-512 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-511 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-510 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-509 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-508 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-507 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-506 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-505 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-504 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-503 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-502 +525,525,-512.5,5.125e+06,-3.576e+06,-8.701e+06,-7.1406e+06,4.5432e-09,1.9792e-09,2.5512e-09,500,500,-501 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-500 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-499 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-498 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-497 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-496 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-495 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-494 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-493 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-492 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-491 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-490 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-489 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-488 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-487 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-486 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-485 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-484 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-483 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-482 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-481 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-480 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-479 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-478 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-477 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-476 +525,525,-487.5,4.875e+06,-3.4016e+06,-8.2766e+06,-6.7922e+06,5.7245e-09,1.9448e-09,2.7185e-09,500,500,-475 +525,525,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.4137e-09,-2.4198e-09,2.5927e-09,500,500,-474 +525,525,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.4137e-09,-2.4198e-09,2.5927e-09,500,500,-473 +525,525,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.4137e-09,-2.4198e-09,2.5927e-09,500,500,-472 +525,525,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.4137e-09,-2.4198e-09,2.5927e-09,500,500,-471 +525,525,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.4137e-09,-2.4198e-09,2.5927e-09,500,500,-470 +525,525,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.4137e-09,-2.4198e-09,2.5927e-09,500,500,-469 +525,525,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.4137e-09,-2.4198e-09,2.5927e-09,500,500,-468 +525,525,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.4137e-09,-2.4198e-09,2.5927e-09,500,500,-467 +525,525,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.4137e-09,-2.4198e-09,2.5927e-09,500,500,-466 +525,525,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.4137e-09,-2.4198e-09,2.5927e-09,500,500,-465 +525,525,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.4137e-09,-2.4198e-09,2.5927e-09,500,500,-464 +525,525,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.4137e-09,-2.4198e-09,2.5927e-09,500,500,-463 +525,475,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.3894e-09,-2.4077e-09,1.2297e-09,500,500,-462 +525,475,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.3894e-09,-2.4077e-09,1.2297e-09,500,500,-461 +525,475,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.3894e-09,-2.4077e-09,1.2297e-09,500,500,-460 +525,475,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.3894e-09,-2.4077e-09,1.2297e-09,500,500,-459 +525,475,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.3894e-09,-2.4077e-09,1.2297e-09,500,500,-458 +525,475,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.3894e-09,-2.4077e-09,1.2297e-09,500,500,-457 +525,475,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.3894e-09,-2.4077e-09,1.2297e-09,500,500,-456 +525,475,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.3894e-09,-2.4077e-09,1.2297e-09,500,500,-455 +525,475,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.3894e-09,-2.4077e-09,1.2297e-09,500,500,-454 +525,475,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.3894e-09,-2.4077e-09,1.2297e-09,500,500,-453 +525,475,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.3894e-09,-2.4077e-09,1.2297e-09,500,500,-452 +525,475,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.3894e-09,-2.4077e-09,1.2297e-09,500,500,-451 +525,475,-462.5,4.625e+06,-3.2271e+06,-7.8521e+06,-6.4438e+06,2.3894e-09,-2.4077e-09,1.2297e-09,500,500,-450 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-449 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-448 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-447 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-446 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-445 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-444 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-443 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-442 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-441 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-440 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-439 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-438 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-437 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-436 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-435 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-434 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-433 +525,475,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,3.2504e-09,2.9329e-09,1.2885e-09,500,500,-432 +525,525,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,2.8413e-09,2.4755e-09,2.6738e-09,500,500,-431 +525,525,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,2.8413e-09,2.4755e-09,2.6738e-09,500,500,-430 +525,525,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,2.8413e-09,2.4755e-09,2.6738e-09,500,500,-429 +525,525,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,2.8413e-09,2.4755e-09,2.6738e-09,500,500,-428 +525,525,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,2.8413e-09,2.4755e-09,2.6738e-09,500,500,-427 +525,525,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,2.8413e-09,2.4755e-09,2.6738e-09,500,500,-426 +525,525,-437.5,4.375e+06,-3.0526e+06,-7.4276e+06,-6.0954e+06,2.8413e-09,2.4755e-09,2.6738e-09,500,500,-425 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-424 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-423 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-422 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-421 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-420 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-419 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-418 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-417 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-416 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-415 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-414 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-413 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-412 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-411 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-410 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-409 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-408 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-407 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-406 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-405 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-404 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-403 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-402 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-401 +525,525,-412.5,4.125e+06,-2.8782e+06,-7.0032e+06,-5.747e+06,-4.8032e-09,1.1377e-09,2.5232e-09,500,500,-400 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-399 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-398 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-397 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-396 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-395 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-394 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-393 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-392 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-391 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-390 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-389 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-388 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-387 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-386 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-385 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-384 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-383 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-382 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-381 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-380 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-379 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-378 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-377 +525,525,-387.5,3.875e+06,-2.7037e+06,-6.5787e+06,-5.3986e+06,4.6369e-09,-3.2797e-11,2.1925e-09,500,500,-376 +525,525,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,9.6765e-10,1.6844e-09,1.9055e-09,500,500,-375 +525,525,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,9.6765e-10,1.6844e-09,1.9055e-09,500,500,-374 +525,525,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,9.6765e-10,1.6844e-09,1.9055e-09,500,500,-373 +525,525,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,9.6765e-10,1.6844e-09,1.9055e-09,500,500,-372 +525,525,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,9.6765e-10,1.6844e-09,1.9055e-09,500,500,-371 +525,525,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,9.6765e-10,1.6844e-09,1.9055e-09,500,500,-370 +525,525,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,9.6765e-10,1.6844e-09,1.9055e-09,500,500,-369 +525,525,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,9.6765e-10,1.6844e-09,1.9055e-09,500,500,-368 +525,525,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,9.6765e-10,1.6844e-09,1.9055e-09,500,500,-367 +525,525,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,9.6765e-10,1.6844e-09,1.9055e-09,500,500,-366 +525,525,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,9.6765e-10,1.6844e-09,1.9055e-09,500,500,-365 +525,525,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,9.6765e-10,1.6844e-09,1.9055e-09,500,500,-364 +525,525,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,9.6765e-10,1.6844e-09,1.9055e-09,500,500,-363 +525,525,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,9.6765e-10,1.6844e-09,1.9055e-09,500,500,-362 +525,525,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,9.6765e-10,1.6844e-09,1.9055e-09,500,500,-361 +525,475,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,1.1919e-09,1.9178e-09,1.1725e-09,500,500,-360 +525,475,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,1.1919e-09,1.9178e-09,1.1725e-09,500,500,-359 +525,475,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,1.1919e-09,1.9178e-09,1.1725e-09,500,500,-358 +525,475,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,1.1919e-09,1.9178e-09,1.1725e-09,500,500,-357 +525,475,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,1.1919e-09,1.9178e-09,1.1725e-09,500,500,-356 +525,475,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,1.1919e-09,1.9178e-09,1.1725e-09,500,500,-355 +525,475,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,1.1919e-09,1.9178e-09,1.1725e-09,500,500,-354 +525,475,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,1.1919e-09,1.9178e-09,1.1725e-09,500,500,-353 +525,475,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,1.1919e-09,1.9178e-09,1.1725e-09,500,500,-352 +525,475,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,1.1919e-09,1.9178e-09,1.1725e-09,500,500,-351 +525,475,-362.5,3.625e+06,-2.5292e+06,-6.1542e+06,-5.0502e+06,1.1919e-09,1.9178e-09,1.1725e-09,500,500,-350 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-349 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-348 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-347 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-346 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-345 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-344 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-343 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-342 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-341 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-340 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-339 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-338 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-337 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-336 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-335 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-334 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-333 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-332 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-331 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-330 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-329 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-328 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-327 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-326 +525,475,-337.5,3.375e+06,-2.3548e+06,-5.7298e+06,-4.7019e+06,2.6102e-10,-4.9738e-10,1.173e-09,500,500,-325 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-324 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-323 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-322 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-321 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-320 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-319 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-318 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-317 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-316 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-315 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-314 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-313 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-312 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-311 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-310 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-309 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-308 +525,475,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,2.0344e-09,3.0247e-09,1.2099e-09,500,500,-307 +525,525,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,1.5852e-09,2.9935e-09,1.6606e-09,500,500,-306 +525,525,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,1.5852e-09,2.9935e-09,1.6606e-09,500,500,-305 +525,525,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,1.5852e-09,2.9935e-09,1.6606e-09,500,500,-304 +525,525,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,1.5852e-09,2.9935e-09,1.6606e-09,500,500,-303 +525,525,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,1.5852e-09,2.9935e-09,1.6606e-09,500,500,-302 +525,525,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,1.5852e-09,2.9935e-09,1.6606e-09,500,500,-301 +525,525,-312.5,3.125e+06,-2.1803e+06,-5.3053e+06,-4.3535e+06,1.5852e-09,2.9935e-09,1.6606e-09,500,500,-300 +525,525,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,2.5181e-10,2.8519e-09,1.5497e-09,500,500,-299 +525,525,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,2.5181e-10,2.8519e-09,1.5497e-09,500,500,-298 +525,525,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,2.5181e-10,2.8519e-09,1.5497e-09,500,500,-297 +525,525,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,2.5181e-10,2.8519e-09,1.5497e-09,500,500,-296 +525,525,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,2.5181e-10,2.8519e-09,1.5497e-09,500,500,-295 +525,525,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,2.5181e-10,2.8519e-09,1.5497e-09,500,500,-294 +525,525,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,2.5181e-10,2.8519e-09,1.5497e-09,500,500,-293 +525,525,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,2.5181e-10,2.8519e-09,1.5497e-09,500,500,-292 +525,525,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,2.5181e-10,2.8519e-09,1.5497e-09,500,500,-291 +525,525,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,2.5181e-10,2.8519e-09,1.5497e-09,500,500,-290 +525,525,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,2.5181e-10,2.8519e-09,1.5497e-09,500,500,-289 +525,525,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,2.5181e-10,2.8519e-09,1.5497e-09,500,500,-288 +525,525,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,2.5181e-10,2.8519e-09,1.5497e-09,500,500,-287 +525,475,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,9.0531e-10,2.5587e-09,1.1061e-09,500,500,-286 +525,475,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,9.0531e-10,2.5587e-09,1.1061e-09,500,500,-285 +525,475,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,9.0531e-10,2.5587e-09,1.1061e-09,500,500,-284 +525,475,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,9.0531e-10,2.5587e-09,1.1061e-09,500,500,-283 +525,475,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,9.0531e-10,2.5587e-09,1.1061e-09,500,500,-282 +525,475,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,9.0531e-10,2.5587e-09,1.1061e-09,500,500,-281 +525,475,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,9.0531e-10,2.5587e-09,1.1061e-09,500,500,-280 +525,475,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,9.0531e-10,2.5587e-09,1.1061e-09,500,500,-279 +525,475,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,9.0531e-10,2.5587e-09,1.1061e-09,500,500,-278 +525,475,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,9.0531e-10,2.5587e-09,1.1061e-09,500,500,-277 +525,475,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,9.0531e-10,2.5587e-09,1.1061e-09,500,500,-276 +525,475,-287.5,2.875e+06,-2.0059e+06,-4.8809e+06,-4.0052e+06,9.0531e-10,2.5587e-09,1.1061e-09,500,500,-275 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-274 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-273 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-272 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-271 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-270 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-269 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-268 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-267 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-266 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-265 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-264 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-263 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-262 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-261 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-260 +525,475,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.7614e-09,1.7419e-09,1.03e-09,500,500,-259 +525,525,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.6197e-09,2.0688e-09,1.59e-09,500,500,-258 +525,525,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.6197e-09,2.0688e-09,1.59e-09,500,500,-257 +525,525,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.6197e-09,2.0688e-09,1.59e-09,500,500,-256 +525,525,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.6197e-09,2.0688e-09,1.59e-09,500,500,-255 +525,525,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.6197e-09,2.0688e-09,1.59e-09,500,500,-254 +525,525,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.6197e-09,2.0688e-09,1.59e-09,500,500,-253 +525,525,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.6197e-09,2.0688e-09,1.59e-09,500,500,-252 +525,525,-262.5,2.625e+06,-1.8315e+06,-4.4565e+06,-3.6569e+06,1.6197e-09,2.0688e-09,1.59e-09,500,500,-251 +525,525,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.7162e-09,1.1193e-09,1.3168e-09,500,500,-250 +525,525,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.7162e-09,1.1193e-09,1.3168e-09,500,500,-249 +525,525,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.7162e-09,1.1193e-09,1.3168e-09,500,500,-248 +525,525,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.7162e-09,1.1193e-09,1.3168e-09,500,500,-247 +525,525,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.7162e-09,1.1193e-09,1.3168e-09,500,500,-246 +525,525,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.7162e-09,1.1193e-09,1.3168e-09,500,500,-245 +525,525,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.7162e-09,1.1193e-09,1.3168e-09,500,500,-244 +525,525,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.7162e-09,1.1193e-09,1.3168e-09,500,500,-243 +525,525,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.7162e-09,1.1193e-09,1.3168e-09,500,500,-242 +525,525,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.7162e-09,1.1193e-09,1.3168e-09,500,500,-241 +525,525,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.7162e-09,1.1193e-09,1.3168e-09,500,500,-240 +525,525,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.7162e-09,1.1193e-09,1.3168e-09,500,500,-239 +525,525,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.7162e-09,1.1193e-09,1.3168e-09,500,500,-238 +525,525,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.7162e-09,1.1193e-09,1.3168e-09,500,500,-237 +525,525,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.7162e-09,1.1193e-09,1.3168e-09,500,500,-236 +525,475,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.6792e-09,7.0582e-10,8.0772e-10,500,500,-235 +525,475,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.6792e-09,7.0582e-10,8.0772e-10,500,500,-234 +525,475,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.6792e-09,7.0582e-10,8.0772e-10,500,500,-233 +525,475,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.6792e-09,7.0582e-10,8.0772e-10,500,500,-232 +525,475,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.6792e-09,7.0582e-10,8.0772e-10,500,500,-231 +525,475,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.6792e-09,7.0582e-10,8.0772e-10,500,500,-230 +525,475,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.6792e-09,7.0582e-10,8.0772e-10,500,500,-229 +525,475,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.6792e-09,7.0582e-10,8.0772e-10,500,500,-228 +525,475,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.6792e-09,7.0582e-10,8.0772e-10,500,500,-227 +525,475,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.6792e-09,7.0582e-10,8.0772e-10,500,500,-226 +525,475,-237.5,2.375e+06,-1.657e+06,-4.032e+06,-3.3085e+06,1.6792e-09,7.0582e-10,8.0772e-10,500,500,-225 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-224 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-223 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-222 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-221 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-220 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-219 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-218 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-217 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-216 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-215 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-214 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-213 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-212 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-211 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-210 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-209 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-208 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-207 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-206 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-205 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-204 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-203 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-202 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-201 +525,475,-212.5,2.125e+06,-1.4826e+06,-3.6076e+06,-2.9602e+06,3.0572e-09,1.9361e-09,6.0434e-10,500,500,-200 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-199 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-198 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-197 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-196 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-195 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-194 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-193 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-192 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-191 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-190 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-189 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-188 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-187 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-186 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-185 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-184 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-183 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-182 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-181 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-180 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-179 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-178 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-177 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-176 +525,475,-187.5,1.875e+06,-1.3081e+06,-3.1831e+06,-2.6119e+06,3.0927e-10,9.9923e-10,4.4779e-10,500,500,-175 +525,475,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,5.9889e-10,5.2977e-10,3.3278e-10,500,500,-174 +525,475,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,5.9889e-10,5.2977e-10,3.3278e-10,500,500,-173 +525,475,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,5.9889e-10,5.2977e-10,3.3278e-10,500,500,-172 +525,475,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,5.9889e-10,5.2977e-10,3.3278e-10,500,500,-171 +525,475,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,5.9889e-10,5.2977e-10,3.3278e-10,500,500,-170 +525,475,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,5.9889e-10,5.2977e-10,3.3278e-10,500,500,-169 +525,475,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,5.9889e-10,5.2977e-10,3.3278e-10,500,500,-168 +525,475,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,5.9889e-10,5.2977e-10,3.3278e-10,500,500,-167 +525,475,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,5.9889e-10,5.2977e-10,3.3278e-10,500,500,-166 +525,475,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,5.9889e-10,5.2977e-10,3.3278e-10,500,500,-165 +525,475,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,5.9889e-10,5.2977e-10,3.3278e-10,500,500,-164 +525,475,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,5.9889e-10,5.2977e-10,3.3278e-10,500,500,-163 +525,475,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,5.9889e-10,5.2977e-10,3.3278e-10,500,500,-162 +525,525,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,7.1002e-10,8.5869e-10,7.5644e-10,500,500,-161 +525,525,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,7.1002e-10,8.5869e-10,7.5644e-10,500,500,-160 +525,525,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,7.1002e-10,8.5869e-10,7.5644e-10,500,500,-159 +525,525,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,7.1002e-10,8.5869e-10,7.5644e-10,500,500,-158 +525,525,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,7.1002e-10,8.5869e-10,7.5644e-10,500,500,-157 +525,525,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,7.1002e-10,8.5869e-10,7.5644e-10,500,500,-156 +525,525,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,7.1002e-10,8.5869e-10,7.5644e-10,500,500,-155 +525,525,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,7.1002e-10,8.5869e-10,7.5644e-10,500,500,-154 +525,525,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,7.1002e-10,8.5869e-10,7.5644e-10,500,500,-153 +525,525,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,7.1002e-10,8.5869e-10,7.5644e-10,500,500,-152 +525,525,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,7.1002e-10,8.5869e-10,7.5644e-10,500,500,-151 +525,525,-162.5,1.625e+06,-1.1337e+06,-2.7587e+06,-2.2636e+06,7.1002e-10,8.5869e-10,7.5644e-10,500,500,-150 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-149 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-148 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-147 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-146 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-145 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-144 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-143 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-142 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-141 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-140 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-139 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-138 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-137 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-136 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-135 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-134 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-133 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-132 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-131 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-130 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-129 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-128 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-127 +525,525,-137.5,1.375e+06,-9.5929e+05,-2.3343e+06,-1.9154e+06,1.4539e-09,1.0711e-09,5.463e-10,500,500,-126 +525,525,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,1.0895e-09,6.821e-10,3.7359e-10,500,500,-125 +525,525,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,1.0895e-09,6.821e-10,3.7359e-10,500,500,-124 +525,525,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,1.0895e-09,6.821e-10,3.7359e-10,500,500,-123 +525,525,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,1.0895e-09,6.821e-10,3.7359e-10,500,500,-122 +525,525,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,1.0895e-09,6.821e-10,3.7359e-10,500,500,-121 +525,525,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,1.0895e-09,6.821e-10,3.7359e-10,500,500,-120 +525,525,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,1.0895e-09,6.821e-10,3.7359e-10,500,500,-119 +525,525,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,1.0895e-09,6.821e-10,3.7359e-10,500,500,-118 +525,525,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,1.0895e-09,6.821e-10,3.7359e-10,500,500,-117 +525,525,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,1.0895e-09,6.821e-10,3.7359e-10,500,500,-116 +525,525,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,1.0895e-09,6.821e-10,3.7359e-10,500,500,-115 +525,525,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,1.0895e-09,6.821e-10,3.7359e-10,500,500,-114 +525,525,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,1.0895e-09,6.821e-10,3.7359e-10,500,500,-113 +525,525,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,1.0895e-09,6.821e-10,3.7359e-10,500,500,-112 +525,525,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,1.0895e-09,6.821e-10,3.7359e-10,500,500,-111 +525,475,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,9.0843e-10,4.9507e-10,1.8174e-10,500,500,-110 +525,475,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,9.0843e-10,4.9507e-10,1.8174e-10,500,500,-109 +525,475,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,9.0843e-10,4.9507e-10,1.8174e-10,500,500,-108 +525,475,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,9.0843e-10,4.9507e-10,1.8174e-10,500,500,-107 +525,475,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,9.0843e-10,4.9507e-10,1.8174e-10,500,500,-106 +525,475,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,9.0843e-10,4.9507e-10,1.8174e-10,500,500,-105 +525,475,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,9.0843e-10,4.9507e-10,1.8174e-10,500,500,-104 +525,475,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,9.0843e-10,4.9507e-10,1.8174e-10,500,500,-103 +525,475,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,9.0843e-10,4.9507e-10,1.8174e-10,500,500,-102 +525,475,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,9.0843e-10,4.9507e-10,1.8174e-10,500,500,-101 +525,475,-112.5,1.125e+06,-7.8486e+05,-1.9099e+06,-1.5671e+06,9.0843e-10,4.9507e-10,1.8174e-10,500,500,-100 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-99 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-98 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-97 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-96 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-95 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-94 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-93 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-92 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-91 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-90 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-89 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-88 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-87 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-86 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-85 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-84 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-83 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-82 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-81 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-80 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-79 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-78 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-77 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-76 +525,475,-87.5,8.75e+05,-6.1044e+05,-1.4854e+06,-1.2188e+06,1.0079e-09,4.7515e-10,1.6434e-10,500,500,-75 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-74 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-73 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-72 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-71 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-70 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-69 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-68 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-67 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-66 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-65 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-64 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-63 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-62 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-61 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-60 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-59 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-58 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-57 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-56 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-55 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-54 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-53 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-52 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-51 +525,475,-62.5,6.25e+05,-4.3603e+05,-1.061e+06,-8.7058e+05,7.3943e-10,3.2228e-10,1.1758e-10,500,500,-50 +525,475,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.9873e-10,2.556e-10,9.2379e-12,500,500,-49 +525,475,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.9873e-10,2.556e-10,9.2379e-12,500,500,-48 +525,475,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.9873e-10,2.556e-10,9.2379e-12,500,500,-47 +525,475,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.9873e-10,2.556e-10,9.2379e-12,500,500,-46 +525,475,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.9873e-10,2.556e-10,9.2379e-12,500,500,-45 +525,475,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.9873e-10,2.556e-10,9.2379e-12,500,500,-44 +525,475,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.9873e-10,2.556e-10,9.2379e-12,500,500,-43 +525,475,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.9873e-10,2.556e-10,9.2379e-12,500,500,-42 +525,475,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.9873e-10,2.556e-10,9.2379e-12,500,500,-41 +525,475,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.9873e-10,2.556e-10,9.2379e-12,500,500,-40 +525,475,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.9873e-10,2.556e-10,9.2379e-12,500,500,-39 +525,475,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.9873e-10,2.556e-10,9.2379e-12,500,500,-38 +525,475,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.9873e-10,2.556e-10,9.2379e-12,500,500,-37 +525,475,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.9873e-10,2.556e-10,9.2379e-12,500,500,-36 +525,525,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.3531e-10,3.5968e-10,1.4975e-10,500,500,-35 +525,525,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.3531e-10,3.5968e-10,1.4975e-10,500,500,-34 +525,525,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.3531e-10,3.5968e-10,1.4975e-10,500,500,-33 +525,525,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.3531e-10,3.5968e-10,1.4975e-10,500,500,-32 +525,525,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.3531e-10,3.5968e-10,1.4975e-10,500,500,-31 +525,525,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.3531e-10,3.5968e-10,1.4975e-10,500,500,-30 +525,525,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.3531e-10,3.5968e-10,1.4975e-10,500,500,-29 +525,525,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.3531e-10,3.5968e-10,1.4975e-10,500,500,-28 +525,525,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.3531e-10,3.5968e-10,1.4975e-10,500,500,-27 +525,525,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.3531e-10,3.5968e-10,1.4975e-10,500,500,-26 +525,525,-37.5,3.75e+05,-2.6161e+05,-6.3661e+05,-5.2234e+05,4.3531e-10,3.5968e-10,1.4975e-10,500,500,-25 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-24 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-23 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-22 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-21 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-20 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-19 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-18 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-17 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-16 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-15 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-14 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-13 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-12 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-11 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-10 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-9 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-8 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-7 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-6 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-5 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-4 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-3 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-2 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,-1 +525,525,-12.5,1.25e+05,-87204,-2.122e+05,-1.7411e+05,9.3783e-11,1.7537e-10,1.3591e-10,500,500,0 diff --git a/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/stressZZ_field.png b/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/stressZZ_field.png new file mode 100644 index 00000000000..8c02e28c428 Binary files /dev/null and b/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/stressZZ_field.png differ diff --git a/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/tableInitializationFigure.py b/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/tableInitializationFigure.py new file mode 100644 index 00000000000..6dbd1fa0e30 --- /dev/null +++ b/src/coreComponents/physicsSolvers/multiphysics/docs/userTableStressInitialization/tableInitializationFigure.py @@ -0,0 +1,168 @@ +import matplotlib +import matplotlib.pyplot as plt +import numpy as np +import h5py +import xml.etree.ElementTree as ElementTree +from mpmath import * +import math +from math import sin,cos,tan,exp,atan,asin +import csv +import os +import argparse + +def getHydromechanicalParametersFromXML(xmlFilePath): + tree = ElementTree.parse(xmlFilePath) + + param1 = tree.find('Constitutive/ElasticIsotropic') + param2 = tree.find('Constitutive/BiotPorosity') + param3 = tree.find('Constitutive/CompressibleSinglePhaseFluid') + + hydromechanicalParameters = dict.fromkeys([ + "bulkModulus", "shearModulus", "youngModulus", "poissonRatio", "rockDensity", "poissonRatio", "biotCoefficient", "porosity", "fluidDensity", "traction"]) + + hydromechanicalParameters["rockDensity"] = float(param1.get("defaultDensity")) + hydromechanicalParameters["poissonRatio"] = float(param1.get("defaultPoissonRatio")) + hydromechanicalParameters["youngModulus"] = float(param1.get("defaultYoungModulus")) + + E = hydromechanicalParameters["youngModulus"] + nu = hydromechanicalParameters["poissonRatio"] + K = E / (3 * (1 - 2 * nu)) + G = E / (2 * (1 + nu)) + + hydromechanicalParameters["poissonRatio"] = nu + hydromechanicalParameters["bulkModulus"] = K + hydromechanicalParameters["shearModulus"] = G + + Ks = float(param2.get("defaultGrainBulkModulus")) + hydromechanicalParameters["biotCoefficient"] = 1.0 - K / Ks + + hydromechanicalParameters["porosity"] = float(param2.get("defaultReferencePorosity")) + + hydromechanicalParameters["fluidDensity"] = float(param3.get("defaultDensity")) + + param4 = tree.findall('FieldSpecifications/Traction') + found_stress = False + for elem in param4: + if elem.get("name") == "tractionTop" and elem.get("tractionType") == "normal": + traction = float(elem.get("scale")) * (-1) + found_stress = True + if found_stress: break + + return hydromechanicalParameters + +def inputStressGradientsMPa(stressXX=None, stressYY=None, stressZZ=None,porePressure=None): + stress_gradients = { + 'stressXX': stressXX, + 'stressYY': stressYY, + 'stressZZ': stressZZ, + 'porePressure': porePressure + } + return stress_gradients + +def main(): + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + + # File path + outputDir = args.outputDir + geosDir = args.geosDir + xmlFile1Path = geosDir + "/inputFiles/initialization/userdefinedStress_initialization_base.xml" + xmlFile2Path = geosDir + "/inputFiles/initialization/userdefinedStress_initialization_benchmark.xml" + + + hydromechanicalParameters = getHydromechanicalParametersFromXML(xmlFile1Path) + stress_gradients = inputStressGradientsMPa(0.17,0.27,0.24,0.1) + sxx_grad = stress_gradients["stressXX"] + syy_grad = stress_gradients["stressYY"] + szz_grad = stress_gradients["stressZZ"] + pp_grad = stress_gradients["porePressure"] + BiotCoefficient = hydromechanicalParameters["biotCoefficient"] + nu = hydromechanicalParameters["poissonRatio"] + rhoF = hydromechanicalParameters["fluidDensity"] + rhoR = hydromechanicalParameters["rockDensity"] + phi = hydromechanicalParameters["porosity"] + rhoB = (1-phi)*rhoR + phi*rhoF + + traction = hydromechanicalParameters["traction"] + gravity = 9.81 + + # rename this file to the name of your Paraview output file + file = open(outputDir + "/simulation_result_0.csv") + csvreader = csv.reader(file) + header = next(csvreader) + header_index = {column_name: index for index, column_name in enumerate(header)} + + rows = [] + for row in csvreader: + rows.append(row) + file.close() + + zloc_index = header_index["elementCenter:2"] + pressure_index = header_index["pressure"] + tsxx_index = header_index["rockSolid_stress:0"] # the solidModelName="rockSolid" has been defined in the gravityInducedStress_initialization_base.xml file, please change if you have a different solidModelName + tsyy_index = header_index["rockSolid_stress:1"] + tszz_index = header_index["rockSolid_stress:2"] + + + rows = np.array(rows) + zloc_0 = np.empty(len(rows[:,1])) + pressure_0 = np.empty(len(rows[:,1])) + tsxx_0 = np.empty(len(rows[:,1])) + tsyy_0 = np.empty(len(rows[:,1])) + tszz_0 = np.empty(len(rows[:,1])) + for i in range(0,len(rows[:,1])): + zloc_0[i]=-(float(rows[i,zloc_index])) + pressure_0[i]=float(rows[i,pressure_index]) + tsxx_0[i]=-(float(rows[i,tsxx_index])-BiotCoefficient*pressure_0[i])/1.0e6 + tsyy_0[i]=-(float(rows[i,tsyy_index])-BiotCoefficient*pressure_0[i])/1.0e6 + tszz_0[i]=-(float(rows[i,tszz_index])-BiotCoefficient*pressure_0[i])/1.0e6 + + + z_analytical= np.linspace(0, 1000, 100) + + pp_analytical= pp_grad*100000*z_analytical/1.0e6 + szz_analtyical= szz_grad*100000*z_analytical/1.0e6 + sxx_analtyical = sxx_grad*100000*z_analytical/1.0e6 + syy_analtyical = syy_grad*100000*z_analytical/1.0e6 + + fsize = 20 + msize = 12 + lw = 6 + mew = 2 + malpha = 0.6 + lalpha = 0.8 + N1=1 + + fig = plt.figure(figsize=(10,8)) + cmap = plt.get_cmap("tab10") + + + plt.plot(tsxx_0[::N1], zloc_0[::N1], 'o', color=cmap(0), markersize=msize, alpha=malpha, mec=cmap(0), fillstyle='none', mew=mew, label= 'Sxx_Total_GEOS') + plt.plot(sxx_analtyical, z_analytical, lw=lw, alpha=0.8, color='b', linestyle= ':', label='Sxx_Total_Reference') + plt.plot(tsyy_0[::N1], zloc_0[::N1], 's', color=cmap(1), markersize=msize, alpha=malpha, mec=cmap(1), fillstyle='none', mew=mew, label= 'Syy_Total_GEOS') + plt.plot(syy_analtyical, z_analytical, lw=lw, alpha=0.8, color='orange', linestyle= ':', label='Syy_Total_Reference') + plt.plot(tszz_0[::N1], zloc_0[::N1], 'd', color=cmap(2), markersize=msize, alpha=malpha, mec=cmap(2), fillstyle='none', mew=mew, label= 'Szz_Total_GEOS') + plt.plot(szz_analtyical, z_analytical, lw=lw, alpha=0.8, color='y', linestyle= ':', label='Szz_Total_Reference') + plt.plot(pressure_0[::N1]/1.0e6, zloc_0[::N1], 'x', color=cmap(3), markersize=msize, alpha=malpha, mec=cmap(3), fillstyle='none', mew=mew, label= 'Pore Pressure_GEOS') + plt.plot(pp_analytical, z_analytical, lw=lw, alpha=0.8, color='r', linestyle= ':', label='Pore Pressure_Reference') + plt.xlabel('Total Stresses [MPa]', size=fsize, weight="bold") + plt.ylabel('Depth [m]', size=fsize, weight="bold") + plt.legend(loc='upper right',fontsize=fsize*0.5) + plt.grid(True) + ax = plt.gca() + ax.xaxis.set_tick_params(labelsize=fsize) + ax.yaxis.set_tick_params(labelsize=fsize) + ax.invert_yaxis() + + plt.show() + +if __name__ == "__main__": + main() diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/MultiphasePoromechanics.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/MultiphasePoromechanics.hpp index 0367fb42b67..ae031f13988 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/MultiphasePoromechanics.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/MultiphasePoromechanics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,10 +20,10 @@ #ifndef GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_MULTIPHASEPOROMECHANICS_HPP_ #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_MULTIPHASEPOROMECHANICS_HPP_ -#include "codingUtilities/Utilities.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" -#include "physicsSolvers/multiphysics/PoromechanicsFields.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsBase.hpp" +#include "physicsSolvers/multiphysics/PoromechanicsFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "codingUtilities/Utilities.hpp" namespace geos { @@ -102,6 +103,7 @@ class MultiphasePoromechanics : localIndex const numPhases, integer const useSimpleAccumulation, integer const useTotalMassEquation, + integer const performStressInitialization, string const fluidModelKey ); //***************************************************************************** @@ -340,8 +342,10 @@ class MultiphasePoromechanics : arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dGlobalCompFraction_dGlobalCompDensity; // Views on component densities + bool m_useMass; arrayView2d< real64 const, compflow::USD_COMP > m_compDens; arrayView2d< real64 const, compflow::USD_COMP > m_compDens_n; + arrayView1d< real64 const > m_componentMolarWeight; /// Number of components localIndex const m_numComponents; @@ -354,6 +358,8 @@ class MultiphasePoromechanics : /// Use total mass equation flag integer const m_useTotalMassEquation; + + integer const m_performStressInitialization; }; using MultiphasePoromechanicsKernelFactory = @@ -369,6 +375,7 @@ using MultiphasePoromechanicsKernelFactory = localIndex const, integer const, integer const, + integer const, string const >; /** @@ -381,20 +388,21 @@ class MultiphaseBulkDensityKernel /** * @brief Constructor - * @param[in] numPhases the number of fluid phases + * @param[in] numComponents the number of fluid components (species) * @param[in] fluid the fluid model * @param[in] solid the porous solid model * @param[in] subRegion the element subregion */ - MultiphaseBulkDensityKernel( integer const numPhases, + MultiphaseBulkDensityKernel( integer const numComponents, constitutive::MultiFluidBase const & fluid, constitutive::CoupledSolidBase const & solid, ElementSubRegionBase & subRegion ) - : m_numPhases( numPhases ), + : m_numComponents( numComponents ), m_bulkDensity( subRegion.getField< fields::poromechanics::bulkDensity >() ), - m_fluidPhaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), + m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ), + m_useMass( fluid.getMassFlag()), m_rockDensity( solid.getDensity() ), - m_fluidPhaseDensity( fluid.phaseMassDensity() ), + m_componentMolarWeight( fluid.componentMolarWeights() ), m_porosity( solid.getPorosity() ) {} @@ -408,12 +416,12 @@ class MultiphaseBulkDensityKernel localIndex const q ) const { m_bulkDensity[ei][q] = 0.0; - for( integer ip = 0; ip < m_numPhases; ++ip ) + for( integer ic = 0; ic < m_numComponents; ++ic ) { - m_bulkDensity[ei][q] += m_fluidPhaseVolFrac[ei][ip] * m_fluidPhaseDensity[ei][q][ip]; + m_bulkDensity[ei][q] = m_bulkDensity[ei][q] + ( m_useMass ? m_compDens[ei][ic] : m_compDens[ei][ic] * m_componentMolarWeight[ic] ); } m_bulkDensity[ei][q] *= m_porosity[ei][q]; - m_bulkDensity[ei][q] += ( 1 - m_porosity[ei][q] ) * m_rockDensity[ei][q]; + m_bulkDensity[ei][q] = m_bulkDensity[ei][q] + ( 1 - m_porosity[ei][q] ) * m_rockDensity[ei][q]; } /** @@ -441,20 +449,23 @@ class MultiphaseBulkDensityKernel protected: - // number of fluid phases - integer const m_numPhases; + // number of fluid components (species) + integer const m_numComponents; // the bulk density arrayView2d< real64 > const m_bulkDensity; - // the fluid phase saturation - arrayView2d< real64 const, compflow::USD_PHASE > const m_fluidPhaseVolFrac; + // the fluid component densities + arrayView2d< real64 const, compflow::USD_PHASE > const m_compDens; + + // the flag for selecting mass formulation instead of molar formulation + bool m_useMass; // the rock density arrayView2d< real64 const > const m_rockDensity; - // the fluid density - arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const m_fluidPhaseDensity; + // the molar component weights + arrayView1d< real64 const > m_componentMolarWeight; // the porosity arrayView2d< real64 const > const m_porosity; @@ -471,19 +482,19 @@ class MultiphaseBulkDensityKernelFactory /** * @brief Create a new kernel and launch * @tparam POLICY the policy used in the RAJA kernel - * @param[in] numPhases number of phases + * @param[in] numComponents number of phases components (species) * @param[in] fluid the fluid model * @param[in] solid the porous solid model * @param[in] subRegion the element subregion */ template< typename POLICY > static void - createAndLaunch( integer const numPhases, + createAndLaunch( integer const numComponents, constitutive::MultiFluidBase const & fluid, constitutive::CoupledSolidBase const & solid, ElementSubRegionBase & subRegion ) { - MultiphaseBulkDensityKernel kernel( numPhases, fluid, solid, subRegion ); + MultiphaseBulkDensityKernel kernel( numComponents, fluid, solid, subRegion ); MultiphaseBulkDensityKernel::launch< POLICY >( subRegion.size(), subRegion.getField< fields::poromechanics::bulkDensity >().size( 1 ), kernel ); diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/MultiphasePoromechanics_impl.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/MultiphasePoromechanics_impl.hpp index 5669a9631e9..b5f2621b165 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/MultiphasePoromechanics_impl.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/MultiphasePoromechanics_impl.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -54,6 +55,7 @@ MultiphasePoromechanics( NodeManager const & nodeManager, localIndex const numPhases, integer const useSimpleAccumulation, integer const useTotalMassEquation, + integer const performStressInitialization, string const fluidModelKey ): Base( nodeManager, edgeManager, @@ -79,7 +81,8 @@ MultiphasePoromechanics( NodeManager const & nodeManager, m_numComponents( numComponents ), m_numPhases( numPhases ), m_useSimpleAccumulation( useSimpleAccumulation ), - m_useTotalMassEquation( useTotalMassEquation ) + m_useTotalMassEquation( useTotalMassEquation ), + m_performStressInitialization( performStressInitialization ) { GEOS_ERROR_IF_GT_MSG( m_numComponents, maxNumComponents, "MultiphasePoromechanics solver allows at most " << @@ -101,6 +104,9 @@ MultiphasePoromechanics( NodeManager const & nodeManager, m_fluidPhaseMassDensity = fluid.phaseMassDensity(); m_dFluidPhaseMassDensity = fluid.dPhaseMassDensity(); + + m_useMass = fluid.getMassFlag(); + m_componentMolarWeight = fluid.componentMolarWeights(); } } @@ -152,9 +158,9 @@ smallStrainUpdate( localIndex const k, // Step 1: call the constitutive model to evaluate the total stress and compute porosity m_constitutiveUpdate.smallStrainUpdatePoromechanics( k, q, - m_pressure_n[k], - m_pressure[k], m_dt, + m_pressure[k], + m_pressure_n[k], stack.temperature, stack.deltaTemperatureFromLastStep, stack.strainIncrement, @@ -162,6 +168,7 @@ smallStrainUpdate( localIndex const k, stack.dTotalStress_dPressure, stack.dTotalStress_dTemperature, stack.stiffness, + m_performStressInitialization, porosity, porosity_n, dPorosity_dVolStrain, @@ -210,39 +217,18 @@ computeBodyForce( localIndex const k, StackVariables & stack, FUNC && bodyForceKernelOp ) const { - using Deriv = constitutive::multifluid::DerivativeOffset; - GEOS_UNUSED_VAR( dPorosity_dTemperature ); - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseMassDensity = m_fluidPhaseMassDensity[k][q]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseMassDensity = m_dFluidPhaseMassDensity[k][q]; - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const phaseVolFrac = m_fluidPhaseVolFrac[k]; - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dFluidPhaseVolFrac[k]; - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const dGlobalCompFrac_dGlobalCompDensity = m_dGlobalCompFraction_dGlobalCompDensity[k]; - // Step 1: compute fluid total mass density and its derivatives real64 totalMassDensity = 0.0; - real64 dTotalMassDensity_dPressure = 0.0; real64 dTotalMassDensity_dComponents[maxNumComponents]{}; - real64 dPhaseMassDensity_dComponents[maxNumComponents]{}; - for( integer ip = 0; ip < m_numPhases; ++ip ) + arraySlice1d< real64 const, compflow::USD_COMP - 1 > const compDens = m_compDens[k]; + for( integer ic = 0; ic < m_numComponents; ++ic ) { - totalMassDensity += phaseVolFrac( ip ) * phaseMassDensity( ip ); - dTotalMassDensity_dPressure += dPhaseVolFrac( ip, Deriv::dP ) * phaseMassDensity( ip ) - + phaseVolFrac( ip ) * dPhaseMassDensity( ip, Deriv::dP ); - - applyChainRule( m_numComponents, - dGlobalCompFrac_dGlobalCompDensity, - dPhaseMassDensity[ip], - dPhaseMassDensity_dComponents, - Deriv::dC ); - for( integer jc = 0; jc < m_numComponents; ++jc ) - { - dTotalMassDensity_dComponents[jc] += dPhaseVolFrac( ip, Deriv::dC+jc ) * phaseMassDensity( ip ) - + phaseVolFrac( ip ) * dPhaseMassDensity_dComponents[jc]; - } + totalMassDensity = totalMassDensity + ( m_useMass ? compDens[ic] : compDens[ic] * m_componentMolarWeight[ic] ); + dTotalMassDensity_dComponents[ic] = m_useMass ? 1.0 : m_componentMolarWeight[ic]; } // Step 2: compute mixture density as an average between total mass density and solid density @@ -250,8 +236,7 @@ computeBodyForce( localIndex const k, real64 const mixtureDensity = ( 1.0 - porosity ) * m_solidDensity( k, q ) + porosity * totalMassDensity; real64 const dMixtureDens_dVolStrainIncrement = dPorosity_dVolStrain * ( -m_solidDensity( k, q ) + totalMassDensity ); real64 const dMixtureDens_dPressure = dPorosity_dPressure * ( -m_solidDensity( k, q ) + totalMassDensity ) - + ( 1.0 - porosity ) * dSolidDensity_dPressure - + porosity * dTotalMassDensity_dPressure; + + ( 1.0 - porosity ) * dSolidDensity_dPressure; LvArray::tensorOps::scale< maxNumComponents >( dTotalMassDensity_dComponents, porosity ); // Step 3: finally, get the body force diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsBase.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsBase.hpp index 722a7fdf6d3..4bd3c9f44aa 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsBase.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsEFEMKernels.cpp.template b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsEFEMKernels.cpp.template index 302c8546551..debff643f00 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsEFEMKernels.cpp.template +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsEFEMKernels.cpp.template @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM_impl.hpp" #include "policies.hpp" diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsKernels.cmake b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsKernels.cmake index ff5ee1f49eb..c3aa48ddb39 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsKernels.cmake +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsKernels.cmake @@ -1,17 +1,17 @@ set( kernelPath "coreComponents/physicsSolvers/multiphysics/poromechanicsKernels" ) -set( SinglePhasePoromechanicsPolicy "geos::parallelDevicePolicy< ${GEOSX_BLOCK_SIZE} >" ) -set( SinglePhasePoromechanicsEFEMPolicy "geos::parallelDevicePolicy< ${GEOSX_BLOCK_SIZE} >" ) -set( MultiphasePoromechanicsPolicy "geos::parallelDevicePolicy< ${GEOSX_BLOCK_SIZE} >" ) -set( ThermalMultiphasePoromechanicsPolicy "geos::parallelDevicePolicy< ${GEOSX_BLOCK_SIZE} >" ) -set( ThermalSinglePhasePoromechanicsPolicy "geos::parallelDevicePolicy< ${GEOSX_BLOCK_SIZE} >" ) -set( ThermalSinglePhasePoromechanicsEFEMPolicy "geos::parallelDevicePolicy< ${GEOSX_BLOCK_SIZE} >" ) +set( SinglePhasePoromechanicsPolicy "geos::parallelDevicePolicy< ${GEOS_BLOCK_SIZE} >" ) +set( SinglePhasePoromechanicsEFEMPolicy "geos::parallelDevicePolicy< ${GEOS_BLOCK_SIZE} >" ) +set( MultiphasePoromechanicsPolicy "geos::parallelDevicePolicy< ${GEOS_BLOCK_SIZE} >" ) +set( ThermalMultiphasePoromechanicsPolicy "geos::parallelDevicePolicy< ${GEOS_BLOCK_SIZE} >" ) +set( ThermalSinglePhasePoromechanicsPolicy "geos::parallelDevicePolicy< ${GEOS_BLOCK_SIZE} >" ) +set( ThermalSinglePhasePoromechanicsEFEMPolicy "geos::parallelDevicePolicy< ${GEOS_BLOCK_SIZE} >" ) configure_file( ${CMAKE_SOURCE_DIR}/${kernelPath}/policies.hpp.in ${CMAKE_BINARY_DIR}/generatedSrc/${kernelPath}/policies.hpp ) -set( kernelNames PoromechanicsKernels ) +set( kernelNames PoromechanicsKernels ThermoPoromechanicsKernels ) set( subregionList CellElementSubRegion ) set( porousSolidDispatch PorousSolid PorousSolid @@ -59,7 +59,7 @@ endif( ) string(REPLACE "," "-" filename ${filename}) string(REPLACE " " "" filename ${filename}) message( " -- Generating file: ${filename}") - configure_file( ${CMAKE_SOURCE_DIR}/${kernelPath}/PoromechanicsKernels.cpp.template + configure_file( ${CMAKE_SOURCE_DIR}/${kernelPath}/${KERNELNAME}.cpp.template ${filename} ) list( APPEND physicsSolvers_sources ${filename} ) @@ -111,45 +111,3 @@ endif( ) endforeach() endforeach() -set( kernelNames ThermoPoromechanicsKernels ) -set( subregionList CellElementSubRegion ) -set( porousSolidDispatch PorousSolid ) - -set( finiteElementDispatch H1_Hexahedron_Lagrange1_GaussLegendre2 - H1_Wedge_Lagrange1_Gauss6 - H1_Tetrahedron_Lagrange1_Gauss1 - H1_Pyramid_Lagrange1_Gauss5 - H1_Tetrahedron_VEM_Gauss1 - H1_Prism5_VEM_Gauss1 - H1_Prism6_VEM_Gauss1 - H1_Prism7_VEM_Gauss1 - H1_Prism8_VEM_Gauss1 - H1_Prism9_VEM_Gauss1 - H1_Prism10_VEM_Gauss1 ) - -if ( NOT ${ENABLE_HIP} ) - list(APPEND finiteElementDispatch - H1_Hexahedron_VEM_Gauss1 - H1_Wedge_VEM_Gauss1 - H1_Prism11_VEM_Gauss1 ) -endif( ) - - foreach( KERNELNAME ${kernelNames} ) - foreach( SUBREGION_TYPE ${subregionList} ) - foreach( CONSTITUTIVE_TYPE ${porousSolidDispatch} ) - foreach( FE_TYPE ${finiteElementDispatch} ) - - set( filename "${CMAKE_BINARY_DIR}/generatedSrc/${kernelPath}/${KERNELNAME}_${SUBREGION_TYPE}_${CONSTITUTIVE_TYPE}_${FE_TYPE}.cpp" ) - string(REPLACE "<" "-" filename ${filename}) - string(REPLACE ">" "-" filename ${filename}) - string(REPLACE "," "-" filename ${filename}) - string(REPLACE " " "" filename ${filename}) - message( " -- Generating file: ${filename}") - configure_file( ${CMAKE_SOURCE_DIR}/${kernelPath}/ThermoPoromechanicsKernels.cpp.template - ${filename} ) - - list( APPEND physicsSolvers_sources ${filename} ) - endforeach() - endforeach() - endforeach() - endforeach() diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsKernels.cpp.template b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsKernels.cpp.template index ca5e412efaa..19f7ad4cb18 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsKernels.cpp.template +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/PoromechanicsKernels.cpp.template @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #include "physicsSolvers/multiphysics/poromechanicsKernels/MultiphasePoromechanics_impl.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanics_impl.hpp" diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanics.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanics.hpp index c286c6dff8c..302c8113b3d 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanics.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -94,6 +95,7 @@ class SinglePhasePoromechanics : real64 const inputDt, real64 const (&gravityVector)[3], string const inputFlowDofKey, + integer const performStressInitialization, string const fluidModelKey ); //***************************************************************************** @@ -257,6 +259,7 @@ class SinglePhasePoromechanics : /// Derivative of fluid density wrt pressure arrayView2d< real64 const > const m_dFluidDensity_dPressure; + integer const m_performStressInitialization; }; using SinglePhasePoromechanicsKernelFactory = @@ -268,10 +271,11 @@ using SinglePhasePoromechanicsKernelFactory = real64 const, real64 const (&)[3], string const, + integer const, string const >; /** - * @class BulkDensityKernel + * @class SinglePhaseBulkDensityKernel * @brief Kernel to update the bulk density before a mechanics solve in sequential schemes */ class SinglePhaseBulkDensityKernel diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp index fc69cd60364..e32a6d26eb7 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOS Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,8 +20,9 @@ #ifndef GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_SINGLEPHASEPOROMECHANICSCONFORMINGFRACTURES_HPP #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_SINGLEPHASEPOROMECHANICSCONFORMINGFRACTURES_HPP -#include "physicsSolvers/fluidFlow/SinglePhaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/FluxKernelsHelper.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp" +#include "codingUtilities/Utilities.hpp" namespace geos { @@ -28,11 +30,8 @@ namespace geos namespace singlePhasePoromechanicsConformingFracturesKernels { -using namespace fluxKernelsHelper; -using namespace constitutive; - template< integer NUM_EQN, integer NUM_DOF > -class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper > +class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper > { public: @@ -45,12 +44,12 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse template< typename VIEWTYPE > using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - using AbstractBase = singlePhaseFVMKernels::FaceBasedAssemblyKernelBase; + using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; using DofNumberAccessor = AbstractBase::DofNumberAccessor; using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; - using FracturePermeabilityAccessors = StencilMaterialAccessors< PermeabilityBase, + using FracturePermeabilityAccessors = StencilMaterialAccessors< constitutive::PermeabilityBase, fields::permeability::dPerm_dDispJump >; using AbstractBase::m_dt; @@ -65,7 +64,7 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse using AbstractBase::m_dens; using AbstractBase::m_dDens_dPres; - using Base = singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; + using Base = singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; using Base::numDof; using Base::numEqn; using Base::maxNumElems; @@ -157,11 +156,11 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse * @param[inout] stack the stack variables * @param[in] NoOpFunc the function used to customize the computation of the flux */ - template< typename FUNC = singlePhaseBaseKernels::NoOpFunc > + template< typename FUNC = NoOpFunc > GEOS_HOST_DEVICE void computeFlux( localIndex const iconn, StackVariables & stack, - FUNC && kernelOp = singlePhaseBaseKernels::NoOpFunc{} ) const + FUNC && kernelOp = NoOpFunc{} ) const { @@ -192,21 +191,21 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse localIndex const subRegionIndex[2] = {m_sesri[iconn][k[0]], m_sesri[iconn][k[1]]}; localIndex const elementIndex[2] = {m_sei[iconn][k[0]], m_sei[iconn][k[1]]}; - computeSinglePhaseFlux( regionIndex, subRegionIndex, elementIndex, - trans, - dTrans, - m_pres, - m_gravCoef, - m_dens, - m_dDens_dPres, - m_mob, - m_dMob_dPres, - alpha, - mobility, - potGrad, - fluxVal, - dFlux_dP, - dFlux_dTrans ); + singlePhaseFluxKernelsHelper::computeSinglePhaseFlux( regionIndex, subRegionIndex, elementIndex, + trans, + dTrans, + m_pres, + m_gravCoef, + m_dens, + m_dDens_dPres, + m_mob, + m_dMob_dPres, + alpha, + mobility, + potGrad, + fluxVal, + dFlux_dP, + dFlux_dTrans ); // populate local flux vector and derivatives stack.localFlux[k[0]* numDof] += m_dt * fluxVal; @@ -237,11 +236,11 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse * @param[in] iconn the connection index * @param[inout] stack the stack variables */ - template< typename FUNC = singlePhaseBaseKernels::NoOpFunc > + template< typename FUNC = NoOpFunc > GEOS_HOST_DEVICE void complete( localIndex const iconn, StackVariables & stack, - FUNC && kernelOp = singlePhaseBaseKernels::NoOpFunc{} ) const + FUNC && kernelOp = NoOpFunc{} ) const { // Call Base::complete to assemble the mass balance equations // In the lambda, fill the dR_dAper matrix @@ -270,7 +269,7 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse /** - * @class FaceBasedAssemblyKernelFactory + * @class ConnectorBasedAssemblyKernelFactory */ class ConnectorBasedAssemblyKernelFactory { diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM.hpp index 939d0eac8dd..ac266ec21d6 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,8 +20,8 @@ #ifndef GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_SINGLEPHASEPOROMECHANICSEFEM_HPP_ #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_SINGLEPHASEPOROMECHANICSEFEM_HPP_ -#include "constitutive/contact/ContactBase.hpp" #include "finiteElement/kernelInterface/ImplicitKernelBase.hpp" +#include "codingUtilities/Utilities.hpp" namespace geos { @@ -28,20 +29,6 @@ namespace geos namespace poromechanicsEFEMKernels { -/** - * @brief Internal struct to provide no-op defaults used in the inclusion - * of lambda functions into kernel component functions. - * @struct NoOpFunc - */ -struct NoOpFunc -{ - template< typename ... Ts > - GEOS_HOST_DEVICE - constexpr void - operator()( Ts && ... ) const {} -}; - - template< typename SUBREGION_TYPE, typename CONSTITUTIVE_TYPE, typename FE_TYPE > @@ -128,6 +115,7 @@ class SinglePhasePoromechanicsEFEM : localKww{ { 0.0 } }, localKwu{ { 0.0 } }, localKuw{ { 0.0 } }, + localEqMStress { 0.0 }, localKwpm{ 0.0 }, localKwpf( 0.0 ), wLocal(), @@ -167,6 +155,9 @@ class SinglePhasePoromechanicsEFEM : /// C-array storage for the element local Kuw matrix. real64 localKuw[numUdofs][numWdofs]; + /// C-array storage for the element local EqM*effStress vector. + real64 localEqMStress[numWdofs]; + /// C-array storage for the element local Kwpm matrix. real64 localKwpm[numWdofs]; @@ -220,12 +211,12 @@ class SinglePhasePoromechanicsEFEM : void setup( localIndex const k, StackVariables & stack ) const; - template< typename FUNC = poromechanicsEFEMKernels::NoOpFunc > + template< typename FUNC = NoOpFunc > GEOS_HOST_DEVICE void quadraturePointKernel( localIndex const k, localIndex const q, StackVariables & stack, - FUNC && kernelOp = poromechanicsEFEMKernels::NoOpFunc{} ) const; + FUNC && kernelOp = NoOpFunc{} ) const; /** * @copydoc geos::finiteElement::ImplicitKernelBase::complete @@ -246,6 +237,9 @@ class SinglePhasePoromechanicsEFEM : arrayView2d< real64 const > const m_w; + /// The effective stress at the current time + arrayView3d< real64 const, solid::STRESS_USD > m_effStress; + /// The global degree of freedom number arrayView1d< globalIndex const > const m_matrixPresDofNumber; @@ -262,6 +256,9 @@ class SinglePhasePoromechanicsEFEM : /// The rank-global fluid pressure array. arrayView1d< real64 const > const m_matrixPressure; + /// The rank-global fluid pressure array. + arrayView1d< real64 const > const m_fracturePressure; + /// The rank-global delta-fluid pressure array. arrayView2d< real64 const > const m_porosity_n; @@ -281,7 +278,9 @@ class SinglePhasePoromechanicsEFEM : arrayView1d< real64 const > const m_surfaceArea; - arrayView1d< real64 const > const m_elementVolume; + arrayView1d< real64 const > const m_elementVolumeCell; + + arrayView1d< real64 const > const m_elementVolumeFrac; arrayView1d< real64 const > const m_deltaVolume; @@ -327,13 +326,12 @@ struct StateUpdateKernel * @param[out] deltaVolume the change in volume * @param[out] aperture the aperture * @param[out] hydraulicAperture the effecture aperture - * @param[out] fractureTraction the fracture traction - * @param[out] dFractureTraction_dPressure the derivative of the fracture traction wrt pressure + * @param[out] fractureContactTraction the fracture contact traction */ - template< typename POLICY, typename POROUS_WRAPPER > + template< typename POLICY, typename POROUS_WRAPPER, typename CONTACT_WRAPPER > static void launch( localIndex const size, - constitutive::ContactBase::KernelWrapper const & contactWrapper, + CONTACT_WRAPPER const & contactWrapper, POROUS_WRAPPER const & porousMaterialWrapper, arrayView2d< real64 const > const & dispJump, arrayView1d< real64 const > const & pressure, @@ -343,32 +341,31 @@ struct StateUpdateKernel arrayView1d< real64 > const & aperture, arrayView1d< real64 const > const & oldHydraulicAperture, arrayView1d< real64 > const & hydraulicAperture, - arrayView2d< real64 > const & fractureTraction, - arrayView1d< real64 > const & dFractureTraction_dPressure ) + arrayView2d< real64 > const & fractureEffectiveTraction ) { forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) { // update aperture to be equal to the normal displacement jump aperture[k] = dispJump[k][0]; // the first component of the jump is the normal one. - real64 dHydraulicAperture_dNormalJump = 0; + real64 dHydraulicAperture_dNormalJump = 0.0; + real64 dHydraulicAperture_dNormalTraction = 0.0; hydraulicAperture[k] = contactWrapper.computeHydraulicAperture( aperture[k], - dHydraulicAperture_dNormalJump ); + fractureEffectiveTraction[k][0], + dHydraulicAperture_dNormalJump, + dHydraulicAperture_dNormalTraction ); deltaVolume[k] = hydraulicAperture[k] * area[k] - volume[k]; - // traction on the fracture to include the pressure contribution - contactWrapper.addPressureToTraction( pressure[k], - fractureTraction[k], - dFractureTraction_dPressure[k] ); - real64 const jump[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3 ( dispJump[k] ); - real64 const traction[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3 ( fractureTraction[k] ); + real64 const effectiveTraction[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3 ( fractureEffectiveTraction[k] ); + // all perm update models below should need effective traction instead of total traction + // (total traction is combined forces of fluid pressure and effective traction) porousMaterialWrapper.updateStateFromPressureApertureJumpAndTraction( k, 0, pressure[k], oldHydraulicAperture[k], hydraulicAperture[k], dHydraulicAperture_dNormalJump, - jump, traction ); + jump, effectiveTraction ); } ); } diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM_impl.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM_impl.hpp index c4beadfe5aa..efc8ae09ea8 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM_impl.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM_impl.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -25,7 +26,7 @@ #include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanics.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM.hpp" -#include "physicsSolvers/contact/SolidMechanicsEFEMKernelsHelper.hpp" +#include "physicsSolvers/contact/kernels/SolidMechanicsEFEMKernelsHelper.hpp" namespace geos { @@ -70,6 +71,7 @@ SinglePhasePoromechanicsEFEM( NodeManager const & nodeManager, m_disp( nodeManager.getField< fields::solidMechanics::totalDisplacement >() ), m_deltaDisp( nodeManager.getField< fields::solidMechanics::incrementalDisplacement >() ), m_w( embeddedSurfSubRegion.getField< fields::contact::dispJump >() ), + m_effStress( inputConstitutiveType.getEffectiveStress()), m_matrixPresDofNumber( elementSubRegion.template getReference< array1d< globalIndex > >( inputFlowDofKey ) ), m_fracturePresDofNumber( embeddedSurfSubRegion.template getReference< array1d< globalIndex > >( inputFlowDofKey ) ), m_wDofNumber( jumpDofNumber ), @@ -79,6 +81,7 @@ SinglePhasePoromechanicsEFEM( NodeManager const & nodeManager, m_dFluidDensity_dPressure( embeddedSurfSubRegion.template getConstitutiveModel< constitutive::SingleFluidBase >( elementSubRegion.template getReference< string >( fluidModelKey ) ).dDensity_dPressure() ), m_matrixPressure( elementSubRegion.template getField< fields::flow::pressure >() ), + m_fracturePressure( embeddedSurfSubRegion.template getField< fields::flow::pressure >() ), m_porosity_n( inputConstitutiveType.getPorosity_n() ), m_tractionVec( embeddedSurfSubRegion.getField< fields::contact::traction >() ), m_dTraction_dJump( embeddedSurfSubRegion.getField< fields::contact::dTraction_dJump >() ), @@ -88,8 +91,9 @@ SinglePhasePoromechanicsEFEM( NodeManager const & nodeManager, m_tVec2( embeddedSurfSubRegion.getTangentVector2() ), m_surfaceCenter( embeddedSurfSubRegion.getElementCenter() ), m_surfaceArea( embeddedSurfSubRegion.getElementArea() ), - m_elementVolume( elementSubRegion.getElementVolume() ), - m_deltaVolume( elementSubRegion.template getField< fields::flow::deltaVolume >() ), + m_elementVolumeCell( elementSubRegion.getElementVolume() ), + m_elementVolumeFrac( embeddedSurfSubRegion.getElementVolume() ), + m_deltaVolume( embeddedSurfSubRegion.template getField< fields::flow::deltaVolume >() ), m_fracturedElems( elementSubRegion.fracturedElementsList() ), m_cellsToEmbeddedSurfaces( elementSubRegion.embeddedSurfacesList().toViewConst() ), m_gravityVector{ inputGravityVector[0], inputGravityVector[1], inputGravityVector[2] }, @@ -145,7 +149,7 @@ setup( localIndex const k, { localIndex const embSurfIndex = m_cellsToEmbeddedSurfaces[k][0]; - stack.hInv = m_surfaceArea[embSurfIndex] / m_elementVolume[k]; + stack.hInv = m_surfaceArea[embSurfIndex] / m_elementVolumeCell[k]; for( localIndex a=0; a( Kwu_gauss, matED, strainMatrix ); // transp(B)DB LvArray::tensorOps::Rij_eq_AikBjk< nUdof, 3, 6 >( Kuw_gauss, matBD, compMatrix ); + // EqMatrix * effStress + LvArray::tensorOps::Ri_eq_AijBj< 3, 6 >( eqMStress_gauss, eqMatrix, m_effStress[k][q] ); LvArray::tensorOps::fill< 3 >( Kwpm_gauss, 0 ); for( int i=0; i < 3; ++i ) @@ -259,6 +274,7 @@ quadraturePointKernel( localIndex const k, LvArray::tensorOps::scaledAdd< 3, 3 >( stack.localKww, Kww_gauss, -detJ ); LvArray::tensorOps::scaledAdd< 3, nUdof >( stack.localKwu, Kwu_gauss, -detJ ); LvArray::tensorOps::scaledAdd< nUdof, 3 >( stack.localKuw, Kuw_gauss, -detJ ); + LvArray::tensorOps::scaledAdd< 3 >( stack.localEqMStress, eqMStress_gauss, -detJ ); /// TODO: should this be negative??? // I had No neg coz the total stress = effective stress - porePressure @@ -284,25 +300,30 @@ complete( localIndex const k, // Compute the local residuals LvArray::tensorOps::Ri_add_AijBj< 3, 3 >( stack.localJumpResidual, stack.localKww, stack.wLocal ); - LvArray::tensorOps::Ri_add_AijBj< 3, nUdof >( stack.localJumpResidual, stack.localKwu, stack.dispLocal ); LvArray::tensorOps::Ri_add_AijBj< nUdof, 3 >( stack.localDispResidual, stack.localKuw, stack.wLocal ); + // add EqM * effStress into the residual of enrichment nodes + LvArray::tensorOps::add< 3 >( stack.localJumpResidual, stack.localEqMStress ); // add pore pressure contribution LvArray::tensorOps::scaledAdd< 3 >( stack.localJumpResidual, stack.localKwpm, m_matrixPressure[ k ] ); localIndex const embSurfIndex = m_cellsToEmbeddedSurfaces[k][0]; - // Add traction contribution tranction + // Add total traction contribution from penalty force and fracture pressure + // total traction is T_total = -k * dispJump + pf (where dispJump < 0) + // -1 is because k*dispJump was saved in tractionVec LvArray::tensorOps::scaledAdd< 3 >( stack.localJumpResidual, stack.tractionVec, -1 ); LvArray::tensorOps::scaledAdd< 3, 3 >( stack.localKww, stack.dTractiondw, -1 ); - // JumpFractureFlowJacobian - real64 const localJumpFracPressureJacobian = -m_dTraction_dPressure[embSurfIndex] * m_surfaceArea[embSurfIndex]; + // fracture pressure only affects normal direction + stack.localJumpResidual[0] += m_fracturePressure[embSurfIndex] * m_surfaceArea[embSurfIndex]; + // fracture force balance residual w.r.t. fracture pressure + real64 const localJumpFracPressureJacobian = m_surfaceArea[embSurfIndex]; // Mass balance accumulation - real64 const newVolume = m_elementVolume( embSurfIndex ) + m_deltaVolume( embSurfIndex ); - real64 const newMass = m_fluidDensity( embSurfIndex, 0 ) * newVolume; - real64 const oldMass = m_fluidDensity_n( embSurfIndex, 0 ) * m_elementVolume( embSurfIndex ); + real64 const newVolume = m_elementVolumeFrac( embSurfIndex ) + m_deltaVolume( embSurfIndex ); + real64 const newMass = m_fluidDensity( embSurfIndex, 0 ) * newVolume; + real64 const oldMass = m_fluidDensity_n( embSurfIndex, 0 ) * m_elementVolumeFrac( embSurfIndex ); real64 const localFlowResidual = ( newMass - oldMass ); real64 const localFlowJumpJacobian = m_fluidDensity( embSurfIndex, 0 ) * m_surfaceArea[ embSurfIndex ]; real64 const localFlowFlowJacobian = m_dFluidDensity_dPressure( embSurfIndex, 0 ) * newVolume; diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEmbeddedFractures.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEmbeddedFractures.hpp index 2edc90377d1..d9e69daf444 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEmbeddedFractures.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEmbeddedFractures.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOS Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,8 +20,9 @@ #ifndef GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_SINGLEPHASEPOROMECHANICSEMBEDDEDFRACTURES_HPP #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_SINGLEPHASEPOROMECHANICSEMBEDDEDFRACTURES_HPP -#include "physicsSolvers/fluidFlow/SinglePhaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/FluxKernelsHelper.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp" +#include "codingUtilities/Utilities.hpp" namespace geos { @@ -28,11 +30,8 @@ namespace geos namespace singlePhasePoromechanicsEmbeddedFracturesKernels { -using namespace fluxKernelsHelper; -using namespace constitutive; - template< integer NUM_EQN, integer NUM_DOF > -class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper > +class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper > { public: @@ -45,12 +44,12 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse template< typename VIEWTYPE > using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - using AbstractBase = singlePhaseFVMKernels::FaceBasedAssemblyKernelBase; + using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; using DofNumberAccessor = AbstractBase::DofNumberAccessor; using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; - using FracturePermeabilityAccessors = StencilMaterialAccessors< PermeabilityBase, + using FracturePermeabilityAccessors = StencilMaterialAccessors< constitutive::PermeabilityBase, fields::permeability::dPerm_dDispJump >; using AbstractBase::m_dt; using AbstractBase::m_rankOffset; @@ -64,7 +63,7 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse using AbstractBase::m_dens; using AbstractBase::m_dDens_dPres; - using Base = singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; + using Base = singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; using Base::numDof; using Base::numEqn; using Base::maxNumElems; @@ -152,11 +151,11 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse * @param[inout] stack the stack variables * @param[in] NoOpFunc the function used to customize the computation of the flux */ - template< typename FUNC = singlePhaseBaseKernels::NoOpFunc > + template< typename FUNC = NoOpFunc > GEOS_HOST_DEVICE void computeFlux( localIndex const iconn, StackVariables & stack, - FUNC && kernelOp = singlePhaseBaseKernels::NoOpFunc{} ) const + FUNC && kernelOp = NoOpFunc{} ) const { @@ -182,21 +181,21 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse real64 mobility = 0.0; real64 potGrad = 0.0; - computeSinglePhaseFlux( regionIndex, subRegionIndex, elementIndex, - trans, - dTrans, - m_pres, - m_gravCoef, - m_dens, - m_dDens_dPres, - m_mob, - m_dMob_dPres, - alpha, - mobility, - potGrad, - fluxVal, - dFlux_dP, - dFlux_dTrans ); + singlePhaseFluxKernelsHelper::computeSinglePhaseFlux( regionIndex, subRegionIndex, elementIndex, + trans, + dTrans, + m_pres, + m_gravCoef, + m_dens, + m_dDens_dPres, + m_mob, + m_dMob_dPres, + alpha, + mobility, + potGrad, + fluxVal, + dFlux_dP, + dFlux_dTrans ); @@ -240,7 +239,7 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse /** - * @class FaceBasedAssemblyKernelFactory + * @class ConnectorBasedAssemblyKernelFactory */ class ConnectorBasedAssemblyKernelFactory { diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsFractures.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsFractures.hpp index 7c098a010dc..34b875a8cd1 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsFractures.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsFractures.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -34,7 +35,7 @@ struct StateUpdateKernel /** * @brief Launch the kernel function doing volume, aperture and fracture traction updates * @tparam POLICY the type of policy used in the kernel launch - * @tparam CONTACT_WRAPPER the type of contact wrapper doing the fracture traction updates + * @tparam HYDRAULIC_APERTURE_WRAPPER the type of hydraulic aperture model wrapper doing the fracture traction updates * @param[in] size the size of the subregion * @param[in] contactWrapper the wrapper implementing the contact relationship * @param[in] dispJump the displacement jump @@ -43,22 +44,21 @@ struct StateUpdateKernel * @param[in] volume the volume * @param[out] deltaVolume the change in volume * @param[out] aperture the aperture - * @param[in] minimumHydraulicAperture the * @param[in] oldHydraulicAperture the old hydraulic aperture * @param[out] hydraulicAperture the effecture aperture * @param[in] fractureTraction the fracture traction */ - template< typename POLICY, typename POROUS_WRAPPER > + template< typename POLICY, typename POROUS_WRAPPER, typename HYDRAULIC_APERTURE_WRAPPER > static void launch( localIndex const size, POROUS_WRAPPER const & porousMaterialWrapper, + HYDRAULIC_APERTURE_WRAPPER const & contactWrapper, arrayView2d< real64 const > const & dispJump, arrayView1d< real64 const > const & pressure, arrayView1d< real64 const > const & area, arrayView1d< real64 const > const & volume, arrayView1d< real64 > const & deltaVolume, arrayView1d< real64 > const & aperture, - arrayView1d< real64 const > const & minimumHydraulicAperture, arrayView1d< real64 const > const & oldHydraulicAperture, arrayView1d< real64 > const & hydraulicAperture, arrayView2d< real64 const > const & fractureTraction ) @@ -69,8 +69,12 @@ struct StateUpdateKernel // update aperture to be equal to the normal displacement jump aperture[k] = dispJump[k][0]; // the first component of the jump is the normal one. - hydraulicAperture[k] = minimumHydraulicAperture[k] + aperture[k]; - real64 const dHydraulicAperture_dNormalJump = 1.0; + real64 dHydraulicAperture_dNormalJump = 0.0; + real64 dHydraulicAperture_dNormalTraction = 0.0; + hydraulicAperture[k] = contactWrapper.computeHydraulicAperture( aperture[k], + fractureTraction[k][0], + dHydraulicAperture_dNormalJump, + dHydraulicAperture_dNormalTraction ); deltaVolume[k] = hydraulicAperture[k] * area[k] - volume[k]; @@ -78,9 +82,11 @@ struct StateUpdateKernel real64 const traction[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3 ( fractureTraction[k] ); porousMaterialWrapper.updateStateFromPressureApertureJumpAndTraction( k, 0, pressure[k], - oldHydraulicAperture[k], hydraulicAperture[k], + oldHydraulicAperture[k], + hydraulicAperture[k], dHydraulicAperture_dNormalJump, - jump, traction ); + jump, + traction ); } ); } diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanics_impl.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanics_impl.hpp index 6ce167b97d9..2f020977794 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanics_impl.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanics_impl.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -50,6 +51,7 @@ SinglePhasePoromechanics( NodeManager const & nodeManager, real64 const inputDt, real64 const (&gravityVector)[3], string const inputFlowDofKey, + integer const performStressInitialization, string const fluidModelKey ): Base( nodeManager, edgeManager, @@ -68,7 +70,8 @@ SinglePhasePoromechanics( NodeManager const & nodeManager, fluidModelKey ), m_fluidDensity( elementSubRegion.template getConstitutiveModel< constitutive::SingleFluidBase >( elementSubRegion.template getReference< string >( fluidModelKey ) ).density() ), m_fluidDensity_n( elementSubRegion.template getConstitutiveModel< constitutive::SingleFluidBase >( elementSubRegion.template getReference< string >( fluidModelKey ) ).density_n() ), - m_dFluidDensity_dPressure( elementSubRegion.template getConstitutiveModel< constitutive::SingleFluidBase >( elementSubRegion.template getReference< string >( fluidModelKey ) ).dDensity_dPressure() ) + m_dFluidDensity_dPressure( elementSubRegion.template getConstitutiveModel< constitutive::SingleFluidBase >( elementSubRegion.template getReference< string >( fluidModelKey ) ).dDensity_dPressure() ), + m_performStressInitialization( performStressInitialization ) {} template< typename SUBREGION_TYPE, @@ -90,9 +93,9 @@ smallStrainUpdate( localIndex const k, // Step 1: call the constitutive model to evaluate the total stress and compute porosity m_constitutiveUpdate.smallStrainUpdatePoromechanics( k, q, - m_pressure_n[k], - m_pressure[k], m_dt, + m_pressure[k], + m_pressure_n[k], stack.temperature, stack.deltaTemperatureFromLastStep, stack.strainIncrement, @@ -100,6 +103,7 @@ smallStrainUpdate( localIndex const k, stack.dTotalStress_dPressure, stack.dTotalStress_dTemperature, stack.stiffness, + m_performStressInitialization, porosity, porosity_n, dPorosity_dVolStrain, diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalMultiphasePoromechanics.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalMultiphasePoromechanics.hpp index 5c60e6820da..110376c9d95 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalMultiphasePoromechanics.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalMultiphasePoromechanics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -76,6 +77,7 @@ class ThermalMultiphasePoromechanics : using Base::m_numComponents; using Base::m_numPhases; using Base::m_useTotalMassEquation; + using Base::m_performStressInitialization; using Base::m_solidDensity; using Base::m_fluidPhaseMassDensity; using Base::m_dFluidPhaseMassDensity; @@ -110,6 +112,7 @@ class ThermalMultiphasePoromechanics : localIndex const numComponents, localIndex const numPhases, integer const useTotalMassEquation, + integer const performStressInitialization, string const fluidModelKey ); /** @@ -341,6 +344,7 @@ using ThermalMultiphasePoromechanicsKernelFactory = localIndex const, localIndex const, integer const, + integer const, string const >; } // namespace thermalporomechanicsKernels diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalMultiphasePoromechanics_impl.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalMultiphasePoromechanics_impl.hpp index 23409cf5db3..98e5a37075f 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalMultiphasePoromechanics_impl.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalMultiphasePoromechanics_impl.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -52,6 +53,7 @@ ThermalMultiphasePoromechanics( NodeManager const & nodeManager, localIndex const numComponents, localIndex const numPhases, integer const useTotalMassEquation, + integer const performStressInitialization, string const fluidModelKey ): Base( nodeManager, edgeManager, @@ -71,6 +73,7 @@ ThermalMultiphasePoromechanics( NodeManager const & nodeManager, numPhases, false, // do not use simple accumulation form useTotalMassEquation, + performStressInitialization, fluidModelKey ), m_rockInternalEnergy_n( inputConstitutiveType.getInternalEnergy_n() ), m_rockInternalEnergy( inputConstitutiveType.getInternalEnergy() ), @@ -127,9 +130,9 @@ smallStrainUpdate( localIndex const k, // Step 1: call the constitutive model to update the total stress, the porosity and their derivatives m_constitutiveUpdate.smallStrainUpdatePoromechanics( k, q, - m_pressure_n[k], - m_pressure[k], m_dt, + m_pressure[k], + m_pressure_n[k], stack.temperature, stack.deltaTemperatureFromLastStep, stack.strainIncrement, @@ -137,6 +140,7 @@ smallStrainUpdate( localIndex const k, stack.dTotalStress_dPressure, stack.dTotalStress_dTemperature, stack.stiffness, + m_performStressInitialization, porosity, porosity_n, dPorosity_dVolStrain, @@ -184,8 +188,6 @@ computeBodyForce( localIndex const k, real64 const & dSolidDensity_dPressure, StackVariables & stack ) const { - using Deriv = constitutive::multifluid::DerivativeOffset; - Base::computeBodyForce( k, q, porosity, dPorosity_dVolStrain, @@ -197,27 +199,11 @@ computeBodyForce( localIndex const k, { GEOS_UNUSED_VAR( mixtureDensity ); - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseMassDensity = m_fluidPhaseMassDensity[k][q]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseMassDensity = m_dFluidPhaseMassDensity[k][q]; - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const phaseVolFrac = m_fluidPhaseVolFrac[k]; - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dFluidPhaseVolFrac[k]; - - // Step 1: compute fluid total mass density and its derivatives - - real64 dTotalMassDensity_dTemperature = 0.0; - - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - dTotalMassDensity_dTemperature += dPhaseVolFrac( ip, Deriv::dT ) * phaseMassDensity( ip ) - + phaseVolFrac( ip ) * dPhaseMassDensity( ip, Deriv::dT ); - } - - // Step 2: compute the derivative of the bulk density (an average between total mass density and solid density) wrt temperature - - real64 const dMixtureDens_dTemperature = dPorosity_dTemperature * ( -m_solidDensity( k, q ) + totalMassDensity ) - + porosity * dTotalMassDensity_dTemperature; + // Step 1: compute the derivative of the mixture density (an average between total mass density and solid density) wrt temperature + // TODO include solid density derivative with respect to temperature + real64 const dMixtureDens_dTemperature = dPorosity_dTemperature * ( -m_solidDensity( k, q ) + totalMassDensity ); - // Step 3: finally, get the body force + // Step 2: finally, get the body force LvArray::tensorOps::scaledCopy< 3 >( stack.dBodyForce_dTemperature, m_gravityVector, dMixtureDens_dTemperature ); diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanics.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanics.hpp index 5fe11040d59..a84c66dbaec 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanics.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -70,6 +71,7 @@ class ThermalSinglePhasePoromechanics : using Base::m_solidDensity; using Base::m_flowDofNumber; using Base::m_dt; + using Base::m_performStressInitialization; /** * @brief Constructor @@ -90,6 +92,7 @@ class ThermalSinglePhasePoromechanics : real64 const inputDt, real64 const (&gravityVector)[3], string const inputFlowDofKey, + integer const performStressInitialization, string const fluidModelKey ); //***************************************************************************** @@ -305,6 +308,7 @@ using ThermalSinglePhasePoromechanicsKernelFactory = real64 const, real64 const (&)[3], string const, + integer const, string const >; } // namespace thermalPoromechanicsKernels diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsConformingFractures.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsConformingFractures.hpp index cb5492687ed..e8589fa70ed 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsConformingFractures.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsConformingFractures.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOS Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,6 +21,7 @@ #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_THERMALSINGLEPHASEPOROMECHANICSCONFORMINGFRACTURES_HPP #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernelBase.hpp" namespace geos { @@ -27,9 +29,6 @@ namespace geos namespace thermalSinglePhasePoromechanicsConformingFracturesKernels { -using namespace fluxKernelsHelper; -using namespace constitutive; - template< integer NUM_EQN, integer NUM_DOF > class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsConformingFracturesKernels::ConnectorBasedAssemblyKernel< NUM_EQN, NUM_DOF > { @@ -44,12 +43,12 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsConformingFr template< typename VIEWTYPE > using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - using SinglePhaseFVMAbstractBase = singlePhaseFVMKernels::FaceBasedAssemblyKernelBase; + using SinglePhaseFVMAbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; using DofNumberAccessor = SinglePhaseFVMAbstractBase::DofNumberAccessor; using SinglePhaseFlowAccessors = SinglePhaseFVMAbstractBase::SinglePhaseFlowAccessors; using SinglePhaseFluidAccessors = SinglePhaseFVMAbstractBase::SinglePhaseFluidAccessors; using PermeabilityAccessors = SinglePhaseFVMAbstractBase::PermeabilityAccessors; - using FracturePermeabilityAccessors = StencilMaterialAccessors< PermeabilityBase, + using FracturePermeabilityAccessors = StencilMaterialAccessors< constitutive::PermeabilityBase, fields::permeability::dPerm_dDispJump >; using SinglePhaseFVMAbstractBase::m_dt; using SinglePhaseFVMAbstractBase::m_rankOffset; @@ -58,7 +57,7 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsConformingFr using SinglePhaseFVMAbstractBase::m_mob; using SinglePhaseFVMAbstractBase::m_dens; - using SinglePhaseFVMBase = singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; + using SinglePhaseFVMBase = singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; using SinglePhaseFVMBase::numDof; using SinglePhaseFVMBase::numEqn; using SinglePhaseFVMBase::maxNumElems; @@ -77,14 +76,14 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsConformingFr fields::flow::dMobility_dTemperature >; using ThermalSinglePhaseFluidAccessors = - StencilMaterialAccessors< SingleFluidBase, + StencilMaterialAccessors< constitutive::SingleFluidBase, fields::singlefluid::dDensity_dTemperature, fields::singlefluid::enthalpy, fields::singlefluid::dEnthalpy_dPressure, fields::singlefluid::dEnthalpy_dTemperature >; using ThermalConductivityAccessors = - StencilMaterialAccessors< SinglePhaseThermalConductivityBase, + StencilMaterialAccessors< constitutive::SinglePhaseThermalConductivityBase, fields::thermalconductivity::effectiveConductivity >; @@ -207,25 +206,25 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsConformingFr real64 trans[2] = {stack.transmissibility[0][0], stack.transmissibility[0][1]}; real64 dMassFlux_dT[2]{}; - computeEnthalpyFlux( seri, sesri, sei, - trans, - m_enthalpy, - m_dEnthalpy_dPres, - m_dEnthalpy_dTemp, - m_gravCoef, - m_dDens_dTemp, - m_dMob_dTemp, - alpha, - mobility, - potGrad, - massFlux, - dMassFlux_dTrans, - dMassFlux_dP, - dMassFlux_dT, - stack.energyFlux, - stack.dEnergyFlux_dTrans, - stack.dEnergyFlux_dP, - stack.dEnergyFlux_dT ); + singlePhaseFluxKernelsHelper::computeEnthalpyFlux( seri, sesri, sei, + trans, + m_enthalpy, + m_dEnthalpy_dPres, + m_dEnthalpy_dTemp, + m_gravCoef, + m_dDens_dTemp, + m_dMob_dTemp, + alpha, + mobility, + potGrad, + massFlux, + dMassFlux_dTrans, + dMassFlux_dP, + dMassFlux_dT, + stack.energyFlux, + stack.dEnergyFlux_dTrans, + stack.dEnergyFlux_dP, + stack.dEnergyFlux_dT ); // add dMassFlux_dT to localFluxJacobian for( integer ke = 0; ke < 2; ++ke ) @@ -262,7 +261,7 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsConformingFr localIndex const sei[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; // Step 2: compute temperature difference at the interface - computeConductiveFlux( seri, sesri, sei, m_temp, thermalTrans, stack.energyFlux, stack.dEnergyFlux_dT ); + singlePhaseFluxKernelsHelper::computeConductiveFlux( seri, sesri, sei, m_temp, thermalTrans, stack.energyFlux, stack.dEnergyFlux_dT ); // add energyFlux and its derivatives to localFlux and localFluxJacobian stack.localFlux[k[0]*numEqn + numEqn - 1] += m_dt * stack.energyFlux; @@ -333,7 +332,7 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsConformingFr /** - * @class FaceBasedAssemblyKernelFactory + * @class ConnectorBasedAssemblyKernelFactory */ class ConnectorBasedAssemblyKernelFactory { diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEFEM.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEFEM.hpp index a8a44801952..f996e34f0ec 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEFEM.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEFEM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -60,7 +61,7 @@ class ThermalSinglePhasePoromechanicsEFEM : using Base::m_dFluidDensity_dPressure; using Base::m_porosity_n; using Base::m_surfaceArea; - using Base::m_elementVolume; + using Base::m_elementVolumeFrac; using Base::m_deltaVolume; using Base::m_cellsToEmbeddedSurfaces; using Base::m_dt; diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEFEM_impl.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEFEM_impl.hpp index 12c7f05dc3e..c5380934118 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEFEM_impl.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEFEM_impl.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -174,8 +175,8 @@ complete( localIndex const k, localIndex const embSurfIndex = m_cellsToEmbeddedSurfaces[k][0]; // Energy balance accumulation - real64 const volume = m_elementVolume( embSurfIndex ) + m_deltaVolume( embSurfIndex ); - real64 const volume_n = m_elementVolume( embSurfIndex ); + real64 const volume = m_elementVolumeFrac( embSurfIndex ) + m_deltaVolume( embSurfIndex ); + real64 const volume_n = m_elementVolumeFrac( embSurfIndex ); real64 const fluidEnergy = m_fluidDensity( embSurfIndex, 0 ) * m_fluidInternalEnergy( embSurfIndex, 0 ) * volume; real64 const fluidEnergy_n = m_fluidDensity_n( embSurfIndex, 0 ) * m_fluidInternalEnergy_n( embSurfIndex, 0 ) * volume_n; diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEmbeddedFractures.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEmbeddedFractures.hpp index 5df71d3b640..ec7184db1f5 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEmbeddedFractures.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEmbeddedFractures.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOS Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -27,9 +28,6 @@ namespace geos namespace thermalSinglePhasePoromechanicsEmbeddedFracturesKernels { -using namespace fluxKernelsHelper; -using namespace constitutive; - template< integer NUM_EQN, integer NUM_DOF > class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsEmbeddedFracturesKernels::ConnectorBasedAssemblyKernel< NUM_EQN, NUM_DOF > { @@ -44,12 +42,12 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsEmbeddedFrac template< typename VIEWTYPE > using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - using SinglePhaseFVMAbstractBase = singlePhaseFVMKernels::FaceBasedAssemblyKernelBase; + using SinglePhaseFVMAbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; using DofNumberAccessor = SinglePhaseFVMAbstractBase::DofNumberAccessor; using SinglePhaseFlowAccessors = SinglePhaseFVMAbstractBase::SinglePhaseFlowAccessors; using SinglePhaseFluidAccessors = SinglePhaseFVMAbstractBase::SinglePhaseFluidAccessors; using PermeabilityAccessors = SinglePhaseFVMAbstractBase::PermeabilityAccessors; - using FracturePermeabilityAccessors = StencilMaterialAccessors< PermeabilityBase, + using FracturePermeabilityAccessors = StencilMaterialAccessors< constitutive::PermeabilityBase, fields::permeability::dPerm_dDispJump >; using SinglePhaseFVMAbstractBase::m_dt; using SinglePhaseFVMAbstractBase::m_rankOffset; @@ -58,7 +56,7 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsEmbeddedFrac using SinglePhaseFVMAbstractBase::m_mob; using SinglePhaseFVMAbstractBase::m_dens; - using SinglePhaseFVMBase = singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; + using SinglePhaseFVMBase = singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; using SinglePhaseFVMBase::numDof; using SinglePhaseFVMBase::numEqn; using SinglePhaseFVMBase::maxNumElems; @@ -77,14 +75,14 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsEmbeddedFrac fields::flow::dMobility_dTemperature >; using ThermalSinglePhaseFluidAccessors = - StencilMaterialAccessors< SingleFluidBase, + StencilMaterialAccessors< constitutive::SingleFluidBase, fields::singlefluid::dDensity_dTemperature, fields::singlefluid::enthalpy, fields::singlefluid::dEnthalpy_dPressure, fields::singlefluid::dEnthalpy_dTemperature >; using ThermalConductivityAccessors = - StencilMaterialAccessors< SinglePhaseThermalConductivityBase, + StencilMaterialAccessors< constitutive::SinglePhaseThermalConductivityBase, fields::thermalconductivity::effectiveConductivity >; @@ -206,25 +204,25 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsEmbeddedFrac real64 trans[2] = {stack.transmissibility[0][0], stack.transmissibility[0][1]}; real64 dMassFlux_dT[2]{}; - computeEnthalpyFlux( seri, sesri, sei, - trans, - m_enthalpy, - m_dEnthalpy_dPres, - m_dEnthalpy_dTemp, - m_gravCoef, - m_dDens_dTemp, - m_dMob_dTemp, - alpha, - mobility, - potGrad, - massFlux, - dMassFlux_dTrans, - dMassFlux_dP, - dMassFlux_dT, - stack.energyFlux, - stack.dEnergyFlux_dTrans, - stack.dEnergyFlux_dP, - stack.dEnergyFlux_dT ); + singlePhaseFluxKernelsHelper::computeEnthalpyFlux( seri, sesri, sei, + trans, + m_enthalpy, + m_dEnthalpy_dPres, + m_dEnthalpy_dTemp, + m_gravCoef, + m_dDens_dTemp, + m_dMob_dTemp, + alpha, + mobility, + potGrad, + massFlux, + dMassFlux_dTrans, + dMassFlux_dP, + dMassFlux_dT, + stack.energyFlux, + stack.dEnergyFlux_dTrans, + stack.dEnergyFlux_dP, + stack.dEnergyFlux_dT ); for( localIndex i=0; i < 3; i++ ) { @@ -273,7 +271,7 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsEmbeddedFrac localIndex const sei[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; // Step 2: compute temperature difference at the interface - computeConductiveFlux( seri, sesri, sei, m_temp, thermalTrans, stack.energyFlux, stack.dEnergyFlux_dT ); + singlePhaseFluxKernelsHelper::computeConductiveFlux( seri, sesri, sei, m_temp, thermalTrans, stack.energyFlux, stack.dEnergyFlux_dT ); // add energyFlux and its derivatives to localFlux and localFluxJacobian stack.localFlux[k[0]*numEqn + numEqn - 1] += m_dt * stack.energyFlux; @@ -345,7 +343,7 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsEmbeddedFrac /** - * @class FaceBasedAssemblyKernelFactory + * @class ConnectorBasedAssemblyKernelFactory */ class ConnectorBasedAssemblyKernelFactory { diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanics_impl.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanics_impl.hpp index 4974aa6fd27..786ad448381 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanics_impl.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanics_impl.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -46,6 +47,7 @@ ThermalSinglePhasePoromechanics( NodeManager const & nodeManager, real64 const inputDt, real64 const (&gravityVector)[3], string const inputFlowDofKey, + integer const performStressInitialization, string const fluidModelKey ): Base( nodeManager, edgeManager, @@ -61,6 +63,7 @@ ThermalSinglePhasePoromechanics( NodeManager const & nodeManager, inputDt, gravityVector, inputFlowDofKey, + performStressInitialization, fluidModelKey ), m_dFluidDensity_dTemperature( elementSubRegion.template getConstitutiveModel< constitutive::SingleFluidBase >( elementSubRegion.template getReference< string >( fluidModelKey ) ).dDensity_dTemperature() ), @@ -111,9 +114,9 @@ smallStrainUpdate( localIndex const k, // Step 1: call the constitutive model to evaluate the total stress and compute porosity m_constitutiveUpdate.smallStrainUpdatePoromechanics( k, q, - m_pressure_n[k], - m_pressure[k], m_dt, + m_pressure[k], + m_pressure_n[k], stack.temperature, stack.deltaTemperatureFromLastStep, stack.strainIncrement, @@ -121,6 +124,7 @@ smallStrainUpdate( localIndex const k, stack.dTotalStress_dPressure, stack.dTotalStress_dTemperature, stack.stiffness, + m_performStressInitialization, porosity, porosity_n, dPorosity_dVolStrain, diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermoPoromechanicsKernels.cpp.template b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermoPoromechanicsKernels.cpp.template index 41201ad1c40..8523ae35545 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermoPoromechanicsKernels.cpp.template +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermoPoromechanicsKernels.cpp.template @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #include "physicsSolvers/multiphysics/poromechanicsKernels/MultiphasePoromechanics_impl.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanics_impl.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEFEM_impl.hpp" diff --git a/src/coreComponents/physicsSolvers/python/CMakeLists.txt b/src/coreComponents/physicsSolvers/python/CMakeLists.txt new file mode 100644 index 00000000000..218447f9231 --- /dev/null +++ b/src/coreComponents/physicsSolvers/python/CMakeLists.txt @@ -0,0 +1,15 @@ + +if( ENABLE_PYGEOSX ) + set( physicsSolvers_headers + ${physicsSolvers_headers} + python/PySolver.hpp + python/PySolverType.hpp + PARENT_SCOPE ) + set( physicsSolvers_sources + ${physicsSolvers_sources} + python/PySolver.cpp + PARENT_SCOPE ) + + set( dependencyList ${dependencyList} Python3::Python pylvarray PARENT_SCOPE) +endif() + diff --git a/src/coreComponents/physicsSolvers/python/PySolver.cpp b/src/coreComponents/physicsSolvers/python/PySolver.cpp index b4feca82892..befc482dc15 100644 --- a/src/coreComponents/physicsSolvers/python/PySolver.cpp +++ b/src/coreComponents/physicsSolvers/python/PySolver.cpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #define PY_SSIZE_T_CLEAN #include @@ -5,6 +20,7 @@ #include "PySolver.hpp" #include "dataRepository/python/PyGroupType.hpp" #include "PySolverType.hpp" +#include "mesh/DomainPartition.hpp" #define VERIFY_NON_NULL_SELF( self ) \ PYTHON_ERROR_IF( self == nullptr, PyExc_RuntimeError, "Passed a nullptr as self.", nullptr ) @@ -22,9 +38,9 @@ struct PySolver PyObject_HEAD static constexpr char const * docString = - "A Python interface to geos::SolverBase."; + "A Python interface to geos::PhysicsSolverBase."; - geos::SolverBase * group; + geos::PhysicsSolverBase *group; }; diff --git a/src/coreComponents/physicsSolvers/python/PySolver.hpp b/src/coreComponents/physicsSolvers/python/PySolver.hpp index 17134398300..968f7a6dffe 100644 --- a/src/coreComponents/physicsSolvers/python/PySolver.hpp +++ b/src/coreComponents/physicsSolvers/python/PySolver.hpp @@ -1,6 +1,21 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #ifndef GEOS_PYTHON_PYSOLVER_HPP_ #define GEOS_PYTHON_PYSOLVER_HPP_ -#include "physicsSolvers/SolverBase.hpp" +#include "physicsSolvers/PhysicsSolverBase.hpp" #endif diff --git a/src/coreComponents/physicsSolvers/python/PySolverType.hpp b/src/coreComponents/physicsSolvers/python/PySolverType.hpp index eda3df1f223..aa59dd45f70 100644 --- a/src/coreComponents/physicsSolvers/python/PySolverType.hpp +++ b/src/coreComponents/physicsSolvers/python/PySolverType.hpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #ifndef GEOS_PYTHON_PYSOLVERTYPE_HPP_ #define GEOS_PYTHON_PYSOLVERTYPE_HPP_ diff --git a/src/coreComponents/physicsSolvers/simplePDE/CMakeLists.txt b/src/coreComponents/physicsSolvers/simplePDE/CMakeLists.txt new file mode 100644 index 00000000000..66521ed88ce --- /dev/null +++ b/src/coreComponents/physicsSolvers/simplePDE/CMakeLists.txt @@ -0,0 +1,17 @@ +# Specify solver headers +set( physicsSolvers_headers + ${physicsSolvers_headers} + simplePDE/LaplaceBaseH1.hpp + simplePDE/LaplaceFEM.hpp + simplePDE/LaplaceFEMKernels.hpp + simplePDE/PhaseFieldDamageFEM.hpp + simplePDE/PhaseFieldDamageFEMKernels.hpp + PARENT_SCOPE ) + +# Specify solver sources +set( physicsSolvers_sources + ${physicsSolvers_sources} + simplePDE/LaplaceBaseH1.cpp + simplePDE/LaplaceFEM.cpp + simplePDE/PhaseFieldDamageFEM.cpp + PARENT_SCOPE ) diff --git a/src/coreComponents/physicsSolvers/simplePDE/LaplaceBaseH1.cpp b/src/coreComponents/physicsSolvers/simplePDE/LaplaceBaseH1.cpp index 448ec383e76..f873ad46826 100644 --- a/src/coreComponents/physicsSolvers/simplePDE/LaplaceBaseH1.cpp +++ b/src/coreComponents/physicsSolvers/simplePDE/LaplaceBaseH1.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,6 +22,7 @@ #include "dataRepository/InputFlags.hpp" #include "mainInterface/GeosxState.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" +#include "mesh/DomainPartition.hpp" namespace geos { @@ -30,7 +32,7 @@ using namespace dataRepository; //START_SPHINX_INCLUDE_CONSTRUCTOR LaplaceBaseH1::LaplaceBaseH1( const string & name, Group * const parent ): - SolverBase( name, parent ), + PhysicsSolverBase( name, parent ), m_fieldName( "primaryField" ), m_timeIntegrationOption( TimeIntegrationOption::ImplicitTransient ) { @@ -87,8 +89,8 @@ void LaplaceBaseH1::registerDataOnMesh( Group & meshBodies ) Here, we decide how we march in time in the resolutions based on the possible two options set in the XML file (Steady state or Implicit transient). In the case of Implicit transient, we perform an implicit step (backward Euler). The implementation of the Implicit Step is found in the - SolverBase. From now on, we oscillate between specific Laplace solver operations if implemented - and more generic SolverBase operations. The initial values of the solver step are all at time_n, + PhysicsSolverBase. From now on, we oscillate between specific Laplace solver operations if implemented + and more generic PhysicsSolverBase operations. The initial values of the solver step are all at time_n, and the solver attempts to advance by a time step of dt. This dt time step size is specified initially by the user and the solverStep method also returns its value. */ @@ -103,7 +105,7 @@ real64 LaplaceBaseH1::solverStep( real64 const & time_n, /* IMPLICIT STEP SETUP - This method uses the system setup from SolverBase (see below). + This method uses the system setup from PhysicsSolverBase (see below). The current system of this class does not use the time variable. The macro GEOS_UNUSED_PARAM is therefore used here to avoid a compilation error. */ @@ -173,7 +175,7 @@ void LaplaceBaseH1::updateState( DomainPartition & domain ) /* APPLY BOUNDARY CONDITIONS - Here, this call is the generic call from SolverBase. + Here, this call is the generic call from PhysicsSolverBase. All it does is to call a specific Dirichlet boundary condition implemented for this solver */ void LaplaceBaseH1::applyBoundaryConditions( real64 const time_n, diff --git a/src/coreComponents/physicsSolvers/simplePDE/LaplaceBaseH1.hpp b/src/coreComponents/physicsSolvers/simplePDE/LaplaceBaseH1.hpp index e1c10bd008f..88bcf008b26 100644 --- a/src/coreComponents/physicsSolvers/simplePDE/LaplaceBaseH1.hpp +++ b/src/coreComponents/physicsSolvers/simplePDE/LaplaceBaseH1.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -15,18 +16,18 @@ #ifndef GEOS_PHYSICSSOLVERS_SIMPLEPDE_LAPLACE_BASE_HPP #define GEOS_PHYSICSSOLVERS_SIMPLEPDE_LAPLACE_BASE_HPP -#include "codingUtilities/EnumStrings.hpp" // facilities for enum-string conversion (for reading enum values from XML input) -#include "physicsSolvers/SolverBase.hpp" // an abstraction class shared by all physics solvers +#include "common/format/EnumStrings.hpp" // facilities for enum-string conversion (for reading enum values from XML input) +#include "physicsSolvers/PhysicsSolverBase.hpp" // an abstraction class shared by all physics solvers #include "fieldSpecification/FieldSpecificationManager.hpp" // a manager that can access and set values on the discretized domain namespace geos { -// Like most physics solvers, the Laplace solver derives from a generic SolverBase class. +// Like most physics solvers, the Laplace solver derives from a generic PhysicsSolverBase class. // The base class is densely Doxygen-commented and worth a look if you have not done so already. // Most important system assembly steps, linear and non-linear resolutions, and time-stepping mechanisms -// are implemented at the SolverBase class level and can thus be used in Laplace without needing reimplementation. -class LaplaceBaseH1 : public SolverBase +// are implemented at the PhysicsSolverBase class level and can thus be used in Laplace without needing reimplementation. +class LaplaceBaseH1 : public PhysicsSolverBase { public: /// The default nullary constructor is disabled to avoid compiler auto-generation: @@ -110,7 +111,7 @@ class LaplaceBaseH1 : public SolverBase /// This structure stores ``dataRepository::ViewKey`` objects used as binding between the input /// XML tags and source code variables (here, timeIntegrationOption and fieldVarName) //START_SPHINX_INCLUDE_VIEWKEY - struct viewKeyStruct : public SolverBase::viewKeyStruct + struct viewKeyStruct : public PhysicsSolverBase::viewKeyStruct { static constexpr char const * timeIntegrationOption() { return "timeIntegrationOption"; } static constexpr char const * fieldVarName() { return "fieldName"; } diff --git a/src/coreComponents/physicsSolvers/simplePDE/LaplaceFEM.cpp b/src/coreComponents/physicsSolvers/simplePDE/LaplaceFEM.cpp index 67750038218..2feaab25a0b 100644 --- a/src/coreComponents/physicsSolvers/simplePDE/LaplaceFEM.cpp +++ b/src/coreComponents/physicsSolvers/simplePDE/LaplaceFEM.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,6 +17,8 @@ * @file LaplaceFEM.cpp */ +#include "mesh/DomainPartition.hpp" + // Source includes #include "LaplaceFEM.hpp" #include "LaplaceFEMKernels.hpp" @@ -64,7 +67,7 @@ using namespace dataRepository; /* CONSTRUCTOR First, let us inspect the constructor of a "LaplaceFEM" object. This constructor does three important things: - 1 - It constructs an instance of the LaplaceFEM class (here: using the SolverBase constructor and passing through the arguments). + 1 - It constructs an instance of the LaplaceFEM class (here: using the PhysicsSolverBase constructor and passing through the arguments). 2 - It sets some default values for the LaplaceFEM-specific private variables (here: m_fieldName and m_timeIntegrationOption). 3 - It creates and activates a "registerWrapper" for each private variable. This is where the private variables are declared either as REQUIRED or OPTIONAL. @@ -96,7 +99,7 @@ void LaplaceFEM::setupSystem( DomainPartition & domain, bool const setSparsity ) { GEOS_MARK_FUNCTION; - SolverBase::setupSystem( domain, dofManager, localMatrix, rhs, solution, setSparsity ); + PhysicsSolverBase::setupSystem( domain, dofManager, localMatrix, rhs, solution, setSparsity ); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & mesh, @@ -176,6 +179,6 @@ void LaplaceFEM::assembleSystem( real64 const GEOS_UNUSED_PARAM( time_n ), //END_SPHINX_INCLUDE_ASSEMBLY //START_SPHINX_INCLUDE_REGISTER -REGISTER_CATALOG_ENTRY( SolverBase, LaplaceFEM, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, LaplaceFEM, string const &, Group * const ) //END_SPHINX_INCLUDE_REGISTER } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/simplePDE/LaplaceFEM.hpp b/src/coreComponents/physicsSolvers/simplePDE/LaplaceFEM.hpp index 74a83834a19..802d6cb1bca 100644 --- a/src/coreComponents/physicsSolvers/simplePDE/LaplaceFEM.hpp +++ b/src/coreComponents/physicsSolvers/simplePDE/LaplaceFEM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,10 +21,10 @@ namespace geos { -// Like most physics solvers, the Laplace solver derives from a generic SolverBase class. +// Like most physics solvers, the Laplace solver derives from a generic PhysicsSolverBase class. // The base class is densely Doxygen-commented and worth a look if you have not done so already. // Most important system assembly steps, linear and non-linear resolutions, and time-stepping mechanisms -// are implemented at the SolverBase class level and can thus be used in Laplace without needing reimplementation. +// are implemented at the PhysicsSolverBase class level and can thus be used in Laplace without needing reimplementation. //START_SPHINX_INCLUDE_BEGINCLASS class LaplaceFEM : public LaplaceBaseH1 @@ -44,7 +45,7 @@ class LaplaceFEM : public LaplaceBaseH1 /// this C++ classes. This is important. static string catalogName() { return "LaplaceFEM"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } diff --git a/src/coreComponents/physicsSolvers/simplePDE/LaplaceFEMKernels.hpp b/src/coreComponents/physicsSolvers/simplePDE/LaplaceFEMKernels.hpp index 2c9023a79d4..6d992ba0134 100644 --- a/src/coreComponents/physicsSolvers/simplePDE/LaplaceFEMKernels.hpp +++ b/src/coreComponents/physicsSolvers/simplePDE/LaplaceFEMKernels.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #ifndef GEOS_PHYSICSSOLVERS_SIMPLEPDE_LAPLACEFEMKERNELS_HPP_ #define GEOS_PHYSICSSOLVERS_SIMPLEPDE_LAPLACEFEMKERNELS_HPP_ -#define GEOSX_DISPATCH_VEM /// enables VEM in FiniteElementDispatch +#define GEOS_DISPATCH_VEM /// enables VEM in FiniteElementDispatch #include "finiteElement/kernelInterface/ImplicitKernelBase.hpp" diff --git a/src/coreComponents/physicsSolvers/simplePDE/PhaseFieldDamageFEM.cpp b/src/coreComponents/physicsSolvers/simplePDE/PhaseFieldDamageFEM.cpp index 75818129611..72d275cd39e 100644 --- a/src/coreComponents/physicsSolvers/simplePDE/PhaseFieldDamageFEM.cpp +++ b/src/coreComponents/physicsSolvers/simplePDE/PhaseFieldDamageFEM.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -54,7 +55,7 @@ using namespace constitutive; PhaseFieldDamageFEM::PhaseFieldDamageFEM( const string & name, Group * const parent ): - SolverBase( name, parent ), + PhysicsSolverBase( name, parent ), m_fieldName( "primaryField" ) { @@ -116,7 +117,7 @@ void PhaseFieldDamageFEM::registerDataOnMesh( Group & meshBodies ) setSizedFromParent( 0 ); string & solidMaterialName = subRegion.getReference< string >( viewKeyStruct::solidModelNamesString() ); - solidMaterialName = SolverBase::getConstitutiveName< SolidBase >( subRegion ); + solidMaterialName = PhysicsSolverBase::getConstitutiveName< SolidBase >( subRegion ); GEOS_ERROR_IF( solidMaterialName.empty(), GEOS_FMT( "{}: SolidBase model not found on subregion {}", getDataContext(), subRegion.getName() ) ); @@ -124,9 +125,9 @@ void PhaseFieldDamageFEM::registerDataOnMesh( Group & meshBodies ) } ); } -void PhaseFieldDamageFEM::postProcessInput() +void PhaseFieldDamageFEM::postInputInitialization() { - SolverBase::postProcessInput(); + PhysicsSolverBase::postInputInitialization(); // Set basic parameters for solver // m_linearSolverParameters.logLevel = 0; @@ -519,8 +520,8 @@ PhaseFieldDamageFEM::calculateResidualNorm( real64 const & GEOS_UNUSED_PARAM( ti // globalResidualNorm[1]: max of max force of each rank. Basically max force globally real64 globalResidualNorm[2] = {0, 0}; - const int rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); - const int size = MpiWrapper::commSize( MPI_COMM_GEOSX ); + const int rank = MpiWrapper::commRank( MPI_COMM_GEOS ); + const int size = MpiWrapper::commSize( MPI_COMM_GEOS ); array1d< real64 > globalValues( size * 2 ); // Everything is done on rank 0 @@ -529,7 +530,7 @@ PhaseFieldDamageFEM::calculateResidualNorm( real64 const & GEOS_UNUSED_PARAM( ti globalValues.data(), 2, 0, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); if( rank==0 ) { @@ -541,7 +542,7 @@ PhaseFieldDamageFEM::calculateResidualNorm( real64 const & GEOS_UNUSED_PARAM( ti } } - MpiWrapper::bcast( globalResidualNorm, 2, 0, MPI_COMM_GEOSX ); + MpiWrapper::bcast( globalResidualNorm, 2, 0, MPI_COMM_GEOS ); const real64 residual = sqrt( globalResidualNorm[0] ) / ( globalResidualNorm[1] ); @@ -645,11 +646,11 @@ void PhaseFieldDamageFEM::applyIrreversibilityConstraint( DofManager const & dof } ); } -void PhaseFieldDamageFEM::saveSequentialIterationState( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) const +void PhaseFieldDamageFEM::saveSequentialIterationState( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) { // nothing to save yet } -REGISTER_CATALOG_ENTRY( SolverBase, PhaseFieldDamageFEM, string const &, +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, PhaseFieldDamageFEM, string const &, Group * const ) } // namespace geos diff --git a/src/coreComponents/physicsSolvers/simplePDE/PhaseFieldDamageFEM.hpp b/src/coreComponents/physicsSolvers/simplePDE/PhaseFieldDamageFEM.hpp index 6c623e73fe3..afd53e8aa5c 100644 --- a/src/coreComponents/physicsSolvers/simplePDE/PhaseFieldDamageFEM.hpp +++ b/src/coreComponents/physicsSolvers/simplePDE/PhaseFieldDamageFEM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -22,7 +23,7 @@ #include "linearAlgebra/DofManager.hpp" #include "linearAlgebra/interfaces/InterfaceTypes.hpp" #include "fieldSpecification/FieldSpecificationManager.hpp" -#include "physicsSolvers/SolverBase.hpp" +#include "physicsSolvers/PhysicsSolverBase.hpp" struct stabledt { @@ -39,7 +40,7 @@ class FieldSpecificationBase; class FiniteElementBase; class DomainPartition; -class PhaseFieldDamageFEM : public SolverBase +class PhaseFieldDamageFEM : public PhysicsSolverBase { public: PhaseFieldDamageFEM( const string & name, Group * const parent ); @@ -51,7 +52,7 @@ class PhaseFieldDamageFEM : public SolverBase return "PhaseFieldDamageFEM"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -131,7 +132,7 @@ class PhaseFieldDamageFEM : public SolverBase CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ); - virtual void saveSequentialIterationState( DomainPartition & domain ) const override; + virtual void saveSequentialIterationState( DomainPartition & domain ) override; enum class TimeIntegrationOption { @@ -146,7 +147,7 @@ class PhaseFieldDamageFEM : public SolverBase Quadratic, }; - struct viewKeyStruct : public SolverBase::viewKeyStruct + struct viewKeyStruct : public PhysicsSolverBase::viewKeyStruct { static constexpr char const * coeffNameString() { return "coeffField"; } static constexpr char const * localDissipationOptionString() { return "localDissipation"; } @@ -174,7 +175,7 @@ class PhaseFieldDamageFEM : public SolverBase } protected: - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; private: string m_fieldName; diff --git a/src/coreComponents/physicsSolvers/simplePDE/PhaseFieldDamageFEMKernels.hpp b/src/coreComponents/physicsSolvers/simplePDE/PhaseFieldDamageFEMKernels.hpp index c991e076398..80296a11b44 100644 --- a/src/coreComponents/physicsSolvers/simplePDE/PhaseFieldDamageFEMKernels.hpp +++ b/src/coreComponents/physicsSolvers/simplePDE/PhaseFieldDamageFEMKernels.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/solidMechanics/CMakeLists.txt b/src/coreComponents/physicsSolvers/solidMechanics/CMakeLists.txt new file mode 100644 index 00000000000..2b0cfeb2233 --- /dev/null +++ b/src/coreComponents/physicsSolvers/solidMechanics/CMakeLists.txt @@ -0,0 +1,37 @@ +# Specify solver headers +set( physicsSolvers_headers + ${physicsSolvers_headers} + solidMechanics/LogLevelsInfo.hpp + solidMechanics/SolidMechanicsFields.hpp + solidMechanics/SolidMechanicsLagrangianFEM.hpp + solidMechanics/SolidMechanicsLagrangianFEM.hpp + solidMechanics/SolidMechanicsLagrangianSSLE.hpp + solidMechanics/kernels/SolidMechanicsLagrangianFEMKernels.hpp + solidMechanics/SolidMechanicsMPM.hpp + solidMechanics/MPMSolverFields.hpp + solidMechanics/kernels/ExplicitFiniteStrain.hpp + solidMechanics/kernels/ExplicitFiniteStrain_impl.hpp + solidMechanics/kernels/ExplicitMPM.hpp + solidMechanics/kernels/ExplicitSmallStrain.hpp + solidMechanics/kernels/ExplicitSmallStrain_impl.hpp + solidMechanics/kernels/FixedStressThermoPoromechanics.hpp + solidMechanics/kernels/FixedStressThermoPoromechanics_impl.hpp + solidMechanics/kernels/ImplicitSmallStrainNewmark.hpp + solidMechanics/kernels/ImplicitSmallStrainNewmark_impl.hpp + solidMechanics/kernels/ImplicitSmallStrainQuasiStatic.hpp + solidMechanics/kernels/ImplicitSmallStrainQuasiStatic_impl.hpp + solidMechanics/SolidMechanicsStateReset.hpp + solidMechanics/SolidMechanicsStatistics.hpp + PARENT_SCOPE ) + +# Specify solver sources +set( physicsSolvers_sources + ${physicsSolvers_sources} + solidMechanics/SolidMechanicsLagrangianFEM.cpp + solidMechanics/SolidMechanicsLagrangianSSLE.cpp + solidMechanics/SolidMechanicsMPM.cpp + solidMechanics/SolidMechanicsStateReset.cpp + solidMechanics/SolidMechanicsStatistics.cpp + PARENT_SCOPE ) + +#include( solidMechanics/kernels/SolidMechanicsKernels.cmake) diff --git a/src/coreComponents/physicsSolvers/solidMechanics/LogLevelsInfo.hpp b/src/coreComponents/physicsSolvers/solidMechanics/LogLevelsInfo.hpp new file mode 100644 index 00000000000..27e59cf4709 --- /dev/null +++ b/src/coreComponents/physicsSolvers/solidMechanics/LogLevelsInfo.hpp @@ -0,0 +1,52 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file LogLevelsInfo.hpp + * This file contains log level informations for flow solvers + */ + +#ifndef GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_LOGLEVELSINFO_HPP +#define GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_LOGLEVELSINFO_HPP + +#include "common/DataTypes.hpp" + +namespace geos +{ + +namespace logInfo +{ + +/** + * @name Wells LogLevels info structures. They must comply with the `is_log_level_info` trait. + */ +///@{ + +/// @cond DO_NOT_DOCUMENT + +struct Statistics +{ + static constexpr int getMinLogLevel() { return 1; } + static constexpr std::string_view getDescription() { return "Print statistics"; } +}; + +/// @endcond +///@} + +} + +} + +#endif // GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_LOGLEVELSINFO_HPP diff --git a/src/coreComponents/physicsSolvers/solidMechanics/MPMSolverFields.hpp b/src/coreComponents/physicsSolvers/solidMechanics/MPMSolverFields.hpp index d83751c0c99..2f77032716b 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/MPMSolverFields.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/MPMSolverFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,8 +17,8 @@ * @file MPMSolverBaseFields.hpp */ -#ifndef GEOSX_PHYSICSSOLVERS_SOLIDMECHANICS_MPMSOLVERBASEFIELDS_HPP_ -#define GEOSX_PHYSICSSOLVERS_SOLIDMECHANICS_MPMSOLVERBASEFIELDS_HPP_ +#ifndef GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_MPMSOLVERBASEFIELDS_HPP_ +#define GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_MPMSOLVERBASEFIELDS_HPP_ #include "mesh/MeshFields.hpp" @@ -149,4 +150,4 @@ DECLARE_FIELD( particleReferencePosition, } -#endif // GEOSX_PHYSICSSOLVERS_SOLIDMECHANICS_MPMSOLVERBASEFIELDS_HPP_ +#endif // GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_MPMSOLVERBASEFIELDS_HPP_ diff --git a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsFields.hpp b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsFields.hpp index 3604c3d82a1..68117918b7f 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsFields.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -41,6 +42,10 @@ using array2dLayoutIncrDisplacement = array2d< real64, nodes::INCR_DISPLACEMENT_ using arrayView2dLayoutIncrDisplacement = arrayView2d< real64, nodes::INCR_DISPLACEMENT_USD >; using arrayViewConst2dLayoutIncrDisplacement = arrayView2d< real64 const, nodes::INCR_DISPLACEMENT_USD >; +using array2dLayoutStrain = array2d< real64, cells::STRAIN_PERM >; +using arrayView2dLayoutStrain = arrayView2d< real64, cells::STRAIN_USD >; +using arrayViewConst2dLayoutStrain = arrayView2d< real64 const, cells::STRAIN_USD >; + using array2dLayoutVelocity = array2d< real64, nodes::VELOCITY_PERM >; using arrayView2dLayoutVelocity = arrayView2d< real64, nodes::VELOCITY_USD >; using arrayViewConst2dLayoutVelocity = arrayView2d< real64 const, nodes::VELOCITY_USD >; @@ -58,6 +63,14 @@ DECLARE_FIELD( totalDisplacement, WRITE_AND_READ, "Total displacements at the nodes" ); +DECLARE_FIELD( totalBubbleDisplacement, + "totalBubbleDisplacement", + array2d< real64 >, + 0, + LEVEL_0, + WRITE_AND_READ, + "Total bubble displacements at the faces" ); + DECLARE_FIELD( incrementalDisplacement, "incrementalDisplacement", array2dLayoutIncrDisplacement, @@ -66,6 +79,22 @@ DECLARE_FIELD( incrementalDisplacement, WRITE_AND_READ, "Incremental displacements for the current time step on the nodes" ); +DECLARE_FIELD( strain, + "strain", + array2dLayoutStrain, + 0, + LEVEL_0, + WRITE_AND_READ, + "Average strain in cell" ); + +DECLARE_FIELD( incrementalBubbleDisplacement, + "incrementalBubbleDisplacement", + array2d< real64 >, + 0, + LEVEL_3, + WRITE_AND_READ, + "Incremental bubble displacements for the current time step on the nodes" ); + DECLARE_FIELD( velocity, "velocity", array2dLayoutVelocity, diff --git a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.cpp b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.cpp index f76259f186b..70cb8b3c56e 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.cpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,7 +17,7 @@ * @file SolidMechanicsLagrangianFEM.cpp */ -#define GEOSX_DISPATCH_VEM /// enables VEM in FiniteElementDispatch +#define GEOS_DISPATCH_VEM /// enables VEM in FiniteElementDispatch #include "SolidMechanicsLagrangianFEM.hpp" #include "kernels/ImplicitSmallStrainNewmark.hpp" @@ -27,7 +28,6 @@ #include "codingUtilities/Utilities.hpp" #include "constitutive/ConstitutiveManager.hpp" -#include "constitutive/contact/ContactBase.hpp" #include "common/GEOS_RAJA_Interface.hpp" #include "discretizationMethods/NumericalMethodsManager.hpp" #include "fieldSpecification/FieldSpecificationManager.hpp" @@ -50,7 +50,7 @@ using namespace fields; SolidMechanicsLagrangianFEM::SolidMechanicsLagrangianFEM( const string & name, Group * const parent ): - SolverBase( name, parent ), + PhysicsSolverBase( name, parent ), m_newmarkGamma( 0.5 ), m_newmarkBeta( 0.25 ), m_massDamping( 0.0 ), @@ -59,7 +59,6 @@ SolidMechanicsLagrangianFEM::SolidMechanicsLagrangianFEM( const string & name, m_maxForce( 0.0 ), m_maxNumResolves( 10 ), m_strainTheory( 0 ), - m_iComm( CommunicationTools::getInstance().getCommID() ), m_isFixedStressPoromechanicsUpdate( false ) { @@ -116,22 +115,29 @@ SolidMechanicsLagrangianFEM::SolidMechanicsLagrangianFEM( const string & name, setInputFlag( InputFlags::OPTIONAL ). setDescription( "Name of contact relation to enforce constraints on fracture boundary." ); + registerWrapper( viewKeyStruct::contactPenaltyStiffnessString(), &m_contactPenaltyStiffness ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( 0.0 ). + setDescription( "Value of the penetration penalty stiffness. Units of Pressure/length" ); + registerWrapper( viewKeyStruct::maxForceString(), &m_maxForce ). setInputFlag( InputFlags::FALSE ). setDescription( "The maximum force contribution in the problem domain." ); } -void SolidMechanicsLagrangianFEM::postProcessInput() +void SolidMechanicsLagrangianFEM::postInputInitialization() { - SolverBase::postProcessInput(); + PhysicsSolverBase::postInputInitialization(); + // configure AMG LinearSolverParameters & linParams = m_linearSolverParameters.get(); linParams.isSymmetric = true; linParams.dofsPerNode = 3; + linParams.amg.numFunctions = linParams.dofsPerNode; linParams.amg.separateComponents = true; - m_surfaceGenerator = this->getParent().getGroupPointer< SolverBase >( m_surfaceGeneratorName ); + m_surfaceGenerator = this->getParent().getGroupPointer< PhysicsSolverBase >( m_surfaceGeneratorName ); } SolidMechanicsLagrangianFEM::~SolidMechanicsLagrangianFEM() @@ -142,6 +148,8 @@ SolidMechanicsLagrangianFEM::~SolidMechanicsLagrangianFEM() void SolidMechanicsLagrangianFEM::registerDataOnMesh( Group & meshBodies ) { + string const voightLabels[6] = { "XX", "YY", "ZZ", "YZ", "XZ", "XY" }; + forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, MeshLevel & meshLevel, arrayView1d< string const > const & regionNames ) @@ -152,6 +160,8 @@ void SolidMechanicsLagrangianFEM::registerDataOnMesh( Group & meshBodies ) ElementSubRegionBase & subRegion ) { setConstitutiveNamesCallSuper( subRegion ); + + subRegion.registerField< solidMechanics::strain >( getName() ).setDimLabels( 1, voightLabels ).reference().resizeDimension< 1 >( 6 ); } ); NodeManager & nodes = meshLevel.getNodeManager(); @@ -220,7 +230,7 @@ void SolidMechanicsLagrangianFEM::registerDataOnMesh( Group & meshBodies ) void SolidMechanicsLagrangianFEM::setConstitutiveNamesCallSuper( ElementSubRegionBase & subRegion ) const { - SolverBase::setConstitutiveNamesCallSuper( subRegion ); + PhysicsSolverBase::setConstitutiveNamesCallSuper( subRegion ); subRegion.registerWrapper< string >( viewKeyStruct::solidMaterialNamesString() ). setPlotLevel( PlotLevel::NOPLOT ). @@ -228,7 +238,7 @@ void SolidMechanicsLagrangianFEM::setConstitutiveNamesCallSuper( ElementSubRegio setSizedFromParent( 0 ); string & solidMaterialName = subRegion.getReference< string >( viewKeyStruct::solidMaterialNamesString() ); - solidMaterialName = SolverBase::getConstitutiveName< SolidBase >( subRegion ); + solidMaterialName = PhysicsSolverBase::getConstitutiveName< SolidBase >( subRegion ); GEOS_ERROR_IF( solidMaterialName.empty(), GEOS_FMT( "{}: SolidBase model not found on subregion {}", getDataContext(), subRegion.getDataContext() ) ); @@ -236,7 +246,7 @@ void SolidMechanicsLagrangianFEM::setConstitutiveNamesCallSuper( ElementSubRegio void SolidMechanicsLagrangianFEM::initializePreSubGroups() { - SolverBase::initializePreSubGroups(); + PhysicsSolverBase::initializePreSubGroups(); DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); @@ -251,7 +261,7 @@ void SolidMechanicsLagrangianFEM::initializePreSubGroups() CellElementSubRegion & subRegion ) { string & solidMaterialName = subRegion.getReference< string >( viewKeyStruct::solidMaterialNamesString() ); - solidMaterialName = SolverBase::getConstitutiveName< SolidBase >( subRegion ); + solidMaterialName = PhysicsSolverBase::getConstitutiveName< SolidBase >( subRegion ); } ); } ); @@ -504,7 +514,7 @@ real64 SolidMechanicsLagrangianFEM::solverStep( real64 const & time_n, &globallyFractured, 1, MPI_MAX, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); } if( globallyFractured == 0 ) { @@ -562,6 +572,7 @@ real64 SolidMechanicsLagrangianFEM::explicitStep( real64 const & time_n, solidMechanics::arrayView2dLayoutIncrDisplacement const & uhat = nodes.getField< solidMechanics::incrementalDisplacement >(); solidMechanics::arrayView2dLayoutAcceleration const & acc = nodes.getField< solidMechanics::acceleration >(); + MPI_iCommData m_iComm; FieldIdentifiers fieldsToBeSync; fieldsToBeSync.addFields( FieldLocation::Node, { solidMechanics::velocity::key(), @@ -715,7 +726,7 @@ void SolidMechanicsLagrangianFEM::applyDisplacementBCImplicit( real64 const time 3, MpiWrapper::getMpiOp( MpiWrapper::Reduction::Max ), 0, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); if( MpiWrapper::commRank() == 0 ) { @@ -904,6 +915,9 @@ void SolidMechanicsLagrangianFEM::implicitStepComplete( real64 const & GEOS_UNUS solidMechanics::arrayView2dLayoutIncrDisplacement const uhat = nodeManager.getField< solidMechanics::incrementalDisplacement >(); + solidMechanics::arrayView2dLayoutTotalDisplacement const disp = + nodeManager.getField< solidMechanics::totalDisplacement >(); + if( this->m_timeIntegrationOption == TimeIntegrationOption::ImplicitDynamic ) { solidMechanics::arrayView2dLayoutAcceleration const a_n = nodeManager.getField< solidMechanics::acceleration >(); @@ -933,6 +947,23 @@ void SolidMechanicsLagrangianFEM::implicitStepComplete( real64 const & GEOS_UNUS string const & solidMaterialName = subRegion.template getReference< string >( viewKeyStruct::solidMaterialNamesString() ); SolidBase & constitutiveRelation = getConstitutiveModel< SolidBase >( subRegion, solidMaterialName ); constitutiveRelation.saveConvergedState(); + + solidMechanics::arrayView2dLayoutStrain strain = subRegion.getField< solidMechanics::strain >(); + + finiteElement::FiniteElementBase & subRegionFE = subRegion.template getReference< finiteElement::FiniteElementBase >( this->getDiscretizationName()); + finiteElement::FiniteElementDispatchHandler< BASE_FE_TYPES >::dispatch3D( subRegionFE, [&] ( auto const finiteElement ) + { + using FE_TYPE = decltype( finiteElement ); + AverageStrainOverQuadraturePointsKernelFactory::createAndLaunch< CellElementSubRegion, FE_TYPE, parallelDevicePolicy<> >( nodeManager, + mesh.getEdgeManager(), + mesh.getFaceManager(), + subRegion, + finiteElement, + disp, + strain ); + } ); + + } ); } ); @@ -961,7 +992,7 @@ void SolidMechanicsLagrangianFEM::setupSystem( DomainPartition & domain, bool const setSparsity ) { GEOS_MARK_FUNCTION; - SolverBase::setupSystem( domain, dofManager, localMatrix, rhs, solution, setSparsity ); + PhysicsSolverBase::setupSystem( domain, dofManager, localMatrix, rhs, solution, setSparsity ); SparsityPattern< globalIndex > sparsityPattern( dofManager.numLocalDofs(), dofManager.numGlobalDofs(), @@ -1022,42 +1053,97 @@ void SolidMechanicsLagrangianFEM::assembleSystem( real64 const GEOS_UNUSED_PARAM localMatrix.zero(); localRhs.zero(); - if( m_isFixedStressPoromechanicsUpdate ) - { - //GEOS_UNUSED_VAR( dt ); - assemblyLaunch< constitutive::PorousSolid< ElasticIsotropic >, // TODO: change once there is a cmake solution - solidMechanicsLagrangianFEMKernels::FixedStressThermoPoromechanicsFactory >( domain, - dofManager, - localMatrix, - localRhs, - dt ); - } - else + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { - if( m_timeIntegrationOption == TimeIntegrationOption::QuasiStatic ) + if( m_isFixedStressPoromechanicsUpdate ) { - //GEOS_UNUSED_VAR( dt ); - assemblyLaunch< constitutive::SolidBase, - solidMechanicsLagrangianFEMKernels::QuasiStaticFactory >( domain, - dofManager, - localMatrix, - localRhs, - dt ); + set< string > poromechanicsRegions; + set< string > mechanicsRegions; + ElementRegionManager const & elementRegionManager = mesh.getElemManager(); + elementRegionManager.forElementSubRegions< CellElementSubRegion >( regionNames, + [&] + ( localIndex const regionIndex, auto & elementSubRegion ) + { + if( elementSubRegion.template hasWrapper< string >( FlowSolverBase::viewKeyStruct::solidNamesString() ) ) + { + poromechanicsRegions.insert( regionNames[regionIndex] ); + } + else + { + mechanicsRegions.insert( regionNames[regionIndex] ); + } + } ); + + array1d< string > poromechanicsRegionNames; + poromechanicsRegionNames.reserve( poromechanicsRegions.size()); + for( auto const & region : poromechanicsRegions ) + { + poromechanicsRegionNames.emplace_back( region ); + } + array1d< string > mechanicsRegionNames; + mechanicsRegionNames.reserve( mechanicsRegions.size()); + for( auto const & region : mechanicsRegions ) + { + mechanicsRegionNames.emplace_back( region ); + } + + // first pass for coupled poromechanics regions + real64 const poromechanicsMaxForce= assemblyLaunch< constitutive::PorousSolid< ElasticIsotropic >, // TODO: change once there is a + // cmake solution + solidMechanicsLagrangianFEMKernels::FixedStressThermoPoromechanicsFactory >( mesh, + dofManager, + poromechanicsRegionNames, + FlowSolverBase::viewKeyStruct::solidNamesString(), + localMatrix, + localRhs, + dt ); + // second pass for pure mechanics regions + real64 const mechanicsMaxForce = assemblyLaunch< constitutive::SolidBase, + solidMechanicsLagrangianFEMKernels::QuasiStaticFactory >( mesh, + dofManager, + mechanicsRegionNames, + viewKeyStruct::solidMaterialNamesString(), + localMatrix, + localRhs, + dt ); + + m_maxForce = LvArray::math::max( mechanicsMaxForce, poromechanicsMaxForce ); } - else if( m_timeIntegrationOption == TimeIntegrationOption::ImplicitDynamic ) + else { - assemblyLaunch< constitutive::SolidBase, - solidMechanicsLagrangianFEMKernels::ImplicitNewmarkFactory >( domain, - dofManager, - localMatrix, - localRhs, - dt, - m_newmarkGamma, - m_newmarkBeta, - m_massDamping, - m_stiffnessDamping ); + if( m_timeIntegrationOption == TimeIntegrationOption::QuasiStatic ) + { + m_maxForce = assemblyLaunch< constitutive::SolidBase, + solidMechanicsLagrangianFEMKernels::QuasiStaticFactory >( mesh, + dofManager, + regionNames, + viewKeyStruct::solidMaterialNamesString(), + localMatrix, + localRhs, + dt ); + } + else if( m_timeIntegrationOption == TimeIntegrationOption::ImplicitDynamic ) + { + m_maxForce = assemblyLaunch< constitutive::SolidBase, + solidMechanicsLagrangianFEMKernels::ImplicitNewmarkFactory >( mesh, + dofManager, + regionNames, + viewKeyStruct::solidMaterialNamesString(), + localMatrix, + localRhs, + dt, + m_newmarkGamma, + m_newmarkBeta, + m_massDamping, + m_stiffnessDamping ); + } } - } + } ); + + applyContactConstraint( dofManager, domain, localMatrix, localRhs ); + } void @@ -1157,14 +1243,14 @@ SolidMechanicsLagrangianFEM:: } } } ); - real64 const localResidualNorm[2] = { localSum.get(), this->m_maxForce }; + real64 const localResidualNorm[2] = { localSum.get(), m_maxForce }; // globalResidualNorm[0]: the sum of all the local sum(rhs^2). // globalResidualNorm[1]: max of max force of each rank. Basically max force globally real64 globalResidualNorm[2] = {0, 0}; - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); - int const size = MpiWrapper::commSize( MPI_COMM_GEOSX ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); + int const size = MpiWrapper::commSize( MPI_COMM_GEOS ); array1d< real64 > globalValues( size * 2 ); // Everything is done on rank 0 @@ -1173,7 +1259,7 @@ SolidMechanicsLagrangianFEM:: globalValues.data(), 2, 0, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); if( rank==0 ) { @@ -1185,11 +1271,11 @@ SolidMechanicsLagrangianFEM:: } } - MpiWrapper::bcast( globalResidualNorm, 2, 0, MPI_COMM_GEOSX ); + MpiWrapper::bcast( globalResidualNorm, 2, 0, MPI_COMM_GEOS ); - real64 const residual = sqrt( globalResidualNorm[0] )/(globalResidualNorm[1]+1); // the + 1 is for the first - // time-step when maxForce = 0; + real64 const residual = sqrt( globalResidualNorm[0] ) / ( globalResidualNorm[1] + 1 ); // the + 1 is for the first + // time-step when maxForce = 0; totalResidualNorm = std::max( residual, totalResidualNorm ); } ); @@ -1300,12 +1386,10 @@ void SolidMechanicsLagrangianFEM::applyContactConstraint( DofManager const & dof elemManager.forElementSubRegions< FaceElementSubRegion >( [&]( FaceElementSubRegion & subRegion ) { - ContactBase const & contact = getConstitutiveModel< ContactBase >( subRegion, m_contactRelationName ); - - real64 const contactStiffness = contact.stiffness(); + real64 const contactStiffness = m_contactPenaltyStiffness; arrayView1d< real64 > const area = subRegion.getElementArea(); - ArrayOfArraysView< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); + arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList().toViewConst(); // TODO: use parallel policy? forAll< serialPolicy >( subRegion.size(), [=] ( localIndex const kfe ) @@ -1393,10 +1477,10 @@ void SolidMechanicsLagrangianFEM::enableFixedStressPoromechanicsUpdate() m_isFixedStressPoromechanicsUpdate = true; } -void SolidMechanicsLagrangianFEM::saveSequentialIterationState( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) const +void SolidMechanicsLagrangianFEM::saveSequentialIterationState( DomainPartition & GEOS_UNUSED_PARAM( domain ) ) { // nothing to save } -REGISTER_CATALOG_ENTRY( SolverBase, SolidMechanicsLagrangianFEM, string const &, dataRepository::Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SolidMechanicsLagrangianFEM, string const &, dataRepository::Group * const ) } diff --git a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp index 8adbd04b132..76d98cb5143 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,13 +20,14 @@ #ifndef GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_SOLIDMECHANICSLAGRANGIANFEM_HPP_ #define GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_SOLIDMECHANICSLAGRANGIANFEM_HPP_ -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include "common/TimingMacros.hpp" #include "kernels/SolidMechanicsLagrangianFEMKernels.hpp" +#include "kernels/StrainHelper.hpp" #include "mesh/MeshForLoopInterface.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "mesh/mpiCommunications/MPI_iCommData.hpp" -#include "physicsSolvers/SolverBase.hpp" +#include "physicsSolvers/PhysicsSolverBase.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBase.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsFields.hpp" @@ -38,7 +40,7 @@ namespace geos * * This class implements a finite element solution to the equations of motion. */ -class SolidMechanicsLagrangianFEM : public SolverBase +class SolidMechanicsLagrangianFEM : public PhysicsSolverBase { public: @@ -78,11 +80,11 @@ class SolidMechanicsLagrangianFEM : public SolverBase virtual ~SolidMechanicsLagrangianFEM() override; /** - * @return The string that may be used to generate a new instance from the SolverBase::CatalogInterface::CatalogType + * @return The string that may be used to generate a new instance from the PhysicsSolverBase::CatalogInterface::CatalogType */ static string catalogName() { return "SolidMechanics_LagrangianFEM"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -172,12 +174,14 @@ class SolidMechanicsLagrangianFEM : public SolverBase template< typename CONSTITUTIVE_BASE, typename KERNEL_WRAPPER, typename ... PARAMS > - void assemblyLaunch( DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - real64 const dt, - PARAMS && ... params ); + real64 assemblyLaunch( MeshLevel & mesh, + DofManager const & dofManager, + arrayView1d< string const > const & regionNames, + string const & materialNamesString, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + real64 const dt, + PARAMS && ... params ); template< typename ... PARAMS > @@ -224,9 +228,9 @@ class SolidMechanicsLagrangianFEM : public SolverBase void enableFixedStressPoromechanicsUpdate(); - virtual void saveSequentialIterationState( DomainPartition & domain ) const override; + virtual void saveSequentialIterationState( DomainPartition & domain ) override; - struct viewKeyStruct : SolverBase::viewKeyStruct + struct viewKeyStruct : PhysicsSolverBase::viewKeyStruct { static constexpr char const * newmarkGammaString() { return "newmarkGamma"; } static constexpr char const * newmarkBetaString() { return "newmarkBeta"; } @@ -247,6 +251,9 @@ class SolidMechanicsLagrangianFEM : public SolverBase static constexpr char const * nonSendOrReceiveNodesString() { return "nonSendOrReceiveNodes";} static constexpr char const * targetNodesString() { return "targetNodes";} static constexpr char const * forceString() { return "Force";} + + static constexpr char const * contactPenaltyStiffnessString() { return "contactPenaltyStiffness"; } + }; SortedArray< localIndex > & getElemsAttachedToSendOrReceiveNodes( ElementSubRegionBase & subRegion ) @@ -260,6 +267,7 @@ class SolidMechanicsLagrangianFEM : public SolverBase } real64 & getMaxForce() { return m_maxForce; } + real64 const & getMaxForce() const { return m_maxForce; } arrayView1d< ParallelVector > const & getRigidBodyModes() const { @@ -272,7 +280,7 @@ class SolidMechanicsLagrangianFEM : public SolverBase } protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; virtual void initializePostInitialConditionsPreSubGroups() override; @@ -286,17 +294,19 @@ class SolidMechanicsLagrangianFEM : public SolverBase real64 m_maxForce = 0.0; integer m_maxNumResolves; integer m_strainTheory; - MPI_iCommData m_iComm; +// MPI_iCommData m_iComm; bool m_isFixedStressPoromechanicsUpdate; /// Rigid body modes array1d< ParallelVector > m_rigidBodyModes; + real64 m_contactPenaltyStiffness; + private: string m_contactRelationName; - SolverBase * m_surfaceGenerator; + PhysicsSolverBase *m_surfaceGenerator; string m_surfaceGeneratorName; }; @@ -313,59 +323,41 @@ ENUM_STRINGS( SolidMechanicsLagrangianFEM::TimeIntegrationOption, template< typename CONSTITUTIVE_BASE, typename KERNEL_WRAPPER, typename ... PARAMS > -void SolidMechanicsLagrangianFEM::assemblyLaunch( DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - real64 const dt, - PARAMS && ... params ) +real64 SolidMechanicsLagrangianFEM::assemblyLaunch( MeshLevel & mesh, + DofManager const & dofManager, + arrayView1d< string const > const & regionNames, + string const & materialNamesString, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + real64 const dt, + PARAMS && ... params ) { GEOS_MARK_FUNCTION; - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - NodeManager const & nodeManager = mesh.getNodeManager(); - - string const dofKey = dofManager.getKey( fields::solidMechanics::totalDisplacement::key() ); - arrayView1d< globalIndex const > const & dofNumber = nodeManager.getReference< globalIndex_array >( dofKey ); - - real64 const gravityVectorData[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3( gravityVector() ); - - KERNEL_WRAPPER kernelWrapper( dofNumber, - dofManager.rankOffset(), - localMatrix, - localRhs, - dt, - gravityVectorData, - std::forward< PARAMS >( params )... ); - - if( m_isFixedStressPoromechanicsUpdate ) - { - m_maxForce = finiteElement:: - regionBasedKernelApplication< parallelDevicePolicy< >, - CONSTITUTIVE_BASE, - CellElementSubRegion >( mesh, - regionNames, - this->getDiscretizationName(), - FlowSolverBase::viewKeyStruct::solidNamesString(), - kernelWrapper ); - } - else - { - m_maxForce = finiteElement:: - regionBasedKernelApplication< parallelDevicePolicy< >, - CONSTITUTIVE_BASE, - CellElementSubRegion >( mesh, - regionNames, - this->getDiscretizationName(), - viewKeyStruct::solidMaterialNamesString(), - kernelWrapper ); - } - } ); - - applyContactConstraint( dofManager, domain, localMatrix, localRhs ); + NodeManager const & nodeManager = mesh.getNodeManager(); + + string const dofKey = dofManager.getKey( fields::solidMechanics::totalDisplacement::key() ); + arrayView1d< globalIndex const > const & dofNumber = nodeManager.getReference< globalIndex_array >( dofKey ); + + real64 const gravityVectorData[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3( gravityVector() ); + + KERNEL_WRAPPER kernelWrapper( dofNumber, + dofManager.rankOffset(), + localMatrix, + localRhs, + dt, + gravityVectorData, + std::forward< PARAMS >( params )... ); + + return finiteElement:: + regionBasedKernelApplication< parallelDevicePolicy< >, + CONSTITUTIVE_BASE, + CellElementSubRegion >( mesh, + regionNames, + this->getDiscretizationName(), + materialNamesString, + kernelWrapper ); + } } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianSSLE.cpp b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianSSLE.cpp index eb4ed9bc931..cf1e138d21b 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianSSLE.cpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianSSLE.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -34,5 +35,5 @@ SolidMechanicsLagrangianSSLE::~SolidMechanicsLagrangianSSLE() {} -REGISTER_CATALOG_ENTRY( SolverBase, SolidMechanicsLagrangianSSLE, string const &, dataRepository::Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SolidMechanicsLagrangianSSLE, string const &, dataRepository::Group * const ) } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianSSLE.hpp b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianSSLE.hpp index 7d090131ff6..77c3c338f36 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianSSLE.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianSSLE.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -39,7 +40,7 @@ class SolidMechanicsLagrangianSSLE : public SolidMechanicsLagrangianFEM static string catalogName() { return "SolidMechanicsLagrangianSSLE"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } diff --git a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsMPM.cpp b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsMPM.cpp index 200ec84f454..a2b1d3ec2ff 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsMPM.cpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsMPM.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -28,7 +29,7 @@ #include "codingUtilities/Utilities.hpp" #include "common/TimingMacros.hpp" #include "constitutive/ConstitutiveManager.hpp" -#include "constitutive/contact/ContactBase.hpp" +#include "constitutive/contact/FrictionBase.hpp" #include "finiteElement/FiniteElementDiscretizationManager.hpp" #include "finiteElement/Kinematics.h" #include "LvArray/src/output.hpp" @@ -54,10 +55,10 @@ using namespace constitutive; SolidMechanicsMPM::SolidMechanicsMPM( const string & name, Group * const parent ): - SolverBase( name, parent ), + PhysicsSolverBase( name, parent ), m_solverProfiling( 0 ), m_timeIntegrationOption( TimeIntegrationOption::ExplicitDynamic ), - m_iComm( CommunicationTools::getInstance().getCommID() ), +// m_iComm( CommunicationTools::getInstance().getCommID() ), m_prescribedBcTable( 0 ), m_boundaryConditionTypes(), m_bcTable(), @@ -289,9 +290,9 @@ SolidMechanicsMPM::SolidMechanicsMPM( const string & name, setDescription( "number of elements along partition directions" ); } -void SolidMechanicsMPM::postProcessInput() +void SolidMechanicsMPM::postInputInitialization() { - SolverBase::postProcessInput(); + PhysicsSolverBase::postInputInitialization(); // Activate neighbor list if necessary if( m_damageFieldPartitioning == 1 || m_surfaceDetection == 1 /*|| m_directionalOverlapCorrection == 1*/ ) @@ -342,8 +343,7 @@ void SolidMechanicsMPM::registerDataOnMesh( Group & meshBodies ) [&]( localIndex const, ParticleSubRegionBase & subRegion ) { - setConstitutiveNamesCallSuper( subRegion ); - setConstitutiveNames( subRegion ); + setParticlesConstitutiveNames( subRegion ); } ); } @@ -467,7 +467,7 @@ void SolidMechanicsMPM::registerDataOnMesh( Group & meshBodies ) void SolidMechanicsMPM::initializePreSubGroups() { - SolverBase::initializePreSubGroups(); + PhysicsSolverBase::initializePreSubGroups(); DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); @@ -487,7 +487,7 @@ void SolidMechanicsMPM::initializePreSubGroups() ParticleSubRegion & subRegion ) { string & solidMaterialName = subRegion.getReference< string >( viewKeyStruct::solidMaterialNamesString() ); - solidMaterialName = SolverBase::getConstitutiveName< SolidBase >( subRegion ); + solidMaterialName = PhysicsSolverBase::getConstitutiveName< SolidBase >( subRegion ); } ); } } ); @@ -528,7 +528,7 @@ real64 SolidMechanicsMPM::solverStep( real64 const & time_n, GEOS_MARK_FUNCTION; real64 dtReturn = dt; - SolverBase * const surfaceGenerator = this->getParent().getGroupPointer< SolverBase >( "SurfaceGen" ); + PhysicsSolverBase * const surfaceGenerator = this->getParent().getGroupPointer< PhysicsSolverBase >( "SurfaceGen" ); if( m_timeIntegrationOption == TimeIntegrationOption::ExplicitDynamic ) { @@ -561,7 +561,7 @@ void SolidMechanicsMPM::initialize( NodeManager & nodeManager, // Read and distribute BC table if( m_prescribedBcTable == 1 ) { - int rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int rank = MpiWrapper::commRank( MPI_COMM_GEOS ); int BCTableSize; std::vector< double > BCTable1D; // Need 1D version of BC table for MPI broadcast @@ -576,12 +576,12 @@ void SolidMechanicsMPM::initialize( NodeManager & nodeManager, BCTableSize = BCTable1D.size(); } - MPI_Bcast( &BCTableSize, 1, MPI_INT, 0, MPI_COMM_GEOSX ); // Broadcast the size of BCTable1D to other processes + MPI_Bcast( &BCTableSize, 1, MPI_INT, 0, MPI_COMM_GEOS ); // Broadcast the size of BCTable1D to other processes if( rank != 0 ) // All processes except for root resize their versions of BCTable1D { BCTable1D.resize( BCTableSize ); } - MPI_Bcast( BCTable1D.data(), BCTableSize, MPI_DOUBLE, 0, MPI_COMM_GEOSX ); // Broadcast BCTable1D to other processes + MPI_Bcast( BCTable1D.data(), BCTableSize, MPI_DOUBLE, 0, MPI_COMM_GEOS ); // Broadcast BCTable1D to other processes // Technically don't need to reshape BCTable1D into a 2D array, but it makes things more readable and should have little runtime penalty m_bcTable.resize( BCTableSize / 7, 7 ); // Initialize size of m_BCTable @@ -599,7 +599,7 @@ void SolidMechanicsMPM::initialize( NodeManager & nodeManager, if( m_prescribedBoundaryFTable == 1 ) { - int rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int rank = MpiWrapper::commRank( MPI_COMM_GEOS ); int FTableSize; std::vector< double > FTable1D; // Need 1D version of F table for MPI broadcast @@ -617,12 +617,12 @@ void SolidMechanicsMPM::initialize( NodeManager & nodeManager, FTableSize = FTable1D.size(); } - MPI_Bcast( &FTableSize, 1, MPI_INT, 0, MPI_COMM_GEOSX ); // Broadcast the size of FTable1D to other processes + MPI_Bcast( &FTableSize, 1, MPI_INT, 0, MPI_COMM_GEOS ); // Broadcast the size of FTable1D to other processes if( rank != 0 ) // All processes except for root resize their versions of FTable1D { FTable1D.resize( FTableSize ); } - MPI_Bcast( FTable1D.data(), FTableSize, MPI_DOUBLE, 0, MPI_COMM_GEOSX ); // Broadcast FTable1D to other processes + MPI_Bcast( FTable1D.data(), FTableSize, MPI_DOUBLE, 0, MPI_COMM_GEOS ); // Broadcast FTable1D to other processes // Techinically don't need to reshape FTable1D into a 2D array, but it makes things more readable and should have little runtime penalty m_fTable.resize( FTableSize / 4, 4 ); // Initialize size of m_fTable @@ -757,7 +757,7 @@ void SolidMechanicsMPM::initialize( NodeManager & nodeManager, } // Initialize reaction force history file and write its header - if( MpiWrapper::commRank( MPI_COMM_GEOSX ) == 0 && m_reactionHistory == 1 ) + if( MpiWrapper::commRank( MPI_COMM_GEOS ) == 0 && m_reactionHistory == 1 ) { std::ofstream file; file.open( "reactionHistory.csv", std::ios::out | std::ios::app ); @@ -827,7 +827,7 @@ void SolidMechanicsMPM::initialize( NodeManager & nodeManager, 1, MPI_DOUBLE, MPI_MIN, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); m_smallMass = fmin( globalMinMass * 1.0e-12, m_smallMass ); // Initialize deformation gradient and velocity gradient @@ -854,7 +854,7 @@ void SolidMechanicsMPM::initialize( NodeManager & nodeManager, } ); if( m_boxAverageHistory == 1 ) { - if( MpiWrapper::commRank( MPI_COMM_GEOSX ) == 0 ) + if( MpiWrapper::commRank( MPI_COMM_GEOS ) == 0 ) { std::ofstream file; file.open( "boxAverageHistory.csv", std::ios::out | std::ios::app ); @@ -865,7 +865,7 @@ void SolidMechanicsMPM::initialize( NodeManager & nodeManager, file.exceptions( file.exceptions() | std::ios::failbit | std::ifstream::badbit ); file << "Time, Sxx, Syy, Szz, Sxy, Syz, Sxz, Density, Damage" << std::endl; } - MpiWrapper::barrier( MPI_COMM_GEOSX ); // wait for the header to be written + MpiWrapper::barrier( MPI_COMM_GEOS ); // wait for the header to be written computeAndWriteBoxAverage( 0.0, 0.0, particleManager ); } @@ -888,7 +888,7 @@ void SolidMechanicsMPM::initialize( NodeManager & nodeManager, 1, MPI_INT, MPI_MAX, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); // Number of contact groups m_numContactGroups = maxGlobalGroupNumber + 1; @@ -940,6 +940,7 @@ real64 SolidMechanicsMPM::explicitStep( real64 const & time_n, MeshLevel & mesh = grid.getBaseDiscretization(); NodeManager & nodeManager = mesh.getNodeManager(); + MPI_iCommData m_iComm; m_iComm.resize( domain.getNeighbors().size() ); @@ -973,9 +974,9 @@ real64 SolidMechanicsMPM::explicitStep( real64 const & time_n, //####################################################################################### - solverProfilingIf( "Perform particle ghosting", MpiWrapper::commSize( MPI_COMM_GEOSX ) > 1 && m_needsNeighborList == 1 ); + solverProfilingIf( "Perform particle ghosting", MpiWrapper::commSize( MPI_COMM_GEOS ) > 1 && m_needsNeighborList == 1 ); //####################################################################################### - if( MpiWrapper::commSize( MPI_COMM_GEOSX ) > 1 && m_needsNeighborList == 1 ) + if( MpiWrapper::commSize( MPI_COMM_GEOS ) > 1 && m_needsNeighborList == 1 ) { // Move everything into host memory space particleManager.forParticleSubRegions( [&]( ParticleSubRegion & subRegion ) @@ -1204,9 +1205,9 @@ real64 SolidMechanicsMPM::explicitStep( real64 const & time_n, //####################################################################################### - solverProfilingIf( "Particle repartitioning", MpiWrapper::commSize( MPI_COMM_GEOSX ) > 1 ); + solverProfilingIf( "Particle repartitioning", MpiWrapper::commSize( MPI_COMM_GEOS ) > 1 ); //####################################################################################### - if( MpiWrapper::commSize( MPI_COMM_GEOSX ) > 1 ) + if( MpiWrapper::commSize( MPI_COMM_GEOS ) > 1 ) { particleManager.forParticleSubRegions( [&]( ParticleSubRegion & subRegion ) { @@ -1258,6 +1259,9 @@ void SolidMechanicsMPM::syncGridFields( std::vector< std::string > const & field fieldsToBeSynced.addFields( FieldLocation::Node, fieldNames ); std::vector< NeighborCommunicator > & neighbors = domain.getNeighbors(); + MPI_iCommData m_iComm; + m_iComm.resize( neighbors.size() ); + // (2) Swap send and receive indices so we can sum from ghost to master for( size_t n=0; n= 1 ) { - MPI_Barrier( MPI_COMM_GEOSX ); + MPI_Barrier( MPI_COMM_GEOS ); GEOS_LOG_RANK_IF( m_solverProfiling == 2, label ); m_profilingTimes.push_back( MPI_Wtime() ); m_profilingLabels.push_back( label ); @@ -1966,25 +1970,18 @@ void SolidMechanicsMPM::solverProfilingIf( std::string label, bool condition ) } } -void SolidMechanicsMPM::setConstitutiveNamesCallSuper( ParticleSubRegionBase & subRegion ) const +void SolidMechanicsMPM::setParticlesConstitutiveNames( ParticleSubRegionBase & subRegion ) const { - SolverBase::setConstitutiveNamesCallSuper( subRegion ); - subRegion.registerWrapper< string >( viewKeyStruct::solidMaterialNamesString() ). setPlotLevel( PlotLevel::NOPLOT ). setRestartFlags( RestartFlags::NO_WRITE ). setSizedFromParent( 0 ); string & solidMaterialName = subRegion.getReference< string >( viewKeyStruct::solidMaterialNamesString() ); - solidMaterialName = SolverBase::getConstitutiveName< SolidBase >( subRegion ); + solidMaterialName = PhysicsSolverBase::getConstitutiveName< SolidBase >( subRegion ); GEOS_ERROR_IF( solidMaterialName.empty(), GEOS_FMT( "SolidBase model not found on subregion {}", subRegion.getName() ) ); } -void SolidMechanicsMPM::setConstitutiveNames( ParticleSubRegionBase & subRegion ) const -{ - GEOS_UNUSED_VAR( subRegion ); -} - real64 SolidMechanicsMPM::computeNeighborList( ParticleManager & particleManager ) { // Time this function @@ -2202,13 +2199,13 @@ void SolidMechanicsMPM::optimizeBinSort( ParticleManager & particleManager ) 1, MPI_DOUBLE, MPI_SUM, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); MPI_Allreduce( &localNumberOfParticles, &globalNumberOfParticles, 1, MPI_INT, MPI_SUM, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); // Set bin size multiplier m_binSizeMultiplier = std::max( (int) std::round( globalWeightedMultiplier / globalNumberOfParticles ), 1 ); @@ -2761,12 +2758,12 @@ void SolidMechanicsMPM::computeAndWriteBoxAverage( const real64 dt, 1, MPI_DOUBLE, MPI_SUM, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); boxSums[i] = globalSum; } int rank; - MPI_Comm_rank( MPI_COMM_GEOSX, &rank ); + MPI_Comm_rank( MPI_COMM_GEOS, &rank ); if( rank == 0 ) { // Calculate the box volume @@ -3310,7 +3307,7 @@ void SolidMechanicsMPM::deleteBadParticles( ParticleManager & particleManager ) void SolidMechanicsMPM::printProfilingResults() { // Use MPI reduction to get the average elapsed time for each step on all partitions - int rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int rank = MpiWrapper::commRank( MPI_COMM_GEOS ); unsigned int numIntervals = m_profilingTimes.size() - 1; std::vector< real64 > timeIntervalsAllRanks( numIntervals ); @@ -3321,7 +3318,7 @@ void SolidMechanicsMPM::printProfilingResults() &totalStepTimeAllRanks, 1, MPI_SUM, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); // Get total CPU times for each queried time interval for( unsigned int i = 0; i < numIntervals; i++ ) @@ -3332,7 +3329,7 @@ void SolidMechanicsMPM::printProfilingResults() &timeIntervalAllRanks, 1, MPI_SUM, - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); if( rank == 0 ) { timeIntervalsAllRanks[i] = timeIntervalAllRanks; @@ -3340,7 +3337,7 @@ void SolidMechanicsMPM::printProfilingResults() } // Print out solver profiling - MPI_Barrier( MPI_COMM_GEOSX ); + MPI_Barrier( MPI_COMM_GEOS ); if( rank == 0 ) { std::cout << "---------------------------------------------" << std::endl; @@ -4066,5 +4063,5 @@ void SolidMechanicsMPM::populateMappingArrays( ParticleManager & particleManager } ); } -REGISTER_CATALOG_ENTRY( SolverBase, SolidMechanicsMPM, string const &, dataRepository::Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SolidMechanicsMPM, string const &, dataRepository::Group * const ) } diff --git a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsMPM.hpp b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsMPM.hpp index 93dbc93a914..571e365f14a 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsMPM.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsMPM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,17 +17,17 @@ * @file SolidMechanicsMPM.hpp */ -#ifndef GEOSX_PHYSICSSOLVERS_SOLIDMECHANICS_MPM_HPP_ -#define GEOSX_PHYSICSSOLVERS_SOLIDMECHANICS_MPM_HPP_ +#ifndef GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_MPM_HPP_ +#define GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_MPM_HPP_ -#include "codingUtilities/EnumStrings.hpp" +#include "common/format/EnumStrings.hpp" #include "common/TimingMacros.hpp" #include "kernels/SolidMechanicsLagrangianFEMKernels.hpp" #include "kernels/ExplicitMPM.hpp" #include "mesh/MeshForLoopInterface.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "mesh/mpiCommunications/MPI_iCommData.hpp" -#include "physicsSolvers/SolverBase.hpp" +#include "physicsSolvers/PhysicsSolverBase.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsFields.hpp" #include "MPMSolverFields.hpp" @@ -41,7 +42,7 @@ class SpatialPartition; * * This class implements a material point method solution to the equations of motion. */ -class SolidMechanicsMPM : public SolverBase +class SolidMechanicsMPM : public PhysicsSolverBase { public: @@ -89,11 +90,11 @@ class SolidMechanicsMPM : public SolverBase virtual ~SolidMechanicsMPM() override; /** - * @return The string that may be used to generate a new instance from the SolverBase::CatalogInterface::CatalogType + * @return The string that may be used to generate a new instance from the PhysicsSolverBase::CatalogInterface::CatalogType */ static string catalogName() { return "SolidMechanics_MPM"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -165,7 +166,7 @@ class SolidMechanicsMPM : public SolverBase * @param solution the solution vector */ - struct viewKeyStruct : SolverBase::viewKeyStruct + struct viewKeyStruct : PhysicsSolverBase::viewKeyStruct { static constexpr char const * cflFactorString() { return "cflFactor"; } static constexpr char const * timeIntegrationOptionString() { return "timeIntegrationOption"; } @@ -361,9 +362,7 @@ class SolidMechanicsMPM : public SolverBase NodeManager & nodeManager ); protected: - virtual void postProcessInput() override final; - - virtual void setConstitutiveNamesCallSuper( ParticleSubRegionBase & subRegion ) const override; + virtual void postInputInitialization() override final; std::vector< array2d< localIndex > > m_mappedNodes; // mappedNodes[subregion index][particle index][node index]. dims = {# of subregions, // # of particles, # of nodes a particle on the subregion maps to} @@ -378,7 +377,6 @@ class SolidMechanicsMPM : public SolverBase std::vector< std::string > m_profilingLabels; TimeIntegrationOption m_timeIntegrationOption; - MPI_iCommData m_iComm; int m_prescribedBcTable; array1d< int > m_boundaryConditionTypes; // TODO: Surely there's a way to have just one variable here @@ -457,7 +455,7 @@ class SolidMechanicsMPM : public SolverBase } }; - virtual void setConstitutiveNames( ParticleSubRegionBase & subRegion ) const override; + void setParticlesConstitutiveNames( ParticleSubRegionBase & subRegion ) const; }; ENUM_STRINGS( SolidMechanicsMPM::TimeIntegrationOption, @@ -476,4 +474,4 @@ ENUM_STRINGS( SolidMechanicsMPM::BoundaryConditionOption, } /* namespace geos */ -#endif /* GEOSX_PHYSICSSOLVERS_SOLIDMECHANICS_SOLIDMECHANICSLAGRANGIANFEM_HPP_ */ +#endif /* GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_SOLIDMECHANICSLAGRANGIANFEM_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStateReset.cpp b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStateReset.cpp index 96179dd8a5c..764d86d8f38 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStateReset.cpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStateReset.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,8 @@ #include "physicsSolvers/PhysicsSolverManager.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp" -#include "mainInterface/ProblemManager.hpp" +#include "physicsSolvers/LogLevelsInfo.hpp" +#include "mesh/DomainPartition.hpp" namespace geos { @@ -50,15 +52,17 @@ SolidMechanicsStateReset::SolidMechanicsStateReset( const string & name, setApplyDefaultValue( false ). setInputFlag( InputFlags::OPTIONAL ). setDescription( "Flag to enable/disable inelastic behavior" ); + + addLogLevel< logInfo::Initialization >(); } SolidMechanicsStateReset::~SolidMechanicsStateReset() {} -void SolidMechanicsStateReset::postProcessInput() +void SolidMechanicsStateReset::postInputInitialization() { - ProblemManager & problemManager = this->getGroupByPath< ProblemManager >( "/Problem" ); - PhysicsSolverManager & physicsSolverManager = problemManager.getPhysicsSolverManager(); + Group & problemManager = this->getGroupByPath( "/Problem" ); + Group & physicsSolverManager = problemManager.getGroup( "Solvers" ); GEOS_THROW_IF( !physicsSolverManager.hasGroup( m_solidSolverName ), GEOS_FMT( "Task {}: physics solver named {} not found", @@ -82,8 +86,9 @@ bool SolidMechanicsStateReset::execute( real64 const time_n, // Option 1: zero out velocity, incremental displacement, and displacement if( m_resetDisplacements ) { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "Task `{}`: at time {}s, physics solver `{}` is resetting total displacement and velocity to zero", - getName(), time_n, m_solidSolverName ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Initialization, + GEOS_FMT( "Task `{}`: at time {}s, physics solver `{}` is resetting total displacement and velocity to zero", + getName(), time_n, m_solidSolverName ) ); NodeManager & nodeManager = mesh.getNodeManager(); @@ -104,10 +109,10 @@ bool SolidMechanicsStateReset::execute( real64 const time_n, string const & solidMaterialName = subRegion.getReference< string >( SolidMechanicsLagrangianFEM::viewKeyStruct::solidMaterialNamesString() ); Group & constitutiveModels = subRegion.getGroup( ElementSubRegionBase::groupKeyStruct::constitutiveModelsString() ); - GEOS_LOG_LEVEL_RANK_0( 2, GEOS_FMT( "Task `{}`: at time {}s, solid model `{}` is setting inelastic behavior to `{}` on subRegion `{}`. ", - getName(), time_n, solidMaterialName, - m_disableInelasticity ? "OFF" : "ON", - subRegion.getName() ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Initialization, GEOS_FMT( "Task `{}`: at time {}s, solid model `{}` is setting inelastic behavior to `{}` on subRegion `{}`. ", + getName(), time_n, solidMaterialName, + m_disableInelasticity ? "OFF" : "ON", + subRegion.getName() ) ); SolidBase & constitutiveRelation = constitutiveModels.getGroup< SolidBase >( solidMaterialName ); constitutiveRelation.disableInelasticity( m_disableInelasticity ); diff --git a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStateReset.hpp b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStateReset.hpp index 0f6986d0285..4a9c5219038 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStateReset.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStateReset.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -91,7 +92,7 @@ class SolidMechanicsStateReset : public TaskBase }; - void postProcessInput() override; + void postInputInitialization() override; /// Name of the solid mechanics solver string m_solidSolverName; diff --git a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStatistics.cpp b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStatistics.cpp index ec97b4bc55d..5e266c0258c 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStatistics.cpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStatistics.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -23,6 +24,8 @@ #include "physicsSolvers/PhysicsSolverManager.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp" #include "fileIO/Outputs/OutputBase.hpp" +#include "mesh/DomainPartition.hpp" +#include "physicsSolvers/solidMechanics/LogLevelsInfo.hpp" namespace geos { @@ -34,7 +37,9 @@ using namespace fields; SolidMechanicsStatistics::SolidMechanicsStatistics( const string & name, Group * const parent ): Base( name, parent ) -{} +{ + addLogLevel< logInfo::Statistics >(); +} void SolidMechanicsStatistics::registerDataOnMesh( Group & meshBodies ) { @@ -142,20 +147,20 @@ void SolidMechanicsStatistics::computeNodeStatistics( MeshLevel & mesh, real64 c nodeStatistics.maxDisplacement.data(), 3, MpiWrapper::getMpiOp( MpiWrapper::Reduction::Max ), - MPI_COMM_GEOSX ); + MPI_COMM_GEOS ); MpiWrapper::allReduce( nodeStatistics.minDisplacement.data(), nodeStatistics.minDisplacement.data(), 3, MpiWrapper::getMpiOp( MpiWrapper::Reduction::Min ), - MPI_COMM_GEOSX ); - - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{} (time {} s): Min displacement (X, Y, Z): {}, {}, {} m", - getName(), time, nodeStatistics.minDisplacement[0], - nodeStatistics.minDisplacement[1], nodeStatistics.minDisplacement[2] ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "{} (time {} s): Max displacement (X, Y, Z): {}, {}, {} m", - getName(), time, nodeStatistics.maxDisplacement[0], - nodeStatistics.maxDisplacement[1], nodeStatistics.maxDisplacement[2] ) ); + MPI_COMM_GEOS ); + + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, GEOS_FMT( "{} (time {} s): Min displacement (X, Y, Z): {}, {}, {} m", + getName(), time, nodeStatistics.minDisplacement[0], + nodeStatistics.minDisplacement[1], nodeStatistics.minDisplacement[2] ) ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Statistics, GEOS_FMT( "{} (time {} s): Max displacement (X, Y, Z): {}, {}, {} m", + getName(), time, nodeStatistics.maxDisplacement[0], + nodeStatistics.maxDisplacement[1], nodeStatistics.maxDisplacement[2] ) ); if( m_writeCSV > 0 && MpiWrapper::commRank() == 0 ) { diff --git a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStatistics.hpp b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStatistics.hpp index 77c32e85e6b..975c057b075 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStatistics.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsStatistics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/solidMechanics/docs/SolidMechanics.rst b/src/coreComponents/physicsSolvers/solidMechanics/docs/SolidMechanics.rst index d0020fd3770..a44e4797a88 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/docs/SolidMechanics.rst +++ b/src/coreComponents/physicsSolvers/solidMechanics/docs/SolidMechanics.rst @@ -195,11 +195,11 @@ Parameters In the preceding XML block, The `SolidMechanics_LagrangianFEM` is specified by the title of the subblock of the `Solvers` block. The following attributes are supported in the input block for `SolidMechanics_LagrangianFEM`: -.. include:: /coreComponents/schema/docs/SolidMechanics_LagrangianFEM.rst +.. include:: /docs/sphinx/datastructure/SolidMechanics_LagrangianFEM.rst The following data are allocated and used by the solver: -.. include:: /coreComponents/schema/docs/SolidMechanics_LagrangianFEM_other.rst +.. include:: /docs/sphinx/datastructure/SolidMechanics_LagrangianFEM_other.rst Example ========================= diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitFiniteStrain.hpp b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitFiniteStrain.hpp index 14d26c2e1bd..6384ac17292 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitFiniteStrain.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitFiniteStrain.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitFiniteStrain_impl.hpp b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitFiniteStrain_impl.hpp index f0b1ec984b5..8454837b438 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitFiniteStrain_impl.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitFiniteStrain_impl.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitMPM.hpp b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitMPM.hpp index a7e7ce7eb26..403619a20a2 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitMPM.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitMPM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,8 +18,8 @@ * @file ExplicitMPM.hpp */ -#ifndef GEOSX_PHYSICSSOLVERS_CONTACT_EXPLICITMPM_HPP_ -#define GEOSX_PHYSICSSOLVERS_CONTACT_EXPLICITMPM_HPP_ +#ifndef GEOS_PHYSICSSOLVERS_CONTACT_EXPLICITMPM_HPP_ +#define GEOS_PHYSICSSOLVERS_CONTACT_EXPLICITMPM_HPP_ #include "constitutive/solid/SolidUtilities.hpp" #include "physicsSolvers/solidMechanics/kernels/ExplicitFiniteStrain.hpp" @@ -32,8 +33,8 @@ namespace solidMechanicsMPMKernels // A helper function to calculate polar decomposition. TODO: Previously this was an LvArray method, hopefully it will be again someday. GEOS_HOST_DEVICE -void polarDecomposition( real64 (& R)[3][3], - real64 const (&matrix)[3][3] ) +static inline void polarDecomposition( real64 (& R)[3][3], + real64 const (&matrix)[3][3] ) { // Initialize LvArray::tensorOps::copy< 3, 3 >( R, matrix ); @@ -84,7 +85,7 @@ struct StateUpdateKernel /** * @brief Launch the kernel function doing constitutive updates * @tparam POLICY the type of policy used in the kernel launch - * @tparam CONTACT_WRAPPER the type of contact wrapper doing the constitutive updates + * @tparam CONSTITUTIVE_WRAPPER the type of consitutive wrapper doing the constitutive updates * @param[in] size the size of the subregion * @param[in] constitutiveWrapper the wrapper implementing the constitutive model * @param[in] deformationGradient the deformation gradient @@ -111,7 +112,7 @@ struct StateUpdateKernel // Copy the beginning-of-step particle stress into the constitutive model's m_oldStress - this fixes the MPI sync issue on Lassen for // some reason - #if defined(GEOSX_USE_CUDA) + #if defined(GEOS_USE_CUDA) LvArray::tensorOps::copy< 6 >( oldStress[p][0], particleStress[p] ); #endif @@ -162,4 +163,4 @@ struct StateUpdateKernel } // namespace geos -#endif /* GEOSX_PHYSICSSOLVERS_CONTACT_EXPLICITMPM_HPP_ */ +#endif /* GEOS_PHYSICSSOLVERS_CONTACT_EXPLICITMPM_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitSmallStrain.hpp b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitSmallStrain.hpp index 8f5fb41a9e8..b4518ca4cbd 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitSmallStrain.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitSmallStrain.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitSmallStrain_impl.hpp b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitSmallStrain_impl.hpp index 9e97f77db0a..30910aac4b0 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitSmallStrain_impl.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitSmallStrain_impl.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/FixedStressThermoPoromechanics.hpp b/src/coreComponents/physicsSolvers/solidMechanics/kernels/FixedStressThermoPoromechanics.hpp index 769352f8dce..4b67faf912a 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/FixedStressThermoPoromechanics.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/FixedStressThermoPoromechanics.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -188,19 +189,19 @@ class FixedStressThermoPoromechanics : /// The gravity vector. real64 const m_gravityVector[3]; - /// The rank global bulk densities + /// The rank global bulk density arrayView2d< real64 const > const m_bulkDensity; /// The rank-global fluid pressure arrays. - arrayView1d< real64 const > const m_pressure_n; arrayView1d< real64 const > const m_pressure; + arrayView1d< real64 const > const m_pressure_n; /// The rank-global initial temperature array arrayView1d< real64 const > const m_initialTemperature; /// The rank-global temperature arrays. - arrayView1d< real64 const > const m_temperature_n; arrayView1d< real64 const > const m_temperature; + arrayView1d< real64 const > const m_temperature_n; /** * @brief Get a parameter representative of the stiffness, used as physical scaling for the diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/FixedStressThermoPoromechanics_impl.hpp b/src/coreComponents/physicsSolvers/solidMechanics/kernels/FixedStressThermoPoromechanics_impl.hpp index ac62e023320..36d70558513 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/FixedStressThermoPoromechanics_impl.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/FixedStressThermoPoromechanics_impl.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -65,11 +66,11 @@ FixedStressThermoPoromechanics( NodeManager const & nodeManager, m_uhat( nodeManager.getField< fields::solidMechanics::incrementalDisplacement >() ), m_gravityVector{ inputGravityVector[0], inputGravityVector[1], inputGravityVector[2] }, m_bulkDensity( elementSubRegion.template getField< fields::poromechanics::bulkDensity >() ), - m_pressure_n( elementSubRegion.template getField< fields::flow::pressure_n >() ), m_pressure( elementSubRegion.template getField< fields::flow::pressure >() ), + m_pressure_n( elementSubRegion.template getField< fields::flow::pressure_n >() ), m_initialTemperature( elementSubRegion.template getField< fields::flow::initialTemperature >() ), - m_temperature_n( elementSubRegion.template getField< fields::flow::temperature_n >() ), - m_temperature( elementSubRegion.template getField< fields::flow::temperature >() ) + m_temperature( elementSubRegion.template getField< fields::flow::temperature >() ), + m_temperature_n( elementSubRegion.template getField< fields::flow::temperature_n >() ) {} template< typename SUBREGION_TYPE, @@ -136,13 +137,12 @@ quadraturePointKernel( localIndex const k, // Evaluate total stress and its derivatives // TODO: allow for a customization of the kernel to pass the average pressure to the small strain update (to account for cap pressure // later) - m_constitutiveUpdate.smallStrainUpdatePoromechanicsFixedStress( k, - q, - m_pressure_n[k], - m_pressure[k], + m_constitutiveUpdate.smallStrainUpdatePoromechanicsFixedStress( k, q, m_dt, - m_temperature_n[k], + m_pressure[k], + m_pressure_n[k], m_temperature[k], + m_temperature_n[k], strainInc, totalStress, stiffness ); diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainNewmark.hpp b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainNewmark.hpp index d426fa6e77d..5b97f0022da 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainNewmark.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainNewmark.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainNewmark_impl.hpp b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainNewmark_impl.hpp index 5f036f6b75e..d0e2c71ea0a 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainNewmark_impl.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainNewmark_impl.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainQuasiStatic.hpp b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainQuasiStatic.hpp index 34d17a2b2f5..0e9bcf87b18 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainQuasiStatic.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainQuasiStatic.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainQuasiStatic_impl.hpp b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainQuasiStatic_impl.hpp index b191586c6a7..12753ab393f 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainQuasiStatic_impl.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ImplicitSmallStrainQuasiStatic_impl.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsFixedStressThermoPoromechanicsKernels.cpp.template b/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsFixedStressThermoPoromechanicsKernels.cpp.template index 704c6b84648..69211cfeb85 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsFixedStressThermoPoromechanicsKernels.cpp.template +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsFixedStressThermoPoromechanicsKernels.cpp.template @@ -1,4 +1,17 @@ - +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ #include "physicsSolvers/solidMechanics/kernels/FixedStressThermoPoromechanics_impl.hpp" #include "policies.hpp" diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsKernels.cmake b/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsKernels.cmake index 4d7058f9553..c71c31bacd2 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsKernels.cmake +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsKernels.cmake @@ -4,11 +4,11 @@ set( kernelPath "coreComponents/physicsSolvers/solidMechanics/kernels" ) -set( ExplicitSmallStrainPolicy "geos::parallelDevicePolicy< ${GEOSX_BLOCK_SIZE} >" ) -set( ExplicitFiniteStrainPolicy "geos::parallelDevicePolicy< ${GEOSX_BLOCK_SIZE} >" ) -set( FixedStressThermoPoromechanicsPolicy "geos::parallelDevicePolicy< ${GEOSX_BLOCK_SIZE} >" ) -set( ImplicitSmallStrainNewmarkPolicy "geos::parallelDevicePolicy< ${GEOSX_BLOCK_SIZE} >" ) -set( ImplicitSmallStrainQuasiStaticPolicy "geos::parallelDevicePolicy< ${GEOSX_BLOCK_SIZE} >" ) +set( ExplicitSmallStrainPolicy "geos::parallelDevicePolicy< ${GEOS_BLOCK_SIZE} >" ) +set( ExplicitFiniteStrainPolicy "geos::parallelDevicePolicy< ${GEOS_BLOCK_SIZE} >" ) +set( FixedStressThermoPoromechanicsPolicy "geos::parallelDevicePolicy< ${GEOS_BLOCK_SIZE} >" ) +set( ImplicitSmallStrainNewmarkPolicy "geos::parallelDevicePolicy< ${GEOS_BLOCK_SIZE} >" ) +set( ImplicitSmallStrainQuasiStaticPolicy "geos::parallelDevicePolicy< ${GEOS_BLOCK_SIZE} >" ) configure_file( ${CMAKE_SOURCE_DIR}/${kernelPath}/policies.hpp.in diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsKernels.cpp.template b/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsKernels.cpp.template index 140bfc9beb2..cd5829c9b16 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsKernels.cpp.template +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsKernels.cpp.template @@ -1,4 +1,17 @@ - +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ #include "physicsSolvers/solidMechanics/kernels/ExplicitSmallStrain_impl.hpp" #include "physicsSolvers/solidMechanics/kernels/ExplicitFiniteStrain_impl.hpp" diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsLagrangianFEMKernels.hpp b/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsLagrangianFEMKernels.hpp index a0c3ffce1cb..2ccdfd7a87d 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsLagrangianFEMKernels.hpp +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsLagrangianFEMKernels.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/StrainHelper.hpp b/src/coreComponents/physicsSolvers/solidMechanics/kernels/StrainHelper.hpp new file mode 100644 index 00000000000..d1c5567eff4 --- /dev/null +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/StrainHelper.hpp @@ -0,0 +1,220 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StrainHelper.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_KERNELS_STRAINHELPER_HPP_ +#define GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_KERNELS_STRAINHELPER_HPP_ + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "finiteElement/FiniteElementDispatch.hpp" +#include "mesh/CellElementSubRegion.hpp" +#include "mesh/utilities/AverageOverQuadraturePointsKernel.hpp" +#include "physicsSolvers/solidMechanics/SolidMechanicsFields.hpp" + +namespace geos +{ +/** + * @class AverageStrainOverQuadraturePoints + * @tparam SUBREGION_TYPE the subRegion type + * @tparam FE_TYPE the finite element type + */ +template< typename SUBREGION_TYPE, + typename FE_TYPE > +class AverageStrainOverQuadraturePoints : + public AverageOverQuadraturePointsBase< SUBREGION_TYPE, + FE_TYPE > +{ +public: + + /// Alias for the base class; + using Base = AverageOverQuadraturePointsBase< SUBREGION_TYPE, + FE_TYPE >; + + using Base::m_elementVolume; + using Base::m_elemsToNodes; + using Base::m_finiteElementSpace; + + /** + * @brief Constructor for the class + * @param nodeManager the node manager + * @param edgeManager the edge manager + * @param faceManager the face manager + * @param elementSubRegion the element subRegion + * @param finiteElementSpace the finite element space + * @param displacement the displacement solution field + * @param avgStrain the strain averaged over quadrature points + */ + AverageStrainOverQuadraturePoints( NodeManager & nodeManager, + EdgeManager const & edgeManager, + FaceManager const & faceManager, + SUBREGION_TYPE const & elementSubRegion, + FE_TYPE const & finiteElementSpace, + fields::solidMechanics::arrayViewConst2dLayoutTotalDisplacement const displacement, + fields::solidMechanics::arrayView2dLayoutStrain const avgStrain ): + Base( nodeManager, + edgeManager, + faceManager, + elementSubRegion, + finiteElementSpace ), + m_displacement( displacement ), + m_avgStrain( avgStrain ) + {} + + /** + * @copydoc finiteElement::KernelBase::StackVariables + */ + struct StackVariables : Base::StackVariables + {real64 uLocal[FE_TYPE::maxSupportPoints][3]; }; + + /** + * @brief Performs the setup phase for the kernel. + * @param k The element index. + * @param stack The StackVariable object that hold the stack variables. + */ + GEOS_HOST_DEVICE + void setup( localIndex const k, + StackVariables & stack ) const + { + Base::setup( k, stack ); + + for( localIndex a = 0; a < FE_TYPE::maxSupportPoints; ++a ) + { + localIndex const localNodeIndex = m_elemsToNodes( k, a ); + for( int i = 0; i < 3; ++i ) + { + stack.uLocal[a][i] = m_displacement[localNodeIndex][i]; + } + } + + for( int icomp = 0; icomp < 6; ++icomp ) + { + m_avgStrain[k][icomp] = 0.0; + } + } + + /** + * @brief Increment the average property with the contribution of the property at this quadrature point + * @param k The element index + * @param q The quadrature point index + * @param stack The StackVariables object that hold the stack variables. + */ + GEOS_HOST_DEVICE + void quadraturePointKernel( localIndex const k, + localIndex const q, + StackVariables & stack ) const + { + //real64 const weight = FE_TYPE::transformedQuadratureWeight( q, stack.xLocal, stack.feStack ) / m_elementVolume[k]; + + real64 dNdX[ FE_TYPE::maxSupportPoints ][3]; + real64 const detJxW = m_finiteElementSpace.template getGradN< FE_TYPE >( k, q, stack.xLocal, stack.feStack, dNdX ); + real64 strain[6] = {0.0}; + FE_TYPE::symmetricGradient( dNdX, stack.uLocal, strain ); + + for( int icomp = 0; icomp < 6; ++icomp ) + { + m_avgStrain[k][icomp] += detJxW*strain[icomp]/m_elementVolume[k]; + } + } + + /** + * @brief Launch the kernel over the elements in the subRegion + * @tparam POLICY the kernel policy + * @tparam KERNEL_TYPE the type of kernel + * @param numElems the number of elements in the subRegion + * @param kernelComponent the kernel component + */ + template< typename POLICY, + typename KERNEL_TYPE > + static void + kernelLaunch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + forAll< POLICY >( numElems, + [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + typename KERNEL_TYPE::StackVariables stack; + + kernelComponent.setup( k, stack ); + for( integer q = 0; q < FE_TYPE::numQuadraturePoints; ++q ) + { + kernelComponent.quadraturePointKernel( k, q, stack ); + } + } ); + } + +protected: + + /// The displacement solution + fields::solidMechanics::arrayViewConst2dLayoutTotalDisplacement const m_displacement; + + /// The average strain + fields::solidMechanics::arrayView2dLayoutStrain const m_avgStrain; + +}; + + + +/** + * @class AverageStrainOverQuadraturePointsKernelFactory + * @brief Class to create and launch the kernel + */ +class AverageStrainOverQuadraturePointsKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam SUBREGION_TYPE the subRegion type + * @tparam FE_TYPE the finite element type + * @tparam POLICY the kernel policy + * @param nodeManager the node manager + * @param edgeManager the edge manager + * @param faceManager the face manager + * @param elementSubRegion the element subRegion + * @param finiteElementSpace the finite element space + * @param property the property at quadrature points + * @param averageProperty the property averaged over quadrature points + */ + template< typename SUBREGION_TYPE, + typename FE_TYPE, + typename POLICY > + static void + createAndLaunch( NodeManager & nodeManager, + EdgeManager const & edgeManager, + FaceManager const & faceManager, + SUBREGION_TYPE const & elementSubRegion, + FE_TYPE const & finiteElementSpace, + fields::solidMechanics::arrayViewConst2dLayoutTotalDisplacement const displacement, + fields::solidMechanics::arrayView2dLayoutStrain const avgStrain ) + { + AverageStrainOverQuadraturePoints< SUBREGION_TYPE, FE_TYPE > + kernel( nodeManager, edgeManager, faceManager, elementSubRegion, finiteElementSpace, + displacement, avgStrain ); + + AverageStrainOverQuadraturePoints< SUBREGION_TYPE, FE_TYPE >::template + kernelLaunch< POLICY >( elementSubRegion.size(), kernel ); + } +}; + + + +} + + +#endif /* GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_KERNELS_STRAINHELPER_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/policies.hpp.in b/src/coreComponents/physicsSolvers/solidMechanics/kernels/policies.hpp.in index b27c8c027bf..c14654cf0c7 100644 --- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/policies.hpp.in +++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/policies.hpp.in @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #ifndef GEOS_CORECOMPONENTS_PHYSICSSOLVERSE_SOLIDMECHANICS_KERNELS_CONFIG_HPP #define GEOS_CORECOMPONENTS_PHYSICSSOLVERSE_SOLIDMECHANICS_KERNELS_CONFIG_HPP diff --git a/src/coreComponents/physicsSolvers/surfaceGeneration/CMakeLists.txt b/src/coreComponents/physicsSolvers/surfaceGeneration/CMakeLists.txt new file mode 100644 index 00000000000..eb2b85d0357 --- /dev/null +++ b/src/coreComponents/physicsSolvers/surfaceGeneration/CMakeLists.txt @@ -0,0 +1,22 @@ +# Specify solver headers +set( physicsSolvers_headers + ${physicsSolvers_headers} + surfaceGeneration/EmbeddedSurfaceGenerator.hpp + surfaceGeneration/EmbeddedSurfacesParallelSynchronization.hpp + surfaceGeneration/ParallelTopologyChange.hpp + surfaceGeneration/SurfaceGenerator.hpp + surfaceGeneration/SurfaceGeneratorFields.hpp + surfaceGeneration/LogLevelsInfo.hpp + surfaceGeneration/kernels/surfaceGenerationKernels.hpp + surfaceGeneration/kernels/surfaceGenerationKernelsHelpers.hpp + PARENT_SCOPE ) + +# Specify solver sources +set( physicsSolvers_sources + ${physicsSolvers_sources} + surfaceGeneration/EmbeddedSurfaceGenerator.cpp + surfaceGeneration/EmbeddedSurfacesParallelSynchronization.cpp + surfaceGeneration/ParallelTopologyChange.cpp + surfaceGeneration/ParallelTopologyChangeNoFixup.cpp + surfaceGeneration/SurfaceGenerator.cpp + PARENT_SCOPE ) \ No newline at end of file diff --git a/src/coreComponents/physicsSolvers/surfaceGeneration/EmbeddedSurfaceGenerator.cpp b/src/coreComponents/physicsSolvers/surfaceGeneration/EmbeddedSurfaceGenerator.cpp index 85d2fbc2aa9..da4e2856368 100644 --- a/src/coreComponents/physicsSolvers/surfaceGeneration/EmbeddedSurfaceGenerator.cpp +++ b/src/coreComponents/physicsSolvers/surfaceGeneration/EmbeddedSurfaceGenerator.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -35,7 +36,7 @@ #include "mesh/simpleGeometricObjects/GeometricObjectManager.hpp" #include "mesh/simpleGeometricObjects/Rectangle.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" - +#include "physicsSolvers/surfaceGeneration/LogLevelsInfo.hpp" namespace geos @@ -63,7 +64,7 @@ void NewObjectLists::insert( NewObjectLists const & newObjects ) EmbeddedSurfaceGenerator::EmbeddedSurfaceGenerator( const string & name, Group * const parent ): - SolverBase( name, parent ), + PhysicsSolverBase( name, parent ), m_fractureRegionName(), m_mpiCommOrder( 0 ) { @@ -190,7 +191,7 @@ void EmbeddedSurfaceGenerator::initializePostSubGroups() if( added ) { - GEOS_LOG_LEVEL_RANK_0( 2, "Element " << cellIndex << " is fractured" ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::SurfaceGenerator, "Element " << cellIndex << " is fractured" ); // Add the information to the CellElementSubRegion subRegion.addFracturedElement( cellIndex, localNumberOfSurfaceElems ); @@ -337,8 +338,8 @@ void EmbeddedSurfaceGenerator::setGlobalIndices( ElementRegionManager & elemMana EmbeddedSurfaceSubRegion & embeddedSurfaceSubRegion ) { // Add new globalIndices - int const thisRank = MpiWrapper::commRank( MPI_COMM_GEOSX ); - int const commSize = MpiWrapper::commSize( MPI_COMM_GEOSX ); + int const thisRank = MpiWrapper::commRank( MPI_COMM_GEOS ); + int const commSize = MpiWrapper::commSize( MPI_COMM_GEOS ); localIndex_array numberOfSurfaceElemsPerRank( commSize ); localIndex_array globalIndexOffset( commSize ); @@ -352,7 +353,7 @@ void EmbeddedSurfaceGenerator::setGlobalIndices( ElementRegionManager & elemMana totalNumberOfSurfaceElements += numberOfSurfaceElemsPerRank[rank]; } - GEOS_LOG_LEVEL_RANK_0( 1, "Number of embedded surface elements: " << totalNumberOfSurfaceElements ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::SurfaceGenerator, "Number of embedded surface elements: " << totalNumberOfSurfaceElements ); arrayView1d< globalIndex > const & elemLocalToGlobal = embeddedSurfaceSubRegion.localToGlobalMap(); @@ -424,7 +425,7 @@ void EmbeddedSurfaceGenerator::addEmbeddedElementsToSets( ElementRegionManager c } ); } -REGISTER_CATALOG_ENTRY( SolverBase, +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, EmbeddedSurfaceGenerator, string const &, dataRepository::Group * const ) diff --git a/src/coreComponents/physicsSolvers/surfaceGeneration/EmbeddedSurfaceGenerator.hpp b/src/coreComponents/physicsSolvers/surfaceGeneration/EmbeddedSurfaceGenerator.hpp index 2c2b6dd8ae1..5f9219a4ea0 100644 --- a/src/coreComponents/physicsSolvers/surfaceGeneration/EmbeddedSurfaceGenerator.hpp +++ b/src/coreComponents/physicsSolvers/surfaceGeneration/EmbeddedSurfaceGenerator.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,7 +21,7 @@ #define GEOS_PHYSICSSOLVERS_SURFACEGENERATION_EMBEDDEDSURFACEGENERATOR_HPP_ #include "mesh/mpiCommunications/NeighborCommunicator.hpp" -#include "physicsSolvers/SolverBase.hpp" +#include "physicsSolvers/PhysicsSolverBase.hpp" #include "mesh/DomainPartition.hpp" @@ -50,7 +51,7 @@ class ElementRegionBase; * This solver manages the mesh topology splitting methods. * */ -class EmbeddedSurfaceGenerator : public SolverBase +class EmbeddedSurfaceGenerator : public PhysicsSolverBase { public: EmbeddedSurfaceGenerator( const string & name, @@ -60,7 +61,7 @@ class EmbeddedSurfaceGenerator : public SolverBase static string catalogName() { return "EmbeddedSurfaceGenerator"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -98,6 +99,11 @@ class EmbeddedSurfaceGenerator : public SolverBase virtual void initializePostInitialConditionsPreSubGroups() override final; + virtual void postRestartInitialization() override final + { + GEOS_ERROR( "Restarting is not supported for cases involving EmbeddedSurfaceGenerator" ); + } + private: void addToFractureStencil( DomainPartition & domain ); @@ -112,7 +118,7 @@ class EmbeddedSurfaceGenerator : public SolverBase /** * @struct viewKeyStruct holds char strings and viewKeys for fast lookup */ - struct viewKeyStruct : SolverBase::viewKeyStruct + struct viewKeyStruct : PhysicsSolverBase::viewKeyStruct { constexpr static char const * solidMaterialNameString() {return "solidMaterialNames"; } constexpr static char const * fractureRegionNameString() {return "fractureRegion"; } diff --git a/src/coreComponents/physicsSolvers/surfaceGeneration/EmbeddedSurfacesParallelSynchronization.cpp b/src/coreComponents/physicsSolvers/surfaceGeneration/EmbeddedSurfacesParallelSynchronization.cpp index f36df20f2e1..26d1c5fe380 100644 --- a/src/coreComponents/physicsSolvers/surfaceGeneration/EmbeddedSurfacesParallelSynchronization.cpp +++ b/src/coreComponents/physicsSolvers/surfaceGeneration/EmbeddedSurfacesParallelSynchronization.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -382,7 +383,7 @@ void synchronizeNewNodes( MeshLevel & mesh, //************************************************************************************************ // We need to send over the new embedded surfaces and related objects for those whose parents are ghosts on neighbors. - MPI_iCommData commData( CommunicationTools::getInstance().getCommID() ); + MPI_iCommData commData; commData.resize( neighbors.size()); for( unsigned int neighborIndex=0; neighborIndex & neighbors, string const fractureRegionName ) { - MPI_iCommData commDataJunk( CommunicationTools::getInstance().getCommID() ); - MPI_iCommData commData( CommunicationTools::getInstance().getCommID() ); + MPI_iCommData commData; commData.resize( neighbors.size()); for( unsigned int neighborIndex=0; neighborIndex( [&]( localIndex const esr, FaceElementSubRegion & subRegion ) { - ArrayOfArraysView< localIndex const > const faceList = subRegion.faceList().toViewConst(); + arrayView2d< localIndex const > const faceList = subRegion.faceList().toViewConst(); localIndex_array & elemGhostsToSend = subRegion.getNeighborData( neighbor->neighborRank() ).ghostsToSend(); elemGhostsToSend.move( hostMemorySpace ); for( localIndex const & k : receivedObjects.newElements.at( {er, esr} ) ) @@ -798,7 +813,7 @@ void parallelTopologyChange::synchronizeTopologyChange( MeshLevel * const mesh, // b) the modified objects to the owning ranks. // pack the buffers, and send the size of the buffers - MPI_iCommData commData( CommunicationTools::getInstance().getCommID() ); + MPI_iCommData commData; commData.resize( neighbors.size() ); for( unsigned int neighborIndex=0; neighborIndex m_elements; + ElementRegionManager::ElementViewAccessor< arrayView1d< localIndex > > m_elementsView; + + array1d< array1d< localIndex_array > > m_elementsData; + buffer_type::size_type m_size; + +}; + +struct TopologyChangeUnpackStepData : public TopologyChangeStepData +{ + void init( buffer_type const & receiveBuffer, + ElementRegionManager const & elemManager ) + { + m_bufferPtr = receiveBuffer.data(); + TopologyChangeStepData::init( elemManager ); + } + + buffer_unit_type const * m_bufferPtr; +}; + } } diff --git a/src/coreComponents/physicsSolvers/surfaceGeneration/ParallelTopologyChangeNoFixup.cpp b/src/coreComponents/physicsSolvers/surfaceGeneration/ParallelTopologyChangeNoFixup.cpp new file mode 100644 index 00000000000..44f42069418 --- /dev/null +++ b/src/coreComponents/physicsSolvers/surfaceGeneration/ParallelTopologyChangeNoFixup.cpp @@ -0,0 +1,1291 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ParallelTopologyChange.cpp + */ + +#include "ParallelTopologyChange.hpp" + +#include "common/GeosxMacros.hpp" +#include "common/TimingMacros.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "mesh/MeshFields.hpp" +#include "mesh/mpiCommunications/CommunicationTools.hpp" +#include "mesh/mpiCommunications/MPI_iCommData.hpp" + +#if PARALLEL_TOPOLOGY_CHANGE_METHOD==1 +namespace geos +{ + +using namespace dataRepository; + +namespace parallelTopologyChange +{ + + +template< typename T > +void filterNonOwnedFromContainer( array1d< localIndex > & newList, + T const & container, + arrayView1d< localIndex const > const & ghostRank, + integer const neighborRank ) +{ + newList.resize( container.size()); + { + localIndex a=0; + for( auto index : container ) + { + if( ghostRank[index] == neighborRank ) + { + newList[a] = index; + ++a; + } + } + newList.resize( a ); + } +} + +template< typename T > +void filterNonOwnedFromContainer( array1d< localIndex > & newList, + T const & container, + arrayView1d< localIndex const > const & parentIndices, + arrayView1d< localIndex const > const & ghostRank, + integer const neighborRank ) +{ + newList.resize( container.size()); + { + localIndex a=0; + for( auto index : container ) + { + localIndex const parentIndex = ObjectManagerBase::getParentRecursive( parentIndices, index ); + if( ghostRank[parentIndex] == neighborRank ) + { + newList[a] = index; + ++a; + } + } + newList.resize( a ); + } +} + +void filterNewObjectsForPackToGhosts( std::set< localIndex > const & objectList, + arrayView1d< localIndex > const & parentIndices, + localIndex_array & ghostsToSend, + localIndex_array & objectsToSend ) +{ + + ghostsToSend.move( hostMemorySpace ); + //TODO this needs to be inverted since the ghostToSend list should be much longer.... + // and the objectList is a searchable set. + for( auto const index : objectList ) + { + localIndex const parentIndex = parentIndices[index]; + for( localIndex a=0; a const & objectList, + localIndex_array const & ghostsToSend, + localIndex_array & objectsToSend ) +{ + ghostsToSend.move( hostMemorySpace ); + for( localIndex a=0; a 0 ) + { + objectsToSend.emplace_back( ghostsToSend[a] ); + } + } +} + + + +//***** 1A *****// +void packNewAndModifiedObjectsToOwningRanks( NeighborCommunicator & neighbor, + MeshLevel * const meshLevel, + ModifiedObjectLists const & modifiedObjects, + int const commID ) +{ + int bufferSize = 0; + + NodeManager & nodeManager = meshLevel->getNodeManager(); + EdgeManager & edgeManager = meshLevel->getEdgeManager(); + FaceManager & faceManager = meshLevel->getFaceManager(); + ElementRegionManager & elemManager = meshLevel->getElemManager(); + + arrayView1d< integer const > const & nodeGhostRank = nodeManager.ghostRank(); + arrayView1d< integer const > const & edgeGhostRank = edgeManager.ghostRank(); + arrayView1d< integer const > const & faceGhostRank = faceManager.ghostRank(); + + arrayView1d< localIndex const > const & parentNodeIndices = nodeManager.getField< fields::parentIndex >(); + arrayView1d< localIndex const > const & parentEdgeIndices = edgeManager.getField< fields::parentIndex >(); + arrayView1d< localIndex const > const & parentFaceIndices = faceManager.getField< fields::parentIndex >(); + + int const neighborRank = neighbor.neighborRank(); + + array1d< localIndex > newNodePackListArray; filterNonOwnedFromContainer( newNodePackListArray, modifiedObjects.newNodes, parentNodeIndices, nodeGhostRank, neighborRank ); + array1d< localIndex > modNodePackListArray; filterNonOwnedFromContainer( modNodePackListArray, modifiedObjects.modifiedNodes, parentNodeIndices, nodeGhostRank, neighborRank ); + array1d< localIndex > newEdgePackListArray; filterNonOwnedFromContainer( newEdgePackListArray, modifiedObjects.newEdges, parentEdgeIndices, edgeGhostRank, neighborRank ); + array1d< localIndex > modEdgePackListArray; filterNonOwnedFromContainer( modEdgePackListArray, modifiedObjects.modifiedEdges, parentEdgeIndices, edgeGhostRank, neighborRank ); + array1d< localIndex > newFacePackListArray; filterNonOwnedFromContainer( newFacePackListArray, modifiedObjects.newFaces, parentFaceIndices, faceGhostRank, neighborRank ); + array1d< localIndex > modFacePackListArray; filterNonOwnedFromContainer( modFacePackListArray, modifiedObjects.modifiedFaces, parentFaceIndices, faceGhostRank, neighborRank ); + + + ElementRegionManager::ElementViewAccessor< arrayView1d< localIndex > > newElemPackList; + array1d< array1d< localIndex_array > > newElemData; + ElementRegionManager::ElementReferenceAccessor< localIndex_array > modElemPackList; + array1d< array1d< localIndex_array > > modElemData; + newElemPackList.resize( elemManager.numRegions()); + newElemData.resize( elemManager.numRegions()); + modElemPackList.resize( elemManager.numRegions()); + modElemData.resize( elemManager.numRegions()); + for( localIndex er=0; er const & subRegionGhostRank = subRegion.ghostRank(); + if( modifiedObjects.modifiedElements.count( {er, esr} ) > 0 ) + { + std::set< localIndex > const & elemList = modifiedObjects.modifiedElements.at( {er, esr} ); + filterNonOwnedFromContainer( modElemData[er][esr], elemList, subRegionGhostRank, neighborRank ); + } + + if( modifiedObjects.newElements.count( {er, esr} ) > 0 ) + { + std::set< localIndex > const & elemList = modifiedObjects.newElements.at( {er, esr} ); + filterNonOwnedFromContainer( newElemData[er][esr], elemList, subRegionGhostRank, neighborRank ); + } + + newElemPackList[er][esr] = newElemData[er][esr]; + modElemPackList[er][esr].set( modElemData[er][esr] ); + } + } + + // if we start packing sizing on device + async, poll for completion + parallelDeviceEvents sizeEvents; + bufferSize += nodeManager.packGlobalMapsSize( newNodePackListArray, 0 ); + bufferSize += edgeManager.packGlobalMapsSize( newEdgePackListArray, 0 ); + bufferSize += faceManager.packGlobalMapsSize( newFacePackListArray, 0 ); + bufferSize += elemManager.packGlobalMapsSize( newElemPackList ); + + bufferSize += nodeManager.packParentChildMapsSize( newNodePackListArray ); + bufferSize += edgeManager.packParentChildMapsSize( newEdgePackListArray ); + bufferSize += faceManager.packParentChildMapsSize( newFacePackListArray ); + bufferSize += elemManager.packFaceElementToFaceSize( newElemPackList ); + + bufferSize += nodeManager.packUpDownMapsSize( newNodePackListArray ); + bufferSize += edgeManager.packUpDownMapsSize( newEdgePackListArray ); + bufferSize += faceManager.packUpDownMapsSize( newFacePackListArray ); + bufferSize += elemManager.packUpDownMapsSize( newElemPackList ); + + bufferSize += nodeManager.packSize( newNodePackListArray, 0, false, sizeEvents ); + bufferSize += edgeManager.packSize( newEdgePackListArray, 0, false, sizeEvents ); + bufferSize += faceManager.packSize( newFacePackListArray, 0, false, sizeEvents ); + bufferSize += elemManager.packSize( newElemPackList ); + + bufferSize += nodeManager.packUpDownMapsSize( modNodePackListArray ); + bufferSize += edgeManager.packUpDownMapsSize( modEdgePackListArray ); + bufferSize += faceManager.packUpDownMapsSize( modFacePackListArray ); + bufferSize += elemManager.packUpDownMapsSize( modElemPackList ); + + bufferSize += nodeManager.packParentChildMapsSize( modNodePackListArray ); + bufferSize += edgeManager.packParentChildMapsSize( modEdgePackListArray ); + bufferSize += faceManager.packParentChildMapsSize( modFacePackListArray ); + + bufferSize += nodeManager.packSize( modNodePackListArray, 0, false, sizeEvents ); + bufferSize += edgeManager.packSize( modEdgePackListArray, 0, false, sizeEvents ); + bufferSize += faceManager.packSize( modFacePackListArray, 0, false, sizeEvents ); + + waitAllDeviceEvents( sizeEvents ); + neighbor.resizeSendBuffer( commID, bufferSize ); + + buffer_type & sendBuffer = neighbor.sendBuffer( commID ); + buffer_unit_type * sendBufferPtr = sendBuffer.data(); + + // empty event buffer + int packedSize = 0; + parallelDeviceEvents packEvents; + + packedSize += nodeManager.packGlobalMaps( sendBufferPtr, newNodePackListArray, 0 ); + packedSize += edgeManager.packGlobalMaps( sendBufferPtr, newEdgePackListArray, 0 ); + packedSize += faceManager.packGlobalMaps( sendBufferPtr, newFacePackListArray, 0 ); + packedSize += elemManager.packGlobalMaps( sendBufferPtr, newElemPackList ); + + packedSize += nodeManager.packParentChildMaps( sendBufferPtr, newNodePackListArray ); + packedSize += edgeManager.packParentChildMaps( sendBufferPtr, newEdgePackListArray ); + packedSize += faceManager.packParentChildMaps( sendBufferPtr, newFacePackListArray ); + packedSize += elemManager.packFaceElementToFace( sendBufferPtr, newElemPackList ); + + packedSize += nodeManager.packUpDownMaps( sendBufferPtr, newNodePackListArray ); + packedSize += edgeManager.packUpDownMaps( sendBufferPtr, newEdgePackListArray ); + packedSize += faceManager.packUpDownMaps( sendBufferPtr, newFacePackListArray ); + packedSize += elemManager.packUpDownMaps( sendBufferPtr, newElemPackList ); + + packedSize += nodeManager.pack( sendBufferPtr, newNodePackListArray, 0, false, packEvents ); + packedSize += edgeManager.pack( sendBufferPtr, newEdgePackListArray, 0, false, packEvents ); + packedSize += faceManager.pack( sendBufferPtr, newFacePackListArray, 0, false, packEvents ); + packedSize += elemManager.pack( sendBufferPtr, newElemPackList ); + + packedSize += nodeManager.packUpDownMaps( sendBufferPtr, modNodePackListArray ); + packedSize += edgeManager.packUpDownMaps( sendBufferPtr, modEdgePackListArray ); + packedSize += faceManager.packUpDownMaps( sendBufferPtr, modFacePackListArray ); + packedSize += elemManager.packUpDownMaps( sendBufferPtr, modElemPackList ); + + packedSize += nodeManager.packParentChildMaps( sendBufferPtr, modNodePackListArray ); + packedSize += edgeManager.packParentChildMaps( sendBufferPtr, modEdgePackListArray ); + packedSize += faceManager.packParentChildMaps( sendBufferPtr, modFacePackListArray ); + + packedSize += nodeManager.pack( sendBufferPtr, modNodePackListArray, 0, false, packEvents ); + packedSize += edgeManager.pack( sendBufferPtr, modEdgePackListArray, 0, false, packEvents ); + packedSize += faceManager.pack( sendBufferPtr, modFacePackListArray, 0, false, packEvents ); + + // poll for pack completion here + waitAllDeviceEvents( packEvents ); + GEOS_ERROR_IF( bufferSize != packedSize, + "Allocated Buffer Size ("<getNodeManager(); + EdgeManager & edgeManager = mesh->getEdgeManager(); + FaceManager & faceManager = mesh->getFaceManager(); + ElementRegionManager & elemManager = mesh->getElemManager(); + + unpackStateData.init( neighbor.receiveBuffer( commID ), elemManager ); + buffer_unit_type const * & receiveBufferPtr = unpackStateData.m_bufferPtr; + + localIndex_array & newLocalNodes = unpackStateData.m_nodes; + localIndex_array & newLocalEdges = unpackStateData.m_edges; + localIndex_array & newLocalFaces = unpackStateData.m_faces; + ElementRegionManager::ElementReferenceAccessor< array1d< localIndex > > & newLocalElements = unpackStateData.m_elements; + array1d< array1d< localIndex_array > > & newLocalElementsData = unpackStateData.m_elementsData; + + newLocalNodes.resize( 0 ); + newLocalEdges.resize( 0 ); + newLocalFaces.resize( 0 ); + + + newLocalElements.resize( elemManager.numRegions()); + newLocalElementsData.resize( elemManager.numRegions()); + for( localIndex er=0; er & allNewNodes = receivedObjects.newNodes; + std::set< localIndex > & allNewEdges = receivedObjects.newEdges; + std::set< localIndex > & allNewFaces = receivedObjects.newFaces; + map< std::pair< localIndex, localIndex >, std::set< localIndex > > & allNewElements = receivedObjects.newElements; + + allNewNodes.insert( newLocalNodes.begin(), newLocalNodes.end() ); + allNewEdges.insert( newLocalEdges.begin(), newLocalEdges.end() ); + allNewFaces.insert( newLocalFaces.begin(), newLocalFaces.end() ); + + for( localIndex er=0; ergetNodeManager(); + EdgeManager & edgeManager = mesh->getEdgeManager(); + FaceManager & faceManager = mesh->getFaceManager(); + ElementRegionManager & elemManager = mesh->getElemManager(); + + localIndex_array & newNodesToSend = packData.m_nodes; + localIndex_array & newEdgesToSend = packData.m_edges; + localIndex_array & newFacesToSend = packData.m_faces; + ElementRegionManager::ElementViewAccessor< arrayView1d< localIndex > > & newElemsToSend = packData.m_elementsView; + array1d< array1d< localIndex_array > > & newElemsToSendData = packData.m_elementsData; + + + localIndex_array & nodeGhostsToSend = nodeManager.getNeighborData( neighbor.neighborRank() ).ghostsToSend(); + localIndex_array & edgeGhostsToSend = edgeManager.getNeighborData( neighbor.neighborRank() ).ghostsToSend(); + localIndex_array & faceGhostsToSend = faceManager.getNeighborData( neighbor.neighborRank() ).ghostsToSend(); + + arrayView1d< localIndex > const & nodalParentIndices = nodeManager.getField< fields::parentIndex >(); + arrayView1d< localIndex > const & edgeParentIndices = edgeManager.getField< fields::parentIndex >(); + arrayView1d< localIndex > const & faceParentIndices = faceManager.getField< fields::parentIndex >(); + + filterNewObjectsForPackToGhosts( modifiedObjects.newNodes, nodalParentIndices, nodeGhostsToSend, newNodesToSend ); + filterNewObjectsForPackToGhosts( modifiedObjects.newEdges, edgeParentIndices, edgeGhostsToSend, newEdgesToSend ); + filterNewObjectsForPackToGhosts( modifiedObjects.newFaces, faceParentIndices, faceGhostsToSend, newFacesToSend ); + + SortedArray< localIndex > faceGhostsToSendSet; + for( localIndex const & kf : faceGhostsToSend ) + { + faceGhostsToSendSet.insert( kf ); + } + + newElemsToSendData.resize( elemManager.numRegions() ); + newElemsToSend.resize( elemManager.numRegions() ); + for( localIndex er=0; er( [&]( localIndex const esr, + FaceElementSubRegion & subRegion ) + { + arrayView2d< localIndex const > const faceList = subRegion.faceList().toViewConst(); + localIndex_array & elemGhostsToSend = subRegion.getNeighborData( neighbor.neighborRank() ).ghostsToSend(); + elemGhostsToSend.move( hostMemorySpace ); + for( localIndex const & k : modifiedObjects.newElements.at( {er, esr} ) ) + { + if( faceGhostsToSendSet.count( faceList( k, 0 ) ) ) + { + newElemsToSendData[er][esr].emplace_back( k ); + elemGhostsToSend.emplace_back( k ); + } + } + newElemsToSend[er][esr] = newElemsToSendData[er][esr]; + } ); + } + + int bufferSize = 0; + + bufferSize += nodeManager.packGlobalMapsSize( newNodesToSend, 0 ); + bufferSize += edgeManager.packGlobalMapsSize( newEdgesToSend, 0 ); + bufferSize += faceManager.packGlobalMapsSize( newFacesToSend, 0 ); + bufferSize += elemManager.packGlobalMapsSize( newElemsToSend ); + bufferSize += elemManager.packFaceElementToFaceSize( newElemsToSend ); + + neighbor.resizeSendBuffer( commID, bufferSize ); + + buffer_type & sendBuffer = neighbor.sendBuffer( commID ); + buffer_unit_type * sendBufferPtr = sendBuffer.data(); + + int packedSize = 0; + + packedSize += nodeManager.packGlobalMaps( sendBufferPtr, newNodesToSend, 0 ); + packedSize += edgeManager.packGlobalMaps( sendBufferPtr, newEdgesToSend, 0 ); + packedSize += faceManager.packGlobalMaps( sendBufferPtr, newFacesToSend, 0 ); + packedSize += elemManager.packGlobalMaps( sendBufferPtr, newElemsToSend ); + packedSize += elemManager.packFaceElementToFace( sendBufferPtr, newElemsToSend ); + + GEOS_ERROR_IF( bufferSize != packedSize, "Allocated Buffer Size is not equal to packed buffer size" ); +} + + +//***** 2b *****// +void unpackNewObjectsOnGhosts( NeighborCommunicator & neighbor, + int commID, + MeshLevel * const mesh, + ModifiedObjectLists & receivedObjects ) +{ + + NodeManager & nodeManager = mesh->getNodeManager(); + EdgeManager & edgeManager = mesh->getEdgeManager(); + FaceManager & faceManager = mesh->getFaceManager(); + ElementRegionManager & elemManager = mesh->getElemManager(); + + localIndex_array & nodeGhostsToRecv = nodeManager.getNeighborData( neighbor.neighborRank() ).ghostsToReceive(); + localIndex_array & edgeGhostsToRecv = edgeManager.getNeighborData( neighbor.neighborRank() ).ghostsToReceive(); + localIndex_array & faceGhostsToRecv = faceManager.getNeighborData( neighbor.neighborRank() ).ghostsToReceive(); + + buffer_type const & receiveBuffer = neighbor.receiveBuffer( commID ); + buffer_unit_type const * receiveBufferPtr = receiveBuffer.data(); + + localIndex_array newGhostNodes; + localIndex_array newGhostEdges; + localIndex_array newGhostFaces; + + ElementRegionManager::ElementReferenceAccessor< localIndex_array > newGhostElems; + array1d< array1d< localIndex_array > > newGhostElemsData; + newGhostElems.resize( elemManager.numRegions() ); + newGhostElemsData.resize( elemManager.numRegions() ); + for( localIndex er=0; er 0 ) + { + nodeGhostsToRecv.move( hostMemorySpace ); + for( localIndex a=0; a 0 ) + { + edgeGhostsToRecv.move( hostMemorySpace ); + for( localIndex a=0; a 0 ) + { + faceGhostsToRecv.move( hostMemorySpace ); + for( localIndex a=0; a( + [&]( localIndex const er, localIndex const esr, ElementRegionBase &, ElementSubRegionBase & subRegion ) + { + localIndex_array & elemGhostsToReceive = subRegion.getNeighborData( neighbor.neighborRank() ).ghostsToReceive(); + if( newGhostElemsData[er][esr].size() > 0 ) + { + elemGhostsToReceive.move( hostMemorySpace ); + + for( localIndex const & newElemIndex : newGhostElemsData[er][esr] ) + { + elemGhostsToReceive.emplace_back( newElemIndex ); + receivedObjects.newElements[ { er, esr } ].insert( newElemIndex ); + } + } + } ); + + receivedObjects.newNodes.insert( newGhostNodes.begin(), newGhostNodes.end() ); + receivedObjects.newEdges.insert( newGhostEdges.begin(), newGhostEdges.end() ); + receivedObjects.newFaces.insert( newGhostFaces.begin(), newGhostFaces.end() ); +} + + + +//***** 3a *****// +localIndex unpackNewAndModifiedObjectsDataOnOwningRanks( MeshLevel * const mesh, + ModifiedObjectLists & receivedObjects, + TopologyChangeUnpackStepData & unpackStateData ) +{ + GEOS_MARK_FUNCTION; + + NodeManager & nodeManager = mesh->getNodeManager(); + EdgeManager & edgeManager = mesh->getEdgeManager(); + FaceManager & faceManager = mesh->getFaceManager(); + ElementRegionManager & elemManager = mesh->getElemManager(); + + buffer_unit_type const * & receiveBufferPtr = unpackStateData.m_bufferPtr; + + localIndex_array & newLocalNodes = unpackStateData.m_nodes; + localIndex_array & newLocalEdges = unpackStateData.m_edges; + localIndex_array & newLocalFaces = unpackStateData.m_faces; + + ElementRegionManager::ElementReferenceAccessor< array1d< localIndex > > & newLocalElements = unpackStateData.m_elements; + + localIndex_array modifiedLocalNodes; + localIndex_array modifiedLocalEdges; + localIndex_array modifiedLocalFaces; + + ElementRegionManager::ElementReferenceAccessor< localIndex_array > modifiedLocalElements; + array1d< array1d< localIndex_array > > modifiedLocalElementsData; + + modifiedLocalElements.resize( elemManager.numRegions()); + modifiedLocalElementsData.resize( elemManager.numRegions()); + for( localIndex er=0; er & allModifiedNodes = receivedObjects.modifiedNodes; + std::set< localIndex > & allModifiedEdges = receivedObjects.modifiedEdges; + std::set< localIndex > & allModifiedFaces = receivedObjects.modifiedFaces; + map< std::pair< localIndex, localIndex >, std::set< localIndex > > & allModifiedElements = receivedObjects.modifiedElements; + + allModifiedNodes.insert( modifiedLocalNodes.begin(), modifiedLocalNodes.end() ); + + allModifiedEdges.insert( modifiedLocalEdges.begin(), modifiedLocalEdges.end() ); + + allModifiedFaces.insert( modifiedLocalFaces.begin(), modifiedLocalFaces.end() ); + + for( localIndex er=0; ergetNodeManager(); + EdgeManager & edgeManager = mesh->getEdgeManager(); + FaceManager & faceManager = mesh->getFaceManager(); + ElementRegionManager & elemManager = mesh->getElemManager(); + + localIndex_array & newNodesToSend = packData.m_nodes; + localIndex_array & newEdgesToSend = packData.m_edges; + localIndex_array & newFacesToSend = packData.m_faces; + ElementRegionManager::ElementViewAccessor< arrayView1d< localIndex > > & newElemsToSend = packData.m_elementsView; + // array1d< array1d< localIndex_array > > & newElemsToSendData = packData.m_elementsData; + + localIndex_array modNodesToSend; + localIndex_array modEdgesToSend; + localIndex_array modFacesToSend; + ElementRegionManager::ElementReferenceAccessor< localIndex_array > modElemsToSend; + array1d< array1d< localIndex_array > > modElemsToSendData; + + localIndex_array & nodeGhostsToSend = nodeManager.getNeighborData( neighbor.neighborRank() ).ghostsToSend(); + localIndex_array & edgeGhostsToSend = edgeManager.getNeighborData( neighbor.neighborRank() ).ghostsToSend(); + localIndex_array & faceGhostsToSend = faceManager.getNeighborData( neighbor.neighborRank() ).ghostsToSend(); + + filterModObjectsForPackToGhosts( receivedObjects.modifiedNodes, nodeGhostsToSend, modNodesToSend ); + filterModObjectsForPackToGhosts( receivedObjects.modifiedEdges, edgeGhostsToSend, modEdgesToSend ); + filterModObjectsForPackToGhosts( receivedObjects.modifiedFaces, faceGhostsToSend, modFacesToSend ); + + // newElemsToSendData.resize( elemManager.numRegions() ); + // newElemsToSend.resize( elemManager.numRegions() ); + modElemsToSendData.resize( elemManager.numRegions() ); + modElemsToSend.resize( elemManager.numRegions() ); + for( localIndex er=0; er( [&]( localIndex const esr, + // FaceElementSubRegion & subRegion ) + // { + // ArrayOfArraysView< localIndex const > const faceList = subRegion.faceList().toViewConst(); + // localIndex_array & elemGhostsToSend = subRegion.getNeighborData( neighbor.neighborRank() ).ghostsToSend(); + // elemGhostsToSend.move( hostMemorySpace ); + // for( localIndex const & k : receivedObjects.newElements.at( {er, esr} ) ) + // { + // if( faceGhostsToSendSet.count( faceList( k, 0 ) ) ) + // { + // newElemsToSendData[er][esr].emplace_back( k ); + // elemGhostsToSend.emplace_back( k ); + // } + // } + // newElemsToSend[er][esr] = newElemsToSendData[er][esr]; + // } ); + + elemRegion.forElementSubRegionsIndex< ElementSubRegionBase >( [&]( localIndex const esr, + ElementSubRegionBase const & subRegion ) + { + modElemsToSend[er][esr].set( modElemsToSendData[er][esr] ); + arrayView1d< localIndex const > const & elemGhostsToSend = subRegion.getNeighborData( neighbor.neighborRank() ).ghostsToSend(); + for( localIndex const ghostToSend : elemGhostsToSend ) + { + if( receivedObjects.modifiedElements.at( { er, esr } ).count( ghostToSend ) > 0 ) + { + modElemsToSendData[er][esr].emplace_back( ghostToSend ); + } + } + } ); + } + + parallelDeviceEvents sizeEvents; + int bufferSize = 0; + + + bufferSize += nodeManager.packUpDownMapsSize( newNodesToSend ); + bufferSize += edgeManager.packUpDownMapsSize( newEdgesToSend ); + bufferSize += faceManager.packUpDownMapsSize( newFacesToSend ); + bufferSize += elemManager.packUpDownMapsSize( newElemsToSend ); + + bufferSize += nodeManager.packParentChildMapsSize( newNodesToSend ); + bufferSize += edgeManager.packParentChildMapsSize( newEdgesToSend ); + bufferSize += faceManager.packParentChildMapsSize( newFacesToSend ); + + bufferSize += nodeManager.packSize( newNodesToSend, 0, false, sizeEvents ); + bufferSize += edgeManager.packSize( newEdgesToSend, 0, false, sizeEvents ); + bufferSize += faceManager.packSize( newFacesToSend, 0, false, sizeEvents ); + bufferSize += elemManager.packSize( newElemsToSend ); + + bufferSize += nodeManager.packUpDownMapsSize( modNodesToSend ); + bufferSize += edgeManager.packUpDownMapsSize( modEdgesToSend ); + bufferSize += faceManager.packUpDownMapsSize( modFacesToSend ); + bufferSize += elemManager.packUpDownMapsSize( modElemsToSend ); + + bufferSize += nodeManager.packParentChildMapsSize( modNodesToSend ); + bufferSize += edgeManager.packParentChildMapsSize( modEdgesToSend ); + bufferSize += faceManager.packParentChildMapsSize( modFacesToSend ); + + waitAllDeviceEvents( sizeEvents ); + neighbor.resizeSendBuffer( commID, bufferSize ); + + buffer_type & sendBuffer = neighbor.sendBuffer( commID ); + buffer_unit_type * sendBufferPtr = sendBuffer.data(); + + parallelDeviceEvents packEvents; + int packedSize = 0; + + packedSize += nodeManager.packUpDownMaps( sendBufferPtr, newNodesToSend ); + packedSize += edgeManager.packUpDownMaps( sendBufferPtr, newEdgesToSend ); + packedSize += faceManager.packUpDownMaps( sendBufferPtr, newFacesToSend ); + packedSize += elemManager.packUpDownMaps( sendBufferPtr, newElemsToSend ); + + packedSize += nodeManager.packParentChildMaps( sendBufferPtr, newNodesToSend ); + packedSize += edgeManager.packParentChildMaps( sendBufferPtr, newEdgesToSend ); + packedSize += faceManager.packParentChildMaps( sendBufferPtr, newFacesToSend ); + + packedSize += nodeManager.pack( sendBufferPtr, newNodesToSend, 0, false, packEvents ); + packedSize += edgeManager.pack( sendBufferPtr, newEdgesToSend, 0, false, packEvents ); + packedSize += faceManager.pack( sendBufferPtr, newFacesToSend, 0, false, packEvents ); + packedSize += elemManager.pack( sendBufferPtr, newElemsToSend ); + + packedSize += nodeManager.packUpDownMaps( sendBufferPtr, modNodesToSend ); + packedSize += edgeManager.packUpDownMaps( sendBufferPtr, modEdgesToSend ); + packedSize += faceManager.packUpDownMaps( sendBufferPtr, modFacesToSend ); + packedSize += elemManager.packUpDownMaps( sendBufferPtr, modElemsToSend ); + + packedSize += nodeManager.packParentChildMaps( sendBufferPtr, modNodesToSend ); + packedSize += edgeManager.packParentChildMaps( sendBufferPtr, modEdgesToSend ); + packedSize += faceManager.packParentChildMaps( sendBufferPtr, modFacesToSend ); + + GEOS_ERROR_IF( bufferSize != packedSize, "Allocated Buffer Size is not equal to packed buffer size" ); + + waitAllDeviceEvents( packEvents ); +} + + +//***** 3c ***** +void unpackNewAndModifiedObjectsDataOnGhosts( NeighborCommunicator & neighbor, + int commID, + MeshLevel * const mesh, + ModifiedObjectLists & receivedObjects ) +{ + + NodeManager & nodeManager = mesh->getNodeManager(); + EdgeManager & edgeManager = mesh->getEdgeManager(); + FaceManager & faceManager = mesh->getFaceManager(); + ElementRegionManager & elemManager = mesh->getElemManager(); + + buffer_type const & receiveBuffer = neighbor.receiveBuffer( commID ); + buffer_unit_type const * receiveBufferPtr = receiveBuffer.data(); + + localIndex_array newGhostNodes; + localIndex_array newGhostEdges; + localIndex_array newGhostFaces; + + localIndex_array modGhostNodes; + localIndex_array modGhostEdges; + localIndex_array modGhostFaces; + + ElementRegionManager::ElementReferenceAccessor< localIndex_array > newGhostElems; + array1d< array1d< localIndex_array > > newGhostElemsData; + newGhostElems.resize( elemManager.numRegions() ); + newGhostElemsData.resize( elemManager.numRegions() ); + ElementRegionManager::ElementReferenceAccessor< localIndex_array > modGhostElems; + array1d< array1d< localIndex_array > > modGhostElemsData; + modGhostElems.resize( elemManager.numRegions() ); + modGhostElemsData.resize( elemManager.numRegions() ); + for( localIndex er=0; er( + [&]( localIndex const er, localIndex const esr, ElementRegionBase &, ElementSubRegionBase & ) + { + receivedObjects.modifiedElements[ { er, esr } ].insert( modGhostElemsData[er][esr].begin(), + modGhostElemsData[er][esr].end() ); + } ); + + receivedObjects.modifiedNodes.insert( modGhostNodes.begin(), modGhostNodes.end() ); + receivedObjects.modifiedEdges.insert( modGhostEdges.begin(), modGhostEdges.end() ); + receivedObjects.modifiedFaces.insert( modGhostFaces.begin(), modGhostFaces.end() ); + +} + + + +void updateConnectorsToFaceElems( std::set< localIndex > const & newFaceElements, + FaceElementSubRegion & faceElemSubRegion ) +{ + ArrayOfArrays< localIndex > & connectorToElem = faceElemSubRegion.m_2dFaceTo2dElems; + map< localIndex, localIndex > & edgesToConnectorEdges = faceElemSubRegion.m_edgesTo2dFaces; + array1d< localIndex > & connectorEdgesToEdges = faceElemSubRegion.m_2dFaceToEdge; + + ArrayOfArraysView< localIndex const > const facesToEdges = faceElemSubRegion.edgeList().toViewConst(); + + for( localIndex const & kfe : newFaceElements ) + { + arraySlice1d< localIndex const > const faceToEdges = facesToEdges[kfe]; + for( localIndex ke=0; ke & neighbors, + ModifiedObjectLists & modifiedObjects, + ModifiedObjectLists & receivedObjects, + int mpiCommOrder ) +{ + + NodeManager & nodeManager = mesh->getNodeManager(); + EdgeManager & edgeManager = mesh->getEdgeManager(); + FaceManager & faceManager = mesh->getFaceManager(); + ElementRegionManager & elemManager = mesh->getElemManager(); + + + /************************************************************************************************ + * The goal is to synchronize the changes from the rank that has topology changes to + * ranks that have copies of the objects that were changed. In this "original" implementation, we + * do this without map unpacking optimizations intended to reduce communications. + * + * Nomenclature is key to understanding the process: + * - "New" objects are objects that have just been created on by the "active color rank (ACR)" + * - "Modified" objects are objects that have been modified by the ACR. + * + * - ACR (active color rank) is the rank that has created the topology changes. Given the way we + * map the colors to ranks, the ACR are NOT neighbors...i.e. do not communicate with each other. + * - OR (Owning rank/s) is the rank that owns the "new/modified" objects. This may or may not be + * the ACR. + * - GR (Ghosted rank/s) is the rank that has a ghost copy of the "new/modified" object. + * + * note: object parents define the owning rank. + * note: for any receive/unpack operation, the current rank is the rank performing the operation + * from each neighbor...i.e. the current rank is the OR and the GR. + * + * The sequence of steps are: + * 1a) On the ACR, pack the new/modified objects that are not owned by the ACR and send them to + * their OR. + * 1b) On the OR, unpack the new objects that are owned by the rank that has the changes. DO NOT + * unpack the maps as they will potentially contain indices that are not on the OR. + * + * At this point the OR has all the new objects that it owns...but not the maps or the fields. + * + * 2a) On the OR, pack the new objects that are owned by the rank and send them to the ranks + * where they are ghosted (GR). DO NOT PACK THE MAPS as they are incomplete. + * 2b) On the GR, unpack the new objects. + * + * Now everyone has all the objects and we can pack/send/receive/unpack the maps. + * + * 3a) On the OR, unpack the map modification on owning ranks from 1b). + * + * Now the OR has the correct maps. + * + * 3b) On the OR, pack the map/field modification and send to the GR. + * 3c) On the GR, unpack the map/field modifications. + * + ***********************************************************************************************/ + + + + //*********************************************************************************************** + // 1a) On the ACR, pack the new/modified objects that are not owned by the ACR and send them to + // their OR. + //*********************************************************************************************** + +// std::cout<<"***** Step 1a *****"< step1bUnpackData( neighbors.size() ); + for( unsigned int count=0; count( [&]( localIndex const er, + localIndex const esr, + ElementRegionBase &, + FaceElementSubRegion & subRegion ) + { + subRegion.inheritGhostRankFromParentFace( faceManager, receivedObjects.newElements[{er, esr}] ); + } ); + + MpiWrapper::waitAll( commData1.size(), + commData1.mpiSendBufferSizeRequest(), + commData1.mpiSendBufferSizeStatus() ); + + MpiWrapper::waitAll( commData1.size(), + commData1.mpiSendBufferRequest(), + commData1.mpiSendBufferSizeStatus() ); + + modifiedObjects.insert( receivedObjects ); + + + //************************************************************************************************ + // 2a) On the OR, pack the new objects that are owned by the rank and send them to the ranks + // where they are ghosted (GR). DO NOT PACK THE MAPS as they are incomplete. + //************************************************************************************************ + + MpiWrapper::barrier(); +// std::cout<<"***** Step 2a *****"< step2and3PackData( neighbors.size() ); + + // pack the new objects to send to ghost ranks + for( unsigned int neighborIndex=0; neighborIndex( [&]( localIndex const er, + localIndex const esr, + ElementRegionBase const &, + FaceElementSubRegion & subRegion ) + { + updateConnectorsToFaceElems( receivedObjects.newElements.at( {er, esr} ), subRegion ); + } ); + + + std::set< localIndex > allTouchedNodes; + allTouchedNodes.insert( modifiedObjects.newNodes.begin(), modifiedObjects.newNodes.end() ); + allTouchedNodes.insert( modifiedObjects.modifiedNodes.begin(), modifiedObjects.modifiedNodes.end() ); + nodeManager.depopulateUpMaps( allTouchedNodes, + edgeManager.nodeList(), + faceManager.nodeList().toViewConst(), + elemManager ); + + std::set< localIndex > allTouchedEdges; + allTouchedEdges.insert( modifiedObjects.newEdges.begin(), modifiedObjects.newEdges.end() ); + allTouchedEdges.insert( modifiedObjects.modifiedEdges.begin(), modifiedObjects.modifiedEdges.end() ); + edgeManager.depopulateUpMaps( allTouchedEdges, + faceManager.edgeList().toViewConst() ); + + std::set< localIndex > allTouchedFaces; + allTouchedFaces.insert( modifiedObjects.newFaces.begin(), modifiedObjects.newFaces.end() ); + allTouchedFaces.insert( modifiedObjects.modifiedFaces.begin(), modifiedObjects.modifiedFaces.end() ); + faceManager.depopulateUpMaps( allTouchedFaces, elemManager ); + + nodeManager.enforceStateFieldConsistencyPostTopologyChange( modifiedObjects.modifiedNodes ); + edgeManager.enforceStateFieldConsistencyPostTopologyChange( modifiedObjects.modifiedEdges ); + faceManager.enforceStateFieldConsistencyPostTopologyChange( modifiedObjects.modifiedFaces ); + + +} + +} + + + +} /* namespace geos */ +#endif // PARALLEL_TOPOLOGY_CHANGE_METHOD==1 diff --git a/src/coreComponents/physicsSolvers/surfaceGeneration/SurfaceGenerator.cpp b/src/coreComponents/physicsSolvers/surfaceGeneration/SurfaceGenerator.cpp index 42e8639eab7..2e16f5bfeea 100644 --- a/src/coreComponents/physicsSolvers/surfaceGeneration/SurfaceGenerator.cpp +++ b/src/coreComponents/physicsSolvers/surfaceGeneration/SurfaceGenerator.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -17,7 +18,6 @@ */ #include "SurfaceGenerator.hpp" -#include "ParallelTopologyChange.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "mesh/mpiCommunications/NeighborCommunicator.hpp" @@ -31,9 +31,11 @@ #include "physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp" #include "physicsSolvers/solidMechanics/kernels/SolidMechanicsLagrangianFEMKernels.hpp" #include "physicsSolvers/surfaceGeneration/SurfaceGeneratorFields.hpp" +#include "physicsSolvers/surfaceGeneration/LogLevelsInfo.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "kernels/surfaceGenerationKernels.hpp" +#include "ParallelTopologyChange.hpp" #include @@ -173,7 +175,7 @@ static void CheckForAndRemoveDeadEndPath( const localIndex edgeIndex, SurfaceGenerator::SurfaceGenerator( const string & name, Group * const parent ): - SolverBase( name, parent ), + PhysicsSolverBase( name, parent ), m_failCriterion( 1 ), // m_maxTurnAngle(91.0), m_nodeBasedSIF( 1 ), @@ -219,9 +221,13 @@ SurfaceGenerator::SurfaceGenerator( const string & name, this->getWrapper< string >( viewKeyStruct::discretizationString() ). setInputFlag( InputFlags::FALSE ); + + addLogLevel< logInfo::SurfaceGenerator >(); + addLogLevel< logInfo::Mapping >(); + addLogLevel< logInfo::RuptureRate >(); } -void SurfaceGenerator::postProcessInput() +void SurfaceGenerator::postInputInitialization() { static const std::set< integer > binaryOptions = { 0, 1 }; @@ -453,7 +459,7 @@ void SurfaceGenerator::postRestartInitialization() FluxApproximationBase * const fluxApprox = fvManager.getGroupPointer< FluxApproximationBase >( a ); if( fluxApprox!=nullptr ) { - fluxApprox->addToFractureStencil( meshLevel, this->m_fractureRegionName, false ); + fluxApprox->addToFractureStencil( meshLevel, this->m_fractureRegionName ); } } @@ -508,13 +514,11 @@ real64 SurfaceGenerator::solverStep( real64 const & time_n, FluxApproximationBase * const fluxApprox = fvManager.getGroupPointer< FluxApproximationBase >( a ); if( fluxApprox!=nullptr ) { - fluxApprox->addToFractureStencil( meshLevel, this->m_fractureRegionName, true ); + fluxApprox->addToFractureStencil( meshLevel, this->m_fractureRegionName ); } } FaceElementSubRegion & fractureSubRegion = fractureRegion.getUniqueSubRegion< FaceElementSubRegion >(); - fractureSubRegion.m_recalculateConnectionsFor2dFaces.clear(); - fractureSubRegion.m_newFaceElements.clear(); // Recreate geometric sets meshLevel.getNodeManager().buildGeometricSets( GeometricObjectManager::getInstance() ); @@ -665,7 +669,7 @@ int SurfaceGenerator::separationDriver( DomainPartition & domain, } } -#ifdef GEOSX_USE_MPI +#ifdef GEOS_USE_MPI modifiedObjects.clearNewFromModified(); @@ -718,7 +722,7 @@ int SurfaceGenerator::separationDriver( DomainPartition & domain, elementManager.forElementSubRegions< FaceElementSubRegion >( [&]( FaceElementSubRegion & subRegion ) { FaceElementSubRegion::NodeMapType & nodeMap = subRegion.nodeList(); - ArrayOfArraysView< localIndex const > const faceMap = subRegion.faceList().toViewConst(); + arrayView2d< localIndex const > const faceMap = subRegion.faceList().toViewConst(); for( localIndex kfe=0; kfe( this->m_fractureRegionName ) ); - GEOS_LOG_LEVEL_RANK_0( 3, "rupture rate is " << ruptureRate ); + GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::RuptureRate, GEOS_FMT( "Rupture rate = {}", ruptureRate ) ); if( ruptureRate > 0 ) m_nextDt = ruptureRate < 1e99 ? m_cflFactor / ruptureRate : 1e99; @@ -1011,9 +1013,9 @@ bool SurfaceGenerator::findFracturePlanes( localIndex const nodeID, ArrayOfArraysView< localIndex const > const & faceToEdgeMap = faceManager.edgeList().toViewConst(); - arraySlice1d< localIndex const > const & nodeToRegionMap = nodeManager.elementRegionList()[nodeID]; - arraySlice1d< localIndex const > const & nodeToSubRegionMap = nodeManager.elementSubRegionList()[nodeID]; - arraySlice1d< localIndex const > const & nodeToElementMap = nodeManager.elementList()[nodeID]; + arraySlice1d< localIndex const > const nodeToRegionMap = nodeManager.elementRegionList()[nodeID]; + arraySlice1d< localIndex const > const nodeToSubRegionMap = nodeManager.elementSubRegionList()[nodeID]; + arraySlice1d< localIndex const > const nodeToElementMap = nodeManager.elementList()[nodeID]; // BACKWARDS COMPATIBILITY HACK! // @@ -1727,14 +1729,13 @@ void SurfaceGenerator::performFracture( const localIndex nodeID, // Split the node into two, using the original index, and a new one. localIndex newNodeIndex; - if( getLogLevel() > 0 ) { std::ostringstream s; for( std::set< localIndex >::const_iterator i=separationPathFaces.begin(); i!=separationPathFaces.end(); ++i ) { s << *i << " "; } - GEOS_LOG_RANK( GEOS_FMT( "Splitting node {} along separation plane faces: {}", nodeID, s.str() ) ); + GEOS_LOG_LEVEL_INFO_BY_RANK( logInfo::SurfaceGenerator, GEOS_FMT( "Splitting node {} along separation plane faces: {}", nodeID, s.str() ) ); } @@ -1773,11 +1774,7 @@ void SurfaceGenerator::performFracture( const localIndex nodeID, // >("usedFaces")[newNodeIndex]; // usedFacesNew = usedFaces[nodeID]; - - if( getLogLevel() > 0 ) - { - GEOS_LOG_RANK( GEOS_FMT( "Done splitting node {} into nodes {} and {}", nodeID, nodeID, newNodeIndex ) ); - } + GEOS_LOG_LEVEL_INFO_BY_RANK( logInfo::SurfaceGenerator, GEOS_FMT( "Done splitting node {} into nodes {} and {}", nodeID, nodeID, newNodeIndex ) ); // split edges map< localIndex, localIndex > splitEdges; @@ -1798,10 +1795,7 @@ void SurfaceGenerator::performFracture( const localIndex nodeID, edgeToFaceMap.clearSet( newEdgeIndex ); - if( getLogLevel() > 0 ) - { - GEOS_LOG_RANK( GEOS_FMT ( "Split edge {} into edges {} and {}", parentEdgeIndex, parentEdgeIndex, newEdgeIndex ) ); - } + GEOS_LOG_LEVEL_INFO_BY_RANK( logInfo::SurfaceGenerator, GEOS_FMT ( "Split edge {} into edges {} and {}", parentEdgeIndex, parentEdgeIndex, newEdgeIndex ) ); splitEdges[parentEdgeIndex] = newEdgeIndex; modifiedObjects.newEdges.insert( newEdgeIndex ); @@ -1857,11 +1851,7 @@ void SurfaceGenerator::performFracture( const localIndex nodeID, if( faceManager.splitObject( faceIndex, rank, newFaceIndex ) ) { - - if( getLogLevel() > 0 ) - { - GEOS_LOG_RANK( GEOS_FMT ( "Split face {} into faces {} and {}", faceIndex, faceIndex, newFaceIndex ) ); - } + GEOS_LOG_LEVEL_INFO_BY_RANK( logInfo::SurfaceGenerator, GEOS_FMT ( "Split face {} into faces {} and {}", faceIndex, faceIndex, newFaceIndex ) ); splitFaces[faceIndex] = newFaceIndex; modifiedObjects.newFaces.insert( newFaceIndex ); @@ -1946,6 +1936,7 @@ void SurfaceGenerator::performFracture( const localIndex nodeID, this->m_originalFaceToEdges.toViewConst(), faceIndices ); m_faceElemsRupturedThisSolve.insert( newFaceElement ); + GEOS_LOG_LEVEL_INFO_BY_RANK( logInfo::SurfaceGenerator, GEOS_FMT ( "Created new FaceElement {} when creating face {} from {}", newFaceElement, newFaceIndex, faceIndex ) ); modifiedObjects.newElements[ {fractureElementRegion.getIndexInParent(), 0} ].insert( newFaceElement ); } } // if( faceManager.SplitObject( faceIndex, newFaceIndex ) ) @@ -2128,23 +2119,19 @@ void SurfaceGenerator::performFracture( const localIndex nodeID, faceToElementMap[faceIndex][1] = -1; } - if( getLogLevel() > 1 ) - { - GEOS_LOG( " faceToRegionMap["<( totalStress, -m_biotCoefficient[er][esr][m_porosityMaterialFullIndex[er]][ei] * m_pressure[er][esr][ei] ); - computeNodalForce( totalStress, dNdX, m_detJ[er][esr][ei][q], force ); + surfaceGenerationKernelsHelpers::computeNodalForce( totalStress, dNdX, m_detJ[er][esr][ei][q], force ); } //wu40: the nodal force need to be weighted by Young's modulus and possion's ratio. - scaleNodalForce( m_bulkModulus[er][esr][m_solidMaterialFullIndex[er]][ei], m_shearModulus[er][esr][m_solidMaterialFullIndex[er]][ei], force ); + surfaceGenerationKernelsHelpers::scaleNodalForce( m_bulkModulus[er][esr][m_solidMaterialFullIndex[er]][ei], m_shearModulus[er][esr][m_solidMaterialFullIndex[er]][ei], force ); } private: diff --git a/src/coreComponents/physicsSolvers/surfaceGeneration/kernels/surfaceGenerationKernelsHelpers.hpp b/src/coreComponents/physicsSolvers/surfaceGeneration/kernels/surfaceGenerationKernelsHelpers.hpp index 917ce1f1a8a..1e1a596bb68 100644 --- a/src/coreComponents/physicsSolvers/surfaceGeneration/kernels/surfaceGenerationKernelsHelpers.hpp +++ b/src/coreComponents/physicsSolvers/surfaceGeneration/kernels/surfaceGenerationKernelsHelpers.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/wavePropagation/AcousticElasticWaveEquationSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/AcousticElasticWaveEquationSEMKernel.hpp deleted file mode 100644 index 9c3e9f5fbdc..00000000000 --- a/src/coreComponents/physicsSolvers/wavePropagation/AcousticElasticWaveEquationSEMKernel.hpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file AcousticElasticWaveEquationSEMKernel.hpp - */ - -#ifndef SRC_CORECOMPONENTS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICELASTICWAVEEQUATIONSEMKERNEL_HPP_ -#define SRC_CORECOMPONENTS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICELASTICWAVEEQUATIONSEMKERNEL_HPP_ - -#include "finiteElement/kernelInterface/KernelBase.hpp" -#if !defined( GEOS_USE_HIP ) -#include "finiteElement/elementFormulations/Qk_Hexahedron_Lagrange_GaussLobatto.hpp" -#endif - -#include - -namespace geos -{ - -namespace acousticElasticWaveEquationSEMKernels -{ - -template< typename FE_TYPE > -struct CouplingKernel -{ - static constexpr localIndex numNodesPerFace = FE_TYPE::numNodesPerFace; - - template< typename EXEC_POLICY, typename ATOMIC_POLICY > - void - launch( localIndex const size, - arrayView2d< WaveSolverBase::wsCoordType const, - nodes::REFERENCE_POSITION_USD > const nodeCoords, - localIndex const regionIndex, - localIndex const subRegionIndex, - arrayView2d< localIndex const > const faceToSubRegion, - arrayView2d< localIndex const > const faceToRegion, - arrayView2d< localIndex const > const faceToElement, - ArrayOfArraysView< localIndex const > const facesToNodes, - arrayView2d< real64 const > const faceNormals, - arrayView1d< real32 > const couplingVectorx, - arrayView1d< real32 > const couplingVectory, - arrayView1d< real32 > const couplingVectorz ) - { - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const f ) - { - localIndex e0 = faceToElement( f, 0 ), e1 = faceToElement( f, 1 ); - localIndex er0 = faceToRegion( f, 0 ), er1 = faceToRegion( f, 1 ); - localIndex esr0 = faceToSubRegion( f, 0 ), esr1 = faceToSubRegion( f, 1 ); - - if( e0 != -1 && e1 != -1 && er0 != er1 ) // an interface is defined as a transition between regions - { - // check that one of the region is the fluid subregion for the fluid -> solid coupling term - if((er0 == regionIndex && esr0 == subRegionIndex) || (er1 == regionIndex && esr1 == subRegionIndex)) - { - // only the four corners of the mesh face are needed to compute the Jacobian - real64 xLocal[ 4 ][ 3 ]; - for( localIndex a = 0; a < 4; ++a ) - { - localIndex const nodeIndex = facesToNodes( f, FE_TYPE::meshIndexToLinearIndex2D( a ) ); - for( localIndex i = 0; i < 3; ++i ) - { - xLocal[a][i] = nodeCoords( nodeIndex, i ); - } - } - - // determine normal sign for fluid -> solid coupling - localIndex sgn = er0 == regionIndex ? 1 : (er1 == regionIndex ? -1 : 0); - - for( localIndex q = 0; q < numNodesPerFace; ++q ) - { - real64 const aux = FE_TYPE::computeDampingTerm( q, xLocal ); - - real32 const localIncrementx = aux * (sgn * faceNormals( f, 0 )); - real32 const localIncrementy = aux * (sgn * faceNormals( f, 1 )); - real32 const localIncrementz = aux * (sgn * faceNormals( f, 2 )); - - RAJA::atomicAdd< ATOMIC_POLICY >( &couplingVectorx[facesToNodes( f, q )], localIncrementx ); - RAJA::atomicAdd< ATOMIC_POLICY >( &couplingVectory[facesToNodes( f, q )], localIncrementy ); - RAJA::atomicAdd< ATOMIC_POLICY >( &couplingVectorz[facesToNodes( f, q )], localIncrementz ); - } - } - } - } ); - - } -}; - -} /* namespace acousticElasticWaveEquationSEMKernels */ - -} /* namespace geos */ - -#endif /* SRC_CORECOMPONENTS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICELASTICWAVEEQUATIONSEMKERNEL_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/AcousticFirstOrderWaveEquationSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/AcousticFirstOrderWaveEquationSEMKernel.hpp deleted file mode 100644 index 97eddf54faf..00000000000 --- a/src/coreComponents/physicsSolvers/wavePropagation/AcousticFirstOrderWaveEquationSEMKernel.hpp +++ /dev/null @@ -1,589 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file AcousticFirstOrderWaveEquationSEMKernel.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICFIRSTTORDERWAVEEQUATIONSEMKERNEL_HPP_ -#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICFIRSTTORDERWAVEEQUATIONSEMKERNEL_HPP_ - -#include "finiteElement/kernelInterface/KernelBase.hpp" -#include "WaveSolverUtils.hpp" - - - -namespace geos -{ - -/// Namespace to contain the first order acoustic wave kernels. -namespace acousticFirstOrderWaveEquationSEMKernels -{ - -struct PrecomputeSourceAndReceiverKernel -{ - - /** - * @brief Launches the precomputation of the source and receiver terms - * @tparam EXEC_POLICY execution policy - * @tparam FE_TYPE finite element type - * @param[in] size the number of cells in the subRegion - * @param[in] numFacesPerElem number of faces per element - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemGhostRank rank of the ghost element - * @param[in] elemsToNodes map from element to nodes - * @param[in] elemsToFaces map from element to faces - * @param[in] elemCenter coordinates of the element centers - * @param[in] faceNormal normal of each faces - * @param[in] faceCenter coordinates of the center of a face - * @param[in] sourceCoordinates coordinates of the source terms - * @param[out] sourceIsAccessible flag indicating whether the source is accessible or not - * @param[out] sourceElem element where a source is located - * @param[out] sourceNodeIds indices of the nodes of the element where the source is located - * @param[out] sourceConstants constant part of the source terms - * @param[in] receiverCoordinates coordinates of the receiver terms - * @param[out] receiverIsLocal flag indicating whether the receiver is local or not - * @param[out] rcvElem element where a receiver is located - * @param[out] receiverNodeIds indices of the nodes of the element where the receiver is located - * @param[out] receiverConstants constant part of the receiver term - * @param[out] sourceValue value of the temporal source (eg. Ricker) - * @param[in] dt time-step - * @param[in] timeSourceFrequency the central frequency of the source - * @param[in] timeSourceDelay the time delay of the source - * @param[in] rickerOrder order of the Ricker wavelet - */ - template< typename EXEC_POLICY, typename FE_TYPE > - static void - launch( localIndex const size, - localIndex const regionIndex, - localIndex const numFacesPerElem, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView1d< integer const > const elemGhostRank, - arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes, - arrayView2d< localIndex const > const elemsToFaces, - arrayView2d< real64 const > const & elemCenter, - arrayView2d< real64 const > const faceNormal, - arrayView2d< real64 const > const faceCenter, - arrayView2d< real64 const > const sourceCoordinates, - arrayView1d< localIndex > const sourceIsAccessible, - arrayView1d< localIndex > const sourceElem, - arrayView2d< localIndex > const sourceNodeIds, - arrayView2d< real64 > const sourceConstants, - arrayView1d< localIndex > const sourceRegion, - arrayView2d< real64 const > const receiverCoordinates, - arrayView1d< localIndex > const receiverIsLocal, - arrayView1d< localIndex > const rcvElem, - arrayView2d< localIndex > const receiverNodeIds, - arrayView2d< real64 > const receiverConstants, - arrayView1d< localIndex > const receiverRegion, - arrayView2d< real32 > const sourceValue, - real64 const dt, - real32 const timeSourceFrequency, - real32 const timeSourceDelay, - localIndex const rickerOrder ) - { - constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; - - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - real64 const center[3] = { elemCenter[k][0], - elemCenter[k][1], - elemCenter[k][2] }; - - // Step 1: locate the sources, and precompute the source term - - /// loop over all the source that haven't been found yet - for( localIndex isrc = 0; isrc < sourceCoordinates.size( 0 ); ++isrc ) - { - if( sourceIsAccessible[isrc] == 0 ) - { - real64 const coords[3] = { sourceCoordinates[isrc][0], - sourceCoordinates[isrc][1], - sourceCoordinates[isrc][2] }; - - bool const sourceFound = - WaveSolverUtils::locateSourceElement( numFacesPerElem, - center, - faceNormal, - faceCenter, - elemsToFaces[k], - coords ); - - if( sourceFound ) - { - real64 coordsOnRefElem[3]{}; - - WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, - elemsToNodes[k], - nodeCoords, - coordsOnRefElem ); - - sourceIsAccessible[isrc] = 1; - sourceElem[isrc] = k; - sourceRegion[isrc] = regionIndex; - real64 Ntest[numNodesPerElem]; - FE_TYPE::calcN( coordsOnRefElem, Ntest ); - - for( localIndex a = 0; a < numNodesPerElem; ++a ) - { - sourceNodeIds[isrc][a] = elemsToNodes[k][a]; - sourceConstants[isrc][a] = Ntest[a]; - } - - for( localIndex cycle = 0; cycle < sourceValue.size( 0 ); ++cycle ) - { - sourceValue[cycle][isrc] = WaveSolverUtils::evaluateRicker( cycle * dt, timeSourceFrequency, timeSourceDelay, rickerOrder ); - } - } - } - } // end loop over all sources - - - // Step 2: locate the receivers, and precompute the receiver term - - /// loop over all the receivers that haven't been found yet - for( localIndex ircv = 0; ircv < receiverCoordinates.size( 0 ); ++ircv ) - { - if( receiverIsLocal[ircv] == 0 ) - { - real64 const coords[3] = { receiverCoordinates[ircv][0], - receiverCoordinates[ircv][1], - receiverCoordinates[ircv][2] }; - - real64 coordsOnRefElem[3]{}; - bool const receiverFound = - WaveSolverUtils::locateSourceElement( numFacesPerElem, - center, - faceNormal, - faceCenter, - elemsToFaces[k], - coords ); - - if( receiverFound && elemGhostRank[k] < 0 ) - { - WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, - elemsToNodes[k], - nodeCoords, - coordsOnRefElem ); - receiverIsLocal[ircv] = 1; - rcvElem[ircv] = k; - receiverRegion[ircv] = regionIndex; - - real64 Ntest[numNodesPerElem]; - FE_TYPE::calcN( coordsOnRefElem, Ntest ); - - for( localIndex a = 0; a < numNodesPerElem; ++a ) - { - receiverNodeIds[ircv][a] = elemsToNodes[k][a]; - receiverConstants[ircv][a] = Ntest[a]; - } - } - } - } // end loop over receivers - - } ); - - } -}; - -template< typename FE_TYPE > -struct MassMatrixKernel -{ - - MassMatrixKernel( FE_TYPE const & finiteElement ) - : m_finiteElement( finiteElement ) - {} - - /** - * @brief Launches the precomputation of the mass matrix - * @tparam EXEC_POLICY the execution policy - * @tparam ATOMIC_POLICY the atomic policy - * @param[in] size the number of cells in the subRegion - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemsToNodes map from element to nodes - * @param[in] velocity cell-wise velocity - * @param[in] density cell-wise density - * @param[out] mass diagonal of the mass matrix - */ - template< typename EXEC_POLICY, typename ATOMIC_POLICY > - void - launch( localIndex const size, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes, - arrayView1d< real32 const > const velocity, - arrayView1d< real32 const > const density, - arrayView1d< real32 > const mass ) - - { - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const e ) - { - - - real32 const invC2 = 1.0 / ( density[e] * pow( velocity[e], 2 ) ); - // only the eight corners of the mesh cell are needed to compute the Jacobian - real64 xLocal[ 8 ][ 3 ]; - for( localIndex a = 0; a < 8; ++a ) - { - localIndex const nodeIndex = elemsToNodes( e, FE_TYPE::meshIndexToLinearIndex3D( a ) ); - for( localIndex i = 0; i < 3; ++i ) - { - xLocal[a][i] = nodeCoords( nodeIndex, i ); - } - } - - constexpr localIndex numQuadraturePointsPerElem = FE_TYPE::numQuadraturePoints; - for( localIndex q = 0; q < numQuadraturePointsPerElem; ++q ) - { - real32 const localIncrement = invC2 * m_finiteElement.computeMassTerm( q, xLocal ); - RAJA::atomicAdd< ATOMIC_POLICY >( &mass[elemsToNodes( e, q )], localIncrement ); - } - } ); // end loop over element - } - - /// The finite element space/discretization object for the element type in the subRegion - FE_TYPE const & m_finiteElement; - -}; - -template< typename FE_TYPE > -struct DampingMatrixKernel -{ - - DampingMatrixKernel( FE_TYPE const & finiteElement ) - : m_finiteElement( finiteElement ) - {} - - /** - * @brief Launches the precomputation of the damping matrices - * @tparam EXEC_POLICY the execution policy - * @tparam ATOMIC_POLICY the atomic policy - * @param[in] size the number of cells in the subRegion - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemsToFaces map from elements to faces - * @param[in] facesToNodes map from face to nodes - * @param[in] facesDomainBoundaryIndicator flag equal to 1 if the face is on the boundary, and to 0 otherwise - * @param[in] freeSurfaceFaceIndicator flag equal to 1 if the face is on the free surface, and to 0 otherwise - * @param[in] velocity cell-wise velocity - * @param[out] damping diagonal of the damping matrix - */ - template< typename EXEC_POLICY, typename ATOMIC_POLICY > - void - launch( localIndex const size, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView2d< localIndex const > const elemsToFaces, - ArrayOfArraysView< localIndex const > const facesToNodes, - arrayView1d< integer const > const facesDomainBoundaryIndicator, - arrayView1d< localIndex const > const freeSurfaceFaceIndicator, - arrayView1d< real32 const > const velocity, - arrayView1d< real32 > const damping ) - { - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const e ) - { - for( localIndex i = 0; i < elemsToFaces.size( 1 ); ++i ) - { - localIndex const f = elemsToFaces( e, i ); - // face on the domain boundary and not on free surface - if( facesDomainBoundaryIndicator[f] == 1 && freeSurfaceFaceIndicator[f] != 1 ) - { - // only the four corners of the mesh face are needed to compute the Jacobian - real64 xLocal[ 4 ][ 3 ]; - for( localIndex a = 0; a < 4; ++a ) - { - localIndex const nodeIndex = facesToNodes( f, FE_TYPE::meshIndexToLinearIndex2D( a ) ); - for( localIndex d = 0; d < 3; ++d ) - { - xLocal[a][d] = nodeCoords( nodeIndex, d ); - } - } - - real32 const alpha = 1.0 / velocity[e]; - constexpr localIndex numNodesPerFace = FE_TYPE::numNodesPerFace; - for( localIndex q = 0; q < numNodesPerFace; ++q ) - { - real32 const localIncrement = alpha * m_finiteElement.computeDampingTerm( q, xLocal ); - RAJA::atomicAdd< ATOMIC_POLICY >( &damping[facesToNodes( f, q )], localIncrement ); - } - } - } - } ); - } - - /// The finite element space/discretization object for the element type in the subRegion - FE_TYPE const & m_finiteElement; - -}; - - - -template< typename FE_TYPE > -struct VelocityComputation -{ - - VelocityComputation( FE_TYPE const & finiteElement ) - : m_finiteElement( finiteElement ) - {} - - /** - * @brief Launches the computation of the velocity for one iteration - * @tparam EXEC_POLICY the execution policy - * @tparam ATOMIC_POLICY the atomic policy - * @param[in] size the number of cells in the subRegion - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemsToNodes map from element to nodes - * @param[in] p_np1 pressure array (only used here) - * @param[in] dt time-step - * @param[out] velocity_x velocity array in the x direction (updated here) - * @param[out] velocity_y velocity array in the y direction (updated here) - * @param[out] velocity_z velocity array in the z direction (updated here) - */ - template< typename EXEC_POLICY, typename ATOMIC_POLICY > - void - launch( localIndex const size, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes, - arrayView1d< real32 const > const p_np1, - arrayView1d< real32 const > const density, - real64 const dt, - arrayView2d< real32 > const velocity_x, - arrayView2d< real32 > const velocity_y, - arrayView2d< real32 > const velocity_z ) - { - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - // only the eight corners of the mesh cell are needed to compute the Jacobian - real64 xLocal[8][3]; - for( localIndex a=0; a< 8; ++a ) - { - localIndex const nodeIndex = elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); - for( localIndex i=0; i<3; ++i ) - { - xLocal[a][i] = nodeCoords( nodeIndex, i ); - } - } - - constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; - real32 uelemx[numNodesPerElem] = {0.0}; - real32 uelemy[numNodesPerElem] = {0.0}; - real32 uelemz[numNodesPerElem] = {0.0}; - real32 flowx[numNodesPerElem] = {0.0}; - real32 flowy[numNodesPerElem] = {0.0}; - real32 flowz[numNodesPerElem] = {0.0}; - - for( localIndex i = 0; i < numNodesPerElem; ++i ) - { - real32 massLoc = m_finiteElement.computeMassTerm( i, xLocal ); - uelemx[i] = massLoc*velocity_x[k][i]; - uelemy[i] = massLoc*velocity_y[k][i]; - uelemz[i] = massLoc*velocity_z[k][i]; - } - - for( localIndex q = 0; q < numNodesPerElem; q++ ) - { - - m_finiteElement.template computeFirstOrderStiffnessTermX( q, xLocal, [&] ( int i, int j, real32 dfx1, real32 dfx2, real32 dfx3 ) - { - flowx[j] += dfx1*p_np1[elemsToNodes[k][i]]; - flowy[j] += dfx2*p_np1[elemsToNodes[k][i]]; - flowz[j] += dfx3*p_np1[elemsToNodes[k][i]]; - } ); - - m_finiteElement.template computeFirstOrderStiffnessTermY( q, xLocal, [&] ( int i, int j, real32 dfy1, real32 dfy2, real32 dfy3 ) - { - flowx[j] += dfy1*p_np1[elemsToNodes[k][i]]; - flowy[j] += dfy2*p_np1[elemsToNodes[k][i]]; - flowz[j] += dfy3*p_np1[elemsToNodes[k][i]]; - } ); - - m_finiteElement.template computeFirstOrderStiffnessTermZ( q, xLocal, [&] ( int i, int j, real32 dfz1, real32 dfz2, real32 dfz3 ) - { - flowx[j] += dfz1*p_np1[elemsToNodes[k][i]]; - flowy[j] += dfz2*p_np1[elemsToNodes[k][i]]; - flowz[j] += dfz3*p_np1[elemsToNodes[k][i]]; - - } ); - - } - for( localIndex i = 0; i < numNodesPerElem; ++i ) - { - real32 massLoc = m_finiteElement.computeMassTerm( i, xLocal ); - uelemx[i]+=dt*flowx[i]/density[k]; - uelemy[i]+=dt*flowy[i]/density[k]; - uelemz[i]+=dt*flowz[i]/density[k]; - - velocity_x[k][i] = uelemx[i]/massLoc; - velocity_y[k][i] = uelemy[i]/massLoc; - velocity_z[k][i] = uelemz[i]/massLoc; - } - } ); - } - - /// The finite element space/discretization object for the element type in the subRegion - FE_TYPE const & m_finiteElement; -}; - -template< typename FE_TYPE > -struct PressureComputation -{ - - PressureComputation( FE_TYPE const & finiteElement ) - : m_finiteElement( finiteElement ) - {} - - /** - * @brief Launches the computation of the pressure for one iteration - * @tparam EXEC_POLICY the execution policy - * @tparam ATOMIC_POLICY the atomic policy - * @param[in] size the number of cells in the subRegion - * @param[in] regionIndex Index of the subregion - * @param[in] size_node the number of nodes in the subRegion - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemsToNodes map from element to nodes - * @param[out] velocity_x velocity array in the x direction (only used here) - * @param[out] velocity_y velocity array in the y direction (only used here) - * @param[out] velocity_z velocity array in the z direction (only used here) - * @param[in] mass the mass matrix - * @param[in] damping the damping matrix - * @param[in] sourceConstants constant part of the source terms - * @param[in] sourceValue value of the temporal source (eg. Ricker) - * @param[in] sourceIsAccessible flag indicating whether the source is accessible or not - * @param[in] sourceElem element where a source is located - * @param[in] cycleNumber the number of cycle - * @param[in] dt time-step - * @param[out] p_np1 pressure array (updated here) - */ - - template< typename EXEC_POLICY, typename ATOMIC_POLICY > - void - launch( localIndex const size, - localIndex const regionIndex, - localIndex const size_node, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes, - arrayView2d< real32 const > const velocity_x, - arrayView2d< real32 const > const velocity_y, - arrayView2d< real32 const > const velocity_z, - arrayView1d< real32 const > const mass, - arrayView1d< real32 const > const damping, - arrayView2d< real64 const > const sourceConstants, - arrayView2d< real32 const > const sourceValue, - arrayView1d< localIndex const > const sourceIsAccessible, - arrayView1d< localIndex const > const sourceElem, - arrayView1d< localIndex const > const sourceRegion, - real64 const dt, - integer const cycleNumber, - arrayView1d< real32 > const p_np1 ) - - { - - //Pre-mult by the first factor for damping - forAll< EXEC_POLICY >( size_node, [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - p_np1[a] *= 1.0-((dt/2)*(damping[a]/mass[a])); - } ); - - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - // only the eight corners of the mesh cell are needed to compute the Jacobian - real64 xLocal[8][3]; - for( localIndex a=0; a< 8; ++a ) - { - localIndex const nodeIndex = elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); - for( localIndex i=0; i<3; ++i ) - { - xLocal[a][i] = nodeCoords( nodeIndex, i ); - } - } - - constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; - real32 auxx[numNodesPerElem] = {0.0}; - real32 auyy[numNodesPerElem] = {0.0}; - real32 auzz[numNodesPerElem] = {0.0}; - real32 uelemx[numNodesPerElem] = {0.0}; - - - // Volume integration - for( localIndex q=0; q < numNodesPerElem; q++ ) - { - - - m_finiteElement.template computeFirstOrderStiffnessTermX( q, xLocal, [&] ( int i, int j, real32 dfx1, real32 dfx2, real32 dfx3 ) - { - auxx[i] -= dfx1*velocity_x[k][j]; - auyy[i] -= dfx2*velocity_y[k][j]; - auzz[i] -= dfx3*velocity_z[k][j]; - } ); - - m_finiteElement.template computeFirstOrderStiffnessTermY( q, xLocal, [&] ( int i, int j, real32 dfy1, real32 dfy2, real32 dfy3 ) - { - auxx[i] -= dfy1*velocity_x[k][j]; - auyy[i] -= dfy2*velocity_y[k][j]; - auzz[i] -= dfy3*velocity_z[k][j]; - } ); - - m_finiteElement.template computeFirstOrderStiffnessTermZ( q, xLocal, [&] ( int i, int j, real32 dfz1, real32 dfz2, real32 dfz3 ) - { - auxx[i] -= dfz1*velocity_x[k][j]; - auyy[i] -= dfz2*velocity_y[k][j]; - auzz[i] -= dfz3*velocity_z[k][j]; - } ); - - - - } - - //Time update + multiplication by inverse of the mass matrix - for( localIndex i = 0; i < numNodesPerElem; ++i ) - { - real32 diag=(auxx[i]+auyy[i]+auzz[i]); - uelemx[i]+=dt*diag; - - real32 const localIncrement = uelemx[i]/mass[elemsToNodes[k][i]]; - RAJA::atomicAdd< ATOMIC_POLICY >( &p_np1[elemsToNodes[k][i]], localIncrement ); - } - - //Source Injection - for( localIndex isrc = 0; isrc < sourceConstants.size( 0 ); ++isrc ) - { - if( sourceIsAccessible[isrc] == 1 ) - { - if( sourceElem[isrc]==k && sourceRegion[isrc] == regionIndex ) - { - for( localIndex i = 0; i < numNodesPerElem; ++i ) - { - real32 const localIncrement2 = dt*(sourceConstants[isrc][i]*sourceValue[cycleNumber][isrc])/(mass[elemsToNodes[k][i]]); - RAJA::atomicAdd< ATOMIC_POLICY >( &p_np1[elemsToNodes[k][i]], localIncrement2 ); - } - } - } - } - - } ); - - //Pre-mult by the first factor for damping - forAll< EXEC_POLICY >( size_node, [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - p_np1[a] /= 1.0+((dt/2)*(damping[a]/mass[a])); - } ); - } - - /// The finite element space/discretization object for the element type in the subRegion - FE_TYPE const & m_finiteElement; - -}; - -} // namespace AcousticFirstOrderWaveEquationSEMKernels - -} // namespace geos - -#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICFIRSTTORDERWAVEEQUATIONSEMKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/AcousticWaveEquationSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/AcousticWaveEquationSEMKernel.hpp deleted file mode 100644 index a0179b278d9..00000000000 --- a/src/coreComponents/physicsSolvers/wavePropagation/AcousticWaveEquationSEMKernel.hpp +++ /dev/null @@ -1,864 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file AcousticWaveEquationSEMKernel.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICWAVEEQUATIONSEMKERNEL_HPP_ -#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICWAVEEQUATIONSEMKERNEL_HPP_ - -#include "finiteElement/kernelInterface/KernelBase.hpp" -#include "WaveSolverUtils.hpp" -#if !defined( GEOS_USE_HIP ) -#include "finiteElement/elementFormulations/Qk_Hexahedron_Lagrange_GaussLobatto.hpp" -#endif -#include "AcousticFields.hpp" - -namespace geos -{ - -using namespace fields; - -/// Namespace to contain the acoustic wave kernels. -namespace acousticWaveEquationSEMKernels -{ - -struct PrecomputeSourceAndReceiverKernel -{ - - /** - * @brief Launches the precomputation of the source and receiver terms - * @tparam EXEC_POLICY execution policy - * @tparam FE_TYPE finite element type - * @param[in] size the number of cells in the subRegion - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemsToNodes map from element to nodes - * @param[in] elemsToFaces map from element to faces - * @param[in] facesToNodes map from faces to nodes - * @param[in] elemCenter coordinates of the element centers - * @param[in] sourceCoordinates coordinates of the source terms - * @param[out] sourceIsAccessible flag indicating whether the source is accessible or not - * @param[out] sourceNodeIds indices of the nodes of the element where the source is located - * @param[out] sourceNodeConstants constant part of the source terms - * @param[in] receiverCoordinates coordinates of the receiver terms - * @param[out] receiverIsLocal flag indicating whether the receiver is local or not - * @param[out] receiverNodeIds indices of the nodes of the element where the receiver is located - * @param[out] receiverNodeConstants constant part of the receiver term - */ - template< typename EXEC_POLICY, typename FE_TYPE > - static void - launch( localIndex const size, - localIndex const numFacesPerElem, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView1d< integer const > const elemGhostRank, - arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes, - arrayView2d< localIndex const > const elemsToFaces, - arrayView2d< real64 const > const & elemCenter, - arrayView2d< real64 const > const faceNormal, - arrayView2d< real64 const > const faceCenter, - arrayView2d< real64 const > const sourceCoordinates, - arrayView1d< localIndex > const sourceIsAccessible, - arrayView2d< localIndex > const sourceNodeIds, - arrayView2d< real64 > const sourceConstants, - arrayView2d< real64 const > const receiverCoordinates, - arrayView1d< localIndex > const receiverIsLocal, - arrayView2d< localIndex > const receiverNodeIds, - arrayView2d< real64 > const receiverConstants, - arrayView2d< real32 > const sourceValue, - real64 const dt, - real32 const timeSourceFrequency, - real32 const timeSourceDelay, - localIndex const rickerOrder ) - { - constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; - - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - real64 const center[3] = { elemCenter[k][0], - elemCenter[k][1], - elemCenter[k][2] }; - - // Step 1: locate the sources, and precompute the source term - - /// loop over all the source that haven't been found yet - for( localIndex isrc = 0; isrc < sourceCoordinates.size( 0 ); ++isrc ) - { - if( sourceIsAccessible[isrc] == 0 ) - { - real64 const coords[3] = { sourceCoordinates[isrc][0], - sourceCoordinates[isrc][1], - sourceCoordinates[isrc][2] }; - - bool const sourceFound = - WaveSolverUtils::locateSourceElement( numFacesPerElem, - center, - faceNormal, - faceCenter, - elemsToFaces[k], - coords ); - if( sourceFound ) - { - real64 coordsOnRefElem[3]{}; - - - WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, - elemsToNodes[k], - nodeCoords, - coordsOnRefElem ); - - sourceIsAccessible[isrc] = 1; - real64 Ntest[numNodesPerElem]; - FE_TYPE::calcN( coordsOnRefElem, Ntest ); - - for( localIndex a = 0; a < numNodesPerElem; ++a ) - { - sourceNodeIds[isrc][a] = elemsToNodes( k, a ); - sourceConstants[isrc][a] = Ntest[a]; - } - - for( localIndex cycle = 0; cycle < sourceValue.size( 0 ); ++cycle ) - { - sourceValue[cycle][isrc] = WaveSolverUtils::evaluateRicker( cycle * dt, timeSourceFrequency, timeSourceDelay, rickerOrder ); - } - } - } - } // end loop over all sources - - - // Step 2: locate the receivers, and precompute the receiver term - - /// loop over all the receivers that haven't been found yet - for( localIndex ircv = 0; ircv < receiverCoordinates.size( 0 ); ++ircv ) - { - if( receiverIsLocal[ircv] == 0 ) - { - real64 const coords[3] = { receiverCoordinates[ircv][0], - receiverCoordinates[ircv][1], - receiverCoordinates[ircv][2] }; - - real64 coordsOnRefElem[3]{}; - bool const receiverFound = - WaveSolverUtils::locateSourceElement( numFacesPerElem, - center, - faceNormal, - faceCenter, - elemsToFaces[k], - coords ); - - if( receiverFound && elemGhostRank[k] < 0 ) - { - WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, - elemsToNodes[k], - nodeCoords, - coordsOnRefElem ); - - receiverIsLocal[ircv] = 1; - - real64 Ntest[numNodesPerElem]; - FE_TYPE::calcN( coordsOnRefElem, Ntest ); - - for( localIndex a = 0; a < numNodesPerElem; ++a ) - { - receiverNodeIds[ircv][a] = elemsToNodes( k, a ); - receiverConstants[ircv][a] = Ntest[a]; - } - } - } - } // end loop over receivers - - } ); - - } -}; - -template< typename FE_TYPE > -struct MassMatrixKernel -{ - - MassMatrixKernel( FE_TYPE const & finiteElement ) - : m_finiteElement( finiteElement ) - {} - - /** - * @brief Launches the precomputation of the mass matrices - * @tparam EXEC_POLICY the execution policy - * @tparam ATOMIC_POLICY the atomic policy - * @param[in] size the number of cells in the subRegion - * @param[in] numFacesPerElem number of faces per element - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemsToNodes map from element to nodes - * @param[in] velocity cell-wise velocity - * @param[in] density cell-wise density - * @param[out] mass diagonal of the mass matrix - */ - template< typename EXEC_POLICY, typename ATOMIC_POLICY > - void - launch( localIndex const size, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes, - arrayView1d< real32 const > const velocity, - arrayView1d< real32 const > const density, - arrayView1d< real32 > const mass ) - - { - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const e ) - { - - real32 const invC2 = 1.0 / ( density[e] * pow( velocity[e], 2 ) ); - // only the eight corners of the mesh cell are needed to compute the Jacobian - real64 xLocal[ 8 ][ 3 ]; - for( localIndex a = 0; a < 8; ++a ) - { - localIndex const nodeIndex = elemsToNodes( e, FE_TYPE::meshIndexToLinearIndex3D( a ) ); - for( localIndex i = 0; i < 3; ++i ) - { - xLocal[a][i] = nodeCoords( nodeIndex, i ); - } - } - constexpr localIndex numQuadraturePointsPerElem = FE_TYPE::numQuadraturePoints; - for( localIndex q = 0; q < numQuadraturePointsPerElem; ++q ) - { - real32 const localIncrement = invC2 * m_finiteElement.computeMassTerm( q, xLocal ); - RAJA::atomicAdd< ATOMIC_POLICY >( &mass[elemsToNodes( e, q )], localIncrement ); - } - } ); // end loop over element - } - - /// The finite element space/discretization object for the element type in the subRegion - FE_TYPE const & m_finiteElement; - -}; - -template< typename FE_TYPE > -struct DampingMatrixKernel -{ - - DampingMatrixKernel( FE_TYPE const & finiteElement ) - : m_finiteElement( finiteElement ) - {} - - /** - * @brief Launches the precomputation of the damping matrices - * @tparam EXEC_POLICY the execution policy - * @tparam ATOMIC_POLICY the atomic policy - * @param[in] size the number of cells in the subRegion - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemsToFaces map from elements to faces - * @param[in] facesToNodes map from face to nodes - * @param[in] facesDomainBoundaryIndicator flag equal to 1 if the face is on the boundary, and to 0 otherwise - * @param[in] freeSurfaceFaceIndicator flag equal to 1 if the face is on the free surface, and to 0 otherwise - * @param[in] velocity cell-wise velocity - * @param[in] density cell-wise density - * @param[out] damping diagonal of the damping matrix - */ - template< typename EXEC_POLICY, typename ATOMIC_POLICY > - void - launch( localIndex const size, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView2d< localIndex const > const elemsToFaces, - ArrayOfArraysView< localIndex const > const facesToNodes, - arrayView1d< integer const > const facesDomainBoundaryIndicator, - arrayView1d< localIndex const > const freeSurfaceFaceIndicator, - arrayView1d< real32 const > const velocity, - arrayView1d< real32 const > const density, - arrayView1d< real32 > const damping ) - { - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const e ) - { - for( localIndex i = 0; i < elemsToFaces.size( 1 ); ++i ) - { - localIndex const f = elemsToFaces( e, i ); - // face on the domain boundary and not on free surface - if( facesDomainBoundaryIndicator[f] == 1 && freeSurfaceFaceIndicator[f] != 1 ) - { - // only the four corners of the mesh face are needed to compute the Jacobian - real64 xLocal[ 4 ][ 3 ]; - for( localIndex a = 0; a < 4; ++a ) - { - localIndex const nodeIndex = facesToNodes( f, FE_TYPE::meshIndexToLinearIndex2D( a ) ); - for( localIndex d = 0; d < 3; ++d ) - { - xLocal[a][d] = nodeCoords( nodeIndex, d ); - } - } - real32 const alpha = 1.0 / (density[e] * velocity[e]); - constexpr localIndex numNodesPerFace = FE_TYPE::numNodesPerFace; - for( localIndex q = 0; q < numNodesPerFace; ++q ) - { - real32 const localIncrement = alpha * m_finiteElement.computeDampingTerm( q, xLocal ); - RAJA::atomicAdd< ATOMIC_POLICY >( &damping[facesToNodes( f, q )], localIncrement ); - } - } - } - } ); - } - - /// The finite element space/discretization object for the element type in the subRegion - FE_TYPE const & m_finiteElement; - -}; - -struct PMLKernelHelper -{ - /** - * @brief Compute the damping profile for the Perfectly Matched Layer (PML) - * @param xLocal a given x-y-z coordinates (3-components array) - * @param xMin coordinate limits of the inner PML boundaries, left-front-top - * @param xMax coordinate limits of the inner PML boundaries, right-back-bottom - * @param dMin PML thickness, left-front-top - * @param dMax PML thickness, right-back-bottom - * @param cMin PML wave speed, left-front-top - * @param cMax PML wave speed, right-back-bottom - * @param r desired reflectivity of the PML - * @param sigma 3-components array to hold the damping profile in each direction - */ - GEOS_HOST_DEVICE - inline - static void computeDampingProfilePML( real32 const (&xLocal)[3], - real32 const (&xMin)[3], - real32 const (&xMax)[3], - real32 const (&dMin)[3], - real32 const (&dMax)[3], - real32 const (&cMin)[3], - real32 const (&cMax)[3], - real32 const r, - real32 (& sigma)[3] ) - { - - sigma[0] = 0; - sigma[1] = 0; - sigma[2] = 0; - - if( xLocal[0] < xMin[0] ) - { - real32 const factor = -3.0/2.0*cMin[0]*log( r )/(dMin[0]*dMin[0]*dMin[0]); - sigma[0] = factor*(xLocal[0]-xMin[0])*(xLocal[0]-xMin[0]); - } - else if( xLocal[0] > xMax[0] ) - { - real32 const factor = -3.0/2.0*cMax[0]*log( r )/(dMax[0]*dMax[0]*dMax[0]); - sigma[0] = factor*(xLocal[0]-xMax[0])*(xLocal[0]-xMax[0]); - } - if( xLocal[1] < xMin[1] ) - { - real32 const factor = -3.0/2.0*cMin[1]*log( r )/(dMin[1]*dMin[1]*dMin[1]); - sigma[1] = factor*(xLocal[1]-xMin[1])*(xLocal[1]-xMin[1]); - } - else if( xLocal[1] > xMax[1] ) - { - real32 const factor = -3.0/2.0*cMax[1]*log( r )/(dMax[1]*dMax[1]*dMax[1]); - sigma[1] = factor*(xLocal[1]-xMax[1])*(xLocal[1]-xMax[1]); - } - if( xLocal[2] < xMin[2] ) - { - real32 const factor = -3.0/2.0*cMin[2]*log( r )/(dMin[2]*dMin[2]*dMin[2]); - sigma[2] = factor*(xLocal[2]-xMin[2])*(xLocal[2]-xMin[2]); - } - else if( xLocal[2] > xMax[2] ) - { - real32 const factor = -3.0/2.0*cMax[2]*log( r )/(dMax[2]*dMax[2]*dMax[2]); - sigma[2] = factor*(xLocal[2]-xMax[2])*(xLocal[2]-xMax[2]); - } - } -}; - -template< typename FE_TYPE > -struct PMLKernel -{ - - PMLKernel( FE_TYPE const & finiteElement ) - : m_finiteElement( finiteElement ) - {} - - /** - * @brief Launches the computation of field gradients and divergence for PML region - * @tparam EXEC_POLICY the execution policy - * @tparam ATOMIC_POLICY the atomic policy - * @param[in] targetSet list of cells in the target set - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemToNodes constant array view of map from element to nodes - * @param[in] velocity cell-wise velocity - * @param[in] p_n pressure field at time n - * @param[in] v_n PML auxiliary field at time n - * @param[in] u_n PML auxiliary field at time n - * @param[in] xMin coordinate limits of the inner PML boundaries, left-front-top - * @param[in] xMax coordinate limits of the inner PML boundaries, right-back-bottom - * @param[in] dMin PML thickness, left-front-top - * @param[in] dMax PML thickness, right-back-bottom - * @param[in] cMin PML wave speed, left-front-top - * @param[in] cMax PML wave speed, right-back-bottom - * @param[in] r desired reflectivity of the PML - * @param[out] grad_n array holding the gradients at time n - * @param[out] divV_n array holding the divergence at time n - */ - template< typename EXEC_POLICY, typename ATOMIC_POLICY > - void - launch( SortedArrayView< localIndex const > const targetSet, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - traits::ViewTypeConst< CellElementSubRegion::NodeMapType > const elemToNodes, - arrayView1d< real32 const > const velocity, - arrayView1d< real32 const > const p_n, - arrayView2d< real32 const > const v_n, - arrayView1d< real32 const > const u_n, - real32 const (&xMin)[3], - real32 const (&xMax)[3], - real32 const (&dMin)[3], - real32 const (&dMax)[3], - real32 const (&cMin)[3], - real32 const (&cMax)[3], - real32 const r, - arrayView2d< real32 > const grad_n, - arrayView1d< real32 > const divV_n ) - { - /// Loop over elements in the subregion, 'l' is the element index within the target set - forAll< EXEC_POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const l ) - { - constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; - - /// global element index - localIndex const k = targetSet[l]; - - /// wave speed at the element - real32 const c = velocity[k]; - - /// coordinates of the element nodes - real64 xLocal[ numNodesPerElem ][ 3 ]; - real32 xLocal32[ numNodesPerElem ][ 3 ]; - - /// local arrays to store the pressure at all nodes and its gradient at a given node - real64 pressure[ numNodesPerElem ]; - real64 pressureGrad[ 3 ]; - - /// local arrays to store the PML vectorial auxiliary variable at all nodes and its gradient at a given node - real64 auxV[3][ numNodesPerElem ]; - real64 auxVGrad[3][3]; - - /// local arrays to store the PML scalar auxiliary variable at all nodes and its gradient at a given node - real64 auxU[ numNodesPerElem ]; - real64 auxUGrad[3]; - - /// local array to store the PML damping profile - real32 sigma[ 3 ]; - - /// copy from global to local arrays - for( localIndex i=0; i( k, i, xLocal, gradN ); - GEOS_UNUSED_VAR ( detJ ); - - /// compute the gradient of the pressure and the PML auxiliary variables at the node - m_finiteElement.template gradient< numNodesPerElem, GRADIENT_TYPE >( gradN, pressure, pressureGrad ); - m_finiteElement.template gradient< numNodesPerElem, GRADIENT_TYPE >( gradN, auxU, auxUGrad ); - for( int j=0; j<3; ++j ) - { - m_finiteElement.template gradient< numNodesPerElem, GRADIENT_TYPE >( gradN, auxV[j], auxVGrad[j] ); - } - - /// compute the PML damping profile - PMLKernelHelper::computeDampingProfilePML( - xLocal32[i], - xMin, - xMax, - dMin, - dMax, - cMin, - cMax, - r, - sigma ); - - /// compute B.pressureGrad - C.auxUGrad where B and C are functions of the damping profile - /// WARNING: the division by 'numNodesPerElem' below is needed because the average of - /// gradient and divergence at the nodes are sought. It is the number of cells contributing - /// to each node that is needed. In this case, it is equal to 'numNodesPerElem'. For high-order - /// SEM, this approach won't work and the average needs to be computed differently (maybe using counters). - real32 localIncrementArray[3]; - localIncrementArray[0] = (sigma[0]-sigma[1]-sigma[2])*pressureGrad[0] - (sigma[1]*sigma[2])*auxUGrad[0]; - localIncrementArray[1] = (sigma[1]-sigma[0]-sigma[2])*pressureGrad[1] - (sigma[0]*sigma[2])*auxUGrad[1]; - localIncrementArray[2] = (sigma[2]-sigma[0]-sigma[1])*pressureGrad[2] - (sigma[0]*sigma[1])*auxUGrad[2]; - for( int j=0; j<3; ++j ) - { - RAJA::atomicAdd< ATOMIC_POLICY >( &grad_n[elemToNodes( k, i )][j], localIncrementArray[j]/numNodesPerElem ); - } - /// compute beta.pressure + gamma.u - c^2 * divV where beta and gamma are functions of the damping profile - real32 const beta = sigma[0]*sigma[1]+sigma[0]*sigma[2]+sigma[1]*sigma[2]; - real32 const gamma = sigma[0]*sigma[1]*sigma[2]; - real32 const localIncrement = beta*p_n[elemToNodes( k, i )] - + gamma*u_n[elemToNodes( k, i )] - - c*c*( auxVGrad[0][0] + auxVGrad[1][1] + auxVGrad[2][2] ); - - RAJA::atomicAdd< ATOMIC_POLICY >( &divV_n[elemToNodes( k, i )], localIncrement/numNodesPerElem ); - } - } ); - } - - /// The finite element space/discretization object for the element type in the subRegion - FE_TYPE const & m_finiteElement; -}; - - -template< typename FE_TYPE > -struct waveSpeedPMLKernel -{ - - waveSpeedPMLKernel( FE_TYPE const & finiteElement ) - : m_finiteElement( finiteElement ) - {} - - /** - * @brief Launches the computation of average wave speeds in the PML region - * @tparam EXEC_POLICY the execution policy - * @tparam ATOMIC_POLICY the atomic policy - * @param[in] targetSet list of cells in the target set - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemToNodes constant array view of map from element to nodes - * @param[in] velocity cell-wise velocity - * @param[in] xMin coordinate limits of the inner PML boundaries, left-front-top - * @param[in] xMax coordinate limits of the inner PML boundaries, right-back-bottom - * @param[out] cMin PML wave speed, left-front-top - * @param[out] cMax PML wave speed, right-back-bottom - * @param[out] counterMin PML wave speed counter, left-front-top - * @param[out] counterMax PML wave speed counter, left-front-top - */ - template< typename EXEC_POLICY, typename ATOMIC_POLICY > - void - launch( SortedArrayView< localIndex const > const targetSet, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - traits::ViewTypeConst< CellElementSubRegion::NodeMapType > const elemToNodes, - arrayView1d< real32 const > const velocity, - real32 const (&xMin)[3], - real32 const (&xMax)[3], - real32 (& cMin)[3], - real32 (& cMax)[3], - int (& counterMin)[3], - int (& counterMax)[3] ) - { - - RAJA::ReduceSum< parallelDeviceReduce, real32 > subRegionAvgWaveSpeedLeft( 0.0 ); - RAJA::ReduceSum< parallelDeviceReduce, real32 > subRegionAvgWaveSpeedRight( 0.0 ); - RAJA::ReduceSum< parallelDeviceReduce, real32 > subRegionAvgWaveSpeedFront( 0.0 ); - RAJA::ReduceSum< parallelDeviceReduce, real32 > subRegionAvgWaveSpeedBack( 0.0 ); - RAJA::ReduceSum< parallelDeviceReduce, real32 > subRegionAvgWaveSpeedTop( 0.0 ); - RAJA::ReduceSum< parallelDeviceReduce, real32 > subRegionAvgWaveSpeedBottom( 0.0 ); - RAJA::ReduceSum< parallelDeviceReduce, int > subRegionAvgWaveSpeedCounterLeft( 0 ); - RAJA::ReduceSum< parallelDeviceReduce, int > subRegionAvgWaveSpeedCounterRight( 0 ); - RAJA::ReduceSum< parallelDeviceReduce, int > subRegionAvgWaveSpeedCounterFront( 0 ); - RAJA::ReduceSum< parallelDeviceReduce, int > subRegionAvgWaveSpeedCounterBack( 0 ); - RAJA::ReduceSum< parallelDeviceReduce, int > subRegionAvgWaveSpeedCounterTop( 0 ); - RAJA::ReduceSum< parallelDeviceReduce, int > subRegionAvgWaveSpeedCounterBottom( 0 ); - - /// Loop over elements in the subregion, 'l' is the element index within the target set - forAll< EXEC_POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const l ) - { - constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; - - /// global element index - localIndex const k = targetSet[l]; - - /// wave speed at the element - real32 const c = velocity[k]; - - /// coordinates of the element center - real64 xLocal[ 3 ] = {0.0, 0.0, 0.0}; - - /// compute the coordinates of the element center - for( int j=0; j<3; ++j ) - { - for( localIndex i=0; i= xMin[1] && xLocal[1] <= xMax[1] - && xLocal[2] >= xMin[2] && xLocal[2] <= xMax[2] ) - { - subRegionAvgWaveSpeedLeft += c; - subRegionAvgWaveSpeedCounterLeft += 1; - } - else if( xLocal[0] > xMax[0] - && xLocal[1] >= xMin[1] && xLocal[1] <= xMax[1] - && xLocal[2] >= xMin[2] && xLocal[2] <= xMax[2] ) - { - subRegionAvgWaveSpeedRight += c; - subRegionAvgWaveSpeedCounterRight += 1; - } - if( xLocal[1] < xMin[1] - && xLocal[0] >= xMin[0] && xLocal[0] <= xMax[0] - && xLocal[2] >= xMin[2] && xLocal[2] <= xMax[2] ) - { - subRegionAvgWaveSpeedFront += c; - subRegionAvgWaveSpeedCounterFront += 1; - } - else if( xLocal[1] > xMax[1] - && xLocal[0] >= xMin[0] && xLocal[0] <= xMax[0] - && xLocal[2] >= xMin[2] && xLocal[2] <= xMax[2] ) - { - subRegionAvgWaveSpeedBack += c; - subRegionAvgWaveSpeedCounterBack += 1; - } - if( xLocal[2] < xMin[2] - && xLocal[0] >= xMin[0] && xLocal[0] <= xMax[0] - && xLocal[1] >= xMin[1] && xLocal[1] <= xMax[1] ) - { - subRegionAvgWaveSpeedTop += c; - subRegionAvgWaveSpeedCounterTop += 1; - } - else if( xLocal[2] > xMax[2] - && xLocal[0] >= xMin[0] && xLocal[0] <= xMax[0] - && xLocal[1] >= xMin[1] && xLocal[1] <= xMax[1] ) - { - subRegionAvgWaveSpeedBottom += c; - subRegionAvgWaveSpeedCounterBottom += 1; - } - } ); - - /// transfer local results to global variables - cMin[0]+=subRegionAvgWaveSpeedLeft.get(); - cMin[1]+=subRegionAvgWaveSpeedFront.get(); - cMin[2]+=subRegionAvgWaveSpeedTop.get(); - cMax[0]+=subRegionAvgWaveSpeedRight.get(); - cMax[1]+=subRegionAvgWaveSpeedBack.get(); - cMax[2]+=subRegionAvgWaveSpeedBottom.get(); - counterMin[0]+=subRegionAvgWaveSpeedCounterLeft.get(); - counterMin[1]+=subRegionAvgWaveSpeedCounterFront.get(); - counterMin[2]+=subRegionAvgWaveSpeedCounterTop.get(); - counterMax[0]+=subRegionAvgWaveSpeedCounterRight.get(); - counterMax[1]+=subRegionAvgWaveSpeedCounterBack.get(); - counterMax[2]+=subRegionAvgWaveSpeedCounterBottom.get(); - } - - /// The finite element space/discretization object for the element type in the subRegion - FE_TYPE const & m_finiteElement; -}; - - - -/** - * @brief Implements kernels for solving the acoustic wave equations - * explicit central FD method and SEM - * @copydoc geos::finiteElement::KernelBase - * @tparam SUBREGION_TYPE The type of subregion that the kernel will act on. - * - * ### AcousticWaveEquationSEMKernel Description - * Implements the KernelBase interface functions required for solving - * the acoustic wave equations using the - * "finite element kernel application" functions such as - * geos::finiteElement::RegionBasedKernelApplication. - * - * The number of degrees of freedom per support point for both - * the test and trial spaces are specified as `1`. - */ - - -template< typename SUBREGION_TYPE, - typename CONSTITUTIVE_TYPE, - typename FE_TYPE > -class ExplicitAcousticSEM : public finiteElement::KernelBase< SUBREGION_TYPE, - CONSTITUTIVE_TYPE, - FE_TYPE, - 1, - 1 > -{ -public: - - /// Alias for the base class; - using Base = finiteElement::KernelBase< SUBREGION_TYPE, - CONSTITUTIVE_TYPE, - FE_TYPE, - 1, - 1 >; - - /// Maximum number of nodes per element, which is equal to the maxNumTestSupportPointPerElem and - /// maxNumTrialSupportPointPerElem by definition. When the FE_TYPE is not a Virtual Element, this - /// will be the actual number of nodes per element. - static constexpr int numNodesPerElem = Base::maxNumTestSupportPointsPerElem; - - using Base::numDofPerTestSupportPoint; - using Base::numDofPerTrialSupportPoint; - using Base::m_elemsToNodes; - using Base::m_elemGhostRank; - using Base::m_constitutiveUpdate; - using Base::m_finiteElementSpace; - -//***************************************************************************** - /** - * @brief Constructor - * @copydoc geos::finiteElement::KernelBase::KernelBase - * @param nodeManager Reference to the NodeManager object. - * @param edgeManager Reference to the EdgeManager object. - * @param faceManager Reference to the FaceManager object. - * @param targetRegionIndex Index of the region the subregion belongs to. - * @param dt The time interval for the step. - * elements to be processed during this kernel launch. - */ - ExplicitAcousticSEM( NodeManager & nodeManager, - EdgeManager const & edgeManager, - FaceManager const & faceManager, - localIndex const targetRegionIndex, - SUBREGION_TYPE const & elementSubRegion, - FE_TYPE const & finiteElementSpace, - CONSTITUTIVE_TYPE & inputConstitutiveType, - real64 const dt ): - Base( elementSubRegion, - finiteElementSpace, - inputConstitutiveType ), - m_nodeCoords( nodeManager.getField< fields::referencePosition32 >() ), - m_p_n( nodeManager.getField< acousticfields::Pressure_n >() ), - m_stiffnessVector( nodeManager.getField< acousticfields::StiffnessVector >() ), - m_density( elementSubRegion.template getField< acousticfields::AcousticDensity >() ), - m_dt( dt ) - { - GEOS_UNUSED_VAR( edgeManager ); - GEOS_UNUSED_VAR( faceManager ); - GEOS_UNUSED_VAR( targetRegionIndex ); - } - - //***************************************************************************** - /** - * @copydoc geos::finiteElement::KernelBase::StackVariables - * - * ### ExplicitAcousticSEM Description - * Adds a stack arrays for the nodal force, primary displacement variable, etc. - */ - struct StackVariables : Base::StackVariables - { -public: - GEOS_HOST_DEVICE - StackVariables(): - xLocal(), - stiffnessVectorLocal() - {} - - /// C-array stack storage for element local the nodal positions. - real64 xLocal[ 8 ][ 3 ]; - real32 stiffnessVectorLocal[ numNodesPerElem ]{}; - real32 invDensity; - }; - //*************************************************************************** - - - /** - * @copydoc geos::finiteElement::KernelBase::setup - * - * Copies the primary variable, and position into the local stack array. - */ - GEOS_HOST_DEVICE - inline - void setup( localIndex const k, - StackVariables & stack ) const - { - stack.invDensity = 1./m_density[k]; - for( localIndex a=0; a< 8; a++ ) - { - localIndex const nodeIndex = m_elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); - for( int i=0; i< 3; ++i ) - { - stack.xLocal[ a ][ i ] = m_nodeCoords[ nodeIndex ][ i ]; - } - } - } - - /** - * @copydoc geos::finiteElement::KernelBase::complete - */ - GEOS_HOST_DEVICE - GEOS_FORCE_INLINE - real64 complete( localIndex const k, - StackVariables & stack ) const - { - for( int i=0; i( &m_stiffnessVector[m_elemsToNodes( k, i )], stack.stiffnessVectorLocal[i] ); - } - return 0; - } - - - /** - * @copydoc geos::finiteElement::KernelBase::quadraturePointKernel - * - * ### ExplicitAcousticSEM Description - * Calculates stiffness vector - * - */ - GEOS_HOST_DEVICE - GEOS_FORCE_INLINE - void quadraturePointKernel( localIndex const k, - localIndex const q, - StackVariables & stack ) const - { - - m_finiteElementSpace.template computeStiffnessTerm( q, stack.xLocal, [&] ( const int i, const int j, const real64 val ) - { - real32 const localIncrement = stack.invDensity*val*m_p_n[m_elemsToNodes( k, j )]; - stack.stiffnessVectorLocal[ i ] += localIncrement; - } ); - } - -protected: - /// The array containing the nodal position array. - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const m_nodeCoords; - - /// The array containing the nodal pressure array. - arrayView1d< real32 const > const m_p_n; - - /// The array containing the product of the stiffness matrix and the nodal pressure. - arrayView1d< real32 > const m_stiffnessVector; - - /// The array containing the cell-wise density - arrayView1d< real32 const > const m_density; - - /// The time increment for this time integration step. - real64 const m_dt; - - -}; - - - -/// The factory used to construct a ExplicitAcousticWaveEquation kernel. -using ExplicitAcousticSEMFactory = finiteElement::KernelFactory< ExplicitAcousticSEM, - real64 >; - - -} // namespace acousticWaveEquationSEMKernels - -} // namespace geos - -#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICWAVEEQUATIONSEMKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/CMakeLists.txt b/src/coreComponents/physicsSolvers/wavePropagation/CMakeLists.txt new file mode 100644 index 00000000000..54fe46da9fa --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/CMakeLists.txt @@ -0,0 +1,43 @@ +# Specify solver headers +set( physicsSolvers_headers + ${physicsSolvers_headers} + wavePropagation/shared/WaveSolverBase.hpp + wavePropagation/shared/WaveSolverUtils.hpp + wavePropagation/shared/PrecomputeSourcesAndReceiversKernel.hpp + wavePropagation/sem/acoustic/shared/AcousticFields.hpp + wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEM.hpp + wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEMKernel.hpp + wavePropagation/sem/acoustic/shared/AcousticTimeSchemeSEMKernel.hpp + wavePropagation/sem/acoustic/shared/AcousticMatricesSEMKernel.hpp + wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticPMLSEMKernel.hpp + wavePropagation/sem/elastic/shared/ElasticFields.hpp + wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEM.hpp + wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEMKernel.hpp + wavePropagation/sem/elastic/shared/ElasticTimeSchemeSEMKernel.hpp + wavePropagation/sem/elastic/firstOrderEqn/isotropic/ElasticFirstOrderWaveEquationSEM.hpp + wavePropagation/sem/elastic/firstOrderEqn/isotropic/ElasticFirstOrderWaveEquationSEMKernel.hpp + wavePropagation/sem/acoustic/firstOrderEqn/isotropic/AcousticFirstOrderWaveEquationSEM.hpp + wavePropagation/sem/acoustic/firstOrderEqn/isotropic/AcousticFirstOrderWaveEquationSEMKernel.hpp + wavePropagation/sem/elastic/shared/ElasticMatricesSEMKernel.hpp + wavePropagation/sem/elastic/secondOrderEqn/anisotropic/ElasticVTIFields.hpp + wavePropagation/sem/elastic/secondOrderEqn/anisotropic/ElasticVTIWaveEquationSEMKernel.hpp + wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIFields.hpp + wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIWaveEquationSEM.hpp + wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIWaveEquationSEMKernel.hpp + wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcoustoElasticFields.hpp + wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcoustoElasticTimeSchemeSEMKernel.hpp + wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcousticElasticWaveEquationSEM.hpp + wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcousticElasticWaveEquationSEMKernel.hpp + PARENT_SCOPE ) + +# Specify solver sources +set( physicsSolvers_sources + ${physicsSolvers_sources} + wavePropagation/shared/WaveSolverBase.cpp + wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEM.cpp + wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEM.cpp + wavePropagation/sem/elastic/firstOrderEqn/isotropic/ElasticFirstOrderWaveEquationSEM.cpp + wavePropagation/sem/acoustic/firstOrderEqn/isotropic/AcousticFirstOrderWaveEquationSEM.cpp + wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIWaveEquationSEM.cpp + wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcousticElasticWaveEquationSEM.cpp + PARENT_SCOPE) diff --git a/src/coreComponents/physicsSolvers/wavePropagation/ElasticFirstOrderWaveEquationSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/ElasticFirstOrderWaveEquationSEMKernel.hpp deleted file mode 100644 index 8ab22a047d1..00000000000 --- a/src/coreComponents/physicsSolvers/wavePropagation/ElasticFirstOrderWaveEquationSEMKernel.hpp +++ /dev/null @@ -1,631 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOS Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file ElasticFirstOrderWaveEquationSEMKernel.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICFIRSTORDERWAVEEQUATIONSEMKERNEL_HPP_ -#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICFIRSTORDERWAVEEQUATIONSEMKERNEL_HPP_ - -#include "finiteElement/kernelInterface/KernelBase.hpp" -#include "WaveSolverUtils.hpp" - - -namespace geos -{ - -/// Namespace to contain the elastic wave kernels. -namespace elasticFirstOrderWaveEquationSEMKernels -{ - -struct PrecomputeSourceAndReceiverKernel -{ - - /** - * @brief Launches the precomputation of the source and receiver terms - * @tparam EXEC_POLICY execution policy - * @tparam FE_TYPE finite element type - * @param[in] size the number of cells in the subRegion - * @param[in] numFacesPerElem number of face on an element - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemGhostRank array containing the ghost rank - * @param[in] elemsToNodes map from element to nodes - * @param[in] elemsToFaces map from element to faces - * @param[in] elemCenter coordinates of the element centers - * @param[in] faceNormal array containing the normal of all faces - * @param[in] faceCenter array containing the center of all faces - * @param[in] sourceCoordinates coordinates of the source terms - * @param[in] receiverCoordinates coordinates of the receiver terms - * @param[in] dt time-step - * @param[in] timeSourceFrequency Peak frequency of the source - * @param[in] timeSourceDelay the time delay of the source - * @param[in] rickerOrder Order of the Ricker wavelet - * @param[out] sourceNodeIds indices of the nodes of the element where the source is located - * @param[out] sourceConstants constant part of the source terms - * @param[out] receiverIsLocal flag indicating whether the receiver is local or not - * @param[out] receiverNodeIds indices of the nodes of the element where the receiver is located - * @param[out] sourceValue array containing the value of the time dependent source (Ricker for e.g) - */ - template< typename EXEC_POLICY, typename FE_TYPE > - static void - launch( localIndex const size, - localIndex const regionIndex, - localIndex const numFacesPerElem, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView1d< integer const > const elemGhostRank, - arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes, - arrayView2d< localIndex const > const elemsToFaces, - arrayView2d< real64 const > const & elemCenter, - arrayView2d< real64 const > const faceNormal, - arrayView2d< real64 const > const faceCenter, - arrayView2d< real64 const > const sourceCoordinates, - arrayView1d< localIndex > const sourceIsAccessible, - arrayView1d< localIndex > const sourceElem, - arrayView2d< localIndex > const sourceNodeIds, - arrayView2d< real64 > const sourceConstants, - arrayView1d< localIndex > const sourceRegion, - arrayView2d< real64 const > const receiverCoordinates, - arrayView1d< localIndex > const receiverIsLocal, - arrayView1d< localIndex > const rcvElem, - arrayView2d< localIndex > const receiverNodeIds, - arrayView2d< real64 > const receiverConstants, - arrayView1d< localIndex > const receiverRegion, - arrayView2d< real32 > const sourceValue, - real64 const dt, - real32 const timeSourceFrequency, - real32 const timeSourceDelay, - localIndex const rickerOrder ) - { - constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; - - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - real64 const center[3] = { elemCenter[k][0], - elemCenter[k][1], - elemCenter[k][2] }; - - // Step 1: locate the sources, and precompute the source term - - /// loop over all the source that haven't been found yet - for( localIndex isrc = 0; isrc < sourceCoordinates.size( 0 ); ++isrc ) - { - if( sourceIsAccessible[isrc] == 0 ) - { - real64 const coords[3] = { sourceCoordinates[isrc][0], - sourceCoordinates[isrc][1], - sourceCoordinates[isrc][2] }; - - bool const sourceFound = - WaveSolverUtils::locateSourceElement( numFacesPerElem, - center, - faceNormal, - faceCenter, - elemsToFaces[k], - coords ); - - if( sourceFound ) - { - real64 coordsOnRefElem[3]{}; - - WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, - elemsToNodes[k], - nodeCoords, - coordsOnRefElem ); - sourceIsAccessible[isrc] = 1; - sourceElem[isrc] = k; - sourceRegion[isrc] = regionIndex; - real64 Ntest[numNodesPerElem]; - FE_TYPE::calcN( coordsOnRefElem, Ntest ); - - for( localIndex a = 0; a < numNodesPerElem; ++a ) - { - sourceNodeIds[isrc][a] = elemsToNodes[k][a]; - sourceConstants[isrc][a] = Ntest[a]; - } - - for( localIndex cycle = 0; cycle < sourceValue.size( 0 ); ++cycle ) - { - sourceValue[cycle][isrc] = WaveSolverUtils::evaluateRicker( cycle * dt, timeSourceFrequency, timeSourceDelay, rickerOrder ); - } - - } - } - } // end loop over all sources - - - // Step 2: locate the receivers, and precompute the receiver term - - /// loop over all the receivers that haven't been found yet - for( localIndex ircv = 0; ircv < receiverCoordinates.size( 0 ); ++ircv ) - { - if( receiverIsLocal[ircv] == 0 ) - { - real64 const coords[3] = { receiverCoordinates[ircv][0], - receiverCoordinates[ircv][1], - receiverCoordinates[ircv][2] }; - - real64 coordsOnRefElem[3]{}; - bool const receiverFound = - WaveSolverUtils::locateSourceElement( numFacesPerElem, - center, - faceNormal, - faceCenter, - elemsToFaces[k], - coords ); - if( receiverFound && elemGhostRank[k] < 0 ) - { - WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, - elemsToNodes[k], - nodeCoords, - coordsOnRefElem ); - receiverIsLocal[ircv] = 1; - rcvElem[ircv] = k; - receiverRegion[ircv] = regionIndex; - - real64 Ntest[numNodesPerElem]; - FE_TYPE::calcN( coordsOnRefElem, Ntest ); - - for( localIndex a = 0; a < numNodesPerElem; ++a ) - { - receiverNodeIds[ircv][a] = elemsToNodes[k][a]; - receiverConstants[ircv][a] = Ntest[a]; - } - } - } - } // end loop over receivers - } ); - - } -}; - -template< typename FE_TYPE > -struct MassMatrixKernel -{ - - MassMatrixKernel( FE_TYPE const & finiteElement ) - : m_finiteElement( finiteElement ) - {} - - /** - * @brief Launches the precomputation of the mass matrices - * @tparam EXEC_POLICY the execution policy - * @tparam ATOMIC_POLICY the atomic policy - * @param[in] size the number of cells in the subRegion - * @param[in] numFacesPerElem number of faces per element - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemsToNodes map from element to nodes - * @param[in] velocity cell-wise velocity - * @param[out] mass diagonal of the mass matrix - */ - template< typename EXEC_POLICY, typename ATOMIC_POLICY > - void - launch( localIndex const size, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes, - arrayView1d< real32 const > const density, - arrayView1d< real32 > const mass ) - - { - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - // only the eight corners of the mesh cell are needed to compute the Jacobian - real64 xLocal[ 8 ][ 3 ]; - for( localIndex a = 0; a < 8; ++a ) - { - localIndex const nodeIndex = elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); - for( localIndex i = 0; i < 3; ++i ) - { - xLocal[a][i] = nodeCoords( nodeIndex, i ); - } - } - - constexpr localIndex numQuadraturePointsPerElem = FE_TYPE::numQuadraturePoints; - for( localIndex q = 0; q < numQuadraturePointsPerElem; ++q ) - { - real32 const localIncrement = density[k] * m_finiteElement.computeMassTerm( q, xLocal ); - RAJA::atomicAdd< ATOMIC_POLICY >( &mass[elemsToNodes[k][q]], localIncrement ); - } - } ); // end loop over element - } - - /// The finite element space/discretization object for the element type in the subRegion - FE_TYPE const & m_finiteElement; - -}; - -template< typename FE_TYPE > -struct DampingMatrixKernel -{ - - DampingMatrixKernel( FE_TYPE const & finiteElement ) - : m_finiteElement( finiteElement ) - {} - - /** - * @brief Launches the precomputation of the damping matrices - * @tparam EXEC_POLICY the execution policy - * @tparam ATOMIC_POLICY the atomic policy - * @param[in] size the number of cells in the subRegion - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemsToFaces map from elements to faces - * @param[in] facesToNodes map from face to nodes - * @param[in] facesDomainBoundaryIndicator flag equal to 1 if the face is on the boundary, and to 0 otherwise - * @param[in] freeSurfaceFaceIndicator flag equal to 1 if the face is on the free surface, and to 0 otherwise - * @param[in] velocity cell-wise velocity - * @param[out] damping diagonal of the damping matrix - */ - template< typename EXEC_POLICY, typename ATOMIC_POLICY > - void - launch( localIndex const size, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView2d< localIndex const > const elemsToFaces, - ArrayOfArraysView< localIndex const > const facesToNodes, - arrayView1d< integer const > const facesDomainBoundaryIndicator, - arrayView1d< localIndex const > const freeSurfaceFaceIndicator, - arrayView2d< real64 const > const faceNormal, - arrayView1d< real32 const > const density, - arrayView1d< real32 const > const velocityVp, - arrayView1d< real32 const > const velocityVs, - arrayView1d< real32 > const dampingx, - arrayView1d< real32 > const dampingy, - arrayView1d< real32 > const dampingz ) - { - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const e ) - { - for( localIndex i = 0; i < elemsToFaces.size( 1 ); ++i ) - { - localIndex const f = elemsToFaces( e, i ); - // face on the domain boundary and not on free surface - if( facesDomainBoundaryIndicator[f] == 1 && freeSurfaceFaceIndicator[f] != 1 ) - { - // only the four corners of the mesh face are needed to compute the Jacobian - real64 xLocal[ 4 ][ 3 ]; - for( localIndex a = 0; a < 4; ++a ) - { - localIndex const nodeIndex = facesToNodes( f, FE_TYPE::meshIndexToLinearIndex2D( a ) ); - for( localIndex d = 0; d < 3; ++d ) - { - xLocal[a][d] = nodeCoords( nodeIndex, d ); - } - } - - real32 const nx = faceNormal( f, 0 ), ny = faceNormal( f, 1 ), nz = faceNormal( f, 2 ); - constexpr localIndex numNodesPerFace = FE_TYPE::numNodesPerFace; - for( localIndex q = 0; q < numNodesPerFace; ++q ) - { - real32 const aux = density[e] * m_finiteElement.computeDampingTerm( q, xLocal ); - real32 const localIncrementx = density[e] * (velocityVp[e] * LvArray::math::abs( nx ) + velocityVs[e] * LvArray::math::sqrt( pow( ny, 2 ) + pow( nz, 2 ) ) ) * aux; - real32 const localIncrementy = density[e] * (velocityVp[e] * LvArray::math::abs( ny ) + velocityVs[e] * LvArray::math::sqrt( pow( nx, 2 ) + pow( nz, 2 ) ) ) * aux; - real32 const localIncrementz = density[e] * (velocityVp[e] * LvArray::math::abs( nz ) + velocityVs[e] * LvArray::math::sqrt( pow( nx, 2 ) + pow( ny, 2 ) ) ) * aux; - - RAJA::atomicAdd< ATOMIC_POLICY >( &dampingx[facesToNodes( f, q )], localIncrementx ); - RAJA::atomicAdd< ATOMIC_POLICY >( &dampingy[facesToNodes( f, q )], localIncrementy ); - RAJA::atomicAdd< ATOMIC_POLICY >( &dampingz[facesToNodes( f, q )], localIncrementz ); - } - } - } - } ); - } - - /// The finite element space/discretization object for the element type in the subRegion - FE_TYPE const & m_finiteElement; - -}; - -template< typename FE_TYPE > -struct StressComputation -{ - - StressComputation( FE_TYPE const & finiteElement ) - : m_finiteElement( finiteElement ) - {} - - /** - * Add comments - */ - - template< typename EXEC_POLICY, typename ATOMIC_POLICY > - void - launch( localIndex const size, - localIndex const regionIndex, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes, - arrayView1d< real32 const > const ux_np1, - arrayView1d< real32 const > const uy_np1, - arrayView1d< real32 const > const uz_np1, - arrayView1d< real32 const > const density, - arrayView1d< real32 const > const velocityVp, - arrayView1d< real32 const > const velocityVs, - arrayView1d< real32 > const lambda, - arrayView1d< real32 > const mu, - arrayView2d< real64 const > const sourceConstants, - arrayView1d< localIndex const > const sourceIsLocal, - arrayView1d< localIndex const > const sourceElem, - arrayView1d< localIndex const > const sourceRegion, - arrayView2d< real32 const > const sourceValue, - real64 const dt, - integer const cycleNumber, - arrayView2d< real32 > const stressxx, - arrayView2d< real32 > const stressyy, - arrayView2d< real32 > const stresszz, - arrayView2d< real32 > const stressxy, - arrayView2d< real32 > const stressxz, - arrayView2d< real32 > const stressyz ) - - { - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - // only the eight corners of the mesh cell are needed to compute the Jacobian - real64 xLocal[8][3]; - for( localIndex a=0; a< 8; ++a ) - { - localIndex const nodeIndex = elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); - for( localIndex i=0; i<3; ++i ) - { - xLocal[a][i] = nodeCoords( nodeIndex, i ); - } - } - - mu[k] = density[k] * pow( velocityVs[k], 2 ); - lambda[k] = density[k] * pow( velocityVp[k], 2 ) - 2.0*mu[k]; - - constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; - real32 uelemxx[numNodesPerElem] = {0.0}; - real32 uelemyy[numNodesPerElem] = {0.0}; - real32 uelemzz[numNodesPerElem] = {0.0}; - real32 uelemxy[numNodesPerElem] = {0.0}; - real32 uelemxz[numNodesPerElem] = {0.0}; - real32 uelemyz[numNodesPerElem]= {0.0}; - real32 auxx[numNodesPerElem] = {0.0}; - real32 auyy[numNodesPerElem] = {0.0}; - real32 auzz[numNodesPerElem] = {0.0}; - real32 auxy[numNodesPerElem] = {0.0}; - real32 auxz[numNodesPerElem] = {0.0}; - real32 auyz[numNodesPerElem] = {0.0}; - - - //Pre-multiplication by mass matrix - for( localIndex i = 0; i < numNodesPerElem; ++i ) - { - real32 massLoc = m_finiteElement.computeMassTerm( i, xLocal ); - uelemxx[i] = massLoc*stressxx[k][i]; - uelemyy[i] = massLoc*stressyy[k][i]; - uelemzz[i] = massLoc*stresszz[k][i]; - uelemxy[i] = massLoc*stressxy[k][i]; - uelemxz[i] = massLoc*stressxz[k][i]; - uelemyz[i] = massLoc*stressyz[k][i]; - } - - for( localIndex q = 0; q < numNodesPerElem; q++ ) - { - - //Volume integral - m_finiteElement.template computeFirstOrderStiffnessTermX( q, xLocal, [&] ( int i, int j, real32 dfx1, real32 dfx2, real32 dfx3 ) - { - auxx[j]+= dfx1*ux_np1[elemsToNodes[k][i]]; - auyy[j]+= dfx2*uy_np1[elemsToNodes[k][i]]; - auzz[j]+= dfx3*uz_np1[elemsToNodes[k][i]]; - auxy[j]+= dfx1*uy_np1[elemsToNodes[k][i]]+dfx2*ux_np1[elemsToNodes[k][i]]; - auxz[j]+= dfx1*uz_np1[elemsToNodes[k][i]]+dfx3*ux_np1[elemsToNodes[k][i]]; - auyz[j]+= dfx2*uz_np1[elemsToNodes[k][i]]+dfx3*uy_np1[elemsToNodes[k][i]]; - - } ); - - m_finiteElement.template computeFirstOrderStiffnessTermY( q, xLocal, [&] ( int i, int j, real32 dfy1, real32 dfy2, real32 dfy3 ) - { - auxx[j]+= dfy1*ux_np1[elemsToNodes[k][i]]; - auyy[j]+= dfy2*uy_np1[elemsToNodes[k][i]]; - auzz[j]+= dfy3*uz_np1[elemsToNodes[k][i]]; - auxy[j]+= dfy1*uy_np1[elemsToNodes[k][i]]+dfy2*ux_np1[elemsToNodes[k][i]]; - auxz[j]+= dfy1*uz_np1[elemsToNodes[k][i]]+dfy3*ux_np1[elemsToNodes[k][i]]; - auyz[j]+= dfy2*uz_np1[elemsToNodes[k][i]]+dfy3*uy_np1[elemsToNodes[k][i]]; - - } ); - - m_finiteElement.template computeFirstOrderStiffnessTermZ( q, xLocal, [&] ( int i, int j, real32 dfz1, real32 dfz2, real32 dfz3 ) - { - auxx[j]+= dfz1*ux_np1[elemsToNodes[k][i]]; - auyy[j]+= dfz2*uy_np1[elemsToNodes[k][i]]; - auzz[j]+= dfz3*uz_np1[elemsToNodes[k][i]]; - auxy[j]+= dfz1*uy_np1[elemsToNodes[k][i]]+dfz2*ux_np1[elemsToNodes[k][i]]; - auxz[j]+= dfz1*uz_np1[elemsToNodes[k][i]]+dfz3*ux_np1[elemsToNodes[k][i]]; - auyz[j]+= dfz2*uz_np1[elemsToNodes[k][i]]+dfz3*uy_np1[elemsToNodes[k][i]]; - - } ); - - } - //Time integration - for( localIndex i = 0; i < numNodesPerElem; ++i ) - { - real32 diag = lambda[k]*(auxx[i]+auyy[i]+auzz[i]); - uelemxx[i]+= dt*(diag+2*mu[k]*auxx[i]); - uelemyy[i]+= dt*(diag+2*mu[k]*auyy[i]); - uelemzz[i]+= dt*(diag+2*mu[k]*auzz[i]); - uelemxy[i]+= dt*mu[k]*auxy[i]; - uelemxz[i]+= dt*mu[k]*auxz[i]; - uelemyz[i]+= dt*mu[k]*auyz[i]; - } - - // Multiplication by inverse mass matrix - for( localIndex i = 0; i < numNodesPerElem; ++i ) - { - real32 massLoc = m_finiteElement.computeMassTerm( i, xLocal ); - stressxx[k][i] = uelemxx[i]/massLoc; - stressyy[k][i] = uelemyy[i]/massLoc; - stresszz[k][i] = uelemzz[i]/massLoc; - stressxy[k][i] = uelemxy[i]/massLoc; - stressxz[k][i] = uelemxz[i]/massLoc; - stressyz[k][i] = uelemyz[i]/massLoc; - } - - - //Source injection - for( localIndex isrc = 0; isrc < sourceConstants.size( 0 ); ++isrc ) - { - if( sourceIsLocal[isrc] == 1 ) - { - if( sourceElem[isrc]==k && sourceRegion[isrc] == regionIndex ) - { - for( localIndex i = 0; i < numNodesPerElem; ++i ) - { - real32 massLoc = m_finiteElement.computeMassTerm( i, xLocal ); - real32 const localIncrement = dt*(sourceConstants[isrc][i]*sourceValue[cycleNumber][isrc])/massLoc; - RAJA::atomicAdd< ATOMIC_POLICY >( &stressxx[k][i], localIncrement ); - RAJA::atomicAdd< ATOMIC_POLICY >( &stressyy[k][i], localIncrement ); - RAJA::atomicAdd< ATOMIC_POLICY >( &stresszz[k][i], localIncrement ); - } - - } - - } - } - - } ); - } - - /// The finite element space/discretization object for the element type in the subRegion - - FE_TYPE const & m_finiteElement; -}; - -template< typename FE_TYPE > -struct VelocityComputation -{ - - VelocityComputation( FE_TYPE const & finiteElement ) - : m_finiteElement( finiteElement ) - {} - - /** - * add doc - */ - - template< typename EXEC_POLICY, typename ATOMIC_POLICY > - void - launch( localIndex const size, - localIndex const size_node, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes, - arrayView2d< real32 const > const stressxx, - arrayView2d< real32 const > const stressyy, - arrayView2d< real32 const > const stresszz, - arrayView2d< real32 const > const stressxy, - arrayView2d< real32 const > const stressxz, - arrayView2d< real32 const > const stressyz, - arrayView1d< const real32 > const mass, - arrayView1d< real32 const > const dampingx, - arrayView1d< real32 const > const dampingy, - arrayView1d< real32 const > const dampingz, - real64 const dt, - arrayView1d< real32 > const ux_np1, - arrayView1d< real32 > const uy_np1, - arrayView1d< real32 > const uz_np1 ) - { - - forAll< EXEC_POLICY >( size_node, [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - ux_np1[a] *= 1.0-((dt/2)*(dampingx[a]/mass[a])); - uy_np1[a] *= 1.0-((dt/2)*(dampingy[a]/mass[a])); - uz_np1[a] *= 1.0-((dt/2)*(dampingz[a]/mass[a])); - } ); - - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - // only the eight corners of the mesh cell are needed to compute the Jacobian - real64 xLocal[8][3]; - for( localIndex a=0; a< 8; ++a ) - { - localIndex const nodeIndex = elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); - for( localIndex i=0; i<3; ++i ) - { - xLocal[a][i] = nodeCoords( nodeIndex, i ); - } - } - - constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; - real32 uelemx[numNodesPerElem] = {0.0}; - real32 uelemy[numNodesPerElem] = {0.0}; - real32 uelemz[numNodesPerElem] = {0.0}; - real32 flowx[numNodesPerElem] = {0.0}; - real32 flowy[numNodesPerElem] = {0.0}; - real32 flowz[numNodesPerElem] = {0.0}; - - for( localIndex q = 0; q < numNodesPerElem; q++ ) - { - - - // Stiffness part - m_finiteElement.template computeFirstOrderStiffnessTermX( q, xLocal, [&] ( int i, int j, real32 dfx1, real32 dfx2, real32 dfx3 ) - { - flowx[i] -= stressxx[k][j]*dfx1 + stressxy[k][j]*dfx2 + stressxz[k][j]*dfx3; - flowy[i] -= stressxy[k][j]*dfx1 + stressyy[k][j]*dfx2 + stressyz[k][j]*dfx3; - flowz[i] -= stressxz[k][j]*dfx1 + stressyz[k][j]*dfx2 + stresszz[k][j]*dfx3; - - } ); - - m_finiteElement.template computeFirstOrderStiffnessTermY( q, xLocal, [&] ( int i, int j, real32 dfy1, real32 dfy2, real32 dfy3 ) - { - flowx[i] -= stressxx[k][j]*dfy1 + stressxy[k][j]*dfy2 + stressxz[k][j]*dfy3; - flowy[i] -= stressxy[k][j]*dfy1 + stressyy[k][j]*dfy2 + stressyz[k][j]*dfy3; - flowz[i] -= stressxz[k][j]*dfy1 + stressyz[k][j]*dfy2 + stresszz[k][j]*dfy3; - } ); - - m_finiteElement.template computeFirstOrderStiffnessTermZ( q, xLocal, [&] ( int i, int j, real32 dfz1, real32 dfz2, real32 dfz3 ) - { - flowx[i] -= stressxx[k][j]*dfz1 + stressxy[k][j]*dfz2 + stressxz[k][j]*dfz3; - flowy[i] -= stressxy[k][j]*dfz1 + stressyy[k][j]*dfz2 + stressyz[k][j]*dfz3; - flowz[i] -= stressxz[k][j]*dfz1 + stressyz[k][j]*dfz2 + stresszz[k][j]*dfz3; - } ); - - } - // Time update - for( localIndex i = 0; i < numNodesPerElem; ++i ) - { - uelemx[i]+=dt*flowx[i]; - uelemy[i]+=dt*flowy[i]; - uelemz[i]+=dt*flowz[i]; - } - - // Mult by inverse mass matrix + damping matrix - for( localIndex i = 0; i < numNodesPerElem; ++i ) - { - real32 localIncrement1 = uelemx[i]/mass[elemsToNodes[k][i]]; - real32 localIncrement2 = uelemy[i]/mass[elemsToNodes[k][i]]; - real32 localIncrement3 = uelemz[i]/mass[elemsToNodes[k][i]]; - RAJA::atomicAdd< ATOMIC_POLICY >( &ux_np1[elemsToNodes[k][i]], localIncrement1 ); - RAJA::atomicAdd< ATOMIC_POLICY >( &uy_np1[elemsToNodes[k][i]], localIncrement2 ); - RAJA::atomicAdd< ATOMIC_POLICY >( &uz_np1[elemsToNodes[k][i]], localIncrement3 ); - } - - } ); - forAll< EXEC_POLICY >( size_node, [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - ux_np1[a] /= 1.0+((dt/2)*(dampingx[a]/mass[a])); - uy_np1[a] /= 1.0+((dt/2)*(dampingy[a]/mass[a])); - uz_np1[a] /= 1.0+((dt/2)*(dampingz[a]/mass[a])); - } ); - } - - /// The finite element space/discretization object for the element type in the subRegion - FE_TYPE const & m_finiteElement; - -}; - - -} // namespace ElasticFirstOrderWaveEquationSEMKernels - -} // namespace geos - -#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICFIRSTORDERWAVEEQUATIONSEMKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/ElasticWaveEquationSEM.cpp b/src/coreComponents/physicsSolvers/wavePropagation/ElasticWaveEquationSEM.cpp deleted file mode 100644 index 1d9e8fed402..00000000000 --- a/src/coreComponents/physicsSolvers/wavePropagation/ElasticWaveEquationSEM.cpp +++ /dev/null @@ -1,786 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - - -/** - * @file ElasticWaveEquationSEM.cpp - */ - -#include "ElasticWaveEquationSEM.hpp" -#include "ElasticWaveEquationSEMKernel.hpp" - -#include "fieldSpecification/FieldSpecificationManager.hpp" -#include "finiteElement/FiniteElementDiscretization.hpp" -#include "mainInterface/ProblemManager.hpp" -#include "mesh/ElementType.hpp" -#include "mesh/mpiCommunications/CommunicationTools.hpp" -#include "WaveSolverUtils.hpp" - -namespace geos -{ - -using namespace dataRepository; -using namespace fields; - -ElasticWaveEquationSEM::ElasticWaveEquationSEM( const std::string & name, - Group * const parent ): - - WaveSolverBase( name, - parent ) -{ - registerWrapper( viewKeyStruct::sourceConstantsString(), &m_sourceConstantsx ). - setInputFlag( InputFlags::FALSE ). - setSizedFromParent( 0 ). - setDescription( "Constant part of the source for the nodes listed in m_sourceNodeIds in x-direction" ); - - registerWrapper( viewKeyStruct::sourceConstantsString(), &m_sourceConstantsy ). - setInputFlag( InputFlags::FALSE ). - setSizedFromParent( 0 ). - setDescription( "Constant part of the source for the nodes listed in m_sourceNodeIds in y-direction" ); - - registerWrapper( viewKeyStruct::sourceConstantsString(), &m_sourceConstantsz ). - setInputFlag( InputFlags::FALSE ). - setSizedFromParent( 0 ). - setDescription( "Constant part of the source for the nodes listed in m_sourceNodeIds in z-direction" ); - - registerWrapper( viewKeyStruct::displacementXNp1AtReceiversString(), &m_displacementXNp1AtReceivers ). - setInputFlag( InputFlags::FALSE ). - setSizedFromParent( 0 ). - setDescription( "Displacement value at each receiver for each timestep (x-component)" ); - - registerWrapper( viewKeyStruct::displacementYNp1AtReceiversString(), &m_displacementYNp1AtReceivers ). - setInputFlag( InputFlags::FALSE ). - setSizedFromParent( 0 ). - setDescription( "Displacement value at each receiver for each timestep (y-component)" ); - - registerWrapper( viewKeyStruct::displacementZNp1AtReceiversString(), &m_displacementZNp1AtReceivers ). - setInputFlag( InputFlags::FALSE ). - setSizedFromParent( 0 ). - setDescription( "Displacement value at each receiver for each timestep (z-component)" ); - - registerWrapper( viewKeyStruct::dasSignalNp1AtReceiversString(), &m_dasSignalNp1AtReceivers ). - setInputFlag( InputFlags::FALSE ). - setSizedFromParent( 0 ). - setDescription( "DAS signal value at each receiver for each timestep" ); - - registerWrapper( viewKeyStruct::sourceForceString(), &m_sourceForce ). - setInputFlag( InputFlags::OPTIONAL ). - setSizedFromParent( 0 ). - setApplyDefaultValue( { 0.0, 0.0, 0.0 } ). - setDescription( "Force of the source: 3 real values for a vector source, and 6 real values for a tensor source (in Voigt notation)." - "The default value is { 0, 0, 0 } (no net force)." ); - - registerWrapper( viewKeyStruct::sourceMomentString(), &m_sourceMoment ). - setInputFlag( InputFlags::OPTIONAL ). - setSizedFromParent( 0 ). - setApplyDefaultValue( { 1.0, 1.0, 1.0, 0.0, 0.0, 0.0 } ). - setDescription( "Moment of the source: 6 real values describing a symmetric tensor in Voigt notation." - "The default value is { 1, 1, 1, 0, 0, 0 } (diagonal moment, corresponding to a pure explosion)." ); -} - -ElasticWaveEquationSEM::~ElasticWaveEquationSEM() -{ - // TODO Auto-generated destructor stub -} - -void ElasticWaveEquationSEM::initializePreSubGroups() -{ - - WaveSolverBase::initializePreSubGroups(); - - localIndex const numNodesPerElem = WaveSolverBase::getNumNodesPerElem(); - - localIndex const numSourcesGlobal = m_sourceCoordinates.size( 0 ); - m_sourceConstantsx.resize( numSourcesGlobal, numNodesPerElem ); - m_sourceConstantsy.resize( numSourcesGlobal, numNodesPerElem ); - m_sourceConstantsz.resize( numSourcesGlobal, numNodesPerElem ); - - localIndex const numReceiversGlobal = m_receiverCoordinates.size( 0 ); - integer nsamples = m_useDAS == WaveSolverUtils::DASType::none ? 1 : m_linearDASSamples; - m_receiverConstants.resize( numReceiversGlobal, nsamples * numNodesPerElem ); - m_receiverNodeIds.resize( numReceiversGlobal, nsamples * numNodesPerElem ); -} - - -void ElasticWaveEquationSEM::registerDataOnMesh( Group & meshBodies ) -{ - WaveSolverBase::registerDataOnMesh( meshBodies ); - - forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & ) - { - NodeManager & nodeManager = mesh.getNodeManager(); - - nodeManager.registerField< elasticfields::Displacementx_nm1, - elasticfields::Displacementy_nm1, - elasticfields::Displacementz_nm1, - elasticfields::Displacementx_n, - elasticfields::Displacementy_n, - elasticfields::Displacementz_n, - elasticfields::Displacementx_np1, - elasticfields::Displacementy_np1, - elasticfields::Displacementz_np1, - elasticfields::ForcingRHSx, - elasticfields::ForcingRHSy, - elasticfields::ForcingRHSz, - elasticfields::ElasticMassVector, - elasticfields::DampingVectorx, - elasticfields::DampingVectory, - elasticfields::DampingVectorz, - elasticfields::StiffnessVectorx, - elasticfields::StiffnessVectory, - elasticfields::StiffnessVectorz, - elasticfields::ElasticFreeSurfaceNodeIndicator >( getName() ); - - FaceManager & faceManager = mesh.getFaceManager(); - faceManager.registerField< elasticfields::ElasticFreeSurfaceFaceIndicator >( getName() ); - - ElementRegionManager & elemManager = mesh.getElemManager(); - - elemManager.forElementSubRegions< CellElementSubRegion >( [&]( CellElementSubRegion & subRegion ) - { - subRegion.registerField< elasticfields::ElasticVelocityVp >( getName() ); - subRegion.registerField< elasticfields::ElasticVelocityVs >( getName() ); - subRegion.registerField< elasticfields::ElasticDensity >( getName() ); - } ); - - } ); -} - - - -void ElasticWaveEquationSEM::postProcessInput() -{ - WaveSolverBase::postProcessInput(); - - EventManager const & event = getGroupByPath< EventManager >( "/Problem/Events" ); - real64 const & maxTime = event.getReference< real64 >( EventManager::viewKeyStruct::maxTimeString() ); - real64 dt = 0; - for( localIndex numSubEvent = 0; numSubEvent < event.numSubGroups(); ++numSubEvent ) - { - EventBase const * subEvent = static_cast< EventBase const * >( event.getSubGroups()[numSubEvent] ); - if( subEvent->getEventName() == "/Solvers/" + getName() ) - { - dt = subEvent->getReference< real64 >( EventBase::viewKeyStruct::forceDtString() ); - } - } - - GEOS_THROW_IF( dt < epsilonLoc*maxTime, getDataContext() << ": Value for dt: " << dt <<" is smaller than local threshold: " << epsilonLoc, std::runtime_error ); - - if( m_dtSeismoTrace > 0 ) - { - m_nsamplesSeismoTrace = int( maxTime / m_dtSeismoTrace ) + 1; - } - else - { - m_nsamplesSeismoTrace = 0; - } - localIndex const nsamples = int( maxTime / dt ) + 1; - - localIndex const numSourcesGlobal = m_sourceCoordinates.size( 0 ); - m_sourceIsAccessible.resize( numSourcesGlobal ); - m_sourceValue.resize( nsamples, numSourcesGlobal ); - - if( m_useDAS == WaveSolverUtils::DASType::none ) - { - localIndex const numReceiversGlobal = m_receiverCoordinates.size( 0 ); - m_displacementXNp1AtReceivers.resize( m_nsamplesSeismoTrace, numReceiversGlobal + 1 ); - m_displacementYNp1AtReceivers.resize( m_nsamplesSeismoTrace, numReceiversGlobal + 1 ); - m_displacementZNp1AtReceivers.resize( m_nsamplesSeismoTrace, numReceiversGlobal + 1 ); - m_displacementXNp1AtReceivers.zero(); - m_displacementYNp1AtReceivers.zero(); - m_displacementZNp1AtReceivers.zero(); - } - else - { - localIndex const numReceiversGlobal = m_linearDASGeometry.size( 0 ); - m_dasSignalNp1AtReceivers.resize( m_nsamplesSeismoTrace, numReceiversGlobal + 1 ); - m_dasSignalNp1AtReceivers.zero(); - } -} - - -void ElasticWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) -{ - NodeManager const & nodeManager = mesh.getNodeManager(); - FaceManager const & faceManager = mesh.getFaceManager(); - - arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const X = - nodeManager.getField< fields::referencePosition32 >().toViewConst(); - arrayView2d< real64 const > const faceNormal = faceManager.faceNormal(); - arrayView2d< real64 const > const faceCenter = faceManager.faceCenter(); - - arrayView2d< real64 const > const sourceCoordinates = m_sourceCoordinates.toViewConst(); - arrayView2d< localIndex > const sourceNodeIds = m_sourceNodeIds.toView(); - arrayView2d< real64 > const sourceConstantsx = m_sourceConstantsx.toView(); - arrayView2d< real64 > const sourceConstantsy = m_sourceConstantsy.toView(); - arrayView2d< real64 > const sourceConstantsz = m_sourceConstantsz.toView(); - arrayView1d< localIndex > const sourceIsAccessible = m_sourceIsAccessible.toView(); - - sourceNodeIds.setValues< EXEC_POLICY >( -1 ); - sourceConstantsx.setValues< EXEC_POLICY >( 0 ); - sourceConstantsy.setValues< EXEC_POLICY >( 0 ); - sourceConstantsz.setValues< EXEC_POLICY >( 0 ); - sourceIsAccessible.zero(); - - arrayView2d< real64 const > const receiverCoordinates = m_receiverCoordinates.toViewConst(); - arrayView2d< localIndex > const receiverNodeIds = m_receiverNodeIds.toView(); - arrayView2d< real64 > const receiverConstants = m_receiverConstants.toView(); - arrayView1d< localIndex > const receiverIsLocal = m_receiverIsLocal.toView(); - receiverNodeIds.setValues< EXEC_POLICY >( -1 ); - receiverConstants.setValues< EXEC_POLICY >( 0 ); - receiverIsLocal.zero(); - - arrayView2d< real32 > const sourceValue = m_sourceValue.toView(); - - real64 dt = 0; - EventManager const & event = getGroupByPath< EventManager >( "/Problem/Events" ); - for( localIndex numSubEvent = 0; numSubEvent < event.numSubGroups(); ++numSubEvent ) - { - EventBase const * subEvent = static_cast< EventBase const * >( event.getSubGroups()[numSubEvent] ); - if( subEvent->getEventName() == "/Solvers/" + getName() ) - { - dt = subEvent->getReference< real64 >( EventBase::viewKeyStruct::forceDtString() ); - } - } - - mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, - CellElementSubRegion & elementSubRegion ) - { - - GEOS_THROW_IF( elementSubRegion.getElementType() != ElementType::Hexahedron, - getDataContext() << ": Invalid type of element, the elastic solver is designed for hexahedral meshes only (C3D8) ", - InputError ); - - arrayView2d< localIndex const > const elemsToFaces = elementSubRegion.faceList(); - arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes = elementSubRegion.nodeList(); - arrayView2d< real64 const > const elemCenter = elementSubRegion.getElementCenter(); - arrayView1d< integer const > const elemGhostRank = elementSubRegion.ghostRank(); - - finiteElement::FiniteElementBase const & - fe = elementSubRegion.getReference< finiteElement::FiniteElementBase >( getDiscretizationName() ); - finiteElement::FiniteElementDispatchHandler< SEM_FE_TYPES >::dispatch3D( fe, [&] ( auto const finiteElement ) - { - using FE_TYPE = TYPEOFREF( finiteElement ); - - localIndex const numFacesPerElem = elementSubRegion.numFacesPerElement(); - elasticWaveEquationSEMKernels:: - PrecomputeSourceAndReceiverKernel:: - launch< EXEC_POLICY, FE_TYPE > - ( elementSubRegion.size(), - numFacesPerElem, - X, - elemGhostRank, - elemsToNodes, - elemsToFaces, - elemCenter, - faceNormal, - faceCenter, - sourceCoordinates, - sourceIsAccessible, - sourceNodeIds, - sourceConstantsx, - sourceConstantsy, - sourceConstantsz, - receiverCoordinates, - receiverIsLocal, - receiverNodeIds, - receiverConstants, - sourceValue, - dt, - m_timeSourceFrequency, - m_timeSourceDelay, - m_rickerOrder, - m_useDAS, - m_linearDASSamples, - m_linearDASGeometry.toViewConst(), - m_sourceForce, - m_sourceMoment ); - } ); - } ); -} - -void ElasticWaveEquationSEM::addSourceToRightHandSide( integer const & cycleNumber, - arrayView1d< real32 > const rhsx, - arrayView1d< real32 > const rhsy, - arrayView1d< real32 > const rhsz ) -{ - arrayView2d< localIndex const > const sourceNodeIds = m_sourceNodeIds.toViewConst(); - arrayView2d< real64 const > const sourceConstantsx = m_sourceConstantsx.toViewConst(); - arrayView2d< real64 const > const sourceConstantsy = m_sourceConstantsy.toViewConst(); - arrayView2d< real64 const > const sourceConstantsz = m_sourceConstantsz.toViewConst(); - - arrayView1d< localIndex const > const sourceIsAccessible = m_sourceIsAccessible.toViewConst(); - arrayView2d< real32 const > const sourceValue = m_sourceValue.toViewConst(); - - GEOS_THROW_IF( cycleNumber > sourceValue.size( 0 ), getDataContext() << ": Too many steps compared to array size", std::runtime_error ); - forAll< EXEC_POLICY >( m_sourceConstantsx.size( 0 ), [=] GEOS_HOST_DEVICE ( localIndex const isrc ) - { - if( sourceIsAccessible[isrc] == 1 ) - { - for( localIndex inode = 0; inode < sourceConstantsx.size( 1 ); ++inode ) - { - real32 const localIncrementx = sourceConstantsx[isrc][inode] * sourceValue[cycleNumber][isrc]; - RAJA::atomicAdd< ATOMIC_POLICY >( &rhsx[sourceNodeIds[isrc][inode]], localIncrementx ); - real32 const localIncrementy = sourceConstantsy[isrc][inode] * sourceValue[cycleNumber][isrc]; - RAJA::atomicAdd< ATOMIC_POLICY >( &rhsy[sourceNodeIds[isrc][inode]], localIncrementy ); - real32 const localIncrementz = sourceConstantsz[isrc][inode] * sourceValue[cycleNumber][isrc]; - RAJA::atomicAdd< ATOMIC_POLICY >( &rhsz[sourceNodeIds[isrc][inode]], localIncrementz ); - } - } - } ); -} - -void ElasticWaveEquationSEM::initializePostInitialConditionsPreSubGroups() -{ - - WaveSolverBase::initializePostInitialConditionsPreSubGroups(); - - DomainPartition & domain = getGroupByPath< DomainPartition >( "/Problem/domain" ); - - applyFreeSurfaceBC( 0.0, domain ); - - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - precomputeSourceAndReceiverTerm( mesh, regionNames ); - - NodeManager & nodeManager = mesh.getNodeManager(); - FaceManager & faceManager = mesh.getFaceManager(); - ElementRegionManager & elemManager = mesh.getElemManager(); - - arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords = nodeManager.getField< fields::referencePosition32 >().toViewConst(); - - // mass matrix to be computed in this function - arrayView1d< real32 > const mass = nodeManager.getField< elasticfields::ElasticMassVector >(); - mass.zero(); - /// damping matrix to be computed for each dof in the boundary of the mesh - arrayView1d< real32 > const dampingx = nodeManager.getField< elasticfields::DampingVectorx >(); - arrayView1d< real32 > const dampingy = nodeManager.getField< elasticfields::DampingVectory >(); - arrayView1d< real32 > const dampingz = nodeManager.getField< elasticfields::DampingVectorz >(); - dampingx.zero(); - dampingy.zero(); - dampingz.zero(); - - /// get array of indicators: 1 if face is on the free surface; 0 otherwise - arrayView1d< localIndex const > const freeSurfaceFaceIndicator = faceManager.getField< elasticfields::ElasticFreeSurfaceFaceIndicator >(); - arrayView1d< integer const > const & facesDomainBoundaryIndicator = faceManager.getDomainBoundaryIndicator(); - ArrayOfArraysView< localIndex const > const facesToNodes = faceManager.nodeList().toViewConst(); - arrayView2d< real64 const > const faceNormal = faceManager.faceNormal(); - - elemManager.forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, - CellElementSubRegion & elementSubRegion ) - { - finiteElement::FiniteElementBase const & - fe = elementSubRegion.getReference< finiteElement::FiniteElementBase >( getDiscretizationName() ); - - arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes = elementSubRegion.nodeList(); - arrayView2d< localIndex const > const elemsToFaces = elementSubRegion.faceList(); - - computeTargetNodeSet( elemsToNodes, elementSubRegion.size(), fe.getNumQuadraturePoints() ); - - arrayView1d< real32 const > const density = elementSubRegion.getField< elasticfields::ElasticDensity >(); - arrayView1d< real32 const > const velocityVp = elementSubRegion.getField< elasticfields::ElasticVelocityVp >(); - arrayView1d< real32 const > const velocityVs = elementSubRegion.getField< elasticfields::ElasticVelocityVs >(); - - finiteElement::FiniteElementDispatchHandler< SEM_FE_TYPES >::dispatch3D( fe, [&] ( auto const finiteElement ) - { - using FE_TYPE = TYPEOFREF( finiteElement ); - - elasticWaveEquationSEMKernels::MassMatrixKernel< FE_TYPE > kernelM( finiteElement ); - kernelM.template launch< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), - nodeCoords, - elemsToNodes, - density, - mass ); - - elasticWaveEquationSEMKernels::DampingMatrixKernel< FE_TYPE > kernelD( finiteElement ); - kernelD.template launch< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), - nodeCoords, - elemsToFaces, - facesToNodes, - facesDomainBoundaryIndicator, - freeSurfaceFaceIndicator, - faceNormal, - density, - velocityVp, - velocityVs, - dampingx, - dampingy, - dampingz ); - } ); - } ); - } ); - - WaveSolverUtils::initTrace( "seismoTraceReceiver", getName(), m_outputSeismoTrace, m_receiverConstants.size( 0 ), m_receiverIsLocal ); - WaveSolverUtils::initTrace( "dasTraceReceiver", getName(), m_outputSeismoTrace, m_linearDASGeometry.size( 0 ), m_receiverIsLocal ); -} - - -void ElasticWaveEquationSEM::applyFreeSurfaceBC( real64 const time, DomainPartition & domain ) -{ - FieldSpecificationManager & fsManager = FieldSpecificationManager::getInstance(); - FunctionManager const & functionManager = FunctionManager::getInstance(); - - FaceManager & faceManager = domain.getMeshBody( 0 ).getMeshLevel( m_discretizationName ).getFaceManager(); - NodeManager & nodeManager = domain.getMeshBody( 0 ).getMeshLevel( m_discretizationName ).getNodeManager(); - - arrayView1d< real32 > const ux_np1 = nodeManager.getField< elasticfields::Displacementx_np1 >(); - arrayView1d< real32 > const uy_np1 = nodeManager.getField< elasticfields::Displacementy_np1 >(); - arrayView1d< real32 > const uz_np1 = nodeManager.getField< elasticfields::Displacementz_np1 >(); - arrayView1d< real32 > const ux_n = nodeManager.getField< elasticfields::Displacementx_n >(); - arrayView1d< real32 > const uy_n = nodeManager.getField< elasticfields::Displacementy_n >(); - arrayView1d< real32 > const uz_n = nodeManager.getField< elasticfields::Displacementz_n >(); - arrayView1d< real32 > const ux_nm1 = nodeManager.getField< elasticfields::Displacementx_nm1 >(); - arrayView1d< real32 > const uy_nm1 = nodeManager.getField< elasticfields::Displacementy_nm1 >(); - arrayView1d< real32 > const uz_nm1 = nodeManager.getField< elasticfields::Displacementz_nm1 >(); - - ArrayOfArraysView< localIndex const > const faceToNodeMap = faceManager.nodeList().toViewConst(); - - /// set array of indicators: 1 if a face is on on free surface; 0 otherwise - arrayView1d< localIndex > const freeSurfaceFaceIndicator = faceManager.getField< elasticfields::ElasticFreeSurfaceFaceIndicator >(); - - /// set array of indicators: 1 if a node is on on free surface; 0 otherwise - arrayView1d< localIndex > const freeSurfaceNodeIndicator = nodeManager.getField< elasticfields::ElasticFreeSurfaceNodeIndicator >(); - - - fsManager.apply( time, - domain.getMeshBody( 0 ).getMeshLevel( m_discretizationName ), - WaveSolverBase::viewKeyStruct::freeSurfaceString(), - [&]( FieldSpecificationBase const & bc, - string const &, - SortedArrayView< localIndex const > const & targetSet, - Group &, - string const & ) - { - string const & functionName = bc.getFunctionName(); - - if( functionName.empty() || functionManager.getGroup< FunctionBase >( functionName ).isFunctionOfTime() == 2 ) - { - real64 const value = bc.getScale(); - - for( localIndex i = 0; i < targetSet.size(); ++i ) - { - localIndex const kf = targetSet[ i ]; - freeSurfaceFaceIndicator[kf] = 1; - - localIndex const numNodes = faceToNodeMap.sizeOfArray( kf ); - for( localIndex a=0; a < numNodes; ++a ) - { - localIndex const dof = faceToNodeMap( kf, a ); - freeSurfaceNodeIndicator[dof] = 1; - - ux_np1[dof] = value; - uy_np1[dof] = value; - uz_np1[dof] = value; - ux_n[dof] = value; - uy_n[dof] = value; - uz_n[dof] = value; - ux_nm1[dof] = value; - uy_nm1[dof] = value; - uz_nm1[dof] = value; - } - } - } - else - { - GEOS_ERROR( getDataContext() << ": This option is not supported yet" ); - } - } ); -} - - - -real64 ElasticWaveEquationSEM::explicitStepForward( real64 const & time_n, - real64 const & dt, - integer cycleNumber, - DomainPartition & domain, - bool GEOS_UNUSED_PARAM( computeGradient ) ) -{ - real64 dtOut = explicitStepInternal( time_n, dt, cycleNumber, domain ); - return dtOut; -} - - - -real64 ElasticWaveEquationSEM::explicitStepBackward( real64 const & time_n, - real64 const & dt, - integer cycleNumber, - DomainPartition & domain, - bool GEOS_UNUSED_PARAM( computeGradient ) ) -{ - GEOS_ERROR( getDataContext() << ": Backward propagation for the elastic wave propagator not yet implemented" ); - real64 dtOut = explicitStepInternal( time_n, dt, cycleNumber, domain ); - return dtOut; -} - -void ElasticWaveEquationSEM::computeUnknowns( real64 const &, - real64 const & dt, - integer const cycleNumber, - DomainPartition &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) -{ - NodeManager & nodeManager = mesh.getNodeManager(); - - arrayView1d< real32 const > const mass = nodeManager.getField< elasticfields::ElasticMassVector >(); - arrayView1d< real32 const > const dampingx = nodeManager.getField< elasticfields::DampingVectorx >(); - arrayView1d< real32 const > const dampingy = nodeManager.getField< elasticfields::DampingVectory >(); - arrayView1d< real32 const > const dampingz = nodeManager.getField< elasticfields::DampingVectorz >(); - arrayView1d< real32 > const stiffnessVectorx = nodeManager.getField< elasticfields::StiffnessVectorx >(); - arrayView1d< real32 > const stiffnessVectory = nodeManager.getField< elasticfields::StiffnessVectory >(); - arrayView1d< real32 > const stiffnessVectorz = nodeManager.getField< elasticfields::StiffnessVectorz >(); - - arrayView1d< real32 > const ux_nm1 = nodeManager.getField< elasticfields::Displacementx_nm1 >(); - arrayView1d< real32 > const uy_nm1 = nodeManager.getField< elasticfields::Displacementy_nm1 >(); - arrayView1d< real32 > const uz_nm1 = nodeManager.getField< elasticfields::Displacementz_nm1 >(); - arrayView1d< real32 > const ux_n = nodeManager.getField< elasticfields::Displacementx_n >(); - arrayView1d< real32 > const uy_n = nodeManager.getField< elasticfields::Displacementy_n >(); - arrayView1d< real32 > const uz_n = nodeManager.getField< elasticfields::Displacementz_n >(); - arrayView1d< real32 > const ux_np1 = nodeManager.getField< elasticfields::Displacementx_np1 >(); - arrayView1d< real32 > const uy_np1 = nodeManager.getField< elasticfields::Displacementy_np1 >(); - arrayView1d< real32 > const uz_np1 = nodeManager.getField< elasticfields::Displacementz_np1 >(); - - /// get array of indicators: 1 if node on free surface; 0 otherwise - arrayView1d< localIndex const > const freeSurfaceNodeIndicator = nodeManager.getField< elasticfields::ElasticFreeSurfaceNodeIndicator >(); - - arrayView1d< real32 > const rhsx = nodeManager.getField< elasticfields::ForcingRHSx >(); - arrayView1d< real32 > const rhsy = nodeManager.getField< elasticfields::ForcingRHSy >(); - arrayView1d< real32 > const rhsz = nodeManager.getField< elasticfields::ForcingRHSz >(); - - auto kernelFactory = elasticWaveEquationSEMKernels::ExplicitElasticSEMFactory( dt ); - - finiteElement:: - regionBasedKernelApplication< EXEC_POLICY, - constitutive::NullModel, - CellElementSubRegion >( mesh, - regionNames, - getDiscretizationName(), - "", - kernelFactory ); - - - addSourceToRightHandSide( cycleNumber, rhsx, rhsy, rhsz ); - - real64 const dt2 = pow( dt, 2 ); - SortedArrayView< localIndex const > const solverTargetNodesSet = m_solverTargetNodesSet.toViewConst(); - forAll< EXEC_POLICY >( solverTargetNodesSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const n ) - { - localIndex const a = solverTargetNodesSet[n]; - if( freeSurfaceNodeIndicator[a] != 1 ) - { - ux_np1[a] = ux_n[a]; - ux_np1[a] *= 2.0*mass[a]; - ux_np1[a] -= (mass[a]-0.5*dt*dampingx[a])*ux_nm1[a]; - ux_np1[a] += dt2*(rhsx[a]-stiffnessVectorx[a]); - ux_np1[a] /= mass[a]+0.5*dt*dampingx[a]; - uy_np1[a] = uy_n[a]; - uy_np1[a] *= 2.0*mass[a]; - uy_np1[a] -= (mass[a]-0.5*dt*dampingy[a])*uy_nm1[a]; - uy_np1[a] += dt2*(rhsy[a]-stiffnessVectory[a]); - uy_np1[a] /= mass[a]+0.5*dt*dampingy[a]; - uz_np1[a] = uz_n[a]; - uz_np1[a] *= 2.0*mass[a]; - uz_np1[a] -= (mass[a]-0.5*dt*dampingz[a])*uz_nm1[a]; - uz_np1[a] += dt2*(rhsz[a]-stiffnessVectorz[a]); - uz_np1[a] /= mass[a]+0.5*dt*dampingz[a]; - } - } ); -} - -void ElasticWaveEquationSEM::synchronizeUnknowns( real64 const & time_n, - real64 const & dt, - integer const, - DomainPartition & domain, - MeshLevel & mesh, - arrayView1d< string const > const & ) -{ - NodeManager & nodeManager = mesh.getNodeManager(); - - arrayView1d< real32 > const stiffnessVectorx = nodeManager.getField< elasticfields::StiffnessVectorx >(); - arrayView1d< real32 > const stiffnessVectory = nodeManager.getField< elasticfields::StiffnessVectory >(); - arrayView1d< real32 > const stiffnessVectorz = nodeManager.getField< elasticfields::StiffnessVectorz >(); - - arrayView1d< real32 > const ux_nm1 = nodeManager.getField< elasticfields::Displacementx_nm1 >(); - arrayView1d< real32 > const uy_nm1 = nodeManager.getField< elasticfields::Displacementy_nm1 >(); - arrayView1d< real32 > const uz_nm1 = nodeManager.getField< elasticfields::Displacementz_nm1 >(); - arrayView1d< real32 > const ux_n = nodeManager.getField< elasticfields::Displacementx_n >(); - arrayView1d< real32 > const uy_n = nodeManager.getField< elasticfields::Displacementy_n >(); - arrayView1d< real32 > const uz_n = nodeManager.getField< elasticfields::Displacementz_n >(); - arrayView1d< real32 > const ux_np1 = nodeManager.getField< elasticfields::Displacementx_np1 >(); - arrayView1d< real32 > const uy_np1 = nodeManager.getField< elasticfields::Displacementy_np1 >(); - arrayView1d< real32 > const uz_np1 = nodeManager.getField< elasticfields::Displacementz_np1 >(); - - arrayView1d< real32 > const rhsx = nodeManager.getField< elasticfields::ForcingRHSx >(); - arrayView1d< real32 > const rhsy = nodeManager.getField< elasticfields::ForcingRHSy >(); - arrayView1d< real32 > const rhsz = nodeManager.getField< elasticfields::ForcingRHSz >(); - - /// synchronize displacement fields - FieldIdentifiers fieldsToBeSync; - fieldsToBeSync.addFields( FieldLocation::Node, { elasticfields::Displacementx_np1::key(), elasticfields::Displacementy_np1::key(), elasticfields::Displacementz_np1::key() } ); - - CommunicationTools & syncFields = CommunicationTools::getInstance(); - syncFields.synchronizeFields( fieldsToBeSync, - domain.getMeshBody( 0 ).getMeshLevel( m_discretizationName ), - domain.getNeighbors(), - true ); - - // compute the seismic traces since last step. - if( m_useDAS == WaveSolverUtils::DASType::none ) - { - arrayView2d< real32 > const uXReceivers = m_displacementXNp1AtReceivers.toView(); - arrayView2d< real32 > const uYReceivers = m_displacementYNp1AtReceivers.toView(); - arrayView2d< real32 > const uZReceivers = m_displacementZNp1AtReceivers.toView(); - computeAllSeismoTraces( time_n, dt, ux_np1, ux_n, uXReceivers ); - computeAllSeismoTraces( time_n, dt, uy_np1, uy_n, uYReceivers ); - computeAllSeismoTraces( time_n, dt, uz_np1, uz_n, uZReceivers ); - } - else - { - arrayView2d< real32 > const dasReceivers = m_dasSignalNp1AtReceivers.toView(); - computeAllSeismoTraces( time_n, dt, ux_np1, ux_n, dasReceivers, m_linearDASVectorX.toView(), true ); - computeAllSeismoTraces( time_n, dt, uy_np1, uy_n, dasReceivers, m_linearDASVectorY.toView(), true ); - computeAllSeismoTraces( time_n, dt, uz_np1, uz_n, dasReceivers, m_linearDASVectorZ.toView(), true ); - } - - incrementIndexSeismoTrace( time_n ); -} - -void ElasticWaveEquationSEM::prepareNextTimestep( MeshLevel & mesh ) -{ - NodeManager & nodeManager = mesh.getNodeManager(); - - arrayView1d< real32 > const ux_nm1 = nodeManager.getField< elasticfields::Displacementx_nm1 >(); - arrayView1d< real32 > const uy_nm1 = nodeManager.getField< elasticfields::Displacementy_nm1 >(); - arrayView1d< real32 > const uz_nm1 = nodeManager.getField< elasticfields::Displacementz_nm1 >(); - arrayView1d< real32 > const ux_n = nodeManager.getField< elasticfields::Displacementx_n >(); - arrayView1d< real32 > const uy_n = nodeManager.getField< elasticfields::Displacementy_n >(); - arrayView1d< real32 > const uz_n = nodeManager.getField< elasticfields::Displacementz_n >(); - arrayView1d< real32 > const ux_np1 = nodeManager.getField< elasticfields::Displacementx_np1 >(); - arrayView1d< real32 > const uy_np1 = nodeManager.getField< elasticfields::Displacementy_np1 >(); - arrayView1d< real32 > const uz_np1 = nodeManager.getField< elasticfields::Displacementz_np1 >(); - - arrayView1d< real32 > const stiffnessVectorx = nodeManager.getField< elasticfields::StiffnessVectorx >(); - arrayView1d< real32 > const stiffnessVectory = nodeManager.getField< elasticfields::StiffnessVectory >(); - arrayView1d< real32 > const stiffnessVectorz = nodeManager.getField< elasticfields::StiffnessVectorz >(); - - arrayView1d< real32 > const rhsx = nodeManager.getField< elasticfields::ForcingRHSx >(); - arrayView1d< real32 > const rhsy = nodeManager.getField< elasticfields::ForcingRHSy >(); - arrayView1d< real32 > const rhsz = nodeManager.getField< elasticfields::ForcingRHSz >(); - - SortedArrayView< localIndex const > const solverTargetNodesSet = m_solverTargetNodesSet.toViewConst(); - - forAll< EXEC_POLICY >( solverTargetNodesSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const n ) - { - localIndex const a = solverTargetNodesSet[n]; - ux_nm1[a] = ux_n[a]; - uy_nm1[a] = uy_n[a]; - uz_nm1[a] = uz_n[a]; - ux_n[a] = ux_np1[a]; - uy_n[a] = uy_np1[a]; - uz_n[a] = uz_np1[a]; - - stiffnessVectorx[a] = stiffnessVectory[a] = stiffnessVectorz[a] = 0.0; - rhsx[a] = rhsy[a] = rhsz[a] = 0.0; - } ); - -} - -real64 ElasticWaveEquationSEM::explicitStepInternal( real64 const & time_n, - real64 const & dt, - integer const cycleNumber, - DomainPartition & domain ) -{ - GEOS_MARK_FUNCTION; - - GEOS_LOG_RANK_0_IF( dt < epsilonLoc, "Warning! Value for dt: " << dt << "s is smaller than local threshold: " << epsilonLoc ); - - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - computeUnknowns( time_n, dt, cycleNumber, domain, mesh, regionNames ); - synchronizeUnknowns( time_n, dt, cycleNumber, domain, mesh, regionNames ); - prepareNextTimestep( mesh ); - } ); - - return dt; -} - -void ElasticWaveEquationSEM::cleanup( real64 const time_n, - integer const cycleNumber, - integer const eventCounter, - real64 const eventProgress, - DomainPartition & domain ) -{ - // call the base class cleanup (for reporting purposes) - SolverBase::cleanup( time_n, cycleNumber, eventCounter, eventProgress, domain ); - - // compute the remaining seismic traces, if needed - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & ) - { - NodeManager & nodeManager = mesh.getNodeManager(); - arrayView1d< real32 const > const ux_n = nodeManager.getField< elasticfields::Displacementx_n >(); - arrayView1d< real32 const > const ux_np1 = nodeManager.getField< elasticfields::Displacementx_np1 >(); - arrayView1d< real32 const > const uy_n = nodeManager.getField< elasticfields::Displacementy_n >(); - arrayView1d< real32 const > const uy_np1 = nodeManager.getField< elasticfields::Displacementy_np1 >(); - arrayView1d< real32 const > const uz_n = nodeManager.getField< elasticfields::Displacementz_n >(); - arrayView1d< real32 const > const uz_np1 = nodeManager.getField< elasticfields::Displacementz_np1 >(); - - if( m_useDAS == WaveSolverUtils::DASType::none ) - { - arrayView2d< real32 > const uXReceivers = m_displacementXNp1AtReceivers.toView(); - arrayView2d< real32 > const uYReceivers = m_displacementYNp1AtReceivers.toView(); - arrayView2d< real32 > const uZReceivers = m_displacementZNp1AtReceivers.toView(); - computeAllSeismoTraces( time_n, 0.0, ux_np1, ux_n, uXReceivers ); - computeAllSeismoTraces( time_n, 0.0, uy_np1, uy_n, uYReceivers ); - computeAllSeismoTraces( time_n, 0.0, uz_np1, uz_n, uZReceivers ); - WaveSolverUtils::writeSeismoTraceVector( "seismoTraceReceiver", getName(), m_outputSeismoTrace, m_receiverConstants.size( 0 ), - m_receiverIsLocal, m_nsamplesSeismoTrace, uXReceivers, uYReceivers, uZReceivers ); - } - else - { - arrayView2d< real32 > const dasReceivers = m_dasSignalNp1AtReceivers.toView(); - computeAllSeismoTraces( time_n, 0.0, ux_np1, ux_n, dasReceivers, m_linearDASVectorX.toView(), true ); - computeAllSeismoTraces( time_n, 0.0, uy_np1, uy_n, dasReceivers, m_linearDASVectorY.toView(), true ); - computeAllSeismoTraces( time_n, 0.0, uz_np1, uz_n, dasReceivers, m_linearDASVectorZ.toView(), true ); - // sum contributions from all MPI ranks, since some receivers might be split among multiple ranks - MpiWrapper::allReduce( dasReceivers.data(), - dasReceivers.data(), - m_linearDASGeometry.size( 0 ), - MpiWrapper::getMpiOp( MpiWrapper::Reduction::Sum ), - MPI_COMM_GEOSX ); - WaveSolverUtils::writeSeismoTrace( "dasTraceReceiver", getName(), m_outputSeismoTrace, m_linearDASGeometry.size( 0 ), - m_receiverIsLocal, m_nsamplesSeismoTrace, dasReceivers ); - } - } ); -} - -void ElasticWaveEquationSEM::initializePML() -{ - GEOS_ERROR( getDataContext() << ": PML for the elastic wave propagator not yet implemented" ); -} - -void ElasticWaveEquationSEM::applyPML( real64 const, DomainPartition & ) -{ - GEOS_ERROR( getDataContext() << ": PML for the elastic wave propagator not yet implemented" ); -} - -REGISTER_CATALOG_ENTRY( SolverBase, ElasticWaveEquationSEM, string const &, dataRepository::Group * const ) - -} /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/ElasticWaveEquationSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/ElasticWaveEquationSEMKernel.hpp deleted file mode 100644 index 78b7292eda7..00000000000 --- a/src/coreComponents/physicsSolvers/wavePropagation/ElasticWaveEquationSEMKernel.hpp +++ /dev/null @@ -1,681 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file ElasticWaveEquationSEMKernel.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICWAVEEQUATIONSEMKERNEL_HPP_ -#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICWAVEEQUATIONSEMKERNEL_HPP_ - -#include "finiteElement/kernelInterface/KernelBase.hpp" -#include "WaveSolverUtils.hpp" -#include "ElasticFields.hpp" - -namespace geos -{ -using namespace fields; -/// Namespace to contain the elastic wave kernels. -namespace elasticWaveEquationSEMKernels -{ - -struct PrecomputeSourceAndReceiverKernel -{ - - /** - * @brief Launches the precomputation of the source and receiver terms - * @tparam EXEC_POLICY execution policy - * @tparam FE_TYPE finite element type - * @param[in] size the number of cells in the subRegion - * @param[in] numFacesPerElem number of face on an element - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemGhostRank array containing the ghost rank - * @param[in] elemsToNodes map from element to nodes - * @param[in] elemsToFaces map from element to faces - * @param[in] elemCenter coordinates of the element centers - * @param[in] faceNormal array containing the normal of all faces - * @param[in] faceCenter array containing the center of all faces - * @param[in] sourceCoordinates coordinates of the source terms - * @param[in] receiverCoordinates coordinates of the receiver terms - * @param[in] dt time-step - * @param[in] timeSourceFrequency Peak frequency of the source - * @param[in] sourceForce force vector of the source - * @param[in] sourceMoment moment (symmetric rank-2 tensor) of the source - * @param[in] useDAS parameter that determines which kind of receiver needs to be modeled (DAS or not, and which type) - * @param[in] linearDASSamples parameter that gives the number of integration points to be used when computing the DAS signal via strain - * integration - * @param[in] linearDASGeometry geometry of the linear DAS receivers, if needed - * @param[in] rickerOrder Order of the Ricker wavelet - * @param[out] sourceIsAccessible flag indicating whether the source is accessible or not - * @param[out] sourceNodeIds indices of the nodes of the element where the source is located - * @param[out] sourceConstantsx constant part of the source terms in x-direction - * @param[out] sourceConstantsy constant part of the source terms in y-direction - * @param[out] sourceConstantsz constant part of the source terms in z-direction - * @param[out] receiverIsLocal flag indicating whether the receiver is local or not - * @param[out] receiverNodeIds indices of the nodes of the element where the receiver is located - * @param[out] receiverNodeConstants constant part of the receiver term - * @param[out] sourceValue array containing the value of the time dependent source (Ricker for e.g) - */ - template< typename EXEC_POLICY, typename FE_TYPE > - static void - launch( localIndex const size, - localIndex const numFacesPerElem, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView1d< integer const > const elemGhostRank, - arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes, - arrayView2d< localIndex const > const elemsToFaces, - arrayView2d< real64 const > const & elemCenter, - arrayView2d< real64 const > const faceNormal, - arrayView2d< real64 const > const faceCenter, - arrayView2d< real64 const > const sourceCoordinates, - arrayView1d< localIndex > const sourceIsAccessible, - arrayView2d< localIndex > const sourceNodeIds, - arrayView2d< real64 > const sourceConstantsx, - arrayView2d< real64 > const sourceConstantsy, - arrayView2d< real64 > const sourceConstantsz, - arrayView2d< real64 const > const receiverCoordinates, - arrayView1d< localIndex > const receiverIsLocal, - arrayView2d< localIndex > const receiverNodeIds, - arrayView2d< real64 > const receiverConstants, - arrayView2d< real32 > const sourceValue, - real64 const dt, - real32 const timeSourceFrequency, - real32 const timeSourceDelay, - localIndex const rickerOrder, - WaveSolverUtils::DASType useDAS, - integer linearDASSamples, - arrayView2d< real64 const > const linearDASGeometry, - R1Tensor const sourceForce, - R2SymTensor const sourceMoment ) - { - constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; - integer nSamples = useDAS == WaveSolverUtils::DASType::none ? 1 : linearDASSamples; - array1d< real64 > const samplePointLocationsA( nSamples ); - arrayView1d< real64 > const samplePointLocations = samplePointLocationsA.toView(); - array1d< real64 > const sampleIntegrationConstantsA( nSamples ); - arrayView1d< real64 > const sampleIntegrationConstants = sampleIntegrationConstantsA.toView(); - - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - real64 const center[3] = { elemCenter[k][0], - elemCenter[k][1], - elemCenter[k][2] }; - - // Step 1: locate the sources, and precompute the source term - - /// loop over all the source that haven't been found yet - for( localIndex isrc = 0; isrc < sourceCoordinates.size( 0 ); ++isrc ) - { - if( sourceIsAccessible[isrc] == 0 ) - { - real64 const coords[3] = { sourceCoordinates[isrc][0], - sourceCoordinates[isrc][1], - sourceCoordinates[isrc][2] }; - - real64 xLocal[numNodesPerElem][3]; - - for( localIndex a=0; a< numNodesPerElem; ++a ) - { - for( localIndex i=0; i<3; ++i ) - { - xLocal[a][i] = nodeCoords( elemsToNodes( k, a ), i ); - } - } - - - bool const sourceFound = - WaveSolverUtils::locateSourceElement( numFacesPerElem, - center, - faceNormal, - faceCenter, - elemsToFaces[k], - coords ); - - if( sourceFound ) - { - real64 coordsOnRefElem[3]{}; - - - WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, - elemsToNodes[k], - nodeCoords, - coordsOnRefElem ); - sourceIsAccessible[isrc] = 1; - - real64 N[numNodesPerElem]; - real64 gradN[numNodesPerElem][3]; - FE_TYPE::calcN( coordsOnRefElem, N ); - FE_TYPE::calcGradN( coordsOnRefElem, xLocal, gradN ); - R2SymTensor moment = sourceMoment; - for( localIndex q=0; q< numNodesPerElem; ++q ) - { - real64 inc[3] = { 0, 0, 0 }; - sourceNodeIds[isrc][q] = elemsToNodes( k, q ); - inc[0] += sourceForce[0] * N[q]; - inc[1] += sourceForce[1] * N[q]; - inc[2] += sourceForce[2] * N[q]; - - LvArray::tensorOps::Ri_add_symAijBj< 3 >( inc, moment.data, gradN[q] ); - sourceConstantsx[isrc][q] += inc[0]; - sourceConstantsy[isrc][q] += inc[1]; - sourceConstantsz[isrc][q] += inc[2]; - } - - for( localIndex cycle = 0; cycle < sourceValue.size( 0 ); ++cycle ) - { - sourceValue[cycle][isrc] = WaveSolverUtils::evaluateRicker( cycle * dt, timeSourceFrequency, timeSourceDelay, rickerOrder ); - } - - } - } - } // end loop over all sources - - // Step 2: locate the receivers, and precompute the receiver term - - // for geophones, we need only a point per receiver. - // for DAS, we need multiple points - - /// compute locations of samples along receiver - if( nSamples == 1 ) - { - samplePointLocations[ 0 ] = 0; - } - else - { - for( integer i = 0; i < nSamples; ++i ) - { - samplePointLocations[ i ] = -0.5 + (real64) i / ( linearDASSamples - 1 ); - } - } - - /// compute integration constants of samples - /// for displacement difference (dipole) DAS, take the discrete derivative of the pair of geophones - if( useDAS == WaveSolverUtils::DASType::dipole ) - { - sampleIntegrationConstants[ 0 ] = -1.0; - sampleIntegrationConstants[ 1 ] = 1.0; - } - /// for strain integration DAS, take the average of strains to average strain data - else if( nSamples == 1 ) - { - sampleIntegrationConstants[ 0 ] = 1.0; - } - else - { - for( integer i = 0; i < linearDASSamples; i++ ) - { - sampleIntegrationConstants[ i ] = 1.0 / nSamples; - } - } - - /// loop over all the receivers - for( localIndex ircv = 0; ircv < receiverCoordinates.size( 0 ); ++ircv ) - { - R1Tensor receiverCenter = { receiverCoordinates[ ircv ][ 0 ], receiverCoordinates[ ircv ][ 1 ], receiverCoordinates[ ircv ][ 2 ] }; - R1Tensor receiverVector; - if( useDAS == WaveSolverUtils::DASType::none ) - { - receiverVector = { 0, 0, 0 }; - } - else - { - receiverVector = WaveSolverUtils::computeDASVector( linearDASGeometry[ ircv ][ 0 ], linearDASGeometry[ ircv ][ 1 ] ); - } - real64 receiverLength = useDAS == WaveSolverUtils::DASType::none ? 0 : linearDASGeometry[ ircv ][ 2 ]; - /// loop over samples - for( integer iSample = 0; iSample < nSamples; ++iSample ) - { - /// compute sample coordinates and locate the element containing it - real64 const coords[3] = { receiverCenter[ 0 ] + receiverVector[ 0 ] * receiverLength * samplePointLocations[ iSample ], - receiverCenter[ 1 ] + receiverVector[ 1 ] * receiverLength * samplePointLocations[ iSample ], - receiverCenter[ 2 ] + receiverVector[ 2 ] * receiverLength * samplePointLocations[ iSample ] }; - bool const sampleFound = - WaveSolverUtils::locateSourceElement( numFacesPerElem, - center, - faceNormal, - faceCenter, - elemsToFaces[k], - coords ); - if( sampleFound && elemGhostRank[k] < 0 ) - { - real64 coordsOnRefElem[3]{}; - real64 xLocal[numNodesPerElem][3]; - - for( localIndex a=0; a< numNodesPerElem; ++a ) - { - for( localIndex i=0; i<3; ++i ) - { - xLocal[a][i] = nodeCoords( elemsToNodes( k, a ), i ); - } - } - - WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, - elemsToNodes[k], - nodeCoords, - coordsOnRefElem ); - real64 N[numNodesPerElem]; - real64 gradN[numNodesPerElem][3]; - FE_TYPE::calcN( coordsOnRefElem, N ); - FE_TYPE::calcGradN( coordsOnRefElem, xLocal, gradN ); - for( localIndex a = 0; a < numNodesPerElem; ++a ) - { - receiverNodeIds[ircv][iSample * numNodesPerElem + a] = elemsToNodes( k, - a ); - if( useDAS == WaveSolverUtils::DASType::strainIntegration ) - { - receiverConstants[ircv][iSample * numNodesPerElem + a] += ( gradN[a][0] * receiverVector[0] + gradN[a][1] * receiverVector[1] + gradN[a][2] * receiverVector[2] ) * - sampleIntegrationConstants[ iSample ]; - } - else - { - receiverConstants[ircv][iSample * numNodesPerElem + a] += N[a] * sampleIntegrationConstants[ iSample ]; - } - } - receiverIsLocal[ ircv ] = 2; - } - } // end loop over samples - // determine if the current rank is the owner of this receiver - real64 const coords[3] = { receiverCenter[ 0 ], receiverCenter[ 1 ], receiverCenter[ 2 ] }; - bool const receiverFound = - WaveSolverUtils::locateSourceElement( numFacesPerElem, - center, - faceNormal, - faceCenter, - elemsToFaces[k], - coords ); - if( receiverFound && elemGhostRank[k] < 0 ) - { - receiverIsLocal[ ircv ] = 1; - } - } // end loop over receivers - } ); - - } -}; - -template< typename FE_TYPE > -struct MassMatrixKernel -{ - - MassMatrixKernel( FE_TYPE const & finiteElement ) - : m_finiteElement( finiteElement ) - {} - - /** - * @brief Launches the precomputation of the mass matrices - * @tparam EXEC_POLICY the execution policy - * @tparam ATOMIC_POLICY the atomic policy - * @param[in] size the number of cells in the subRegion - * @param[in] numFacesPerElem number of faces per element - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemsToNodes map from element to nodes - * @param[in] velocity cell-wise velocity - * @param[out] mass diagonal of the mass matrix - */ - template< typename EXEC_POLICY, typename ATOMIC_POLICY > - //std::enable_if_t< geos::is_sem_formulation< std::remove_cv_t< FE_TYPE_ > >::value, void > - void - launch( localIndex const size, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes, - arrayView1d< real32 const > const density, - arrayView1d< real32 > const mass ) - - { - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const e ) - { - - // only the eight corners of the mesh cell are needed to compute the Jacobian - real64 xLocal[ 8 ][ 3 ]; - for( localIndex a = 0; a < 8; ++a ) - { - localIndex const nodeIndex = elemsToNodes( e, FE_TYPE::meshIndexToLinearIndex3D( a ) ); - for( localIndex i = 0; i < 3; ++i ) - { - xLocal[a][i] = nodeCoords( nodeIndex, i ); - } - } - - constexpr localIndex numQuadraturePointsPerElem = FE_TYPE::numQuadraturePoints; - for( localIndex q = 0; q < numQuadraturePointsPerElem; ++q ) - { - real32 const localIncrement = density[e] * m_finiteElement.computeMassTerm( q, xLocal ); - RAJA::atomicAdd< ATOMIC_POLICY >( &mass[elemsToNodes( e, q )], localIncrement ); - } - } ); // end loop over element - } - - /// The finite element space/discretization object for the element type in the subRegion - FE_TYPE const & m_finiteElement; - -}; - -template< typename FE_TYPE > -struct DampingMatrixKernel -{ - - DampingMatrixKernel( FE_TYPE const & finiteElement ) - : m_finiteElement( finiteElement ) - {} - - /** - * @brief Launches the precomputation of the damping matrices - * @tparam EXEC_POLICY the execution policy - * @tparam ATOMIC_POLICY the atomic policy - * @param[in] size the number of cells in the subRegion - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemsToFaces map from elements to faces - * @param[in] facesToNodes map from face to nodes - * @param[in] facesDomainBoundaryIndicator flag equal to 1 if the face is on the boundary, and to 0 otherwise - * @param[in] freeSurfaceFaceIndicator flag equal to 1 if the face is on the free surface, and to 0 otherwise - * @param[in] velocity cell-wise velocity - * @param[out] damping diagonal of the damping matrix - */ - template< typename EXEC_POLICY, typename ATOMIC_POLICY > - //std::enable_if_t< geos::is_sem_formulation< std::remove_cv_t< FE_TYPE_ > >::value, void > - void - launch( localIndex const size, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - arrayView2d< localIndex const > const elemsToFaces, - ArrayOfArraysView< localIndex const > const facesToNodes, - arrayView1d< integer const > const facesDomainBoundaryIndicator, - arrayView1d< localIndex const > const freeSurfaceFaceIndicator, - arrayView2d< real64 const > const faceNormal, - arrayView1d< real32 const > const density, - arrayView1d< real32 const > const velocityVp, - arrayView1d< real32 const > const velocityVs, - arrayView1d< real32 > const dampingx, - arrayView1d< real32 > const dampingy, - arrayView1d< real32 > const dampingz ) - { - forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const e ) - { - for( localIndex i = 0; i < elemsToFaces.size( 1 ); ++i ) - { - localIndex const f = elemsToFaces( e, i ); - // face on the domain boundary and not on free surface - if( facesDomainBoundaryIndicator[f] == 1 && freeSurfaceFaceIndicator[f] != 1 ) - { - // only the four corners of the mesh face are needed to compute the Jacobian - real64 xLocal[ 4 ][ 3 ]; - for( localIndex a = 0; a < 4; ++a ) - { - localIndex const nodeIndex = facesToNodes( f, FE_TYPE::meshIndexToLinearIndex2D( a ) ); - for( localIndex d = 0; d < 3; ++d ) - { - xLocal[a][d] = nodeCoords( nodeIndex, d ); - } - } - - real32 const nx = faceNormal( f, 0 ), ny = faceNormal( f, 1 ), nz = faceNormal( f, 2 ); - constexpr localIndex numNodesPerFace = FE_TYPE::numNodesPerFace; - for( localIndex q = 0; q < numNodesPerFace; ++q ) - { - real32 const aux = density[e] * m_finiteElement.computeDampingTerm( q, xLocal ); - real32 const localIncrementx = aux * ( velocityVp[e] * LvArray::math::abs( nx ) + velocityVs[e] * LvArray::math::sqrt( pow( ny, 2 ) + pow( nz, 2 ) ) ); - real32 const localIncrementy = aux * ( velocityVp[e] * LvArray::math::abs( ny ) + velocityVs[e] * LvArray::math::sqrt( pow( nx, 2 ) + pow( nz, 2 ) ) ); - real32 const localIncrementz = aux * ( velocityVp[e] * LvArray::math::abs( nz ) + velocityVs[e] * LvArray::math::sqrt( pow( nx, 2 ) + pow( ny, 2 ) ) ); - - RAJA::atomicAdd< ATOMIC_POLICY >( &dampingx[facesToNodes( f, q )], localIncrementx ); - RAJA::atomicAdd< ATOMIC_POLICY >( &dampingy[facesToNodes( f, q )], localIncrementy ); - RAJA::atomicAdd< ATOMIC_POLICY >( &dampingz[facesToNodes( f, q )], localIncrementz ); - } - } - } - } ); - } - - /// The finite element space/discretization object for the element type in the subRegion - FE_TYPE const & m_finiteElement; - -}; - -/** - * @brief Implements kernels for solving the elastic wave equations - * explicit central FD method and SEM - * @copydoc geos::finiteElement::KernelBase - * @tparam SUBREGION_TYPE The type of subregion that the kernel will act on. - * - * ### ElasticWaveEquationSEMKernel Description - * Implements the KernelBase interface functions required for solving - * the acoustic wave equations using the - * "finite element kernel application" functions such as - * geos::finiteElement::RegionBasedKernelApplication. - * - * The number of degrees of freedom per support point for both - * the test and trial spaces are specified as `1`. - */ - - -template< typename SUBREGION_TYPE, - typename CONSTITUTIVE_TYPE, - typename FE_TYPE > -class ExplicitElasticSEM : public finiteElement::KernelBase< SUBREGION_TYPE, - CONSTITUTIVE_TYPE, - FE_TYPE, - 1, - 1 > -{ -public: - - /// Alias for the base class; - using Base = finiteElement::KernelBase< SUBREGION_TYPE, - CONSTITUTIVE_TYPE, - FE_TYPE, - 1, - 1 >; - - /// Number of nodes per element...which is equal to the - /// numTestSupportPointPerElem and numTrialSupportPointPerElem by definition. - static constexpr int numNodesPerElem = Base::maxNumTestSupportPointsPerElem; - - using Base::numDofPerTestSupportPoint; - using Base::numDofPerTrialSupportPoint; - using Base::m_elemsToNodes; - using Base::m_elemGhostRank; - using Base::m_constitutiveUpdate; - using Base::m_finiteElementSpace; - -//***************************************************************************** - /** - * @brief Constructor - * @copydoc geos::finiteElement::KernelBase::KernelBase - * @param nodeManager Reference to the NodeManager object. - * @param edgeManager Reference to the EdgeManager object. - * @param faceManager Reference to the FaceManager object. - * @param targetRegionIndex Index of the region the subregion belongs to. - * @param dt The time interval for the step. - */ - ExplicitElasticSEM( NodeManager & nodeManager, - EdgeManager const & edgeManager, - FaceManager const & faceManager, - localIndex const targetRegionIndex, - SUBREGION_TYPE const & elementSubRegion, - FE_TYPE const & finiteElementSpace, - CONSTITUTIVE_TYPE & inputConstitutiveType, - real64 const dt ): - Base( elementSubRegion, - finiteElementSpace, - inputConstitutiveType ), - m_nodeCoords( nodeManager.getField< fields::referencePosition32 >() ), - m_ux_n( nodeManager.getField< elasticfields::Displacementx_n >() ), - m_uy_n( nodeManager.getField< elasticfields::Displacementy_n >() ), - m_uz_n( nodeManager.getField< elasticfields::Displacementz_n >() ), - m_stiffnessVectorx( nodeManager.getField< elasticfields::StiffnessVectorx >() ), - m_stiffnessVectory( nodeManager.getField< elasticfields::StiffnessVectory >() ), - m_stiffnessVectorz( nodeManager.getField< elasticfields::StiffnessVectorz >() ), - m_density( elementSubRegion.template getField< elasticfields::ElasticDensity >() ), - m_velocityVp( elementSubRegion.template getField< elasticfields::ElasticVelocityVp >() ), - m_velocityVs( elementSubRegion.template getField< elasticfields::ElasticVelocityVs >() ), - m_dt( dt ) - { - GEOS_UNUSED_VAR( edgeManager ); - GEOS_UNUSED_VAR( faceManager ); - GEOS_UNUSED_VAR( targetRegionIndex ); - } - - - - //***************************************************************************** - /** - * @copydoc geos::finiteElement::KernelBase::StackVariables - * - * ### ExplicitElasticSEM Description - * Adds a stack arrays for the nodal force, primary displacement variable, etc. - */ - struct StackVariables : Base::StackVariables - { -public: - GEOS_HOST_DEVICE - StackVariables(): - xLocal(), - stiffnessVectorxLocal(), - stiffnessVectoryLocal(), - stiffnessVectorzLocal() - {} - /// C-array stack storage for element local the nodal positions. - real64 xLocal[ 8 ][ 3 ]{}; - real32 stiffnessVectorxLocal[ numNodesPerElem ]; - real32 stiffnessVectoryLocal[ numNodesPerElem ]; - real32 stiffnessVectorzLocal[ numNodesPerElem ]; - real32 mu=0; - real32 lambda=0; - }; - //*************************************************************************** - - - /** - * @copydoc geos::finiteElement::KernelBase::setup - * - * Copies the primary variable, and position into the local stack array. - */ - GEOS_HOST_DEVICE - inline - void setup( localIndex const k, - StackVariables & stack ) const - { - for( localIndex a=0; a< 8; a++ ) - { - localIndex const nodeIndex = m_elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); - for( int i=0; i< 3; ++i ) - { - stack.xLocal[ a ][ i ] = m_nodeCoords[ nodeIndex ][ i ]; - } - } - stack.mu = m_density[k] * pow( m_velocityVs[k], 2 ); - stack.lambda = m_density[k] * pow( m_velocityVp[k], 2 ) - 2.0 * stack.mu; - } - - /** - * @copydoc geos::finiteElement::KernelBase::complete - */ - GEOS_HOST_DEVICE - GEOS_FORCE_INLINE - real64 complete( localIndex const k, - StackVariables & stack ) const - { - for( int i=0; i( &m_stiffnessVectorx[ nodeIndex ], stack.stiffnessVectorxLocal[ i ] ); - RAJA::atomicAdd< parallelDeviceAtomic >( &m_stiffnessVectory[ nodeIndex ], stack.stiffnessVectoryLocal[ i ] ); - RAJA::atomicAdd< parallelDeviceAtomic >( &m_stiffnessVectorz[ nodeIndex ], stack.stiffnessVectorzLocal[ i ] ); - } - return 0; - } - - /** - * @copydoc geos::finiteElement::KernelBase::quadraturePointKernel - * - * ### ExplicitElasticSEM Description - * Calculates stiffness vector - * - */ - GEOS_HOST_DEVICE - GEOS_FORCE_INLINE - void quadraturePointKernel( localIndex const k, - localIndex const q, - StackVariables & stack ) const - { - - m_finiteElementSpace.template computeFirstOrderStiffnessTerm( q, stack.xLocal, [&] ( int i, int j, real64 val, real64 J[3][3], int p, int r ) - { - real32 const Rxx_ij = val*((stack.lambda+2.0*stack.mu)*J[p][0]*J[r][0]+stack.mu*(J[p][1]*J[r][1]+J[p][2]*J[r][2])); - real32 const Ryy_ij = val*((stack.lambda+2.0*stack.mu)*J[p][1]*J[r][1]+stack.mu*(J[p][0]*J[r][0]+J[p][2]*J[r][2])); - real32 const Rzz_ij = val*((stack.lambda+2.0*stack.mu)*J[p][2]*J[r][2]+stack.mu*(J[p][0]*J[r][0]+J[p][1]*J[r][1])); - real32 const Rxy_ij = val*(stack.lambda*J[p][0]*J[r][1]+stack.mu*J[p][1]*J[r][0]); - real32 const Ryx_ij = val*(stack.mu*J[p][0]*J[r][1]+stack.lambda*J[p][1]*J[r][0]); - real32 const Rxz_ij = val*(stack.lambda*J[p][0]*J[r][2]+stack.mu*J[p][2]*J[r][0]); - real32 const Rzx_ij = val*(stack.mu*J[p][0]*J[r][2]+stack.lambda*J[p][2]*J[r][0]); - real32 const Ryz_ij = val*(stack.lambda*J[p][1]*J[r][2]+stack.mu*J[p][2]*J[r][1]); - real32 const Rzy_ij = val*(stack.mu*J[p][1]*J[r][2]+stack.lambda*J[p][2]*J[r][1]); - - real32 const localIncrementx = (Rxx_ij * m_ux_n[m_elemsToNodes( k, j )] + Rxy_ij*m_uy_n[m_elemsToNodes( k, j )] + Rxz_ij*m_uz_n[m_elemsToNodes( k, j )]); - real32 const localIncrementy = (Ryx_ij * m_ux_n[m_elemsToNodes( k, j )] + Ryy_ij*m_uy_n[m_elemsToNodes( k, j )] + Ryz_ij*m_uz_n[m_elemsToNodes( k, j )]); - real32 const localIncrementz = (Rzx_ij * m_ux_n[m_elemsToNodes( k, j )] + Rzy_ij*m_uy_n[m_elemsToNodes( k, j )] + Rzz_ij*m_uz_n[m_elemsToNodes( k, j )]); - - stack.stiffnessVectorxLocal[ i ] += localIncrementx; - stack.stiffnessVectoryLocal[ i ] += localIncrementy; - stack.stiffnessVectorzLocal[ i ] += localIncrementz; - } ); - } - - -protected: - /// The array containing the nodal position array. - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const m_nodeCoords; - - /// The array containing the nodal displacement array in x direction. - arrayView1d< real32 > const m_ux_n; - - /// The array containing the nodal displacement array in y direction. - arrayView1d< real32 > const m_uy_n; - - /// The array containing the nodal displacement array in z direction. - arrayView1d< real32 > const m_uz_n; - - /// The array containing the product of the stiffness matrix and the nodal displacement. - arrayView1d< real32 > const m_stiffnessVectorx; - - /// The array containing the product of the stiffness matrix and the nodal displacement. - arrayView1d< real32 > const m_stiffnessVectory; - - /// The array containing the product of the stiffness matrix and the nodal displacement. - arrayView1d< real32 > const m_stiffnessVectorz; - - /// The array containing the density of the medium - arrayView1d< real32 const > const m_density; - - /// The array containing the P-wavespeed - arrayView1d< real32 const > const m_velocityVp; - - /// The array containing the S-wavespeed - arrayView1d< real32 const > const m_velocityVs; - - /// The time increment for this time integration step. - real64 const m_dt; - - -}; - - -/// The factory used to construct a ExplicitAcousticWaveEquation kernel. -using ExplicitElasticSEMFactory = finiteElement::KernelFactory< ExplicitElasticSEM, - real64 >; - -} // namespace ElasticWaveEquationSEMKernels - -} // namespace geos - -#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICWAVEEQUATIONSEMKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/WaveSolverUtils.hpp b/src/coreComponents/physicsSolvers/wavePropagation/WaveSolverUtils.hpp deleted file mode 100644 index 5b9e91dbcb8..00000000000 --- a/src/coreComponents/physicsSolvers/wavePropagation/WaveSolverUtils.hpp +++ /dev/null @@ -1,376 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - - -/** - * @file WaveSolverUtils.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_WAVESOLVERUTILS_HPP_ -#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_WAVESOLVERUTILS_HPP_ - -#include "mesh/utilities/ComputationalGeometry.hpp" -#include "fileIO/Outputs/OutputBase.hpp" -#include "LvArray/src/tensorOps.hpp" - -namespace geos -{ - -struct WaveSolverUtils -{ - static constexpr real64 epsilonLoc = 1e-8; - - using EXEC_POLICY = parallelDevicePolicy< >; - using wsCoordType = real32; - - enum class DASType : integer - { - none, ///< deactivate DAS computation - dipole, ///< use dipole formulation for DAS - strainIntegration, ///< use strain integration for DAS - }; - - GEOS_HOST_DEVICE - static real32 evaluateRicker( real64 const time_n, real32 const f0, real32 const t0, localIndex const order ) - { - real32 const delay = t0 > 0 ? t0 : 1 / f0; - real32 pulse = 0.0; - if( time_n <= -0.9 * delay || time_n >= 2.9 * delay ) - { - return pulse; - } - - real32 const alpha = -pow( f0 * M_PI, 2 ); - real32 const time_d = time_n - delay; - real32 const gaussian = exp( alpha * pow( time_d, 2 )); - localIndex const sgn = pow( -1, order + 1 ); - - switch( order ) - { - case 0: - pulse = sgn * gaussian; - break; - case 1: - pulse = sgn * (2 * alpha * time_d) * gaussian; - break; - case 2: - pulse = sgn * (2 * alpha + 4 * pow( alpha, 2 ) * pow( time_d, 2 )) * gaussian; - break; - case 3: - pulse = sgn * (12 * pow( alpha, 2 ) * time_d + 8 * pow( alpha, 3 ) * pow( time_d, 3 )) * gaussian; - break; - case 4: - pulse = sgn * (12 * pow( alpha, 2 ) + 48 * pow( alpha, 3 ) * pow( time_d, 2 ) + 16 * pow( alpha, 4 ) * pow( time_d, 4 )) * gaussian; - break; - default: - GEOS_ERROR( "This option is not supported yet, rickerOrder must be in range {0:4}" ); - } - - return pulse; - } - - /** - * @brief Initialize (clear) the trace file. - */ - static void initTrace( char const * prefix, - string const & name, - bool const outputSeismoTrace, - localIndex const nReceivers, - arrayView1d< localIndex const > const receiverIsLocal ) - { - if( !outputSeismoTrace ) return; - - string const outputDir = OutputBase::getOutputDirectory(); - RAJA::ReduceSum< ReducePolicy< serialPolicy >, localIndex > count( 0 ); - - forAll< serialPolicy >( nReceivers, [=] ( localIndex const ircv ) - { - if( receiverIsLocal[ircv] == 1 ) - { - count += 1; - string const fn = joinPath( outputDir, GEOS_FMT( "{}_{}_{:03}.txt", prefix, name, ircv ) ); - std::ofstream f( fn, std::ios::out | std::ios::trunc ); - } - } ); - - localIndex const total = MpiWrapper::sum( count.get() ); - GEOS_ERROR_IF( nReceivers != total, GEOS_FMT( ": Invalid distribution of receivers: nReceivers={} != MPI::sum={}.", nReceivers, total ) ); - } - - /** - * @brief Convenient helper for 3D vectors calling 3 times the scalar version with only the sampled variable argument changed. - */ - static void writeSeismoTraceVector( char const * prefix, - string const & name, - bool const outputSeismoTrace, - localIndex const nReceivers, - arrayView1d< localIndex const > const receiverIsLocal, - localIndex const nsamplesSeismoTrace, - arrayView2d< real32 const > const varAtReceiversx, - arrayView2d< real32 const > const varAtReceiversy, - arrayView2d< real32 const > const varAtReceiversz ) - { - writeSeismoTrace( prefix, name, outputSeismoTrace, nReceivers, receiverIsLocal, nsamplesSeismoTrace, varAtReceiversx ); - writeSeismoTrace( prefix, name, outputSeismoTrace, nReceivers, receiverIsLocal, nsamplesSeismoTrace, varAtReceiversy ); - writeSeismoTrace( prefix, name, outputSeismoTrace, nReceivers, receiverIsLocal, nsamplesSeismoTrace, varAtReceiversz ); - } - - /** - * @brief Write the seismo traces to a file. - */ - static void writeSeismoTrace( char const * prefix, - string const & name, - bool const outputSeismoTrace, - localIndex const nReceivers, - arrayView1d< localIndex const > const receiverIsLocal, - localIndex const nsamplesSeismoTrace, - arrayView2d< real32 const > const varAtReceivers ) - { - if( !outputSeismoTrace ) return; - - string const outputDir = OutputBase::getOutputDirectory(); - forAll< serialPolicy >( nReceivers, [=] ( localIndex const ircv ) - { - if( receiverIsLocal[ircv] == 1 ) - { - string const fn = joinPath( outputDir, GEOS_FMT( "{}_{}_{:03}.txt", prefix, name, ircv ) ); - std::ofstream f( fn, std::ios::app ); - if( f ) - { - GEOS_LOG_RANK( GEOS_FMT( "Append to seismo trace file {}", fn ) ); - for( localIndex iSample = 0; iSample < nsamplesSeismoTrace; ++iSample ) - { - // index - time - value - f << iSample << " " << varAtReceivers[iSample][nReceivers] << " " << varAtReceivers[iSample][ircv] << std::endl; - } - f.close(); - } - else - { - GEOS_WARNING( GEOS_FMT( "Failed to open output file {}", fn ) ); - } - } - } ); - } - - /** - * @brief Compute the seismo traces. - */ - static void computeSeismoTrace( real64 const time_n, - real64 const dt, - real64 const timeSeismo, - localIndex const iSeismo, - arrayView2d< localIndex const > const receiverNodeIds, - arrayView2d< real64 const > const receiverConstants, - arrayView1d< localIndex const > const receiverIsLocal, - arrayView1d< real32 const > const var_np1, - arrayView1d< real32 const > const var_n, - arrayView2d< real32 > varAtReceivers, - arrayView1d< real32 > coeffs = {}, - bool add = false ) - { - real64 const time_np1 = time_n + dt; - - real32 const a1 = LvArray::math::abs( dt ) < epsilonLoc ? 1.0 : (time_np1 - timeSeismo) / dt; - real32 const a2 = 1.0 - a1; - - localIndex const nReceivers = receiverConstants.size( 0 ); - forAll< EXEC_POLICY >( nReceivers, [=] GEOS_HOST_DEVICE ( localIndex const ircv ) - { - if( receiverIsLocal[ircv] > 0 ) - { - real32 vtmp_np1 = 0.0, vtmp_n = 0.0; - for( localIndex inode = 0; inode < receiverConstants.size( 1 ); ++inode ) - { - if( receiverNodeIds( ircv, inode ) >= 0 ) - { - vtmp_np1 += var_np1[receiverNodeIds( ircv, inode )] * receiverConstants( ircv, inode ); - vtmp_n += var_n[receiverNodeIds( ircv, inode )] * receiverConstants( ircv, inode ); - } - } - // linear interpolation between the pressure value at time_n and time_{n+1} - real32 rcvCoeff = coeffs.size( 0 ) == 0 ? 1.0 : coeffs( ircv ); - if( add ) - { - varAtReceivers( iSeismo, ircv ) += rcvCoeff * ( a1 * vtmp_n + a2 * vtmp_np1 ); - } - else - { - varAtReceivers( iSeismo, ircv ) = rcvCoeff * ( a1 * vtmp_n + a2 * vtmp_np1 ); - } - // NOTE: varAtReceivers has size(1) = numReceiversGlobal + 1, this does not OOB - // left in the forAll loop for sync issues since the following does not depend on `ircv` - varAtReceivers( iSeismo, nReceivers ) = a1 * time_n + a2 * time_np1; - } - } ); - } - - static void compute2dVariableSeismoTrace( real64 const time_n, - real64 const dt, - localIndex const regionIndex, - arrayView1d< localIndex const > const receiverRegion, - real64 const timeSeismo, - localIndex const iSeismo, - arrayView1d< localIndex const > const rcvElem, - arrayView2d< real64 const > const receiverConstants, - arrayView1d< localIndex const > const receiverIsLocal, - arrayView2d< real32 const > const var_np1, - arrayView2d< real32 const > const var_n, - arrayView2d< real32 > varAtReceivers ) - { - real64 const time_np1 = time_n + dt; - - real32 const a1 = dt < epsilonLoc ? 1.0 : (time_np1 - timeSeismo) / dt; - real32 const a2 = 1.0 - a1; - - localIndex const nReceivers = receiverConstants.size( 0 ); - - forAll< EXEC_POLICY >( nReceivers, [=] GEOS_HOST_DEVICE ( localIndex const ircv ) - { - if( receiverIsLocal[ircv] == 1 ) - { - if( receiverRegion[ircv] == regionIndex ) - { - real32 vtmp_np1 = 0.0, vtmp_n = 0.0; - for( localIndex inode = 0; inode < receiverConstants.size( 1 ); ++inode ) - { - vtmp_np1 += var_np1( rcvElem[ircv], inode ) * receiverConstants( ircv, inode ); - vtmp_n += var_n( rcvElem[ircv], inode ) * receiverConstants( ircv, inode ); - } - // linear interpolation between the pressure value at time_n and time_{n+1} - varAtReceivers( iSeismo, ircv ) = a1 * vtmp_n + a2 * vtmp_np1; - // NOTE: varAtReceivers has size(1) = numReceiversGlobal + 1, this does not OOB - // left in the forAll loop for sync issues since the following does not depend on `ircv` - varAtReceivers( iSeismo, nReceivers ) = a1 * time_n + a2 * time_np1; - } - } - } ); - } - - /** - * @brief Check if the source point is inside an element or not - * @param numFacesPerElem number of face on an element - * @param elemCenter array containing the center of the elements - * @param faceNormal array containing the normal of all faces - * @param faceCenter array containing the center of all faces - * @param elemsToFaces map to get the global faces from element index and local face index - * @param coords coordinate of the point - * @return true if coords is inside the element - */ - GEOS_HOST_DEVICE - static bool - locateSourceElement( real64 const numFacesPerElem, - real64 const (&elemCenter)[3], - arrayView2d< real64 const > const faceNormal, - arrayView2d< real64 const > const faceCenter, - arraySlice1d< localIndex const > const elemsToFaces, - real64 const (&coords)[3] ) - { - //Loop over the element faces - real64 tmpVector[3]{}; - for( localIndex kfe = 0; kfe < numFacesPerElem; ++kfe ) - { - - localIndex const iface = elemsToFaces[kfe]; - real64 faceCenterOnFace[3] = {faceCenter[iface][0], - faceCenter[iface][1], - faceCenter[iface][2]}; - real64 faceNormalOnFace[3] = {faceNormal[iface][0], - faceNormal[iface][1], - faceNormal[iface][2]}; - - //Test to make sure if the normal is outwardly directed - LvArray::tensorOps::copy< 3 >( tmpVector, faceCenterOnFace ); - LvArray::tensorOps::subtract< 3 >( tmpVector, elemCenter ); - if( LvArray::tensorOps::AiBi< 3 >( tmpVector, faceNormalOnFace ) < 0.0 ) - { - LvArray::tensorOps::scale< 3 >( faceNormalOnFace, -1 ); - } - - // compute the vector face center to query point - LvArray::tensorOps::subtract< 3 >( faceCenterOnFace, coords ); - localIndex const s = computationalGeometry::sign( LvArray::tensorOps::AiBi< 3 >( faceNormalOnFace, faceCenterOnFace )); - - // all dot products should be non-negative (we enforce outward normals) - if( s < 0 ) return false; - - } - return true; - } - - /** - * @brief Convert a mesh element point coordinate into a coordinate on the reference element - * @tparam FE_TYPE finite element type - * @param[in] coords coordinate of the point - * @param[in] elemsToNodes map to obtaint global nodes from element index - * @param[in] nodeCoords array of mesh nodes coordinates - * @param[out] coordsOnRefElem to contain the coordinate computed in the reference element - */ - template< typename FE_TYPE > - GEOS_HOST_DEVICE - static void - computeCoordinatesOnReferenceElement( real64 const (&coords)[3], - arraySlice1d< localIndex const, cells::NODE_MAP_USD - 1 > const elemsToNodes, - arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, - real64 (& coordsOnRefElem)[3] ) - { - // only the eight corners of the mesh cell are needed to compute the Jacobian - real64 xLocal[8][3]{}; - for( localIndex a = 0; a < 8; ++a ) - { - LvArray::tensorOps::copy< 3 >( xLocal[a], nodeCoords[ elemsToNodes[ FE_TYPE::meshIndexToLinearIndex3D( a )] ] ); - } - // coordsOnRefElem = invJ*(coords-coordsNode_0) - real64 invJ[3][3]{}; - FE_TYPE::invJacobianTransformation( 0, xLocal, invJ ); - for( localIndex i = 0; i < 3; ++i ) - { - // init at (-1,-1,-1) as the origin of the referential elem - coordsOnRefElem[i] = -1.0; - for( localIndex j = 0; j < 3; ++j ) - { - coordsOnRefElem[i] += invJ[i][j] * (coords[j] - xLocal[0][j]); - } - } - } - -/** - * @brief Converts the DAS direction from dip/azimuth to a 3D unit vector - * @param[in] dip the dip of the linear DAS - * @param[in] azimuth the azimuth of the linear DAS - * @param[out] a unit vector pointing in the DAS direction - */ - GEOS_HOST_DEVICE - static - R1Tensor computeDASVector( real64 const dip, real64 const azimuth ) - { - real64 cd = cos( dip ); - real64 v1 = cd * cos( azimuth ); - real64 v2 = cd * sin( azimuth ); - real64 v3 = sin( dip ); - R1Tensor dasVector = { v1, v2, v3 }; - return dasVector; - } - -}; - -/// Declare strings associated with enumeration values. -ENUM_STRINGS( WaveSolverUtils::DASType, - "none", - "dipole", - "strainIntegration" ); - -} /* namespace geos */ - -#endif /* GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_WAVESOLVERUTILS_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/AcousticFirstOrderWaveEquationSEM.cpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/firstOrderEqn/isotropic/AcousticFirstOrderWaveEquationSEM.cpp similarity index 79% rename from src/coreComponents/physicsSolvers/wavePropagation/AcousticFirstOrderWaveEquationSEM.cpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/firstOrderEqn/isotropic/AcousticFirstOrderWaveEquationSEM.cpp index 1ede25c9b42..506c95a3d5d 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/AcousticFirstOrderWaveEquationSEM.cpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/firstOrderEqn/isotropic/AcousticFirstOrderWaveEquationSEM.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -25,7 +26,11 @@ #include "fieldSpecification/FieldSpecificationManager.hpp" #include "mainInterface/ProblemManager.hpp" #include "mesh/ElementType.hpp" +#include "mesh/DomainPartition.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" +#include "physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticMatricesSEMKernel.hpp" +#include "physicsSolvers/wavePropagation/shared/PrecomputeSourcesAndReceiversKernel.hpp" +#include "events/EventManager.hpp" namespace geos { @@ -133,9 +138,9 @@ void AcousticFirstOrderWaveEquationSEM::registerDataOnMesh( Group & meshBodies ) } -void AcousticFirstOrderWaveEquationSEM::postProcessInput() +void AcousticFirstOrderWaveEquationSEM::postInputInitialization() { - WaveSolverBase::postProcessInput(); + WaveSolverBase::postInputInitialization(); localIndex const numSourcesGlobal = m_sourceCoordinates.size( 0 ); localIndex const numReceiversGlobal = m_receiverCoordinates.size( 0 ); @@ -145,19 +150,18 @@ void AcousticFirstOrderWaveEquationSEM::postProcessInput() m_uzNp1AtReceivers.resize( m_nsamplesSeismoTrace, numReceiversGlobal + 1 ); m_sourceElem.resize( numSourcesGlobal ); m_sourceRegion.resize( numSourcesGlobal ); - m_rcvElem.resize( numReceiversGlobal ); + m_receiverElem.resize( numReceiversGlobal ); m_receiverRegion.resize( numReceiversGlobal ); } -void AcousticFirstOrderWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) +void AcousticFirstOrderWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & baseMesh, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) { - NodeManager const & nodeManager = mesh.getNodeManager(); - FaceManager const & faceManager = mesh.getFaceManager(); + GEOS_MARK_FUNCTION; - arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const - X = nodeManager.getField< fields::referencePosition32 >().toViewConst(); - arrayView2d< real64 const > const faceNormal = faceManager.faceNormal(); - arrayView2d< real64 const > const faceCenter = faceManager.faceCenter(); + arrayView1d< globalIndex const > const nodeLocalToGlobal = baseMesh.getNodeManager().localToGlobalMap().toViewConst(); + ArrayOfArraysView< localIndex const > const nodesToElements = baseMesh.getNodeManager().elementList().toViewConst(); + ArrayOfArraysView< localIndex const > const facesToNodes = baseMesh.getFaceManager().nodeList().toViewConst(); + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const nodeCoords = baseMesh.getNodeManager().referencePosition(); arrayView2d< real64 const > const sourceCoordinates = m_sourceCoordinates.toViewConst(); arrayView2d< localIndex > const sourceNodeIds = m_sourceNodeIds.toView(); @@ -173,26 +177,17 @@ void AcousticFirstOrderWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLev arrayView2d< localIndex > const receiverNodeIds = m_receiverNodeIds.toView(); arrayView2d< real64 > const receiverConstants = m_receiverConstants.toView(); arrayView1d< localIndex > const receiverIsLocal = m_receiverIsLocal.toView(); - arrayView1d< localIndex > const rcvElem = m_rcvElem.toView(); + arrayView1d< localIndex > const receiverElem = m_receiverElem.toView(); arrayView1d< localIndex > const receiverRegion = m_receiverRegion.toView(); receiverNodeIds.setValues< EXEC_POLICY >( -1 ); receiverConstants.setValues< EXEC_POLICY >( -1 ); receiverIsLocal.zero(); - arrayView2d< real32 > const sourceValue = m_sourceValue.toView(); - real64 dt = 0; - EventManager const & event = getGroupByPath< EventManager >( "/Problem/Events" ); - for( localIndex numSubEvent = 0; numSubEvent < event.numSubGroups(); ++numSubEvent ) - { - EventBase const * subEvent = static_cast< EventBase const * >( event.getSubGroups()[numSubEvent] ); - if( subEvent->getEventName() == "/Solvers/" + getName() ) - { - dt = subEvent->getReference< real64 >( EventBase::viewKeyStruct::forceDtString() ); - } - } - - mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const regionIndex, - CellElementSubRegion & elementSubRegion ) + mesh.getElemManager().forElementSubRegionsComplete< CellElementSubRegion >( regionNames, [&]( localIndex const, + localIndex const regionIndex, + localIndex const esr, + ElementRegionBase &, + CellElementSubRegion & elementSubRegion ) { GEOS_THROW_IF( elementSubRegion.getElementType() != ElementType::Hexahedron, getDataContext() << ": Invalid type of element, the acoustic solver is designed for hexahedral meshes only (C3D8) ", @@ -200,8 +195,10 @@ void AcousticFirstOrderWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLev arrayView2d< localIndex const > const elemsToFaces = elementSubRegion.faceList(); arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes = elementSubRegion.nodeList(); + arrayView2d< localIndex const, cells::NODE_MAP_USD > const & baseElemsToNodes = baseMesh.getElemManager().getRegion( regionIndex ).getSubRegion< CellElementSubRegion >( esr ).nodeList(); arrayView2d< real64 const > const elemCenter = elementSubRegion.getElementCenter(); arrayView1d< integer const > const elemGhostRank = elementSubRegion.ghostRank(); + arrayView1d< globalIndex const > const elemLocalToGlobal = elementSubRegion.localToGlobalMap().toViewConst(); finiteElement::FiniteElementBase const & fe = elementSubRegion.getReference< finiteElement::FiniteElementBase >( getDiscretizationName() ); @@ -209,21 +206,21 @@ void AcousticFirstOrderWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLev { using FE_TYPE = TYPEOFREF( finiteElement ); - localIndex const numFacesPerElem = elementSubRegion.numFacesPerElement(); - - acousticFirstOrderWaveEquationSEMKernels:: - PrecomputeSourceAndReceiverKernel:: - launch< EXEC_POLICY, FE_TYPE > + PreComputeSourcesAndReceivers:: + Compute1DSourceAndReceiverConstantsWithElementsAndRegionStorage + < EXEC_POLICY, FE_TYPE > ( elementSubRegion.size(), regionIndex, - numFacesPerElem, - X, + facesToNodes, + nodeCoords, + nodeLocalToGlobal, + elemLocalToGlobal, + nodesToElements, + baseElemsToNodes, elemGhostRank, elemsToNodes, elemsToFaces, elemCenter, - faceNormal, - faceCenter, sourceCoordinates, sourceIsAccessible, sourceElem, @@ -232,18 +229,23 @@ void AcousticFirstOrderWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLev sourceRegion, receiverCoordinates, receiverIsLocal, - rcvElem, + receiverElem, receiverNodeIds, receiverConstants, - receiverRegion, - sourceValue, - dt, - m_timeSourceFrequency, - m_timeSourceDelay, - m_rickerOrder ); + receiverRegion ); } ); + elementSubRegion.faceList().freeOnDevice(); + baseMesh.getElemManager().getRegion( regionIndex ).getSubRegion< CellElementSubRegion >( esr ).nodeList().freeOnDevice(); + elementSubRegion.getElementCenter().freeOnDevice(); + elementSubRegion.ghostRank().freeOnDevice(); + elementSubRegion.localToGlobalMap().freeOnDevice(); } ); - + baseMesh.getNodeManager().localToGlobalMap().freeOnDevice(); + baseMesh.getNodeManager().elementList().toView().freeOnDevice(); + baseMesh.getFaceManager().nodeList().toView().freeOnDevice(); + baseMesh.getNodeManager().referencePosition().freeOnDevice(); + facesToNodes.freeOnDevice(); + nodesToElements.freeOnDevice(); } void AcousticFirstOrderWaveEquationSEM::initializePostInitialConditionsPreSubGroups() @@ -254,18 +256,19 @@ void AcousticFirstOrderWaveEquationSEM::initializePostInitialConditionsPreSubGro applyFreeSurfaceBC( 0.0, domain ); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshBodyName, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) { - precomputeSourceAndReceiverTerm( mesh, regionNames ); + MeshLevel & baseMesh = domain.getMeshBodies().getGroup< MeshBody >( meshBodyName ).getBaseDiscretization(); + precomputeSourceAndReceiverTerm( baseMesh, mesh, regionNames ); NodeManager & nodeManager = mesh.getNodeManager(); FaceManager & faceManager = mesh.getFaceManager(); /// get the array of indicators: 1 if the face is on the boundary; 0 otherwise arrayView1d< integer const > const & facesDomainBoundaryIndicator = faceManager.getDomainBoundaryIndicator(); - arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const X = nodeManager.getField< fields::referencePosition32 >().toViewConst(); + arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords = nodeManager.getField< fields::referencePosition32 >().toViewConst(); /// get table containing face to nodes map ArrayOfArraysView< localIndex const > const facesToNodes = faceManager.nodeList().toViewConst(); @@ -295,25 +298,26 @@ void AcousticFirstOrderWaveEquationSEM::initializePostInitialConditionsPreSubGro { using FE_TYPE = TYPEOFREF( finiteElement ); - acousticFirstOrderWaveEquationSEMKernels::MassMatrixKernel< FE_TYPE > kernelM( finiteElement ); - - kernelM.template launch< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), - X, - elemsToNodes, - velocity, - density, - mass ); - - acousticFirstOrderWaveEquationSEMKernels::DampingMatrixKernel< FE_TYPE > kernelD( finiteElement ); - - kernelD.template launch< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), - X, - elemsToFaces, - facesToNodes, - facesDomainBoundaryIndicator, - freeSurfaceFaceIndicator, - velocity, - damping ); + AcousticMatricesSEM::MassMatrix< FE_TYPE > kernelM( finiteElement ); + kernelM.template computeMassMatrix< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), + nodeCoords, + elemsToNodes, + velocity, + density, + mass ); + + AcousticMatricesSEM::DampingMatrix< FE_TYPE > kernelD( finiteElement ); + kernelD.template computeDampingMatrix< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), + nodeCoords, + elemsToFaces, + facesToNodes, + facesDomainBoundaryIndicator, + freeSurfaceFaceIndicator, + velocity, + density, + damping ); + + } ); } ); } ); @@ -321,6 +325,12 @@ void AcousticFirstOrderWaveEquationSEM::initializePostInitialConditionsPreSubGro WaveSolverUtils::initTrace( "seismoTraceReceiver", getName(), m_outputSeismoTrace, m_receiverConstants.size( 0 ), m_receiverIsLocal ); } +real64 AcousticFirstOrderWaveEquationSEM::computeTimeStep( real64 & dtOut ) +{ + GEOS_ERROR( getDataContext() << ": Time-Step computation for the first order acoustic wave propagator not yet implemented" ); + return dtOut; +} + void AcousticFirstOrderWaveEquationSEM::applyFreeSurfaceBC( real64 const time, DomainPartition & domain ) { @@ -419,7 +429,6 @@ real64 AcousticFirstOrderWaveEquationSEM::explicitStepInternal( real64 const & t arrayView1d< localIndex const > const sourceIsAccessible = m_sourceIsAccessible.toView(); arrayView1d< localIndex const > const sourceElem = m_sourceElem.toView(); arrayView1d< localIndex const > const sourceRegion = m_sourceRegion.toView(); - arrayView2d< real32 const > const sourceValue = m_sourceValue.toView(); GEOS_LOG_RANK_0_IF( dt < epsilonLoc, "Warning! Value for dt: " << dt << "s is smaller than local threshold: " << epsilonLoc ); @@ -430,7 +439,7 @@ real64 AcousticFirstOrderWaveEquationSEM::explicitStepInternal( real64 const & t { NodeManager & nodeManager = mesh.getNodeManager(); - arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const X = nodeManager.getField< fields::referencePosition32 >().toViewConst(); + arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords = nodeManager.getField< fields::referencePosition32 >().toViewConst(); arrayView1d< real32 const > const mass = nodeManager.getField< acousticfields::AcousticMassVector >(); arrayView1d< real32 const > const damping = nodeManager.getField< acousticfields::DampingVector >(); @@ -453,13 +462,11 @@ real64 AcousticFirstOrderWaveEquationSEM::explicitStepInternal( real64 const & t { using FE_TYPE = TYPEOFREF( finiteElement ); - - acousticFirstOrderWaveEquationSEMKernels:: VelocityComputation< FE_TYPE > kernel( finiteElement ); kernel.template launch< EXEC_POLICY, ATOMIC_POLICY > ( elementSubRegion.size(), - X, + nodeCoords, elemsToNodes, p_np1, density, @@ -473,7 +480,7 @@ real64 AcousticFirstOrderWaveEquationSEM::explicitStepInternal( real64 const & t ( elementSubRegion.size(), regionIndex, nodeManager.size(), - X, + nodeCoords, elemsToNodes, velocity_x, velocity_y, @@ -481,12 +488,16 @@ real64 AcousticFirstOrderWaveEquationSEM::explicitStepInternal( real64 const & t mass, damping, sourceConstants, - sourceValue, sourceIsAccessible, sourceElem, sourceRegion, dt, - cycleNumber, + time_n, + m_timeSourceFrequency, + m_timeSourceDelay, + m_rickerOrder, + m_useSourceWaveletTables, + m_sourceWaveletTableWrappers, p_np1 ); } ); arrayView2d< real32 > const uxReceivers = m_uxNp1AtReceivers.toView(); @@ -565,6 +576,6 @@ void AcousticFirstOrderWaveEquationSEM::applyPML( real64 const, DomainPartition GEOS_ERROR( getDataContext() << ": PML for the first order acoustic wave propagator not yet implemented" ); } -REGISTER_CATALOG_ENTRY( SolverBase, AcousticFirstOrderWaveEquationSEM, string const &, dataRepository::Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, AcousticFirstOrderWaveEquationSEM, string const &, dataRepository::Group * const ) } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/AcousticFirstOrderWaveEquationSEM.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/firstOrderEqn/isotropic/AcousticFirstOrderWaveEquationSEM.hpp similarity index 87% rename from src/coreComponents/physicsSolvers/wavePropagation/AcousticFirstOrderWaveEquationSEM.hpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/firstOrderEqn/isotropic/AcousticFirstOrderWaveEquationSEM.hpp index 14a6dc502ae..173600e1b90 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/AcousticFirstOrderWaveEquationSEM.hpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/firstOrderEqn/isotropic/AcousticFirstOrderWaveEquationSEM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,8 +22,8 @@ #define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICFIRSTORDERWAVEEQUATIONSEM_HPP_ #include "mesh/MeshFields.hpp" -#include "AcousticFields.hpp" -#include "WaveSolverBase.hpp" +#include "physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticFields.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp" namespace geos { @@ -41,7 +42,7 @@ class AcousticFirstOrderWaveEquationSEM : public WaveSolverBase static string catalogName() { return "AcousticFirstOrderSEM"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -109,7 +110,7 @@ class AcousticFirstOrderWaveEquationSEM : public WaveSolverBase protected: - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; virtual void initializePostInitialConditionsPreSubGroups() override final; @@ -118,9 +119,10 @@ class AcousticFirstOrderWaveEquationSEM : public WaveSolverBase /** * @brief Locate sources and receivers position in the mesh elements, evaluate the basis functions at each point and save them to the * corresponding elements nodes. + * @param baseMesh the level-0 mesh * @param mesh mesh of the computational domain */ - virtual void precomputeSourceAndReceiverTerm( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) override; + virtual void precomputeSourceAndReceiverTerm( MeshLevel & baseMesh, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) override; /** * @brief Apply free surface condition to the face define in the geometry box from the xml @@ -136,6 +138,8 @@ class AcousticFirstOrderWaveEquationSEM : public WaveSolverBase */ virtual void applyPML( real64 const time, DomainPartition & domain ) override; + virtual real64 computeTimeStep( real64 & dtOut ) override; + /// Pressure_np1 at the receiver location for each time step for each receiver array2d< real32 > m_pressureNp1AtReceivers; diff --git a/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/firstOrderEqn/isotropic/AcousticFirstOrderWaveEquationSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/firstOrderEqn/isotropic/AcousticFirstOrderWaveEquationSEMKernel.hpp new file mode 100644 index 00000000000..92f36773282 --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/firstOrderEqn/isotropic/AcousticFirstOrderWaveEquationSEMKernel.hpp @@ -0,0 +1,303 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AcousticFirstOrderWaveEquationSEMKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICFIRSTTORDERWAVEEQUATIONSEMKERNEL_HPP_ +#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICFIRSTTORDERWAVEEQUATIONSEMKERNEL_HPP_ + +#include "finiteElement/kernelInterface/KernelBase.hpp" + +namespace geos +{ + +/// Namespace to contain the first order acoustic wave kernels. +namespace acousticFirstOrderWaveEquationSEMKernels +{ + +template< typename FE_TYPE > +struct VelocityComputation +{ + + VelocityComputation( FE_TYPE const & finiteElement ) + : m_finiteElement( finiteElement ) + {} + + /** + * @brief Launches the computation of the velocity for one iteration + * @tparam EXEC_POLICY the execution policy + * @tparam ATOMIC_POLICY the atomic policy + * @param[in] size the number of cells in the subRegion + * @param[in] nodeCoords coordinates of the nodes + * @param[in] elemsToNodes map from element to nodes + * @param[in] p_np1 pressure array (only used here) + * @param[in] density cell-wise density + * @param[in] dt time-step + * @param[out] velocity_x velocity array in the x direction (updated here) + * @param[out] velocity_y velocity array in the y direction (updated here) + * @param[out] velocity_z velocity array in the z direction (updated here) + */ + template< typename EXEC_POLICY, typename ATOMIC_POLICY > + void + launch( localIndex const size, + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, + arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes, + arrayView1d< real32 const > const p_np1, + arrayView1d< real32 const > const density, + real64 const dt, + arrayView2d< real32 > const velocity_x, + arrayView2d< real32 > const velocity_y, + arrayView2d< real32 > const velocity_z ) + { + forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + // only the eight corners of the mesh cell are needed to compute the Jacobian + real64 xLocal[8][3]; + for( localIndex a=0; a< 8; ++a ) + { + localIndex const nodeIndex = elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); + for( localIndex i=0; i<3; ++i ) + { + xLocal[a][i] = nodeCoords( nodeIndex, i ); + } + } + + constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; + real32 uelemx[numNodesPerElem] = {0.0}; + real32 uelemy[numNodesPerElem] = {0.0}; + real32 uelemz[numNodesPerElem] = {0.0}; + real32 flowx[numNodesPerElem] = {0.0}; + real32 flowy[numNodesPerElem] = {0.0}; + real32 flowz[numNodesPerElem] = {0.0}; + + for( localIndex i = 0; i < numNodesPerElem; ++i ) + { + real32 massLoc = m_finiteElement.computeMassTerm( i, xLocal ); + uelemx[i] = massLoc*velocity_x[k][i]; + uelemy[i] = massLoc*velocity_y[k][i]; + uelemz[i] = massLoc*velocity_z[k][i]; + } + + for( localIndex q = 0; q < numNodesPerElem; q++ ) + { + + m_finiteElement.template computeFirstOrderStiffnessTermX( q, xLocal, [&] ( int i, int j, real32 dfx1, real32 dfx2, real32 dfx3 ) + { + flowx[j] += dfx1*p_np1[elemsToNodes[k][i]]; + flowy[j] += dfx2*p_np1[elemsToNodes[k][i]]; + flowz[j] += dfx3*p_np1[elemsToNodes[k][i]]; + } ); + + m_finiteElement.template computeFirstOrderStiffnessTermY( q, xLocal, [&] ( int i, int j, real32 dfy1, real32 dfy2, real32 dfy3 ) + { + flowx[j] += dfy1*p_np1[elemsToNodes[k][i]]; + flowy[j] += dfy2*p_np1[elemsToNodes[k][i]]; + flowz[j] += dfy3*p_np1[elemsToNodes[k][i]]; + } ); + + m_finiteElement.template computeFirstOrderStiffnessTermZ( q, xLocal, [&] ( int i, int j, real32 dfz1, real32 dfz2, real32 dfz3 ) + { + flowx[j] += dfz1*p_np1[elemsToNodes[k][i]]; + flowy[j] += dfz2*p_np1[elemsToNodes[k][i]]; + flowz[j] += dfz3*p_np1[elemsToNodes[k][i]]; + + } ); + + } + for( localIndex i = 0; i < numNodesPerElem; ++i ) + { + real32 massLoc = m_finiteElement.computeMassTerm( i, xLocal ); + uelemx[i]+=dt*flowx[i]/density[k]; + uelemy[i]+=dt*flowy[i]/density[k]; + uelemz[i]+=dt*flowz[i]/density[k]; + + velocity_x[k][i] = uelemx[i]/massLoc; + velocity_y[k][i] = uelemy[i]/massLoc; + velocity_z[k][i] = uelemz[i]/massLoc; + } + } ); + } + + /// The finite element space/discretization object for the element type in the subRegion + FE_TYPE const & m_finiteElement; +}; + +template< typename FE_TYPE > +struct PressureComputation +{ + + PressureComputation( FE_TYPE const & finiteElement ) + : m_finiteElement( finiteElement ) + {} + + /** + * @brief Launches the computation of the pressure for one iteration + * @tparam EXEC_POLICY the execution policy + * @tparam ATOMIC_POLICY the atomic policy + * @param[in] size the number of cells in the subRegion + * @param[in] regionIndex Index of the subregion + * @param[in] size_node the number of nodes in the subRegion + * @param[in] nodeCoords coordinates of the nodes + * @param[in] elemsToNodes map from element to nodes + * @param[out] velocity_x velocity array in the x direction (only used here) + * @param[out] velocity_y velocity array in the y direction (only used here) + * @param[out] velocity_z velocity array in the z direction (only used here) + * @param[in] mass the mass matrix + * @param[in] damping the damping matrix + * @param[in] sourceConstants constant part of the source terms + * @param[in] sourceIsAccessible flag indicating whether the source is accessible or not + * @param[in] sourceElem element where a source is located + * @param[in] dt time-step + * @param[in] timeSourceFrequency the central frequency of the source + * @param[in] timeSourceDelay the time delay of the source + * @param[in] rickerOrder order of the Ricker wavelet + * @param[out] p_np1 pressure array (updated here) + */ + + template< typename EXEC_POLICY, typename ATOMIC_POLICY > + void + launch( localIndex const size, + localIndex const regionIndex, + localIndex const size_node, + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, + arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes, + arrayView2d< real32 const > const velocity_x, + arrayView2d< real32 const > const velocity_y, + arrayView2d< real32 const > const velocity_z, + arrayView1d< real32 const > const mass, + arrayView1d< real32 const > const damping, + arrayView2d< real64 const > const sourceConstants, + arrayView1d< localIndex const > const sourceIsAccessible, + arrayView1d< localIndex const > const sourceElem, + arrayView1d< localIndex const > const sourceRegion, + real64 const dt, + real64 const time_n, + real32 const timeSourceFrequency, + real32 const timeSourceDelay, + localIndex const rickerOrder, + bool const useSourceWaveletTables, + arrayView1d< TableFunction::KernelWrapper const > const sourceWaveletTableWrappers, + arrayView1d< real32 > const p_np1 ) + + { + + //Pre-mult by the first factor for damping + forAll< EXEC_POLICY >( size_node, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + p_np1[a] *= 1.0-((dt/2)*(damping[a]/mass[a])); + } ); + + //Source initialization + + real64 const rickerValue = useSourceWaveletTables ? 0 : WaveSolverUtils::evaluateRicker( time_n, timeSourceFrequency, timeSourceDelay, rickerOrder ); + + forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + // only the eight corners of the mesh cell are needed to compute the Jacobian + real64 xLocal[8][3]; + for( localIndex a=0; a< 8; ++a ) + { + localIndex const nodeIndex = elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); + for( localIndex i=0; i<3; ++i ) + { + xLocal[a][i] = nodeCoords( nodeIndex, i ); + } + } + + constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; + real32 auxx[numNodesPerElem] = {0.0}; + real32 auyy[numNodesPerElem] = {0.0}; + real32 auzz[numNodesPerElem] = {0.0}; + real32 uelemx[numNodesPerElem] = {0.0}; + + + // Volume integration + for( localIndex q=0; q < numNodesPerElem; q++ ) + { + + + m_finiteElement.template computeFirstOrderStiffnessTermX( q, xLocal, [&] ( int i, int j, real32 dfx1, real32 dfx2, real32 dfx3 ) + { + auxx[i] -= dfx1*velocity_x[k][j]; + auyy[i] -= dfx2*velocity_y[k][j]; + auzz[i] -= dfx3*velocity_z[k][j]; + } ); + + m_finiteElement.template computeFirstOrderStiffnessTermY( q, xLocal, [&] ( int i, int j, real32 dfy1, real32 dfy2, real32 dfy3 ) + { + auxx[i] -= dfy1*velocity_x[k][j]; + auyy[i] -= dfy2*velocity_y[k][j]; + auzz[i] -= dfy3*velocity_z[k][j]; + } ); + + m_finiteElement.template computeFirstOrderStiffnessTermZ( q, xLocal, [&] ( int i, int j, real32 dfz1, real32 dfz2, real32 dfz3 ) + { + auxx[i] -= dfz1*velocity_x[k][j]; + auyy[i] -= dfz2*velocity_y[k][j]; + auzz[i] -= dfz3*velocity_z[k][j]; + } ); + + + + } + + //Time update + multiplication by inverse of the mass matrix + for( localIndex i = 0; i < numNodesPerElem; ++i ) + { + real32 diag=(auxx[i]+auyy[i]+auzz[i]); + uelemx[i]+=dt*diag; + + real32 const localIncrement = uelemx[i]/mass[elemsToNodes[k][i]]; + RAJA::atomicAdd< ATOMIC_POLICY >( &p_np1[elemsToNodes[k][i]], localIncrement ); + } + + //Source Injection + for( localIndex isrc = 0; isrc < sourceConstants.size( 0 ); ++isrc ) + { + if( sourceIsAccessible[isrc] == 1 ) + { + if( sourceElem[isrc]==k && sourceRegion[isrc] == regionIndex ) + { + real64 const srcValue = useSourceWaveletTables ? sourceWaveletTableWrappers[ isrc ].compute( &time_n ) : rickerValue; + for( localIndex i = 0; i < numNodesPerElem; ++i ) + { + real32 const localIncrement2 = dt*(sourceConstants[isrc][i]*srcValue)/(mass[elemsToNodes[k][i]]); + RAJA::atomicAdd< ATOMIC_POLICY >( &p_np1[elemsToNodes[k][i]], localIncrement2 ); + } + } + } + } + + } ); + + //Pre-mult by the first factor for damping + forAll< EXEC_POLICY >( size_node, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + p_np1[a] /= 1.0+((dt/2)*(damping[a]/mass[a])); + } ); + } + + /// The finite element space/discretization object for the element type in the subRegion + FE_TYPE const & m_finiteElement; + +}; + +} // namespace AcousticFirstOrderWaveEquationSEMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICFIRSTTORDERWAVEEQUATIONSEMKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/AcousticVTIFields.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIFields.hpp similarity index 95% rename from src/coreComponents/physicsSolvers/wavePropagation/AcousticVTIFields.hpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIFields.hpp index a361d77e55c..a53cf0c52ac 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/AcousticVTIFields.hpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/wavePropagation/AcousticVTIWaveEquationSEM.cpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIWaveEquationSEM.cpp similarity index 85% rename from src/coreComponents/physicsSolvers/wavePropagation/AcousticVTIWaveEquationSEM.cpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIWaveEquationSEM.cpp index 967327730a6..28b2497012d 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/AcousticVTIWaveEquationSEM.cpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIWaveEquationSEM.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOS Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -25,8 +26,11 @@ #include "fieldSpecification/PerfectlyMatchedLayer.hpp" #include "mainInterface/ProblemManager.hpp" #include "mesh/ElementType.hpp" +#include "mesh/DomainPartition.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" -#include "WaveSolverUtils.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverUtils.hpp" +#include "physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticTimeSchemeSEMKernel.hpp" +#include "events/EventManager.hpp" namespace geos { @@ -99,28 +103,25 @@ void AcousticVTIWaveEquationSEM::registerDataOnMesh( Group & meshBodies ) } -void AcousticVTIWaveEquationSEM::postProcessInput() +void AcousticVTIWaveEquationSEM::postInputInitialization() { - WaveSolverBase::postProcessInput(); + WaveSolverBase::postInputInitialization(); localIndex const numReceiversGlobal = m_receiverCoordinates.size( 0 ); m_pressureNp1AtReceivers.resize( m_nsamplesSeismoTrace, numReceiversGlobal + 1 ); } -void AcousticVTIWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & mesh, +void AcousticVTIWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & baseMesh, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) { - NodeManager const & nodeManager = mesh.getNodeManager(); - FaceManager const & faceManager = mesh.getFaceManager(); - - arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords32 = - nodeManager.getField< fields::referencePosition32 >().toViewConst(); - - arrayView2d< real64 const > const faceNormal = faceManager.faceNormal(); - arrayView2d< real64 const > const faceCenter = faceManager.faceCenter(); + GEOS_MARK_FUNCTION; + arrayView1d< globalIndex const > const nodeLocalToGlobal = baseMesh.getNodeManager().localToGlobalMap().toViewConst(); + ArrayOfArraysView< localIndex const > const nodesToElements = baseMesh.getNodeManager().elementList().toViewConst(); + ArrayOfArraysView< localIndex const > const facesToNodes = baseMesh.getFaceManager().nodeList().toViewConst(); + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const nodeCoords = baseMesh.getNodeManager().referencePosition().toViewConst(); arrayView2d< real64 const > const sourceCoordinates = m_sourceCoordinates.toViewConst(); arrayView2d< localIndex > const sourceNodeIds = m_sourceNodeIds.toView(); @@ -138,20 +139,11 @@ void AcousticVTIWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & me receiverConstants.setValues< EXEC_POLICY >( -1 ); receiverIsLocal.zero(); - arrayView2d< real32 > const sourceValue = m_sourceValue.toView(); - real64 dt = 0; - EventManager const & event = getGroupByPath< EventManager >( "/Problem/Events" ); - for( localIndex numSubEvent = 0; numSubEvent < event.numSubGroups(); ++numSubEvent ) - { - EventBase const * subEvent = static_cast< EventBase const * >( event.getSubGroups()[numSubEvent] ); - if( subEvent->getEventName() == "/Solvers/" + getName() ) - { - dt = subEvent->getReference< real64 >( EventBase::viewKeyStruct::forceDtString() ); - } - } - - mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, - CellElementSubRegion & elementSubRegion ) + mesh.getElemManager().forElementSubRegionsComplete< CellElementSubRegion >( regionNames, [&]( localIndex const, + localIndex const er, + localIndex const esr, + ElementRegionBase &, + CellElementSubRegion & elementSubRegion ) { GEOS_THROW_IF( elementSubRegion.getElementType() != ElementType::Hexahedron, "Invalid type of element, the acoustic solver is designed for hexahedral meshes only (C3D8), using the SEM formulation", @@ -159,8 +151,10 @@ void AcousticVTIWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & me arrayView2d< localIndex const > const elemsToFaces = elementSubRegion.faceList(); arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes = elementSubRegion.nodeList(); + arrayView2d< localIndex const, cells::NODE_MAP_USD > const & baseElemsToNodes = baseMesh.getElemManager().getRegion( er ).getSubRegion< CellElementSubRegion >( esr ).nodeList(); arrayView2d< real64 const > const elemCenter = elementSubRegion.getElementCenter(); arrayView1d< integer const > const elemGhostRank = elementSubRegion.ghostRank(); + arrayView1d< globalIndex const > const elemLocalToGlobal = elementSubRegion.localToGlobalMap().toViewConst(); finiteElement::FiniteElementBase const & fe = elementSubRegion.getReference< finiteElement::FiniteElementBase >( getDiscretizationName() ); @@ -168,20 +162,20 @@ void AcousticVTIWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & me { using FE_TYPE = TYPEOFREF( finiteElement ); - localIndex const numFacesPerElem = elementSubRegion.numFacesPerElement(); - acousticVTIWaveEquationSEMKernels:: PrecomputeSourceAndReceiverKernel:: launch< EXEC_POLICY, FE_TYPE > ( elementSubRegion.size(), - numFacesPerElem, - nodeCoords32, + facesToNodes, + nodeCoords, + nodeLocalToGlobal, + elemLocalToGlobal, + nodesToElements, + baseElemsToNodes, elemGhostRank, elemsToNodes, elemsToFaces, elemCenter, - faceNormal, - faceCenter, sourceCoordinates, sourceIsAccessible, sourceNodeIds, @@ -189,31 +183,38 @@ void AcousticVTIWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & me receiverCoordinates, receiverIsLocal, receiverNodeIds, - receiverConstants, - sourceValue, - dt, - m_timeSourceFrequency, - m_timeSourceDelay, - m_rickerOrder ); + receiverConstants ); } ); + elementSubRegion.faceList().freeOnDevice(); + baseMesh.getElemManager().getRegion( er ).getSubRegion< CellElementSubRegion >( esr ).nodeList().freeOnDevice(); + elementSubRegion.getElementCenter().freeOnDevice(); + elementSubRegion.ghostRank().freeOnDevice(); + elementSubRegion.localToGlobalMap().freeOnDevice(); } ); + baseMesh.getNodeManager().localToGlobalMap().freeOnDevice(); + baseMesh.getNodeManager().elementList().toView().freeOnDevice(); + baseMesh.getFaceManager().nodeList().toView().freeOnDevice(); + baseMesh.getNodeManager().referencePosition().freeOnDevice(); + facesToNodes.freeOnDevice(); + nodesToElements.freeOnDevice(); } -void AcousticVTIWaveEquationSEM::addSourceToRightHandSide( integer const & cycleNumber, arrayView1d< real32 > const rhs ) +void AcousticVTIWaveEquationSEM::addSourceToRightHandSide( real64 const & time_n, arrayView1d< real32 > const rhs ) { arrayView2d< localIndex const > const sourceNodeIds = m_sourceNodeIds.toViewConst(); arrayView2d< real64 const > const sourceConstants = m_sourceConstants.toViewConst(); arrayView1d< localIndex const > const sourceIsAccessible = m_sourceIsAccessible.toViewConst(); - arrayView2d< real32 const > const sourceValue = m_sourceValue.toViewConst(); - - GEOS_THROW_IF( cycleNumber > sourceValue.size( 0 ), "Too many steps compared to array size", std::runtime_error ); + bool useSourceWaveletTables = m_useSourceWaveletTables; + real64 const rickerValue = useSourceWaveletTables ? 0 : WaveSolverUtils::evaluateRicker( time_n, m_timeSourceFrequency, m_timeSourceDelay, m_rickerOrder ); + arrayView1d< TableFunction::KernelWrapper const > const sourceWaveletTableWrappers = m_sourceWaveletTableWrappers.toViewConst(); forAll< EXEC_POLICY >( sourceConstants.size( 0 ), [=] GEOS_HOST_DEVICE ( localIndex const isrc ) { if( sourceIsAccessible[isrc] == 1 ) { + real64 const srcValue = useSourceWaveletTables ? sourceWaveletTableWrappers[ isrc ].compute( &time_n ) : rickerValue; for( localIndex inode = 0; inode < sourceConstants.size( 1 ); ++inode ) { - real32 const localIncrement = sourceConstants[isrc][inode] * sourceValue[cycleNumber][isrc]; + real32 const localIncrement = sourceConstants[isrc][inode] * srcValue; RAJA::atomicAdd< ATOMIC_POLICY >( &rhs[sourceNodeIds[isrc][inode]], localIncrement ); } } @@ -230,19 +231,19 @@ void AcousticVTIWaveEquationSEM::initializePostInitialConditionsPreSubGroups() applyFreeSurfaceBC( 0.0, domain ); precomputeSurfaceFieldIndicator( domain ); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshBodyName, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) { - precomputeSourceAndReceiverTerm( mesh, regionNames ); + MeshLevel & baseMesh = domain.getMeshBodies().getGroup< MeshBody >( meshBodyName ).getBaseDiscretization(); + precomputeSourceAndReceiverTerm( baseMesh, mesh, regionNames ); NodeManager & nodeManager = mesh.getNodeManager(); FaceManager & faceManager = mesh.getFaceManager(); /// get the array of indicators: 1 if the face is on the boundary; 0 otherwise arrayView1d< integer > const & facesDomainBoundaryIndicator = faceManager.getDomainBoundaryIndicator(); - arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords = - nodeManager.getField< fields::referencePosition32 >().toViewConst(); + arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords = nodeManager.getField< fields::referencePosition32 >().toViewConst(); /// get face to node map ArrayOfArraysView< localIndex const > const facesToNodes = faceManager.nodeList().toViewConst(); @@ -315,6 +316,13 @@ void AcousticVTIWaveEquationSEM::initializePostInitialConditionsPreSubGroups() WaveSolverUtils::initTrace( "seismoTraceReceiver", getName(), m_outputSeismoTrace, m_receiverConstants.size( 0 ), m_receiverIsLocal ); } +real64 AcousticVTIWaveEquationSEM::computeTimeStep( real64 & dtOut ) +{ + GEOS_ERROR( getDataContext() << ": Time-Step computation for the second order acoustic vti wave propagator not yet implemented" ); + return dtOut; +} + + void AcousticVTIWaveEquationSEM::precomputeSurfaceFieldIndicator( DomainPartition & domain ) { real64 const time = 0.0; @@ -472,11 +480,11 @@ void AcousticVTIWaveEquationSEM::applyFreeSurfaceBC( real64 time, DomainPartitio real64 AcousticVTIWaveEquationSEM::explicitStepForward( real64 const & time_n, real64 const & dt, - integer cycleNumber, + integer, DomainPartition & domain, bool computeGradient ) { - real64 dtOut = explicitStepInternal( time_n, dt, cycleNumber, domain ); + real64 dtOut = explicitStepInternal( time_n, dt, domain ); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, @@ -537,7 +545,6 @@ real64 AcousticVTIWaveEquationSEM::explicitStepBackward( real64 const & GEOS_UNU real64 AcousticVTIWaveEquationSEM::explicitStepInternal( real64 const & time_n, real64 const & dt, - integer cycleNumber, DomainPartition & domain ) { GEOS_MARK_FUNCTION; @@ -583,57 +590,16 @@ real64 AcousticVTIWaveEquationSEM::explicitStepInternal( real64 const & time_n, "", kernelFactory ); - addSourceToRightHandSide( cycleNumber, rhs ); + addSourceToRightHandSide( time_n, rhs ); /// calculate your time integrators - real64 const dt2 = dt*dt; GEOS_MARK_SCOPE ( updateP ); - forAll< EXEC_POLICY >( nodeManager.size(), [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - if( freeSurfaceNodeIndicator[a] != 1 ) - { - p_np1[a] = 2.0*mass[a]*p_n[a]/dt2; - p_np1[a] -= mass[a]*p_nm1[a]/dt2; - p_np1[a] += stiffnessVector_p[a]; - p_np1[a] += rhs[a]; - - q_np1[a] = 2.0*mass[a]*q_n[a]/dt2; - q_np1[a] -= mass[a]*q_nm1[a]/dt2; - q_np1[a] += stiffnessVector_q[a]; - q_np1[a] += rhs[a]; - if( lateralSurfaceNodeIndicator[a] != 1 && bottomSurfaceNodeIndicator[a] != 1 ) - { - // Interior node, no boundary terms - p_np1[a] /= mass[a]/dt2; - q_np1[a] /= mass[a]/dt2; - } - else - { - // Boundary node - p_np1[a] += damping_p[a]*p_nm1[a]/dt/2; - p_np1[a] += damping_pq[a]*q_nm1[a]/dt/2; - - q_np1[a] += damping_q[a]*q_nm1[a]/dt/2; - q_np1[a] += damping_qp[a]*p_nm1[a]/dt/2; - // Hand-made Inversion of 2x2 matrix - real32 coef_pp = mass[a]/dt2; - coef_pp += damping_p[a]/dt/2; - real32 coef_pq = damping_pq[a]/dt/2; - - real32 coef_qq = mass[a]/dt2; - coef_qq += damping_q[a]/2/dt; - real32 coef_qp = damping_qp[a]/dt/2; - - real32 det_pq = 1/(coef_pp * coef_qq - coef_pq*coef_qp); - - real32 aux_p_np1 = p_np1[a]; - p_np1[a] = det_pq*(coef_qq*p_np1[a] - coef_pq*q_np1[a]); - q_np1[a] = det_pq*(coef_pp*q_np1[a] - coef_qp*aux_p_np1); - } - } - } ); + AcousticTimeSchemeSEM::LeapFrogforVTI( nodeManager.size(), dt, p_np1, p_n, p_nm1, q_np1, q_n, q_nm1, mass, stiffnessVector_p, + stiffnessVector_q, damping_p, damping_pq, damping_q, damping_qp, + rhs, freeSurfaceNodeIndicator, lateralSurfaceNodeIndicator, + bottomSurfaceNodeIndicator ); /// synchronize pressure fields FieldIdentifiers fieldsToBeSync; @@ -672,7 +638,7 @@ void AcousticVTIWaveEquationSEM::cleanup( real64 const time_n, DomainPartition & domain ) { // call the base class cleanup (for reporting purposes) - SolverBase::cleanup( time_n, cycleNumber, eventCounter, eventProgress, domain ); + PhysicsSolverBase::cleanup( time_n, cycleNumber, eventCounter, eventProgress, domain ); // compute the remaining seismic traces, if needed forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, @@ -690,6 +656,6 @@ void AcousticVTIWaveEquationSEM::cleanup( real64 const time_n, } ); } -REGISTER_CATALOG_ENTRY( SolverBase, AcousticVTIWaveEquationSEM, string const &, dataRepository::Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, AcousticVTIWaveEquationSEM, string const &, dataRepository::Group * const ) } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/AcousticVTIWaveEquationSEM.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIWaveEquationSEM.hpp similarity index 85% rename from src/coreComponents/physicsSolvers/wavePropagation/AcousticVTIWaveEquationSEM.hpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIWaveEquationSEM.hpp index 932568e3f6e..dcfe6da4d14 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/AcousticVTIWaveEquationSEM.hpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIWaveEquationSEM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOS Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,9 +22,9 @@ #define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICVTIWAVEEQUATIONSEM_HPP_ #include "mesh/MeshFields.hpp" -#include "physicsSolvers/SolverBase.hpp" -#include "WaveSolverBase.hpp" -#include "AcousticFields.hpp" +#include "physicsSolvers/PhysicsSolverBase.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp" +#include "physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticFields.hpp" #include "AcousticVTIFields.hpp" namespace geos @@ -41,7 +42,7 @@ class AcousticVTIWaveEquationSEM : public WaveSolverBase static string catalogName() { return "AcousticVTISEM"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -75,7 +76,7 @@ class AcousticVTIWaveEquationSEM : public WaveSolverBase * @param cycleNumber the cycle number/step number of evaluation of the source * @param rhs the right hand side vector to be computed */ - virtual void addSourceToRightHandSide( integer const & cycleNumber, arrayView1d< real32 > const rhs ); + virtual void addSourceToRightHandSide( real64 const & time_n, arrayView1d< real32 > const rhs ); /** * @brief Overridden from ExecutableGroup. Used to write last seismogram if needed. @@ -100,7 +101,6 @@ class AcousticVTIWaveEquationSEM : public WaveSolverBase */ real64 explicitStepInternal( real64 const & time_n, real64 const & dt, - integer const cycleNumber, DomainPartition & domain ); /** @@ -117,7 +117,7 @@ class AcousticVTIWaveEquationSEM : public WaveSolverBase protected: - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; virtual void initializePostInitialConditionsPreSubGroups() override final; @@ -126,9 +126,10 @@ class AcousticVTIWaveEquationSEM : public WaveSolverBase /** * @brief Locate sources and receivers position in the mesh elements, evaluate the basis functions at each point and save them to the * corresponding elements nodes. + * @param baseMesh the level-0 mesh * @param mesh mesh of the computational domain */ - virtual void precomputeSourceAndReceiverTerm( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) override; + virtual void precomputeSourceAndReceiverTerm( MeshLevel & baseMesh, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) override; /** * @brief Compute the lateral and bottom surface Field indicators of the boxed domain @@ -143,6 +144,8 @@ class AcousticVTIWaveEquationSEM : public WaveSolverBase */ virtual void applyFreeSurfaceBC( real64 const time, DomainPartition & domain ) override; + virtual real64 computeTimeStep( real64 & dtOut ) override; + /// Pressure_p_np1 at the receiver location for each time step for each receiver array2d< real32 > m_pressureNp1AtReceivers; diff --git a/src/coreComponents/physicsSolvers/wavePropagation/AcousticVTIWaveEquationSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIWaveEquationSEMKernel.hpp similarity index 84% rename from src/coreComponents/physicsSolvers/wavePropagation/AcousticVTIWaveEquationSEMKernel.hpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIWaveEquationSEMKernel.hpp index 72cd2da8d73..c0b6e66e190 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/AcousticVTIWaveEquationSEMKernel.hpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/anisotropic/AcousticVTIWaveEquationSEMKernel.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOS Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,12 +22,11 @@ #include "finiteElement/elementFormulations/Qk_Hexahedron_Lagrange_GaussLobatto.hpp" #include "finiteElement/kernelInterface/KernelBase.hpp" -#include "WaveSolverUtils.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverUtils.hpp" #include "AcousticVTIFields.hpp" namespace geos { -using namespace fields; /// Namespace to contain the acoustic wave kernels. namespace acousticVTIWaveEquationSEMKernels @@ -39,38 +39,38 @@ struct PrecomputeSourceAndReceiverKernel * @tparam EXEC_POLICY execution policy * @tparam FE_TYPE finite element type * @param[in] size the number of cells in the subRegion - * @param[in] numFacesPerElem number of faces per element - * @param[in] nodeCoords coordinates of the nodes - * @param[in] elemGhostRank the ghost ranks + * @param[in] baseFacesToNodes face to node map + * @param[in] baseNodeCoords coordinates of the nodes + * @param[in] baseNodeLocalToGlobal local to global index map for nodes + * @param[in] elementLocalToGlobal local to global index map for elements + * @param[in] baseNodesToElements node to element map for the base mesh + * @param[in] baseElemsToNodes element to node map for the base mesh + * @param[in] elemGhostRank rank of the ghost element * @param[in] elemsToNodes map from element to nodes * @param[in] elemsToFaces map from element to faces - * @param[in] facesToNodes map from faces to nodes * @param[in] elemCenter coordinates of the element centers * @param[in] sourceCoordinates coordinates of the source terms * @param[out] sourceIsAccessible flag indicating whether the source is accessible or not * @param[out] sourceNodeIds indices of the nodes of the element where the source is located - * @param[out] sourceNodeConstants constant part of the source terms + * @param[out] sourceConstants constant part of the source terms * @param[in] receiverCoordinates coordinates of the receiver terms * @param[out] receiverIsLocal flag indicating whether the receiver is local or not * @param[out] receiverNodeIds indices of the nodes of the element where the receiver is located - * @param[out] receiverNodeConstants constant part of the receiver term - * @param[out] sourceValue the value of the source - * @param[in] dt the time step size - * @param[in] timeSourceFrequency the time frequency of the source - * @param[in] timeSourceDelay the time delay of the source - * @param[in] rickerOrder the order of the ricker + * @param[out] receiverConstants constant part of the receiver term */ template< typename EXEC_POLICY, typename FE_TYPE > static void launch( localIndex const size, - localIndex const numFacesPerElem, - arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, + ArrayOfArraysView< localIndex const > const baseFacesToNodes, + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const baseNodeCoords, + arrayView1d< globalIndex const > const baseNodeLocalToGlobal, + arrayView1d< globalIndex const > const elementLocalToGlobal, + ArrayOfArraysView< localIndex const > const baseNodesToElements, + arrayView2d< localIndex const, cells::NODE_MAP_USD > const & baseElemsToNodes, arrayView1d< integer const > const elemGhostRank, arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes, arrayView2d< localIndex const > const elemsToFaces, arrayView2d< real64 const > const & elemCenter, - arrayView2d< real64 const > const faceNormal, - arrayView2d< real64 const > const faceCenter, arrayView2d< real64 const > const sourceCoordinates, arrayView1d< localIndex > const sourceIsAccessible, arrayView2d< localIndex > const sourceNodeIds, @@ -78,12 +78,7 @@ struct PrecomputeSourceAndReceiverKernel arrayView2d< real64 const > const receiverCoordinates, arrayView1d< localIndex > const receiverIsLocal, arrayView2d< localIndex > const receiverNodeIds, - arrayView2d< real64 > const receiverConstants, - arrayView2d< real32 > const sourceValue, - real64 const dt, - real32 const timeSourceFrequency, - real32 const timeSourceDelay, - localIndex const rickerOrder ) + arrayView2d< real64 > const receiverConstants ) { constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; @@ -105,20 +100,23 @@ struct PrecomputeSourceAndReceiverKernel sourceCoordinates[isrc][2] }; bool const sourceFound = - WaveSolverUtils::locateSourceElement( numFacesPerElem, - center, - faceNormal, - faceCenter, - elemsToFaces[k], - coords ); + computationalGeometry::isPointInsideConvexPolyhedronRobust( k, + baseNodeCoords, + elemsToFaces, + baseFacesToNodes, + baseNodesToElements, + baseNodeLocalToGlobal, + elementLocalToGlobal, + center, + coords ); if( sourceFound ) { real64 coordsOnRefElem[3]{}; WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, - elemsToNodes[k], - nodeCoords, + baseElemsToNodes[k], + baseNodeCoords, coordsOnRefElem ); sourceIsAccessible[isrc] = 1; @@ -131,10 +129,6 @@ struct PrecomputeSourceAndReceiverKernel sourceConstants[isrc][a] = Ntest[a]; } - for( localIndex cycle = 0; cycle < sourceValue.size( 0 ); ++cycle ) - { - sourceValue[cycle][isrc] = WaveSolverUtils::evaluateRicker( cycle * dt, timeSourceFrequency, timeSourceDelay, rickerOrder ); - } } } } // end loop over all sources @@ -152,19 +146,22 @@ struct PrecomputeSourceAndReceiverKernel receiverCoordinates[ircv][2] }; real64 coordsOnRefElem[3]{}; - bool const receiverFound = - WaveSolverUtils::locateSourceElement( numFacesPerElem, - center, - faceNormal, - faceCenter, - elemsToFaces[k], - coords ); + bool const receiverFound = + computationalGeometry::isPointInsideConvexPolyhedronRobust( k, + baseNodeCoords, + elemsToFaces, + baseFacesToNodes, + baseNodesToElements, + baseNodeLocalToGlobal, + elementLocalToGlobal, + center, + coords ); if( receiverFound && elemGhostRank[k] < 0 ) { WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, - elemsToNodes[k], - nodeCoords, + baseElemsToNodes[k], + baseNodeCoords, coordsOnRefElem ); receiverIsLocal[ircv] = 1; @@ -430,13 +427,13 @@ class ExplicitAcousticVTISEM : public finiteElement::KernelBase< SUBREGION_TYPE, finiteElementSpace, inputConstitutiveType ), m_nodeCoords( nodeManager.getField< fields::referencePosition32 >() ), - m_p_n( nodeManager.getField< acousticvtifields::Pressure_p_n >() ), - m_q_n( nodeManager.getField< acousticvtifields::Pressure_q_n >() ), - m_stiffnessVector_p( nodeManager.getField< acousticvtifields::StiffnessVector_p >() ), - m_stiffnessVector_q( nodeManager.getField< acousticvtifields::StiffnessVector_q >() ), - m_epsilon( elementSubRegion.template getField< acousticvtifields::Epsilon >() ), - m_delta( elementSubRegion.template getField< acousticvtifields::Delta >() ), - m_vti_f( elementSubRegion.template getField< acousticvtifields::F >() ), + m_p_n( nodeManager.getField< fields::acousticvtifields::Pressure_p_n >() ), + m_q_n( nodeManager.getField< fields::acousticvtifields::Pressure_q_n >() ), + m_stiffnessVector_p( nodeManager.getField< fields::acousticvtifields::StiffnessVector_p >() ), + m_stiffnessVector_q( nodeManager.getField< fields::acousticvtifields::StiffnessVector_q >() ), + m_epsilon( elementSubRegion.template getField< fields::acousticvtifields::Epsilon >() ), + m_delta( elementSubRegion.template getField< fields::acousticvtifields::Delta >() ), + m_vti_f( elementSubRegion.template getField< fields::acousticvtifields::F >() ), m_dt( dt ) { GEOS_UNUSED_VAR( edgeManager ); diff --git a/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticPMLSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticPMLSEMKernel.hpp new file mode 100644 index 00000000000..8f1b96077ba --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticPMLSEMKernel.hpp @@ -0,0 +1,390 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AcousticPMLSEMKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICPMLSEMKERNEL_HPP_ +#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICPMLSEMKERNEL_HPP_ + +namespace geos +{ + +struct AcousticPMLSEM +{ + struct ComputeDamping + { + /** + * @brief Compute the damping profile for the Perfectly Matched Layer (PML) + * @param xLocal a given x-y-z coordinates (3-components array) + * @param xMin coordinate limits of the inner PML boundaries, left-front-top + * @param xMax coordinate limits of the inner PML boundaries, right-back-bottom + * @param dMin PML thickness, left-front-top + * @param dMax PML thickness, right-back-bottom + * @param cMin PML wave speed, left-front-top + * @param cMax PML wave speed, right-back-bottom + * @param r desired reflectivity of the PML + * @param sigma 3-components array to hold the damping profile in each direction + */ + GEOS_HOST_DEVICE + inline + static void computeDampingProfile( real32 const (&xLocal)[3], + real32 const (&xMin)[3], + real32 const (&xMax)[3], + real32 const (&dMin)[3], + real32 const (&dMax)[3], + real32 const (&cMin)[3], + real32 const (&cMax)[3], + real32 const r, + real32 (& sigma)[3] ) + { + + sigma[0] = 0; + sigma[1] = 0; + sigma[2] = 0; + + if( xLocal[0] < xMin[0] ) + { + real32 const factor = -3.0/2.0*cMin[0]*log( r )/(dMin[0]*dMin[0]*dMin[0]); + sigma[0] = factor*(xLocal[0]-xMin[0])*(xLocal[0]-xMin[0]); + } + else if( xLocal[0] > xMax[0] ) + { + real32 const factor = -3.0/2.0*cMax[0]*log( r )/(dMax[0]*dMax[0]*dMax[0]); + sigma[0] = factor*(xLocal[0]-xMax[0])*(xLocal[0]-xMax[0]); + } + if( xLocal[1] < xMin[1] ) + { + real32 const factor = -3.0/2.0*cMin[1]*log( r )/(dMin[1]*dMin[1]*dMin[1]); + sigma[1] = factor*(xLocal[1]-xMin[1])*(xLocal[1]-xMin[1]); + } + else if( xLocal[1] > xMax[1] ) + { + real32 const factor = -3.0/2.0*cMax[1]*log( r )/(dMax[1]*dMax[1]*dMax[1]); + sigma[1] = factor*(xLocal[1]-xMax[1])*(xLocal[1]-xMax[1]); + } + if( xLocal[2] < xMin[2] ) + { + real32 const factor = -3.0/2.0*cMin[2]*log( r )/(dMin[2]*dMin[2]*dMin[2]); + sigma[2] = factor*(xLocal[2]-xMin[2])*(xLocal[2]-xMin[2]); + } + else if( xLocal[2] > xMax[2] ) + { + real32 const factor = -3.0/2.0*cMax[2]*log( r )/(dMax[2]*dMax[2]*dMax[2]); + sigma[2] = factor*(xLocal[2]-xMax[2])*(xLocal[2]-xMax[2]); + } + } + }; + + template< typename FE_TYPE > + struct PMLKernel + { + + PMLKernel( FE_TYPE const & finiteElement ) + : m_finiteElement( finiteElement ) + {} + + /** + * @brief Launches the computation of field gradients and divergence for PML region + * @tparam EXEC_POLICY the execution policy + * @tparam ATOMIC_POLICY the atomic policy + * @param[in] targetSet list of cells in the target set + * @param[in] nodeCoords coordinates of the nodes + * @param[in] elemToNodes constant array view of map from element to nodes + * @param[in] velocity cell-wise velocity + * @param[in] p_n pressure field at time n + * @param[in] v_n PML auxiliary field at time n + * @param[in] u_n PML auxiliary field at time n + * @param[in] xMin coordinate limits of the inner PML boundaries, left-front-top + * @param[in] xMax coordinate limits of the inner PML boundaries, right-back-bottom + * @param[in] dMin PML thickness, left-front-top + * @param[in] dMax PML thickness, right-back-bottom + * @param[in] cMin PML wave speed, left-front-top + * @param[in] cMax PML wave speed, right-back-bottom + * @param[in] r desired reflectivity of the PML + * @param[out] grad_n array holding the gradients at time n + * @param[out] divV_n array holding the divergence at time n + */ + template< typename EXEC_POLICY, typename ATOMIC_POLICY > + void + launch( SortedArrayView< localIndex const > const targetSet, + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, + traits::ViewTypeConst< CellElementSubRegion::NodeMapType > const elemToNodes, + arrayView1d< real32 const > const velocity, + arrayView1d< real32 const > const p_n, + arrayView2d< real32 const > const v_n, + arrayView1d< real32 const > const u_n, + real32 const (&xMin)[3], + real32 const (&xMax)[3], + real32 const (&dMin)[3], + real32 const (&dMax)[3], + real32 const (&cMin)[3], + real32 const (&cMax)[3], + real32 const r, + arrayView2d< real32 > const grad_n, + arrayView1d< real32 > const divV_n ) + { + /// Loop over elements in the subregion, 'l' is the element index within the target set + forAll< EXEC_POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const l ) + { + constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; + + /// global element index + localIndex const k = targetSet[l]; + + /// wave speed at the element + real32 const c = velocity[k]; + + /// coordinates of the element nodes + real64 xLocal[ numNodesPerElem ][ 3 ]; + real32 xLocal32[ numNodesPerElem ][ 3 ]; + + /// local arrays to store the pressure at all nodes and its gradient at a given node + real64 pressure[ numNodesPerElem ]; + real64 pressureGrad[ 3 ]; + + /// local arrays to store the PML vectorial auxiliary variable at all nodes and its gradient at a given node + real64 auxV[3][ numNodesPerElem ]; + real64 auxVGrad[3][3]; + + /// local arrays to store the PML scalar auxiliary variable at all nodes and its gradient at a given node + real64 auxU[ numNodesPerElem ]; + real64 auxUGrad[3]; + + /// local array to store the PML damping profile + real32 sigma[ 3 ]; + + /// copy from global to local arrays + for( localIndex i=0; i( k, i, xLocal, gradN ); + GEOS_UNUSED_VAR ( detJ ); + + /// compute the gradient of the pressure and the PML auxiliary variables at the node + m_finiteElement.template gradient< numNodesPerElem, GRADIENT_TYPE >( gradN, pressure, pressureGrad ); + m_finiteElement.template gradient< numNodesPerElem, GRADIENT_TYPE >( gradN, auxU, auxUGrad ); + for( int j=0; j<3; ++j ) + { + m_finiteElement.template gradient< numNodesPerElem, GRADIENT_TYPE >( gradN, auxV[j], auxVGrad[j] ); + } + + /// compute the PML damping profile + ComputeDamping::computeDampingProfile( + xLocal32[i], + xMin, + xMax, + dMin, + dMax, + cMin, + cMax, + r, + sigma ); + + /// compute B.pressureGrad - C.auxUGrad where B and C are functions of the damping profile + /// WARNING: the division by 'numNodesPerElem' below is needed because the average of + /// gradient and divergence at the nodes are sought. It is the number of cells contributing + /// to each node that is needed. In this case, it is equal to 'numNodesPerElem'. For high-order + /// SEM, this approach won't work and the average needs to be computed differently (maybe using counters). + real32 localIncrementArray[3]; + localIncrementArray[0] = (sigma[0]-sigma[1]-sigma[2])*pressureGrad[0] - (sigma[1]*sigma[2])*auxUGrad[0]; + localIncrementArray[1] = (sigma[1]-sigma[0]-sigma[2])*pressureGrad[1] - (sigma[0]*sigma[2])*auxUGrad[1]; + localIncrementArray[2] = (sigma[2]-sigma[0]-sigma[1])*pressureGrad[2] - (sigma[0]*sigma[1])*auxUGrad[2]; + for( int j=0; j<3; ++j ) + { + RAJA::atomicAdd< ATOMIC_POLICY >( &grad_n[elemToNodes( k, i )][j], localIncrementArray[j]/numNodesPerElem ); + } + /// compute beta.pressure + gamma.u - c^2 * divV where beta and gamma are functions of the damping profile + real32 const beta = sigma[0]*sigma[1]+sigma[0]*sigma[2]+sigma[1]*sigma[2]; + real32 const gamma = sigma[0]*sigma[1]*sigma[2]; + real32 const localIncrement = beta*p_n[elemToNodes( k, i )] + + gamma*u_n[elemToNodes( k, i )] + - c*c*( auxVGrad[0][0] + auxVGrad[1][1] + auxVGrad[2][2] ); + + RAJA::atomicAdd< ATOMIC_POLICY >( &divV_n[elemToNodes( k, i )], localIncrement/numNodesPerElem ); + } + } ); + } + + /// The finite element space/discretization object for the element type in the subRegion + FE_TYPE const & m_finiteElement; + }; + + + template< typename FE_TYPE > + struct waveSpeedPMLKernel + { + + waveSpeedPMLKernel( FE_TYPE const & finiteElement ) + : m_finiteElement( finiteElement ) + {} + + /** + * @brief Launches the computation of average wave speeds in the PML region + * @tparam EXEC_POLICY the execution policy + * @tparam ATOMIC_POLICY the atomic policy + * @param[in] targetSet list of cells in the target set + * @param[in] nodeCoords coordinates of the nodes + * @param[in] elemToNodes constant array view of map from element to nodes + * @param[in] velocity cell-wise velocity + * @param[in] xMin coordinate limits of the inner PML boundaries, left-front-top + * @param[in] xMax coordinate limits of the inner PML boundaries, right-back-bottom + * @param[out] cMin PML wave speed, left-front-top + * @param[out] cMax PML wave speed, right-back-bottom + * @param[out] counterMin PML wave speed counter, left-front-top + * @param[out] counterMax PML wave speed counter, left-front-top + */ + template< typename EXEC_POLICY, typename ATOMIC_POLICY > + void + launch( SortedArrayView< localIndex const > const targetSet, + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, + traits::ViewTypeConst< CellElementSubRegion::NodeMapType > const elemToNodes, + arrayView1d< real32 const > const velocity, + real32 const (&xMin)[3], + real32 const (&xMax)[3], + real32 (& cMin)[3], + real32 (& cMax)[3], + int (& counterMin)[3], + int (& counterMax)[3] ) + { + + RAJA::ReduceSum< parallelDeviceReduce, real32 > subRegionAvgWaveSpeedLeft( 0.0 ); + RAJA::ReduceSum< parallelDeviceReduce, real32 > subRegionAvgWaveSpeedRight( 0.0 ); + RAJA::ReduceSum< parallelDeviceReduce, real32 > subRegionAvgWaveSpeedFront( 0.0 ); + RAJA::ReduceSum< parallelDeviceReduce, real32 > subRegionAvgWaveSpeedBack( 0.0 ); + RAJA::ReduceSum< parallelDeviceReduce, real32 > subRegionAvgWaveSpeedTop( 0.0 ); + RAJA::ReduceSum< parallelDeviceReduce, real32 > subRegionAvgWaveSpeedBottom( 0.0 ); + RAJA::ReduceSum< parallelDeviceReduce, int > subRegionAvgWaveSpeedCounterLeft( 0 ); + RAJA::ReduceSum< parallelDeviceReduce, int > subRegionAvgWaveSpeedCounterRight( 0 ); + RAJA::ReduceSum< parallelDeviceReduce, int > subRegionAvgWaveSpeedCounterFront( 0 ); + RAJA::ReduceSum< parallelDeviceReduce, int > subRegionAvgWaveSpeedCounterBack( 0 ); + RAJA::ReduceSum< parallelDeviceReduce, int > subRegionAvgWaveSpeedCounterTop( 0 ); + RAJA::ReduceSum< parallelDeviceReduce, int > subRegionAvgWaveSpeedCounterBottom( 0 ); + + /// Loop over elements in the subregion, 'l' is the element index within the target set + forAll< EXEC_POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const l ) + { + constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; + + /// global element index + localIndex const k = targetSet[l]; + + /// wave speed at the element + real32 const c = velocity[k]; + + /// coordinates of the element center + real64 xLocal[ 3 ] = {0.0, 0.0, 0.0}; + + /// compute the coordinates of the element center + for( int j=0; j<3; ++j ) + { + for( localIndex i=0; i= xMin[1] && xLocal[1] <= xMax[1] + && xLocal[2] >= xMin[2] && xLocal[2] <= xMax[2] ) + { + subRegionAvgWaveSpeedLeft += c; + subRegionAvgWaveSpeedCounterLeft += 1; + } + else if( xLocal[0] > xMax[0] + && xLocal[1] >= xMin[1] && xLocal[1] <= xMax[1] + && xLocal[2] >= xMin[2] && xLocal[2] <= xMax[2] ) + { + subRegionAvgWaveSpeedRight += c; + subRegionAvgWaveSpeedCounterRight += 1; + } + if( xLocal[1] < xMin[1] + && xLocal[0] >= xMin[0] && xLocal[0] <= xMax[0] + && xLocal[2] >= xMin[2] && xLocal[2] <= xMax[2] ) + { + subRegionAvgWaveSpeedFront += c; + subRegionAvgWaveSpeedCounterFront += 1; + } + else if( xLocal[1] > xMax[1] + && xLocal[0] >= xMin[0] && xLocal[0] <= xMax[0] + && xLocal[2] >= xMin[2] && xLocal[2] <= xMax[2] ) + { + subRegionAvgWaveSpeedBack += c; + subRegionAvgWaveSpeedCounterBack += 1; + } + if( xLocal[2] < xMin[2] + && xLocal[0] >= xMin[0] && xLocal[0] <= xMax[0] + && xLocal[1] >= xMin[1] && xLocal[1] <= xMax[1] ) + { + subRegionAvgWaveSpeedTop += c; + subRegionAvgWaveSpeedCounterTop += 1; + } + else if( xLocal[2] > xMax[2] + && xLocal[0] >= xMin[0] && xLocal[0] <= xMax[0] + && xLocal[1] >= xMin[1] && xLocal[1] <= xMax[1] ) + { + subRegionAvgWaveSpeedBottom += c; + subRegionAvgWaveSpeedCounterBottom += 1; + } + } ); + + /// transfer local results to global variables + cMin[0]+=subRegionAvgWaveSpeedLeft.get(); + cMin[1]+=subRegionAvgWaveSpeedFront.get(); + cMin[2]+=subRegionAvgWaveSpeedTop.get(); + cMax[0]+=subRegionAvgWaveSpeedRight.get(); + cMax[1]+=subRegionAvgWaveSpeedBack.get(); + cMax[2]+=subRegionAvgWaveSpeedBottom.get(); + counterMin[0]+=subRegionAvgWaveSpeedCounterLeft.get(); + counterMin[1]+=subRegionAvgWaveSpeedCounterFront.get(); + counterMin[2]+=subRegionAvgWaveSpeedCounterTop.get(); + counterMax[0]+=subRegionAvgWaveSpeedCounterRight.get(); + counterMax[1]+=subRegionAvgWaveSpeedCounterBack.get(); + counterMax[2]+=subRegionAvgWaveSpeedCounterBottom.get(); + } + + /// The finite element space/discretization object for the element type in the subRegion + FE_TYPE const & m_finiteElement; + }; + + +}; + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICPMLSEMKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/AcousticWaveEquationSEM.cpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEM.cpp similarity index 75% rename from src/coreComponents/physicsSolvers/wavePropagation/AcousticWaveEquationSEM.cpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEM.cpp index 0dc0f3f97c7..c47e6e83fc1 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/AcousticWaveEquationSEM.cpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEM.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -25,8 +26,14 @@ #include "fieldSpecification/PerfectlyMatchedLayer.hpp" #include "mainInterface/ProblemManager.hpp" #include "mesh/ElementType.hpp" +#include "mesh/DomainPartition.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" -#include "WaveSolverUtils.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverUtils.hpp" +#include "physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticTimeSchemeSEMKernel.hpp" +#include "physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticMatricesSEMKernel.hpp" +#include "events/EventManager.hpp" +#include "AcousticPMLSEMKernel.hpp" +#include "physicsSolvers/wavePropagation/shared/PrecomputeSourcesAndReceiversKernel.hpp" namespace geos { @@ -70,7 +77,7 @@ void AcousticWaveEquationSEM::registerDataOnMesh( Group & meshBodies ) nodeManager.registerField< acousticfields::Pressure_nm1, acousticfields::Pressure_n, acousticfields::Pressure_np1, - acousticfields::PressureDoubleDerivative, + acousticfields::PressureForward, acousticfields::ForcingRHS, acousticfields::AcousticMassVector, acousticfields::DampingVector, @@ -99,31 +106,29 @@ void AcousticWaveEquationSEM::registerDataOnMesh( Group & meshBodies ) subRegion.registerField< acousticfields::AcousticVelocity >( getName() ); subRegion.registerField< acousticfields::AcousticDensity >( getName() ); subRegion.registerField< acousticfields::PartialGradient >( getName() ); + subRegion.registerField< acousticfields::PartialGradient2 >( getName() ); } ); } ); } -void AcousticWaveEquationSEM::postProcessInput() +void AcousticWaveEquationSEM::postInputInitialization() { - WaveSolverBase::postProcessInput(); + WaveSolverBase::postInputInitialization(); m_pressureNp1AtReceivers.resize( m_nsamplesSeismoTrace, m_receiverCoordinates.size( 0 ) + 1 ); } -void AcousticWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & mesh, +void AcousticWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & baseMesh, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) { GEOS_MARK_FUNCTION; - NodeManager const & nodeManager = mesh.getNodeManager(); - FaceManager const & faceManager = mesh.getFaceManager(); - arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const - nodeCoords32 = nodeManager.getField< fields::referencePosition32 >().toViewConst(); - - arrayView2d< real64 const > const faceNormal = faceManager.faceNormal(); - arrayView2d< real64 const > const faceCenter = faceManager.faceCenter(); + arrayView1d< globalIndex const > const nodeLocalToGlobalMap = baseMesh.getNodeManager().localToGlobalMap().toViewConst(); + ArrayOfArraysView< localIndex const > const nodesToElements = baseMesh.getNodeManager().elementList().toViewConst(); + ArrayOfArraysView< localIndex const > const facesToNodes = baseMesh.getFaceManager().nodeList().toViewConst(); + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const nodeCoords = baseMesh.getNodeManager().referencePosition(); arrayView2d< real64 const > const sourceCoordinates = m_sourceCoordinates.toViewConst(); arrayView2d< localIndex > const sourceNodeIds = m_sourceNodeIds.toView(); @@ -141,20 +146,11 @@ void AcousticWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & mesh, receiverConstants.setValues< EXEC_POLICY >( -1 ); receiverIsLocal.zero(); - arrayView2d< real32 > const sourceValue = m_sourceValue.toView(); - real64 dt = 0; - EventManager const & event = getGroupByPath< EventManager >( "/Problem/Events" ); - for( localIndex numSubEvent = 0; numSubEvent < event.numSubGroups(); ++numSubEvent ) - { - EventBase const * subEvent = static_cast< EventBase const * >( event.getSubGroups()[numSubEvent] ); - if( subEvent->getEventName() == "/Solvers/" + getName() ) - { - dt = subEvent->getReference< real64 >( EventBase::viewKeyStruct::forceDtString() ); - } - } - - mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, - CellElementSubRegion & elementSubRegion ) + mesh.getElemManager().forElementSubRegionsComplete< CellElementSubRegion >( regionNames, [&]( localIndex const, + localIndex const er, + localIndex const esr, + ElementRegionBase &, + CellElementSubRegion & elementSubRegion ) { GEOS_THROW_IF( elementSubRegion.getElementType() != ElementType::Hexahedron, getDataContext() << ": Invalid type of element, the acoustic solver is designed for hexahedral meshes only (C3D8), using the SEM formulation", @@ -162,8 +158,10 @@ void AcousticWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & mesh, arrayView2d< localIndex const > const elemsToFaces = elementSubRegion.faceList(); arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes = elementSubRegion.nodeList(); + arrayView2d< localIndex const, cells::NODE_MAP_USD > const & baseElemsToNodes = baseMesh.getElemManager().getRegion( er ).getSubRegion< CellElementSubRegion >( esr ).nodeList(); arrayView2d< real64 const > const elemCenter = elementSubRegion.getElementCenter(); arrayView1d< integer const > const elemGhostRank = elementSubRegion.ghostRank(); + arrayView1d< globalIndex const > const elemLocalToGlobalMap = elementSubRegion.localToGlobalMap().toViewConst(); finiteElement::FiniteElementBase const & fe = elementSubRegion.getReference< finiteElement::FiniteElementBase >( getDiscretizationName() ); @@ -171,22 +169,22 @@ void AcousticWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & mesh, { using FE_TYPE = TYPEOFREF( finiteElement ); - localIndex const numFacesPerElem = elementSubRegion.numFacesPerElement(); - { GEOS_MARK_SCOPE( acousticWaveEquationSEMKernels::PrecomputeSourceAndReceiverKernel ); - acousticWaveEquationSEMKernels:: - PrecomputeSourceAndReceiverKernel:: - launch< EXEC_POLICY, FE_TYPE > + PreComputeSourcesAndReceivers:: + Compute1DSourceAndReceiverConstants + < EXEC_POLICY, FE_TYPE > ( elementSubRegion.size(), - numFacesPerElem, - nodeCoords32, + facesToNodes, + nodeCoords, + nodeLocalToGlobalMap, + elemLocalToGlobalMap, + nodesToElements, + baseElemsToNodes, elemGhostRank, elemsToNodes, elemsToFaces, elemCenter, - faceNormal, - faceCenter, sourceCoordinates, sourceIsAccessible, sourceNodeIds, @@ -194,34 +192,42 @@ void AcousticWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & mesh, receiverCoordinates, receiverIsLocal, receiverNodeIds, - receiverConstants, - sourceValue, - dt, - m_timeSourceFrequency, - m_timeSourceDelay, - m_rickerOrder ); + receiverConstants ); } } ); + elementSubRegion.faceList().freeOnDevice(); + baseMesh.getElemManager().getRegion( er ).getSubRegion< CellElementSubRegion >( esr ).nodeList().freeOnDevice(); + elementSubRegion.getElementCenter().freeOnDevice(); + elementSubRegion.ghostRank().freeOnDevice(); + elementSubRegion.localToGlobalMap().freeOnDevice(); } ); + baseMesh.getNodeManager().localToGlobalMap().freeOnDevice(); + baseMesh.getNodeManager().elementList().toView().freeOnDevice(); + baseMesh.getFaceManager().nodeList().toView().freeOnDevice(); + baseMesh.getNodeManager().referencePosition().freeOnDevice(); + facesToNodes.freeOnDevice(); + nodesToElements.freeOnDevice(); } -void AcousticWaveEquationSEM::addSourceToRightHandSide( integer const & cycleNumber, arrayView1d< real32 > const rhs ) +void AcousticWaveEquationSEM::addSourceToRightHandSide( real64 const & time_n, arrayView1d< real32 > const rhs ) { arrayView2d< localIndex const > const sourceNodeIds = m_sourceNodeIds.toViewConst(); arrayView2d< real64 const > const sourceConstants = m_sourceConstants.toViewConst(); arrayView1d< localIndex const > const sourceIsAccessible = m_sourceIsAccessible.toViewConst(); - arrayView2d< real32 const > const sourceValue = m_sourceValue.toViewConst(); - - GEOS_THROW_IF( cycleNumber > sourceValue.size( 0 ), - getDataContext() << ": Too many steps compared to array size", - std::runtime_error ); + real32 const timeSourceFrequency = m_timeSourceFrequency; + real32 const timeSourceDelay = m_timeSourceDelay; + localIndex const rickerOrder = m_rickerOrder; + bool useSourceWaveletTables = m_useSourceWaveletTables; + arrayView1d< TableFunction::KernelWrapper const > const sourceWaveletTableWrappers = m_sourceWaveletTableWrappers.toViewConst(); forAll< EXEC_POLICY >( sourceConstants.size( 0 ), [=] GEOS_HOST_DEVICE ( localIndex const isrc ) { if( sourceIsAccessible[isrc] == 1 ) { + real64 const srcValue = + useSourceWaveletTables ? sourceWaveletTableWrappers[ isrc ].compute( &time_n ) : WaveSolverUtils::evaluateRicker( time_n, timeSourceFrequency, timeSourceDelay, rickerOrder ); for( localIndex inode = 0; inode < sourceConstants.size( 1 ); ++inode ) { - real32 const localIncrement = sourceConstants[isrc][inode] * sourceValue[cycleNumber][isrc]; + real32 const localIncrement = sourceConstants[isrc][inode] * srcValue; RAJA::atomicAdd< ATOMIC_POLICY >( &rhs[sourceNodeIds[isrc][inode]], localIncrement ); } } @@ -244,11 +250,14 @@ void AcousticWaveEquationSEM::initializePostInitialConditionsPreSubGroups() applyFreeSurfaceBC( 0.0, domain ); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshBodyName, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) { - precomputeSourceAndReceiverTerm( mesh, regionNames ); + MeshLevel & baseMesh = domain.getMeshBodies().getGroup< MeshBody >( meshBodyName ).getBaseDiscretization(); + precomputeSourceAndReceiverTerm( baseMesh, mesh, regionNames ); NodeManager & nodeManager = mesh.getNodeManager(); FaceManager & faceManager = mesh.getFaceManager(); @@ -288,38 +297,163 @@ void AcousticWaveEquationSEM::initializePostInitialConditionsPreSubGroups() /// Partial gradient if gradient as to be computed arrayView1d< real32 > grad = elementSubRegion.getField< acousticfields::PartialGradient >(); + grad.zero(); + arrayView1d< real32 > grad2 = elementSubRegion.getField< acousticfields::PartialGradient2 >(); + grad2.zero(); finiteElement::FiniteElementDispatchHandler< SEM_FE_TYPES >::dispatch3D( fe, [&] ( auto const finiteElement ) { using FE_TYPE = TYPEOFREF( finiteElement ); - acousticWaveEquationSEMKernels::MassMatrixKernel< FE_TYPE > kernelM( finiteElement ); - kernelM.template launch< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), - nodeCoords, - elemsToNodes, - velocity, - density, - mass ); - - acousticWaveEquationSEMKernels::DampingMatrixKernel< FE_TYPE > kernelD( finiteElement ); - kernelD.template launch< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), - nodeCoords, - elemsToFaces, - facesToNodes, - facesDomainBoundaryIndicator, - freeSurfaceFaceIndicator, - velocity, - density, - damping ); + AcousticMatricesSEM::MassMatrix< FE_TYPE > kernelM( finiteElement ); + kernelM.template computeMassMatrix< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), + nodeCoords, + elemsToNodes, + velocity, + density, + mass ); + + AcousticMatricesSEM::DampingMatrix< FE_TYPE > kernelD( finiteElement ); + kernelD.template computeDampingMatrix< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), + nodeCoords, + elemsToFaces, + facesToNodes, + facesDomainBoundaryIndicator, + freeSurfaceFaceIndicator, + velocity, + density, + damping ); + } ); } ); } ); + if( m_timestepStabilityLimit==1 ) + { + real64 dtOut = 0.0; + computeTimeStep( dtOut ); + m_timestepStabilityLimit = 0; + m_timeStep=dtOut; + } + + WaveSolverUtils::initTrace( "seismoTraceReceiver", getName(), m_outputSeismoTrace, m_receiverConstants.size( 0 ), m_receiverIsLocal ); } +//This function is only to give an easy accesss to the computation of the time-step for Pygeosx interface and avoid to exit the code when +// using Pygeosx + +real64 AcousticWaveEquationSEM::computeTimeStep( real64 & dtOut ) +{ + + DomainPartition & domain = getGroupByPath< DomainPartition >( "/Problem/domain" ); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + + NodeManager & nodeManager = mesh.getNodeManager(); + + arrayView1d< real32 > const mass = nodeManager.getField< acousticfields::AcousticMassVector >(); + arrayView1d< real32 > const p = nodeManager.getField< acousticfields::Pressure_n >(); + arrayView1d< real32 > const stiffnessVector = nodeManager.getField< acousticfields::StiffnessVector >(); + + localIndex const sizeNode = nodeManager.size(); + + real64 const epsilon = 0.00001; + localIndex const nIterMax = 10000; + localIndex numberIter = 0; + localIndex counter = 0; + real64 lambdaNew = 0.0; + + //Randomize p values + srand( time( NULL )); + for( localIndex a = 0; a < sizeNode; ++a ) + { + p[a] = (real64)rand()/(real64) RAND_MAX; + } + + //Step 1: Normalize randomized pressure + real64 normP= 0.0; + WaveSolverUtils::dotProduct( sizeNode, p, p, normP ); + + forAll< EXEC_POLICY >( sizeNode, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + p[a]/= sqrt( normP ); + } ); + + //Step 2: Iterations of M^{-1}K)p until we found the max eigenvalues + auto kernelFactory = acousticWaveEquationSEMKernels::ExplicitAcousticSEMFactory( dtOut ); + real64 dotProductPPaux = 0.0; + real64 normPaux = 0.0; + real64 lambdaOld = lambdaNew; + do + { + stiffnessVector.zero(); + + finiteElement:: + regionBasedKernelApplication< EXEC_POLICY, + constitutive::NullModel, + CellElementSubRegion >( mesh, + regionNames, + getDiscretizationName(), + "", + kernelFactory ); + + forAll< EXEC_POLICY >( sizeNode, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + stiffnessVector[a]/= mass[a]; + } ); + + lambdaOld = lambdaNew; + + dotProductPPaux = 0.0; + normP=0.0; + WaveSolverUtils::dotProduct( sizeNode, p, stiffnessVector, dotProductPPaux ); + WaveSolverUtils::dotProduct( sizeNode, p, p, normP ); + + lambdaNew = dotProductPPaux/normP; + + normPaux = 0.0; + WaveSolverUtils::dotProduct( sizeNode, stiffnessVector, stiffnessVector, normPaux ); + + forAll< EXEC_POLICY >( sizeNode, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + p[a] = stiffnessVector[a]/( normPaux ); + } ); + + if( LvArray::math::abs( lambdaNew-lambdaOld )/LvArray::math::abs( lambdaNew )<= epsilon ) + { + counter++; + } + else + { + counter=0; + } + + numberIter++; + + + } + while (counter < 10 && numberIter < nIterMax); + + GEOS_THROW_IF( numberIter> nIterMax, "Power Iteration algorithm does not converge", std::runtime_error ); + + // We use 1.99 instead of 2 to have a 5% margin error + real64 dt = 1.99/sqrt( LvArray::math::abs( lambdaNew )); + + dtOut = MpiWrapper::min( dt ); + + stiffnessVector.zero(); + p.zero(); + } ); + return m_timeStep * m_cflFactor; +} + + void AcousticWaveEquationSEM::applyFreeSurfaceBC( real64 time, DomainPartition & domain ) { @@ -342,9 +476,6 @@ void AcousticWaveEquationSEM::applyFreeSurfaceBC( real64 time, DomainPartition & /// array of indicators: 1 if a node is on on free surface; 0 otherwise arrayView1d< localIndex > const freeSurfaceNodeIndicator = nodeManager.getField< acousticfields::AcousticFreeSurfaceNodeIndicator >(); - // freeSurfaceFaceIndicator.zero(); - // freeSurfaceNodeIndicator.zero(); - fsManager.apply< FaceManager >( time, domain.getMeshBody( 0 ).getMeshLevel( m_discretizationName ), string( "FreeSurface" ), @@ -426,7 +557,7 @@ void AcousticWaveEquationSEM::initializePML() NodeManager & nodeManager = mesh.getNodeManager(); /// WARNING: the array below is one of the PML auxiliary variables arrayView1d< real32 > const indicatorPML = nodeManager.getField< acousticfields::AuxiliaryVar4PML >(); - arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords32 = nodeManager.getField< fields::referencePosition32 >().toViewConst(); + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords32 = nodeManager.getField< fields::referencePosition32 >().toViewConst(); indicatorPML.zero(); real32 xInteriorMin[3]{}; @@ -565,7 +696,7 @@ void AcousticWaveEquationSEM::initializePML() { using FE_TYPE = TYPEOFREF( finiteElement ); - acousticWaveEquationSEMKernels:: + AcousticPMLSEM:: waveSpeedPMLKernel< FE_TYPE > kernel( finiteElement ); kernel.template launch< EXEC_POLICY, ATOMIC_POLICY > ( targetSet, @@ -713,7 +844,7 @@ void AcousticWaveEquationSEM::applyPML( real64 const time, DomainPartition & dom using FE_TYPE = TYPEOFREF( finiteElement ); /// apply the PML kernel - acousticWaveEquationSEMKernels:: + AcousticPMLSEM:: PMLKernel< FE_TYPE > kernel( finiteElement ); kernel.template launch< EXEC_POLICY, ATOMIC_POLICY > ( targetSet, @@ -744,7 +875,7 @@ real64 AcousticWaveEquationSEM::explicitStepForward( real64 const & time_n, DomainPartition & domain, bool computeGradient ) { - real64 dtOut = explicitStepInternal( time_n, dt, cycleNumber, domain ); + real64 dtCompute = explicitStepInternal( time_n, dt, domain ); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, @@ -753,43 +884,35 @@ real64 AcousticWaveEquationSEM::explicitStepForward( real64 const & time_n, { NodeManager & nodeManager = mesh.getNodeManager(); - arrayView1d< real32 > const p_nm1 = nodeManager.getField< acousticfields::Pressure_nm1 >(); arrayView1d< real32 > const p_n = nodeManager.getField< acousticfields::Pressure_n >(); - arrayView1d< real32 > const p_np1 = nodeManager.getField< acousticfields::Pressure_np1 >(); if( computeGradient && cycleNumber >= 0 ) { - arrayView1d< real32 > const p_dt2 = nodeManager.getField< acousticfields::PressureDoubleDerivative >(); - if( m_enableLifo ) { if( !m_lifo ) { - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); - std::string lifoPrefix = GEOS_FMT( "lifo/rank_{:05}/pdt2_shot{:06}", rank, m_shotIndex ); - m_lifo = std::make_unique< LifoStorage< real32, localIndex > >( lifoPrefix, p_dt2, m_lifoOnDevice, m_lifoOnHost, m_lifoSize ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); + std::string lifoPrefix = GEOS_FMT( "lifo/rank_{:05}/p_forward_shot{:06}", rank, m_shotIndex ); + m_lifo = std::make_unique< LifoStorage< real32, localIndex > >( lifoPrefix, p_n, m_lifoOnDevice, m_lifoOnHost, m_lifoSize ); } m_lifo->pushWait(); } - forAll< EXEC_POLICY >( nodeManager.size(), [=] GEOS_HOST_DEVICE ( localIndex const nodeIdx ) - { - p_dt2[nodeIdx] = (p_np1[nodeIdx] - 2*p_n[nodeIdx] + p_nm1[nodeIdx]) / pow( dt, 2 ); - } ); if( m_enableLifo ) { // Need to tell LvArray data is on GPU to avoir HtoD copy - p_dt2.move( MemorySpace::cuda, false ); - m_lifo->pushAsync( p_dt2 ); + p_n.move( LvArray::MemorySpace::cuda, false ); + m_lifo->pushAsync( p_n ); } else { GEOS_MARK_SCOPE ( DirectWrite ); - p_dt2.move( MemorySpace::host, false ); - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); - std::string fileName = GEOS_FMT( "lifo/rank_{:05}/pressuredt2_{:06}_{:08}.dat", rank, m_shotIndex, cycleNumber ); + p_n.move( LvArray::MemorySpace::host, false ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); + std::string fileName = GEOS_FMT( "lifo/rank_{:05}/pressure_forward_{:06}_{:08}.dat", rank, m_shotIndex, cycleNumber ); int lastDirSeparator = fileName.find_last_of( "/\\" ); std::string dirName = fileName.substr( 0, lastDirSeparator ); if( string::npos != (size_t)lastDirSeparator && !directoryExists( dirName )) @@ -801,7 +924,7 @@ real64 AcousticWaveEquationSEM::explicitStepForward( real64 const & time_n, GEOS_THROW_IF( !wf, getDataContext() << ": Could not open file "<< fileName << " for writing", InputError ); - wf.write( (char *)&p_dt2[0], p_dt2.size()*sizeof( real32 ) ); + wf.write( (char *)&p_n[0], p_n.size()*sizeof( real32 ) ); wf.close( ); GEOS_THROW_IF( !wf.good(), getDataContext() << ": An error occured while writing "<< fileName, @@ -813,7 +936,7 @@ real64 AcousticWaveEquationSEM::explicitStepForward( real64 const & time_n, prepareNextTimestep( mesh ); } ); - return dtOut; + return dtCompute; } @@ -823,7 +946,7 @@ real64 AcousticWaveEquationSEM::explicitStepBackward( real64 const & time_n, DomainPartition & domain, bool computeGradient ) { - real64 dtOut = explicitStepInternal( time_n, dt, cycleNumber, domain ); + real64 dtCompute = explicitStepInternal( time_n, dt, domain ); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & mesh, @@ -831,12 +954,18 @@ real64 AcousticWaveEquationSEM::explicitStepBackward( real64 const & time_n, { NodeManager & nodeManager = mesh.getNodeManager(); - arrayView1d< real32 const > const mass = nodeManager.getField< acousticfields::AcousticMassVector >(); - arrayView1d< real32 > const p_nm1 = nodeManager.getField< acousticfields::Pressure_nm1 >(); arrayView1d< real32 > const p_n = nodeManager.getField< acousticfields::Pressure_n >(); arrayView1d< real32 > const p_np1 = nodeManager.getField< acousticfields::Pressure_np1 >(); + //// Compute q_dt2 and store it in p_nm1 + SortedArrayView< localIndex const > const solverTargetNodesSet = m_solverTargetNodesSet.toViewConst(); + forAll< EXEC_POLICY >( solverTargetNodesSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const n ) + { + localIndex const a = solverTargetNodesSet[n]; + p_nm1[a] = (p_np1[a] - 2*p_n[a] + p_nm1[a]) / pow( dt, 2 ); + } ); + EventManager const & event = getGroupByPath< EventManager >( "/Problem/Events" ); real64 const & maxTime = event.getReference< real64 >( EventManager::viewKeyStruct::maxTimeString() ); int const maxCycle = int(round( maxTime / dt )); @@ -845,11 +974,11 @@ real64 AcousticWaveEquationSEM::explicitStepBackward( real64 const & time_n, { ElementRegionManager & elemManager = mesh.getElemManager(); - arrayView1d< real32 > const p_dt2 = nodeManager.getField< acousticfields::PressureDoubleDerivative >(); + arrayView1d< real32 > const p_forward = nodeManager.getField< acousticfields::PressureForward >(); if( m_enableLifo ) { - m_lifo->pop( p_dt2 ); + m_lifo->pop( p_forward ); if( m_lifo->empty() ) delete m_lifo.release(); } @@ -857,45 +986,68 @@ real64 AcousticWaveEquationSEM::explicitStepBackward( real64 const & time_n, { GEOS_MARK_SCOPE ( DirectRead ); - int const rank = MpiWrapper::commRank( MPI_COMM_GEOSX ); - std::string fileName = GEOS_FMT( "lifo/rank_{:05}/pressuredt2_{:06}_{:08}.dat", rank, m_shotIndex, cycleNumber ); + int const rank = MpiWrapper::commRank( MPI_COMM_GEOS ); + std::string fileName = GEOS_FMT( "lifo/rank_{:05}/pressure_forward_{:06}_{:08}.dat", rank, m_shotIndex, cycleNumber ); std::ifstream wf( fileName, std::ios::in | std::ios::binary ); GEOS_THROW_IF( !wf, getDataContext() << ": Could not open file "<< fileName << " for reading", InputError ); - p_dt2.move( MemorySpace::host, true ); - wf.read( (char *)&p_dt2[0], p_dt2.size()*sizeof( real32 ) ); + p_forward.move( LvArray::MemorySpace::host, true ); + wf.read( (char *)&p_forward[0], p_forward.size()*sizeof( real32 ) ); wf.close( ); remove( fileName.c_str() ); } elemManager.forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, CellElementSubRegion & elementSubRegion ) { - arrayView1d< real32 const > const velocity = elementSubRegion.getField< acousticfields::AcousticVelocity >(); + arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords = nodeManager.getField< fields::referencePosition32 >().toViewConst(); arrayView1d< real32 > grad = elementSubRegion.getField< acousticfields::PartialGradient >(); + arrayView1d< real32 > grad2 = elementSubRegion.getField< acousticfields::PartialGradient2 >(); arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes = elementSubRegion.nodeList(); - constexpr localIndex numNodesPerElem = 8; arrayView1d< integer const > const elemGhostRank = elementSubRegion.ghostRank(); GEOS_MARK_SCOPE ( updatePartialGradient ); - forAll< EXEC_POLICY >( elementSubRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const eltIdx ) + + //COMPUTE GRADIENTS with respect to K=1/rho*c2 (grad) and b=1/rho (grad2) + finiteElement::FiniteElementBase const & + fe = elementSubRegion.getReference< finiteElement::FiniteElementBase >( getDiscretizationName() ); + + finiteElement::FiniteElementDispatchHandler< SEM_FE_TYPES >::dispatch3D( fe, [&] ( auto const finiteElement ) { - if( elemGhostRank[eltIdx]<0 ) - { - for( localIndex i = 0; i < numNodesPerElem; ++i ) - { - localIndex nodeIdx = elemsToNodes[eltIdx][i]; - grad[eltIdx] += (-2/velocity[eltIdx]) * mass[nodeIdx]/8.0 * (p_dt2[nodeIdx] * p_n[nodeIdx]); - } - } + using FE_TYPE = TYPEOFREF( finiteElement ); + + AcousticMatricesSEM::GradientKappaBuoyancy< FE_TYPE > kernelG( finiteElement ); + kernelG.template computeGradient< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), + nodeCoords, + elemsToNodes, + elemGhostRank, + p_nm1, + p_n, + p_forward, + grad, + grad2 ); + + } ); + + // // Change of variables to return grad with respect to c and rho + // arrayView1d< real32 const > const velocity = elementSubRegion.getField< acousticfields::AcousticVelocity >(); + // arrayView1d< real32 const > const density = elementSubRegion.getField< acousticfields::AcousticDensity >(); + // forAll< EXEC_POLICY >( elementSubRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const eltIdx ) + // { + // if( elemGhostRank[eltIdx]<0 ) + // { + // grad2[eltIdx] = -1/(pow(density[eltIdx]*velocity[eltIdx],2)) * grad[eltIdx] - 1/pow(density[eltIdx],2) * grad2[eltIdx]; + // grad[eltIdx]= -2/(density[eltIdx]*pow(velocity[eltIdx],3)) * grad[eltIdx]; + // } + // } ); } ); } prepareNextTimestep( mesh ); } ); - return dtOut; + return dtCompute; } void AcousticWaveEquationSEM::prepareNextTimestep( MeshLevel & mesh ) @@ -924,7 +1076,6 @@ void AcousticWaveEquationSEM::prepareNextTimestep( MeshLevel & mesh ) void AcousticWaveEquationSEM::computeUnknowns( real64 const & time_n, real64 const & dt, - integer cycleNumber, DomainPartition & domain, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) @@ -952,11 +1103,8 @@ void AcousticWaveEquationSEM::computeUnknowns( real64 const & time_n, getDiscretizationName(), "", kernelFactory ); - - EventManager const & event = getGroupByPath< EventManager >( "/Problem/Events" ); - real64 const & minTime = event.getReference< real64 >( EventManager::viewKeyStruct::minTimeString() ); - integer const cycleForSource = int(round( -minTime / dt + cycleNumber )); - addSourceToRightHandSide( cycleForSource, rhs ); + //Modification of cycleNember useful when minTime < 0 + addSourceToRightHandSide( time_n, rhs ); /// calculate your time integrators real64 const dt2 = pow( dt, 2 ); @@ -965,18 +1113,8 @@ void AcousticWaveEquationSEM::computeUnknowns( real64 const & time_n, if( !m_usePML ) { GEOS_MARK_SCOPE ( updateP ); - forAll< EXEC_POLICY >( solverTargetNodesSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const n ) - { - localIndex const a = solverTargetNodesSet[n]; - if( freeSurfaceNodeIndicator[a] != 1 ) - { - p_np1[a] = p_n[a]; - p_np1[a] *= 2.0 * mass[a]; - p_np1[a] -= (mass[a] - 0.5 * dt * damping[a]) * p_nm1[a]; - p_np1[a] += dt2 * (rhs[a] - stiffnessVector[a]); - p_np1[a] /= mass[a] + 0.5 * dt * damping[a]; - } - } ); + AcousticTimeSchemeSEM::LeapFrogWithoutPML( dt, p_np1, p_n, p_nm1, mass, stiffnessVector, damping, + rhs, freeSurfaceNodeIndicator, solverTargetNodesSet ); } else { @@ -1014,7 +1152,7 @@ void AcousticWaveEquationSEM::computeUnknowns( real64 const & time_n, xLocal[i] = nodeCoords32[a][i]; } - acousticWaveEquationSEMKernels::PMLKernelHelper::computeDampingProfilePML( + AcousticPMLSEM::ComputeDamping::computeDampingProfile( xLocal, xMin, xMax, @@ -1044,7 +1182,6 @@ void AcousticWaveEquationSEM::computeUnknowns( real64 const & time_n, void AcousticWaveEquationSEM::synchronizeUnknowns( real64 const & time_n, real64 const & dt, - integer const, DomainPartition & domain, MeshLevel & mesh, arrayView1d< string const > const & ) @@ -1068,6 +1205,7 @@ void AcousticWaveEquationSEM::synchronizeUnknowns( real64 const & time_n, acousticfields::AuxiliaryVar4PML::key() } ); } + CommunicationTools & syncFields = CommunicationTools::getInstance(); syncFields.synchronizeFields( fieldsToBeSync, mesh, @@ -1090,22 +1228,24 @@ void AcousticWaveEquationSEM::synchronizeUnknowns( real64 const & time_n, real64 AcousticWaveEquationSEM::explicitStepInternal( real64 const & time_n, real64 const & dt, - integer const cycleNumber, DomainPartition & domain ) { GEOS_MARK_FUNCTION; GEOS_LOG_RANK_0_IF( dt < epsilonLoc, "Warning! Value for dt: " << dt << "s is smaller than local threshold: " << epsilonLoc ); + real64 dtCompute; forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) { - computeUnknowns( time_n, dt, cycleNumber, domain, mesh, regionNames ); - synchronizeUnknowns( time_n, dt, cycleNumber, domain, mesh, regionNames ); + localIndex nSubSteps = (int) ceil( dt/m_timeStep ); + dtCompute = dt/nSubSteps; + computeUnknowns( time_n, dtCompute, domain, mesh, regionNames ); + synchronizeUnknowns( time_n, dtCompute, domain, mesh, regionNames ); } ); - return dt; + return dtCompute; } void AcousticWaveEquationSEM::cleanup( real64 const time_n, @@ -1115,7 +1255,7 @@ void AcousticWaveEquationSEM::cleanup( real64 const time_n, DomainPartition & domain ) { // call the base class cleanup (for reporting purposes) - SolverBase::cleanup( time_n, cycleNumber, eventCounter, eventProgress, domain ); + PhysicsSolverBase::cleanup( time_n, cycleNumber, eventCounter, eventProgress, domain ); // compute the remaining seismic traces, if needed forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, @@ -1133,6 +1273,6 @@ void AcousticWaveEquationSEM::cleanup( real64 const time_n, } ); } -REGISTER_CATALOG_ENTRY( SolverBase, AcousticWaveEquationSEM, string const &, dataRepository::Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, AcousticWaveEquationSEM, string const &, dataRepository::Group * const ) } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/AcousticWaveEquationSEM.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEM.hpp similarity index 86% rename from src/coreComponents/physicsSolvers/wavePropagation/AcousticWaveEquationSEM.hpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEM.hpp index 9396a8201bf..5f3f1c70885 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/AcousticWaveEquationSEM.hpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,10 +21,10 @@ #ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICWAVEEQUATIONSEM_HPP_ #define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICWAVEEQUATIONSEM_HPP_ -#include "WaveSolverBase.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp" #include "mesh/MeshFields.hpp" -#include "physicsSolvers/SolverBase.hpp" -#include "AcousticFields.hpp" +#include "physicsSolvers/PhysicsSolverBase.hpp" +#include "physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticFields.hpp" namespace geos { @@ -52,7 +53,7 @@ class AcousticWaveEquationSEM : public WaveSolverBase static string catalogName() { return "AcousticSEM"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -86,7 +87,7 @@ class AcousticWaveEquationSEM : public WaveSolverBase * @param cycleNumber the cycle number/step number of evaluation of the source * @param rhs the right hand side vector to be computed */ - virtual void addSourceToRightHandSide( integer const & cycleNumber, arrayView1d< real32 > const rhs ); + virtual void addSourceToRightHandSide( real64 const & time_n, arrayView1d< real32 > const rhs ); /** @@ -94,6 +95,11 @@ class AcousticWaveEquationSEM : public WaveSolverBase */ virtual void initializePML() override; + /** + */ + virtual real64 computeTimeStep( real64 & dtOut ) override; + + /** * @brief Overridden from ExecutableGroup. Used to write last seismogram if needed. @@ -117,19 +123,16 @@ class AcousticWaveEquationSEM : public WaveSolverBase */ real64 explicitStepInternal( real64 const & time_n, real64 const & dt, - integer const cycleNumber, DomainPartition & domain ); void computeUnknowns( real64 const & time_n, real64 const & dt, - integer const cycleNumber, DomainPartition & domain, MeshLevel & mesh, arrayView1d< string const > const & regionNames ); void synchronizeUnknowns( real64 const & time_n, real64 const & dt, - integer const cycleNumber, DomainPartition & domain, MeshLevel & mesh, arrayView1d< string const > const & regionNames ); @@ -138,7 +141,7 @@ class AcousticWaveEquationSEM : public WaveSolverBase protected: - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; virtual void initializePostInitialConditionsPreSubGroups() override final; @@ -147,9 +150,10 @@ class AcousticWaveEquationSEM : public WaveSolverBase /** * @brief Locate sources and receivers position in the mesh elements, evaluate the basis functions at each point and save them to the * corresponding elements nodes. + * @param baseMesh the level-0 mesh * @param mesh mesh of the computational domain */ - virtual void precomputeSourceAndReceiverTerm( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) override; + virtual void precomputeSourceAndReceiverTerm( MeshLevel & baseMesh, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) override; /** * @brief Apply free surface condition to the face define in the geometry box from the xml diff --git a/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEMKernel.hpp new file mode 100644 index 00000000000..1e993b9aa4e --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEMKernel.hpp @@ -0,0 +1,229 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AcousticWaveEquationSEMKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICWAVEEQUATIONSEMKERNEL_HPP_ +#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICWAVEEQUATIONSEMKERNEL_HPP_ + +#include "finiteElement/kernelInterface/KernelBase.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverUtils.hpp" +#if !defined( GEOS_USE_HIP ) +#include "finiteElement/elementFormulations/Qk_Hexahedron_Lagrange_GaussLobatto.hpp" +#endif +#include "physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticFields.hpp" + +namespace geos +{ + +/// Namespace to contain the acoustic wave kernels. +namespace acousticWaveEquationSEMKernels +{ + +/** + * @brief Implements kernels for solving the acoustic wave equations + * explicit central FD method and SEM + * @copydoc geos::finiteElement::KernelBase + * @tparam SUBREGION_TYPE The type of subregion that the kernel will act on. + * + * ### AcousticWaveEquationSEMKernel Description + * Implements the KernelBase interface functions required for solving + * the acoustic wave equations using the + * "finite element kernel application" functions such as + * geos::finiteElement::RegionBasedKernelApplication. + * + * The number of degrees of freedom per support point for both + * the test and trial spaces are specified as `1`. + */ + + +template< typename SUBREGION_TYPE, + typename CONSTITUTIVE_TYPE, + typename FE_TYPE > +class ExplicitAcousticSEM : public finiteElement::KernelBase< SUBREGION_TYPE, + CONSTITUTIVE_TYPE, + FE_TYPE, + 1, + 1 > +{ +public: + + /// Alias for the base class; + using Base = finiteElement::KernelBase< SUBREGION_TYPE, + CONSTITUTIVE_TYPE, + FE_TYPE, + 1, + 1 >; + + /// Maximum number of nodes per element, which is equal to the maxNumTestSupportPointPerElem and + /// maxNumTrialSupportPointPerElem by definition. When the FE_TYPE is not a Virtual Element, this + /// will be the actual number of nodes per element. + static constexpr int numNodesPerElem = Base::maxNumTestSupportPointsPerElem; + + using Base::numDofPerTestSupportPoint; + using Base::numDofPerTrialSupportPoint; + using Base::m_elemsToNodes; + using Base::m_elemGhostRank; + using Base::m_constitutiveUpdate; + using Base::m_finiteElementSpace; + +//***************************************************************************** + /** + * @brief Constructor + * @copydoc geos::finiteElement::KernelBase::KernelBase + * @param nodeManager Reference to the NodeManager object. + * @param edgeManager Reference to the EdgeManager object. + * @param faceManager Reference to the FaceManager object. + * @param targetRegionIndex Index of the region the subregion belongs to. + * @param dt The time interval for the step. + * elements to be processed during this kernel launch. + */ + ExplicitAcousticSEM( NodeManager & nodeManager, + EdgeManager const & edgeManager, + FaceManager const & faceManager, + localIndex const targetRegionIndex, + SUBREGION_TYPE const & elementSubRegion, + FE_TYPE const & finiteElementSpace, + CONSTITUTIVE_TYPE & inputConstitutiveType, + real64 const dt ): + Base( elementSubRegion, + finiteElementSpace, + inputConstitutiveType ), + m_nodeCoords( nodeManager.getField< fields::referencePosition32 >() ), + m_p_n( nodeManager.getField< fields::acousticfields::Pressure_n >() ), + m_stiffnessVector( nodeManager.getField< fields::acousticfields::StiffnessVector >() ), + m_density( elementSubRegion.template getField< fields::acousticfields::AcousticDensity >() ), + m_dt( dt ) + { + GEOS_UNUSED_VAR( edgeManager ); + GEOS_UNUSED_VAR( faceManager ); + GEOS_UNUSED_VAR( targetRegionIndex ); + } + + //***************************************************************************** + /** + * @copydoc geos::finiteElement::KernelBase::StackVariables + * + * ### ExplicitAcousticSEM Description + * Adds a stack arrays for the nodal force, primary displacement variable, etc. + */ + struct StackVariables : Base::StackVariables + { +public: + GEOS_HOST_DEVICE + StackVariables(): + xLocal(), + stiffnessVectorLocal() + {} + + /// C-array stack storage for element local the nodal positions. + real64 xLocal[ 8 ][ 3 ]; + real32 stiffnessVectorLocal[ numNodesPerElem ]{}; + real32 invDensity; + }; + //*************************************************************************** + + + /** + * @copydoc geos::finiteElement::KernelBase::setup + * + * Copies the primary variable, and position into the local stack array. + */ + GEOS_HOST_DEVICE + inline + void setup( localIndex const k, + StackVariables & stack ) const + { + stack.invDensity = 1./m_density[k]; + for( localIndex a=0; a< 8; a++ ) + { + localIndex const nodeIndex = m_elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); + for( int i=0; i< 3; ++i ) + { + stack.xLocal[ a ][ i ] = m_nodeCoords[ nodeIndex ][ i ]; + } + } + } + + /** + * @copydoc geos::finiteElement::KernelBase::complete + */ + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + real64 complete( localIndex const k, + StackVariables & stack ) const + { + for( int i=0; i( &m_stiffnessVector[m_elemsToNodes( k, i )], stack.stiffnessVectorLocal[i] ); + } + return 0; + } + + + /** + * @copydoc geos::finiteElement::KernelBase::quadraturePointKernel + * + * ### ExplicitAcousticSEM Description + * Calculates stiffness vector + * + */ + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + void quadraturePointKernel( localIndex const k, + localIndex const q, + StackVariables & stack ) const + { + + m_finiteElementSpace.template computeStiffnessTerm( q, stack.xLocal, [&] ( const int i, const int j, const real64 val ) + { + real32 const localIncrement = stack.invDensity*val*m_p_n[m_elemsToNodes( k, j )]; + stack.stiffnessVectorLocal[ i ] += localIncrement; + } ); + } + +protected: + /// The array containing the nodal position array. + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const m_nodeCoords; + + /// The array containing the nodal pressure array. + arrayView1d< real32 const > const m_p_n; + + /// The array containing the product of the stiffness matrix and the nodal pressure. + arrayView1d< real32 > const m_stiffnessVector; + + /// The array containing the cell-wise density + arrayView1d< real32 const > const m_density; + + /// The time increment for this time integration step. + real64 const m_dt; + + +}; + + + +/// The factory used to construct a ExplicitAcousticWaveEquation kernel. +using ExplicitAcousticSEMFactory = finiteElement::KernelFactory< ExplicitAcousticSEM, + real64 >; + + +} // namespace acousticWaveEquationSEMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICWAVEEQUATIONSEMKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/AcousticFields.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticFields.hpp similarity index 88% rename from src/coreComponents/physicsSolvers/wavePropagation/AcousticFields.hpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticFields.hpp index 903809d893b..5222bc115a3 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/AcousticFields.hpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -58,13 +59,13 @@ DECLARE_FIELD( Pressure_np1, WRITE_AND_READ, "Scalar pressure at time n+1." ); -DECLARE_FIELD( PressureDoubleDerivative, - "pressureDoubleDerivative", +DECLARE_FIELD( PressureForward, + "pressureForward", array1d< real32 >, 0, NOPLOT, WRITE_AND_READ, - "Double derivative of the pressure for each node to compute the gradient" ); + "Pressure field from forward pass on each node to compute the gradient" ); DECLARE_FIELD( Velocity_x, "velocity_x", @@ -98,6 +99,14 @@ DECLARE_FIELD( PartialGradient, WRITE_AND_READ, "Partiel gradient computed during backward propagation" ); +DECLARE_FIELD( PartialGradient2, + "partialGradient2", + array1d< real32 >, + 0, + NOPLOT, + WRITE_AND_READ, + "Partial gradient for density/velocity computed during backward propagation" ); + DECLARE_FIELD( ForcingRHS, "rhs", array1d< real32 >, @@ -141,7 +150,7 @@ DECLARE_FIELD( AcousticVelocity, DECLARE_FIELD( AcousticDensity, "acousticDensity", array1d< real32 >, - 0, + 1, NOPLOT, WRITE_AND_READ, "Medium density of the cell" ); diff --git a/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticMatricesSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticMatricesSEMKernel.hpp new file mode 100644 index 00000000000..279c6c1e834 --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticMatricesSEMKernel.hpp @@ -0,0 +1,224 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AcousticMatricesSEMKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICMATRICESSEMKERNEL_HPP_ +#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICMATRICESSEMKERNEL_HPP_ + +namespace geos +{ + +struct AcousticMatricesSEM +{ + + template< typename FE_TYPE > + struct MassMatrix + { + + MassMatrix( FE_TYPE const & finiteElement ) + : m_finiteElement( finiteElement ) + {} + /** + * @brief Launches the precomputation of the mass matrices + * @tparam EXEC_POLICY the execution policy + * @tparam ATOMIC_POLICY the atomic policy + * @tparam FE_TYPE the type of discretization + * @param[in] finiteElement The finite element discretization used + * @param[in] size the number of cells in the subRegion + * @param[in] numFacesPerElem number of faces per element + * @param[in] nodeCoords coordinates of the nodes + * @param[in] elemsToNodes map from element to nodes + * @param[in] velocity cell-wise velocity + * @param[in] density cell-wise density + * @param[out] mass diagonal of the mass matrix + */ + template< typename EXEC_POLICY, typename ATOMIC_POLICY > + void + computeMassMatrix( localIndex const size, + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, + arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes, + arrayView1d< real32 const > const velocity, + arrayView1d< real32 const > const density, + arrayView1d< real32 > const mass ) + + { + forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const e ) + { + + real32 const invC2 = 1.0 / ( density[e] * pow( velocity[e], 2 ) ); + // only the eight corners of the mesh cell are needed to compute the Jacobian + real64 xLocal[ 8 ][ 3 ]; + for( localIndex a = 0; a < 8; ++a ) + { + localIndex const nodeIndex = elemsToNodes( e, FE_TYPE::meshIndexToLinearIndex3D( a ) ); + for( localIndex i = 0; i < 3; ++i ) + { + xLocal[a][i] = nodeCoords( nodeIndex, i ); + } + } + constexpr localIndex numQuadraturePointsPerElem = FE_TYPE::numQuadraturePoints; + for( localIndex q = 0; q < numQuadraturePointsPerElem; ++q ) + { + real32 const localIncrement = invC2 * m_finiteElement.computeMassTerm( q, xLocal ); + RAJA::atomicAdd< ATOMIC_POLICY >( &mass[elemsToNodes( e, q )], localIncrement ); + } + } ); // end loop over element + } + + FE_TYPE const & m_finiteElement; + + }; + template< typename FE_TYPE > + struct DampingMatrix + { + + DampingMatrix( FE_TYPE const & finiteElement ) + : m_finiteElement( finiteElement ) + {} + + /** + * @brief Launches the precomputation of the damping matrices + * @tparam EXEC_POLICY the execution policy + * @tparam ATOMIC_POLICY the atomic policy + * @param[in] size the number of cells in the subRegion + * @param[in] nodeCoords coordinates of the nodes + * @param[in] elemsToFaces map from elements to faces + * @param[in] facesToNodes map from face to nodes + * @param[in] facesDomainBoundaryIndicator flag equal to 1 if the face is on the boundary, and to 0 otherwise + * @param[in] freeSurfaceFaceIndicator flag equal to 1 if the face is on the free surface, and to 0 otherwise + * @param[in] velocity cell-wise velocity + * @param[in] density cell-wise density + * @param[out] damping diagonal of the damping matrix + */ + template< typename EXEC_POLICY, typename ATOMIC_POLICY > + void + computeDampingMatrix( localIndex const size, + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, + arrayView2d< localIndex const > const elemsToFaces, + ArrayOfArraysView< localIndex const > const facesToNodes, + arrayView1d< integer const > const facesDomainBoundaryIndicator, + arrayView1d< localIndex const > const freeSurfaceFaceIndicator, + arrayView1d< real32 const > const velocity, + arrayView1d< real32 const > const density, + arrayView1d< real32 > const damping ) + { + forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const e ) + { + for( localIndex i = 0; i < elemsToFaces.size( 1 ); ++i ) + { + localIndex const f = elemsToFaces( e, i ); + // face on the domain boundary and not on free surface + if( facesDomainBoundaryIndicator[f] == 1 && freeSurfaceFaceIndicator[f] != 1 ) + { + // only the four corners of the mesh face are needed to compute the Jacobian + real64 xLocal[ 4 ][ 3 ]; + for( localIndex a = 0; a < 4; ++a ) + { + localIndex const nodeIndex = facesToNodes( f, FE_TYPE::meshIndexToLinearIndex2D( a ) ); + for( localIndex d = 0; d < 3; ++d ) + { + xLocal[a][d] = nodeCoords( nodeIndex, d ); + } + } + real32 const alpha = 1.0 / (density[e] * velocity[e]); + constexpr localIndex numNodesPerFace = FE_TYPE::numNodesPerFace; + for( localIndex q = 0; q < numNodesPerFace; ++q ) + { + real32 const localIncrement = alpha * m_finiteElement.computeDampingTerm( q, xLocal ); + RAJA::atomicAdd< ATOMIC_POLICY >( &damping[facesToNodes( f, q )], localIncrement ); + } + } + } + } ); + } + + /// The finite element space/discretization object for the element type in the subRegion + FE_TYPE const & m_finiteElement; + + }; + + template< typename FE_TYPE > + struct GradientKappaBuoyancy + { + + GradientKappaBuoyancy( FE_TYPE const & finiteElement ) + : m_finiteElement( finiteElement ) + {} + + /** + * @brief Launch the computation of the 2 gradients relative to the coeff of the wave equation K=1/rho*c2 and b=1/rho + * @tparam EXEC_POLICY the execution policy + * @tparam ATOMIC_POLICY the atomic policy + * @param[in] size the number of cells in the subRegion + * @param[in] nodeCoords coordinates of the nodes + * @param[in] elemsToNodes map from element to nodes + * @param[in] q_dt2 second order derivative in time of backward + * @param[in] q_n current time step of backward + * @param[in] p_n current time step of forward + * @param[out] grad first part of gradient vector with respect to K=1/rho*c2 + * @param[out] grad2 second part of gradient vector with respact to b=1/rho + */ + template< typename EXEC_POLICY, typename ATOMIC_POLICY > + void + computeGradient( localIndex const size, + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, + arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes, + arrayView1d< integer const > const elemGhostRank, + arrayView1d< real32 const > const q_dt2, + arrayView1d< real32 const > const q_n, + arrayView1d< real32 const > const p_n, + arrayView1d< real32 > const grad, + arrayView1d< real32 > const grad2 ) + + { + forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const e ) + { + if( elemGhostRank[e]<0 ) + { + // only the eight corners of the mesh cell are needed to compute the Jacobian + real64 xLocal[ 8 ][ 3 ]; + for( localIndex a = 0; a < 8; ++a ) + { + localIndex const nodeIndex = elemsToNodes( e, FE_TYPE::meshIndexToLinearIndex3D( a ) ); + for( localIndex i = 0; i < 3; ++i ) + { + xLocal[a][i] = nodeCoords( nodeIndex, i ); + } + } + constexpr localIndex numQuadraturePointsPerElem = FE_TYPE::numQuadraturePoints; + for( localIndex q = 0; q < numQuadraturePointsPerElem; ++q ) + { + localIndex nodeIdx = elemsToNodes( e, q ); + grad[e] += q_dt2[nodeIdx] * p_n[nodeIdx] * m_finiteElement.computeMassTerm( q, xLocal ); + m_finiteElement.template computeStiffnessTerm( q, xLocal, [&] ( const int i, const int j, const real64 val ) + { + grad2[e] += val* q_n[elemsToNodes( e, j )] * p_n[elemsToNodes( e, i )]; + } ); + } + } + } ); // end loop over element + } + /// The finite element space/discretization object for the element type in the subRegion + FE_TYPE const & m_finiteElement; + }; + +}; + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICMATRICESSEMKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticTimeSchemeSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticTimeSchemeSEMKernel.hpp new file mode 100644 index 00000000000..69b78be7a78 --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustic/shared/AcousticTimeSchemeSEMKernel.hpp @@ -0,0 +1,169 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AcousticTimeSchemeSEMKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICTIMESCHEMESEMKERNEL_HPP_ +#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICTIMESCHEMESEMKERNEL_HPP_ + +namespace geos +{ + +struct AcousticTimeSchemeSEM +{ + + using EXEC_POLICY = parallelDevicePolicy< >; + + + /** + * @brief Apply second order Leap-Frog time scheme for isotropic case without PML + * @param[in] dt time-step + * @param[out] p_np1 pressure array at time n+1 (updated here) + * @param[in] p_n pressure array at time n + * @param[in] p_nm1 pressure array at time n-1 + * @param[in] mass the mass matrix + * @param[in] stiffnessVector array containing the product of the stiffness matrix R and the pressure at time n + * @param[in] damping the damping matrix + * @param[in] rhs the right-hand-side + * @param[in] freeSurfaceNodeIndicator array which contains indicators to tell if we are on a free-surface boundary or not + * @param[in] solverTargetNodesSet the targetted nodeset (useful in particular when we do elasto-acoustic simulation ) + */ + static void LeapFrogWithoutPML( real64 const dt, + arrayView1d< real32 > const p_np1, + arrayView1d< real32 > const p_n, + arrayView1d< real32 > const p_nm1, + arrayView1d< real32 const > const mass, + arrayView1d< real32 > const stiffnessVector, + arrayView1d< real32 const > const damping, + arrayView1d< real32 > const rhs, + arrayView1d< localIndex const > const freeSurfaceNodeIndicator, + SortedArrayView< localIndex const > const solverTargetNodesSet ) + { + real64 const dt2 = pow( dt, 2 ); + forAll< EXEC_POLICY >( solverTargetNodesSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const n ) + { + localIndex const a = solverTargetNodesSet[n]; + if( freeSurfaceNodeIndicator[a] != 1 ) + { + p_np1[a] = p_n[a]; + p_np1[a] *= 2.0 * mass[a]; + p_np1[a] -= (mass[a] - 0.5 * dt * damping[a]) * p_nm1[a]; + p_np1[a] += dt2 * (rhs[a] - stiffnessVector[a]); + p_np1[a] /= mass[a] + 0.5 * dt * damping[a]; + } + } ); + + }; + + /** + * @brief Apply second order Leap-Frog time scheme for VTI case without PML + * @param[in] size The number of nodes in the nodeManager + * @param[in] dt time-step + * @param[out] p_np1 pressure array at time n+1 (updated here) + * @param[in] p_n pressure array at time n + * @param[in] p_nm1 pressure array at time n-1 + * @param[out] q_np1 auxiliary pressure array at time n+1 (updated here) + * @param[in] q_n auxiliary pressure array at time n + * @param[in] q_nm1 auxiliary pressure array at time n-1 + * @param[in] mass the mass matrix + * @param[in] stiffnessVector_p array containing the product of the stiffness matrix R and the pressure at time n + * @param[in] stiffnessVector_q array containing the product of the stiffness matrix R and the auxiliary pressure at time n + * @param[in] damping_p the damping matrix + * @param[in] damping_pq the damping matrix + * @param[in] damping_q the damping matrix + * @param[in] damping_qp the damping matrix + * @param[in] rhs the right-hand-side + * @param[in] freeSurfaceNodeIndicator array which contains indicators to tell if we are on a free-surface boundary or not + * @param[in] lateralSurfaceNodeIndicator array which contains indicators to tell if we are on a lateral boundary or not + * @param[in] bottomSurfaceNodeIndicator array which contains indicators to telle if we are on the bottom boundary or not + */ + static void LeapFrogforVTI( localIndex const size, + real64 const dt, + arrayView1d< real32 > const p_np1, + arrayView1d< real32 > const p_n, + arrayView1d< real32 > const p_nm1, + arrayView1d< real32 > const q_np1, + arrayView1d< real32 > const q_n, + arrayView1d< real32 > const q_nm1, + arrayView1d< real32 const > const mass, + arrayView1d< real32 > const stiffnessVector_p, + arrayView1d< real32 > const stiffnessVector_q, + arrayView1d< real32 const > const damping_p, + arrayView1d< real32 const > const damping_pq, + arrayView1d< real32 const > const damping_q, + arrayView1d< real32 const > const damping_qp, + arrayView1d< real32 > const rhs, + arrayView1d< localIndex const > const freeSurfaceNodeIndicator, + arrayView1d< localIndex const > const lateralSurfaceNodeIndicator, + arrayView1d< localIndex const > const bottomSurfaceNodeIndicator ) + + { + real64 const dt2 = pow( dt, 2 ); + forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + if( freeSurfaceNodeIndicator[a] != 1 ) + { + p_np1[a] = 2.0*mass[a]*p_n[a]/dt2; + p_np1[a] -= mass[a]*p_nm1[a]/dt2; + p_np1[a] += stiffnessVector_p[a]; + p_np1[a] += rhs[a]; + + q_np1[a] = 2.0*mass[a]*q_n[a]/dt2; + q_np1[a] -= mass[a]*q_nm1[a]/dt2; + q_np1[a] += stiffnessVector_q[a]; + q_np1[a] += rhs[a]; + + if( lateralSurfaceNodeIndicator[a] != 1 && bottomSurfaceNodeIndicator[a] != 1 ) + { + // Interior node, no boundary terms + p_np1[a] /= mass[a]/dt2; + q_np1[a] /= mass[a]/dt2; + } + else + { + // Boundary node + p_np1[a] += damping_p[a]*p_nm1[a]/dt/2; + p_np1[a] += damping_pq[a]*q_nm1[a]/dt/2; + + q_np1[a] += damping_q[a]*q_nm1[a]/dt/2; + q_np1[a] += damping_qp[a]*p_nm1[a]/dt/2; + // Hand-made Inversion of 2x2 matrix + real32 coef_pp = mass[a]/dt2; + coef_pp += damping_p[a]/dt/2; + real32 coef_pq = damping_pq[a]/dt/2; + + real32 coef_qq = mass[a]/dt2; + coef_qq += damping_q[a]/2/dt; + real32 coef_qp = damping_qp[a]/dt/2; + + real32 det_pq = 1/(coef_pp * coef_qq - coef_pq*coef_qp); + + real32 aux_p_np1 = p_np1[a]; + p_np1[a] = det_pq*(coef_qq*p_np1[a] - coef_pq*q_np1[a]); + q_np1[a] = det_pq*(coef_pp*q_np1[a] - coef_qp*aux_p_np1); + } + } + } ); + }; + + + +}; + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICTIMESCHEMESEMKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/AcousticElasticWaveEquationSEM.cpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcousticElasticWaveEquationSEM.cpp similarity index 80% rename from src/coreComponents/physicsSolvers/wavePropagation/AcousticElasticWaveEquationSEM.cpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcousticElasticWaveEquationSEM.cpp index 590cfd0f084..ce244edf2ec 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/AcousticElasticWaveEquationSEM.cpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcousticElasticWaveEquationSEM.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,7 +19,9 @@ #include "AcousticElasticWaveEquationSEM.hpp" #include "AcousticElasticWaveEquationSEMKernel.hpp" +#include "AcoustoElasticTimeSchemeSEMKernel.hpp" #include "dataRepository/Group.hpp" +#include "mesh/DomainPartition.hpp" #include #include @@ -29,7 +32,7 @@ using namespace fields; void AcousticElasticWaveEquationSEM::registerDataOnMesh( Group & meshBodies ) { - SolverBase::registerDataOnMesh( meshBodies ); + PhysicsSolverBase::registerDataOnMesh( meshBodies ); forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, MeshLevel & mesh, @@ -44,7 +47,7 @@ void AcousticElasticWaveEquationSEM::registerDataOnMesh( Group & meshBodies ) void AcousticElasticWaveEquationSEM::initializePostInitialConditionsPreSubGroups() { - SolverBase::initializePostInitialConditionsPreSubGroups(); + PhysicsSolverBase::initializePostInitialConditionsPreSubGroups(); auto acousSolver = acousticSolver(); auto elasSolver = elasticSolver(); @@ -60,14 +63,14 @@ void AcousticElasticWaveEquationSEM::initializePostInitialConditionsPreSubGroups localIndex const numInterfaceNodes = MpiWrapper::sum( m_interfaceNodesSet.size() ); GEOS_THROW_IF( numInterfaceNodes == 0, "Failed to compute interface: check xml input (solver order)", std::runtime_error ); - m_acousRegions = acousSolver->getReference< array1d< string > >( SolverBase::viewKeyStruct::targetRegionsString() ); - m_elasRegions = elasSolver->getReference< array1d< string > >( SolverBase::viewKeyStruct::targetRegionsString() ); + m_acousRegions = acousSolver->getReference< array1d< string > >( PhysicsSolverBase::viewKeyStruct::targetRegionsString() ); + m_elasRegions = elasSolver->getReference< array1d< string > >( PhysicsSolverBase::viewKeyStruct::targetRegionsString() ); DomainPartition & domain = getGroupByPath< DomainPartition >( "/Problem/domain" ); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & mesh, - arrayView1d< string const > const & GEOS_UNUSED_PARAM( regionNames ) ) + arrayView1d< string const > const & ) { NodeManager & nodeManager = mesh.getNodeManager(); FaceManager & faceManager = mesh.getFaceManager(); @@ -76,6 +79,7 @@ void AcousticElasticWaveEquationSEM::initializePostInitialConditionsPreSubGroups arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords = nodeManager.getField< fields::referencePosition32 >().toViewConst(); arrayView2d< real64 const > const faceNormals = faceManager.faceNormal().toViewConst(); + arrayView2d< real64 const > const faceCenters = faceManager.faceCenter().toViewConst(); ArrayOfArraysView< localIndex const > const faceToNode = faceManager.nodeList().toViewConst(); arrayView2d< localIndex const > const faceToSubRegion = faceManager.elementSubRegionList(); arrayView2d< localIndex const > const faceToRegion = faceManager.elementRegionList(); @@ -96,6 +100,7 @@ void AcousticElasticWaveEquationSEM::initializePostInitialConditionsPreSubGroups { finiteElement::FiniteElementBase const & fe = elementSubRegion.getReference< finiteElement::FiniteElementBase >( getDiscretizationName() ); + arrayView2d< real64 const > const elemCenters = elementSubRegion.getElementCenter().toViewConst(); finiteElement::FiniteElementDispatchHandler< SEM_FE_TYPES >::dispatch3D( fe, [&] ( auto const finiteElement ) { @@ -111,6 +116,8 @@ void AcousticElasticWaveEquationSEM::initializePostInitialConditionsPreSubGroups faceToElement, faceToNode, faceNormals, + faceCenters, + elemCenters, couplingVectorx, couplingVectory, couplingVectorz ); @@ -122,7 +129,7 @@ void AcousticElasticWaveEquationSEM::initializePostInitialConditionsPreSubGroups real64 AcousticElasticWaveEquationSEM::solverStep( real64 const & time_n, real64 const & dt, - int const cycleNumber, + int const, DomainPartition & domain ) { GEOS_MARK_FUNCTION; @@ -134,7 +141,7 @@ real64 AcousticElasticWaveEquationSEM::solverStep( real64 const & time_n, forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & mesh, - arrayView1d< string const > const & GEOS_UNUSED_PARAM( regionNames ) ) + arrayView1d< string const > const & ) { NodeManager & nodeManager = mesh.getNodeManager(); @@ -150,6 +157,7 @@ real64 AcousticElasticWaveEquationSEM::solverStep( real64 const & time_n, arrayView1d< real32 const > const ux_n = nodeManager.getField< elasticfields::Displacementx_n >(); arrayView1d< real32 const > const uy_n = nodeManager.getField< elasticfields::Displacementy_n >(); arrayView1d< real32 const > const uz_n = nodeManager.getField< elasticfields::Displacementz_n >(); + // acoutic -> elastic coupling vectors arrayView1d< real32 const > const atoex = nodeManager.getField< acoustoelasticfields::CouplingVectorx >(); arrayView1d< real32 const > const atoey = nodeManager.getField< acoustoelasticfields::CouplingVectory >(); arrayView1d< real32 const > const atoez = nodeManager.getField< acoustoelasticfields::CouplingVectorz >(); @@ -159,46 +167,31 @@ real64 AcousticElasticWaveEquationSEM::solverStep( real64 const & time_n, arrayView1d< real32 > const uy_np1 = nodeManager.getField< elasticfields::Displacementy_np1 >(); arrayView1d< real32 > const uz_np1 = nodeManager.getField< elasticfields::Displacementz_np1 >(); - real32 const dt2 = pow( dt, 2 ); + elasSolver->computeUnknowns( time_n, dt, domain, mesh, m_elasRegions ); - elasSolver->computeUnknowns( time_n, dt, cycleNumber, domain, mesh, m_elasRegions ); + AcoustoElasticTimeSchemeSEM::LeapFrog( dt, ux_np1, uy_np1, uz_np1, p_n, elasticMass, atoex, atoey, atoez, + elasticFSNodeIndicator, interfaceNodesSet ); - forAll< EXEC_POLICY >( interfaceNodesSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const n ) - { - localIndex const a = interfaceNodesSet[n]; - if( elasticFSNodeIndicator[a] == 1 ) - return; - - real32 const aux = -p_n[a] / elasticMass[a]; - real32 const localIncrementx = dt2 * atoex[a] * aux; - real32 const localIncrementy = dt2 * atoey[a] * aux; - real32 const localIncrementz = dt2 * atoez[a] * aux; - - RAJA::atomicAdd< ATOMIC_POLICY >( &ux_np1[a], localIncrementx ); - RAJA::atomicAdd< ATOMIC_POLICY >( &uy_np1[a], localIncrementy ); - RAJA::atomicAdd< ATOMIC_POLICY >( &uz_np1[a], localIncrementz ); - } ); - - elasSolver->synchronizeUnknowns( time_n, dt, cycleNumber, domain, mesh, m_elasRegions ); + elasSolver->synchronizeUnknowns( time_n, dt, domain, mesh, m_elasRegions ); - acousSolver->computeUnknowns( time_n, dt, cycleNumber, domain, mesh, m_acousRegions ); + acousSolver->computeUnknowns( time_n, dt, domain, mesh, m_acousRegions ); - forAll< EXEC_POLICY >( interfaceNodesSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const n ) + forAll< EXEC_POLICY >( interfaceNodesSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const in ) { - localIndex const a = interfaceNodesSet[n]; - if( acousticFSNodeIndicator[a] == 1 ) + localIndex const n = interfaceNodesSet[in]; + if( acousticFSNodeIndicator[n] == 1 ) return; real32 const localIncrement = ( - atoex[a] * ( ux_np1[a] - 2.0 * ux_n[a] + ux_nm1[a] ) + - atoey[a] * ( uy_np1[a] - 2.0 * uy_n[a] + uy_nm1[a] ) + - atoez[a] * ( uz_np1[a] - 2.0 * uz_n[a] + uz_nm1[a] ) - ) / acousticMass[a]; + atoex[n] * ( ux_np1[n] - 2.0 * ux_n[n] + ux_nm1[n] ) + + atoey[n] * ( uy_np1[n] - 2.0 * uy_n[n] + uy_nm1[n] ) + + atoez[n] * ( uz_np1[n] - 2.0 * uz_n[n] + uz_nm1[n] ) + ) / acousticMass[n]; - RAJA::atomicAdd< ATOMIC_POLICY >( &p_np1[a], localIncrement ); + RAJA::atomicAdd< ATOMIC_POLICY >( &p_np1[n], localIncrement ); } ); - acousSolver->synchronizeUnknowns( time_n, dt, cycleNumber, domain, mesh, m_acousRegions ); + acousSolver->synchronizeUnknowns( time_n, dt, domain, mesh, m_acousRegions ); acousSolver->prepareNextTimestep( mesh ); elasSolver->prepareNextTimestep( mesh ); @@ -217,6 +210,6 @@ void AcousticElasticWaveEquationSEM::cleanup( real64 const time_n, acousticSolver()->cleanup( time_n, cycleNumber, eventCounter, eventProgress, domain ); } -REGISTER_CATALOG_ENTRY( SolverBase, AcousticElasticWaveEquationSEM, string const &, Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, AcousticElasticWaveEquationSEM, string const &, Group * const ) } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/AcousticElasticWaveEquationSEM.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcousticElasticWaveEquationSEM.hpp similarity index 85% rename from src/coreComponents/physicsSolvers/wavePropagation/AcousticElasticWaveEquationSEM.hpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcousticElasticWaveEquationSEM.hpp index ea72af060af..72bdd0473ea 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/AcousticElasticWaveEquationSEM.hpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcousticElasticWaveEquationSEM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,9 +21,9 @@ #ifndef SRC_CORECOMPONENTS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICELASTICWAVEEQUATIONSEM_HPP_ #define SRC_CORECOMPONENTS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICELASTICWAVEEQUATIONSEM_HPP_ -#include "physicsSolvers/wavePropagation/ElasticWaveEquationSEM.hpp" -#include "physicsSolvers/wavePropagation/AcousticWaveEquationSEM.hpp" -#include "physicsSolvers/SolverBase.hpp" +#include "physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEM.hpp" +#include "physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEM.hpp" +#include "physicsSolvers/PhysicsSolverBase.hpp" #include "AcoustoElasticFields.hpp" #include @@ -30,7 +31,7 @@ namespace geos { template< typename ... SOLVERS > -class CoupledWaveSolver : public SolverBase +class CoupledWaveSolver : public PhysicsSolverBase { public: @@ -42,7 +43,7 @@ class CoupledWaveSolver : public SolverBase */ CoupledWaveSolver( const string & name, Group * const parent ) - : SolverBase( name, parent ) + : PhysicsSolverBase( name, parent ) { forEachArgInTuple( m_solvers, [&]( auto solver, auto idx ) { @@ -68,9 +69,9 @@ class CoupledWaveSolver : public SolverBase CoupledWaveSolver & operator=( CoupledWaveSolver && ) = delete; virtual void - postProcessInput() override final + postInputInitialization() override final { - SolverBase::postProcessInput(); + PhysicsSolverBase::postInputInitialization(); forEachArgInTuple( m_solvers, [&]( auto & solver, auto idx ) { @@ -135,13 +136,13 @@ class AcousticElasticWaveEquationSEM : public CoupledWaveSolver< AcousticWaveEqu static string catalogName() { return "AcousticElasticSEM"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } /** - * @brief accessor for the pointer to the solid mechanics solver - * @return a pointer to the solid mechanics solver + * @brief accessor for the pointer to the acoustic solver + * @return a pointer to the acoustic solver */ AcousticWaveEquationSEM * acousticSolver() const { @@ -149,8 +150,8 @@ class AcousticElasticWaveEquationSEM : public CoupledWaveSolver< AcousticWaveEqu } /** - * @brief accessor for the pointer to the flow solver - * @return a pointer to the flow solver + * @brief accessor for the pointer to the elastic solver + * @return a pointer to the elastic solver */ ElasticWaveEquationSEM * elasticSolver() const { diff --git a/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcousticElasticWaveEquationSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcousticElasticWaveEquationSEMKernel.hpp new file mode 100644 index 00000000000..bef479eb855 --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcousticElasticWaveEquationSEMKernel.hpp @@ -0,0 +1,137 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AcousticElasticWaveEquationSEMKernel.hpp + */ + +#ifndef SRC_CORECOMPONENTS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICELASTICWAVEEQUATIONSEMKERNEL_HPP_ +#define SRC_CORECOMPONENTS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICELASTICWAVEEQUATIONSEMKERNEL_HPP_ + +#include "finiteElement/kernelInterface/KernelBase.hpp" +#if !defined( GEOS_USE_HIP ) +#include "finiteElement/elementFormulations/Qk_Hexahedron_Lagrange_GaussLobatto.hpp" +#endif + +#include + +namespace geos +{ + +namespace acousticElasticWaveEquationSEMKernels +{ + +template< typename FE_TYPE > +struct CouplingKernel +{ + static constexpr localIndex numNodesPerFace = FE_TYPE::numNodesPerFace; + + + /** + * @brief Launches the computation of the coupling vector + * @tparam EXEC_POLICY the execution policy + * @tparam ATOMIC_POLICY the atomic policy + * @param[in] size the number of faces + * @param[in] nodeCoords coordinates of the nodes + * @param[in] fluidRegionIndex Acoustic region + * @param[in] fluidSubRegionIndex Acoustic subregion + * @param[in] faceToSubRegion Array which gives you the subregion on which the face belongs + * @param[in] faceToRegion Array which gives you the region on which the face belongs + * @param[in] faceToElement Array which gives you the element on which the face belongs + * @param[in] facesToNodes Array which gives the nodes on the mesh knowing the face and the local node on an element + * @param[in] faceNormal Normals of the faces + * @param[in] faceCenters Centers of the faces + * @param[in] elemCenters Centers of the elements + * @param[out] couplingVectorx x-component of the coupling vector + * @param[out] couplingVectory y-component of the coupling vector + * @param[out] couplingVectorz z-component of the coupling vector + */ + template< typename EXEC_POLICY, typename ATOMIC_POLICY > + void + launch( localIndex const size, + arrayView2d< WaveSolverBase::wsCoordType const, + nodes::REFERENCE_POSITION_USD > const nodeCoords, + localIndex const fluidRegionIndex, + localIndex const fluidSubRegionIndex, + arrayView2d< localIndex const > const faceToSubRegion, + arrayView2d< localIndex const > const faceToRegion, + arrayView2d< localIndex const > const faceToElement, + ArrayOfArraysView< localIndex const > const facesToNodes, + arrayView2d< real64 const > const faceNormals, + arrayView2d< real64 const > const faceCenters, + arrayView2d< real64 const > const elemCenters, + arrayView1d< real32 > const couplingVectorx, + arrayView1d< real32 > const couplingVectory, + arrayView1d< real32 > const couplingVectorz ) + { + forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const f ) + { + localIndex const e0 = faceToElement( f, 0 ), e1 = faceToElement( f, 1 ); + localIndex const er0 = faceToRegion( f, 0 ), er1 = faceToRegion( f, 1 ); + localIndex const esr0 = faceToSubRegion( f, 0 ), esr1 = faceToSubRegion( f, 1 ); + + if( e0 != -1 && e1 != -1 && er0 != er1 ) // an interface is defined as a transition between regions + { + // check that one of the region is the fluid subregion for the fluid -> solid coupling term + bool const e0IsFluid = er0 == fluidRegionIndex && esr0 == fluidSubRegionIndex; + bool const e1IsFluid = er1 == fluidRegionIndex && esr1 == fluidSubRegionIndex; + + if( e0IsFluid != e1IsFluid ) // xor: a single element must be fluid + { + // only the four corners of the mesh face are needed to compute the Jacobian + real64 xLocal[ 4 ][ 3 ]; + for( localIndex a = 0; a < 4; ++a ) + { + localIndex const nodeIndex = facesToNodes( f, FE_TYPE::meshIndexToLinearIndex2D( a ) ); + for( localIndex i = 0; i < 3; ++i ) + { + xLocal[a][i] = nodeCoords( nodeIndex, i ); + } + } + + real64 const nx = faceNormals( f, 0 ), ny = faceNormals( f, 1 ), nz = faceNormals( f, 2 ); + + // determine sign to get an outward pointing normal for the fluid -> solid coupling + localIndex const e = e0IsFluid ? e0 : (e1IsFluid ? e1 : -1); // fluid element + localIndex const sgn = ( + (faceCenters( f, 0 ) - elemCenters( e, 0 )) * nx + + (faceCenters( f, 1 ) - elemCenters( e, 1 )) * ny + + (faceCenters( f, 2 ) - elemCenters( e, 2 )) * nz + ) < 0 ? 1 : -1; + + for( localIndex q = 0; q < numNodesPerFace; ++q ) + { + real64 const aux = FE_TYPE::computeDampingTerm( q, xLocal ); + + real32 const localIncrementx = aux * (sgn * nx); + real32 const localIncrementy = aux * (sgn * ny); + real32 const localIncrementz = aux * (sgn * nz); + + RAJA::atomicAdd< ATOMIC_POLICY >( &couplingVectorx[facesToNodes( f, q )], localIncrementx ); + RAJA::atomicAdd< ATOMIC_POLICY >( &couplingVectory[facesToNodes( f, q )], localIncrementy ); + RAJA::atomicAdd< ATOMIC_POLICY >( &couplingVectorz[facesToNodes( f, q )], localIncrementz ); + } + } + } + } ); + + } +}; + +} /* namespace acousticElasticWaveEquationSEMKernels */ + +} /* namespace geos */ + +#endif /* SRC_CORECOMPONENTS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTICELASTICWAVEEQUATIONSEMKERNEL_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/AcoustoElasticFields.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcoustoElasticFields.hpp similarity index 85% rename from src/coreComponents/physicsSolvers/wavePropagation/AcoustoElasticFields.hpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcoustoElasticFields.hpp index bdc80bea84f..977e8ab7898 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/AcoustoElasticFields.hpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcoustoElasticFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcoustoElasticTimeSchemeSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcoustoElasticTimeSchemeSEMKernel.hpp new file mode 100644 index 00000000000..b8064cbbbf7 --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/acoustoelastic/secondOrderEqn/isotropic/AcoustoElasticTimeSchemeSEMKernel.hpp @@ -0,0 +1,81 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AcoustoElasticTimeSchemeSEMKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTOELASTICTIMESCHEMESEMKERNEL_HPP_ +#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTOELASTICTIMESCHEMESEMKERNEL_HPP_ + +namespace geos +{ + +struct AcoustoElasticTimeSchemeSEM +{ + + using EXEC_POLICY = parallelDevicePolicy< >; + using ATOMIC_POLICY = parallelDeviceAtomic; + /** + * @brief Apply second order Leap-Frog time scheme for the coupling condition of elasto-acoustic scheme + * @param[in] dt time-step + * @param[out] ux_np1 displacement in x-direction array at time n+1 (updated here) + * @param[out] uy_np1 displacement in y-direction array at time n+1 (updated here) + * @param[out] uz_np1 displacement in z-direction array at time n+1 (updated here) + * @param[in] p_n pressure at time n + * @param[in] elasticMass the mass matrix for the elastic equation + * @param[in] atoex the coupling matrix for x-component + * @param[in] atoey the coupling matrix for y-component + * @param[in] atoez the coupling matrix for z-component + * @param[in] elasticFSNodeIndicator array which contains indicators to tell if we are on a free-surface boundary or not (elastic region) + * @param[in] interfaceNodesSet the nodeset containing the nodes belonging to the interface + */ + + static void LeapFrog( real64 const dt, + arrayView1d< real32 > const ux_np1, + arrayView1d< real32 > const uy_np1, + arrayView1d< real32 > const uz_np1, + arrayView1d< real32 const > const p_n, + arrayView1d< real32 const > const elasticMass, + arrayView1d< real32 const > const atoex, + arrayView1d< real32 const > const atoey, + arrayView1d< real32 const > const atoez, + arrayView1d< localIndex const > const elasticFSNodeIndicator, + SortedArrayView< localIndex const > const interfaceNodesSet ) + { + real64 const dt2 = pow( dt, 2 ); + forAll< EXEC_POLICY >( interfaceNodesSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const n ) + { + localIndex const a = interfaceNodesSet[n]; + if( elasticFSNodeIndicator[a] == 1 ) + return; + + real32 const aux = -p_n[a] / elasticMass[a]; + real32 const localIncrementx = dt2 * atoex[a] * aux; + real32 const localIncrementy = dt2 * atoey[a] * aux; + real32 const localIncrementz = dt2 * atoez[a] * aux; + + RAJA::atomicAdd< ATOMIC_POLICY >( &ux_np1[a], localIncrementx ); + RAJA::atomicAdd< ATOMIC_POLICY >( &uy_np1[a], localIncrementy ); + RAJA::atomicAdd< ATOMIC_POLICY >( &uz_np1[a], localIncrementz ); + } ); + + }; + +}; + +} + +#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ACOUSTOELASTICTIMESCHEMESEMKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/ElasticFirstOrderWaveEquationSEM.cpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/firstOrderEqn/isotropic/ElasticFirstOrderWaveEquationSEM.cpp similarity index 82% rename from src/coreComponents/physicsSolvers/wavePropagation/ElasticFirstOrderWaveEquationSEM.cpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/firstOrderEqn/isotropic/ElasticFirstOrderWaveEquationSEM.cpp index 5a2c9e053b8..5569e40dcdf 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/ElasticFirstOrderWaveEquationSEM.cpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/firstOrderEqn/isotropic/ElasticFirstOrderWaveEquationSEM.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOS Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -24,7 +25,11 @@ #include "fieldSpecification/FieldSpecificationManager.hpp" #include "mainInterface/ProblemManager.hpp" #include "mesh/ElementType.hpp" +#include "mesh/DomainPartition.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" +#include "physicsSolvers/wavePropagation/sem/elastic/shared/ElasticMatricesSEMKernel.hpp" +#include "physicsSolvers/wavePropagation/shared/PrecomputeSourcesAndReceiversKernel.hpp" +#include "events/EventManager.hpp" namespace geos { @@ -172,17 +177,17 @@ void ElasticFirstOrderWaveEquationSEM::registerDataOnMesh( Group & meshBodies ) -void ElasticFirstOrderWaveEquationSEM::postProcessInput() +void ElasticFirstOrderWaveEquationSEM::postInputInitialization() { - WaveSolverBase::postProcessInput(); + WaveSolverBase::postInputInitialization(); localIndex const numSourcesGlobal = m_sourceCoordinates.size( 0 ); m_sourceElem.resize( numSourcesGlobal ); m_sourceRegion.resize( numSourcesGlobal ); localIndex const numReceiversGlobal = m_receiverCoordinates.size( 0 ); - m_rcvElem.resize( numReceiversGlobal ); + m_receiverElem.resize( numReceiversGlobal ); m_receiverRegion.resize( numReceiversGlobal ); m_displacementxNp1AtReceivers.resize( m_nsamplesSeismoTrace, numReceiversGlobal + 1 ); @@ -198,14 +203,14 @@ void ElasticFirstOrderWaveEquationSEM::postProcessInput() } -void ElasticFirstOrderWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) +void ElasticFirstOrderWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & baseMesh, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) { - NodeManager const & nodeManager = mesh.getNodeManager(); - FaceManager const & faceManager = mesh.getFaceManager(); + GEOS_MARK_FUNCTION; - arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const X = nodeManager.getField< fields::referencePosition32 >().toViewConst(); - arrayView2d< real64 const > const faceNormal = faceManager.faceNormal(); - arrayView2d< real64 const > const faceCenter = faceManager.faceCenter(); + arrayView1d< globalIndex const > const nodeLocalToGlobal = baseMesh.getNodeManager().localToGlobalMap().toViewConst(); + ArrayOfArraysView< localIndex const > const nodesToElements = baseMesh.getNodeManager().elementList().toViewConst(); + ArrayOfArraysView< localIndex const > const facesToNodes = baseMesh.getFaceManager().nodeList().toViewConst(); + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const nodeCoords = baseMesh.getNodeManager().referencePosition(); arrayView2d< real64 const > const sourceCoordinates = m_sourceCoordinates.toViewConst(); arrayView2d< localIndex > const sourceNodeIds = m_sourceNodeIds.toView(); @@ -221,28 +226,18 @@ void ElasticFirstOrderWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLeve arrayView2d< localIndex > const receiverNodeIds = m_receiverNodeIds.toView(); arrayView2d< real64 > const receiverConstants = m_receiverConstants.toView(); arrayView1d< localIndex > const receiverIsLocal = m_receiverIsLocal.toView(); - arrayView1d< localIndex > const rcvElem = m_rcvElem.toView(); + arrayView1d< localIndex > const receiverElem = m_receiverElem.toView(); arrayView1d< localIndex > const receiverRegion = m_receiverRegion.toView(); receiverNodeIds.setValues< serialPolicy >( -1 ); receiverConstants.setValues< serialPolicy >( -1 ); receiverIsLocal.zero(); - arrayView2d< real32 > const sourceValue = m_sourceValue.toView(); - real64 dt = 0; - EventManager const & event = getGroupByPath< EventManager >( "/Problem/Events" ); - - for( localIndex numSubEvent = 0; numSubEvent < event.numSubGroups(); ++numSubEvent ) - { - EventBase const * subEvent = static_cast< EventBase const * >( event.getSubGroups()[numSubEvent] ); - if( subEvent->getEventName() == "/Solvers/" + getName() ) - { - dt = subEvent->getReference< real64 >( EventBase::viewKeyStruct::forceDtString() ); - } - } - - mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const regionIndex, - CellElementSubRegion & elementSubRegion ) + mesh.getElemManager().forElementSubRegionsComplete< CellElementSubRegion >( regionNames, [&]( localIndex const, + localIndex const regionIndex, + localIndex const esr, + ElementRegionBase &, + CellElementSubRegion & elementSubRegion ) { GEOS_THROW_IF( elementSubRegion.getElementType() != ElementType::Hexahedron, @@ -251,8 +246,10 @@ void ElasticFirstOrderWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLeve arrayView2d< localIndex const > const elemsToFaces = elementSubRegion.faceList(); arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes = elementSubRegion.nodeList(); + arrayView2d< localIndex const, cells::NODE_MAP_USD > const & baseElemsToNodes = baseMesh.getElemManager().getRegion( regionIndex ).getSubRegion< CellElementSubRegion >( esr ).nodeList(); arrayView2d< real64 const > const elemCenter = elementSubRegion.getElementCenter(); arrayView1d< integer const > const elemGhostRank = elementSubRegion.ghostRank(); + arrayView1d< globalIndex const > const elemLocalToGlobal = elementSubRegion.localToGlobalMap().toViewConst(); finiteElement::FiniteElementBase const & fe = elementSubRegion.getReference< finiteElement::FiniteElementBase >( getDiscretizationName() ); @@ -260,21 +257,21 @@ void ElasticFirstOrderWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLeve { using FE_TYPE = TYPEOFREF( finiteElement ); - localIndex const numFacesPerElem = elementSubRegion.numFacesPerElement(); - - elasticFirstOrderWaveEquationSEMKernels:: - PrecomputeSourceAndReceiverKernel:: - launch< EXEC_POLICY, FE_TYPE > + PreComputeSourcesAndReceivers:: + Compute1DSourceAndReceiverConstantsWithElementsAndRegionStorage + < EXEC_POLICY, FE_TYPE > ( elementSubRegion.size(), regionIndex, - numFacesPerElem, - X, + facesToNodes, + nodeCoords, + nodeLocalToGlobal, + elemLocalToGlobal, + nodesToElements, + baseElemsToNodes, elemGhostRank, elemsToNodes, elemsToFaces, elemCenter, - faceNormal, - faceCenter, sourceCoordinates, sourceIsAccessible, sourceElem, @@ -283,17 +280,23 @@ void ElasticFirstOrderWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLeve sourceRegion, receiverCoordinates, receiverIsLocal, - rcvElem, + receiverElem, receiverNodeIds, receiverConstants, - receiverRegion, - sourceValue, - dt, - m_timeSourceFrequency, - m_timeSourceDelay, - m_rickerOrder ); + receiverRegion ); } ); + elementSubRegion.faceList().freeOnDevice(); + baseMesh.getElemManager().getRegion( regionIndex ).getSubRegion< CellElementSubRegion >( esr ).nodeList().freeOnDevice(); + elementSubRegion.getElementCenter().freeOnDevice(); + elementSubRegion.ghostRank().freeOnDevice(); + elementSubRegion.localToGlobalMap().freeOnDevice(); } ); + baseMesh.getNodeManager().localToGlobalMap().freeOnDevice(); + baseMesh.getNodeManager().elementList().toView().freeOnDevice(); + baseMesh.getFaceManager().nodeList().toView().freeOnDevice(); + baseMesh.getNodeManager().referencePosition().freeOnDevice(); + facesToNodes.freeOnDevice(); + nodesToElements.freeOnDevice(); } void ElasticFirstOrderWaveEquationSEM::initializePostInitialConditionsPreSubGroups() @@ -306,18 +309,19 @@ void ElasticFirstOrderWaveEquationSEM::initializePostInitialConditionsPreSubGrou real64 const time = 0.0; applyFreeSurfaceBC( time, domain ); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshBodyName, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) { - precomputeSourceAndReceiverTerm( mesh, regionNames ); + MeshLevel & baseMesh = domain.getMeshBodies().getGroup< MeshBody >( meshBodyName ).getBaseDiscretization(); + precomputeSourceAndReceiverTerm( baseMesh, mesh, regionNames ); NodeManager & nodeManager = mesh.getNodeManager(); FaceManager & faceManager = mesh.getFaceManager(); /// get the array of indicators: 1 if the face is on the boundary; 0 otherwise arrayView1d< integer const > const & facesDomainBoundaryIndicator = faceManager.getDomainBoundaryIndicator(); - arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const X = nodeManager.getField< fields::referencePosition32 >().toViewConst(); + arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords = nodeManager.getField< fields::referencePosition32 >().toViewConst(); arrayView2d< real64 const > const faceNormal = faceManager.faceNormal(); /// get face to node map @@ -343,9 +347,11 @@ void ElasticFirstOrderWaveEquationSEM::initializePostInitialConditionsPreSubGrou arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes = elementSubRegion.nodeList(); arrayView2d< localIndex const > const elemsToFaces = elementSubRegion.faceList(); - arrayView1d< real32 > const density = elementSubRegion.getField< elasticfields::ElasticDensity >(); - arrayView1d< real32 > const velocityVp = elementSubRegion.getField< elasticfields::ElasticVelocityVp >(); - arrayView1d< real32 > const velocityVs = elementSubRegion.getField< elasticfields::ElasticVelocityVs >(); + arrayView1d< real32 const > const density = elementSubRegion.getField< elasticfields::ElasticDensity >(); + arrayView1d< real32 const > const velocityVp = elementSubRegion.getField< elasticfields::ElasticVelocityVp >(); + arrayView1d< real32 const > const velocityVs = elementSubRegion.getField< elasticfields::ElasticVelocityVs >(); + arrayView1d< real32 > const lambda = elementSubRegion.getField< elasticfields::Lambda >(); + arrayView1d< real32 > const mu = elementSubRegion.getField< elasticfields::Mu >(); finiteElement::FiniteElementBase const & fe = elementSubRegion.getReference< finiteElement::FiniteElementBase >( getDiscretizationName() ); @@ -356,34 +362,40 @@ void ElasticFirstOrderWaveEquationSEM::initializePostInitialConditionsPreSubGrou { using FE_TYPE = TYPEOFREF( finiteElement ); - elasticFirstOrderWaveEquationSEMKernels::MassMatrixKernel< FE_TYPE > kernelM( finiteElement ); - - kernelM.template launch< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), - X, - elemsToNodes, - density, - mass ); - - elasticFirstOrderWaveEquationSEMKernels::DampingMatrixKernel< FE_TYPE > kernelD( finiteElement ); - - kernelD.template launch< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), - X, - elemsToFaces, - facesToNodes, - facesDomainBoundaryIndicator, - freeSurfaceFaceIndicator, - faceNormal, - density, - velocityVp, - velocityVs, - dampingx, - dampingy, - dampingz ); + ElasticMatricesSEM::MassMatrix< FE_TYPE > kernelM( finiteElement ); + + kernelM.template computeMassMatrix< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), + nodeCoords, + elemsToNodes, + density, + mass ); + + + ElasticMatricesSEM::DampingMatrix< FE_TYPE > kernelD( finiteElement ); + + kernelD.template computeDampingMatrix< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), + nodeCoords, + elemsToFaces, + facesToNodes, + facesDomainBoundaryIndicator, + freeSurfaceFaceIndicator, + faceNormal, + density, + velocityVp, + velocityVs, + dampingx, + dampingy, + dampingz ); } ); } ); } ); } +real64 ElasticFirstOrderWaveEquationSEM::computeTimeStep( real64 & dtOut ) +{ + GEOS_ERROR( getDataContext() << ": Time-Step computation for the first order elastic wave propagator not yet implemented" ); + return dtOut; +} void ElasticFirstOrderWaveEquationSEM::applyFreeSurfaceBC( real64 const time, DomainPartition & domain ) { @@ -485,7 +497,6 @@ real64 ElasticFirstOrderWaveEquationSEM::explicitStepInternal( real64 const & ti arrayView1d< localIndex const > const sourceIsAccessible = m_sourceIsAccessible.toView(); arrayView1d< localIndex const > const sourceElem = m_sourceElem.toView(); arrayView1d< localIndex const > const sourceRegion = m_sourceRegion.toView(); - arrayView2d< real32 const > const sourceValue = m_sourceValue.toView(); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, @@ -496,7 +507,7 @@ real64 ElasticFirstOrderWaveEquationSEM::explicitStepInternal( real64 const & ti NodeManager & nodeManager = mesh.getNodeManager(); - arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const X = nodeManager.getField< fields::referencePosition32 >().toViewConst(); + arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords = nodeManager.getField< fields::referencePosition32 >().toViewConst(); arrayView1d< real32 const > const mass = nodeManager.getField< elasticfields::ElasticMassVector >(); arrayView1d< real32 > const dampingx = nodeManager.getField< elasticfields::DampingVectorx >(); @@ -535,12 +546,14 @@ real64 ElasticFirstOrderWaveEquationSEM::explicitStepInternal( real64 const & ti { using FE_TYPE = TYPEOFREF( finiteElement ); + //Modification of cycleNember useful when minTime < 0 + elasticFirstOrderWaveEquationSEMKernels:: StressComputation< FE_TYPE > kernel( finiteElement ); kernel.template launch< EXEC_POLICY, ATOMIC_POLICY > ( elementSubRegion.size(), regionIndex, - X, + nodeCoords, elemsToNodes, ux_np1, uy_np1, @@ -554,9 +567,13 @@ real64 ElasticFirstOrderWaveEquationSEM::explicitStepInternal( real64 const & ti sourceIsAccessible, sourceElem, sourceRegion, - sourceValue, dt, - cycleNumber, + time_n, + m_timeSourceFrequency, + m_timeSourceDelay, + m_rickerOrder, + m_useSourceWaveletTables, + m_sourceWaveletTableWrappers, stressxx, stressyy, stresszz, @@ -569,7 +586,7 @@ real64 ElasticFirstOrderWaveEquationSEM::explicitStepInternal( real64 const & ti kernel2.template launch< EXEC_POLICY, ATOMIC_POLICY > ( elementSubRegion.size(), nodeManager.size(), - X, + nodeCoords, elemsToNodes, stressxx, stressyy, @@ -639,7 +656,7 @@ void ElasticFirstOrderWaveEquationSEM::cleanup( real64 const time_n, real64 const eventProgress, DomainPartition & domain ) { - SolverBase::cleanup( time_n, cycleNumber, eventCounter, eventProgress, domain ); + PhysicsSolverBase::cleanup( time_n, cycleNumber, eventCounter, eventProgress, domain ); // compute the remaining seismic traces, if needed forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, @@ -706,6 +723,6 @@ void ElasticFirstOrderWaveEquationSEM::applyPML( real64 const, DomainPartition & GEOS_ERROR( getDataContext() << ": PML for the first order elastic wave propagator not yet implemented" ); } -REGISTER_CATALOG_ENTRY( SolverBase, ElasticFirstOrderWaveEquationSEM, string const &, dataRepository::Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, ElasticFirstOrderWaveEquationSEM, string const &, dataRepository::Group * const ) } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/ElasticFirstOrderWaveEquationSEM.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/firstOrderEqn/isotropic/ElasticFirstOrderWaveEquationSEM.hpp similarity index 89% rename from src/coreComponents/physicsSolvers/wavePropagation/ElasticFirstOrderWaveEquationSEM.hpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/firstOrderEqn/isotropic/ElasticFirstOrderWaveEquationSEM.hpp index b96d8697412..4cdf886919a 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/ElasticFirstOrderWaveEquationSEM.hpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/firstOrderEqn/isotropic/ElasticFirstOrderWaveEquationSEM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOS Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,8 +22,8 @@ #define SRC_CORECOMPONENTS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICFIRSTORDERWAVEEQUATIONSEM_HPP_ #include "mesh/MeshFields.hpp" -#include "ElasticFields.hpp" -#include "WaveSolverBase.hpp" +#include "physicsSolvers/wavePropagation/sem/elastic/shared/ElasticFields.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp" namespace geos @@ -42,7 +43,7 @@ class ElasticFirstOrderWaveEquationSEM : public WaveSolverBase static string catalogName() { return "ElasticFirstOrderSEM"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -82,7 +83,7 @@ class ElasticFirstOrderWaveEquationSEM : public WaveSolverBase virtual void cleanup( real64 const time_n, integer const cycleNumber, integer const eventCounter, real64 const eventProgress, DomainPartition & domain ) override; - struct viewKeyStruct : SolverBase::viewKeyStruct + struct viewKeyStruct : PhysicsSolverBase::viewKeyStruct { static constexpr char const * displacementxNp1AtReceiversString() { return "displacementxNp1AtReceivers"; } static constexpr char const * displacementyNp1AtReceiversString() { return "displacementyNp1AtReceivers"; } @@ -115,7 +116,7 @@ class ElasticFirstOrderWaveEquationSEM : public WaveSolverBase protected: - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; virtual void initializePostInitialConditionsPreSubGroups() override final; @@ -124,10 +125,11 @@ class ElasticFirstOrderWaveEquationSEM : public WaveSolverBase /** * @brief Locate sources and receivers position in the mesh elements, evaluate the basis functions at each point and save them to the * corresponding elements nodes. + * @param baseMesh the level-0 mesh * @param mesh mesh of the computational domain * @param regionNames name of the region you are currently on */ - virtual void precomputeSourceAndReceiverTerm( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) override; + virtual void precomputeSourceAndReceiverTerm( MeshLevel & baseMesh, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) override; /** * @brief Apply free surface condition to the face define in the geometry box from the xml @@ -143,6 +145,8 @@ class ElasticFirstOrderWaveEquationSEM : public WaveSolverBase */ virtual void applyPML( real64 const time, DomainPartition & domain ) override; + virtual real64 computeTimeStep( real64 & dtOut ) override; + /// Displacement_np1 at the receiver location for each time step for each receiver array2d< real32 > m_displacementxNp1AtReceivers; diff --git a/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/firstOrderEqn/isotropic/ElasticFirstOrderWaveEquationSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/firstOrderEqn/isotropic/ElasticFirstOrderWaveEquationSEMKernel.hpp new file mode 100644 index 00000000000..5525d6cbb44 --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/firstOrderEqn/isotropic/ElasticFirstOrderWaveEquationSEMKernel.hpp @@ -0,0 +1,395 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ElasticFirstOrderWaveEquationSEMKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICFIRSTORDERWAVEEQUATIONSEMKERNEL_HPP_ +#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICFIRSTORDERWAVEEQUATIONSEMKERNEL_HPP_ + +#include "finiteElement/kernelInterface/KernelBase.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverUtils.hpp" + + +namespace geos +{ + +/// Namespace to contain the elastic wave kernels. +namespace elasticFirstOrderWaveEquationSEMKernels +{ + +template< typename FE_TYPE > +struct StressComputation +{ + + StressComputation( FE_TYPE const & finiteElement ) + : m_finiteElement( finiteElement ) + {} + + /** + * @brief Launches the computation of the strain tensor for one iteration + * @tparam EXEC_POLICY the execution policy + * @tparam ATOMIC_POLICY the atomic policy + * @param[in] size the number of cells in the subRegion + * @param[in] regionIndex Index of the subregion + * @param[in] nodeCoords coordinates of the nodes + * @param[in] elemsToNodes map from element to nodes + * @param[in] ux_np1 displacement array in the x direction (only used here) + * @param[in] uy_np1 displacement array in the y direction (only used here) + * @param[in] uz_np1 displacement array in the z direction (only used here) + * @param[in] velocityVp P-wavespeed array + * @param[in] velocityVs S-wavespeed array + * @param[in] lambda lambda (Lamé parameter) array + * @param[in] mu mu (Lamé parameter) array + * @param[in] sourceConstants constant part of the source terms + * @param[in] sourceIsLocal flag indicating whether the source is accessible or not + * @param[in] sourceElem element where a source is located + * @param[in] sourceRegion region where the source is located + * @param[in] dt time-step + * @param[in] time_n current time + * @param[in] timeSourceFrequency the central frequency of the source + * @param[in] timeSourceDelay the time delay of the source + * @param[in] rickerOrder order of the Ricker wavelet + * @param[out] stressxx xx-component of the strain tensor array (updated here) + * @param[out] stressyy yy-component of the strain tensor array (updated here) + * @param[out] stresszz zz-component of the strain tensor array (updated here) + * @param[out] stressxy xy-component of the strain tensor array (updated here) + * @param[out] stressxz xz-component of the strain tensor array (updated here) + * @param[out] stressyz yz-component of the strain tensor array (updated here) + */ + + template< typename EXEC_POLICY, typename ATOMIC_POLICY > + void + launch( localIndex const size, + localIndex const regionIndex, + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, + arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes, + arrayView1d< real32 const > const ux_np1, + arrayView1d< real32 const > const uy_np1, + arrayView1d< real32 const > const uz_np1, + arrayView1d< real32 const > const density, + arrayView1d< real32 const > const velocityVp, + arrayView1d< real32 const > const velocityVs, + arrayView1d< real32 > const lambda, + arrayView1d< real32 > const mu, + arrayView2d< real64 const > const sourceConstants, + arrayView1d< localIndex const > const sourceIsLocal, + arrayView1d< localIndex const > const sourceElem, + arrayView1d< localIndex const > const sourceRegion, + real64 const dt, + real64 const time_n, + real32 const timeSourceFrequency, + real32 const timeSourceDelay, + localIndex const rickerOrder, + bool const useSourceWaveletTables, + arrayView1d< TableFunction::KernelWrapper const > const sourceWaveletTableWrappers, + arrayView2d< real32 > const stressxx, + arrayView2d< real32 > const stressyy, + arrayView2d< real32 > const stresszz, + arrayView2d< real32 > const stressxy, + arrayView2d< real32 > const stressxz, + arrayView2d< real32 > const stressyz ) + + { + real64 const rickerValue = useSourceWaveletTables ? 0 : WaveSolverUtils::evaluateRicker( time_n, timeSourceFrequency, timeSourceDelay, rickerOrder ); + forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + // only the eight corners of the mesh cell are needed to compute the Jacobian + real64 xLocal[8][3]; + for( localIndex a=0; a< 8; ++a ) + { + localIndex const nodeIndex = elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); + for( localIndex i=0; i<3; ++i ) + { + xLocal[a][i] = nodeCoords( nodeIndex, i ); + } + } + + mu[k] = density[k] * pow( velocityVs[k], 2 ); + lambda[k] = density[k] * pow( velocityVp[k], 2 ) - 2.0*mu[k]; + + constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; + real32 uelemxx[numNodesPerElem] = {0.0}; + real32 uelemyy[numNodesPerElem] = {0.0}; + real32 uelemzz[numNodesPerElem] = {0.0}; + real32 uelemxy[numNodesPerElem] = {0.0}; + real32 uelemxz[numNodesPerElem] = {0.0}; + real32 uelemyz[numNodesPerElem]= {0.0}; + real32 auxx[numNodesPerElem] = {0.0}; + real32 auyy[numNodesPerElem] = {0.0}; + real32 auzz[numNodesPerElem] = {0.0}; + real32 auxy[numNodesPerElem] = {0.0}; + real32 auxz[numNodesPerElem] = {0.0}; + real32 auyz[numNodesPerElem] = {0.0}; + + + //Pre-multiplication by mass matrix + for( localIndex i = 0; i < numNodesPerElem; ++i ) + { + real32 massLoc = m_finiteElement.computeMassTerm( i, xLocal ); + uelemxx[i] = massLoc*stressxx[k][i]; + uelemyy[i] = massLoc*stressyy[k][i]; + uelemzz[i] = massLoc*stresszz[k][i]; + uelemxy[i] = massLoc*stressxy[k][i]; + uelemxz[i] = massLoc*stressxz[k][i]; + uelemyz[i] = massLoc*stressyz[k][i]; + } + + for( localIndex q = 0; q < numNodesPerElem; q++ ) + { + + //Volume integral + m_finiteElement.template computeFirstOrderStiffnessTermX( q, xLocal, [&] ( int const i, int const j, real32 const dfx1, real32 const dfx2, real32 const dfx3 ) + { + localIndex const nodeIndex = elemsToNodes[k][i]; + auxx[j] = auxx[j] + dfx1*ux_np1[nodeIndex]; + auyy[j] = auyy[j] + dfx2*uy_np1[nodeIndex]; + auzz[j] = auzz[j] + dfx3*uz_np1[nodeIndex]; + auxy[j] = auxy[j] + dfx1*uy_np1[nodeIndex]+dfx2*ux_np1[nodeIndex]; + auxz[j] = auxz[j] + dfx1*uz_np1[nodeIndex]+dfx3*ux_np1[nodeIndex]; + auyz[j] = auyz[j] + dfx2*uz_np1[nodeIndex]+dfx3*uy_np1[nodeIndex]; + + } ); + + m_finiteElement.template computeFirstOrderStiffnessTermY( q, xLocal, [&] ( int const i, int const j, real32 const dfy1, real32 const dfy2, real32 const dfy3 ) + { + localIndex const nodeIndex = elemsToNodes[k][i]; + auxx[j] = auxx[j] + dfy1*ux_np1[nodeIndex]; + auyy[j] = auyy[j] + dfy2*uy_np1[nodeIndex]; + auzz[j] = auzz[j] + dfy3*uz_np1[nodeIndex]; + auxy[j] = auxy[j] + dfy1*uy_np1[nodeIndex]+dfy2*ux_np1[nodeIndex]; + auxz[j] = auxz[j] + dfy1*uz_np1[nodeIndex]+dfy3*ux_np1[nodeIndex]; + auyz[j] = auyz[j] + dfy2*uz_np1[nodeIndex]+dfy3*uy_np1[nodeIndex]; + + } ); + + m_finiteElement.template computeFirstOrderStiffnessTermZ( q, xLocal, [&] ( int const i, int const j, real32 const dfz1, real32 const dfz2, real32 const dfz3 ) + { + localIndex const nodeIndex = elemsToNodes[k][i]; + auxx[j] = auxx[j] + dfz1*ux_np1[nodeIndex]; + auyy[j] = auyy[j] + dfz2*uy_np1[nodeIndex]; + auzz[j] = auzz[j] + dfz3*uz_np1[nodeIndex]; + auxy[j] = auxy[j] + dfz1*uy_np1[nodeIndex]+dfz2*ux_np1[nodeIndex]; + auxz[j] = auxz[j] + dfz1*uz_np1[nodeIndex]+dfz3*ux_np1[nodeIndex]; + auyz[j] = auyz[j] + dfz2*uz_np1[nodeIndex]+dfz3*uy_np1[nodeIndex]; + + } ); + + } + //Time integration + for( localIndex i = 0; i < numNodesPerElem; ++i ) + { + real32 diag = lambda[k]*(auxx[i]+auyy[i]+auzz[i]); + uelemxx[i]+= dt*(diag+2*mu[k]*auxx[i]); + uelemyy[i]+= dt*(diag+2*mu[k]*auyy[i]); + uelemzz[i]+= dt*(diag+2*mu[k]*auzz[i]); + uelemxy[i]+= dt*mu[k]*auxy[i]; + uelemxz[i]+= dt*mu[k]*auxz[i]; + uelemyz[i]+= dt*mu[k]*auyz[i]; + } + + // Multiplication by inverse mass matrix + for( localIndex i = 0; i < numNodesPerElem; ++i ) + { + real32 massLoc = m_finiteElement.computeMassTerm( i, xLocal ); + stressxx[k][i] = uelemxx[i]/massLoc; + stressyy[k][i] = uelemyy[i]/massLoc; + stresszz[k][i] = uelemzz[i]/massLoc; + stressxy[k][i] = uelemxy[i]/massLoc; + stressxz[k][i] = uelemxz[i]/massLoc; + stressyz[k][i] = uelemyz[i]/massLoc; + } + + + //Source injection + for( localIndex isrc = 0; isrc < sourceConstants.size( 0 ); ++isrc ) + { + if( sourceIsLocal[isrc] == 1 ) + { + if( sourceElem[isrc]==k && sourceRegion[isrc] == regionIndex ) + { + real64 const srcValue = useSourceWaveletTables ? sourceWaveletTableWrappers[ isrc ].compute( &time_n ) : rickerValue; + for( localIndex i = 0; i < numNodesPerElem; ++i ) + { + real32 massLoc = m_finiteElement.computeMassTerm( i, xLocal ); + real32 const localIncrement = dt*(sourceConstants[isrc][i]*srcValue)/massLoc; + RAJA::atomicAdd< ATOMIC_POLICY >( &stressxx[k][i], localIncrement ); + RAJA::atomicAdd< ATOMIC_POLICY >( &stressyy[k][i], localIncrement ); + RAJA::atomicAdd< ATOMIC_POLICY >( &stresszz[k][i], localIncrement ); + } + + } + + } + } + + } ); + } + + /// The finite element space/discretization object for the element type in the subRegion + + FE_TYPE const & m_finiteElement; +}; + +template< typename FE_TYPE > +struct VelocityComputation +{ + + VelocityComputation( FE_TYPE const & finiteElement ) + : m_finiteElement( finiteElement ) + {} + + /** + * @brief Launches the computation of the displacement for one iteration + * @tparam EXEC_POLICY the execution policy + * @tparam ATOMIC_POLICY the atomic policy + * @param[in] size the number of cells in the subRegion + * @param[in] size_node the number of nodes in the subRegion + * @param[in] nodeCoords coordinates of the nodes + * @param[in] elemsToNodes map from element to nodes + * @param[out] stressxx xx-component of the strain tensor array (only used here) + * @param[out] stressyy yy-component of the strain tensor array (only used here) + * @param[out] stresszz zz-component of the strain tensor array (only used here) + * @param[out] stressxy xy-component of the strain tensor array (only used here) + * @param[out] stressxz xz-component of the strain tensor array (only used here) + * @param[out] stressyz yz-component of the strain tensor array (only used here) + * @param[in] mass the mass matrix + * @param[in] dampingx the damping (x-component) matrix + * @param[in] dampingy the damping for (y-component) matrix + * @param[in] dampingz the damping for (z-component) matrix + * @param[in] dt time-step + * @param[in] ux_np1 displacement array in the x direction (updated here) + * @param[in] uy_np1 displacement array in the y direction (updated here) + * @param[in] uz_np1 displacement array in the z direction (updated here) + */ + + template< typename EXEC_POLICY, typename ATOMIC_POLICY > + void + launch( localIndex const size, + localIndex const size_node, + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, + arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes, + arrayView2d< real32 const > const stressxx, + arrayView2d< real32 const > const stressyy, + arrayView2d< real32 const > const stresszz, + arrayView2d< real32 const > const stressxy, + arrayView2d< real32 const > const stressxz, + arrayView2d< real32 const > const stressyz, + arrayView1d< const real32 > const mass, + arrayView1d< real32 const > const dampingx, + arrayView1d< real32 const > const dampingy, + arrayView1d< real32 const > const dampingz, + real64 const dt, + arrayView1d< real32 > const ux_np1, + arrayView1d< real32 > const uy_np1, + arrayView1d< real32 > const uz_np1 ) + { + + forAll< EXEC_POLICY >( size_node, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + ux_np1[a] *= 1.0-((dt/2)*(dampingx[a]/mass[a])); + uy_np1[a] *= 1.0-((dt/2)*(dampingy[a]/mass[a])); + uz_np1[a] *= 1.0-((dt/2)*(dampingz[a]/mass[a])); + } ); + + forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + // only the eight corners of the mesh cell are needed to compute the Jacobian + real64 xLocal[8][3]; + for( localIndex a=0; a< 8; ++a ) + { + localIndex const nodeIndex = elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); + for( localIndex i=0; i<3; ++i ) + { + xLocal[a][i] = nodeCoords( nodeIndex, i ); + } + } + + constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; + real32 uelemx[numNodesPerElem] = {0.0}; + real32 uelemy[numNodesPerElem] = {0.0}; + real32 uelemz[numNodesPerElem] = {0.0}; + real32 flowx[numNodesPerElem] = {0.0}; + real32 flowy[numNodesPerElem] = {0.0}; + real32 flowz[numNodesPerElem] = {0.0}; + + for( localIndex q = 0; q < numNodesPerElem; q++ ) + { + + + // Stiffness part + m_finiteElement.template computeFirstOrderStiffnessTermX( q, xLocal, [&] ( int i, int j, real32 dfx1, real32 dfx2, real32 dfx3 ) + { + flowx[i] -= stressxx[k][j]*dfx1 + stressxy[k][j]*dfx2 + stressxz[k][j]*dfx3; + flowy[i] -= stressxy[k][j]*dfx1 + stressyy[k][j]*dfx2 + stressyz[k][j]*dfx3; + flowz[i] -= stressxz[k][j]*dfx1 + stressyz[k][j]*dfx2 + stresszz[k][j]*dfx3; + + } ); + + m_finiteElement.template computeFirstOrderStiffnessTermY( q, xLocal, [&] ( int i, int j, real32 dfy1, real32 dfy2, real32 dfy3 ) + { + flowx[i] -= stressxx[k][j]*dfy1 + stressxy[k][j]*dfy2 + stressxz[k][j]*dfy3; + flowy[i] -= stressxy[k][j]*dfy1 + stressyy[k][j]*dfy2 + stressyz[k][j]*dfy3; + flowz[i] -= stressxz[k][j]*dfy1 + stressyz[k][j]*dfy2 + stresszz[k][j]*dfy3; + } ); + + m_finiteElement.template computeFirstOrderStiffnessTermZ( q, xLocal, [&] ( int i, int j, real32 dfz1, real32 dfz2, real32 dfz3 ) + { + flowx[i] -= stressxx[k][j]*dfz1 + stressxy[k][j]*dfz2 + stressxz[k][j]*dfz3; + flowy[i] -= stressxy[k][j]*dfz1 + stressyy[k][j]*dfz2 + stressyz[k][j]*dfz3; + flowz[i] -= stressxz[k][j]*dfz1 + stressyz[k][j]*dfz2 + stresszz[k][j]*dfz3; + } ); + + } + // Time update + for( localIndex i = 0; i < numNodesPerElem; ++i ) + { + uelemx[i]+=dt*flowx[i]; + uelemy[i]+=dt*flowy[i]; + uelemz[i]+=dt*flowz[i]; + } + + // Mult by inverse mass matrix + damping matrix + for( localIndex i = 0; i < numNodesPerElem; ++i ) + { + real32 localIncrement1 = uelemx[i]/mass[elemsToNodes[k][i]]; + real32 localIncrement2 = uelemy[i]/mass[elemsToNodes[k][i]]; + real32 localIncrement3 = uelemz[i]/mass[elemsToNodes[k][i]]; + RAJA::atomicAdd< ATOMIC_POLICY >( &ux_np1[elemsToNodes[k][i]], localIncrement1 ); + RAJA::atomicAdd< ATOMIC_POLICY >( &uy_np1[elemsToNodes[k][i]], localIncrement2 ); + RAJA::atomicAdd< ATOMIC_POLICY >( &uz_np1[elemsToNodes[k][i]], localIncrement3 ); + } + + } ); + forAll< EXEC_POLICY >( size_node, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + ux_np1[a] /= 1.0+((dt/2)*(dampingx[a]/mass[a])); + uy_np1[a] /= 1.0+((dt/2)*(dampingy[a]/mass[a])); + uz_np1[a] /= 1.0+((dt/2)*(dampingz[a]/mass[a])); + } ); + } + + /// The finite element space/discretization object for the element type in the subRegion + FE_TYPE const & m_finiteElement; + +}; + + +} // namespace ElasticFirstOrderWaveEquationSEMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICFIRSTORDERWAVEEQUATIONSEMKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/anisotropic/ElasticVTIFields.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/anisotropic/ElasticVTIFields.hpp new file mode 100644 index 00000000000..e2380615eb4 --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/anisotropic/ElasticVTIFields.hpp @@ -0,0 +1,65 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + + +/** + * @file ElasticVTIFields.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICVTIFIELDS_HPP_ +#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICVTIFIELDS_HPP_ + +#include "common/DataLayouts.hpp" +#include "mesh/MeshFields.hpp" + +namespace geos +{ + +namespace fields +{ + +namespace elasticvtifields +{ +DECLARE_FIELD( Delta, + "delta", + array1d< real32 >, + 0, + NOPLOT, + WRITE_AND_READ, + "Delta thomsen anisotropy parameter" ); + +DECLARE_FIELD( Epsilon, + "epsilon", + array1d< real32 >, + 0, + NOPLOT, + WRITE_AND_READ, + "Epsilon thomsen anisotropy parameter" ); + +DECLARE_FIELD( Gamma, + "gamma", + array1d< real32 >, + 0, + NOPLOT, + WRITE_AND_READ, + "Gamma thomsen anisotropy parameter" ); + +} + +} + +} /* namespace geos */ + +#endif /* GEOS_PHYSICSSOLVERS_WAVEPROPAGATION__HPP_ELASTICVTIFIELDS */ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/anisotropic/ElasticVTIWaveEquationSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/anisotropic/ElasticVTIWaveEquationSEMKernel.hpp new file mode 100644 index 00000000000..181c41884da --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/anisotropic/ElasticVTIWaveEquationSEMKernel.hpp @@ -0,0 +1,582 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ElasticVTIWaveEquationSEMKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ElasticVTIWaveEquationSEMKERNEL_HPP_ +#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ElasticVTIWaveEquationSEMKERNEL_HPP_ + +#include "finiteElement/kernelInterface/KernelBase.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverUtils.hpp" +#include "physicsSolvers/wavePropagation/sem/elastic/shared/ElasticFields.hpp" +#include "ElasticVTIFields.hpp" + +namespace geos +{ + +/// Namespace to contain the elastic wave kernels. +namespace elasticVTIWaveEquationSEMKernels +{ + +template< typename FE_TYPE > +struct ComputeTimeStep +{ + + ComputeTimeStep( FE_TYPE const & finiteElement ) + : m_finiteElement( finiteElement ) + {} + + /** + * @brief Compute timestep using power iteration method + */ + template< typename EXEC_POLICY, typename ATOMIC_POLICY > + real64 + launch( localIndex const sizeElem, + localIndex const sizeNode, + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, + arrayView1d< real32 const > const density, + arrayView1d< real32 const > const Vp, + arrayView1d< real32 const > const Vs, + arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes, + arrayView1d< real32 > const mass ) + { + + constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; + + real64 const epsilon = 0.00001; + localIndex const nIterMax = 10000; + localIndex numberIter = 0; + localIndex counter = 0; + real64 lambdaNew = 0.0; + + array1d< real32 > const ux( sizeNode ); + array1d< real32 > const uy( sizeNode ); + array1d< real32 > const uz( sizeNode ); + array1d< real32 > const uxAux( sizeNode ); + array1d< real32 > const uyAux( sizeNode ); + array1d< real32 > const uzAux( sizeNode ); + + + + arrayView1d< real32 > const uxView = ux; + arrayView1d< real32 > const uyView = uy; + arrayView1d< real32 > const uzView = uz; + arrayView1d< real32 > const uxAuxView = uxAux; + arrayView1d< real32 > const uyAuxView = uyAux; + arrayView1d< real32 > const uzAuxView = uzAux; + + //Randomize p values + srand( time( NULL )); + for( localIndex a = 0; a < sizeNode; ++a ) + { + uxView[a] = (real64)rand()/(real64) RAND_MAX; + uyView[a] = (real64)rand()/(real64) RAND_MAX; + uzView[a] = (real64)rand()/(real64) RAND_MAX; + } + + //Step 1: Normalize randomized pressure + real64 normUx= 0.0; + real64 normUy= 0.0; + real64 normUz= 0.0; + WaveSolverUtils::dotProduct( sizeNode, uxView, uxView, normUx ); + WaveSolverUtils::dotProduct( sizeNode, uyView, uyView, normUy ); + WaveSolverUtils::dotProduct( sizeNode, uzView, uzView, normUz ); + real64 normUtot = normUx+normUy+normUz; + + + forAll< EXEC_POLICY >( sizeNode, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + uxView[a]/= sqrt( normUtot ); + uyView[a]/= sqrt( normUtot ); + uzView[a]/= sqrt( normUtot ); + } ); + + //Step 2: Initial iteration of (M^{-1}K)p + uxAuxView.zero(); + uyAuxView.zero(); + uzAuxView.zero(); + forAll< EXEC_POLICY >( sizeElem, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + + real64 mu = density[k]*Vs[k]*Vs[k]; + real64 lambda = density[k]*Vp[k]*Vp[k]-2*mu; + + real64 xLocal[8][3]; + for( localIndex a=0; a< 8; ++a ) + { + localIndex const nodeIndex = elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); + for( localIndex i=0; i<3; ++i ) + { + xLocal[a][i] = nodeCoords[ nodeIndex ][ i ]; + } + } + for( localIndex q = 0; q < numNodesPerElem; ++q ) + { + m_finiteElement.computeFirstOrderStiffnessTerm( q, xLocal, [&] ( int i, int j, real64 val, real64 J[3][3], int p, int r ) + { + real32 const Rxx_ij = val*((lambda+2.0*mu)*J[p][0]*J[r][0]+mu*(J[p][1]*J[r][1]+J[p][2]*J[r][2])); + real32 const Ryy_ij = val*((lambda+2.0*mu)*J[p][1]*J[r][1]+mu*(J[p][0]*J[r][0]+J[p][2]*J[r][2])); + real32 const Rzz_ij = val*((lambda+2.0*mu)*J[p][2]*J[r][2]+mu*(J[p][0]*J[r][0]+J[p][1]*J[r][1])); + real32 const Rxy_ij = val*(lambda*J[p][0]*J[r][1]+mu*J[p][1]*J[r][0]); + real32 const Ryx_ij = val*(mu*J[p][0]*J[r][1]+lambda*J[p][1]*J[r][0]); + real32 const Rxz_ij = val*(lambda*J[p][0]*J[r][2]+mu*J[p][2]*J[r][0]); + real32 const Rzx_ij = val*(mu*J[p][0]*J[r][2]+lambda*J[p][2]*J[r][0]); + real32 const Ryz_ij = val*(lambda*J[p][1]*J[r][2]+mu*J[p][2]*J[r][1]); + real32 const Rzy_ij = val*(mu*J[p][1]*J[r][2]+lambda*J[p][2]*J[r][1]); + + real32 const localIncrementx = (Rxx_ij * uxView[elemsToNodes[k][j]] + Rxy_ij*uyView[elemsToNodes[k][j]] + Rxz_ij*uzView[elemsToNodes[k][j]]); + real32 const localIncrementy = (Ryx_ij * uxView[elemsToNodes[k][j]] + Ryy_ij*uyView[elemsToNodes[k][j]] + Ryz_ij*uzView[elemsToNodes[k][j]]); + real32 const localIncrementz = (Rzx_ij * uxView[elemsToNodes[k][j]] + Rzy_ij*uyView[elemsToNodes[k][j]] + Rzz_ij*uzView[elemsToNodes[k][j]]); + + RAJA::atomicAdd< parallelDeviceAtomic >( &uxAuxView[elemsToNodes[k][i]], localIncrementx ); + RAJA::atomicAdd< parallelDeviceAtomic >( &uyAuxView[elemsToNodes[k][i]], localIncrementy ); + RAJA::atomicAdd< parallelDeviceAtomic >( &uzAuxView[elemsToNodes[k][i]], localIncrementz ); + } ); + + } + + } ); + + forAll< EXEC_POLICY >( sizeNode, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + uxAuxView[a]/= mass[a]; + uyAuxView[a]/= mass[a]; + uzAuxView[a]/= mass[a]; + } ); + real64 lambdaOld = lambdaNew; + + //Compute lambdaNew using two dotProducts + real64 dotProductUxUxaux = 0.0; + real64 dotProductUyUyaux = 0.0; + real64 dotProductUzUzaux = 0.0; + + WaveSolverUtils::dotProduct( sizeNode, uxView, uxAuxView, dotProductUxUxaux ); + WaveSolverUtils::dotProduct( sizeNode, uyView, uyAuxView, dotProductUyUyaux ); + WaveSolverUtils::dotProduct( sizeNode, uzView, uzAuxView, dotProductUzUzaux ); + real64 dotProductUtotUtotAux = dotProductUxUxaux+dotProductUyUyaux+dotProductUzUzaux; + + normUx = 0.0; + normUy = 0.0; + normUz = 0.0; + + WaveSolverUtils::dotProduct( sizeNode, uxView, uxView, normUx ); + WaveSolverUtils::dotProduct( sizeNode, uyView, uyView, normUy ); + WaveSolverUtils::dotProduct( sizeNode, uzView, uzView, normUz ); + normUtot = normUx+normUy+normUz; + + + lambdaNew = dotProductUtotUtotAux/normUtot; + + real64 normUxaux = 0.0; + real64 normUyaux = 0.0; + real64 normUzaux = 0.0; + WaveSolverUtils::dotProduct( sizeNode, uxAuxView, uxAuxView, normUxaux ); + WaveSolverUtils::dotProduct( sizeNode, uyAuxView, uyAuxView, normUyaux ); + WaveSolverUtils::dotProduct( sizeNode, uzAuxView, uzAuxView, normUzaux ); + + real64 normUtotAux = normUxaux+normUyaux+normUzaux; + + + forAll< EXEC_POLICY >( sizeNode, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + uxView[a]= uxAuxView[a]/sqrt( normUtotAux ); + uyView[a]= uyAuxView[a]/sqrt( normUtotAux ); + uzView[a]= uzAuxView[a]/sqrt( normUtotAux ); + } ); + + //Step 3: Do previous algorithm until we found the max eigenvalues + do + { + uxAuxView.zero(); + uyAuxView.zero(); + uzAuxView.zero(); + forAll< EXEC_POLICY >( sizeElem, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + + real64 mu = density[k]*Vs[k]*Vs[k]; + real64 lambda = density[k]*Vp[k]*Vp[k]-2*mu; + + real64 xLocal[8][3]; + for( localIndex a=0; a< 8; ++a ) + { + localIndex const nodeIndex = elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); + for( localIndex i=0; i<3; ++i ) + { + xLocal[a][i] = nodeCoords[ nodeIndex ][ i ]; + } + } + for( localIndex q = 0; q < numNodesPerElem; ++q ) + { + m_finiteElement.computeFirstOrderStiffnessTerm( q, xLocal, [&] ( int i, int j, real64 val, real64 J[3][3], int p, int r ) + { + real32 const Rxx_ij = val*((lambda+2.0*mu)*J[p][0]*J[r][0]+mu*(J[p][1]*J[r][1]+J[p][2]*J[r][2])); + real32 const Ryy_ij = val*((lambda+2.0*mu)*J[p][1]*J[r][1]+mu*(J[p][0]*J[r][0]+J[p][2]*J[r][2])); + real32 const Rzz_ij = val*((lambda+2.0*mu)*J[p][2]*J[r][2]+mu*(J[p][0]*J[r][0]+J[p][1]*J[r][1])); + real32 const Rxy_ij = val*(lambda*J[p][0]*J[r][1]+mu*J[p][1]*J[r][0]); + real32 const Ryx_ij = val*(mu*J[p][0]*J[r][1]+lambda*J[p][1]*J[r][0]); + real32 const Rxz_ij = val*(lambda*J[p][0]*J[r][2]+mu*J[p][2]*J[r][0]); + real32 const Rzx_ij = val*(mu*J[p][0]*J[r][2]+lambda*J[p][2]*J[r][0]); + real32 const Ryz_ij = val*(lambda*J[p][1]*J[r][2]+mu*J[p][2]*J[r][1]); + real32 const Rzy_ij = val*(mu*J[p][1]*J[r][2]+lambda*J[p][2]*J[r][1]); + + real32 const localIncrementx = (Rxx_ij * uxView[elemsToNodes[k][j]] + Rxy_ij*uyView[elemsToNodes[k][j]] + Rxz_ij*uzView[elemsToNodes[k][j]]); + real32 const localIncrementy = (Ryx_ij * uxView[elemsToNodes[k][j]] + Ryy_ij*uyView[elemsToNodes[k][j]] + Ryz_ij*uzView[elemsToNodes[k][j]]); + real32 const localIncrementz = (Rzx_ij * uxView[elemsToNodes[k][j]] + Rzy_ij*uyView[elemsToNodes[k][j]] + Rzz_ij*uzView[elemsToNodes[k][j]]); + + RAJA::atomicAdd< parallelDeviceAtomic >( &uxAuxView[elemsToNodes[k][i]], localIncrementx ); + RAJA::atomicAdd< parallelDeviceAtomic >( &uyAuxView[elemsToNodes[k][i]], localIncrementy ); + RAJA::atomicAdd< parallelDeviceAtomic >( &uzAuxView[elemsToNodes[k][i]], localIncrementz ); + } ); + + } + + } ); + + forAll< EXEC_POLICY >( sizeNode, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + uxAuxView[a]/= mass[a]; + uyAuxView[a]/= mass[a]; + uzAuxView[a]/= mass[a]; + } ); + lambdaOld = lambdaNew; + + //Compute lambdaNew using two dotProducts + dotProductUxUxaux = 0.0; + dotProductUyUyaux = 0.0; + dotProductUzUzaux = 0.0; + + WaveSolverUtils::dotProduct( sizeNode, uxView, uxAuxView, dotProductUxUxaux ); + WaveSolverUtils::dotProduct( sizeNode, uyView, uyAuxView, dotProductUyUyaux ); + WaveSolverUtils::dotProduct( sizeNode, uzView, uzAuxView, dotProductUzUzaux ); + dotProductUtotUtotAux = dotProductUxUxaux+dotProductUyUyaux+dotProductUzUzaux; + + normUx = 0.0; + normUy = 0.0; + normUz = 0.0; + + WaveSolverUtils::dotProduct( sizeNode, uxView, uxView, normUx ); + WaveSolverUtils::dotProduct( sizeNode, uyView, uyView, normUy ); + WaveSolverUtils::dotProduct( sizeNode, uzView, uzView, normUz ); + normUtot = normUx+normUy+normUz; + + + lambdaNew = dotProductUtotUtotAux/normUtot; + + normUxaux = 0.0; + normUyaux = 0.0; + normUzaux = 0.0; + WaveSolverUtils::dotProduct( sizeNode, uxAuxView, uxAuxView, normUxaux ); + WaveSolverUtils::dotProduct( sizeNode, uyAuxView, uyAuxView, normUyaux ); + WaveSolverUtils::dotProduct( sizeNode, uzAuxView, uzAuxView, normUzaux ); + + normUtotAux = normUxaux+normUyaux+normUzaux; + + + forAll< EXEC_POLICY >( sizeNode, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + uxView[a]= uxAuxView[a]/sqrt( normUtotAux ); + uyView[a]= uyAuxView[a]/sqrt( normUtotAux ); + uzView[a]= uzAuxView[a]/sqrt( normUtotAux ); + } ); + + if( LvArray::math::abs( lambdaNew-lambdaOld )/LvArray::math::abs( lambdaNew )<= epsilon ) + { + counter++; + } + else + { + counter=0; + } + + numberIter++; + + + } + while (counter < 10 && numberIter < nIterMax); + + GEOS_THROW_IF( numberIter> nIterMax, "Power Iteration algorithm does not converge", std::runtime_error ); + + real64 dt = 1.99/sqrt( LvArray::math::abs( lambdaNew )); + + return dt; + + } + + /// The finite element space/discretization object for the element type in the subRegion + FE_TYPE const & m_finiteElement; +}; + +/** + * @brief Implements kernels for solving the elastic wave equations + * explicit central FD method and SEM in the Vertical Transverse Isotropic (VTI) case + * @copydoc geos::finiteElement::KernelBase + * @tparam SUBREGION_TYPE The type of subregion that the kernel will act on. + * + * ### ElasticVTIWaveEquationSEMKernel Description + * Implements the KernelBase interface functions required for solving + * the acoustic wave equations using the + * "finite element kernel application" functions such as + * geos::finiteElement::RegionBasedKernelApplication. + * + * The number of degrees of freedom per support point for both + * the test and trial spaces are specified as `1`. + */ + + +template< typename SUBREGION_TYPE, + typename CONSTITUTIVE_TYPE, + typename FE_TYPE > +class ExplicitElasticVTISEM : public finiteElement::KernelBase< SUBREGION_TYPE, + CONSTITUTIVE_TYPE, + FE_TYPE, + 1, + 1 > +{ +public: + + /// Alias for the base class; + using Base = finiteElement::KernelBase< SUBREGION_TYPE, + CONSTITUTIVE_TYPE, + FE_TYPE, + 1, + 1 >; + + /// Number of nodes per element...which is equal to the + /// numTestSupportPointPerElem and numTrialSupportPointPerElem by definition. + static constexpr int numNodesPerElem = Base::maxNumTestSupportPointsPerElem; + + using Base::numDofPerTestSupportPoint; + using Base::numDofPerTrialSupportPoint; + using Base::m_elemsToNodes; + using Base::m_elemGhostRank; + using Base::m_constitutiveUpdate; + using Base::m_finiteElementSpace; + +//***************************************************************************** + /** + * @brief Constructor + * @copydoc geos::finiteElement::KernelBase::KernelBase + * @param nodeManager Reference to the NodeManager object. + * @param edgeManager Reference to the EdgeManager object. + * @param faceManager Reference to the FaceManager object. + * @param targetRegionIndex Index of the region the subregion belongs to. + * @param dt The time interval for the step. + */ + ExplicitElasticVTISEM( NodeManager & nodeManager, + EdgeManager const & edgeManager, + FaceManager const & faceManager, + localIndex const targetRegionIndex, + SUBREGION_TYPE const & elementSubRegion, + FE_TYPE const & finiteElementSpace, + CONSTITUTIVE_TYPE & inputConstitutiveType, + real64 const dt ): + Base( elementSubRegion, + finiteElementSpace, + inputConstitutiveType ), + m_nodeCoords( nodeManager.getField< fields::referencePosition32 >() ), + m_ux_n( nodeManager.getField< fields::elasticfields::Displacementx_n >() ), + m_uy_n( nodeManager.getField< fields::elasticfields::Displacementy_n >() ), + m_uz_n( nodeManager.getField< fields::elasticfields::Displacementz_n >() ), + m_stiffnessVectorx( nodeManager.getField< fields::elasticfields::StiffnessVectorx >() ), + m_stiffnessVectory( nodeManager.getField< fields::elasticfields::StiffnessVectory >() ), + m_stiffnessVectorz( nodeManager.getField< fields::elasticfields::StiffnessVectorz >() ), + m_density( elementSubRegion.template getField< fields::elasticfields::ElasticDensity >() ), + m_velocityVp( elementSubRegion.template getField< fields::elasticfields::ElasticVelocityVp >() ), + m_velocityVs( elementSubRegion.template getField< fields::elasticfields::ElasticVelocityVs >() ), + m_gamma( elementSubRegion.template getField< fields::elasticvtifields::Gamma >()), + m_epsilon( elementSubRegion.template getField< fields::elasticvtifields::Epsilon >()), + m_delta( elementSubRegion.template getField< fields::elasticvtifields::Delta >()), + m_dt( dt ) + { + GEOS_UNUSED_VAR( edgeManager ); + GEOS_UNUSED_VAR( faceManager ); + GEOS_UNUSED_VAR( targetRegionIndex ); + } + + + + //***************************************************************************** + /** + * @copydoc geos::finiteElement::KernelBase::StackVariables + * + * ### ExplicitElasticVTISEM Description + * Adds a stack arrays for the nodal force, primary displacement variable, etc. + */ + struct StackVariables : Base::StackVariables + { +public: + GEOS_HOST_DEVICE + StackVariables(): + xLocal(), + stiffnessVectorxLocal(), + stiffnessVectoryLocal(), + stiffnessVectorzLocal() + {} + /// C-array stack storage for element local the nodal positions. + real64 xLocal[ 8 ][ 3 ]{}; + real32 stiffnessVectorxLocal[ numNodesPerElem ]; + real32 stiffnessVectoryLocal[ numNodesPerElem ]; + real32 stiffnessVectorzLocal[ numNodesPerElem ]; + real32 Cvti[6]; + + }; + //*************************************************************************** + + + /** + * @copydoc geos::finiteElement::KernelBase::setup + * + * Copies the primary variable, and position into the local stack array. + */ + GEOS_HOST_DEVICE + inline + void setup( localIndex const k, + StackVariables & stack ) const + { + for( localIndex a=0; a< 8; a++ ) + { + localIndex const nodeIndex = m_elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); + for( int i=0; i< 3; ++i ) + { + stack.xLocal[ a ][ i ] = m_nodeCoords[ nodeIndex ][ i ]; + } + } + + stack.Cvti[0] = m_density[k] * pow( m_velocityVp[k], 2 ) * (1.0 + 2.0*m_epsilon[k]); + stack.Cvti[1] = m_density[k] * pow( m_velocityVp[k], 2 ); + stack.Cvti[2] = m_density[k] * + sqrt( pow((pow( m_velocityVp[k], + 2 ) - pow( m_velocityVs[k], 2 )), + 2 ) + 2.0 * pow( m_velocityVp[k], 2 ) * m_delta[k] * (pow( m_velocityVp[k], 2 ) - pow( m_velocityVs[k], 2 )) ) - m_density[k] * pow( + m_velocityVs[k], 2 ); + stack.Cvti[3] = m_density[k] * pow( m_velocityVs[k], 2 ); + stack.Cvti[4] = m_density[k] * pow( m_velocityVs[k], 2 )*(1.0 + 2.0 * m_gamma[k]); + stack.Cvti[5] = stack.Cvti[0] - 2.0 * stack.Cvti[4]; + + } + + /** + * @copydoc geos::finiteElement::KernelBase::complete + */ + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + real64 complete( localIndex const k, + StackVariables & stack ) const + { + for( int i=0; i( &m_stiffnessVectorx[ nodeIndex ], stack.stiffnessVectorxLocal[ i ] ); + RAJA::atomicAdd< parallelDeviceAtomic >( &m_stiffnessVectory[ nodeIndex ], stack.stiffnessVectoryLocal[ i ] ); + RAJA::atomicAdd< parallelDeviceAtomic >( &m_stiffnessVectorz[ nodeIndex ], stack.stiffnessVectorzLocal[ i ] ); + } + return 0; + } + + /** + * @copydoc geos::finiteElement::KernelBase::quadraturePointKernel + * + * ### ExplicitElasticVTISEM Description + * Calculates stiffness vector + * + */ + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + void quadraturePointKernel( localIndex const k, + localIndex const q, + StackVariables & stack ) const + { + + m_finiteElementSpace.template computeFirstOrderStiffnessTerm( q, stack.xLocal, [&] ( int i, int j, real64 val, real64 J[3][3], int p, int r ) + { + real32 const Rxx_ij = val*(stack.Cvti[0]*J[p][0]*J[r][0]+stack.Cvti[4]*(J[p][1]*J[r][1])+stack.Cvti[3]*(J[p][2]*J[r][2])); + real32 const Ryy_ij = val*(stack.Cvti[0]*J[p][1]*J[r][1]+stack.Cvti[4]*(J[p][0]*J[r][0])+stack.Cvti[3]*(J[p][2]*J[r][2])); + real32 const Rzz_ij = val*(stack.Cvti[1]*J[p][2]*J[r][2]+stack.Cvti[3]*(J[p][0]*J[r][0]+J[p][1]*J[r][1])); + real32 const Rxy_ij = val*(stack.Cvti[5]*J[p][0]*J[r][1]+stack.Cvti[4]*J[p][1]*J[r][0]); + real32 const Ryx_ij = val*(stack.Cvti[4]*J[p][0]*J[r][1]+stack.Cvti[5]*J[p][1]*J[r][0]); + real32 const Rxz_ij = val*(stack.Cvti[2]*J[p][0]*J[r][2]+stack.Cvti[3]*J[p][2]*J[r][0]); + real32 const Rzx_ij = val*(stack.Cvti[3]*J[p][0]*J[r][2]+stack.Cvti[2]*J[p][2]*J[r][0]); + real32 const Ryz_ij = val*(stack.Cvti[2]*J[p][1]*J[r][2]+stack.Cvti[3]*J[p][2]*J[r][1]); + real32 const Rzy_ij = val*(stack.Cvti[3]*J[p][1]*J[r][2]+stack.Cvti[2]*J[p][2]*J[r][1]); + + real32 const localIncrementx = (Rxx_ij * m_ux_n[m_elemsToNodes( k, j )] + Rxy_ij*m_uy_n[m_elemsToNodes( k, j )] + Rxz_ij*m_uz_n[m_elemsToNodes( k, j )]); + real32 const localIncrementy = (Ryx_ij * m_ux_n[m_elemsToNodes( k, j )] + Ryy_ij*m_uy_n[m_elemsToNodes( k, j )] + Ryz_ij*m_uz_n[m_elemsToNodes( k, j )]); + real32 const localIncrementz = (Rzx_ij * m_ux_n[m_elemsToNodes( k, j )] + Rzy_ij*m_uy_n[m_elemsToNodes( k, j )] + Rzz_ij*m_uz_n[m_elemsToNodes( k, j )]); + + stack.stiffnessVectorxLocal[ i ] += localIncrementx; + stack.stiffnessVectoryLocal[ i ] += localIncrementy; + stack.stiffnessVectorzLocal[ i ] += localIncrementz; + } ); + } + + +protected: + /// The array containing the nodal position array. + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const m_nodeCoords; + + /// The array containing the nodal displacement array in x direction. + arrayView1d< real32 > const m_ux_n; + + /// The array containing the nodal displacement array in y direction. + arrayView1d< real32 > const m_uy_n; + + /// The array containing the nodal displacement array in z direction. + arrayView1d< real32 > const m_uz_n; + + /// The array containing the product of the stiffness matrix and the nodal displacement. + arrayView1d< real32 > const m_stiffnessVectorx; + + /// The array containing the product of the stiffness matrix and the nodal displacement. + arrayView1d< real32 > const m_stiffnessVectory; + + /// The array containing the product of the stiffness matrix and the nodal displacement. + arrayView1d< real32 > const m_stiffnessVectorz; + + /// The array containing the density of the medium + arrayView1d< real32 const > const m_density; + + /// The array containing the P-wavespeed + arrayView1d< real32 const > const m_velocityVp; + + /// The array containing the S-wavespeed + arrayView1d< real32 const > const m_velocityVs; + + ///The array containing the Thomsen constant gamma + arrayView1d< real32 const > const m_gamma; + + ///The array containing the Thomsen constant epsilon + arrayView1d< real32 const > const m_epsilon; + + ///The array containing the Thomsen constant delta + arrayView1d< real32 const > const m_delta; + + /// The time increment for this time integration step. + real64 const m_dt; + + +}; + + +/// The factory used to construct a ExplicitAcousticWaveEquation kernel. +using ExplicitElasticVTISEMFactory = finiteElement::KernelFactory< ExplicitElasticVTISEM, + real64 >; + +} // namespace elasticVTIWaveEquationSEMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ElasticVTIWaveEquationSEMKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEM.cpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEM.cpp new file mode 100644 index 00000000000..acf9572b216 --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEM.cpp @@ -0,0 +1,1039 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + + +/** + * @file ElasticWaveEquationSEM.cpp + */ + +#include "ElasticWaveEquationSEM.hpp" +#include "ElasticWaveEquationSEMKernel.hpp" +#include "physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/anisotropic/ElasticVTIWaveEquationSEMKernel.hpp" + +#include "fieldSpecification/FieldSpecificationManager.hpp" +#include "finiteElement/FiniteElementDiscretization.hpp" +#include "mainInterface/ProblemManager.hpp" +#include "mesh/ElementType.hpp" +#include "mesh/DomainPartition.hpp" +#include "mesh/mpiCommunications/CommunicationTools.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverUtils.hpp" +#include "physicsSolvers/wavePropagation/shared/PrecomputeSourcesAndReceiversKernel.hpp" +#include "physicsSolvers/wavePropagation/sem/elastic/shared/ElasticTimeSchemeSEMKernel.hpp" +#include "physicsSolvers/wavePropagation/sem/elastic/shared/ElasticMatricesSEMKernel.hpp" +#include "events/EventManager.hpp" + +namespace geos +{ + +using namespace dataRepository; +using namespace fields; + +ElasticWaveEquationSEM::ElasticWaveEquationSEM( const std::string & name, + Group * const parent ): + + WaveSolverBase( name, + parent ) +{ + registerWrapper( viewKeyStruct::sourceConstantsString(), &m_sourceConstantsx ). + setInputFlag( InputFlags::FALSE ). + setSizedFromParent( 0 ). + setDescription( "Constant part of the source for the nodes listed in m_sourceNodeIds in x-direction" ); + + registerWrapper( viewKeyStruct::sourceConstantsString(), &m_sourceConstantsy ). + setInputFlag( InputFlags::FALSE ). + setSizedFromParent( 0 ). + setDescription( "Constant part of the source for the nodes listed in m_sourceNodeIds in y-direction" ); + + registerWrapper( viewKeyStruct::sourceConstantsString(), &m_sourceConstantsz ). + setInputFlag( InputFlags::FALSE ). + setSizedFromParent( 0 ). + setDescription( "Constant part of the source for the nodes listed in m_sourceNodeIds in z-direction" ); + + registerWrapper( viewKeyStruct::displacementXNp1AtReceiversString(), &m_displacementXNp1AtReceivers ). + setInputFlag( InputFlags::FALSE ). + setSizedFromParent( 0 ). + setDescription( "Displacement value at each receiver for each timestep (x-component)" ); + + registerWrapper( viewKeyStruct::displacementYNp1AtReceiversString(), &m_displacementYNp1AtReceivers ). + setInputFlag( InputFlags::FALSE ). + setSizedFromParent( 0 ). + setDescription( "Displacement value at each receiver for each timestep (y-component)" ); + + registerWrapper( viewKeyStruct::displacementZNp1AtReceiversString(), &m_displacementZNp1AtReceivers ). + setInputFlag( InputFlags::FALSE ). + setSizedFromParent( 0 ). + setDescription( "Displacement value at each receiver for each timestep (z-component)" ); + + registerWrapper( viewKeyStruct::dasSignalNp1AtReceiversString(), &m_dasSignalNp1AtReceivers ). + setInputFlag( InputFlags::FALSE ). + setSizedFromParent( 0 ). + setDescription( "DAS signal value at each receiver for each timestep" ); + + registerWrapper( viewKeyStruct::sourceForceString(), &m_sourceForce ). + setInputFlag( InputFlags::OPTIONAL ). + setSizedFromParent( 0 ). + setApplyDefaultValue( { 0.0, 0.0, 0.0 } ). + setDescription( "Force of the source: 3 real values for a vector source, and 6 real values for a tensor source (in Voigt notation)." + "The default value is { 0, 0, 0 } (no net force)." ); + + registerWrapper( viewKeyStruct::sourceMomentString(), &m_sourceMoment ). + setInputFlag( InputFlags::OPTIONAL ). + setSizedFromParent( 0 ). + setApplyDefaultValue( { 1.0, 1.0, 1.0, 0.0, 0.0, 0.0 } ). + setDescription( "Moment of the source: 6 real values describing a symmetric tensor in Voigt notation." + "The default value is { 1, 1, 1, 0, 0, 0 } (diagonal moment, corresponding to a seismic charge)." ); + + + registerWrapper( viewKeyStruct::useVtiString(), &m_useVTI ). + setInputFlag( InputFlags::OPTIONAL ). + setSizedFromParent( 0 ). + setApplyDefaultValue( 0 ). + setDescription( "Flag to apply VTI anisotropy. The default is to use isotropic physic." ); +} + +ElasticWaveEquationSEM::~ElasticWaveEquationSEM() +{ + // TODO Auto-generated destructor stub +} + +void ElasticWaveEquationSEM::initializePreSubGroups() +{ + + WaveSolverBase::initializePreSubGroups(); + + localIndex const numNodesPerElem = WaveSolverBase::getNumNodesPerElem(); + + localIndex const numSourcesGlobal = m_sourceCoordinates.size( 0 ); + m_sourceConstantsx.resize( numSourcesGlobal, numNodesPerElem ); + m_sourceConstantsy.resize( numSourcesGlobal, numNodesPerElem ); + m_sourceConstantsz.resize( numSourcesGlobal, numNodesPerElem ); + + localIndex const numReceiversGlobal = m_receiverCoordinates.size( 0 ); + integer nsamples = m_useDAS == WaveSolverUtils::DASType::none ? 1 : m_linearDASSamples; + m_receiverConstants.resize( numReceiversGlobal, nsamples * numNodesPerElem ); + m_receiverNodeIds.resize( numReceiversGlobal, nsamples * numNodesPerElem ); +} + + +void ElasticWaveEquationSEM::registerDataOnMesh( Group & meshBodies ) +{ + WaveSolverBase::registerDataOnMesh( meshBodies ); + + forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + { + NodeManager & nodeManager = mesh.getNodeManager(); + + nodeManager.registerField< elasticfields::Displacementx_nm1, + elasticfields::Displacementy_nm1, + elasticfields::Displacementz_nm1, + elasticfields::Displacementx_n, + elasticfields::Displacementy_n, + elasticfields::Displacementz_n, + elasticfields::Displacementx_np1, + elasticfields::Displacementy_np1, + elasticfields::Displacementz_np1, + elasticfields::ForcingRHSx, + elasticfields::ForcingRHSy, + elasticfields::ForcingRHSz, + elasticfields::ElasticMassVector, + elasticfields::DampingVectorx, + elasticfields::DampingVectory, + elasticfields::DampingVectorz, + elasticfields::StiffnessVectorx, + elasticfields::StiffnessVectory, + elasticfields::StiffnessVectorz, + elasticfields::ElasticFreeSurfaceNodeIndicator >( getName() ); + + if( m_attenuationType == WaveSolverUtils::AttenuationType::sls ) + { + integer l = m_slsReferenceAngularFrequencies.size( 0 ); + nodeManager.registerField< elasticfields::DivPsix, + elasticfields::DivPsiy, + elasticfields::DivPsiz, + elasticfields::StiffnessVectorAx, + elasticfields::StiffnessVectorAy, + elasticfields::StiffnessVectorAz >( getName() ); + nodeManager.getField< elasticfields::DivPsix >().resizeDimension< 1 >( l ); + nodeManager.getField< elasticfields::DivPsiy >().resizeDimension< 1 >( l ); + nodeManager.getField< elasticfields::DivPsiz >().resizeDimension< 1 >( l ); + } + + FaceManager & faceManager = mesh.getFaceManager(); + faceManager.registerField< elasticfields::ElasticFreeSurfaceFaceIndicator >( getName() ); + + ElementRegionManager & elemManager = mesh.getElemManager(); + + elemManager.forElementSubRegions< CellElementSubRegion >( [&]( CellElementSubRegion & subRegion ) + { + subRegion.registerField< elasticfields::ElasticVelocityVp >( getName() ); + subRegion.registerField< elasticfields::ElasticVelocityVs >( getName() ); + subRegion.registerField< elasticfields::ElasticDensity >( getName() ); + if( m_attenuationType == WaveSolverUtils::AttenuationType::sls ) + { + subRegion.registerField< elasticfields::ElasticQualityFactorP >( getName() ); + subRegion.registerField< elasticfields::ElasticQualityFactorS >( getName() ); + } + + if( m_useVTI ) + { + subRegion.registerField< elasticvtifields::Gamma >( getName() ); + subRegion.registerField< elasticvtifields::Epsilon >( getName() ); + subRegion.registerField< elasticvtifields::Delta >( getName() ); + } + } ); + + } ); +} + + + +void ElasticWaveEquationSEM::postInputInitialization() +{ + WaveSolverBase::postInputInitialization(); + + if( m_useDAS == WaveSolverUtils::DASType::none ) + { + localIndex const numReceiversGlobal = m_receiverCoordinates.size( 0 ); + m_displacementXNp1AtReceivers.resize( m_nsamplesSeismoTrace, numReceiversGlobal + 1 ); + m_displacementYNp1AtReceivers.resize( m_nsamplesSeismoTrace, numReceiversGlobal + 1 ); + m_displacementZNp1AtReceivers.resize( m_nsamplesSeismoTrace, numReceiversGlobal + 1 ); + m_displacementXNp1AtReceivers.zero(); + m_displacementYNp1AtReceivers.zero(); + m_displacementZNp1AtReceivers.zero(); + } + else + { + localIndex const numReceiversGlobal = m_linearDASGeometry.size( 0 ); + m_dasSignalNp1AtReceivers.resize( m_nsamplesSeismoTrace, numReceiversGlobal + 1 ); + m_dasSignalNp1AtReceivers.zero(); + } +} + + +void ElasticWaveEquationSEM::precomputeSourceAndReceiverTerm( MeshLevel & baseMesh, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) +{ + GEOS_MARK_FUNCTION; + + arrayView1d< globalIndex const > const nodeLocalToGlobal = baseMesh.getNodeManager().localToGlobalMap().toViewConst(); + ArrayOfArraysView< localIndex const > const nodesToElements = baseMesh.getNodeManager().elementList().toViewConst(); + ArrayOfArraysView< localIndex const > const facesToNodes = baseMesh.getFaceManager().nodeList().toViewConst(); + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const nodeCoords = baseMesh.getNodeManager().referencePosition(); + + arrayView2d< real64 const > const sourceCoordinates = m_sourceCoordinates.toViewConst(); + arrayView2d< localIndex > const sourceNodeIds = m_sourceNodeIds.toView(); + arrayView2d< real64 > const sourceConstantsx = m_sourceConstantsx.toView(); + arrayView2d< real64 > const sourceConstantsy = m_sourceConstantsy.toView(); + arrayView2d< real64 > const sourceConstantsz = m_sourceConstantsz.toView(); + arrayView1d< localIndex > const sourceIsAccessible = m_sourceIsAccessible.toView(); + + sourceNodeIds.setValues< EXEC_POLICY >( -1 ); + sourceConstantsx.setValues< EXEC_POLICY >( 0 ); + sourceConstantsy.setValues< EXEC_POLICY >( 0 ); + sourceConstantsz.setValues< EXEC_POLICY >( 0 ); + sourceIsAccessible.zero(); + + arrayView2d< real64 const > const receiverCoordinates = m_receiverCoordinates.toViewConst(); + arrayView2d< localIndex > const receiverNodeIds = m_receiverNodeIds.toView(); + arrayView2d< real64 > const receiverConstants = m_receiverConstants.toView(); + arrayView1d< localIndex > const receiverIsLocal = m_receiverIsLocal.toView(); + receiverNodeIds.setValues< EXEC_POLICY >( -1 ); + receiverConstants.setValues< EXEC_POLICY >( 0 ); + receiverIsLocal.zero(); + + mesh.getElemManager().forElementSubRegionsComplete< CellElementSubRegion >( regionNames, [&]( localIndex const, + localIndex const er, + localIndex const esr, + ElementRegionBase &, + CellElementSubRegion & elementSubRegion ) + { + + GEOS_THROW_IF( elementSubRegion.getElementType() != ElementType::Hexahedron, + getDataContext() << ": Invalid type of element, the elastic solver is designed for hexahedral meshes only (C3D8) ", + InputError ); + + arrayView2d< localIndex const > const elemsToFaces = elementSubRegion.faceList(); + arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes = elementSubRegion.nodeList(); + arrayView2d< localIndex const, cells::NODE_MAP_USD > const & baseElemsToNodes = baseMesh.getElemManager().getRegion( er ).getSubRegion< CellElementSubRegion >( esr ).nodeList(); + arrayView2d< real64 const > const elemCenter = elementSubRegion.getElementCenter(); + arrayView1d< integer const > const elemGhostRank = elementSubRegion.ghostRank(); + arrayView1d< globalIndex const > const elemLocalToGlobal = elementSubRegion.localToGlobalMap().toViewConst(); + + finiteElement::FiniteElementBase const & + fe = elementSubRegion.getReference< finiteElement::FiniteElementBase >( getDiscretizationName() ); + finiteElement::FiniteElementDispatchHandler< SEM_FE_TYPES >::dispatch3D( fe, [&] ( auto const finiteElement ) + { + using FE_TYPE = TYPEOFREF( finiteElement ); + + PreComputeSourcesAndReceivers:: + Compute3DSourceAndReceiverConstantsWithDAS + < EXEC_POLICY, FE_TYPE > + ( elementSubRegion.size(), + facesToNodes, + nodeCoords, + nodeLocalToGlobal, + elemLocalToGlobal, + nodesToElements, + baseElemsToNodes, + elemGhostRank, + elemsToNodes, + elemsToFaces, + elemCenter, + sourceCoordinates, + sourceIsAccessible, + sourceNodeIds, + sourceConstantsx, + sourceConstantsy, + sourceConstantsz, + receiverCoordinates, + receiverIsLocal, + receiverNodeIds, + receiverConstants, + m_useDAS, + m_linearDASSamples, + m_linearDASGeometry.toViewConst(), + m_sourceForce, + m_sourceMoment ); + } ); + elementSubRegion.faceList().freeOnDevice(); + baseMesh.getElemManager().getRegion( er ).getSubRegion< CellElementSubRegion >( esr ).nodeList().freeOnDevice(); + elementSubRegion.getElementCenter().freeOnDevice(); + elementSubRegion.ghostRank().freeOnDevice(); + elementSubRegion.localToGlobalMap().freeOnDevice(); + } ); + baseMesh.getNodeManager().localToGlobalMap().freeOnDevice(); + baseMesh.getNodeManager().elementList().toView().freeOnDevice(); + baseMesh.getFaceManager().nodeList().toView().freeOnDevice(); + baseMesh.getNodeManager().referencePosition().freeOnDevice(); + facesToNodes.freeOnDevice(); + nodesToElements.freeOnDevice(); +} + +void ElasticWaveEquationSEM::addSourceToRightHandSide( real64 const & time_n, + arrayView1d< real32 > const rhsx, + arrayView1d< real32 > const rhsy, + arrayView1d< real32 > const rhsz ) +{ + arrayView2d< localIndex const > const sourceNodeIds = m_sourceNodeIds.toViewConst(); + arrayView2d< real64 const > const sourceConstantsx = m_sourceConstantsx.toViewConst(); + arrayView2d< real64 const > const sourceConstantsy = m_sourceConstantsy.toViewConst(); + arrayView2d< real64 const > const sourceConstantsz = m_sourceConstantsz.toViewConst(); + arrayView1d< localIndex const > const sourceIsAccessible = m_sourceIsAccessible.toViewConst(); + real32 const timeSourceFrequency = m_timeSourceFrequency; + real32 const timeSourceDelay = m_timeSourceDelay; + localIndex const rickerOrder = m_rickerOrder; + bool useSourceWaveletTables = m_useSourceWaveletTables; + arrayView1d< TableFunction::KernelWrapper const > const sourceWaveletTableWrappers = m_sourceWaveletTableWrappers.toViewConst(); + forAll< EXEC_POLICY >( m_sourceConstantsx.size( 0 ), [=] GEOS_HOST_DEVICE ( localIndex const isrc ) + { + if( sourceIsAccessible[isrc] == 1 ) + { + real64 const srcValue = + useSourceWaveletTables ? sourceWaveletTableWrappers[ isrc ].compute( &time_n ) : WaveSolverUtils::evaluateRicker( time_n, timeSourceFrequency, timeSourceDelay, rickerOrder ); + for( localIndex inode = 0; inode < sourceConstantsx.size( 1 ); ++inode ) + { + real32 const localIncrementx = sourceConstantsx[isrc][inode] * srcValue; + RAJA::atomicAdd< ATOMIC_POLICY >( &rhsx[sourceNodeIds[isrc][inode]], localIncrementx ); + real32 const localIncrementy = sourceConstantsy[isrc][inode] * srcValue; + RAJA::atomicAdd< ATOMIC_POLICY >( &rhsy[sourceNodeIds[isrc][inode]], localIncrementy ); + real32 const localIncrementz = sourceConstantsz[isrc][inode] * srcValue; + RAJA::atomicAdd< ATOMIC_POLICY >( &rhsz[sourceNodeIds[isrc][inode]], localIncrementz ); + } + } + } ); +} + +void ElasticWaveEquationSEM::initializePostInitialConditionsPreSubGroups() +{ + + WaveSolverBase::initializePostInitialConditionsPreSubGroups(); + + DomainPartition & domain = getGroupByPath< DomainPartition >( "/Problem/domain" ); + + applyFreeSurfaceBC( 0.0, domain ); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshBodyName, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + MeshLevel & baseMesh = domain.getMeshBodies().getGroup< MeshBody >( meshBodyName ).getBaseDiscretization(); + precomputeSourceAndReceiverTerm( baseMesh, mesh, regionNames ); + + NodeManager & nodeManager = mesh.getNodeManager(); + FaceManager & faceManager = mesh.getFaceManager(); + ElementRegionManager & elemManager = mesh.getElemManager(); + + arrayView2d< wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords = nodeManager.getField< fields::referencePosition32 >().toViewConst(); + + // mass matrix to be computed in this function + arrayView1d< real32 > const mass = nodeManager.getField< elasticfields::ElasticMassVector >(); + mass.zero(); + /// damping matrix to be computed for each dof in the boundary of the mesh + arrayView1d< real32 > const dampingx = nodeManager.getField< elasticfields::DampingVectorx >(); + arrayView1d< real32 > const dampingy = nodeManager.getField< elasticfields::DampingVectory >(); + arrayView1d< real32 > const dampingz = nodeManager.getField< elasticfields::DampingVectorz >(); + dampingx.zero(); + dampingy.zero(); + dampingz.zero(); + + /// get array of indicators: 1 if face is on the free surface; 0 otherwise + arrayView1d< localIndex const > const freeSurfaceFaceIndicator = faceManager.getField< elasticfields::ElasticFreeSurfaceFaceIndicator >(); + arrayView1d< integer const > const & facesDomainBoundaryIndicator = faceManager.getDomainBoundaryIndicator(); + ArrayOfArraysView< localIndex const > const facesToNodes = faceManager.nodeList().toViewConst(); + arrayView2d< real64 const > const faceNormal = faceManager.faceNormal(); + + elemManager.forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, + CellElementSubRegion & elementSubRegion ) + { + finiteElement::FiniteElementBase const & + fe = elementSubRegion.getReference< finiteElement::FiniteElementBase >( getDiscretizationName() ); + + arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes = elementSubRegion.nodeList(); + arrayView2d< localIndex const > const elemsToFaces = elementSubRegion.faceList(); + + computeTargetNodeSet( elemsToNodes, elementSubRegion.size(), fe.getNumQuadraturePoints() ); + + arrayView1d< real32 const > const density = elementSubRegion.getField< elasticfields::ElasticDensity >(); + arrayView1d< real32 const > const velocityVp = elementSubRegion.getField< elasticfields::ElasticVelocityVp >(); + arrayView1d< real32 const > const velocityVs = elementSubRegion.getField< elasticfields::ElasticVelocityVs >(); + + finiteElement::FiniteElementDispatchHandler< SEM_FE_TYPES >::dispatch3D( fe, [&] ( auto const finiteElement ) + { + using FE_TYPE = TYPEOFREF( finiteElement ); + + ElasticMatricesSEM::MassMatrix< FE_TYPE > kernelM( finiteElement ); + kernelM.template computeMassMatrix< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), + nodeCoords, + elemsToNodes, + density, + mass ); + + + + ElasticMatricesSEM::DampingMatrix< FE_TYPE > kernelD( finiteElement ); + kernelD.template computeDampingMatrix< EXEC_POLICY, ATOMIC_POLICY >( elementSubRegion.size(), + nodeCoords, + elemsToFaces, + facesToNodes, + facesDomainBoundaryIndicator, + freeSurfaceFaceIndicator, + faceNormal, + density, + velocityVp, + velocityVs, + dampingx, + dampingy, + dampingz ); + } ); + } ); + + // check anelasticity coefficient and/or compute it if needed + if( m_attenuationType == WaveSolverUtils::AttenuationType::sls ) + { + real32 minQVal = computeGlobalMinQFactor(); + if( m_slsAnelasticityCoefficients.size( 0 ) == 1 && m_slsAnelasticityCoefficients[ 0 ] < 0 ) + { + m_slsAnelasticityCoefficients[ 0 ] = 2.0 * minQVal / ( minQVal - 1.0 ); + } + // test if anelasticity is too high and artifacts could appear + real32 ySum = 0.0; + for( integer l = 0; l < m_slsAnelasticityCoefficients.size( 0 ); l++ ) + { + ySum += m_slsAnelasticityCoefficients[ l ]; + } + GEOS_WARNING_IF( ySum > minQVal, "The anelasticity parameters are too high for the given quality factor. This could lead to solution artifacts such as zero-velocity waves." ); + } + + } ); + + if( m_timestepStabilityLimit==1 ) + { + real64 dtOut = 0.0; + computeTimeStep( dtOut ); + m_timestepStabilityLimit = 0; + m_timeStep=dtOut; + } + + WaveSolverUtils::initTrace( "seismoTraceReceiver", getName(), m_outputSeismoTrace, m_receiverConstants.size( 0 ), m_receiverIsLocal ); + WaveSolverUtils::initTrace( "dasTraceReceiver", getName(), m_outputSeismoTrace, m_linearDASGeometry.size( 0 ), m_receiverIsLocal ); +} + +real64 ElasticWaveEquationSEM::computeTimeStep( real64 & dtOut ) +{ + + DomainPartition & domain = getGroupByPath< DomainPartition >( "/Problem/domain" ); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + + NodeManager & nodeManager = mesh.getNodeManager(); + + // mass matrix to be computed in this function + arrayView1d< real32 > const mass = nodeManager.getField< elasticfields::ElasticMassVector >(); + arrayView1d< real32 > const stiffnessVectorx = nodeManager.getField< elasticfields::StiffnessVectorx >(); + arrayView1d< real32 > const stiffnessVectory = nodeManager.getField< elasticfields::StiffnessVectory >(); + arrayView1d< real32 > const stiffnessVectorz = nodeManager.getField< elasticfields::StiffnessVectorz >(); + + arrayView1d< real32 > const ux_n = nodeManager.getField< elasticfields::Displacementx_n >(); + arrayView1d< real32 > const uy_n = nodeManager.getField< elasticfields::Displacementy_n >(); + arrayView1d< real32 > const uz_n = nodeManager.getField< elasticfields::Displacementz_n >(); + + localIndex const sizeNode = nodeManager.size(); + + real64 const epsilon = 0.00001; + localIndex const nIterMax = 10000; + localIndex numberIter = 0; + localIndex counter = 0; + real64 lambdaNew = 0.0; + + //Randomize p values + srand( time( NULL )); + for( localIndex a = 0; a < sizeNode; ++a ) + { + ux_n[a] = (real64)rand()/(real64) RAND_MAX; + uy_n[a] = (real64)rand()/(real64) RAND_MAX; + uz_n[a] = (real64)rand()/(real64) RAND_MAX; + } + + //Step 1: Normalize randomized pressure + real64 normUx= 0.0; + real64 normUy= 0.0; + real64 normUz= 0.0; + WaveSolverUtils::dotProduct( sizeNode, ux_n, ux_n, normUx ); + WaveSolverUtils::dotProduct( sizeNode, uy_n, uy_n, normUy ); + WaveSolverUtils::dotProduct( sizeNode, uz_n, uz_n, normUz ); + real64 normUtot = normUx+normUy+normUz; + + forAll< EXEC_POLICY >( sizeNode, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + ux_n[a]/= sqrt( normUtot ); + uy_n[a]/= sqrt( normUtot ); + uz_n[a]/= sqrt( normUtot ); + } ); + + //Step 2: Iterations of M^{-1}K)p until we found the max eigenvalues + auto kernelFactory = elasticWaveEquationSEMKernels::ExplicitElasticSEMFactory( dtOut ); + real64 lambdaOld = lambdaNew; + real64 dotProductUxUxaux = 0.0; + real64 dotProductUyUyaux = 0.0; + real64 dotProductUzUzaux = 0.0; + real64 dotProductUtotUtotAux = dotProductUxUxaux+dotProductUyUyaux+dotProductUzUzaux; + real64 normUxaux = 0.0; + real64 normUyaux = 0.0; + real64 normUzaux = 0.0; + real64 normUtotAux = normUxaux+normUyaux+normUzaux; + + do + { + + stiffnessVectorx.zero(); + stiffnessVectory.zero(); + stiffnessVectorz.zero(); + + finiteElement:: + regionBasedKernelApplication< EXEC_POLICY, + constitutive::NullModel, + CellElementSubRegion >( mesh, + regionNames, + getDiscretizationName(), + "", + kernelFactory ); + + + + forAll< EXEC_POLICY >( sizeNode, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + stiffnessVectorx[a]/= mass[a]; + stiffnessVectory[a]/= mass[a]; + stiffnessVectorz[a]/= mass[a]; + } ); + lambdaOld = lambdaNew; + + //Compute lambdaNew using two dotProducts + dotProductUxUxaux = 0.0; + dotProductUyUyaux = 0.0; + dotProductUzUzaux = 0.0; + normUx= 0.0; + normUy= 0.0; + normUz= 0.0; + + WaveSolverUtils::dotProduct( sizeNode, ux_n, stiffnessVectorx, dotProductUxUxaux ); + WaveSolverUtils::dotProduct( sizeNode, uy_n, stiffnessVectory, dotProductUyUyaux ); + WaveSolverUtils::dotProduct( sizeNode, uz_n, stiffnessVectorz, dotProductUzUzaux ); + dotProductUtotUtotAux = dotProductUxUxaux+dotProductUyUyaux+dotProductUzUzaux; + WaveSolverUtils::dotProduct( sizeNode, ux_n, ux_n, normUx ); + WaveSolverUtils::dotProduct( sizeNode, uy_n, uy_n, normUy ); + WaveSolverUtils::dotProduct( sizeNode, uz_n, uz_n, normUz ); + normUtot = normUx+normUy+normUz; + + lambdaNew = dotProductUtotUtotAux/normUtot; + + normUxaux = 0.0; + normUyaux = 0.0; + normUzaux = 0.0; + WaveSolverUtils::dotProduct( sizeNode, stiffnessVectorx, stiffnessVectorx, normUxaux ); + WaveSolverUtils::dotProduct( sizeNode, stiffnessVectory, stiffnessVectory, normUyaux ); + WaveSolverUtils::dotProduct( sizeNode, stiffnessVectorz, stiffnessVectorz, normUzaux ); + + normUtotAux = normUxaux+normUyaux+normUzaux; + + forAll< EXEC_POLICY >( sizeNode, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + ux_n[a] = stiffnessVectorx[a]/( normUtotAux ); + uy_n[a] = stiffnessVectory[a]/( normUtotAux ); + uz_n[a] = stiffnessVectorz[a]/( normUtotAux ); + } ); + + if( LvArray::math::abs( lambdaNew-lambdaOld )/LvArray::math::abs( lambdaNew )<= epsilon ) + { + counter++; + } + else + { + counter=0; + } + + numberIter++; + + + } + while (counter < 10 && numberIter < nIterMax); + + GEOS_THROW_IF( numberIter> nIterMax, "Power Iteration algorithm does not converge", std::runtime_error ); + + //We use 1.99 instead of 2 to have a 5% margin error + real64 dt = 1.99/sqrt( LvArray::math::abs( lambdaNew )); + + dtOut = MpiWrapper::min( dt ); + + stiffnessVectorx.zero(); + stiffnessVectory.zero(); + stiffnessVectorz.zero(); + ux_n.zero(); + uy_n.zero(); + uz_n.zero(); + } ); + return m_timeStep * m_cflFactor; +} + +real32 ElasticWaveEquationSEM::computeGlobalMinQFactor() +{ + RAJA::ReduceMin< ReducePolicy< EXEC_POLICY >, real32 > minQ( LvArray::NumericLimits< real32 >::max ); + DomainPartition & domain = getGroupByPath< DomainPartition >( "/Problem/domain" ); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, + CellElementSubRegion & elementSubRegion ) + { + arrayView1d< real32 const > const qp = elementSubRegion.getField< elasticfields::ElasticQualityFactorP >(); + arrayView1d< real32 const > const qs = elementSubRegion.getField< elasticfields::ElasticQualityFactorS >(); + forAll< EXEC_POLICY >( elementSubRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const e ) { + minQ.min( qp[e] ); + minQ.min( qs[e] ); + } ); + } ); + } ); + real32 minQVal = minQ.get(); + return MpiWrapper::min< real32 >( minQVal ); +} + +void ElasticWaveEquationSEM::applyFreeSurfaceBC( real64 const time, DomainPartition & domain ) +{ + FieldSpecificationManager & fsManager = FieldSpecificationManager::getInstance(); + FunctionManager const & functionManager = FunctionManager::getInstance(); + + FaceManager & faceManager = domain.getMeshBody( 0 ).getMeshLevel( m_discretizationName ).getFaceManager(); + NodeManager & nodeManager = domain.getMeshBody( 0 ).getMeshLevel( m_discretizationName ).getNodeManager(); + + arrayView1d< real32 > const ux_np1 = nodeManager.getField< elasticfields::Displacementx_np1 >(); + arrayView1d< real32 > const uy_np1 = nodeManager.getField< elasticfields::Displacementy_np1 >(); + arrayView1d< real32 > const uz_np1 = nodeManager.getField< elasticfields::Displacementz_np1 >(); + arrayView1d< real32 > const ux_n = nodeManager.getField< elasticfields::Displacementx_n >(); + arrayView1d< real32 > const uy_n = nodeManager.getField< elasticfields::Displacementy_n >(); + arrayView1d< real32 > const uz_n = nodeManager.getField< elasticfields::Displacementz_n >(); + arrayView1d< real32 > const ux_nm1 = nodeManager.getField< elasticfields::Displacementx_nm1 >(); + arrayView1d< real32 > const uy_nm1 = nodeManager.getField< elasticfields::Displacementy_nm1 >(); + arrayView1d< real32 > const uz_nm1 = nodeManager.getField< elasticfields::Displacementz_nm1 >(); + + ArrayOfArraysView< localIndex const > const faceToNodeMap = faceManager.nodeList().toViewConst(); + + /// set array of indicators: 1 if a face is on on free surface; 0 otherwise + arrayView1d< localIndex > const freeSurfaceFaceIndicator = faceManager.getField< elasticfields::ElasticFreeSurfaceFaceIndicator >(); + + /// set array of indicators: 1 if a node is on on free surface; 0 otherwise + arrayView1d< localIndex > const freeSurfaceNodeIndicator = nodeManager.getField< elasticfields::ElasticFreeSurfaceNodeIndicator >(); + + + fsManager.apply( time, + domain.getMeshBody( 0 ).getMeshLevel( m_discretizationName ), + WaveSolverBase::viewKeyStruct::freeSurfaceString(), + [&]( FieldSpecificationBase const & bc, + string const &, + SortedArrayView< localIndex const > const & targetSet, + Group &, + string const & ) + { + string const & functionName = bc.getFunctionName(); + + if( functionName.empty() || functionManager.getGroup< FunctionBase >( functionName ).isFunctionOfTime() == 2 ) + { + real64 const value = bc.getScale(); + + for( localIndex i = 0; i < targetSet.size(); ++i ) + { + localIndex const kf = targetSet[ i ]; + freeSurfaceFaceIndicator[kf] = 1; + + localIndex const numNodes = faceToNodeMap.sizeOfArray( kf ); + for( localIndex a=0; a < numNodes; ++a ) + { + localIndex const dof = faceToNodeMap( kf, a ); + freeSurfaceNodeIndicator[dof] = 1; + + ux_np1[dof] = value; + uy_np1[dof] = value; + uz_np1[dof] = value; + ux_n[dof] = value; + uy_n[dof] = value; + uz_n[dof] = value; + ux_nm1[dof] = value; + uy_nm1[dof] = value; + uz_nm1[dof] = value; + } + } + } + else + { + GEOS_ERROR( getDataContext() << ": This option is not supported yet" ); + } + } ); +} + + + +real64 ElasticWaveEquationSEM::explicitStepForward( real64 const & time_n, + real64 const & dt, + integer, + DomainPartition & domain, + bool GEOS_UNUSED_PARAM( computeGradient ) ) +{ + real64 dtCompute = explicitStepInternal( time_n, dt, domain ); + return dtCompute; +} + + + +real64 ElasticWaveEquationSEM::explicitStepBackward( real64 const & time_n, + real64 const & dt, + integer, + DomainPartition & domain, + bool GEOS_UNUSED_PARAM( computeGradient ) ) +{ + GEOS_ERROR( getDataContext() << ": Backward propagation for the elastic wave propagator not yet implemented" ); + real64 dtOut = explicitStepInternal( time_n, dt, domain ); + return dtOut; +} + +void ElasticWaveEquationSEM::computeUnknowns( real64 const & time_n, + real64 const & dt, + DomainPartition &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) +{ + NodeManager & nodeManager = mesh.getNodeManager(); + + arrayView1d< real32 const > const mass = nodeManager.getField< elasticfields::ElasticMassVector >(); + arrayView1d< real32 const > const dampingx = nodeManager.getField< elasticfields::DampingVectorx >(); + arrayView1d< real32 const > const dampingy = nodeManager.getField< elasticfields::DampingVectory >(); + arrayView1d< real32 const > const dampingz = nodeManager.getField< elasticfields::DampingVectorz >(); + arrayView1d< real32 > const stiffnessVectorx = nodeManager.getField< elasticfields::StiffnessVectorx >(); + arrayView1d< real32 > const stiffnessVectory = nodeManager.getField< elasticfields::StiffnessVectory >(); + arrayView1d< real32 > const stiffnessVectorz = nodeManager.getField< elasticfields::StiffnessVectorz >(); + + arrayView1d< real32 > const ux_nm1 = nodeManager.getField< elasticfields::Displacementx_nm1 >(); + arrayView1d< real32 > const uy_nm1 = nodeManager.getField< elasticfields::Displacementy_nm1 >(); + arrayView1d< real32 > const uz_nm1 = nodeManager.getField< elasticfields::Displacementz_nm1 >(); + arrayView1d< real32 > const ux_n = nodeManager.getField< elasticfields::Displacementx_n >(); + arrayView1d< real32 > const uy_n = nodeManager.getField< elasticfields::Displacementy_n >(); + arrayView1d< real32 > const uz_n = nodeManager.getField< elasticfields::Displacementz_n >(); + arrayView1d< real32 > const ux_np1 = nodeManager.getField< elasticfields::Displacementx_np1 >(); + arrayView1d< real32 > const uy_np1 = nodeManager.getField< elasticfields::Displacementy_np1 >(); + arrayView1d< real32 > const uz_np1 = nodeManager.getField< elasticfields::Displacementz_np1 >(); + + arrayView1d< real32 > const rhsx = nodeManager.getField< elasticfields::ForcingRHSx >(); + arrayView1d< real32 > const rhsy = nodeManager.getField< elasticfields::ForcingRHSy >(); + arrayView1d< real32 > const rhsz = nodeManager.getField< elasticfields::ForcingRHSz >(); + + if( m_useVTI ) + { + auto kernelFactory = elasticVTIWaveEquationSEMKernels::ExplicitElasticVTISEMFactory( dt ); + finiteElement:: + regionBasedKernelApplication< EXEC_POLICY, + constitutive::NullModel, + CellElementSubRegion >( mesh, + regionNames, + getDiscretizationName(), + "", + kernelFactory ); + } + else + { + auto kernelFactory = elasticWaveEquationSEMKernels::ExplicitElasticSEMFactory( dt ); + finiteElement:: + regionBasedKernelApplication< EXEC_POLICY, + constitutive::NullModel, + CellElementSubRegion >( mesh, + regionNames, + getDiscretizationName(), + "", + kernelFactory ); + } + + if( m_attenuationType == WaveSolverUtils::AttenuationType::sls ) + { + auto kernelFactory = elasticWaveEquationSEMKernels::ExplicitElasticAttenuativeSEMFactory( dt ); + finiteElement:: + regionBasedKernelApplication< EXEC_POLICY, + constitutive::NullModel, + CellElementSubRegion >( mesh, + regionNames, + getDiscretizationName(), + "", + kernelFactory ); + } + + addSourceToRightHandSide( time_n, rhsx, rhsy, rhsz ); + + SortedArrayView< localIndex const > const solverTargetNodesSet = m_solverTargetNodesSet.toViewConst(); + if( m_attenuationType == WaveSolverUtils::AttenuationType::sls ) + { + arrayView1d< real32 > const stiffnessVectorAx = nodeManager.getField< elasticfields::StiffnessVectorAx >(); + arrayView1d< real32 > const stiffnessVectorAy = nodeManager.getField< elasticfields::StiffnessVectorAy >(); + arrayView1d< real32 > const stiffnessVectorAz = nodeManager.getField< elasticfields::StiffnessVectorAz >(); + arrayView2d< real32 > const divpsix = nodeManager.getField< elasticfields::DivPsix >(); + arrayView2d< real32 > const divpsiy = nodeManager.getField< elasticfields::DivPsiy >(); + arrayView2d< real32 > const divpsiz = nodeManager.getField< elasticfields::DivPsiz >(); + arrayView1d< real32 > const referenceFrequencies = m_slsReferenceAngularFrequencies.toView(); + arrayView1d< real32 > const anelasticityCoefficients = m_slsAnelasticityCoefficients.toView(); + ElasticTimeSchemeSEM::AttenuationLeapFrog( dt, ux_np1, ux_n, ux_nm1, uy_np1, uy_n, uy_nm1, uz_np1, uz_n, uz_nm1, + divpsix, divpsiy, divpsiz, + mass, dampingx, dampingy, dampingz, stiffnessVectorx, stiffnessVectory, + stiffnessVectorz, stiffnessVectorAx, stiffnessVectorAy, stiffnessVectorAz, + rhsx, rhsy, rhsz, solverTargetNodesSet, + referenceFrequencies, anelasticityCoefficients ); + } + else + { + ElasticTimeSchemeSEM::LeapFrog( dt, ux_np1, ux_n, ux_nm1, uy_np1, uy_n, uy_nm1, uz_np1, uz_n, uz_nm1, + mass, dampingx, dampingy, dampingz, stiffnessVectorx, stiffnessVectory, + stiffnessVectorz, rhsx, rhsy, rhsz, solverTargetNodesSet ); + } +} + +void ElasticWaveEquationSEM::synchronizeUnknowns( real64 const & time_n, + real64 const & dt, + DomainPartition & domain, + MeshLevel & mesh, + arrayView1d< string const > const & ) +{ + NodeManager & nodeManager = mesh.getNodeManager(); + + arrayView1d< real32 > const ux_n = nodeManager.getField< elasticfields::Displacementx_n >(); + arrayView1d< real32 > const uy_n = nodeManager.getField< elasticfields::Displacementy_n >(); + arrayView1d< real32 > const uz_n = nodeManager.getField< elasticfields::Displacementz_n >(); + arrayView1d< real32 > const ux_np1 = nodeManager.getField< elasticfields::Displacementx_np1 >(); + arrayView1d< real32 > const uy_np1 = nodeManager.getField< elasticfields::Displacementy_np1 >(); + arrayView1d< real32 > const uz_np1 = nodeManager.getField< elasticfields::Displacementz_np1 >(); + + /// synchronize displacement fields + FieldIdentifiers fieldsToBeSync; + fieldsToBeSync.addFields( FieldLocation::Node, { elasticfields::Displacementx_np1::key(), elasticfields::Displacementy_np1::key(), elasticfields::Displacementz_np1::key() } ); + + if( m_slsReferenceAngularFrequencies.size( 0 ) > 0 ) + { + fieldsToBeSync.addFields( FieldLocation::Node, { elasticfields::DivPsix::key(), elasticfields::DivPsiy::key(), elasticfields::DivPsiz::key() } ); + } + + CommunicationTools & syncFields = CommunicationTools::getInstance(); + syncFields.synchronizeFields( fieldsToBeSync, + domain.getMeshBody( 0 ).getMeshLevel( m_discretizationName ), + domain.getNeighbors(), + true ); + + // compute the seismic traces since last step. + if( m_useDAS == WaveSolverUtils::DASType::none ) + { + arrayView2d< real32 > const uXReceivers = m_displacementXNp1AtReceivers.toView(); + arrayView2d< real32 > const uYReceivers = m_displacementYNp1AtReceivers.toView(); + arrayView2d< real32 > const uZReceivers = m_displacementZNp1AtReceivers.toView(); + computeAllSeismoTraces( time_n, dt, ux_np1, ux_n, uXReceivers ); + computeAllSeismoTraces( time_n, dt, uy_np1, uy_n, uYReceivers ); + computeAllSeismoTraces( time_n, dt, uz_np1, uz_n, uZReceivers ); + } + else + { + arrayView2d< real32 > const dasReceivers = m_dasSignalNp1AtReceivers.toView(); + computeAllSeismoTraces( time_n, dt, ux_np1, ux_n, dasReceivers, m_linearDASVectorX.toView(), true ); + computeAllSeismoTraces( time_n, dt, uy_np1, uy_n, dasReceivers, m_linearDASVectorY.toView(), true ); + computeAllSeismoTraces( time_n, dt, uz_np1, uz_n, dasReceivers, m_linearDASVectorZ.toView(), true ); + } + + incrementIndexSeismoTrace( time_n ); +} + +void ElasticWaveEquationSEM::prepareNextTimestep( MeshLevel & mesh ) +{ + NodeManager & nodeManager = mesh.getNodeManager(); + + arrayView1d< real32 > const ux_nm1 = nodeManager.getField< elasticfields::Displacementx_nm1 >(); + arrayView1d< real32 > const uy_nm1 = nodeManager.getField< elasticfields::Displacementy_nm1 >(); + arrayView1d< real32 > const uz_nm1 = nodeManager.getField< elasticfields::Displacementz_nm1 >(); + arrayView1d< real32 > const ux_n = nodeManager.getField< elasticfields::Displacementx_n >(); + arrayView1d< real32 > const uy_n = nodeManager.getField< elasticfields::Displacementy_n >(); + arrayView1d< real32 > const uz_n = nodeManager.getField< elasticfields::Displacementz_n >(); + arrayView1d< real32 > const ux_np1 = nodeManager.getField< elasticfields::Displacementx_np1 >(); + arrayView1d< real32 > const uy_np1 = nodeManager.getField< elasticfields::Displacementy_np1 >(); + arrayView1d< real32 > const uz_np1 = nodeManager.getField< elasticfields::Displacementz_np1 >(); + + arrayView1d< real32 > const stiffnessVectorx = nodeManager.getField< elasticfields::StiffnessVectorx >(); + arrayView1d< real32 > const stiffnessVectory = nodeManager.getField< elasticfields::StiffnessVectory >(); + arrayView1d< real32 > const stiffnessVectorz = nodeManager.getField< elasticfields::StiffnessVectorz >(); + + arrayView1d< real32 > const rhsx = nodeManager.getField< elasticfields::ForcingRHSx >(); + arrayView1d< real32 > const rhsy = nodeManager.getField< elasticfields::ForcingRHSy >(); + arrayView1d< real32 > const rhsz = nodeManager.getField< elasticfields::ForcingRHSz >(); + + SortedArrayView< localIndex const > const solverTargetNodesSet = m_solverTargetNodesSet.toViewConst(); + + forAll< EXEC_POLICY >( solverTargetNodesSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const n ) + { + localIndex const a = solverTargetNodesSet[n]; + ux_nm1[a] = ux_n[a]; + uy_nm1[a] = uy_n[a]; + uz_nm1[a] = uz_n[a]; + ux_n[a] = ux_np1[a]; + uy_n[a] = uy_np1[a]; + uz_n[a] = uz_np1[a]; + + stiffnessVectorx[a] = stiffnessVectory[a] = stiffnessVectorz[a] = 0.0; + rhsx[a] = rhsy[a] = rhsz[a] = 0.0; + } ); + if( m_attenuationType == WaveSolverUtils::AttenuationType::sls ) + { + arrayView1d< real32 > const stiffnessVectorAx = nodeManager.getField< elasticfields::StiffnessVectorAx >(); + arrayView1d< real32 > const stiffnessVectorAy = nodeManager.getField< elasticfields::StiffnessVectorAy >(); + arrayView1d< real32 > const stiffnessVectorAz = nodeManager.getField< elasticfields::StiffnessVectorAz >(); + forAll< EXEC_POLICY >( solverTargetNodesSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const n ) + { + localIndex const a = solverTargetNodesSet[n]; + stiffnessVectorAx[a] = stiffnessVectorAy[a] = stiffnessVectorAz[a] = 0.0; + } ); + } + +} + +real64 ElasticWaveEquationSEM::explicitStepInternal( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) +{ + GEOS_MARK_FUNCTION; + + GEOS_LOG_RANK_0_IF( dt < epsilonLoc, "Warning! Value for dt: " << dt << "s is smaller than local threshold: " << epsilonLoc ); + + real64 dtCompute; + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + localIndex nSubSteps = (int) ceil( dt/m_timeStep ); + dtCompute = dt/nSubSteps; + computeUnknowns( time_n, dtCompute, domain, mesh, regionNames ); + synchronizeUnknowns( time_n, dtCompute, domain, mesh, regionNames ); + prepareNextTimestep( mesh ); + } ); + + return dtCompute; +} + +void ElasticWaveEquationSEM::cleanup( real64 const time_n, + integer const cycleNumber, + integer const eventCounter, + real64 const eventProgress, + DomainPartition & domain ) +{ + // call the base class cleanup (for reporting purposes) + PhysicsSolverBase::cleanup( time_n, cycleNumber, eventCounter, eventProgress, domain ); + + // compute the remaining seismic traces, if needed + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + { + NodeManager & nodeManager = mesh.getNodeManager(); + arrayView1d< real32 const > const ux_n = nodeManager.getField< elasticfields::Displacementx_n >(); + arrayView1d< real32 const > const ux_np1 = nodeManager.getField< elasticfields::Displacementx_np1 >(); + arrayView1d< real32 const > const uy_n = nodeManager.getField< elasticfields::Displacementy_n >(); + arrayView1d< real32 const > const uy_np1 = nodeManager.getField< elasticfields::Displacementy_np1 >(); + arrayView1d< real32 const > const uz_n = nodeManager.getField< elasticfields::Displacementz_n >(); + arrayView1d< real32 const > const uz_np1 = nodeManager.getField< elasticfields::Displacementz_np1 >(); + + if( m_useDAS == WaveSolverUtils::DASType::none ) + { + arrayView2d< real32 > const uXReceivers = m_displacementXNp1AtReceivers.toView(); + arrayView2d< real32 > const uYReceivers = m_displacementYNp1AtReceivers.toView(); + arrayView2d< real32 > const uZReceivers = m_displacementZNp1AtReceivers.toView(); + computeAllSeismoTraces( time_n, 0.0, ux_np1, ux_n, uXReceivers ); + computeAllSeismoTraces( time_n, 0.0, uy_np1, uy_n, uYReceivers ); + computeAllSeismoTraces( time_n, 0.0, uz_np1, uz_n, uZReceivers ); + WaveSolverUtils::writeSeismoTraceVector( "seismoTraceReceiver", getName(), m_outputSeismoTrace, m_receiverConstants.size( 0 ), + m_receiverIsLocal, m_nsamplesSeismoTrace, uXReceivers, uYReceivers, uZReceivers ); + } + else + { + arrayView2d< real32 > const dasReceivers = m_dasSignalNp1AtReceivers.toView(); + computeAllSeismoTraces( time_n, 0.0, ux_np1, ux_n, dasReceivers, m_linearDASVectorX.toView(), true ); + computeAllSeismoTraces( time_n, 0.0, uy_np1, uy_n, dasReceivers, m_linearDASVectorY.toView(), true ); + computeAllSeismoTraces( time_n, 0.0, uz_np1, uz_n, dasReceivers, m_linearDASVectorZ.toView(), true ); + // sum contributions from all MPI ranks, since some receivers might be split among multiple ranks + MpiWrapper::allReduce( dasReceivers.data(), + dasReceivers.data(), + m_linearDASGeometry.size( 0 ), + MpiWrapper::getMpiOp( MpiWrapper::Reduction::Sum ), + MPI_COMM_GEOS ); + WaveSolverUtils::writeSeismoTrace( "dasTraceReceiver", getName(), m_outputSeismoTrace, m_linearDASGeometry.size( 0 ), + m_receiverIsLocal, m_nsamplesSeismoTrace, dasReceivers ); + } + } ); +} + +void ElasticWaveEquationSEM::initializePML() +{ + GEOS_ERROR( getDataContext() << ": PML for the elastic wave propagator not yet implemented" ); +} + +void ElasticWaveEquationSEM::applyPML( real64 const, DomainPartition & ) +{ + GEOS_ERROR( getDataContext() << ": PML for the elastic wave propagator not yet implemented" ); +} + +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, ElasticWaveEquationSEM, string const &, dataRepository::Group * const ) + +} /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/ElasticWaveEquationSEM.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEM.hpp similarity index 85% rename from src/coreComponents/physicsSolvers/wavePropagation/ElasticWaveEquationSEM.hpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEM.hpp index 74d58e3cfd0..8907f35cd76 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/ElasticWaveEquationSEM.hpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEM.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -20,10 +21,10 @@ #ifndef SRC_CORECOMPONENTS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICWAVEEQUATIONSEM_HPP_ #define SRC_CORECOMPONENTS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICWAVEEQUATIONSEM_HPP_ -#include "WaveSolverBase.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp" #include "mesh/MeshFields.hpp" -#include "physicsSolvers/SolverBase.hpp" -#include "ElasticFields.hpp" +#include "physicsSolvers/PhysicsSolverBase.hpp" +#include "physicsSolvers/wavePropagation/sem/elastic/shared/ElasticFields.hpp" namespace geos { @@ -52,7 +53,7 @@ class ElasticWaveEquationSEM : public WaveSolverBase static string catalogName() { return "ElasticSEM"; } /** - * @copydoc SolverBase::getCatalogName() + * @copydoc PhysicsSolverBase::getCatalogName() */ string getCatalogName() const override { return catalogName(); } @@ -87,7 +88,7 @@ class ElasticWaveEquationSEM : public WaveSolverBase * @param rhsy the right hand side vector to be computed (y-component) * @param rhsz the right hand side vector to be computed (z-component) */ - void addSourceToRightHandSide( integer const & cycleNumber, arrayView1d< real32 > const rhsx, arrayView1d< real32 > const rhsy, arrayView1d< real32 > const rhsz ); + void addSourceToRightHandSide( real64 const & time_n, arrayView1d< real32 > const rhsx, arrayView1d< real32 > const rhsy, arrayView1d< real32 > const rhsz ); /** * TODO: move implementation into WaveSolverBase once 'm_receiverIsLocal' is also moved @@ -101,6 +102,9 @@ class ElasticWaveEquationSEM : public WaveSolverBase arrayView2d< real32 > const yCompRcv, arrayView2d< real32 > const zCompRcv ); + virtual real64 computeTimeStep( real64 & dtOut ) override; + + /** * @brief Overridden from ExecutableGroup. Used to write last seismogram if needed. */ @@ -121,6 +125,8 @@ class ElasticWaveEquationSEM : public WaveSolverBase static constexpr char const * sourceForceString() { return "sourceForce"; } static constexpr char const * sourceMomentString() { return "sourceMoment"; } + static constexpr char const * useVtiString() { return "useVTI"; } + } waveEquationViewKeys; @@ -129,32 +135,37 @@ class ElasticWaveEquationSEM : public WaveSolverBase * @param time_n time at the beginning of the step * @param dt the perscribed timestep * @param cycleNumber the current cycle number + * @param meshBodyName the name of the mesh body * @param domain the domain object * @return return the timestep that was achieved during the step. */ real64 explicitStepInternal( real64 const & time_n, real64 const & dt, - integer const cycleNumber, DomainPartition & domain ); void computeUnknowns( real64 const & time_n, real64 const & dt, - integer const cycleNumber, DomainPartition & domain, MeshLevel & mesh, arrayView1d< string const > const & regionNames ); void synchronizeUnknowns( real64 const & time_n, real64 const & dt, - integer const cycleNumber, DomainPartition & domain, MeshLevel & mesh, arrayView1d< string const > const & regionNames ); void prepareNextTimestep( MeshLevel & mesh ); + + /** + * @brief Computes the minimum attenuation quality factor over all the mesh. This is useful for computing anelasticity coefficients, which + * are usually global parameters + */ + real32 computeGlobalMinQFactor(); + protected: - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; virtual void initializePostInitialConditionsPreSubGroups() override final; @@ -163,10 +174,11 @@ class ElasticWaveEquationSEM : public WaveSolverBase /** * @brief Locate sources and receivers position in the mesh elements, evaluate the basis functions at each point and save them to the * corresponding elements nodes. + * @param baseMesh the level-0 mesh * @param mesh mesh of the computational domain * @param regionNames the names of the region you loop on */ - virtual void precomputeSourceAndReceiverTerm( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) override; + virtual void precomputeSourceAndReceiverTerm( MeshLevel & baseMesh, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) override; /** * @brief Apply free surface condition to the face define in the geometry box from the xml @@ -214,6 +226,9 @@ class ElasticWaveEquationSEM : public WaveSolverBase /// Symmetric tensor describing the moment of the source R2SymTensor m_sourceMoment; + /// Flag to appliy VTI anisotropy + integer m_useVTI; + }; } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEMKernel.hpp new file mode 100644 index 00000000000..c7c9b44a1a4 --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEMKernel.hpp @@ -0,0 +1,353 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ElasticWaveEquationSEMKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICWAVEEQUATIONSEMKERNEL_HPP_ +#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICWAVEEQUATIONSEMKERNEL_HPP_ + +#include "finiteElement/kernelInterface/KernelBase.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverUtils.hpp" +#include "physicsSolvers/wavePropagation/sem/elastic/shared/ElasticFields.hpp" + +namespace geos +{ + +/// Namespace to contain the elastic wave kernels. +namespace elasticWaveEquationSEMKernels +{ + +/** + * @brief Implements kernels for solving the elastic wave equations + * explicit central FD method and SEM + * @copydoc geos::finiteElement::KernelBase + * @tparam SUBREGION_TYPE The type of subregion that the kernel will act on. + * + * ### ElasticWaveEquationSEMKernel Description + * Implements the KernelBase interface functions required for solving + * the acoustic wave equations using the + * "finite element kernel application" functions such as + * geos::finiteElement::RegionBasedKernelApplication. + * + * The number of degrees of freedom per support point for both + * the test and trial spaces are specified as `1`. + */ + + +template< typename SUBREGION_TYPE, + typename CONSTITUTIVE_TYPE, + typename FE_TYPE, + typename SX = fields::elasticfields::StiffnessVectorx, typename SY = fields::elasticfields::StiffnessVectory, typename SZ = fields::elasticfields::StiffnessVectorz > +class ExplicitElasticSEMBase : public finiteElement::KernelBase< SUBREGION_TYPE, + CONSTITUTIVE_TYPE, + FE_TYPE, + 1, + 1 > +{ +public: + + /// Alias for the base class; + using Base = finiteElement::KernelBase< SUBREGION_TYPE, + CONSTITUTIVE_TYPE, + FE_TYPE, + 1, + 1 >; + + /// Number of nodes per element...which is equal to the + /// numTestSupportPointPerElem and numTrialSupportPointPerElem by definition. + static constexpr int numNodesPerElem = Base::maxNumTestSupportPointsPerElem; + + using Base::numDofPerTestSupportPoint; + using Base::numDofPerTrialSupportPoint; + using Base::m_elemsToNodes; + using Base::m_elemGhostRank; + using Base::m_constitutiveUpdate; + using Base::m_finiteElementSpace; + +//***************************************************************************** + /** + * @brief Constructor + * @copydoc geos::finiteElement::KernelBase::KernelBase + * @param nodeManager Reference to the NodeManager object. + * @param edgeManager Reference to the EdgeManager object. + * @param faceManager Reference to the FaceManager object. + * @param targetRegionIndex Index of the region the subregion belongs to. + * @param dt The time interval for the step. + */ + ExplicitElasticSEMBase( NodeManager & nodeManager, + EdgeManager const & edgeManager, + FaceManager const & faceManager, + localIndex const targetRegionIndex, + SUBREGION_TYPE const & elementSubRegion, + FE_TYPE const & finiteElementSpace, + CONSTITUTIVE_TYPE & inputConstitutiveType, + real64 const dt ): + Base( elementSubRegion, + finiteElementSpace, + inputConstitutiveType ), + m_nodeCoords( nodeManager.getField< fields::referencePosition32 >() ), + m_ux_n( nodeManager.getField< fields::elasticfields::Displacementx_n >() ), + m_uy_n( nodeManager.getField< fields::elasticfields::Displacementy_n >() ), + m_uz_n( nodeManager.getField< fields::elasticfields::Displacementz_n >() ), + m_stiffnessVectorx( nodeManager.getField< SX >() ), + m_stiffnessVectory( nodeManager.getField< SY >() ), + m_stiffnessVectorz( nodeManager.getField< SZ >() ), + m_density( elementSubRegion.template getField< fields::elasticfields::ElasticDensity >() ), + m_velocityVp( elementSubRegion.template getField< fields::elasticfields::ElasticVelocityVp >() ), + m_velocityVs( elementSubRegion.template getField< fields::elasticfields::ElasticVelocityVs >() ), + m_dt( dt ) + { + GEOS_UNUSED_VAR( edgeManager ); + GEOS_UNUSED_VAR( faceManager ); + GEOS_UNUSED_VAR( targetRegionIndex ); + } + + + //***************************************************************************** + /** + * @copydoc geos::finiteElement::KernelBase::StackVariables + * + * ### ExplicitElasticSEMBase Description + * Adds a stack arrays for the nodal force, primary displacement variable, etc. + */ + struct StackVariables : Base::StackVariables + { +public: + GEOS_HOST_DEVICE + StackVariables(): + xLocal(), + stiffnessVectorxLocal(), + stiffnessVectoryLocal(), + stiffnessVectorzLocal() + {} + /// C-array stack storage for element local the nodal positions. + real64 xLocal[ 8 ][ 3 ]{}; + real32 stiffnessVectorxLocal[ numNodesPerElem ]; + real32 stiffnessVectoryLocal[ numNodesPerElem ]; + real32 stiffnessVectorzLocal[ numNodesPerElem ]; + real32 mu=0; + real32 lambda=0; + }; + //*************************************************************************** + + + /** + * @copydoc geos::finiteElement::KernelBase::setup + * + * Copies the primary variable, and position into the local stack array. + */ + GEOS_HOST_DEVICE + inline + void setup( localIndex const k, + StackVariables & stack ) const + { + for( localIndex a=0; a< 8; a++ ) + { + localIndex const nodeIndex = m_elemsToNodes( k, FE_TYPE::meshIndexToLinearIndex3D( a ) ); + for( int i=0; i< 3; ++i ) + { + stack.xLocal[ a ][ i ] = m_nodeCoords[ nodeIndex ][ i ]; + } + } + stack.mu = m_density[k] * pow( m_velocityVs[k], 2 ); + stack.lambda = m_density[k] * pow( m_velocityVp[k], 2 ) - 2.0 * stack.mu; + } + + /** + * @copydoc geos::finiteElement::KernelBase::complete + */ + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + real64 complete( localIndex const k, + StackVariables & stack ) const + { + for( int i=0; i( &m_stiffnessVectorx[ nodeIndex ], stack.stiffnessVectorxLocal[ i ] ); + RAJA::atomicAdd< parallelDeviceAtomic >( &m_stiffnessVectory[ nodeIndex ], stack.stiffnessVectoryLocal[ i ] ); + RAJA::atomicAdd< parallelDeviceAtomic >( &m_stiffnessVectorz[ nodeIndex ], stack.stiffnessVectorzLocal[ i ] ); + } + return 0; + } + + /** + * @copydoc geos::finiteElement::KernelBase::quadraturePointKernel + * + * ### ExplicitElasticSEMBase Description + * Calculates stiffness vector + * + */ + GEOS_HOST_DEVICE + GEOS_FORCE_INLINE + void quadraturePointKernel( localIndex const k, + localIndex const q, + StackVariables & stack ) const + { + + m_finiteElementSpace.template computeFirstOrderStiffnessTerm( q, stack.xLocal, [&] ( int i, int j, real64 val, real64 J[3][3], int p, int r ) + { + real32 const Rxx_ij = val*((stack.lambda+2.0*stack.mu)*J[p][0]*J[r][0]+stack.mu*(J[p][1]*J[r][1]+J[p][2]*J[r][2])); + real32 const Ryy_ij = val*((stack.lambda+2.0*stack.mu)*J[p][1]*J[r][1]+stack.mu*(J[p][0]*J[r][0]+J[p][2]*J[r][2])); + real32 const Rzz_ij = val*((stack.lambda+2.0*stack.mu)*J[p][2]*J[r][2]+stack.mu*(J[p][0]*J[r][0]+J[p][1]*J[r][1])); + real32 const Rxy_ij = val*(stack.lambda*J[p][0]*J[r][1]+stack.mu*J[p][1]*J[r][0]); + real32 const Ryx_ij = val*(stack.mu*J[p][0]*J[r][1]+stack.lambda*J[p][1]*J[r][0]); + real32 const Rxz_ij = val*(stack.lambda*J[p][0]*J[r][2]+stack.mu*J[p][2]*J[r][0]); + real32 const Rzx_ij = val*(stack.mu*J[p][0]*J[r][2]+stack.lambda*J[p][2]*J[r][0]); + real32 const Ryz_ij = val*(stack.lambda*J[p][1]*J[r][2]+stack.mu*J[p][2]*J[r][1]); + real32 const Rzy_ij = val*(stack.mu*J[p][1]*J[r][2]+stack.lambda*J[p][2]*J[r][1]); + + real32 const localIncrementx = (Rxx_ij * m_ux_n[m_elemsToNodes( k, j )] + Rxy_ij*m_uy_n[m_elemsToNodes( k, j )] + Rxz_ij*m_uz_n[m_elemsToNodes( k, j )]); + real32 const localIncrementy = (Ryx_ij * m_ux_n[m_elemsToNodes( k, j )] + Ryy_ij*m_uy_n[m_elemsToNodes( k, j )] + Ryz_ij*m_uz_n[m_elemsToNodes( k, j )]); + real32 const localIncrementz = (Rzx_ij * m_ux_n[m_elemsToNodes( k, j )] + Rzy_ij*m_uy_n[m_elemsToNodes( k, j )] + Rzz_ij*m_uz_n[m_elemsToNodes( k, j )]); + + stack.stiffnessVectorxLocal[ i ] += localIncrementx; + stack.stiffnessVectoryLocal[ i ] += localIncrementy; + stack.stiffnessVectorzLocal[ i ] += localIncrementz; + } ); + } + + +protected: + /// The array containing the nodal position array. + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const m_nodeCoords; + + /// The array containing the nodal displacement array in x direction. + arrayView1d< real32 > const m_ux_n; + + /// The array containing the nodal displacement array in y direction. + arrayView1d< real32 > const m_uy_n; + + /// The array containing the nodal displacement array in z direction. + arrayView1d< real32 > const m_uz_n; + + /// The array containing the product of the stiffness matrix and the nodal displacement. + arrayView1d< real32 > const m_stiffnessVectorx; + + /// The array containing the product of the stiffness matrix and the nodal displacement. + arrayView1d< real32 > const m_stiffnessVectory; + + /// The array containing the product of the stiffness matrix and the nodal displacement. + arrayView1d< real32 > const m_stiffnessVectorz; + + /// The array containing the density of the medium + arrayView1d< real32 const > const m_density; + + /// The array containing the P-wavespeed + arrayView1d< real32 const > const m_velocityVp; + + /// The array containing the S-wavespeed + arrayView1d< real32 const > const m_velocityVs; + + /// The time increment for this time integration step. + real64 const m_dt; + +}; + + +/// Specialization for standard iso elastic kernel +template< typename SUBREGION_TYPE, + typename CONSTITUTIVE_TYPE, + typename FE_TYPE > +using ExplicitElasticSEM = ExplicitElasticSEMBase< SUBREGION_TYPE, CONSTITUTIVE_TYPE, FE_TYPE >; +using ExplicitElasticSEMFactory = finiteElement::KernelFactory< ExplicitElasticSEM, + real64 >; +/// Specialization for attenuation kernel +template< typename SUBREGION_TYPE, + typename CONSTITUTIVE_TYPE, + typename FE_TYPE > +class ExplicitElasticAttenuativeSEM : public ExplicitElasticSEMBase< SUBREGION_TYPE, + CONSTITUTIVE_TYPE, + FE_TYPE, + fields::elasticfields::StiffnessVectorAx, + fields::elasticfields::StiffnessVectorAy, + fields::elasticfields::StiffnessVectorAz > +{ +public: + + /// Alias for the base class; + using Base = ExplicitElasticSEMBase< SUBREGION_TYPE, + CONSTITUTIVE_TYPE, + FE_TYPE, + fields::elasticfields::StiffnessVectorAx, + fields::elasticfields::StiffnessVectorAy, + fields::elasticfields::StiffnessVectorAz >; + +//***************************************************************************** + /** + * @brief Constructor + * @copydoc geos::finiteElement::KernelBase::KernelBase + * @param nodeManager Reference to the NodeManager object. + * @param edgeManager Reference to the EdgeManager object. + * @param faceManager Reference to the FaceManager object. + * @param targetRegionIndex Index of the region the subregion belongs to. + * @param dt The time interval for the step. + */ + ExplicitElasticAttenuativeSEM( NodeManager & nodeManager, + EdgeManager const & edgeManager, + FaceManager const & faceManager, + localIndex const targetRegionIndex, + SUBREGION_TYPE const & elementSubRegion, + FE_TYPE const & finiteElementSpace, + CONSTITUTIVE_TYPE & inputConstitutiveType, + real64 const dt ): + Base( nodeManager, + edgeManager, + faceManager, + targetRegionIndex, + elementSubRegion, + finiteElementSpace, + inputConstitutiveType, + dt ), + m_qualityFactorP( elementSubRegion.template getField< fields::elasticfields::ElasticQualityFactorP >() ), + m_qualityFactorS( elementSubRegion.template getField< fields::elasticfields::ElasticQualityFactorS >() ) + {} + + /** + * @copydoc geos::finiteElement::KernelBase::setup + * + * Copies the primary variable, and position into the local stack array. + */ + GEOS_HOST_DEVICE + inline + void setup( localIndex const k, + typename Base::StackVariables & stack ) const + { + Base::setup( k, stack ); + real64 lambdap2mua= (stack.lambda + 2.0 * stack.mu ) / m_qualityFactorP[ k ]; + stack.mu = stack.mu / m_qualityFactorS[ k ]; + stack.lambda = (lambdap2mua - 2.0 * stack.mu ); + } + +protected: + + /// The array containing the P-wave attenuation quality factor + arrayView1d< real32 const > const m_qualityFactorP; + + /// The array containing the S-wave attenuation quality factor + arrayView1d< real32 const > const m_qualityFactorS; + +}; + +using ExplicitElasticAttenuativeSEMFactory = finiteElement::KernelFactory< ExplicitElasticAttenuativeSEM, + real64 >; + +} // namespace ElasticWaveEquationSEMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICWAVEEQUATIONSEMKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/ElasticFields.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/shared/ElasticFields.hpp similarity index 79% rename from src/coreComponents/physicsSolvers/wavePropagation/ElasticFields.hpp rename to src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/shared/ElasticFields.hpp index 8669c653534..c9d2e62b43b 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/ElasticFields.hpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/shared/ElasticFields.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -104,6 +105,30 @@ DECLARE_FIELD( Displacementz_np1, WRITE_AND_READ, "z-component of displacement at time n+1." ); +DECLARE_FIELD( DivPsix, + "divpsix", + array2d< real32 >, + 0, + NOPLOT, + WRITE_AND_READ, + "x-component of memory variables for attenuation." ); + +DECLARE_FIELD( DivPsiy, + "divpsiy", + array2d< real32 >, + 0, + NOPLOT, + WRITE_AND_READ, + "y-component of memory variables for attenuation." ); + +DECLARE_FIELD( DivPsiz, + "divpsiz", + array2d< real32 >, + 0, + NOPLOT, + WRITE_AND_READ, + "z-component of memory variables for attenuation." ); + DECLARE_FIELD( Stresstensorxx, "stresstensorxx", array2d< real32 >, @@ -216,6 +241,30 @@ DECLARE_FIELD( StiffnessVectorz, WRITE_AND_READ, "z-component of stiffness vector." ); +DECLARE_FIELD( StiffnessVectorAx, + "stiffnessVectorAx", + array1d< real32 >, + 0, + NOPLOT, + WRITE_AND_READ, + "x-component of attenuation stiffness vector." ); + +DECLARE_FIELD( StiffnessVectorAy, + "stiffnessVectorAy", + array1d< real32 >, + 0, + NOPLOT, + WRITE_AND_READ, + "y-component of attenuation stiffness vector." ); + +DECLARE_FIELD( StiffnessVectorAz, + "stiffnessVectorAz", + array1d< real32 >, + 0, + NOPLOT, + WRITE_AND_READ, + "z-component of attenuation stiffness vector." ); + DECLARE_FIELD( DampingVectorx, "dampingVectorx", array1d< real32 >, @@ -264,6 +313,22 @@ DECLARE_FIELD( ElasticDensity, WRITE_AND_READ, "Medium density of the cell" ); +DECLARE_FIELD( ElasticQualityFactorP, + "elasticQualityFactorP", + array1d< real32 >, + 0, + NOPLOT, + WRITE_AND_READ, + "Quality factor for P-wave attenuation in the cell" ); + +DECLARE_FIELD( ElasticQualityFactorS, + "elasticQualityFactorS", + array1d< real32 >, + 0, + NOPLOT, + WRITE_AND_READ, + "Quality factor for S-wave attenuation in the cell" ); + DECLARE_FIELD( ElasticFreeSurfaceFaceIndicator, "elasticFreeSurfaceFaceIndicator", array1d< localIndex >, diff --git a/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/shared/ElasticMatricesSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/shared/ElasticMatricesSEMKernel.hpp new file mode 100644 index 00000000000..40b8947ead5 --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/shared/ElasticMatricesSEMKernel.hpp @@ -0,0 +1,174 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ElasticMatricesSEMKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICMATRICESSEMKERNEL_HPP_ +#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICMATRICESSEMKERNEL_HPP_ + +namespace geos +{ + +struct ElasticMatricesSEM +{ + template< typename FE_TYPE > + struct MassMatrix + { + + MassMatrix( FE_TYPE const & finiteElement ) + : m_finiteElement( finiteElement ) + {} + + /** + * @brief Launches the precomputation of the mass matrices + * @tparam EXEC_POLICY the execution policy + * @tparam ATOMIC_POLICY the atomic policy + * @param[in] size the number of cells in the subRegion + * @param[in] numFacesPerElem number of faces per element + * @param[in] nodeCoords coordinates of the nodes + * @param[in] elemsToNodes map from element to nodes + * @param[in] velocity cell-wise velocity + * @param[out] mass diagonal of the mass matrix + */ + template< typename EXEC_POLICY, typename ATOMIC_POLICY > + void + computeMassMatrix( localIndex const size, + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, + arrayView2d< localIndex const, cells::NODE_MAP_USD > const elemsToNodes, + arrayView1d< real32 const > const density, + arrayView1d< real32 > const mass ) + + { + forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const e ) + { + + // only the eight corners of the mesh cell are needed to compute the Jacobian + real64 xLocal[ 8 ][ 3 ]; + for( localIndex a = 0; a < 8; ++a ) + { + localIndex const nodeIndex = elemsToNodes( e, FE_TYPE::meshIndexToLinearIndex3D( a ) ); + for( localIndex i = 0; i < 3; ++i ) + { + xLocal[a][i] = nodeCoords( nodeIndex, i ); + } + } + + constexpr localIndex numQuadraturePointsPerElem = FE_TYPE::numQuadraturePoints; + for( localIndex q = 0; q < numQuadraturePointsPerElem; ++q ) + { + real32 const localIncrement = density[e] * m_finiteElement.computeMassTerm( q, xLocal ); + RAJA::atomicAdd< ATOMIC_POLICY >( &mass[elemsToNodes( e, q )], localIncrement ); + } + } ); // end loop over element + } + + /// The finite element space/discretization object for the element type in the subRegion + FE_TYPE const & m_finiteElement; + + }; + + template< typename FE_TYPE > + struct DampingMatrix + { + + DampingMatrix( FE_TYPE const & finiteElement ) + : m_finiteElement( finiteElement ) + {} + + /** + * @brief Launches the precomputation of the damping matrices + * @tparam EXEC_POLICY the execution policy + * @tparam ATOMIC_POLICY the atomic policy + * @param[in] size the number of cells in the subRegion + * @param[in] nodeCoords coordinates of the nodes + * @param[in] elemsToFaces map from elements to faces + * @param[in] facesToNodes map from face to nodes + * @param[in] facesDomainBoundaryIndicator flag equal to 1 if the face is on the boundary, and to 0 otherwise + * @param[in] freeSurfaceFaceIndicator flag equal to 1 if the face is on the free surface, and to 0 otherwise + * @param[in] faceNormal array containing the normal fo the faces + * @param[in] density cell-wise density + * @param[in] velocityVp cell-wise P-wavespeed + * @param[in] velocityVs cell-wise S-wavespeed + * @param[out] dampingx diagonal of the damping matrix (x-direction) + * @param[out] dampingy diagonal of the damping matrix (y-direction) + * @param[out] dampingz diagonal of the damping matrix (z-direction) + */ + template< typename EXEC_POLICY, typename ATOMIC_POLICY > + void + computeDampingMatrix( localIndex const size, + arrayView2d< WaveSolverBase::wsCoordType const, nodes::REFERENCE_POSITION_USD > const nodeCoords, + arrayView2d< localIndex const > const elemsToFaces, + ArrayOfArraysView< localIndex const > const facesToNodes, + arrayView1d< integer const > const facesDomainBoundaryIndicator, + arrayView1d< localIndex const > const freeSurfaceFaceIndicator, + arrayView2d< real64 const > const faceNormal, + arrayView1d< real32 const > const density, + arrayView1d< real32 const > const velocityVp, + arrayView1d< real32 const > const velocityVs, + arrayView1d< real32 > const dampingx, + arrayView1d< real32 > const dampingy, + arrayView1d< real32 > const dampingz ) + { + forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const e ) + { + for( localIndex i = 0; i < elemsToFaces.size( 1 ); ++i ) + { + localIndex const f = elemsToFaces( e, i ); + // face on the domain boundary and not on free surface + if( facesDomainBoundaryIndicator[f] == 1 && freeSurfaceFaceIndicator[f] != 1 ) + { + // only the four corners of the mesh face are needed to compute the Jacobian + real64 xLocal[ 4 ][ 3 ]; + for( localIndex a = 0; a < 4; ++a ) + { + localIndex const nodeIndex = facesToNodes( f, FE_TYPE::meshIndexToLinearIndex2D( a ) ); + for( localIndex d = 0; d < 3; ++d ) + { + xLocal[a][d] = nodeCoords( nodeIndex, d ); + } + } + + real32 const nx = faceNormal( f, 0 ), ny = faceNormal( f, 1 ), nz = faceNormal( f, 2 ); + constexpr localIndex numNodesPerFace = FE_TYPE::numNodesPerFace; + for( localIndex q = 0; q < numNodesPerFace; ++q ) + { + real32 const aux = density[e] * m_finiteElement.computeDampingTerm( q, xLocal ); + real32 const localIncrementx = aux * ( velocityVp[e] * LvArray::math::abs( nx ) + velocityVs[e] * LvArray::math::sqrt( pow( ny, 2 ) + pow( nz, 2 ) ) ); + real32 const localIncrementy = aux * ( velocityVp[e] * LvArray::math::abs( ny ) + velocityVs[e] * LvArray::math::sqrt( pow( nx, 2 ) + pow( nz, 2 ) ) ); + real32 const localIncrementz = aux * ( velocityVp[e] * LvArray::math::abs( nz ) + velocityVs[e] * LvArray::math::sqrt( pow( nx, 2 ) + pow( ny, 2 ) ) ); + + RAJA::atomicAdd< ATOMIC_POLICY >( &dampingx[facesToNodes( f, q )], localIncrementx ); + RAJA::atomicAdd< ATOMIC_POLICY >( &dampingy[facesToNodes( f, q )], localIncrementy ); + RAJA::atomicAdd< ATOMIC_POLICY >( &dampingz[facesToNodes( f, q )], localIncrementz ); + } + } + } + } ); + } + + /// The finite element space/discretization object for the element type in the subRegion + FE_TYPE const & m_finiteElement; + + }; + + + +}; + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICMATRICESSEMKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/shared/ElasticTimeSchemeSEMKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/shared/ElasticTimeSchemeSEMKernel.hpp new file mode 100644 index 00000000000..9b36fea0443 --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/sem/elastic/shared/ElasticTimeSchemeSEMKernel.hpp @@ -0,0 +1,203 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ElasticTimeSchemeSEMKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICTIMESCHEMESEMKERNEL_HPP_ +#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICTIMESCHEMESEMKERNEL_HPP_ + +namespace geos +{ + +struct ElasticTimeSchemeSEM +{ + + using EXEC_POLICY = parallelDevicePolicy< >; + /** + * @brief Apply second order Leap-Frog time scheme for isotropic case without PML + * @param[in] dt time-step + * @param[out] ux_np1 displacement in x-direction array at time n+1 (updated here) + * @param[in] ux_n displacement in x-direction array at time n + * @param[in] ux_nm1 displacement in x-direction array at time n-1 + * @param[out] uy_np1 displacement in y-direction array at time n+1 (updated here) + * @param[in] uy_n displacement in y-direction array at time n + * @param[in] uy_nm1 displacement in y-direction array at time n-1 + * @param[out] uz_np1 displacement in z-direction array at time n+1 (updated here) + * @param[in] uz_n displacement in z-direction array at time n + * @param[in] uz_nm1 displacement in z-direction array at time n-1 + * @param[in] mass the mass matrix + * @param[in] dampingx the damping matrix for x-component + * @param[in] dampingy the damping matrix for y-component + * @param[in] dampingz the damping matrix for z-component + * @param[in] stiffnessVectorx array containing the product of the stiffness matrix R and the displacement in x-direction at time n + * @param[in] stiffnessVectory array containing the product of the stiffness matrix R and the displacement in y-direction at time n + * @param[in] stiffnessVectorz array containing the product of the stiffness matrix R and the displacement in z-direction at time n + * @param[in] rhsx the right-hand-side for displacement in x-direction + * @param[in] rhsy the right-hand-side for displacement in y-direction + * @param[in] rhsz the right-hand-side for displacement in z-direction + * @param[in] solverTargetNodesSet the targetted nodeset (useful in particular when we do elasto-acoustic simulation ) + */ + static void LeapFrog( real64 const dt, + arrayView1d< real32 > const ux_np1, + arrayView1d< real32 > const ux_n, + arrayView1d< real32 > const ux_nm1, + arrayView1d< real32 > const uy_np1, + arrayView1d< real32 > const uy_n, + arrayView1d< real32 > const uy_nm1, + arrayView1d< real32 > const uz_np1, + arrayView1d< real32 > const uz_n, + arrayView1d< real32 > const uz_nm1, + arrayView1d< real32 const > const mass, + arrayView1d< real32 const > const dampingx, + arrayView1d< real32 const > const dampingy, + arrayView1d< real32 const > const dampingz, + arrayView1d< real32 > const stiffnessVectorx, + arrayView1d< real32 > const stiffnessVectory, + arrayView1d< real32 > const stiffnessVectorz, + arrayView1d< real32 > const rhsx, + arrayView1d< real32 > const rhsy, + arrayView1d< real32 > const rhsz, + SortedArrayView< localIndex const > const solverTargetNodesSet ) + { + real64 const dt2 = pow( dt, 2 ); + forAll< EXEC_POLICY >( solverTargetNodesSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const n ) + { + localIndex const a = solverTargetNodesSet[n]; + ux_np1[a] = ux_n[a]; + ux_np1[a] *= 2.0*mass[a]; + ux_np1[a] -= (mass[a]-0.5*dt*dampingx[a])*ux_nm1[a]; + ux_np1[a] += dt2*(rhsx[a]-stiffnessVectorx[a]); + ux_np1[a] /= mass[a]+0.5*dt*dampingx[a]; + uy_np1[a] = uy_n[a]; + uy_np1[a] *= 2.0*mass[a]; + uy_np1[a] -= (mass[a]-0.5*dt*dampingy[a])*uy_nm1[a]; + uy_np1[a] += dt2*(rhsy[a]-stiffnessVectory[a]); + uy_np1[a] /= mass[a]+0.5*dt*dampingy[a]; + uz_np1[a] = uz_n[a]; + uz_np1[a] *= 2.0*mass[a]; + uz_np1[a] -= (mass[a]-0.5*dt*dampingz[a])*uz_nm1[a]; + uz_np1[a] += dt2*(rhsz[a]-stiffnessVectorz[a]); + uz_np1[a] /= mass[a]+0.5*dt*dampingz[a]; + } ); + + }; + + /** + * @brief Apply second order Leap-Frog time scheme for isotropic case without PML, but with attenuation + * @param[in] dt time-step + * @param[out] ux_np1 displacement in x-direction array at time n+1 (updated here) + * @param[in] ux_n displacement in x-direction array at time n + * @param[in] ux_nm1 displacement in x-direction array at time n-1 + * @param[out] uy_np1 displacement in y-direction array at time n+1 (updated here) + * @param[in] uy_n displacement in y-direction array at time n + * @param[in] uy_nm1 displacement in y-direction array at time n-1 + * @param[out] uz_np1 displacement in z-direction array at time n+1 (updated here) + * @param[in] uz_n displacement in z-direction array at time n + * @param[in] uz_nm1 displacement in z-direction array at time n-1 + * @param[in] divpsix divergence of the memory variables in the x direction + * @param[in] divpsiy divergence of the memory variables in the y direction + * @param[in] divpsiz divergence of the memory variables in the z direction + * @param[in] mass the mass matrix + * @param[in] dampingx the damping matrix for x-component + * @param[in] dampingy the damping matrix for y-component + * @param[in] dampingz the damping matrix for z-component + * @param[in] stiffnessVectorx array containing the product of the stiffness matrix R and the displacement in x-direction at time n + * @param[in] stiffnessVectory array containing the product of the stiffness matrix R and the displacement in y-direction at time n + * @param[in] stiffnessVectorz array containing the product of the stiffness matrix R and the displacement in z-direction at time n + * @param[in] stiffnessVectorAx array containing the product of the attenuation stiffness matrix R and the displacement in x-direction at + * time n + * @param[in] stiffnessVectorAy array containing the product of the attenuation stiffness matrix R and the displacement in y-direction at + * time n + * @param[in] stiffnessVectorAz array containing the product of the attenuation stiffness matrix R and the displacement in z-direction at + * time n + * @param[in] rhsx the right-hand-side for displacement in x-direction + * @param[in] rhsy the right-hand-side for displacement in y-direction + * @param[in] rhsz the right-hand-side for displacement in z-direction + * @param[in] solverTargetNodesSet the targetted nodeset (useful in particular when we do elasto-acoustic simulation ) + */ + static void AttenuationLeapFrog( real64 const dt, + arrayView1d< real32 > const ux_np1, + arrayView1d< real32 > const ux_n, + arrayView1d< real32 > const ux_nm1, + arrayView1d< real32 > const uy_np1, + arrayView1d< real32 > const uy_n, + arrayView1d< real32 > const uy_nm1, + arrayView1d< real32 > const uz_np1, + arrayView1d< real32 > const uz_n, + arrayView1d< real32 > const uz_nm1, + arrayView2d< real32 > const divpsix, + arrayView2d< real32 > const divpsiy, + arrayView2d< real32 > const divpsiz, + arrayView1d< real32 const > const mass, + arrayView1d< real32 const > const dampingx, + arrayView1d< real32 const > const dampingy, + arrayView1d< real32 const > const dampingz, + arrayView1d< real32 > const stiffnessVectorx, + arrayView1d< real32 > const stiffnessVectory, + arrayView1d< real32 > const stiffnessVectorz, + arrayView1d< real32 > const stiffnessVectorAx, + arrayView1d< real32 > const stiffnessVectorAy, + arrayView1d< real32 > const stiffnessVectorAz, + arrayView1d< real32 > const rhsx, + arrayView1d< real32 > const rhsy, + arrayView1d< real32 > const rhsz, + SortedArrayView< localIndex const > const solverTargetNodesSet, + arrayView1d< real32 > referenceFrequencies, + arrayView1d< real32 > anelasticityCoefficients ) + { + real64 const dt2 = pow( dt, 2 ); + integer nl = referenceFrequencies.size( 0 ); + forAll< EXEC_POLICY >( solverTargetNodesSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const n ) + { + localIndex const a = solverTargetNodesSet[n]; + ux_np1[a] = ux_n[a]; + ux_np1[a] *= 2.0*mass[a]; + ux_np1[a] -= (mass[a]-0.5*dt*dampingx[a])*ux_nm1[a]; + ux_np1[a] += dt2*(rhsx[a]-stiffnessVectorx[a]); + uy_np1[a] = uy_n[a]; + uy_np1[a] *= 2.0*mass[a]; + uy_np1[a] -= (mass[a]-0.5*dt*dampingy[a])*uy_nm1[a]; + uy_np1[a] += dt2*(rhsy[a]-stiffnessVectory[a]); + uz_np1[a] = uz_n[a]; + uz_np1[a] *= 2.0*mass[a]; + uz_np1[a] -= (mass[a]-0.5*dt*dampingz[a])*uz_nm1[a]; + uz_np1[a] += dt2*(rhsz[a]-stiffnessVectorz[a]); + for( integer l = 0; l < nl; l++ ) + { + real32 gammal = ( 2.0 - referenceFrequencies[ l ] * dt )/( 2.0 + referenceFrequencies[ l ] * dt ); + real32 betal = anelasticityCoefficients[ l ] * referenceFrequencies[ l ] * 2.0 * dt /( 2.0 + referenceFrequencies[ l ] * dt ); + real32 gammalp = 0.5 + 0.5 * gammal; + real32 betalp = 0.5 * betal; + ux_np1[a] += dt2 * ( gammalp * divpsix( a, l ) + betalp * stiffnessVectorAx[ a ] ); + uy_np1[a] += dt2 * ( gammalp * divpsiy( a, l ) + betalp * stiffnessVectorAy[ a ] ); + uz_np1[a] += dt2 * ( gammalp * divpsiz( a, l ) + betalp * stiffnessVectorAz[ a ] ); + divpsix( a, l ) = gammal * divpsix( a, l ) + betal * stiffnessVectorAx[ a ]; + divpsiy( a, l ) = gammal * divpsiy( a, l ) + betal * stiffnessVectorAy[ a ]; + divpsiz( a, l ) = gammal * divpsiz( a, l ) + betal * stiffnessVectorAz[ a ]; + } + ux_np1[a] /= mass[a]+0.5*dt*dampingx[a]; + uy_np1[a] /= mass[a]+0.5*dt*dampingy[a]; + uz_np1[a] /= mass[a]+0.5*dt*dampingz[a]; + } ); + + }; + +}; + +} + +#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_ELASTICTIMESCHEMESEMKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/shared/PrecomputeSourcesAndReceiversKernel.hpp b/src/coreComponents/physicsSolvers/wavePropagation/shared/PrecomputeSourcesAndReceiversKernel.hpp new file mode 100644 index 00000000000..6fd876ff6ef --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/shared/PrecomputeSourcesAndReceiversKernel.hpp @@ -0,0 +1,612 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PrecomputeSourcesAndReceiversKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_PRECOMPUTESOURCESANDRECEIVERSKERNEL_HPP_ +#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_PRECOMPUTESOURCESANDRECEIVERSKERNEL_HPP_ + +namespace geos +{ + +struct PreComputeSourcesAndReceivers +{ + + using EXEC_POLICY = parallelDevicePolicy< >; + + /** + * @brief Launches the precomputation of the source and receiver terms for 1D solution (2nd order acoustic) + * @tparam EXEC_POLICY execution policy + * @tparam FE_TYPE finite element type + * @param[in] size the number of cells in the subRegion + * @param[in] baseFacesToNodes face to node map + * @param[in] baseNodeCoords coordinates of the nodes + * @param[in] baseNodeLocalToGlobal local to global index map for nodes + * @param[in] elementLocalToGlobal local to global index map for elements + * @param[in] baseNodesToElements node to element map for the base mesh + * @param[in] baseElemsToNodes element to node map for the base mesh + * @param[in] elemGhostRank rank of the ghost element + * @param[in] elemsToNodes map from element to nodes + * @param[in] elemsToFaces map from element to faces + * @param[in] elemCenter coordinates of the element centers + * @param[in] sourceCoordinates coordinates of the source terms + * @param[out] sourceIsAccessible flag indicating whether the source is accessible or not + * @param[out] sourceNodeIds indices of the nodes of the element where the source is located + * @param[out] sourceConstants constant part of the source terms + * @param[in] receiverCoordinates coordinates of the receiver terms + * @param[out] receiverIsLocal flag indicating whether the receiver is local or not + * @param[out] receiverNodeIds indices of the nodes of the element where the receiver is located + * @param[out] receiverConstants constant part of the receiver term + */ + template< typename EXEC_POLICY, typename FE_TYPE > + static void + Compute1DSourceAndReceiverConstants( localIndex const size, + ArrayOfArraysView< localIndex const > const baseFacesToNodes, + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const baseNodeCoords, + arrayView1d< globalIndex const > const baseNodeLocalToGlobal, + arrayView1d< globalIndex const > const elementLocalToGlobal, + ArrayOfArraysView< localIndex const > const baseNodesToElements, + arrayView2d< localIndex const, cells::NODE_MAP_USD > const & baseElemsToNodes, + arrayView1d< integer const > const elemGhostRank, + arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes, + arrayView2d< localIndex const > const elemsToFaces, + arrayView2d< real64 const > const & elemCenter, + arrayView2d< real64 const > const sourceCoordinates, + arrayView1d< localIndex > const sourceIsAccessible, + arrayView2d< localIndex > const sourceNodeIds, + arrayView2d< real64 > const sourceConstants, + arrayView2d< real64 const > const receiverCoordinates, + arrayView1d< localIndex > const receiverIsLocal, + arrayView2d< localIndex > const receiverNodeIds, + arrayView2d< real64 > const receiverConstants ) + { + constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; + + forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + real64 const center[3] = { elemCenter[k][0], + elemCenter[k][1], + elemCenter[k][2] }; + + // Step 1: locate the sources, and precompute the source term + + /// loop over all the source that haven't been found yet + for( localIndex isrc = 0; isrc < sourceCoordinates.size( 0 ); ++isrc ) + { + if( sourceIsAccessible[isrc] == 0 ) + { + real64 const coords[3] = { sourceCoordinates[isrc][0], + sourceCoordinates[isrc][1], + sourceCoordinates[isrc][2] }; + bool const sourceFound = + computationalGeometry::isPointInsideConvexPolyhedronRobust( k, + baseNodeCoords, + elemsToFaces, + baseFacesToNodes, + baseNodesToElements, + baseNodeLocalToGlobal, + elementLocalToGlobal, + center, + coords ); + if( sourceFound ) + { + real64 coordsOnRefElem[3]{}; + + + WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, + baseElemsToNodes[k], + baseNodeCoords, + coordsOnRefElem ); + + sourceIsAccessible[isrc] = 1; + real64 Ntest[numNodesPerElem]; + FE_TYPE::calcN( coordsOnRefElem, Ntest ); + + for( localIndex a = 0; a < numNodesPerElem; ++a ) + { + sourceNodeIds[isrc][a] = elemsToNodes( k, a ); + sourceConstants[isrc][a] = Ntest[a]; + } + } + } + } // end loop over all sources + + + // Step 2: locate the receivers, and precompute the receiver term + + /// loop over all the receivers that haven't been found yet + for( localIndex ircv = 0; ircv < receiverCoordinates.size( 0 ); ++ircv ) + { + if( receiverIsLocal[ircv] == 0 ) + { + real64 const coords[3] = { receiverCoordinates[ircv][0], + receiverCoordinates[ircv][1], + receiverCoordinates[ircv][2] }; + + real64 coordsOnRefElem[3]{}; + bool const receiverFound = + computationalGeometry::isPointInsideConvexPolyhedronRobust( k, + baseNodeCoords, + elemsToFaces, + baseFacesToNodes, + baseNodesToElements, + baseNodeLocalToGlobal, + elementLocalToGlobal, + center, + coords ); + + if( receiverFound && elemGhostRank[k] < 0 ) + { + WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, + baseElemsToNodes[k], + baseNodeCoords, + coordsOnRefElem ); + + receiverIsLocal[ircv] = 1; + + real64 Ntest[numNodesPerElem]; + FE_TYPE::calcN( coordsOnRefElem, Ntest ); + + for( localIndex a = 0; a < numNodesPerElem; ++a ) + { + receiverNodeIds[ircv][a] = elemsToNodes( k, a ); + receiverConstants[ircv][a] = Ntest[a]; + } + } + } + } // end loop over receivers + + } ); + + } + + + /** + * @brief Launches the precomputation of the source and receiver terms with storage of elements and region + * in which the receivers and sources are located + * @tparam EXEC_POLICY execution policy + * @tparam FE_TYPE finite element type + * @param[in] size the number of cells in the subRegion + * @param[in] baseFacesToNodes face to node map of the base mesh + * @param[in] baseNodeCoords coordinates of the nodes of the base mesh + * @param[in] baseNodeLocalToGlobal local to global index map for nodes of the base mesh + * @param[in] elementLocalToGlobal local to global index map for elements (for the base or high order mesh) + * @param[in] baseNodesToElements local node to element map for the base mesh + * @param[in] baseElemsToNodes element to node map for the base mesh + * @param[in] elemGhostRank rank of the ghost element + * @param[in] elemsToNodes map from element to nodes + * @param[in] elemsToFaces map from element to faces + * @param[in] elemCenter coordinates of the element centers + * @param[in] sourceCoordinates coordinates of the source terms + * @param[out] sourceIsAccessible flag indicating whether the source is accessible or not + * @param[out] sourceElem element where a source is located + * @param[out] sourceNodeIds indices of the nodes of the element where the source is located + * @param[out] sourceConstants constant part of the source terms + * @param[in] receiverCoordinates coordinates of the receiver terms + * @param[out] receiverIsLocal flag indicating whether the receiver is local or not + * @param[out] receiverElem element where a receiver is located + * @param[out] receiverNodeIds indices of the nodes of the element where the receiver is located + * @param[out] receiverConstants constant part of the receiver term + */ + template< typename EXEC_POLICY, typename FE_TYPE > + static void + Compute1DSourceAndReceiverConstantsWithElementsAndRegionStorage( localIndex const size, + localIndex const regionIndex, + ArrayOfArraysView< localIndex const > const baseFacesToNodes, + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const baseNodeCoords, + arrayView1d< globalIndex const > const baseNodeLocalToGlobal, + arrayView1d< globalIndex const > const elementLocalToGlobal, + ArrayOfArraysView< localIndex const > const baseNodesToElements, + arrayView2d< localIndex const, cells::NODE_MAP_USD > const & baseElemsToNodes, + arrayView1d< integer const > const elemGhostRank, + arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes, + arrayView2d< localIndex const > const elemsToFaces, + arrayView2d< real64 const > const & elemCenter, + arrayView2d< real64 const > const sourceCoordinates, + arrayView1d< localIndex > const sourceIsAccessible, + arrayView1d< localIndex > const sourceElem, + arrayView2d< localIndex > const sourceNodeIds, + arrayView2d< real64 > const sourceConstants, + arrayView1d< localIndex > const sourceRegion, + arrayView2d< real64 const > const receiverCoordinates, + arrayView1d< localIndex > const receiverIsLocal, + arrayView1d< localIndex > const receiverElem, + arrayView2d< localIndex > const receiverNodeIds, + arrayView2d< real64 > const receiverConstants, + arrayView1d< localIndex > const receiverRegion ) + { + constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; + + forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + real64 const center[3] = { elemCenter[k][0], + elemCenter[k][1], + elemCenter[k][2] }; + + // Step 1: locate the sources, and precompute the source term + + /// loop over all the source that haven't been found yet + for( localIndex isrc = 0; isrc < sourceCoordinates.size( 0 ); ++isrc ) + { + if( sourceIsAccessible[isrc] == 0 ) + { + real64 const coords[3] = { sourceCoordinates[isrc][0], + sourceCoordinates[isrc][1], + sourceCoordinates[isrc][2] }; + + bool const sourceFound = + computationalGeometry::isPointInsideConvexPolyhedronRobust( k, + baseNodeCoords, + elemsToFaces, + baseFacesToNodes, + baseNodesToElements, + baseNodeLocalToGlobal, + elementLocalToGlobal, + center, + coords ); + if( sourceFound ) + { + real64 coordsOnRefElem[3]{}; + + WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, + baseElemsToNodes[k], + baseNodeCoords, + coordsOnRefElem ); + + sourceIsAccessible[isrc] = 1; + sourceElem[isrc] = k; + sourceRegion[isrc] = regionIndex; + real64 Ntest[numNodesPerElem]; + FE_TYPE::calcN( coordsOnRefElem, Ntest ); + + for( localIndex a = 0; a < numNodesPerElem; ++a ) + { + sourceNodeIds[isrc][a] = elemsToNodes[k][a]; + sourceConstants[isrc][a] = Ntest[a]; + } + + } + } + } // end loop over all sources + + + // Step 2: locate the receivers, and precompute the receiver term + + /// loop over all the receivers that haven't been found yet + for( localIndex ircv = 0; ircv < receiverCoordinates.size( 0 ); ++ircv ) + { + if( receiverIsLocal[ircv] == 0 ) + { + real64 const coords[3] = { receiverCoordinates[ircv][0], + receiverCoordinates[ircv][1], + receiverCoordinates[ircv][2] }; + + real64 coordsOnRefElem[3]{}; + bool const receiverFound = + computationalGeometry::isPointInsideConvexPolyhedronRobust( k, + baseNodeCoords, + elemsToFaces, + baseFacesToNodes, + baseNodesToElements, + baseNodeLocalToGlobal, + elementLocalToGlobal, + center, + coords ); + + if( receiverFound && elemGhostRank[k] < 0 ) + { + WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, + baseElemsToNodes[k], + baseNodeCoords, + coordsOnRefElem ); + receiverIsLocal[ircv] = 1; + receiverElem[ircv] = k; + receiverRegion[ircv] = regionIndex; + + real64 Ntest[numNodesPerElem]; + FE_TYPE::calcN( coordsOnRefElem, Ntest ); + + for( localIndex a = 0; a < numNodesPerElem; ++a ) + { + receiverNodeIds[ircv][a] = elemsToNodes[k][a]; + receiverConstants[ircv][a] = Ntest[a]; + } + } + } + } // end loop over receivers + + } ); + + } + + + + /** + * @brief Launches the precomputation of the source and receiver terms for 3D arrays solution and DAS receiver constants + * computation + * @tparam EXEC_POLICY execution policy + * @tparam FE_TYPE finite element type + * @param[in] size the number of cells in the subRegion + * @param[in] baseFacesToNodes face to node map + * @param[in] baseNodeCoords coordinates of the nodes + * @param[in] baseNodeLocalToGlobal local to global index map for nodes + * @param[in] elementLocalToGlobal local to global index map for elements + * @param[in] baseNodesToElements node to element map for the base mesh + * @param[in] baseElemsToNodes element to node map for the base mesh + * @param[in] elemGhostRank array containing the ghost rank + * @param[in] elemsToNodes map from element to nodes + * @param[in] elemsToFaces map from element to faces + * @param[in] elemCenter coordinates of the element centers + * @param[in] sourceCoordinates coordinates of the source terms + * @param[out] sourceIsAccessible flag indicating whether the source is accessible or not + * @param[out] sourceNodeIds indices of the nodes of the element where the source is located + * @param[out] sourceConstantsx constant part of the source terms in x-direction + * @param[out] sourceConstantsy constant part of the source terms in y-direction + * @param[out] sourceConstantsz constant part of the source terms in z-direction + * @param[in] receiverCoordinates coordinates of the receiver terms + * @param[out] receiverIsLocal flag indicating whether the receiver is local or not + * @param[out] receiverNodeIds indices of the nodes of the element where the receiver is located + * @param[out] receiverConstants constant part of the receiver term + * @param[in] useDAS parameter that determines which kind of receiver needs to be modeled (DAS or not, and which type) + * @param[in] linearDASSamples parameter that gives the number of integration points to be used when computing the DAS signal via strain + * integration + * @param[in] linearDASGeometry geometry of the linear DAS receivers, if needed + * @param[in] sourceForce force vector of the source + * @param[in] sourceMoment moment (symmetric rank-2 tensor) of the source + */ + template< typename EXEC_POLICY, typename FE_TYPE > + static void + Compute3DSourceAndReceiverConstantsWithDAS( localIndex const size, + ArrayOfArraysView< localIndex const > const baseFacesToNodes, + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const baseNodeCoords, + arrayView1d< globalIndex const > const baseNodeLocalToGlobal, + arrayView1d< globalIndex const > const elementLocalToGlobal, + ArrayOfArraysView< localIndex const > const baseNodesToElements, + arrayView2d< localIndex const, cells::NODE_MAP_USD > const & baseElemsToNodes, + arrayView1d< integer const > const elemGhostRank, + arrayView2d< localIndex const, cells::NODE_MAP_USD > const & elemsToNodes, + arrayView2d< localIndex const > const elemsToFaces, + arrayView2d< real64 const > const & elemCenter, + arrayView2d< real64 const > const sourceCoordinates, + arrayView1d< localIndex > const sourceIsAccessible, + arrayView2d< localIndex > const sourceNodeIds, + arrayView2d< real64 > const sourceConstantsx, + arrayView2d< real64 > const sourceConstantsy, + arrayView2d< real64 > const sourceConstantsz, + arrayView2d< real64 const > const receiverCoordinates, + arrayView1d< localIndex > const receiverIsLocal, + arrayView2d< localIndex > const receiverNodeIds, + arrayView2d< real64 > const receiverConstants, + WaveSolverUtils::DASType useDAS, + integer linearDASSamples, + arrayView2d< real64 const > const linearDASGeometry, + R1Tensor const sourceForce, + R2SymTensor const sourceMoment ) + { + constexpr localIndex numNodesPerElem = FE_TYPE::numNodes; + integer nSamples = useDAS == WaveSolverUtils::DASType::none ? 1 : linearDASSamples; + array1d< real64 > const samplePointLocationsA( nSamples ); + arrayView1d< real64 > const samplePointLocations = samplePointLocationsA.toView(); + array1d< real64 > const sampleIntegrationConstantsA( nSamples ); + arrayView1d< real64 > const sampleIntegrationConstants = sampleIntegrationConstantsA.toView(); + + forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + real64 const center[3] = { elemCenter[k][0], + elemCenter[k][1], + elemCenter[k][2] }; + + // Step 1: locate the sources, and precompute the source term + + /// loop over all the source that haven't been found yet + for( localIndex isrc = 0; isrc < sourceCoordinates.size( 0 ); ++isrc ) + { + if( sourceIsAccessible[isrc] == 0 ) + { + real64 const coords[3] = { sourceCoordinates[isrc][0], + sourceCoordinates[isrc][1], + sourceCoordinates[isrc][2] }; + + real64 xLocal[8][3]; + + for( localIndex a = 0; a < 8; ++a ) + { + for( localIndex i = 0; i < 3; ++i ) + { + xLocal[a][i] = baseNodeCoords( baseElemsToNodes( k, a ), i ); + } + } + + + bool const sourceFound = + computationalGeometry::isPointInsideConvexPolyhedronRobust( k, + baseNodeCoords, + elemsToFaces, + baseFacesToNodes, + baseNodesToElements, + baseNodeLocalToGlobal, + elementLocalToGlobal, + center, + coords ); + + if( sourceFound ) + { + real64 coordsOnRefElem[3]{}; + + + WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, + baseElemsToNodes[k], + baseNodeCoords, + coordsOnRefElem ); + sourceIsAccessible[isrc] = 1; + + real64 N[numNodesPerElem]; + real64 gradN[numNodesPerElem][3]; + FE_TYPE::calcN( coordsOnRefElem, N ); + FE_TYPE::calcGradNWithCorners( coordsOnRefElem, xLocal, gradN ); + R2SymTensor moment = sourceMoment; + for( localIndex q=0; q< numNodesPerElem; ++q ) + { + real64 inc[3] = { 0, 0, 0 }; + sourceNodeIds[isrc][q] = elemsToNodes( k, q ); + inc[0] += sourceForce[0] * N[q]; + inc[1] += sourceForce[1] * N[q]; + inc[2] += sourceForce[2] * N[q]; + + LvArray::tensorOps::Ri_add_symAijBj< 3 >( inc, moment.data, gradN[q] ); + sourceConstantsx[isrc][q] += inc[0]; + sourceConstantsy[isrc][q] += inc[1]; + sourceConstantsz[isrc][q] += inc[2]; + } + + } + } + } // end loop over all sources + + // Step 2: locate the receivers, and precompute the receiver term + + // for geophones, we need only a point per receiver. + // for DAS, we need multiple points + + /// compute locations of samples along receiver + if( nSamples == 1 ) + { + samplePointLocations[ 0 ] = 0; + } + else + { + for( integer i = 0; i < nSamples; ++i ) + { + samplePointLocations[ i ] = -0.5 + (real64) i / ( linearDASSamples - 1 ); + } + } + + /// compute integration constants of samples + /// for displacement difference (dipole) DAS, take the discrete derivative of the pair of geophones + if( useDAS == WaveSolverUtils::DASType::dipole ) + { + sampleIntegrationConstants[ 0 ] = -1.0; + sampleIntegrationConstants[ 1 ] = 1.0; + } + /// for strain integration DAS, take the average of strains to average strain data + else if( nSamples == 1 ) + { + sampleIntegrationConstants[ 0 ] = 1.0; + } + else + { + for( integer i = 0; i < linearDASSamples; i++ ) + { + sampleIntegrationConstants[ i ] = 1.0 / nSamples; + } + } + + /// loop over all the receivers + for( localIndex ircv = 0; ircv < receiverCoordinates.size( 0 ); ++ircv ) + { + R1Tensor receiverCenter = { receiverCoordinates[ ircv ][ 0 ], receiverCoordinates[ ircv ][ 1 ], receiverCoordinates[ ircv ][ 2 ] }; + R1Tensor receiverVector; + if( useDAS == WaveSolverUtils::DASType::none ) + { + receiverVector = { 0, 0, 0 }; + } + else + { + receiverVector = WaveSolverUtils::computeDASVector( linearDASGeometry[ ircv ][ 0 ], linearDASGeometry[ ircv ][ 1 ] ); + } + real64 receiverLength = useDAS == WaveSolverUtils::DASType::none ? 0 : linearDASGeometry[ ircv ][ 2 ]; + /// loop over samples + for( integer iSample = 0; iSample < nSamples; ++iSample ) + { + /// compute sample coordinates and locate the element containing it + real64 const coords[3] = { receiverCenter[ 0 ] + receiverVector[ 0 ] * receiverLength * samplePointLocations[ iSample ], + receiverCenter[ 1 ] + receiverVector[ 1 ] * receiverLength * samplePointLocations[ iSample ], + receiverCenter[ 2 ] + receiverVector[ 2 ] * receiverLength * samplePointLocations[ iSample ] }; + bool const sampleFound = + computationalGeometry::isPointInsideConvexPolyhedronRobust( k, + baseNodeCoords, + elemsToFaces, + baseFacesToNodes, + baseNodesToElements, + baseNodeLocalToGlobal, + elementLocalToGlobal, + center, + coords ); + if( sampleFound && elemGhostRank[k] < 0 ) + { + real64 coordsOnRefElem[3]{}; + real64 xLocal[8][3]; + + for( localIndex a = 0; a < 8; ++a ) + { + for( localIndex i=0; i < 3; ++i ) + { + xLocal[a][i] = baseNodeCoords( baseElemsToNodes( k, a ), i ); + } + } + + WaveSolverUtils::computeCoordinatesOnReferenceElement< FE_TYPE >( coords, + baseElemsToNodes[k], + baseNodeCoords, + coordsOnRefElem ); + real64 N[numNodesPerElem]; + real64 gradN[numNodesPerElem][3]; + FE_TYPE::calcN( coordsOnRefElem, N ); + FE_TYPE::calcGradNWithCorners( coordsOnRefElem, xLocal, gradN ); + for( localIndex a = 0; a < numNodesPerElem; ++a ) + { + receiverNodeIds[ircv][iSample * numNodesPerElem + a] = elemsToNodes( k, + a ); + if( useDAS == WaveSolverUtils::DASType::strainIntegration ) + { + receiverConstants[ircv][iSample * numNodesPerElem + a] += ( gradN[a][0] * receiverVector[0] + gradN[a][1] * receiverVector[1] + gradN[a][2] * receiverVector[2] ) * + sampleIntegrationConstants[ iSample ]; + } + else + { + receiverConstants[ircv][iSample * numNodesPerElem + a] += N[a] * sampleIntegrationConstants[ iSample ]; + } + } + receiverIsLocal[ ircv ] = 2; + } + } // end loop over samples + // determine if the current rank is the owner of this receiver + real64 const coords[3] = { receiverCenter[ 0 ], receiverCenter[ 1 ], receiverCenter[ 2 ] }; + bool const receiverFound = + computationalGeometry::isPointInsideConvexPolyhedronRobust( k, + baseNodeCoords, + elemsToFaces, + baseFacesToNodes, + baseNodesToElements, + baseNodeLocalToGlobal, + elementLocalToGlobal, + center, + coords ); + if( receiverFound && elemGhostRank[k] < 0 ) + { + receiverIsLocal[ ircv ] = 1; + } + } // end loop over receivers + } ); + + } + +}; + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_PRECOMPUTESOURCESANDRECEIVERSKERNEL_HPP_ diff --git a/src/coreComponents/physicsSolvers/wavePropagation/WaveSolverBase.cpp b/src/coreComponents/physicsSolvers/wavePropagation/shared/WaveSolverBase.cpp similarity index 75% rename from src/coreComponents/physicsSolvers/wavePropagation/WaveSolverBase.cpp rename to src/coreComponents/physicsSolvers/wavePropagation/shared/WaveSolverBase.cpp index 3278086f9e4..b55ca1f38d7 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/WaveSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/shared/WaveSolverBase.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -26,7 +27,9 @@ #include "fieldSpecification/PerfectlyMatchedLayer.hpp" #include "mainInterface/ProblemManager.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" +#include "mesh/DomainPartition.hpp" #include "WaveSolverUtils.hpp" +#include "events/EventManager.hpp" #include @@ -37,8 +40,8 @@ using namespace dataRepository; WaveSolverBase::WaveSolverBase( const std::string & name, Group * const parent ): - SolverBase( name, - parent ) + PhysicsSolverBase( name, + parent ) { registerWrapper( viewKeyStruct::sourceCoordinatesString(), &m_sourceCoordinates ). @@ -51,12 +54,6 @@ WaveSolverBase::WaveSolverBase( const std::string & name, setSizedFromParent( 0 ). setDescription( "Coordinates (x,y,z) of the receivers" ); - registerWrapper( viewKeyStruct::sourceValueString(), &m_sourceValue ). - setInputFlag( InputFlags::FALSE ). - setRestartFlags( RestartFlags::NO_WRITE ). - setSizedFromParent( 0 ). - setDescription( "Source Value of the sources" ); - registerWrapper( viewKeyStruct::timeSourceDelayString(), &m_timeSourceDelay ). setInputFlag( InputFlags::OPTIONAL ). setApplyDefaultValue( -1 ). @@ -130,7 +127,8 @@ WaveSolverBase::WaveSolverBase( const std::string & name, registerWrapper( viewKeyStruct::useDASString(), &m_useDAS ). setInputFlag( InputFlags::OPTIONAL ). setApplyDefaultValue( WaveSolverUtils::DASType::none ). - setDescription( "Flag to indicate if DAS data will be modeled, and which DAS type to use: 1 for strain integration, 2 for displacement difference" ); + setDescription( + "Flag to indicate if DAS data will be modeled, and which DAS type to use: \"none\" to deactivate DAS, \"strainIntegration\" for strain integration, \"dipole\" for displacement difference" ); registerWrapper( viewKeyStruct::linearDASSamplesString(), &m_linearDASSamples ). setInputFlag( InputFlags::OPTIONAL ). @@ -187,15 +185,52 @@ WaveSolverBase::WaveSolverBase( const std::string & name, setSizedFromParent( 0 ). setDescription( "Flag that indicates whether the receiver is local to this MPI rank" ); + registerWrapper( viewKeyStruct::timestepStabilityLimitString(), &m_timestepStabilityLimit ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( 0 ). + setDescription( "Set to 1 to apply a stability limit to the simulation timestep. The timestep used is that given by the CFL condition times the cflFactor parameter." ); + + registerWrapper( viewKeyStruct::timeStepString(), &m_timeStep ). + setInputFlag( InputFlags::FALSE ). + setSizedFromParent( 0 ). + setApplyDefaultValue( 1 ). + setDescription( "TimeStep computed with the power iteration method (if we don't want to compute it, it is initialized with the XML value" ); + + registerWrapper( viewKeyStruct::receiverRegionString(), &m_receiverRegion ). setInputFlag( InputFlags::FALSE ). setSizedFromParent( 0 ). setDescription( "Region containing the receivers" ); - registerWrapper( viewKeyStruct::receiverElemString(), &m_rcvElem ). + registerWrapper( viewKeyStruct::receiverElemString(), &m_receiverElem ). setInputFlag( InputFlags::FALSE ). setSizedFromParent( 0 ). setDescription( "Element containing the receivers" ); + + registerWrapper( viewKeyStruct::slsReferenceAngularFrequenciesString(), &m_slsReferenceAngularFrequencies ). + setInputFlag( InputFlags::OPTIONAL ). + setSizedFromParent( 0 ). + setApplyDefaultValue( { } ). + setDescription( "Reference angular frequencies (omega) for the standard-linear-solid (SLS) anelasticity." + "The default value is { }, corresponding to no attenuation. An array with the corresponding anelasticity coefficients must be provided." ); + + registerWrapper( viewKeyStruct::slsAnelasticityCoefficientsString(), &m_slsAnelasticityCoefficients ). + setInputFlag( InputFlags::OPTIONAL ). + setSizedFromParent( 0 ). + setApplyDefaultValue( { } ). + setDescription( "Anelasticity coefficients for the standard-linear-solid (SLS) anelasticity." + "The default value is { }, corresponding to no attenuation. An array with the corresponding reference frequencies must be provided." ); + + registerWrapper( viewKeyStruct::attenuationTypeString(), &m_attenuationType ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( WaveSolverUtils::AttenuationType::none ). + setDescription( "Flag to indicate which attenuation model to use: \"none\" for no attenuation, \"sls\\" " for the standard-linear-solid (SLS) model (Fichtner, 2014)." ); + + registerWrapper( viewKeyStruct::sourceWaveletTableNames(), &m_sourceWaveletTableNames ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Names of the table functions, one for each source, that are used to define the source wavelets. If a list is given, it overrides the Ricker wavelet definitions." + "The default value is an empty list, which means that a Ricker wavelet is used everywhere." ); + } WaveSolverBase::~WaveSolverBase() @@ -206,7 +241,7 @@ WaveSolverBase::~WaveSolverBase() void WaveSolverBase::reinit() { initializePreSubGroups(); - postProcessInput(); + postInputInitialization(); initializePostInitialConditionsPreSubGroups(); } @@ -235,7 +270,7 @@ void WaveSolverBase::registerDataOnMesh( Group & meshBodies ) void WaveSolverBase::initializePreSubGroups() { - SolverBase::initializePreSubGroups(); + PhysicsSolverBase::initializePreSubGroups(); localIndex const numNodesPerElem = WaveSolverBase::getNumNodesPerElem(); @@ -249,11 +284,22 @@ void WaveSolverBase::initializePreSubGroups() m_receiverConstants.resize( numReceiversGlobal, numNodesPerElem ); m_receiverIsLocal.resize( numReceiversGlobal ); + if( m_useSourceWaveletTables ) + { + FunctionManager const & functionManager = FunctionManager::getInstance(); + m_sourceWaveletTableWrappers.clear(); + for( integer i = 0; i < m_sourceWaveletTableNames.size(); i++ ) + { + TableFunction const & sourceWaveletTable = functionManager.getGroup< TableFunction >( m_sourceWaveletTableNames[ i ] ); + m_sourceWaveletTableWrappers.emplace_back( sourceWaveletTable.createKernelWrapper() ); + } + } + } -void WaveSolverBase::postProcessInput() +void WaveSolverBase::postInputInitialization() { - SolverBase::postProcessInput(); + PhysicsSolverBase::postInputInitialization(); /// set flag PML to one if a PML field is specified in the xml /// if counter>1, an error will be thrown as one single PML field is allowed @@ -309,6 +355,22 @@ void WaveSolverBase::postProcessInput() } } + if( m_attenuationType == WaveSolverUtils::AttenuationType::sls ) + { + GEOS_THROW_IF( m_slsReferenceAngularFrequencies.size( 0 ) != m_slsAnelasticityCoefficients.size( 0 ), + "The number of attenuation anelasticity coefficients for the SLS model must be equal to the number of reference angular frequencies", + InputError ); + if( m_slsReferenceAngularFrequencies.size( 0 ) == 0 || m_slsAnelasticityCoefficients.size( 0 ) == 0 ) + { + m_slsReferenceAngularFrequencies.resize( 1 ); + m_slsReferenceAngularFrequencies[ 0 ] = 2.0 * M_PI * m_timeSourceFrequency; + m_slsAnelasticityCoefficients.resize( 1 ); + // set the coefficient to a negative value, so that it will be recomputed when the quality factor is available + m_slsAnelasticityCoefficients[ 0 ] = -1; + } + } + + GEOS_THROW_IF( m_sourceCoordinates.size( 0 ) > 0 && m_sourceCoordinates.size( 1 ) != 3, "Invalid number of physical coordinates for the sources", InputError ); @@ -319,18 +381,6 @@ void WaveSolverBase::postProcessInput() EventManager const & event = getGroupByPath< EventManager >( "/Problem/Events" ); real64 const & maxTime = event.getReference< real64 >( EventManager::viewKeyStruct::maxTimeString() ); - real64 const & minTime = event.getReference< real64 >( EventManager::viewKeyStruct::minTimeString() ); - real64 dt = 0; - for( localIndex numSubEvent = 0; numSubEvent < event.numSubGroups(); ++numSubEvent ) - { - EventBase const * subEvent = static_cast< EventBase const * >( event.getSubGroups()[numSubEvent] ); - if( subEvent->getEventName() == "/Solvers/" + this->getName() ) - { - dt = subEvent->getReference< real64 >( EventBase::viewKeyStruct::forceDtString() ); - } - } - - GEOS_THROW_IF( dt < epsilonLoc * maxTime, getDataContext() << ": Value for dt: " << dt <<" is smaller than local threshold: " << epsilonLoc, std::runtime_error ); if( m_dtSeismoTrace > 0 ) { @@ -340,10 +390,11 @@ void WaveSolverBase::postProcessInput() { m_nsamplesSeismoTrace = 0; } - localIndex const nsamples = int( (maxTime - minTime) / dt) + 1; - localIndex const numSourcesGlobal = m_sourceCoordinates.size( 0 ); - m_sourceValue.resize( nsamples, numSourcesGlobal ); + GEOS_THROW_IF( m_sourceWaveletTableNames.size() > 0 && m_sourceWaveletTableNames.size() != m_sourceCoordinates.size( 0 ), + "Invalid number of source wavelet table names. The number of table functions must be equal to the number of sources", + InputError ); + m_useSourceWaveletTables = m_sourceWaveletTableNames.size() > 0; } @@ -433,9 +484,19 @@ void WaveSolverBase::computeTargetNodeSet( arrayView2d< localIndex const, cells: void WaveSolverBase::incrementIndexSeismoTrace( real64 const time_n ) { - while( (m_dtSeismoTrace * m_indexSeismoTrace) <= (time_n + epsilonLoc) && m_indexSeismoTrace < m_nsamplesSeismoTrace ) + if( m_forward ) + { + while( (m_dtSeismoTrace * m_indexSeismoTrace) <= (time_n + epsilonLoc) && m_indexSeismoTrace < m_nsamplesSeismoTrace ) + { + m_indexSeismoTrace++; + } + } + else { - m_indexSeismoTrace++; + while( (m_dtSeismoTrace * m_indexSeismoTrace) >= (time_n - epsilonLoc) && m_indexSeismoTrace > 0 ) + { + m_indexSeismoTrace--; + } } } @@ -464,12 +525,14 @@ void WaveSolverBase::computeAllSeismoTraces( real64 const time_n, if( m_nsamplesSeismoTrace == 0 ) return; integer const dir = m_forward ? +1 : -1; - for( localIndex iSeismo = m_indexSeismoTrace; iSeismo < m_nsamplesSeismoTrace; iSeismo++ ) + integer const beginIndex = m_forward ? m_indexSeismoTrace : m_nsamplesSeismoTrace-m_indexSeismoTrace; + for( localIndex iSeismo = beginIndex; iSeismo < m_nsamplesSeismoTrace; iSeismo++ ) { - real64 const timeSeismo = m_dtSeismoTrace * (m_forward ? iSeismo : (m_nsamplesSeismoTrace - 1) - iSeismo); - if( dir * timeSeismo > dir * (time_n + epsilonLoc) ) + localIndex seismoIndex = m_forward ? iSeismo : m_nsamplesSeismoTrace-iSeismo; + real64 const timeSeismo = m_dtSeismoTrace * seismoIndex; + if( dir * timeSeismo > dir * time_n + epsilonLoc ) break; - WaveSolverUtils::computeSeismoTrace( time_n, dir * dt, timeSeismo, iSeismo, m_receiverNodeIds, + WaveSolverUtils::computeSeismoTrace( time_n, dir * dt, timeSeismo, seismoIndex, m_receiverNodeIds, m_receiverConstants, m_receiverIsLocal, var_np1, var_n, varAtReceivers, coeffs, add ); } } @@ -484,12 +547,14 @@ void WaveSolverBase::compute2dVariableAllSeismoTraces( localIndex const regionIn if( m_nsamplesSeismoTrace == 0 ) return; integer const dir = m_forward ? +1 : -1; - for( localIndex iSeismo = m_indexSeismoTrace; iSeismo < m_nsamplesSeismoTrace; iSeismo++ ) + integer const beginIndex = m_forward ? m_indexSeismoTrace : m_nsamplesSeismoTrace-m_indexSeismoTrace; + for( localIndex iSeismo = beginIndex; iSeismo < m_nsamplesSeismoTrace; iSeismo++ ) { - real64 const timeSeismo = m_dtSeismoTrace * (m_forward ? iSeismo : (m_nsamplesSeismoTrace - 1) - iSeismo); - if( dir * timeSeismo > dir * (time_n + epsilonLoc)) + localIndex seismoIndex = m_forward ? iSeismo : m_nsamplesSeismoTrace-iSeismo; + real64 const timeSeismo = m_dtSeismoTrace * seismoIndex; + if( dir * timeSeismo > dir * time_n + epsilonLoc ) break; - WaveSolverUtils::compute2dVariableSeismoTrace( time_n, dir * dt, regionIndex, m_receiverRegion, timeSeismo, iSeismo, m_rcvElem, + WaveSolverUtils::compute2dVariableSeismoTrace( time_n, dir * dt, regionIndex, m_receiverRegion, timeSeismo, seismoIndex, m_receiverElem, m_receiverConstants, m_receiverIsLocal, var_np1, var_n, varAtReceivers ); } } diff --git a/src/coreComponents/physicsSolvers/wavePropagation/WaveSolverBase.hpp b/src/coreComponents/physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp similarity index 85% rename from src/coreComponents/physicsSolvers/wavePropagation/WaveSolverBase.hpp rename to src/coreComponents/physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp index 93819ec6a60..2c319ca4f38 100644 --- a/src/coreComponents/physicsSolvers/wavePropagation/WaveSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -22,8 +23,9 @@ #include "mesh/MeshFields.hpp" -#include "physicsSolvers/SolverBase.hpp" +#include "physicsSolvers/PhysicsSolverBase.hpp" #include "common/LifoStorage.hpp" +#include "functions/TableFunction.hpp" #if !defined( GEOS_USE_HIP ) #include "finiteElement/elementFormulations/Qk_Hexahedron_Lagrange_GaussLobatto.hpp" #endif @@ -45,7 +47,7 @@ namespace geos { -class WaveSolverBase : public SolverBase +class WaveSolverBase : public PhysicsSolverBase { public: @@ -78,10 +80,9 @@ class WaveSolverBase : public SolverBase integer const cycleNumber, DomainPartition & domain ) override; - struct viewKeyStruct : SolverBase::viewKeyStruct + struct viewKeyStruct : PhysicsSolverBase::viewKeyStruct { static constexpr char const * sourceCoordinatesString() { return "sourceCoordinates"; } - static constexpr char const * sourceValueString() { return "sourceValue"; } static constexpr char const * timeSourceFrequencyString() { return "timeSourceFrequency"; } static constexpr char const * timeSourceDelayString() { return "timeSourceDelay"; } @@ -118,9 +119,18 @@ class WaveSolverBase : public SolverBase static constexpr char const * usePMLString() { return "usePML"; } static constexpr char const * parametersPMLString() { return "parametersPML"; } - static constexpr char const * receiverElemString() { return "rcvElem"; } + static constexpr char const * receiverElemString() { return "receiverElem"; } static constexpr char const * receiverRegionString() { return "receiverRegion"; } static constexpr char const * freeSurfaceString() { return "FreeSurface"; } + + static constexpr char const * timestepStabilityLimitString() { return "timestepStabilityLimit"; } + static constexpr char const * timeStepString() { return "timeStep"; } + + static constexpr char const * attenuationTypeString() { return "attenuationType"; } + static constexpr char const * slsReferenceAngularFrequenciesString() { return "slsReferenceAngularFrequencies"; } + static constexpr char const * slsAnelasticityCoefficientsString() { return "slsAnelasticityCoefficients"; } + + static constexpr char const * sourceWaveletTableNames() { return "sourceWaveletTableNames"; } }; /** @@ -136,7 +146,7 @@ class WaveSolverBase : public SolverBase protected: - virtual void postProcessInput() override; + virtual void postInputInitialization() override; /** * @brief Utility function to check if a directory exists @@ -152,6 +162,9 @@ class WaveSolverBase : public SolverBase */ virtual void applyFreeSurfaceBC( real64 const time, DomainPartition & domain ) = 0; + /** + */ + virtual real64 computeTimeStep( real64 & dtOut ) = 0; /** * @brief Initialize Perfectly Matched Layer (PML) information @@ -202,9 +215,10 @@ class WaveSolverBase : public SolverBase /** * @brief Locate sources and receivers positions in the mesh elements, evaluate the basis functions at each point and save them to the * corresponding elements nodes. + * @param baseMesh the level-0 mesh * @param mesh mesh of the computational domain */ - virtual void precomputeSourceAndReceiverTerm( MeshLevel & mesh, arrayView1d< string const > const & regionNames ) = 0; + virtual void precomputeSourceAndReceiverTerm( MeshLevel & baseMesh, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) = 0; /** * @brief Perform forward explicit step @@ -243,9 +257,6 @@ class WaveSolverBase : public SolverBase /// Coordinates of the sources in the mesh array2d< real64 > m_sourceCoordinates; - /// Precomputed value of the source terms - array2d< real32 > m_sourceValue; - /// Central frequency for the Ricker time source real32 m_timeSourceFrequency; @@ -270,7 +281,7 @@ class WaveSolverBase : public SolverBase /// Amount of seismoTrace that will be recorded for each receiver localIndex m_nsamplesSeismoTrace; - /// Flag to indicate which DAS type will be modeled + /// Flag to indicate which DAS type will be modeled WaveSolverUtils::DASType m_useDAS; /// Number of points used for strain integration for dipole DAS @@ -288,6 +299,15 @@ class WaveSolverBase : public SolverBase /// Z component of the linear DAS direction vector array1d< real32 > m_linearDASVectorZ; + /// Flag to indicate which attenuation type will be modeled + WaveSolverUtils::AttenuationType m_attenuationType; + + /// Vector containing the reference frequencies for the standard-linear-solid (SLS) anelasticity model. + array1d< real32 > m_slsReferenceAngularFrequencies; + + /// Vector containing the anelasticity coefficients for the standard-linear-solid (SLS) anelasticity model. + array1d< real32 > m_slsAnelasticityCoefficients; + /// Indicate if we want to compute forward ou backward localIndex m_forward; @@ -300,6 +320,14 @@ class WaveSolverBase : public SolverBase /// Flag to apply PML integer m_usePML; + /// Flag to precompute the time-step + /// usage: the time-step is computed then the code exit and you can + /// copy paste the time-step inside the XML then deactivate the option + integer m_timestepStabilityLimit; + + //Time step computed with power iteration + real64 m_timeStep; + /// Indices of the nodes (in the right order) for each source point array2d< localIndex > m_sourceNodeIds; @@ -319,7 +347,7 @@ class WaveSolverBase : public SolverBase array1d< localIndex > m_receiverIsLocal; /// Array containing the elements which contain a receiver - array1d< localIndex > m_rcvElem; + array1d< localIndex > m_receiverElem; /// Array containing the elements which contain the region which the receiver belongs array1d< localIndex > m_receiverRegion; @@ -342,6 +370,15 @@ class WaveSolverBase : public SolverBase /// A set of target nodes IDs that will be handled by the current solver SortedArray< localIndex > m_solverTargetNodesSet; + /// Names of table functions for source wavelet (time dependency) + array1d< string > m_sourceWaveletTableNames; + + /// Flag to indicate if source wavelet table functions are used + bool m_useSourceWaveletTables; + + /// Wrappers of table functions for source wavelet (time dependency) + array1d< TableFunction::KernelWrapper > m_sourceWaveletTableWrappers; + struct parametersPML { /// Mininum (x,y,z) coordinates of inner PML boundaries diff --git a/src/coreComponents/physicsSolvers/wavePropagation/shared/WaveSolverUtils.hpp b/src/coreComponents/physicsSolvers/wavePropagation/shared/WaveSolverUtils.hpp new file mode 100644 index 00000000000..530f7e3b8e0 --- /dev/null +++ b/src/coreComponents/physicsSolvers/wavePropagation/shared/WaveSolverUtils.hpp @@ -0,0 +1,459 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + + +/** + * @file WaveSolverUtils.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_WAVESOLVERUTILS_HPP_ +#define GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_WAVESOLVERUTILS_HPP_ + +#include "mesh/utilities/ComputationalGeometry.hpp" +#include "fileIO/Outputs/OutputBase.hpp" +#include "LvArray/src/tensorOps.hpp" + +namespace geos +{ + +struct WaveSolverUtils +{ + static constexpr real64 epsilonLoc = 1e-8; + + using EXEC_POLICY = parallelDevicePolicy< >; + using wsCoordType = real32; + + enum class DASType : integer + { + none, ///< deactivate DAS computation + dipole, ///< use dipole formulation for DAS + strainIntegration, ///< use strain integration for DAS + }; + + enum class AttenuationType : integer + { + none, ///< deactivate attenuation (default) + sls, ///< istandard-linear-solid description [Fichtner 2014] + }; + + + GEOS_HOST_DEVICE + static real32 evaluateRicker( real64 const time_n, real32 const f0, real32 const t0, localIndex const order ) + { + real32 const delay = t0 > 0 ? t0 : 1 / f0; + real32 pulse = 0.0; + real32 const alpha = -pow( f0 * M_PI, 2 ); + real32 const time_d = time_n - delay; + real32 const gaussian = exp( alpha * pow( time_d, 2 )); + localIndex const sgn = pow( -1, order + 1 ); + + switch( order ) + { + case 0: + pulse = sgn * gaussian; + break; + case 1: + pulse = sgn * (2 * alpha * time_d) * gaussian; + break; + case 2: + pulse = sgn * (2 * alpha + 4 * pow( alpha, 2 ) * pow( time_d, 2 )) * gaussian; + break; + case 3: + pulse = sgn * (12 * pow( alpha, 2 ) * time_d + 8 * pow( alpha, 3 ) * pow( time_d, 3 )) * gaussian; + break; + case 4: + pulse = sgn * (12 * pow( alpha, 2 ) + 48 * pow( alpha, 3 ) * pow( time_d, 2 ) + 16 * pow( alpha, 4 ) * pow( time_d, 4 )) * gaussian; + break; + default: + GEOS_ERROR( "This option is not supported yet, rickerOrder must be in range {0:4}" ); + } + + return pulse; + } + + /** + * @brief Initialize (clear) the trace file. + * @param[in] prefix Prefix of the output file + * @param[in] name Name of the solver on which you write the seismo trace + * @param[in] outputSeismoTrace Boolean equals to 1 if you want to output the seismotrace on a txt file 0 either + * @param[in] nReceivers Number of receivers + * @param[in] receiverIsLocal Array to check if the receiver is local to the MPI partition + */ + static void initTrace( char const * prefix, + string const & name, + bool const outputSeismoTrace, + localIndex const nReceivers, + arrayView1d< localIndex const > const receiverIsLocal ) + { + if( !outputSeismoTrace ) return; + + string const outputDir = OutputBase::getOutputDirectory(); + RAJA::ReduceSum< ReducePolicy< serialPolicy >, localIndex > count( 0 ); + + forAll< serialPolicy >( nReceivers, [=] ( localIndex const ircv ) + { + if( receiverIsLocal[ircv] == 1 ) + { + count += 1; + string const fn = joinPath( outputDir, GEOS_FMT( "{}_{}_{:03}.txt", prefix, name, ircv ) ); + std::ofstream f( fn, std::ios::out | std::ios::trunc ); + } + } ); + + localIndex const total = MpiWrapper::sum( count.get() ); + GEOS_ERROR_IF( nReceivers != total, GEOS_FMT( ": Invalid distribution of receivers: nReceivers={} != MPI::sum={}.", nReceivers, total ) ); + } + + /** + * @brief Convenient helper for 3D vectors calling 3 times the scalar version with only the sampled variable argument changed. + * @param[in] prefix Prefix of the output file + * @param[in] name Name of the solver on which you write the seismo trace + * @param[in] outputSeismoTrace Boolean equals to 1 if you want to output the seismotrace on a txt file 0 either + * @param[in] nReceivers Number of receivers + * @param[in] receiverIsLocal Array to check if the receiver is local to the MPI partition + * @param[in] nsamplesSeismoTrace Number of samples per seismo trace + * @param[out] varAtReceiversx Array containing the variable (x-direction) computed at the receivers + * @param[out] varAtReceiversy Array containing the variable (y-direction) computed at the receivers + * @param[out] varAtReceiversz Array containing the variable (z-direction) computed at the receivers + */ + static void writeSeismoTraceVector( char const * prefix, + string const & name, + bool const outputSeismoTrace, + localIndex const nReceivers, + arrayView1d< localIndex const > const receiverIsLocal, + localIndex const nsamplesSeismoTrace, + arrayView2d< real32 const > const varAtReceiversx, + arrayView2d< real32 const > const varAtReceiversy, + arrayView2d< real32 const > const varAtReceiversz ) + { + writeSeismoTrace( prefix, name, outputSeismoTrace, nReceivers, receiverIsLocal, nsamplesSeismoTrace, varAtReceiversx ); + writeSeismoTrace( prefix, name, outputSeismoTrace, nReceivers, receiverIsLocal, nsamplesSeismoTrace, varAtReceiversy ); + writeSeismoTrace( prefix, name, outputSeismoTrace, nReceivers, receiverIsLocal, nsamplesSeismoTrace, varAtReceiversz ); + } + + /** + * @brief Write the seismo traces to a file. + * @param[in] prefix Prefix of the output file + * @param[in] name Name of the solver on which you write the seismo trace + * @param[in] outputSeismoTrace Boolean equals to 1 if you want to output the seismotrace on a txt file 0 either + * @param[in] nReceivers Number of receivers + * @param[in] receiverIsLocal Array to check if the receiver is local to the MPI partition + * @param[in] nsamplesSeismoTrace Number of samples per seismo trace + * @param[in] varAtReceivers Array containing the the variable computed at the receivers + */ + static void writeSeismoTrace( char const * prefix, + string const & name, + bool const outputSeismoTrace, + localIndex const nReceivers, + arrayView1d< localIndex const > const receiverIsLocal, + localIndex const nsamplesSeismoTrace, + arrayView2d< real32 const > const varAtReceivers ) + { + if( !outputSeismoTrace ) return; + + string const outputDir = OutputBase::getOutputDirectory(); + forAll< serialPolicy >( nReceivers, [=] ( localIndex const ircv ) + { + if( receiverIsLocal[ircv] == 1 ) + { + string const fn = joinPath( outputDir, GEOS_FMT( "{}_{}_{:03}.txt", prefix, name, ircv ) ); + std::ofstream f( fn, std::ios::app ); + if( f ) + { + GEOS_LOG_RANK( GEOS_FMT( "Append to seismo trace file {}", fn ) ); + for( localIndex iSample = 0; iSample < nsamplesSeismoTrace; ++iSample ) + { + // index - time - value + f << iSample << " " << varAtReceivers[iSample][nReceivers] << " " << varAtReceivers[iSample][ircv] << std::endl; + } + f.close(); + } + else + { + GEOS_WARNING( GEOS_FMT( "Failed to open output file {}", fn ) ); + } + } + } ); + } + + /** + * @brief Compute the seismo traces. + * @param[in] time_n Current time iteration + * @param[in] dt time-step + * @param[in] timeSeismo time when the seismo is computed + * @param[in] iSeismo i-th seismo trace + * @param[in] receiverNodeIds indices of the nodes of the element where the receiver is located + * @param[in] receiverConstants constant part of the receiver term + * @param[in] receiverIsLocal flag indicating whether the receiver is local or not + * @param[in] var_np1 Array containing the variable at time n+1 + * @param[in] var_n Array containing the variable at time n + * @param[out] varAtReceivers Array containing the the variable computed at the receivers + * @param[in] coeffs Coefficients array for receivers + * @param[in] add Boolean to say if you want to add the value of interpolation to the same receiver coefficient or not + */ + static void computeSeismoTrace( real64 const time_n, + real64 const dt, + real64 const timeSeismo, + localIndex const iSeismo, + arrayView2d< localIndex const > const receiverNodeIds, + arrayView2d< real64 const > const receiverConstants, + arrayView1d< localIndex const > const receiverIsLocal, + arrayView1d< real32 const > const var_np1, + arrayView1d< real32 const > const var_n, + arrayView2d< real32 > varAtReceivers, + arrayView1d< real32 > coeffs = {}, + bool add = false ) + { + real64 const time_np1 = time_n + dt; + + real32 const a1 = LvArray::math::abs( dt ) < epsilonLoc ? 1.0 : (time_np1 - timeSeismo) / dt; + real32 const a2 = 1.0 - a1; + + localIndex const nReceivers = receiverConstants.size( 0 ); + forAll< EXEC_POLICY >( nReceivers, [=] GEOS_HOST_DEVICE ( localIndex const ircv ) + { + if( receiverIsLocal[ircv] > 0 ) + { + real32 vtmp_np1 = 0.0, vtmp_n = 0.0; + for( localIndex inode = 0; inode < receiverConstants.size( 1 ); ++inode ) + { + if( receiverNodeIds( ircv, inode ) >= 0 ) + { + vtmp_np1 += var_np1[receiverNodeIds( ircv, inode )] * receiverConstants( ircv, inode ); + vtmp_n += var_n[receiverNodeIds( ircv, inode )] * receiverConstants( ircv, inode ); + } + } + // linear interpolation between the pressure value at time_n and time_{n+1} + real32 receiverCoeff = coeffs.size( 0 ) == 0 ? 1.0 : coeffs( ircv ); + if( add ) + { + varAtReceivers( iSeismo, ircv ) += receiverCoeff * ( a1 * vtmp_n + a2 * vtmp_np1 ); + } + else + { + varAtReceivers( iSeismo, ircv ) = receiverCoeff * ( a1 * vtmp_n + a2 * vtmp_np1 ); + } + // NOTE: varAtReceivers has size(1) = numReceiversGlobal + 1, this does not OOB + // left in the forAll loop for sync issues since the following does not depend on `ircv` + varAtReceivers( iSeismo, nReceivers ) = a1 * time_n + a2 * time_np1; + } + } ); + } + + /** + * @brief Compute the seismo traces for 2d arrays + * @param[in] time_n Current time iteration + * @param[in] dt time-step + * @param[in] regionIndex Index of the current region + * @param[in] receiverRegion Array containing the region in which the receiver is located + * @param[in] timeSeismo time when the seismo is computed + * @param[in] iSeismo i-th seismo trace + * @param[in] receiverElem Array containing the element on which the receiver is located + * @param[in] receiverConstants constant part of the receiver term + * @param[in] receiverIsLocal flag indicating whether the receiver is local or not + * @param[in] var_np1 Array containing the variable at time n+1 + * @param[in] var_n Array containing the variable at time n + * @param[out] varAtReceivers Array containing the the variable computed at the receivers + */ + static void compute2dVariableSeismoTrace( real64 const time_n, + real64 const dt, + localIndex const regionIndex, + arrayView1d< localIndex const > const receiverRegion, + real64 const timeSeismo, + localIndex const iSeismo, + arrayView1d< localIndex const > const receiverElem, + arrayView2d< real64 const > const receiverConstants, + arrayView1d< localIndex const > const receiverIsLocal, + arrayView2d< real32 const > const var_np1, + arrayView2d< real32 const > const var_n, + arrayView2d< real32 > varAtReceivers ) + { + real64 const time_np1 = time_n + dt; + + real32 const a1 = dt < epsilonLoc ? 1.0 : (time_np1 - timeSeismo) / dt; + real32 const a2 = 1.0 - a1; + + localIndex const nReceivers = receiverConstants.size( 0 ); + + forAll< EXEC_POLICY >( nReceivers, [=] GEOS_HOST_DEVICE ( localIndex const ircv ) + { + if( receiverIsLocal[ircv] == 1 ) + { + if( receiverRegion[ircv] == regionIndex ) + { + real32 vtmp_np1 = 0.0, vtmp_n = 0.0; + for( localIndex inode = 0; inode < receiverConstants.size( 1 ); ++inode ) + { + vtmp_np1 += var_np1( receiverElem[ircv], inode ) * receiverConstants( ircv, inode ); + vtmp_n += var_n( receiverElem[ircv], inode ) * receiverConstants( ircv, inode ); + } + // linear interpolation between the pressure value at time_n and time_{n+1} + varAtReceivers( iSeismo, ircv ) = a1 * vtmp_n + a2 * vtmp_np1; + // NOTE: varAtReceivers has size(1) = numReceiversGlobal + 1, this does not OOB + // left in the forAll loop for sync issues since the following does not depend on `ircv` + varAtReceivers( iSeismo, nReceivers ) = a1 * time_n + a2 * time_np1; + } + } + } ); + } + + /** + * @brief Check if the source point is inside an element or not + * @param numFacesPerElem number of face on an element + * @param elemCenter array containing the center of the elements + * @param faceNormal array containing the normal of all faces + * @param faceCenter array containing the center of all faces + * @param elemsToFaces map to get the global faces from element index and local face index + * @param coords coordinate of the point + * @return true if coords is inside the element + */ + GEOS_HOST_DEVICE + static bool + locateSourceElement( real64 const numFacesPerElem, + real64 const (&elemCenter)[3], + arrayView2d< real64 const > const faceNormal, + arrayView2d< real64 const > const faceCenter, + arraySlice1d< localIndex const > const elemsToFaces, + real64 const (&coords)[3] ) + { + //Loop over the element faces + real64 tmpVector[3]{}; + for( localIndex kfe = 0; kfe < numFacesPerElem; ++kfe ) + { + + localIndex const iface = elemsToFaces[kfe]; + real64 faceCenterOnFace[3] = {faceCenter[iface][0], + faceCenter[iface][1], + faceCenter[iface][2]}; + real64 faceNormalOnFace[3] = {faceNormal[iface][0], + faceNormal[iface][1], + faceNormal[iface][2]}; + + //Test to make sure if the normal is outwardly directed + LvArray::tensorOps::copy< 3 >( tmpVector, faceCenterOnFace ); + LvArray::tensorOps::subtract< 3 >( tmpVector, elemCenter ); + if( LvArray::tensorOps::AiBi< 3 >( tmpVector, faceNormalOnFace ) < 0.0 ) + { + LvArray::tensorOps::scale< 3 >( faceNormalOnFace, -1 ); + } + + // compute the vector face center to query point + LvArray::tensorOps::subtract< 3 >( faceCenterOnFace, coords ); + localIndex const s = computationalGeometry::sign( LvArray::tensorOps::AiBi< 3 >( faceNormalOnFace, faceCenterOnFace )); + + // all dot products should be non-negative (we enforce outward normals) + if( s < 0 ) return false; + + } + return true; + } + + /** + * @brief Convert a mesh element point coordinate into a coordinate on the reference element + * @tparam FE_TYPE finite element type + * @param[in] coords coordinate of the point + * @param[in] elemsToNodes element to node map for the base mesh + * @param[in] nodeCoords array of base mesh nodes coordinates + * @param[out] coordsOnRefElem to contain the coordinate computed in the reference element + */ + template< typename FE_TYPE > + GEOS_HOST_DEVICE + static void + computeCoordinatesOnReferenceElement( real64 const (&coords)[3], + arraySlice1d< localIndex const, cells::NODE_MAP_USD - 1 > const elemsToNodes, + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const nodeCoords, + real64 (& coordsOnRefElem)[3] ) + { + // only the eight corners of the mesh cell are needed to compute the Jacobian + real64 xLocal[8][3]{}; + for( localIndex a = 0; a < 8; ++a ) + { + LvArray::tensorOps::copy< 3 >( xLocal[a], nodeCoords[ elemsToNodes[ a ] ] ); + } + // coordsOnRefElem = invJ*(coords-coordsNode_0) + real64 invJ[3][3]{}; + FE_TYPE::invJacobianTransformation( 0, xLocal, invJ ); + for( localIndex i = 0; i < 3; ++i ) + { + // init at (-1,-1,-1) as the origin of the referential elem + coordsOnRefElem[i] = -1.0; + for( localIndex j = 0; j < 3; ++j ) + { + coordsOnRefElem[i] += invJ[i][j] * (coords[j] - xLocal[0][j]); + } + } + } + + /** + * @brief Compute dotProduct between two vectors + * @param numFacesPerElem number of face on an element + * @param elemCenter array containing the center of the elements + * @param faceNormal array containing the normal of all faces + * @param faceCenter array containing the center of all faces + * @param elemsToFaces map to get the global faces from element index and local face index + * @param coords coordinate of the point + * @return true if coords is inside the element + */ + + + static void dotProduct( localIndex const size, + arrayView1d< real32 > const & vector1, + arrayView1d< real32 > const & vector2, + real64 & res ) + { + + RAJA::ReduceSum< parallelDeviceReduce, real64 > tmp( 0.0 ); + forAll< EXEC_POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + tmp+= vector1[a]*vector2[a]; + } ); + + res = tmp.get(); + + } + +/** + * @brief Converts the DAS direction from dip/azimuth to a 3D unit vector + * @param[in] dip the dip of the linear DAS + * @param[in] azimuth the azimuth of the linear DAS + * @param[out] a unit vector pointing in the DAS direction + */ + GEOS_HOST_DEVICE + static + R1Tensor computeDASVector( real64 const dip, real64 const azimuth ) + { + real64 cd = cos( dip ); + real64 v1 = cd * cos( azimuth ); + real64 v2 = cd * sin( azimuth ); + real64 v3 = sin( dip ); + R1Tensor dasVector = { v1, v2, v3 }; + return dasVector; + } + +}; + +/// Declare strings associated with enumeration values. +ENUM_STRINGS( WaveSolverUtils::DASType, + "none", + "dipole", + "strainIntegration" ); + +ENUM_STRINGS( WaveSolverUtils::AttenuationType, + "none", + "sls" ); + +} /* namespace geos */ + +#endif /* GEOS_PHYSICSSOLVERS_WAVEPROPAGATION_WAVESOLVERUTILS_HPP_ */ diff --git a/src/coreComponents/schema/CMakeLists.txt b/src/coreComponents/schema/CMakeLists.txt index ccee0a436dd..2a331ee9d69 100644 --- a/src/coreComponents/schema/CMakeLists.txt +++ b/src/coreComponents/schema/CMakeLists.txt @@ -1,4 +1,21 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- +#[[ +Package: schema + +Contains XML schema definition and functions to generate it. +#]] # # Specify all headers @@ -14,13 +31,18 @@ set( schema_sources set( dependencyList ${parallelDeps} dataRepository ) +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) + blt_add_library( NAME schema SOURCES ${schema_sources} HEADERS ${schema_headers} - DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} + DEPENDS_ON ${decoratedDependencies} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} ) target_include_directories( schema PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents) +install( TARGETS schema LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) diff --git a/src/coreComponents/schema/docs/AcousticElasticSEM.rst b/src/coreComponents/schema/docs/AcousticElasticSEM.rst deleted file mode 100644 index 8a99bd42d0f..00000000000 --- a/src/coreComponents/schema/docs/AcousticElasticSEM.rst +++ /dev/null @@ -1,18 +0,0 @@ - - -========================= ================== ======== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ================== ======== ======================================================================================================================================================================================================================================================================================================================== -acousticSolverName groupNameRef required Name of the acoustic solver used by the coupled solver -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -elasticSolverName groupNameRef required Name of the elastic solver used by the coupled solver -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ================== ======== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/AcousticElasticSEM_other.rst b/src/coreComponents/schema/docs/AcousticElasticSEM_other.rst deleted file mode 100644 index 3f1b37c3d6c..00000000000 --- a/src/coreComponents/schema/docs/AcousticElasticSEM_other.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -========================= ============================================================================================================================================================== ================================================================ -Name Type Description -========================= ============================================================================================================================================================== ================================================================ -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ================================================================ - - diff --git a/src/coreComponents/schema/docs/AcousticFirstOrderSEM.rst b/src/coreComponents/schema/docs/AcousticFirstOrderSEM.rst deleted file mode 100644 index 22d9753df98..00000000000 --- a/src/coreComponents/schema/docs/AcousticFirstOrderSEM.rst +++ /dev/null @@ -1,33 +0,0 @@ - - -========================= ============================ ========== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ============================ ========== ======================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -dtSeismoTrace real64 0 Time step for output pressure at receivers -enableLifo integer 0 Set to 1 to enable LIFO storage feature -forward integer 1 Set to 1 to compute forward propagation -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -lifoOnDevice integer -80 Set the capacity of the lifo device storage (if negative, opposite of percentage of remaining memory) -lifoOnHost integer -80 Set the capacity of the lifo host storage (if negative, opposite of percentage of remaining memory) -lifoSize integer 2147483647 Set the capacity of the lifo storage (should be the total number of buffers to store in the LIFO) -linearDASGeometry real64_array2d {{0}} Geometry parameters for a linear DAS fiber (dip, azimuth, gauge length) -linearDASSamples integer 5 Number of sample points to be used for strain integration when integrating the strain for the DAS signal -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -outputSeismoTrace integer 0 Flag that indicates if we write the seismo trace in a file .txt, 0 no output, 1 otherwise -receiverCoordinates real64_array2d {{0}} Coordinates (x,y,z) of the receivers -rickerOrder integer 2 Flag that indicates the order of the Ricker to be used o, 1 or 2. Order 2 by default -saveFields integer 0 Set to 1 to save fields during forward and restore them during backward -shotIndex integer 0 Set the current shot for temporary files -sourceCoordinates real64_array2d {{0}} Coordinates (x,y,z) of the sources -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -timeSourceDelay real32 -1 Source time delay (1 / f0 by default) -timeSourceFrequency real32 0 Central frequency for the time source -useDAS geos_WaveSolverUtils_DASType none Flag to indicate if DAS data will be modeled, and which DAS type to use: 1 for strain integration, 2 for displacement difference -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ============================ ========== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/AcousticFirstOrderSEM_other.rst b/src/coreComponents/schema/docs/AcousticFirstOrderSEM_other.rst deleted file mode 100644 index 955f1c1ca6d..00000000000 --- a/src/coreComponents/schema/docs/AcousticFirstOrderSEM_other.rst +++ /dev/null @@ -1,33 +0,0 @@ - - -========================= ============================================================================================================================================================== ======================================================================= -Name Type Description -========================= ============================================================================================================================================================== ======================================================================= -indexSeismoTrace integer Count for output pressure at receivers -linearDASVectorX real32_array X component of the linear DAS direction vector -linearDASVectorY real32_array Y component of the linear DAS direction vector -linearDASVectorZ real32_array Z component of the linear DAS direction vector -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -pressureNp1AtReceivers real32_array2d Pressure value at each receiver for each timestep -rcvElem integer_array Element containing the receivers -receiverConstants real64_array2d Constant part of the receiver for the nodes listed in m_receiverNodeIds -receiverIsLocal integer_array Flag that indicates whether the receiver is local to this MPI rank -receiverNodeIds integer_array2d Indices of the nodes (in the right order) for each receiver point -receiverRegion integer_array Region containing the receivers -sourceConstants real64_array2d Constant part of the source for the nodes listed in m_sourceNodeIds -sourceElem integer_array Element containing the sources -sourceIsAccessible integer_array Flag that indicates whether the source is local to this MPI rank -sourceNodeIds integer_array2d Indices of the nodes (in the right order) for each source point -sourceRegion integer_array Region containing the sources -sourceValue real32_array2d Source Value of the sources -usePML integer Flag to apply PML -uxNp1AtReceivers real32_array2d Ux value at each receiver for each timestep -uyNp1AtReceivers real32_array2d Uy value at each receiver for each timestep -uzNp1AtReceivers real32_array2d Uz value at each receiver for each timestep -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ======================================================================= - - diff --git a/src/coreComponents/schema/docs/AcousticSEM.rst b/src/coreComponents/schema/docs/AcousticSEM.rst deleted file mode 100644 index 22d9753df98..00000000000 --- a/src/coreComponents/schema/docs/AcousticSEM.rst +++ /dev/null @@ -1,33 +0,0 @@ - - -========================= ============================ ========== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ============================ ========== ======================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -dtSeismoTrace real64 0 Time step for output pressure at receivers -enableLifo integer 0 Set to 1 to enable LIFO storage feature -forward integer 1 Set to 1 to compute forward propagation -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -lifoOnDevice integer -80 Set the capacity of the lifo device storage (if negative, opposite of percentage of remaining memory) -lifoOnHost integer -80 Set the capacity of the lifo host storage (if negative, opposite of percentage of remaining memory) -lifoSize integer 2147483647 Set the capacity of the lifo storage (should be the total number of buffers to store in the LIFO) -linearDASGeometry real64_array2d {{0}} Geometry parameters for a linear DAS fiber (dip, azimuth, gauge length) -linearDASSamples integer 5 Number of sample points to be used for strain integration when integrating the strain for the DAS signal -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -outputSeismoTrace integer 0 Flag that indicates if we write the seismo trace in a file .txt, 0 no output, 1 otherwise -receiverCoordinates real64_array2d {{0}} Coordinates (x,y,z) of the receivers -rickerOrder integer 2 Flag that indicates the order of the Ricker to be used o, 1 or 2. Order 2 by default -saveFields integer 0 Set to 1 to save fields during forward and restore them during backward -shotIndex integer 0 Set the current shot for temporary files -sourceCoordinates real64_array2d {{0}} Coordinates (x,y,z) of the sources -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -timeSourceDelay real32 -1 Source time delay (1 / f0 by default) -timeSourceFrequency real32 0 Central frequency for the time source -useDAS geos_WaveSolverUtils_DASType none Flag to indicate if DAS data will be modeled, and which DAS type to use: 1 for strain integration, 2 for displacement difference -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ============================ ========== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/AcousticSEM_other.rst b/src/coreComponents/schema/docs/AcousticSEM_other.rst deleted file mode 100644 index 280974da35a..00000000000 --- a/src/coreComponents/schema/docs/AcousticSEM_other.rst +++ /dev/null @@ -1,28 +0,0 @@ - - -========================= ============================================================================================================================================================== ======================================================================= -Name Type Description -========================= ============================================================================================================================================================== ======================================================================= -indexSeismoTrace integer Count for output pressure at receivers -linearDASVectorX real32_array X component of the linear DAS direction vector -linearDASVectorY real32_array Y component of the linear DAS direction vector -linearDASVectorZ real32_array Z component of the linear DAS direction vector -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -pressureNp1AtReceivers real32_array2d Pressure value at each receiver for each timestep -rcvElem integer_array Element containing the receivers -receiverConstants real64_array2d Constant part of the receiver for the nodes listed in m_receiverNodeIds -receiverIsLocal integer_array Flag that indicates whether the receiver is local to this MPI rank -receiverNodeIds integer_array2d Indices of the nodes (in the right order) for each receiver point -receiverRegion integer_array Region containing the receivers -sourceConstants real64_array2d Constant part of the source for the nodes listed in m_sourceNodeIds -sourceIsAccessible integer_array Flag that indicates whether the source is local to this MPI rank -sourceNodeIds integer_array2d Indices of the nodes (in the right order) for each source point -sourceValue real32_array2d Source Value of the sources -usePML integer Flag to apply PML -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ======================================================================= - - diff --git a/src/coreComponents/schema/docs/AcousticVTISEM.rst b/src/coreComponents/schema/docs/AcousticVTISEM.rst deleted file mode 100644 index 22d9753df98..00000000000 --- a/src/coreComponents/schema/docs/AcousticVTISEM.rst +++ /dev/null @@ -1,33 +0,0 @@ - - -========================= ============================ ========== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ============================ ========== ======================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -dtSeismoTrace real64 0 Time step for output pressure at receivers -enableLifo integer 0 Set to 1 to enable LIFO storage feature -forward integer 1 Set to 1 to compute forward propagation -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -lifoOnDevice integer -80 Set the capacity of the lifo device storage (if negative, opposite of percentage of remaining memory) -lifoOnHost integer -80 Set the capacity of the lifo host storage (if negative, opposite of percentage of remaining memory) -lifoSize integer 2147483647 Set the capacity of the lifo storage (should be the total number of buffers to store in the LIFO) -linearDASGeometry real64_array2d {{0}} Geometry parameters for a linear DAS fiber (dip, azimuth, gauge length) -linearDASSamples integer 5 Number of sample points to be used for strain integration when integrating the strain for the DAS signal -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -outputSeismoTrace integer 0 Flag that indicates if we write the seismo trace in a file .txt, 0 no output, 1 otherwise -receiverCoordinates real64_array2d {{0}} Coordinates (x,y,z) of the receivers -rickerOrder integer 2 Flag that indicates the order of the Ricker to be used o, 1 or 2. Order 2 by default -saveFields integer 0 Set to 1 to save fields during forward and restore them during backward -shotIndex integer 0 Set the current shot for temporary files -sourceCoordinates real64_array2d {{0}} Coordinates (x,y,z) of the sources -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -timeSourceDelay real32 -1 Source time delay (1 / f0 by default) -timeSourceFrequency real32 0 Central frequency for the time source -useDAS geos_WaveSolverUtils_DASType none Flag to indicate if DAS data will be modeled, and which DAS type to use: 1 for strain integration, 2 for displacement difference -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ============================ ========== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/AcousticVTISEM_other.rst b/src/coreComponents/schema/docs/AcousticVTISEM_other.rst deleted file mode 100644 index 280974da35a..00000000000 --- a/src/coreComponents/schema/docs/AcousticVTISEM_other.rst +++ /dev/null @@ -1,28 +0,0 @@ - - -========================= ============================================================================================================================================================== ======================================================================= -Name Type Description -========================= ============================================================================================================================================================== ======================================================================= -indexSeismoTrace integer Count for output pressure at receivers -linearDASVectorX real32_array X component of the linear DAS direction vector -linearDASVectorY real32_array Y component of the linear DAS direction vector -linearDASVectorZ real32_array Z component of the linear DAS direction vector -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -pressureNp1AtReceivers real32_array2d Pressure value at each receiver for each timestep -rcvElem integer_array Element containing the receivers -receiverConstants real64_array2d Constant part of the receiver for the nodes listed in m_receiverNodeIds -receiverIsLocal integer_array Flag that indicates whether the receiver is local to this MPI rank -receiverNodeIds integer_array2d Indices of the nodes (in the right order) for each receiver point -receiverRegion integer_array Region containing the receivers -sourceConstants real64_array2d Constant part of the source for the nodes listed in m_sourceNodeIds -sourceIsAccessible integer_array Flag that indicates whether the source is local to this MPI rank -sourceNodeIds integer_array2d Indices of the nodes (in the right order) for each source point -sourceValue real32_array2d Source Value of the sources -usePML integer Flag to apply PML -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ======================================================================= - - diff --git a/src/coreComponents/schema/docs/Aquifer.rst b/src/coreComponents/schema/docs/Aquifer.rst deleted file mode 100644 index 20c477d38bc..00000000000 --- a/src/coreComponents/schema/docs/Aquifer.rst +++ /dev/null @@ -1,38 +0,0 @@ - - -================================== ================== ======== ========================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -================================== ================== ======== ========================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================== -allowAllPhasesIntoAquifer integer 0 | Flag to allow all phases to flow into the aquifer. - | This flag only matters for the configuration in which flow is from reservoir to aquifer. - | - If the flag is equal to 1, then all phases, including non-aqueous phases, are allowed to flow into the aquifer. - | - If the flag is equal to 0, then only the water phase is allowed to flow into the aquifer. - | If you are in a configuration in which flow is from reservoir to aquifer and you expect non-aqueous phases to saturate the reservoir cells next to the aquifer, set this flag to 1. - | This keyword is ignored for single-phase flow simulations -aquiferAngle real64 required Angle subtended by the aquifer boundary from the center of the reservoir [degress] -aquiferElevation real64 required Aquifer elevation (positive going upward) [m] -aquiferInitialPressure real64 required Aquifer initial pressure [Pa] -aquiferInnerRadius real64 required Aquifer inner radius [m] -aquiferPermeability real64 required Aquifer permeability [m^2] -aquiferPorosity real64 required Aquifer porosity -aquiferThickness real64 required Aquifer thickness [m] -aquiferTotalCompressibility real64 required Aquifer total compressibility (rock and fluid) [Pa^-1] -aquiferWaterDensity real64 required Aquifer water density [kg.m^-3] -aquiferWaterPhaseComponentFraction real64_array {0} Aquifer water phase component fraction. This keyword is ignored for single-phase flow simulations. -aquiferWaterPhaseComponentNames string_array {} Aquifer water phase component names. This keyword is ignored for single-phase flow simulations. -aquiferWaterViscosity real64 required Aquifer water viscosity [Pa.s] -bcApplicationTableName groupNameRef Name of table that specifies the on/off application of the boundary condition. -beginTime real64 -1e+99 Time at which the boundary condition will start being applied. -direction R1Tensor {0,0,0} Direction to apply boundary condition to. -endTime real64 1e+99 Time at which the boundary condition will stop being applied. -functionName groupNameRef Name of function that specifies variation of the boundary condition. -initialCondition integer 0 Boundary condition is applied as an initial condition. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -pressureInfluenceFunctionName groupNameRef | Name of the table describing the pressure influence function - | . If not provided, we use a default pressure influence function -scale real64 0 Scale factor for value of the boundary condition. -setNames groupNameRef_array required Name of sets that boundary condition is applied to. -================================== ================== ======== ========================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/Aquifer_other.rst b/src/coreComponents/schema/docs/Aquifer_other.rst deleted file mode 100644 index b171b95f04b..00000000000 --- a/src/coreComponents/schema/docs/Aquifer_other.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -============== ============ ============================================================== -Name Type Description -============== ============ ============================================================== -component integer Component of field (if tensor) to apply boundary condition to. -cumulativeFlux real64 (no description available) -fieldName groupNameRef Name of field that boundary condition is applied to. -objectPath groupNameRef Path to the target field -============== ============ ============================================================== - - diff --git a/src/coreComponents/schema/docs/Benchmarks.rst b/src/coreComponents/schema/docs/Benchmarks.rst deleted file mode 100644 index faa738ea57d..00000000000 --- a/src/coreComponents/schema/docs/Benchmarks.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -======= ==== ======= ================== -Name Type Default Description -======= ==== ======= ================== -crusher node unique :ref:`XML_crusher` -lassen node unique :ref:`XML_lassen` -quartz node unique :ref:`XML_quartz` -======= ==== ======= ================== - - diff --git a/src/coreComponents/schema/docs/Benchmarks_other.rst b/src/coreComponents/schema/docs/Benchmarks_other.rst deleted file mode 100644 index daf4c9768fa..00000000000 --- a/src/coreComponents/schema/docs/Benchmarks_other.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -======= ==== ============================ -Name Type Description -======= ==== ============================ -crusher node :ref:`DATASTRUCTURE_crusher` -lassen node :ref:`DATASTRUCTURE_lassen` -quartz node :ref:`DATASTRUCTURE_quartz` -======= ==== ============================ - - diff --git a/src/coreComponents/schema/docs/BiotPorosity.rst b/src/coreComponents/schema/docs/BiotPorosity.rst deleted file mode 100644 index 2bc5c5f2678..00000000000 --- a/src/coreComponents/schema/docs/BiotPorosity.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -======================== ========= ======== =========================================== -Name Type Default Description -======================== ========= ======== =========================================== -defaultPorosityTEC real64 0 Default thermal expansion coefficient -defaultReferencePorosity real64 required Default value of the reference porosity -grainBulkModulus real64 required Grain bulk modulus -name groupName required A name is required for any non-unique nodes -======================== ========= ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/BiotPorosity_other.rst b/src/coreComponents/schema/docs/BiotPorosity_other.rst deleted file mode 100644 index 49c9bd3d373..00000000000 --- a/src/coreComponents/schema/docs/BiotPorosity_other.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -================================= ============== ================================================================================================ -Name Type Description -================================= ============== ================================================================================================ -averageMeanTotalStressIncrement_k real64_array Mean total stress increment averaged over quadrature points at the previous sequential iteration -biotCoefficient real64_array Biot coefficient -dPorosity_dPressure real64_array2d Derivative of rock porosity with respect to pressure -dPorosity_dTemperature real64_array2d Derivative of rock porosity with respect to temperature -initialPorosity real64_array2d Initial porosity -meanTotalStressIncrement_k real64_array2d Mean total stress increment at quadrature points at the previous sequential iteration -porosity real64_array2d Rock porosity -porosity_n real64_array2d Rock porosity at the previous converged time step -referencePorosity real64_array Reference porosity -solidBulkModulus real64_array Solid bulk modulus -thermalExpansionCoefficient real64_array Thermal expansion coefficient -================================= ============== ================================================================================================ - - diff --git a/src/coreComponents/schema/docs/BlackOilFluid.rst b/src/coreComponents/schema/docs/BlackOilFluid.rst deleted file mode 100644 index c34b2d2ec84..00000000000 --- a/src/coreComponents/schema/docs/BlackOilFluid.rst +++ /dev/null @@ -1,25 +0,0 @@ - - -======================================= ================== ======== ===================================================================================================================================================================================================================================================================================================== -Name Type Default Description -======================================= ================== ======== ===================================================================================================================================================================================================================================================================================================== -checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. -componentMolarWeight real64_array required Component molar weights -componentNames string_array {} List of component names -hydrocarbonFormationVolFactorTableNames groupNameRef_array {} | List of formation volume factor TableFunction names from the Functions block. - | The user must provide one TableFunction per hydrocarbon phase, in the order provided in "phaseNames". - | For instance, if "oil" is before "gas" in "phaseNames", the table order should be: oilTableName, gasTableName -hydrocarbonViscosityTableNames groupNameRef_array {} | List of viscosity TableFunction names from the Functions block. - | The user must provide one TableFunction per hydrocarbon phase, in the order provided in "phaseNames". - | For instance, if "oil" is before "gas" in "phaseNames", the table order should be: oilTableName, gasTableName -name groupName required A name is required for any non-unique nodes -phaseNames groupNameRef_array required List of fluid phases -surfaceDensities real64_array required List of surface mass densities for each phase -tableFiles path_array {} List of filenames with input PVT tables (one per phase) -waterCompressibility real64 0 Water compressibility -waterFormationVolumeFactor real64 0 Water formation volume factor -waterReferencePressure real64 0 Water reference pressure -waterViscosity real64 0 Water viscosity -======================================= ================== ======== ===================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/BlackOilFluid_other.rst b/src/coreComponents/schema/docs/BlackOilFluid_other.rst deleted file mode 100644 index 60b6325d615..00000000000 --- a/src/coreComponents/schema/docs/BlackOilFluid_other.rst +++ /dev/null @@ -1,36 +0,0 @@ - - -=============================== ======================================================================================================= ============================================================================================================ -Name Type Description -=============================== ======================================================================================================= ============================================================================================================ -PVTO geos_constitutive_PVTOData (no description available) -dPhaseCompFraction LvArray_Array< double, 5, camp_int_seq< long, 0l, 1l, 2l, 3l, 4l >, int, LvArray_ChaiBuffer > Derivative of phase component fraction with respect to pressure, temperature, and global component fractions -dPhaseDensity real64_array4d Derivative of phase density with respect to pressure, temperature, and global component fractions -dPhaseEnthalpy real64_array4d Derivative of phase enthalpy with respect to pressure, temperature, and global component fractions -dPhaseFraction real64_array4d Derivative of phase fraction with respect to pressure, temperature, and global component fractions -dPhaseInternalEnergy real64_array4d Derivative of phase internal energy with respect to pressure, temperature, and global component fractions -dPhaseMassDensity real64_array4d Derivative of phase mass density with respect to pressure, temperature, and global component fractions -dPhaseViscosity real64_array4d Derivative of phase viscosity with respect to pressure, temperature, and global component fractions -dTotalDensity real64_array3d Derivative of total density with respect to pressure, temperature, and global component fractions -formationVolFactorTableWrappers LvArray_Array< geos_TableFunction_KernelWrapper, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer > (no description available) -hydrocarbonPhaseOrder integer_array (no description available) -phaseCompFraction real64_array4d Phase component fraction -phaseCompFraction_n real64_array4d Phase component fraction at the previous converged time step -phaseDensity real64_array3d Phase density -phaseDensity_n real64_array3d Phase density at the previous converged time step -phaseEnthalpy real64_array3d Phase enthalpy -phaseEnthalpy_n real64_array3d Phase enthalpy at the previous converged time step -phaseFraction real64_array3d Phase fraction -phaseInternalEnergy real64_array3d Phase internal energy -phaseInternalEnergy_n real64_array3d Phase internal energy at the previous converged time step -phaseMassDensity real64_array3d Phase mass density -phaseOrder integer_array (no description available) -phaseTypes integer_array (no description available) -phaseViscosity real64_array3d Phase viscosity -totalDensity real64_array2d Total density -totalDensity_n real64_array2d Total density at the previous converged time step -useMass integer (no description available) -viscosityTableWrappers LvArray_Array< geos_TableFunction_KernelWrapper, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer > (no description available) -=============================== ======================================================================================================= ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/Blueprint.rst b/src/coreComponents/schema/docs/Blueprint.rst deleted file mode 100644 index 13d7114d15c..00000000000 --- a/src/coreComponents/schema/docs/Blueprint.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -======================== ============================= ======== =============================================================== -Name Type Default Description -======================== ============================= ======== =============================================================== -childDirectory string Child directory path -name groupName required A name is required for any non-unique nodes -outputFullQuadratureData integer 0 If true writes out data associated with every quadrature point. -parallelThreads integer 1 Number of plot files. -plotLevel geos_dataRepository_PlotLevel 1 Determines which fields to write. -======================== ============================= ======== =============================================================== - - diff --git a/src/coreComponents/schema/docs/Blueprint_other.rst b/src/coreComponents/schema/docs/Blueprint_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/Blueprint_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/Box.rst b/src/coreComponents/schema/docs/Box.rst deleted file mode 100644 index 02f28e2078b..00000000000 --- a/src/coreComponents/schema/docs/Box.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -====== ========= ======== =========================================== -Name Type Default Description -====== ========= ======== =========================================== -name groupName required A name is required for any non-unique nodes -strike real64 -90 The strike angle of the box -xMax R1Tensor required Maximum (x,y,z) coordinates of the box -xMin R1Tensor required Minimum (x,y,z) coordinates of the box -====== ========= ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/Box_other.rst b/src/coreComponents/schema/docs/Box_other.rst deleted file mode 100644 index b24a032b246..00000000000 --- a/src/coreComponents/schema/docs/Box_other.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -========= ======== ========================== -Name Type Description -========= ======== ========================== -center R1Tensor (no description available) -cosStrike real64 (no description available) -sinStrike real64 (no description available) -========= ======== ========================== - - diff --git a/src/coreComponents/schema/docs/BrooksCoreyBakerRelativePermeability.rst b/src/coreComponents/schema/docs/BrooksCoreyBakerRelativePermeability.rst deleted file mode 100644 index c10a2a48b2f..00000000000 --- a/src/coreComponents/schema/docs/BrooksCoreyBakerRelativePermeability.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -======================= ================== ======== ========================================================================================================================================================== -Name Type Default Description -======================= ================== ======== ========================================================================================================================================================== -gasOilRelPermExponent real64_array {1} | Rel perm power law exponent for the pair (gas phase, oil phase) at residual water saturation - | The expected format is "{ gasExp, oilExp }", in that order -gasOilRelPermMaxValue real64_array {0} | Maximum rel perm value for the pair (gas phase, oil phase) at residual water saturation - | The expected format is "{ gasMax, oilMax }", in that order -name groupName required A name is required for any non-unique nodes -phaseMinVolumeFraction real64_array {0} Minimum volume fraction value for each phase -phaseNames groupNameRef_array required List of fluid phases -waterOilRelPermExponent real64_array {1} | Rel perm power law exponent for the pair (water phase, oil phase) at residual gas saturation - | The expected format is "{ waterExp, oilExp }", in that order -waterOilRelPermMaxValue real64_array {0} | Maximum rel perm value for the pair (water phase, oil phase) at residual gas saturation - | The expected format is "{ waterMax, oilMax }", in that order -======================= ================== ======== ========================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/BrooksCoreyBakerRelativePermeability_other.rst b/src/coreComponents/schema/docs/BrooksCoreyBakerRelativePermeability_other.rst deleted file mode 100644 index e6dd24aeb13..00000000000 --- a/src/coreComponents/schema/docs/BrooksCoreyBakerRelativePermeability_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=============================== ============== ======================================================================================================================= -Name Type Description -=============================== ============== ======================================================================================================================= -dPhaseRelPerm_dPhaseVolFraction real64_array4d Derivative of phase relative permeability with respect to phase volume fraction -phaseOrder integer_array (no description available) -phaseRelPerm real64_array3d Phase relative permeability -phaseRelPerm_n real64_array3d Phase relative permeability at previous time -phaseTrappedVolFraction real64_array3d Phase trapped volume fraction -phaseTypes integer_array (no description available) -volFracScale real64 Factor used to scale the phase capillary pressure, defined as: one minus the sum of the phase minimum volume fractions. -=============================== ============== ======================================================================================================================= - - diff --git a/src/coreComponents/schema/docs/BrooksCoreyCapillaryPressure.rst b/src/coreComponents/schema/docs/BrooksCoreyCapillaryPressure.rst deleted file mode 100644 index 32e8ddad824..00000000000 --- a/src/coreComponents/schema/docs/BrooksCoreyCapillaryPressure.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -=========================== ================== ======== ============================================================================================================================================== -Name Type Default Description -=========================== ================== ======== ============================================================================================================================================== -capPressureEpsilon real64 1e-06 Wetting-phase saturation at which the max cap. pressure is attained; used to avoid infinite cap. pressure values for saturations close to zero -name groupName required A name is required for any non-unique nodes -phaseCapPressureExponentInv real64_array {2} Inverse of capillary power law exponent for each phase -phaseEntryPressure real64_array {1} Entry pressure value for each phase -phaseMinVolumeFraction real64_array {0} Minimum volume fraction value for each phase -phaseNames groupNameRef_array required List of fluid phases -=========================== ================== ======== ============================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/BrooksCoreyCapillaryPressure_other.rst b/src/coreComponents/schema/docs/BrooksCoreyCapillaryPressure_other.rst deleted file mode 100644 index 336528e2f6f..00000000000 --- a/src/coreComponents/schema/docs/BrooksCoreyCapillaryPressure_other.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -=================================== ============== ======================================================================================================================= -Name Type Description -=================================== ============== ======================================================================================================================= -dPhaseCapPressure_dPhaseVolFraction real64_array4d Derivative of phase capillary pressure with respect to phase volume fraction -phaseCapPressure real64_array3d Phase capillary pressure -phaseOrder integer_array (no description available) -phaseTypes integer_array (no description available) -volFracScale real64 Factor used to scale the phase capillary pressure, defined as: one minus the sum of the phase minimum volume fractions. -=================================== ============== ======================================================================================================================= - - diff --git a/src/coreComponents/schema/docs/BrooksCoreyRelativePermeability.rst b/src/coreComponents/schema/docs/BrooksCoreyRelativePermeability.rst deleted file mode 100644 index 675393020c0..00000000000 --- a/src/coreComponents/schema/docs/BrooksCoreyRelativePermeability.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -====================== ================== ======== =============================================================== -Name Type Default Description -====================== ================== ======== =============================================================== -name groupName required A name is required for any non-unique nodes -phaseMinVolumeFraction real64_array {0} Minimum volume fraction value for each phase -phaseNames groupNameRef_array required List of fluid phases -phaseRelPermExponent real64_array {1} Minimum relative permeability power law exponent for each phase -phaseRelPermMaxValue real64_array {0} Maximum relative permeability value for each phase -====================== ================== ======== =============================================================== - - diff --git a/src/coreComponents/schema/docs/BrooksCoreyRelativePermeability_other.rst b/src/coreComponents/schema/docs/BrooksCoreyRelativePermeability_other.rst deleted file mode 100644 index d77ac5b3557..00000000000 --- a/src/coreComponents/schema/docs/BrooksCoreyRelativePermeability_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=============================== ============== ========================================================================================================================== -Name Type Description -=============================== ============== ========================================================================================================================== -dPhaseRelPerm_dPhaseVolFraction real64_array4d Derivative of phase relative permeability with respect to phase volume fraction -phaseOrder integer_array (no description available) -phaseRelPerm real64_array3d Phase relative permeability -phaseRelPerm_n real64_array3d Phase relative permeability at previous time -phaseTrappedVolFraction real64_array3d Phase trapped volume fraction -phaseTypes integer_array (no description available) -volFracScale real64 Factor used to scale the phase relative permeability, defined as: one minus the sum of the phase minimum volume fractions. -=============================== ============== ========================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/BrooksCoreyStone2RelativePermeability.rst b/src/coreComponents/schema/docs/BrooksCoreyStone2RelativePermeability.rst deleted file mode 100644 index c10a2a48b2f..00000000000 --- a/src/coreComponents/schema/docs/BrooksCoreyStone2RelativePermeability.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -======================= ================== ======== ========================================================================================================================================================== -Name Type Default Description -======================= ================== ======== ========================================================================================================================================================== -gasOilRelPermExponent real64_array {1} | Rel perm power law exponent for the pair (gas phase, oil phase) at residual water saturation - | The expected format is "{ gasExp, oilExp }", in that order -gasOilRelPermMaxValue real64_array {0} | Maximum rel perm value for the pair (gas phase, oil phase) at residual water saturation - | The expected format is "{ gasMax, oilMax }", in that order -name groupName required A name is required for any non-unique nodes -phaseMinVolumeFraction real64_array {0} Minimum volume fraction value for each phase -phaseNames groupNameRef_array required List of fluid phases -waterOilRelPermExponent real64_array {1} | Rel perm power law exponent for the pair (water phase, oil phase) at residual gas saturation - | The expected format is "{ waterExp, oilExp }", in that order -waterOilRelPermMaxValue real64_array {0} | Maximum rel perm value for the pair (water phase, oil phase) at residual gas saturation - | The expected format is "{ waterMax, oilMax }", in that order -======================= ================== ======== ========================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/BrooksCoreyStone2RelativePermeability_other.rst b/src/coreComponents/schema/docs/BrooksCoreyStone2RelativePermeability_other.rst deleted file mode 100644 index e6dd24aeb13..00000000000 --- a/src/coreComponents/schema/docs/BrooksCoreyStone2RelativePermeability_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=============================== ============== ======================================================================================================================= -Name Type Description -=============================== ============== ======================================================================================================================= -dPhaseRelPerm_dPhaseVolFraction real64_array4d Derivative of phase relative permeability with respect to phase volume fraction -phaseOrder integer_array (no description available) -phaseRelPerm real64_array3d Phase relative permeability -phaseRelPerm_n real64_array3d Phase relative permeability at previous time -phaseTrappedVolFraction real64_array3d Phase trapped volume fraction -phaseTypes integer_array (no description available) -volFracScale real64 Factor used to scale the phase capillary pressure, defined as: one minus the sum of the phase minimum volume fractions. -=============================== ============== ======================================================================================================================= - - diff --git a/src/coreComponents/schema/docs/CO2BrineEzrokhiFluid.rst b/src/coreComponents/schema/docs/CO2BrineEzrokhiFluid.rst deleted file mode 100644 index 8d5cb05986a..00000000000 --- a/src/coreComponents/schema/docs/CO2BrineEzrokhiFluid.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -==================== ================== ======== ============================================================================================================ -Name Type Default Description -==================== ================== ======== ============================================================================================================ -checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. -componentMolarWeight real64_array {0} Component molar weights -componentNames string_array {} List of component names -flashModelParaFile path Name of the file defining the parameters of the flash model -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -phaseNames groupNameRef_array {} List of fluid phases -phasePVTParaFiles path_array required Names of the files defining the parameters of the viscosity and density models -solubilityTableNames string_array {} Names of solubility tables for each phase -==================== ================== ======== ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/CO2BrineEzrokhiFluid_other.rst b/src/coreComponents/schema/docs/CO2BrineEzrokhiFluid_other.rst deleted file mode 100644 index 476b50195e5..00000000000 --- a/src/coreComponents/schema/docs/CO2BrineEzrokhiFluid_other.rst +++ /dev/null @@ -1,30 +0,0 @@ - - -===================== ============================================================================================= ============================================================================================================ -Name Type Description -===================== ============================================================================================= ============================================================================================================ -dPhaseCompFraction LvArray_Array< double, 5, camp_int_seq< long, 0l, 1l, 2l, 3l, 4l >, int, LvArray_ChaiBuffer > Derivative of phase component fraction with respect to pressure, temperature, and global component fractions -dPhaseDensity real64_array4d Derivative of phase density with respect to pressure, temperature, and global component fractions -dPhaseEnthalpy real64_array4d Derivative of phase enthalpy with respect to pressure, temperature, and global component fractions -dPhaseFraction real64_array4d Derivative of phase fraction with respect to pressure, temperature, and global component fractions -dPhaseInternalEnergy real64_array4d Derivative of phase internal energy with respect to pressure, temperature, and global component fractions -dPhaseMassDensity real64_array4d Derivative of phase mass density with respect to pressure, temperature, and global component fractions -dPhaseViscosity real64_array4d Derivative of phase viscosity with respect to pressure, temperature, and global component fractions -dTotalDensity real64_array3d Derivative of total density with respect to pressure, temperature, and global component fractions -phaseCompFraction real64_array4d Phase component fraction -phaseCompFraction_n real64_array4d Phase component fraction at the previous converged time step -phaseDensity real64_array3d Phase density -phaseDensity_n real64_array3d Phase density at the previous converged time step -phaseEnthalpy real64_array3d Phase enthalpy -phaseEnthalpy_n real64_array3d Phase enthalpy at the previous converged time step -phaseFraction real64_array3d Phase fraction -phaseInternalEnergy real64_array3d Phase internal energy -phaseInternalEnergy_n real64_array3d Phase internal energy at the previous converged time step -phaseMassDensity real64_array3d Phase mass density -phaseViscosity real64_array3d Phase viscosity -totalDensity real64_array2d Total density -totalDensity_n real64_array2d Total density at the previous converged time step -useMass integer (no description available) -===================== ============================================================================================= ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/CO2BrineEzrokhiThermalFluid.rst b/src/coreComponents/schema/docs/CO2BrineEzrokhiThermalFluid.rst deleted file mode 100644 index 8d5cb05986a..00000000000 --- a/src/coreComponents/schema/docs/CO2BrineEzrokhiThermalFluid.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -==================== ================== ======== ============================================================================================================ -Name Type Default Description -==================== ================== ======== ============================================================================================================ -checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. -componentMolarWeight real64_array {0} Component molar weights -componentNames string_array {} List of component names -flashModelParaFile path Name of the file defining the parameters of the flash model -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -phaseNames groupNameRef_array {} List of fluid phases -phasePVTParaFiles path_array required Names of the files defining the parameters of the viscosity and density models -solubilityTableNames string_array {} Names of solubility tables for each phase -==================== ================== ======== ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/CO2BrineEzrokhiThermalFluid_other.rst b/src/coreComponents/schema/docs/CO2BrineEzrokhiThermalFluid_other.rst deleted file mode 100644 index 476b50195e5..00000000000 --- a/src/coreComponents/schema/docs/CO2BrineEzrokhiThermalFluid_other.rst +++ /dev/null @@ -1,30 +0,0 @@ - - -===================== ============================================================================================= ============================================================================================================ -Name Type Description -===================== ============================================================================================= ============================================================================================================ -dPhaseCompFraction LvArray_Array< double, 5, camp_int_seq< long, 0l, 1l, 2l, 3l, 4l >, int, LvArray_ChaiBuffer > Derivative of phase component fraction with respect to pressure, temperature, and global component fractions -dPhaseDensity real64_array4d Derivative of phase density with respect to pressure, temperature, and global component fractions -dPhaseEnthalpy real64_array4d Derivative of phase enthalpy with respect to pressure, temperature, and global component fractions -dPhaseFraction real64_array4d Derivative of phase fraction with respect to pressure, temperature, and global component fractions -dPhaseInternalEnergy real64_array4d Derivative of phase internal energy with respect to pressure, temperature, and global component fractions -dPhaseMassDensity real64_array4d Derivative of phase mass density with respect to pressure, temperature, and global component fractions -dPhaseViscosity real64_array4d Derivative of phase viscosity with respect to pressure, temperature, and global component fractions -dTotalDensity real64_array3d Derivative of total density with respect to pressure, temperature, and global component fractions -phaseCompFraction real64_array4d Phase component fraction -phaseCompFraction_n real64_array4d Phase component fraction at the previous converged time step -phaseDensity real64_array3d Phase density -phaseDensity_n real64_array3d Phase density at the previous converged time step -phaseEnthalpy real64_array3d Phase enthalpy -phaseEnthalpy_n real64_array3d Phase enthalpy at the previous converged time step -phaseFraction real64_array3d Phase fraction -phaseInternalEnergy real64_array3d Phase internal energy -phaseInternalEnergy_n real64_array3d Phase internal energy at the previous converged time step -phaseMassDensity real64_array3d Phase mass density -phaseViscosity real64_array3d Phase viscosity -totalDensity real64_array2d Total density -totalDensity_n real64_array2d Total density at the previous converged time step -useMass integer (no description available) -===================== ============================================================================================= ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/CO2BrinePhillipsFluid.rst b/src/coreComponents/schema/docs/CO2BrinePhillipsFluid.rst deleted file mode 100644 index 8d5cb05986a..00000000000 --- a/src/coreComponents/schema/docs/CO2BrinePhillipsFluid.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -==================== ================== ======== ============================================================================================================ -Name Type Default Description -==================== ================== ======== ============================================================================================================ -checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. -componentMolarWeight real64_array {0} Component molar weights -componentNames string_array {} List of component names -flashModelParaFile path Name of the file defining the parameters of the flash model -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -phaseNames groupNameRef_array {} List of fluid phases -phasePVTParaFiles path_array required Names of the files defining the parameters of the viscosity and density models -solubilityTableNames string_array {} Names of solubility tables for each phase -==================== ================== ======== ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/CO2BrinePhillipsFluid_other.rst b/src/coreComponents/schema/docs/CO2BrinePhillipsFluid_other.rst deleted file mode 100644 index 476b50195e5..00000000000 --- a/src/coreComponents/schema/docs/CO2BrinePhillipsFluid_other.rst +++ /dev/null @@ -1,30 +0,0 @@ - - -===================== ============================================================================================= ============================================================================================================ -Name Type Description -===================== ============================================================================================= ============================================================================================================ -dPhaseCompFraction LvArray_Array< double, 5, camp_int_seq< long, 0l, 1l, 2l, 3l, 4l >, int, LvArray_ChaiBuffer > Derivative of phase component fraction with respect to pressure, temperature, and global component fractions -dPhaseDensity real64_array4d Derivative of phase density with respect to pressure, temperature, and global component fractions -dPhaseEnthalpy real64_array4d Derivative of phase enthalpy with respect to pressure, temperature, and global component fractions -dPhaseFraction real64_array4d Derivative of phase fraction with respect to pressure, temperature, and global component fractions -dPhaseInternalEnergy real64_array4d Derivative of phase internal energy with respect to pressure, temperature, and global component fractions -dPhaseMassDensity real64_array4d Derivative of phase mass density with respect to pressure, temperature, and global component fractions -dPhaseViscosity real64_array4d Derivative of phase viscosity with respect to pressure, temperature, and global component fractions -dTotalDensity real64_array3d Derivative of total density with respect to pressure, temperature, and global component fractions -phaseCompFraction real64_array4d Phase component fraction -phaseCompFraction_n real64_array4d Phase component fraction at the previous converged time step -phaseDensity real64_array3d Phase density -phaseDensity_n real64_array3d Phase density at the previous converged time step -phaseEnthalpy real64_array3d Phase enthalpy -phaseEnthalpy_n real64_array3d Phase enthalpy at the previous converged time step -phaseFraction real64_array3d Phase fraction -phaseInternalEnergy real64_array3d Phase internal energy -phaseInternalEnergy_n real64_array3d Phase internal energy at the previous converged time step -phaseMassDensity real64_array3d Phase mass density -phaseViscosity real64_array3d Phase viscosity -totalDensity real64_array2d Total density -totalDensity_n real64_array2d Total density at the previous converged time step -useMass integer (no description available) -===================== ============================================================================================= ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/CO2BrinePhillipsThermalFluid.rst b/src/coreComponents/schema/docs/CO2BrinePhillipsThermalFluid.rst deleted file mode 100644 index 8d5cb05986a..00000000000 --- a/src/coreComponents/schema/docs/CO2BrinePhillipsThermalFluid.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -==================== ================== ======== ============================================================================================================ -Name Type Default Description -==================== ================== ======== ============================================================================================================ -checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. -componentMolarWeight real64_array {0} Component molar weights -componentNames string_array {} List of component names -flashModelParaFile path Name of the file defining the parameters of the flash model -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -phaseNames groupNameRef_array {} List of fluid phases -phasePVTParaFiles path_array required Names of the files defining the parameters of the viscosity and density models -solubilityTableNames string_array {} Names of solubility tables for each phase -==================== ================== ======== ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/CO2BrinePhillipsThermalFluid_other.rst b/src/coreComponents/schema/docs/CO2BrinePhillipsThermalFluid_other.rst deleted file mode 100644 index 476b50195e5..00000000000 --- a/src/coreComponents/schema/docs/CO2BrinePhillipsThermalFluid_other.rst +++ /dev/null @@ -1,30 +0,0 @@ - - -===================== ============================================================================================= ============================================================================================================ -Name Type Description -===================== ============================================================================================= ============================================================================================================ -dPhaseCompFraction LvArray_Array< double, 5, camp_int_seq< long, 0l, 1l, 2l, 3l, 4l >, int, LvArray_ChaiBuffer > Derivative of phase component fraction with respect to pressure, temperature, and global component fractions -dPhaseDensity real64_array4d Derivative of phase density with respect to pressure, temperature, and global component fractions -dPhaseEnthalpy real64_array4d Derivative of phase enthalpy with respect to pressure, temperature, and global component fractions -dPhaseFraction real64_array4d Derivative of phase fraction with respect to pressure, temperature, and global component fractions -dPhaseInternalEnergy real64_array4d Derivative of phase internal energy with respect to pressure, temperature, and global component fractions -dPhaseMassDensity real64_array4d Derivative of phase mass density with respect to pressure, temperature, and global component fractions -dPhaseViscosity real64_array4d Derivative of phase viscosity with respect to pressure, temperature, and global component fractions -dTotalDensity real64_array3d Derivative of total density with respect to pressure, temperature, and global component fractions -phaseCompFraction real64_array4d Phase component fraction -phaseCompFraction_n real64_array4d Phase component fraction at the previous converged time step -phaseDensity real64_array3d Phase density -phaseDensity_n real64_array3d Phase density at the previous converged time step -phaseEnthalpy real64_array3d Phase enthalpy -phaseEnthalpy_n real64_array3d Phase enthalpy at the previous converged time step -phaseFraction real64_array3d Phase fraction -phaseInternalEnergy real64_array3d Phase internal energy -phaseInternalEnergy_n real64_array3d Phase internal energy at the previous converged time step -phaseMassDensity real64_array3d Phase mass density -phaseViscosity real64_array3d Phase viscosity -totalDensity real64_array2d Total density -totalDensity_n real64_array2d Total density at the previous converged time step -useMass integer (no description available) -===================== ============================================================================================= ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/CarmanKozenyPermeability.rst b/src/coreComponents/schema/docs/CarmanKozenyPermeability.rst deleted file mode 100644 index 5bda6c4bfbc..00000000000 --- a/src/coreComponents/schema/docs/CarmanKozenyPermeability.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -================ ========= ======== ===================================================== -Name Type Default Description -================ ========= ======== ===================================================== -anisotropy R1Tensor {1,1,1} Anisotropy factors for three permeability components. -name groupName required A name is required for any non-unique nodes -particleDiameter real64 required Diameter of the spherical particles. -sphericity real64 required Sphericity of the particles. -================ ========= ======== ===================================================== - - diff --git a/src/coreComponents/schema/docs/CarmanKozenyPermeability_other.rst b/src/coreComponents/schema/docs/CarmanKozenyPermeability_other.rst deleted file mode 100644 index 3e91e0e04e9..00000000000 --- a/src/coreComponents/schema/docs/CarmanKozenyPermeability_other.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -=============== ============== ======================================================== -Name Type Description -=============== ============== ======================================================== -dPerm_dPorosity real64_array3d (no description available) -dPerm_dPressure real64_array3d Derivative of rock permeability with respect to pressure -permeability real64_array3d Rock permeability -=============== ============== ======================================================== - - diff --git a/src/coreComponents/schema/docs/CellElementRegion.rst b/src/coreComponents/schema/docs/CellElementRegion.rst deleted file mode 100644 index 7c773016b98..00000000000 --- a/src/coreComponents/schema/docs/CellElementRegion.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -=============== ================== ======== =========================================== -Name Type Default Description -=============== ================== ======== =========================================== -cellBlocks groupNameRef_array required (no description available) -coarseningRatio real64 0 (no description available) -materialList groupNameRef_array required List of materials present in this region -meshBody groupNameRef Mesh body that contains this region -name groupName required A name is required for any non-unique nodes -=============== ================== ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/CellElementRegion_other.rst b/src/coreComponents/schema/docs/CellElementRegion_other.rst deleted file mode 100644 index a65968b0105..00000000000 --- a/src/coreComponents/schema/docs/CellElementRegion_other.rst +++ /dev/null @@ -1,16 +0,0 @@ - - -======================= ==================================================================== ========================================================= -Name Type Description -======================= ==================================================================== ========================================================= -domainBoundaryIndicator integer_array (no description available) -ghostRank integer_array (no description available) -globalToLocalMap geos_mapBase< long long, int, std_integral_constant< bool, false > > (no description available) -isExternal integer_array (no description available) -localToGlobalMap globalIndex_array Array that contains a map from localIndex to globalIndex. -elementSubRegions node :ref:`DATASTRUCTURE_elementSubRegions` -neighborData node :ref:`DATASTRUCTURE_neighborData` -sets node :ref:`DATASTRUCTURE_sets` -======================= ==================================================================== ========================================================= - - diff --git a/src/coreComponents/schema/docs/CeramicDamage.rst b/src/coreComponents/schema/docs/CeramicDamage.rst deleted file mode 100644 index fa671dd48bc..00000000000 --- a/src/coreComponents/schema/docs/CeramicDamage.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -======================= ========= ======== ==================================================================== -Name Type Default Description -======================= ========= ======== ==================================================================== -compressiveStrength real64 required Compressive strength -crackSpeed real64 required Crack speed -defaultBulkModulus real64 -1 Default Bulk Modulus Parameter -defaultDensity real64 required Default Material Density -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultPoissonRatio real64 -1 Default Poisson's Ratio -defaultShearModulus real64 -1 Default Shear Modulus Parameter -defaultYoungModulus real64 -1 Default Young's Modulus -maximumStrength real64 required Maximum theoretical strength -name groupName required A name is required for any non-unique nodes -tensileStrength real64 required Tensile strength -======================= ========= ======== ==================================================================== - - diff --git a/src/coreComponents/schema/docs/CeramicDamage_other.rst b/src/coreComponents/schema/docs/CeramicDamage_other.rst deleted file mode 100644 index 4614da5bcc8..00000000000 --- a/src/coreComponents/schema/docs/CeramicDamage_other.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -bulkModulus real64_array Elastic Bulk Modulus Field -damage real64_array2d Array of quadrature point damage values -density real64_array2d Material Density -jacobian real64_array2d Array of quadrature point jacobian values -lengthScale real64_array Array of quadrature point damage values -oldStress real64_array3d Previous Material Stress -shearModulus real64_array Elastic Shear Modulus Field -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/ChomboIO.rst b/src/coreComponents/schema/docs/ChomboIO.rst deleted file mode 100644 index 300787a76c2..00000000000 --- a/src/coreComponents/schema/docs/ChomboIO.rst +++ /dev/null @@ -1,16 +0,0 @@ - - -================== ========= =================== =============================================================================================== -Name Type Default Description -================== ========= =================== =============================================================================================== -beginCycle real64 required Cycle at which the coupling will commence. -childDirectory string Child directory path -inputPath string /INVALID_INPUT_PATH Path at which the chombo to geosx file will be written. -name groupName required A name is required for any non-unique nodes -outputPath string required Path at which the geosx to chombo file will be written. -parallelThreads integer 1 Number of plot files. -useChomboPressures integer 0 True iff geosx should use the pressures chombo writes out. -waitForInput integer required True iff geosx should wait for chombo to write out a file. When true the inputPath must be set. -================== ========= =================== =============================================================================================== - - diff --git a/src/coreComponents/schema/docs/ChomboIO_other.rst b/src/coreComponents/schema/docs/ChomboIO_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/ChomboIO_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/CompositeFunction.rst b/src/coreComponents/schema/docs/CompositeFunction.rst deleted file mode 100644 index 81bfb601d57..00000000000 --- a/src/coreComponents/schema/docs/CompositeFunction.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============= ================== ======== ========================================================================== -Name Type Default Description -============= ================== ======== ========================================================================== -expression string Composite math expression -functionNames string_array {} List of source functions. The order must match the variableNames argument. -inputVarNames groupNameRef_array {} Name of fields are input to function. -name groupName required A name is required for any non-unique nodes -variableNames groupNameRef_array {} List of variables in expression -============= ================== ======== ========================================================================== - - diff --git a/src/coreComponents/schema/docs/CompositeFunction_other.rst b/src/coreComponents/schema/docs/CompositeFunction_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/CompositeFunction_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseFVM.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseFVM.rst deleted file mode 100644 index 7202cd18e81..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseFVM.rst +++ /dev/null @@ -1,45 +0,0 @@ - - -========================================= =========================================== ======== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================================= =========================================== ======== ======================================================================================================================================================================================================================================================================================================================== -allowLocalCompDensityChopping integer 1 Flag indicating whether local (cell-wise) chopping of negative compositions is allowed -allowNegativePressure integer 1 Flag indicating if negative pressure is allowed -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -contMultiplierDBC real64 0.5 Factor by which continuation parameter is changed every newton when DBC is used -continuationDBC integer 1 Flag for enabling continuation parameter -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isThermal integer 0 Flag indicating whether the problem is thermal or not. -kappaminDBC real64 1e-20 Factor that controls how much dissipation is kept in the system when continuation is used -logLevel integer 0 Log level -maxAbsolutePressureChange real64 -1 Maximum (absolute) pressure change in a Newton iteration -maxCompFractionChange real64 0.5 Maximum (absolute) change in a component fraction in a Newton iteration -maxRelativePressureChange real64 0.5 Maximum (relative) change in pressure in a Newton iteration -maxRelativeTemperatureChange real64 0.5 Maximum (relative) change in temperature in a Newton iteration -maxSequentialCompDensChange real64 1 Maximum (absolute) component density change in a sequential iteration, used for outer loop convergence check -maxSequentialPressureChange real64 100000 Maximum (absolute) pressure change in a sequential iteration, used for outer loop convergence check -maxSequentialTemperatureChange real64 0.1 Maximum (absolute) temperature change in a sequential iteration, used for outer loop convergence check -minCompDens real64 1e-10 Minimum allowed global component density -miscibleDBC integer 0 Flag for enabling DBC formulation with/without miscibility -name groupName required A name is required for any non-unique nodes -omegaDBC real64 1 Factor by which DBC flux is multiplied -scalingType geos_CompositionalMultiphaseFVM_ScalingType Global | Solution scaling type.Valid options: - | * Global - | * Local -solutionChangeScalingFactor real64 0.5 Damping factor for solution change targets -targetFlowCFL real64 -1 Target CFL condition `CFL condition `_when computing the next timestep. -targetPhaseVolFractionChangeInTimeStep real64 0.2 Target (absolute) change in phase volume fraction in a time step -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -targetRelativePressureChangeInTimeStep real64 0.2 Target (relative) change in pressure in a time step (expected value between 0 and 1) -targetRelativeTemperatureChangeInTimeStep real64 0.2 Target (relative) change in temperature in a time step (expected value between 0 and 1) -temperature real64 required Temperature -useDBC integer 0 Enable Dissipation-based continuation flux -useMass integer 0 Use mass formulation instead of molar -useSimpleAccumulation integer 1 Flag indicating whether simple accumulation form is used -useTotalMassEquation integer 1 Flag indicating whether total mass equation is used -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================================= =========================================== ======== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseFVM_other.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseFVM_other.rst deleted file mode 100644 index 3f1b37c3d6c..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseFVM_other.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -========================= ============================================================================================================================================================== ================================================================ -Name Type Description -========================= ============================================================================================================================================================== ================================================================ -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ================================================================ - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseFluid.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseFluid.rst deleted file mode 100644 index c9db4e7d190..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseFluid.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -============================ ================== ======== ============================================================================================================ -Name Type Default Description -============================ ================== ======== ============================================================================================================ -checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. -componentAcentricFactor real64_array required Component acentric factors -componentBinaryCoeff real64_array2d {{0}} Table of binary interaction coefficients -componentCriticalPressure real64_array required Component critical pressures -componentCriticalTemperature real64_array required Component critical temperatures -componentMolarWeight real64_array required Component molar weights -componentNames string_array required List of component names -componentVolumeShift real64_array {0} Component volume shifts -equationsOfState string_array required List of equation of state types for each phase -name groupName required A name is required for any non-unique nodes -phaseNames groupNameRef_array required List of fluid phases -============================ ================== ======== ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseFluid_other.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseFluid_other.rst deleted file mode 100644 index 476b50195e5..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseFluid_other.rst +++ /dev/null @@ -1,30 +0,0 @@ - - -===================== ============================================================================================= ============================================================================================================ -Name Type Description -===================== ============================================================================================= ============================================================================================================ -dPhaseCompFraction LvArray_Array< double, 5, camp_int_seq< long, 0l, 1l, 2l, 3l, 4l >, int, LvArray_ChaiBuffer > Derivative of phase component fraction with respect to pressure, temperature, and global component fractions -dPhaseDensity real64_array4d Derivative of phase density with respect to pressure, temperature, and global component fractions -dPhaseEnthalpy real64_array4d Derivative of phase enthalpy with respect to pressure, temperature, and global component fractions -dPhaseFraction real64_array4d Derivative of phase fraction with respect to pressure, temperature, and global component fractions -dPhaseInternalEnergy real64_array4d Derivative of phase internal energy with respect to pressure, temperature, and global component fractions -dPhaseMassDensity real64_array4d Derivative of phase mass density with respect to pressure, temperature, and global component fractions -dPhaseViscosity real64_array4d Derivative of phase viscosity with respect to pressure, temperature, and global component fractions -dTotalDensity real64_array3d Derivative of total density with respect to pressure, temperature, and global component fractions -phaseCompFraction real64_array4d Phase component fraction -phaseCompFraction_n real64_array4d Phase component fraction at the previous converged time step -phaseDensity real64_array3d Phase density -phaseDensity_n real64_array3d Phase density at the previous converged time step -phaseEnthalpy real64_array3d Phase enthalpy -phaseEnthalpy_n real64_array3d Phase enthalpy at the previous converged time step -phaseFraction real64_array3d Phase fraction -phaseInternalEnergy real64_array3d Phase internal energy -phaseInternalEnergy_n real64_array3d Phase internal energy at the previous converged time step -phaseMassDensity real64_array3d Phase mass density -phaseViscosity real64_array3d Phase viscosity -totalDensity real64_array2d Total density -totalDensity_n real64_array2d Total density at the previous converged time step -useMass integer (no description available) -===================== ============================================================================================= ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseHybridFVM.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseHybridFVM.rst deleted file mode 100644 index 4cdd10dd766..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseHybridFVM.rst +++ /dev/null @@ -1,36 +0,0 @@ - - -========================================= ================== ======== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================================= ================== ======== ======================================================================================================================================================================================================================================================================================================================== -allowLocalCompDensityChopping integer 1 Flag indicating whether local (cell-wise) chopping of negative compositions is allowed -allowNegativePressure integer 1 Flag indicating if negative pressure is allowed -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isThermal integer 0 Flag indicating whether the problem is thermal or not. -logLevel integer 0 Log level -maxAbsolutePressureChange real64 -1 Maximum (absolute) pressure change in a Newton iteration -maxCompFractionChange real64 0.5 Maximum (absolute) change in a component fraction in a Newton iteration -maxRelativePressureChange real64 0.5 Maximum (relative) change in pressure in a Newton iteration -maxRelativeTemperatureChange real64 0.5 Maximum (relative) change in temperature in a Newton iteration -maxSequentialCompDensChange real64 1 Maximum (absolute) component density change in a sequential iteration, used for outer loop convergence check -maxSequentialPressureChange real64 100000 Maximum (absolute) pressure change in a sequential iteration, used for outer loop convergence check -maxSequentialTemperatureChange real64 0.1 Maximum (absolute) temperature change in a sequential iteration, used for outer loop convergence check -minCompDens real64 1e-10 Minimum allowed global component density -name groupName required A name is required for any non-unique nodes -solutionChangeScalingFactor real64 0.5 Damping factor for solution change targets -targetFlowCFL real64 -1 Target CFL condition `CFL condition `_when computing the next timestep. -targetPhaseVolFractionChangeInTimeStep real64 0.2 Target (absolute) change in phase volume fraction in a time step -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -targetRelativePressureChangeInTimeStep real64 0.2 Target (relative) change in pressure in a time step (expected value between 0 and 1) -targetRelativeTemperatureChangeInTimeStep real64 0.2 Target (relative) change in temperature in a time step (expected value between 0 and 1) -temperature real64 required Temperature -useMass integer 0 Use mass formulation instead of molar -useSimpleAccumulation integer 1 Flag indicating whether simple accumulation form is used -useTotalMassEquation integer 1 Flag indicating whether total mass equation is used -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================================= ================== ======== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseHybridFVM_other.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseHybridFVM_other.rst deleted file mode 100644 index c69ff8f4e38..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseHybridFVM_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -========================= ============================================================================================================================================================== ================================ ================================================================ -Name Type Registered On Description -========================= ============================================================================================================================================================== ================================ ================================================================ -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -facePressure_n real64_array :ref:`DATASTRUCTURE_faceManager` Face pressure at the previous converged time step -mimGravityCoefficient real64_array :ref:`DATASTRUCTURE_faceManager` Mimetic gravity coefficient -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ================================ ================================================================ - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseReservoir.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseReservoir.rst deleted file mode 100644 index f25a13fb960..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseReservoir.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -flowSolverName groupNameRef required Name of the flow solver used by the coupled solver -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -wellSolverName groupNameRef required Name of the well solver used by the coupled solver -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanics.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanics.rst deleted file mode 100644 index c85eff65ff8..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanics.rst +++ /dev/null @@ -1,24 +0,0 @@ - - -=========================== ==================================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -=========================== ==================================== ======== ====================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isThermal integer 0 Flag indicating whether the problem is thermal or not. Set isThermal="1" to enable the thermal coupling -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -reservoirAndWellsSolverName groupNameRef required Name of the reservoirAndWells solver used by the coupled solver -solidSolverName groupNameRef required Name of the solid solver used by the coupled solver -stabilizationMultiplier real64 1 Constant multiplier of stabilization strength. -stabilizationRegionNames groupNameRef_array {} Regions where stabilization is applied. -stabilizationType geos_stabilization_StabilizationType None | Stabilization type. Options are: - | None - Add no stabilization to mass equation, - | Global - Add stabilization to all faces, - | Local - Add stabilization only to interiors of macro elements. -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -=========================== ==================================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanicsInitialization.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanicsInitialization.rst deleted file mode 100644 index 27129634c0b..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanicsInitialization.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -=========================== ============ ======== ========================================================================== -Name Type Default Description -=========================== ============ ======== ========================================================================== -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -performStressInitialization integer required Flag to indicate that the solver is going to perform stress initialization -poromechanicsSolverName groupNameRef required Name of the poromechanics solver -=========================== ============ ======== ========================================================================== - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanicsInitialization_other.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanicsInitialization_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanicsInitialization_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanics_other.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanics_other.rst deleted file mode 100644 index 80b71ab722d..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanics_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -performStressInitialization integer Flag to indicate that the solver is going to perform stress initialization -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseReservoir_other.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseReservoir_other.rst deleted file mode 100644 index 45d9a187f0a..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseReservoir_other.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseStatistics.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseStatistics.rst deleted file mode 100644 index 4a386d1d1c3..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseStatistics.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -======================= ============ ======== =============================================================================================================================================================== -Name Type Default Description -======================= ============ ======== =============================================================================================================================================================== -computeCFLNumbers integer 0 Flag to decide whether CFL numbers are computed or not -computeRegionStatistics integer 1 Flag to decide whether region statistics are computed or not -flowSolverName groupNameRef required Name of the flow solver -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -relpermThreshold real64 1e-06 Flag to decide whether a phase is considered mobile (when the relperm is above the threshold) or immobile (when the relperm is below the threshold) in metric 2 -writeCSV integer 0 Write statistics into a CSV file -======================= ============ ======== =============================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseStatistics_other.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseStatistics_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseStatistics_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseWell.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseWell.rst deleted file mode 100644 index b072785ff00..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseWell.rst +++ /dev/null @@ -1,22 +0,0 @@ - - -============================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -============================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -allowLocalCompDensityChopping integer 1 Flag indicating whether local (cell-wise) chopping of negative compositions is allowed -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -maxAbsolutePressureChange real64 -1 Maximum (absolute) pressure change in a Newton iteration -maxCompFractionChange real64 1 Maximum (absolute) change in a component fraction between two Newton iterations -maxRelativePressureChange real64 1 Maximum (relative) change in pressure between two Newton iterations (recommended with rate control) -name groupName required A name is required for any non-unique nodes -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -useMass integer 0 Use total mass equation -writeCSV integer 0 Write rates into a CSV file -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -WellControls node :ref:`XML_WellControls` -============================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseWell_other.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseWell_other.rst deleted file mode 100644 index 3f16a155d2b..00000000000 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseWell_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -WellControls node :ref:`DATASTRUCTURE_WellControls` -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/CompositonalTwoPhaseFluidPengRobinson.rst b/src/coreComponents/schema/docs/CompositonalTwoPhaseFluidPengRobinson.rst deleted file mode 100644 index cf67a8118c4..00000000000 --- a/src/coreComponents/schema/docs/CompositonalTwoPhaseFluidPengRobinson.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -============================ ================== ======== ============================================================================================================ -Name Type Default Description -============================ ================== ======== ============================================================================================================ -checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. -componentAcentricFactor real64_array required Component acentric factors -componentBinaryCoeff real64_array2d {{0}} Table of binary interaction coefficients -componentCriticalPressure real64_array required Component critical pressures -componentCriticalTemperature real64_array required Component critical temperatures -componentCriticalVolume real64_array {0} Component critical volumnes -componentMolarWeight real64_array required Component molar weights -componentNames string_array required List of component names -componentVolumeShift real64_array {0} Component volume shifts -name groupName required A name is required for any non-unique nodes -phaseNames groupNameRef_array required List of fluid phases -============================ ================== ======== ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/CompositonalTwoPhaseFluidPengRobinson_other.rst b/src/coreComponents/schema/docs/CompositonalTwoPhaseFluidPengRobinson_other.rst deleted file mode 100644 index 476b50195e5..00000000000 --- a/src/coreComponents/schema/docs/CompositonalTwoPhaseFluidPengRobinson_other.rst +++ /dev/null @@ -1,30 +0,0 @@ - - -===================== ============================================================================================= ============================================================================================================ -Name Type Description -===================== ============================================================================================= ============================================================================================================ -dPhaseCompFraction LvArray_Array< double, 5, camp_int_seq< long, 0l, 1l, 2l, 3l, 4l >, int, LvArray_ChaiBuffer > Derivative of phase component fraction with respect to pressure, temperature, and global component fractions -dPhaseDensity real64_array4d Derivative of phase density with respect to pressure, temperature, and global component fractions -dPhaseEnthalpy real64_array4d Derivative of phase enthalpy with respect to pressure, temperature, and global component fractions -dPhaseFraction real64_array4d Derivative of phase fraction with respect to pressure, temperature, and global component fractions -dPhaseInternalEnergy real64_array4d Derivative of phase internal energy with respect to pressure, temperature, and global component fractions -dPhaseMassDensity real64_array4d Derivative of phase mass density with respect to pressure, temperature, and global component fractions -dPhaseViscosity real64_array4d Derivative of phase viscosity with respect to pressure, temperature, and global component fractions -dTotalDensity real64_array3d Derivative of total density with respect to pressure, temperature, and global component fractions -phaseCompFraction real64_array4d Phase component fraction -phaseCompFraction_n real64_array4d Phase component fraction at the previous converged time step -phaseDensity real64_array3d Phase density -phaseDensity_n real64_array3d Phase density at the previous converged time step -phaseEnthalpy real64_array3d Phase enthalpy -phaseEnthalpy_n real64_array3d Phase enthalpy at the previous converged time step -phaseFraction real64_array3d Phase fraction -phaseInternalEnergy real64_array3d Phase internal energy -phaseInternalEnergy_n real64_array3d Phase internal energy at the previous converged time step -phaseMassDensity real64_array3d Phase mass density -phaseViscosity real64_array3d Phase viscosity -totalDensity real64_array2d Total density -totalDensity_n real64_array2d Total density at the previous converged time step -useMass integer (no description available) -===================== ============================================================================================= ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/CompositonalTwoPhaseFluidSoaveRedlichKwong.rst b/src/coreComponents/schema/docs/CompositonalTwoPhaseFluidSoaveRedlichKwong.rst deleted file mode 100644 index cf67a8118c4..00000000000 --- a/src/coreComponents/schema/docs/CompositonalTwoPhaseFluidSoaveRedlichKwong.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -============================ ================== ======== ============================================================================================================ -Name Type Default Description -============================ ================== ======== ============================================================================================================ -checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. -componentAcentricFactor real64_array required Component acentric factors -componentBinaryCoeff real64_array2d {{0}} Table of binary interaction coefficients -componentCriticalPressure real64_array required Component critical pressures -componentCriticalTemperature real64_array required Component critical temperatures -componentCriticalVolume real64_array {0} Component critical volumnes -componentMolarWeight real64_array required Component molar weights -componentNames string_array required List of component names -componentVolumeShift real64_array {0} Component volume shifts -name groupName required A name is required for any non-unique nodes -phaseNames groupNameRef_array required List of fluid phases -============================ ================== ======== ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/CompositonalTwoPhaseFluidSoaveRedlichKwong_other.rst b/src/coreComponents/schema/docs/CompositonalTwoPhaseFluidSoaveRedlichKwong_other.rst deleted file mode 100644 index 476b50195e5..00000000000 --- a/src/coreComponents/schema/docs/CompositonalTwoPhaseFluidSoaveRedlichKwong_other.rst +++ /dev/null @@ -1,30 +0,0 @@ - - -===================== ============================================================================================= ============================================================================================================ -Name Type Description -===================== ============================================================================================= ============================================================================================================ -dPhaseCompFraction LvArray_Array< double, 5, camp_int_seq< long, 0l, 1l, 2l, 3l, 4l >, int, LvArray_ChaiBuffer > Derivative of phase component fraction with respect to pressure, temperature, and global component fractions -dPhaseDensity real64_array4d Derivative of phase density with respect to pressure, temperature, and global component fractions -dPhaseEnthalpy real64_array4d Derivative of phase enthalpy with respect to pressure, temperature, and global component fractions -dPhaseFraction real64_array4d Derivative of phase fraction with respect to pressure, temperature, and global component fractions -dPhaseInternalEnergy real64_array4d Derivative of phase internal energy with respect to pressure, temperature, and global component fractions -dPhaseMassDensity real64_array4d Derivative of phase mass density with respect to pressure, temperature, and global component fractions -dPhaseViscosity real64_array4d Derivative of phase viscosity with respect to pressure, temperature, and global component fractions -dTotalDensity real64_array3d Derivative of total density with respect to pressure, temperature, and global component fractions -phaseCompFraction real64_array4d Phase component fraction -phaseCompFraction_n real64_array4d Phase component fraction at the previous converged time step -phaseDensity real64_array3d Phase density -phaseDensity_n real64_array3d Phase density at the previous converged time step -phaseEnthalpy real64_array3d Phase enthalpy -phaseEnthalpy_n real64_array3d Phase enthalpy at the previous converged time step -phaseFraction real64_array3d Phase fraction -phaseInternalEnergy real64_array3d Phase internal energy -phaseInternalEnergy_n real64_array3d Phase internal energy at the previous converged time step -phaseMassDensity real64_array3d Phase mass density -phaseViscosity real64_array3d Phase viscosity -totalDensity real64_array2d Total density -totalDensity_n real64_array2d Total density at the previous converged time step -useMass integer (no description available) -===================== ============================================================================================= ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/CompressibleSinglePhaseFluid.rst b/src/coreComponents/schema/docs/CompressibleSinglePhaseFluid.rst deleted file mode 100644 index bdba4fedb0b..00000000000 --- a/src/coreComponents/schema/docs/CompressibleSinglePhaseFluid.rst +++ /dev/null @@ -1,24 +0,0 @@ - - -================== =========================================== ======== ============================================================================= -Name Type Default Description -================== =========================================== ======== ============================================================================= -compressibility real64 0 Fluid compressibility -defaultDensity real64 required Default value for density. -defaultViscosity real64 required Default value for viscosity. -densityModelType geos_constitutive_ExponentApproximationType linear | Type of density model. Valid options: - | * exponential - | * linear - | * quadratic -name groupName required A name is required for any non-unique nodes -referenceDensity real64 1000 Reference fluid density -referencePressure real64 0 Reference pressure -referenceViscosity real64 0.001 Reference fluid viscosity -viscosibility real64 0 Fluid viscosity exponential coefficient -viscosityModelType geos_constitutive_ExponentApproximationType linear | Type of viscosity model. Valid options: - | * exponential - | * linear - | * quadratic -================== =========================================== ======== ============================================================================= - - diff --git a/src/coreComponents/schema/docs/CompressibleSinglePhaseFluid_other.rst b/src/coreComponents/schema/docs/CompressibleSinglePhaseFluid_other.rst deleted file mode 100644 index 53255e66ebc..00000000000 --- a/src/coreComponents/schema/docs/CompressibleSinglePhaseFluid_other.rst +++ /dev/null @@ -1,22 +0,0 @@ - - -============================ ============== ========================================================= -Name Type Description -============================ ============== ========================================================= -dDensity_dPressure real64_array2d Derivative of density with respect to pressure -dDensity_dTemperature real64_array2d Derivative of density with respect to temperature -dEnthalpy_dPressure real64_array2d Derivative of enthalpy with respect to pressure -dEnthalpy_dTemperature real64_array2d Derivative of enthalpy with respect to temperature -dInternalEnergy_dPressure real64_array2d Derivative of internal energy with respect to pressure -dInternalEnergy_dTemperature real64_array2d Derivative of internal energy with respect to temperature -dViscosity_dPressure real64_array2d Derivative of viscosity with respect to pressure -dViscosity_dTemperature real64_array2d Derivative of viscosity with respect to temperature -density real64_array2d Density -density_n real64_array2d Density at the previous converged time step -enthalpy real64_array2d Enthalpy -internalEnergy real64_array2d Internal energy -internalEnergy_n real64_array2d Fluid internal energy at the previous converged step -viscosity real64_array2d Viscosity -============================ ============== ========================================================= - - diff --git a/src/coreComponents/schema/docs/CompressibleSolidCarmanKozenyPermeability.rst b/src/coreComponents/schema/docs/CompressibleSolidCarmanKozenyPermeability.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/CompressibleSolidCarmanKozenyPermeability.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/CompressibleSolidCarmanKozenyPermeability_other.rst b/src/coreComponents/schema/docs/CompressibleSolidCarmanKozenyPermeability_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/CompressibleSolidCarmanKozenyPermeability_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/CompressibleSolidConstantPermeability.rst b/src/coreComponents/schema/docs/CompressibleSolidConstantPermeability.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/CompressibleSolidConstantPermeability.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/CompressibleSolidConstantPermeability_other.rst b/src/coreComponents/schema/docs/CompressibleSolidConstantPermeability_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/CompressibleSolidConstantPermeability_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/CompressibleSolidExponentialDecayPermeability.rst b/src/coreComponents/schema/docs/CompressibleSolidExponentialDecayPermeability.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/CompressibleSolidExponentialDecayPermeability.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/CompressibleSolidExponentialDecayPermeability_other.rst b/src/coreComponents/schema/docs/CompressibleSolidExponentialDecayPermeability_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/CompressibleSolidExponentialDecayPermeability_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/CompressibleSolidParallelPlatesPermeability.rst b/src/coreComponents/schema/docs/CompressibleSolidParallelPlatesPermeability.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/CompressibleSolidParallelPlatesPermeability.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/CompressibleSolidParallelPlatesPermeability_other.rst b/src/coreComponents/schema/docs/CompressibleSolidParallelPlatesPermeability_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/CompressibleSolidParallelPlatesPermeability_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/CompressibleSolidSlipDependentPermeability.rst b/src/coreComponents/schema/docs/CompressibleSolidSlipDependentPermeability.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/CompressibleSolidSlipDependentPermeability.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/CompressibleSolidSlipDependentPermeability_other.rst b/src/coreComponents/schema/docs/CompressibleSolidSlipDependentPermeability_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/CompressibleSolidSlipDependentPermeability_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/CompressibleSolidWillisRichardsPermeability.rst b/src/coreComponents/schema/docs/CompressibleSolidWillisRichardsPermeability.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/CompressibleSolidWillisRichardsPermeability.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/CompressibleSolidWillisRichardsPermeability_other.rst b/src/coreComponents/schema/docs/CompressibleSolidWillisRichardsPermeability_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/CompressibleSolidWillisRichardsPermeability_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/ConstantDiffusion.rst b/src/coreComponents/schema/docs/ConstantDiffusion.rst deleted file mode 100644 index 4b1d8180c32..00000000000 --- a/src/coreComponents/schema/docs/ConstantDiffusion.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -================================== ============ ======== ========================================================= -Name Type Default Description -================================== ============ ======== ========================================================= -defaultPhaseDiffusivityMultipliers real64_array {1} List of phase diffusivity multipliers -diffusivityComponents real64_array required xx, yy, and zz components of a diffusivity tensor [m^2/s] -name groupName required A name is required for any non-unique nodes -phaseNames string_array required List of fluid phases -================================== ============ ======== ========================================================= - - diff --git a/src/coreComponents/schema/docs/ConstantDiffusion_other.rst b/src/coreComponents/schema/docs/ConstantDiffusion_other.rst deleted file mode 100644 index 1879103f909..00000000000 --- a/src/coreComponents/schema/docs/ConstantDiffusion_other.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -========================== ============== ====================================================== -Name Type Description -========================== ============== ====================================================== -dDiffusivity_dTemperature real64_array3d Derivatives of diffusivity with respect to temperature -diffusivity real64_array3d Diffusivity -phaseDiffusivityMultiplier real64_array3d Phase multipliers for the diffusivity coefficients -========================== ============== ====================================================== - - diff --git a/src/coreComponents/schema/docs/ConstantPermeability.rst b/src/coreComponents/schema/docs/ConstantPermeability.rst deleted file mode 100644 index dc2314ec8db..00000000000 --- a/src/coreComponents/schema/docs/ConstantPermeability.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -====================== ========= ======== =========================================================== -Name Type Default Description -====================== ========= ======== =========================================================== -name groupName required A name is required for any non-unique nodes -permeabilityComponents R1Tensor required xx, yy and zz components of a diagonal permeability tensor. -====================== ========= ======== =========================================================== - - diff --git a/src/coreComponents/schema/docs/ConstantPermeability_other.rst b/src/coreComponents/schema/docs/ConstantPermeability_other.rst deleted file mode 100644 index fa997a57413..00000000000 --- a/src/coreComponents/schema/docs/ConstantPermeability_other.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -=============== ============== ======================================================== -Name Type Description -=============== ============== ======================================================== -dPerm_dPressure real64_array3d Derivative of rock permeability with respect to pressure -permeability real64_array3d Rock permeability -=============== ============== ======================================================== - - diff --git a/src/coreComponents/schema/docs/Constitutive.rst b/src/coreComponents/schema/docs/Constitutive.rst deleted file mode 100644 index f0a48fcf31f..00000000000 --- a/src/coreComponents/schema/docs/Constitutive.rst +++ /dev/null @@ -1,90 +0,0 @@ - - -============================================= ==== ======= ======================================================== -Name Type Default Description -============================================= ==== ======= ======================================================== -BiotPorosity node :ref:`XML_BiotPorosity` -BlackOilFluid node :ref:`XML_BlackOilFluid` -BrooksCoreyBakerRelativePermeability node :ref:`XML_BrooksCoreyBakerRelativePermeability` -BrooksCoreyCapillaryPressure node :ref:`XML_BrooksCoreyCapillaryPressure` -BrooksCoreyRelativePermeability node :ref:`XML_BrooksCoreyRelativePermeability` -BrooksCoreyStone2RelativePermeability node :ref:`XML_BrooksCoreyStone2RelativePermeability` -CO2BrineEzrokhiFluid node :ref:`XML_CO2BrineEzrokhiFluid` -CO2BrineEzrokhiThermalFluid node :ref:`XML_CO2BrineEzrokhiThermalFluid` -CO2BrinePhillipsFluid node :ref:`XML_CO2BrinePhillipsFluid` -CO2BrinePhillipsThermalFluid node :ref:`XML_CO2BrinePhillipsThermalFluid` -CarmanKozenyPermeability node :ref:`XML_CarmanKozenyPermeability` -CeramicDamage node :ref:`XML_CeramicDamage` -CompositionalMultiphaseFluid node :ref:`XML_CompositionalMultiphaseFluid` -CompositonalTwoPhaseFluidPengRobinson node :ref:`XML_CompositonalTwoPhaseFluidPengRobinson` -CompositonalTwoPhaseFluidSoaveRedlichKwong node :ref:`XML_CompositonalTwoPhaseFluidSoaveRedlichKwong` -CompressibleSinglePhaseFluid node :ref:`XML_CompressibleSinglePhaseFluid` -CompressibleSolidCarmanKozenyPermeability node :ref:`XML_CompressibleSolidCarmanKozenyPermeability` -CompressibleSolidConstantPermeability node :ref:`XML_CompressibleSolidConstantPermeability` -CompressibleSolidExponentialDecayPermeability node :ref:`XML_CompressibleSolidExponentialDecayPermeability` -CompressibleSolidParallelPlatesPermeability node :ref:`XML_CompressibleSolidParallelPlatesPermeability` -CompressibleSolidSlipDependentPermeability node :ref:`XML_CompressibleSolidSlipDependentPermeability` -CompressibleSolidWillisRichardsPermeability node :ref:`XML_CompressibleSolidWillisRichardsPermeability` -ConstantDiffusion node :ref:`XML_ConstantDiffusion` -ConstantPermeability node :ref:`XML_ConstantPermeability` -Coulomb node :ref:`XML_Coulomb` -DamageElasticIsotropic node :ref:`XML_DamageElasticIsotropic` -DamageSpectralElasticIsotropic node :ref:`XML_DamageSpectralElasticIsotropic` -DamageVolDevElasticIsotropic node :ref:`XML_DamageVolDevElasticIsotropic` -DeadOilFluid node :ref:`XML_DeadOilFluid` -DelftEgg node :ref:`XML_DelftEgg` -DruckerPrager node :ref:`XML_DruckerPrager` -ElasticIsotropic node :ref:`XML_ElasticIsotropic` -ElasticIsotropicPressureDependent node :ref:`XML_ElasticIsotropicPressureDependent` -ElasticOrthotropic node :ref:`XML_ElasticOrthotropic` -ElasticTransverseIsotropic node :ref:`XML_ElasticTransverseIsotropic` -ExponentialDecayPermeability node :ref:`XML_ExponentialDecayPermeability` -ExtendedDruckerPrager node :ref:`XML_ExtendedDruckerPrager` -FrictionlessContact node :ref:`XML_FrictionlessContact` -JFunctionCapillaryPressure node :ref:`XML_JFunctionCapillaryPressure` -LinearIsotropicDispersion node :ref:`XML_LinearIsotropicDispersion` -ModifiedCamClay node :ref:`XML_ModifiedCamClay` -MultiPhaseConstantThermalConductivity node :ref:`XML_MultiPhaseConstantThermalConductivity` -MultiPhaseVolumeWeightedThermalConductivity node :ref:`XML_MultiPhaseVolumeWeightedThermalConductivity` -NullModel node :ref:`XML_NullModel` -ParallelPlatesPermeability node :ref:`XML_ParallelPlatesPermeability` -ParticleFluid node :ref:`XML_ParticleFluid` -PerfectlyPlastic node :ref:`XML_PerfectlyPlastic` -PermeabilityBase node :ref:`XML_PermeabilityBase` -PorousDamageElasticIsotropic node :ref:`XML_PorousDamageElasticIsotropic` -PorousDamageSpectralElasticIsotropic node :ref:`XML_PorousDamageSpectralElasticIsotropic` -PorousDamageVolDevElasticIsotropic node :ref:`XML_PorousDamageVolDevElasticIsotropic` -PorousDelftEgg node :ref:`XML_PorousDelftEgg` -PorousDruckerPrager node :ref:`XML_PorousDruckerPrager` -PorousElasticIsotropic node :ref:`XML_PorousElasticIsotropic` -PorousElasticOrthotropic node :ref:`XML_PorousElasticOrthotropic` -PorousElasticTransverseIsotropic node :ref:`XML_PorousElasticTransverseIsotropic` -PorousExtendedDruckerPrager node :ref:`XML_PorousExtendedDruckerPrager` -PorousModifiedCamClay node :ref:`XML_PorousModifiedCamClay` -PorousViscoDruckerPrager node :ref:`XML_PorousViscoDruckerPrager` -PorousViscoExtendedDruckerPrager node :ref:`XML_PorousViscoExtendedDruckerPrager` -PorousViscoModifiedCamClay node :ref:`XML_PorousViscoModifiedCamClay` -PressurePorosity node :ref:`XML_PressurePorosity` -ProppantPermeability node :ref:`XML_ProppantPermeability` -ProppantPorosity node :ref:`XML_ProppantPorosity` -ProppantSlurryFluid node :ref:`XML_ProppantSlurryFluid` -ProppantSolidProppantPermeability node :ref:`XML_ProppantSolidProppantPermeability` -ReactiveBrine node :ref:`XML_ReactiveBrine` -ReactiveBrineThermal node :ref:`XML_ReactiveBrineThermal` -SinglePhaseConstantThermalConductivity node :ref:`XML_SinglePhaseConstantThermalConductivity` -SlipDependentPermeability node :ref:`XML_SlipDependentPermeability` -SolidInternalEnergy node :ref:`XML_SolidInternalEnergy` -TableCapillaryPressure node :ref:`XML_TableCapillaryPressure` -TableRelativePermeability node :ref:`XML_TableRelativePermeability` -TableRelativePermeabilityHysteresis node :ref:`XML_TableRelativePermeabilityHysteresis` -ThermalCompressibleSinglePhaseFluid node :ref:`XML_ThermalCompressibleSinglePhaseFluid` -VanGenuchtenBakerRelativePermeability node :ref:`XML_VanGenuchtenBakerRelativePermeability` -VanGenuchtenCapillaryPressure node :ref:`XML_VanGenuchtenCapillaryPressure` -VanGenuchtenStone2RelativePermeability node :ref:`XML_VanGenuchtenStone2RelativePermeability` -ViscoDruckerPrager node :ref:`XML_ViscoDruckerPrager` -ViscoExtendedDruckerPrager node :ref:`XML_ViscoExtendedDruckerPrager` -ViscoModifiedCamClay node :ref:`XML_ViscoModifiedCamClay` -WillisRichardsPermeability node :ref:`XML_WillisRichardsPermeability` -============================================= ==== ======= ======================================================== - - diff --git a/src/coreComponents/schema/docs/ConstitutiveModels_other.rst b/src/coreComponents/schema/docs/ConstitutiveModels_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/ConstitutiveModels_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/Constitutive_other.rst b/src/coreComponents/schema/docs/Constitutive_other.rst deleted file mode 100644 index 9ce0f20a901..00000000000 --- a/src/coreComponents/schema/docs/Constitutive_other.rst +++ /dev/null @@ -1,90 +0,0 @@ - - -============================================= ==== ================================================================== -Name Type Description -============================================= ==== ================================================================== -BiotPorosity node :ref:`DATASTRUCTURE_BiotPorosity` -BlackOilFluid node :ref:`DATASTRUCTURE_BlackOilFluid` -BrooksCoreyBakerRelativePermeability node :ref:`DATASTRUCTURE_BrooksCoreyBakerRelativePermeability` -BrooksCoreyCapillaryPressure node :ref:`DATASTRUCTURE_BrooksCoreyCapillaryPressure` -BrooksCoreyRelativePermeability node :ref:`DATASTRUCTURE_BrooksCoreyRelativePermeability` -BrooksCoreyStone2RelativePermeability node :ref:`DATASTRUCTURE_BrooksCoreyStone2RelativePermeability` -CO2BrineEzrokhiFluid node :ref:`DATASTRUCTURE_CO2BrineEzrokhiFluid` -CO2BrineEzrokhiThermalFluid node :ref:`DATASTRUCTURE_CO2BrineEzrokhiThermalFluid` -CO2BrinePhillipsFluid node :ref:`DATASTRUCTURE_CO2BrinePhillipsFluid` -CO2BrinePhillipsThermalFluid node :ref:`DATASTRUCTURE_CO2BrinePhillipsThermalFluid` -CarmanKozenyPermeability node :ref:`DATASTRUCTURE_CarmanKozenyPermeability` -CeramicDamage node :ref:`DATASTRUCTURE_CeramicDamage` -CompositionalMultiphaseFluid node :ref:`DATASTRUCTURE_CompositionalMultiphaseFluid` -CompositonalTwoPhaseFluidPengRobinson node :ref:`DATASTRUCTURE_CompositonalTwoPhaseFluidPengRobinson` -CompositonalTwoPhaseFluidSoaveRedlichKwong node :ref:`DATASTRUCTURE_CompositonalTwoPhaseFluidSoaveRedlichKwong` -CompressibleSinglePhaseFluid node :ref:`DATASTRUCTURE_CompressibleSinglePhaseFluid` -CompressibleSolidCarmanKozenyPermeability node :ref:`DATASTRUCTURE_CompressibleSolidCarmanKozenyPermeability` -CompressibleSolidConstantPermeability node :ref:`DATASTRUCTURE_CompressibleSolidConstantPermeability` -CompressibleSolidExponentialDecayPermeability node :ref:`DATASTRUCTURE_CompressibleSolidExponentialDecayPermeability` -CompressibleSolidParallelPlatesPermeability node :ref:`DATASTRUCTURE_CompressibleSolidParallelPlatesPermeability` -CompressibleSolidSlipDependentPermeability node :ref:`DATASTRUCTURE_CompressibleSolidSlipDependentPermeability` -CompressibleSolidWillisRichardsPermeability node :ref:`DATASTRUCTURE_CompressibleSolidWillisRichardsPermeability` -ConstantDiffusion node :ref:`DATASTRUCTURE_ConstantDiffusion` -ConstantPermeability node :ref:`DATASTRUCTURE_ConstantPermeability` -Coulomb node :ref:`DATASTRUCTURE_Coulomb` -DamageElasticIsotropic node :ref:`DATASTRUCTURE_DamageElasticIsotropic` -DamageSpectralElasticIsotropic node :ref:`DATASTRUCTURE_DamageSpectralElasticIsotropic` -DamageVolDevElasticIsotropic node :ref:`DATASTRUCTURE_DamageVolDevElasticIsotropic` -DeadOilFluid node :ref:`DATASTRUCTURE_DeadOilFluid` -DelftEgg node :ref:`DATASTRUCTURE_DelftEgg` -DruckerPrager node :ref:`DATASTRUCTURE_DruckerPrager` -ElasticIsotropic node :ref:`DATASTRUCTURE_ElasticIsotropic` -ElasticIsotropicPressureDependent node :ref:`DATASTRUCTURE_ElasticIsotropicPressureDependent` -ElasticOrthotropic node :ref:`DATASTRUCTURE_ElasticOrthotropic` -ElasticTransverseIsotropic node :ref:`DATASTRUCTURE_ElasticTransverseIsotropic` -ExponentialDecayPermeability node :ref:`DATASTRUCTURE_ExponentialDecayPermeability` -ExtendedDruckerPrager node :ref:`DATASTRUCTURE_ExtendedDruckerPrager` -FrictionlessContact node :ref:`DATASTRUCTURE_FrictionlessContact` -JFunctionCapillaryPressure node :ref:`DATASTRUCTURE_JFunctionCapillaryPressure` -LinearIsotropicDispersion node :ref:`DATASTRUCTURE_LinearIsotropicDispersion` -ModifiedCamClay node :ref:`DATASTRUCTURE_ModifiedCamClay` -MultiPhaseConstantThermalConductivity node :ref:`DATASTRUCTURE_MultiPhaseConstantThermalConductivity` -MultiPhaseVolumeWeightedThermalConductivity node :ref:`DATASTRUCTURE_MultiPhaseVolumeWeightedThermalConductivity` -NullModel node :ref:`DATASTRUCTURE_NullModel` -ParallelPlatesPermeability node :ref:`DATASTRUCTURE_ParallelPlatesPermeability` -ParticleFluid node :ref:`DATASTRUCTURE_ParticleFluid` -PerfectlyPlastic node :ref:`DATASTRUCTURE_PerfectlyPlastic` -PermeabilityBase node :ref:`DATASTRUCTURE_PermeabilityBase` -PorousDamageElasticIsotropic node :ref:`DATASTRUCTURE_PorousDamageElasticIsotropic` -PorousDamageSpectralElasticIsotropic node :ref:`DATASTRUCTURE_PorousDamageSpectralElasticIsotropic` -PorousDamageVolDevElasticIsotropic node :ref:`DATASTRUCTURE_PorousDamageVolDevElasticIsotropic` -PorousDelftEgg node :ref:`DATASTRUCTURE_PorousDelftEgg` -PorousDruckerPrager node :ref:`DATASTRUCTURE_PorousDruckerPrager` -PorousElasticIsotropic node :ref:`DATASTRUCTURE_PorousElasticIsotropic` -PorousElasticOrthotropic node :ref:`DATASTRUCTURE_PorousElasticOrthotropic` -PorousElasticTransverseIsotropic node :ref:`DATASTRUCTURE_PorousElasticTransverseIsotropic` -PorousExtendedDruckerPrager node :ref:`DATASTRUCTURE_PorousExtendedDruckerPrager` -PorousModifiedCamClay node :ref:`DATASTRUCTURE_PorousModifiedCamClay` -PorousViscoDruckerPrager node :ref:`DATASTRUCTURE_PorousViscoDruckerPrager` -PorousViscoExtendedDruckerPrager node :ref:`DATASTRUCTURE_PorousViscoExtendedDruckerPrager` -PorousViscoModifiedCamClay node :ref:`DATASTRUCTURE_PorousViscoModifiedCamClay` -PressurePorosity node :ref:`DATASTRUCTURE_PressurePorosity` -ProppantPermeability node :ref:`DATASTRUCTURE_ProppantPermeability` -ProppantPorosity node :ref:`DATASTRUCTURE_ProppantPorosity` -ProppantSlurryFluid node :ref:`DATASTRUCTURE_ProppantSlurryFluid` -ProppantSolidProppantPermeability node :ref:`DATASTRUCTURE_ProppantSolidProppantPermeability` -ReactiveBrine node :ref:`DATASTRUCTURE_ReactiveBrine` -ReactiveBrineThermal node :ref:`DATASTRUCTURE_ReactiveBrineThermal` -SinglePhaseConstantThermalConductivity node :ref:`DATASTRUCTURE_SinglePhaseConstantThermalConductivity` -SlipDependentPermeability node :ref:`DATASTRUCTURE_SlipDependentPermeability` -SolidInternalEnergy node :ref:`DATASTRUCTURE_SolidInternalEnergy` -TableCapillaryPressure node :ref:`DATASTRUCTURE_TableCapillaryPressure` -TableRelativePermeability node :ref:`DATASTRUCTURE_TableRelativePermeability` -TableRelativePermeabilityHysteresis node :ref:`DATASTRUCTURE_TableRelativePermeabilityHysteresis` -ThermalCompressibleSinglePhaseFluid node :ref:`DATASTRUCTURE_ThermalCompressibleSinglePhaseFluid` -VanGenuchtenBakerRelativePermeability node :ref:`DATASTRUCTURE_VanGenuchtenBakerRelativePermeability` -VanGenuchtenCapillaryPressure node :ref:`DATASTRUCTURE_VanGenuchtenCapillaryPressure` -VanGenuchtenStone2RelativePermeability node :ref:`DATASTRUCTURE_VanGenuchtenStone2RelativePermeability` -ViscoDruckerPrager node :ref:`DATASTRUCTURE_ViscoDruckerPrager` -ViscoExtendedDruckerPrager node :ref:`DATASTRUCTURE_ViscoExtendedDruckerPrager` -ViscoModifiedCamClay node :ref:`DATASTRUCTURE_ViscoModifiedCamClay` -WillisRichardsPermeability node :ref:`DATASTRUCTURE_WillisRichardsPermeability` -============================================= ==== ================================================================== - - diff --git a/src/coreComponents/schema/docs/Coulomb.rst b/src/coreComponents/schema/docs/Coulomb.rst deleted file mode 100644 index 7b1a581e860..00000000000 --- a/src/coreComponents/schema/docs/Coulomb.rst +++ /dev/null @@ -1,16 +0,0 @@ - - -========================= ============ =========== ============================================================================================================================================================================================================================================================================================================================================================================================================================================================= -Name Type Default Description -========================= ============ =========== ============================================================================================================================================================================================================================================================================================================================================================================================================================================================= -apertureTableName groupNameRef required Name of the aperture table -apertureTolerance real64 1e-09 Value to be used to avoid floating point errors in expressions involving aperture. For example in the case of dividing by the actual aperture (not the effective aperture that results from the aperture function) this value may be used to avoid the 1/0 error. Note that this value may have some physical significance in its usage, as it may be used to smooth out highly nonlinear behavior associated with 1/0 in addition to avoiding the 1/0 error. -cohesion real64 required Cohesion -displacementJumpThreshold real64 2.22045e-16 A threshold valued to determine whether a fracture is open or not. -frictionCoefficient real64 required Friction coefficient -name groupName required A name is required for any non-unique nodes -penaltyStiffness real64 0 Value of the penetration penalty stiffness. Units of Pressure/length -shearStiffness real64 0 Value of the shear elastic stiffness. Units of Pressure/length -========================= ============ =========== ============================================================================================================================================================================================================================================================================================================================================================================================================================================================= - - diff --git a/src/coreComponents/schema/docs/Coulomb_other.rst b/src/coreComponents/schema/docs/Coulomb_other.rst deleted file mode 100644 index e34713e1c47..00000000000 --- a/src/coreComponents/schema/docs/Coulomb_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -=========== ============== ============ -Name Type Description -=========== ============== ============ -elasticSlip real64_array2d Elastic Slip -=========== ============== ============ - - diff --git a/src/coreComponents/schema/docs/CustomPolarObject.rst b/src/coreComponents/schema/docs/CustomPolarObject.rst deleted file mode 100644 index dc3565d6b83..00000000000 --- a/src/coreComponents/schema/docs/CustomPolarObject.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -============ ============ ======== ========================================================================================================================================= -Name Type Default Description -============ ============ ======== ========================================================================================================================================= -center R1Tensor required (x,y,z) coordinates of the center of the CustomPolarObject -coefficients real64_array required Coefficients of the CustomPolarObject function relating the localradius to the angle theta. -lengthVector R1Tensor required Tangent vector defining the orthonormal basis along with the normal. -name groupName required A name is required for any non-unique nodes -normal R1Tensor required Normal (n_x,n_y,n_z) to the plane (will be normalized automatically) -tolerance real64 1e-05 Tolerance to determine if a point sits on the CustomPolarObject or not. It is relative to the maximum dimension of the CustomPolarObject. -widthVector R1Tensor required Tangent vector defining the orthonormal basis along with the normal. -============ ============ ======== ========================================================================================================================================= - - diff --git a/src/coreComponents/schema/docs/CustomPolarObject_other.rst b/src/coreComponents/schema/docs/CustomPolarObject_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/CustomPolarObject_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/Cylinder.rst b/src/coreComponents/schema/docs/Cylinder.rst deleted file mode 100644 index c96dc7455b4..00000000000 --- a/src/coreComponents/schema/docs/Cylinder.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -================ ========= ======== =============================================== -Name Type Default Description -================ ========= ======== =============================================== -firstFaceCenter R1Tensor required Center point of the first face of the cylinder -innerRadius real64 -1 Inner radius of the annulus -name groupName required A name is required for any non-unique nodes -outerRadius real64 required Outer radius of the cylinder -secondFaceCenter R1Tensor required Center point of the second face of the cylinder -================ ========= ======== =============================================== - - diff --git a/src/coreComponents/schema/docs/Cylinder_other.rst b/src/coreComponents/schema/docs/Cylinder_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/Cylinder_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/DamageElasticIsotropic.rst b/src/coreComponents/schema/docs/DamageElasticIsotropic.rst deleted file mode 100644 index 19236b59dcf..00000000000 --- a/src/coreComponents/schema/docs/DamageElasticIsotropic.rst +++ /dev/null @@ -1,23 +0,0 @@ - - -======================= ========= ======== ==================================================================== -Name Type Default Description -======================= ========= ======== ==================================================================== -compressiveStrength real64 0 Compressive strength from the uniaxial compression test -criticalFractureEnergy real64 required Critical fracture energy -criticalStrainEnergy real64 required Critical stress in a 1d tension test -defaultBulkModulus real64 -1 Default Bulk Modulus Parameter -defaultDensity real64 required Default Material Density -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultPoissonRatio real64 -1 Default Poisson's Ratio -defaultShearModulus real64 -1 Default Shear Modulus Parameter -defaultYoungModulus real64 -1 Default Young's Modulus -degradationLowerLimit real64 0 The lower limit of the degradation function -deltaCoefficient real64 -1 Coefficient in the calculation of the external driving force -extDrivingForceFlag integer 0 Whether to have external driving force. Can be 0 or 1 -lengthScale real64 required Length scale l in the phase-field equation -name groupName required A name is required for any non-unique nodes -tensileStrength real64 0 Tensile strength from the uniaxial tension test -======================= ========= ======== ==================================================================== - - diff --git a/src/coreComponents/schema/docs/DamageElasticIsotropic_other.rst b/src/coreComponents/schema/docs/DamageElasticIsotropic_other.rst deleted file mode 100644 index 2cda8d3e931..00000000000 --- a/src/coreComponents/schema/docs/DamageElasticIsotropic_other.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -bulkModulus real64_array Elastic Bulk Modulus Field -damage real64_array2d Material Damage Variable -density real64_array2d Material Density -extDrivingForce real64_array2d External Driving Force -oldStress real64_array3d Previous Material Stress -shearModulus real64_array Elastic Shear Modulus Field -strainEnergyDensity real64_array2d Strain Energy Density -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/DamageSpectralElasticIsotropic.rst b/src/coreComponents/schema/docs/DamageSpectralElasticIsotropic.rst deleted file mode 100644 index 19236b59dcf..00000000000 --- a/src/coreComponents/schema/docs/DamageSpectralElasticIsotropic.rst +++ /dev/null @@ -1,23 +0,0 @@ - - -======================= ========= ======== ==================================================================== -Name Type Default Description -======================= ========= ======== ==================================================================== -compressiveStrength real64 0 Compressive strength from the uniaxial compression test -criticalFractureEnergy real64 required Critical fracture energy -criticalStrainEnergy real64 required Critical stress in a 1d tension test -defaultBulkModulus real64 -1 Default Bulk Modulus Parameter -defaultDensity real64 required Default Material Density -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultPoissonRatio real64 -1 Default Poisson's Ratio -defaultShearModulus real64 -1 Default Shear Modulus Parameter -defaultYoungModulus real64 -1 Default Young's Modulus -degradationLowerLimit real64 0 The lower limit of the degradation function -deltaCoefficient real64 -1 Coefficient in the calculation of the external driving force -extDrivingForceFlag integer 0 Whether to have external driving force. Can be 0 or 1 -lengthScale real64 required Length scale l in the phase-field equation -name groupName required A name is required for any non-unique nodes -tensileStrength real64 0 Tensile strength from the uniaxial tension test -======================= ========= ======== ==================================================================== - - diff --git a/src/coreComponents/schema/docs/DamageSpectralElasticIsotropic_other.rst b/src/coreComponents/schema/docs/DamageSpectralElasticIsotropic_other.rst deleted file mode 100644 index 2cda8d3e931..00000000000 --- a/src/coreComponents/schema/docs/DamageSpectralElasticIsotropic_other.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -bulkModulus real64_array Elastic Bulk Modulus Field -damage real64_array2d Material Damage Variable -density real64_array2d Material Density -extDrivingForce real64_array2d External Driving Force -oldStress real64_array3d Previous Material Stress -shearModulus real64_array Elastic Shear Modulus Field -strainEnergyDensity real64_array2d Strain Energy Density -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/DamageVolDevElasticIsotropic.rst b/src/coreComponents/schema/docs/DamageVolDevElasticIsotropic.rst deleted file mode 100644 index 19236b59dcf..00000000000 --- a/src/coreComponents/schema/docs/DamageVolDevElasticIsotropic.rst +++ /dev/null @@ -1,23 +0,0 @@ - - -======================= ========= ======== ==================================================================== -Name Type Default Description -======================= ========= ======== ==================================================================== -compressiveStrength real64 0 Compressive strength from the uniaxial compression test -criticalFractureEnergy real64 required Critical fracture energy -criticalStrainEnergy real64 required Critical stress in a 1d tension test -defaultBulkModulus real64 -1 Default Bulk Modulus Parameter -defaultDensity real64 required Default Material Density -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultPoissonRatio real64 -1 Default Poisson's Ratio -defaultShearModulus real64 -1 Default Shear Modulus Parameter -defaultYoungModulus real64 -1 Default Young's Modulus -degradationLowerLimit real64 0 The lower limit of the degradation function -deltaCoefficient real64 -1 Coefficient in the calculation of the external driving force -extDrivingForceFlag integer 0 Whether to have external driving force. Can be 0 or 1 -lengthScale real64 required Length scale l in the phase-field equation -name groupName required A name is required for any non-unique nodes -tensileStrength real64 0 Tensile strength from the uniaxial tension test -======================= ========= ======== ==================================================================== - - diff --git a/src/coreComponents/schema/docs/DamageVolDevElasticIsotropic_other.rst b/src/coreComponents/schema/docs/DamageVolDevElasticIsotropic_other.rst deleted file mode 100644 index 2cda8d3e931..00000000000 --- a/src/coreComponents/schema/docs/DamageVolDevElasticIsotropic_other.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -bulkModulus real64_array Elastic Bulk Modulus Field -damage real64_array2d Material Damage Variable -density real64_array2d Material Density -extDrivingForce real64_array2d External Driving Force -oldStress real64_array3d Previous Material Stress -shearModulus real64_array Elastic Shear Modulus Field -strainEnergyDensity real64_array2d Strain Energy Density -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/DeadOilFluid.rst b/src/coreComponents/schema/docs/DeadOilFluid.rst deleted file mode 100644 index c34b2d2ec84..00000000000 --- a/src/coreComponents/schema/docs/DeadOilFluid.rst +++ /dev/null @@ -1,25 +0,0 @@ - - -======================================= ================== ======== ===================================================================================================================================================================================================================================================================================================== -Name Type Default Description -======================================= ================== ======== ===================================================================================================================================================================================================================================================================================================== -checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. -componentMolarWeight real64_array required Component molar weights -componentNames string_array {} List of component names -hydrocarbonFormationVolFactorTableNames groupNameRef_array {} | List of formation volume factor TableFunction names from the Functions block. - | The user must provide one TableFunction per hydrocarbon phase, in the order provided in "phaseNames". - | For instance, if "oil" is before "gas" in "phaseNames", the table order should be: oilTableName, gasTableName -hydrocarbonViscosityTableNames groupNameRef_array {} | List of viscosity TableFunction names from the Functions block. - | The user must provide one TableFunction per hydrocarbon phase, in the order provided in "phaseNames". - | For instance, if "oil" is before "gas" in "phaseNames", the table order should be: oilTableName, gasTableName -name groupName required A name is required for any non-unique nodes -phaseNames groupNameRef_array required List of fluid phases -surfaceDensities real64_array required List of surface mass densities for each phase -tableFiles path_array {} List of filenames with input PVT tables (one per phase) -waterCompressibility real64 0 Water compressibility -waterFormationVolumeFactor real64 0 Water formation volume factor -waterReferencePressure real64 0 Water reference pressure -waterViscosity real64 0 Water viscosity -======================================= ================== ======== ===================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/DeadOilFluid_other.rst b/src/coreComponents/schema/docs/DeadOilFluid_other.rst deleted file mode 100644 index 139d0708316..00000000000 --- a/src/coreComponents/schema/docs/DeadOilFluid_other.rst +++ /dev/null @@ -1,35 +0,0 @@ - - -=============================== ======================================================================================================= ============================================================================================================ -Name Type Description -=============================== ======================================================================================================= ============================================================================================================ -dPhaseCompFraction LvArray_Array< double, 5, camp_int_seq< long, 0l, 1l, 2l, 3l, 4l >, int, LvArray_ChaiBuffer > Derivative of phase component fraction with respect to pressure, temperature, and global component fractions -dPhaseDensity real64_array4d Derivative of phase density with respect to pressure, temperature, and global component fractions -dPhaseEnthalpy real64_array4d Derivative of phase enthalpy with respect to pressure, temperature, and global component fractions -dPhaseFraction real64_array4d Derivative of phase fraction with respect to pressure, temperature, and global component fractions -dPhaseInternalEnergy real64_array4d Derivative of phase internal energy with respect to pressure, temperature, and global component fractions -dPhaseMassDensity real64_array4d Derivative of phase mass density with respect to pressure, temperature, and global component fractions -dPhaseViscosity real64_array4d Derivative of phase viscosity with respect to pressure, temperature, and global component fractions -dTotalDensity real64_array3d Derivative of total density with respect to pressure, temperature, and global component fractions -formationVolFactorTableWrappers LvArray_Array< geos_TableFunction_KernelWrapper, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer > (no description available) -hydrocarbonPhaseOrder integer_array (no description available) -phaseCompFraction real64_array4d Phase component fraction -phaseCompFraction_n real64_array4d Phase component fraction at the previous converged time step -phaseDensity real64_array3d Phase density -phaseDensity_n real64_array3d Phase density at the previous converged time step -phaseEnthalpy real64_array3d Phase enthalpy -phaseEnthalpy_n real64_array3d Phase enthalpy at the previous converged time step -phaseFraction real64_array3d Phase fraction -phaseInternalEnergy real64_array3d Phase internal energy -phaseInternalEnergy_n real64_array3d Phase internal energy at the previous converged time step -phaseMassDensity real64_array3d Phase mass density -phaseOrder integer_array (no description available) -phaseTypes integer_array (no description available) -phaseViscosity real64_array3d Phase viscosity -totalDensity real64_array2d Total density -totalDensity_n real64_array2d Total density at the previous converged time step -useMass integer (no description available) -viscosityTableWrappers LvArray_Array< geos_TableFunction_KernelWrapper, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer > (no description available) -=============================== ======================================================================================================= ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/DelftEgg.rst b/src/coreComponents/schema/docs/DelftEgg.rst deleted file mode 100644 index a509cdd295e..00000000000 --- a/src/coreComponents/schema/docs/DelftEgg.rst +++ /dev/null @@ -1,20 +0,0 @@ - - -=============================== ========= ======== ==================================================================== -Name Type Default Description -=============================== ========= ======== ==================================================================== -defaultBulkModulus real64 -1 Default Bulk Modulus Parameter -defaultCslSlope real64 1 Slope of the critical state line -defaultDensity real64 required Default Material Density -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultPoissonRatio real64 -1 Default Poisson's Ratio -defaultPreConsolidationPressure real64 -1.5 Initial preconsolidation pressure -defaultRecompressionIndex real64 0.002 Recompresion Index -defaultShapeParameter real64 1 Shape parameter for the yield surface -defaultShearModulus real64 -1 Default Shear Modulus Parameter -defaultVirginCompressionIndex real64 0.005 Virgin compression index -defaultYoungModulus real64 -1 Default Young's Modulus -name groupName required A name is required for any non-unique nodes -=============================== ========= ======== ==================================================================== - - diff --git a/src/coreComponents/schema/docs/DelftEgg_other.rst b/src/coreComponents/schema/docs/DelftEgg_other.rst deleted file mode 100644 index a03c1dc5716..00000000000 --- a/src/coreComponents/schema/docs/DelftEgg_other.rst +++ /dev/null @@ -1,20 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -bulkModulus real64_array Elastic Bulk Modulus Field -cslSlope real64_array Slope of the critical state line -density real64_array2d Material Density -oldPreConsolidationPressure real64_array2d Old preconsolidation pressure -oldStress real64_array3d Previous Material Stress -preConsolidationPressure real64_array2d New preconsolidation pressure -recompressionIndex real64_array Recompression index -shapeParameter real64_array Shape parameter for the yield surface -shearModulus real64_array Elastic Shear Modulus Field -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -virginCompressionIndex real64_array Virgin compression index -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/Dirichlet.rst b/src/coreComponents/schema/docs/Dirichlet.rst deleted file mode 100644 index 81d6fead75e..00000000000 --- a/src/coreComponents/schema/docs/Dirichlet.rst +++ /dev/null @@ -1,21 +0,0 @@ - - -====================== ================== ======== ============================================================================== -Name Type Default Description -====================== ================== ======== ============================================================================== -bcApplicationTableName groupNameRef Name of table that specifies the on/off application of the boundary condition. -beginTime real64 -1e+99 Time at which the boundary condition will start being applied. -component integer -1 Component of field (if tensor) to apply boundary condition to. -direction R1Tensor {0,0,0} Direction to apply boundary condition to. -endTime real64 1e+99 Time at which the boundary condition will stop being applied. -fieldName groupNameRef Name of field that boundary condition is applied to. -functionName groupNameRef Name of function that specifies variation of the boundary condition. -initialCondition integer 0 Boundary condition is applied as an initial condition. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -objectPath groupNameRef Path to the target field -scale real64 0 Scale factor for value of the boundary condition. -setNames groupNameRef_array required Name of sets that boundary condition is applied to. -====================== ================== ======== ============================================================================== - - diff --git a/src/coreComponents/schema/docs/Dirichlet_other.rst b/src/coreComponents/schema/docs/Dirichlet_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/Dirichlet_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/Disc.rst b/src/coreComponents/schema/docs/Disc.rst deleted file mode 100644 index b3e07062220..00000000000 --- a/src/coreComponents/schema/docs/Disc.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -============ ========= ======== =============================================================================================================== -Name Type Default Description -============ ========= ======== =============================================================================================================== -center R1Tensor required (x,y,z) coordinates of the center of the disc -lengthVector R1Tensor required Tangent vector defining the orthonormal basis along with the normal. -name groupName required A name is required for any non-unique nodes -normal R1Tensor required Normal (n_x,n_y,n_z) to the plane (will be normalized automatically) -radius real64 required Radius of the disc. -tolerance real64 1e-05 Tolerance to determine if a point sits on the disc or not. It is relative to the maximum dimension of the disc. -widthVector R1Tensor required Tangent vector defining the orthonormal basis along with the normal. -============ ========= ======== =============================================================================================================== - - diff --git a/src/coreComponents/schema/docs/Disc_other.rst b/src/coreComponents/schema/docs/Disc_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/Disc_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/DruckerPrager.rst b/src/coreComponents/schema/docs/DruckerPrager.rst deleted file mode 100644 index 3f5d4ef7249..00000000000 --- a/src/coreComponents/schema/docs/DruckerPrager.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -======================= ========= ======== ==================================================================== -Name Type Default Description -======================= ========= ======== ==================================================================== -defaultBulkModulus real64 -1 Default Bulk Modulus Parameter -defaultCohesion real64 0 Initial cohesion -defaultDensity real64 required Default Material Density -defaultDilationAngle real64 30 Dilation angle (degrees) -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultFrictionAngle real64 30 Friction angle (degrees) -defaultHardeningRate real64 0 Cohesion hardening/softening rate -defaultPoissonRatio real64 -1 Default Poisson's Ratio -defaultShearModulus real64 -1 Default Shear Modulus Parameter -defaultYoungModulus real64 -1 Default Young's Modulus -name groupName required A name is required for any non-unique nodes -======================= ========= ======== ==================================================================== - - diff --git a/src/coreComponents/schema/docs/DruckerPrager_other.rst b/src/coreComponents/schema/docs/DruckerPrager_other.rst deleted file mode 100644 index 3185dd07d81..00000000000 --- a/src/coreComponents/schema/docs/DruckerPrager_other.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -bulkModulus real64_array Elastic Bulk Modulus Field -cohesion real64_array2d New cohesion state -density real64_array2d Material Density -dilation real64_array Plastic potential slope -friction real64_array Yield surface slope -hardening real64_array Hardening rate -oldCohesion real64_array2d Old cohesion state -oldStress real64_array3d Previous Material Stress -shearModulus real64_array Elastic Shear Modulus Field -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/ElasticFirstOrderSEM.rst b/src/coreComponents/schema/docs/ElasticFirstOrderSEM.rst deleted file mode 100644 index 22d9753df98..00000000000 --- a/src/coreComponents/schema/docs/ElasticFirstOrderSEM.rst +++ /dev/null @@ -1,33 +0,0 @@ - - -========================= ============================ ========== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ============================ ========== ======================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -dtSeismoTrace real64 0 Time step for output pressure at receivers -enableLifo integer 0 Set to 1 to enable LIFO storage feature -forward integer 1 Set to 1 to compute forward propagation -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -lifoOnDevice integer -80 Set the capacity of the lifo device storage (if negative, opposite of percentage of remaining memory) -lifoOnHost integer -80 Set the capacity of the lifo host storage (if negative, opposite of percentage of remaining memory) -lifoSize integer 2147483647 Set the capacity of the lifo storage (should be the total number of buffers to store in the LIFO) -linearDASGeometry real64_array2d {{0}} Geometry parameters for a linear DAS fiber (dip, azimuth, gauge length) -linearDASSamples integer 5 Number of sample points to be used for strain integration when integrating the strain for the DAS signal -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -outputSeismoTrace integer 0 Flag that indicates if we write the seismo trace in a file .txt, 0 no output, 1 otherwise -receiverCoordinates real64_array2d {{0}} Coordinates (x,y,z) of the receivers -rickerOrder integer 2 Flag that indicates the order of the Ricker to be used o, 1 or 2. Order 2 by default -saveFields integer 0 Set to 1 to save fields during forward and restore them during backward -shotIndex integer 0 Set the current shot for temporary files -sourceCoordinates real64_array2d {{0}} Coordinates (x,y,z) of the sources -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -timeSourceDelay real32 -1 Source time delay (1 / f0 by default) -timeSourceFrequency real32 0 Central frequency for the time source -useDAS geos_WaveSolverUtils_DASType none Flag to indicate if DAS data will be modeled, and which DAS type to use: 1 for strain integration, 2 for displacement difference -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ============================ ========== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/ElasticFirstOrderSEM_other.rst b/src/coreComponents/schema/docs/ElasticFirstOrderSEM_other.rst deleted file mode 100644 index a5e6f05623a..00000000000 --- a/src/coreComponents/schema/docs/ElasticFirstOrderSEM_other.rst +++ /dev/null @@ -1,38 +0,0 @@ - - -=========================== ============================================================================================================================================================== ======================================================================= -Name Type Description -=========================== ============================================================================================================================================================== ======================================================================= -displacementxNp1AtReceivers real32_array2d Displacement value at each receiver for each timestep (x-components) -displacementyNp1AtReceivers real32_array2d Displacement value at each receiver for each timestep (y-components) -displacementzNp1AtReceivers real32_array2d Displacement value at each receiver for each timestep (z-components) -indexSeismoTrace integer Count for output pressure at receivers -linearDASVectorX real32_array X component of the linear DAS direction vector -linearDASVectorY real32_array Y component of the linear DAS direction vector -linearDASVectorZ real32_array Z component of the linear DAS direction vector -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -rcvElem integer_array Element containing the receivers -receiverConstants real64_array2d Constant part of the receiver for the nodes listed in m_receiverNodeIds -receiverIsLocal integer_array Flag that indicates whether the receiver is local to this MPI rank -receiverNodeIds integer_array2d Indices of the nodes (in the right order) for each receiver point -receiverRegion integer_array Region containing the receivers -sigmaxxNp1AtReceivers real32_array2d Displacement value at each receiver for each timestep (z-components) -sigmaxyNp1AtReceivers real32_array2d Displacement value at each receiver for each timestep (z-components) -sigmaxzNp1AtReceivers real32_array2d Displacement value at each receiver for each timestep (z-components) -sigmayyNp1AtReceivers real32_array2d Displacement value at each receiver for each timestep (z-components) -sigmayzNp1AtReceivers real32_array2d Displacement value at each receiver for each timestep (z-components) -sigmazzNp1AtReceivers real32_array2d Displacement value at each receiver for each timestep (z-components) -sourceConstants real64_array2d Constant part of the source for the nodes listed in m_sourceNodeIds -sourceElem integer_array Element containing the sources -sourceIsAccessible integer_array Flag that indicates whether the source is local to this MPI rank -sourceNodeIds integer_array2d Indices of the nodes (in the right order) for each source point -sourceRegion integer_array Region containing the sources -sourceValue real32_array2d Source Value of the sources -usePML integer Flag to apply PML -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -=========================== ============================================================================================================================================================== ======================================================================= - - diff --git a/src/coreComponents/schema/docs/ElasticIsotropic.rst b/src/coreComponents/schema/docs/ElasticIsotropic.rst deleted file mode 100644 index 15e42d76f2b..00000000000 --- a/src/coreComponents/schema/docs/ElasticIsotropic.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -======================= ========= ======== ==================================================================== -Name Type Default Description -======================= ========= ======== ==================================================================== -defaultBulkModulus real64 -1 Default Bulk Modulus Parameter -defaultDensity real64 required Default Material Density -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultPoissonRatio real64 -1 Default Poisson's Ratio -defaultShearModulus real64 -1 Default Shear Modulus Parameter -defaultYoungModulus real64 -1 Default Young's Modulus -name groupName required A name is required for any non-unique nodes -======================= ========= ======== ==================================================================== - - diff --git a/src/coreComponents/schema/docs/ElasticIsotropicPressureDependent.rst b/src/coreComponents/schema/docs/ElasticIsotropicPressureDependent.rst deleted file mode 100644 index 96015fd3861..00000000000 --- a/src/coreComponents/schema/docs/ElasticIsotropicPressureDependent.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -========================= ========= ======== ==================================================================== -Name Type Default Description -========================= ========= ======== ==================================================================== -defaultDensity real64 required Default Material Density -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultRecompressionIndex real64 0.002 Recompresion Index -defaultRefPressure real64 -1 Reference Pressure -defaultRefStrainVol real64 0 Reference Volumetric Strain -defaultShearModulus real64 -1 Elastic Shear Modulus Parameter -name groupName required A name is required for any non-unique nodes -========================= ========= ======== ==================================================================== - - diff --git a/src/coreComponents/schema/docs/ElasticIsotropicPressureDependent_other.rst b/src/coreComponents/schema/docs/ElasticIsotropicPressureDependent_other.rst deleted file mode 100644 index 3c45927c9b2..00000000000 --- a/src/coreComponents/schema/docs/ElasticIsotropicPressureDependent_other.rst +++ /dev/null @@ -1,16 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -density real64_array2d Material Density -oldStress real64_array3d Previous Material Stress -recompressionIndex real64_array Recompression Index Field -refPressure real64 Reference Pressure Field -refStrainVol real64 Reference Volumetric Strain -shearModulus real64_array Elastic Shear Modulus -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/ElasticIsotropic_other.rst b/src/coreComponents/schema/docs/ElasticIsotropic_other.rst deleted file mode 100644 index f202084d9bf..00000000000 --- a/src/coreComponents/schema/docs/ElasticIsotropic_other.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -bulkModulus real64_array Elastic Bulk Modulus Field -density real64_array2d Material Density -oldStress real64_array3d Previous Material Stress -shearModulus real64_array Elastic Shear Modulus Field -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/ElasticOrthotropic.rst b/src/coreComponents/schema/docs/ElasticOrthotropic.rst deleted file mode 100644 index f2d55b8530f..00000000000 --- a/src/coreComponents/schema/docs/ElasticOrthotropic.rst +++ /dev/null @@ -1,29 +0,0 @@ - - -======================= ========= ======== ==================================================================== -Name Type Default Description -======================= ========= ======== ==================================================================== -defaultC11 real64 -1 Default C11 Component of Voigt Stiffness Tensor -defaultC12 real64 -1 Default C12 Component of Voigt Stiffness Tensor -defaultC13 real64 -1 Default C13 Component of Voigt Stiffness Tensor -defaultC22 real64 -1 Default C22 Component of Voigt Stiffness Tensor -defaultC23 real64 -1 Default C23 Component of Voigt Stiffness Tensor -defaultC33 real64 -1 Default C33 Component of Voigt Stiffness Tensor -defaultC44 real64 -1 Default C44 Component of Voigt Stiffness Tensor -defaultC55 real64 -1 Default C55 Component of Voigt Stiffness Tensor -defaultC66 real64 -1 Default C66 Component of Voigt Stiffness Tensor -defaultDensity real64 required Default Material Density -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultE1 real64 -1 Default Young's Modulus E1 -defaultE2 real64 -1 Default Young's Modulus E2 -defaultE3 real64 -1 Default Young's Modulus E3 -defaultG12 real64 -1 Default Shear Modulus G12 -defaultG13 real64 -1 Default Shear Modulus G13 -defaultG23 real64 -1 Default Shear Modulus G23 -defaultNu12 real64 -1 Default Poission's Ratio Nu12 -defaultNu13 real64 -1 Default Poission's Ratio Nu13 -defaultNu23 real64 -1 Default Poission's Ratio Nu23 -name groupName required A name is required for any non-unique nodes -======================= ========= ======== ==================================================================== - - diff --git a/src/coreComponents/schema/docs/ElasticOrthotropic_other.rst b/src/coreComponents/schema/docs/ElasticOrthotropic_other.rst deleted file mode 100644 index e4df4dab8e0..00000000000 --- a/src/coreComponents/schema/docs/ElasticOrthotropic_other.rst +++ /dev/null @@ -1,21 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -c11 real64_array Elastic Stiffness Field C11 -c12 real64_array Elastic Stiffness Field C12 -c13 real64_array Elastic Stiffness Field C13 -c22 real64_array Elastic Stiffness Field C22 -c23 real64_array Elastic Stiffness Field C23 -c33 real64_array Elastic Stiffness Field C33 -c44 real64_array Elastic Stiffness Field C44 -c55 real64_array Elastic Stiffness Field C55 -c66 real64_array Elastic Stiffness Field C66 -density real64_array2d Material Density -oldStress real64_array3d Previous Material Stress -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/ElasticSEM.rst b/src/coreComponents/schema/docs/ElasticSEM.rst deleted file mode 100644 index 6cc28146502..00000000000 --- a/src/coreComponents/schema/docs/ElasticSEM.rst +++ /dev/null @@ -1,35 +0,0 @@ - - -========================= ============================ ============= ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ============================ ============= ======================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -dtSeismoTrace real64 0 Time step for output pressure at receivers -enableLifo integer 0 Set to 1 to enable LIFO storage feature -forward integer 1 Set to 1 to compute forward propagation -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -lifoOnDevice integer -80 Set the capacity of the lifo device storage (if negative, opposite of percentage of remaining memory) -lifoOnHost integer -80 Set the capacity of the lifo host storage (if negative, opposite of percentage of remaining memory) -lifoSize integer 2147483647 Set the capacity of the lifo storage (should be the total number of buffers to store in the LIFO) -linearDASGeometry real64_array2d {{0}} Geometry parameters for a linear DAS fiber (dip, azimuth, gauge length) -linearDASSamples integer 5 Number of sample points to be used for strain integration when integrating the strain for the DAS signal -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -outputSeismoTrace integer 0 Flag that indicates if we write the seismo trace in a file .txt, 0 no output, 1 otherwise -receiverCoordinates real64_array2d {{0}} Coordinates (x,y,z) of the receivers -rickerOrder integer 2 Flag that indicates the order of the Ricker to be used o, 1 or 2. Order 2 by default -saveFields integer 0 Set to 1 to save fields during forward and restore them during backward -shotIndex integer 0 Set the current shot for temporary files -sourceCoordinates real64_array2d {{0}} Coordinates (x,y,z) of the sources -sourceForce R1Tensor {0,0,0} Force of the source: 3 real values for a vector source, and 6 real values for a tensor source (in Voigt notation).The default value is { 0, 0, 0 } (no net force). -sourceMoment R2SymTensor {1,1,1,0,0,0} Moment of the source: 6 real values describing a symmetric tensor in Voigt notation.The default value is { 1, 1, 1, 0, 0, 0 } (diagonal moment, corresponding to a pure explosion). -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -timeSourceDelay real32 -1 Source time delay (1 / f0 by default) -timeSourceFrequency real32 0 Central frequency for the time source -useDAS geos_WaveSolverUtils_DASType none Flag to indicate if DAS data will be modeled, and which DAS type to use: 1 for strain integration, 2 for displacement difference -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ============================ ============= ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/ElasticSEM_other.rst b/src/coreComponents/schema/docs/ElasticSEM_other.rst deleted file mode 100644 index 06969fee16a..00000000000 --- a/src/coreComponents/schema/docs/ElasticSEM_other.rst +++ /dev/null @@ -1,31 +0,0 @@ - - -=========================== ============================================================================================================================================================== ================================================================================== -Name Type Description -=========================== ============================================================================================================================================================== ================================================================================== -dasSignalNp1AtReceivers real32_array2d DAS signal value at each receiver for each timestep -displacementXNp1AtReceivers real32_array2d Displacement value at each receiver for each timestep (x-component) -displacementYNp1AtReceivers real32_array2d Displacement value at each receiver for each timestep (y-component) -displacementZNp1AtReceivers real32_array2d Displacement value at each receiver for each timestep (z-component) -indexSeismoTrace integer Count for output pressure at receivers -linearDASVectorX real32_array X component of the linear DAS direction vector -linearDASVectorY real32_array Y component of the linear DAS direction vector -linearDASVectorZ real32_array Z component of the linear DAS direction vector -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -rcvElem integer_array Element containing the receivers -receiverConstants real64_array2d Constant part of the receiver for the nodes listed in m_receiverNodeIds -receiverIsLocal integer_array Flag that indicates whether the receiver is local to this MPI rank -receiverNodeIds integer_array2d Indices of the nodes (in the right order) for each receiver point -receiverRegion integer_array Region containing the receivers -sourceConstants real64_array2d Constant part of the source for the nodes listed in m_sourceNodeIds in z-direction -sourceIsAccessible integer_array Flag that indicates whether the source is local to this MPI rank -sourceNodeIds integer_array2d Indices of the nodes (in the right order) for each source point -sourceValue real32_array2d Source Value of the sources -usePML integer Flag to apply PML -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -=========================== ============================================================================================================================================================== ================================================================================== - - diff --git a/src/coreComponents/schema/docs/ElasticTransverseIsotropic.rst b/src/coreComponents/schema/docs/ElasticTransverseIsotropic.rst deleted file mode 100644 index e07838a1fd3..00000000000 --- a/src/coreComponents/schema/docs/ElasticTransverseIsotropic.rst +++ /dev/null @@ -1,21 +0,0 @@ - - -================================== ========= ======== ==================================================================== -Name Type Default Description -================================== ========= ======== ==================================================================== -defaultC11 real64 -1 Default Stiffness Parameter C11 -defaultC13 real64 -1 Default Stiffness Parameter C13 -defaultC33 real64 -1 Default Stiffness Parameter C33 -defaultC44 real64 -1 Default Stiffness Parameter C44 -defaultC66 real64 -1 Default Stiffness Parameter C66 -defaultDensity real64 required Default Material Density -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultPoissonRatioAxialTransverse real64 -1 Default Axial-Transverse Poisson's Ratio -defaultPoissonRatioTransverse real64 -1 Default Transverse Poisson's Ratio -defaultShearModulusAxialTransverse real64 -1 Default Axial-Transverse Shear Modulus -defaultYoungModulusAxial real64 -1 Default Axial Young's Modulus -defaultYoungModulusTransverse real64 -1 Default Transverse Young's Modulus -name groupName required A name is required for any non-unique nodes -================================== ========= ======== ==================================================================== - - diff --git a/src/coreComponents/schema/docs/ElasticTransverseIsotropic_other.rst b/src/coreComponents/schema/docs/ElasticTransverseIsotropic_other.rst deleted file mode 100644 index 310de3990d0..00000000000 --- a/src/coreComponents/schema/docs/ElasticTransverseIsotropic_other.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -c11 real64_array Elastic Stiffness Field C11 -c13 real64_array Elastic Stiffness Field C13 -c33 real64_array Elastic Stiffness Field C33 -c44 real64_array Elastic Stiffness Field C44 -c66 real64_array Elastic Stiffness Field C66 -density real64_array2d Material Density -oldStress real64_array3d Previous Material Stress -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/ElementRegions.rst b/src/coreComponents/schema/docs/ElementRegions.rst deleted file mode 100644 index 82d745e17be..00000000000 --- a/src/coreComponents/schema/docs/ElementRegions.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -==================== ==== ======= =============================== -Name Type Default Description -==================== ==== ======= =============================== -CellElementRegion node :ref:`XML_CellElementRegion` -SurfaceElementRegion node :ref:`XML_SurfaceElementRegion` -WellElementRegion node :ref:`XML_WellElementRegion` -==================== ==== ======= =============================== - - diff --git a/src/coreComponents/schema/docs/ElementRegions_other.rst b/src/coreComponents/schema/docs/ElementRegions_other.rst deleted file mode 100644 index 17af822cdb0..00000000000 --- a/src/coreComponents/schema/docs/ElementRegions_other.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -======================= ==================================================================== ========================================================= -Name Type Description -======================= ==================================================================== ========================================================= -domainBoundaryIndicator integer_array (no description available) -ghostRank integer_array (no description available) -globalToLocalMap geos_mapBase< long long, int, std_integral_constant< bool, false > > (no description available) -isExternal integer_array (no description available) -localToGlobalMap globalIndex_array Array that contains a map from localIndex to globalIndex. -CellElementRegion node :ref:`DATASTRUCTURE_CellElementRegion` -SurfaceElementRegion node :ref:`DATASTRUCTURE_SurfaceElementRegion` -WellElementRegion node :ref:`DATASTRUCTURE_WellElementRegion` -elementRegionsGroup node :ref:`DATASTRUCTURE_elementRegionsGroup` -neighborData node :ref:`DATASTRUCTURE_neighborData` -sets node :ref:`DATASTRUCTURE_sets` -======================= ==================================================================== ========================================================= - - diff --git a/src/coreComponents/schema/docs/EmbeddedSurfaceGenerator.rst b/src/coreComponents/schema/docs/EmbeddedSurfaceGenerator.rst deleted file mode 100644 index 32ce1ed3490..00000000000 --- a/src/coreComponents/schema/docs/EmbeddedSurfaceGenerator.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -========================= ================== ============== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ================== ============== ======================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -fractureRegion groupNameRef FractureRegion (no description available) -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -mpiCommOrder integer 0 Flag to enable MPI consistent communication ordering -name groupName required A name is required for any non-unique nodes -targetObjects groupNameRef_array required List of geometric objects that will be used to initialized the embedded surfaces/fractures. -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ================== ============== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/EmbeddedSurfaceGenerator_other.rst b/src/coreComponents/schema/docs/EmbeddedSurfaceGenerator_other.rst deleted file mode 100644 index 46c029f2c1a..00000000000 --- a/src/coreComponents/schema/docs/EmbeddedSurfaceGenerator_other.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -========================= ============================================================================================================================================================== ================================================ ================================================================ -Name Type Registered On Description -========================= ============================================================================================================================================================== ================================================ ================================================================ -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -parentEdgeIndex integer_array :ref:`DATASTRUCTURE_embeddedSurfacesNodeManager` Index of parent edge within the mesh object it is registered on. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ================================================ ================================================================ - - diff --git a/src/coreComponents/schema/docs/Events.rst b/src/coreComponents/schema/docs/Events.rst deleted file mode 100644 index 4073b6fdc2c..00000000000 --- a/src/coreComponents/schema/docs/Events.rst +++ /dev/null @@ -1,16 +0,0 @@ - - -================ ================================== ============ =================================================== -Name Type Default Description -================ ================================== ============ =================================================== -logLevel integer 0 Log level -maxCycle integer 2147483647 Maximum simulation cycle for the global event loop. -maxTime real64 1.79769e+308 Maximum simulation time for the global event loop. -minTime real64 0 Start simulation time for the global event loop. -timeOutputFormat geos_EventManager_TimeOutputFormat seconds Format of the time in the GEOS log. -HaltEvent node :ref:`XML_HaltEvent` -PeriodicEvent node :ref:`XML_PeriodicEvent` -SoloEvent node :ref:`XML_SoloEvent` -================ ================================== ============ =================================================== - - diff --git a/src/coreComponents/schema/docs/Events_other.rst b/src/coreComponents/schema/docs/Events_other.rst deleted file mode 100644 index b9ef302077f..00000000000 --- a/src/coreComponents/schema/docs/Events_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=============== ======= ================================== -Name Type Description -=============== ======= ================================== -currentSubEvent integer Index of the current subevent. -cycle integer Current simulation cycle number. -dt real64 Current simulation timestep. -time real64 Current simulation time. -HaltEvent node :ref:`DATASTRUCTURE_HaltEvent` -PeriodicEvent node :ref:`DATASTRUCTURE_PeriodicEvent` -SoloEvent node :ref:`DATASTRUCTURE_SoloEvent` -=============== ======= ================================== - - diff --git a/src/coreComponents/schema/docs/ExponentialDecayPermeability.rst b/src/coreComponents/schema/docs/ExponentialDecayPermeability.rst deleted file mode 100644 index 478b850e596..00000000000 --- a/src/coreComponents/schema/docs/ExponentialDecayPermeability.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -=================== ========= ======== =========================================== -Name Type Default Description -=================== ========= ======== =========================================== -empiricalConstant real64 required an empirical constant. -initialPermeability R1Tensor required initial permeability of the fracture. -name groupName required A name is required for any non-unique nodes -=================== ========= ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/ExponentialDecayPermeability_other.rst b/src/coreComponents/schema/docs/ExponentialDecayPermeability_other.rst deleted file mode 100644 index 945812dafaa..00000000000 --- a/src/coreComponents/schema/docs/ExponentialDecayPermeability_other.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -=============== ============== =================================================================== -Name Type Description -=============== ============== =================================================================== -dPerm_dDispJump real64_array4d Derivative of rock permeability with respect to displacement jump -dPerm_dPressure real64_array3d Derivative of rock permeability with respect to pressure -dPerm_dTraction real64_array4d Derivative of rock permeability with respect to the traction vector -permeability real64_array3d Rock permeability -=============== ============== =================================================================== - - diff --git a/src/coreComponents/schema/docs/ExtendedDruckerPrager.rst b/src/coreComponents/schema/docs/ExtendedDruckerPrager.rst deleted file mode 100644 index a196499ef95..00000000000 --- a/src/coreComponents/schema/docs/ExtendedDruckerPrager.rst +++ /dev/null @@ -1,20 +0,0 @@ - - -============================ ========= ======== ==================================================================== -Name Type Default Description -============================ ========= ======== ==================================================================== -defaultBulkModulus real64 -1 Default Bulk Modulus Parameter -defaultCohesion real64 0 Initial cohesion -defaultDensity real64 required Default Material Density -defaultDilationRatio real64 1 Dilation ratio [0,1] (ratio = tan dilationAngle / tan frictionAngle) -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultHardening real64 0 Hardening parameter (hardening rate is faster for smaller values) -defaultInitialFrictionAngle real64 30 Initial friction angle (degrees) -defaultPoissonRatio real64 -1 Default Poisson's Ratio -defaultResidualFrictionAngle real64 30 Residual friction angle (degrees) -defaultShearModulus real64 -1 Default Shear Modulus Parameter -defaultYoungModulus real64 -1 Default Young's Modulus -name groupName required A name is required for any non-unique nodes -============================ ========= ======== ==================================================================== - - diff --git a/src/coreComponents/schema/docs/ExtendedDruckerPrager_other.rst b/src/coreComponents/schema/docs/ExtendedDruckerPrager_other.rst deleted file mode 100644 index 729d894b362..00000000000 --- a/src/coreComponents/schema/docs/ExtendedDruckerPrager_other.rst +++ /dev/null @@ -1,21 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -bulkModulus real64_array Elastic Bulk Modulus Field -density real64_array2d Material Density -dilationRatio real64_array Plastic potential slope ratio -hardening real64_array Hardening parameter -initialFriction real64_array Initial yield surface slope -oldStateVariable real64_array2d Old equivalent plastic shear strain -oldStress real64_array3d Previous Material Stress -pressureIntercept real64_array Pressure point at cone vertex -residualFriction real64_array Residual yield surface slope -shearModulus real64_array Elastic Shear Modulus Field -stateVariable real64_array2d New equivalent plastic shear strain -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/FieldSpecification.rst b/src/coreComponents/schema/docs/FieldSpecification.rst deleted file mode 100644 index 81d6fead75e..00000000000 --- a/src/coreComponents/schema/docs/FieldSpecification.rst +++ /dev/null @@ -1,21 +0,0 @@ - - -====================== ================== ======== ============================================================================== -Name Type Default Description -====================== ================== ======== ============================================================================== -bcApplicationTableName groupNameRef Name of table that specifies the on/off application of the boundary condition. -beginTime real64 -1e+99 Time at which the boundary condition will start being applied. -component integer -1 Component of field (if tensor) to apply boundary condition to. -direction R1Tensor {0,0,0} Direction to apply boundary condition to. -endTime real64 1e+99 Time at which the boundary condition will stop being applied. -fieldName groupNameRef Name of field that boundary condition is applied to. -functionName groupNameRef Name of function that specifies variation of the boundary condition. -initialCondition integer 0 Boundary condition is applied as an initial condition. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -objectPath groupNameRef Path to the target field -scale real64 0 Scale factor for value of the boundary condition. -setNames groupNameRef_array required Name of sets that boundary condition is applied to. -====================== ================== ======== ============================================================================== - - diff --git a/src/coreComponents/schema/docs/FieldSpecification_other.rst b/src/coreComponents/schema/docs/FieldSpecification_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/FieldSpecification_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/FieldSpecifications.rst b/src/coreComponents/schema/docs/FieldSpecifications.rst deleted file mode 100644 index f0da4190ad4..00000000000 --- a/src/coreComponents/schema/docs/FieldSpecifications.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -====================== ==== ======= ================================= -Name Type Default Description -====================== ==== ======= ================================= -Aquifer node :ref:`XML_Aquifer` -Dirichlet node :ref:`XML_Dirichlet` -FieldSpecification node :ref:`XML_FieldSpecification` -HydrostaticEquilibrium node :ref:`XML_HydrostaticEquilibrium` -PML node :ref:`XML_PML` -SourceFlux node :ref:`XML_SourceFlux` -Traction node :ref:`XML_Traction` -====================== ==== ======= ================================= - - diff --git a/src/coreComponents/schema/docs/FieldSpecifications_other.rst b/src/coreComponents/schema/docs/FieldSpecifications_other.rst deleted file mode 100644 index 7280e734cf5..00000000000 --- a/src/coreComponents/schema/docs/FieldSpecifications_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -====================== ==== =========================================== -Name Type Description -====================== ==== =========================================== -Aquifer node :ref:`DATASTRUCTURE_Aquifer` -Dirichlet node :ref:`DATASTRUCTURE_Dirichlet` -FieldSpecification node :ref:`DATASTRUCTURE_FieldSpecification` -HydrostaticEquilibrium node :ref:`DATASTRUCTURE_HydrostaticEquilibrium` -PML node :ref:`DATASTRUCTURE_PML` -SourceFlux node :ref:`DATASTRUCTURE_SourceFlux` -Traction node :ref:`DATASTRUCTURE_Traction` -====================== ==== =========================================== - - diff --git a/src/coreComponents/schema/docs/File.rst b/src/coreComponents/schema/docs/File.rst deleted file mode 100644 index 949fd71db6e..00000000000 --- a/src/coreComponents/schema/docs/File.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ======== ======================= -Name Type Default Description -==== ==== ======== ======================= -name path required The relative file path. -==== ==== ======== ======================= - - diff --git a/src/coreComponents/schema/docs/File_other.rst b/src/coreComponents/schema/docs/File_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/File_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/FiniteElementSpace.rst b/src/coreComponents/schema/docs/FiniteElementSpace.rst deleted file mode 100644 index 1dfa434e822..00000000000 --- a/src/coreComponents/schema/docs/FiniteElementSpace.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -================== ============================================ ======== ======================================================================================================================================================================= -Name Type Default Description -================== ============================================ ======== ======================================================================================================================================================================= -formulation geos_FiniteElementDiscretization_Formulation default Specifier to indicate any specialized formuations. For instance, one of the many enhanced assumed strain methods of the Hexahedron parent shape would be indicated here -name groupName required A name is required for any non-unique nodes -order integer required The order of the finite element basis. -useVirtualElements integer 0 Specifier to indicate whether to force the use of VEM -================== ============================================ ======== ======================================================================================================================================================================= - - diff --git a/src/coreComponents/schema/docs/FiniteElementSpace_other.rst b/src/coreComponents/schema/docs/FiniteElementSpace_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/FiniteElementSpace_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/FiniteElements.rst b/src/coreComponents/schema/docs/FiniteElements.rst deleted file mode 100644 index 8a027502bcb..00000000000 --- a/src/coreComponents/schema/docs/FiniteElements.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -========================= ==== ======= ==================================== -Name Type Default Description -========================= ==== ======= ==================================== -FiniteElementSpace node :ref:`XML_FiniteElementSpace` -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ==== ======= ==================================== - - diff --git a/src/coreComponents/schema/docs/FiniteElements_other.rst b/src/coreComponents/schema/docs/FiniteElements_other.rst deleted file mode 100644 index 2c1625e9f5a..00000000000 --- a/src/coreComponents/schema/docs/FiniteElements_other.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -========================= ==== ============================================== -Name Type Description -========================= ==== ============================================== -FiniteElementSpace node :ref:`DATASTRUCTURE_FiniteElementSpace` -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -========================= ==== ============================================== - - diff --git a/src/coreComponents/schema/docs/FiniteVolume.rst b/src/coreComponents/schema/docs/FiniteVolume.rst deleted file mode 100644 index 2eeb1baa188..00000000000 --- a/src/coreComponents/schema/docs/FiniteVolume.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -=========================== ==== ======= ====================================== -Name Type Default Description -=========================== ==== ======= ====================================== -HybridMimeticDiscretization node :ref:`XML_HybridMimeticDiscretization` -TwoPointFluxApproximation node :ref:`XML_TwoPointFluxApproximation` -=========================== ==== ======= ====================================== - - diff --git a/src/coreComponents/schema/docs/FiniteVolume_other.rst b/src/coreComponents/schema/docs/FiniteVolume_other.rst deleted file mode 100644 index f72f9ada3c7..00000000000 --- a/src/coreComponents/schema/docs/FiniteVolume_other.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -=========================== ==== ================================================ -Name Type Description -=========================== ==== ================================================ -HybridMimeticDiscretization node :ref:`DATASTRUCTURE_HybridMimeticDiscretization` -TwoPointFluxApproximation node :ref:`DATASTRUCTURE_TwoPointFluxApproximation` -=========================== ==== ================================================ - - diff --git a/src/coreComponents/schema/docs/FlowProppantTransport.rst b/src/coreComponents/schema/docs/FlowProppantTransport.rst deleted file mode 100644 index c9f1110c6fa..00000000000 --- a/src/coreComponents/schema/docs/FlowProppantTransport.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -flowSolverName groupNameRef required Name of the flow solver used by the coupled solver -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -proppantSolverName groupNameRef required Name of the proppant solver used by the coupled solver -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/FlowProppantTransport_other.rst b/src/coreComponents/schema/docs/FlowProppantTransport_other.rst deleted file mode 100644 index 45d9a187f0a..00000000000 --- a/src/coreComponents/schema/docs/FlowProppantTransport_other.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/FrictionlessContact.rst b/src/coreComponents/schema/docs/FrictionlessContact.rst deleted file mode 100644 index 385d3738b2a..00000000000 --- a/src/coreComponents/schema/docs/FrictionlessContact.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -========================= ============ =========== ============================================================================================================================================================================================================================================================================================================================================================================================================================================================= -Name Type Default Description -========================= ============ =========== ============================================================================================================================================================================================================================================================================================================================================================================================================================================================= -apertureTableName groupNameRef required Name of the aperture table -apertureTolerance real64 1e-09 Value to be used to avoid floating point errors in expressions involving aperture. For example in the case of dividing by the actual aperture (not the effective aperture that results from the aperture function) this value may be used to avoid the 1/0 error. Note that this value may have some physical significance in its usage, as it may be used to smooth out highly nonlinear behavior associated with 1/0 in addition to avoiding the 1/0 error. -displacementJumpThreshold real64 2.22045e-16 A threshold valued to determine whether a fracture is open or not. -name groupName required A name is required for any non-unique nodes -penaltyStiffness real64 0 Value of the penetration penalty stiffness. Units of Pressure/length -shearStiffness real64 0 Value of the shear elastic stiffness. Units of Pressure/length -========================= ============ =========== ============================================================================================================================================================================================================================================================================================================================================================================================================================================================= - - diff --git a/src/coreComponents/schema/docs/FrictionlessContact_other.rst b/src/coreComponents/schema/docs/FrictionlessContact_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/FrictionlessContact_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/Functions.rst b/src/coreComponents/schema/docs/Functions.rst deleted file mode 100644 index 7f0ec63e038..00000000000 --- a/src/coreComponents/schema/docs/Functions.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -========================== ==== ======= ===================================== -Name Type Default Description -========================== ==== ======= ===================================== -CompositeFunction node :ref:`XML_CompositeFunction` -MultivariableTableFunction node :ref:`XML_MultivariableTableFunction` -SymbolicFunction node :ref:`XML_SymbolicFunction` -TableFunction node :ref:`XML_TableFunction` -========================== ==== ======= ===================================== - - diff --git a/src/coreComponents/schema/docs/Functions_other.rst b/src/coreComponents/schema/docs/Functions_other.rst deleted file mode 100644 index 93d4ce21f6c..00000000000 --- a/src/coreComponents/schema/docs/Functions_other.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -========================== ==== =============================================== -Name Type Description -========================== ==== =============================================== -CompositeFunction node :ref:`DATASTRUCTURE_CompositeFunction` -MultivariableTableFunction node :ref:`DATASTRUCTURE_MultivariableTableFunction` -SymbolicFunction node :ref:`DATASTRUCTURE_SymbolicFunction` -TableFunction node :ref:`DATASTRUCTURE_TableFunction` -========================== ==== =============================================== - - diff --git a/src/coreComponents/schema/docs/Geometry.rst b/src/coreComponents/schema/docs/Geometry.rst deleted file mode 100644 index 43bc76a5f42..00000000000 --- a/src/coreComponents/schema/docs/Geometry.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -================= ==== ======= ============================ -Name Type Default Description -================= ==== ======= ============================ -Box node :ref:`XML_Box` -CustomPolarObject node :ref:`XML_CustomPolarObject` -Cylinder node :ref:`XML_Cylinder` -Disc node :ref:`XML_Disc` -Rectangle node :ref:`XML_Rectangle` -ThickPlane node :ref:`XML_ThickPlane` -================= ==== ======= ============================ - - diff --git a/src/coreComponents/schema/docs/Geometry_other.rst b/src/coreComponents/schema/docs/Geometry_other.rst deleted file mode 100644 index af15f983b0a..00000000000 --- a/src/coreComponents/schema/docs/Geometry_other.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -================= ==== ====================================== -Name Type Description -================= ==== ====================================== -Box node :ref:`DATASTRUCTURE_Box` -CustomPolarObject node :ref:`DATASTRUCTURE_CustomPolarObject` -Cylinder node :ref:`DATASTRUCTURE_Cylinder` -Disc node :ref:`DATASTRUCTURE_Disc` -Rectangle node :ref:`DATASTRUCTURE_Rectangle` -ThickPlane node :ref:`DATASTRUCTURE_ThickPlane` -================= ==== ====================================== - - diff --git a/src/coreComponents/schema/docs/HaltEvent.rst b/src/coreComponents/schema/docs/HaltEvent.rst deleted file mode 100644 index de2a154b525..00000000000 --- a/src/coreComponents/schema/docs/HaltEvent.rst +++ /dev/null @@ -1,21 +0,0 @@ - - -==================== ============ ======== ===================================================================================================================== -Name Type Default Description -==================== ============ ======== ===================================================================================================================== -beginTime real64 0 Start time of this event. -endTime real64 1e+100 End time of this event. -finalDtStretch real64 0.001 Allow the final dt request for this event to grow by this percentage to match the endTime exactly. -forceDt real64 -1 While active, this event will request this timestep value (ignoring any children/targets requests). -logLevel integer 0 Log level -maxEventDt real64 -1 While active, this event will request a timestep <= this value (depending upon any child/target requests). -maxRuntime real64 required The maximum allowable runtime for the job. -name groupName required A name is required for any non-unique nodes -target groupNameRef Name of the object to be executed when the event criteria are met. -targetExactStartStop integer 1 If this option is set, the event will reduce its timestep requests to match any specified beginTime/endTimes exactly. -HaltEvent node :ref:`XML_HaltEvent` -PeriodicEvent node :ref:`XML_PeriodicEvent` -SoloEvent node :ref:`XML_SoloEvent` -==================== ============ ======== ===================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/HaltEvent_other.rst b/src/coreComponents/schema/docs/HaltEvent_other.rst deleted file mode 100644 index f63756dd49b..00000000000 --- a/src/coreComponents/schema/docs/HaltEvent_other.rst +++ /dev/null @@ -1,16 +0,0 @@ - - -================= ======= =============================================== -Name Type Description -================= ======= =============================================== -currentSubEvent integer Index of the current subevent -eventForecast integer Indicates when the event is expected to execute -isTargetExecuting integer Index of the current subevent -lastCycle integer Last event occurrence (cycle) -lastTime real64 Last event occurrence (time) -HaltEvent node :ref:`DATASTRUCTURE_HaltEvent` -PeriodicEvent node :ref:`DATASTRUCTURE_PeriodicEvent` -SoloEvent node :ref:`DATASTRUCTURE_SoloEvent` -================= ======= =============================================== - - diff --git a/src/coreComponents/schema/docs/HybridMimeticDiscretization.rst b/src/coreComponents/schema/docs/HybridMimeticDiscretization.rst deleted file mode 100644 index 1ada365b75a..00000000000 --- a/src/coreComponents/schema/docs/HybridMimeticDiscretization.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -================ ========= ======== =================================================== -Name Type Default Description -================ ========= ======== =================================================== -innerProductType string required Type of inner product used in the hybrid FVM solver -name groupName required A name is required for any non-unique nodes -================ ========= ======== =================================================== - - diff --git a/src/coreComponents/schema/docs/HybridMimeticDiscretization_other.rst b/src/coreComponents/schema/docs/HybridMimeticDiscretization_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/HybridMimeticDiscretization_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/Hydrofracture.rst b/src/coreComponents/schema/docs/Hydrofracture.rst deleted file mode 100644 index c65d103f356..00000000000 --- a/src/coreComponents/schema/docs/Hydrofracture.rst +++ /dev/null @@ -1,23 +0,0 @@ - - -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -contactRelationName groupNameRef required Name of contact relation to enforce constraints on fracture boundary. -flowSolverName groupNameRef required Name of the flow solver used by the coupled solver -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isMatrixPoroelastic integer 0 (no description available) -isThermal integer 0 Flag indicating whether the problem is thermal or not. Set isThermal="1" to enable the thermal coupling -logLevel integer 0 Log level -maxNumResolves integer 10 Value to indicate how many resolves may be executed to perform surface generation after the execution of flow and mechanics solver. -name groupName required A name is required for any non-unique nodes -solidSolverName groupNameRef required Name of the solid solver used by the coupled solver -surfaceGeneratorName groupNameRef required Name of the surface generator to use in the hydrofracture solver -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -useQuasiNewton integer 0 (no description available) -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/Hydrofracture_other.rst b/src/coreComponents/schema/docs/Hydrofracture_other.rst deleted file mode 100644 index 80b71ab722d..00000000000 --- a/src/coreComponents/schema/docs/Hydrofracture_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -performStressInitialization integer Flag to indicate that the solver is going to perform stress initialization -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/HydrostaticEquilibrium.rst b/src/coreComponents/schema/docs/HydrostaticEquilibrium.rst deleted file mode 100644 index 3b1f86b4003..00000000000 --- a/src/coreComponents/schema/docs/HydrostaticEquilibrium.rst +++ /dev/null @@ -1,26 +0,0 @@ - - -============================================ ================== ======== ==================================================================================================== -Name Type Default Description -============================================ ================== ======== ==================================================================================================== -bcApplicationTableName groupNameRef Name of table that specifies the on/off application of the boundary condition. -beginTime real64 -1e+99 Time at which the boundary condition will start being applied. -componentFractionVsElevationTableNames groupNameRef_array {} Names of the tables specifying the (component fraction vs elevation) relationship for each component -componentNames string_array {} Names of the fluid components -datumElevation real64 required Datum elevation [m] -datumPressure real64 required Datum pressure [Pa] -direction R1Tensor {0,0,0} Direction to apply boundary condition to. -elevationIncrementInHydrostaticPressureTable real64 0.6096 Elevation increment [m] in the hydrostatic pressure table constructed internally -endTime real64 1e+99 Time at which the boundary condition will stop being applied. -equilibrationTolerance real64 0.001 Tolerance in the fixed-point iteration scheme used for hydrostatic initialization -functionName groupNameRef Name of function that specifies variation of the boundary condition. -initialPhaseName groupNameRef Name of the phase initially saturating the reservoir -logLevel integer 0 Log level -maxNumberOfEquilibrationIterations integer 5 Maximum number of equilibration iterations -name groupName required A name is required for any non-unique nodes -objectPath groupNameRef Path to the target field -scale real64 0 Scale factor for value of the boundary condition. -temperatureVsElevationTableName groupNameRef Name of the table specifying the (temperature [K] vs elevation) relationship -============================================ ================== ======== ==================================================================================================== - - diff --git a/src/coreComponents/schema/docs/HydrostaticEquilibrium_other.rst b/src/coreComponents/schema/docs/HydrostaticEquilibrium_other.rst deleted file mode 100644 index 57ad4f17a8c..00000000000 --- a/src/coreComponents/schema/docs/HydrostaticEquilibrium_other.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -================ ================== ============================================================== -Name Type Description -================ ================== ============================================================== -component integer Component of field (if tensor) to apply boundary condition to. -fieldName groupNameRef Name of field that boundary condition is applied to. -initialCondition integer Boundary condition is applied as an initial condition. -setNames groupNameRef_array Name of sets that boundary condition is applied to. -================ ================== ============================================================== - - diff --git a/src/coreComponents/schema/docs/Included.rst b/src/coreComponents/schema/docs/Included.rst deleted file mode 100644 index c3b01961df6..00000000000 --- a/src/coreComponents/schema/docs/Included.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ======= =============== -Name Type Default Description -==== ==== ======= =============== -File node :ref:`XML_File` -==== ==== ======= =============== - - diff --git a/src/coreComponents/schema/docs/Included_other.rst b/src/coreComponents/schema/docs/Included_other.rst deleted file mode 100644 index 2fbd25975df..00000000000 --- a/src/coreComponents/schema/docs/Included_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ========================= -Name Type Description -==== ==== ========================= -File node :ref:`DATASTRUCTURE_File` -==== ==== ========================= - - diff --git a/src/coreComponents/schema/docs/InternalMesh.rst b/src/coreComponents/schema/docs/InternalMesh.rst deleted file mode 100644 index c8de2fad08c..00000000000 --- a/src/coreComponents/schema/docs/InternalMesh.rst +++ /dev/null @@ -1,24 +0,0 @@ - - -================= ================== ======== ======================================================================================================= -Name Type Default Description -================= ================== ======== ======================================================================================================= -cellBlockNames groupNameRef_array required Names of each mesh block -elementTypes string_array required Element types of each mesh block -name groupName required A name is required for any non-unique nodes -nx integer_array required Number of elements in the x-direction within each mesh block -ny integer_array required Number of elements in the y-direction within each mesh block -nz integer_array required Number of elements in the z-direction within each mesh block -positionTolerance real64 1e-10 A position tolerance to verify if a node belong to a nodeset -trianglePattern integer 0 Pattern by which to decompose the hex mesh into wedges -xBias real64_array {1} Bias of element sizes in the x-direction within each mesh block (dx_left=(1+b)*L/N, dx_right=(1-b)*L/N) -xCoords real64_array required x-coordinates of each mesh block vertex -yBias real64_array {1} Bias of element sizes in the y-direction within each mesh block (dy_left=(1+b)*L/N, dx_right=(1-b)*L/N) -yCoords real64_array required y-coordinates of each mesh block vertex -zBias real64_array {1} Bias of element sizes in the z-direction within each mesh block (dz_left=(1+b)*L/N, dz_right=(1-b)*L/N) -zCoords real64_array required z-coordinates of each mesh block vertex -InternalWell node :ref:`XML_InternalWell` -VTKWell node :ref:`XML_VTKWell` -================= ================== ======== ======================================================================================================= - - diff --git a/src/coreComponents/schema/docs/InternalMesh_other.rst b/src/coreComponents/schema/docs/InternalMesh_other.rst deleted file mode 100644 index 8ca4f02bc36..00000000000 --- a/src/coreComponents/schema/docs/InternalMesh_other.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -============ ==== ================================= -Name Type Description -============ ==== ================================= -InternalWell node :ref:`DATASTRUCTURE_InternalWell` -VTKWell node :ref:`DATASTRUCTURE_VTKWell` -meshLevels node :ref:`DATASTRUCTURE_meshLevels` -============ ==== ================================= - - diff --git a/src/coreComponents/schema/docs/InternalWell.rst b/src/coreComponents/schema/docs/InternalWell.rst deleted file mode 100644 index bb26958fc59..00000000000 --- a/src/coreComponents/schema/docs/InternalWell.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -===================== =================== ======== ==================================================================================================== -Name Type Default Description -===================== =================== ======== ==================================================================================================== -logLevel integer 0 Log level -minElementLength real64 0.001 Minimum length of a well element, computed as (segment length / number of elements per segment ) [m] -minSegmentLength real64 0.01 Minimum length of a well segment [m] -name groupName required A name is required for any non-unique nodes -numElementsPerSegment integer required Number of well elements per polyline segment -polylineNodeCoords real64_array2d required Physical coordinates of the well polyline nodes -polylineSegmentConn globalIndex_array2d required Connectivity of the polyline segments -radius real64 required Radius of the well [m] -wellControlsName string required Name of the set of constraints associated with this well -wellRegionName string required Name of the well element region -Perforation node :ref:`XML_Perforation` -===================== =================== ======== ==================================================================================================== - - diff --git a/src/coreComponents/schema/docs/InternalWell_other.rst b/src/coreComponents/schema/docs/InternalWell_other.rst deleted file mode 100644 index 638cc779598..00000000000 --- a/src/coreComponents/schema/docs/InternalWell_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -=========== ==== ================================ -Name Type Description -=========== ==== ================================ -Perforation node :ref:`DATASTRUCTURE_Perforation` -=========== ==== ================================ - - diff --git a/src/coreComponents/schema/docs/InternalWellbore.rst b/src/coreComponents/schema/docs/InternalWellbore.rst deleted file mode 100644 index d9e3151e2f9..00000000000 --- a/src/coreComponents/schema/docs/InternalWellbore.rst +++ /dev/null @@ -1,30 +0,0 @@ - - -=========================== ================== ======== ============================================================================================================================================================================================================================ -Name Type Default Description -=========================== ================== ======== ============================================================================================================================================================================================================================ -autoSpaceRadialElems real64_array {-1} Automatically set number and spacing of elements in the radial direction. This overrides the values of nr!Value in each block indicates factor to scale the radial increment.Larger numbers indicate larger radial elements. -cartesianMappingInnerRadius real64 1e+99 If using a Cartesian aligned outer boundary, this is inner radius at which to start the mapping. -cellBlockNames groupNameRef_array required Names of each mesh block -elementTypes string_array required Element types of each mesh block -hardRadialCoords real64_array {0} Sets the radial spacing to specified values -name groupName required A name is required for any non-unique nodes -nr integer_array required Number of elements in the radial direction -nt integer_array required Number of elements in the tangent direction -nz integer_array required Number of elements in the z-direction within each mesh block -positionTolerance real64 1e-10 A position tolerance to verify if a node belong to a nodeset -rBias real64_array {-0.8} Bias of element sizes in the radial direction -radius real64_array required Wellbore radius -theta real64_array required Tangent angle defining geometry size: 90 for quarter, 180 for half and 360 for full wellbore geometry -trajectory real64_array2d {{0}} Coordinates defining the wellbore trajectory -trianglePattern integer 0 Pattern by which to decompose the hex mesh into wedges -useCartesianOuterBoundary integer 1000000 Enforce a Cartesian aligned outer boundary on the outer block starting with the radial block specified in this value -xBias real64_array {1} Bias of element sizes in the x-direction within each mesh block (dx_left=(1+b)*L/N, dx_right=(1-b)*L/N) -yBias real64_array {1} Bias of element sizes in the y-direction within each mesh block (dy_left=(1+b)*L/N, dx_right=(1-b)*L/N) -zBias real64_array {1} Bias of element sizes in the z-direction within each mesh block (dz_left=(1+b)*L/N, dz_right=(1-b)*L/N) -zCoords real64_array required z-coordinates of each mesh block vertex -InternalWell node :ref:`XML_InternalWell` -VTKWell node :ref:`XML_VTKWell` -=========================== ================== ======== ============================================================================================================================================================================================================================ - - diff --git a/src/coreComponents/schema/docs/InternalWellbore_other.rst b/src/coreComponents/schema/docs/InternalWellbore_other.rst deleted file mode 100644 index 14901e94dac..00000000000 --- a/src/coreComponents/schema/docs/InternalWellbore_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -============ ============= ============================================================ -Name Type Description -============ ============= ============================================================ -nx integer_array Number of elements in the x-direction within each mesh block -ny integer_array Number of elements in the y-direction within each mesh block -xCoords real64_array x-coordinates of each mesh block vertex -yCoords real64_array y-coordinates of each mesh block vertex -InternalWell node :ref:`DATASTRUCTURE_InternalWell` -VTKWell node :ref:`DATASTRUCTURE_VTKWell` -meshLevels node :ref:`DATASTRUCTURE_meshLevels` -============ ============= ============================================================ - - diff --git a/src/coreComponents/schema/docs/JFunctionCapillaryPressure.rst b/src/coreComponents/schema/docs/JFunctionCapillaryPressure.rst deleted file mode 100644 index 5f42b347615..00000000000 --- a/src/coreComponents/schema/docs/JFunctionCapillaryPressure.rst +++ /dev/null @@ -1,38 +0,0 @@ - - -======================================== ================================================================== ======== ========================================================================================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -======================================== ================================================================== ======== ========================================================================================================================================================================================================================================================================================================================================================================================== -name groupName required A name is required for any non-unique nodes -nonWettingIntermediateJFunctionTableName groupNameRef | J-function table (dimensionless) for the pair (non-wetting phase, intermediate phase) - | Note that this input is only used for three-phase flow. - | If you want to do a two-phase simulation, please use instead wettingNonWettingJFunctionTableName to specify the table names. -nonWettingIntermediateSurfaceTension real64 0 | Surface tension [N/m] for the pair (non-wetting phase, intermediate phase) - | If you have a value in [dyne/cm], divide it by 1000 to obtain the value in [N/m] - | Note that this input is only used for three-phase flow. - | If you want to do a two-phase simulation, please use instead wettingNonWettingSurfaceTension to specify the surface tensions. -permeabilityDirection geos_constitutive_JFunctionCapillaryPressure_PermeabilityDirection required | Permeability direction. Options are: - | XY - use the average of the permeabilities in the x and y directions, - | X - only use the permeability in the x direction, - | Y - only use the permeability in the y direction, - | Z - only use the permeability in the z direction. -permeabilityExponent real64 0.5 Permeability exponent -phaseNames groupNameRef_array required List of fluid phases -porosityExponent real64 0.5 Porosity exponent -wettingIntermediateJFunctionTableName groupNameRef | J-function table (dimensionless) for the pair (wetting phase, intermediate phase) - | Note that this input is only used for three-phase flow. - | If you want to do a two-phase simulation, please use instead wettingNonWettingJFunctionTableName to specify the table names. -wettingIntermediateSurfaceTension real64 0 | Surface tension [N/m] for the pair (wetting phase, intermediate phase) - | If you have a value in [dyne/cm], divide it by 1000 to obtain the value in [N/m] - | Note that this input is only used for three-phase flow. - | If you want to do a two-phase simulation, please use instead wettingNonWettingSurfaceTension to specify the surface tensions. -wettingNonWettingJFunctionTableName groupNameRef | J-function table (dimensionless) for the pair (wetting phase, non-wetting phase) - | Note that this input is only used for two-phase flow. - | If you want to do a three-phase simulation, please use instead wettingIntermediateJFunctionTableName and nonWettingIntermediateJFunctionTableName to specify the table names. -wettingNonWettingSurfaceTension real64 0 | Surface tension [N/m] for the pair (wetting phase, non-wetting phase) - | If you have a value in [dyne/cm], divide it by 1000 to obtain the value in [N/m] - | Note that this input is only used for two-phase flow. - | If you want to do a three-phase simulation, please use instead wettingIntermediateSurfaceTension and nonWettingIntermediateSurfaceTension to specify the surface tensions. -======================================== ================================================================== ======== ========================================================================================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/JFunctionCapillaryPressure_other.rst b/src/coreComponents/schema/docs/JFunctionCapillaryPressure_other.rst deleted file mode 100644 index 68708936927..00000000000 --- a/src/coreComponents/schema/docs/JFunctionCapillaryPressure_other.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -=================================== ======================================================================================================= ============================================================================ -Name Type Description -=================================== ======================================================================================================= ============================================================================ -dPhaseCapPressure_dPhaseVolFraction real64_array4d Derivative of phase capillary pressure with respect to phase volume fraction -jFuncMultiplier real64_array2d Multiplier for the Leverett J-function -jFunctionWrappers LvArray_Array< geos_TableFunction_KernelWrapper, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer > (no description available) -phaseCapPressure real64_array3d Phase capillary pressure -phaseOrder integer_array (no description available) -phaseTypes integer_array (no description available) -=================================== ======================================================================================================= ============================================================================ - - diff --git a/src/coreComponents/schema/docs/LaplaceFEM.rst b/src/coreComponents/schema/docs/LaplaceFEM.rst deleted file mode 100644 index 2353f6bde5f..00000000000 --- a/src/coreComponents/schema/docs/LaplaceFEM.rst +++ /dev/null @@ -1,20 +0,0 @@ - - -========================= ======================================== ======== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ======================================== ======== ======================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -fieldName groupNameRef required Name of field variable -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -timeIntegrationOption geos_LaplaceBaseH1_TimeIntegrationOption required | Time integration method. Options are: - | * SteadyState - | * ImplicitTransient -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ======================================== ======== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/LaplaceFEM_other.rst b/src/coreComponents/schema/docs/LaplaceFEM_other.rst deleted file mode 100644 index 3f1b37c3d6c..00000000000 --- a/src/coreComponents/schema/docs/LaplaceFEM_other.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -========================= ============================================================================================================================================================== ================================================================ -Name Type Description -========================= ============================================================================================================================================================== ================================================================ -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ================================================================ - - diff --git a/src/coreComponents/schema/docs/Level0_other.rst b/src/coreComponents/schema/docs/Level0_other.rst deleted file mode 100644 index 14597cbcd99..00000000000 --- a/src/coreComponents/schema/docs/Level0_other.rst +++ /dev/null @@ -1,16 +0,0 @@ - - -=========================== ======= ================================================ -Name Type Description -=========================== ======= ================================================ -meshLevel integer (no description available) -ElementRegions node :ref:`DATASTRUCTURE_ElementRegions` -ParticleRegions node :ref:`DATASTRUCTURE_ParticleRegions` -edgeManager node :ref:`DATASTRUCTURE_edgeManager` -embeddedSurfacesEdgeManager node :ref:`DATASTRUCTURE_embeddedSurfacesEdgeManager` -embeddedSurfacesNodeManager node :ref:`DATASTRUCTURE_embeddedSurfacesNodeManager` -faceManager node :ref:`DATASTRUCTURE_faceManager` -nodeManager node :ref:`DATASTRUCTURE_nodeManager` -=========================== ======= ================================================ - - diff --git a/src/coreComponents/schema/docs/LinearIsotropicDispersion.rst b/src/coreComponents/schema/docs/LinearIsotropicDispersion.rst deleted file mode 100644 index 705ac240c42..00000000000 --- a/src/coreComponents/schema/docs/LinearIsotropicDispersion.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -======================== ========= ======== =========================================== -Name Type Default Description -======================== ========= ======== =========================================== -longitudinalDispersivity real64 required Longitudinal dispersivity [m] -name groupName required A name is required for any non-unique nodes -======================== ========= ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/LinearIsotropicDispersion_other.rst b/src/coreComponents/schema/docs/LinearIsotropicDispersion_other.rst deleted file mode 100644 index 27d657ba903..00000000000 --- a/src/coreComponents/schema/docs/LinearIsotropicDispersion_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -============ ============== ============ -Name Type Description -============ ============== ============ -dispersivity real64_array3d Dispersivity -============ ============== ============ - - diff --git a/src/coreComponents/schema/docs/LinearSolverParameters.rst b/src/coreComponents/schema/docs/LinearSolverParameters.rst deleted file mode 100644 index 67d62e850dd..00000000000 --- a/src/coreComponents/schema/docs/LinearSolverParameters.rst +++ /dev/null @@ -1,43 +0,0 @@ - - -============================= ============================================== ============= ======================================================================================================================================================================================================================================================================================================================= -Name Type Default Description -============================= ============================================== ============= ======================================================================================================================================================================================================================================================================================================================= -amgAggressiveCoarseningLevels integer 0 AMG number of levels for aggressive coarsening -amgAggressiveCoarseningPaths integer 1 AMG number of paths for aggressive coarsening -amgAggressiveInterpType geos_LinearSolverParameters_AMG_AggInterpType multipass AMG aggressive interpolation algorithm. Available options are: ``default\|extendedIStage2\|standardStage2\|extendedStage2\|multipass\|modifiedExtended\|modifiedExtendedI\|modifiedExtendedE\|modifiedMultipass`` -amgCoarseSolver geos_LinearSolverParameters_AMG_CoarseType direct AMG coarsest level solver/smoother type. Available options are: ``default\|jacobi\|l1jacobi\|fgs\|sgs\|l1sgs\|chebyshev\|direct\|bgs`` -amgCoarseningType geos_LinearSolverParameters_AMG_CoarseningType HMIS AMG coarsening algorithm. Available options are: ``default\|CLJP\|RugeStueben\|Falgout\|PMIS\|HMIS`` -amgInterpolationMaxNonZeros integer 4 AMG interpolation maximum number of nonzeros per row -amgInterpolationType geos_LinearSolverParameters_AMG_InterpType extendedI AMG interpolation algorithm. Available options are: ``default\|modifiedClassical\|direct\|multipass\|extendedI\|standard\|extended\|directBAMG\|modifiedExtended\|modifiedExtendedI\|modifiedExtendedE`` -amgNullSpaceType geos_LinearSolverParameters_AMG_NullSpaceType constantModes AMG near null space approximation. Available options are:``constantModes\|rigidBodyModes`` -amgNumFunctions integer 1 AMG number of functions -amgNumSweeps integer 1 AMG smoother sweeps -amgRelaxWeight real64 1 AMG relaxation factor for the smoother -amgSeparateComponents integer 0 AMG apply separate component filter for multi-variable problems -amgSmootherType geos_LinearSolverParameters_AMG_SmootherType l1sgs AMG smoother type. Available options are: ``default\|jacobi\|l1jacobi\|fgs\|bgs\|sgs\|l1sgs\|chebyshev\|ilu0\|ilut\|ic0\|ict`` -amgThreshold real64 0 AMG strength-of-connection threshold -directCheckResidual integer 0 Whether to check the linear system solution residual -directColPerm geos_LinearSolverParameters_Direct_ColPerm metis How to permute the columns. Available options are: ``none\|MMD_AtplusA\|MMD_AtA\|colAMD\|metis\|parmetis`` -directEquil integer 1 Whether to scale the rows and columns of the matrix -directIterRef integer 1 Whether to perform iterative refinement -directParallel integer 1 Whether to use a parallel solver (instead of a serial one) -directReplTinyPivot integer 1 Whether to replace tiny pivots by sqrt(epsilon)*norm(A) -directRowPerm geos_LinearSolverParameters_Direct_RowPerm mc64 How to permute the rows. Available options are: ``none\|mc64`` -iluFill integer 0 ILU(K) fill factor -iluThreshold real64 0 ILU(T) threshold factor -krylovAdaptiveTol integer 0 Use Eisenstat-Walker adaptive linear tolerance -krylovMaxIter integer 200 Maximum iterations allowed for an iterative solver -krylovMaxRestart integer 200 Maximum iterations before restart (GMRES only) -krylovTol real64 1e-06 | Relative convergence tolerance of the iterative method - | If the method converges, the iterative solution :math:`\mathsf{x}_k` is such that - | the relative residual norm satisfies: - | :math:`\left\lVert \mathsf{b} - \mathsf{A} \mathsf{x}_k \right\rVert_2` < ``krylovTol`` * :math:`\left\lVert\mathsf{b}\right\rVert_2` -krylovWeakestTol real64 0.001 Weakest-allowed tolerance for adaptive method -logLevel integer 0 Log level -preconditionerType geos_LinearSolverParameters_PreconditionerType iluk Preconditioner type. Available options are: ``none\|jacobi\|l1jacobi\|fgs\|sgs\|l1sgs\|chebyshev\|iluk\|ilut\|icc\|ict\|amg\|mgr\|block\|direct\|bgs`` -solverType geos_LinearSolverParameters_SolverType direct Linear solver type. Available options are: ``direct\|cg\|gmres\|fgmres\|bicgstab\|preconditioner`` -stopIfError integer 1 Whether to stop the simulation if the linear solver reports an error -============================= ============================================== ============= ======================================================================================================================================================================================================================================================================================================================= - - diff --git a/src/coreComponents/schema/docs/LinearSolverParameters_other.rst b/src/coreComponents/schema/docs/LinearSolverParameters_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/LinearSolverParameters_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/Mesh.rst b/src/coreComponents/schema/docs/Mesh.rst deleted file mode 100644 index b64bf1d9e19..00000000000 --- a/src/coreComponents/schema/docs/Mesh.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -================ ==== ======= =========================== -Name Type Default Description -================ ==== ======= =========================== -InternalMesh node :ref:`XML_InternalMesh` -InternalWellbore node :ref:`XML_InternalWellbore` -ParticleMesh node :ref:`XML_ParticleMesh` -VTKMesh node :ref:`XML_VTKMesh` -================ ==== ======= =========================== - - diff --git a/src/coreComponents/schema/docs/MeshBodies_other.rst b/src/coreComponents/schema/docs/MeshBodies_other.rst deleted file mode 100644 index 03f870a1bdc..00000000000 --- a/src/coreComponents/schema/docs/MeshBodies_other.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -================ ==== ===================================== -Name Type Description -================ ==== ===================================== -InternalMesh node :ref:`DATASTRUCTURE_InternalMesh` -InternalWellbore node :ref:`DATASTRUCTURE_InternalWellbore` -ParticleMesh node :ref:`DATASTRUCTURE_ParticleMesh` -VTKMesh node :ref:`DATASTRUCTURE_VTKMesh` -================ ==== ===================================== - - diff --git a/src/coreComponents/schema/docs/Mesh_other.rst b/src/coreComponents/schema/docs/Mesh_other.rst deleted file mode 100644 index 03f870a1bdc..00000000000 --- a/src/coreComponents/schema/docs/Mesh_other.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -================ ==== ===================================== -Name Type Description -================ ==== ===================================== -InternalMesh node :ref:`DATASTRUCTURE_InternalMesh` -InternalWellbore node :ref:`DATASTRUCTURE_InternalWellbore` -ParticleMesh node :ref:`DATASTRUCTURE_ParticleMesh` -VTKMesh node :ref:`DATASTRUCTURE_VTKMesh` -================ ==== ===================================== - - diff --git a/src/coreComponents/schema/docs/ModifiedCamClay.rst b/src/coreComponents/schema/docs/ModifiedCamClay.rst deleted file mode 100644 index 1784d9660fb..00000000000 --- a/src/coreComponents/schema/docs/ModifiedCamClay.rst +++ /dev/null @@ -1,18 +0,0 @@ - - -=============================== ========= ======== ==================================================================== -Name Type Default Description -=============================== ========= ======== ==================================================================== -defaultCslSlope real64 1 Slope of the critical state line -defaultDensity real64 required Default Material Density -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultPreConsolidationPressure real64 -1.5 Initial preconsolidation pressure -defaultRecompressionIndex real64 0.002 Recompresion Index -defaultRefPressure real64 -1 Reference Pressure -defaultRefStrainVol real64 0 Reference Volumetric Strain -defaultShearModulus real64 -1 Elastic Shear Modulus Parameter -defaultVirginCompressionIndex real64 0.005 Virgin compression index -name groupName required A name is required for any non-unique nodes -=============================== ========= ======== ==================================================================== - - diff --git a/src/coreComponents/schema/docs/ModifiedCamClay_other.rst b/src/coreComponents/schema/docs/ModifiedCamClay_other.rst deleted file mode 100644 index 9cbfc0ba5ef..00000000000 --- a/src/coreComponents/schema/docs/ModifiedCamClay_other.rst +++ /dev/null @@ -1,20 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -cslSlope real64_array Slope of the critical state line -density real64_array2d Material Density -oldPreConsolidationPressure real64_array2d Old preconsolidation pressure -oldStress real64_array3d Previous Material Stress -preConsolidationPressure real64_array2d New preconsolidation pressure -recompressionIndex real64_array Recompression Index Field -refPressure real64 Reference Pressure Field -refStrainVol real64 Reference Volumetric Strain -shearModulus real64_array Elastic Shear Modulus -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -virginCompressionIndex real64_array Virgin compression index -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/MultiPhaseConstantThermalConductivity.rst b/src/coreComponents/schema/docs/MultiPhaseConstantThermalConductivity.rst deleted file mode 100644 index 6e3bc5a89be..00000000000 --- a/src/coreComponents/schema/docs/MultiPhaseConstantThermalConductivity.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -============================= ================== ======== =============================================================================== -Name Type Default Description -============================= ================== ======== =============================================================================== -name groupName required A name is required for any non-unique nodes -phaseNames groupNameRef_array required List of fluid phases -thermalConductivityComponents R1Tensor required xx, yy, and zz components of a diagonal thermal conductivity tensor [J/(s.m.K)] -============================= ================== ======== =============================================================================== - - diff --git a/src/coreComponents/schema/docs/MultiPhaseConstantThermalConductivity_other.rst b/src/coreComponents/schema/docs/MultiPhaseConstantThermalConductivity_other.rst deleted file mode 100644 index d05e1e4c5be..00000000000 --- a/src/coreComponents/schema/docs/MultiPhaseConstantThermalConductivity_other.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -======================================== ============== ========================================================================== -Name Type Description -======================================== ============== ========================================================================== -dEffectiveConductivity_dPhaseVolFraction real64_array4d Derivative of effective conductivity with respect to phase volume fraction -effectiveConductivity real64_array3d Effective conductivity -======================================== ============== ========================================================================== - - diff --git a/src/coreComponents/schema/docs/MultiPhaseVolumeWeightedThermalConductivity.rst b/src/coreComponents/schema/docs/MultiPhaseVolumeWeightedThermalConductivity.rst deleted file mode 100644 index 9e3b5842029..00000000000 --- a/src/coreComponents/schema/docs/MultiPhaseVolumeWeightedThermalConductivity.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -================================= ================== ======== ================================================================================== -Name Type Default Description -================================= ================== ======== ================================================================================== -name groupName required A name is required for any non-unique nodes -phaseNames groupNameRef_array required List of fluid phases -phaseThermalConductivity real64_array required Phase thermal conductivity [W/(m.K)] -rockThermalConductivityComponents R1Tensor required xx, yy, and zz components of a diagonal rock thermal conductivity tensor [W/(m.K)] -================================= ================== ======== ================================================================================== - - diff --git a/src/coreComponents/schema/docs/MultiPhaseVolumeWeightedThermalConductivity_other.rst b/src/coreComponents/schema/docs/MultiPhaseVolumeWeightedThermalConductivity_other.rst deleted file mode 100644 index 9884bfb7511..00000000000 --- a/src/coreComponents/schema/docs/MultiPhaseVolumeWeightedThermalConductivity_other.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -======================================== ============== ========================================================================== -Name Type Description -======================================== ============== ========================================================================== -dEffectiveConductivity_dPhaseVolFraction real64_array4d Derivative of effective conductivity with respect to phase volume fraction -effectiveConductivity real64_array3d Effective conductivity -rockThermalConductivity real64_array3d Rock thermal conductivity -======================================== ============== ========================================================================== - - diff --git a/src/coreComponents/schema/docs/MultiphasePoromechanics.rst b/src/coreComponents/schema/docs/MultiphasePoromechanics.rst deleted file mode 100644 index 8ce423105cc..00000000000 --- a/src/coreComponents/schema/docs/MultiphasePoromechanics.rst +++ /dev/null @@ -1,24 +0,0 @@ - - -========================= ==================================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ==================================== ======== ====================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -flowSolverName groupNameRef required Name of the flow solver used by the coupled solver -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isThermal integer 0 Flag indicating whether the problem is thermal or not. Set isThermal="1" to enable the thermal coupling -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -solidSolverName groupNameRef required Name of the solid solver used by the coupled solver -stabilizationMultiplier real64 1 Constant multiplier of stabilization strength. -stabilizationRegionNames groupNameRef_array {} Regions where stabilization is applied. -stabilizationType geos_stabilization_StabilizationType None | Stabilization type. Options are: - | None - Add no stabilization to mass equation, - | Global - Add stabilization to all faces, - | Local - Add stabilization only to interiors of macro elements. -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ==================================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/MultiphasePoromechanicsInitialization.rst b/src/coreComponents/schema/docs/MultiphasePoromechanicsInitialization.rst deleted file mode 100644 index 27129634c0b..00000000000 --- a/src/coreComponents/schema/docs/MultiphasePoromechanicsInitialization.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -=========================== ============ ======== ========================================================================== -Name Type Default Description -=========================== ============ ======== ========================================================================== -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -performStressInitialization integer required Flag to indicate that the solver is going to perform stress initialization -poromechanicsSolverName groupNameRef required Name of the poromechanics solver -=========================== ============ ======== ========================================================================== - - diff --git a/src/coreComponents/schema/docs/MultiphasePoromechanicsInitialization_other.rst b/src/coreComponents/schema/docs/MultiphasePoromechanicsInitialization_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/MultiphasePoromechanicsInitialization_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/MultiphasePoromechanicsReservoir.rst b/src/coreComponents/schema/docs/MultiphasePoromechanicsReservoir.rst deleted file mode 100644 index b2ccf01c20b..00000000000 --- a/src/coreComponents/schema/docs/MultiphasePoromechanicsReservoir.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -poromechanicsSolverName groupNameRef required Name of the poromechanics solver used by the coupled solver -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -wellSolverName groupNameRef required Name of the well solver used by the coupled solver -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/MultiphasePoromechanicsReservoir_other.rst b/src/coreComponents/schema/docs/MultiphasePoromechanicsReservoir_other.rst deleted file mode 100644 index 45d9a187f0a..00000000000 --- a/src/coreComponents/schema/docs/MultiphasePoromechanicsReservoir_other.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/MultiphasePoromechanics_other.rst b/src/coreComponents/schema/docs/MultiphasePoromechanics_other.rst deleted file mode 100644 index 80b71ab722d..00000000000 --- a/src/coreComponents/schema/docs/MultiphasePoromechanics_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -performStressInitialization integer Flag to indicate that the solver is going to perform stress initialization -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/MultivariableTableFunction.rst b/src/coreComponents/schema/docs/MultivariableTableFunction.rst deleted file mode 100644 index e82bf5f8a22..00000000000 --- a/src/coreComponents/schema/docs/MultivariableTableFunction.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -============= ================== ======== =========================================== -Name Type Default Description -============= ================== ======== =========================================== -inputVarNames groupNameRef_array {} Name of fields are input to function. -name groupName required A name is required for any non-unique nodes -============= ================== ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/MultivariableTableFunction_other.rst b/src/coreComponents/schema/docs/MultivariableTableFunction_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/MultivariableTableFunction_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/NonlinearSolverParameters.rst b/src/coreComponents/schema/docs/NonlinearSolverParameters.rst deleted file mode 100644 index 0a48c42e401..00000000000 --- a/src/coreComponents/schema/docs/NonlinearSolverParameters.rst +++ /dev/null @@ -1,45 +0,0 @@ - - -============================== ============================================================= ============= =================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -============================== ============================================================= ============= =================================================================================================================================================================================================================================================================================================================== -allowNonConverged integer 0 Allow non-converged solution to be accepted. (i.e. exit from the Newton loop without achieving the desired tolerance) -couplingType geos_NonlinearSolverParameters_CouplingType FullyImplicit | Type of coupling. Valid options: - | * FullyImplicit - | * Sequential -lineSearchAction geos_NonlinearSolverParameters_LineSearchAction Attempt | How the line search is to be used. Options are: - | * None - Do not use line search. - | * Attempt - Use line search. Allow exit from line search without achieving smaller residual than starting residual. - | * Require - Use line search. If smaller residual than starting resdual is not achieved, cut time step. -lineSearchCutFactor real64 0.5 Line search cut factor. For instance, a value of 0.5 will result in the effective application of the last solution by a factor of (0.5, 0.25, 0.125, ...) -lineSearchInterpolationType geos_NonlinearSolverParameters_LineSearchInterpolationType Linear | Strategy to cut the solution update during the line search. Options are: - | * Linear - | * Parabolic -lineSearchMaxCuts integer 4 Maximum number of line search cuts. -lineSearchStartingIteration integer 0 Iteration when line search starts. -logLevel integer 0 Log level -maxAllowedResidualNorm real64 1e+09 Maximum value of residual norm that is allowed in a Newton loop -maxNumConfigurationAttempts integer 10 Max number of times that the configuration can be changed -maxSubSteps integer 10 Maximum number of time sub-steps allowed for the solver -maxTimeStepCuts integer 2 Max number of time step cuts -minNormalizer real64 1e-12 Value used to make sure that residual normalizers are not too small when computing residual norm. -newtonMaxIter integer 5 Maximum number of iterations that are allowed in a Newton loop. -newtonMinIter integer 1 Minimum number of iterations that are required before exiting the Newton loop. -newtonTol real64 1e-06 The required tolerance in order to exit the Newton iteration loop. -nonlinearAccelerationType geos_NonlinearSolverParameters_NonlinearAccelerationType None Nonlinear acceleration type for sequential solver. -normType geos_solverBaseKernels_NormType Linfinity | Norm used by the flow solver to check nonlinear convergence. Valid options: - | * Linfinity - | * L2 -sequentialConvergenceCriterion geos_NonlinearSolverParameters_SequentialConvergenceCriterion ResidualNorm | Criterion used to check outer-loop convergence in sequential schemes. Valid options: - | * ResidualNorm - | * NumberOfNonlinearIterations - | * SolutionIncrements -subcycling integer 0 Flag to decide whether to iterate between sequentially coupled solvers or not. -timeStepCutFactor real64 0.5 Factor by which the time step will be cut if a timestep cut is required. -timeStepDecreaseFactor real64 0.5 Factor by which the time step is decreased when the number of Newton iterations is large. -timeStepDecreaseIterLimit real64 0.7 Fraction of the max Newton iterations above which the solver asks for the time-step to be decreased for the next time step. -timeStepIncreaseFactor real64 2 Factor by which the time step is increased when the number of Newton iterations is small. -timeStepIncreaseIterLimit real64 0.4 Fraction of the max Newton iterations below which the solver asks for the time-step to be increased for the next time step. -============================== ============================================================= ============= =================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/NonlinearSolverParameters_other.rst b/src/coreComponents/schema/docs/NonlinearSolverParameters_other.rst deleted file mode 100644 index 4ead4f562eb..00000000000 --- a/src/coreComponents/schema/docs/NonlinearSolverParameters_other.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -======================== =============================== ============================================================================================== -Name Type Description -======================== =============================== ============================================================================================== -newtonNumberOfIterations integer Number of Newton's iterations. -normType geos_solverBaseKernels_NormType | Norm used by the flow solver to check nonlinear convergence. Valid options: - | * Linfinity - | * L2 -======================== =============================== ============================================================================================== - - diff --git a/src/coreComponents/schema/docs/NullModel.rst b/src/coreComponents/schema/docs/NullModel.rst deleted file mode 100644 index f6c735e1d91..00000000000 --- a/src/coreComponents/schema/docs/NullModel.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ========= ======== =========================================== -Name Type Default Description -==== ========= ======== =========================================== -name groupName required A name is required for any non-unique nodes -==== ========= ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/NullModel_other.rst b/src/coreComponents/schema/docs/NullModel_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/NullModel_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/NumericalMethods.rst b/src/coreComponents/schema/docs/NumericalMethods.rst deleted file mode 100644 index 8eacb5881ba..00000000000 --- a/src/coreComponents/schema/docs/NumericalMethods.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -============== ==== ======= ========================= -Name Type Default Description -============== ==== ======= ========================= -FiniteElements node unique :ref:`XML_FiniteElements` -FiniteVolume node unique :ref:`XML_FiniteVolume` -============== ==== ======= ========================= - - diff --git a/src/coreComponents/schema/docs/NumericalMethods_other.rst b/src/coreComponents/schema/docs/NumericalMethods_other.rst deleted file mode 100644 index 8db7a57c3d9..00000000000 --- a/src/coreComponents/schema/docs/NumericalMethods_other.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -============== ==== =================================== -Name Type Description -============== ==== =================================== -FiniteElements node :ref:`DATASTRUCTURE_FiniteElements` -FiniteVolume node :ref:`DATASTRUCTURE_FiniteVolume` -============== ==== =================================== - - diff --git a/src/coreComponents/schema/docs/Outputs.rst b/src/coreComponents/schema/docs/Outputs.rst deleted file mode 100644 index 9950b014151..00000000000 --- a/src/coreComponents/schema/docs/Outputs.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=========== ==== ======= ====================== -Name Type Default Description -=========== ==== ======= ====================== -Blueprint node :ref:`XML_Blueprint` -ChomboIO node :ref:`XML_ChomboIO` -Python node :ref:`XML_Python` -Restart node :ref:`XML_Restart` -Silo node :ref:`XML_Silo` -TimeHistory node :ref:`XML_TimeHistory` -VTK node :ref:`XML_VTK` -=========== ==== ======= ====================== - - diff --git a/src/coreComponents/schema/docs/Outputs_other.rst b/src/coreComponents/schema/docs/Outputs_other.rst deleted file mode 100644 index cbcc1b80401..00000000000 --- a/src/coreComponents/schema/docs/Outputs_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=========== ==== ================================ -Name Type Description -=========== ==== ================================ -Blueprint node :ref:`DATASTRUCTURE_Blueprint` -ChomboIO node :ref:`DATASTRUCTURE_ChomboIO` -Python node :ref:`DATASTRUCTURE_Python` -Restart node :ref:`DATASTRUCTURE_Restart` -Silo node :ref:`DATASTRUCTURE_Silo` -TimeHistory node :ref:`DATASTRUCTURE_TimeHistory` -VTK node :ref:`DATASTRUCTURE_VTK` -=========== ==== ================================ - - diff --git a/src/coreComponents/schema/docs/PML.rst b/src/coreComponents/schema/docs/PML.rst deleted file mode 100644 index 7aa79ed39a6..00000000000 --- a/src/coreComponents/schema/docs/PML.rst +++ /dev/null @@ -1,26 +0,0 @@ - - -====================== ================== ======================================== ================================================================================================== -Name Type Default Description -====================== ================== ======================================== ================================================================================================== -bcApplicationTableName groupNameRef Name of table that specifies the on/off application of the boundary condition. -beginTime real64 -1e+99 Time at which the boundary condition will start being applied. -component integer -1 Component of field (if tensor) to apply boundary condition to. -direction R1Tensor {0,0,0} Direction to apply boundary condition to. -endTime real64 1e+99 Time at which the boundary condition will stop being applied. -functionName groupNameRef Name of function that specifies variation of the boundary condition. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -objectPath groupNameRef Path to the target field -reflectivity real32 0.001 Desired reflectivity of the PML region, used to compute the damping profile -scale real64 0 Scale factor for value of the boundary condition. -setNames groupNameRef_array required Name of sets that boundary condition is applied to. -thicknessMaxXYZ R1Tensor32 {-1,-1,-1} Thickness of the PML region, at right, back, and bottom sides, used to compute the damping profile -thicknessMinXYZ R1Tensor32 {-1,-1,-1} Thickness of the PML region, at left, front, and top sides, used to compute the damping profile -waveSpeedMaxXYZ R1Tensor32 {-1,-1,-1} Wave speed in the PML, at right, back, and bottom sides, used to compute the damping profile -waveSpeedMinXYZ R1Tensor32 {-1,-1,-1} Wave speed in the PML, at left, front, and top sides, used to compute the damping profile -xMax R1Tensor32 {3.40282e+38,3.40282e+38,3.40282e+38} Maximum (x,y,z) coordinates of the inner PML boundaries -xMin R1Tensor32 {-3.40282e+38,-3.40282e+38,-3.40282e+38} Minimum (x,y,z) coordinates of the inner PML boundaries -====================== ================== ======================================== ================================================================================================== - - diff --git a/src/coreComponents/schema/docs/PML_other.rst b/src/coreComponents/schema/docs/PML_other.rst deleted file mode 100644 index 32f3b5042b3..00000000000 --- a/src/coreComponents/schema/docs/PML_other.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -================ ============ ====================================================== -Name Type Description -================ ============ ====================================================== -fieldName groupNameRef Name of field that boundary condition is applied to. -initialCondition integer Boundary condition is applied as an initial condition. -================ ============ ====================================================== - - diff --git a/src/coreComponents/schema/docs/PVTDriver.rst b/src/coreComponents/schema/docs/PVTDriver.rst deleted file mode 100644 index 6faf196ec68..00000000000 --- a/src/coreComponents/schema/docs/PVTDriver.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -====================== ============ ======== ================================================================ -Name Type Default Description -====================== ============ ======== ================================================================ -baseline path none Baseline file -feedComposition real64_array required Feed composition array [mol fraction] -fluid groupNameRef required Fluid to test -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -output string none Output file -outputCompressibility integer 0 Flag to indicate that the total compressibility should be output -outputPhaseComposition integer 0 Flag to indicate that phase compositions should be output -pressureControl groupNameRef required Function controlling pressure time history -steps integer required Number of load steps to take -temperatureControl groupNameRef required Function controlling temperature time history -====================== ============ ======== ================================================================ - - diff --git a/src/coreComponents/schema/docs/PVTDriver_other.rst b/src/coreComponents/schema/docs/PVTDriver_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/PVTDriver_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/PackCollection.rst b/src/coreComponents/schema/docs/PackCollection.rst deleted file mode 100644 index 0548e8255d7..00000000000 --- a/src/coreComponents/schema/docs/PackCollection.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -====================== ================== ======== =========================================================================================== -Name Type Default Description -====================== ================== ======== =========================================================================================== -disableCoordCollection integer 0 Whether or not to create coordinate meta-collectors if collected objects are mesh objects. -fieldName groupNameRef required The name of the (packable) field associated with the specified object to retrieve data from -name groupName required A name is required for any non-unique nodes -objectPath groupNameRef required The name of the object from which to retrieve field values. -onlyOnSetChange integer 0 Whether or not to only collect when the collected sets of indices change in any way. -setNames groupNameRef_array {} The set(s) for which to retrieve data. -====================== ================== ======== =========================================================================================== - - diff --git a/src/coreComponents/schema/docs/PackCollection_other.rst b/src/coreComponents/schema/docs/PackCollection_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/PackCollection_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/ParallelPlatesPermeability.rst b/src/coreComponents/schema/docs/ParallelPlatesPermeability.rst deleted file mode 100644 index 3302c76016c..00000000000 --- a/src/coreComponents/schema/docs/ParallelPlatesPermeability.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -======================= ========= ======== =========================================================================================================================== -Name Type Default Description -======================= ========= ======== =========================================================================================================================== -name groupName required A name is required for any non-unique nodes -transversalPermeability real64 -1 Default value of the permeability normal to the surface. If not specified the permeability is updated using the cubic law. -======================= ========= ======== =========================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/ParallelPlatesPermeability_other.rst b/src/coreComponents/schema/docs/ParallelPlatesPermeability_other.rst deleted file mode 100644 index 43a2d06a562..00000000000 --- a/src/coreComponents/schema/docs/ParallelPlatesPermeability_other.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -=============== ============== ================================================================= -Name Type Description -=============== ============== ================================================================= -dPerm_dDispJump real64_array4d Derivative of rock permeability with respect to displacement jump -dPerm_dPressure real64_array3d Derivative of rock permeability with respect to pressure -permeability real64_array3d Rock permeability -=============== ============== ================================================================= - - diff --git a/src/coreComponents/schema/docs/Parameter.rst b/src/coreComponents/schema/docs/Parameter.rst deleted file mode 100644 index d9baf793024..00000000000 --- a/src/coreComponents/schema/docs/Parameter.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -===== ========= ======== =============================================== -Name Type Default Description -===== ========= ======== =============================================== -name groupName required A name is required for any non-unique nodes -value string required Input parameter definition for the preprocessor -===== ========= ======== =============================================== - - diff --git a/src/coreComponents/schema/docs/Parameter_other.rst b/src/coreComponents/schema/docs/Parameter_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/Parameter_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/Parameters.rst b/src/coreComponents/schema/docs/Parameters.rst deleted file mode 100644 index c871a1cfb34..00000000000 --- a/src/coreComponents/schema/docs/Parameters.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -========= ==== ======= ==================== -Name Type Default Description -========= ==== ======= ==================== -Parameter node :ref:`XML_Parameter` -========= ==== ======= ==================== - - diff --git a/src/coreComponents/schema/docs/Parameters_other.rst b/src/coreComponents/schema/docs/Parameters_other.rst deleted file mode 100644 index 626d3944b70..00000000000 --- a/src/coreComponents/schema/docs/Parameters_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -========= ==== ============================== -Name Type Description -========= ==== ============================== -Parameter node :ref:`DATASTRUCTURE_Parameter` -========= ==== ============================== - - diff --git a/src/coreComponents/schema/docs/ParticleFluid.rst b/src/coreComponents/schema/docs/ParticleFluid.rst deleted file mode 100644 index 6f659a16e35..00000000000 --- a/src/coreComponents/schema/docs/ParticleFluid.rst +++ /dev/null @@ -1,23 +0,0 @@ - - -=========================== ======================================= ======== ======================================================================================== -Name Type Default Description -=========================== ======================================= ======== ======================================================================================== -collisionAlpha real64 1.27 Collision alpha coefficient -collisionBeta real64 1.5 Collision beta coefficient -fluidViscosity real64 0.001 Fluid viscosity -hinderedSettlingCoefficient real64 5.9 Hindered settling coefficient -isCollisionalSlip integer 0 Whether the collisional component of the slip velocity is considered -maxProppantConcentration real64 0.6 Max proppant concentration -name groupName required A name is required for any non-unique nodes -particleSettlingModel geos_constitutive_ParticleSettlingModel required | Particle settling velocity model. Valid options: - | * Stokes - | * Intermediate - | * Turbulence -proppantDensity real64 1400 Proppant density -proppantDiameter real64 0.0002 Proppant diameter -slipConcentration real64 0.1 Slip concentration -sphericity real64 1 Sphericity -=========================== ======================================= ======== ======================================================================================== - - diff --git a/src/coreComponents/schema/docs/ParticleFluid_other.rst b/src/coreComponents/schema/docs/ParticleFluid_other.rst deleted file mode 100644 index bd2a5de8053..00000000000 --- a/src/coreComponents/schema/docs/ParticleFluid_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -======================================= ============== ===================================================================== -Name Type Description -======================================= ============== ===================================================================== -collisionFactor real64_array Collision factor -dCollisionFactor_dProppantConcentration real64_array Derivative of collision factor with respect to proppant concentration -dSettlingFactor_dComponentConcentration real64_array2d Derivative of settling factor with respect to component concentration -dSettlingFactor_dPressure real64_array Derivative of settling factor with respect to pressure -dSettlingFactor_dProppantConcentration real64_array Derivative of settling factor with respect to proppant concentration -proppantPackPermeability real64_array Proppant pack permeability -settlingFactor real64_array Settling factor -======================================= ============== ===================================================================== - - diff --git a/src/coreComponents/schema/docs/ParticleMesh.rst b/src/coreComponents/schema/docs/ParticleMesh.rst deleted file mode 100644 index 435f9ccf07a..00000000000 --- a/src/coreComponents/schema/docs/ParticleMesh.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -================== ============ ======== =========================================== -Name Type Default Description -================== ============ ======== =========================================== -headerFile path required path to the header file -name groupName required A name is required for any non-unique nodes -particleBlockNames string_array required Names of each particle block -particleFile path required path to the particle file -particleTypes string_array required Particle types of each particle block -================== ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/ParticleMesh_other.rst b/src/coreComponents/schema/docs/ParticleMesh_other.rst deleted file mode 100644 index 14257041f64..00000000000 --- a/src/coreComponents/schema/docs/ParticleMesh_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -========== ==== =============================== -Name Type Description -========== ==== =============================== -meshLevels node :ref:`DATASTRUCTURE_meshLevels` -========== ==== =============================== - - diff --git a/src/coreComponents/schema/docs/ParticleRegion.rst b/src/coreComponents/schema/docs/ParticleRegion.rst deleted file mode 100644 index 6cfaeb99938..00000000000 --- a/src/coreComponents/schema/docs/ParticleRegion.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -============== ============ ======== =========================================== -Name Type Default Description -============== ============ ======== =========================================== -materialList string_array required List of materials present in this region -meshBody string Mesh body that contains this region -name groupName required A name is required for any non-unique nodes -particleBlocks string_array {} (no description available) -============== ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/ParticleRegion_other.rst b/src/coreComponents/schema/docs/ParticleRegion_other.rst deleted file mode 100644 index fbfc33ebf7f..00000000000 --- a/src/coreComponents/schema/docs/ParticleRegion_other.rst +++ /dev/null @@ -1,16 +0,0 @@ - - -======================= ==================================================================== ========================================================= -Name Type Description -======================= ==================================================================== ========================================================= -domainBoundaryIndicator integer_array (no description available) -ghostRank integer_array (no description available) -globalToLocalMap geos_mapBase< long long, int, std_integral_constant< bool, false > > (no description available) -isExternal integer_array (no description available) -localToGlobalMap globalIndex_array Array that contains a map from localIndex to globalIndex. -neighborData node :ref:`DATASTRUCTURE_neighborData` -particleSubRegions node :ref:`DATASTRUCTURE_particleSubRegions` -sets node :ref:`DATASTRUCTURE_sets` -======================= ==================================================================== ========================================================= - - diff --git a/src/coreComponents/schema/docs/ParticleRegions.rst b/src/coreComponents/schema/docs/ParticleRegions.rst deleted file mode 100644 index bd41c7378b9..00000000000 --- a/src/coreComponents/schema/docs/ParticleRegions.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -============== ==== ======= ========================= -Name Type Default Description -============== ==== ======= ========================= -ParticleRegion node :ref:`XML_ParticleRegion` -============== ==== ======= ========================= - - diff --git a/src/coreComponents/schema/docs/ParticleRegions_other.rst b/src/coreComponents/schema/docs/ParticleRegions_other.rst deleted file mode 100644 index 48075ebfe05..00000000000 --- a/src/coreComponents/schema/docs/ParticleRegions_other.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -======================= ==================================================================== ========================================================= -Name Type Description -======================= ==================================================================== ========================================================= -domainBoundaryIndicator integer_array (no description available) -ghostRank integer_array (no description available) -globalToLocalMap geos_mapBase< long long, int, std_integral_constant< bool, false > > (no description available) -isExternal integer_array (no description available) -localToGlobalMap globalIndex_array Array that contains a map from localIndex to globalIndex. -ParticleRegion node :ref:`DATASTRUCTURE_ParticleRegion` -neighborData node :ref:`DATASTRUCTURE_neighborData` -particleRegionsGroup node :ref:`DATASTRUCTURE_particleRegionsGroup` -sets node :ref:`DATASTRUCTURE_sets` -======================= ==================================================================== ========================================================= - - diff --git a/src/coreComponents/schema/docs/PerfectlyPlastic.rst b/src/coreComponents/schema/docs/PerfectlyPlastic.rst deleted file mode 100644 index 019ce1379dc..00000000000 --- a/src/coreComponents/schema/docs/PerfectlyPlastic.rst +++ /dev/null @@ -1,16 +0,0 @@ - - -======================= ========= ============ ==================================================================== -Name Type Default Description -======================= ========= ============ ==================================================================== -defaultBulkModulus real64 -1 Default Bulk Modulus Parameter -defaultDensity real64 required Default Material Density -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultPoissonRatio real64 -1 Default Poisson's Ratio -defaultShearModulus real64 -1 Default Shear Modulus Parameter -defaultYieldStress real64 1.79769e+308 Default yield stress -defaultYoungModulus real64 -1 Default Young's Modulus -name groupName required A name is required for any non-unique nodes -======================= ========= ============ ==================================================================== - - diff --git a/src/coreComponents/schema/docs/PerfectlyPlastic_other.rst b/src/coreComponents/schema/docs/PerfectlyPlastic_other.rst deleted file mode 100644 index b1207ce6f4a..00000000000 --- a/src/coreComponents/schema/docs/PerfectlyPlastic_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -bulkModulus real64_array Elastic Bulk Modulus Field -density real64_array2d Material Density -oldStress real64_array3d Previous Material Stress -shearModulus real64_array Elastic Shear Modulus Field -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -yieldStress real64_array Array of element yield stresses -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/Perforation.rst b/src/coreComponents/schema/docs/Perforation.rst deleted file mode 100644 index 60a3f8c0b92..00000000000 --- a/src/coreComponents/schema/docs/Perforation.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -================ ========= ======== ================================================= -Name Type Default Description -================ ========= ======== ================================================= -distanceFromHead real64 required Linear distance from well head to the perforation -name groupName required A name is required for any non-unique nodes -skinFactor real64 0 Perforation skin factor -transmissibility real64 -1 Perforation transmissibility -================ ========= ======== ================================================= - - diff --git a/src/coreComponents/schema/docs/Perforation_other.rst b/src/coreComponents/schema/docs/Perforation_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/Perforation_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/PeriodicEvent.rst b/src/coreComponents/schema/docs/PeriodicEvent.rst deleted file mode 100644 index 3f1c9b21b88..00000000000 --- a/src/coreComponents/schema/docs/PeriodicEvent.rst +++ /dev/null @@ -1,28 +0,0 @@ - - -==================== ============ ======== ================================================================================================================================================================================= -Name Type Default Description -==================== ============ ======== ================================================================================================================================================================================= -beginTime real64 0 Start time of this event. -cycleFrequency integer 1 Event application frequency (cycle, default) -endTime real64 1e+100 End time of this event. -finalDtStretch real64 0.001 Allow the final dt request for this event to grow by this percentage to match the endTime exactly. -forceDt real64 -1 While active, this event will request this timestep value (ignoring any children/targets requests). -function groupNameRef Name of an optional function to evaluate when the time/cycle criteria are met.If the result is greater than the specified eventThreshold, the function will continue to execute. -logLevel integer 0 Log level -maxEventDt real64 -1 While active, this event will request a timestep <= this value (depending upon any child/target requests). -name groupName required A name is required for any non-unique nodes -object groupNameRef If the optional function requires an object as an input, specify its path here. -set groupNameRef If the optional function is applied to an object, specify the setname to evaluate (default = everything). -stat integer 0 If the optional function is applied to an object, specify the statistic to compare to the eventThreshold.The current options include: min, avg, and max. -target groupNameRef Name of the object to be executed when the event criteria are met. -targetExactStartStop integer 1 If this option is set, the event will reduce its timestep requests to match any specified beginTime/endTimes exactly. -targetExactTimestep integer 1 If this option is set, the event will reduce its timestep requests to match the specified timeFrequency perfectly: dt_request = min(dt_request, t_last + time_frequency - time)). -threshold real64 0 If the optional function is used, the event will execute if the value returned by the function exceeds this threshold. -timeFrequency real64 -1 Event application frequency (time). Note: if this value is specified, it will override any cycle-based behavior. -HaltEvent node :ref:`XML_HaltEvent` -PeriodicEvent node :ref:`XML_PeriodicEvent` -SoloEvent node :ref:`XML_SoloEvent` -==================== ============ ======== ================================================================================================================================================================================= - - diff --git a/src/coreComponents/schema/docs/PeriodicEvent_other.rst b/src/coreComponents/schema/docs/PeriodicEvent_other.rst deleted file mode 100644 index f63756dd49b..00000000000 --- a/src/coreComponents/schema/docs/PeriodicEvent_other.rst +++ /dev/null @@ -1,16 +0,0 @@ - - -================= ======= =============================================== -Name Type Description -================= ======= =============================================== -currentSubEvent integer Index of the current subevent -eventForecast integer Indicates when the event is expected to execute -isTargetExecuting integer Index of the current subevent -lastCycle integer Last event occurrence (cycle) -lastTime real64 Last event occurrence (time) -HaltEvent node :ref:`DATASTRUCTURE_HaltEvent` -PeriodicEvent node :ref:`DATASTRUCTURE_PeriodicEvent` -SoloEvent node :ref:`DATASTRUCTURE_SoloEvent` -================= ======= =============================================== - - diff --git a/src/coreComponents/schema/docs/PermeabilityBase.rst b/src/coreComponents/schema/docs/PermeabilityBase.rst deleted file mode 100644 index f6c735e1d91..00000000000 --- a/src/coreComponents/schema/docs/PermeabilityBase.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ========= ======== =========================================== -Name Type Default Description -==== ========= ======== =========================================== -name groupName required A name is required for any non-unique nodes -==== ========= ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/PermeabilityBase_other.rst b/src/coreComponents/schema/docs/PermeabilityBase_other.rst deleted file mode 100644 index fa997a57413..00000000000 --- a/src/coreComponents/schema/docs/PermeabilityBase_other.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -=============== ============== ======================================================== -Name Type Description -=============== ============== ======================================================== -dPerm_dPressure real64_array3d Derivative of rock permeability with respect to pressure -permeability real64_array3d Rock permeability -=============== ============== ======================================================== - - diff --git a/src/coreComponents/schema/docs/PhaseFieldDamageFEM.rst b/src/coreComponents/schema/docs/PhaseFieldDamageFEM.rst deleted file mode 100644 index d0d26cc6fb3..00000000000 --- a/src/coreComponents/schema/docs/PhaseFieldDamageFEM.rst +++ /dev/null @@ -1,21 +0,0 @@ - - -========================= ============================================== ======== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ============================================== ======== ======================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -damageUpperBound real64 1.5 The upper bound of the damage -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -fieldName groupNameRef required name of field variable -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -irreversibilityFlag integer 0 The flag to indicate whether to apply the irreversibility constraint -localDissipation geos_PhaseFieldDamageFEM_LocalDissipation required Type of local dissipation function. Can be Linear or Quadratic -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -timeIntegrationOption geos_PhaseFieldDamageFEM_TimeIntegrationOption required option for default time integration method -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ============================================== ======== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/PhaseFieldDamageFEM_other.rst b/src/coreComponents/schema/docs/PhaseFieldDamageFEM_other.rst deleted file mode 100644 index 3f1b37c3d6c..00000000000 --- a/src/coreComponents/schema/docs/PhaseFieldDamageFEM_other.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -========================= ============================================================================================================================================================== ================================================================ -Name Type Description -========================= ============================================================================================================================================================== ================================================================ -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ================================================================ - - diff --git a/src/coreComponents/schema/docs/PhaseFieldFracture.rst b/src/coreComponents/schema/docs/PhaseFieldFracture.rst deleted file mode 100644 index 0c7e530a888..00000000000 --- a/src/coreComponents/schema/docs/PhaseFieldFracture.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -damageSolverName groupNameRef required Name of the damage solver used by the coupled solver -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -solidSolverName groupNameRef required Name of the solid solver used by the coupled solver -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/PhaseFieldFracture_other.rst b/src/coreComponents/schema/docs/PhaseFieldFracture_other.rst deleted file mode 100644 index 45d9a187f0a..00000000000 --- a/src/coreComponents/schema/docs/PhaseFieldFracture_other.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/PorousDamageElasticIsotropic.rst b/src/coreComponents/schema/docs/PorousDamageElasticIsotropic.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/PorousDamageElasticIsotropic.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/PorousDamageElasticIsotropic_other.rst b/src/coreComponents/schema/docs/PorousDamageElasticIsotropic_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/PorousDamageElasticIsotropic_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/PorousDamageSpectralElasticIsotropic.rst b/src/coreComponents/schema/docs/PorousDamageSpectralElasticIsotropic.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/PorousDamageSpectralElasticIsotropic.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/PorousDamageSpectralElasticIsotropic_other.rst b/src/coreComponents/schema/docs/PorousDamageSpectralElasticIsotropic_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/PorousDamageSpectralElasticIsotropic_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/PorousDamageVolDevElasticIsotropic.rst b/src/coreComponents/schema/docs/PorousDamageVolDevElasticIsotropic.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/PorousDamageVolDevElasticIsotropic.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/PorousDamageVolDevElasticIsotropic_other.rst b/src/coreComponents/schema/docs/PorousDamageVolDevElasticIsotropic_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/PorousDamageVolDevElasticIsotropic_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/PorousDelftEgg.rst b/src/coreComponents/schema/docs/PorousDelftEgg.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/PorousDelftEgg.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/PorousDelftEgg_other.rst b/src/coreComponents/schema/docs/PorousDelftEgg_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/PorousDelftEgg_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/PorousDruckerPrager.rst b/src/coreComponents/schema/docs/PorousDruckerPrager.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/PorousDruckerPrager.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/PorousDruckerPrager_other.rst b/src/coreComponents/schema/docs/PorousDruckerPrager_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/PorousDruckerPrager_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/PorousElasticIsotropic.rst b/src/coreComponents/schema/docs/PorousElasticIsotropic.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/PorousElasticIsotropic.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/PorousElasticIsotropic_other.rst b/src/coreComponents/schema/docs/PorousElasticIsotropic_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/PorousElasticIsotropic_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/PorousElasticOrthotropic.rst b/src/coreComponents/schema/docs/PorousElasticOrthotropic.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/PorousElasticOrthotropic.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/PorousElasticOrthotropic_other.rst b/src/coreComponents/schema/docs/PorousElasticOrthotropic_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/PorousElasticOrthotropic_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/PorousElasticTransverseIsotropic.rst b/src/coreComponents/schema/docs/PorousElasticTransverseIsotropic.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/PorousElasticTransverseIsotropic.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/PorousElasticTransverseIsotropic_other.rst b/src/coreComponents/schema/docs/PorousElasticTransverseIsotropic_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/PorousElasticTransverseIsotropic_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/PorousExtendedDruckerPrager.rst b/src/coreComponents/schema/docs/PorousExtendedDruckerPrager.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/PorousExtendedDruckerPrager.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/PorousExtendedDruckerPrager_other.rst b/src/coreComponents/schema/docs/PorousExtendedDruckerPrager_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/PorousExtendedDruckerPrager_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/PorousModifiedCamClay.rst b/src/coreComponents/schema/docs/PorousModifiedCamClay.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/PorousModifiedCamClay.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/PorousModifiedCamClay_other.rst b/src/coreComponents/schema/docs/PorousModifiedCamClay_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/PorousModifiedCamClay_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/PorousViscoDruckerPrager.rst b/src/coreComponents/schema/docs/PorousViscoDruckerPrager.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/PorousViscoDruckerPrager.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/PorousViscoDruckerPrager_other.rst b/src/coreComponents/schema/docs/PorousViscoDruckerPrager_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/PorousViscoDruckerPrager_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/PorousViscoExtendedDruckerPrager.rst b/src/coreComponents/schema/docs/PorousViscoExtendedDruckerPrager.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/PorousViscoExtendedDruckerPrager.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/PorousViscoExtendedDruckerPrager_other.rst b/src/coreComponents/schema/docs/PorousViscoExtendedDruckerPrager_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/PorousViscoExtendedDruckerPrager_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/PorousViscoModifiedCamClay.rst b/src/coreComponents/schema/docs/PorousViscoModifiedCamClay.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/PorousViscoModifiedCamClay.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/PorousViscoModifiedCamClay_other.rst b/src/coreComponents/schema/docs/PorousViscoModifiedCamClay_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/PorousViscoModifiedCamClay_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/PressurePorosity.rst b/src/coreComponents/schema/docs/PressurePorosity.rst deleted file mode 100644 index 1025b310512..00000000000 --- a/src/coreComponents/schema/docs/PressurePorosity.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -======================== ========= ======== ============================================ -Name Type Default Description -======================== ========= ======== ============================================ -compressibility real64 required Solid compressibility -defaultReferencePorosity real64 required Default value of the reference porosity -name groupName required A name is required for any non-unique nodes -referencePressure real64 required Reference pressure for solid compressibility -======================== ========= ======== ============================================ - - diff --git a/src/coreComponents/schema/docs/PressurePorosity_other.rst b/src/coreComponents/schema/docs/PressurePorosity_other.rst deleted file mode 100644 index 17d801d7587..00000000000 --- a/src/coreComponents/schema/docs/PressurePorosity_other.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -====================== ============== ======================================================= -Name Type Description -====================== ============== ======================================================= -dPorosity_dPressure real64_array2d Derivative of rock porosity with respect to pressure -dPorosity_dTemperature real64_array2d Derivative of rock porosity with respect to temperature -initialPorosity real64_array2d Initial porosity -porosity real64_array2d Rock porosity -porosity_n real64_array2d Rock porosity at the previous converged time step -referencePorosity real64_array Reference porosity -====================== ============== ======================================================= - - diff --git a/src/coreComponents/schema/docs/Problem.rst b/src/coreComponents/schema/docs/Problem.rst deleted file mode 100644 index a34b51acf38..00000000000 --- a/src/coreComponents/schema/docs/Problem.rst +++ /dev/null @@ -1,23 +0,0 @@ - - -=================== ==== ================ ============================== -Name Type Default Description -=================== ==== ================ ============================== -Benchmarks node unique :ref:`XML_Benchmarks` -Constitutive node unique :ref:`XML_Constitutive` -ElementRegions node unique :ref:`XML_ElementRegions` -Events node unique, required :ref:`XML_Events` -FieldSpecifications node unique :ref:`XML_FieldSpecifications` -Functions node unique :ref:`XML_Functions` -Geometry node unique :ref:`XML_Geometry` -Included node unique :ref:`XML_Included` -Mesh node unique, required :ref:`XML_Mesh` -NumericalMethods node unique :ref:`XML_NumericalMethods` -Outputs node unique, required :ref:`XML_Outputs` -Parameters node unique :ref:`XML_Parameters` -ParticleRegions node unique :ref:`XML_ParticleRegions` -Solvers node unique, required :ref:`XML_Solvers` -Tasks node unique :ref:`XML_Tasks` -=================== ==== ================ ============================== - - diff --git a/src/coreComponents/schema/docs/Problem_other.rst b/src/coreComponents/schema/docs/Problem_other.rst deleted file mode 100644 index 2f154100ff3..00000000000 --- a/src/coreComponents/schema/docs/Problem_other.rst +++ /dev/null @@ -1,25 +0,0 @@ - - -=================== ==== ======================================== -Name Type Description -=================== ==== ======================================== -Benchmarks node :ref:`DATASTRUCTURE_Benchmarks` -Constitutive node :ref:`DATASTRUCTURE_Constitutive` -ElementRegions node :ref:`DATASTRUCTURE_ElementRegions` -Events node :ref:`DATASTRUCTURE_Events` -FieldSpecifications node :ref:`DATASTRUCTURE_FieldSpecifications` -Functions node :ref:`DATASTRUCTURE_Functions` -Geometry node :ref:`DATASTRUCTURE_Geometry` -Included node :ref:`DATASTRUCTURE_Included` -Mesh node :ref:`DATASTRUCTURE_Mesh` -NumericalMethods node :ref:`DATASTRUCTURE_NumericalMethods` -Outputs node :ref:`DATASTRUCTURE_Outputs` -Parameters node :ref:`DATASTRUCTURE_Parameters` -ParticleRegions node :ref:`DATASTRUCTURE_ParticleRegions` -Solvers node :ref:`DATASTRUCTURE_Solvers` -Tasks node :ref:`DATASTRUCTURE_Tasks` -commandLine node :ref:`DATASTRUCTURE_commandLine` -domain node :ref:`DATASTRUCTURE_domain` -=================== ==== ======================================== - - diff --git a/src/coreComponents/schema/docs/ProppantPermeability.rst b/src/coreComponents/schema/docs/ProppantPermeability.rst deleted file mode 100644 index a8877faca2f..00000000000 --- a/src/coreComponents/schema/docs/ProppantPermeability.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -======================== ========= ======== =========================================== -Name Type Default Description -======================== ========= ======== =========================================== -maxProppantConcentration real64 required Maximum proppant concentration. -name groupName required A name is required for any non-unique nodes -proppantDiameter real64 required Proppant diameter. -======================== ========= ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/ProppantPermeability_other.rst b/src/coreComponents/schema/docs/ProppantPermeability_other.rst deleted file mode 100644 index 989c76d45c1..00000000000 --- a/src/coreComponents/schema/docs/ProppantPermeability_other.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -======================== ============== ================================================================= -Name Type Description -======================== ============== ================================================================= -dPerm_dDispJump real64_array4d Derivative of rock permeability with respect to displacement jump -dPerm_dPressure real64_array3d Derivative of rock permeability with respect to pressure -permeability real64_array3d Rock permeability -permeabilityMultiplier real64_array3d Rock permeability multiplier -proppantPackPermeability real64 (no description available) -======================== ============== ================================================================= - - diff --git a/src/coreComponents/schema/docs/ProppantPorosity.rst b/src/coreComponents/schema/docs/ProppantPorosity.rst deleted file mode 100644 index e5ce1f5fdb6..00000000000 --- a/src/coreComponents/schema/docs/ProppantPorosity.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -======================== ========= ======== =========================================== -Name Type Default Description -======================== ========= ======== =========================================== -defaultReferencePorosity real64 required Default value of the reference porosity -maxProppantConcentration real64 required Maximum proppant concentration -name groupName required A name is required for any non-unique nodes -======================== ========= ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/ProppantPorosity_other.rst b/src/coreComponents/schema/docs/ProppantPorosity_other.rst deleted file mode 100644 index 17d801d7587..00000000000 --- a/src/coreComponents/schema/docs/ProppantPorosity_other.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -====================== ============== ======================================================= -Name Type Description -====================== ============== ======================================================= -dPorosity_dPressure real64_array2d Derivative of rock porosity with respect to pressure -dPorosity_dTemperature real64_array2d Derivative of rock porosity with respect to temperature -initialPorosity real64_array2d Initial porosity -porosity real64_array2d Rock porosity -porosity_n real64_array2d Rock porosity at the previous converged time step -referencePorosity real64_array Reference porosity -====================== ============== ======================================================= - - diff --git a/src/coreComponents/schema/docs/ProppantSlurryFluid.rst b/src/coreComponents/schema/docs/ProppantSlurryFluid.rst deleted file mode 100644 index d960825e262..00000000000 --- a/src/coreComponents/schema/docs/ProppantSlurryFluid.rst +++ /dev/null @@ -1,21 +0,0 @@ - - -========================= ============ ======== ================================================ -Name Type Default Description -========================= ============ ======== ================================================ -componentNames string_array {} List of fluid component names -compressibility real64 0 Fluid compressibility -defaultComponentDensity real64_array {0} Default value for the component density. -defaultComponentViscosity real64_array {0} Default value for the component viscosity. -defaultCompressibility real64_array {0} Default value for the component compressibility. -flowBehaviorIndex real64_array {0} Flow behavior index -flowConsistencyIndex real64_array {0} Flow consistency index -maxProppantConcentration real64 0.6 Maximum proppant concentration -name groupName required A name is required for any non-unique nodes -referenceDensity real64 1000 Reference fluid density -referencePressure real64 100000 Reference pressure -referenceProppantDensity real64 1400 Reference proppant density -referenceViscosity real64 0.001 Reference fluid viscosity -========================= ============ ======== ================================================ - - diff --git a/src/coreComponents/schema/docs/ProppantSlurryFluid_other.rst b/src/coreComponents/schema/docs/ProppantSlurryFluid_other.rst deleted file mode 100644 index 5248c9d190d..00000000000 --- a/src/coreComponents/schema/docs/ProppantSlurryFluid_other.rst +++ /dev/null @@ -1,35 +0,0 @@ - - -============================ ============== ======================================================================= -Name Type Description -============================ ============== ======================================================================= -FluidDensity real64_array2d Fluid density -FluidViscosity real64_array2d Fluid viscosity -componentDensity real64_array3d Component density -dCompDens_dCompConc real64_array4d Derivative of component density with respect to component concentration -dCompDens_dPres real64_array3d Derivative of component density with respect to pressure -dDens_dCompConc real64_array3d Derivative of density with respect to component concentration -dDens_dProppantConc real64_array2d Derivative of density with respect to proppant concentration -dDensity_dPressure real64_array2d Derivative of density with respect to pressure -dDensity_dTemperature real64_array2d Derivative of density with respect to temperature -dEnthalpy_dPressure real64_array2d Derivative of enthalpy with respect to pressure -dEnthalpy_dTemperature real64_array2d Derivative of enthalpy with respect to temperature -dFluidDens_dCompConc real64_array3d Derivative of fluid density with respect to component concentration -dFluidDens_dPres real64_array2d Derivative of fluid density with respect to pressure -dFluidVisc_dCompConc real64_array3d Derivative of fluid viscosity with respect to component concentration -dFluidVisc_dPres real64_array2d Derivative of fluid viscosity with respect to pressure -dInternalEnergy_dPressure real64_array2d Derivative of internal energy with respect to pressure -dInternalEnergy_dTemperature real64_array2d Derivative of internal energy with respect to temperature -dVisc_dCompConc real64_array3d Derivative of viscosity with respect to component concentration -dVisc_dProppantConc real64_array2d Derivative of viscosity with respect to proppant concentration -dViscosity_dPressure real64_array2d Derivative of viscosity with respect to pressure -dViscosity_dTemperature real64_array2d Derivative of viscosity with respect to temperature -density real64_array2d Density -density_n real64_array2d Density at the previous converged time step -enthalpy real64_array2d Enthalpy -internalEnergy real64_array2d Internal energy -internalEnergy_n real64_array2d Fluid internal energy at the previous converged step -viscosity real64_array2d Viscosity -============================ ============== ======================================================================= - - diff --git a/src/coreComponents/schema/docs/ProppantSolidProppantPermeability.rst b/src/coreComponents/schema/docs/ProppantSolidProppantPermeability.rst deleted file mode 100644 index 7d6d29602c1..00000000000 --- a/src/coreComponents/schema/docs/ProppantSolidProppantPermeability.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -============================ ============ ======== =========================================== -Name Type Default Description -============================ ============ ======== =========================================== -name groupName required A name is required for any non-unique nodes -permeabilityModelName groupNameRef required Name of the permeability model. -porosityModelName groupNameRef required Name of the porosity model. -solidInternalEnergyModelName groupNameRef Name of the solid internal energy model. -solidModelName groupNameRef required Name of the solid model. -============================ ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/ProppantSolidProppantPermeability_other.rst b/src/coreComponents/schema/docs/ProppantSolidProppantPermeability_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/ProppantSolidProppantPermeability_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/ProppantTransport.rst b/src/coreComponents/schema/docs/ProppantTransport.rst deleted file mode 100644 index c7b0b39c500..00000000000 --- a/src/coreComponents/schema/docs/ProppantTransport.rst +++ /dev/null @@ -1,28 +0,0 @@ - - -============================== ================== ======== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -============================== ================== ======== ======================================================================================================================================================================================================================================================================================================================== -allowNegativePressure integer 1 Flag indicating if negative pressure is allowed -bridgingFactor real64 0 Bridging factor used for bridging/screen-out calculation -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -criticalShieldsNumber real64 0 Critical Shields number -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -frictionCoefficient real64 0.03 Friction coefficient -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isThermal integer 0 Flag indicating whether the problem is thermal or not. -logLevel integer 0 Log level -maxAbsolutePressureChange real64 -1 Maximum (absolute) pressure change in a Newton iteration -maxProppantConcentration real64 0.6 Maximum proppant concentration -maxSequentialPressureChange real64 100000 Maximum (absolute) pressure change in a sequential iteration, used for outer loop convergence check -maxSequentialTemperatureChange real64 0.1 Maximum (absolute) temperature change in a sequential iteration, used for outer loop convergence check -name groupName required A name is required for any non-unique nodes -proppantDensity real64 2500 Proppant density -proppantDiameter real64 0.0004 Proppant diameter -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -updateProppantPacking integer 0 Flag that enables/disables proppant-packing update -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -============================== ================== ======== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/ProppantTransport_other.rst b/src/coreComponents/schema/docs/ProppantTransport_other.rst deleted file mode 100644 index 3f1b37c3d6c..00000000000 --- a/src/coreComponents/schema/docs/ProppantTransport_other.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -========================= ============================================================================================================================================================== ================================================================ -Name Type Description -========================= ============================================================================================================================================================== ================================================================ -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ================================================================ - - diff --git a/src/coreComponents/schema/docs/Python.rst b/src/coreComponents/schema/docs/Python.rst deleted file mode 100644 index c7dc6b70183..00000000000 --- a/src/coreComponents/schema/docs/Python.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -=============== ========= ======== =========================================== -Name Type Default Description -=============== ========= ======== =========================================== -childDirectory string Child directory path -name groupName required A name is required for any non-unique nodes -parallelThreads integer 1 Number of plot files. -=============== ========= ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/Python_other.rst b/src/coreComponents/schema/docs/Python_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/Python_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/ReactiveBrine.rst b/src/coreComponents/schema/docs/ReactiveBrine.rst deleted file mode 100644 index d710c396a38..00000000000 --- a/src/coreComponents/schema/docs/ReactiveBrine.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -==================== ================== ======== ============================================================================================================ -Name Type Default Description -==================== ================== ======== ============================================================================================================ -checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. -componentMolarWeight real64_array {0} Component molar weights -componentNames string_array {} List of component names -name groupName required A name is required for any non-unique nodes -phaseNames groupNameRef_array {} List of fluid phases -phasePVTParaFiles path_array required Names of the files defining the parameters of the viscosity and density models -==================== ================== ======== ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/ReactiveBrineThermal.rst b/src/coreComponents/schema/docs/ReactiveBrineThermal.rst deleted file mode 100644 index d710c396a38..00000000000 --- a/src/coreComponents/schema/docs/ReactiveBrineThermal.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -==================== ================== ======== ============================================================================================================ -Name Type Default Description -==================== ================== ======== ============================================================================================================ -checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. -componentMolarWeight real64_array {0} Component molar weights -componentNames string_array {} List of component names -name groupName required A name is required for any non-unique nodes -phaseNames groupNameRef_array {} List of fluid phases -phasePVTParaFiles path_array required Names of the files defining the parameters of the viscosity and density models -==================== ================== ======== ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/ReactiveBrineThermal_other.rst b/src/coreComponents/schema/docs/ReactiveBrineThermal_other.rst deleted file mode 100644 index 74f30d53b77..00000000000 --- a/src/coreComponents/schema/docs/ReactiveBrineThermal_other.rst +++ /dev/null @@ -1,34 +0,0 @@ - - -================================ ============================================================================================= ============================================================================================================ -Name Type Description -================================ ============================================================================================= ============================================================================================================ -dPhaseCompFraction LvArray_Array< double, 5, camp_int_seq< long, 0l, 1l, 2l, 3l, 4l >, int, LvArray_ChaiBuffer > Derivative of phase component fraction with respect to pressure, temperature, and global component fractions -dPhaseDensity real64_array4d Derivative of phase density with respect to pressure, temperature, and global component fractions -dPhaseEnthalpy real64_array4d Derivative of phase enthalpy with respect to pressure, temperature, and global component fractions -dPhaseFraction real64_array4d Derivative of phase fraction with respect to pressure, temperature, and global component fractions -dPhaseInternalEnergy real64_array4d Derivative of phase internal energy with respect to pressure, temperature, and global component fractions -dPhaseMassDensity real64_array4d Derivative of phase mass density with respect to pressure, temperature, and global component fractions -dPhaseViscosity real64_array4d Derivative of phase viscosity with respect to pressure, temperature, and global component fractions -dTotalDensity real64_array3d Derivative of total density with respect to pressure, temperature, and global component fractions -kineticReactionRates real64_array2d kineticReactionRates -phaseCompFraction real64_array4d Phase component fraction -phaseCompFraction_n real64_array4d Phase component fraction at the previous converged time step -phaseDensity real64_array3d Phase density -phaseDensity_n real64_array3d Phase density at the previous converged time step -phaseEnthalpy real64_array3d Phase enthalpy -phaseEnthalpy_n real64_array3d Phase enthalpy at the previous converged time step -phaseFraction real64_array3d Phase fraction -phaseInternalEnergy real64_array3d Phase internal energy -phaseInternalEnergy_n real64_array3d Phase internal energy at the previous converged time step -phaseMassDensity real64_array3d Phase mass density -phaseViscosity real64_array3d Phase viscosity -primarySpeciesConcentration real64_array2d primarySpeciesConcentration -primarySpeciesTotalConcentration real64_array2d primarySpeciesTotalConcentration -secondarySpeciesConcentration real64_array2d secondarySpeciesConcentration -totalDensity real64_array2d Total density -totalDensity_n real64_array2d Total density at the previous converged time step -useMass integer (no description available) -================================ ============================================================================================= ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/ReactiveBrine_other.rst b/src/coreComponents/schema/docs/ReactiveBrine_other.rst deleted file mode 100644 index 74f30d53b77..00000000000 --- a/src/coreComponents/schema/docs/ReactiveBrine_other.rst +++ /dev/null @@ -1,34 +0,0 @@ - - -================================ ============================================================================================= ============================================================================================================ -Name Type Description -================================ ============================================================================================= ============================================================================================================ -dPhaseCompFraction LvArray_Array< double, 5, camp_int_seq< long, 0l, 1l, 2l, 3l, 4l >, int, LvArray_ChaiBuffer > Derivative of phase component fraction with respect to pressure, temperature, and global component fractions -dPhaseDensity real64_array4d Derivative of phase density with respect to pressure, temperature, and global component fractions -dPhaseEnthalpy real64_array4d Derivative of phase enthalpy with respect to pressure, temperature, and global component fractions -dPhaseFraction real64_array4d Derivative of phase fraction with respect to pressure, temperature, and global component fractions -dPhaseInternalEnergy real64_array4d Derivative of phase internal energy with respect to pressure, temperature, and global component fractions -dPhaseMassDensity real64_array4d Derivative of phase mass density with respect to pressure, temperature, and global component fractions -dPhaseViscosity real64_array4d Derivative of phase viscosity with respect to pressure, temperature, and global component fractions -dTotalDensity real64_array3d Derivative of total density with respect to pressure, temperature, and global component fractions -kineticReactionRates real64_array2d kineticReactionRates -phaseCompFraction real64_array4d Phase component fraction -phaseCompFraction_n real64_array4d Phase component fraction at the previous converged time step -phaseDensity real64_array3d Phase density -phaseDensity_n real64_array3d Phase density at the previous converged time step -phaseEnthalpy real64_array3d Phase enthalpy -phaseEnthalpy_n real64_array3d Phase enthalpy at the previous converged time step -phaseFraction real64_array3d Phase fraction -phaseInternalEnergy real64_array3d Phase internal energy -phaseInternalEnergy_n real64_array3d Phase internal energy at the previous converged time step -phaseMassDensity real64_array3d Phase mass density -phaseViscosity real64_array3d Phase viscosity -primarySpeciesConcentration real64_array2d primarySpeciesConcentration -primarySpeciesTotalConcentration real64_array2d primarySpeciesTotalConcentration -secondarySpeciesConcentration real64_array2d secondarySpeciesConcentration -totalDensity real64_array2d Total density -totalDensity_n real64_array2d Total density at the previous converged time step -useMass integer (no description available) -================================ ============================================================================================= ============================================================================================================ - - diff --git a/src/coreComponents/schema/docs/ReactiveCompositionalMultiphaseOBL.rst b/src/coreComponents/schema/docs/ReactiveCompositionalMultiphaseOBL.rst deleted file mode 100644 index da7fa66a198..00000000000 --- a/src/coreComponents/schema/docs/ReactiveCompositionalMultiphaseOBL.rst +++ /dev/null @@ -1,31 +0,0 @@ - - -============================== ================== ======== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -============================== ================== ======== ======================================================================================================================================================================================================================================================================================================================== -OBLOperatorsTableFile path required File containing OBL operator values -allowLocalOBLChopping integer 1 Allow keeping solution within OBL limits -allowNegativePressure integer 1 Flag indicating if negative pressure is allowed -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -componentNames string_array {} List of component names -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -enableEnergyBalance integer required Enable energy balance calculation and temperature degree of freedom -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isThermal integer 0 Flag indicating whether the problem is thermal or not. -logLevel integer 0 Log level -maxAbsolutePressureChange real64 -1 Maximum (absolute) pressure change in a Newton iteration -maxCompFractionChange real64 1 Maximum (absolute) change in a component fraction between two Newton iterations -maxSequentialPressureChange real64 100000 Maximum (absolute) pressure change in a sequential iteration, used for outer loop convergence check -maxSequentialTemperatureChange real64 0.1 Maximum (absolute) temperature change in a sequential iteration, used for outer loop convergence check -name groupName required A name is required for any non-unique nodes -numComponents integer required Number of components -numPhases integer required Number of phases -phaseNames groupNameRef_array {} List of fluid phases -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -transMultExp real64 1 Exponent of dynamic transmissibility multiplier -useDARTSL2Norm integer 1 Use L2 norm calculation similar to one used DARTS -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -============================== ================== ======== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/ReactiveCompositionalMultiphaseOBL_other.rst b/src/coreComponents/schema/docs/ReactiveCompositionalMultiphaseOBL_other.rst deleted file mode 100644 index 3f1b37c3d6c..00000000000 --- a/src/coreComponents/schema/docs/ReactiveCompositionalMultiphaseOBL_other.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -========================= ============================================================================================================================================================== ================================================================ -Name Type Description -========================= ============================================================================================================================================================== ================================================================ -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ================================================================ - - diff --git a/src/coreComponents/schema/docs/ReactiveFluidDriver.rst b/src/coreComponents/schema/docs/ReactiveFluidDriver.rst deleted file mode 100644 index b2c089baae6..00000000000 --- a/src/coreComponents/schema/docs/ReactiveFluidDriver.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -================== ============ ======== =================================================================== -Name Type Default Description -================== ============ ======== =================================================================== -baseline path none Baseline file -feedComposition real64_array required Feed composition array: total concentration of the primary species -fluid groupNameRef required Fluid to test -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -output string none Output file -pressureControl groupNameRef required Function controlling pressure time history -steps integer required Number of load steps to take -temperatureControl groupNameRef required Function controlling temperature time history -================== ============ ======== =================================================================== - - diff --git a/src/coreComponents/schema/docs/ReactiveFluidDriver_other.rst b/src/coreComponents/schema/docs/ReactiveFluidDriver_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/ReactiveFluidDriver_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/Rectangle.rst b/src/coreComponents/schema/docs/Rectangle.rst deleted file mode 100644 index 2413e9f671b..00000000000 --- a/src/coreComponents/schema/docs/Rectangle.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -============ ============ ======== ================================================================================================================= -Name Type Default Description -============ ============ ======== ================================================================================================================= -dimensions real64_array required Length and width of the bounded plane -lengthVector R1Tensor required Tangent vector defining the orthonormal basis along with the normal. -name groupName required A name is required for any non-unique nodes -normal R1Tensor required Normal (n_x,n_y,n_z) to the plane (will be normalized automatically) -origin R1Tensor required Origin point (x,y,z) of the plane (basically, any point on the plane) -tolerance real64 1e-05 Tolerance to determine if a point sits on the plane or not. It is relative to the maximum dimension of the plane. -widthVector R1Tensor required Tangent vector defining the orthonormal basis along with the normal. -============ ============ ======== ================================================================================================================= - - diff --git a/src/coreComponents/schema/docs/Rectangle_other.rst b/src/coreComponents/schema/docs/Rectangle_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/Rectangle_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/RelpermDriver.rst b/src/coreComponents/schema/docs/RelpermDriver.rst deleted file mode 100644 index 090a04d2c45..00000000000 --- a/src/coreComponents/schema/docs/RelpermDriver.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -======== ============ ======== =========================================== -Name Type Default Description -======== ============ ======== =========================================== -baseline path none Baseline file -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -output string none Output file -relperm groupNameRef required Relperm model to test -steps integer required Number of saturation steps to take -======== ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/RelpermDriver_other.rst b/src/coreComponents/schema/docs/RelpermDriver_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/RelpermDriver_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/Restart.rst b/src/coreComponents/schema/docs/Restart.rst deleted file mode 100644 index c7dc6b70183..00000000000 --- a/src/coreComponents/schema/docs/Restart.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -=============== ========= ======== =========================================== -Name Type Default Description -=============== ========= ======== =========================================== -childDirectory string Child directory path -name groupName required A name is required for any non-unique nodes -parallelThreads integer 1 Number of plot files. -=============== ========= ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/Restart_other.rst b/src/coreComponents/schema/docs/Restart_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/Restart_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/Run.rst b/src/coreComponents/schema/docs/Run.rst deleted file mode 100644 index feeeefeb973..00000000000 --- a/src/coreComponents/schema/docs/Run.rst +++ /dev/null @@ -1,18 +0,0 @@ - - -============== ============= ======== ======================================================================================================================================================= -Name Type Default Description -============== ============= ======== ======================================================================================================================================================= -args string Any extra command line arguments to pass to GEOSX. -autoPartition string May be 'Off' or 'On', if 'On' partitioning arguments are created automatically. Default is Off. -meshSizes integer_array {0} The target number of elements in the internal mesh (per-process for weak scaling, globally for strong scaling) default doesn't modify the internalMesh. -name string required The name of this benchmark. -nodes integer 0 The number of nodes needed to run the base benchmark, default is 1. -scaleList integer_array {0} The scales at which to run the problem ( scale * nodes * tasksPerNode ). -scaling string Whether to run a scaling, and which type of scaling to run. -tasksPerNode integer required The number of tasks per node to run the benchmark with. -threadsPerTask integer 0 The number of threads per task to run the benchmark with. -timeLimit integer 0 The time limit of the benchmark. -============== ============= ======== ======================================================================================================================================================= - - diff --git a/src/coreComponents/schema/docs/Run_other.rst b/src/coreComponents/schema/docs/Run_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/Run_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/Silo.rst b/src/coreComponents/schema/docs/Silo.rst deleted file mode 100644 index 8257591bdb5..00000000000 --- a/src/coreComponents/schema/docs/Silo.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -=========================== ================== ======== ======================================================================================================================================================================================== -Name Type Default Description -=========================== ================== ======== ======================================================================================================================================================================================== -childDirectory string Child directory path -fieldNames groupNameRef_array {} Names of the fields to output. If this attribute is specified, GEOSX outputs all (and only) the fields specified by the user, regardless of their plotLevel -name groupName required A name is required for any non-unique nodes -onlyPlotSpecifiedFieldNames integer 0 If this flag is equal to 1, then we only plot the fields listed in `fieldNames`. Otherwise, we plot all the fields with the required `plotLevel`, plus the fields listed in `fieldNames` -parallelThreads integer 1 Number of plot files. -plotFileRoot string plot (no description available) -plotLevel integer 1 (no description available) -writeCellElementMesh integer 1 (no description available) -writeEdgeMesh integer 0 (no description available) -writeFEMFaces integer 0 (no description available) -writeFaceElementMesh integer 1 (no description available) -=========================== ================== ======== ======================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/Silo_other.rst b/src/coreComponents/schema/docs/Silo_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/Silo_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/SinglePhaseConstantThermalConductivity.rst b/src/coreComponents/schema/docs/SinglePhaseConstantThermalConductivity.rst deleted file mode 100644 index d9dc99ad411..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseConstantThermalConductivity.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -============================= ========= ======== =============================================================================== -Name Type Default Description -============================= ========= ======== =============================================================================== -name groupName required A name is required for any non-unique nodes -thermalConductivityComponents R1Tensor required xx, yy, and zz components of a diagonal thermal conductivity tensor [J/(s.m.K)] -============================= ========= ======== =============================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhaseConstantThermalConductivity_other.rst b/src/coreComponents/schema/docs/SinglePhaseConstantThermalConductivity_other.rst deleted file mode 100644 index 02570b893e3..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseConstantThermalConductivity_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -===================== ============== ====================== -Name Type Description -===================== ============== ====================== -effectiveConductivity real64_array3d Effective conductivity -===================== ============== ====================== - - diff --git a/src/coreComponents/schema/docs/SinglePhaseFVM.rst b/src/coreComponents/schema/docs/SinglePhaseFVM.rst deleted file mode 100644 index 6000056c728..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseFVM.rst +++ /dev/null @@ -1,22 +0,0 @@ - - -============================== ================== ======== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -============================== ================== ======== ======================================================================================================================================================================================================================================================================================================================== -allowNegativePressure integer 1 Flag indicating if negative pressure is allowed -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isThermal integer 0 Flag indicating whether the problem is thermal or not. -logLevel integer 0 Log level -maxAbsolutePressureChange real64 -1 Maximum (absolute) pressure change in a Newton iteration -maxSequentialPressureChange real64 100000 Maximum (absolute) pressure change in a sequential iteration, used for outer loop convergence check -maxSequentialTemperatureChange real64 0.1 Maximum (absolute) temperature change in a sequential iteration, used for outer loop convergence check -name groupName required A name is required for any non-unique nodes -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -temperature real64 0 Temperature -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -============================== ================== ======== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhaseFVM_other.rst b/src/coreComponents/schema/docs/SinglePhaseFVM_other.rst deleted file mode 100644 index 3f1b37c3d6c..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseFVM_other.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -========================= ============================================================================================================================================================== ================================================================ -Name Type Description -========================= ============================================================================================================================================================== ================================================================ -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ================================================================ - - diff --git a/src/coreComponents/schema/docs/SinglePhaseHybridFVM.rst b/src/coreComponents/schema/docs/SinglePhaseHybridFVM.rst deleted file mode 100644 index 6000056c728..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseHybridFVM.rst +++ /dev/null @@ -1,22 +0,0 @@ - - -============================== ================== ======== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -============================== ================== ======== ======================================================================================================================================================================================================================================================================================================================== -allowNegativePressure integer 1 Flag indicating if negative pressure is allowed -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isThermal integer 0 Flag indicating whether the problem is thermal or not. -logLevel integer 0 Log level -maxAbsolutePressureChange real64 -1 Maximum (absolute) pressure change in a Newton iteration -maxSequentialPressureChange real64 100000 Maximum (absolute) pressure change in a sequential iteration, used for outer loop convergence check -maxSequentialTemperatureChange real64 0.1 Maximum (absolute) temperature change in a sequential iteration, used for outer loop convergence check -name groupName required A name is required for any non-unique nodes -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -temperature real64 0 Temperature -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -============================== ================== ======== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhaseHybridFVM_other.rst b/src/coreComponents/schema/docs/SinglePhaseHybridFVM_other.rst deleted file mode 100644 index d1627f7fba7..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseHybridFVM_other.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -========================= ============================================================================================================================================================== ================================ ================================================================ -Name Type Registered On Description -========================= ============================================================================================================================================================== ================================ ================================================================ -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -facePressure_n real64_array :ref:`DATASTRUCTURE_faceManager` Face pressure at the previous converged time step -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ================================ ================================================================ - - diff --git a/src/coreComponents/schema/docs/SinglePhasePoromechanics.rst b/src/coreComponents/schema/docs/SinglePhasePoromechanics.rst deleted file mode 100644 index 89d7b79139b..00000000000 --- a/src/coreComponents/schema/docs/SinglePhasePoromechanics.rst +++ /dev/null @@ -1,18 +0,0 @@ - - -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -flowSolverName groupNameRef required Name of the flow solver used by the coupled solver -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isThermal integer 0 Flag indicating whether the problem is thermal or not. Set isThermal="1" to enable the thermal coupling -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -solidSolverName groupNameRef required Name of the solid solver used by the coupled solver -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhasePoromechanicsConformingFractures.rst b/src/coreComponents/schema/docs/SinglePhasePoromechanicsConformingFractures.rst deleted file mode 100644 index 89d7b79139b..00000000000 --- a/src/coreComponents/schema/docs/SinglePhasePoromechanicsConformingFractures.rst +++ /dev/null @@ -1,18 +0,0 @@ - - -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -flowSolverName groupNameRef required Name of the flow solver used by the coupled solver -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isThermal integer 0 Flag indicating whether the problem is thermal or not. Set isThermal="1" to enable the thermal coupling -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -solidSolverName groupNameRef required Name of the solid solver used by the coupled solver -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhasePoromechanicsConformingFractures_other.rst b/src/coreComponents/schema/docs/SinglePhasePoromechanicsConformingFractures_other.rst deleted file mode 100644 index 80b71ab722d..00000000000 --- a/src/coreComponents/schema/docs/SinglePhasePoromechanicsConformingFractures_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -performStressInitialization integer Flag to indicate that the solver is going to perform stress initialization -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhasePoromechanicsEmbeddedFractures.rst b/src/coreComponents/schema/docs/SinglePhasePoromechanicsEmbeddedFractures.rst deleted file mode 100644 index 89d7b79139b..00000000000 --- a/src/coreComponents/schema/docs/SinglePhasePoromechanicsEmbeddedFractures.rst +++ /dev/null @@ -1,18 +0,0 @@ - - -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -flowSolverName groupNameRef required Name of the flow solver used by the coupled solver -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isThermal integer 0 Flag indicating whether the problem is thermal or not. Set isThermal="1" to enable the thermal coupling -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -solidSolverName groupNameRef required Name of the solid solver used by the coupled solver -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhasePoromechanicsEmbeddedFractures_other.rst b/src/coreComponents/schema/docs/SinglePhasePoromechanicsEmbeddedFractures_other.rst deleted file mode 100644 index 80b71ab722d..00000000000 --- a/src/coreComponents/schema/docs/SinglePhasePoromechanicsEmbeddedFractures_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -performStressInitialization integer Flag to indicate that the solver is going to perform stress initialization -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhasePoromechanicsInitialization.rst b/src/coreComponents/schema/docs/SinglePhasePoromechanicsInitialization.rst deleted file mode 100644 index 27129634c0b..00000000000 --- a/src/coreComponents/schema/docs/SinglePhasePoromechanicsInitialization.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -=========================== ============ ======== ========================================================================== -Name Type Default Description -=========================== ============ ======== ========================================================================== -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -performStressInitialization integer required Flag to indicate that the solver is going to perform stress initialization -poromechanicsSolverName groupNameRef required Name of the poromechanics solver -=========================== ============ ======== ========================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhasePoromechanicsInitialization_other.rst b/src/coreComponents/schema/docs/SinglePhasePoromechanicsInitialization_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/SinglePhasePoromechanicsInitialization_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/SinglePhasePoromechanicsReservoir.rst b/src/coreComponents/schema/docs/SinglePhasePoromechanicsReservoir.rst deleted file mode 100644 index b2ccf01c20b..00000000000 --- a/src/coreComponents/schema/docs/SinglePhasePoromechanicsReservoir.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -poromechanicsSolverName groupNameRef required Name of the poromechanics solver used by the coupled solver -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -wellSolverName groupNameRef required Name of the well solver used by the coupled solver -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhasePoromechanicsReservoir_other.rst b/src/coreComponents/schema/docs/SinglePhasePoromechanicsReservoir_other.rst deleted file mode 100644 index 45d9a187f0a..00000000000 --- a/src/coreComponents/schema/docs/SinglePhasePoromechanicsReservoir_other.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhasePoromechanics_other.rst b/src/coreComponents/schema/docs/SinglePhasePoromechanics_other.rst deleted file mode 100644 index 80b71ab722d..00000000000 --- a/src/coreComponents/schema/docs/SinglePhasePoromechanics_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -performStressInitialization integer Flag to indicate that the solver is going to perform stress initialization -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhaseProppantFVM.rst b/src/coreComponents/schema/docs/SinglePhaseProppantFVM.rst deleted file mode 100644 index 6000056c728..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseProppantFVM.rst +++ /dev/null @@ -1,22 +0,0 @@ - - -============================== ================== ======== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -============================== ================== ======== ======================================================================================================================================================================================================================================================================================================================== -allowNegativePressure integer 1 Flag indicating if negative pressure is allowed -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isThermal integer 0 Flag indicating whether the problem is thermal or not. -logLevel integer 0 Log level -maxAbsolutePressureChange real64 -1 Maximum (absolute) pressure change in a Newton iteration -maxSequentialPressureChange real64 100000 Maximum (absolute) pressure change in a sequential iteration, used for outer loop convergence check -maxSequentialTemperatureChange real64 0.1 Maximum (absolute) temperature change in a sequential iteration, used for outer loop convergence check -name groupName required A name is required for any non-unique nodes -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -temperature real64 0 Temperature -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -============================== ================== ======== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhaseProppantFVM_other.rst b/src/coreComponents/schema/docs/SinglePhaseProppantFVM_other.rst deleted file mode 100644 index 3f1b37c3d6c..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseProppantFVM_other.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -========================= ============================================================================================================================================================== ================================================================ -Name Type Description -========================= ============================================================================================================================================================== ================================================================ -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ================================================================ - - diff --git a/src/coreComponents/schema/docs/SinglePhaseReservoir.rst b/src/coreComponents/schema/docs/SinglePhaseReservoir.rst deleted file mode 100644 index f25a13fb960..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseReservoir.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -flowSolverName groupNameRef required Name of the flow solver used by the coupled solver -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -wellSolverName groupNameRef required Name of the well solver used by the coupled solver -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhaseReservoirPoromechanics.rst b/src/coreComponents/schema/docs/SinglePhaseReservoirPoromechanics.rst deleted file mode 100644 index e19bd9b1ac7..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseReservoirPoromechanics.rst +++ /dev/null @@ -1,18 +0,0 @@ - - -=========================== ================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -=========================== ================== ======== ====================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isThermal integer 0 Flag indicating whether the problem is thermal or not. Set isThermal="1" to enable the thermal coupling -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -reservoirAndWellsSolverName groupNameRef required Name of the reservoirAndWells solver used by the coupled solver -solidSolverName groupNameRef required Name of the solid solver used by the coupled solver -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -=========================== ================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhaseReservoirPoromechanicsInitialization.rst b/src/coreComponents/schema/docs/SinglePhaseReservoirPoromechanicsInitialization.rst deleted file mode 100644 index 27129634c0b..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseReservoirPoromechanicsInitialization.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -=========================== ============ ======== ========================================================================== -Name Type Default Description -=========================== ============ ======== ========================================================================== -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -performStressInitialization integer required Flag to indicate that the solver is going to perform stress initialization -poromechanicsSolverName groupNameRef required Name of the poromechanics solver -=========================== ============ ======== ========================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhaseReservoirPoromechanicsInitialization_other.rst b/src/coreComponents/schema/docs/SinglePhaseReservoirPoromechanicsInitialization_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseReservoirPoromechanicsInitialization_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/SinglePhaseReservoirPoromechanics_other.rst b/src/coreComponents/schema/docs/SinglePhaseReservoirPoromechanics_other.rst deleted file mode 100644 index 80b71ab722d..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseReservoirPoromechanics_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -performStressInitialization integer Flag to indicate that the solver is going to perform stress initialization -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -=========================== ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhaseReservoir_other.rst b/src/coreComponents/schema/docs/SinglePhaseReservoir_other.rst deleted file mode 100644 index 45d9a187f0a..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseReservoir_other.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhaseStatistics.rst b/src/coreComponents/schema/docs/SinglePhaseStatistics.rst deleted file mode 100644 index ff3105519bd..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseStatistics.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -============== ============ ======== =========================================== -Name Type Default Description -============== ============ ======== =========================================== -flowSolverName groupNameRef required Name of the flow solver -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -writeCSV integer 0 Write statistics into a CSV file -============== ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhaseStatistics_other.rst b/src/coreComponents/schema/docs/SinglePhaseStatistics_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseStatistics_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/SinglePhaseWell.rst b/src/coreComponents/schema/docs/SinglePhaseWell.rst deleted file mode 100644 index ba2a66c6297..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseWell.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -writeCSV integer 0 Write rates into a CSV file -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -WellControls node :ref:`XML_WellControls` -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SinglePhaseWell_other.rst b/src/coreComponents/schema/docs/SinglePhaseWell_other.rst deleted file mode 100644 index 3f16a155d2b..00000000000 --- a/src/coreComponents/schema/docs/SinglePhaseWell_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -WellControls node :ref:`DATASTRUCTURE_WellControls` -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SlipDependentPermeability.rst b/src/coreComponents/schema/docs/SlipDependentPermeability.rst deleted file mode 100644 index 86118d26163..00000000000 --- a/src/coreComponents/schema/docs/SlipDependentPermeability.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -=================== ========= ======== =========================================== -Name Type Default Description -=================== ========= ======== =========================================== -initialPermeability R1Tensor required initial permeability of the fracture. -maxPermMultiplier real64 required Maximum permeability multiplier. -name groupName required A name is required for any non-unique nodes -shearDispThreshold real64 required Threshold of shear displacement. -=================== ========= ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/SlipDependentPermeability_other.rst b/src/coreComponents/schema/docs/SlipDependentPermeability_other.rst deleted file mode 100644 index 43a2d06a562..00000000000 --- a/src/coreComponents/schema/docs/SlipDependentPermeability_other.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -=============== ============== ================================================================= -Name Type Description -=============== ============== ================================================================= -dPerm_dDispJump real64_array4d Derivative of rock permeability with respect to displacement jump -dPerm_dPressure real64_array3d Derivative of rock permeability with respect to pressure -permeability real64_array3d Rock permeability -=============== ============== ================================================================= - - diff --git a/src/coreComponents/schema/docs/SolidInternalEnergy.rst b/src/coreComponents/schema/docs/SolidInternalEnergy.rst deleted file mode 100644 index 3eea9887790..00000000000 --- a/src/coreComponents/schema/docs/SolidInternalEnergy.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -======================= ========= ======== =================================================== -Name Type Default Description -======================= ========= ======== =================================================== -name groupName required A name is required for any non-unique nodes -referenceInternalEnergy real64 required Internal energy at the reference temperature [J/kg] -referenceTemperature real64 required Reference temperature [K] -volumetricHeatCapacity real64 required Solid volumetric heat capacity [J/(kg.K)] -======================= ========= ======== =================================================== - - diff --git a/src/coreComponents/schema/docs/SolidInternalEnergy_other.rst b/src/coreComponents/schema/docs/SolidInternalEnergy_other.rst deleted file mode 100644 index c6d23064113..00000000000 --- a/src/coreComponents/schema/docs/SolidInternalEnergy_other.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -============================ ============== ============================================================================== -Name Type Description -============================ ============== ============================================================================== -dInternalEnergy_dTemperature real64_array2d Derivative of the solid internal energy w.r.t. temperature [J/(m^3.K)] -internalEnergy real64_array2d Internal energy of the solid per unit volume [J/m^3] -internalEnergy_n real64_array2d Internal energy of the solid per unit volume at the previous time-step [J/m^3] -============================ ============== ============================================================================== - - diff --git a/src/coreComponents/schema/docs/SolidMechanicsEmbeddedFractures.rst b/src/coreComponents/schema/docs/SolidMechanicsEmbeddedFractures.rst deleted file mode 100644 index c51f1d33c6b..00000000000 --- a/src/coreComponents/schema/docs/SolidMechanicsEmbeddedFractures.rst +++ /dev/null @@ -1,29 +0,0 @@ - - -========================= ====================================================== =============== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ====================================================== =============== ======================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -massDamping real64 0 Value of mass based damping coefficient. -maxNumResolves integer 10 Value to indicate how many resolves may be executed after some other event is executed. For example, if a SurfaceGenerator is specified, it will be executed after the mechanics solve. However if a new surface is generated, then the mechanics solve must be executed again due to the change in topology. -name groupName required A name is required for any non-unique nodes -newmarkBeta real64 0.25 Value of :math:`\beta` in the Newmark Method for Implicit Dynamic time integration option. This should be pow(newmarkGamma+0.5,2.0)/4.0 unless you know what you are doing. -newmarkGamma real64 0.5 Value of :math:`\gamma` in the Newmark Method for Implicit Dynamic time integration option -stiffnessDamping real64 0 Value of stiffness based damping coefficient. -strainTheory integer 0 | Indicates whether or not to use `Infinitesimal Strain Theory `_, or `Finite Strain Theory `_. Valid Inputs are: - | 0 - Infinitesimal Strain - | 1 - Finite Strain -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -timeIntegrationOption geos_SolidMechanicsLagrangianFEM_TimeIntegrationOption ExplicitDynamic | Time integration method. Options are: - | * QuasiStatic - | * ImplicitDynamic - | * ExplicitDynamic -useStaticCondensation integer 0 Defines whether to use static condensation or not. -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ====================================================== =============== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SolidMechanicsEmbeddedFractures_other.rst b/src/coreComponents/schema/docs/SolidMechanicsEmbeddedFractures_other.rst deleted file mode 100644 index 17da1cb5b33..00000000000 --- a/src/coreComponents/schema/docs/SolidMechanicsEmbeddedFractures_other.rst +++ /dev/null @@ -1,16 +0,0 @@ - - -========================= ============================================================================================================================================================== ===================================================================== -Name Type Description -========================= ============================================================================================================================================================== ===================================================================== -contactRelationName groupNameRef Name of contact relation to enforce constraints on fracture boundary. -maxForce real64 The maximum force contribution in the problem domain. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -surfaceGeneratorName string Name of the surface generator to use -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ===================================================================== - - diff --git a/src/coreComponents/schema/docs/SolidMechanicsLagrangeContact.rst b/src/coreComponents/schema/docs/SolidMechanicsLagrangeContact.rst deleted file mode 100644 index dcc17ebc657..00000000000 --- a/src/coreComponents/schema/docs/SolidMechanicsLagrangeContact.rst +++ /dev/null @@ -1,29 +0,0 @@ - - -========================= ====================================================== =============== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ====================================================== =============== ======================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -massDamping real64 0 Value of mass based damping coefficient. -maxNumResolves integer 10 Value to indicate how many resolves may be executed after some other event is executed. For example, if a SurfaceGenerator is specified, it will be executed after the mechanics solve. However if a new surface is generated, then the mechanics solve must be executed again due to the change in topology. -name groupName required A name is required for any non-unique nodes -newmarkBeta real64 0.25 Value of :math:`\beta` in the Newmark Method for Implicit Dynamic time integration option. This should be pow(newmarkGamma+0.5,2.0)/4.0 unless you know what you are doing. -newmarkGamma real64 0.5 Value of :math:`\gamma` in the Newmark Method for Implicit Dynamic time integration option -stabilizationName groupNameRef required Name of the stabilization to use in the lagrangian contact solver -stiffnessDamping real64 0 Value of stiffness based damping coefficient. -strainTheory integer 0 | Indicates whether or not to use `Infinitesimal Strain Theory `_, or `Finite Strain Theory `_. Valid Inputs are: - | 0 - Infinitesimal Strain - | 1 - Finite Strain -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -timeIntegrationOption geos_SolidMechanicsLagrangianFEM_TimeIntegrationOption ExplicitDynamic | Time integration method. Options are: - | * QuasiStatic - | * ImplicitDynamic - | * ExplicitDynamic -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ====================================================== =============== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SolidMechanicsLagrangeContact_other.rst b/src/coreComponents/schema/docs/SolidMechanicsLagrangeContact_other.rst deleted file mode 100644 index 17da1cb5b33..00000000000 --- a/src/coreComponents/schema/docs/SolidMechanicsLagrangeContact_other.rst +++ /dev/null @@ -1,16 +0,0 @@ - - -========================= ============================================================================================================================================================== ===================================================================== -Name Type Description -========================= ============================================================================================================================================================== ===================================================================== -contactRelationName groupNameRef Name of contact relation to enforce constraints on fracture boundary. -maxForce real64 The maximum force contribution in the problem domain. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -surfaceGeneratorName string Name of the surface generator to use -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ===================================================================== - - diff --git a/src/coreComponents/schema/docs/SolidMechanicsLagrangianSSLE.rst b/src/coreComponents/schema/docs/SolidMechanicsLagrangianSSLE.rst deleted file mode 100644 index 21cdc11d22d..00000000000 --- a/src/coreComponents/schema/docs/SolidMechanicsLagrangianSSLE.rst +++ /dev/null @@ -1,30 +0,0 @@ - - -========================= ====================================================== =============== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ====================================================== =============== ======================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -contactRelationName groupNameRef NOCONTACT Name of contact relation to enforce constraints on fracture boundary. -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -massDamping real64 0 Value of mass based damping coefficient. -maxNumResolves integer 10 Value to indicate how many resolves may be executed after some other event is executed. For example, if a SurfaceGenerator is specified, it will be executed after the mechanics solve. However if a new surface is generated, then the mechanics solve must be executed again due to the change in topology. -name groupName required A name is required for any non-unique nodes -newmarkBeta real64 0.25 Value of :math:`\beta` in the Newmark Method for Implicit Dynamic time integration option. This should be pow(newmarkGamma+0.5,2.0)/4.0 unless you know what you are doing. -newmarkGamma real64 0.5 Value of :math:`\gamma` in the Newmark Method for Implicit Dynamic time integration option -stiffnessDamping real64 0 Value of stiffness based damping coefficient. -strainTheory integer 0 | Indicates whether or not to use `Infinitesimal Strain Theory `_, or `Finite Strain Theory `_. Valid Inputs are: - | 0 - Infinitesimal Strain - | 1 - Finite Strain -surfaceGeneratorName string Name of the surface generator to use -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -timeIntegrationOption geos_SolidMechanicsLagrangianFEM_TimeIntegrationOption ExplicitDynamic | Time integration method. Options are: - | * QuasiStatic - | * ImplicitDynamic - | * ExplicitDynamic -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ====================================================== =============== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SolidMechanicsLagrangianSSLE_other.rst b/src/coreComponents/schema/docs/SolidMechanicsLagrangianSSLE_other.rst deleted file mode 100644 index a4018f48d74..00000000000 --- a/src/coreComponents/schema/docs/SolidMechanicsLagrangianSSLE_other.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -========================= ============================================================================================================================================================== ================================================================ -Name Type Description -========================= ============================================================================================================================================================== ================================================================ -maxForce real64 The maximum force contribution in the problem domain. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ================================================================ - - diff --git a/src/coreComponents/schema/docs/SolidMechanicsStateReset.rst b/src/coreComponents/schema/docs/SolidMechanicsStateReset.rst deleted file mode 100644 index c8483e51e88..00000000000 --- a/src/coreComponents/schema/docs/SolidMechanicsStateReset.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -=================== ============ ======== ============================================ -Name Type Default Description -=================== ============ ======== ============================================ -disableInelasticity integer 0 Flag to enable/disable inelastic behavior -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -resetDisplacements integer 1 Flag to reset displacements (and velocities) -solidSolverName groupNameRef required Name of the solid mechanics solver -=================== ============ ======== ============================================ - - diff --git a/src/coreComponents/schema/docs/SolidMechanicsStateReset_other.rst b/src/coreComponents/schema/docs/SolidMechanicsStateReset_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/SolidMechanicsStateReset_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/SolidMechanicsStatistics.rst b/src/coreComponents/schema/docs/SolidMechanicsStatistics.rst deleted file mode 100644 index 2395830a112..00000000000 --- a/src/coreComponents/schema/docs/SolidMechanicsStatistics.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -=============== ============ ======== =========================================== -Name Type Default Description -=============== ============ ======== =========================================== -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -solidSolverName groupNameRef required Name of the solid solver -writeCSV integer 0 Write statistics into a CSV file -=============== ============ ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/SolidMechanicsStatistics_other.rst b/src/coreComponents/schema/docs/SolidMechanicsStatistics_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/SolidMechanicsStatistics_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/SolidMechanics_LagrangianFEM.rst b/src/coreComponents/schema/docs/SolidMechanics_LagrangianFEM.rst deleted file mode 100644 index 21cdc11d22d..00000000000 --- a/src/coreComponents/schema/docs/SolidMechanics_LagrangianFEM.rst +++ /dev/null @@ -1,30 +0,0 @@ - - -========================= ====================================================== =============== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ====================================================== =============== ======================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -contactRelationName groupNameRef NOCONTACT Name of contact relation to enforce constraints on fracture boundary. -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -massDamping real64 0 Value of mass based damping coefficient. -maxNumResolves integer 10 Value to indicate how many resolves may be executed after some other event is executed. For example, if a SurfaceGenerator is specified, it will be executed after the mechanics solve. However if a new surface is generated, then the mechanics solve must be executed again due to the change in topology. -name groupName required A name is required for any non-unique nodes -newmarkBeta real64 0.25 Value of :math:`\beta` in the Newmark Method for Implicit Dynamic time integration option. This should be pow(newmarkGamma+0.5,2.0)/4.0 unless you know what you are doing. -newmarkGamma real64 0.5 Value of :math:`\gamma` in the Newmark Method for Implicit Dynamic time integration option -stiffnessDamping real64 0 Value of stiffness based damping coefficient. -strainTheory integer 0 | Indicates whether or not to use `Infinitesimal Strain Theory `_, or `Finite Strain Theory `_. Valid Inputs are: - | 0 - Infinitesimal Strain - | 1 - Finite Strain -surfaceGeneratorName string Name of the surface generator to use -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -timeIntegrationOption geos_SolidMechanicsLagrangianFEM_TimeIntegrationOption ExplicitDynamic | Time integration method. Options are: - | * QuasiStatic - | * ImplicitDynamic - | * ExplicitDynamic -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ====================================================== =============== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SolidMechanics_LagrangianFEM_other.rst b/src/coreComponents/schema/docs/SolidMechanics_LagrangianFEM_other.rst deleted file mode 100644 index a4018f48d74..00000000000 --- a/src/coreComponents/schema/docs/SolidMechanics_LagrangianFEM_other.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -========================= ============================================================================================================================================================== ================================================================ -Name Type Description -========================= ============================================================================================================================================================== ================================================================ -maxForce real64 The maximum force contribution in the problem domain. -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ================================================================ - - diff --git a/src/coreComponents/schema/docs/SolidMechanics_MPM.rst b/src/coreComponents/schema/docs/SolidMechanics_MPM.rst deleted file mode 100644 index 2c7d14f5866..00000000000 --- a/src/coreComponents/schema/docs/SolidMechanics_MPM.rst +++ /dev/null @@ -1,41 +0,0 @@ - - -============================== ============================================ =============== ======================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -============================== ============================================ =============== ======================================================================================================================================================================================================================================================================================================================== -boundaryConditionTypes integer_array {0} | Boundary conditions on x-, x+, y-, y+, z- and z+ faces. Options are: - | * Outflow - | * Symmetry -boxAverageHistory integer 0 Flag for whether to output box average history -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -contactGapCorrection integer 0 Flag for mitigating contact gaps -cpdiDomainScaling integer 0 Option for CPDI domain scaling -damageFieldPartitioning integer 0 Flag for using the gradient of the particle damage field to partition material into separate velocity fields -discretization groupNameRef required Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -fTableInterpType integer 0 The type of F table interpolation. Options are 0 (linear), 1 (cosine), 2 (quintic polynomial). -fTablePath path Path to f-table -frictionCoefficient real64 0 Coefficient of friction, currently assumed to be the same everywhere -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -needsNeighborList integer 0 Flag for whether to construct neighbor list -neighborRadius real64 -1 Neighbor radius for SPH-type calculations -planeStrain integer 0 Flag for performing plane strain calculations -prescribedBcTable integer 0 Flag for whether to have time-dependent boundary condition types -prescribedBoundaryFTable integer 0 Flag for whether to have time-dependent boundary conditions described by a global background grid F -reactionHistory integer 0 Flag for whether to output face reaction history -separabilityMinDamage real64 0.5 Damage threshold for field separability -solverProfiling integer 0 Flag for timing subroutines in the solver -surfaceDetection integer 0 Flag for automatic surface detection on the 1st cycle -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -timeIntegrationOption geos_SolidMechanicsMPM_TimeIntegrationOption ExplicitDynamic | Time integration method. Options are: - | * QuasiStatic - | * ImplicitDynamic - | * ExplicitDynamic -treatFullyDamagedAsSingleField integer 1 Whether to consolidate fully damaged fields into a single field. Nice for modeling damaged mush. -useDamageAsSurfaceFlag integer 0 Indicates whether particle damage at the beginning of the simulation should be interpreted as a surface flag -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -============================== ============================================ =============== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SolidMechanics_MPM_other.rst b/src/coreComponents/schema/docs/SolidMechanics_MPM_other.rst deleted file mode 100644 index 4cd129ff504..00000000000 --- a/src/coreComponents/schema/docs/SolidMechanics_MPM_other.rst +++ /dev/null @@ -1,34 +0,0 @@ - - -========================= ============================================================================================================================================================== ================================================================================================== -Name Type Description -========================= ============================================================================================================================================================== ================================================================================================== -bcTable real64_array2d Array that stores time-dependent bc types on x-, x+, y-, y+, z- and z+ faces. -binSizeMultiplier integer Multiplier for setting bin size, used to speed up particle neighbor sorting -domainExtent real64_array domain extent -domainF real64_array domain deformation gradient -domainL real64_array domain L -elementSize real64_array Minimum element size in x, y and z -fTable real64_array2d Array that stores time-dependent grid-aligned stretches interpreted as a global background grid F. -globalMaximum real64_array global maximum -globalMinimum real64_array global minimum -localMaximum real64_array local maximum -localMaximumNoGhost real64_array local maximum without ghost cells -localMinimum real64_array local minimum -localMinimumNoGhost real64_array local minimum without ghost cells -m_ijkMap integer_array3d Map from indices in each spatial dimension to local node ID -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -numContactFlags integer Number of contact flags that can appear due to damage -numContactGroups integer Number of prescribed contact groups -numDims integer The number of active spatial dimensions, 2 for plane strain, 3 otherwise -numElements integer_array number of elements along partition directions -numVelocityFields integer Number of velocity fields -partitionExtent real64_array parititon extent -smallMass real64 The small mass threshold for ignoring extremely low-mass nodes. -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SoloEvent.rst b/src/coreComponents/schema/docs/SoloEvent.rst deleted file mode 100644 index de9a7ad86ee..00000000000 --- a/src/coreComponents/schema/docs/SoloEvent.rst +++ /dev/null @@ -1,23 +0,0 @@ - - -==================== ============ ======== ================================================================================================================================================================= -Name Type Default Description -==================== ============ ======== ================================================================================================================================================================= -beginTime real64 0 Start time of this event. -endTime real64 1e+100 End time of this event. -finalDtStretch real64 0.001 Allow the final dt request for this event to grow by this percentage to match the endTime exactly. -forceDt real64 -1 While active, this event will request this timestep value (ignoring any children/targets requests). -logLevel integer 0 Log level -maxEventDt real64 -1 While active, this event will request a timestep <= this value (depending upon any child/target requests). -name groupName required A name is required for any non-unique nodes -target groupNameRef Name of the object to be executed when the event criteria are met. -targetCycle integer -1 Targeted cycle to execute the event. -targetExactStartStop integer 1 If this option is set, the event will reduce its timestep requests to match any specified beginTime/endTimes exactly. -targetExactTimestep integer 1 If this option is set, the event will reduce its timestep requests to match the specified execution time exactly: dt_request = min(dt_request, t_target - time)). -targetTime real64 -1 Targeted time to execute the event. -HaltEvent node :ref:`XML_HaltEvent` -PeriodicEvent node :ref:`XML_PeriodicEvent` -SoloEvent node :ref:`XML_SoloEvent` -==================== ============ ======== ================================================================================================================================================================= - - diff --git a/src/coreComponents/schema/docs/SoloEvent_other.rst b/src/coreComponents/schema/docs/SoloEvent_other.rst deleted file mode 100644 index f63756dd49b..00000000000 --- a/src/coreComponents/schema/docs/SoloEvent_other.rst +++ /dev/null @@ -1,16 +0,0 @@ - - -================= ======= =============================================== -Name Type Description -================= ======= =============================================== -currentSubEvent integer Index of the current subevent -eventForecast integer Indicates when the event is expected to execute -isTargetExecuting integer Index of the current subevent -lastCycle integer Last event occurrence (cycle) -lastTime real64 Last event occurrence (time) -HaltEvent node :ref:`DATASTRUCTURE_HaltEvent` -PeriodicEvent node :ref:`DATASTRUCTURE_PeriodicEvent` -SoloEvent node :ref:`DATASTRUCTURE_SoloEvent` -================= ======= =============================================== - - diff --git a/src/coreComponents/schema/docs/SolverStatistics_other.rst b/src/coreComponents/schema/docs/SolverStatistics_other.rst deleted file mode 100644 index 51ffa886326..00000000000 --- a/src/coreComponents/schema/docs/SolverStatistics_other.rst +++ /dev/null @@ -1,16 +0,0 @@ - - -================================ ======= ===================================================== -Name Type Description -================================ ======= ===================================================== -numDiscardedLinearIterations integer Cumulative number of discarded linear iterations -numDiscardedNonlinearIterations integer Cumulative number of discarded nonlinear iterations -numDiscardedOuterLoopIterations integer Cumulative number of discarded outer loop iterations -numSuccessfulLinearIterations integer Cumulative number of successful linear iterations -numSuccessfulNonlinearIterations integer Cumulative number of successful nonlinear iterations -numSuccessfulOuterLoopIterations integer Cumulative number of successful outer loop iterations -numTimeStepCuts integer Number of time step cuts -numTimeSteps integer Number of time steps -================================ ======= ===================================================== - - diff --git a/src/coreComponents/schema/docs/Solvers.rst b/src/coreComponents/schema/docs/Solvers.rst deleted file mode 100644 index b592e00dde7..00000000000 --- a/src/coreComponents/schema/docs/Solvers.rst +++ /dev/null @@ -1,46 +0,0 @@ - - -============================================= ======== =========== ======================================================== -Name Type Default Description -============================================= ======== =========== ======================================================== -gravityVector R1Tensor {0,0,-9.81} Gravity vector used in the physics solvers -AcousticElasticSEM node :ref:`XML_AcousticElasticSEM` -AcousticFirstOrderSEM node :ref:`XML_AcousticFirstOrderSEM` -AcousticSEM node :ref:`XML_AcousticSEM` -AcousticVTISEM node :ref:`XML_AcousticVTISEM` -CompositionalMultiphaseFVM node :ref:`XML_CompositionalMultiphaseFVM` -CompositionalMultiphaseHybridFVM node :ref:`XML_CompositionalMultiphaseHybridFVM` -CompositionalMultiphaseReservoir node :ref:`XML_CompositionalMultiphaseReservoir` -CompositionalMultiphaseReservoirPoromechanics node :ref:`XML_CompositionalMultiphaseReservoirPoromechanics` -CompositionalMultiphaseWell node :ref:`XML_CompositionalMultiphaseWell` -ElasticFirstOrderSEM node :ref:`XML_ElasticFirstOrderSEM` -ElasticSEM node :ref:`XML_ElasticSEM` -EmbeddedSurfaceGenerator node :ref:`XML_EmbeddedSurfaceGenerator` -FlowProppantTransport node :ref:`XML_FlowProppantTransport` -Hydrofracture node :ref:`XML_Hydrofracture` -LaplaceFEM node :ref:`XML_LaplaceFEM` -MultiphasePoromechanics node :ref:`XML_MultiphasePoromechanics` -MultiphasePoromechanicsReservoir node :ref:`XML_MultiphasePoromechanicsReservoir` -PhaseFieldDamageFEM node :ref:`XML_PhaseFieldDamageFEM` -PhaseFieldFracture node :ref:`XML_PhaseFieldFracture` -ProppantTransport node :ref:`XML_ProppantTransport` -ReactiveCompositionalMultiphaseOBL node :ref:`XML_ReactiveCompositionalMultiphaseOBL` -SinglePhaseFVM node :ref:`XML_SinglePhaseFVM` -SinglePhaseHybridFVM node :ref:`XML_SinglePhaseHybridFVM` -SinglePhasePoromechanics node :ref:`XML_SinglePhasePoromechanics` -SinglePhasePoromechanicsConformingFractures node :ref:`XML_SinglePhasePoromechanicsConformingFractures` -SinglePhasePoromechanicsEmbeddedFractures node :ref:`XML_SinglePhasePoromechanicsEmbeddedFractures` -SinglePhasePoromechanicsReservoir node :ref:`XML_SinglePhasePoromechanicsReservoir` -SinglePhaseProppantFVM node :ref:`XML_SinglePhaseProppantFVM` -SinglePhaseReservoir node :ref:`XML_SinglePhaseReservoir` -SinglePhaseReservoirPoromechanics node :ref:`XML_SinglePhaseReservoirPoromechanics` -SinglePhaseWell node :ref:`XML_SinglePhaseWell` -SolidMechanicsEmbeddedFractures node :ref:`XML_SolidMechanicsEmbeddedFractures` -SolidMechanicsLagrangeContact node :ref:`XML_SolidMechanicsLagrangeContact` -SolidMechanicsLagrangianSSLE node :ref:`XML_SolidMechanicsLagrangianSSLE` -SolidMechanics_LagrangianFEM node :ref:`XML_SolidMechanics_LagrangianFEM` -SolidMechanics_MPM node :ref:`XML_SolidMechanics_MPM` -SurfaceGenerator node :ref:`XML_SurfaceGenerator` -============================================= ======== =========== ======================================================== - - diff --git a/src/coreComponents/schema/docs/Solvers_other.rst b/src/coreComponents/schema/docs/Solvers_other.rst deleted file mode 100644 index a4b9911d0f2..00000000000 --- a/src/coreComponents/schema/docs/Solvers_other.rst +++ /dev/null @@ -1,45 +0,0 @@ - - -============================================= ==== ================================================================== -Name Type Description -============================================= ==== ================================================================== -AcousticElasticSEM node :ref:`DATASTRUCTURE_AcousticElasticSEM` -AcousticFirstOrderSEM node :ref:`DATASTRUCTURE_AcousticFirstOrderSEM` -AcousticSEM node :ref:`DATASTRUCTURE_AcousticSEM` -AcousticVTISEM node :ref:`DATASTRUCTURE_AcousticVTISEM` -CompositionalMultiphaseFVM node :ref:`DATASTRUCTURE_CompositionalMultiphaseFVM` -CompositionalMultiphaseHybridFVM node :ref:`DATASTRUCTURE_CompositionalMultiphaseHybridFVM` -CompositionalMultiphaseReservoir node :ref:`DATASTRUCTURE_CompositionalMultiphaseReservoir` -CompositionalMultiphaseReservoirPoromechanics node :ref:`DATASTRUCTURE_CompositionalMultiphaseReservoirPoromechanics` -CompositionalMultiphaseWell node :ref:`DATASTRUCTURE_CompositionalMultiphaseWell` -ElasticFirstOrderSEM node :ref:`DATASTRUCTURE_ElasticFirstOrderSEM` -ElasticSEM node :ref:`DATASTRUCTURE_ElasticSEM` -EmbeddedSurfaceGenerator node :ref:`DATASTRUCTURE_EmbeddedSurfaceGenerator` -FlowProppantTransport node :ref:`DATASTRUCTURE_FlowProppantTransport` -Hydrofracture node :ref:`DATASTRUCTURE_Hydrofracture` -LaplaceFEM node :ref:`DATASTRUCTURE_LaplaceFEM` -MultiphasePoromechanics node :ref:`DATASTRUCTURE_MultiphasePoromechanics` -MultiphasePoromechanicsReservoir node :ref:`DATASTRUCTURE_MultiphasePoromechanicsReservoir` -PhaseFieldDamageFEM node :ref:`DATASTRUCTURE_PhaseFieldDamageFEM` -PhaseFieldFracture node :ref:`DATASTRUCTURE_PhaseFieldFracture` -ProppantTransport node :ref:`DATASTRUCTURE_ProppantTransport` -ReactiveCompositionalMultiphaseOBL node :ref:`DATASTRUCTURE_ReactiveCompositionalMultiphaseOBL` -SinglePhaseFVM node :ref:`DATASTRUCTURE_SinglePhaseFVM` -SinglePhaseHybridFVM node :ref:`DATASTRUCTURE_SinglePhaseHybridFVM` -SinglePhasePoromechanics node :ref:`DATASTRUCTURE_SinglePhasePoromechanics` -SinglePhasePoromechanicsConformingFractures node :ref:`DATASTRUCTURE_SinglePhasePoromechanicsConformingFractures` -SinglePhasePoromechanicsEmbeddedFractures node :ref:`DATASTRUCTURE_SinglePhasePoromechanicsEmbeddedFractures` -SinglePhasePoromechanicsReservoir node :ref:`DATASTRUCTURE_SinglePhasePoromechanicsReservoir` -SinglePhaseProppantFVM node :ref:`DATASTRUCTURE_SinglePhaseProppantFVM` -SinglePhaseReservoir node :ref:`DATASTRUCTURE_SinglePhaseReservoir` -SinglePhaseReservoirPoromechanics node :ref:`DATASTRUCTURE_SinglePhaseReservoirPoromechanics` -SinglePhaseWell node :ref:`DATASTRUCTURE_SinglePhaseWell` -SolidMechanicsEmbeddedFractures node :ref:`DATASTRUCTURE_SolidMechanicsEmbeddedFractures` -SolidMechanicsLagrangeContact node :ref:`DATASTRUCTURE_SolidMechanicsLagrangeContact` -SolidMechanicsLagrangianSSLE node :ref:`DATASTRUCTURE_SolidMechanicsLagrangianSSLE` -SolidMechanics_LagrangianFEM node :ref:`DATASTRUCTURE_SolidMechanics_LagrangianFEM` -SolidMechanics_MPM node :ref:`DATASTRUCTURE_SolidMechanics_MPM` -SurfaceGenerator node :ref:`DATASTRUCTURE_SurfaceGenerator` -============================================= ==== ================================================================== - - diff --git a/src/coreComponents/schema/docs/SourceFlux.rst b/src/coreComponents/schema/docs/SourceFlux.rst deleted file mode 100644 index c227dcbd7d8..00000000000 --- a/src/coreComponents/schema/docs/SourceFlux.rst +++ /dev/null @@ -1,20 +0,0 @@ - - -====================== ================== ======== ============================================================================== -Name Type Default Description -====================== ================== ======== ============================================================================== -bcApplicationTableName groupNameRef Name of table that specifies the on/off application of the boundary condition. -beginTime real64 -1e+99 Time at which the boundary condition will start being applied. -component integer -1 Component of field (if tensor) to apply boundary condition to. -direction R1Tensor {0,0,0} Direction to apply boundary condition to. -endTime real64 1e+99 Time at which the boundary condition will stop being applied. -functionName groupNameRef Name of function that specifies variation of the boundary condition. -initialCondition integer 0 Boundary condition is applied as an initial condition. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -objectPath groupNameRef Path to the target field -scale real64 0 Scale factor for value of the boundary condition. -setNames groupNameRef_array required Name of sets that boundary condition is applied to. -====================== ================== ======== ============================================================================== - - diff --git a/src/coreComponents/schema/docs/SourceFlux_other.rst b/src/coreComponents/schema/docs/SourceFlux_other.rst deleted file mode 100644 index c3574d52b05..00000000000 --- a/src/coreComponents/schema/docs/SourceFlux_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -========= ============ ==================================================== -Name Type Description -========= ============ ==================================================== -fieldName groupNameRef Name of field that boundary condition is applied to. -========= ============ ==================================================== - - diff --git a/src/coreComponents/schema/docs/SurfaceElementRegion.rst b/src/coreComponents/schema/docs/SurfaceElementRegion.rst deleted file mode 100644 index 8e8ab2e6ec6..00000000000 --- a/src/coreComponents/schema/docs/SurfaceElementRegion.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -=============== ============================================== ================= ================================================================================= -Name Type Default Description -=============== ============================================== ================= ================================================================================= -defaultAperture real64 required The default aperture of newly formed surface elements. -faceBlock groupNameRef FractureSubRegion The name of the face block in the mesh, or the embedded surface. -materialList groupNameRef_array required List of materials present in this region -meshBody groupNameRef Mesh body that contains this region -name groupName required A name is required for any non-unique nodes -subRegionType geos_SurfaceElementRegion_SurfaceSubRegionType faceElement Type of surface element subregion. Valid options: {faceElement, embeddedElement}. -=============== ============================================== ================= ================================================================================= - - diff --git a/src/coreComponents/schema/docs/SurfaceElementRegion_other.rst b/src/coreComponents/schema/docs/SurfaceElementRegion_other.rst deleted file mode 100644 index a65968b0105..00000000000 --- a/src/coreComponents/schema/docs/SurfaceElementRegion_other.rst +++ /dev/null @@ -1,16 +0,0 @@ - - -======================= ==================================================================== ========================================================= -Name Type Description -======================= ==================================================================== ========================================================= -domainBoundaryIndicator integer_array (no description available) -ghostRank integer_array (no description available) -globalToLocalMap geos_mapBase< long long, int, std_integral_constant< bool, false > > (no description available) -isExternal integer_array (no description available) -localToGlobalMap globalIndex_array Array that contains a map from localIndex to globalIndex. -elementSubRegions node :ref:`DATASTRUCTURE_elementSubRegions` -neighborData node :ref:`DATASTRUCTURE_neighborData` -sets node :ref:`DATASTRUCTURE_sets` -======================= ==================================================================== ========================================================= - - diff --git a/src/coreComponents/schema/docs/SurfaceGenerator.rst b/src/coreComponents/schema/docs/SurfaceGenerator.rst deleted file mode 100644 index 36b64dffb8b..00000000000 --- a/src/coreComponents/schema/docs/SurfaceGenerator.rst +++ /dev/null @@ -1,20 +0,0 @@ - - -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== -cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] -fractureRegion groupNameRef Fracture (no description available) -initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isPoroelastic integer 0 Flag that defines whether the material is poroelastic or not. -logLevel integer 0 Log level -mpiCommOrder integer 0 Flag to enable MPI consistent communication ordering -name groupName required A name is required for any non-unique nodes -nodeBasedSIF integer 0 Flag for choosing between node or edge based criteria: 1 for node based criterion -rockToughness real64 required Rock toughness of the solid material -targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. -LinearSolverParameters node unique :ref:`XML_LinearSolverParameters` -NonlinearSolverParameters node unique :ref:`XML_NonlinearSolverParameters` -========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SurfaceGenerator_other.rst b/src/coreComponents/schema/docs/SurfaceGenerator_other.rst deleted file mode 100644 index d9e8cac2e2d..00000000000 --- a/src/coreComponents/schema/docs/SurfaceGenerator_other.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -Name Type Description -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== -discretization groupNameRef Name of discretization object (defined in the :ref:`NumericalMethodsManager`) to use for this solver. For instance, if this is a Finite Element Solver, the name of a :ref:`FiniteElement` should be specified. If this is a Finite Volume Method, the name of a :ref:`FiniteVolume` discretization should be specified. -failCriterion integer (no description available) -maxStableDt real64 Value of the Maximum Stable Timestep for this solver. -meshTargets geos_mapBase< std_pair< string, string >, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > MeshBody/Region combinations that the solver will be applied to. -tipEdges LvArray_SortedArray< int, int, LvArray_ChaiBuffer > Set containing all the tip edges -tipFaces LvArray_SortedArray< int, int, LvArray_ChaiBuffer > Set containing all the tip faces -tipNodes LvArray_SortedArray< int, int, LvArray_ChaiBuffer > Set containing all the nodes at the fracture tip -trailingFaces LvArray_SortedArray< int, int, LvArray_ChaiBuffer > Set containing all the trailing faces -LinearSolverParameters node :ref:`DATASTRUCTURE_LinearSolverParameters` -NonlinearSolverParameters node :ref:`DATASTRUCTURE_NonlinearSolverParameters` -SolverStatistics node :ref:`DATASTRUCTURE_SolverStatistics` -========================= ============================================================================================================================================================== ======================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/SymbolicFunction.rst b/src/coreComponents/schema/docs/SymbolicFunction.rst deleted file mode 100644 index 0429ef7ef0d..00000000000 --- a/src/coreComponents/schema/docs/SymbolicFunction.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -============= ================== ======== ============================================================================ -Name Type Default Description -============= ================== ======== ============================================================================ -expression string required Symbolic math expression -inputVarNames groupNameRef_array {} Name of fields are input to function. -name groupName required A name is required for any non-unique nodes -variableNames groupNameRef_array required List of variables in expression. The order must match the evaluate argument -============= ================== ======== ============================================================================ - - diff --git a/src/coreComponents/schema/docs/SymbolicFunction_other.rst b/src/coreComponents/schema/docs/SymbolicFunction_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/SymbolicFunction_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/TableCapillaryPressure.rst b/src/coreComponents/schema/docs/TableCapillaryPressure.rst deleted file mode 100644 index c3732b8a9b7..00000000000 --- a/src/coreComponents/schema/docs/TableCapillaryPressure.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -========================================== ================== ======== ====================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================================== ================== ======== ====================================================================================================================================================================================================================================================================================================================== -name groupName required A name is required for any non-unique nodes -nonWettingIntermediateCapPressureTableName groupNameRef | Capillary pressure table [Pa] for the pair (non-wetting phase, intermediate phase) - | Note that this input is only used for three-phase flow. - | If you want to do a two-phase simulation, please use instead wettingNonWettingCapPressureTableName to specify the table names -phaseNames groupNameRef_array required List of fluid phases -wettingIntermediateCapPressureTableName groupNameRef | Capillary pressure table [Pa] for the pair (wetting phase, intermediate phase) - | Note that this input is only used for three-phase flow. - | If you want to do a two-phase simulation, please use instead wettingNonWettingCapPressureTableName to specify the table names -wettingNonWettingCapPressureTableName groupNameRef | Capillary pressure table [Pa] for the pair (wetting phase, non-wetting phase) - | Note that this input is only used for two-phase flow. - | If you want to do a three-phase simulation, please use instead wettingIntermediateCapPressureTableName and nonWettingIntermediateCapPressureTableName to specify the table names -========================================== ================== ======== ====================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/TableCapillaryPressure_other.rst b/src/coreComponents/schema/docs/TableCapillaryPressure_other.rst deleted file mode 100644 index d8e9f22248c..00000000000 --- a/src/coreComponents/schema/docs/TableCapillaryPressure_other.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -=================================== ======================================================================================================= ============================================================================ -Name Type Description -=================================== ======================================================================================================= ============================================================================ -capPresWrappers LvArray_Array< geos_TableFunction_KernelWrapper, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer > (no description available) -dPhaseCapPressure_dPhaseVolFraction real64_array4d Derivative of phase capillary pressure with respect to phase volume fraction -phaseCapPressure real64_array3d Phase capillary pressure -phaseOrder integer_array (no description available) -phaseTypes integer_array (no description available) -=================================== ======================================================================================================= ============================================================================ - - diff --git a/src/coreComponents/schema/docs/TableFunction.rst b/src/coreComponents/schema/docs/TableFunction.rst deleted file mode 100644 index b8909ae71d7..00000000000 --- a/src/coreComponents/schema/docs/TableFunction.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -=============== ==================================== ======== =========================================================================== -Name Type Default Description -=============== ==================================== ======== =========================================================================== -coordinateFiles path_array {} List of coordinate file names for ND Table -coordinates real64_array {0} Coordinates inputs for 1D tables -inputVarNames groupNameRef_array {} Name of fields are input to function. -interpolation geos_TableFunction_InterpolationType linear | Interpolation method. Valid options: - | * linear - | * nearest - | * upper - | * lower -name groupName required A name is required for any non-unique nodes -values real64_array {0} Values for 1D tables -voxelFile path Voxel file name for ND Table -=============== ==================================== ======== =========================================================================== - - diff --git a/src/coreComponents/schema/docs/TableFunction_other.rst b/src/coreComponents/schema/docs/TableFunction_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/TableFunction_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/TableRelativePermeability.rst b/src/coreComponents/schema/docs/TableRelativePermeability.rst deleted file mode 100644 index e5570ab4b80..00000000000 --- a/src/coreComponents/schema/docs/TableRelativePermeability.rst +++ /dev/null @@ -1,25 +0,0 @@ - - -======================================= ======================================== ======== ================================================================================================================================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -======================================= ======================================== ======== ================================================================================================================================================================================================================================================================================================================================================================================================================================== -name groupName required A name is required for any non-unique nodes -nonWettingIntermediateRelPermTableNames groupNameRef_array {} | List of relative permeability tables for the pair (non-wetting phase, intermediate phase) - | The expected format is "{ nonWettingPhaseRelPermTableName, intermediatePhaseRelPermTableName }", in that order - | Note that this input is only used for three-phase flow. - | If you want to do a two-phase simulation, please use instead wettingNonWettingRelPermTableNames to specify the table names -phaseNames groupNameRef_array required List of fluid phases -threePhaseInterpolator geos_constitutive_ThreePhaseInterpolator BAKER | Type of Three phase interpolator.Valid options - | * BAKER - | * STONEII -wettingIntermediateRelPermTableNames groupNameRef_array {} | List of relative permeability tables for the pair (wetting phase, intermediate phase) - | The expected format is "{ wettingPhaseRelPermTableName, intermediatePhaseRelPermTableName }", in that order - | Note that this input is only used for three-phase flow. - | If you want to do a two-phase simulation, please use instead wettingNonWettingRelPermTableNames to specify the table names -wettingNonWettingRelPermTableNames groupNameRef_array {} | List of relative permeability tables for the pair (wetting phase, non-wetting phase) - | The expected format is "{ wettingPhaseRelPermTableName, nonWettingPhaseRelPermTableName }", in that order - | Note that this input is only used for two-phase flow. - | If you want to do a three-phase simulation, please use instead wettingIntermediateRelPermTableNames and nonWettingIntermediateRelPermTableNames to specify the table names -======================================= ======================================== ======== ================================================================================================================================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/TableRelativePermeabilityHysteresis.rst b/src/coreComponents/schema/docs/TableRelativePermeabilityHysteresis.rst deleted file mode 100644 index 6d8d9b07bb7..00000000000 --- a/src/coreComponents/schema/docs/TableRelativePermeabilityHysteresis.rst +++ /dev/null @@ -1,32 +0,0 @@ - - -=============================================== ======================================== ======== =========================================================================================================================================================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -=============================================== ======================================== ======== =========================================================================================================================================================================================================================================================================================================================================================================================================================================================== -drainageNonWettingIntermediateRelPermTableNames groupNameRef_array {} | List of drainage relative permeability tables for the pair (non-wetting phase, intermediate phase) - | The expected format is "{ nonWettingPhaseRelPermTableName, intermediatePhaseRelPermTableName }", in that order - | Note that this input is only used for three-phase flow. - | If you want to do a two-phase simulation, please use instead drainageWettingNonWettingRelPermTableNames to specify the table names -drainageWettingIntermediateRelPermTableNames groupNameRef_array {} | List of drainage relative permeability tables for the pair (wetting phase, intermediate phase) - | The expected format is "{ wettingPhaseRelPermTableName, intermediatePhaseRelPermTableName }", in that order - | Note that this input is only used for three-phase flow. - | If you want to do a two-phase simulation, please use instead drainageWettingNonWettingRelPermTableNames to specify the table names -drainageWettingNonWettingRelPermTableNames groupNameRef_array {} | List of drainage relative permeability tables for the pair (wetting phase, non-wetting phase) - | The expected format is "{ wettingPhaseRelPermTableName, nonWettingPhaseRelPermTableName }", in that order - | Note that this input is only used for two-phase flow. - | If you want to do a three-phase simulation, please use instead drainageWettingIntermediateRelPermTableNames and drainageNonWettingIntermediateRelPermTableNames to specify the table names -imbibitionNonWettingRelPermTableName groupNameRef | Imbibition relative permeability table name for the non-wetting phase. - | To neglect hysteresis on this phase, just use the same table name for the drainage and imbibition curves -imbibitionWettingRelPermTableName groupNameRef | Imbibition relative permeability table name for the wetting phase. - | To neglect hysteresis on this phase, just use the same table name for the drainage and imbibition curves -jerauldParameterA real64 0.1 First parameter (modification parameter) introduced by Jerauld in the Land trapping model (see RTD documentation). -jerauldParameterB real64 0 Second parameter introduced by Jerauld in the Land trapping model (see RTD documentation). -killoughCurvatureParameter real64 1 Curvature parameter introduced by Killough for wetting-phase hysteresis (see RTD documentation). -name groupName required A name is required for any non-unique nodes -phaseNames groupNameRef_array required List of fluid phases -threePhaseInterpolator geos_constitutive_ThreePhaseInterpolator BAKER | Type of Three phase interpolator.Valid options - | * BAKER - | * STONEII -=============================================== ======================================== ======== =========================================================================================================================================================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/TableRelativePermeabilityHysteresis_other.rst b/src/coreComponents/schema/docs/TableRelativePermeabilityHysteresis_other.rst deleted file mode 100644 index 1952771c2e9..00000000000 --- a/src/coreComponents/schema/docs/TableRelativePermeabilityHysteresis_other.rst +++ /dev/null @@ -1,27 +0,0 @@ - - -================================ ======================================================================================================= =============================================================================== -Name Type Description -================================ ======================================================================================================= =============================================================================== -dPhaseRelPerm_dPhaseVolFraction real64_array4d Derivative of phase relative permeability with respect to phase volume fraction -drainagePhaseMaxVolumeFraction real64_array (no description available) -drainagePhaseMinVolumeFraction real64_array (no description available) -drainagePhaseRelPermEndPoint real64_array (no description available) -drainageRelPermWrappers LvArray_Array< geos_TableFunction_KernelWrapper, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer > (no description available) -imbibitionPhaseMaxVolumeFraction real64_array (no description available) -imbibitionPhaseMinVolumeFraction real64_array (no description available) -imbibitionPhaseRelPermEndPoint real64_array (no description available) -imbibitionRelPermWrappers LvArray_Array< geos_TableFunction_KernelWrapper, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer > (no description available) -landParameter real64_array (no description available) -phaseHasHysteresis integer_array (no description available) -phaseMaxHistoricalVolFraction real64_array2d Phase max historical phase volume fraction -phaseMinHistoricalVolFraction real64_array2d Phase min historical phase volume fraction -phaseOrder integer_array (no description available) -phaseRelPerm real64_array3d Phase relative permeability -phaseRelPerm_n real64_array3d Phase relative permeability at previous time -phaseTrappedVolFraction real64_array3d Phase trapped volume fraction -phaseTypes integer_array (no description available) -waterOilMaxRelPerm real64 (no description available) -================================ ======================================================================================================= =============================================================================== - - diff --git a/src/coreComponents/schema/docs/TableRelativePermeability_other.rst b/src/coreComponents/schema/docs/TableRelativePermeability_other.rst deleted file mode 100644 index d71522f8a7a..00000000000 --- a/src/coreComponents/schema/docs/TableRelativePermeability_other.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -=============================== ======================================================================================================= =============================================================================== -Name Type Description -=============================== ======================================================================================================= =============================================================================== -dPhaseRelPerm_dPhaseVolFraction real64_array4d Derivative of phase relative permeability with respect to phase volume fraction -phaseMinVolumeFraction real64_array (no description available) -phaseOrder integer_array (no description available) -phaseRelPerm real64_array3d Phase relative permeability -phaseRelPerm_n real64_array3d Phase relative permeability at previous time -phaseTrappedVolFraction real64_array3d Phase trapped volume fraction -phaseTypes integer_array (no description available) -relPermWrappers LvArray_Array< geos_TableFunction_KernelWrapper, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer > (no description available) -waterOilMaxRelPerm real64 (no description available) -=============================== ======================================================================================================= =============================================================================== - - diff --git a/src/coreComponents/schema/docs/Tasks.rst b/src/coreComponents/schema/docs/Tasks.rst deleted file mode 100644 index 95301497c5c..00000000000 --- a/src/coreComponents/schema/docs/Tasks.rst +++ /dev/null @@ -1,21 +0,0 @@ - - -=========================================================== ==== ======= ====================================================================== -Name Type Default Description -=========================================================== ==== ======= ====================================================================== -CompositionalMultiphaseReservoirPoromechanicsInitialization node :ref:`XML_CompositionalMultiphaseReservoirPoromechanicsInitialization` -CompositionalMultiphaseStatistics node :ref:`XML_CompositionalMultiphaseStatistics` -MultiphasePoromechanicsInitialization node :ref:`XML_MultiphasePoromechanicsInitialization` -PVTDriver node :ref:`XML_PVTDriver` -PackCollection node :ref:`XML_PackCollection` -ReactiveFluidDriver node :ref:`XML_ReactiveFluidDriver` -RelpermDriver node :ref:`XML_RelpermDriver` -SinglePhasePoromechanicsInitialization node :ref:`XML_SinglePhasePoromechanicsInitialization` -SinglePhaseReservoirPoromechanicsInitialization node :ref:`XML_SinglePhaseReservoirPoromechanicsInitialization` -SinglePhaseStatistics node :ref:`XML_SinglePhaseStatistics` -SolidMechanicsStateReset node :ref:`XML_SolidMechanicsStateReset` -SolidMechanicsStatistics node :ref:`XML_SolidMechanicsStatistics` -TriaxialDriver node :ref:`XML_TriaxialDriver` -=========================================================== ==== ======= ====================================================================== - - diff --git a/src/coreComponents/schema/docs/Tasks_other.rst b/src/coreComponents/schema/docs/Tasks_other.rst deleted file mode 100644 index dca37a26a99..00000000000 --- a/src/coreComponents/schema/docs/Tasks_other.rst +++ /dev/null @@ -1,21 +0,0 @@ - - -=========================================================== ==== ================================================================================ -Name Type Description -=========================================================== ==== ================================================================================ -CompositionalMultiphaseReservoirPoromechanicsInitialization node :ref:`DATASTRUCTURE_CompositionalMultiphaseReservoirPoromechanicsInitialization` -CompositionalMultiphaseStatistics node :ref:`DATASTRUCTURE_CompositionalMultiphaseStatistics` -MultiphasePoromechanicsInitialization node :ref:`DATASTRUCTURE_MultiphasePoromechanicsInitialization` -PVTDriver node :ref:`DATASTRUCTURE_PVTDriver` -PackCollection node :ref:`DATASTRUCTURE_PackCollection` -ReactiveFluidDriver node :ref:`DATASTRUCTURE_ReactiveFluidDriver` -RelpermDriver node :ref:`DATASTRUCTURE_RelpermDriver` -SinglePhasePoromechanicsInitialization node :ref:`DATASTRUCTURE_SinglePhasePoromechanicsInitialization` -SinglePhaseReservoirPoromechanicsInitialization node :ref:`DATASTRUCTURE_SinglePhaseReservoirPoromechanicsInitialization` -SinglePhaseStatistics node :ref:`DATASTRUCTURE_SinglePhaseStatistics` -SolidMechanicsStateReset node :ref:`DATASTRUCTURE_SolidMechanicsStateReset` -SolidMechanicsStatistics node :ref:`DATASTRUCTURE_SolidMechanicsStatistics` -TriaxialDriver node :ref:`DATASTRUCTURE_TriaxialDriver` -=========================================================== ==== ================================================================================ - - diff --git a/src/coreComponents/schema/docs/ThermalCompressibleSinglePhaseFluid.rst b/src/coreComponents/schema/docs/ThermalCompressibleSinglePhaseFluid.rst deleted file mode 100644 index 469050d50fa..00000000000 --- a/src/coreComponents/schema/docs/ThermalCompressibleSinglePhaseFluid.rst +++ /dev/null @@ -1,32 +0,0 @@ - - -======================= =========================================== ======== =================================================================================== -Name Type Default Description -======================= =========================================== ======== =================================================================================== -compressibility real64 0 Fluid compressibility -defaultDensity real64 required Default value for density. -defaultViscosity real64 required Default value for viscosity. -densityModelType geos_constitutive_ExponentApproximationType linear | Type of density model. Valid options: - | * exponential - | * linear - | * quadratic -internalEnergyModelType geos_constitutive_ExponentApproximationType linear | Type of internal energy model. Valid options: - | * exponential - | * linear - | * quadratic -name groupName required A name is required for any non-unique nodes -referenceDensity real64 1000 Reference fluid density -referenceInternalEnergy real64 0.001 Reference fluid internal energy -referencePressure real64 0 Reference pressure -referenceTemperature real64 0 Reference temperature -referenceViscosity real64 0.001 Reference fluid viscosity -specificHeatCapacity real64 0 Fluid heat capacity. Unit: J/kg/K -thermalExpansionCoeff real64 0 Fluid thermal expansion coefficient. Unit: 1/K -viscosibility real64 0 Fluid viscosity exponential coefficient -viscosityModelType geos_constitutive_ExponentApproximationType linear | Type of viscosity model. Valid options: - | * exponential - | * linear - | * quadratic -======================= =========================================== ======== =================================================================================== - - diff --git a/src/coreComponents/schema/docs/ThermalCompressibleSinglePhaseFluid_other.rst b/src/coreComponents/schema/docs/ThermalCompressibleSinglePhaseFluid_other.rst deleted file mode 100644 index 53255e66ebc..00000000000 --- a/src/coreComponents/schema/docs/ThermalCompressibleSinglePhaseFluid_other.rst +++ /dev/null @@ -1,22 +0,0 @@ - - -============================ ============== ========================================================= -Name Type Description -============================ ============== ========================================================= -dDensity_dPressure real64_array2d Derivative of density with respect to pressure -dDensity_dTemperature real64_array2d Derivative of density with respect to temperature -dEnthalpy_dPressure real64_array2d Derivative of enthalpy with respect to pressure -dEnthalpy_dTemperature real64_array2d Derivative of enthalpy with respect to temperature -dInternalEnergy_dPressure real64_array2d Derivative of internal energy with respect to pressure -dInternalEnergy_dTemperature real64_array2d Derivative of internal energy with respect to temperature -dViscosity_dPressure real64_array2d Derivative of viscosity with respect to pressure -dViscosity_dTemperature real64_array2d Derivative of viscosity with respect to temperature -density real64_array2d Density -density_n real64_array2d Density at the previous converged time step -enthalpy real64_array2d Enthalpy -internalEnergy real64_array2d Internal energy -internalEnergy_n real64_array2d Fluid internal energy at the previous converged step -viscosity real64_array2d Viscosity -============================ ============== ========================================================= - - diff --git a/src/coreComponents/schema/docs/ThickPlane.rst b/src/coreComponents/schema/docs/ThickPlane.rst deleted file mode 100644 index d48c386ac4d..00000000000 --- a/src/coreComponents/schema/docs/ThickPlane.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -========= ========= ======== ===================================================================== -Name Type Default Description -========= ========= ======== ===================================================================== -name groupName required A name is required for any non-unique nodes -normal R1Tensor required Normal (n_x,n_y,n_z) to the plane (will be normalized automatically) -origin R1Tensor required Origin point (x,y,z) of the plane (basically, any point on the plane) -thickness real64 required The total thickness of the plane (with half to each side) -========= ========= ======== ===================================================================== - - diff --git a/src/coreComponents/schema/docs/ThickPlane_other.rst b/src/coreComponents/schema/docs/ThickPlane_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/ThickPlane_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/TimeHistory.rst b/src/coreComponents/schema/docs/TimeHistory.rst deleted file mode 100644 index 8a4f5fe402d..00000000000 --- a/src/coreComponents/schema/docs/TimeHistory.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -=============== ================== =========== =============================================================================== -Name Type Default Description -=============== ================== =========== =============================================================================== -childDirectory string Child directory path -filename string TimeHistory The filename to which to write time history output. -format string hdf The output file format for time history output. -name groupName required A name is required for any non-unique nodes -parallelThreads integer 1 Number of plot files. -sources groupNameRef_array required A list of collectors from which to collect and output time history information. -=============== ================== =========== =============================================================================== - - diff --git a/src/coreComponents/schema/docs/TimeHistory_other.rst b/src/coreComponents/schema/docs/TimeHistory_other.rst deleted file mode 100644 index dff6ceb0fc6..00000000000 --- a/src/coreComponents/schema/docs/TimeHistory_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -======= ======= ====================================================================================================================== -Name Type Description -======= ======= ====================================================================================================================== -restart integer The current history record to be written, on restart from an earlier time allows use to remove invalid future history. -======= ======= ====================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/Traction.rst b/src/coreComponents/schema/docs/Traction.rst deleted file mode 100644 index 58522e086bc..00000000000 --- a/src/coreComponents/schema/docs/Traction.rst +++ /dev/null @@ -1,24 +0,0 @@ - - -====================== =========================================== ============= =============================================================================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -====================== =========================================== ============= =============================================================================================================================================================================================================================================================================================================================================================================== -bcApplicationTableName groupNameRef Name of table that specifies the on/off application of the boundary condition. -beginTime real64 -1e+99 Time at which the boundary condition will start being applied. -direction R1Tensor {0,0,0} Direction to apply boundary condition to. -endTime real64 1e+99 Time at which the boundary condition will stop being applied. -functionName groupNameRef Name of function that specifies variation of the boundary condition. -initialCondition integer 0 Boundary condition is applied as an initial condition. -inputStress R2SymTensor {0,0,0,0,0,0} Input stress for tractionType = stress -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -objectPath groupNameRef Path to the target field -scale real64 0 Scale factor for value of the boundary condition. -setNames groupNameRef_array required Name of sets that boundary condition is applied to. -tractionType geos_TractionBoundaryCondition_TractionType vector | Type of traction boundary condition. Options are: - | vector - traction is applied to the faces as specified from the scale and direction, - | normal - traction is applied to the faces as a pressure specified from the product of scale and the outward face normal, - | stress - traction is applied to the faces as specified by the inner product of input stress and face normal. -====================== =========================================== ============= =============================================================================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/Traction_other.rst b/src/coreComponents/schema/docs/Traction_other.rst deleted file mode 100644 index 15200f2e3a7..00000000000 --- a/src/coreComponents/schema/docs/Traction_other.rst +++ /dev/null @@ -1,10 +0,0 @@ - - -========= ============ ============================================================== -Name Type Description -========= ============ ============================================================== -component integer Component of field (if tensor) to apply boundary condition to. -fieldName groupNameRef Name of field that boundary condition is applied to. -========= ============ ============================================================== - - diff --git a/src/coreComponents/schema/docs/TriaxialDriver.rst b/src/coreComponents/schema/docs/TriaxialDriver.rst deleted file mode 100644 index d8144999bee..00000000000 --- a/src/coreComponents/schema/docs/TriaxialDriver.rst +++ /dev/null @@ -1,18 +0,0 @@ - - -============= ======================== ======== ===================================================================== -Name Type Default Description -============= ======================== ======== ===================================================================== -axialControl groupNameRef required Function controlling axial stress or strain (depending on test mode) -baseline path none Baseline file -initialStress real64 required Initial stress (scalar used to set an isotropic stress state) -logLevel integer 0 Log level -material groupNameRef required Solid material to test -mode geos_TriaxialDriver_Mode required Test mode [stressControl, strainControl, mixedControl] -name groupName required A name is required for any non-unique nodes -output string none Output file -radialControl groupNameRef required Function controlling radial stress or strain (depending on test mode) -steps integer required Number of load steps to take -============= ======================== ======== ===================================================================== - - diff --git a/src/coreComponents/schema/docs/TriaxialDriver_other.rst b/src/coreComponents/schema/docs/TriaxialDriver_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/TriaxialDriver_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/TwoPointFluxApproximation.rst b/src/coreComponents/schema/docs/TwoPointFluxApproximation.rst deleted file mode 100644 index 57ec23d2f8a..00000000000 --- a/src/coreComponents/schema/docs/TwoPointFluxApproximation.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=================== ==================== ======== ======================================================== -Name Type Default Description -=================== ==================== ======== ======================================================== -areaRelTol real64 1e-08 Relative tolerance for area calculations. -meanPermCoefficient real64 1 (no description available) -name groupName required A name is required for any non-unique nodes -upwindingScheme geos_UpwindingScheme PPU | Type of upwinding scheme. Valid options: - | * PPU - | * C1PPU -usePEDFM integer 0 (no description available) -=================== ==================== ======== ======================================================== - - diff --git a/src/coreComponents/schema/docs/TwoPointFluxApproximation_other.rst b/src/coreComponents/schema/docs/TwoPointFluxApproximation_other.rst deleted file mode 100644 index 9194c2431f9..00000000000 --- a/src/coreComponents/schema/docs/TwoPointFluxApproximation_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -======================== ========================================================================================================================================== ======================================== -Name Type Description -======================== ========================================================================================================================================== ======================================== -cellStencil geos_CellElementStencilTPFA (no description available) -coefficientName groupNameRef Name of coefficient field -edfmStencil geos_EmbeddedSurfaceToCellStencil (no description available) -faceElementToCellStencil geos_FaceElementToCellStencil (no description available) -fieldName groupNameRef_array Name of primary solution field -fractureStencil geos_SurfaceElementStencil (no description available) -targetRegions geos_mapBase< string, LvArray_Array< string, 1, camp_int_seq< long, 0l >, int, LvArray_ChaiBuffer >, std_integral_constant< bool, true > > List of regions to build the stencil for -======================== ========================================================================================================================================== ======================================== - - diff --git a/src/coreComponents/schema/docs/VTK.rst b/src/coreComponents/schema/docs/VTK.rst deleted file mode 100644 index 3a376546ee3..00000000000 --- a/src/coreComponents/schema/docs/VTK.rst +++ /dev/null @@ -1,21 +0,0 @@ - - -=========================== ======================= ======== ======================================================================================================================================================================================== -Name Type Default Description -=========================== ======================= ======== ======================================================================================================================================================================================== -childDirectory string Child directory path -fieldNames groupNameRef_array {} Names of the fields to output. If this attribute is specified, GEOSX outputs all the fields specified by the user, regardless of their `plotLevel` -format geos_vtk_VTKOutputMode binary Output data format. Valid options: ``binary``, ``ascii`` -levelNames string_array {} Names of mesh levels to output. -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -onlyPlotSpecifiedFieldNames integer 0 If this flag is equal to 1, then we only plot the fields listed in `fieldNames`. Otherwise, we plot all the fields with the required `plotLevel`, plus the fields listed in `fieldNames` -outputRegionType geos_vtk_VTKRegionTypes all Output region types. Valid options: ``cell``, ``well``, ``surface``, ``particle``, ``all`` -parallelThreads integer 1 Number of plot files. -plotFileRoot string VTK Name of the root file for this output. -plotLevel integer 1 Level detail plot. Only fields with lower of equal plot level will be output. -writeFEMFaces integer 0 (no description available) -writeGhostCells integer 0 Should the vtk files contain the ghost cells or not. -=========================== ======================= ======== ======================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/VTKMesh.rst b/src/coreComponents/schema/docs/VTKMesh.rst deleted file mode 100644 index 688b0d98319..00000000000 --- a/src/coreComponents/schema/docs/VTKMesh.rst +++ /dev/null @@ -1,26 +0,0 @@ - - -====================== ======================== ========= ============================================================================================================================================================================================================================================================================================================================================================================================================================================================================ -Name Type Default Description -====================== ======================== ========= ============================================================================================================================================================================================================================================================================================================================================================================================================================================================================ -faceBlocks groupNameRef_array {} For multi-block files, names of the face mesh block. -fieldNamesInGEOSX groupNameRef_array {} Names of the volumic fields in GEOSX to import into -fieldsToImport groupNameRef_array {} Volumic fields to be imported from the external mesh file -file path required Path to the mesh file -logLevel integer 0 Log level -mainBlockName groupNameRef main For multi-block files, name of the 3d mesh block. -name groupName required A name is required for any non-unique nodes -nodesetNames groupNameRef_array {} Names of the VTK nodesets to import -partitionMethod geos_vtk_PartitionMethod parmetis Method (library) used to partition the mesh -partitionRefinement integer 1 Number of partitioning refinement iterations (defaults to 1, recommended value).A value of 0 disables graph partitioning and keeps simple kd-tree partitions (not recommended). Values higher than 1 may lead to slightly improved partitioning, but yield diminishing returns. -regionAttribute groupNameRef attribute Name of the VTK cell attribute to use as region marker -scale R1Tensor {1,1,1} Scale the coordinates of the vertices by given scale factors (after translation) -surfacicFieldsInGEOSX groupNameRef_array {} Names of the surfacic fields in GEOSX to import into -surfacicFieldsToImport groupNameRef_array {} Surfacic fields to be imported from the external mesh file -translate R1Tensor {0,0,0} Translate the coordinates of the vertices by a given vector (prior to scaling) -useGlobalIds integer 0 Controls the use of global IDs in the input file for cells and points. If set to 0 (default value), the GlobalId arrays in the input mesh are used if available, and generated otherwise. If set to a negative value, the GlobalId arrays in the input mesh are not used, and generated global Ids are automatically generated. If set to a positive value, the GlobalId arrays in the input mesh are used and required, and the simulation aborts if they are not available -InternalWell node :ref:`XML_InternalWell` -VTKWell node :ref:`XML_VTKWell` -====================== ======================== ========= ============================================================================================================================================================================================================================================================================================================================================================================================================================================================================ - - diff --git a/src/coreComponents/schema/docs/VTKMesh_other.rst b/src/coreComponents/schema/docs/VTKMesh_other.rst deleted file mode 100644 index 8ca4f02bc36..00000000000 --- a/src/coreComponents/schema/docs/VTKMesh_other.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -============ ==== ================================= -Name Type Description -============ ==== ================================= -InternalWell node :ref:`DATASTRUCTURE_InternalWell` -VTKWell node :ref:`DATASTRUCTURE_VTKWell` -meshLevels node :ref:`DATASTRUCTURE_meshLevels` -============ ==== ================================= - - diff --git a/src/coreComponents/schema/docs/VTKWell.rst b/src/coreComponents/schema/docs/VTKWell.rst deleted file mode 100644 index 0df45b1798d..00000000000 --- a/src/coreComponents/schema/docs/VTKWell.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -===================== ========= ======== ==================================================================================================== -Name Type Default Description -===================== ========= ======== ==================================================================================================== -file path required Path to the well file -minElementLength real64 0.001 Minimum length of a well element, computed as (segment length / number of elements per segment ) [m] -minSegmentLength real64 0.01 Minimum length of a well segment [m] -name groupName required A name is required for any non-unique nodes -numElementsPerSegment integer required Number of well elements per polyline segment -radius real64 required Radius of the well [m] -wellControlsName string required Name of the set of constraints associated with this well -wellRegionName string required Name of the well element region -Perforation node :ref:`XML_Perforation` -===================== ========= ======== ==================================================================================================== - - diff --git a/src/coreComponents/schema/docs/VTKWell_other.rst b/src/coreComponents/schema/docs/VTKWell_other.rst deleted file mode 100644 index 638cc779598..00000000000 --- a/src/coreComponents/schema/docs/VTKWell_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -=========== ==== ================================ -Name Type Description -=========== ==== ================================ -Perforation node :ref:`DATASTRUCTURE_Perforation` -=========== ==== ================================ - - diff --git a/src/coreComponents/schema/docs/VTK_other.rst b/src/coreComponents/schema/docs/VTK_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/VTK_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/VanGenuchtenBakerRelativePermeability.rst b/src/coreComponents/schema/docs/VanGenuchtenBakerRelativePermeability.rst deleted file mode 100644 index 00d74f74608..00000000000 --- a/src/coreComponents/schema/docs/VanGenuchtenBakerRelativePermeability.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -========================== ================== ======== ================================================================================================================================================================== -Name Type Default Description -========================== ================== ======== ================================================================================================================================================================== -gasOilRelPermExponentInv real64_array {0.5} | Rel perm power law exponent inverse for the pair (gas phase, oil phase) at residual water saturation - | The expected format is "{ gasExp, oilExp }", in that order -gasOilRelPermMaxValue real64_array {0} | Maximum rel perm value for the pair (gas phase, oil phase) at residual water saturation - | The expected format is "{ gasMax, oilMax }", in that order -name groupName required A name is required for any non-unique nodes -phaseMinVolumeFraction real64_array {0} Minimum volume fraction value for each phase -phaseNames groupNameRef_array required List of fluid phases -waterOilRelPermExponentInv real64_array {0.5} | Rel perm power law exponent inverse for the pair (water phase, oil phase) at residual gas saturation - | The expected format is "{ waterExp, oilExp }", in that order -waterOilRelPermMaxValue real64_array {0} | Maximum rel perm value for the pair (water phase, oil phase) at residual gas saturation - | The expected format is "{ waterMax, oilMax }", in that order -========================== ================== ======== ================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/VanGenuchtenBakerRelativePermeability_other.rst b/src/coreComponents/schema/docs/VanGenuchtenBakerRelativePermeability_other.rst deleted file mode 100644 index e6dd24aeb13..00000000000 --- a/src/coreComponents/schema/docs/VanGenuchtenBakerRelativePermeability_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=============================== ============== ======================================================================================================================= -Name Type Description -=============================== ============== ======================================================================================================================= -dPhaseRelPerm_dPhaseVolFraction real64_array4d Derivative of phase relative permeability with respect to phase volume fraction -phaseOrder integer_array (no description available) -phaseRelPerm real64_array3d Phase relative permeability -phaseRelPerm_n real64_array3d Phase relative permeability at previous time -phaseTrappedVolFraction real64_array3d Phase trapped volume fraction -phaseTypes integer_array (no description available) -volFracScale real64 Factor used to scale the phase capillary pressure, defined as: one minus the sum of the phase minimum volume fractions. -=============================== ============== ======================================================================================================================= - - diff --git a/src/coreComponents/schema/docs/VanGenuchtenCapillaryPressure.rst b/src/coreComponents/schema/docs/VanGenuchtenCapillaryPressure.rst deleted file mode 100644 index d1ba6cf0266..00000000000 --- a/src/coreComponents/schema/docs/VanGenuchtenCapillaryPressure.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -=========================== ================== ======== ================================================================================================================================================== -Name Type Default Description -=========================== ================== ======== ================================================================================================================================================== -capPressureEpsilon real64 1e-06 Saturation at which the extremum capillary pressure is attained; used to avoid infinite capillary pressure values for saturations close to 0 and 1 -name groupName required A name is required for any non-unique nodes -phaseCapPressureExponentInv real64_array {0.5} Inverse of capillary power law exponent for each phase -phaseCapPressureMultiplier real64_array {1} Entry pressure value for each phase -phaseMinVolumeFraction real64_array {0} Minimum volume fraction value for each phase -phaseNames groupNameRef_array required List of fluid phases -=========================== ================== ======== ================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/VanGenuchtenCapillaryPressure_other.rst b/src/coreComponents/schema/docs/VanGenuchtenCapillaryPressure_other.rst deleted file mode 100644 index 336528e2f6f..00000000000 --- a/src/coreComponents/schema/docs/VanGenuchtenCapillaryPressure_other.rst +++ /dev/null @@ -1,13 +0,0 @@ - - -=================================== ============== ======================================================================================================================= -Name Type Description -=================================== ============== ======================================================================================================================= -dPhaseCapPressure_dPhaseVolFraction real64_array4d Derivative of phase capillary pressure with respect to phase volume fraction -phaseCapPressure real64_array3d Phase capillary pressure -phaseOrder integer_array (no description available) -phaseTypes integer_array (no description available) -volFracScale real64 Factor used to scale the phase capillary pressure, defined as: one minus the sum of the phase minimum volume fractions. -=================================== ============== ======================================================================================================================= - - diff --git a/src/coreComponents/schema/docs/VanGenuchtenStone2RelativePermeability.rst b/src/coreComponents/schema/docs/VanGenuchtenStone2RelativePermeability.rst deleted file mode 100644 index 00d74f74608..00000000000 --- a/src/coreComponents/schema/docs/VanGenuchtenStone2RelativePermeability.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -========================== ================== ======== ================================================================================================================================================================== -Name Type Default Description -========================== ================== ======== ================================================================================================================================================================== -gasOilRelPermExponentInv real64_array {0.5} | Rel perm power law exponent inverse for the pair (gas phase, oil phase) at residual water saturation - | The expected format is "{ gasExp, oilExp }", in that order -gasOilRelPermMaxValue real64_array {0} | Maximum rel perm value for the pair (gas phase, oil phase) at residual water saturation - | The expected format is "{ gasMax, oilMax }", in that order -name groupName required A name is required for any non-unique nodes -phaseMinVolumeFraction real64_array {0} Minimum volume fraction value for each phase -phaseNames groupNameRef_array required List of fluid phases -waterOilRelPermExponentInv real64_array {0.5} | Rel perm power law exponent inverse for the pair (water phase, oil phase) at residual gas saturation - | The expected format is "{ waterExp, oilExp }", in that order -waterOilRelPermMaxValue real64_array {0} | Maximum rel perm value for the pair (water phase, oil phase) at residual gas saturation - | The expected format is "{ waterMax, oilMax }", in that order -========================== ================== ======== ================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/VanGenuchtenStone2RelativePermeability_other.rst b/src/coreComponents/schema/docs/VanGenuchtenStone2RelativePermeability_other.rst deleted file mode 100644 index e6dd24aeb13..00000000000 --- a/src/coreComponents/schema/docs/VanGenuchtenStone2RelativePermeability_other.rst +++ /dev/null @@ -1,15 +0,0 @@ - - -=============================== ============== ======================================================================================================================= -Name Type Description -=============================== ============== ======================================================================================================================= -dPhaseRelPerm_dPhaseVolFraction real64_array4d Derivative of phase relative permeability with respect to phase volume fraction -phaseOrder integer_array (no description available) -phaseRelPerm real64_array3d Phase relative permeability -phaseRelPerm_n real64_array3d Phase relative permeability at previous time -phaseTrappedVolFraction real64_array3d Phase trapped volume fraction -phaseTypes integer_array (no description available) -volFracScale real64 Factor used to scale the phase capillary pressure, defined as: one minus the sum of the phase minimum volume fractions. -=============================== ============== ======================================================================================================================= - - diff --git a/src/coreComponents/schema/docs/ViscoDruckerPrager.rst b/src/coreComponents/schema/docs/ViscoDruckerPrager.rst deleted file mode 100644 index 0fcfe196f5d..00000000000 --- a/src/coreComponents/schema/docs/ViscoDruckerPrager.rst +++ /dev/null @@ -1,20 +0,0 @@ - - -======================= ========= ======== ==================================================================== -Name Type Default Description -======================= ========= ======== ==================================================================== -defaultBulkModulus real64 -1 Default Bulk Modulus Parameter -defaultCohesion real64 0 Initial cohesion -defaultDensity real64 required Default Material Density -defaultDilationAngle real64 30 Dilation angle (degrees) -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultFrictionAngle real64 30 Friction angle (degrees) -defaultHardeningRate real64 0 Cohesion hardening/softening rate -defaultPoissonRatio real64 -1 Default Poisson's Ratio -defaultShearModulus real64 -1 Default Shear Modulus Parameter -defaultYoungModulus real64 -1 Default Young's Modulus -name groupName required A name is required for any non-unique nodes -relaxationTime real64 required Relaxation time -======================= ========= ======== ==================================================================== - - diff --git a/src/coreComponents/schema/docs/ViscoDruckerPrager_other.rst b/src/coreComponents/schema/docs/ViscoDruckerPrager_other.rst deleted file mode 100644 index 3185dd07d81..00000000000 --- a/src/coreComponents/schema/docs/ViscoDruckerPrager_other.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -bulkModulus real64_array Elastic Bulk Modulus Field -cohesion real64_array2d New cohesion state -density real64_array2d Material Density -dilation real64_array Plastic potential slope -friction real64_array Yield surface slope -hardening real64_array Hardening rate -oldCohesion real64_array2d Old cohesion state -oldStress real64_array3d Previous Material Stress -shearModulus real64_array Elastic Shear Modulus Field -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/ViscoExtendedDruckerPrager.rst b/src/coreComponents/schema/docs/ViscoExtendedDruckerPrager.rst deleted file mode 100644 index 6f9cc0dda2b..00000000000 --- a/src/coreComponents/schema/docs/ViscoExtendedDruckerPrager.rst +++ /dev/null @@ -1,21 +0,0 @@ - - -============================ ========= ======== ==================================================================== -Name Type Default Description -============================ ========= ======== ==================================================================== -defaultBulkModulus real64 -1 Default Bulk Modulus Parameter -defaultCohesion real64 0 Initial cohesion -defaultDensity real64 required Default Material Density -defaultDilationRatio real64 1 Dilation ratio [0,1] (ratio = tan dilationAngle / tan frictionAngle) -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultHardening real64 0 Hardening parameter (hardening rate is faster for smaller values) -defaultInitialFrictionAngle real64 30 Initial friction angle (degrees) -defaultPoissonRatio real64 -1 Default Poisson's Ratio -defaultResidualFrictionAngle real64 30 Residual friction angle (degrees) -defaultShearModulus real64 -1 Default Shear Modulus Parameter -defaultYoungModulus real64 -1 Default Young's Modulus -name groupName required A name is required for any non-unique nodes -relaxationTime real64 required Relaxation time -============================ ========= ======== ==================================================================== - - diff --git a/src/coreComponents/schema/docs/ViscoExtendedDruckerPrager_other.rst b/src/coreComponents/schema/docs/ViscoExtendedDruckerPrager_other.rst deleted file mode 100644 index 729d894b362..00000000000 --- a/src/coreComponents/schema/docs/ViscoExtendedDruckerPrager_other.rst +++ /dev/null @@ -1,21 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -bulkModulus real64_array Elastic Bulk Modulus Field -density real64_array2d Material Density -dilationRatio real64_array Plastic potential slope ratio -hardening real64_array Hardening parameter -initialFriction real64_array Initial yield surface slope -oldStateVariable real64_array2d Old equivalent plastic shear strain -oldStress real64_array3d Previous Material Stress -pressureIntercept real64_array Pressure point at cone vertex -residualFriction real64_array Residual yield surface slope -shearModulus real64_array Elastic Shear Modulus Field -stateVariable real64_array2d New equivalent plastic shear strain -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/ViscoModifiedCamClay.rst b/src/coreComponents/schema/docs/ViscoModifiedCamClay.rst deleted file mode 100644 index 2649b896438..00000000000 --- a/src/coreComponents/schema/docs/ViscoModifiedCamClay.rst +++ /dev/null @@ -1,19 +0,0 @@ - - -=============================== ========= ======== ==================================================================== -Name Type Default Description -=============================== ========= ======== ==================================================================== -defaultCslSlope real64 1 Slope of the critical state line -defaultDensity real64 required Default Material Density -defaultDrainedLinearTEC real64 0 Default Linear Thermal Expansion Coefficient of the Solid Rock Frame -defaultPreConsolidationPressure real64 -1.5 Initial preconsolidation pressure -defaultRecompressionIndex real64 0.002 Recompresion Index -defaultRefPressure real64 -1 Reference Pressure -defaultRefStrainVol real64 0 Reference Volumetric Strain -defaultShearModulus real64 -1 Elastic Shear Modulus Parameter -defaultVirginCompressionIndex real64 0.005 Virgin compression index -name groupName required A name is required for any non-unique nodes -relaxationTime real64 required Relaxation time -=============================== ========= ======== ==================================================================== - - diff --git a/src/coreComponents/schema/docs/ViscoModifiedCamClay_other.rst b/src/coreComponents/schema/docs/ViscoModifiedCamClay_other.rst deleted file mode 100644 index 9cbfc0ba5ef..00000000000 --- a/src/coreComponents/schema/docs/ViscoModifiedCamClay_other.rst +++ /dev/null @@ -1,20 +0,0 @@ - - -=========================== ============== ========================================== -Name Type Description -=========================== ============== ========================================== -cslSlope real64_array Slope of the critical state line -density real64_array2d Material Density -oldPreConsolidationPressure real64_array2d Old preconsolidation pressure -oldStress real64_array3d Previous Material Stress -preConsolidationPressure real64_array2d New preconsolidation pressure -recompressionIndex real64_array Recompression Index Field -refPressure real64 Reference Pressure Field -refStrainVol real64 Reference Volumetric Strain -shearModulus real64_array Elastic Shear Modulus -stress real64_array3d Current Material Stress -thermalExpansionCoefficient real64_array Linear Thermal Expansion Coefficient Field -virginCompressionIndex real64_array Virgin compression index -=========================== ============== ========================================== - - diff --git a/src/coreComponents/schema/docs/WellControls.rst b/src/coreComponents/schema/docs/WellControls.rst deleted file mode 100644 index 6560ae29291..00000000000 --- a/src/coreComponents/schema/docs/WellControls.rst +++ /dev/null @@ -1,40 +0,0 @@ - - -========================== ========================= ======== =================================================================================================================================================================================================================================================================================================================================================================================================== -Name Type Default Description -========================== ========================= ======== =================================================================================================================================================================================================================================================================================================================================================================================================== -control geos_WellControls_Control required | Well control. Valid options: - | * BHP - | * phaseVolRate - | * totalVolRate - | * uninitialized -enableCrossflow integer 1 | Flag to enable crossflow. Currently only supported for injectors: - | - If the flag is set to 1, both reservoir-to-well flow and well-to-reservoir flow are allowed at the perforations. - | - If the flag is set to 0, we only allow well-to-reservoir flow at the perforations. -initialPressureCoefficient real64 0.1 | Tuning coefficient for the initial well pressure of rate-controlled wells: - | - Injector pressure at reference depth initialized as: (1+initialPressureCoefficient)*reservoirPressureAtClosestPerforation + density*g*( zRef - zPerf ) - | - Producer pressure at reference depth initialized as: (1-initialPressureCoefficient)*reservoirPressureAtClosestPerforation + density*g*( zRef - zPerf ) -injectionStream real64_array {-1} Global component densities of the injection stream [moles/m^3 or kg/m^3] -injectionTemperature real64 -1 Temperature of the injection stream [K] -logLevel integer 0 Log level -name groupName required A name is required for any non-unique nodes -referenceElevation real64 required Reference elevation where BHP control is enforced [m] -statusTableName groupNameRef | Name of the well status table when the status of the well is a time dependent function. - | If the status function evaluates to a positive value at the current time, the well will be open otherwise the well will be shut. -surfacePressure real64 0 Surface pressure used to compute volumetric rates when surface conditions are used [Pa] -surfaceTemperature real64 0 Surface temperature used to compute volumetric rates when surface conditions are used [K] -targetBHP real64 0 Target bottom-hole pressure [Pa] -targetBHPTableName groupNameRef Name of the BHP table when the rate is a time dependent function -targetPhaseName groupNameRef Name of the target phase -targetPhaseRate real64 0 Target phase volumetric rate (if useSurfaceConditions: [surface m^3/s]; else [reservoir m^3/s]) -targetPhaseRateTableName groupNameRef Name of the phase rate table when the rate is a time dependent function -targetTotalRate real64 0 Target total volumetric rate (if useSurfaceConditions: [surface m^3/s]; else [reservoir m^3/s]) -targetTotalRateTableName groupNameRef Name of the total rate table when the rate is a time dependent function -type geos_WellControls_Type required | Well type. Valid options: - | * producer - | * injector -useSurfaceConditions integer 0 | Flag to specify whether rates are checked at surface or reservoir conditions. - | Equal to 1 for surface conditions, and to 0 for reservoir conditions -========================== ========================= ======== =================================================================================================================================================================================================================================================================================================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/WellControls_other.rst b/src/coreComponents/schema/docs/WellControls_other.rst deleted file mode 100644 index 503c03ed6f5..00000000000 --- a/src/coreComponents/schema/docs/WellControls_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -============== ========================= ==================== -Name Type Description -============== ========================= ==================== -currentControl geos_WellControls_Control Current well control -============== ========================= ==================== - - diff --git a/src/coreComponents/schema/docs/WellElementRegion.rst b/src/coreComponents/schema/docs/WellElementRegion.rst deleted file mode 100644 index d34dc05fe1a..00000000000 --- a/src/coreComponents/schema/docs/WellElementRegion.rst +++ /dev/null @@ -1,11 +0,0 @@ - - -============ ================== ======== =========================================== -Name Type Default Description -============ ================== ======== =========================================== -materialList groupNameRef_array required List of materials present in this region -meshBody groupNameRef Mesh body that contains this region -name groupName required A name is required for any non-unique nodes -============ ================== ======== =========================================== - - diff --git a/src/coreComponents/schema/docs/WellElementRegionUniqueSubRegion_other.rst b/src/coreComponents/schema/docs/WellElementRegionUniqueSubRegion_other.rst deleted file mode 100644 index 3a4675201c0..00000000000 --- a/src/coreComponents/schema/docs/WellElementRegionUniqueSubRegion_other.rst +++ /dev/null @@ -1,29 +0,0 @@ - - -========================== ========================================================================================================== ========================================================= -Name Type Description -========================== ========================================================================================================== ========================================================= -domainBoundaryIndicator integer_array (no description available) -elementCenter real64_array2d (no description available) -elementVolume real64_array (no description available) -ghostRank integer_array (no description available) -globalToLocalMap geos_mapBase< long long, int, std_integral_constant< bool, false > > (no description available) -isExternal integer_array (no description available) -localToGlobalMap globalIndex_array Array that contains a map from localIndex to globalIndex. -nextWellElementIndex integer_array (no description available) -nextWellElementIndexGlobal integer_array (no description available) -nodeList geos_InterObjectRelation< LvArray_Array< int, 2, camp_int_seq< long, 0l, 1l >, int, LvArray_ChaiBuffer > > (no description available) -numEdgesPerElement integer (no description available) -numFacesPerElement integer (no description available) -numNodesPerElement integer (no description available) -radius real64_array (no description available) -topRank integer (no description available) -topWellElementIndex integer (no description available) -wellControlsName groupNameRef (no description available) -ConstitutiveModels node :ref:`DATASTRUCTURE_ConstitutiveModels` -neighborData node :ref:`DATASTRUCTURE_neighborData` -sets node :ref:`DATASTRUCTURE_sets` -wellElementSubRegion node :ref:`DATASTRUCTURE_wellElementSubRegion` -========================== ========================================================================================================== ========================================================= - - diff --git a/src/coreComponents/schema/docs/WellElementRegion_other.rst b/src/coreComponents/schema/docs/WellElementRegion_other.rst deleted file mode 100644 index 7235a663f6d..00000000000 --- a/src/coreComponents/schema/docs/WellElementRegion_other.rst +++ /dev/null @@ -1,18 +0,0 @@ - - -======================= ==================================================================== ========================================================= -Name Type Description -======================= ==================================================================== ========================================================= -domainBoundaryIndicator integer_array (no description available) -ghostRank integer_array (no description available) -globalToLocalMap geos_mapBase< long long, int, std_integral_constant< bool, false > > (no description available) -isExternal integer_array (no description available) -localToGlobalMap globalIndex_array Array that contains a map from localIndex to globalIndex. -wellControlsName groupNameRef (no description available) -wellGeneratorName groupNameRef (no description available) -elementSubRegions node :ref:`DATASTRUCTURE_elementSubRegions` -neighborData node :ref:`DATASTRUCTURE_neighborData` -sets node :ref:`DATASTRUCTURE_sets` -======================= ==================================================================== ========================================================= - - diff --git a/src/coreComponents/schema/docs/WillisRichardsPermeability.rst b/src/coreComponents/schema/docs/WillisRichardsPermeability.rst deleted file mode 100644 index 47299a37b6a..00000000000 --- a/src/coreComponents/schema/docs/WillisRichardsPermeability.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -=================== ========= ======== ========================================================= -Name Type Default Description -=================== ========= ======== ========================================================= -dilationCoefficient real64 required Dilation coefficient (tan of dilation angle). -maxFracAperture real64 required Maximum fracture aperture at zero contact stress. -name groupName required A name is required for any non-unique nodes -refClosureStress real64 required Effective normal stress causes 90% reduction in aperture. -=================== ========= ======== ========================================================= - - diff --git a/src/coreComponents/schema/docs/WillisRichardsPermeability_other.rst b/src/coreComponents/schema/docs/WillisRichardsPermeability_other.rst deleted file mode 100644 index 945812dafaa..00000000000 --- a/src/coreComponents/schema/docs/WillisRichardsPermeability_other.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -=============== ============== =================================================================== -Name Type Description -=============== ============== =================================================================== -dPerm_dDispJump real64_array4d Derivative of rock permeability with respect to displacement jump -dPerm_dPressure real64_array3d Derivative of rock permeability with respect to pressure -dPerm_dTraction real64_array4d Derivative of rock permeability with respect to the traction vector -permeability real64_array3d Rock permeability -=============== ============== =================================================================== - - diff --git a/src/coreComponents/schema/docs/commandLine_other.rst b/src/coreComponents/schema/docs/commandLine_other.rst deleted file mode 100644 index 6800ed46187..00000000000 --- a/src/coreComponents/schema/docs/commandLine_other.rst +++ /dev/null @@ -1,20 +0,0 @@ - - -======================== ======= ====================================================================================================================== -Name Type Description -======================== ======= ====================================================================================================================== -beginFromRestart integer Flag to indicate restart run. -inputFileName string Name of the input xml file. -outputDirectory string Directory in which to put the output files, if not specified defaults to the current directory. -overridePartitionNumbers integer Flag to indicate partition number override -problemName string Used in writing the output files, if not specified defaults to the name of the input file. -restartFileName string Name of the restart file. -schemaFileName string Name of the output schema -suppressPinned integer Whether to disallow using pinned memory allocations for MPI communication buffers. -useNonblockingMPI integer Whether to prefer using non-blocking MPI communication where implemented (results in non-deterministic DOF numbering). -xPartitionsOverride integer Number of partitions in the x-direction -yPartitionsOverride integer Number of partitions in the y-direction -zPartitionsOverride integer Number of partitions in the z-direction -======================== ======= ====================================================================================================================== - - diff --git a/src/coreComponents/schema/docs/crusher.rst b/src/coreComponents/schema/docs/crusher.rst deleted file mode 100644 index 5c143d46c6a..00000000000 --- a/src/coreComponents/schema/docs/crusher.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ======= ============== -Name Type Default Description -==== ==== ======= ============== -Run node unique :ref:`XML_Run` -==== ==== ======= ============== - - diff --git a/src/coreComponents/schema/docs/crusher_other.rst b/src/coreComponents/schema/docs/crusher_other.rst deleted file mode 100644 index fb5ee6f8329..00000000000 --- a/src/coreComponents/schema/docs/crusher_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ======================== -Name Type Description -==== ==== ======================== -Run node :ref:`DATASTRUCTURE_Run` -==== ==== ======================== - - diff --git a/src/coreComponents/schema/docs/domain_other.rst b/src/coreComponents/schema/docs/domain_other.rst deleted file mode 100644 index 18e678dae42..00000000000 --- a/src/coreComponents/schema/docs/domain_other.rst +++ /dev/null @@ -1,12 +0,0 @@ - - -================ =================================================================================== ================================= -Name Type Description -================ =================================================================================== ================================= -Neighbors std_vector< geos_NeighborCommunicator, std_allocator< geos_NeighborCommunicator > > (no description available) -partitionManager geos_PartitionBase (no description available) -Constitutive node :ref:`DATASTRUCTURE_Constitutive` -MeshBodies node :ref:`DATASTRUCTURE_MeshBodies` -================ =================================================================================== ================================= - - diff --git a/src/coreComponents/schema/docs/edgeManager_other.rst b/src/coreComponents/schema/docs/edgeManager_other.rst deleted file mode 100644 index 597da5bf9b8..00000000000 --- a/src/coreComponents/schema/docs/edgeManager_other.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -======================= ========================================================================================================== ========================================================= -Name Type Description -======================= ========================================================================================================== ========================================================= -domainBoundaryIndicator integer_array (no description available) -faceList geos_InterObjectRelation< LvArray_ArrayOfSets< int, int, LvArray_ChaiBuffer > > (no description available) -ghostRank integer_array (no description available) -globalToLocalMap geos_mapBase< long long, int, std_integral_constant< bool, false > > (no description available) -isExternal integer_array (no description available) -localToGlobalMap globalIndex_array Array that contains a map from localIndex to globalIndex. -nodeList geos_InterObjectRelation< LvArray_Array< int, 2, camp_int_seq< long, 0l, 1l >, int, LvArray_ChaiBuffer > > (no description available) -neighborData node :ref:`DATASTRUCTURE_neighborData` -sets node :ref:`DATASTRUCTURE_sets` -======================= ========================================================================================================== ========================================================= - - diff --git a/src/coreComponents/schema/docs/elementRegionsGroup_other.rst b/src/coreComponents/schema/docs/elementRegionsGroup_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/elementRegionsGroup_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/elementSubRegions_other.rst b/src/coreComponents/schema/docs/elementSubRegions_other.rst deleted file mode 100644 index 3be4d2e912b..00000000000 --- a/src/coreComponents/schema/docs/elementSubRegions_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -================================ ==== ===================================================== -Name Type Description -================================ ==== ===================================================== -WellElementRegionUniqueSubRegion node :ref:`DATASTRUCTURE_WellElementRegionUniqueSubRegion` -================================ ==== ===================================================== - - diff --git a/src/coreComponents/schema/docs/embeddedSurfacesEdgeManager_other.rst b/src/coreComponents/schema/docs/embeddedSurfacesEdgeManager_other.rst deleted file mode 100644 index 597da5bf9b8..00000000000 --- a/src/coreComponents/schema/docs/embeddedSurfacesEdgeManager_other.rst +++ /dev/null @@ -1,17 +0,0 @@ - - -======================= ========================================================================================================== ========================================================= -Name Type Description -======================= ========================================================================================================== ========================================================= -domainBoundaryIndicator integer_array (no description available) -faceList geos_InterObjectRelation< LvArray_ArrayOfSets< int, int, LvArray_ChaiBuffer > > (no description available) -ghostRank integer_array (no description available) -globalToLocalMap geos_mapBase< long long, int, std_integral_constant< bool, false > > (no description available) -isExternal integer_array (no description available) -localToGlobalMap globalIndex_array Array that contains a map from localIndex to globalIndex. -nodeList geos_InterObjectRelation< LvArray_Array< int, 2, camp_int_seq< long, 0l, 1l >, int, LvArray_ChaiBuffer > > (no description available) -neighborData node :ref:`DATASTRUCTURE_neighborData` -sets node :ref:`DATASTRUCTURE_sets` -======================= ========================================================================================================== ========================================================= - - diff --git a/src/coreComponents/schema/docs/embeddedSurfacesNodeManager_other.rst b/src/coreComponents/schema/docs/embeddedSurfacesNodeManager_other.rst deleted file mode 100644 index 7c14a19c09a..00000000000 --- a/src/coreComponents/schema/docs/embeddedSurfacesNodeManager_other.rst +++ /dev/null @@ -1,22 +0,0 @@ - - -======================= =============================================================================== ============================================= ================================================================ -Name Type Registered By Description -======================= =============================================================================== ============================================= ================================================================ -domainBoundaryIndicator integer_array (no description available) -edgeList geos_InterObjectRelation< LvArray_ArrayOfSets< int, int, LvArray_ChaiBuffer > > (no description available) -elemList LvArray_ArrayOfArrays< int, int, LvArray_ChaiBuffer > (no description available) -elemRegionList LvArray_ArrayOfArrays< int, int, LvArray_ChaiBuffer > (no description available) -elemSubRegionList LvArray_ArrayOfArrays< int, int, LvArray_ChaiBuffer > (no description available) -ghostRank integer_array (no description available) -globalToLocalMap geos_mapBase< long long, int, std_integral_constant< bool, false > > (no description available) -isExternal integer_array (no description available) -localToGlobalMap globalIndex_array Array that contains a map from localIndex to globalIndex. -parentEdgeGlobalIndex globalIndex_array (no description available) -referencePosition real64_array2d (no description available) -parentEdgeIndex integer_array :ref:`DATASTRUCTURE_EmbeddedSurfaceGenerator` Index of parent edge within the mesh object it is registered on. -neighborData node :ref:`DATASTRUCTURE_neighborData` -sets node :ref:`DATASTRUCTURE_sets` -======================= =============================================================================== ============================================= ================================================================ - - diff --git a/src/coreComponents/schema/docs/faceManager_other.rst b/src/coreComponents/schema/docs/faceManager_other.rst deleted file mode 100644 index f821f295cfd..00000000000 --- a/src/coreComponents/schema/docs/faceManager_other.rst +++ /dev/null @@ -1,25 +0,0 @@ - - -======================= ================================================================================= ================================================================================================ ========================================================= -Name Type Registered By Description -======================= ================================================================================= ================================================================================================ ========================================================= -domainBoundaryIndicator integer_array (no description available) -edgeList geos_InterObjectRelation< LvArray_ArrayOfArrays< int, int, LvArray_ChaiBuffer > > (no description available) -elemList integer_array2d (no description available) -elemRegionList integer_array2d (no description available) -elemSubRegionList integer_array2d (no description available) -faceArea real64_array (no description available) -faceCenter real64_array2d (no description available) -faceNormal real64_array2d (no description available) -ghostRank integer_array (no description available) -globalToLocalMap geos_mapBase< long long, int, std_integral_constant< bool, false > > (no description available) -isExternal integer_array (no description available) -localToGlobalMap globalIndex_array Array that contains a map from localIndex to globalIndex. -nodeList geos_InterObjectRelation< LvArray_ArrayOfArrays< int, int, LvArray_ChaiBuffer > > (no description available) -facePressure_n real64_array :ref:`DATASTRUCTURE_CompositionalMultiphaseHybridFVM`, :ref:`DATASTRUCTURE_SinglePhaseHybridFVM` Face pressure at the previous converged time step -mimGravityCoefficient real64_array :ref:`DATASTRUCTURE_CompositionalMultiphaseHybridFVM` Mimetic gravity coefficient -neighborData node :ref:`DATASTRUCTURE_neighborData` -sets node :ref:`DATASTRUCTURE_sets` -======================= ================================================================================= ================================================================================================ ========================================================= - - diff --git a/src/coreComponents/schema/docs/lassen.rst b/src/coreComponents/schema/docs/lassen.rst deleted file mode 100644 index 5c143d46c6a..00000000000 --- a/src/coreComponents/schema/docs/lassen.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ======= ============== -Name Type Default Description -==== ==== ======= ============== -Run node unique :ref:`XML_Run` -==== ==== ======= ============== - - diff --git a/src/coreComponents/schema/docs/lassen_other.rst b/src/coreComponents/schema/docs/lassen_other.rst deleted file mode 100644 index fb5ee6f8329..00000000000 --- a/src/coreComponents/schema/docs/lassen_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ======================== -Name Type Description -==== ==== ======================== -Run node :ref:`DATASTRUCTURE_Run` -==== ==== ======================== - - diff --git a/src/coreComponents/schema/docs/meshLevels_other.rst b/src/coreComponents/schema/docs/meshLevels_other.rst deleted file mode 100644 index ec43e922076..00000000000 --- a/src/coreComponents/schema/docs/meshLevels_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -====== ==== =========================== -Name Type Description -====== ==== =========================== -Level0 node :ref:`DATASTRUCTURE_Level0` -====== ==== =========================== - - diff --git a/src/coreComponents/schema/docs/neighborData_other.rst b/src/coreComponents/schema/docs/neighborData_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/neighborData_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/nodeManager_other.rst b/src/coreComponents/schema/docs/nodeManager_other.rst deleted file mode 100644 index e4fa1245fee..00000000000 --- a/src/coreComponents/schema/docs/nodeManager_other.rst +++ /dev/null @@ -1,22 +0,0 @@ - - -======================= =============================================================================== ========================================================= -Name Type Description -======================= =============================================================================== ========================================================= -ReferencePosition real64_array2d (no description available) -domainBoundaryIndicator integer_array (no description available) -edgeList geos_InterObjectRelation< LvArray_ArrayOfSets< int, int, LvArray_ChaiBuffer > > (no description available) -elemList LvArray_ArrayOfArrays< int, int, LvArray_ChaiBuffer > (no description available) -elemRegionList LvArray_ArrayOfArrays< int, int, LvArray_ChaiBuffer > (no description available) -elemSubRegionList LvArray_ArrayOfArrays< int, int, LvArray_ChaiBuffer > (no description available) -faceList geos_InterObjectRelation< LvArray_ArrayOfSets< int, int, LvArray_ChaiBuffer > > (no description available) -ghostRank integer_array (no description available) -globalToLocalMap geos_mapBase< long long, int, std_integral_constant< bool, false > > (no description available) -isExternal integer_array (no description available) -localToGlobalMap globalIndex_array Array that contains a map from localIndex to globalIndex. -primaryField real64_array Primary field variable -neighborData node :ref:`DATASTRUCTURE_neighborData` -sets node :ref:`DATASTRUCTURE_sets` -======================= =============================================================================== ========================================================= - - diff --git a/src/coreComponents/schema/docs/particleRegionsGroup_other.rst b/src/coreComponents/schema/docs/particleRegionsGroup_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/particleRegionsGroup_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/particleSubRegions_other.rst b/src/coreComponents/schema/docs/particleSubRegions_other.rst deleted file mode 100644 index adf1c1b8aec..00000000000 --- a/src/coreComponents/schema/docs/particleSubRegions_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ============================ -Name Type Description -==== ==== ============================ - (no documentation available) -==== ==== ============================ - - diff --git a/src/coreComponents/schema/docs/quartz.rst b/src/coreComponents/schema/docs/quartz.rst deleted file mode 100644 index 5c143d46c6a..00000000000 --- a/src/coreComponents/schema/docs/quartz.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ======= ============== -Name Type Default Description -==== ==== ======= ============== -Run node unique :ref:`XML_Run` -==== ==== ======= ============== - - diff --git a/src/coreComponents/schema/docs/quartz_other.rst b/src/coreComponents/schema/docs/quartz_other.rst deleted file mode 100644 index fb5ee6f8329..00000000000 --- a/src/coreComponents/schema/docs/quartz_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -==== ==== ======================== -Name Type Description -==== ==== ======================== -Run node :ref:`DATASTRUCTURE_Run` -==== ==== ======================== - - diff --git a/src/coreComponents/schema/docs/sets_other.rst b/src/coreComponents/schema/docs/sets_other.rst deleted file mode 100644 index 07baf6428bc..00000000000 --- a/src/coreComponents/schema/docs/sets_other.rst +++ /dev/null @@ -1,9 +0,0 @@ - - -=========== =================================================== ========================== -Name Type Description -=========== =================================================== ========================== -externalSet LvArray_SortedArray< int, int, LvArray_ChaiBuffer > (no description available) -=========== =================================================== ========================== - - diff --git a/src/coreComponents/schema/docs/wellElementSubRegion_other.rst b/src/coreComponents/schema/docs/wellElementSubRegion_other.rst deleted file mode 100644 index 13799ea3e78..00000000000 --- a/src/coreComponents/schema/docs/wellElementSubRegion_other.rst +++ /dev/null @@ -1,23 +0,0 @@ - - -========================= ==================================================================== ====================================================================== -Name Type Description -========================= ==================================================================== ====================================================================== -domainBoundaryIndicator integer_array (no description available) -ghostRank integer_array (no description available) -globalToLocalMap geos_mapBase< long long, int, std_integral_constant< bool, false > > (no description available) -isExternal integer_array (no description available) -localToGlobalMap globalIndex_array Array that contains a map from localIndex to globalIndex. -location real64_array2d For each perforation, physical location (x,y,z coordinates) -numPerforationsGlobal globalIndex (no description available) -reservoirElementIndex integer_array For each perforation, element index of the perforated element -reservoirElementRegion integer_array For each perforation, elementRegion index of the perforated element -reservoirElementSubregion integer_array For each perforation, elementSubRegion index of the perforated element -wellElementIndex integer_array For each perforation, index of the well element -wellSkinFactor real64_array For each perforation, well skin factor -wellTransmissibility real64_array For each perforation, well transmissibility -neighborData node :ref:`DATASTRUCTURE_neighborData` -sets node :ref:`DATASTRUCTURE_sets` -========================= ==================================================================== ====================================================================== - - diff --git a/src/coreComponents/schema/schema.xsd b/src/coreComponents/schema/schema.xsd index bb9ab1cbbdf..e130b1e56d4 100644 --- a/src/coreComponents/schema/schema.xsd +++ b/src/coreComponents/schema/schema.xsd @@ -50,12 +50,12 @@ - + - + @@ -185,6 +185,12 @@ + + + + + + @@ -389,10 +395,22 @@ + + + + + + + + + + + + @@ -409,6 +427,10 @@ + + + + @@ -429,10 +451,18 @@ + + + + + + + + @@ -441,6 +471,10 @@ + + + + @@ -459,6 +493,10 @@ + + + + @@ -467,6 +505,10 @@ + + + + @@ -487,10 +529,22 @@ + + + + + + + + + + + + @@ -507,6 +561,10 @@ + + + + @@ -565,12 +623,16 @@ - - + + + + + + - - + + @@ -593,6 +655,10 @@ + + + + @@ -665,6 +731,10 @@ + + + + @@ -701,10 +771,6 @@ - - - - @@ -757,6 +823,10 @@ + + + + @@ -777,6 +847,10 @@ + + + + @@ -785,8 +859,8 @@ - - + + @@ -906,10 +980,10 @@ - + - - + + @@ -1019,6 +1093,25 @@ + + + + + + + + + + + + + + + + + + + @@ -1229,7 +1322,7 @@ This keyword is ignored for single-phase flow simulations--> - + @@ -1237,7 +1330,7 @@ This keyword is ignored for single-phase flow simulations--> - + @@ -1438,6 +1531,10 @@ stress - traction is applied to the faces as specified by the inner product of i + + + + @@ -1448,6 +1545,10 @@ stress - traction is applied to the faces as specified by the inner product of i + + + + @@ -1459,6 +1560,10 @@ stress - traction is applied to the faces as specified by the inner product of i + + + + @@ -1474,6 +1579,7 @@ stress - traction is applied to the faces as specified by the inner product of i + @@ -1483,7 +1589,7 @@ stress - traction is applied to the faces as specified by the inner product of i - + @@ -1545,6 +1651,14 @@ stress - traction is applied to the faces as specified by the inner product of i + + + + + + + + @@ -1574,6 +1688,7 @@ stress - traction is applied to the faces as specified by the inner product of i + @@ -1587,7 +1702,7 @@ stress - traction is applied to the faces as specified by the inner product of i - + @@ -1642,6 +1757,7 @@ stress - traction is applied to the faces as specified by the inner product of i + @@ -1649,14 +1765,16 @@ stress - traction is applied to the faces as specified by the inner product of i + + - - + + - + @@ -1671,8 +1789,8 @@ stress - traction is applied to the faces as specified by the inner product of i - - + + @@ -1730,13 +1848,17 @@ stress - traction is applied to the faces as specified by the inner product of i + + + + - + @@ -1782,6 +1904,8 @@ stress - traction is applied to the faces as specified by the inner product of i + + + + @@ -1858,7 +1984,7 @@ the relative residual norm satisfies: +* Require - Use line search. If smaller residual than starting resdual is not achieved, cut time-step.--> @@ -1868,6 +1994,8 @@ the relative residual norm satisfies: + + @@ -1878,10 +2006,12 @@ the relative residual norm satisfies: - + + + @@ -1897,20 +2027,20 @@ the relative residual norm satisfies: - + - + - + - + - + - + @@ -1956,7 +2086,8 @@ the relative residual norm satisfies: +* C1PPU +* IHU--> @@ -1965,7 +2096,7 @@ the relative residual norm satisfies: - + @@ -1982,6 +2113,11 @@ the relative residual norm satisfies: + + @@ -1996,15 +2132,20 @@ the relative residual norm satisfies: - + - + + + - + - + @@ -2012,6 +2153,11 @@ the relative residual norm satisfies: + + @@ -2020,6 +2166,11 @@ the relative residual norm satisfies: + + @@ -2030,6 +2181,11 @@ the relative residual norm satisfies: + + @@ -2056,6 +2212,8 @@ the relative residual norm satisfies: + + @@ -2066,7 +2224,7 @@ the relative residual norm satisfies: - + @@ -2074,6 +2232,8 @@ the relative residual norm satisfies: + + @@ -2086,6 +2246,8 @@ the relative residual norm satisfies: + + @@ -2128,24 +2290,31 @@ the relative residual norm satisfies: + + + + + + + @@ -2169,10 +2338,23 @@ the relative residual norm satisfies: - + + + @@ -2181,6 +2363,8 @@ the relative residual norm satisfies: + + @@ -2203,7 +2387,18 @@ the relative residual norm satisfies: - + @@ -2215,19 +2410,34 @@ the relative residual norm satisfies: + + + + + + - + + + + + + + + + + @@ -2238,6 +2448,8 @@ the relative residual norm satisfies: + + @@ -2260,7 +2472,18 @@ the relative residual norm satisfies: - + @@ -2272,16 +2495,26 @@ the relative residual norm satisfies: + + + + + + - + + + + + @@ -2290,6 +2523,8 @@ the relative residual norm satisfies: + + @@ -2312,7 +2547,18 @@ the relative residual norm satisfies: - + @@ -2324,16 +2570,26 @@ the relative residual norm satisfies: + + + + + + - + + + + + @@ -2360,12 +2616,25 @@ the relative residual norm satisfies: - + + + @@ -2378,6 +2647,8 @@ the relative residual norm satisfies: + + @@ -2388,12 +2659,14 @@ the relative residual norm satisfies: - + + + @@ -2402,16 +2675,20 @@ the relative residual norm satisfies: - + + + + + - + @@ -2438,12 +2715,25 @@ the relative residual norm satisfies: - + + + @@ -2456,26 +2746,34 @@ the relative residual norm satisfies: + + - + + + - + + + + + @@ -2490,12 +2788,27 @@ the relative residual norm satisfies: - + + + @@ -2510,23 +2823,37 @@ the relative residual norm satisfies: - + - + - + + + @@ -2547,20 +2874,43 @@ Local - Add stabilization only to interiors of macro elements.--> - + + + + + + + - + + + + + @@ -2569,6 +2919,7 @@ Local - Add stabilization only to interiors of macro elements.--> * BHP * phaseVolRate * totalVolRate +* massRate * uninitialized--> + + + + @@ -2620,7 +2975,7 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> - + @@ -2633,6 +2988,8 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> + + @@ -2655,7 +3012,18 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> - + @@ -2667,16 +3035,26 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> + + + + + + - + + + + + @@ -2685,6 +3063,8 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> + + @@ -2707,7 +3087,18 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> - + @@ -2719,20 +3110,32 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> + + + + - + + + - + + + + + + + @@ -2749,7 +3152,18 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> - + @@ -2757,6 +3171,8 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> + + @@ -2771,12 +3187,26 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> - + + + @@ -2787,31 +3217,62 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> - - + + - + + + + + + + + + + + + + + + + @@ -2825,7 +3286,18 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> - + @@ -2833,6 +3305,8 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> * SteadyState * ImplicitTransient--> + + @@ -2854,21 +3328,35 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> - + - + - + + + @@ -2881,7 +3369,20 @@ Local - Add stabilization only to interiors of macro elements.--> - + @@ -2889,6 +3390,8 @@ Local - Add stabilization only to interiors of macro elements.--> + + @@ -2911,12 +3414,25 @@ Local - Add stabilization only to interiors of macro elements.--> - + + + @@ -2941,12 +3457,26 @@ Local - Add stabilization only to interiors of macro elements.--> - + + + @@ -2971,7 +3501,18 @@ Local - Add stabilization only to interiors of macro elements.--> - + @@ -2989,6 +3530,80 @@ Local - Add stabilization only to interiors of macro elements.--> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3015,7 +3630,18 @@ Local - Add stabilization only to interiors of macro elements.--> - + @@ -3037,6 +3663,47 @@ Local - Add stabilization only to interiors of macro elements.--> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3053,9 +3720,24 @@ Local - Add stabilization only to interiors of macro elements.--> - + - + @@ -3067,6 +3749,8 @@ Local - Add stabilization only to interiors of macro elements.--> + + @@ -3083,9 +3767,24 @@ Local - Add stabilization only to interiors of macro elements.--> - + - + @@ -3097,6 +3796,8 @@ Local - Add stabilization only to interiors of macro elements.--> + + @@ -3113,12 +3814,35 @@ Local - Add stabilization only to interiors of macro elements.--> - + + + + + + + + + @@ -3135,12 +3859,69 @@ Local - Add stabilization only to interiors of macro elements.--> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3157,12 +3938,35 @@ Local - Add stabilization only to interiors of macro elements.--> - + + + + + + + + + @@ -3175,7 +3979,19 @@ Local - Add stabilization only to interiors of macro elements.--> - + @@ -3183,6 +3999,8 @@ Local - Add stabilization only to interiors of macro elements.--> + + @@ -3199,9 +4017,24 @@ Local - Add stabilization only to interiors of macro elements.--> - + - + @@ -3213,6 +4046,8 @@ Local - Add stabilization only to interiors of macro elements.--> + + @@ -3227,12 +4062,26 @@ Local - Add stabilization only to interiors of macro elements.--> - + + + @@ -3247,14 +4096,82 @@ Local - Add stabilization only to interiors of macro elements.--> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3264,31 +4181,64 @@ Local - Add stabilization only to interiors of macro elements.--> + + - + + + + + - + + + - + @@ -3311,8 +4261,8 @@ Local - Add stabilization only to interiors of macro elements.--> * ImplicitDynamic * ExplicitDynamic--> - - + + @@ -3321,6 +4271,60 @@ Local - Add stabilization only to interiors of macro elements.--> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3328,11 +4332,25 @@ Local - Add stabilization only to interiors of macro elements.--> + + - + @@ -3344,6 +4362,8 @@ Local - Add stabilization only to interiors of macro elements.--> + + * ImplicitDynamic * ExplicitDynamic--> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3367,13 +4441,26 @@ Local - Add stabilization only to interiors of macro elements.--> + + - + @@ -3398,6 +4485,8 @@ Local - Add stabilization only to interiors of macro elements.--> * ImplicitDynamic * ExplicitDynamic--> + + @@ -3408,13 +4497,26 @@ Local - Add stabilization only to interiors of macro elements.--> + + - + @@ -3439,6 +4541,8 @@ Local - Add stabilization only to interiors of macro elements.--> * ImplicitDynamic * ExplicitDynamic--> + + @@ -3471,7 +4575,18 @@ Local - Add stabilization only to interiors of macro elements.--> - + @@ -3502,6 +4617,8 @@ Local - Add stabilization only to interiors of macro elements.--> + + @@ -3523,7 +4640,22 @@ Local - Add stabilization only to interiors of macro elements.--> - + @@ -3533,33 +4665,54 @@ Local - Add stabilization only to interiors of macro elements.--> + + + + + + + + + + + + + + + + + + - + - - + + @@ -3570,7 +4723,11 @@ Local - Add stabilization only to interiors of macro elements.--> - + @@ -3579,13 +4736,29 @@ Local - Add stabilization only to interiors of macro elements.--> + + + + + + + + + + - + - - + + @@ -3602,6 +4775,8 @@ Local - Add stabilization only to interiors of macro elements.--> + + @@ -3661,30 +4836,78 @@ Local - Add stabilization only to interiors of macro elements.--> + + + + + + + + + + + + + + + + + + + + - + - - + + + + + + + + + + + + - + - - + + - + @@ -3694,7 +4917,10 @@ Local - Add stabilization only to interiors of macro elements.--> - + @@ -3704,7 +4930,10 @@ Local - Add stabilization only to interiors of macro elements.--> - + @@ -3713,6 +4942,21 @@ Local - Add stabilization only to interiors of macro elements.--> + + + + + + + + + + + + @@ -3755,13 +4999,15 @@ Local - Add stabilization only to interiors of macro elements.--> - - + + + + @@ -3780,6 +5026,7 @@ Local - Add stabilization only to interiors of macro elements.--> + @@ -3789,7 +5036,6 @@ Local - Add stabilization only to interiors of macro elements.--> - @@ -3803,14 +5049,16 @@ Local - Add stabilization only to interiors of macro elements.--> + + - + @@ -3827,12 +5075,14 @@ Local - Add stabilization only to interiors of macro elements.--> + + - - + + @@ -3951,6 +5201,8 @@ The expected format is "{ waterMax, oilMax }", in that order--> + + @@ -3971,6 +5223,8 @@ The expected format is "{ waterMax, oilMax }", in that order--> + + @@ -3991,6 +5245,8 @@ The expected format is "{ waterMax, oilMax }", in that order--> + + @@ -4011,6 +5267,8 @@ The expected format is "{ waterMax, oilMax }", in that order--> + + @@ -4065,6 +5323,8 @@ The expected format is "{ waterMax, oilMax }", in that order--> + + @@ -4072,7 +5332,56 @@ The expected format is "{ waterMax, oilMax }", in that order--> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4083,7 +5392,7 @@ The expected format is "{ waterMax, oilMax }", in that order--> - + @@ -4091,12 +5400,18 @@ The expected format is "{ waterMax, oilMax }", in that order--> + + + + - + @@ -4107,7 +5422,7 @@ The expected format is "{ waterMax, oilMax }", in that order--> - + @@ -4115,8 +5430,17 @@ The expected format is "{ waterMax, oilMax }", in that order--> + + + + @@ -4201,6 +5525,18 @@ The expected format is "{ waterMax, oilMax }", in that order--> + + + + + + + + + + + + @@ -4242,18 +5578,12 @@ The expected format is "{ waterMax, oilMax }", in that order--> - - - - - - @@ -4576,16 +5906,18 @@ For instance, if "oil" is before "gas" in "phaseNames", the table order should b + + + + + + - - - - - - + + @@ -4745,10 +6077,6 @@ If you want to do a three-phase simulation, please use instead wettingIntermedia - - - - @@ -4905,6 +6233,25 @@ If you want to do a three-phase simulation, please use instead wettingIntermedia + + + + + + + + + + + + + + + + + + + @@ -4971,6 +6318,22 @@ If you want to do a three-phase simulation, please use instead wettingIntermedia + + + + + + + + + + + + + + + + @@ -4982,6 +6345,8 @@ If you want to do a three-phase simulation, please use instead wettingIntermedia + + @@ -4996,12 +6361,18 @@ If you want to do a three-phase simulation, please use instead wettingIntermedia + + - - - + + + + + + + @@ -5016,12 +6387,14 @@ If you want to do a three-phase simulation, please use instead wettingIntermedia + + - - + + @@ -5302,7 +6675,8 @@ The expected format is "{ waterMax, oilMax }", in that order--> - + diff --git a/src/coreComponents/schema/schema.xsd.other b/src/coreComponents/schema/schema.xsd.other index c81efef7141..3abf5b863f0 100644 --- a/src/coreComponents/schema/schema.xsd.other +++ b/src/coreComponents/schema/schema.xsd.other @@ -50,12 +50,12 @@ - + - + @@ -173,6 +173,7 @@ + @@ -279,6 +280,16 @@ + + + + + + + + + + @@ -380,6 +391,7 @@ + @@ -390,6 +402,7 @@ + @@ -398,6 +411,7 @@ + @@ -418,6 +432,7 @@ + @@ -443,9 +458,9 @@ - + - + @@ -471,7 +486,7 @@ - + @@ -522,19 +537,26 @@ + + + + + + + @@ -550,7 +572,7 @@ - + @@ -587,13 +609,13 @@ - + - - + + @@ -610,8 +632,8 @@ - - + + @@ -638,13 +660,13 @@ - + - - + + @@ -657,8 +679,8 @@ - - + + @@ -679,13 +701,13 @@ - + - - + + @@ -698,8 +720,8 @@ - - + + @@ -712,7 +734,7 @@ - + @@ -723,7 +745,7 @@ - + @@ -736,7 +758,7 @@ - + @@ -749,7 +771,7 @@ - + @@ -765,7 +787,7 @@ - + @@ -773,7 +795,7 @@ - + @@ -799,11 +821,11 @@ - - - + + + @@ -832,8 +854,8 @@ - - + + @@ -862,11 +884,11 @@ - - - + + + @@ -879,8 +901,8 @@ - - + + @@ -893,7 +915,7 @@ - + @@ -906,7 +928,7 @@ - + @@ -919,7 +941,7 @@ - + @@ -932,7 +954,7 @@ - + @@ -945,7 +967,7 @@ - + @@ -960,7 +982,7 @@ - + @@ -971,7 +993,7 @@ - + @@ -984,7 +1006,7 @@ - + @@ -995,7 +1017,29 @@ - + + + + + + + + + + + + + + + + + + + + + + + @@ -1006,7 +1050,20 @@ - + + + + + + + + + + + + + + @@ -1017,7 +1074,7 @@ - + @@ -1028,7 +1085,7 @@ - + @@ -1041,7 +1098,7 @@ - + @@ -1056,10 +1113,23 @@ - + + + + + + + + + + + + + + @@ -1071,7 +1141,7 @@ - + @@ -1086,7 +1156,7 @@ - + @@ -1097,7 +1167,7 @@ - + @@ -1110,7 +1180,7 @@ - + @@ -1123,7 +1193,22 @@ - + + + + + + + + + + + + + + + + @@ -1139,7 +1224,24 @@ - + + + + + + + + + + + + + + + + + + @@ -1154,7 +1256,7 @@ - + @@ -1171,7 +1273,24 @@ - + + + + + + + + + + + + + + + + + + @@ -1186,7 +1305,7 @@ - + @@ -1199,7 +1318,7 @@ - + @@ -1238,7 +1357,7 @@ - + @@ -1267,45 +1386,66 @@ - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + @@ -1339,7 +1479,7 @@ - + @@ -1358,13 +1498,15 @@ - - + + + + @@ -1383,6 +1525,7 @@ + @@ -1392,7 +1535,6 @@ - @@ -1406,14 +1548,16 @@ + + - + @@ -1438,6 +1582,8 @@ + + @@ -1450,6 +1596,8 @@ + + @@ -1457,7 +1605,7 @@ - + @@ -1473,7 +1621,7 @@ - + @@ -1509,7 +1657,7 @@ - + @@ -1573,7 +1721,7 @@ - + @@ -1619,7 +1767,7 @@ - + @@ -1665,7 +1813,7 @@ - + @@ -1711,7 +1859,7 @@ - + @@ -1785,7 +1933,7 @@ - + @@ -1829,9 +1977,9 @@ - + - + @@ -1846,6 +1994,8 @@ + + @@ -1866,6 +2016,8 @@ + + @@ -1875,9 +2027,9 @@ - + - + @@ -1892,6 +2044,8 @@ + + @@ -1912,6 +2066,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1955,6 +2161,7 @@ + @@ -2037,7 +2244,7 @@ - + @@ -2053,7 +2260,7 @@ - + @@ -2089,7 +2296,7 @@ - + @@ -2260,13 +2467,14 @@ + - + @@ -2359,12 +2567,6 @@ - - - - - - @@ -2378,6 +2580,14 @@ + + + + + + + + @@ -2475,9 +2685,23 @@ + + + + + + + + + + + + + + - + @@ -2531,7 +2755,7 @@ - + @@ -2583,7 +2807,9 @@ - + + + @@ -2605,7 +2831,7 @@ - + @@ -2631,7 +2857,7 @@ - + @@ -2645,7 +2871,7 @@ - + @@ -2653,7 +2879,7 @@ - + @@ -2877,17 +3103,21 @@ - + + + + + - + @@ -2901,11 +3131,15 @@ - + + + + + @@ -2916,17 +3150,21 @@ - + - + + + + + - + @@ -2936,17 +3174,21 @@ - + - + + + + + - + @@ -2956,21 +3198,25 @@ - + - + - + - + - + + + + + @@ -2986,7 +3232,7 @@ - + @@ -3004,15 +3250,19 @@ - + + + + + - + @@ -3024,23 +3274,27 @@ - + - + - + - + - + - + + + + + @@ -3055,11 +3309,15 @@ - + + + + + @@ -3077,11 +3335,15 @@ - + + + + + @@ -3094,11 +3356,15 @@ - + + + + + @@ -3120,17 +3386,21 @@ - + + + + + - + @@ -3157,15 +3427,21 @@ - + + + + + + + @@ -3190,11 +3466,15 @@ - + + + + + diff --git a/src/coreComponents/schema/schemaUtilities.cpp b/src/coreComponents/schema/schemaUtilities.cpp index 93eb8ce0f7e..d39b1af77f3 100644 --- a/src/coreComponents/schema/schemaUtilities.cpp +++ b/src/coreComponents/schema/schemaUtilities.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,7 +20,7 @@ /// Source includes #include "schemaUtilities.hpp" -#include "codingUtilities/StringUtilities.hpp" +#include "common/format/StringUtilities.hpp" #include "common/DataTypes.hpp" #include "dataRepository/Group.hpp" #include "dataRepository/InputFlags.hpp" @@ -76,9 +77,15 @@ string getSchemaTypeName( string_view rtTypeName ) // Note: Some type names involving strings can vary on compiler and be ugly. Convert these to "string" auto constexpr typeMergingRegex = "std_(__cxx11_basic_)?string(<\\s*char,\\s*std_char_traits,\\s*std_allocator\\s*>)?"; - string const xmlSafeName = std::regex_replace( sanitizedName, - std::regex( typeMergingRegex ), - "string" ); + string xmlSafeName = std::regex_replace( sanitizedName, + std::regex( typeMergingRegex ), + "string" ); + + // Replace '<', '>', spaces and ',' because the schema does not like them + xmlSafeName = std::regex_replace( xmlSafeName, std::regex( "<" ), "_lt_" ); + xmlSafeName = std::regex_replace( xmlSafeName, std::regex( ">" ), "_gt_" ); + xmlSafeName = std::regex_replace( xmlSafeName, std::regex( "," ), "_cm_" ); + xmlSafeName = std::regex_replace( xmlSafeName, std::regex( " " ), "-" ); return xmlSafeName; } diff --git a/src/coreComponents/schema/schemaUtilities.hpp b/src/coreComponents/schema/schemaUtilities.hpp index f81df636bf5..aa9ae40e9b5 100644 --- a/src/coreComponents/schema/schemaUtilities.hpp +++ b/src/coreComponents/schema/schemaUtilities.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/unitTests/CMakeLists.txt b/src/coreComponents/unitTests/CMakeLists.txt index 3d49c154263..8b760067a42 100644 --- a/src/coreComponents/unitTests/CMakeLists.txt +++ b/src/coreComponents/unitTests/CMakeLists.txt @@ -1,14 +1,36 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# +# Copyright (c) 2016-2024 Lawrence Livermore National Security LLC +# Copyright (c) 2018-2024 TotalEnergies +# Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University +# Copyright (c) 2023-2024 Chevron +# Copyright (c) 2019- GEOS/GEOSX Contributors +# All rights reserved +# +# See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. +# +#-------------------------------------------------------------------------------------------------- + +#[[ +Package: mainInterface + +Contains high-level unit tests that depends typically depends on mainInterface components like the +ProblemManager. +#]] + add_subdirectory( toolchain ) +add_subdirectory( testingUtilities ) add_subdirectory( xmlTests ) add_subdirectory( virtualElementTests ) add_subdirectory( linearAlgebraTests ) add_subdirectory( dataRepositoryTests ) -#add_subdirectory( functionsTests ) add_subdirectory( fieldSpecificationTests ) add_subdirectory( constitutiveTests ) add_subdirectory( meshTests ) add_subdirectory( finiteVolumeTests ) add_subdirectory( fileIOTests ) -add_subdirectory( fluidFlowTests ) +if( GEOS_ENABLE_FLUIDFLOW ) + add_subdirectory( fluidFlowTests ) +endif() add_subdirectory( wellsTests ) -add_subdirectory( wavePropagationTests ) +add_subdirectory( wavePropagationTests ) diff --git a/src/coreComponents/unitTests/constitutiveTests/CMakeLists.txt b/src/coreComponents/unitTests/constitutiveTests/CMakeLists.txt index e8b27218b8f..f59c739a956 100644 --- a/src/coreComponents/unitTests/constitutiveTests/CMakeLists.txt +++ b/src/coreComponents/unitTests/constitutiveTests/CMakeLists.txt @@ -1,9 +1,15 @@ # Specify list of tests set( gtest_geosx_tests + testCapillaryPressure.cpp + testCO2BrinePVTModels.cpp + testCO2SpycherPruessModels.cpp testDamage.cpp + testMultiFluidCO2Brine.cpp + testMultiFluidCompositionalMultiphase.cpp + testMultiFluidDeadOil.cpp + testMultiFluidLiveOil.cpp testRelPerm.cpp - testRelPermHysteresis.cpp - testCapillaryPressure.cpp ) + testRelPermHysteresis.cpp ) set( gtest_triaxial_xmls testTriaxial_druckerPragerExtended.xml @@ -22,42 +28,23 @@ set( gtest_pvt_xmls testPVT_CO2Brine.xml testPVT_CO2BrineTables.xml testPVT_PhaseComposition.xml + testPVT_ThreePhaseCompositional.xml ) set( gtest_reactivefluid_xmls testReactiveFluid.xml ) -set( dependencyList ${parallelDeps} gtest ) +set( tplDependencyList ${parallelDeps} gtest ) -if ( GEOSX_BUILD_SHARED_LIBS ) - list( APPEND dependencyList geosx_core ) -else() - list( APPEND dependencyList ${geosx_core_libs} ) -endif() +set( dependencyList mainInterface ) if( ENABLE_PVTPackage ) list( APPEND gtest_geosx_tests - testMultiFluid.cpp - testCO2BrinePVTModels.cpp ) - - list( APPEND dependencyList PVTPackage ) -endif() - -if (TARGET pugixml::pugixml) - list( APPEND dependencyList pugixml::pugixml ) -endif() - -if (TARGET pugixml) - list( APPEND dependencyList pugixml ) + testMultiFluidCompositionalMultiphasePVTPackage.cpp ) endif() -if (TARGET fmt::fmt) - list( APPEND dependencyList fmt::fmt ) -endif() - -if (TARGET fmt) - list( APPEND dependencyList fmt ) -endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) # Add gtest C++ based tests foreach(test ${gtest_geosx_tests}) @@ -65,8 +52,7 @@ foreach(test ${gtest_geosx_tests}) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} ) - + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} ) geos_add_test( NAME ${test_name} COMMAND ${test_name} ) @@ -76,7 +62,7 @@ endforeach() blt_add_executable( NAME testTriaxial SOURCES testTriaxial.cpp OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} "-lz" ) + DEPENDS_ON ${dependencyList} "-lz" ${tplDependencyList}) foreach(test ${gtest_triaxial_xmls}) get_filename_component( test_name ${test} NAME_WE ) @@ -88,7 +74,7 @@ endforeach() blt_add_executable( NAME testPVT SOURCES testPVT.cpp OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} "-lz" ) + DEPENDS_ON ${dependencyList} "-lz" ${tplDependencyList} ) foreach(test ${gtest_pvt_xmls}) get_filename_component( test_name ${test} NAME_WE ) @@ -101,7 +87,7 @@ endforeach() blt_add_executable( NAME testReactiveFluid SOURCES testReactiveFluid.cpp OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} "-lz" ) + DEPENDS_ON ${dependencyList} "-lz" ${tplDependencyList} ) foreach(test ${gtest_reactivefluid_xmls}) get_filename_component( test_name ${test} NAME_WE ) diff --git a/src/coreComponents/unitTests/constitutiveTests/MultiFluidTest.hpp b/src/coreComponents/unitTests/constitutiveTests/MultiFluidTest.hpp new file mode 100644 index 00000000000..5aa748e071b --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/MultiFluidTest.hpp @@ -0,0 +1,527 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file MultiFluidTest.hpp + */ + +#ifndef GEOS_UNITTESTS_CONSTITUTIVETESTS_MULTIFLUIDTEST_HPP_ +#define GEOS_UNITTESTS_CONSTITUTIVETESTS_MULTIFLUIDTEST_HPP_ + +#include "constitutiveTestHelpers.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "constitutive/fluid/multifluid/MultiFluidSelector.hpp" + + +namespace geos +{ +namespace testing +{ + +template< typename FLUID_TYPE > +struct UsePVTPackage +{ + static constexpr bool value = false; +}; + +template< integer N > +using Feed = std::array< real64, N >; + +template< integer N, typename ARRAY1, typename ARRAY2 > +void copy( ARRAY1 const & inputArray, ARRAY2 & outputArray ) +{ + for( integer i = 0; i < N; ++i ) + { + outputArray[i] = inputArray[i]; + } +} + +template< integer N, typename T > +void fill( array1d< T > & outputArray, std::array< T const, N > const inputArray ) +{ + for( integer i = 0; i < N; ++i ) + { + outputArray.emplace_back( inputArray[i] ); + } +} + +template< integer N, integer U, typename T > +void fill( arraySlice1d< T, U > const & outputArray, std::array< T const, N > const inputArray ) +{ + for( integer i = 0; i < N; ++i ) + { + outputArray[i] = inputArray[i]; + } +} + +template< integer NUM_PHASE, integer NUM_COMP > +struct MultiFluidTestData +{ + MultiFluidTestData( real64 const pressure_, + real64 const temperature_, + Feed< NUM_COMP > && composition_ ); + + MultiFluidTestData( real64 const pressure_, + real64 const temperature_, + arraySlice1d< real64 const > const & composition_ ); + + MultiFluidTestData( real64 const pressure_, + real64 const temperature_, + Feed< NUM_COMP > && composition_, + real64 const totalDensity_, + Feed< NUM_PHASE > && phaseFraction_, + Feed< NUM_PHASE > && phaseDensity_, + Feed< NUM_PHASE > && phaseMassDensity_, + Feed< NUM_PHASE > && phaseViscosity_, + Feed< NUM_PHASE > && phaseEnthalpy_, + Feed< NUM_PHASE > && phaseInternalEnergy_ ); + + real64 const pressure{0.0}; + real64 const temperature{0.0}; + Feed< NUM_COMP > composition{}; + real64 const totalDensity{0.0}; + Feed< NUM_PHASE > phaseFraction{}; + Feed< NUM_PHASE > phaseDensity{}; + Feed< NUM_PHASE > phaseMassDensity{}; + Feed< NUM_PHASE > phaseViscosity{}; + Feed< NUM_PHASE > phaseEnthalpy{}; + Feed< NUM_PHASE > phaseInternalEnergy{}; +}; + +template< typename FLUID_TYPE, integer NUM_PHASE, integer NUM_COMP > +class MultiFluidTest : public ConstitutiveTestBase< constitutive::MultiFluidBase > +{ +public: + static constexpr integer numPhase = NUM_PHASE; + static constexpr integer numComp = NUM_COMP; + using TestData = MultiFluidTestData< numPhase, numComp >; + +public: + MultiFluidTest() = default; + ~MultiFluidTest() override = default; + + constitutive::MultiFluidBase & getFluid() const { return *m_model; } + + dataRepository::Group & getParent() { return m_parent; } + + void testValuesAgainstPreviousImplementation( typename FLUID_TYPE::KernelWrapper const & wrapper, + MultiFluidTestData< NUM_PHASE, NUM_COMP > const & testData, + real64 const relTol ) const; + + void testNumericalDerivatives( constitutive::MultiFluidBase & fluid, + dataRepository::Group * parent, + MultiFluidTestData< NUM_PHASE, NUM_COMP > const & testData, + real64 const perturbParameter, + real64 const relTol, + real64 const absTol = std::numeric_limits< real64 >::max() ); + + +protected: + virtual void resetFluid( constitutive::MultiFluidBase & fluid ) const + { + GEOS_UNUSED_VAR( fluid ); + } + + static void writeTableToFile( string const & fileName, char const * content ) + { + std::ofstream os( fileName ); + ASSERT_TRUE( os.is_open() ); + os << content; + os.close(); + } + + static void removeFile( string const & fileName ) + { + int const ret = std::remove( fileName.c_str() ); + ASSERT_TRUE( ret == 0 ); + } +}; + +template< typename FLUID_TYPE, integer NUM_PHASE, integer NUM_COMP > +void MultiFluidTest< FLUID_TYPE, NUM_PHASE, NUM_COMP >:: +testNumericalDerivatives( constitutive::MultiFluidBase & fluid, + dataRepository::Group * parent, + MultiFluidTestData< NUM_PHASE, NUM_COMP > const & testData, + real64 const perturbParameter, + real64 const relTol, + real64 const absTol ) +{ + using Deriv = constitutive::multifluid::DerivativeOffset; + + integer const NC = fluid.numFluidComponents(); + integer const NP = fluid.numFluidPhases(); + integer const NDOF = NC+2; + + bool const isThermal = fluid.isThermal(); + + // Copy input values into an array with expected layout + array2d< real64, compflow::LAYOUT_COMP > compositionValues( 1, NC ); + for( integer i = 0; i < NC; ++i ) + { + compositionValues[0][i] = testData.composition[i]; + } + arraySlice1d< real64 const, compflow::USD_COMP - 1 > const composition = compositionValues[0]; + + auto const & components = fluid.getReference< string_array >( constitutive::MultiFluidBase::viewKeyStruct::componentNamesString() ); + auto const & phases = fluid.getReference< string_array >( constitutive::MultiFluidBase::viewKeyStruct::phaseNamesString() ); + + // create a clone of the fluid to run updates on + string const fluidCopyName = fluid.getName() + "Copy"; + std::unique_ptr< constitutive::ConstitutiveBase > fluidCopyPtr = fluid.deliverClone( fluidCopyName, parent ); + constitutive::MultiFluidBase & fluidCopy = dynamicCast< constitutive::MultiFluidBase & >( *fluidCopyPtr ); + + fluid.allocateConstitutiveData( fluid.getParent(), 1 ); + fluidCopy.allocateConstitutiveData( fluid.getParent(), 1 ); + + // extract data views from both fluids + #define GET_FLUID_DATA( FLUID, TRAIT ) \ + FLUID.getReference< TRAIT::type >( TRAIT::key() )[0][0] + + constitutive::MultiFluidVarSlice< real64, 1, constitutive::multifluid::USD_PHASE - 2, constitutive::multifluid::USD_PHASE_DC - 2 > phaseFrac { + GET_FLUID_DATA( fluid, fields::multifluid::phaseFraction ), + GET_FLUID_DATA( fluid, fields::multifluid::dPhaseFraction ) + }; + + constitutive::MultiFluidVarSlice< real64, 1, constitutive::multifluid::USD_PHASE - 2, constitutive::multifluid::USD_PHASE_DC - 2 > phaseDens { + GET_FLUID_DATA( fluid, fields::multifluid::phaseDensity ), + GET_FLUID_DATA( fluid, fields::multifluid::dPhaseDensity ) + }; + + constitutive::MultiFluidVarSlice< real64, 1, constitutive::multifluid::USD_PHASE - 2, constitutive::multifluid::USD_PHASE_DC - 2 > phaseVisc { + GET_FLUID_DATA( fluid, fields::multifluid::phaseViscosity ), + GET_FLUID_DATA( fluid, fields::multifluid::dPhaseViscosity ) + }; + + constitutive::MultiFluidVarSlice< real64, 1, constitutive::multifluid::USD_PHASE - 2, constitutive::multifluid::USD_PHASE_DC - 2 > phaseEnthalpy { + GET_FLUID_DATA( fluid, fields::multifluid::phaseEnthalpy ), + GET_FLUID_DATA( fluid, fields::multifluid::dPhaseEnthalpy ) + }; + + constitutive::MultiFluidVarSlice< real64, 1, constitutive::multifluid::USD_PHASE - 2, constitutive::multifluid::USD_PHASE_DC - 2 > phaseInternalEnergy { + GET_FLUID_DATA( fluid, fields::multifluid::phaseInternalEnergy ), + GET_FLUID_DATA( fluid, fields::multifluid::dPhaseInternalEnergy ) + }; + + constitutive::MultiFluidVarSlice< real64, 2, constitutive::multifluid::USD_PHASE_COMP - 2, constitutive::multifluid::USD_PHASE_COMP_DC - 2 > phaseCompFrac { + GET_FLUID_DATA( fluid, fields::multifluid::phaseCompFraction ), + GET_FLUID_DATA( fluid, fields::multifluid::dPhaseCompFraction ) + }; + + constitutive::MultiFluidVarSlice< real64, 0, constitutive::multifluid::USD_FLUID - 2, constitutive::multifluid::USD_FLUID_DC - 2 > totalDens { + GET_FLUID_DATA( fluid, fields::multifluid::totalDensity ), + GET_FLUID_DATA( fluid, fields::multifluid::dTotalDensity ) + }; + + auto const & phaseFracCopy = GET_FLUID_DATA( fluidCopy, fields::multifluid::phaseFraction ); + auto const & phaseDensCopy = GET_FLUID_DATA( fluidCopy, fields::multifluid::phaseDensity ); + auto const & phaseViscCopy = GET_FLUID_DATA( fluidCopy, fields::multifluid::phaseViscosity ); + auto const & phaseEnthCopy = GET_FLUID_DATA( fluidCopy, fields::multifluid::phaseEnthalpy ); + auto const & phaseEnergyCopy = GET_FLUID_DATA( fluidCopy, fields::multifluid::phaseInternalEnergy ); + auto const & phaseCompFracCopy = GET_FLUID_DATA( fluidCopy, fields::multifluid::phaseCompFraction ); + auto const & totalDensCopy = GET_FLUID_DATA( fluidCopy, fields::multifluid::totalDensity ); + +#undef GET_FLUID_DATA + + // Enthalpy and internal energy values can be quite large and prone to round-off errors when + // performing finite difference derivatives. We will therefore scale the values using this + // reference enthalpy value to bring them to a more manageable scale. + real64 constexpr referenceEnthalpy = 5.0584e5; + auto const scaleEnthalpy = []( auto & arraySlice ) + { + LvArray::forValuesInSlice( arraySlice, []( real64 & value ){ value /= referenceEnthalpy; } ); + }; + + real64 const pressure = testData.pressure; + real64 const temperature = testData.temperature; + + // set the original fluid state to current + constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) + { + typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); + fluidWrapper.update( 0, 0, pressure, temperature, composition ); + } ); + + if( isThermal ) + { + scaleEnthalpy( phaseEnthalpy.value ); + scaleEnthalpy( phaseEnthalpy.derivs ); + scaleEnthalpy( phaseInternalEnergy.value ); + scaleEnthalpy( phaseInternalEnergy.derivs ); + } + + // now perturb variables and update the copied fluid's state + constitutive::constitutiveUpdatePassThru( fluidCopy, [&] ( auto & castedFluid ) + { + typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); + + // to be able to use the checkDerivative utility function, we have to invert the layout + auto dPhaseFrac = invertLayout( phaseFrac.derivs.toSliceConst(), NP, NDOF ); + auto dPhaseDens = invertLayout( phaseDens.derivs.toSliceConst(), NP, NDOF ); + auto dPhaseVisc = invertLayout( phaseVisc.derivs.toSliceConst(), NP, NDOF ); + auto dPhaseEnth = invertLayout( phaseEnthalpy.derivs.toSliceConst(), NP, NDOF ); + auto dPhaseEnergy = invertLayout( phaseInternalEnergy.derivs.toSliceConst(), NP, NDOF ); + auto dTotalDens = invertLayout( totalDens.derivs.toSliceConst(), NDOF ); + auto dPhaseCompFrac = invertLayout( phaseCompFrac.derivs.toSliceConst(), NP, NC, NDOF ); + + // update pressure and check derivatives + { + real64 const dP = perturbParameter * (pressure + perturbParameter); + resetFluid( fluidCopy ); + fluidWrapper.update( 0, 0, pressure + dP, temperature, composition ); + + checkDerivative( phaseFracCopy.toSliceConst(), phaseFrac.value.toSliceConst(), dPhaseFrac[Deriv::dP].toSliceConst(), + dP, relTol, absTol, "phaseFrac", "Pres", phases ); + checkDerivative( phaseDensCopy.toSliceConst(), phaseDens.value.toSliceConst(), dPhaseDens[Deriv::dP].toSliceConst(), + dP, relTol, absTol, "phaseDens", "Pres", phases ); + checkDerivative( phaseViscCopy.toSliceConst(), phaseVisc.value.toSliceConst(), dPhaseVisc[Deriv::dP].toSliceConst(), + dP, relTol, absTol, "phaseVisc", "Pres", phases ); + checkDerivative( totalDensCopy, totalDens.value, dTotalDens[Deriv::dP], + dP, relTol, absTol, "totalDens", "Pres" ); + checkDerivative( phaseCompFracCopy.toSliceConst(), phaseCompFrac.value.toSliceConst(), dPhaseCompFrac[Deriv::dP].toSliceConst(), + dP, relTol, absTol, "phaseCompFrac", "Pres", phases, components ); + if( isThermal ) + { + scaleEnthalpy( phaseEnthCopy ); + scaleEnthalpy( phaseEnergyCopy ); + checkDerivative( phaseEnthCopy.toSliceConst(), phaseEnthalpy.value.toSliceConst(), dPhaseEnth[Deriv::dP].toSliceConst(), + dP, relTol, absTol, "phaseEnth", "Pres", phases ); + checkDerivative( phaseEnergyCopy.toSliceConst(), phaseInternalEnergy.value.toSliceConst(), dPhaseEnergy[Deriv::dP].toSliceConst(), + dP, relTol, absTol, "phaseEnergy", "Pres", phases ); + } + } + + // update temperature and check derivatives + { + real64 const dT = perturbParameter * (temperature + perturbParameter); + resetFluid( fluidCopy ); + fluidWrapper.update( 0, 0, pressure, temperature + dT, composition ); + + checkDerivative( phaseFracCopy.toSliceConst(), phaseFrac.value.toSliceConst(), dPhaseFrac[Deriv::dT].toSliceConst(), + dT, relTol, absTol, "phaseFrac", "Temp", phases ); + checkDerivative( phaseDensCopy.toSliceConst(), phaseDens.value.toSliceConst(), dPhaseDens[Deriv::dT].toSliceConst(), + dT, relTol, absTol, "phaseDens", "Temp", phases ); + checkDerivative( phaseViscCopy.toSliceConst(), phaseVisc.value.toSliceConst(), dPhaseVisc[Deriv::dT].toSliceConst(), + dT, relTol, absTol, "phaseVisc", "Temp", phases ); + checkDerivative( totalDensCopy, totalDens.value, dTotalDens[Deriv::dT], + dT, relTol, absTol, "totalDens", "Temp" ); + checkDerivative( phaseCompFracCopy.toSliceConst(), phaseCompFrac.value.toSliceConst(), dPhaseCompFrac[Deriv::dT].toSliceConst(), + dT, relTol, absTol, "phaseCompFrac", "Temp", phases, components ); + if( isThermal ) + { + scaleEnthalpy( phaseEnthCopy ); + scaleEnthalpy( phaseEnergyCopy ); + checkDerivative( phaseEnthCopy.toSliceConst(), phaseEnthalpy.value.toSliceConst(), dPhaseEnth[Deriv::dT].toSliceConst(), + dT, relTol, absTol, "phaseEnth", "Temp", phases ); + checkDerivative( phaseEnergyCopy.toSliceConst(), phaseInternalEnergy.value.toSliceConst(), dPhaseEnergy[Deriv::dT].toSliceConst(), + dT, relTol, absTol, "phaseEnergy", "Temp", phases ); + } + } + + array2d< real64, compflow::LAYOUT_COMP > compNew( 1, NC ); + for( integer jc = 0; jc < NC; ++jc ) + { + real64 const dC = LvArray::math::max( 1.0e-7, perturbParameter * ( composition[jc] + perturbParameter ) ); + for( integer ic = 0; ic < NC; ++ic ) + { + compNew[0][ic] = composition[ic]; + } + compNew[0][jc] += dC; + + // Note: in PVTPackage, derivatives are obtained with finite-difference approx **with normalization of the comp fraction** + // The component fraction is perturbed (just as above), and then all the component fractions are normalized (as below) + // But, in the native DO model and in CO2BrinePhillips, derivatives are computed analytically, which results in different + // derivatives wrt component fractions--although the derivatives wrt component densities obtained with the chain rule + // in the solver will be very similar (see discussion on PR #1325 on GitHub). + // + // Since both approaches--FD approximation of derivatives with normalization, and analytical derivatives--are correct, + // we have to support both when we check the intermediate derivatives wrt component fractions below. Therefore, if the + // PVTPackage is used, then we normalize the perturbed component fractions before taking the FD approx. If the native + // DO or CO2-brine models are used, we skip the normalization below. + if constexpr ( UsePVTPackage< FLUID_TYPE >::value ) + { + // renormalize + real64 sum = 0.0; + for( integer ic = 0; ic < NC; ++ic ) + { + sum += compNew[0][ic]; + } + for( integer ic = 0; ic < NC; ++ic ) + { + compNew[0][ic] /= sum; + } + } + + resetFluid( fluidCopy ); + fluidWrapper.update( 0, 0, pressure, temperature, compNew[0] ); + + string const var = "compFrac[" + components[jc] + "]"; + checkDerivative( phaseFracCopy.toSliceConst(), phaseFrac.value.toSliceConst(), dPhaseFrac[Deriv::dC+jc].toSliceConst(), + dC, relTol, absTol, "phaseFrac", var, phases ); + checkDerivative( phaseDensCopy.toSliceConst(), phaseDens.value.toSliceConst(), dPhaseDens[Deriv::dC+jc].toSliceConst(), + dC, relTol, absTol, "phaseDens", var, phases ); + checkDerivative( phaseViscCopy.toSliceConst(), phaseVisc.value.toSliceConst(), dPhaseVisc[Deriv::dC+jc].toSliceConst(), + dC, relTol, absTol, "phaseVisc", var, phases ); + checkDerivative( totalDensCopy, totalDens.value, dTotalDens[Deriv::dC+jc], + dC, relTol, absTol, "totalDens", var ); + checkDerivative( phaseCompFracCopy.toSliceConst(), phaseCompFrac.value.toSliceConst(), dPhaseCompFrac[Deriv::dC+jc].toSliceConst(), + dC, relTol, absTol, "phaseCompFrac", var, phases, components ); + if( isThermal ) + { + scaleEnthalpy( phaseEnthCopy ); + scaleEnthalpy( phaseEnergyCopy ); + checkDerivative( phaseEnthCopy.toSliceConst(), phaseEnthalpy.value.toSliceConst(), dPhaseEnth[Deriv::dC+jc].toSliceConst(), + dC, relTol, absTol, "phaseEnth", var, phases ); + checkDerivative( phaseEnergyCopy.toSliceConst(), phaseInternalEnergy.value.toSliceConst(), dPhaseEnergy[Deriv::dC+jc].toSliceConst(), + dC, relTol, absTol, "phaseEnergy", var, phases ); + } + } + } ); +} + +template< typename FLUID_TYPE, integer NUM_PHASE, integer NUM_COMP > +void MultiFluidTest< FLUID_TYPE, NUM_PHASE, NUM_COMP >::testValuesAgainstPreviousImplementation( typename FLUID_TYPE::KernelWrapper const & wrapper, + MultiFluidTestData< NUM_PHASE, NUM_COMP > const & testData, + real64 const relTol ) const +{ + integer constexpr numDof = numComp + 2; + + // Copy input values into an array with expected layout + array2d< real64, compflow::LAYOUT_COMP > compositionValues( 1, numComp ); + for( integer i = 0; i < numComp; ++i ) + { + compositionValues[0][i] = testData.composition[i]; + } + arraySlice1d< real64 const, compflow::USD_COMP - 1 > const composition = compositionValues[0]; + + StackArray< real64, 3, numPhase, constitutive::multifluid::LAYOUT_PHASE > phaseFraction( 1, 1, numPhase ); + StackArray< real64, 4, numDof *numPhase, constitutive::multifluid::LAYOUT_PHASE_DC > dPhaseFraction( 1, 1, numPhase, numDof ); + StackArray< real64, 3, numPhase, constitutive::multifluid::LAYOUT_PHASE > phaseDensity( 1, 1, numPhase ); + StackArray< real64, 4, numDof *numPhase, constitutive::multifluid::LAYOUT_PHASE_DC > dPhaseDensity( 1, 1, numPhase, numDof ); + StackArray< real64, 3, numPhase, constitutive::multifluid::LAYOUT_PHASE > phaseMassDensity( 1, 1, numPhase ); + StackArray< real64, 4, numDof *numPhase, constitutive::multifluid::LAYOUT_PHASE_DC > dPhaseMassDensity( 1, 1, numPhase, numDof ); + StackArray< real64, 3, numPhase, constitutive::multifluid::LAYOUT_PHASE > phaseViscosity( 1, 1, numPhase ); + StackArray< real64, 4, numDof *numPhase, constitutive::multifluid::LAYOUT_PHASE_DC > dPhaseViscosity( 1, 1, numPhase, numDof ); + StackArray< real64, 3, numPhase, constitutive::multifluid::LAYOUT_PHASE > phaseEnthalpy( 1, 1, numPhase ); + StackArray< real64, 4, numDof *numPhase, constitutive::multifluid::LAYOUT_PHASE_DC > dPhaseEnthalpy( 1, 1, numPhase, numDof ); + StackArray< real64, 3, numPhase, constitutive::multifluid::LAYOUT_PHASE > phaseInternalEnergy( 1, 1, numPhase ); + StackArray< real64, 4, numDof *numPhase, constitutive::multifluid::LAYOUT_PHASE_DC > dPhaseInternalEnergy( 1, 1, numPhase, numDof ); + StackArray< real64, 4, numComp *numPhase, constitutive::multifluid::LAYOUT_PHASE_COMP > phaseCompFraction( 1, 1, numPhase, numComp ); + StackArray< real64, 5, numDof *numComp *numPhase, constitutive::multifluid::LAYOUT_PHASE_COMP_DC > dPhaseCompFraction( 1, 1, numPhase, numComp, numDof ); + StackArray< real64, 2, 1, constitutive::multifluid::LAYOUT_FLUID > totalDensity( 1, 1 ); + StackArray< real64, 3, numDof, constitutive::multifluid::LAYOUT_FLUID_DC > dTotalDensity( 1, 1, numDof ); + + wrapper.compute( testData.pressure, + testData.temperature, + composition, + { phaseFraction[0][0], dPhaseFraction[0][0] }, + { phaseDensity[0][0], dPhaseDensity[0][0] }, + { phaseMassDensity[0][0], dPhaseMassDensity[0][0] }, + { phaseViscosity[0][0], dPhaseViscosity[0][0] }, + { phaseEnthalpy[0][0], dPhaseEnthalpy[0][0] }, + { phaseInternalEnergy[0][0], dPhaseInternalEnergy[0][0] }, + { phaseCompFraction[0][0], dPhaseCompFraction[0][0] }, + { totalDensity[0][0], dTotalDensity[0][0] } ); + + checkRelativeError( totalDensity[0][0], testData.totalDensity, relTol ); + for( integer ip = 0; ip < numPhase; ++ip ) + { + checkRelativeError( phaseFraction[0][0][ip], testData.phaseFraction[ip], relTol ); + checkRelativeError( phaseDensity[0][0][ip], testData.phaseDensity[ip], relTol ); + checkRelativeError( phaseMassDensity[0][0][ip], testData.phaseMassDensity[ip], relTol ); + checkRelativeError( phaseViscosity[0][0][ip], testData.phaseViscosity[ip], relTol ); + checkRelativeError( phaseEnthalpy[0][0][ip], testData.phaseEnthalpy[ip], relTol ); + checkRelativeError( phaseInternalEnergy[0][0][ip], testData.phaseInternalEnergy[ip], relTol ); + } +} + +template< integer NUM_PHASE, integer NUM_COMP > +MultiFluidTestData< NUM_PHASE, NUM_COMP >::MultiFluidTestData( real64 const pressure_, + real64 const temperature_, + Feed< NUM_COMP > && composition_ ): + pressure( pressure_ ), + temperature( temperature_ ), + composition( composition_ ) +{} + +template< integer NUM_PHASE, integer NUM_COMP > +MultiFluidTestData< NUM_PHASE, NUM_COMP >::MultiFluidTestData( real64 const pressure_, + real64 const temperature_, + arraySlice1d< real64 const > const & composition_ ): + pressure( pressure_ ), + temperature( temperature_ ) +{ + copy< NUM_COMP >( composition_, composition ); +} + +template< integer NUM_PHASE, integer NUM_COMP > +MultiFluidTestData< NUM_PHASE, NUM_COMP >::MultiFluidTestData( real64 const pressure_, + real64 const temperature_, + Feed< NUM_COMP > && composition_, + real64 const totalDensity_, + Feed< NUM_PHASE > && phaseFraction_, + Feed< NUM_PHASE > && phaseDensity_, + Feed< NUM_PHASE > && phaseMassDensity_, + Feed< NUM_PHASE > && phaseViscosity_, + Feed< NUM_PHASE > && phaseEnthalpy_, + Feed< NUM_PHASE > && phaseInternalEnergy_ ): + pressure( pressure_ ), + temperature( temperature_ ), + composition( composition_ ), + totalDensity( totalDensity_ ), + phaseFraction( phaseFraction_ ), + phaseDensity( phaseDensity_ ), + phaseMassDensity( phaseMassDensity_ ), + phaseViscosity( phaseViscosity_ ), + phaseEnthalpy( phaseEnthalpy_ ), + phaseInternalEnergy( phaseInternalEnergy_ ) +{} + +template< integer N > +inline ::std::ostream & PrintTo( string const & name, Feed< N > const & data, ::std::ostream & os ) +{ + os << " \"" << name << "\": [ " << data[0]; + for( integer i = 1; i < N; i++ ) + { + os << ", " << data[i]; + } + os << " ]"; + return os; +} + +template< integer NUM_PHASE, integer NUM_COMP > +inline void PrintTo( MultiFluidTestData< NUM_PHASE, NUM_COMP > const & data, ::std::ostream *s ) +{ + std::ostream & os = *s; + + os << "{\n"; + os << " \"pressure\": " << data.pressure << ",\n"; + os << " \"temperature\": " << data.temperature << ",\n"; + PrintTo< NUM_COMP >( "composition", data.composition, os ) << ",\n"; + os << " \"totalDensity\": " << data.totalDensity << ",\n"; + PrintTo< NUM_PHASE >( "phaseFraction", data.phaseFraction, os ) << ",\n"; + PrintTo< NUM_PHASE >( "phaseDensity", data.phaseDensity, os ) << ",\n"; + PrintTo< NUM_PHASE >( "phaseMassDensity", data.phaseMassDensity, os ) << ",\n"; + PrintTo< NUM_PHASE >( "phaseViscosity", data.phaseViscosity, os ) << ",\n"; + PrintTo< NUM_PHASE >( "phaseEnthalpy", data.phaseEnthalpy, os ) << ",\n"; + PrintTo< NUM_PHASE >( "phaseInternalEnergy", data.phaseInternalEnergy, os ) << "\n"; + os << "}"; +} + +} // namespace testing + +} // namespace geos + +#endif //GEOS_UNITTESTS_CONSTITUTIVETESTS_MULTIFLUIDTEST_HPP_ diff --git a/src/coreComponents/unitTests/constitutiveTests/constitutiveTestHelpers.hpp b/src/coreComponents/unitTests/constitutiveTests/constitutiveTestHelpers.hpp index 2874dda757f..5762461edff 100644 --- a/src/coreComponents/unitTests/constitutiveTests/constitutiveTestHelpers.hpp +++ b/src/coreComponents/unitTests/constitutiveTests/constitutiveTestHelpers.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -21,7 +22,7 @@ #include "constitutive/capillaryPressure/capillaryPressureSelector.hpp" #include "functions/FunctionManager.hpp" #include "functions/TableFunction.hpp" -#include "unitTests/fluidFlowTests/testCompFlowUtils.hpp" +#include "unitTests/fluidFlowTests/testFlowUtils.hpp" // TPL includes #include diff --git a/src/coreComponents/unitTests/constitutiveTests/testCO2BrinePVTModels.cpp b/src/coreComponents/unitTests/constitutiveTests/testCO2BrinePVTModels.cpp index 723a30af1da..a686c917319 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testCO2BrinePVTModels.cpp +++ b/src/coreComponents/unitTests/constitutiveTests/testCO2BrinePVTModels.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -360,13 +361,18 @@ std::unique_ptr< MODEL > makePVTFunction( string const & filename, { array1d< string > const strs = stringutilities::tokenizeBySpaces< array1d >( str ); + TableFunction::OutputOptions const pvtOutputOpts = { + true,// writeCSV + true, // writeInLog + }; + if( strs.size()>1 && strs[0] == key ) { pvtFunction = std::make_unique< MODEL >( strs[1], strs, componentNames, componentMolarWeight, - true ); // print PVT tables + pvtOutputOpts ); } } GEOS_ERROR_IF( pvtFunction == nullptr, @@ -400,7 +406,10 @@ std::unique_ptr< MODEL > makeFlashModel( string const & filename, while( std::getline( is, str ) ) { array1d< string > const strs = stringutilities::tokenizeBySpaces< array1d >( str ); - + TableFunction::OutputOptions const flashOutputOpts = { + true, // writeCSV + true, // writeInLog + }; if( strs.size()>1 && strs[0] == key ) { flashModel = std::make_unique< MODEL >( strs[1], @@ -408,7 +417,7 @@ std::unique_ptr< MODEL > makeFlashModel( string const & filename, phaseNames, componentNames, componentMolarWeight, - true ); // print PVT tables + flashOutputOpts ); } } GEOS_ERROR_IF( flashModel == nullptr, diff --git a/src/coreComponents/unitTests/constitutiveTests/testCO2SpycherPruessModels.cpp b/src/coreComponents/unitTests/constitutiveTests/testCO2SpycherPruessModels.cpp new file mode 100644 index 00000000000..24214ecc6fa --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testCO2SpycherPruessModels.cpp @@ -0,0 +1,380 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// Source includes +#include "codingUtilities/UnitTestUtilities.hpp" +#include "constitutive/fluid/multifluid/CO2Brine/functions/CO2Solubility.hpp" +#include "constitutive/fluid/multifluid/MultiFluidUtils.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mainInterface/initialization.hpp" +#include "functions/FunctionManager.hpp" + +// TPL includes +#include + +using namespace geos; +using namespace geos::testing; +using namespace geos::stringutilities; +using namespace geos::constitutive; +using namespace geos::constitutive::multifluid; +using namespace geos::constitutive::PVTProps; + +// Test parameter +using TestParam = std::tuple< + real64 const, // Pressure [Pa] + real64 const, // Temperature [C] + real64 const, // Total co2 mole fraction (z_co2 = 1-z_wat) + real64 const, // Expected vapour fraction (V) + real64 const, // Expected dissolved CO2 fraction (x_co2) + real64 const // Expected vapourised water fraction (y_wat) + >; + +class CO2SolubilitySpycherPruessTestFixture : public ::testing::TestWithParam< TestParam > +{ +protected: + static integer constexpr numPhase = 2; + static integer constexpr numComp = 2; + static integer constexpr numDof = numComp + 2; + static real64 constexpr relTol = 1.0e-5; + static real64 constexpr absTol = 1.0e-7; + static real64 constexpr pertubation = 1.0e-6; + static constexpr char const * flashContent = "FlashModel CO2Solubility 1.0e5 1.0e7 9.9e5 283.15 383.15 10.0 0.15 1.0e-8 SpycherPruess"; + +public: + CO2SolubilitySpycherPruessTestFixture() = default; + ~CO2SolubilitySpycherPruessTestFixture() override = default; + +protected: + static std::unique_ptr< CO2Solubility > makeFlashModel( string const & fileContent ); +}; + +std::unique_ptr< CO2Solubility > +CO2SolubilitySpycherPruessTestFixture::makeFlashModel( string const & fileContent ) +{ + // Define phase names + string_array phaseNames; + phaseNames.resize( 2 ); + phaseNames[0] = "gas"; + phaseNames[1] = "liquid"; + + // Define component names and molar weight + string_array componentNames; + componentNames.resize( 2 ); + componentNames[0] = "co2"; + componentNames[1] = "water"; + + array1d< real64 > componentMolarWeight; + componentMolarWeight.resize( 2 ); + componentMolarWeight[0] = 44.0e-3; + componentMolarWeight[1] = 18.0e-3; + + // Read file parameters + array1d< string > const strs = stringutilities::tokenizeBySpaces< array1d >( fileContent ); + + TableFunction::OutputOptions const flashOutputOpts = { + false, // writeCSV + false, // writeInLog + }; + + return std::make_unique< CO2Solubility >( strs[1], + strs, + phaseNames, + componentNames, + componentMolarWeight, + flashOutputOpts ); +} + +TEST_P( CO2SolubilitySpycherPruessTestFixture, testExpectedValues ) +{ + auto flashModel = makeFlashModel( CO2SolubilitySpycherPruessTestFixture::flashContent ); + + auto [pressure, temperature, z_co2, expected_V, expected_x_co2, expected_y_wat] = GetParam(); + + StackArray< real64, 1, numComp > composition( 2 ); + composition[0] = z_co2; + composition[1] = 1.0 - z_co2; + + StackArray< real64, 3, numPhase, LAYOUT_PHASE > phaseFrac( 1, 1, numPhase ); + StackArray< real64, 4, numDof *numPhase, LAYOUT_PHASE_DC > dPhaseFrac( 1, 1, numPhase, numDof ); + MultiFluidVarSlice< real64, 1, USD_PHASE - 2, USD_PHASE_DC - 2 > + phaseFracAndDeriv { phaseFrac[0][0], dPhaseFrac[0][0] }; + + StackArray< real64, 4, numComp *numPhase, LAYOUT_PHASE_COMP > phaseCompFrac( 1, 1, numPhase, numComp ); + StackArray< real64, 5, numDof *numComp *numPhase, LAYOUT_PHASE_COMP_DC > dPhaseCompFrac( 1, 1, numPhase, numComp, numDof ); + MultiFluidVarSlice< real64, 2, USD_PHASE_COMP - 2, USD_PHASE_COMP_DC - 2 > + phaseCompFracAndDeriv { phaseCompFrac[0][0], dPhaseCompFrac[0][0] }; + + auto flashModelWrapper = flashModel->createKernelWrapper(); + + flashModelWrapper.compute( pressure, + temperature, + composition.toSliceConst(), + phaseFracAndDeriv, + phaseCompFracAndDeriv ); + + real64 const V = phaseFracAndDeriv.value[0]; + real64 const x_co2 = phaseCompFracAndDeriv.value[1][0]; + real64 const y_wat = phaseCompFracAndDeriv.value[0][1]; + + checkRelativeError( V, expected_V, relTol, absTol ); + checkRelativeError( x_co2, expected_x_co2, relTol, absTol ); + checkRelativeError( y_wat, expected_y_wat, relTol, absTol ); +} + +TEST_P( CO2SolubilitySpycherPruessTestFixture, testNumericalDerivatives ) +{ + using Deriv = multifluid::DerivativeOffset; + + auto flashModel = makeFlashModel( CO2SolubilitySpycherPruessTestFixture::flashContent ); + + auto [pressure, temperature, z_co2, expected_V, expected_x_co2, expected_y_wat] = GetParam(); + GEOS_UNUSED_VAR( expected_V, expected_x_co2, expected_y_wat ); + + StackArray< real64, 1, numComp > composition( numComp ); + composition[0] = z_co2; + composition[1] = 1.0 - z_co2; + StackArray< real64, 1, numComp > perturbedComposition( numComp ); + + StackArray< real64, 3, numPhase, LAYOUT_PHASE > phaseFrac( 1, 1, numPhase ); + StackArray< real64, 4, numDof *numPhase, LAYOUT_PHASE_DC > dPhaseFrac( 1, 1, numPhase, numDof ); + MultiFluidVarSlice< real64, 1, USD_PHASE - 2, USD_PHASE_DC - 2 > + phaseFracAndDeriv { phaseFrac[0][0], dPhaseFrac[0][0] }; + + StackArray< real64, 4, numComp *numPhase, LAYOUT_PHASE_COMP > phaseCompFrac( 1, 1, numPhase, numComp ); + StackArray< real64, 5, numDof *numComp *numPhase, LAYOUT_PHASE_COMP_DC > dPhaseCompFrac( 1, 1, numPhase, numComp, numDof ); + MultiFluidVarSlice< real64, 2, USD_PHASE_COMP - 2, USD_PHASE_COMP_DC - 2 > + phaseCompFracAndDeriv { phaseCompFrac[0][0], dPhaseCompFrac[0][0] }; + + // 1) First compute the unperturbed parameters + + auto flashModelWrapper = flashModel->createKernelWrapper(); + + flashModelWrapper.compute( pressure, + temperature, + composition.toSliceConst(), + phaseFracAndDeriv, + phaseCompFracAndDeriv ); + + StackArray< real64, 3, numPhase, LAYOUT_PHASE > perturbedPhaseFrac( 1, 1, numPhase ); + StackArray< real64, 4, numDof *numPhase, LAYOUT_PHASE_DC > dPerturbedPhaseFrac( 1, 1, numPhase, numDof ); + MultiFluidVarSlice< real64, 1, USD_PHASE - 2, USD_PHASE_DC - 2 > + perturbedPhaseFracAndDeriv { perturbedPhaseFrac[0][0], dPerturbedPhaseFrac[0][0] }; + + StackArray< real64, 4, numComp *numPhase, LAYOUT_PHASE_COMP > perturbedPhaseCompFrac( 1, 1, numPhase, numComp ); + StackArray< real64, 5, numDof *numComp *numPhase, LAYOUT_PHASE_COMP_DC > dPerturbedPhaseCompFrac( 1, 1, numPhase, numComp, numDof ); + MultiFluidVarSlice< real64, 2, USD_PHASE_COMP - 2, USD_PHASE_COMP_DC - 2 > + perturbedPhaseCompFracAndDeriv { perturbedPhaseCompFrac[0][0], dPerturbedPhaseCompFrac[0][0] }; + + real64 numericalDerivative = 0.0; + real64 analyticalDerivative = 0.0; + + // 2) Check derivative with respect to pressure + real64 const dP = pertubation * pressure; + flashModelWrapper.compute( pressure + dP, + temperature, + composition.toSliceConst(), + perturbedPhaseFracAndDeriv, + perturbedPhaseCompFracAndDeriv ); + + for( integer i = 0; i < numPhase; ++i ) + { + numericalDerivative = (perturbedPhaseFracAndDeriv.value[i]-phaseFracAndDeriv.value[i])/dP; + analyticalDerivative = perturbedPhaseFracAndDeriv.derivs[i][Deriv::dP]; + checkRelativeError( numericalDerivative, analyticalDerivative, relTol, absTol ); + for( integer j = 0; j < numComp; ++j ) + { + numericalDerivative = (perturbedPhaseCompFracAndDeriv.value[i][j]-phaseCompFracAndDeriv.value[i][j])/dP; + analyticalDerivative = perturbedPhaseCompFracAndDeriv.derivs[i][j][Deriv::dP]; + checkRelativeError( numericalDerivative, analyticalDerivative, relTol, absTol ); + } + } + + // 3) Check derivative with respect to temperature + real64 const dT = pertubation * temperature; + flashModelWrapper.compute( pressure, + temperature + dT, + composition.toSliceConst(), + perturbedPhaseFracAndDeriv, + perturbedPhaseCompFracAndDeriv ); + + for( integer i = 0; i < numPhase; ++i ) + { + numericalDerivative = (perturbedPhaseFracAndDeriv.value[i]-phaseFracAndDeriv.value[i])/dT; + analyticalDerivative = perturbedPhaseFracAndDeriv.derivs[i][Deriv::dT]; + checkRelativeError( numericalDerivative, analyticalDerivative, relTol, absTol ); + + for( integer j = 0; j < numComp; ++j ) + { + numericalDerivative = (perturbedPhaseCompFracAndDeriv.value[i][j]-phaseCompFracAndDeriv.value[i][j])/dT; + analyticalDerivative = perturbedPhaseCompFracAndDeriv.derivs[i][j][Deriv::dT]; + checkRelativeError( numericalDerivative, analyticalDerivative, relTol, absTol ); + } + } + + // 4) Check derivative with respect to composition + for( integer ic=0; ic < numComp; ++ic ) + { + real64 const dC = pertubation; + for( integer k=0; k < numComp; ++k ) + perturbedComposition[k] = composition[k]; + perturbedComposition[ic] += dC; + + flashModelWrapper.compute( pressure, + temperature, + perturbedComposition.toSliceConst(), + perturbedPhaseFracAndDeriv, + perturbedPhaseCompFracAndDeriv ); + + for( integer i = 0; i < numPhase; ++i ) + { + numericalDerivative = (perturbedPhaseFracAndDeriv.value[i]-phaseFracAndDeriv.value[i])/dC; + analyticalDerivative = perturbedPhaseFracAndDeriv.derivs[i][Deriv::dC+ic]; + checkRelativeError( numericalDerivative, analyticalDerivative, relTol, absTol ); + + for( integer j = 0; j < numComp; ++j ) + { + numericalDerivative = (perturbedPhaseCompFracAndDeriv.value[i][j]-phaseCompFracAndDeriv.value[i][j])/dC; + analyticalDerivative = perturbedPhaseCompFracAndDeriv.derivs[i][j][Deriv::dC+ic]; + checkRelativeError( numericalDerivative, analyticalDerivative, relTol, absTol ); + } + } + } +} + +// Test data +std::vector< TestParam > generateTestData() +{ + return { + {1.00000000e+05, 1.00000000e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+05, 5.00000000e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+05, 8.00000000e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+05, 1.10000000e+02, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+06, 1.00000000e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+06, 5.00000000e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+06, 8.00000000e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+06, 1.10000000e+02, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {5.00000000e+06, 1.00000000e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {5.00000000e+06, 5.00000000e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {5.00000000e+06, 8.00000000e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {5.00000000e+06, 1.10000000e+02, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+07, 1.00000000e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+07, 5.00000000e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+07, 8.00000000e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+07, 1.10000000e+02, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+08, 1.00000000e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+08, 5.00000000e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+08, 8.00000000e+01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+08, 1.10000000e+02, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+05, 1.00000000e+01, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {1.00000000e+05, 5.00000000e+01, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {1.00000000e+05, 8.00000000e+01, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {1.00000000e+05, 1.10000000e+02, 1.00000000e-05, 1.00000000e-05, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+06, 1.00000000e+01, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {1.00000000e+06, 5.00000000e+01, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {1.00000000e+06, 8.00000000e+01, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {1.00000000e+06, 1.10000000e+02, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {5.00000000e+06, 1.00000000e+01, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {5.00000000e+06, 5.00000000e+01, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {5.00000000e+06, 8.00000000e+01, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {5.00000000e+06, 1.10000000e+02, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {1.00000000e+07, 1.00000000e+01, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {1.00000000e+07, 5.00000000e+01, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {1.00000000e+07, 8.00000000e+01, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {1.00000000e+07, 1.10000000e+02, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {1.00000000e+08, 1.00000000e+01, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {1.00000000e+08, 5.00000000e+01, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {1.00000000e+08, 8.00000000e+01, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {1.00000000e+08, 1.10000000e+02, 1.00000000e-05, 0.00000000e+00, 1.00000000e-05, 0.00000000e+00}, + {1.00000000e+05, 1.00000000e+01, 3.00000000e-01, 3.03161030e-01, 8.58355906e-04, 1.23998968e-02}, + {1.00000000e+05, 5.00000000e+01, 3.00000000e-01, 3.42216891e-01, 3.10066097e-04, 1.23958952e-01}, + {1.00000000e+05, 8.00000000e+01, 3.00000000e-01, 5.66944658e-01, 1.24160030e-04, 4.70942662e-01}, + {1.00000000e+05, 1.10000000e+02, 3.00000000e-01, 3.00000000e-01, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+06, 1.00000000e+01, 3.00000000e-01, 2.94948990e-01, 8.11504677e-03, 2.27331474e-03}, + {1.00000000e+06, 5.00000000e+01, 3.00000000e-01, 3.04861076e-01, 3.32772200e-03, 2.35330303e-02}, + {1.00000000e+06, 8.00000000e+01, 3.00000000e-01, 3.35758987e-01, 2.14620607e-03, 1.10747849e-01}, + {1.00000000e+06, 1.10000000e+02, 3.00000000e-01, 3.40957999e-01, 1.62203194e-03, 1.23261476e-01}, + {5.00000000e+06, 1.00000000e+01, 3.00000000e-01, 2.79742151e-01, 2.89079228e-02, 2.01367187e-03}, + {5.00000000e+06, 5.00000000e+01, 3.00000000e-01, 2.91378214e-01, 1.36880088e-02, 3.69909366e-03}, + {5.00000000e+06, 8.00000000e+01, 3.00000000e-01, 2.97134400e-01, 9.51668603e-03, 1.28674138e-02}, + {5.00000000e+06, 1.10000000e+02, 3.00000000e-01, 3.05337535e-01, 8.04059852e-03, 3.57736478e-02}, + {1.00000000e+07, 1.00000000e+01, 3.00000000e-01, 2.78859111e-01, 3.01769401e-02, 2.22670319e-03}, + {1.00000000e+07, 5.00000000e+01, 3.00000000e-01, 2.86981820e-01, 1.98935606e-02, 4.06398711e-03}, + {1.00000000e+07, 8.00000000e+01, 3.00000000e-01, 2.91881746e-01, 1.54455782e-02, 9.65816584e-03}, + {1.00000000e+07, 1.10000000e+02, 3.00000000e-01, 2.97372350e-01, 1.38649677e-02, 2.39237441e-02}, + {1.00000000e+08, 1.00000000e+01, 3.00000000e-01, 2.78859111e-01, 3.01769401e-02, 2.22670319e-03}, + {1.00000000e+08, 5.00000000e+01, 3.00000000e-01, 2.86981820e-01, 1.98935606e-02, 4.06398711e-03}, + {1.00000000e+08, 8.00000000e+01, 3.00000000e-01, 2.91881746e-01, 1.54455782e-02, 9.65816584e-03}, + {1.00000000e+08, 1.10000000e+02, 3.00000000e-01, 2.97372350e-01, 1.38649677e-02, 2.39237441e-02}, + {1.00000000e+05, 1.00000000e+01, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {1.00000000e+05, 5.00000000e+01, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {1.00000000e+05, 8.00000000e+01, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {1.00000000e+05, 1.10000000e+02, 9.99990000e-01, 9.99990000e-01, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+06, 1.00000000e+01, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {1.00000000e+06, 5.00000000e+01, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {1.00000000e+06, 8.00000000e+01, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {1.00000000e+06, 1.10000000e+02, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {5.00000000e+06, 1.00000000e+01, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {5.00000000e+06, 5.00000000e+01, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {5.00000000e+06, 8.00000000e+01, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {5.00000000e+06, 1.10000000e+02, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {1.00000000e+07, 1.00000000e+01, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {1.00000000e+07, 5.00000000e+01, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {1.00000000e+07, 8.00000000e+01, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {1.00000000e+07, 1.10000000e+02, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {1.00000000e+08, 1.00000000e+01, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {1.00000000e+08, 5.00000000e+01, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {1.00000000e+08, 8.00000000e+01, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {1.00000000e+08, 1.10000000e+02, 9.99990000e-01, 1.00000000e+00, 0.00000000e+00, 1.00000000e-05}, + {1.00000000e+05, 1.00000000e+01, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+05, 5.00000000e+01, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+05, 8.00000000e+01, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+05, 1.10000000e+02, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+06, 1.00000000e+01, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+06, 5.00000000e+01, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+06, 8.00000000e+01, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+06, 1.10000000e+02, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {5.00000000e+06, 1.00000000e+01, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {5.00000000e+06, 5.00000000e+01, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {5.00000000e+06, 8.00000000e+01, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {5.00000000e+06, 1.10000000e+02, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+07, 1.00000000e+01, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+07, 5.00000000e+01, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+07, 8.00000000e+01, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+07, 1.10000000e+02, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+08, 1.00000000e+01, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+08, 5.00000000e+01, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+08, 8.00000000e+01, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00}, + {1.00000000e+08, 1.10000000e+02, 1.00000000e+00, 1.00000000e+00, 0.00000000e+00, 0.00000000e+00} + }; +} + +INSTANTIATE_TEST_SUITE_P( + CO2SolubilitySpycherPruessTest, + CO2SolubilitySpycherPruessTestFixture, + ::testing::ValuesIn( generateTestData() ) + ); + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + + geos::GeosxState state( geos::basicSetup( argc, argv ) ); + + int const result = RUN_ALL_TESTS(); + + geos::basicCleanup(); + + return result; +} diff --git a/src/coreComponents/unitTests/constitutiveTests/testCapillaryPressure.cpp b/src/coreComponents/unitTests/constitutiveTests/testCapillaryPressure.cpp index 01880c05e55..9d8d5ac3941 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testCapillaryPressure.cpp +++ b/src/coreComponents/unitTests/constitutiveTests/testCapillaryPressure.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -49,7 +50,7 @@ CapillaryPressureBase & makeBrooksCoreyCapPressureTwoPhase( string const & name, real64 & capPressureEpsilon = capPressure.getReference< real64 >( BrooksCoreyCapillaryPressure::viewKeyStruct::capPressureEpsilonString() ); capPressureEpsilon = 1e-4; - capPressure.postProcessInputRecursive(); + capPressure.postInputInitializationRecursive(); return capPressure; } @@ -78,7 +79,7 @@ CapillaryPressureBase & makeBrooksCoreyCapPressureThreePhase( string const & nam real64 & capPressureEpsilon = capPressure.getReference< real64 >( BrooksCoreyCapillaryPressure::viewKeyStruct::capPressureEpsilonString() ); capPressureEpsilon = 1e-7; - capPressure.postProcessInputRecursive(); + capPressure.postInputInitializationRecursive(); return capPressure; } @@ -108,7 +109,7 @@ CapillaryPressureBase & makeVanGenuchtenCapPressureTwoPhase( string const & name real64 & capPressureEpsilon = capPressure.getReference< real64 >( VanGenuchtenCapillaryPressure::viewKeyStruct::capPressureEpsilonString() ); capPressureEpsilon = 1e-4; - capPressure.postProcessInputRecursive(); + capPressure.postInputInitializationRecursive(); return capPressure; } @@ -137,7 +138,7 @@ CapillaryPressureBase & makeVanGenuchtenCapPressureThreePhase( string const & na real64 & capPressureEpsilon = capPressure.getReference< real64 >( VanGenuchtenCapillaryPressure::viewKeyStruct::capPressureEpsilonString() ); capPressureEpsilon = 1e-4; - capPressure.postProcessInputRecursive(); + capPressure.postInputInitializationRecursive(); return capPressure; } @@ -187,7 +188,7 @@ CapillaryPressureBase & makeTableCapPressureTwoPhase( string const & name, Group auto & waterTableName = capPressure.getReference< string >( TableCapillaryPressure::viewKeyStruct::wettingNonWettingCapPresTableNameString() ); waterTableName = "water_pc"; - capPressure.postProcessInputRecursive(); + capPressure.postInputInitializationRecursive(); capPressure.initialize(); // to test all the checks return capPressure; } @@ -270,7 +271,7 @@ CapillaryPressureBase & makeTableCapPressureThreePhase( string const & name, Gro auto & gasTableName = capPressure.getReference< string >( TableCapillaryPressure::viewKeyStruct::nonWettingIntermediateCapPresTableNameString() ); gasTableName = "gas_og_pc"; - capPressure.postProcessInputRecursive(); + capPressure.postInputInitializationRecursive(); capPressure.initialize(); // to test all the checks return capPressure; } @@ -338,7 +339,7 @@ CapillaryPressureBase & makeJFunctionCapPressureTwoPhase( string const & name, G capPressure.getReference< JFunctionCapillaryPressure::PermeabilityDirection >( JFunctionCapillaryPressure::viewKeyStruct::permeabilityDirectionString() ); permeabilityDirection = JFunctionCapillaryPressure::PermeabilityDirection::XY; - capPressure.postProcessInputRecursive(); + capPressure.postInputInitializationRecursive(); capPressure.initialize(); // to test all the checks return capPressure; @@ -432,7 +433,7 @@ CapillaryPressureBase & makeJFunctionCapPressureThreePhase( string const & name, capPressure.getReference< JFunctionCapillaryPressure::PermeabilityDirection >( JFunctionCapillaryPressure::viewKeyStruct::permeabilityDirectionString() ); permeabilityDirection = JFunctionCapillaryPressure::PermeabilityDirection::Z; - capPressure.postProcessInputRecursive(); + capPressure.postInputInitializationRecursive(); capPressure.initialize(); // to test all the checks return capPressure; } diff --git a/src/coreComponents/unitTests/constitutiveTests/testDamage.cpp b/src/coreComponents/unitTests/constitutiveTests/testDamage.cpp index 972449c8b96..28f85106fc5 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testDamage.cpp +++ b/src/coreComponents/unitTests/constitutiveTests/testDamage.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -56,7 +57,7 @@ TEST( DamageTests, testDamageSpectral ) xmlWrapper::xmlNode xmlConstitutiveNode = xmlDocument.getChild( "Constitutive" ); constitutiveManager.processInputFileRecursive( xmlDocument, xmlConstitutiveNode ); - constitutiveManager.postProcessInputRecursive(); + constitutiveManager.postInputInitializationRecursive(); localIndex constexpr numElem = 2; localIndex constexpr numQuad = 4; diff --git a/src/coreComponents/unitTests/constitutiveTests/testMultiFluid.cpp b/src/coreComponents/unitTests/constitutiveTests/testMultiFluid.cpp deleted file mode 100644 index 2297aaba3f3..00000000000 --- a/src/coreComponents/unitTests/constitutiveTests/testMultiFluid.cpp +++ /dev/null @@ -1,1173 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -// Source includes -#include "common/DataTypes.hpp" -#include "common/TimingMacros.hpp" -#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" -#include "constitutive/fluid/multifluid/MultiFluidSelector.hpp" -#include "constitutive/fluid/multifluid/MultiFluidUtils.hpp" -#include "unitTests/fluidFlowTests/testCompFlowUtils.hpp" -#include "mainInterface/initialization.hpp" -#include "functions/FunctionManager.hpp" -#include "mainInterface/GeosxState.hpp" - -// TPL includes -#include -#include - -using namespace geos; -using namespace geos::testing; -using namespace geos::constitutive; -using namespace geos::constitutive::multifluid; -using namespace geos::dataRepository; -using namespace geos::constitutive::PVTProps; - -/// Black-oil tables written into temporary files during testing - -static const char * pvtoTableContent = "# Rs[sm3/sm3]\tPbub[Pa]\tBo[m3/sm3]\tVisc(Pa.s)\n" - "\n" - " 2\t 2000000\t 1.02\t 0.000975\n" - " 5\t 5000000\t 1.03\t 0.00091\n" - " 10\t 10000000\t1.04\t 0.00083\n" - " 15\t 20000000\t1.05\t 0.000695\n" - " 90000000\t1.03\t 0.000985 -- some line comment\n" - " 30\t 30000000\t1.07\t 0.000594\n" - " 40\t 40000000\t1.08\t 0.00051\n" - " 50000000\t1.07\t 0.000549 -- another one\n" - " 90000000\t1.06\t 0.00074\n" - " 50\t 50000000.7\t1.09\t 0.000449\n" - " 90000000.7\t1.08\t 0.000605"; - -static const char * pvtwTableContent = "#\tPref[Pa]\tBw[m3/sm3]\tCp[1/Pa]\t Visc[Pa.s]\n" - "\t30600000.1\t1.03\t\t0.00000000041\t0.0003"; - -/// Dead-oil tables written into temporary files during testing - -static const char * pvdgTableContent = "# Pg(Pa) Bg(m3/sm3) Visc(Pa.s)\n" - "3000000 0.04234 0.00001344\n" - "6000000 0.02046 0.0000142\n" - "9000000 0.01328 0.00001526\n" - "12000000 0.00977 0.0000166\n" - "15000000 0.00773 0.00001818\n" - "18000000 0.006426 0.00001994\n" - "21000000 0.005541 0.00002181\n" - "24000000 0.004919 0.0000237\n" - "27000000 0.004471 0.00002559\n" - "29500000 0.004194 0.00002714\n" - "31000000 0.004031 0.00002806\n" - "33000000 0.00391 0.00002832\n" - "53000000 0.003868 0.00002935"; - -static const char * pvdoTableContent = "#P[Pa] Bo[m3/sm3] Visc(Pa.s)\n" - "10000000.0 1.23331 0.00015674\n" - "12500000.0 1.21987 0.00016570\n" - "15000000.0 1.20802 0.00017445\n" - "20000000.0 1.18791 0.00019143\n" - "25000000.0 1.17137 0.00020779\n" - "30000000.0 1.15742 0.00022361\n" - "33200000.3 1.14946 0.00023359\n" - "35000000.0 1.14543 0.00023894\n" - "40000000.0 1.13498 0.00025383\n" - "50000000.0 1.11753 0.00028237\n" - "60000000.0 1.10346 0.00030941\n" - "70000000.0 1.09180 0.00033506\n" - "80000000.0 1.08194 0.00035945\n" - "90000000.0 1.07347 0.00038266\n" - "95000000.0 1.06966 0.00039384\n" - "100000000.0 1.06610 0.00040476\n" - "110000000.0 1.05961 0.00042584\n" - "112500000.0 1.05811 0.00043096\n" - "115000000.0 1.05665 0.00043602\n" - "117500000.0 1.05523 0.00044102\n" - "120000000.0 1.05385 0.00044596\n"; - -static const char * pvdwTableContent = "# Pref[Pa] Bw[m3/sm3] Cp[1/Pa] Visc[Pa.s]\n" - " 30600000.1 1.03 0.00000000041 0.0003"; - -// CO2-brine model - -static const char * pvtLiquidPhillipsTableContent = "DensityFun PhillipsBrineDensity 1e6 1.5e7 5e4 367.15 369.15 1 0.2\n" - "ViscosityFun PhillipsBrineViscosity 0.1"; - -// the last are set relatively high (1e-4) to increase derivative value and check it properly -static const char * pvtLiquidEzrokhiTableContent = "DensityFun EzrokhiBrineDensity 2.01e-6 -6.34e-7 1e-4\n" - "ViscosityFun EzrokhiBrineViscosity 2.42e-7 0 1e-4"; - -static const char * pvtGasTableContent = "DensityFun SpanWagnerCO2Density 1e6 1.5e7 5e4 367.15 369.15 1\n" - "ViscosityFun FenghourCO2Viscosity 1e6 1.5e7 5e4 367.15 369.15 1"; - -static const char * co2FlashTableContent = "FlashModel CO2Solubility 1e6 1.5e7 5e4 367.15 369.15 1 0.15"; - -void testNumericalDerivatives( MultiFluidBase & fluid, - Group & parent, - real64 const P, - real64 const T, - arraySlice1d< real64 > const & compositionInput, - real64 const perturbParameter, - bool usePVTPackage, - real64 const relTol, - real64 const absTol = std::numeric_limits< real64 >::max() ) -{ - using Deriv = multifluid::DerivativeOffset; - - integer const NC = fluid.numFluidComponents(); - integer const NP = fluid.numFluidPhases(); - integer const NDOF = NC+2; - - // Copy input values into an array with expected layout - array2d< real64, compflow::LAYOUT_COMP > compositionValues( 1, NC ); - for( integer i = 0; i < NC; ++i ) - { - compositionValues[0][i] = compositionInput[i]; - } - arraySlice1d< real64 const, compflow::USD_COMP - 1 > const composition = compositionValues[0]; - - auto const & components = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::componentNamesString() ); - auto const & phases = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::phaseNamesString() ); - - // create a clone of the fluid to run updates on - std::unique_ptr< ConstitutiveBase > fluidCopyPtr = fluid.deliverClone( "fluidCopy", &parent ); - MultiFluidBase & fluidCopy = dynamicCast< MultiFluidBase & >( *fluidCopyPtr ); - - fluid.allocateConstitutiveData( fluid.getParent(), 1 ); - fluidCopy.allocateConstitutiveData( fluid.getParent(), 1 ); - - // extract data views from both fluids - #define GET_FLUID_DATA( FLUID, TRAIT ) \ - FLUID.getReference< TRAIT::type >( TRAIT::key() )[0][0] - - MultiFluidVarSlice< real64, 1, USD_PHASE - 2, USD_PHASE_DC - 2 > phaseFrac { - GET_FLUID_DATA( fluid, fields::multifluid::phaseFraction ), - GET_FLUID_DATA( fluid, fields::multifluid::dPhaseFraction ) - }; - - MultiFluidVarSlice< real64, 1, USD_PHASE - 2, USD_PHASE_DC - 2 > phaseDens { - GET_FLUID_DATA( fluid, fields::multifluid::phaseDensity ), - GET_FLUID_DATA( fluid, fields::multifluid::dPhaseDensity ) - }; - - MultiFluidVarSlice< real64, 1, USD_PHASE - 2, USD_PHASE_DC - 2 > phaseVisc { - GET_FLUID_DATA( fluid, fields::multifluid::phaseViscosity ), - GET_FLUID_DATA( fluid, fields::multifluid::dPhaseViscosity ) - }; - - MultiFluidVarSlice< real64, 2, USD_PHASE_COMP - 2, USD_PHASE_COMP_DC - 2 > phaseCompFrac { - GET_FLUID_DATA( fluid, fields::multifluid::phaseCompFraction ), - GET_FLUID_DATA( fluid, fields::multifluid::dPhaseCompFraction ) - }; - - MultiFluidVarSlice< real64, 0, USD_FLUID - 2, USD_FLUID_DC - 2 > totalDens { - GET_FLUID_DATA( fluid, fields::multifluid::totalDensity ), - GET_FLUID_DATA( fluid, fields::multifluid::dTotalDensity ) - }; - - auto const & phaseFracCopy = GET_FLUID_DATA( fluidCopy, fields::multifluid::phaseFraction ); - auto const & phaseDensCopy = GET_FLUID_DATA( fluidCopy, fields::multifluid::phaseDensity ); - auto const & phaseViscCopy = GET_FLUID_DATA( fluidCopy, fields::multifluid::phaseViscosity ); - auto const & phaseCompFracCopy = GET_FLUID_DATA( fluidCopy, fields::multifluid::phaseCompFraction ); - auto const & totalDensCopy = GET_FLUID_DATA( fluidCopy, fields::multifluid::totalDensity ); - -#undef GET_FLUID_DATA - - // set the original fluid state to current - constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) - { - typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - fluidWrapper.update( 0, 0, P, T, composition ); - } ); - - // now perturb variables and update the copied fluid's state - constitutive::constitutiveUpdatePassThru( fluidCopy, [&] ( auto & castedFluid ) - { - typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - - // to be able to use the checkDerivative utility function, we have to invert the layout - auto dPhaseFrac = invertLayout( phaseFrac.derivs.toSliceConst(), NP, NDOF ); - auto dPhaseDens = invertLayout( phaseDens.derivs.toSliceConst(), NP, NDOF ); - auto dPhaseVisc = invertLayout( phaseVisc.derivs.toSliceConst(), NP, NDOF ); - auto dTotalDens = invertLayout( totalDens.derivs.toSliceConst(), NDOF ); - auto dPhaseCompFrac = invertLayout( phaseCompFrac.derivs.toSliceConst(), NP, NC, NDOF ); - - // update pressure and check derivatives - { - real64 const dP = perturbParameter * (P + perturbParameter); - fluidWrapper.update( 0, 0, P + dP, T, composition ); - - checkDerivative( phaseFracCopy.toSliceConst(), phaseFrac.value.toSliceConst(), dPhaseFrac[Deriv::dP].toSliceConst(), - dP, relTol, absTol, "phaseFrac", "Pres", phases ); - checkDerivative( phaseDensCopy.toSliceConst(), phaseDens.value.toSliceConst(), dPhaseDens[Deriv::dP].toSliceConst(), - dP, relTol, absTol, "phaseDens", "Pres", phases ); - checkDerivative( phaseViscCopy.toSliceConst(), phaseVisc.value.toSliceConst(), dPhaseVisc[Deriv::dP].toSliceConst(), - dP, relTol, absTol, "phaseVisc", "Pres", phases ); - checkDerivative( totalDensCopy, totalDens.value, dTotalDens[Deriv::dP], - dP, relTol, absTol, "totalDens", "Pres" ); - checkDerivative( phaseCompFracCopy.toSliceConst(), phaseCompFrac.value.toSliceConst(), dPhaseCompFrac[Deriv::dP].toSliceConst(), - dP, relTol, absTol, "phaseCompFrac", "Pres", phases, components ); - } - - // update temperature and check derivatives - { - real64 const dT = perturbParameter * (T + perturbParameter); - fluidWrapper.update( 0, 0, P, T + dT, composition ); - - checkDerivative( phaseFracCopy.toSliceConst(), phaseFrac.value.toSliceConst(), dPhaseFrac[Deriv::dT].toSliceConst(), - dT, relTol, absTol, "phaseFrac", "Temp", phases ); - checkDerivative( phaseDensCopy.toSliceConst(), phaseDens.value.toSliceConst(), dPhaseDens[Deriv::dT].toSliceConst(), - dT, relTol, absTol, "phaseDens", "Temp", phases ); - checkDerivative( phaseViscCopy.toSliceConst(), phaseVisc.value.toSliceConst(), dPhaseVisc[Deriv::dT].toSliceConst(), - dT, relTol, absTol, "phaseVisc", "Temp", phases ); - checkDerivative( totalDensCopy, totalDens.value, dTotalDens[Deriv::dT], - dT, relTol, absTol, "totalDens", "Temp" ); - checkDerivative( phaseCompFracCopy.toSliceConst(), phaseCompFrac.value.toSliceConst(), dPhaseCompFrac[Deriv::dT].toSliceConst(), - dT, relTol, absTol, "phaseCompFrac", "Temp", phases, components ); - } - - array2d< real64, compflow::LAYOUT_COMP > compNew( 1, NC ); - for( integer jc = 0; jc < NC; ++jc ) - { - real64 const dC = perturbParameter * ( composition[jc] + perturbParameter ); - for( integer ic = 0; ic < NC; ++ic ) - { - compNew[0][ic] = composition[ic]; - } - compNew[0][jc] += dC; - - // Note: in PVTPackage, derivatives are obtained with finite-difference approx **with normalization of the comp fraction** - // The component fraction is perturbed (just as above), and then all the component fractions are normalized (as below) - // But, in the native DO model and in CO2BrinePhillips, derivatives are computed analytically, which results in different - // derivatives wrt component fractions--although the derivatives wrt component densities obtained with the chain rule - // in the solver will be very similar (see discussion on PR #1325 on GitHub). - // - // Since both approaches--FD approximation of derivatives with normalization, and analytical derivatives--are correct, - // we have to support both when we check the intermediate derivatives wrt component fractions below. Therefore, if the - // PVTPackage is used, then we normalize the perturbed component fractions before taking the FD approx. If the native - // DO or CO2-brine models are used, we skip the normalization below. - if( usePVTPackage ) - { - // renormalize - real64 sum = 0.0; - for( integer ic = 0; ic < NC; ++ic ) - { - sum += compNew[0][ic]; - } - for( integer ic = 0; ic < NC; ++ic ) - { - compNew[0][ic] /= sum; - } - } - - fluidWrapper.update( 0, 0, P, T, compNew[0] ); - - string const var = "compFrac[" + components[jc] + "]"; - checkDerivative( phaseFracCopy.toSliceConst(), phaseFrac.value.toSliceConst(), dPhaseFrac[Deriv::dC+jc].toSliceConst(), - dC, relTol, absTol, "phaseFrac", var, phases ); - checkDerivative( phaseDensCopy.toSliceConst(), phaseDens.value.toSliceConst(), dPhaseDens[Deriv::dC+jc].toSliceConst(), - dC, relTol, absTol, "phaseDens", var, phases ); - checkDerivative( phaseViscCopy.toSliceConst(), phaseVisc.value.toSliceConst(), dPhaseVisc[Deriv::dC+jc].toSliceConst(), - dC, relTol, absTol, "phaseVisc", var, phases ); - checkDerivative( totalDensCopy, totalDens.value, dTotalDens[Deriv::dC+jc], - dC, relTol, absTol, "totalDens", var ); - checkDerivative( phaseCompFracCopy.toSliceConst(), phaseCompFrac.value.toSliceConst(), dPhaseCompFrac[Deriv::dC+jc].toSliceConst(), - dC, relTol, absTol, "phaseCompFrac", var, phases, components ); - } - } ); -} - -void testValuesAgainstPreviousImplementation( CO2BrinePhillipsFluid::KernelWrapper const & wrapper, - real64 const P, - real64 const T, - arraySlice1d< real64 const > const & compositionInput, - real64 const & savedTotalDensity, - real64 const & savedGasPhaseFrac, - real64 const & savedWaterDens, - real64 const & savedGasDens, - real64 const & savedWaterMassDens, - real64 const & savedGasMassDens, - real64 const & savedWaterVisc, - real64 const & savedGasVisc, - real64 const & savedWaterPhaseGasComp, - real64 const & savedWaterPhaseWaterComp, - real64 const relTol ) -{ - integer constexpr numPhase = 2; - integer constexpr numComp = 2; - integer constexpr numDof = numComp + 2; - - // Copy input values into an array with expected layout - array2d< real64, compflow::LAYOUT_COMP > compositionValues( 1, numComp ); - for( integer i = 0; i < numComp; ++i ) - { - compositionValues[0][i] = compositionInput[i]; - } - arraySlice1d< real64 const, compflow::USD_COMP - 1 > const composition = compositionValues[0]; - - StackArray< real64, 3, numPhase, LAYOUT_PHASE > phaseFraction( 1, 1, numPhase ); - StackArray< real64, 4, numDof *numPhase, LAYOUT_PHASE_DC > dPhaseFraction( 1, 1, numPhase, numDof ); - StackArray< real64, 3, numPhase, LAYOUT_PHASE > phaseDensity( 1, 1, numPhase ); - StackArray< real64, 4, numDof *numPhase, LAYOUT_PHASE_DC > dPhaseDensity( 1, 1, numPhase, numDof ); - StackArray< real64, 3, numPhase, LAYOUT_PHASE > phaseMassDensity( 1, 1, numPhase ); - StackArray< real64, 4, numDof *numPhase, LAYOUT_PHASE_DC > dPhaseMassDensity( 1, 1, numPhase, numDof ); - StackArray< real64, 3, numPhase, LAYOUT_PHASE > phaseViscosity( 1, 1, numPhase ); - StackArray< real64, 4, numDof *numPhase, LAYOUT_PHASE_DC > dPhaseViscosity( 1, 1, numPhase, numDof ); - StackArray< real64, 3, numPhase, LAYOUT_PHASE > phaseEnthalpy( 1, 1, numPhase ); - StackArray< real64, 4, numDof *numPhase, LAYOUT_PHASE_DC > dPhaseEnthalpy( 1, 1, numPhase, numDof ); - StackArray< real64, 3, numPhase, LAYOUT_PHASE > phaseInternalEnergy( 1, 1, numPhase ); - StackArray< real64, 4, numDof *numPhase, LAYOUT_PHASE_DC > dPhaseInternalEnergy( 1, 1, numPhase, numDof ); - StackArray< real64, 4, numComp *numPhase, LAYOUT_PHASE_COMP > phaseCompFraction( 1, 1, numPhase, numComp ); - StackArray< real64, 5, numDof *numComp *numPhase, LAYOUT_PHASE_COMP_DC > dPhaseCompFraction( 1, 1, numPhase, numComp, numDof ); - StackArray< real64, 2, 1, LAYOUT_FLUID > totalDensity( 1, 1 ); - StackArray< real64, 3, numDof, LAYOUT_FLUID_DC > dTotalDensity( 1, 1, numDof ); - - wrapper.compute( P, T, composition, - { - phaseFraction[0][0], - dPhaseFraction[0][0] - }, - { - phaseDensity[0][0], - dPhaseDensity[0][0] - }, - { - phaseMassDensity[0][0], - dPhaseMassDensity[0][0] - }, - { - phaseViscosity[0][0], - dPhaseViscosity[0][0] - }, - { - phaseEnthalpy[0][0], - dPhaseEnthalpy[0][0] - }, - { - phaseInternalEnergy[0][0], - dPhaseInternalEnergy[0][0] - }, - { - phaseCompFraction[0][0], - dPhaseCompFraction[0][0] - }, - { - totalDensity[0][0], - dTotalDensity[0][0] - } ); - - checkRelativeError( totalDensity[0][0], savedTotalDensity, relTol ); - for( integer ip = 0; ip < numPhase; ++ip ) - { - real64 const savedPhaseFrac = ( ip == 0 ) ? savedGasPhaseFrac : 1 - savedGasPhaseFrac; - checkRelativeError( phaseFraction[0][0][ip], savedPhaseFrac, relTol ); - real64 const savedPhaseDens = ( ip == 0 ) ? savedGasDens : savedWaterDens; - checkRelativeError( phaseDensity[0][0][ip], savedPhaseDens, relTol ); - real64 const savedPhaseMassDens = ( ip == 0 ) ? savedGasMassDens : savedWaterMassDens; - checkRelativeError( phaseMassDensity[0][0][ip], savedPhaseMassDens, relTol ); - real64 const savedPhaseVisc = ( ip == 0 ) ? savedGasVisc : savedWaterVisc; - checkRelativeError( phaseViscosity[0][0][ip], savedPhaseVisc, relTol ); - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 savedCompFrac = 0.0; - if( ip == 0 ) - { - savedCompFrac = ( ic == 0 ) ? 1 : 0; - } - else - { - savedCompFrac = ( ic == 0 ) ? savedWaterPhaseGasComp : savedWaterPhaseWaterComp; - } - checkRelativeError( phaseCompFraction[0][0][ip][ic], savedCompFrac, relTol ); - } - } -} - -MultiFluidBase & makeCompositionalFluid( string const & name, Group & parent ) -{ - CompositionalMultiphaseFluidPVTPackage & fluid = parent.registerGroup< CompositionalMultiphaseFluidPVTPackage >( name ); - - // TODO we should actually create a fake XML node with data, but this seemed easier... - - auto & compNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::componentNamesString() ); - compNames.resize( 4 ); - compNames[0] = "N2"; compNames[1] = "C10"; compNames[2] = "C20"; compNames[3] = "H20"; - - auto & molarWgt = fluid.getReference< array1d< real64 > >( MultiFluidBase::viewKeyStruct::componentMolarWeightString() ); - molarWgt.resize( 4 ); - molarWgt[0] = 28e-3; molarWgt[1] = 134e-3; molarWgt[2] = 275e-3; molarWgt[3] = 18e-3; - - auto & phaseNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::phaseNamesString() ); - phaseNames.resize( 2 ); - phaseNames[0] = "oil"; phaseNames[1] = "gas"; - - auto & eqnOfState = fluid.getReference< string_array >( CompositionalMultiphaseFluidPVTPackage::viewKeyStruct::equationsOfStateString() ); - eqnOfState.resize( 2 ); - eqnOfState[0] = "PR"; eqnOfState[1] = "PR"; - - auto & critPres = fluid.getReference< array1d< real64 > >( CompositionalMultiphaseFluidPVTPackage::viewKeyStruct::componentCriticalPressureString() ); - critPres.resize( 4 ); - critPres[0] = 34e5; critPres[1] = 25.3e5; critPres[2] = 14.6e5; critPres[3] = 220.5e5; - - auto & critTemp = fluid.getReference< array1d< real64 > >( CompositionalMultiphaseFluidPVTPackage::viewKeyStruct::componentCriticalTemperatureString() ); - critTemp.resize( 4 ); - critTemp[0] = 126.2; critTemp[1] = 622.0; critTemp[2] = 782.0; critTemp[3] = 647.0; - - auto & acFactor = fluid.getReference< array1d< real64 > >( CompositionalMultiphaseFluidPVTPackage::viewKeyStruct::componentAcentricFactorString() ); - acFactor.resize( 4 ); - acFactor[0] = 0.04; acFactor[1] = 0.443; acFactor[2] = 0.816; acFactor[3] = 0.344; - - fluid.postProcessInputRecursive(); - return fluid; -} - -class CompositionalFluidTestBase : public ::testing::Test -{ -public: - CompositionalFluidTestBase(): - node(), - parent( "parent", node ) - {} - -protected: - conduit::Node node; - Group parent; - MultiFluidBase * fluid; -}; - -class CompositionalFluidTest : public CompositionalFluidTestBase -{ -public: - CompositionalFluidTest() - { - parent.resize( 1 ); - fluid = &makeCompositionalFluid( "fluid", parent ); - - parent.initialize(); - parent.initializePostInitialConditions(); - } -}; - -TEST_F( CompositionalFluidTest, numericalDerivativesMolar ) -{ - fluid->setMassFlag( false ); - - // TODO test over a range of values - real64 const P = 5e6; - real64 const T = 297.15; - array1d< real64 > comp( 4 ); - comp[0] = 0.099; comp[1] = 0.3; comp[2] = 0.6; comp[3] = 0.001; - - real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); - real64 const relTol = 1e-4; - - testNumericalDerivatives( *fluid, parent, P, T, comp, eps, true, relTol ); -} - -TEST_F( CompositionalFluidTest, numericalDerivativesMass ) -{ - fluid->setMassFlag( true ); - - // TODO test over a range of values - real64 const P = 5e6; - real64 const T = 297.15; - array1d< real64 > comp( 4 ); - comp[0] = 0.099; comp[1] = 0.3; comp[2] = 0.6; comp[3] = 0.001; - - real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); - real64 const relTol = 1e-2; - - testNumericalDerivatives( *fluid, parent, P, T, comp, eps, true, relTol ); -} - -MultiFluidBase & makeLiveOilFluid( string const & name, Group * parent ) -{ - BlackOilFluid & fluid = parent->registerGroup< BlackOilFluid >( name ); - - string_array & compNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::componentNamesString() ); - compNames.resize( 3 ); - compNames[0] = "oil"; compNames[1] = "gas"; compNames[2] = "water"; - - array1d< real64 > & molarWgt = fluid.getReference< array1d< real64 > >( MultiFluidBase::viewKeyStruct::componentMolarWeightString() ); - molarWgt.resize( 3 ); - molarWgt[0] = 114e-3; molarWgt[1] = 16e-3; molarWgt[2] = 18e-3; - - string_array & phaseNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::phaseNamesString() ); - phaseNames.resize( 3 ); - phaseNames[0] = "oil"; phaseNames[1] = "gas"; phaseNames[2] = "water"; - - array1d< real64 > & surfaceDens = fluid.getReference< array1d< real64 > >( BlackOilFluidBase::viewKeyStruct::surfacePhaseMassDensitiesString() ); - surfaceDens.resize( 3 ); - surfaceDens[0] = 800.0; surfaceDens[1] = 0.9907; surfaceDens[2] = 1022.0; - - path_array & tableNames = fluid.getReference< path_array >( BlackOilFluidBase::viewKeyStruct::tableFilesString() ); - tableNames.resize( 3 ); - tableNames[0] = "pvto.txt"; tableNames[1] = "pvdg.txt"; tableNames[2] = "pvtw.txt"; - - fluid.postProcessInputRecursive(); - return fluid; -} - -MultiFluidBase & makeDeadOilFluid( string const & name, Group * parent ) -{ - DeadOilFluid & fluid = parent->registerGroup< DeadOilFluid >( name ); - - string_array & compNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::componentNamesString() ); - compNames.resize( 3 ); - compNames[0] = "oil"; compNames[1] = "water"; compNames[2] = "gas"; - - array1d< real64 > & molarWgt = fluid.getReference< array1d< real64 > >( MultiFluidBase::viewKeyStruct::componentMolarWeightString() ); - molarWgt.resize( 3 ); - molarWgt[0] = 114e-3; molarWgt[1] = 16e-3; molarWgt[2] = 18e-3; - - string_array & phaseNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::phaseNamesString() ); - phaseNames.resize( 3 ); - phaseNames[0] = "oil"; phaseNames[1] = "water"; phaseNames[2] = "gas"; - - array1d< real64 > & surfaceDens = fluid.getReference< array1d< real64 > >( BlackOilFluidBase::viewKeyStruct::surfacePhaseMassDensitiesString() ); - surfaceDens.resize( 3 ); - surfaceDens[0] = 800.0; surfaceDens[1] = 1022.0; surfaceDens[2] = 0.9907; - - path_array & tableNames = fluid.getReference< path_array >( BlackOilFluidBase::viewKeyStruct::tableFilesString() ); - tableNames.resize( 3 ); - tableNames[0] = "pvdo.txt"; tableNames[1] = "pvdw.txt"; tableNames[2] = "pvdg.txt"; - - fluid.postProcessInputRecursive(); - return fluid; -} - -MultiFluidBase & makeDeadOilFluidFromTable( string const & name, Group * parent ) -{ - FunctionManager & functionManager = FunctionManager::getInstance(); - - // 1) First, define the tables (PVDO, PVDG) - - // 1D table with linear interpolation - integer const NaxisPVDO = 21; - integer const NaxisPVDG = 13; - - array1d< real64_array > coordinatesPVDO; - real64_array valuesPVDO_Bo( NaxisPVDO ); - real64_array valuesPVDO_visc( NaxisPVDO ); - coordinatesPVDO.resize( 1 ); - coordinatesPVDO[0].resize( NaxisPVDO ); - coordinatesPVDO[0][0] = 10000000.0; valuesPVDO_Bo[0] = 1.23331; valuesPVDO_visc[0] = 0.00015674; - coordinatesPVDO[0][1] = 12500000.0; valuesPVDO_Bo[1] = 1.21987; valuesPVDO_visc[1] = 0.00016570; - coordinatesPVDO[0][2] = 15000000.0; valuesPVDO_Bo[2] = 1.20802; valuesPVDO_visc[2] = 0.00017445; - coordinatesPVDO[0][3] = 20000000.0; valuesPVDO_Bo[3] = 1.18791; valuesPVDO_visc[3] = 0.00019143; - coordinatesPVDO[0][4] = 25000000.0; valuesPVDO_Bo[4] = 1.17137; valuesPVDO_visc[4] = 0.00020779; - coordinatesPVDO[0][5] = 30000000.0; valuesPVDO_Bo[5] = 1.15742; valuesPVDO_visc[5] = 0.00022361; - coordinatesPVDO[0][6] = 33200000.3; valuesPVDO_Bo[6] = 1.14946; valuesPVDO_visc[6] = 0.00023359; - coordinatesPVDO[0][7] = 35000000.0; valuesPVDO_Bo[7] = 1.14543; valuesPVDO_visc[7] = 0.00023894; - coordinatesPVDO[0][8] = 40000000.0; valuesPVDO_Bo[8] = 1.13498; valuesPVDO_visc[8] = 0.00025383; - coordinatesPVDO[0][9] = 50000000.0; valuesPVDO_Bo[9] = 1.11753; valuesPVDO_visc[9] = 0.00028237; - coordinatesPVDO[0][10] = 60000000.0; valuesPVDO_Bo[10] = 1.10346; valuesPVDO_visc[10] = 0.00030941; - coordinatesPVDO[0][11] = 70000000.0; valuesPVDO_Bo[11] = 1.09180; valuesPVDO_visc[11] = 0.00033506; - coordinatesPVDO[0][12] = 80000000.0; valuesPVDO_Bo[12] = 1.08194; valuesPVDO_visc[12] = 0.00035945; - coordinatesPVDO[0][13] = 90000000.0; valuesPVDO_Bo[13] = 1.07347; valuesPVDO_visc[13] = 0.00038266; - coordinatesPVDO[0][14] = 95000000.0; valuesPVDO_Bo[14] = 1.06966; valuesPVDO_visc[14] = 0.00039384; - coordinatesPVDO[0][15] = 100000000.0; valuesPVDO_Bo[15] = 1.06610; valuesPVDO_visc[15] = 0.00040476; - coordinatesPVDO[0][16] = 110000000.0; valuesPVDO_Bo[16] = 1.05961; valuesPVDO_visc[16] = 0.00042584; - coordinatesPVDO[0][17] = 112500000.0; valuesPVDO_Bo[17] = 1.05811; valuesPVDO_visc[17] = 0.00043096; - coordinatesPVDO[0][18] = 115000000.0; valuesPVDO_Bo[18] = 1.05665; valuesPVDO_visc[18] = 0.00043602; - coordinatesPVDO[0][19] = 117500000.0; valuesPVDO_Bo[19] = 1.05523; valuesPVDO_visc[19] = 0.00044102; - coordinatesPVDO[0][20] = 120000000.0; valuesPVDO_Bo[20] = 1.05385; valuesPVDO_visc[20] = 0.00044596; - - array1d< real64_array > coordinatesPVDG; - real64_array valuesPVDG_Bg( NaxisPVDG ); - real64_array valuesPVDG_visc( NaxisPVDG ); - coordinatesPVDG.resize( 1 ); - coordinatesPVDG[0].resize( NaxisPVDG ); - coordinatesPVDG[0][0] = 3000000; valuesPVDG_Bg[0] = 0.04234; valuesPVDG_visc[0] = 0.00001344; - coordinatesPVDG[0][1] = 6000000; valuesPVDG_Bg[1] = 0.02046; valuesPVDG_visc[1] = 0.0000142; - coordinatesPVDG[0][2] = 9000000; valuesPVDG_Bg[2] = 0.01328; valuesPVDG_visc[2] = 0.00001526; - coordinatesPVDG[0][3] = 12000000; valuesPVDG_Bg[3] = 0.00977; valuesPVDG_visc[3] = 0.0000166; - coordinatesPVDG[0][4] = 15000000; valuesPVDG_Bg[4] = 0.00773; valuesPVDG_visc[4] = 0.00001818; - coordinatesPVDG[0][5] = 18000000; valuesPVDG_Bg[5] = 0.006426; valuesPVDG_visc[5] = 0.00001994; - coordinatesPVDG[0][6] = 21000000; valuesPVDG_Bg[6] = 0.005541; valuesPVDG_visc[6] = 0.00002181; - coordinatesPVDG[0][7] = 24000000; valuesPVDG_Bg[7] = 0.004919; valuesPVDG_visc[7] = 0.0000237; - coordinatesPVDG[0][8] = 27000000; valuesPVDG_Bg[8] = 0.004471; valuesPVDG_visc[8] = 0.00002559; - coordinatesPVDG[0][9] = 29500000; valuesPVDG_Bg[9] = 0.004194; valuesPVDG_visc[9] = 0.00002714; - coordinatesPVDG[0][10] = 31000000; valuesPVDG_Bg[10] = 0.004031; valuesPVDG_visc[10] = 0.00002806; - coordinatesPVDG[0][11] = 33000000; valuesPVDG_Bg[11] = 0.00391; valuesPVDG_visc[11] = 0.00002832; - coordinatesPVDG[0][12] = 53000000; valuesPVDG_Bg[12] = 0.003868; valuesPVDG_visc[12] = 0.00002935; - - TableFunction & tablePVDO_Bo = dynamicCast< TableFunction & >( *functionManager.createChild( "TableFunction", "PVDO_Bo" ) ); - tablePVDO_Bo.setTableCoordinates( coordinatesPVDO, { units::Pressure } ); - tablePVDO_Bo.setTableValues( valuesPVDO_Bo, units::Dimensionless ); - tablePVDO_Bo.reInitializeFunction(); - tablePVDO_Bo.setInterpolationMethod( TableFunction::InterpolationType::Linear ); - - TableFunction & tablePVDO_visc = dynamicCast< TableFunction & >( *functionManager.createChild( "TableFunction", "PVDO_visc" ) ); - tablePVDO_visc.setTableCoordinates( coordinatesPVDO, { units::Pressure } ); - tablePVDO_visc.setTableValues( valuesPVDO_visc, units::Viscosity ); - tablePVDO_visc.reInitializeFunction(); - tablePVDO_visc.setInterpolationMethod( TableFunction::InterpolationType::Linear ); - - TableFunction & tablePVDG_Bg = dynamicCast< TableFunction & >( *functionManager.createChild( "TableFunction", "PVDG_Bg" ) ); - tablePVDG_Bg.setTableCoordinates( coordinatesPVDG, { units::Pressure } ); - tablePVDG_Bg.setTableValues( valuesPVDG_Bg, units::Dimensionless ); - tablePVDG_Bg.reInitializeFunction(); - tablePVDG_Bg.setInterpolationMethod( TableFunction::InterpolationType::Linear ); - - TableFunction & tablePVDG_visc = dynamicCast< TableFunction & >( *functionManager.createChild( "TableFunction", "PVDG_visc" ) ); - tablePVDG_visc.setTableCoordinates( coordinatesPVDG, { units::Pressure } ); - tablePVDG_visc.setTableValues( valuesPVDG_visc, units::Viscosity ); - tablePVDG_visc.reInitializeFunction(); - tablePVDG_visc.setInterpolationMethod( TableFunction::InterpolationType::Linear ); - - // 2) Then, define the Dead-Oil constitutive model - - DeadOilFluid & fluid = parent->registerGroup< DeadOilFluid >( name ); - - string_array & compNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::componentNamesString() ); - compNames.resize( 3 ); - compNames[0] = "gas"; compNames[1] = "water"; compNames[2] = "oil"; - - array1d< real64 > & molarWgt = fluid.getReference< array1d< real64 > >( MultiFluidBase::viewKeyStruct::componentMolarWeightString() ); - molarWgt.resize( 3 ); - molarWgt[0] = 18e-3; molarWgt[1] = 16e-3; molarWgt[2] = 114e-3; - - string_array & phaseNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::phaseNamesString() ); - phaseNames.resize( 3 ); - phaseNames[0] = "gas"; phaseNames[1] = "water"; phaseNames[2] = "oil"; - - array1d< real64 > & surfaceDens = fluid.getReference< array1d< real64 > >( DeadOilFluid::viewKeyStruct::surfacePhaseMassDensitiesString() ); - surfaceDens.resize( 3 ); - surfaceDens[0] = 0.9907; surfaceDens[1] = 1022.0; surfaceDens[2] = 800.0; - - string_array & FVFTableNames = fluid.getReference< string_array >( DeadOilFluid::viewKeyStruct::formationVolumeFactorTableNamesString() ); - FVFTableNames.resize( 2 ); - FVFTableNames[0] = "PVDG_Bg"; FVFTableNames[1] = "PVDO_Bo"; - - string_array & viscosityTableNames = fluid.getReference< string_array >( DeadOilFluid::viewKeyStruct::viscosityTableNamesString() ); - viscosityTableNames.resize( 2 ); - viscosityTableNames[0] = "PVDG_visc"; viscosityTableNames[1] = "PVDO_visc"; - - real64 & waterRefPressure = fluid.getReference< real64 >( DeadOilFluid::viewKeyStruct::waterRefPressureString() ); - waterRefPressure = 30600000.1; - real64 & waterFormationVolumeFactor = fluid.getReference< real64 >( DeadOilFluid::viewKeyStruct::waterFormationVolumeFactorString() ); - waterFormationVolumeFactor = 1.03; - real64 & waterCompressibility = fluid.getReference< real64 >( DeadOilFluid::viewKeyStruct::waterCompressibilityString() ); - waterCompressibility = 0.00000000041; - real64 & waterViscosity = fluid.getReference< real64 >( DeadOilFluid::viewKeyStruct::waterViscosityString() ); - waterViscosity = 0.0003; - - fluid.postProcessInputRecursive(); - return fluid; -} - -void writeTableToFile( string const & filename, char const * str ) -{ - std::ofstream os( filename ); - ASSERT_TRUE( os.is_open() ); - os << str; - os.close(); -} - -void removeFile( string const & filename ) -{ - int const ret = std::remove( filename.c_str() ); - ASSERT_TRUE( ret == 0 ); -} - -class LiveOilFluidTest : public CompositionalFluidTestBase -{ -public: - LiveOilFluidTest() - { - writeTableToFile( "pvto.txt", pvtoTableContent ); - writeTableToFile( "pvdg.txt", pvdgTableContent ); - writeTableToFile( "pvtw.txt", pvtwTableContent ); - - parent.resize( 1 ); - fluid = &makeLiveOilFluid( "fluid", &parent ); - - parent.initialize(); - parent.initializePostInitialConditions(); - } - - ~LiveOilFluidTest() - { - removeFile( "pvto.txt" ); - removeFile( "pvdg.txt" ); - removeFile( "pvtw.txt" ); - } -}; - -TEST_F( LiveOilFluidTest, numericalDerivativesMolar ) -{ - fluid->setMassFlag( false ); - - real64 const P[3] = { 5.4e6, 1.24e7, 3.21e7 }; - real64 const T = 297.15; - array1d< real64 > comp( 3 ); - comp[0] = 0.79999; comp[1] = 0.2; comp[2] = 0.00001; - - real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); - real64 const relTol = 1e-12; - - for( integer i = 0; i < 3; ++i ) - { - testNumericalDerivatives( *fluid, parent, P[i], T, comp, eps, false, relTol ); - } -} - -TEST_F( LiveOilFluidTest, numericalDerivativesMass ) -{ - fluid->setMassFlag( true ); - - real64 const P[3] = { 5.4e6, 1.24e7, 3.21e7 }; - real64 const T = 297.15; - array1d< real64 > comp( 3 ); - comp[0] = 0.79999; comp[1] = 0.2; comp[2] = 0.00001; - - real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); - real64 const relTol = 1e-12; - - for( integer i = 0; i < 3; ++i ) - { - testNumericalDerivatives( *fluid, parent, P[i], T, comp, eps, false, relTol ); - } -} - -class DeadOilFluidTest : public CompositionalFluidTestBase -{ -public: - - DeadOilFluidTest() - { - writeTableToFile( "pvdo.txt", pvdoTableContent ); - writeTableToFile( "pvdg.txt", pvdgTableContent ); - writeTableToFile( "pvdw.txt", pvdwTableContent ); - - parent.resize( 1 ); - fluid = &makeDeadOilFluid( "fluid", &parent ); - - parent.initialize(); - parent.initializePostInitialConditions(); - } - - ~DeadOilFluidTest() - { - removeFile( "pvdo.txt" ); - removeFile( "pvdg.txt" ); - removeFile( "pvdw.txt" ); - } -}; - -TEST_F( DeadOilFluidTest, numericalDerivativesMolar ) -{ - fluid->setMassFlag( false ); - - real64 const P[3] = { 1.24e7, 3.21e7, 5.01e7 }; - real64 const T = 297.15; - array1d< real64 > comp( 3 ); - comp[0] = 0.1; comp[1] = 0.3; comp[2] = 0.6; - - real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); - real64 const relTol = 1e-4; - - for( integer i = 0; i < 3; ++i ) - { - testNumericalDerivatives( *fluid, parent, P[i], T, comp, eps, false, relTol ); - } -} - -TEST_F( DeadOilFluidTest, numericalDerivativesMass ) -{ - fluid->setMassFlag( true ); - - real64 const P[3] = { 5.4e6, 1.24e7, 3.21e7 }; - real64 const T = 297.15; - array1d< real64 > comp( 3 ); - comp[0] = 0.1; comp[1] = 0.3; comp[2] = 0.6; - - real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); - real64 const relTol = 1e-4; - real64 const absTol = 1e-14; - - for( integer i = 0; i < 3; ++i ) - { - testNumericalDerivatives( *fluid, parent, P[i], T, comp, eps, false, relTol, absTol ); - } -} - -class DeadOilFluidFromTableTest : public CompositionalFluidTestBase -{ -public: - - DeadOilFluidFromTableTest() - { - parent.resize( 1 ); - fluid = &makeDeadOilFluidFromTable( "fluid", &parent ); - - parent.initialize(); - parent.initializePostInitialConditions(); - } -}; - -TEST_F( DeadOilFluidFromTableTest, numericalDerivativesMolar ) -{ - fluid->setMassFlag( false ); - - real64 const P[3] = { 5.4e6, 1.24e7, 3.21e7 }; - real64 const T = 297.15; - array1d< real64 > comp( 3 ); - comp[0] = 0.1; comp[1] = 0.3; comp[2] = 0.6; - - real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); - real64 const relTol = 1e-4; - - for( integer i = 0; i < 3; ++i ) - { - testNumericalDerivatives( *fluid, parent, P[i], T, comp, eps, false, relTol ); - } -} - -MultiFluidBase & makeCO2BrinePhillipsFluid( string const & name, Group * parent ) -{ - CO2BrinePhillipsFluid & fluid = parent->registerGroup< CO2BrinePhillipsFluid >( name ); - - auto & compNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::componentNamesString() ); - compNames.resize( 2 ); - compNames[0] = "co2"; compNames[1] = "water"; - - auto & molarWgt = fluid.getReference< array1d< real64 > >( MultiFluidBase::viewKeyStruct::componentMolarWeightString() ); - molarWgt.resize( 2 ); - molarWgt[0] = 44e-3; molarWgt[1] = 18e-3; - - auto & phaseNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::phaseNamesString() ); - phaseNames.resize( 2 ); - phaseNames[0] = "gas"; phaseNames[1] = "liquid"; - - auto & phasePVTParaFileNames = fluid.getReference< path_array >( CO2BrinePhillipsFluid::viewKeyStruct::phasePVTParaFilesString() ); - phasePVTParaFileNames.resize( 2 ); - phasePVTParaFileNames[0] = "pvtgas.txt"; phasePVTParaFileNames[1] = "pvtliquid.txt"; - - auto & flashModelParaFileName = fluid.getReference< Path >( CO2BrinePhillipsFluid::viewKeyStruct::flashModelParaFileString() ); - flashModelParaFileName = "co2flash.txt"; - - fluid.postProcessInputRecursive(); - return fluid; -} - -class CO2BrinePhillipsFluidTest : public CompositionalFluidTestBase -{ -protected: - - CO2BrinePhillipsFluidTest() - { - writeTableToFile( "pvtliquid.txt", pvtLiquidPhillipsTableContent ); - writeTableToFile( "pvtgas.txt", pvtGasTableContent ); - writeTableToFile( "co2flash.txt", co2FlashTableContent ); - - parent.resize( 1 ); - fluid = &makeCO2BrinePhillipsFluid( "fluid", &parent ); - - parent.initialize(); - parent.initializePostInitialConditions(); - } - - ~CO2BrinePhillipsFluidTest() - { - removeFile( "pvtliquid.txt" ); - removeFile( "pvtgas.txt" ); - removeFile( "co2flash.txt" ); - } - -}; - - -TEST_F( CO2BrinePhillipsFluidTest, checkAgainstPreviousImplementationMolar ) -{ - fluid->setMassFlag( false ); - - real64 const P[3] = { 5e6, 7.5e6, 1.2e7 }; - real64 const T[3] = { 367.65, 368.15, 368.75 }; - array1d< real64 > comp( 2 ); - comp[0] = 0.3; comp[1] = 0.7; - - real64 const relTol = 1e-10; - - fluid->allocateConstitutiveData( fluid->getParent(), 1 ); - - CO2BrinePhillipsFluid::KernelWrapper wrapper = - dynamicCast< CO2BrinePhillipsFluid * >( fluid )->createKernelWrapper(); - - real64 const savedTotalDens[] = - { 5881.9010529428224, 5869.6094131788523, 5855.0332090690354, 9181.3523596865525, 9157.6071613646127, 9129.5728206336826, 15757.685798517123, 15698.877814368472, - 15630.149353340639 }; - real64 const savedGasPhaseFrac[] = - { 0.29413690046142371148, 0.29415754810481165027, 0.29418169867697463449, 0.29194010802017489326, 0.29196434961986583723, 0.29199266189550621142, 0.2890641335638892695, 0.28908718137828937067, - 0.28911404840933618843 }; - real64 const savedWaterDens[] = - { 53296.719183517576, 53274.578175308554, 53247.856162690216, 53248.577831698305, 53226.801031868054, 53200.505577694363, 53232.959859840405, 53211.345942175059, - 53185.244751356993 }; - real64 const savedGasDens[] = - { 1876.2436091302606656, 1872.184636376355229, 1867.3711104617746059, 3053.1548401973859654, 3044.5748249030266379, 3034.4507978134674886, 5769.0622621289458039, 5742.8476745352018042, - 5712.2837704249559465 }; - real64 const savedWaterMassDens[] = - { 970.85108546544745423, 970.4075834766143771, 969.87385780866463847, 974.23383396044232541, 973.78856424100911227, 973.25280170872576946, 979.48333010951580491, 979.04147229150635212, - 978.50977403260912979 }; - real64 const savedGasMassDens[] = - { 82.554718801731468147, 82.376124000559627802, 82.164328860318079251, 134.33881296868497657, 133.96129229573315911, 133.51583510379256836, 253.83873953367358922, 252.68529767954885301, - 251.34048589869803436 }; - real64 const savedWaterVisc[] = - { 0.0003032144206279845924, 0.00030157070452334377216, 0.00029959815370251820189, 0.0003032144206279845924, 0.00030157070452334377216, 0.00029959815370251820189, 0.0003032144206279845924, - 0.00030157070452334377216, 0.00029959815370251820189 }; - - real64 const savedGasVisc[] = - { 1.9042384704865343673e-05, 1.9062615947696152414e-05, 1.9086923154230274463e-05, 2.0061713844617985449e-05, 2.0075955757102255573e-05, 2.0093249989250199265e-05, 2.3889596884008691474e-05, - 2.3865756080512667728e-05, 2.3839170076324036522e-05 }; - real64 const savedWaterPhaseGasComp[] = - { 0.0083062842389820552153, 0.008277274736736653718, 0.0082433415400525456018, 0.011383065290266058955, 0.011349217198060387521, 0.011309682362800700661, 0.015382352969377973903, - 0.015350431636424789056, 0.015313218057419366105 }; - real64 const savedWaterPhaseWaterComp[] = - { 0.99169371576101794652, 0.9917227252632633272, 0.99175665845994742664, 0.98861693470973388553, 0.98865078280193963156, 0.98869031763719927852, 0.98461764703062204518, 0.98464956836357520054, - 0.98468678194258063563 }; - - integer counter = 0; - for( integer i = 0; i < 3; ++i ) - { - for( integer j = 0; j < 3; ++j ) - { - testValuesAgainstPreviousImplementation( wrapper, - P[i], T[j], comp, - savedTotalDens[counter], savedGasPhaseFrac[counter], - savedWaterDens[counter], savedGasDens[counter], - savedWaterMassDens[counter], savedGasMassDens[counter], - savedWaterVisc[counter], savedGasVisc[counter], - savedWaterPhaseGasComp[counter], savedWaterPhaseWaterComp[counter], - relTol ); - counter++; - } - } -} - -TEST_F( CO2BrinePhillipsFluidTest, checkAgainstPreviousImplementationMass ) -{ - fluid->setMassFlag( true ); - - real64 const P[3] = { 5e6, 7.5e6, 1.2e7 }; - real64 const T[3] = { 367.65, 368.15, 368.75 }; - array1d< real64 > comp( 2 ); - comp[0] = 0.3; comp[1] = 0.7; - - real64 const relTol = 1e-10; - - fluid->allocateConstitutiveData( fluid->getParent(), 1 ); - - CO2BrinePhillipsFluid::KernelWrapper wrapper = - dynamicCast< CO2BrinePhillipsFluid * >( fluid )->createKernelWrapper(); - - real64 const savedTotalDens[] = - { 238.31504112633914, 237.83897306400553, 237.27445306546298, 353.95258514794097, 353.12773295711992, 352.1532278769692, 549.90502586392017, 548.2725957521294, - 546.35992000222234 }; - real64 const savedGasPhaseFrac[] = - { 0.28566797890570228, 0.28571845092287312, 0.28577748565482669, 0.28029804182709406, 0.28035729907078311, 0.2804265068556816, 0.27326788204506247, 0.27332422114692956, - 0.27338989611171055 }; - real64 const savedWaterDens[] = - { 970.85108546544745423, 970.4075834766143771, 969.87385780866463847, 974.23383396044232541, 973.78856424100911227, 973.25280170872576946, 979.48333010951580491, 979.04147229150635212, - 978.50977403260912979 }; - real64 const savedGasDens[] = - { 82.554718801731468147, 82.376124000559627802, 82.164328860318079251, 134.33881296868497657, 133.96129229573315911, 133.51583510379256836, 253.83873953367358922, 252.68529767954885301, - 251.34048589869803436 }; - real64 const savedWaterMassDens[] = - { 970.85108546544745423, 970.4075834766143771, 969.87385780866463847, 974.23383396044232541, 973.78856424100911227, 973.25280170872576946, 979.48333010951580491, 979.04147229150635212, - 978.50977403260912979 }; - real64 const savedGasMassDens[] = - { 82.554718801731468147, 82.376124000559627802, 82.164328860318079251, 134.33881296868497657, 133.96129229573315911, 133.51583510379256836, 253.83873953367358922, 252.68529767954885301, - 251.34048589869803436 }; - real64 const savedWaterVisc[] = - { 0.0003032144206279845924, 0.00030157070452334377216, 0.00029959815370251820189, 0.0003032144206279845924, 0.00030157070452334377216, 0.00029959815370251820189, 0.0003032144206279845924, - 0.00030157070452334377216, 0.00029959815370251820189 }; - real64 const savedGasVisc[] = - { 1.9042384704865343673e-05, 1.9062615947696152414e-05, 1.9086923154230274463e-05, 2.0061713844617985449e-05, 2.0075955757102255573e-05, 2.0093249989250199265e-05, 2.3889596884008691474e-05, - 2.3865756080512667728e-05, 2.3839170076324036522e-05 }; - real64 const savedWaterPhaseGasComp[] = - { 0.020063528822832473, 0.019994285300494085, 0.019913282008777046, 0.027375162661670061, 0.027295074213708581, 0.02720152052681666, 0.036784005129927563, - 0.036709327088310859, 0.036622259649145526 }; - real64 const savedWaterPhaseWaterComp[] = - { 0.97993647117716742, 0.98000571469950604, 0.98008671799122282, 0.97262483733832983, 0.97270492578629131, 0.97279847947318321, 0.96321599487007259, 0.96329067291168902, - 0.96337774035085455 }; - - integer counter = 0; - for( integer i = 0; i < 3; ++i ) - { - for( integer j = 0; j < 3; ++j ) - { - testValuesAgainstPreviousImplementation( wrapper, - P[i], T[j], comp, - savedTotalDens[counter], savedGasPhaseFrac[counter], - savedWaterDens[counter], savedGasDens[counter], - savedWaterMassDens[counter], savedGasMassDens[counter], - savedWaterVisc[counter], savedGasVisc[counter], - savedWaterPhaseGasComp[counter], savedWaterPhaseWaterComp[counter], - relTol ); - counter++; - } - } -} - -TEST_F( CO2BrinePhillipsFluidTest, numericalDerivativesMolar ) -{ - fluid->setMassFlag( false ); - - // TODO test over a range of values - real64 const P[3] = { 5e6, 7.5e6, 1.2e7 }; - real64 const T[3] = { 367.65, 368.15, 368.75 }; - array1d< real64 > comp( 2 ); - comp[0] = 0.3; comp[1] = 0.7; - - real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); - real64 const relTol = 1e-4; - - for( integer i = 0; i < 3; ++i ) - { - for( integer j = 0; j < 3; ++j ) - { - testNumericalDerivatives( *fluid, parent, P[i], T[j], comp, eps, false, relTol ); - } - } -} - -TEST_F( CO2BrinePhillipsFluidTest, numericalDerivativesMass ) -{ - fluid->setMassFlag( true ); - - // TODO test over a range of values - real64 const P[3] = { 5e6, 7.5e6, 1.2e7 }; - real64 const T[3] = { 367.65, 368.15, 368.75 }; - array1d< real64 > comp( 2 ); - comp[0] = 0.3; comp[1] = 0.7; - - real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); - real64 const relTol = 1e-8; - - for( integer i = 0; i < 3; ++i ) - { - for( integer j = 0; j < 3; ++j ) - { - testNumericalDerivatives( *fluid, parent, P[i], T[j], comp, eps, false, relTol ); - } - } -} - -MultiFluidBase & makeCO2BrineEzrokhiFluid( string const & name, Group * parent ) -{ - CO2BrineEzrokhiFluid & fluid = parent->registerGroup< CO2BrineEzrokhiFluid >( name ); - - auto & compNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::componentNamesString() ); - compNames.resize( 2 ); - compNames[0] = "co2"; compNames[1] = "water"; - - auto & molarWgt = fluid.getReference< array1d< real64 > >( MultiFluidBase::viewKeyStruct::componentMolarWeightString() ); - molarWgt.resize( 2 ); - molarWgt[0] = 44e-3; molarWgt[1] = 18e-3; - - auto & phaseNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::phaseNamesString() ); - phaseNames.resize( 2 ); - phaseNames[0] = "gas"; phaseNames[1] = "liquid"; - - auto & phasePVTParaFileNames = fluid.getReference< path_array >( CO2BrineEzrokhiFluid::viewKeyStruct::phasePVTParaFilesString() ); - phasePVTParaFileNames.resize( 2 ); - phasePVTParaFileNames[0] = "pvtgas.txt"; phasePVTParaFileNames[1] = "pvtliquid.txt"; - - auto & flashModelParaFileName = fluid.getReference< Path >( CO2BrineEzrokhiFluid::viewKeyStruct::flashModelParaFileString() ); - flashModelParaFileName = "co2flash.txt"; - - fluid.postProcessInputRecursive(); - return fluid; -} - -class CO2BrineEzrokhiFluidTest : public CompositionalFluidTestBase -{ -protected: - - CO2BrineEzrokhiFluidTest() - { - writeTableToFile( "pvtliquid.txt", pvtLiquidEzrokhiTableContent ); - writeTableToFile( "pvtgas.txt", pvtGasTableContent ); - writeTableToFile( "co2flash.txt", co2FlashTableContent ); - - parent.resize( 1 ); - fluid = &makeCO2BrineEzrokhiFluid( "fluid", &parent ); - - parent.initialize(); - parent.initializePostInitialConditions(); - } - - ~CO2BrineEzrokhiFluidTest() - { - removeFile( "pvtliquid.txt" ); - removeFile( "pvtgas.txt" ); - removeFile( "co2flash.txt" ); - } - -}; - -TEST_F( CO2BrineEzrokhiFluidTest, numericalDerivativesMolar ) -{ - fluid->setMassFlag( false ); - - // TODO test over a range of values - real64 const P[3] = { 5e6, 7.5e6, 1.2e7 }; - real64 const T[3] = { 367.65, 368.15, 368.75 }; - array1d< real64 > comp( 2 ); - comp[0] = 0.3; comp[1] = 0.7; - - real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); - real64 const relTol = 1e-4; - - for( integer i = 0; i < 3; ++i ) - { - for( integer j = 0; j < 3; ++j ) - { - testNumericalDerivatives( *fluid, parent, P[i], T[j], comp, eps, false, relTol ); - } - } -} - -TEST_F( CO2BrineEzrokhiFluidTest, numericalDerivativesMass ) -{ - fluid->setMassFlag( true ); - - // TODO test over a range of values - real64 const P[3] = { 5e6, 7.5e6, 1.2e7 }; - real64 const T[3] = { 367.65, 368.15, 368.75 }; - array1d< real64 > comp( 2 ); - comp[0] = 0.3; comp[1] = 0.7; - - real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); - real64 const relTol = 1e-8; - - for( integer i = 0; i < 3; ++i ) - { - for( integer j = 0; j < 3; ++j ) - { - testNumericalDerivatives( *fluid, parent, P[i], T[j], comp, eps, false, relTol ); - } - } -} - -int main( int argc, char * * argv ) -{ - ::testing::InitGoogleTest( &argc, argv ); - - geos::GeosxState state( geos::basicSetup( argc, argv ) ); - - int const result = RUN_ALL_TESTS(); - - geos::basicCleanup(); - - return result; -} diff --git a/src/coreComponents/unitTests/constitutiveTests/testMultiFluidCO2Brine.cpp b/src/coreComponents/unitTests/constitutiveTests/testMultiFluidCO2Brine.cpp new file mode 100644 index 00000000000..a55618c19d2 --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testMultiFluidCO2Brine.cpp @@ -0,0 +1,375 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file testMultiFluidCO2Brine.cpp + */ + +#include "MultiFluidTest.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mainInterface/initialization.hpp" +#include "common/GeosxConfig.hpp" + +using namespace geos; +using namespace geos::testing; +using namespace geos::dataRepository; +using namespace geos::constitutive; + +enum class BrineModelType : int {Phillips, Ezrokhi}; +enum class FlashType : int {DuanSun, SpycherPruess}; + +ENUM_STRINGS( BrineModelType, "Phillips", "Ezrokhi" ); +ENUM_STRINGS( FlashType, "DuanSun", "SpycherPruess" ); + +template< BrineModelType BRINE, bool THERMAL > +struct FluidType {}; + +template<> +struct FluidType< BrineModelType::Phillips, false > +{ + using type = CO2BrinePhillipsFluid; + static constexpr const char * brineContent = "DensityFun PhillipsBrineDensity 1e6 1.5e7 5e4 367.15 369.15 1 0.2\n" + "ViscosityFun PhillipsBrineViscosity 0.1"; + static constexpr const char * gasContent = "DensityFun SpanWagnerCO2Density 1e6 1.5e7 5e4 367.15 369.15 1\n" + "ViscosityFun FenghourCO2Viscosity 1e6 1.5e7 5e4 367.15 369.15 1"; +}; +template<> +struct FluidType< BrineModelType::Phillips, true > +{ + using type = CO2BrinePhillipsThermalFluid; + static constexpr const char * brineContent = "DensityFun PhillipsBrineDensity 1e6 1.5e7 5e4 367.15 369.15 1 0.2\n" + "ViscosityFun PhillipsBrineViscosity 0.1\n" + "EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0"; + static constexpr const char * gasContent = "DensityFun SpanWagnerCO2Density 1e6 1.5e7 5e4 367.15 369.15 1\n" + "ViscosityFun FenghourCO2Viscosity 1e6 1.5e7 5e4 367.15 369.15 1\n" + "EnthalpyFun CO2Enthalpy 1e6 1.5e7 5e4 367.15 369.15 1"; +}; +template<> +struct FluidType< BrineModelType::Ezrokhi, false > +{ + using type = CO2BrineEzrokhiFluid; + static constexpr const char * brineContent = "DensityFun EzrokhiBrineDensity 2.01e-6 -6.34e-7 1e-4\n" + "ViscosityFun EzrokhiBrineViscosity 2.42e-7 0 1e-4"; + static constexpr const char * gasContent = "DensityFun SpanWagnerCO2Density 1e6 1.5e7 5e4 367.15 369.15 1\n" + "ViscosityFun FenghourCO2Viscosity 1e6 1.5e7 5e4 367.15 369.15 1"; +}; +template<> +struct FluidType< BrineModelType::Ezrokhi, true > +{ + using type = CO2BrineEzrokhiThermalFluid; + static constexpr const char * brineContent = "DensityFun EzrokhiBrineDensity 2.01e-6 -6.34e-7 1e-4\n" + "ViscosityFun EzrokhiBrineViscosity 2.42e-7 0 1e-4\n" + "EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0"; + static constexpr const char * gasContent = "DensityFun SpanWagnerCO2Density 1e6 1.5e7 5e4 367.15 369.15 1\n" + "ViscosityFun FenghourCO2Viscosity 1e6 1.5e7 5e4 367.15 369.15 1\n" + "EnthalpyFun CO2Enthalpy 1e6 1.5e7 5e4 367.15 369.15 1"; +}; + +template< FlashType FLASH > +struct FlashModel {}; + +template<> +struct FlashModel< FlashType::DuanSun > +{ + static constexpr const char * flashContent = "FlashModel CO2Solubility 1e6 1.5e7 5e4 367.15 369.15 1 0.15"; +}; +template<> +struct FlashModel< FlashType::SpycherPruess > +{ + static constexpr const char * flashContent = "FlashModel CO2Solubility 1e6 1.5e7 5e4 367.15 369.15 1 0.15 1.0e-10 SpycherPruess"; +}; + +template< BrineModelType BRINE, FlashType FLASH, bool THERMAL > +class MultiFluidCO2BrineTest : public MultiFluidTest< typename FluidType< BRINE, THERMAL >::type, 2, 2 >, + public ::testing::WithParamInterface< typename MultiFluidTest< typename FluidType< BRINE, THERMAL >::type, 2, 2 >::TestData > +{ +public: + using CO2BrineFluid = typename FluidType< BRINE, THERMAL >::type; + using Base = MultiFluidTest< typename FluidType< BRINE, THERMAL >::type, 2, 2 >; + static constexpr real64 relTol = 1.0e-4; + static constexpr real64 absTol = 1.0e-4; + +public: + MultiFluidCO2BrineTest() + { + Base::writeTableToFile( pvtGasFileName, FluidType< BRINE, THERMAL >::gasContent ); + Base::writeTableToFile( pvtLiquidFileName, FluidType< BRINE, THERMAL >::brineContent ); + Base::writeTableToFile( pvtFlashFileName, FlashModel< FLASH >::flashContent ); + + auto & parent = this->m_parent; + parent.resize( 1 ); + string const fluidName = GEOS_FMT( "fluid{}{}{}", + EnumStrings< BrineModelType >::toString( BRINE ), + EnumStrings< FlashType >::toString( FLASH ), + (THERMAL ? "Thermal" : "")); + this->m_model = makeCO2BrineFluid( fluidName, &parent ); + + parent.initialize(); + parent.initializePostInitialConditions(); + } + + ~MultiFluidCO2BrineTest() override + { + Base::removeFile( pvtGasFileName ); + Base::removeFile( pvtLiquidFileName ); + Base::removeFile( pvtFlashFileName ); + } + + // Test numerical derivatives at selected data points + void testNumericalDerivatives( bool const useMass ) + { + auto * parent = &(this->getParent()); + auto & fluid = this->getFluid(); + fluid.setMassFlag( useMass ); + + real64 constexpr eps = 1.0e-5; + + // Some of the functions are simply table lookups. We need to keep the test points away from + // the table nodes because the kink in the linear interpolation might cause numerical derivative + // mismatches. Some of these values have been manually inspected and the differences, although + // not meeting the tolerance here, are small as expected. + constexpr real64 temperatures[] = { 367.65, 368.00, 368.75 }; + constexpr real64 pressures[] = { 5.001e6, 7.501e6, 1.201e7 }; + + for( real64 const pressure : pressures ) + { + for( real64 const temperature : temperatures ) + { + typename Base::TestData data ( pressure, temperature, { 0.3, 0.7 } ); + Base::testNumericalDerivatives( fluid, parent, data, eps, relTol, absTol ); + } + } + } + +private: + static CO2BrineFluid * makeCO2BrineFluid( string const & name, Group * parent ); + static constexpr const char * pvtGasFileName = "pvtgas.txt"; + static constexpr const char * pvtLiquidFileName = "pvtliquid.txt"; + static constexpr const char * pvtFlashFileName = "co2flash.txt"; +}; + +template< BrineModelType BRINE, FlashType FLASH, bool THERMAL > +typename MultiFluidCO2BrineTest< BRINE, FLASH, THERMAL >::CO2BrineFluid * +MultiFluidCO2BrineTest< BRINE, FLASH, THERMAL >::makeCO2BrineFluid( string const & name, Group * parent ) +{ + CO2BrineFluid & co2BrineFluid = parent->registerGroup< CO2BrineFluid >( name ); + + Group & fluid = co2BrineFluid; + + auto & phaseNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::phaseNamesString() ); + fill< 2 >( phaseNames, {"gas", "liquid"} ); + + auto & compNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::componentNamesString() ); + fill< 2 >( compNames, {"co2", "water"} ); + + auto & molarWeight = fluid.getReference< array1d< real64 > >( MultiFluidBase::viewKeyStruct::componentMolarWeightString() ); + fill< 2 >( molarWeight, {44e-3, 18e-3} ); + + auto & phasePVTParaFileNames = fluid.getReference< path_array >( CO2BrineFluid::viewKeyStruct::phasePVTParaFilesString() ); + fill< 2 >( phasePVTParaFileNames, {pvtGasFileName, pvtLiquidFileName} ); + + auto & flashModelParaFileName = fluid.getReference< Path >( CO2BrineFluid::viewKeyStruct::flashModelParaFileString() ); + flashModelParaFileName = pvtFlashFileName; + + co2BrineFluid.postInputInitializationRecursive(); + + return &co2BrineFluid; +} + +using MultiFluidCO2BrineBrinePhillipsTest = MultiFluidCO2BrineTest< BrineModelType::Phillips, + FlashType::DuanSun, + false >; +using MultiFluidCO2BrineBrineEzrokhiTest = MultiFluidCO2BrineTest< BrineModelType::Ezrokhi, + FlashType::DuanSun, + false >; +using MultiFluidCO2BrineBrinePhillipsThermalTest = MultiFluidCO2BrineTest< BrineModelType::Phillips, + FlashType::DuanSun, + true >; +using MultiFluidCO2BrineBrinePhillipsSpycherPruessTest = MultiFluidCO2BrineTest< BrineModelType::Phillips, + FlashType::SpycherPruess, + false >; +#if !defined(GEOS_DEVICE_COMPILE) +using MultiFluidCO2BrineBrineEzrokhiThermalTest = MultiFluidCO2BrineTest< BrineModelType::Ezrokhi, + FlashType::DuanSun, + true >; +#endif + +TEST_F( MultiFluidCO2BrineBrinePhillipsTest, numericalDerivativesMolar ) +{ + testNumericalDerivatives( false ); +} +TEST_F( MultiFluidCO2BrineBrinePhillipsTest, numericalDerivativesMass ) +{ + testNumericalDerivatives( true ); +} + +TEST_F( MultiFluidCO2BrineBrineEzrokhiTest, numericalDerivativesMolar ) +{ + testNumericalDerivatives( false ); +} +TEST_F( MultiFluidCO2BrineBrineEzrokhiTest, numericalDerivativesMass ) +{ + testNumericalDerivatives( true ); +} + +TEST_F( MultiFluidCO2BrineBrinePhillipsThermalTest, numericalDerivativesMolar ) +{ + testNumericalDerivatives( false ); +} +TEST_F( MultiFluidCO2BrineBrinePhillipsThermalTest, numericalDerivativesMass ) +{ + testNumericalDerivatives( true ); +} + +#if !defined(GEOS_DEVICE_COMPILE) +TEST_F( MultiFluidCO2BrineBrineEzrokhiThermalTest, numericalDerivativesMolar ) +{ + testNumericalDerivatives( false ); +} +TEST_F( MultiFluidCO2BrineBrineEzrokhiThermalTest, numericalDerivativesMass ) +{ + testNumericalDerivatives( true ); +} +#endif + +TEST_F( MultiFluidCO2BrineBrinePhillipsSpycherPruessTest, numericalDerivativesMolar ) +{ + testNumericalDerivatives( false ); +} +TEST_F( MultiFluidCO2BrineBrinePhillipsSpycherPruessTest, numericalDerivativesMass ) +{ + testNumericalDerivatives( true ); +} + +TEST_P( MultiFluidCO2BrineBrinePhillipsTest, checkAgainstPreviousImplementationMass ) +{ + auto & fluid = dynamicCast< CO2BrineFluid & >( this->getFluid()); + auto fluidWrapper = fluid.createKernelWrapper(); + testValuesAgainstPreviousImplementation( fluidWrapper, GetParam(), relTol ); +} + +TEST_P( MultiFluidCO2BrineBrineEzrokhiTest, checkAgainstPreviousImplementationMass ) +{ + auto & fluid = dynamicCast< CO2BrineFluid & >( this->getFluid()); + auto fluidWrapper = fluid.createKernelWrapper(); + testValuesAgainstPreviousImplementation( fluidWrapper, GetParam(), relTol ); +} + +TEST_P( MultiFluidCO2BrineBrinePhillipsThermalTest, checkAgainstPreviousImplementationMass ) +{ + auto & fluid = dynamicCast< CO2BrineFluid & >( this->getFluid()); + auto fluidWrapper = fluid.createKernelWrapper(); + testValuesAgainstPreviousImplementation( fluidWrapper, GetParam(), relTol ); +} + +TEST_P( MultiFluidCO2BrineBrinePhillipsSpycherPruessTest, checkAgainstPreviousImplementationMass ) +{ + auto & fluid = dynamicCast< CO2BrineFluid & >( this->getFluid()); + auto fluidWrapper = fluid.createKernelWrapper(); + testValuesAgainstPreviousImplementation( fluidWrapper, GetParam(), relTol ); +} + +//------------------------------------------------------------------------------- +// Data +//------------------------------------------------------------------------------- + +/* UNCRUSTIFY-OFF */ + +#define D( ... ) MultiFluidCO2BrineBrinePhillipsTest::TestData{ __VA_ARGS__ } +INSTANTIATE_TEST_SUITE_P( + MultiFluidCO2Brine, MultiFluidCO2BrineBrinePhillipsTest, + ::testing::Values( + //| pressure | temp | composition | density | phase fraction | phase density | phase mass density | phase viscosity | phase enthalpy | phase internal energy | + D( 5.00100e+06, 3.67650e+02, {3.00000e-01, 7.00000e-01}, 5.88317e+03, {2.94136e-01, 7.05864e-01}, {1.87668e+03, 5.32967e+04}, {8.25738e+01, 9.70853e+02}, {1.90427e-05, 3.03214e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 5.00100e+06, 3.68000e+02, {3.00000e-01, 7.00000e-01}, 5.87456e+03, {2.94150e-01, 7.05850e-01}, {1.87383e+03, 5.32812e+04}, {8.24487e+01, 9.70542e+02}, {1.90569e-05, 3.02064e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 5.00100e+06, 3.68750e+02, {3.00000e-01, 7.00000e-01}, 5.85630e+03, {2.94181e-01, 7.05819e-01}, {1.86780e+03, 5.32478e+04}, {8.21833e+01, 9.69875e+02}, {1.90872e-05, 2.99598e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 7.50100e+06, 3.67650e+02, {3.00000e-01, 7.00000e-01}, 9.18273e+03, {2.91939e-01, 7.08061e-01}, {3.05367e+03, 5.32486e+04}, {1.34361e+02, 9.74235e+02}, {2.00622e-05, 3.03214e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 7.50100e+06, 3.68000e+02, {3.00000e-01, 7.00000e-01}, 9.16610e+03, {2.91956e-01, 7.08044e-01}, {3.04766e+03, 5.32333e+04}, {1.34097e+02, 9.73923e+02}, {2.00722e-05, 3.02064e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 7.50100e+06, 3.68750e+02, {3.00000e-01, 7.00000e-01}, 9.13094e+03, {2.91992e-01, 7.08008e-01}, {3.03496e+03, 5.32005e+04}, {1.33538e+02, 9.73254e+02}, {2.00938e-05, 2.99598e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 1.20100e+07, 3.67650e+02, {3.00000e-01, 7.00000e-01}, 1.57730e+04, {2.89059e-01, 7.10941e-01}, {5.77607e+03, 5.32330e+04}, {2.54147e+02, 9.79494e+02}, {2.39022e-05, 3.03214e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 1.20100e+07, 3.68000e+02, {3.00000e-01, 7.00000e-01}, 1.57318e+04, {2.89075e-01, 7.10925e-01}, {5.75768e+03, 5.32179e+04}, {2.53338e+02, 9.79185e+02}, {2.38854e-05, 3.02064e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 1.20100e+07, 3.68750e+02, {3.00000e-01, 7.00000e-01}, 1.56452e+04, {2.89109e-01, 7.10891e-01}, {5.71917e+03, 5.31853e+04}, {2.51643e+02, 9.78520e+02}, {2.38514e-05, 2.99598e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ) + ) +); +#undef D + +#define D( ... ) MultiFluidCO2BrineBrineEzrokhiTest::TestData{ __VA_ARGS__ } +INSTANTIATE_TEST_SUITE_P( + MultiFluidCO2Brine, MultiFluidCO2BrineBrineEzrokhiTest, + ::testing::Values( + //| pressure | temp | composition | density | phase fraction | phase density | phase mass density | phase viscosity | phase enthalpy | phase internal energy | + D( 5.00100e+06, 3.67650e+02, {3.00000e-01, 7.00000e-01}, 5.89876e+03, {2.94136e-01, 7.05864e-01}, {1.87668e+03, 5.51674e+04}, {8.25738e+01, 1.00493e+03}, {1.90427e-05, 3.12148e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 5.00100e+06, 3.68000e+02, {3.00000e-01, 7.00000e-01}, 5.89023e+03, {2.94150e-01, 7.05850e-01}, {1.87383e+03, 5.51663e+04}, {8.24487e+01, 1.00488e+03}, {1.90569e-05, 3.11023e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 5.00100e+06, 3.68750e+02, {3.00000e-01, 7.00000e-01}, 5.87213e+03, {2.94181e-01, 7.05819e-01}, {1.86780e+03, 5.51642e+04}, {8.21833e+01, 1.00478e+03}, {1.90872e-05, 3.08611e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 7.50100e+06, 3.67650e+02, {3.00000e-01, 7.00000e-01}, 9.23469e+03, {2.91939e-01, 7.08061e-01}, {3.05367e+03, 5.58209e+04}, {1.34361e+02, 1.02130e+03}, {2.00622e-05, 3.16876e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 7.50100e+06, 3.68000e+02, {3.00000e-01, 7.00000e-01}, 9.21829e+03, {2.91956e-01, 7.08044e-01}, {3.04766e+03, 5.58254e+04}, {1.34097e+02, 1.02135e+03}, {2.00722e-05, 3.15764e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 7.50100e+06, 3.68750e+02, {3.00000e-01, 7.00000e-01}, 9.18360e+03, {2.91992e-01, 7.08008e-01}, {3.03496e+03, 5.58353e+04}, {1.33538e+02, 1.02146e+03}, {2.00938e-05, 3.13381e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 1.20100e+07, 3.67650e+02, {3.00000e-01, 7.00000e-01}, 1.59791e+04, {2.89059e-01, 7.10941e-01}, {5.77607e+03, 5.67057e+04}, {2.54147e+02, 1.04339e+03}, {2.39022e-05, 3.23075e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 1.20100e+07, 3.68000e+02, {3.00000e-01, 7.00000e-01}, 1.59385e+04, {2.89075e-01, 7.10925e-01}, {5.75768e+03, 5.67188e+04}, {2.53338e+02, 1.04360e+03}, {2.38854e-05, 3.21991e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 1.20100e+07, 3.68750e+02, {3.00000e-01, 7.00000e-01}, 1.58533e+04, {2.89109e-01, 7.10891e-01}, {5.71917e+03, 5.67472e+04}, {2.51643e+02, 1.04405e+03}, {2.38514e-05, 3.19665e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ) + ) +); +#undef D + +#define D( ... ) MultiFluidCO2BrineBrinePhillipsThermalTest::TestData{ __VA_ARGS__ } +INSTANTIATE_TEST_SUITE_P( + MultiFluidCO2Brine, MultiFluidCO2BrineBrinePhillipsThermalTest, + ::testing::Values( + //| pressure | temp | composition | density | phase fraction | phase density | phase mass density | phase viscosity | phase enthalpy | phase internal energy | + D( 5.00100e+06, 3.67650e+02, {3.00000e-01, 7.00000e-01}, 5.88317e+03, {2.94136e-01, 7.05864e-01}, {1.87668e+03, 5.32967e+04}, {8.25738e+01, 9.70853e+02}, {1.90427e-05, 3.03214e-04}, {1.21447e+07, 2.18796e+07}, {1.20841e+07, 2.18744e+07} ), + D( 5.00100e+06, 3.68000e+02, {3.00000e-01, 7.00000e-01}, 5.87456e+03, {2.94150e-01, 7.05850e-01}, {1.87383e+03, 5.32812e+04}, {8.24487e+01, 9.70542e+02}, {1.90569e-05, 3.02064e-04}, {1.21537e+07, 2.19628e+07}, {1.20931e+07, 2.19576e+07} ), + D( 5.00100e+06, 3.68750e+02, {3.00000e-01, 7.00000e-01}, 5.85630e+03, {2.94181e-01, 7.05819e-01}, {1.86780e+03, 5.32478e+04}, {8.21833e+01, 9.69875e+02}, {1.90872e-05, 2.99598e-04}, {1.21731e+07, 2.21410e+07}, {1.21123e+07, 2.21359e+07} ), + D( 7.50100e+06, 3.67650e+02, {3.00000e-01, 7.00000e-01}, 9.18273e+03, {2.91939e-01, 7.08061e-01}, {3.05367e+03, 5.32486e+04}, {1.34361e+02, 9.74235e+02}, {2.00622e-05, 3.03214e-04}, {1.17163e+07, 2.18445e+07}, {1.16605e+07, 2.18368e+07} ), + D( 7.50100e+06, 3.68000e+02, {3.00000e-01, 7.00000e-01}, 9.16610e+03, {2.91956e-01, 7.08044e-01}, {3.04766e+03, 5.32333e+04}, {1.34097e+02, 9.73923e+02}, {2.00722e-05, 3.02064e-04}, {1.17269e+07, 2.19275e+07}, {1.16709e+07, 2.19198e+07} ), + D( 7.50100e+06, 3.68750e+02, {3.00000e-01, 7.00000e-01}, 9.13094e+03, {2.91992e-01, 7.08008e-01}, {3.03496e+03, 5.32005e+04}, {1.33538e+02, 9.73254e+02}, {2.00938e-05, 2.99598e-04}, {1.17494e+07, 2.21054e+07}, {1.16932e+07, 2.20977e+07} ), + D( 1.20100e+07, 3.67650e+02, {3.00000e-01, 7.00000e-01}, 1.57730e+04, {2.89059e-01, 7.10941e-01}, {5.77607e+03, 5.32330e+04}, {2.54147e+02, 9.79494e+02}, {2.39022e-05, 3.03214e-04}, {1.08306e+07, 2.17898e+07}, {1.07833e+07, 2.17775e+07} ), + D( 1.20100e+07, 3.68000e+02, {3.00000e-01, 7.00000e-01}, 1.57318e+04, {2.89075e-01, 7.10925e-01}, {5.75768e+03, 5.32179e+04}, {2.53338e+02, 9.79185e+02}, {2.38854e-05, 3.02064e-04}, {1.08453e+07, 2.18726e+07}, {1.07979e+07, 2.18603e+07} ), + D( 1.20100e+07, 3.68750e+02, {3.00000e-01, 7.00000e-01}, 1.56452e+04, {2.89109e-01, 7.10891e-01}, {5.71917e+03, 5.31853e+04}, {2.51643e+02, 9.78520e+02}, {2.38514e-05, 2.99598e-04}, {1.08767e+07, 2.20500e+07}, {1.08290e+07, 2.20378e+07} ) + ) +); +#undef D + +#define D( ... ) MultiFluidCO2BrineBrinePhillipsSpycherPruessTest::TestData{ __VA_ARGS__ } +INSTANTIATE_TEST_SUITE_P( + MultiFluidCO2Brine, MultiFluidCO2BrineBrinePhillipsSpycherPruessTest, + ::testing::Values( + //| pressure | temp | composition | density | phase fraction | phase density | phase mass density | phase viscosity | phase enthalpy | phase internal energy | + D( 5.00100e+06, 3.67650e+02, {3.00000e-01, 7.00000e-01}, 5.77217e+03, {3.00488e-01, 6.99512e-01}, {1.87668e+03, 5.32842e+04}, {8.25738e+01, 9.70985e+02}, {1.90427e-05, 3.03214e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 5.00100e+06, 3.68000e+02, {3.00000e-01, 7.00000e-01}, 5.76239e+03, {3.00580e-01, 6.99420e-01}, {1.87383e+03, 5.32686e+04}, {8.24487e+01, 9.70677e+02}, {1.90569e-05, 3.02064e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 5.00100e+06, 3.68750e+02, {3.00000e-01, 7.00000e-01}, 5.74154e+03, {3.00781e-01, 6.99219e-01}, {1.86780e+03, 5.32348e+04}, {8.21833e+01, 9.70013e+02}, {1.90872e-05, 2.99598e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 7.50100e+06, 3.67650e+02, {3.00000e-01, 7.00000e-01}, 9.05928e+03, {2.96731e-01, 7.03269e-01}, {3.05367e+03, 5.32295e+04}, {1.34361e+02, 9.74440e+02}, {2.00622e-05, 3.03214e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 7.50100e+06, 3.68000e+02, {3.00000e-01, 7.00000e-01}, 9.04143e+03, {2.96804e-01, 7.03196e-01}, {3.04766e+03, 5.32141e+04}, {1.34097e+02, 9.74130e+02}, {2.00722e-05, 3.02064e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 7.50100e+06, 3.68750e+02, {3.00000e-01, 7.00000e-01}, 9.00358e+03, {2.96962e-01, 7.03038e-01}, {3.03496e+03, 5.31808e+04}, {1.33538e+02, 9.73465e+02}, {2.00938e-05, 2.99598e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 1.20100e+07, 3.67650e+02, {3.00000e-01, 7.00000e-01}, 1.56195e+04, {2.93050e-01, 7.06950e-01}, {5.77607e+03, 5.32048e+04}, {2.54147e+02, 9.79798e+02}, {2.39022e-05, 3.03214e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 1.20100e+07, 3.68000e+02, {3.00000e-01, 7.00000e-01}, 1.55771e+04, {2.93105e-01, 7.06895e-01}, {5.75768e+03, 5.31894e+04}, {2.53338e+02, 9.79492e+02}, {2.38854e-05, 3.02064e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ), + D( 1.20100e+07, 3.68750e+02, {3.00000e-01, 7.00000e-01}, 1.54878e+04, {2.93225e-01, 7.06775e-01}, {5.71917e+03, 5.31561e+04}, {2.51643e+02, 9.78834e+02}, {2.38514e-05, 2.99598e-04}, {0.00000e+00, 0.00000e+00}, {0.00000e+00, 0.00000e+00} ) + ) +); +#undef D + +/* UNCRUSTIFY-ON */ + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + + geos::GeosxState state( geos::basicSetup( argc, argv ) ); + + int const result = RUN_ALL_TESTS(); + + geos::basicCleanup(); + + return result; +} diff --git a/src/coreComponents/unitTests/constitutiveTests/testMultiFluidCompositionalMultiphase.cpp b/src/coreComponents/unitTests/constitutiveTests/testMultiFluidCompositionalMultiphase.cpp new file mode 100644 index 00000000000..ffd9658a0b6 --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testMultiFluidCompositionalMultiphase.cpp @@ -0,0 +1,250 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file testMultiFluidCompositionalMultiphase.cpp + */ + +#include "MultiFluidTest.hpp" +#include "constitutive/fluid/multifluid/compositional/models/EquationOfState.hpp" +#include "constitutive/fluid/multifluid/compositional/CompositionalMultiphaseFluid.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mainInterface/initialization.hpp" + +using namespace geos; +using namespace geos::dataRepository; +using namespace geos::testing; +using namespace geos::constitutive; +using namespace geos::constitutive::compositional; + +enum class VISCOSITY_TYPE : int { CONSTANT, LBC }; +ENUM_STRINGS( VISCOSITY_TYPE, "Constant", "LohrenzBrayClark" ); + +template< VISCOSITY_TYPE VISCOSITY > +struct Viscosity {}; + +template<> +struct Viscosity< VISCOSITY_TYPE::CONSTANT > +{ + using FluidType = CompositionalTwoPhaseConstantViscosity; +}; +template<> +struct Viscosity< VISCOSITY_TYPE::LBC > +{ + using FluidType = CompositionalTwoPhaseLohrenzBrayClarkViscosity; +}; + +template< typename FluidModel, integer NUM_COMP > +struct Fluid +{}; + +template< EquationOfStateType EOS, VISCOSITY_TYPE VISCOSITY, integer NUM_COMP > +class MultiFluidCompositionalMultiphaseTest : public MultiFluidTest< typename Viscosity< VISCOSITY >::FluidType, 2, NUM_COMP > +{ +public: + using FluidModel = typename Viscosity< VISCOSITY >::FluidType; + using Base = MultiFluidTest< FluidModel, 2, NUM_COMP >; + static constexpr real64 relTol = 1.0e-4; + static constexpr real64 absTol = 1.0e-4; +public: + MultiFluidCompositionalMultiphaseTest() + { + auto & parent = this->m_parent; + parent.resize( 1 ); + + string fluidName = GEOS_FMT( "fluid{}{}{}", + NUM_COMP, + EnumStrings< EquationOfStateType >::toString( EOS ), + EnumStrings< VISCOSITY_TYPE >::toString( VISCOSITY ) ); + this->m_model = makeFluid( fluidName, &parent ); + + parent.initialize(); + parent.initializePostInitialConditions(); + } + + ~MultiFluidCompositionalMultiphaseTest() override = default; + + void testNumericalDerivatives( const bool useMass ) + { + auto & fluid = this->getFluid(); + fluid.setMassFlag( useMass ); + + auto * parent = &(this->getParent()); + + array2d< real64 > samples; + Fluid< FluidModel, Base::numComp >::getSamples( samples ); + integer const sampleCount = samples.size( 0 ); + + real64 constexpr eps = 1.0e-6; + + constexpr real64 pressures[] = { 1.0e5, 50.0e5, 100.0e5, 600.0e5 }; + constexpr real64 temperatures[] = { 15.5, 24.0, 40.0, 80.0 }; + + for( integer sampleIndex = 0; sampleIndex < sampleCount; ++sampleIndex ) + { + for( real64 const pressure : pressures ) + { + for( real64 const temperature : temperatures ) + { + typename Base::TestData data ( pressure, units::convertCToK( temperature ), samples[sampleIndex].toSliceConst() ); + Base::testNumericalDerivatives( fluid, parent, data, eps, relTol, absTol ); + } + } + } + } + +private: + static FluidModel * makeFluid( string const & name, Group * parent ); +}; + +template< integer NUM_COMP > +static void fillBinaryCoeffs( array2d< real64 > & binaryCoeff, std::array< real64 const, NUM_COMP *(NUM_COMP-1)/2 > const data ) +{ + auto bic = data.begin(); + binaryCoeff.resize( NUM_COMP, NUM_COMP ); + for( integer i = 0; i < NUM_COMP; ++i ) + { + binaryCoeff( i, i ) = 0.0; + for( integer j = i+1; j < NUM_COMP; ++j ) + { + binaryCoeff( i, j ) = *bic++; + binaryCoeff( j, i ) = binaryCoeff( i, j ); + } + } +} + +template< typename FluidModel > +struct Fluid< FluidModel, 4 > +{ + static void fillProperties( Group & fluid ) + { + string_array & componentNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::componentNamesString() ); + fill< 4 >( componentNames, {"N2", "C10", "C20", "H20"} ); + + array1d< real64 > & molarWeight = fluid.getReference< array1d< real64 > >( MultiFluidBase::viewKeyStruct::componentMolarWeightString() ); + fill< 4 >( molarWeight, {28e-3, 134e-3, 275e-3, 18e-3} ); + + array1d< real64 > & criticalPressure = fluid.getReference< array1d< real64 > >( FluidModel::viewKeyStruct::componentCriticalPressureString() ); + fill< 4 >( criticalPressure, {34e5, 25.3e5, 14.6e5, 220.5e5} ); + array1d< real64 > & criticalTemperature = fluid.getReference< array1d< real64 > >( FluidModel::viewKeyStruct::componentCriticalTemperatureString() ); + fill< 4 >( criticalTemperature, {126.2, 622.0, 782.0, 647.0} ); + array1d< real64 > & acentricFactor = fluid.getReference< array1d< real64 > >( FluidModel::viewKeyStruct::componentAcentricFactorString() ); + fill< 4 >( acentricFactor, {0.04, 0.443, 0.816, 0.344} ); + array2d< real64 > & binaryCoeff = fluid.getReference< array2d< real64 > >( FluidModel::viewKeyStruct::componentBinaryCoeffString() ); + fillBinaryCoeffs< 4 >( binaryCoeff, {0.0, 0.1, 0.0, 0.0, 0.0, 0.0} ); + } + + static void getSamples( array2d< real64 > & samples ) + { + samples.resize( 3, 4 ); + fill< 4 >( samples[0], {0.099, 0.300, 0.600, 0.001} ); + fill< 4 >( samples[1], {0.350, 0.350, 0.200, 0.100} ); + fill< 4 >( samples[2], {0.000, 0.000, 0.000, 1.000} ); + } +}; + +template< typename FluidModel > +struct Fluid< FluidModel, 5 > +{ + static void fillProperties( Group & fluid ) + { + string_array & componentNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::componentNamesString() ); + fill< 5 >( componentNames, {"CO2", "N2", "C1", "C2", "C4"} ); + + array1d< real64 > & molarWeight = fluid.getReference< array1d< real64 > >( MultiFluidBase::viewKeyStruct::componentMolarWeightString() ); + fill< 5 >( molarWeight, {44.0098e-3, 28.0135e-3, 16.0428e-3, 30.0700e-3, 82.4191e-3} ); + + array1d< real64 > & criticalPressure = fluid.getReference< array1d< real64 > >( FluidModel::viewKeyStruct::componentCriticalPressureString() ); + fill< 5 >( criticalPressure, {73.77300e5, 33.95800e5, 45.99200e5, 48.71800e5, 33.20710e5} ); + array1d< real64 > & criticalTemperature = fluid.getReference< array1d< real64 > >( FluidModel::viewKeyStruct::componentCriticalTemperatureString() ); + fill< 5 >( criticalTemperature, {304.1280, 126.1920, 190.5640, 305.3300, 504.2160} ); + array1d< real64 > & acentricFactor = fluid.getReference< array1d< real64 > >( FluidModel::viewKeyStruct::componentAcentricFactorString() ); + fill< 5 >( acentricFactor, {0.223000, 0.037200, 0.010400, 0.099100, 0.250274} ); + array1d< real64 > & volumeShift = fluid.getReference< array1d< real64 > >( FluidModel::viewKeyStruct::componentVolumeShiftString() ); + fill< 5 >( volumeShift, {1.845465e-01, -1.283880e-01, 9.225800e-02, 6.458060e-02, 0.000000e+00} ); + array2d< real64 > & binaryCoeff = fluid.getReference< array2d< real64 > >( FluidModel::viewKeyStruct::componentBinaryCoeffString() ); + fillBinaryCoeffs< 5 >( binaryCoeff, {0.0, 0.1, 0.03, 0.139, 0.032, 0.0, 0.12, 0.03, 0.0, 0.0} ); + } + + static void getSamples( array2d< real64 > & samples ) + { + samples.resize( 1, 5 ); + fill< 5 >( samples[0], {0.050, 0.150, 0.550, 0.150, 0.100} ); + } +}; +template< EquationOfStateType EOS, VISCOSITY_TYPE VISCOSITY, integer NUM_COMP > +typename MultiFluidCompositionalMultiphaseTest< EOS, VISCOSITY, NUM_COMP >::FluidModel * +MultiFluidCompositionalMultiphaseTest< EOS, VISCOSITY, NUM_COMP >:: +makeFluid( string const & name, Group * parent ) +{ + FluidModel & fluid = parent->registerGroup< FluidModel >( name ); + + string_array & phaseNames = fluid.template getReference< string_array >( MultiFluidBase::viewKeyStruct::phaseNamesString() ); + fill< 2 >( phaseNames, {"oil", "gas"} ); + + string const eosName = EnumStrings< EquationOfStateType >::toString( EOS ); + string_array & equationOfState = fluid.template getReference< string_array >( EquationOfState::viewKeyStruct::equationsOfStateString() ); + fill< 2 >( equationOfState, {eosName, eosName} ); + + Fluid< FluidModel, NUM_COMP >::fillProperties( fluid ); + + fluid.postInputInitializationRecursive(); + return &fluid; +} + +using PengRobinson4Test = MultiFluidCompositionalMultiphaseTest< EquationOfStateType::PengRobinson, VISCOSITY_TYPE::CONSTANT, 4 >; +using PengRobinsonLBC4Test = MultiFluidCompositionalMultiphaseTest< EquationOfStateType::PengRobinson, VISCOSITY_TYPE::LBC, 4 >; +using SoaveRedlichKwong4Test = MultiFluidCompositionalMultiphaseTest< EquationOfStateType::SoaveRedlichKwong, VISCOSITY_TYPE::CONSTANT, 4 >; +using SoaveRedlichKwongLBC4Test = MultiFluidCompositionalMultiphaseTest< EquationOfStateType::SoaveRedlichKwong, VISCOSITY_TYPE::LBC, 4 >; +TEST_F( PengRobinson4Test, numericalDerivativesMolar ) +{ + testNumericalDerivatives( false ); +} +TEST_F( PengRobinsonLBC4Test, numericalDerivativesMolar ) +{ + testNumericalDerivatives( false ); +} +TEST_F( SoaveRedlichKwong4Test, numericalDerivativesMolar ) +{ + testNumericalDerivatives( false ); +} +TEST_F( SoaveRedlichKwongLBC4Test, numericalDerivativesMolar ) +{ + testNumericalDerivatives( false ); +} + +using PengRobinsonLBC5Test = MultiFluidCompositionalMultiphaseTest< EquationOfStateType::PengRobinson, VISCOSITY_TYPE::LBC, 5 >; +using SoaveRedlichKwongLBC5Test = MultiFluidCompositionalMultiphaseTest< EquationOfStateType::SoaveRedlichKwong, VISCOSITY_TYPE::LBC, 5 >; +TEST_F( PengRobinsonLBC5Test, numericalDerivativesMolar ) +{ + testNumericalDerivatives( false ); +} +TEST_F( SoaveRedlichKwongLBC5Test, numericalDerivativesMolar ) +{ + testNumericalDerivatives( false ); +} + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + + geos::GeosxState state( geos::basicSetup( argc, argv ) ); + + int const result = RUN_ALL_TESTS(); + + geos::basicCleanup(); + + return result; +} diff --git a/src/coreComponents/unitTests/constitutiveTests/testMultiFluidCompositionalMultiphasePVTPackage.cpp b/src/coreComponents/unitTests/constitutiveTests/testMultiFluidCompositionalMultiphasePVTPackage.cpp new file mode 100644 index 00000000000..150da341455 --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testMultiFluidCompositionalMultiphasePVTPackage.cpp @@ -0,0 +1,200 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file testMultiFluidCompositionalMultiphasePVTPackage.cpp + */ + +#include "MultiFluidTest.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mainInterface/initialization.hpp" + +using namespace geos; +using namespace geos::testing; +using namespace geos::dataRepository; +using namespace geos::constitutive; + +namespace geos +{ +namespace testing +{ + +template< > +struct UsePVTPackage< CompositionalMultiphaseFluidPVTPackage > +{ + static constexpr bool value = true; +}; + +} // namespace testing + +} // namespace geos + +enum class EOS_TYPE : int { PR, SRK }; +ENUM_STRINGS( EOS_TYPE, "PR", "SRK" ); + +template< integer NUM_COMP > +struct Fluid +{}; + +template< EOS_TYPE EOS, integer NUM_COMP > +class MultiFluidCompositionalMultiphasePVTPackageTest : public MultiFluidTest< CompositionalMultiphaseFluidPVTPackage, 2, NUM_COMP > +{ +public: + using Base = MultiFluidTest< CompositionalMultiphaseFluidPVTPackage, 2, NUM_COMP >; + static constexpr real64 relTol = 1.0e-4; +public: + MultiFluidCompositionalMultiphasePVTPackageTest() + { + auto & parent = this->m_parent; + parent.resize( 1 ); + + string fluidName = GEOS_FMT( "fluid{}{}", EnumStrings< EOS_TYPE >::toString( EOS ), NUM_COMP ); + this->m_model = makeFluid( fluidName, &parent ); + + parent.initialize(); + parent.initializePostInitialConditions(); + } + + ~MultiFluidCompositionalMultiphasePVTPackageTest() override = default; + + void testNumericatDerivatives( const bool useMass ) + { + auto & fluid = this->getFluid(); + fluid.setMassFlag( useMass ); + + auto * parent = &(this->getParent()); + + array2d< real64 > samples; + Fluid< Base::numComp >::getSamples( samples ); + integer const sampleCount = samples.size( 0 ); + + real64 constexpr eps = 1.0e-7; + + constexpr real64 pressures[] = { 1.0e5, 50.0e5, 100.0e5, 600.0e5 }; + constexpr real64 temperatures[] = { 15.5, 24.0, 40.0, 80.0 }; + + for( integer sampleIndex = 0; sampleIndex < sampleCount; ++sampleIndex ) + { + for( real64 const pressure : pressures ) + { + for( real64 const temperature : temperatures ) + { + typename Base::TestData data ( pressure, units::convertCToK( temperature ), samples[sampleIndex].toSliceConst() ); + Base::testNumericalDerivatives( fluid, parent, data, eps, relTol ); + } + } + } + } + +private: + static CompositionalMultiphaseFluidPVTPackage * makeFluid( string const & name, Group * parent ); +}; + +template< integer NUM_COMP > +static void fillBinaryCoeffs( array2d< real64 > & binaryCoeff, std::array< real64 const, NUM_COMP *(NUM_COMP-1)/2 > const data ) +{ + auto bic = data.begin(); + binaryCoeff.resize( NUM_COMP, NUM_COMP ); + for( integer i = 0; i < NUM_COMP; ++i ) + { + binaryCoeff( i, i ) = 0.0; + for( integer j = i+1; j < NUM_COMP; ++j ) + { + binaryCoeff( i, j ) = *bic++; + binaryCoeff( j, i ) = binaryCoeff( i, j ); + } + } +} + +template< > +struct Fluid< 4 > +{ + static void fillProperties( Group & fluid ) + { + string_array & componentNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::componentNamesString() ); + fill< 4 >( componentNames, {"N2", "C10", "C20", "H20"} ); + + array1d< real64 > & molarWeight = fluid.getReference< array1d< real64 > >( MultiFluidBase::viewKeyStruct::componentMolarWeightString() ); + fill< 4 >( molarWeight, {28e-3, 134e-3, 275e-3, 18e-3} ); + + array1d< real64 > & criticalPressure = fluid.getReference< array1d< real64 > >( CompositionalMultiphaseFluidPVTPackage::viewKeyStruct::componentCriticalPressureString() ); + fill< 4 >( criticalPressure, {34e5, 25.3e5, 14.6e5, 220.5e5} ); + array1d< real64 > & criticalTemperature = fluid.getReference< array1d< real64 > >( CompositionalMultiphaseFluidPVTPackage::viewKeyStruct::componentCriticalTemperatureString() ); + fill< 4 >( criticalTemperature, {126.2, 622.0, 782.0, 647.0} ); + array1d< real64 > & acentricFactor = fluid.getReference< array1d< real64 > >( CompositionalMultiphaseFluidPVTPackage::viewKeyStruct::componentAcentricFactorString() ); + fill< 4 >( acentricFactor, {0.04, 0.443, 0.816, 0.344} ); + } + + static void getSamples( array2d< real64 > & samples ) + { + samples.resize( 2, 4 ); + fill< 4 >( samples[0], {0.099, 0.300, 0.600, 0.001} ); + fill< 4 >( samples[1], {0.000, 0.000, 0.000, 1.000} ); + } +}; + +template< EOS_TYPE EOS, integer NUM_COMP > +CompositionalMultiphaseFluidPVTPackage * +MultiFluidCompositionalMultiphasePVTPackageTest< EOS, NUM_COMP >:: +makeFluid( string const & name, Group * parent ) +{ + CompositionalMultiphaseFluidPVTPackage & fluid = parent->registerGroup< CompositionalMultiphaseFluidPVTPackage >( name ); + + string_array & phaseNames = fluid.getReference< string_array >( string( MultiFluidBase::viewKeyStruct::phaseNamesString()) ); + fill< 2 >( phaseNames, {"oil", "gas"} ); + + string const eosName = EnumStrings< EOS_TYPE >::toString( EOS ); + string_array & equationOfState = fluid.getReference< string_array >( CompositionalMultiphaseFluidPVTPackage::viewKeyStruct::equationsOfStateString() ); + fill< 2 >( equationOfState, {eosName, eosName} ); + + Fluid< NUM_COMP >::fillProperties( fluid ); + + fluid.postInputInitializationRecursive(); + return &fluid; +} + +using PengRobinson4Test = MultiFluidCompositionalMultiphasePVTPackageTest< EOS_TYPE::PR, 4 >; +using SoaveRedlichKwong4Test = MultiFluidCompositionalMultiphasePVTPackageTest< EOS_TYPE::SRK, 4 >; + +TEST_F( PengRobinson4Test, numericalDerivativesMolar ) +{ + testNumericatDerivatives( false ); +} +TEST_F( PengRobinson4Test, numericalDerivativesMass ) +{ + testNumericatDerivatives( true ); +} + +TEST_F( SoaveRedlichKwong4Test, numericalDerivativesMolar ) +{ + testNumericatDerivatives( false ); +} +TEST_F( SoaveRedlichKwong4Test, numericalDerivativesMass ) +{ + testNumericatDerivatives( true ); +} + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + + geos::GeosxState state( geos::basicSetup( argc, argv ) ); + + int const result = RUN_ALL_TESTS(); + + geos::basicCleanup(); + + return result; +} diff --git a/src/coreComponents/unitTests/constitutiveTests/testMultiFluidDeadOil.cpp b/src/coreComponents/unitTests/constitutiveTests/testMultiFluidDeadOil.cpp new file mode 100644 index 00000000000..58aefab3ed3 --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testMultiFluidDeadOil.cpp @@ -0,0 +1,277 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file testMultiFluidDeadOil.cpp + */ + +#include "MultiFluidTest.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mainInterface/initialization.hpp" + +using namespace geos; +using namespace geos::testing; +using namespace geos::dataRepository; +using namespace geos::constitutive; + +static constexpr char const * pvdgTableContent = "# Pg(Pa) Bg(m3/sm3) Visc(Pa.s)\n" + "3000000 0.04234 0.00001344\n" + "6000000 0.02046 0.0000142\n" + "9000000 0.01328 0.00001526\n" + "12000000 0.00977 0.0000166\n" + "15000000 0.00773 0.00001818\n" + "18000000 0.006426 0.00001994\n" + "21000000 0.005541 0.00002181\n" + "24000000 0.004919 0.0000237\n" + "27000000 0.004471 0.00002559 -- this is a comment\n" + "29500000 0.004194 0.00002714\n" + "31000000 0.004031 0.00002806\n" + "33000000 0.00391 0.00002832\n" + "53000000 0.003868 0.00002935"; + +static constexpr char const * pvdoTableContent = "#P[Pa] Bo[m3/sm3] Visc(Pa.s)\n" + "10000000.0 1.23331 0.00015674\n" + "12500000.0 1.21987 0.00016570\n" + "15000000.0 1.20802 0.00017445\n" + "20000000.0 1.18791 0.00019143\n" + "25000000.0 1.17137 0.00020779\n" + "30000000.0 1.15742 0.00022361\n" + "33200000.3 1.14946 0.00023359\n" + "35000000.0 1.14543 0.00023894\n" + "40000000.0 1.13498 0.00025383 -- this is a comment\n" + "50000000.0 1.11753 0.00028237\n" + "60000000.0 1.10346 0.00030941\n" + "70000000.0 1.09180 0.00033506\n" + "80000000.0 1.08194 0.00035945\n" + "90000000.0 1.07347 0.00038266\n" + "95000000.0 1.06966 0.00039384\n" + "100000000.0 1.06610 0.00040476\n" + "110000000.0 1.05961 0.00042584\n" + "112500000.0 1.05811 0.00043096\n" + "115000000.0 1.05665 0.00043602\n" + "117500000.0 1.05523 0.00044102\n" + "120000000.0 1.05385 0.00044596\n"; + +static constexpr char const * pvdwTableContent = "# Pref[Pa] Bw[m3/sm3] Cp[1/Pa] Visc[Pa.s]\n" + " 30600000.1 1.03 0.00000000041 0.0003"; + +template< bool FROM_TABLE > +class MultiFluidDeadOilTest : public MultiFluidTest< DeadOilFluid, 3, 3 > +{ +public: + static constexpr real64 relTol = 1.0e-4; + static constexpr real64 absTol = 1.0e-4; +public: + MultiFluidDeadOilTest() + { + if constexpr (!FROM_TABLE) + { + writeTableToFile( "pvdo.txt", pvdoTableContent ); + writeTableToFile( "pvdg.txt", pvdgTableContent ); + writeTableToFile( "pvdw.txt", pvdwTableContent ); + } + + m_parent.resize( 1 ); + string const fluidName = GEOS_FMT( "fluid{}", (FROM_TABLE ? "Tables" : "Files")); + m_model = makeDeadOilFluid( fluidName, &m_parent ); + + m_parent.initialize(); + m_parent.initializePostInitialConditions(); + } + + ~MultiFluidDeadOilTest() override + { + if constexpr (!FROM_TABLE) + { + removeFile( "pvdo.txt" ); + removeFile( "pvdg.txt" ); + removeFile( "pvdw.txt" ); + } + } + +private: + static DeadOilFluid * makeDeadOilFluid( string const & name, Group * parent ); + static void fillPhysicalProperties( DeadOilFluid & fluid ); +}; + +template< bool FROM_TABLE > +void MultiFluidDeadOilTest< FROM_TABLE >::fillPhysicalProperties( DeadOilFluid & fluid ) +{ + string_array & phaseNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::phaseNamesString() ); + fill< 3 >( phaseNames, {"oil", "water", "gas"} ); + + string_array & compNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::componentNamesString() ); + fill< 3 >( compNames, {"oil", "water", "gas"} ); + + array1d< real64 > & molarWgt = fluid.getReference< array1d< real64 > >( MultiFluidBase::viewKeyStruct::componentMolarWeightString() ); + fill< 3 >( molarWgt, {114e-3, 18e-3, 16e-3} ); + + array1d< real64 > & surfaceDens = fluid.getReference< array1d< real64 > >( BlackOilFluidBase::viewKeyStruct::surfacePhaseMassDensitiesString() ); + fill< 3 >( surfaceDens, {800.0, 1022.0, 0.9907} ); +} + +template<> +DeadOilFluid * MultiFluidDeadOilTest< false >::makeDeadOilFluid( string const & name, Group * parent ) +{ + DeadOilFluid & fluid = parent->registerGroup< DeadOilFluid >( name ); + + fillPhysicalProperties( fluid ); + + path_array & tableNames = fluid.getReference< path_array >( BlackOilFluidBase::viewKeyStruct::tableFilesString() ); + fill< 3 >( tableNames, {"pvdo.txt", "pvdw.txt", "pvdg.txt"} ); + + fluid.postInputInitializationRecursive(); + return &fluid; +} + +template<> +DeadOilFluid * MultiFluidDeadOilTest< true >::makeDeadOilFluid( string const & name, Group * parent ) +{ + // 1) First, define the tables (PVDO, PVDG) + + // 1D table with linear interpolation + integer constexpr NaxisPVDO = 21; + integer constexpr NaxisPVDG = 13; + + array1d< real64_array > coordinatesPVDO( 1 ); + real64_array valuesPVDO_Bo; + real64_array valuesPVDO_visc; + fill< NaxisPVDO >( coordinatesPVDO[0], { + 1.000e+07, 1.250e+07, 1.500e+07, 2.000e+07, 2.500e+07, 3.000e+07, 3.320e+07, 3.500e+07, + 4.000e+07, 5.000e+07, 6.000e+07, 7.000e+07, 8.000e+07, 9.000e+07, 9.500e+07, 1.000e+08, + 1.100e+08, 1.125e+08, 1.150e+08, 1.175e+08, 1.200e+08 } ); + fill< NaxisPVDO >( valuesPVDO_Bo, { + 1.23331, 1.21987, 1.20802, 1.18791, 1.17137, 1.15742, 1.14946, 1.14543, + 1.13498, 1.11753, 1.10346, 1.09180, 1.08194, 1.07347, 1.06966, 1.06610, + 1.05961, 1.05811, 1.05665, 1.05523, 1.05385 } ); + fill< NaxisPVDO >( valuesPVDO_visc, { + 1.56740e-04, 1.65700e-04, 1.74450e-04, 1.91430e-04, 2.07790e-04, 2.23610e-04, 2.33590e-04, 2.38940e-04, + 2.53830e-04, 2.82370e-04, 3.09410e-04, 3.35060e-04, 3.59450e-04, 3.82660e-04, 3.93840e-04, 4.04760e-04, + 4.25840e-04, 4.30960e-04, 4.36020e-04, 4.41020e-04, 4.45960e-04 } ); + + array1d< real64_array > coordinatesPVDG( 1 ); + real64_array valuesPVDG_Bg; + real64_array valuesPVDG_visc; + fill< NaxisPVDG >( coordinatesPVDG[0], { + 3.000e+06, 6.000e+06, 9.000e+06, 1.200e+07, 1.500e+07, 1.800e+07, 2.100e+07, 2.400e+07, + 2.700e+07, 2.950e+07, 3.100e+07, 3.300e+07, 5.300e+07 } ); + fill< NaxisPVDG >( valuesPVDG_Bg, { + 4.23400e-02, 2.04600e-02, 1.32800e-02, 9.77000e-03, 7.73000e-03, 6.42600e-03, 5.54100e-03, 4.91900e-03, + 4.47100e-03, 4.19400e-03, 4.03100e-03, 3.91000e-03, 3.86800e-03 } ); + fill< NaxisPVDG >( valuesPVDG_visc, { + 1.34400e-05, 1.42000e-05, 1.52600e-05, 1.66000e-05, 1.81800e-05, 1.99400e-05, 2.18100e-05, 2.37000e-05, + 2.55900e-05, 2.71400e-05, 2.80600e-05, 2.83200e-05, 2.93500e-05 } ); + + initializeTable( "PVDO_Bo", coordinatesPVDO, valuesPVDO_Bo ); + initializeTable( "PVDO_visc", coordinatesPVDO, valuesPVDO_visc ); + initializeTable( "PVDG_Bg", coordinatesPVDG, valuesPVDG_Bg ); + initializeTable( "PVDG_visc", coordinatesPVDG, valuesPVDG_visc ); + + // 2) Then, define the Dead-Oil constitutive model + + DeadOilFluid & fluid = parent->registerGroup< DeadOilFluid >( name ); + + fillPhysicalProperties( fluid ); + + string_array & FVFTableNames = fluid.getReference< string_array >( DeadOilFluid::viewKeyStruct::formationVolumeFactorTableNamesString() ); + fill< 2 >( FVFTableNames, {"PVDG_Bg", "PVDO_Bo"} ); + + string_array & viscosityTableNames = fluid.getReference< string_array >( DeadOilFluid::viewKeyStruct::viscosityTableNamesString() ); + fill< 2 >( viscosityTableNames, {"PVDG_visc", "PVDO_visc"} ); + + real64 & waterRefPressure = fluid.getReference< real64 >( DeadOilFluid::viewKeyStruct::waterRefPressureString() ); + waterRefPressure = 30600000.1; + real64 & waterFormationVolumeFactor = fluid.getReference< real64 >( DeadOilFluid::viewKeyStruct::waterFormationVolumeFactorString() ); + waterFormationVolumeFactor = 1.03; + real64 & waterCompressibility = fluid.getReference< real64 >( DeadOilFluid::viewKeyStruct::waterCompressibilityString() ); + waterCompressibility = 0.00000000041; + real64 & waterViscosity = fluid.getReference< real64 >( DeadOilFluid::viewKeyStruct::waterViscosityString() ); + waterViscosity = 0.0003; + + fluid.postInputInitializationRecursive(); + return &fluid; +} + +using MultiFluidDeadOilTestFromFiles = MultiFluidDeadOilTest< false >; +using MultiFluidDeadOilTestFromTables = MultiFluidDeadOilTest< true >; + +TEST_F( MultiFluidDeadOilTestFromFiles, numericalDerivativesMolar ) +{ + auto & fluid = getFluid(); + fluid.setMassFlag( false ); + + real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); + + for( real64 const pressure : { 1.24e7, 3.21e7, 5.01e7 } ) + { + TestData data ( pressure, 297.15, { 0.1, 0.3, 0.6 } ); + testNumericalDerivatives( fluid, &getParent(), data, eps, relTol, absTol ); + } +} + +TEST_F( MultiFluidDeadOilTestFromFiles, numericalDerivativesMass ) +{ + auto & fluid = getFluid(); + fluid.setMassFlag( true ); + + real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); + + for( real64 const pressure : { 1.24e7, 3.21e7, 5.01e7 } ) + { + TestData data ( pressure, 297.15, { 0.1, 0.3, 0.6 } ); + testNumericalDerivatives( fluid, &getParent(), data, eps, relTol, absTol ); + } +} + +TEST_F( MultiFluidDeadOilTestFromTables, numericalDerivativesMolar ) +{ + auto & fluid = getFluid(); + fluid.setMassFlag( false ); + + real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); + + for( real64 const pressure : { 1.24e7, 3.21e7, 5.01e7 } ) + { + TestData data ( pressure, 297.15, { 0.1, 0.3, 0.6 } ); + testNumericalDerivatives( fluid, &getParent(), data, eps, relTol, absTol ); + } +} + +TEST_F( MultiFluidDeadOilTestFromTables, numericalDerivativesMass ) +{ + auto & fluid = getFluid(); + fluid.setMassFlag( true ); + + real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); + + for( real64 const pressure : { 1.24e7, 3.21e7, 5.01e7 } ) + { + TestData data ( pressure, 297.15, { 0.1, 0.3, 0.6 } ); + testNumericalDerivatives( fluid, &getParent(), data, eps, relTol, absTol ); + } +} + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + + geos::GeosxState state( geos::basicSetup( argc, argv ) ); + + int const result = RUN_ALL_TESTS(); + + geos::basicCleanup(); + + return result; +} diff --git a/src/coreComponents/unitTests/constitutiveTests/testMultiFluidLiveOil.cpp b/src/coreComponents/unitTests/constitutiveTests/testMultiFluidLiveOil.cpp new file mode 100644 index 00000000000..37ac3043753 --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testMultiFluidLiveOil.cpp @@ -0,0 +1,170 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file testMultiFluidLiveOil.cpp + */ + +#include "MultiFluidTest.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mainInterface/initialization.hpp" + +using namespace geos; +using namespace geos::testing; +using namespace geos::dataRepository; +using namespace geos::constitutive; + +static constexpr char const * pvdgTableContent = "# Pg(Pa) Bg(m3/sm3) Visc(Pa.s)\n" + "3000000 0.04234 0.00001344\n" + "6000000 0.02046 0.0000142\n" + "9000000 0.01328 0.00001526\n" + "12000000 0.00977 0.0000166\n" + "15000000 0.00773 0.00001818\n" + "18000000 0.006426 0.00001994\n" + "21000000 0.005541 0.00002181\n" + "24000000 0.004919 0.0000237\n" + "27000000 0.004471 0.00002559 -- this is a comment\n" + "29500000 0.004194 0.00002714\n" + "31000000 0.004031 0.00002806\n" + "33000000 0.00391 0.00002832\n" + "53000000 0.003868 0.00002935"; + +static const char * pvtoTableContent = "# Rs[sm3/sm3]\tPbub[Pa]\tBo[m3/sm3]\tVisc(Pa.s)\n" + "\n" + " 2\t 2000000\t 1.02\t 0.000975\n" + " 5\t 5000000\t 1.03\t 0.00091\n" + " 10\t 10000000\t1.04\t 0.00083\n" + " 15\t 20000000\t1.05\t 0.000695\n" + " 90000000\t1.03\t 0.000985 -- some line comment\n" + " 30\t 30000000\t1.07\t 0.000594\n" + " 40\t 40000000\t1.08\t 0.00051\n" + " 50000000\t1.07\t 0.000549 -- another one\n" + " 90000000\t1.06\t 0.00074\n" + " 50\t 50000000.7\t1.09\t 0.000449\n" + " 90000000.7\t1.08\t 0.000605"; + +static const char * pvtwTableContent = "#\tPref[Pa]\tBw[m3/sm3]\tCp[1/Pa]\t Visc[Pa.s]\n" + "\t30600000.1\t1.03\t\t0.00000000041\t0.0003"; + +class MultiFluidLiveOilTest : public MultiFluidTest< BlackOilFluid, 3, 3 > +{ +public: + static constexpr real64 relTol = 1.0e-4; + static constexpr real64 absTol = 1.0e-4; +public: + MultiFluidLiveOilTest() + { + writeTableToFile( pvtoFileName, pvtoTableContent ); + writeTableToFile( pvdgFileName, pvdgTableContent ); + writeTableToFile( pvtwFileName, pvtwTableContent ); + + m_parent.resize( 1 ); + m_model = makeLiveOilFluid( "fluid", &m_parent ); + + m_parent.initialize(); + m_parent.initializePostInitialConditions(); + } + + ~MultiFluidLiveOilTest() override + { + removeFile( pvtoFileName ); + removeFile( pvdgFileName ); + removeFile( pvtwFileName ); + } + +private: + static BlackOilFluid * makeLiveOilFluid( string const & name, Group * parent ); + static constexpr const char * pvtoFileName = "pvto.txt"; + static constexpr const char * pvdgFileName = "pvdg.txt"; + static constexpr const char * pvtwFileName = "pvtw.txt"; +}; + +BlackOilFluid * MultiFluidLiveOilTest::makeLiveOilFluid( string const & name, Group * parent ) +{ + BlackOilFluid & fluid = parent->registerGroup< BlackOilFluid >( name ); + + string_array & phaseNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::phaseNamesString() ); + fill< 3 >( phaseNames, {"oil", "gas", "water"} ); + + string_array & compNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::componentNamesString() ); + fill< 3 >( compNames, {"oil", "gas", "water"} ); + + array1d< real64 > & molarWgt = fluid.getReference< array1d< real64 > >( MultiFluidBase::viewKeyStruct::componentMolarWeightString() ); + fill< 3 >( molarWgt, {114e-3, 16e-3, 18e-3} ); + + array1d< real64 > & surfaceDens = fluid.getReference< array1d< real64 > >( BlackOilFluidBase::viewKeyStruct::surfacePhaseMassDensitiesString() ); + fill< 3 >( surfaceDens, {800.0, 0.9907, 1022.0} ); + + path_array & tableNames = fluid.getReference< path_array >( BlackOilFluidBase::viewKeyStruct::tableFilesString() ); + fill< 3 >( tableNames, {pvtoFileName, pvdgFileName, pvtwFileName} ); + + fluid.postInputInitializationRecursive(); + return &fluid; +} + +TEST_F( MultiFluidLiveOilTest, numericalDerivativesMolar ) +{ + auto & fluid = getFluid(); + fluid.setMassFlag( false ); + + real64 constexpr eps = 1.0e-6; + + array2d< real64 > samples( 2, 3 ); + fill< 3 >( samples[0], { 0.10000, 0.3, 0.60000 } ); + fill< 3 >( samples[1], { 0.79999, 0.2, 0.00001 } ); + + for( real64 const pressure : { 1.24e7, 3.21e7, 5.01e7 } ) + { + for( integer sampleIndex = 0; sampleIndex < samples.size( 0 ); sampleIndex++ ) + { + TestData data ( pressure, 297.15, samples[sampleIndex] ); + testNumericalDerivatives( fluid, &getParent(), data, eps, relTol, absTol ); + } + } +} + +TEST_F( MultiFluidLiveOilTest, numericalDerivativesMass ) +{ + auto & fluid = getFluid(); + fluid.setMassFlag( true ); + + real64 constexpr eps = 1.0e-6; + + array2d< real64 > samples( 2, 3 ); + fill< 3 >( samples[0], { 0.10000, 0.3, 0.60000 } ); + fill< 3 >( samples[1], { 0.79999, 0.2, 0.00001 } ); + + for( real64 const pressure : { 1.24e7, 3.21e7, 5.01e7 } ) + { + for( integer sampleIndex = 0; sampleIndex < samples.size( 0 ); sampleIndex++ ) + { + TestData data ( pressure, 297.15, samples[sampleIndex] ); + testNumericalDerivatives( fluid, &getParent(), data, eps, relTol, absTol ); + } + } +} + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + + geos::GeosxState state( geos::basicSetup( argc, argv ) ); + + int const result = RUN_ALL_TESTS(); + + geos::basicCleanup(); + + return result; +} diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT.cpp b/src/coreComponents/unitTests/constitutiveTests/testPVT.cpp index 16cd497b723..205153ceda8 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testPVT.cpp +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,7 +22,7 @@ #include #include -// this unit test basically launches a full geosx instance, and then uses the +// this unit test basically launches a full geos instance, and then uses the // input xml to launch a PVTDriver task TEST( testPVT, testPVT ) diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT.xml b/src/coreComponents/unitTests/constitutiveTests/testPVT.xml index aacf9b001c0..cb59ac5f35c 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testPVT.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT.xml @@ -113,7 +113,7 @@ diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT_CO2Brine.xml b/src/coreComponents/unitTests/constitutiveTests/testPVT_CO2Brine.xml index 7363117393c..a48e22dfbe5 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testPVT_CO2Brine.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT_CO2Brine.xml @@ -46,6 +46,28 @@ outputPhaseComposition="1" baseline="testPVT_CO2Brine_testCo2BrineEzrokhiMixtureB.txt" logLevel="1" /> + + + + @@ -79,6 +107,13 @@ componentMolarWeight="{ 44e-3, 18e-3 }" phasePVTParaFiles="{ testPVT_data/carbonDioxidePVT.txt, testPVT_data/brinePVTEzrokhi.txt }" flashModelParaFile="testPVT_data/carbonDioxideFlash.txt" /> + @@ -112,7 +147,7 @@ diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT_CO2BrineTables.xml b/src/coreComponents/unitTests/constitutiveTests/testPVT_CO2BrineTables.xml index 4a667e05691..4db6d9f6b7a 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testPVT_CO2BrineTables.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT_CO2BrineTables.xml @@ -96,7 +96,7 @@ diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT_CO2Brine_testCo2SpycherPruessBrinePhillipsMixtureA.txt b/src/coreComponents/unitTests/constitutiveTests/testPVT_CO2Brine_testCo2SpycherPruessBrinePhillipsMixtureA.txt new file mode 100644 index 00000000000..0a33d6dc22e --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT_CO2Brine_testCo2SpycherPruessBrinePhillipsMixtureA.txt @@ -0,0 +1,31 @@ +# column 1 = time +# column 2 = pressure +# column 3 = temperature +# column 4 = density +# column 5 = total compressibility +# columns 6-7 = phase fractions +# columns 8-9 = phase densities +# columns 10-11 = phase viscosities +# columns 12-13 = gas phase fractions [co2, water] +# columns 14-15 = water phase fractions [co2, water] +0.0000e+00 1.0000e+06 3.5000e+02 6.7780e+01 2.1337e-08 2.1773e-01 7.8227e-01 1.5581e+01 1.0033e+03 1.7476e-05 4.1330e-04 9.5589e-01 4.4112e-02 2.2320e-03 9.9777e-01 +5.0000e-02 6.4444e+06 3.5000e+02 4.2328e+02 1.3988e-07 1.9253e-01 8.0747e-01 1.2309e+02 1.0114e+03 1.8998e-05 4.1330e-04 9.8984e-01 1.0158e-02 1.1731e-02 9.8827e-01 +1.0000e-01 1.1889e+07 3.5000e+02 7.1407e+02 6.1644e-08 1.8180e-01 8.1820e-01 3.0497e+02 1.0173e+03 2.5353e-05 4.1330e-04 9.9079e-01 9.2115e-03 1.7035e-02 9.8297e-01 +1.5000e-01 1.7333e+07 3.5000e+02 8.8262e+02 1.8484e-08 1.7661e-01 8.2339e-01 5.3970e+02 1.0219e+03 4.0932e-05 4.1330e-04 9.8874e-01 1.1255e-02 1.9789e-02 9.8021e-01 +2.0000e-01 2.2778e+07 3.5000e+02 9.3903e+02 7.0636e-09 1.7314e-01 8.2686e-01 6.6850e+02 1.0260e+03 5.3806e-05 4.1330e-04 9.8725e-01 1.2749e-02 2.1623e-02 9.7838e-01 +2.5000e-01 2.8222e+07 3.5000e+02 9.6553e+02 3.7969e-09 1.7065e-01 8.2935e-01 7.4098e+02 1.0297e+03 6.3051e-05 4.1330e-04 9.8650e-01 1.3500e-02 2.2909e-02 9.7709e-01 +3.0000e-01 3.3667e+07 3.5000e+02 9.8236e+02 2.6667e-09 1.6883e-01 8.3117e-01 7.9054e+02 1.0333e+03 7.0528e-05 4.1330e-04 9.8604e-01 1.3961e-02 2.3841e-02 9.7616e-01 +3.5000e-01 3.9111e+07 3.5000e+02 9.9478e+02 2.0090e-09 1.6746e-01 8.3254e-01 8.2831e+02 1.0367e+03 7.7028e-05 4.1330e-04 9.8571e-01 1.4290e-02 2.4538e-02 9.7546e-01 +4.0000e-01 4.4556e+07 3.5000e+02 1.0047e+03 1.6650e-09 1.6641e-01 8.3359e-01 8.5890e+02 1.0400e+03 8.2914e-05 4.1330e-04 9.8545e-01 1.4547e-02 2.5069e-02 9.7493e-01 +4.5000e-01 5.0000e+07 3.5000e+02 1.0131e+03 5.1360e-11 1.6561e-01 8.3439e-01 8.8476e+02 1.0432e+03 8.8389e-05 4.1330e-04 9.8524e-01 1.4761e-02 2.5477e-02 9.7452e-01 +5.0000e-01 3.0000e+07 3.0400e+02 9.8816e+02 2.6607e-09 1.6844e-01 8.3156e-01 8.0121e+02 1.0372e+03 7.1971e-05 8.6631e-04 9.8918e-01 1.0819e-02 2.3786e-02 9.7621e-01 +5.5000e-01 1.0000e+07 2.5800e+02 6.6430e+02 8.2527e-08 1.8156e-01 8.1844e-01 2.5862e+02 1.0189e+03 2.2796e-05 1.9511e-03 9.9359e-01 6.4066e-03 1.6921e-02 9.8308e-01 +6.0000e-01 1.0000e+07 2.7156e+02 6.6481e+02 8.2643e-08 1.8156e-01 8.1844e-01 2.5862e+02 1.0203e+03 2.2796e-05 1.9588e-03 9.9359e-01 6.4066e-03 1.6921e-02 9.8308e-01 +6.5000e-01 1.0000e+07 2.8511e+02 6.6522e+02 8.2733e-08 1.8156e-01 8.1844e-01 2.5862e+02 1.0215e+03 2.2796e-05 1.3681e-03 9.9359e-01 6.4066e-03 1.6921e-02 9.8308e-01 +7.0000e-01 1.0000e+07 2.9867e+02 6.6551e+02 8.2800e-08 1.8156e-01 8.1844e-01 2.5862e+02 1.0223e+03 2.2796e-05 9.7022e-04 9.9359e-01 6.4066e-03 1.6921e-02 9.8308e-01 +7.5000e-01 1.0000e+07 3.1222e+02 6.6570e+02 8.2842e-08 1.8156e-01 8.1844e-01 2.5862e+02 1.0229e+03 2.2796e-05 7.3691e-04 9.9359e-01 6.4066e-03 1.6921e-02 9.8308e-01 +8.0000e-01 1.0000e+07 3.2578e+02 6.6579e+02 8.2862e-08 1.8156e-01 8.1844e-01 2.5862e+02 1.0231e+03 2.2796e-05 5.8345e-04 9.9359e-01 6.4066e-03 1.6921e-02 9.8308e-01 +8.5000e-01 1.0000e+07 3.3933e+02 6.6563e+02 8.2888e-08 1.8167e-01 8.1833e-01 2.5862e+02 1.0231e+03 2.2796e-05 4.7645e-04 9.9353e-01 6.4726e-03 1.6875e-02 9.8313e-01 +9.0000e-01 1.0000e+07 3.5289e+02 6.1186e+02 7.9623e-08 1.8498e-01 8.1502e-01 2.2287e+02 1.0133e+03 2.2020e-05 3.9764e-04 9.9066e-01 9.3377e-03 1.5456e-02 9.8454e-01 +9.5000e-01 1.0000e+07 3.6644e+02 5.8928e+02 7.7989e-08 1.8498e-01 8.1502e-01 2.0825e+02 1.0078e+03 2.1800e-05 3.4093e-04 9.9066e-01 9.3377e-03 1.5456e-02 9.8454e-01 +1.0000e+00 1.0000e+07 3.8000e+02 5.8907e+02 7.7935e-08 1.8498e-01 8.1502e-01 2.0825e+02 1.0070e+03 2.1860e-05 2.9672e-04 9.9066e-01 9.3377e-03 1.5456e-02 9.8454e-01 diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT_CO2Brine_testCo2SpycherPruessBrinePhillipsMixtureB.txt b/src/coreComponents/unitTests/constitutiveTests/testPVT_CO2Brine_testCo2SpycherPruessBrinePhillipsMixtureB.txt new file mode 100644 index 00000000000..762ffae5a75 --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT_CO2Brine_testCo2SpycherPruessBrinePhillipsMixtureB.txt @@ -0,0 +1,31 @@ +# column 1 = time +# column 2 = pressure +# column 3 = temperature +# column 4 = density +# column 5 = total compressibility +# columns 6-7 = phase fractions +# columns 8-9 = phase densities +# columns 10-11 = phase viscosities +# columns 12-13 = gas phase fractions [co2, water] +# columns 14-15 = water phase fractions [co2, water] +0.0000e+00 1.0000e+06 3.5000e+02 2.9256e+01 8.7493e-09 5.2521e-01 4.7479e-01 1.5581e+01 1.0033e+03 1.7476e-05 4.1330e-04 9.5589e-01 4.4112e-02 2.2320e-03 9.9777e-01 +5.0000e-02 6.4444e+06 3.5000e+02 2.1910e+02 1.8135e-07 5.0111e-01 4.9889e-01 1.2309e+02 1.0114e+03 1.8998e-05 4.1330e-04 9.8984e-01 1.0158e-02 1.1731e-02 9.8827e-01 +1.0000e-01 1.1889e+07 3.5000e+02 4.7218e+02 1.0761e-07 4.9425e-01 5.0575e-01 3.0497e+02 1.0173e+03 2.5353e-05 4.1330e-04 9.9079e-01 9.2115e-03 1.7035e-02 9.8297e-01 +1.5000e-01 1.7333e+07 3.5000e+02 7.1004e+02 3.9438e-08 4.9158e-01 5.0842e-01 5.3970e+02 1.0219e+03 4.0932e-05 4.1330e-04 9.8874e-01 1.1255e-02 1.9789e-02 9.8021e-01 +2.0000e-01 2.2778e+07 3.5000e+02 8.1301e+02 1.5784e-08 4.8984e-01 5.1016e-01 6.6850e+02 1.0260e+03 5.3806e-05 4.1330e-04 9.8725e-01 1.2749e-02 2.1623e-02 9.7838e-01 +2.5000e-01 2.8222e+07 3.5000e+02 8.6506e+02 8.4258e-09 4.8850e-01 5.1150e-01 7.4098e+02 1.0297e+03 6.3051e-05 4.1330e-04 9.8650e-01 1.3500e-02 2.2909e-02 9.7709e-01 +3.0000e-01 3.3667e+07 3.5000e+02 8.9875e+02 5.8443e-09 4.8750e-01 5.1250e-01 7.9054e+02 1.0333e+03 7.0528e-05 4.1330e-04 9.8604e-01 1.3961e-02 2.3841e-02 9.7616e-01 +3.5000e-01 3.9111e+07 3.5000e+02 9.2359e+02 4.2911e-09 4.8675e-01 5.1325e-01 8.2831e+02 1.0367e+03 7.7028e-05 4.1330e-04 9.8571e-01 1.4290e-02 2.4538e-02 9.7546e-01 +4.0000e-01 4.4556e+07 3.5000e+02 9.4329e+02 3.4823e-09 4.8618e-01 5.1382e-01 8.5890e+02 1.0400e+03 8.2914e-05 4.1330e-04 9.8545e-01 1.4547e-02 2.5069e-02 9.7493e-01 +4.5000e-01 5.0000e+07 3.5000e+02 9.5970e+02 2.8240e-11 4.8574e-01 5.1426e-01 8.8476e+02 1.0432e+03 8.8389e-05 4.1330e-04 9.8524e-01 1.4761e-02 2.5477e-02 9.7452e-01 +5.0000e-01 3.0000e+07 3.0400e+02 9.0721e+02 5.8529e-09 4.8643e-01 5.1357e-01 8.0121e+02 1.0372e+03 7.1971e-05 8.6631e-04 9.8918e-01 1.0819e-02 2.3786e-02 9.7621e-01 +5.5000e-01 1.0000e+07 2.5800e+02 4.1580e+02 1.3435e-07 4.9338e-01 5.0662e-01 2.5862e+02 1.0189e+03 2.2796e-05 1.9511e-03 9.9359e-01 6.4066e-03 1.6921e-02 9.8308e-01 +6.0000e-01 1.0000e+07 2.7156e+02 4.1592e+02 1.3441e-07 4.9338e-01 5.0662e-01 2.5862e+02 1.0203e+03 2.2796e-05 1.9588e-03 9.9359e-01 6.4066e-03 1.6921e-02 9.8308e-01 +6.5000e-01 1.0000e+07 2.8511e+02 4.1602e+02 1.3446e-07 4.9338e-01 5.0662e-01 2.5862e+02 1.0215e+03 2.2796e-05 1.3681e-03 9.9359e-01 6.4066e-03 1.6921e-02 9.8308e-01 +7.0000e-01 1.0000e+07 2.9867e+02 4.1609e+02 1.3449e-07 4.9338e-01 5.0662e-01 2.5862e+02 1.0223e+03 2.2796e-05 9.7022e-04 9.9359e-01 6.4066e-03 1.6921e-02 9.8308e-01 +7.5000e-01 1.0000e+07 3.1222e+02 4.1614e+02 1.3452e-07 4.9338e-01 5.0662e-01 2.5862e+02 1.0229e+03 2.2796e-05 7.3691e-04 9.9359e-01 6.4066e-03 1.6921e-02 9.8308e-01 +8.0000e-01 1.0000e+07 3.2578e+02 4.1616e+02 1.3453e-07 4.9338e-01 5.0662e-01 2.5862e+02 1.0231e+03 2.2796e-05 5.8345e-04 9.9359e-01 6.4066e-03 1.6921e-02 9.8308e-01 +8.5000e-01 1.0000e+07 3.3933e+02 4.1611e+02 1.3454e-07 4.9346e-01 5.0654e-01 2.5862e+02 1.0231e+03 2.2796e-05 4.7645e-04 9.9353e-01 6.4726e-03 1.6875e-02 9.8313e-01 +9.0000e-01 1.0000e+07 3.5289e+02 3.6713e+02 1.2176e-07 4.9624e-01 5.0376e-01 2.2287e+02 1.0133e+03 2.2020e-05 3.9764e-04 9.9066e-01 9.3377e-03 1.5456e-02 9.8454e-01 +9.5000e-01 1.0000e+07 3.6644e+02 3.4688e+02 1.1663e-07 4.9624e-01 5.0376e-01 2.0825e+02 1.0078e+03 2.1800e-05 3.4093e-04 9.9066e-01 9.3377e-03 1.5456e-02 9.8454e-01 +1.0000e+00 1.0000e+07 3.8000e+02 3.4684e+02 1.1661e-07 4.9624e-01 5.0376e-01 2.0825e+02 1.0070e+03 2.1860e-05 2.9672e-04 9.9066e-01 9.3377e-03 1.5456e-02 9.8454e-01 diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT_Compositional.xml b/src/coreComponents/unitTests/constitutiveTests/testPVT_Compositional.xml new file mode 100644 index 00000000000..2d811787db2 --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT_Compositional.xml @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT_Compositional_liveOilPR.txt b/src/coreComponents/unitTests/constitutiveTests/testPVT_Compositional_liveOilPR.txt new file mode 100644 index 00000000000..d0479350bf9 --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT_Compositional_liveOilPR.txt @@ -0,0 +1,112 @@ +# column 1 = time +# column 2 = pressure +# column 3 = temperature +# column 4 = density +# column 5 = total compressibility +# columns 6-7 = phase fractions +# columns 8-9 = phase densities +# columns 10-11 = phase mass densities +# columns 12-13 = phase viscosities +# columns 14-22 = oil phase fractions [CO2, N2, C1, C2, C3, C4, C5, C6, C7+] +# columns 23-31 = gas phase fractions [CO2, N2, C1, C2, C3, C4, C5, C6, C7+] +0.0000e+00 3.5000e+07 5.5315e+02 6.8078e+03 1.3932e-08 1.0000e+00 0.0000e+00 6.8078e+03 6.8078e+03 3.4772e+02 3.4772e+02 1.0000e-03 1.0000e-03 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +2.0000e-02 3.4000e+07 5.5315e+02 6.7113e+03 1.4639e-08 1.0000e+00 0.0000e+00 6.7113e+03 6.7113e+03 3.4279e+02 3.4279e+02 1.0000e-03 1.0000e-03 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +4.0000e-02 3.3000e+07 5.5315e+02 6.6112e+03 1.5406e-08 1.0000e+00 0.0000e+00 6.6112e+03 6.6112e+03 3.3768e+02 3.3768e+02 1.0000e-03 1.0000e-03 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +6.0000e-02 3.2000e+07 5.5315e+02 6.5075e+03 1.6240e-08 1.0000e+00 0.0000e+00 6.5075e+03 6.5075e+03 3.3238e+02 3.3238e+02 1.0000e-03 1.0000e-03 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +8.0000e-02 3.1000e+07 5.5315e+02 6.3998e+03 1.7151e-08 0.0000e+00 1.0000e+00 6.3998e+03 6.3998e+03 3.2688e+02 3.2688e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0000e-01 3.0000e+07 5.5315e+02 6.2879e+03 1.8147e-08 0.0000e+00 1.0000e+00 6.2879e+03 6.2879e+03 3.2117e+02 3.2117e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2000e-01 2.9000e+07 5.5315e+02 6.1715e+03 1.9240e-08 0.0000e+00 1.0000e+00 6.1715e+03 6.1715e+03 3.1522e+02 3.1522e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4000e-01 2.8000e+07 5.5315e+02 6.0503e+03 2.0443e-08 0.0000e+00 1.0000e+00 6.0503e+03 6.0503e+03 3.0903e+02 3.0903e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6000e-01 2.7000e+07 5.5315e+02 5.9240e+03 2.1772e-08 0.0000e+00 1.0000e+00 5.9240e+03 5.9240e+03 3.0258e+02 3.0258e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8000e-01 2.6000e+07 5.5315e+02 5.7922e+03 2.3244e-08 0.0000e+00 1.0000e+00 5.7922e+03 5.7922e+03 2.9585e+02 2.9585e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0000e-01 2.5000e+07 5.5315e+02 5.6546e+03 2.4879e-08 0.0000e+00 1.0000e+00 5.6546e+03 5.6546e+03 2.8882e+02 2.8882e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.2000e-01 2.4000e+07 5.5315e+02 5.5107e+03 2.6704e-08 0.0000e+00 1.0000e+00 5.5107e+03 5.5107e+03 2.8147e+02 2.8147e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.4000e-01 2.3000e+07 5.5315e+02 5.3601e+03 2.8747e-08 0.0000e+00 1.0000e+00 5.3601e+03 5.3601e+03 2.7378e+02 2.7378e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.6000e-01 2.2000e+07 5.5315e+02 5.2024e+03 3.1042e-08 0.0000e+00 1.0000e+00 5.2024e+03 5.2024e+03 2.6572e+02 2.6572e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.8000e-01 2.1000e+07 5.5315e+02 5.0370e+03 3.3630e-08 0.0000e+00 1.0000e+00 5.0370e+03 5.0370e+03 2.5728e+02 2.5728e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.0000e-01 2.0000e+07 5.5315e+02 4.8634e+03 3.6560e-08 0.0000e+00 1.0000e+00 4.8634e+03 4.8634e+03 2.4841e+02 2.4841e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.2000e-01 1.9000e+07 5.5315e+02 4.6812e+03 3.9890e-08 0.0000e+00 1.0000e+00 4.6812e+03 4.6812e+03 2.3910e+02 2.3910e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.4000e-01 1.8000e+07 5.5315e+02 4.4898e+03 4.3686e-08 0.0000e+00 1.0000e+00 4.4898e+03 4.4898e+03 2.2933e+02 2.2933e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.6000e-01 1.7000e+07 5.5315e+02 4.2898e+03 4.6261e-08 4.5641e-02 9.5436e-01 4.7351e+03 4.2706e+03 3.3247e+02 2.1533e+02 1.0000e-03 1.0000e-03 7.6825e-03 2.2373e-03 4.2618e-01 1.0167e-01 8.3774e-02 4.6651e-02 2.2890e-02 1.7745e-02 2.9117e-01 9.0452e-03 3.0262e-03 5.3843e-01 1.1504e-01 8.8042e-02 4.5564e-02 2.0832e-02 1.5009e-02 1.6501e-01 +3.8000e-01 1.6000e+07 5.5315e+02 4.0893e+03 4.9564e-08 1.8812e-01 8.1188e-01 4.6823e+03 3.9727e+03 3.6079e+02 1.8822e+02 1.0000e-03 1.0000e-03 7.1915e-03 1.9892e-03 3.8884e-01 9.6576e-02 8.1672e-02 4.6619e-02 2.3403e-02 1.8552e-02 3.3516e-01 9.2576e-03 3.1440e-03 5.5548e-01 1.1717e-01 8.8787e-02 4.5455e-02 2.0543e-02 1.4608e-02 1.4556e-01 +4.0000e-01 1.5000e+07 5.5315e+02 3.8842e+03 5.3440e-08 2.4423e-01 7.5577e-01 4.6085e+03 3.6965e+03 3.8231e+02 1.6795e+02 1.0000e-03 1.0000e-03 6.7572e-03 1.7894e-03 3.5754e-01 9.1894e-02 7.9461e-02 4.6321e-02 2.3709e-02 1.9148e-02 3.7339e-01 9.3969e-03 3.2143e-03 5.6606e-01 1.1862e-01 8.9394e-02 4.5472e-02 2.0403e-02 1.4383e-02 1.3306e-01 +4.2000e-01 1.4000e+07 5.5315e+02 3.6739e+03 5.8034e-08 2.7428e-01 7.2572e-01 4.5259e+03 3.4299e+03 4.0050e+02 1.5105e+02 1.0000e-03 1.0000e-03 6.3418e-03 1.6141e-03 3.2902e-01 8.7264e-02 7.7032e-02 4.5789e-02 2.3863e-02 1.9608e-02 4.0947e-01 9.5000e-03 3.2607e-03 5.7339e-01 1.1974e-01 8.9944e-02 4.5565e-02 2.0343e-02 1.4252e-02 1.2401e-01 +4.4000e-01 1.3000e+07 5.5315e+02 3.4575e+03 6.3540e-08 2.9189e-01 7.0811e-01 4.4387e+03 3.1688e+03 4.1665e+02 1.3625e+02 1.0000e-03 1.0000e-03 5.9319e-03 1.4546e-03 3.0213e-01 8.2554e-02 7.4331e-02 4.5021e-02 2.3875e-02 1.9947e-02 4.4476e-01 9.5793e-03 3.2918e-03 5.7862e-01 1.2065e-01 9.0462e-02 4.5709e-02 2.0338e-02 1.4185e-02 1.1717e-01 +4.6000e-01 1.2000e+07 5.5315e+02 3.2342e+03 7.0225e-08 3.0194e-01 6.9806e-01 4.3489e+03 2.9114e+03 4.3138e+02 1.2292e+02 1.0000e-03 1.0000e-03 5.5208e-03 1.3065e-03 2.7628e-01 7.7691e-02 7.1321e-02 4.4001e-02 2.3741e-02 2.0165e-02 4.7998e-01 9.6405e-03 3.3118e-03 5.8228e-01 1.2140e-01 9.0952e-02 4.5894e-02 2.0377e-02 1.4168e-02 1.1198e-01 +4.8000e-01 1.1000e+07 5.5315e+02 3.0029e+03 7.8464e-08 3.0653e-01 6.9347e-01 4.2574e+03 2.6569e+03 4.4506e+02 1.1069e+02 1.0000e-03 1.0000e-03 5.1047e-03 1.1672e-03 2.5115e-01 7.2629e-02 6.7965e-02 4.2709e-02 2.3447e-02 2.0250e-02 5.1558e-01 9.6862e-03 3.3228e-03 5.8465e-01 1.2199e-01 9.1412e-02 4.6109e-02 2.0451e-02 1.4193e-02 1.0818e-01 +5.0000e-01 1.0000e+07 5.5315e+02 2.7626e+03 8.8797e-08 3.0652e-01 6.9348e-01 4.1650e+03 2.4047e+03 4.5794e+02 9.9319e+01 1.0000e-03 1.0000e-03 4.6810e-03 1.0353e-03 2.2653e-01 6.7336e-02 6.4228e-02 4.1113e-02 2.2974e-02 2.0183e-02 5.5192e-01 9.7171e-03 3.3262e-03 5.8587e-01 1.2245e-01 9.1830e-02 4.6345e-02 2.0556e-02 1.4256e-02 1.0566e-01 +5.2000e-01 9.6040e+06 5.5315e+02 2.6646e+03 9.3634e-08 3.0530e-01 6.9470e-01 4.1282e+03 2.3054e+03 4.6286e+02 9.5019e+01 1.0000e-03 1.0000e-03 4.5107e-03 9.8476e-04 2.1689e-01 6.5170e-02 6.2635e-02 4.0391e-02 2.2731e-02 2.0109e-02 5.6658e-01 9.7252e-03 3.3256e-03 5.8604e-01 1.2259e-01 9.1982e-02 4.6442e-02 2.0604e-02 1.4291e-02 1.0500e-01 +5.4000e-01 9.2080e+06 5.5315e+02 2.5649e+03 9.8987e-08 3.0338e-01 6.9662e-01 4.0913e+03 2.2065e+03 4.6768e+02 9.0820e+01 1.0000e-03 1.0000e-03 4.3389e-03 9.3517e-04 2.0731e-01 6.2962e-02 6.0974e-02 3.9613e-02 2.2454e-02 2.0005e-02 5.8141e-01 9.7309e-03 3.3238e-03 5.8604e-01 1.2270e-01 9.2122e-02 4.6539e-02 2.0656e-02 1.4331e-02 1.0456e-01 +5.6000e-01 8.8120e+06 5.5315e+02 2.4635e+03 1.0494e-07 3.0072e-01 6.9928e-01 4.0544e+03 2.1078e+03 4.7243e+02 8.6716e+01 1.0000e-03 1.0000e-03 4.1655e-03 8.8643e-04 1.9777e-01 6.0710e-02 5.9243e-02 3.8777e-02 2.2141e-02 1.9868e-02 5.9644e-01 9.7341e-03 3.3209e-03 5.8586e-01 1.2278e-01 9.2251e-02 4.6636e-02 2.0712e-02 1.4376e-02 1.0433e-01 +5.8000e-01 8.4160e+06 5.5315e+02 2.3602e+03 1.1158e-07 2.9729e-01 7.0271e-01 4.0174e+03 2.0095e+03 4.7709e+02 8.2700e+01 1.0000e-03 1.0000e-03 3.9904e-03 8.3852e-04 1.8827e-01 5.8414e-02 5.7439e-02 3.7881e-02 2.1790e-02 1.9696e-02 6.1168e-01 9.7345e-03 3.3169e-03 5.8549e-01 1.2284e-01 9.2366e-02 4.6732e-02 2.0769e-02 1.4426e-02 1.0433e-01 +6.0000e-01 8.0200e+06 5.5315e+02 2.2549e+03 1.1902e-07 2.9301e-01 7.0699e-01 3.9803e+03 1.9115e+03 4.8169e+02 7.8767e+01 1.0000e-03 1.0000e-03 3.8136e-03 7.9138e-04 1.7882e-01 5.6072e-02 5.5560e-02 3.6921e-02 2.1398e-02 1.9487e-02 6.2714e-01 9.7319e-03 3.3117e-03 5.8492e-01 1.2286e-01 9.2464e-02 4.6825e-02 2.0830e-02 1.4481e-02 1.0457e-01 +6.2000e-01 7.6240e+06 5.5315e+02 2.1476e+03 1.2742e-07 2.8781e-01 7.1219e-01 3.9433e+03 1.8138e+03 4.8622e+02 7.4911e+01 1.0000e-03 1.0000e-03 3.6350e-03 7.4500e-04 1.6939e-01 5.3682e-02 5.3604e-02 3.5895e-02 2.0962e-02 1.9237e-02 6.4285e-01 9.7262e-03 3.3052e-03 5.8415e-01 1.2285e-01 9.2542e-02 4.6914e-02 2.0892e-02 1.4540e-02 1.0509e-01 +6.4000e-01 7.2280e+06 5.5315e+02 2.0381e+03 1.3694e-07 2.8158e-01 7.1842e-01 3.9062e+03 1.7164e+03 4.9069e+02 7.1128e+01 1.0000e-03 1.0000e-03 3.4546e-03 6.9934e-04 1.6000e-01 5.1244e-02 5.1567e-02 3.4799e-02 2.0480e-02 1.8942e-02 6.5881e-01 9.7170e-03 3.2975e-03 5.8315e-01 1.2279e-01 9.2598e-02 4.6997e-02 2.0954e-02 1.4603e-02 1.0590e-01 +6.6000e-01 6.8320e+06 5.5315e+02 1.9265e+03 1.4781e-07 2.7416e-01 7.2584e-01 3.8690e+03 1.6194e+03 4.9510e+02 6.7415e+01 1.0000e-03 1.0000e-03 3.2724e-03 6.5437e-04 1.5064e-01 4.8757e-02 4.9447e-02 3.3630e-02 1.9949e-02 1.8599e-02 6.7505e-01 9.7038e-03 3.2882e-03 5.8189e-01 1.2269e-01 9.2625e-02 4.7071e-02 2.1017e-02 1.4670e-02 1.0704e-01 +6.8000e-01 6.4360e+06 5.5315e+02 1.8126e+03 1.6031e-07 2.6540e-01 7.3460e-01 3.8319e+03 1.5227e+03 4.9946e+02 6.3766e+01 1.0000e-03 1.0000e-03 3.0883e-03 6.1007e-04 1.4131e-01 4.6220e-02 4.7241e-02 3.2385e-02 1.9365e-02 1.8204e-02 6.9158e-01 9.6862e-03 3.2774e-03 5.8036e-01 1.2254e-01 9.2619e-02 4.7134e-02 2.1078e-02 1.4740e-02 1.0857e-01 +7.0000e-01 6.0400e+06 5.5315e+02 1.6964e+03 1.7480e-07 2.5503e-01 7.4497e-01 3.7947e+03 1.4263e+03 5.0378e+02 6.0179e+01 1.0000e-03 1.0000e-03 2.9022e-03 5.6642e-04 1.3200e-01 4.3631e-02 4.4946e-02 3.1059e-02 1.8725e-02 1.7751e-02 7.0842e-01 9.6634e-03 3.2648e-03 5.7851e-01 1.2232e-01 9.2573e-02 4.7182e-02 2.1137e-02 1.4812e-02 1.1054e-01 +7.2000e-01 5.6440e+06 5.5315e+02 1.5777e+03 1.9174e-07 2.4276e-01 7.5724e-01 3.7575e+03 1.3303e+03 5.0805e+02 5.6650e+01 1.0000e-03 1.0000e-03 2.7143e-03 5.2340e-04 1.2272e-01 4.0990e-02 4.2560e-02 2.9648e-02 1.8024e-02 1.7237e-02 7.2559e-01 9.6346e-03 3.2500e-03 5.7630e-01 1.2203e-01 9.2478e-02 4.7211e-02 2.1190e-02 1.4884e-02 1.1303e-01 +7.4000e-01 5.2480e+06 5.5315e+02 1.4568e+03 2.1177e-07 2.2816e-01 7.7184e-01 3.7203e+03 1.2347e+03 5.1228e+02 5.3177e+01 1.0000e-03 1.0000e-03 2.5244e-03 4.8100e-04 1.1346e-01 3.8295e-02 4.0080e-02 2.8149e-02 1.7259e-02 1.6654e-02 7.4310e-01 9.5987e-03 3.2329e-03 5.7365e-01 1.2165e-01 9.2321e-02 4.7213e-02 2.1237e-02 1.4956e-02 1.1614e-01 +7.6000e-01 4.8520e+06 5.5315e+02 1.3334e+03 2.3574e-07 2.1067e-01 7.8933e-01 3.6830e+03 1.1394e+03 5.1647e+02 4.9756e+01 1.0000e-03 1.0000e-03 2.3326e-03 4.3920e-04 1.0422e-01 3.5547e-02 3.7502e-02 2.6557e-02 1.6425e-02 1.5997e-02 7.6098e-01 9.5541e-03 3.2128e-03 5.7048e-01 1.2117e-01 9.2089e-02 4.7183e-02 2.1272e-02 1.5025e-02 1.2002e-01 +7.8000e-01 4.4560e+06 5.5315e+02 1.2078e+03 2.6481e-07 1.8950e-01 8.1050e-01 3.6457e+03 1.0445e+03 5.2063e+02 4.6386e+01 1.0000e-03 1.0000e-03 2.1388e-03 3.9798e-04 9.4999e-02 3.2743e-02 3.4823e-02 2.4868e-02 1.5517e-02 1.5258e-02 7.7926e-01 9.4988e-03 3.1892e-03 5.6667e-01 1.2055e-01 9.1759e-02 4.7107e-02 2.1291e-02 1.5089e-02 1.2485e-01 +8.0000e-01 4.0600e+06 5.5315e+02 1.0802e+03 3.0068e-07 1.6353e-01 8.3647e-01 3.6084e+03 9.5005e+02 5.2476e+02 4.3064e+01 1.0000e-03 1.0000e-03 1.9431e-03 3.5734e-04 8.5803e-02 2.9884e-02 3.2040e-02 2.3075e-02 1.4530e-02 1.4429e-02 7.9794e-01 9.4300e-03 3.1610e-03 5.6205e-01 1.1976e-01 9.1304e-02 4.6973e-02 2.1288e-02 1.5141e-02 1.3089e-01 +8.2000e-01 3.6640e+06 5.5315e+02 9.5074e+02 3.4583e-07 1.3110e-01 8.6890e-01 3.5711e+03 8.5597e+02 5.2886e+02 3.9788e+01 1.0000e-03 1.0000e-03 1.7455e-03 3.1726e-04 7.6629e-02 2.6969e-02 2.9151e-02 2.1175e-02 1.3457e-02 1.3502e-02 8.1705e-01 9.3436e-03 3.1270e-03 5.5639e-01 1.1875e-01 9.0682e-02 4.6757e-02 2.1252e-02 1.5176e-02 1.3852e-01 +8.4000e-01 3.2680e+06 5.5315e+02 8.1998e+02 4.0405e-07 8.9676e-02 9.1032e-01 3.5337e+03 7.6231e+02 5.3294e+02 3.6555e+01 1.0000e-03 1.0000e-03 1.5459e-03 2.7773e-04 6.7475e-02 2.3996e-02 2.6151e-02 1.9163e-02 1.2294e-02 1.2467e-02 8.3663e-01 9.2335e-03 3.0853e-03 5.4933e-01 1.1744e-01 8.9834e-02 4.6428e-02 2.1170e-02 1.5182e-02 1.4830e-01 +8.6000e-01 2.8720e+06 5.5315e+02 6.8864e+02 4.8147e-07 3.5115e-02 9.6488e-01 3.4962e+03 6.6908e+02 5.3699e+02 3.3364e+01 1.0000e-03 1.0000e-03 1.3444e-03 2.3875e-04 5.8344e-02 2.0966e-02 2.3038e-02 1.7031e-02 1.1033e-02 1.1313e-02 8.5669e-01 9.0905e-03 3.0326e-03 5.4033e-01 1.1571e-01 8.8666e-02 4.5938e-02 2.1017e-02 1.5145e-02 1.6108e-01 +8.8000e-01 2.4760e+06 5.5315e+02 5.7384e+02 4.2818e-07 0.0000e+00 1.0000e+00 5.7384e+02 5.7384e+02 2.9310e+01 2.9310e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.0000e-01 2.0800e+06 5.5315e+02 4.7739e+02 5.0563e-07 0.0000e+00 1.0000e+00 4.7739e+02 4.7739e+02 2.4384e+01 2.4384e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.2000e-01 1.6840e+06 5.5315e+02 3.8268e+02 6.1919e-07 0.0000e+00 1.0000e+00 3.8268e+02 3.8268e+02 1.9546e+01 1.9546e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.4000e-01 1.2880e+06 5.5315e+02 2.8974e+02 8.0221e-07 0.0000e+00 1.0000e+00 2.8974e+02 2.8974e+02 1.4799e+01 1.4799e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.6000e-01 8.9200e+05 5.5315e+02 1.9860e+02 1.1473e-06 0.0000e+00 1.0000e+00 1.9860e+02 1.9860e+02 1.0144e+01 1.0144e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.8000e-01 4.9600e+05 5.5315e+02 1.0929e+02 2.0427e-06 0.0000e+00 1.0000e+00 1.0929e+02 1.0929e+02 5.5820e+00 5.5820e+00 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0000e+00 1.0000e+05 5.5315e+02 2.1802e+01 1.0027e-05 0.0000e+00 1.0000e+00 2.1802e+01 2.1802e+01 1.1136e+00 1.1136e+00 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0200e+00 4.9600e+05 5.8315e+02 1.0339e+02 2.0372e-06 0.0000e+00 1.0000e+00 1.0339e+02 1.0339e+02 5.2808e+00 5.2808e+00 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0400e+00 8.9200e+05 5.8315e+02 1.8748e+02 1.1418e-06 0.0000e+00 1.0000e+00 1.8748e+02 1.8748e+02 9.5758e+00 9.5758e+00 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0600e+00 1.2880e+06 5.8315e+02 2.7291e+02 7.9661e-07 0.0000e+00 1.0000e+00 2.7291e+02 2.7291e+02 1.3939e+01 1.3939e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0800e+00 1.6840e+06 5.8315e+02 3.5965e+02 6.1354e-07 0.0000e+00 1.0000e+00 3.5965e+02 3.5965e+02 1.8370e+01 1.8370e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1000e+00 2.0800e+06 5.8315e+02 4.4765e+02 4.9994e-07 0.0000e+00 1.0000e+00 4.4765e+02 4.4765e+02 2.2865e+01 2.2865e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1200e+00 2.4760e+06 5.8315e+02 5.3688e+02 4.2246e-07 0.0000e+00 1.0000e+00 5.3688e+02 5.3688e+02 2.7422e+01 2.7422e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1400e+00 2.8720e+06 5.8315e+02 6.2727e+02 3.6616e-07 0.0000e+00 1.0000e+00 6.2727e+02 6.2727e+02 3.2039e+01 3.2039e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1600e+00 3.2680e+06 5.8315e+02 7.1876e+02 3.2331e-07 0.0000e+00 1.0000e+00 7.1876e+02 7.1876e+02 3.6712e+01 3.6712e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1800e+00 3.6640e+06 5.8315e+02 8.1129e+02 2.8954e-07 0.0000e+00 1.0000e+00 8.1129e+02 8.1129e+02 4.1438e+01 4.1438e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2000e+00 4.0600e+06 5.8315e+02 9.0478e+02 2.6219e-07 0.0000e+00 1.0000e+00 9.0478e+02 9.0478e+02 4.6214e+01 4.6214e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2200e+00 4.4560e+06 5.8315e+02 9.9914e+02 2.3954e-07 0.0000e+00 1.0000e+00 9.9914e+02 9.9914e+02 5.1033e+01 5.1033e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2400e+00 4.8520e+06 5.8315e+02 1.0943e+03 2.2043e-07 0.0000e+00 1.0000e+00 1.0943e+03 1.0943e+03 5.5894e+01 5.5894e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2600e+00 5.2480e+06 5.8315e+02 1.1902e+03 2.0406e-07 0.0000e+00 1.0000e+00 1.1902e+03 1.1902e+03 6.0790e+01 6.0790e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2800e+00 5.6440e+06 5.8315e+02 1.2866e+03 1.8984e-07 0.0000e+00 1.0000e+00 1.2866e+03 1.2866e+03 6.5717e+01 6.5717e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3000e+00 6.0400e+06 5.8315e+02 1.3836e+03 1.7735e-07 0.0000e+00 1.0000e+00 1.3836e+03 1.3836e+03 7.0669e+01 7.0669e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3200e+00 6.4360e+06 5.8315e+02 1.4809e+03 1.6627e-07 0.0000e+00 1.0000e+00 1.4809e+03 1.4809e+03 7.5641e+01 7.5641e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3400e+00 6.8320e+06 5.8315e+02 1.5785e+03 1.5636e-07 0.0000e+00 1.0000e+00 1.5785e+03 1.5785e+03 8.0628e+01 8.0628e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3600e+00 7.2280e+06 5.8315e+02 1.6764e+03 1.4743e-07 0.0000e+00 1.0000e+00 1.6764e+03 1.6764e+03 8.5624e+01 8.5624e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3800e+00 7.6240e+06 5.8315e+02 1.7742e+03 1.3931e-07 0.0000e+00 1.0000e+00 1.7742e+03 1.7742e+03 9.0624e+01 9.0624e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4000e+00 8.0200e+06 5.8315e+02 1.8721e+03 1.3191e-07 0.0000e+00 1.0000e+00 1.8721e+03 1.8721e+03 9.5621e+01 9.5621e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4200e+00 8.4160e+06 5.8315e+02 1.9698e+03 1.2511e-07 0.0000e+00 1.0000e+00 1.9698e+03 1.9698e+03 1.0061e+02 1.0061e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4400e+00 8.8120e+06 5.8315e+02 2.0672e+03 1.1885e-07 0.0000e+00 1.0000e+00 2.0672e+03 2.0672e+03 1.0559e+02 1.0559e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4600e+00 9.2080e+06 5.8315e+02 2.1643e+03 1.1305e-07 0.0000e+00 1.0000e+00 2.1643e+03 2.1643e+03 1.1055e+02 1.1055e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4800e+00 9.6040e+06 5.8315e+02 2.2610e+03 1.0766e-07 0.0000e+00 1.0000e+00 2.2610e+03 2.2610e+03 1.1549e+02 1.1549e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5000e+00 1.0000e+07 5.8315e+02 2.3571e+03 1.0264e-07 0.0000e+00 1.0000e+00 2.3571e+03 2.3571e+03 1.2039e+02 1.2039e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5200e+00 1.1000e+07 5.8315e+02 2.5968e+03 9.1381e-08 0.0000e+00 1.0000e+00 2.5968e+03 2.5968e+03 1.3264e+02 1.3264e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5400e+00 1.2000e+07 5.8315e+02 2.8313e+03 8.1781e-08 0.0000e+00 1.0000e+00 2.8313e+03 2.8313e+03 1.4462e+02 1.4462e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5600e+00 1.3000e+07 5.8315e+02 3.0596e+03 7.3522e-08 0.0000e+00 1.0000e+00 3.0596e+03 3.0596e+03 1.5628e+02 1.5628e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5800e+00 1.4000e+07 5.8315e+02 3.2810e+03 6.6367e-08 0.0000e+00 1.0000e+00 3.2810e+03 3.2810e+03 1.6759e+02 1.6759e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6000e+00 1.5000e+07 5.8315e+02 3.4950e+03 6.0138e-08 0.0000e+00 1.0000e+00 3.4950e+03 3.4950e+03 1.7852e+02 1.7852e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6200e+00 1.6000e+07 5.8315e+02 3.7013e+03 5.4692e-08 0.0000e+00 1.0000e+00 3.7013e+03 3.7013e+03 1.8905e+02 1.8905e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6400e+00 1.7000e+07 5.8315e+02 3.8999e+03 4.9912e-08 0.0000e+00 1.0000e+00 3.8999e+03 3.8999e+03 1.9920e+02 1.9920e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6600e+00 1.8000e+07 5.8315e+02 4.0907e+03 4.5705e-08 0.0000e+00 1.0000e+00 4.0907e+03 4.0907e+03 2.0894e+02 2.0894e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6800e+00 1.9000e+07 5.8315e+02 4.2739e+03 4.1989e-08 0.0000e+00 1.0000e+00 4.2739e+03 4.2739e+03 2.1830e+02 2.1830e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7000e+00 2.0000e+07 5.8315e+02 4.4497e+03 3.8697e-08 0.0000e+00 1.0000e+00 4.4497e+03 4.4497e+03 2.2728e+02 2.2728e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7200e+00 2.1000e+07 5.8315e+02 4.6183e+03 3.5771e-08 0.0000e+00 1.0000e+00 4.6183e+03 4.6183e+03 2.3589e+02 2.3589e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7400e+00 2.2000e+07 5.8315e+02 4.7802e+03 3.3162e-08 0.0000e+00 1.0000e+00 4.7802e+03 4.7802e+03 2.4416e+02 2.4416e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7600e+00 2.3000e+07 5.8315e+02 4.9355e+03 3.0829e-08 0.0000e+00 1.0000e+00 4.9355e+03 4.9355e+03 2.5209e+02 2.5209e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7800e+00 2.4000e+07 5.8315e+02 5.0846e+03 2.8736e-08 0.0000e+00 1.0000e+00 5.0846e+03 5.0846e+03 2.5971e+02 2.5971e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8000e+00 2.5000e+07 5.8315e+02 5.2278e+03 2.6853e-08 0.0000e+00 1.0000e+00 5.2278e+03 5.2278e+03 2.6702e+02 2.6702e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8200e+00 2.6000e+07 5.8315e+02 5.3654e+03 2.5153e-08 0.0000e+00 1.0000e+00 5.3654e+03 5.3654e+03 2.7405e+02 2.7405e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8400e+00 2.7000e+07 5.8315e+02 5.4978e+03 2.3615e-08 0.0000e+00 1.0000e+00 5.4978e+03 5.4978e+03 2.8081e+02 2.8081e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8600e+00 2.8000e+07 5.8315e+02 5.6252e+03 2.2218e-08 0.0000e+00 1.0000e+00 5.6252e+03 5.6252e+03 2.8732e+02 2.8732e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8800e+00 2.9000e+07 5.8315e+02 5.7479e+03 2.0947e-08 0.0000e+00 1.0000e+00 5.7479e+03 5.7479e+03 2.9359e+02 2.9359e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9000e+00 3.0000e+07 5.8315e+02 5.8661e+03 1.9787e-08 0.0000e+00 1.0000e+00 5.8661e+03 5.8661e+03 2.9962e+02 2.9962e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9200e+00 3.1000e+07 5.8315e+02 5.9801e+03 1.8725e-08 0.0000e+00 1.0000e+00 5.9801e+03 5.9801e+03 3.0545e+02 3.0545e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9400e+00 3.2000e+07 5.8315e+02 6.0901e+03 1.7751e-08 0.0000e+00 1.0000e+00 6.0901e+03 6.0901e+03 3.1107e+02 3.1107e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9600e+00 3.3000e+07 5.8315e+02 6.1964e+03 1.6856e-08 0.0000e+00 1.0000e+00 6.1964e+03 6.1964e+03 3.1649e+02 3.1649e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9800e+00 3.4000e+07 5.8315e+02 6.2991e+03 1.6030e-08 0.0000e+00 1.0000e+00 6.2991e+03 6.2991e+03 3.2174e+02 3.2174e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0000e+00 3.5000e+07 5.8315e+02 6.3984e+03 1.5268e-08 0.0000e+00 1.0000e+00 6.3984e+03 6.3984e+03 3.2681e+02 3.2681e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT_Compositional_liveOilPRLBC.txt b/src/coreComponents/unitTests/constitutiveTests/testPVT_Compositional_liveOilPRLBC.txt new file mode 100644 index 00000000000..9094419bc8a --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT_Compositional_liveOilPRLBC.txt @@ -0,0 +1,1012 @@ +# column 1 = time +# column 2 = pressure +# column 3 = temperature +# column 4 = density +# column 5 = total compressibility +# columns 6-7 = phase fractions +# columns 8-9 = phase densities +# columns 10-11 = phase mass densities +# columns 12-13 = phase viscosities +# columns 14-22 = oil phase fractions [CO2, N2, C1, C2, C3, C4, C5, C6, C7+] +# columns 23-31 = gas phase fractions [CO2, N2, C1, C2, C3, C4, C5, C6, C7+] +0.0000e+00 3.5000e+07 5.5315e+02 6.8078e+03 1.3932e-08 1.0000e+00 0.0000e+00 6.8078e+03 6.8078e+03 3.4772e+02 3.4772e+02 4.5175e-05 4.5175e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +2.0000e-03 3.4900e+07 5.5315e+02 6.7983e+03 1.4001e-08 1.0000e+00 0.0000e+00 6.7983e+03 6.7983e+03 3.4724e+02 3.4724e+02 4.5093e-05 4.5093e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +4.0000e-03 3.4800e+07 5.5315e+02 6.7887e+03 1.4069e-08 1.0000e+00 0.0000e+00 6.7887e+03 6.7887e+03 3.4675e+02 3.4675e+02 4.5010e-05 4.5010e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +6.0000e-03 3.4700e+07 5.5315e+02 6.7792e+03 1.4138e-08 1.0000e+00 0.0000e+00 6.7792e+03 6.7792e+03 3.4626e+02 3.4626e+02 4.4928e-05 4.4928e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +8.0000e-03 3.4600e+07 5.5315e+02 6.7696e+03 1.4208e-08 1.0000e+00 0.0000e+00 6.7696e+03 6.7696e+03 3.4577e+02 3.4577e+02 4.4845e-05 4.4845e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.0000e-02 3.4500e+07 5.5315e+02 6.7599e+03 1.4278e-08 1.0000e+00 0.0000e+00 6.7599e+03 6.7599e+03 3.4528e+02 3.4528e+02 4.4762e-05 4.4762e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.2000e-02 3.4400e+07 5.5315e+02 6.7503e+03 1.4349e-08 1.0000e+00 0.0000e+00 6.7503e+03 6.7503e+03 3.4479e+02 3.4479e+02 4.4679e-05 4.4679e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.4000e-02 3.4300e+07 5.5315e+02 6.7406e+03 1.4421e-08 1.0000e+00 0.0000e+00 6.7406e+03 6.7406e+03 3.4429e+02 3.4429e+02 4.4596e-05 4.4596e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.6000e-02 3.4200e+07 5.5315e+02 6.7308e+03 1.4493e-08 1.0000e+00 0.0000e+00 6.7308e+03 6.7308e+03 3.4379e+02 3.4379e+02 4.4513e-05 4.4513e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.8000e-02 3.4100e+07 5.5315e+02 6.7211e+03 1.4566e-08 1.0000e+00 0.0000e+00 6.7211e+03 6.7211e+03 3.4329e+02 3.4329e+02 4.4430e-05 4.4430e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +2.0000e-02 3.4000e+07 5.5315e+02 6.7113e+03 1.4639e-08 1.0000e+00 0.0000e+00 6.7113e+03 6.7113e+03 3.4279e+02 3.4279e+02 4.4346e-05 4.4346e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +2.2000e-02 3.3900e+07 5.5315e+02 6.7014e+03 1.4713e-08 1.0000e+00 0.0000e+00 6.7014e+03 6.7014e+03 3.4229e+02 3.4229e+02 4.4263e-05 4.4263e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +2.4000e-02 3.3800e+07 5.5315e+02 6.6915e+03 1.4787e-08 1.0000e+00 0.0000e+00 6.6915e+03 6.6915e+03 3.4179e+02 3.4179e+02 4.4179e-05 4.4179e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +2.6000e-02 3.3700e+07 5.5315e+02 6.6816e+03 1.4862e-08 1.0000e+00 0.0000e+00 6.6816e+03 6.6816e+03 3.4128e+02 3.4128e+02 4.4095e-05 4.4095e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +2.8000e-02 3.3600e+07 5.5315e+02 6.6717e+03 1.4938e-08 1.0000e+00 0.0000e+00 6.6717e+03 6.6717e+03 3.4077e+02 3.4077e+02 4.4012e-05 4.4012e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +3.0000e-02 3.3500e+07 5.5315e+02 6.6617e+03 1.5014e-08 1.0000e+00 0.0000e+00 6.6617e+03 6.6617e+03 3.4026e+02 3.4026e+02 4.3928e-05 4.3928e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +3.2000e-02 3.3400e+07 5.5315e+02 6.6517e+03 1.5091e-08 1.0000e+00 0.0000e+00 6.6517e+03 6.6517e+03 3.3975e+02 3.3975e+02 4.3843e-05 4.3843e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +3.4000e-02 3.3300e+07 5.5315e+02 6.6416e+03 1.5169e-08 1.0000e+00 0.0000e+00 6.6416e+03 6.6416e+03 3.3924e+02 3.3924e+02 4.3759e-05 4.3759e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +3.6000e-02 3.3200e+07 5.5315e+02 6.6315e+03 1.5247e-08 1.0000e+00 0.0000e+00 6.6315e+03 6.6315e+03 3.3872e+02 3.3872e+02 4.3675e-05 4.3675e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +3.8000e-02 3.3100e+07 5.5315e+02 6.6214e+03 1.5326e-08 1.0000e+00 0.0000e+00 6.6214e+03 6.6214e+03 3.3820e+02 3.3820e+02 4.3590e-05 4.3590e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +4.0000e-02 3.3000e+07 5.5315e+02 6.6112e+03 1.5406e-08 1.0000e+00 0.0000e+00 6.6112e+03 6.6112e+03 3.3768e+02 3.3768e+02 4.3505e-05 4.3505e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +4.2000e-02 3.2900e+07 5.5315e+02 6.6010e+03 1.5486e-08 1.0000e+00 0.0000e+00 6.6010e+03 6.6010e+03 3.3716e+02 3.3716e+02 4.3420e-05 4.3420e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +4.4000e-02 3.2800e+07 5.5315e+02 6.5908e+03 1.5567e-08 1.0000e+00 0.0000e+00 6.5908e+03 6.5908e+03 3.3664e+02 3.3664e+02 4.3336e-05 4.3336e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +4.6000e-02 3.2700e+07 5.5315e+02 6.5805e+03 1.5648e-08 1.0000e+00 0.0000e+00 6.5805e+03 6.5805e+03 3.3611e+02 3.3611e+02 4.3250e-05 4.3250e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +4.8000e-02 3.2600e+07 5.5315e+02 6.5702e+03 1.5731e-08 1.0000e+00 0.0000e+00 6.5702e+03 6.5702e+03 3.3559e+02 3.3559e+02 4.3165e-05 4.3165e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +5.0000e-02 3.2500e+07 5.5315e+02 6.5598e+03 1.5814e-08 1.0000e+00 0.0000e+00 6.5598e+03 6.5598e+03 3.3506e+02 3.3506e+02 4.3080e-05 4.3080e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +5.2000e-02 3.2400e+07 5.5315e+02 6.5494e+03 1.5898e-08 1.0000e+00 0.0000e+00 6.5494e+03 6.5494e+03 3.3453e+02 3.3453e+02 4.2994e-05 4.2994e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +5.4000e-02 3.2300e+07 5.5315e+02 6.5390e+03 1.5982e-08 1.0000e+00 0.0000e+00 6.5390e+03 6.5390e+03 3.3400e+02 3.3400e+02 4.2909e-05 4.2909e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +5.6000e-02 3.2200e+07 5.5315e+02 6.5285e+03 1.6067e-08 1.0000e+00 0.0000e+00 6.5285e+03 6.5285e+03 3.3346e+02 3.3346e+02 4.2823e-05 4.2823e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +5.8000e-02 3.2100e+07 5.5315e+02 6.5180e+03 1.6153e-08 1.0000e+00 0.0000e+00 6.5180e+03 6.5180e+03 3.3292e+02 3.3292e+02 4.2737e-05 4.2737e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +6.0000e-02 3.2000e+07 5.5315e+02 6.5075e+03 1.6240e-08 1.0000e+00 0.0000e+00 6.5075e+03 6.5075e+03 3.3238e+02 3.3238e+02 4.2651e-05 4.2651e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +6.2000e-02 3.1900e+07 5.5315e+02 6.4969e+03 1.6327e-08 1.0000e+00 0.0000e+00 6.4969e+03 6.4969e+03 3.3184e+02 3.3184e+02 4.2564e-05 4.2564e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +6.4000e-02 3.1800e+07 5.5315e+02 6.4863e+03 1.6416e-08 1.0000e+00 0.0000e+00 6.4863e+03 6.4863e+03 3.3130e+02 3.3130e+02 4.2478e-05 4.2478e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +6.6000e-02 3.1700e+07 5.5315e+02 6.4756e+03 1.6505e-08 1.0000e+00 0.0000e+00 6.4756e+03 6.4756e+03 3.3076e+02 3.3076e+02 4.2391e-05 4.2391e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +6.8000e-02 3.1600e+07 5.5315e+02 6.4649e+03 1.6595e-08 1.0000e+00 0.0000e+00 6.4649e+03 6.4649e+03 3.3021e+02 3.3021e+02 4.2305e-05 4.2305e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +7.0000e-02 3.1500e+07 5.5315e+02 6.4541e+03 1.6685e-08 1.0000e+00 0.0000e+00 6.4541e+03 6.4541e+03 3.2966e+02 3.2966e+02 4.2218e-05 4.2218e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +7.2000e-02 3.1400e+07 5.5315e+02 6.4434e+03 1.6777e-08 1.0000e+00 0.0000e+00 6.4434e+03 6.4434e+03 3.2911e+02 3.2911e+02 4.2131e-05 4.2131e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +7.4000e-02 3.1300e+07 5.5315e+02 6.4325e+03 1.6869e-08 0.0000e+00 1.0000e+00 6.4325e+03 6.4325e+03 3.2856e+02 3.2856e+02 4.2044e-05 4.2044e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +7.6000e-02 3.1200e+07 5.5315e+02 6.4216e+03 1.6962e-08 0.0000e+00 1.0000e+00 6.4216e+03 6.4216e+03 3.2800e+02 3.2800e+02 4.1956e-05 4.1956e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +7.8000e-02 3.1100e+07 5.5315e+02 6.4107e+03 1.7056e-08 0.0000e+00 1.0000e+00 6.4107e+03 6.4107e+03 3.2744e+02 3.2744e+02 4.1869e-05 4.1869e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.0000e-02 3.1000e+07 5.5315e+02 6.3998e+03 1.7151e-08 0.0000e+00 1.0000e+00 6.3998e+03 6.3998e+03 3.2688e+02 3.2688e+02 4.1781e-05 4.1781e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.2000e-02 3.0900e+07 5.5315e+02 6.3888e+03 1.7246e-08 0.0000e+00 1.0000e+00 6.3888e+03 6.3888e+03 3.2632e+02 3.2632e+02 4.1693e-05 4.1693e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.4000e-02 3.0800e+07 5.5315e+02 6.3777e+03 1.7343e-08 0.0000e+00 1.0000e+00 6.3777e+03 6.3777e+03 3.2576e+02 3.2576e+02 4.1605e-05 4.1605e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.6000e-02 3.0700e+07 5.5315e+02 6.3667e+03 1.7440e-08 0.0000e+00 1.0000e+00 6.3667e+03 6.3667e+03 3.2519e+02 3.2519e+02 4.1517e-05 4.1517e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.8000e-02 3.0600e+07 5.5315e+02 6.3555e+03 1.7538e-08 0.0000e+00 1.0000e+00 6.3555e+03 6.3555e+03 3.2462e+02 3.2462e+02 4.1429e-05 4.1429e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.0000e-02 3.0500e+07 5.5315e+02 6.3444e+03 1.7637e-08 0.0000e+00 1.0000e+00 6.3444e+03 6.3444e+03 3.2405e+02 3.2405e+02 4.1341e-05 4.1341e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.2000e-02 3.0400e+07 5.5315e+02 6.3332e+03 1.7737e-08 0.0000e+00 1.0000e+00 6.3332e+03 6.3332e+03 3.2348e+02 3.2348e+02 4.1252e-05 4.1252e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.4000e-02 3.0300e+07 5.5315e+02 6.3219e+03 1.7838e-08 0.0000e+00 1.0000e+00 6.3219e+03 6.3219e+03 3.2291e+02 3.2291e+02 4.1163e-05 4.1163e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.6000e-02 3.0200e+07 5.5315e+02 6.3106e+03 1.7940e-08 0.0000e+00 1.0000e+00 6.3106e+03 6.3106e+03 3.2233e+02 3.2233e+02 4.1074e-05 4.1074e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.8000e-02 3.0100e+07 5.5315e+02 6.2993e+03 1.8043e-08 0.0000e+00 1.0000e+00 6.2993e+03 6.2993e+03 3.2175e+02 3.2175e+02 4.0985e-05 4.0985e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0000e-01 3.0000e+07 5.5315e+02 6.2879e+03 1.8147e-08 0.0000e+00 1.0000e+00 6.2879e+03 6.2879e+03 3.2117e+02 3.2117e+02 4.0896e-05 4.0896e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0200e-01 2.9900e+07 5.5315e+02 6.2764e+03 1.8252e-08 0.0000e+00 1.0000e+00 6.2764e+03 6.2764e+03 3.2058e+02 3.2058e+02 4.0806e-05 4.0806e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0400e-01 2.9800e+07 5.5315e+02 6.2650e+03 1.8357e-08 0.0000e+00 1.0000e+00 6.2650e+03 6.2650e+03 3.2000e+02 3.2000e+02 4.0717e-05 4.0717e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0600e-01 2.9700e+07 5.5315e+02 6.2534e+03 1.8464e-08 0.0000e+00 1.0000e+00 6.2534e+03 6.2534e+03 3.1941e+02 3.1941e+02 4.0627e-05 4.0627e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0800e-01 2.9600e+07 5.5315e+02 6.2419e+03 1.8572e-08 0.0000e+00 1.0000e+00 6.2419e+03 6.2419e+03 3.1882e+02 3.1882e+02 4.0537e-05 4.0537e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1000e-01 2.9500e+07 5.5315e+02 6.2303e+03 1.8681e-08 0.0000e+00 1.0000e+00 6.2303e+03 6.2303e+03 3.1822e+02 3.1822e+02 4.0447e-05 4.0447e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1200e-01 2.9400e+07 5.5315e+02 6.2186e+03 1.8790e-08 0.0000e+00 1.0000e+00 6.2186e+03 6.2186e+03 3.1763e+02 3.1763e+02 4.0356e-05 4.0356e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1400e-01 2.9300e+07 5.5315e+02 6.2069e+03 1.8901e-08 0.0000e+00 1.0000e+00 6.2069e+03 6.2069e+03 3.1703e+02 3.1703e+02 4.0266e-05 4.0266e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1600e-01 2.9200e+07 5.5315e+02 6.1951e+03 1.9013e-08 0.0000e+00 1.0000e+00 6.1951e+03 6.1951e+03 3.1643e+02 3.1643e+02 4.0175e-05 4.0175e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1800e-01 2.9100e+07 5.5315e+02 6.1833e+03 1.9126e-08 0.0000e+00 1.0000e+00 6.1833e+03 6.1833e+03 3.1583e+02 3.1583e+02 4.0084e-05 4.0084e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2000e-01 2.9000e+07 5.5315e+02 6.1715e+03 1.9240e-08 0.0000e+00 1.0000e+00 6.1715e+03 6.1715e+03 3.1522e+02 3.1522e+02 3.9993e-05 3.9993e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2200e-01 2.8900e+07 5.5315e+02 6.1596e+03 1.9355e-08 0.0000e+00 1.0000e+00 6.1596e+03 6.1596e+03 3.1461e+02 3.1461e+02 3.9902e-05 3.9902e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2400e-01 2.8800e+07 5.5315e+02 6.1476e+03 1.9472e-08 0.0000e+00 1.0000e+00 6.1476e+03 6.1476e+03 3.1400e+02 3.1400e+02 3.9811e-05 3.9811e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2600e-01 2.8700e+07 5.5315e+02 6.1356e+03 1.9589e-08 0.0000e+00 1.0000e+00 6.1356e+03 6.1356e+03 3.1339e+02 3.1339e+02 3.9719e-05 3.9719e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2800e-01 2.8600e+07 5.5315e+02 6.1236e+03 1.9707e-08 0.0000e+00 1.0000e+00 6.1236e+03 6.1236e+03 3.1278e+02 3.1278e+02 3.9627e-05 3.9627e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3000e-01 2.8500e+07 5.5315e+02 6.1115e+03 1.9827e-08 0.0000e+00 1.0000e+00 6.1115e+03 6.1115e+03 3.1216e+02 3.1216e+02 3.9535e-05 3.9535e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3200e-01 2.8400e+07 5.5315e+02 6.0994e+03 1.9948e-08 0.0000e+00 1.0000e+00 6.0994e+03 6.0994e+03 3.1154e+02 3.1154e+02 3.9443e-05 3.9443e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3400e-01 2.8300e+07 5.5315e+02 6.0872e+03 2.0070e-08 0.0000e+00 1.0000e+00 6.0872e+03 6.0872e+03 3.1092e+02 3.1092e+02 3.9351e-05 3.9351e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3600e-01 2.8200e+07 5.5315e+02 6.0749e+03 2.0193e-08 0.0000e+00 1.0000e+00 6.0749e+03 6.0749e+03 3.1029e+02 3.1029e+02 3.9258e-05 3.9258e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3800e-01 2.8100e+07 5.5315e+02 6.0626e+03 2.0318e-08 0.0000e+00 1.0000e+00 6.0626e+03 6.0626e+03 3.0966e+02 3.0966e+02 3.9166e-05 3.9166e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4000e-01 2.8000e+07 5.5315e+02 6.0503e+03 2.0443e-08 0.0000e+00 1.0000e+00 6.0503e+03 6.0503e+03 3.0903e+02 3.0903e+02 3.9073e-05 3.9073e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4200e-01 2.7900e+07 5.5315e+02 6.0379e+03 2.0570e-08 0.0000e+00 1.0000e+00 6.0379e+03 6.0379e+03 3.0840e+02 3.0840e+02 3.8979e-05 3.8979e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4400e-01 2.7800e+07 5.5315e+02 6.0254e+03 2.0699e-08 0.0000e+00 1.0000e+00 6.0254e+03 6.0254e+03 3.0776e+02 3.0776e+02 3.8886e-05 3.8886e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4600e-01 2.7700e+07 5.5315e+02 6.0129e+03 2.0828e-08 0.0000e+00 1.0000e+00 6.0129e+03 6.0129e+03 3.0713e+02 3.0713e+02 3.8793e-05 3.8793e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4800e-01 2.7600e+07 5.5315e+02 6.0004e+03 2.0959e-08 0.0000e+00 1.0000e+00 6.0004e+03 6.0004e+03 3.0648e+02 3.0648e+02 3.8699e-05 3.8699e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5000e-01 2.7500e+07 5.5315e+02 5.9878e+03 2.1091e-08 0.0000e+00 1.0000e+00 5.9878e+03 5.9878e+03 3.0584e+02 3.0584e+02 3.8605e-05 3.8605e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5200e-01 2.7400e+07 5.5315e+02 5.9751e+03 2.1224e-08 0.0000e+00 1.0000e+00 5.9751e+03 5.9751e+03 3.0519e+02 3.0519e+02 3.8511e-05 3.8511e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5400e-01 2.7300e+07 5.5315e+02 5.9624e+03 2.1359e-08 0.0000e+00 1.0000e+00 5.9624e+03 5.9624e+03 3.0455e+02 3.0455e+02 3.8416e-05 3.8416e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5600e-01 2.7200e+07 5.5315e+02 5.9497e+03 2.1495e-08 0.0000e+00 1.0000e+00 5.9497e+03 5.9497e+03 3.0389e+02 3.0389e+02 3.8322e-05 3.8322e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5800e-01 2.7100e+07 5.5315e+02 5.9369e+03 2.1633e-08 0.0000e+00 1.0000e+00 5.9369e+03 5.9369e+03 3.0324e+02 3.0324e+02 3.8227e-05 3.8227e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6000e-01 2.7000e+07 5.5315e+02 5.9240e+03 2.1772e-08 0.0000e+00 1.0000e+00 5.9240e+03 5.9240e+03 3.0258e+02 3.0258e+02 3.8132e-05 3.8132e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6200e-01 2.6900e+07 5.5315e+02 5.9111e+03 2.1912e-08 0.0000e+00 1.0000e+00 5.9111e+03 5.9111e+03 3.0192e+02 3.0192e+02 3.8037e-05 3.8037e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6400e-01 2.6800e+07 5.5315e+02 5.8981e+03 2.2054e-08 0.0000e+00 1.0000e+00 5.8981e+03 5.8981e+03 3.0126e+02 3.0126e+02 3.7942e-05 3.7942e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6600e-01 2.6700e+07 5.5315e+02 5.8850e+03 2.2198e-08 0.0000e+00 1.0000e+00 5.8850e+03 5.8850e+03 3.0059e+02 3.0059e+02 3.7846e-05 3.7846e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6800e-01 2.6600e+07 5.5315e+02 5.8720e+03 2.2342e-08 0.0000e+00 1.0000e+00 5.8720e+03 5.8720e+03 2.9992e+02 2.9992e+02 3.7750e-05 3.7750e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7000e-01 2.6500e+07 5.5315e+02 5.8588e+03 2.2489e-08 0.0000e+00 1.0000e+00 5.8588e+03 5.8588e+03 2.9925e+02 2.9925e+02 3.7654e-05 3.7654e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7200e-01 2.6400e+07 5.5315e+02 5.8456e+03 2.2637e-08 0.0000e+00 1.0000e+00 5.8456e+03 5.8456e+03 2.9858e+02 2.9858e+02 3.7558e-05 3.7558e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7400e-01 2.6300e+07 5.5315e+02 5.8323e+03 2.2786e-08 0.0000e+00 1.0000e+00 5.8323e+03 5.8323e+03 2.9790e+02 2.9790e+02 3.7462e-05 3.7462e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7600e-01 2.6200e+07 5.5315e+02 5.8190e+03 2.2937e-08 0.0000e+00 1.0000e+00 5.8190e+03 5.8190e+03 2.9722e+02 2.9722e+02 3.7365e-05 3.7365e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7800e-01 2.6100e+07 5.5315e+02 5.8056e+03 2.3090e-08 0.0000e+00 1.0000e+00 5.8056e+03 5.8056e+03 2.9654e+02 2.9654e+02 3.7268e-05 3.7268e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8000e-01 2.6000e+07 5.5315e+02 5.7922e+03 2.3244e-08 0.0000e+00 1.0000e+00 5.7922e+03 5.7922e+03 2.9585e+02 2.9585e+02 3.7171e-05 3.7171e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8200e-01 2.5900e+07 5.5315e+02 5.7787e+03 2.3400e-08 0.0000e+00 1.0000e+00 5.7787e+03 5.7787e+03 2.9516e+02 2.9516e+02 3.7074e-05 3.7074e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8400e-01 2.5800e+07 5.5315e+02 5.7652e+03 2.3557e-08 0.0000e+00 1.0000e+00 5.7652e+03 5.7652e+03 2.9447e+02 2.9447e+02 3.6976e-05 3.6976e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8600e-01 2.5700e+07 5.5315e+02 5.7516e+03 2.3716e-08 0.0000e+00 1.0000e+00 5.7516e+03 5.7516e+03 2.9377e+02 2.9377e+02 3.6879e-05 3.6879e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8800e-01 2.5600e+07 5.5315e+02 5.7379e+03 2.3877e-08 0.0000e+00 1.0000e+00 5.7379e+03 5.7379e+03 2.9308e+02 2.9308e+02 3.6781e-05 3.6781e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9000e-01 2.5500e+07 5.5315e+02 5.7242e+03 2.4040e-08 0.0000e+00 1.0000e+00 5.7242e+03 5.7242e+03 2.9237e+02 2.9237e+02 3.6682e-05 3.6682e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9200e-01 2.5400e+07 5.5315e+02 5.7104e+03 2.4204e-08 0.0000e+00 1.0000e+00 5.7104e+03 5.7104e+03 2.9167e+02 2.9167e+02 3.6584e-05 3.6584e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9400e-01 2.5300e+07 5.5315e+02 5.6965e+03 2.4370e-08 0.0000e+00 1.0000e+00 5.6965e+03 5.6965e+03 2.9096e+02 2.9096e+02 3.6485e-05 3.6485e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9600e-01 2.5200e+07 5.5315e+02 5.6826e+03 2.4538e-08 0.0000e+00 1.0000e+00 5.6826e+03 5.6826e+03 2.9025e+02 2.9025e+02 3.6387e-05 3.6387e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9800e-01 2.5100e+07 5.5315e+02 5.6686e+03 2.4708e-08 0.0000e+00 1.0000e+00 5.6686e+03 5.6686e+03 2.8954e+02 2.8954e+02 3.6287e-05 3.6287e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0000e-01 2.5000e+07 5.5315e+02 5.6546e+03 2.4879e-08 0.0000e+00 1.0000e+00 5.6546e+03 5.6546e+03 2.8882e+02 2.8882e+02 3.6188e-05 3.6188e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0200e-01 2.4900e+07 5.5315e+02 5.6405e+03 2.5053e-08 0.0000e+00 1.0000e+00 5.6405e+03 5.6405e+03 2.8810e+02 2.8810e+02 3.6089e-05 3.6089e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0400e-01 2.4800e+07 5.5315e+02 5.6263e+03 2.5228e-08 0.0000e+00 1.0000e+00 5.6263e+03 5.6263e+03 2.8738e+02 2.8738e+02 3.5989e-05 3.5989e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0600e-01 2.4700e+07 5.5315e+02 5.6121e+03 2.5406e-08 0.0000e+00 1.0000e+00 5.6121e+03 5.6121e+03 2.8665e+02 2.8665e+02 3.5889e-05 3.5889e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0800e-01 2.4600e+07 5.5315e+02 5.5978e+03 2.5585e-08 0.0000e+00 1.0000e+00 5.5978e+03 5.5978e+03 2.8592e+02 2.8592e+02 3.5789e-05 3.5789e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.1000e-01 2.4500e+07 5.5315e+02 5.5835e+03 2.5766e-08 0.0000e+00 1.0000e+00 5.5835e+03 5.5835e+03 2.8519e+02 2.8519e+02 3.5688e-05 3.5688e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.1200e-01 2.4400e+07 5.5315e+02 5.5690e+03 2.5950e-08 0.0000e+00 1.0000e+00 5.5690e+03 5.5690e+03 2.8445e+02 2.8445e+02 3.5587e-05 3.5587e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.1400e-01 2.4300e+07 5.5315e+02 5.5545e+03 2.6135e-08 0.0000e+00 1.0000e+00 5.5545e+03 5.5545e+03 2.8371e+02 2.8371e+02 3.5487e-05 3.5487e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.1600e-01 2.4200e+07 5.5315e+02 5.5400e+03 2.6323e-08 0.0000e+00 1.0000e+00 5.5400e+03 5.5400e+03 2.8297e+02 2.8297e+02 3.5385e-05 3.5385e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.1800e-01 2.4100e+07 5.5315e+02 5.5254e+03 2.6512e-08 0.0000e+00 1.0000e+00 5.5254e+03 5.5254e+03 2.8222e+02 2.8222e+02 3.5284e-05 3.5284e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.2000e-01 2.4000e+07 5.5315e+02 5.5107e+03 2.6704e-08 0.0000e+00 1.0000e+00 5.5107e+03 5.5107e+03 2.8147e+02 2.8147e+02 3.5182e-05 3.5182e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.2200e-01 2.3900e+07 5.5315e+02 5.4960e+03 2.6898e-08 0.0000e+00 1.0000e+00 5.4960e+03 5.4960e+03 2.8072e+02 2.8072e+02 3.5080e-05 3.5080e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.2400e-01 2.3800e+07 5.5315e+02 5.4811e+03 2.7094e-08 0.0000e+00 1.0000e+00 5.4811e+03 5.4811e+03 2.7996e+02 2.7996e+02 3.4978e-05 3.4978e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.2600e-01 2.3700e+07 5.5315e+02 5.4663e+03 2.7292e-08 0.0000e+00 1.0000e+00 5.4663e+03 5.4663e+03 2.7920e+02 2.7920e+02 3.4876e-05 3.4876e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.2800e-01 2.3600e+07 5.5315e+02 5.4513e+03 2.7493e-08 0.0000e+00 1.0000e+00 5.4513e+03 5.4513e+03 2.7844e+02 2.7844e+02 3.4773e-05 3.4773e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.3000e-01 2.3500e+07 5.5315e+02 5.4363e+03 2.7696e-08 0.0000e+00 1.0000e+00 5.4363e+03 5.4363e+03 2.7767e+02 2.7767e+02 3.4671e-05 3.4671e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.3200e-01 2.3400e+07 5.5315e+02 5.4212e+03 2.7901e-08 0.0000e+00 1.0000e+00 5.4212e+03 5.4212e+03 2.7690e+02 2.7690e+02 3.4568e-05 3.4568e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.3400e-01 2.3300e+07 5.5315e+02 5.4060e+03 2.8109e-08 0.0000e+00 1.0000e+00 5.4060e+03 5.4060e+03 2.7613e+02 2.7613e+02 3.4464e-05 3.4464e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.3600e-01 2.3200e+07 5.5315e+02 5.3908e+03 2.8319e-08 0.0000e+00 1.0000e+00 5.3908e+03 5.3908e+03 2.7535e+02 2.7535e+02 3.4361e-05 3.4361e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.3800e-01 2.3100e+07 5.5315e+02 5.3755e+03 2.8532e-08 0.0000e+00 1.0000e+00 5.3755e+03 5.3755e+03 2.7457e+02 2.7457e+02 3.4257e-05 3.4257e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.4000e-01 2.3000e+07 5.5315e+02 5.3601e+03 2.8747e-08 0.0000e+00 1.0000e+00 5.3601e+03 5.3601e+03 2.7378e+02 2.7378e+02 3.4153e-05 3.4153e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.4200e-01 2.2900e+07 5.5315e+02 5.3447e+03 2.8964e-08 0.0000e+00 1.0000e+00 5.3447e+03 5.3447e+03 2.7299e+02 2.7299e+02 3.4049e-05 3.4049e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.4400e-01 2.2800e+07 5.5315e+02 5.3292e+03 2.9184e-08 0.0000e+00 1.0000e+00 5.3292e+03 5.3292e+03 2.7220e+02 2.7220e+02 3.3944e-05 3.3944e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.4600e-01 2.2700e+07 5.5315e+02 5.3136e+03 2.9407e-08 0.0000e+00 1.0000e+00 5.3136e+03 5.3136e+03 2.7140e+02 2.7140e+02 3.3839e-05 3.3839e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.4800e-01 2.2600e+07 5.5315e+02 5.2979e+03 2.9632e-08 0.0000e+00 1.0000e+00 5.2979e+03 5.2979e+03 2.7060e+02 2.7060e+02 3.3734e-05 3.3734e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.5000e-01 2.2500e+07 5.5315e+02 5.2822e+03 2.9860e-08 0.0000e+00 1.0000e+00 5.2822e+03 5.2822e+03 2.6980e+02 2.6980e+02 3.3629e-05 3.3629e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.5200e-01 2.2400e+07 5.5315e+02 5.2664e+03 3.0091e-08 0.0000e+00 1.0000e+00 5.2664e+03 5.2664e+03 2.6899e+02 2.6899e+02 3.3524e-05 3.3524e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.5400e-01 2.2300e+07 5.5315e+02 5.2505e+03 3.0324e-08 0.0000e+00 1.0000e+00 5.2505e+03 5.2505e+03 2.6818e+02 2.6818e+02 3.3418e-05 3.3418e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.5600e-01 2.2200e+07 5.5315e+02 5.2345e+03 3.0561e-08 0.0000e+00 1.0000e+00 5.2345e+03 5.2345e+03 2.6737e+02 2.6737e+02 3.3312e-05 3.3312e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.5800e-01 2.2100e+07 5.5315e+02 5.2185e+03 3.0800e-08 0.0000e+00 1.0000e+00 5.2185e+03 5.2185e+03 2.6655e+02 2.6655e+02 3.3206e-05 3.3206e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.6000e-01 2.2000e+07 5.5315e+02 5.2024e+03 3.1042e-08 0.0000e+00 1.0000e+00 5.2024e+03 5.2024e+03 2.6572e+02 2.6572e+02 3.3099e-05 3.3099e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.6200e-01 2.1900e+07 5.5315e+02 5.1862e+03 3.1286e-08 0.0000e+00 1.0000e+00 5.1862e+03 5.1862e+03 2.6490e+02 2.6490e+02 3.2993e-05 3.2993e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.6400e-01 2.1800e+07 5.5315e+02 5.1699e+03 3.1534e-08 0.0000e+00 1.0000e+00 5.1699e+03 5.1699e+03 2.6407e+02 2.6407e+02 3.2886e-05 3.2886e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.6600e-01 2.1700e+07 5.5315e+02 5.1536e+03 3.1785e-08 0.0000e+00 1.0000e+00 5.1536e+03 5.1536e+03 2.6323e+02 2.6323e+02 3.2779e-05 3.2779e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.6800e-01 2.1600e+07 5.5315e+02 5.1372e+03 3.2039e-08 0.0000e+00 1.0000e+00 5.1372e+03 5.1372e+03 2.6239e+02 2.6239e+02 3.2671e-05 3.2671e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.7000e-01 2.1500e+07 5.5315e+02 5.1207e+03 3.2296e-08 0.0000e+00 1.0000e+00 5.1207e+03 5.1207e+03 2.6155e+02 2.6155e+02 3.2564e-05 3.2564e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.7200e-01 2.1400e+07 5.5315e+02 5.1041e+03 3.2556e-08 0.0000e+00 1.0000e+00 5.1041e+03 5.1041e+03 2.6070e+02 2.6070e+02 3.2456e-05 3.2456e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.7400e-01 2.1300e+07 5.5315e+02 5.0874e+03 3.2820e-08 0.0000e+00 1.0000e+00 5.0874e+03 5.0874e+03 2.5985e+02 2.5985e+02 3.2348e-05 3.2348e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.7600e-01 2.1200e+07 5.5315e+02 5.0707e+03 3.3087e-08 0.0000e+00 1.0000e+00 5.0707e+03 5.0707e+03 2.5900e+02 2.5900e+02 3.2239e-05 3.2239e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.7800e-01 2.1100e+07 5.5315e+02 5.0539e+03 3.3357e-08 0.0000e+00 1.0000e+00 5.0539e+03 5.0539e+03 2.5814e+02 2.5814e+02 3.2131e-05 3.2131e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.8000e-01 2.1000e+07 5.5315e+02 5.0370e+03 3.3630e-08 0.0000e+00 1.0000e+00 5.0370e+03 5.0370e+03 2.5728e+02 2.5728e+02 3.2022e-05 3.2022e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.8200e-01 2.0900e+07 5.5315e+02 5.0200e+03 3.3907e-08 0.0000e+00 1.0000e+00 5.0200e+03 5.0200e+03 2.5641e+02 2.5641e+02 3.1913e-05 3.1913e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.8400e-01 2.0800e+07 5.5315e+02 5.0029e+03 3.4187e-08 0.0000e+00 1.0000e+00 5.0029e+03 5.0029e+03 2.5554e+02 2.5554e+02 3.1803e-05 3.1803e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.8600e-01 2.0700e+07 5.5315e+02 4.9858e+03 3.4471e-08 0.0000e+00 1.0000e+00 4.9858e+03 4.9858e+03 2.5466e+02 2.5466e+02 3.1694e-05 3.1694e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.8800e-01 2.0600e+07 5.5315e+02 4.9686e+03 3.4758e-08 0.0000e+00 1.0000e+00 4.9686e+03 4.9686e+03 2.5378e+02 2.5378e+02 3.1584e-05 3.1584e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.9000e-01 2.0500e+07 5.5315e+02 4.9512e+03 3.5049e-08 0.0000e+00 1.0000e+00 4.9512e+03 4.9512e+03 2.5290e+02 2.5290e+02 3.1474e-05 3.1474e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.9200e-01 2.0400e+07 5.5315e+02 4.9339e+03 3.5344e-08 0.0000e+00 1.0000e+00 4.9339e+03 4.9339e+03 2.5201e+02 2.5201e+02 3.1364e-05 3.1364e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.9400e-01 2.0300e+07 5.5315e+02 4.9164e+03 3.5642e-08 0.0000e+00 1.0000e+00 4.9164e+03 4.9164e+03 2.5112e+02 2.5112e+02 3.1253e-05 3.1253e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.9600e-01 2.0200e+07 5.5315e+02 4.8988e+03 3.5944e-08 0.0000e+00 1.0000e+00 4.8988e+03 4.8988e+03 2.5022e+02 2.5022e+02 3.1143e-05 3.1143e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.9800e-01 2.0100e+07 5.5315e+02 4.8812e+03 3.6250e-08 0.0000e+00 1.0000e+00 4.8812e+03 4.8812e+03 2.4932e+02 2.4932e+02 3.1032e-05 3.1032e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.0000e-01 2.0000e+07 5.5315e+02 4.8634e+03 3.6560e-08 0.0000e+00 1.0000e+00 4.8634e+03 4.8634e+03 2.4841e+02 2.4841e+02 3.0921e-05 3.0921e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.0200e-01 1.9900e+07 5.5315e+02 4.8456e+03 3.6874e-08 0.0000e+00 1.0000e+00 4.8456e+03 4.8456e+03 2.4750e+02 2.4750e+02 3.0809e-05 3.0809e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.0400e-01 1.9800e+07 5.5315e+02 4.8277e+03 3.7192e-08 0.0000e+00 1.0000e+00 4.8277e+03 4.8277e+03 2.4659e+02 2.4659e+02 3.0698e-05 3.0698e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.0600e-01 1.9700e+07 5.5315e+02 4.8097e+03 3.7514e-08 0.0000e+00 1.0000e+00 4.8097e+03 4.8097e+03 2.4567e+02 2.4567e+02 3.0586e-05 3.0586e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.0800e-01 1.9600e+07 5.5315e+02 4.7916e+03 3.7840e-08 0.0000e+00 1.0000e+00 4.7916e+03 4.7916e+03 2.4474e+02 2.4474e+02 3.0474e-05 3.0474e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.1000e-01 1.9500e+07 5.5315e+02 4.7734e+03 3.8171e-08 0.0000e+00 1.0000e+00 4.7734e+03 4.7734e+03 2.4381e+02 2.4381e+02 3.0362e-05 3.0362e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.1200e-01 1.9400e+07 5.5315e+02 4.7552e+03 3.8506e-08 0.0000e+00 1.0000e+00 4.7552e+03 4.7552e+03 2.4288e+02 2.4288e+02 3.0249e-05 3.0249e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.1400e-01 1.9300e+07 5.5315e+02 4.7368e+03 3.8845e-08 0.0000e+00 1.0000e+00 4.7368e+03 4.7368e+03 2.4194e+02 2.4194e+02 3.0137e-05 3.0137e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.1600e-01 1.9200e+07 5.5315e+02 4.7184e+03 3.9189e-08 0.0000e+00 1.0000e+00 4.7184e+03 4.7184e+03 2.4100e+02 2.4100e+02 3.0024e-05 3.0024e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.1800e-01 1.9100e+07 5.5315e+02 4.6998e+03 3.9537e-08 0.0000e+00 1.0000e+00 4.6998e+03 4.6998e+03 2.4005e+02 2.4005e+02 2.9911e-05 2.9911e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.2000e-01 1.9000e+07 5.5315e+02 4.6812e+03 3.9890e-08 0.0000e+00 1.0000e+00 4.6812e+03 4.6812e+03 2.3910e+02 2.3910e+02 2.9797e-05 2.9797e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.2200e-01 1.8900e+07 5.5315e+02 4.6625e+03 4.0247e-08 0.0000e+00 1.0000e+00 4.6625e+03 4.6625e+03 2.3815e+02 2.3815e+02 2.9684e-05 2.9684e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.2400e-01 1.8800e+07 5.5315e+02 4.6437e+03 4.0609e-08 0.0000e+00 1.0000e+00 4.6437e+03 4.6437e+03 2.3719e+02 2.3719e+02 2.9570e-05 2.9570e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.2600e-01 1.8700e+07 5.5315e+02 4.6248e+03 4.0976e-08 0.0000e+00 1.0000e+00 4.6248e+03 4.6248e+03 2.3622e+02 2.3622e+02 2.9456e-05 2.9456e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.2800e-01 1.8600e+07 5.5315e+02 4.6058e+03 4.1348e-08 0.0000e+00 1.0000e+00 4.6058e+03 4.6058e+03 2.3525e+02 2.3525e+02 2.9342e-05 2.9342e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.3000e-01 1.8500e+07 5.5315e+02 4.5867e+03 4.1725e-08 0.0000e+00 1.0000e+00 4.5867e+03 4.5867e+03 2.3427e+02 2.3427e+02 2.9228e-05 2.9228e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.3200e-01 1.8400e+07 5.5315e+02 4.5675e+03 4.2107e-08 0.0000e+00 1.0000e+00 4.5675e+03 4.5675e+03 2.3329e+02 2.3329e+02 2.9114e-05 2.9114e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.3400e-01 1.8300e+07 5.5315e+02 4.5482e+03 4.2494e-08 0.0000e+00 1.0000e+00 4.5482e+03 4.5482e+03 2.3231e+02 2.3231e+02 2.8999e-05 2.8999e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.3600e-01 1.8200e+07 5.5315e+02 4.5288e+03 4.2886e-08 0.0000e+00 1.0000e+00 4.5288e+03 4.5288e+03 2.3132e+02 2.3132e+02 2.8885e-05 2.8885e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.3800e-01 1.8100e+07 5.5315e+02 4.5094e+03 4.3283e-08 0.0000e+00 1.0000e+00 4.5094e+03 4.5094e+03 2.3033e+02 2.3033e+02 2.8770e-05 2.8770e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.4000e-01 1.8000e+07 5.5315e+02 4.4898e+03 4.3686e-08 0.0000e+00 1.0000e+00 4.4898e+03 4.4898e+03 2.2933e+02 2.2933e+02 2.8654e-05 2.8654e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.4200e-01 1.7900e+07 5.5315e+02 4.4701e+03 4.4094e-08 0.0000e+00 1.0000e+00 4.4701e+03 4.4701e+03 2.2832e+02 2.2832e+02 2.8539e-05 2.8539e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.4400e-01 1.7800e+07 5.5315e+02 4.4504e+03 4.4508e-08 0.0000e+00 1.0000e+00 4.4504e+03 4.4504e+03 2.2731e+02 2.2731e+02 2.8424e-05 2.8424e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.4600e-01 1.7700e+07 5.5315e+02 4.4305e+03 4.4928e-08 0.0000e+00 1.0000e+00 4.4305e+03 4.4305e+03 2.2630e+02 2.2630e+02 2.8308e-05 2.8308e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.4800e-01 1.7600e+07 5.5315e+02 4.4106e+03 4.5353e-08 0.0000e+00 1.0000e+00 4.4106e+03 4.4106e+03 2.2528e+02 2.2528e+02 2.8193e-05 2.8193e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.5000e-01 1.7500e+07 5.5315e+02 4.3905e+03 4.5784e-08 0.0000e+00 1.0000e+00 4.3905e+03 4.3905e+03 2.2426e+02 2.2426e+02 2.8077e-05 2.8077e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.5200e-01 1.7400e+07 5.5315e+02 4.3704e+03 4.6221e-08 0.0000e+00 1.0000e+00 4.3704e+03 4.3704e+03 2.2323e+02 2.2323e+02 2.7961e-05 2.7961e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.5400e-01 1.7300e+07 5.5315e+02 4.3501e+03 4.6664e-08 0.0000e+00 1.0000e+00 4.3501e+03 4.3501e+03 2.2219e+02 2.2219e+02 2.7845e-05 2.7845e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.5600e-01 1.7200e+07 5.5315e+02 4.3298e+03 4.7113e-08 0.0000e+00 1.0000e+00 4.3298e+03 4.3298e+03 2.2115e+02 2.2115e+02 2.7728e-05 2.7728e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.5800e-01 1.7100e+07 5.5315e+02 4.3097e+03 4.5958e-08 1.6940e-02 9.8306e-01 4.7378e+03 4.3030e+03 3.2888e+02 2.1879e+02 4.0756e-05 2.7484e-05 7.7388e-03 2.2673e-03 4.3060e-01 1.0225e-01 8.3990e-02 4.6636e-02 2.2821e-02 1.7645e-02 2.8606e-01 9.0159e-03 3.0092e-03 5.3601e-01 1.1476e-01 8.7949e-02 4.5587e-02 2.0876e-02 1.5068e-02 1.6773e-01 +3.6000e-01 1.7000e+07 5.5315e+02 4.2898e+03 4.6261e-08 4.5641e-02 9.5436e-01 4.7351e+03 4.2706e+03 3.3247e+02 2.1533e+02 4.1261e-05 2.7137e-05 7.6825e-03 2.2373e-03 4.2618e-01 1.0167e-01 8.3774e-02 4.6651e-02 2.2890e-02 1.7745e-02 2.9117e-01 9.0452e-03 3.0262e-03 5.3843e-01 1.1504e-01 8.8042e-02 4.5564e-02 2.0832e-02 1.5009e-02 1.6501e-01 +3.6200e-01 1.6900e+07 5.5315e+02 4.2700e+03 4.6569e-08 6.9687e-02 9.3031e-01 4.7316e+03 4.2390e+03 3.3585e+02 2.1206e+02 4.1743e-05 2.6815e-05 7.6282e-03 2.2087e-03 4.2194e-01 1.0112e-01 8.3562e-02 4.6663e-02 2.2955e-02 1.7841e-02 2.9608e-01 9.0724e-03 3.0418e-03 5.4065e-01 1.1531e-01 8.8129e-02 4.5544e-02 2.0792e-02 1.4955e-02 1.6250e-01 +3.6400e-01 1.6800e+07 5.5315e+02 4.2501e+03 4.6881e-08 9.0201e-02 9.0980e-01 4.7276e+03 4.2079e+03 3.3906e+02 2.0897e+02 4.2206e-05 2.6512e-05 7.5755e-03 2.1812e-03 4.1786e-01 1.0058e-01 8.3351e-02 4.6671e-02 2.3016e-02 1.7932e-02 3.0083e-01 9.0978e-03 3.0562e-03 5.4272e-01 1.1556e-01 8.8212e-02 4.5527e-02 2.0755e-02 1.4906e-02 1.6016e-01 +3.6600e-01 1.6700e+07 5.5315e+02 4.2301e+03 4.7199e-08 1.0796e-01 8.9204e-01 4.7231e+03 4.1773e+03 3.4214e+02 2.0601e+02 4.2651e-05 2.6227e-05 7.5242e-03 2.1547e-03 4.1391e-01 1.0005e-01 8.3141e-02 4.6675e-02 2.3074e-02 1.8020e-02 3.0545e-01 9.1216e-03 3.0697e-03 5.4465e-01 1.1580e-01 8.8292e-02 4.5511e-02 2.0721e-02 1.4859e-02 1.5797e-01 +3.6800e-01 1.6600e+07 5.5315e+02 4.2101e+03 4.7521e-08 1.2352e-01 8.7648e-01 4.7181e+03 4.1472e+03 3.4508e+02 2.0319e+02 4.3082e-05 2.5958e-05 7.4742e-03 2.1291e-03 4.1008e-01 9.9536e-02 8.2932e-02 4.6676e-02 2.3128e-02 1.8104e-02 3.0994e-01 9.1441e-03 3.0822e-03 5.4647e-01 1.1602e-01 8.8369e-02 4.5498e-02 2.0690e-02 1.4816e-02 1.5591e-01 +3.7000e-01 1.6500e+07 5.5315e+02 4.1901e+03 4.7848e-08 1.3730e-01 8.6270e-01 4.7129e+03 4.1174e+03 3.4792e+02 2.0048e+02 4.3501e-05 2.5702e-05 7.4251e-03 2.1042e-03 4.0634e-01 9.9028e-02 8.2724e-02 4.6673e-02 2.3180e-02 1.8185e-02 3.1434e-01 9.1653e-03 3.0940e-03 5.4817e-01 1.1623e-01 8.8443e-02 4.5487e-02 2.0661e-02 1.4776e-02 1.5396e-01 +3.7200e-01 1.6400e+07 5.5315e+02 4.1700e+03 4.8181e-08 1.4960e-01 8.5040e-01 4.7072e+03 4.0880e+03 3.5065e+02 1.9786e+02 4.3908e-05 2.5458e-05 7.3770e-03 2.0801e-03 4.0269e-01 9.8526e-02 8.2515e-02 4.6668e-02 2.3229e-02 1.8263e-02 3.1865e-01 9.1855e-03 3.1051e-03 5.4979e-01 1.1644e-01 8.8516e-02 4.5478e-02 2.0634e-02 1.4738e-02 1.5212e-01 +3.7400e-01 1.6300e+07 5.5315e+02 4.1499e+03 4.8518e-08 1.6066e-01 8.3934e-01 4.7014e+03 4.0588e+03 3.5330e+02 1.9534e+02 4.4304e-05 2.5225e-05 7.3297e-03 2.0566e-03 3.9913e-01 9.8031e-02 8.2305e-02 4.6660e-02 2.3276e-02 1.8339e-02 3.2287e-01 9.2048e-03 3.1157e-03 5.5132e-01 1.1663e-01 8.8586e-02 4.5470e-02 2.0609e-02 1.4703e-02 1.5036e-01 +3.7600e-01 1.6200e+07 5.5315e+02 4.1298e+03 4.8861e-08 1.7067e-01 8.2933e-01 4.6952e+03 4.0299e+03 3.5587e+02 1.9289e+02 4.4692e-05 2.5002e-05 7.2830e-03 2.0336e-03 3.9563e-01 9.7542e-02 8.2095e-02 4.6649e-02 2.3320e-02 1.8412e-02 3.2703e-01 9.2231e-03 3.1256e-03 5.5277e-01 1.1682e-01 8.8654e-02 4.5464e-02 2.0585e-02 1.4670e-02 1.4869e-01 +3.7800e-01 1.6100e+07 5.5315e+02 4.1096e+03 4.9210e-08 1.7978e-01 8.2022e-01 4.6888e+03 4.0012e+03 3.5836e+02 1.9052e+02 4.5072e-05 2.4788e-05 7.2370e-03 2.0112e-03 3.9221e-01 9.7057e-02 8.1884e-02 4.6635e-02 2.3363e-02 1.8483e-02 3.3112e-01 9.2407e-03 3.1350e-03 5.5416e-01 1.1700e-01 8.8722e-02 4.5459e-02 2.0564e-02 1.4638e-02 1.4709e-01 +3.8000e-01 1.6000e+07 5.5315e+02 4.0893e+03 4.9564e-08 1.8812e-01 8.1188e-01 4.6823e+03 3.9727e+03 3.6079e+02 1.8822e+02 4.5444e-05 2.4582e-05 7.1915e-03 1.9892e-03 3.8884e-01 9.6576e-02 8.1672e-02 4.6619e-02 2.3403e-02 1.8552e-02 3.3516e-01 9.2576e-03 3.1440e-03 5.5548e-01 1.1717e-01 8.8787e-02 4.5455e-02 2.0543e-02 1.4608e-02 1.4556e-01 +3.8200e-01 1.5900e+07 5.5315e+02 4.0690e+03 4.9924e-08 1.9577e-01 8.0423e-01 4.6755e+03 3.9445e+03 3.6315e+02 1.8597e+02 4.5809e-05 2.4384e-05 7.1465e-03 1.9677e-03 3.8552e-01 9.6099e-02 8.1458e-02 4.6600e-02 2.3441e-02 1.8619e-02 3.3915e-01 9.2739e-03 3.1525e-03 5.5674e-01 1.1733e-01 8.8852e-02 4.5452e-02 2.0525e-02 1.4580e-02 1.4409e-01 +3.8400e-01 1.5800e+07 5.5315e+02 4.0487e+03 5.0289e-08 2.0283e-01 7.9717e-01 4.6686e+03 3.9164e+03 3.6546e+02 1.8379e+02 4.6168e-05 2.4193e-05 7.1020e-03 1.9466e-03 3.8225e-01 9.5624e-02 8.1244e-02 4.6578e-02 2.3478e-02 1.8684e-02 3.4309e-01 9.2895e-03 3.1607e-03 5.5795e-01 1.1749e-01 8.8915e-02 4.5451e-02 2.0507e-02 1.4553e-02 1.4268e-01 +3.8600e-01 1.5700e+07 5.5315e+02 4.0283e+03 5.0661e-08 2.0936e-01 7.9064e-01 4.6615e+03 3.8884e+03 3.6772e+02 1.8166e+02 4.6521e-05 2.4008e-05 7.0579e-03 1.9258e-03 3.7903e-01 9.5152e-02 8.1027e-02 4.6555e-02 2.3512e-02 1.8748e-02 3.4699e-01 9.3046e-03 3.1684e-03 5.5911e-01 1.1765e-01 8.8978e-02 4.5450e-02 2.0490e-02 1.4528e-02 1.4132e-01 +3.8800e-01 1.5600e+07 5.5315e+02 4.0079e+03 5.1038e-08 2.1541e-01 7.8459e-01 4.6543e+03 3.8607e+03 3.6993e+02 1.7957e+02 4.6868e-05 2.3829e-05 7.0141e-03 1.9054e-03 3.7586e-01 9.4683e-02 8.0809e-02 4.6528e-02 2.3545e-02 1.8810e-02 3.5085e-01 9.3191e-03 3.1759e-03 5.6022e-01 1.1780e-01 8.9039e-02 4.5451e-02 2.0475e-02 1.4504e-02 1.4001e-01 +3.9000e-01 1.5500e+07 5.5315e+02 3.9874e+03 5.1422e-08 2.2105e-01 7.7895e-01 4.6469e+03 3.8330e+03 3.7209e+02 1.7754e+02 4.7211e-05 2.3656e-05 6.9706e-03 1.8854e-03 3.7272e-01 9.4215e-02 8.0589e-02 4.6500e-02 2.3576e-02 1.8870e-02 3.5467e-01 9.3331e-03 3.1830e-03 5.6129e-01 1.1795e-01 8.9100e-02 4.5452e-02 2.0461e-02 1.4481e-02 1.3875e-01 +3.9200e-01 1.5400e+07 5.5315e+02 3.9669e+03 5.1812e-08 2.2631e-01 7.7369e-01 4.6394e+03 3.8055e+03 3.7421e+02 1.7554e+02 4.7550e-05 2.3489e-05 6.9274e-03 1.8656e-03 3.6962e-01 9.3749e-02 8.0368e-02 4.6468e-02 2.3606e-02 1.8928e-02 3.5847e-01 9.3467e-03 3.1898e-03 5.6232e-01 1.1809e-01 8.9160e-02 4.5455e-02 2.0447e-02 1.4460e-02 1.3754e-01 +3.9400e-01 1.5300e+07 5.5315e+02 3.9463e+03 5.2209e-08 2.3123e-01 7.6877e-01 4.6318e+03 3.7781e+03 3.7629e+02 1.7359e+02 4.7884e-05 2.3326e-05 6.8845e-03 1.8462e-03 3.6655e-01 9.3284e-02 8.0144e-02 4.6435e-02 2.3634e-02 1.8985e-02 3.6224e-01 9.3599e-03 3.1963e-03 5.6330e-01 1.1823e-01 8.9219e-02 4.5458e-02 2.0435e-02 1.4439e-02 1.3636e-01 +3.9600e-01 1.5200e+07 5.5315e+02 3.9257e+03 5.2612e-08 2.3584e-01 7.6416e-01 4.6242e+03 3.7508e+03 3.7833e+02 1.7168e+02 4.8214e-05 2.3168e-05 6.8419e-03 1.8270e-03 3.6352e-01 9.2820e-02 7.9919e-02 4.6399e-02 2.3660e-02 1.9041e-02 3.6598e-01 9.3726e-03 3.2025e-03 5.6426e-01 1.1836e-01 8.9278e-02 4.5462e-02 2.0423e-02 1.4420e-02 1.3523e-01 +3.9800e-01 1.5100e+07 5.5315e+02 3.9050e+03 5.3023e-08 2.4016e-01 7.5984e-01 4.6164e+03 3.7236e+03 3.8033e+02 1.6980e+02 4.8540e-05 2.3014e-05 6.7994e-03 1.8081e-03 3.6051e-01 9.2356e-02 7.9691e-02 4.6361e-02 2.3685e-02 1.9095e-02 3.6969e-01 9.3850e-03 3.2085e-03 5.6517e-01 1.1849e-01 8.9336e-02 4.5467e-02 2.0413e-02 1.4401e-02 1.3413e-01 +4.0000e-01 1.5000e+07 5.5315e+02 3.8842e+03 5.3440e-08 2.4423e-01 7.5577e-01 4.6085e+03 3.6965e+03 3.8231e+02 1.6795e+02 4.8863e-05 2.2865e-05 6.7572e-03 1.7894e-03 3.5754e-01 9.1894e-02 7.9461e-02 4.6321e-02 2.3709e-02 1.9148e-02 3.7339e-01 9.3969e-03 3.2143e-03 5.6606e-01 1.1862e-01 8.9394e-02 4.5472e-02 2.0403e-02 1.4383e-02 1.3306e-01 +4.0200e-01 1.4900e+07 5.5315e+02 3.8635e+03 5.3864e-08 2.4805e-01 7.5195e-01 4.6005e+03 3.6695e+03 3.8425e+02 1.6614e+02 4.9182e-05 2.2720e-05 6.7151e-03 1.7710e-03 3.5459e-01 9.1431e-02 7.9229e-02 4.6278e-02 2.3730e-02 1.9200e-02 3.7706e-01 9.4086e-03 3.2198e-03 5.6691e-01 1.1874e-01 8.9451e-02 4.5479e-02 2.0394e-02 1.4367e-02 1.3203e-01 +4.0400e-01 1.4800e+07 5.5315e+02 3.8426e+03 5.4296e-08 2.5166e-01 7.4834e-01 4.5925e+03 3.6426e+03 3.8616e+02 1.6436e+02 4.9499e-05 2.2578e-05 6.6732e-03 1.7528e-03 3.5166e-01 9.0969e-02 7.8995e-02 4.6233e-02 2.3751e-02 1.9250e-02 3.8072e-01 9.4199e-03 3.2251e-03 5.6773e-01 1.1886e-01 8.9507e-02 4.5486e-02 2.0386e-02 1.4351e-02 1.3103e-01 +4.0600e-01 1.4700e+07 5.5315e+02 3.8217e+03 5.4735e-08 2.5506e-01 7.4494e-01 4.5844e+03 3.6158e+03 3.8804e+02 1.6261e+02 4.9812e-05 2.2440e-05 6.6314e-03 1.7348e-03 3.4876e-01 9.0507e-02 7.8758e-02 4.6185e-02 2.3770e-02 1.9299e-02 3.8435e-01 9.4309e-03 3.2302e-03 5.6853e-01 1.1898e-01 8.9563e-02 4.5494e-02 2.0378e-02 1.4336e-02 1.3006e-01 +4.0800e-01 1.4600e+07 5.5315e+02 3.8008e+03 5.5182e-08 2.5828e-01 7.4172e-01 4.5762e+03 3.5890e+03 3.8989e+02 1.6088e+02 5.0123e-05 2.2306e-05 6.5897e-03 1.7170e-03 3.4588e-01 9.0045e-02 7.8519e-02 4.6136e-02 2.3787e-02 1.9347e-02 3.8798e-01 9.4416e-03 3.2351e-03 5.6929e-01 1.1910e-01 8.9619e-02 4.5502e-02 2.0371e-02 1.4322e-02 1.2912e-01 +4.1000e-01 1.4500e+07 5.5315e+02 3.7798e+03 5.5636e-08 2.6132e-01 7.3868e-01 4.5680e+03 3.5623e+03 3.9172e+02 1.5918e+02 5.0432e-05 2.2175e-05 6.5482e-03 1.6994e-03 3.4302e-01 8.9583e-02 7.8277e-02 4.6084e-02 2.3803e-02 1.9394e-02 3.9159e-01 9.4520e-03 3.2398e-03 5.7003e-01 1.1921e-01 8.9674e-02 4.5511e-02 2.0365e-02 1.4309e-02 1.2820e-01 +4.1200e-01 1.4400e+07 5.5315e+02 3.7587e+03 5.6099e-08 2.6420e-01 7.3580e-01 4.5597e+03 3.5357e+03 3.9352e+02 1.5751e+02 5.0738e-05 2.2046e-05 6.5068e-03 1.6820e-03 3.4019e-01 8.9120e-02 7.8033e-02 4.6029e-02 2.3818e-02 1.9439e-02 3.9518e-01 9.4621e-03 3.2443e-03 5.7075e-01 1.1932e-01 8.9729e-02 4.5520e-02 2.0359e-02 1.4296e-02 1.2732e-01 +4.1400e-01 1.4300e+07 5.5315e+02 3.7376e+03 5.6570e-08 2.6693e-01 7.3307e-01 4.5513e+03 3.5092e+03 3.9530e+02 1.5586e+02 5.1041e-05 2.1921e-05 6.4654e-03 1.6648e-03 3.3737e-01 8.8657e-02 7.7787e-02 4.5973e-02 2.3831e-02 1.9483e-02 3.9877e-01 9.4720e-03 3.2486e-03 5.7144e-01 1.1943e-01 8.9783e-02 4.5531e-02 2.0354e-02 1.4284e-02 1.2645e-01 +4.1600e-01 1.4200e+07 5.5315e+02 3.7164e+03 5.7049e-08 2.6951e-01 7.3049e-01 4.5429e+03 3.4827e+03 3.9706e+02 1.5424e+02 5.1343e-05 2.1799e-05 6.4241e-03 1.6477e-03 3.3457e-01 8.8194e-02 7.7538e-02 4.5914e-02 2.3843e-02 1.9526e-02 4.0234e-01 9.4815e-03 3.2528e-03 5.7211e-01 1.1954e-01 8.9837e-02 4.5541e-02 2.0350e-02 1.4273e-02 1.2561e-01 +4.1800e-01 1.4100e+07 5.5315e+02 3.6952e+03 5.7537e-08 2.7196e-01 7.2804e-01 4.5344e+03 3.4563e+03 3.9879e+02 1.5263e+02 5.1642e-05 2.1680e-05 6.3829e-03 1.6308e-03 3.3179e-01 8.7729e-02 7.7286e-02 4.5852e-02 2.3854e-02 1.9567e-02 4.0591e-01 9.4909e-03 3.2568e-03 5.7276e-01 1.1964e-01 8.9891e-02 4.5553e-02 2.0346e-02 1.4262e-02 1.2480e-01 +4.2000e-01 1.4000e+07 5.5315e+02 3.6739e+03 5.8034e-08 2.7428e-01 7.2572e-01 4.5259e+03 3.4299e+03 4.0050e+02 1.5105e+02 5.1940e-05 2.1563e-05 6.3418e-03 1.6141e-03 3.2902e-01 8.7264e-02 7.7032e-02 4.5789e-02 2.3863e-02 1.9608e-02 4.0947e-01 9.5000e-03 3.2607e-03 5.7339e-01 1.1974e-01 8.9944e-02 4.5565e-02 2.0343e-02 1.4252e-02 1.2401e-01 +4.2200e-01 1.3900e+07 5.5315e+02 3.6526e+03 5.8540e-08 2.7649e-01 7.2351e-01 4.5174e+03 3.4036e+03 4.0220e+02 1.4949e+02 5.2236e-05 2.1449e-05 6.3007e-03 1.5975e-03 3.2627e-01 8.6798e-02 7.6774e-02 4.5723e-02 2.3870e-02 1.9647e-02 4.1302e-01 9.5089e-03 3.2644e-03 5.7399e-01 1.1984e-01 8.9997e-02 4.5577e-02 2.0340e-02 1.4243e-02 1.2324e-01 +4.2400e-01 1.3800e+07 5.5315e+02 3.6312e+03 5.9055e-08 2.7858e-01 7.2142e-01 4.5088e+03 3.3773e+03 4.0387e+02 1.4795e+02 5.2530e-05 2.1337e-05 6.2596e-03 1.5811e-03 3.2354e-01 8.6332e-02 7.6515e-02 4.5654e-02 2.3876e-02 1.9685e-02 4.1656e-01 9.5175e-03 3.2680e-03 5.7458e-01 1.1994e-01 9.0050e-02 4.5590e-02 2.0338e-02 1.4234e-02 1.2248e-01 +4.2600e-01 1.3700e+07 5.5315e+02 3.6097e+03 5.9579e-08 2.8057e-01 7.1943e-01 4.5001e+03 3.3511e+03 4.0553e+02 1.4643e+02 5.2822e-05 2.1227e-05 6.2186e-03 1.5648e-03 3.2082e-01 8.5864e-02 7.6252e-02 4.5584e-02 2.3881e-02 1.9722e-02 4.2010e-01 9.5260e-03 3.2714e-03 5.7515e-01 1.2003e-01 9.0103e-02 4.5603e-02 2.0336e-02 1.4226e-02 1.2176e-01 +4.2800e-01 1.3600e+07 5.5315e+02 3.5881e+03 6.0114e-08 2.8245e-01 7.1755e-01 4.4915e+03 3.3249e+03 4.0716e+02 1.4492e+02 5.3113e-05 2.1120e-05 6.1776e-03 1.5487e-03 3.1811e-01 8.5395e-02 7.5986e-02 4.5510e-02 2.3885e-02 1.9758e-02 4.2363e-01 9.5342e-03 3.2747e-03 5.7569e-01 1.2013e-01 9.0155e-02 4.5617e-02 2.0335e-02 1.4218e-02 1.2104e-01 +4.3000e-01 1.3500e+07 5.5315e+02 3.5665e+03 6.0658e-08 2.8424e-01 7.1576e-01 4.4828e+03 3.2988e+03 4.0878e+02 1.4344e+02 5.3402e-05 2.1015e-05 6.1367e-03 1.5327e-03 3.1542e-01 8.4925e-02 7.5718e-02 4.5435e-02 2.3887e-02 1.9792e-02 4.2716e-01 9.5422e-03 3.2778e-03 5.7622e-01 1.2022e-01 9.0207e-02 4.5631e-02 2.0334e-02 1.4212e-02 1.2035e-01 +4.3200e-01 1.3400e+07 5.5315e+02 3.5449e+03 6.1213e-08 2.8594e-01 7.1406e-01 4.4740e+03 3.2727e+03 4.1039e+02 1.4197e+02 5.3690e-05 2.0912e-05 6.0957e-03 1.5168e-03 3.1273e-01 8.4453e-02 7.5447e-02 4.5357e-02 2.3887e-02 1.9825e-02 4.3068e-01 9.5500e-03 3.2809e-03 5.7673e-01 1.2031e-01 9.0258e-02 4.5646e-02 2.0334e-02 1.4205e-02 1.1968e-01 +4.3400e-01 1.3300e+07 5.5315e+02 3.5231e+03 6.1778e-08 2.8755e-01 7.1245e-01 4.4652e+03 3.2467e+03 4.1198e+02 1.4052e+02 5.3977e-05 2.0811e-05 6.0547e-03 1.5011e-03 3.1007e-01 8.3980e-02 7.5172e-02 4.5276e-02 2.3886e-02 1.9858e-02 4.3421e-01 9.5576e-03 3.2838e-03 5.7723e-01 1.2040e-01 9.0310e-02 4.5661e-02 2.0335e-02 1.4199e-02 1.1903e-01 +4.3600e-01 1.3200e+07 5.5315e+02 3.5013e+03 6.2354e-08 2.8908e-01 7.1092e-01 4.4564e+03 3.2207e+03 4.1355e+02 1.3908e+02 5.4262e-05 2.0713e-05 6.0138e-03 1.4855e-03 3.0741e-01 8.3506e-02 7.4895e-02 4.5194e-02 2.3884e-02 1.9889e-02 4.3773e-01 9.5650e-03 3.2866e-03 5.7771e-01 1.2048e-01 9.0361e-02 4.5677e-02 2.0335e-02 1.4194e-02 1.1839e-01 +4.3800e-01 1.3100e+07 5.5315e+02 3.4795e+03 6.2941e-08 2.9052e-01 7.0948e-01 4.4476e+03 3.1947e+03 4.1511e+02 1.3766e+02 5.4546e-05 2.0616e-05 5.9728e-03 1.4700e-03 3.0476e-01 8.3031e-02 7.4615e-02 4.5108e-02 2.3880e-02 1.9918e-02 4.4124e-01 9.5723e-03 3.2893e-03 5.7817e-01 1.2057e-01 9.0412e-02 4.5693e-02 2.0337e-02 1.4189e-02 1.1777e-01 +4.4000e-01 1.3000e+07 5.5315e+02 3.4575e+03 6.3540e-08 2.9189e-01 7.0811e-01 4.4387e+03 3.1688e+03 4.1665e+02 1.3625e+02 5.4829e-05 2.0521e-05 5.9319e-03 1.4546e-03 3.0213e-01 8.2554e-02 7.4331e-02 4.5021e-02 2.3875e-02 1.9947e-02 4.4476e-01 9.5793e-03 3.2918e-03 5.7862e-01 1.2065e-01 9.0462e-02 4.5709e-02 2.0338e-02 1.4185e-02 1.1717e-01 +4.4200e-01 1.2900e+07 5.5315e+02 3.4355e+03 6.4150e-08 2.9319e-01 7.0681e-01 4.4299e+03 3.1429e+03 4.1818e+02 1.3486e+02 5.5111e-05 2.0427e-05 5.8909e-03 1.4393e-03 2.9950e-01 8.2075e-02 7.4045e-02 4.4930e-02 2.3868e-02 1.9974e-02 4.4828e-01 9.5862e-03 3.2943e-03 5.7905e-01 1.2073e-01 9.0512e-02 4.5726e-02 2.0340e-02 1.4181e-02 1.1658e-01 +4.4400e-01 1.2800e+07 5.5315e+02 3.4135e+03 6.4773e-08 2.9442e-01 7.0558e-01 4.4209e+03 3.1171e+03 4.1969e+02 1.3348e+02 5.5392e-05 2.0336e-05 5.8499e-03 1.4241e-03 2.9689e-01 8.1595e-02 7.3755e-02 4.4837e-02 2.3860e-02 2.0000e-02 4.5179e-01 9.5929e-03 3.2966e-03 5.7946e-01 1.2081e-01 9.0562e-02 4.5744e-02 2.0343e-02 1.4178e-02 1.1601e-01 +4.4600e-01 1.2700e+07 5.5315e+02 3.3913e+03 6.5407e-08 2.9557e-01 7.0443e-01 4.4120e+03 3.0912e+03 4.2120e+02 1.3212e+02 5.5672e-05 2.0246e-05 5.8089e-03 1.4091e-03 2.9428e-01 8.1113e-02 7.3462e-02 4.4742e-02 2.3851e-02 2.0025e-02 4.5531e-01 9.5994e-03 3.2989e-03 5.7986e-01 1.2089e-01 9.0612e-02 4.5761e-02 2.0346e-02 1.4175e-02 1.1546e-01 +4.4800e-01 1.2600e+07 5.5315e+02 3.3691e+03 6.6055e-08 2.9667e-01 7.0333e-01 4.4031e+03 3.0655e+03 4.2269e+02 1.3077e+02 5.5951e-05 2.0157e-05 5.7679e-03 1.3941e-03 2.9168e-01 8.0630e-02 7.3166e-02 4.4644e-02 2.3840e-02 2.0049e-02 4.5883e-01 9.6058e-03 3.3010e-03 5.8025e-01 1.2097e-01 9.0662e-02 4.5779e-02 2.0349e-02 1.4172e-02 1.1492e-01 +4.5000e-01 1.2500e+07 5.5315e+02 3.3468e+03 6.6715e-08 2.9769e-01 7.0231e-01 4.3941e+03 3.0397e+03 4.2416e+02 1.2943e+02 5.6229e-05 2.0071e-05 5.7268e-03 1.3793e-03 2.8910e-01 8.0145e-02 7.2867e-02 4.4544e-02 2.3827e-02 2.0071e-02 4.6235e-01 9.6120e-03 3.3030e-03 5.8062e-01 1.2104e-01 9.0711e-02 4.5798e-02 2.0353e-02 1.4170e-02 1.1439e-01 +4.5200e-01 1.2400e+07 5.5315e+02 3.3244e+03 6.7389e-08 2.9866e-01 7.0134e-01 4.3851e+03 3.0140e+03 4.2563e+02 1.2810e+02 5.6506e-05 1.9985e-05 5.6857e-03 1.3645e-03 2.8652e-01 7.9657e-02 7.2564e-02 4.4441e-02 2.3813e-02 2.0093e-02 4.6587e-01 9.6180e-03 3.3050e-03 5.8098e-01 1.2112e-01 9.0760e-02 4.5816e-02 2.0357e-02 1.4169e-02 1.1388e-01 +4.5400e-01 1.2300e+07 5.5315e+02 3.3020e+03 6.8076e-08 2.9957e-01 7.0043e-01 4.3761e+03 2.9883e+03 4.2708e+02 1.2679e+02 5.6783e-05 1.9902e-05 5.6445e-03 1.3499e-03 2.8394e-01 7.9169e-02 7.2259e-02 4.4335e-02 2.3797e-02 2.0113e-02 4.6939e-01 9.6239e-03 3.3068e-03 5.8132e-01 1.2119e-01 9.0808e-02 4.5835e-02 2.0361e-02 1.4168e-02 1.1339e-01 +4.5600e-01 1.2200e+07 5.5315e+02 3.2795e+03 6.8778e-08 3.0041e-01 6.9959e-01 4.3670e+03 2.9627e+03 4.2853e+02 1.2549e+02 5.7058e-05 1.9819e-05 5.6033e-03 1.3353e-03 2.8138e-01 7.8678e-02 7.1949e-02 4.4226e-02 2.3780e-02 2.0131e-02 4.7292e-01 9.6296e-03 3.3086e-03 5.8165e-01 1.2126e-01 9.0857e-02 4.5855e-02 2.0366e-02 1.4167e-02 1.1290e-01 +4.5800e-01 1.2100e+07 5.5315e+02 3.2569e+03 6.9494e-08 3.0121e-01 6.9879e-01 4.3580e+03 2.9370e+03 4.2996e+02 1.2420e+02 5.7333e-05 1.9739e-05 5.5621e-03 1.3208e-03 2.7883e-01 7.8185e-02 7.1637e-02 4.4115e-02 2.3761e-02 2.0149e-02 4.7644e-01 9.6351e-03 3.3102e-03 5.8197e-01 1.2133e-01 9.0905e-02 4.5874e-02 2.0371e-02 1.4167e-02 1.1244e-01 +4.6000e-01 1.2000e+07 5.5315e+02 3.2342e+03 7.0225e-08 3.0194e-01 6.9806e-01 4.3489e+03 2.9114e+03 4.3138e+02 1.2292e+02 5.7608e-05 1.9659e-05 5.5208e-03 1.3065e-03 2.7628e-01 7.7691e-02 7.1321e-02 4.4001e-02 2.3741e-02 2.0165e-02 4.7998e-01 9.6405e-03 3.3118e-03 5.8228e-01 1.2140e-01 9.0952e-02 4.5894e-02 2.0377e-02 1.4168e-02 1.1198e-01 +4.6200e-01 1.1900e+07 5.5315e+02 3.2115e+03 7.0972e-08 3.0263e-01 6.9737e-01 4.3398e+03 2.8859e+03 4.3279e+02 1.2165e+02 5.7881e-05 1.9581e-05 5.4795e-03 1.2922e-03 2.7374e-01 7.7194e-02 7.1001e-02 4.3885e-02 2.3719e-02 2.0180e-02 4.8351e-01 9.6458e-03 3.3133e-03 5.8257e-01 1.2146e-01 9.1000e-02 4.5915e-02 2.0383e-02 1.4168e-02 1.1155e-01 +4.6400e-01 1.1800e+07 5.5315e+02 3.1886e+03 7.1734e-08 3.0326e-01 6.9674e-01 4.3307e+03 2.8603e+03 4.3419e+02 1.2039e+02 5.8154e-05 1.9504e-05 5.4381e-03 1.2780e-03 2.7120e-01 7.6695e-02 7.0678e-02 4.3766e-02 2.3696e-02 2.0193e-02 4.8705e-01 9.6509e-03 3.3147e-03 5.8285e-01 1.2153e-01 9.1047e-02 4.5935e-02 2.0389e-02 1.4169e-02 1.1112e-01 +4.6600e-01 1.1700e+07 5.5315e+02 3.1657e+03 7.2513e-08 3.0384e-01 6.9616e-01 4.3216e+03 2.8348e+03 4.3558e+02 1.1915e+02 5.8427e-05 1.9428e-05 5.3966e-03 1.2638e-03 2.6867e-01 7.6195e-02 7.0352e-02 4.3644e-02 2.3670e-02 2.0205e-02 4.9060e-01 9.6558e-03 3.3160e-03 5.8312e-01 1.2159e-01 9.1094e-02 4.5956e-02 2.0396e-02 1.4171e-02 1.1071e-01 +4.6800e-01 1.1600e+07 5.5315e+02 3.1427e+03 7.3309e-08 3.0436e-01 6.9564e-01 4.3125e+03 2.8093e+03 4.3696e+02 1.1791e+02 5.8699e-05 1.9354e-05 5.3551e-03 1.2498e-03 2.6615e-01 7.5692e-02 7.0022e-02 4.3519e-02 2.3644e-02 2.0216e-02 4.9415e-01 9.6606e-03 3.3172e-03 5.8337e-01 1.2165e-01 9.1140e-02 4.5977e-02 2.0403e-02 1.4173e-02 1.1031e-01 +4.7000e-01 1.1500e+07 5.5315e+02 3.1196e+03 7.4121e-08 3.0484e-01 6.9516e-01 4.3033e+03 2.7838e+03 4.3833e+02 1.1668e+02 5.8970e-05 1.9281e-05 5.3136e-03 1.2358e-03 2.6364e-01 7.5187e-02 6.9688e-02 4.3391e-02 2.3615e-02 2.0225e-02 4.9771e-01 9.6652e-03 3.3183e-03 5.8361e-01 1.2171e-01 9.1186e-02 4.5999e-02 2.0410e-02 1.4175e-02 1.0992e-01 +4.7200e-01 1.1400e+07 5.5315e+02 3.0965e+03 7.4952e-08 3.0527e-01 6.9473e-01 4.2942e+03 2.7584e+03 4.3970e+02 1.1546e+02 5.9241e-05 1.9208e-05 5.2719e-03 1.2220e-03 2.6113e-01 7.4680e-02 6.9351e-02 4.3260e-02 2.3585e-02 2.0233e-02 5.0127e-01 9.6697e-03 3.3194e-03 5.8384e-01 1.2177e-01 9.1232e-02 4.6020e-02 2.0418e-02 1.4178e-02 1.0955e-01 +4.7400e-01 1.1300e+07 5.5315e+02 3.0732e+03 7.5801e-08 3.0566e-01 6.9434e-01 4.2850e+03 2.7330e+03 4.4105e+02 1.1426e+02 5.9511e-05 1.9138e-05 5.2302e-03 1.2082e-03 2.5862e-01 7.4171e-02 6.9010e-02 4.3127e-02 2.3553e-02 2.0239e-02 5.0484e-01 9.6740e-03 3.3204e-03 5.8406e-01 1.2183e-01 9.1278e-02 4.6042e-02 2.0426e-02 1.4181e-02 1.0919e-01 +4.7600e-01 1.1200e+07 5.5315e+02 3.0499e+03 7.6669e-08 3.0599e-01 6.9401e-01 4.2758e+03 2.7076e+03 4.4240e+02 1.1306e+02 5.9781e-05 1.9068e-05 5.1884e-03 1.1944e-03 2.5613e-01 7.3659e-02 6.8665e-02 4.2990e-02 2.3520e-02 2.0244e-02 5.0841e-01 9.6782e-03 3.3213e-03 5.8427e-01 1.2188e-01 9.1323e-02 4.6064e-02 2.0434e-02 1.4185e-02 1.0884e-01 +4.7800e-01 1.1100e+07 5.5315e+02 3.0265e+03 7.7556e-08 3.0628e-01 6.9372e-01 4.2666e+03 2.6822e+03 4.4373e+02 1.1187e+02 6.0051e-05 1.8999e-05 5.1466e-03 1.1808e-03 2.5363e-01 7.3145e-02 6.8317e-02 4.2851e-02 2.3484e-02 2.0248e-02 5.1199e-01 9.6823e-03 3.3221e-03 5.8446e-01 1.2194e-01 9.1367e-02 4.6087e-02 2.0442e-02 1.4189e-02 1.0851e-01 +4.8000e-01 1.1000e+07 5.5315e+02 3.0029e+03 7.8464e-08 3.0653e-01 6.9347e-01 4.2574e+03 2.6569e+03 4.4506e+02 1.1069e+02 6.0320e-05 1.8931e-05 5.1047e-03 1.1672e-03 2.5115e-01 7.2629e-02 6.7965e-02 4.2709e-02 2.3447e-02 2.0250e-02 5.1558e-01 9.6862e-03 3.3228e-03 5.8465e-01 1.2199e-01 9.1412e-02 4.6109e-02 2.0451e-02 1.4193e-02 1.0818e-01 +4.8200e-01 1.0900e+07 5.5315e+02 2.9793e+03 7.9392e-08 3.0673e-01 6.9327e-01 4.2482e+03 2.6316e+03 4.4638e+02 1.0951e+02 6.0589e-05 1.8864e-05 5.0627e-03 1.1537e-03 2.4866e-01 7.2111e-02 6.7609e-02 4.2563e-02 2.3408e-02 2.0251e-02 5.1918e-01 9.6899e-03 3.3235e-03 5.8482e-01 1.2205e-01 9.1456e-02 4.6132e-02 2.0460e-02 1.4197e-02 1.0787e-01 +4.8400e-01 1.0800e+07 5.5315e+02 2.9556e+03 8.0342e-08 3.0688e-01 6.9312e-01 4.2390e+03 2.6063e+03 4.4770e+02 1.0835e+02 6.0857e-05 1.8798e-05 5.0206e-03 1.1403e-03 2.4619e-01 7.1590e-02 6.7249e-02 4.2415e-02 2.3368e-02 2.0250e-02 5.2278e-01 9.6935e-03 3.3241e-03 5.8498e-01 1.2210e-01 9.1499e-02 4.6155e-02 2.0470e-02 1.4203e-02 1.0758e-01 +4.8600e-01 1.0700e+07 5.5315e+02 2.9318e+03 8.1314e-08 3.0699e-01 6.9301e-01 4.2298e+03 2.5810e+03 4.4900e+02 1.0719e+02 6.1125e-05 1.8734e-05 4.9785e-03 1.1269e-03 2.4371e-01 7.1067e-02 6.6885e-02 4.2263e-02 2.3325e-02 2.0247e-02 5.2639e-01 9.6970e-03 3.3246e-03 5.8513e-01 1.2214e-01 9.1542e-02 4.6178e-02 2.0480e-02 1.4208e-02 1.0729e-01 +4.8800e-01 1.0600e+07 5.5315e+02 2.9080e+03 8.2308e-08 3.0705e-01 6.9295e-01 4.2205e+03 2.5557e+03 4.5030e+02 1.0605e+02 6.1393e-05 1.8670e-05 4.9362e-03 1.1136e-03 2.4125e-01 7.0542e-02 6.6518e-02 4.2109e-02 2.3281e-02 2.0243e-02 5.3001e-01 9.7003e-03 3.3251e-03 5.8527e-01 1.2219e-01 9.1585e-02 4.6202e-02 2.0490e-02 1.4214e-02 1.0702e-01 +4.9000e-01 1.0500e+07 5.5315e+02 2.8840e+03 8.3326e-08 3.0707e-01 6.9293e-01 4.2113e+03 2.5305e+03 4.5159e+02 1.0491e+02 6.1661e-05 1.8607e-05 4.8939e-03 1.1004e-03 2.3878e-01 7.0014e-02 6.6146e-02 4.1951e-02 2.3234e-02 2.0237e-02 5.3364e-01 9.7035e-03 3.3254e-03 5.8540e-01 1.2224e-01 9.1627e-02 4.6225e-02 2.0500e-02 1.4220e-02 1.0676e-01 +4.9200e-01 1.0400e+07 5.5315e+02 2.8599e+03 8.4368e-08 3.0705e-01 6.9295e-01 4.2021e+03 2.5053e+03 4.5287e+02 1.0377e+02 6.1928e-05 1.8545e-05 4.8515e-03 1.0873e-03 2.3632e-01 6.9483e-02 6.5771e-02 4.1790e-02 2.3186e-02 2.0230e-02 5.3728e-01 9.7065e-03 3.3257e-03 5.8551e-01 1.2228e-01 9.1669e-02 4.6249e-02 2.0511e-02 1.4226e-02 1.0652e-01 +4.9400e-01 1.0300e+07 5.5315e+02 2.8357e+03 8.5436e-08 3.0698e-01 6.9302e-01 4.1928e+03 2.4801e+03 4.5415e+02 1.0265e+02 6.2195e-05 1.8483e-05 4.8090e-03 1.0742e-03 2.3387e-01 6.8950e-02 6.5391e-02 4.1626e-02 2.3136e-02 2.0221e-02 5.4092e-01 9.7094e-03 3.3260e-03 5.8562e-01 1.2233e-01 9.1710e-02 4.6273e-02 2.0522e-02 1.4233e-02 1.0628e-01 +4.9600e-01 1.0200e+07 5.5315e+02 2.8114e+03 8.6529e-08 3.0687e-01 6.9313e-01 4.1835e+03 2.4550e+03 4.5542e+02 1.0153e+02 6.2462e-05 1.8423e-05 4.7664e-03 1.0611e-03 2.3142e-01 6.8415e-02 6.5007e-02 4.1458e-02 2.3084e-02 2.0210e-02 5.4458e-01 9.7121e-03 3.3261e-03 5.8571e-01 1.2237e-01 9.1751e-02 4.6297e-02 2.0533e-02 1.4241e-02 1.0606e-01 +4.9800e-01 1.0100e+07 5.5315e+02 2.7871e+03 8.7649e-08 3.0672e-01 6.9328e-01 4.1743e+03 2.4298e+03 4.5668e+02 1.0042e+02 6.2728e-05 1.8364e-05 4.7238e-03 1.0482e-03 2.2897e-01 6.7877e-02 6.4620e-02 4.1288e-02 2.3030e-02 2.0197e-02 5.4824e-01 9.7147e-03 3.3262e-03 5.8580e-01 1.2241e-01 9.1791e-02 4.6321e-02 2.0544e-02 1.4248e-02 1.0585e-01 +5.0000e-01 1.0000e+07 5.5315e+02 2.7626e+03 8.8797e-08 3.0652e-01 6.9348e-01 4.1650e+03 2.4047e+03 4.5794e+02 9.9319e+01 6.2995e-05 1.8305e-05 4.6810e-03 1.0353e-03 2.2653e-01 6.7336e-02 6.4228e-02 4.1113e-02 2.2974e-02 2.0183e-02 5.5192e-01 9.7171e-03 3.3262e-03 5.8587e-01 1.2245e-01 9.1830e-02 4.6345e-02 2.0556e-02 1.4256e-02 1.0566e-01 +5.0200e-01 9.9604e+06 5.5315e+02 2.7529e+03 8.9259e-08 3.0643e-01 6.9357e-01 4.1613e+03 2.3947e+03 4.5844e+02 9.8885e+01 6.3100e-05 1.8282e-05 4.6640e-03 1.0302e-03 2.2556e-01 6.7121e-02 6.4071e-02 4.1044e-02 2.2951e-02 2.0177e-02 5.5338e-01 9.7180e-03 3.3262e-03 5.8589e-01 1.2246e-01 9.1846e-02 4.6355e-02 2.0560e-02 1.4259e-02 1.0558e-01 +5.0400e-01 9.9208e+06 5.5315e+02 2.7431e+03 8.9726e-08 3.0633e-01 6.9367e-01 4.1576e+03 2.3848e+03 4.5893e+02 9.8451e+01 6.3206e-05 1.8259e-05 4.6471e-03 1.0251e-03 2.2460e-01 6.6906e-02 6.3914e-02 4.0973e-02 2.2928e-02 2.0171e-02 5.5484e-01 9.7189e-03 3.3262e-03 5.8592e-01 1.2248e-01 9.1861e-02 4.6364e-02 2.0565e-02 1.4263e-02 1.0551e-01 +5.0600e-01 9.8812e+06 5.5315e+02 2.7334e+03 9.0198e-08 3.0623e-01 6.9377e-01 4.1540e+03 2.3749e+03 4.5943e+02 9.8018e+01 6.3311e-05 1.8236e-05 4.6301e-03 1.0200e-03 2.2363e-01 6.6691e-02 6.3757e-02 4.0902e-02 2.2904e-02 2.0164e-02 5.5630e-01 9.7198e-03 3.3261e-03 5.8594e-01 1.2249e-01 9.1877e-02 4.6374e-02 2.0570e-02 1.4266e-02 1.0544e-01 +5.0800e-01 9.8416e+06 5.5315e+02 2.7236e+03 9.0674e-08 3.0612e-01 6.9388e-01 4.1503e+03 2.3649e+03 4.5992e+02 9.7587e+01 6.3416e-05 1.8213e-05 4.6131e-03 1.0150e-03 2.2267e-01 6.6475e-02 6.3599e-02 4.0831e-02 2.2881e-02 2.0157e-02 5.5776e-01 9.7206e-03 3.3261e-03 5.8596e-01 1.2251e-01 9.1892e-02 4.6383e-02 2.0575e-02 1.4269e-02 1.0537e-01 +5.1000e-01 9.8020e+06 5.5315e+02 2.7138e+03 9.1155e-08 3.0600e-01 6.9400e-01 4.1466e+03 2.3550e+03 4.6041e+02 9.7156e+01 6.3522e-05 1.8191e-05 4.5960e-03 1.0099e-03 2.2170e-01 6.6258e-02 6.3440e-02 4.0759e-02 2.2857e-02 2.0150e-02 5.5923e-01 9.7215e-03 3.3260e-03 5.8598e-01 1.2252e-01 9.1907e-02 4.6393e-02 2.0579e-02 1.4273e-02 1.0530e-01 +5.1200e-01 9.7624e+06 5.5315e+02 2.7040e+03 9.1641e-08 3.0587e-01 6.9413e-01 4.1429e+03 2.3451e+03 4.6090e+02 9.6727e+01 6.3627e-05 1.8168e-05 4.5790e-03 1.0049e-03 2.2074e-01 6.6042e-02 6.3280e-02 4.0686e-02 2.2832e-02 2.0142e-02 5.6069e-01 9.7223e-03 3.3260e-03 5.8599e-01 1.2253e-01 9.1922e-02 4.6403e-02 2.0584e-02 1.4276e-02 1.0524e-01 +5.1400e-01 9.7228e+06 5.5315e+02 2.6942e+03 9.2132e-08 3.0574e-01 6.9426e-01 4.1392e+03 2.3352e+03 4.6139e+02 9.6298e+01 6.3732e-05 1.8146e-05 4.5620e-03 9.9982e-04 2.1978e-01 6.5824e-02 6.3120e-02 4.0613e-02 2.2807e-02 2.0134e-02 5.6216e-01 9.7231e-03 3.3259e-03 5.8601e-01 1.2255e-01 9.1937e-02 4.6412e-02 2.0589e-02 1.4280e-02 1.0518e-01 +5.1600e-01 9.6832e+06 5.5315e+02 2.6843e+03 9.2627e-08 3.0560e-01 6.9440e-01 4.1356e+03 2.3252e+03 4.6188e+02 9.5871e+01 6.3837e-05 1.8124e-05 4.5449e-03 9.9479e-04 2.1882e-01 6.5607e-02 6.2959e-02 4.0540e-02 2.2782e-02 2.0126e-02 5.6363e-01 9.7238e-03 3.3258e-03 5.8602e-01 1.2256e-01 9.1952e-02 4.6422e-02 2.0594e-02 1.4283e-02 1.0512e-01 +5.1800e-01 9.6436e+06 5.5315e+02 2.6745e+03 9.3128e-08 3.0545e-01 6.9455e-01 4.1319e+03 2.3153e+03 4.6237e+02 9.5444e+01 6.3943e-05 1.8102e-05 4.5278e-03 9.8977e-04 2.1785e-01 6.5389e-02 6.2797e-02 4.0465e-02 2.2757e-02 2.0118e-02 5.6510e-01 9.7245e-03 3.3257e-03 5.8603e-01 1.2257e-01 9.1967e-02 4.6432e-02 2.0599e-02 1.4287e-02 1.0506e-01 +5.2000e-01 9.6040e+06 5.5315e+02 2.6646e+03 9.3634e-08 3.0530e-01 6.9470e-01 4.1282e+03 2.3054e+03 4.6286e+02 9.5019e+01 6.4048e-05 1.8080e-05 4.5107e-03 9.8476e-04 2.1689e-01 6.5170e-02 6.2635e-02 4.0391e-02 2.2731e-02 2.0109e-02 5.6658e-01 9.7252e-03 3.3256e-03 5.8604e-01 1.2259e-01 9.1982e-02 4.6442e-02 2.0604e-02 1.4291e-02 1.0500e-01 +5.2200e-01 9.5644e+06 5.5315e+02 2.6547e+03 9.4145e-08 3.0514e-01 6.9486e-01 4.1245e+03 2.2955e+03 4.6335e+02 9.4595e+01 6.4153e-05 1.8058e-05 4.4936e-03 9.7976e-04 2.1593e-01 6.4951e-02 6.2472e-02 4.0315e-02 2.2705e-02 2.0100e-02 5.6805e-01 9.7259e-03 3.3254e-03 5.8605e-01 1.2260e-01 9.1996e-02 4.6451e-02 2.0609e-02 1.4295e-02 1.0495e-01 +5.2400e-01 9.5248e+06 5.5315e+02 2.6448e+03 9.4661e-08 3.0497e-01 6.9503e-01 4.1208e+03 2.2856e+03 4.6383e+02 9.4171e+01 6.4258e-05 1.8036e-05 4.4765e-03 9.7477e-04 2.1497e-01 6.4732e-02 6.2308e-02 4.0240e-02 2.2679e-02 2.0091e-02 5.6953e-01 9.7266e-03 3.3253e-03 5.8606e-01 1.2261e-01 9.2011e-02 4.6461e-02 2.0614e-02 1.4298e-02 1.0490e-01 +5.2600e-01 9.4852e+06 5.5315e+02 2.6349e+03 9.5182e-08 3.0480e-01 6.9520e-01 4.1171e+03 2.2757e+03 4.6432e+02 9.3749e+01 6.4363e-05 1.8014e-05 4.4593e-03 9.6979e-04 2.1401e-01 6.4512e-02 6.2144e-02 4.0163e-02 2.2652e-02 2.0081e-02 5.7101e-01 9.7272e-03 3.3251e-03 5.8606e-01 1.2262e-01 9.2025e-02 4.6471e-02 2.0619e-02 1.4302e-02 1.0485e-01 +5.2800e-01 9.4456e+06 5.5315e+02 2.6250e+03 9.5709e-08 3.0462e-01 6.9538e-01 4.1134e+03 2.2658e+03 4.6480e+02 9.3328e+01 6.4469e-05 1.7993e-05 4.4422e-03 9.6482e-04 2.1305e-01 6.4292e-02 6.1979e-02 4.0086e-02 2.2625e-02 2.0071e-02 5.7249e-01 9.7278e-03 3.3250e-03 5.8606e-01 1.2263e-01 9.2039e-02 4.6480e-02 2.0625e-02 1.4306e-02 1.0480e-01 +5.3000e-01 9.4060e+06 5.5315e+02 2.6150e+03 9.6241e-08 3.0443e-01 6.9557e-01 4.1098e+03 2.2559e+03 4.6528e+02 9.2908e+01 6.4574e-05 1.7971e-05 4.4250e-03 9.5985e-04 2.1209e-01 6.4071e-02 6.1813e-02 4.0009e-02 2.2597e-02 2.0061e-02 5.7397e-01 9.7284e-03 3.3248e-03 5.8606e-01 1.2264e-01 9.2053e-02 4.6490e-02 2.0630e-02 1.4310e-02 1.0476e-01 +5.3200e-01 9.3664e+06 5.5315e+02 2.6050e+03 9.6779e-08 3.0423e-01 6.9577e-01 4.1061e+03 2.2460e+03 4.6576e+02 9.2488e+01 6.4679e-05 1.7950e-05 4.4078e-03 9.5490e-04 2.1113e-01 6.3850e-02 6.1646e-02 3.9931e-02 2.2569e-02 2.0050e-02 5.7546e-01 9.7290e-03 3.3246e-03 5.8606e-01 1.2266e-01 9.2067e-02 4.6500e-02 2.0635e-02 1.4314e-02 1.0471e-01 +5.3400e-01 9.3268e+06 5.5315e+02 2.5950e+03 9.7322e-08 3.0403e-01 6.9597e-01 4.1024e+03 2.2361e+03 4.6625e+02 9.2070e+01 6.4784e-05 1.7928e-05 4.3906e-03 9.4995e-04 2.1018e-01 6.3629e-02 6.1479e-02 3.9852e-02 2.2541e-02 2.0039e-02 5.7694e-01 9.7295e-03 3.3244e-03 5.8606e-01 1.2267e-01 9.2081e-02 4.6510e-02 2.0640e-02 1.4318e-02 1.0467e-01 +5.3600e-01 9.2872e+06 5.5315e+02 2.5850e+03 9.7871e-08 3.0382e-01 6.9618e-01 4.0987e+03 2.2262e+03 4.6673e+02 9.1652e+01 6.4889e-05 1.7907e-05 4.3734e-03 9.4502e-04 2.0922e-01 6.3407e-02 6.1312e-02 3.9773e-02 2.2513e-02 2.0028e-02 5.7843e-01 9.7300e-03 3.3242e-03 5.8605e-01 1.2268e-01 9.2095e-02 4.6519e-02 2.0646e-02 1.4322e-02 1.0463e-01 +5.3800e-01 9.2476e+06 5.5315e+02 2.5750e+03 9.8426e-08 3.0360e-01 6.9640e-01 4.0950e+03 2.2163e+03 4.6721e+02 9.1236e+01 6.4994e-05 1.7886e-05 4.3562e-03 9.4009e-04 2.0826e-01 6.3185e-02 6.1143e-02 3.9693e-02 2.2484e-02 2.0016e-02 5.7992e-01 9.7305e-03 3.3240e-03 5.8605e-01 1.2269e-01 9.2109e-02 4.6529e-02 2.0651e-02 1.4327e-02 1.0459e-01 +5.4000e-01 9.2080e+06 5.5315e+02 2.5649e+03 9.8987e-08 3.0338e-01 6.9662e-01 4.0913e+03 2.2065e+03 4.6768e+02 9.0820e+01 6.5099e-05 1.7865e-05 4.3389e-03 9.3517e-04 2.0731e-01 6.2962e-02 6.0974e-02 3.9613e-02 2.2454e-02 2.0005e-02 5.8141e-01 9.7309e-03 3.3238e-03 5.8604e-01 1.2270e-01 9.2122e-02 4.6539e-02 2.0656e-02 1.4331e-02 1.0456e-01 +5.4200e-01 9.1684e+06 5.5315e+02 2.5549e+03 9.9554e-08 3.0315e-01 6.9685e-01 4.0876e+03 2.1966e+03 4.6816e+02 9.0406e+01 6.5204e-05 1.7844e-05 4.3217e-03 9.3026e-04 2.0635e-01 6.2739e-02 6.0804e-02 3.9532e-02 2.2425e-02 1.9992e-02 5.8291e-01 9.7314e-03 3.3236e-03 5.8603e-01 1.2271e-01 9.2136e-02 4.6549e-02 2.0662e-02 1.4335e-02 1.0453e-01 +5.4400e-01 9.1288e+06 5.5315e+02 2.5448e+03 1.0013e-07 3.0291e-01 6.9709e-01 4.0839e+03 2.1867e+03 4.6864e+02 8.9992e+01 6.5309e-05 1.7824e-05 4.3044e-03 9.2535e-04 2.0540e-01 6.2515e-02 6.0633e-02 3.9450e-02 2.2395e-02 1.9980e-02 5.8440e-01 9.7318e-03 3.3233e-03 5.8602e-01 1.2272e-01 9.2149e-02 4.6558e-02 2.0667e-02 1.4340e-02 1.0450e-01 +5.4600e-01 9.0892e+06 5.5315e+02 2.5347e+03 1.0071e-07 3.0266e-01 6.9734e-01 4.0802e+03 2.1768e+03 4.6912e+02 8.9579e+01 6.5414e-05 1.7803e-05 4.2871e-03 9.2046e-04 2.0444e-01 6.2291e-02 6.0462e-02 3.9368e-02 2.2364e-02 1.9967e-02 5.8590e-01 9.7321e-03 3.3231e-03 5.8600e-01 1.2273e-01 9.2162e-02 4.6568e-02 2.0673e-02 1.4344e-02 1.0447e-01 +5.4800e-01 9.0496e+06 5.5315e+02 2.5246e+03 1.0129e-07 3.0241e-01 6.9759e-01 4.0765e+03 2.1670e+03 4.6959e+02 8.9168e+01 6.5519e-05 1.7782e-05 4.2698e-03 9.1557e-04 2.0349e-01 6.2066e-02 6.0290e-02 3.9285e-02 2.2334e-02 1.9954e-02 5.8740e-01 9.7325e-03 3.3228e-03 5.8599e-01 1.2273e-01 9.2175e-02 4.6578e-02 2.0678e-02 1.4348e-02 1.0444e-01 +5.5000e-01 9.0100e+06 5.5315e+02 2.5145e+03 1.0188e-07 3.0215e-01 6.9785e-01 4.0729e+03 2.1571e+03 4.7007e+02 8.8757e+01 6.5624e-05 1.7762e-05 4.2524e-03 9.1069e-04 2.0253e-01 6.1842e-02 6.0117e-02 3.9202e-02 2.2303e-02 1.9940e-02 5.8890e-01 9.7328e-03 3.3225e-03 5.8597e-01 1.2274e-01 9.2188e-02 4.6588e-02 2.0684e-02 1.4353e-02 1.0442e-01 +5.5200e-01 8.9704e+06 5.5315e+02 2.5043e+03 1.0248e-07 3.0188e-01 6.9812e-01 4.0692e+03 2.1472e+03 4.7054e+02 8.8347e+01 6.5729e-05 1.7742e-05 4.2351e-03 9.0583e-04 2.0158e-01 6.1616e-02 5.9944e-02 3.9118e-02 2.2271e-02 1.9927e-02 5.9040e-01 9.7331e-03 3.3222e-03 5.8595e-01 1.2275e-01 9.2201e-02 4.6597e-02 2.0689e-02 1.4357e-02 1.0439e-01 +5.5400e-01 8.9308e+06 5.5315e+02 2.4941e+03 1.0308e-07 3.0160e-01 6.9840e-01 4.0655e+03 2.1374e+03 4.7101e+02 8.7938e+01 6.5834e-05 1.7721e-05 4.2177e-03 9.0096e-04 2.0063e-01 6.1390e-02 5.9770e-02 3.9034e-02 2.2239e-02 1.9912e-02 5.9191e-01 9.7334e-03 3.3219e-03 5.8593e-01 1.2276e-01 9.2214e-02 4.6607e-02 2.0695e-02 1.4362e-02 1.0437e-01 +5.5600e-01 8.8912e+06 5.5315e+02 2.4839e+03 1.0369e-07 3.0132e-01 6.9868e-01 4.0618e+03 2.1275e+03 4.7149e+02 8.7530e+01 6.5939e-05 1.7701e-05 4.2003e-03 8.9611e-04 1.9967e-01 6.1164e-02 5.9595e-02 3.8949e-02 2.2207e-02 1.9898e-02 5.9342e-01 9.7336e-03 3.3216e-03 5.8591e-01 1.2277e-01 9.2227e-02 4.6617e-02 2.0700e-02 1.4367e-02 1.0436e-01 +5.5800e-01 8.8516e+06 5.5315e+02 2.4737e+03 1.0431e-07 3.0102e-01 6.9898e-01 4.0581e+03 2.1177e+03 4.7196e+02 8.7123e+01 6.6044e-05 1.7681e-05 4.1829e-03 8.9127e-04 1.9872e-01 6.0937e-02 5.9419e-02 3.8863e-02 2.2174e-02 1.9883e-02 5.9493e-01 9.7339e-03 3.3213e-03 5.8588e-01 1.2278e-01 9.2239e-02 4.6626e-02 2.0706e-02 1.4371e-02 1.0434e-01 +5.6000e-01 8.8120e+06 5.5315e+02 2.4635e+03 1.0494e-07 3.0072e-01 6.9928e-01 4.0544e+03 2.1078e+03 4.7243e+02 8.6716e+01 6.6149e-05 1.7661e-05 4.1655e-03 8.8643e-04 1.9777e-01 6.0710e-02 5.9243e-02 3.8777e-02 2.2141e-02 1.9868e-02 5.9644e-01 9.7341e-03 3.3209e-03 5.8586e-01 1.2278e-01 9.2251e-02 4.6636e-02 2.0712e-02 1.4376e-02 1.0433e-01 +5.6200e-01 8.7724e+06 5.5315e+02 2.4533e+03 1.0557e-07 3.0042e-01 6.9958e-01 4.0507e+03 2.0980e+03 4.7290e+02 8.6311e+01 6.6254e-05 1.7641e-05 4.1481e-03 8.8160e-04 1.9682e-01 6.0483e-02 5.9066e-02 3.8690e-02 2.2108e-02 1.9852e-02 5.9795e-01 9.7342e-03 3.3206e-03 5.8583e-01 1.2279e-01 9.2263e-02 4.6646e-02 2.0717e-02 1.4381e-02 1.0432e-01 +5.6400e-01 8.7328e+06 5.5315e+02 2.4430e+03 1.0621e-07 3.0010e-01 6.9990e-01 4.0470e+03 2.0881e+03 4.7337e+02 8.5906e+01 6.6358e-05 1.7621e-05 4.1306e-03 8.7678e-04 1.9587e-01 6.0255e-02 5.8888e-02 3.8603e-02 2.2074e-02 1.9836e-02 5.9947e-01 9.7344e-03 3.3202e-03 5.8580e-01 1.2280e-01 9.2275e-02 4.6655e-02 2.0723e-02 1.4386e-02 1.0431e-01 +5.6600e-01 8.6932e+06 5.5315e+02 2.4327e+03 1.0685e-07 2.9978e-01 7.0022e-01 4.0433e+03 2.0783e+03 4.7384e+02 8.5502e+01 6.6463e-05 1.7601e-05 4.1132e-03 8.7197e-04 1.9492e-01 6.0026e-02 5.8709e-02 3.8514e-02 2.2040e-02 1.9820e-02 6.0099e-01 9.7345e-03 3.3198e-03 5.8577e-01 1.2280e-01 9.2287e-02 4.6665e-02 2.0729e-02 1.4391e-02 1.0430e-01 +5.6800e-01 8.6536e+06 5.5315e+02 2.4224e+03 1.0750e-07 2.9945e-01 7.0055e-01 4.0396e+03 2.0684e+03 4.7430e+02 8.5100e+01 6.6568e-05 1.7582e-05 4.0957e-03 8.6717e-04 1.9397e-01 5.9797e-02 5.8530e-02 3.8426e-02 2.2006e-02 1.9804e-02 6.0251e-01 9.7345e-03 3.3194e-03 5.8573e-01 1.2281e-01 9.2299e-02 4.6675e-02 2.0734e-02 1.4396e-02 1.0430e-01 +5.7000e-01 8.6140e+06 5.5315e+02 2.4121e+03 1.0816e-07 2.9911e-01 7.0089e-01 4.0359e+03 2.0586e+03 4.7477e+02 8.4698e+01 6.6673e-05 1.7562e-05 4.0782e-03 8.6237e-04 1.9302e-01 5.9568e-02 5.8350e-02 3.8336e-02 2.1971e-02 1.9787e-02 6.0403e-01 9.7346e-03 3.3191e-03 5.8570e-01 1.2281e-01 9.2310e-02 4.6684e-02 2.0740e-02 1.4401e-02 1.0430e-01 +5.7200e-01 8.5744e+06 5.5315e+02 2.4017e+03 1.0883e-07 2.9876e-01 7.0124e-01 4.0322e+03 2.0488e+03 4.7524e+02 8.4296e+01 6.6778e-05 1.7543e-05 4.0607e-03 8.5759e-04 1.9207e-01 5.9338e-02 5.8169e-02 3.8246e-02 2.1935e-02 1.9769e-02 6.0556e-01 9.7346e-03 3.3186e-03 5.8566e-01 1.2282e-01 9.2322e-02 4.6694e-02 2.0746e-02 1.4406e-02 1.0430e-01 +5.7400e-01 8.5348e+06 5.5315e+02 2.3914e+03 1.0950e-07 2.9840e-01 7.0160e-01 4.0285e+03 2.0390e+03 4.7570e+02 8.3896e+01 6.6883e-05 1.7523e-05 4.0431e-03 8.5281e-04 1.9112e-01 5.9108e-02 5.7988e-02 3.8156e-02 2.1900e-02 1.9752e-02 6.0708e-01 9.7346e-03 3.3182e-03 5.8562e-01 1.2282e-01 9.2333e-02 4.6703e-02 2.0752e-02 1.4411e-02 1.0430e-01 +5.7600e-01 8.4952e+06 5.5315e+02 2.3810e+03 1.1019e-07 2.9804e-01 7.0196e-01 4.0248e+03 2.0291e+03 4.7617e+02 8.3497e+01 6.6988e-05 1.7504e-05 4.0256e-03 8.4804e-04 1.9017e-01 5.8877e-02 5.7806e-02 3.8065e-02 2.1864e-02 1.9733e-02 6.0861e-01 9.7346e-03 3.3178e-03 5.8558e-01 1.2283e-01 9.2344e-02 4.6713e-02 2.0758e-02 1.4416e-02 1.0431e-01 +5.7800e-01 8.4556e+06 5.5315e+02 2.3706e+03 1.1088e-07 2.9767e-01 7.0233e-01 4.0211e+03 2.0193e+03 4.7663e+02 8.3098e+01 6.7093e-05 1.7485e-05 4.0080e-03 8.4327e-04 1.8922e-01 5.8646e-02 5.7623e-02 3.7973e-02 2.1827e-02 1.9715e-02 6.1014e-01 9.7345e-03 3.3173e-03 5.8554e-01 1.2283e-01 9.2355e-02 4.6722e-02 2.0764e-02 1.4421e-02 1.0432e-01 +5.8000e-01 8.4160e+06 5.5315e+02 2.3602e+03 1.1158e-07 2.9729e-01 7.0271e-01 4.0174e+03 2.0095e+03 4.7709e+02 8.2700e+01 6.7198e-05 1.7465e-05 3.9904e-03 8.3852e-04 1.8827e-01 5.8414e-02 5.7439e-02 3.7881e-02 2.1790e-02 1.9696e-02 6.1168e-01 9.7345e-03 3.3169e-03 5.8549e-01 1.2284e-01 9.2366e-02 4.6732e-02 2.0769e-02 1.4426e-02 1.0433e-01 +5.8200e-01 8.3764e+06 5.5315e+02 2.3497e+03 1.1228e-07 2.9690e-01 7.0310e-01 4.0137e+03 1.9997e+03 4.7756e+02 8.2303e+01 6.7302e-05 1.7446e-05 3.9728e-03 8.3377e-04 1.8733e-01 5.8182e-02 5.7255e-02 3.7787e-02 2.1753e-02 1.9677e-02 6.1321e-01 9.7343e-03 3.3164e-03 5.8544e-01 1.2284e-01 9.2376e-02 4.6741e-02 2.0775e-02 1.4431e-02 1.0434e-01 +5.8400e-01 8.3368e+06 5.5315e+02 2.3393e+03 1.1300e-07 2.9650e-01 7.0350e-01 4.0100e+03 1.9899e+03 4.7802e+02 8.1907e+01 6.7407e-05 1.7427e-05 3.9552e-03 8.2903e-04 1.8638e-01 5.7949e-02 5.7069e-02 3.7694e-02 2.1715e-02 1.9657e-02 6.1475e-01 9.7342e-03 3.3159e-03 5.8539e-01 1.2284e-01 9.2387e-02 4.6751e-02 2.0781e-02 1.4437e-02 1.0436e-01 +5.8600e-01 8.2972e+06 5.5315e+02 2.3288e+03 1.1372e-07 2.9610e-01 7.0390e-01 4.0063e+03 1.9801e+03 4.7848e+02 8.1512e+01 6.7512e-05 1.7408e-05 3.9376e-03 8.2430e-04 1.8543e-01 5.7716e-02 5.6883e-02 3.7599e-02 2.1677e-02 1.9638e-02 6.1629e-01 9.7340e-03 3.3155e-03 5.8534e-01 1.2285e-01 9.2397e-02 4.6760e-02 2.0787e-02 1.4442e-02 1.0438e-01 +5.8800e-01 8.2576e+06 5.5315e+02 2.3183e+03 1.1445e-07 2.9568e-01 7.0432e-01 4.0026e+03 1.9703e+03 4.7894e+02 8.1117e+01 6.7617e-05 1.7389e-05 3.9199e-03 8.1957e-04 1.8449e-01 5.7482e-02 5.6697e-02 3.7504e-02 2.1638e-02 1.9617e-02 6.1784e-01 9.7338e-03 3.3150e-03 5.8529e-01 1.2285e-01 9.2407e-02 4.6769e-02 2.0793e-02 1.4448e-02 1.0440e-01 +5.9000e-01 8.2180e+06 5.5315e+02 2.3078e+03 1.1519e-07 2.9526e-01 7.0474e-01 3.9989e+03 1.9604e+03 4.7940e+02 8.0724e+01 6.7722e-05 1.7371e-05 3.9022e-03 8.1485e-04 1.8354e-01 5.7248e-02 5.6509e-02 3.7409e-02 2.1599e-02 1.9596e-02 6.1938e-01 9.7336e-03 3.3144e-03 5.8523e-01 1.2285e-01 9.2417e-02 4.6779e-02 2.0799e-02 1.4453e-02 1.0442e-01 +5.9200e-01 8.1784e+06 5.5315e+02 2.2973e+03 1.1594e-07 2.9483e-01 7.0517e-01 3.9952e+03 1.9506e+03 4.7986e+02 8.0331e+01 6.7827e-05 1.7352e-05 3.8845e-03 8.1014e-04 1.8259e-01 5.7014e-02 5.6321e-02 3.7313e-02 2.1560e-02 1.9575e-02 6.2093e-01 9.7333e-03 3.3139e-03 5.8517e-01 1.2285e-01 9.2427e-02 4.6788e-02 2.0805e-02 1.4458e-02 1.0444e-01 +5.9400e-01 8.1388e+06 5.5315e+02 2.2867e+03 1.1670e-07 2.9439e-01 7.0561e-01 3.9915e+03 1.9409e+03 4.8032e+02 7.9939e+01 6.7931e-05 1.7333e-05 3.8668e-03 8.0544e-04 1.8165e-01 5.6779e-02 5.6132e-02 3.7216e-02 2.1520e-02 1.9554e-02 6.2248e-01 9.7330e-03 3.3134e-03 5.8512e-01 1.2286e-01 9.2436e-02 4.6797e-02 2.0811e-02 1.4464e-02 1.0447e-01 +5.9600e-01 8.0992e+06 5.5315e+02 2.2761e+03 1.1746e-07 2.9394e-01 7.0606e-01 3.9878e+03 1.9311e+03 4.8077e+02 7.9547e+01 6.8036e-05 1.7315e-05 3.8491e-03 8.0075e-04 1.8070e-01 5.6544e-02 5.5942e-02 3.7118e-02 2.1480e-02 1.9532e-02 6.2403e-01 9.7327e-03 3.3128e-03 5.8505e-01 1.2286e-01 9.2446e-02 4.6807e-02 2.0818e-02 1.4470e-02 1.0450e-01 +5.9800e-01 8.0596e+06 5.5315e+02 2.2655e+03 1.1824e-07 2.9348e-01 7.0652e-01 3.9841e+03 1.9213e+03 4.8123e+02 7.9157e+01 6.8141e-05 1.7296e-05 3.8314e-03 7.9606e-04 1.7976e-01 5.6308e-02 5.5752e-02 3.7020e-02 2.1439e-02 1.9510e-02 6.2558e-01 9.7323e-03 3.3123e-03 5.8499e-01 1.2286e-01 9.2455e-02 4.6816e-02 2.0824e-02 1.4475e-02 1.0454e-01 +6.0000e-01 8.0200e+06 5.5315e+02 2.2549e+03 1.1902e-07 2.9301e-01 7.0699e-01 3.9803e+03 1.9115e+03 4.8169e+02 7.8767e+01 6.8246e-05 1.7278e-05 3.8136e-03 7.9138e-04 1.7882e-01 5.6072e-02 5.5560e-02 3.6921e-02 2.1398e-02 1.9487e-02 6.2714e-01 9.7319e-03 3.3117e-03 5.8492e-01 1.2286e-01 9.2464e-02 4.6825e-02 2.0830e-02 1.4481e-02 1.0457e-01 +6.0200e-01 7.9804e+06 5.5315e+02 2.2443e+03 1.1982e-07 2.9254e-01 7.0746e-01 3.9766e+03 1.9017e+03 4.8214e+02 7.8378e+01 6.8351e-05 1.7259e-05 3.7958e-03 7.8671e-04 1.7787e-01 5.5835e-02 5.5368e-02 3.6821e-02 2.1356e-02 1.9464e-02 6.2870e-01 9.7315e-03 3.3111e-03 5.8486e-01 1.2286e-01 9.2473e-02 4.6834e-02 2.0836e-02 1.4487e-02 1.0461e-01 +6.0400e-01 7.9408e+06 5.5315e+02 2.2336e+03 1.2062e-07 2.9205e-01 7.0795e-01 3.9729e+03 1.8919e+03 4.8260e+02 7.7990e+01 6.8456e-05 1.7241e-05 3.7780e-03 7.8205e-04 1.7693e-01 5.5597e-02 5.5175e-02 3.6721e-02 2.1314e-02 1.9440e-02 6.3026e-01 9.7310e-03 3.3105e-03 5.8479e-01 1.2286e-01 9.2481e-02 4.6843e-02 2.0842e-02 1.4492e-02 1.0465e-01 +6.0600e-01 7.9012e+06 5.5315e+02 2.2229e+03 1.2144e-07 2.9155e-01 7.0845e-01 3.9692e+03 1.8821e+03 4.8305e+02 7.7602e+01 6.8560e-05 1.7223e-05 3.7602e-03 7.7739e-04 1.7599e-01 5.5360e-02 5.4982e-02 3.6620e-02 2.1272e-02 1.9416e-02 6.3183e-01 9.7306e-03 3.3099e-03 5.8471e-01 1.2286e-01 9.2490e-02 4.6852e-02 2.0848e-02 1.4498e-02 1.0470e-01 +6.0800e-01 7.8616e+06 5.5315e+02 2.2122e+03 1.2226e-07 2.9105e-01 7.0895e-01 3.9655e+03 1.8724e+03 4.8351e+02 7.7216e+01 6.8665e-05 1.7204e-05 3.7424e-03 7.7274e-04 1.7504e-01 5.5121e-02 5.4787e-02 3.6519e-02 2.1229e-02 1.9392e-02 6.3339e-01 9.7300e-03 3.3093e-03 5.8464e-01 1.2286e-01 9.2498e-02 4.6861e-02 2.0854e-02 1.4504e-02 1.0474e-01 +6.1000e-01 7.8220e+06 5.5315e+02 2.2015e+03 1.2309e-07 2.9053e-01 7.0947e-01 3.9618e+03 1.8626e+03 4.8396e+02 7.6830e+01 6.8770e-05 1.7186e-05 3.7245e-03 7.6810e-04 1.7410e-01 5.4883e-02 5.4592e-02 3.6416e-02 2.1186e-02 1.9367e-02 6.3496e-01 9.7295e-03 3.3086e-03 5.8456e-01 1.2286e-01 9.2506e-02 4.6870e-02 2.0860e-02 1.4510e-02 1.0479e-01 +6.1200e-01 7.7824e+06 5.5315e+02 2.1908e+03 1.2394e-07 2.9001e-01 7.0999e-01 3.9581e+03 1.8528e+03 4.8441e+02 7.6444e+01 6.8875e-05 1.7168e-05 3.7067e-03 7.6347e-04 1.7316e-01 5.4644e-02 5.4396e-02 3.6313e-02 2.1142e-02 1.9342e-02 6.3654e-01 9.7289e-03 3.3080e-03 5.8448e-01 1.2286e-01 9.2514e-02 4.6879e-02 2.0867e-02 1.4516e-02 1.0485e-01 +6.1400e-01 7.7428e+06 5.5315e+02 2.1800e+03 1.2479e-07 2.8947e-01 7.1053e-01 3.9544e+03 1.8431e+03 4.8487e+02 7.6060e+01 6.8980e-05 1.7150e-05 3.6888e-03 7.5884e-04 1.7222e-01 5.4404e-02 5.4199e-02 3.6210e-02 2.1098e-02 1.9316e-02 6.3811e-01 9.7283e-03 3.3073e-03 5.8440e-01 1.2285e-01 9.2521e-02 4.6888e-02 2.0873e-02 1.4522e-02 1.0490e-01 +6.1600e-01 7.7032e+06 5.5315e+02 2.1692e+03 1.2566e-07 2.8893e-01 7.1107e-01 3.9507e+03 1.8333e+03 4.8532e+02 7.5676e+01 6.9085e-05 1.7132e-05 3.6709e-03 7.5422e-04 1.7128e-01 5.4164e-02 5.4001e-02 3.6105e-02 2.1053e-02 1.9290e-02 6.3969e-01 9.7276e-03 3.3066e-03 5.8432e-01 1.2285e-01 9.2528e-02 4.6896e-02 2.0879e-02 1.4528e-02 1.0496e-01 +6.1800e-01 7.6636e+06 5.5315e+02 2.1584e+03 1.2653e-07 2.8838e-01 7.1162e-01 3.9470e+03 1.8236e+03 4.8577e+02 7.5293e+01 6.9189e-05 1.7114e-05 3.6530e-03 7.4961e-04 1.7033e-01 5.3923e-02 5.3803e-02 3.6000e-02 2.1008e-02 1.9263e-02 6.4127e-01 9.7269e-03 3.3059e-03 5.8424e-01 1.2285e-01 9.2536e-02 4.6905e-02 2.0885e-02 1.4534e-02 1.0502e-01 +6.2000e-01 7.6240e+06 5.5315e+02 2.1476e+03 1.2742e-07 2.8781e-01 7.1219e-01 3.9433e+03 1.8138e+03 4.8622e+02 7.4911e+01 6.9294e-05 1.7097e-05 3.6350e-03 7.4500e-04 1.6939e-01 5.3682e-02 5.3604e-02 3.5895e-02 2.0962e-02 1.9237e-02 6.4285e-01 9.7262e-03 3.3052e-03 5.8415e-01 1.2285e-01 9.2542e-02 4.6914e-02 2.0892e-02 1.4540e-02 1.0509e-01 +6.2200e-01 7.5844e+06 5.5315e+02 2.1367e+03 1.2832e-07 2.8724e-01 7.1276e-01 3.9396e+03 1.8040e+03 4.8667e+02 7.4530e+01 6.9399e-05 1.7079e-05 3.6171e-03 7.4040e-04 1.6845e-01 5.3440e-02 5.3404e-02 3.5788e-02 2.0916e-02 1.9209e-02 6.4443e-01 9.7255e-03 3.3045e-03 5.8406e-01 1.2284e-01 9.2549e-02 4.6922e-02 2.0898e-02 1.4546e-02 1.0515e-01 +6.2400e-01 7.5448e+06 5.5315e+02 2.1259e+03 1.2923e-07 2.8665e-01 7.1335e-01 3.9359e+03 1.7943e+03 4.8712e+02 7.4149e+01 6.9504e-05 1.7061e-05 3.5991e-03 7.3581e-04 1.6751e-01 5.3198e-02 5.3203e-02 3.5681e-02 2.0870e-02 1.9181e-02 6.4602e-01 9.7247e-03 3.3038e-03 5.8397e-01 1.2284e-01 9.2555e-02 4.6931e-02 2.0904e-02 1.4552e-02 1.0522e-01 +6.2600e-01 7.5052e+06 5.5315e+02 2.1150e+03 1.3015e-07 2.8605e-01 7.1395e-01 3.9321e+03 1.7846e+03 4.8757e+02 7.3769e+01 6.9609e-05 1.7043e-05 3.5811e-03 7.3123e-04 1.6657e-01 5.2956e-02 5.3001e-02 3.5573e-02 2.0823e-02 1.9153e-02 6.4761e-01 9.7238e-03 3.3031e-03 5.8387e-01 1.2283e-01 9.2562e-02 4.6939e-02 2.0910e-02 1.4559e-02 1.0530e-01 +6.2800e-01 7.4656e+06 5.5315e+02 2.1041e+03 1.3108e-07 2.8545e-01 7.1455e-01 3.9284e+03 1.7748e+03 4.8801e+02 7.3390e+01 6.9714e-05 1.7026e-05 3.5631e-03 7.2665e-04 1.6563e-01 5.2713e-02 5.2799e-02 3.5465e-02 2.0775e-02 1.9124e-02 6.4920e-01 9.7230e-03 3.3023e-03 5.8378e-01 1.2283e-01 9.2568e-02 4.6948e-02 2.0917e-02 1.4565e-02 1.0537e-01 +6.3000e-01 7.4260e+06 5.5315e+02 2.0931e+03 1.3203e-07 2.8483e-01 7.1517e-01 3.9247e+03 1.7651e+03 4.8846e+02 7.3011e+01 6.9818e-05 1.7008e-05 3.5451e-03 7.2208e-04 1.6469e-01 5.2469e-02 5.2595e-02 3.5356e-02 2.0727e-02 1.9095e-02 6.5080e-01 9.7221e-03 3.3015e-03 5.8368e-01 1.2282e-01 9.2573e-02 4.6956e-02 2.0923e-02 1.4571e-02 1.0545e-01 +6.3200e-01 7.3864e+06 5.5315e+02 2.0822e+03 1.3299e-07 2.8420e-01 7.1580e-01 3.9210e+03 1.7553e+03 4.8891e+02 7.2633e+01 6.9923e-05 1.6991e-05 3.5270e-03 7.1752e-04 1.6376e-01 5.2225e-02 5.2391e-02 3.5246e-02 2.0679e-02 1.9065e-02 6.5239e-01 9.7211e-03 3.3007e-03 5.8358e-01 1.2282e-01 9.2579e-02 4.6964e-02 2.0929e-02 1.4578e-02 1.0553e-01 +6.3400e-01 7.3468e+06 5.5315e+02 2.0712e+03 1.3396e-07 2.8356e-01 7.1644e-01 3.9173e+03 1.7456e+03 4.8935e+02 7.2256e+01 7.0028e-05 1.6973e-05 3.5089e-03 7.1296e-04 1.6282e-01 5.1981e-02 5.2186e-02 3.5135e-02 2.0630e-02 1.9035e-02 6.5399e-01 9.7201e-03 3.2999e-03 5.8347e-01 1.2281e-01 9.2584e-02 4.6972e-02 2.0935e-02 1.4584e-02 1.0562e-01 +6.3600e-01 7.3072e+06 5.5315e+02 2.0602e+03 1.3494e-07 2.8291e-01 7.1709e-01 3.9136e+03 1.7359e+03 4.8980e+02 7.1879e+01 7.0133e-05 1.6956e-05 3.4909e-03 7.0841e-04 1.6188e-01 5.1736e-02 5.1981e-02 3.5024e-02 2.0581e-02 1.9004e-02 6.5560e-01 9.7191e-03 3.2991e-03 5.8337e-01 1.2281e-01 9.2589e-02 4.6981e-02 2.0942e-02 1.4590e-02 1.0571e-01 +6.3800e-01 7.2676e+06 5.5315e+02 2.0492e+03 1.3593e-07 2.8225e-01 7.1775e-01 3.9099e+03 1.7262e+03 4.9024e+02 7.1504e+01 7.0238e-05 1.6938e-05 3.4728e-03 7.0387e-04 1.6094e-01 5.1490e-02 5.1774e-02 3.4912e-02 2.0531e-02 1.8973e-02 6.5720e-01 9.7181e-03 3.2983e-03 5.8326e-01 1.2280e-01 9.2593e-02 4.6989e-02 2.0948e-02 1.4597e-02 1.0580e-01 +6.4000e-01 7.2280e+06 5.5315e+02 2.0381e+03 1.3694e-07 2.8158e-01 7.1842e-01 3.9062e+03 1.7164e+03 4.9069e+02 7.1128e+01 7.0343e-05 1.6921e-05 3.4546e-03 6.9934e-04 1.6000e-01 5.1244e-02 5.1567e-02 3.4799e-02 2.0480e-02 1.8942e-02 6.5881e-01 9.7170e-03 3.2975e-03 5.8315e-01 1.2279e-01 9.2598e-02 4.6997e-02 2.0954e-02 1.4603e-02 1.0590e-01 +6.4200e-01 7.1884e+06 5.5315e+02 2.0271e+03 1.3797e-07 2.8089e-01 7.1911e-01 3.9025e+03 1.7067e+03 4.9113e+02 7.0754e+01 7.0447e-05 1.6904e-05 3.4365e-03 6.9481e-04 1.5907e-01 5.0998e-02 5.1359e-02 3.4685e-02 2.0430e-02 1.8910e-02 6.6042e-01 9.7158e-03 3.2966e-03 5.8303e-01 1.2278e-01 9.2602e-02 4.7004e-02 2.0961e-02 1.4610e-02 1.0600e-01 +6.4400e-01 7.1488e+06 5.5315e+02 2.0160e+03 1.3900e-07 2.8019e-01 7.1981e-01 3.8987e+03 1.6970e+03 4.9157e+02 7.0380e+01 7.0552e-05 1.6887e-05 3.4183e-03 6.9029e-04 1.5813e-01 5.0751e-02 5.1150e-02 3.4571e-02 2.0378e-02 1.8877e-02 6.6204e-01 9.7147e-03 3.2957e-03 5.8292e-01 1.2278e-01 9.2606e-02 4.7012e-02 2.0967e-02 1.4616e-02 1.0610e-01 +6.4600e-01 7.1092e+06 5.5315e+02 2.0049e+03 1.4005e-07 2.7948e-01 7.2052e-01 3.8950e+03 1.6873e+03 4.9202e+02 7.0007e+01 7.0657e-05 1.6870e-05 3.4002e-03 6.8577e-04 1.5719e-01 5.0503e-02 5.0940e-02 3.4456e-02 2.0326e-02 1.8844e-02 6.6365e-01 9.7135e-03 3.2948e-03 5.8280e-01 1.2277e-01 9.2609e-02 4.7020e-02 2.0973e-02 1.4623e-02 1.0620e-01 +6.4800e-01 7.0696e+06 5.5315e+02 1.9938e+03 1.4112e-07 2.7876e-01 7.2124e-01 3.8913e+03 1.6776e+03 4.9246e+02 6.9635e+01 7.0762e-05 1.6852e-05 3.3820e-03 6.8127e-04 1.5626e-01 5.0255e-02 5.0729e-02 3.4340e-02 2.0274e-02 1.8811e-02 6.6527e-01 9.7122e-03 3.2939e-03 5.8268e-01 1.2276e-01 9.2612e-02 4.7027e-02 2.0979e-02 1.4630e-02 1.0631e-01 +6.5000e-01 7.0300e+06 5.5315e+02 1.9826e+03 1.4219e-07 2.7803e-01 7.2197e-01 3.8876e+03 1.6679e+03 4.9290e+02 6.9263e+01 7.0867e-05 1.6835e-05 3.3637e-03 6.7677e-04 1.5532e-01 5.0007e-02 5.0517e-02 3.4224e-02 2.0221e-02 1.8777e-02 6.6689e-01 9.7109e-03 3.2930e-03 5.8255e-01 1.2275e-01 9.2615e-02 4.7035e-02 2.0986e-02 1.4636e-02 1.0642e-01 +6.5200e-01 6.9904e+06 5.5315e+02 1.9714e+03 1.4329e-07 2.7728e-01 7.2272e-01 3.8839e+03 1.6582e+03 4.9334e+02 6.8892e+01 7.0972e-05 1.6818e-05 3.3455e-03 6.7227e-04 1.5438e-01 4.9758e-02 5.0305e-02 3.4107e-02 2.0168e-02 1.8742e-02 6.6852e-01 9.7096e-03 3.2921e-03 5.8243e-01 1.2274e-01 9.2618e-02 4.7042e-02 2.0992e-02 1.4643e-02 1.0654e-01 +6.5400e-01 6.9508e+06 5.5315e+02 1.9602e+03 1.4440e-07 2.7652e-01 7.2348e-01 3.8802e+03 1.6485e+03 4.9378e+02 6.8522e+01 7.1077e-05 1.6801e-05 3.3273e-03 6.6779e-04 1.5345e-01 4.9509e-02 5.0092e-02 3.3989e-02 2.0114e-02 1.8707e-02 6.7015e-01 9.7082e-03 3.2912e-03 5.8230e-01 1.2273e-01 9.2620e-02 4.7050e-02 2.0998e-02 1.4650e-02 1.0666e-01 +6.5600e-01 6.9112e+06 5.5315e+02 1.9490e+03 1.4552e-07 2.7575e-01 7.2425e-01 3.8765e+03 1.6388e+03 4.9422e+02 6.8152e+01 7.1181e-05 1.6784e-05 3.3090e-03 6.6331e-04 1.5251e-01 4.9259e-02 4.9878e-02 3.3870e-02 2.0059e-02 1.8672e-02 6.7178e-01 9.7068e-03 3.2902e-03 5.8216e-01 1.2271e-01 9.2622e-02 4.7057e-02 2.1004e-02 1.4656e-02 1.0678e-01 +6.5800e-01 6.8716e+06 5.5315e+02 1.9378e+03 1.4666e-07 2.7496e-01 7.2504e-01 3.8727e+03 1.6291e+03 4.9466e+02 6.7783e+01 7.1286e-05 1.6767e-05 3.2907e-03 6.5883e-04 1.5158e-01 4.9008e-02 4.9663e-02 3.3750e-02 2.0005e-02 1.8636e-02 6.7341e-01 9.7053e-03 3.2892e-03 5.8203e-01 1.2270e-01 9.2624e-02 4.7064e-02 2.1011e-02 1.4663e-02 1.0691e-01 +6.6000e-01 6.8320e+06 5.5315e+02 1.9265e+03 1.4781e-07 2.7416e-01 7.2584e-01 3.8690e+03 1.6194e+03 4.9510e+02 6.7415e+01 7.1391e-05 1.6750e-05 3.2724e-03 6.5437e-04 1.5064e-01 4.8757e-02 4.9447e-02 3.3630e-02 1.9949e-02 1.8599e-02 6.7505e-01 9.7038e-03 3.2882e-03 5.8189e-01 1.2269e-01 9.2625e-02 4.7071e-02 2.1017e-02 1.4670e-02 1.0704e-01 +6.6200e-01 6.7924e+06 5.5315e+02 1.9152e+03 1.4898e-07 2.7335e-01 7.2665e-01 3.8653e+03 1.6097e+03 4.9554e+02 6.7047e+01 7.1496e-05 1.6734e-05 3.2541e-03 6.4991e-04 1.4971e-01 4.8506e-02 4.9230e-02 3.3509e-02 1.9893e-02 1.8562e-02 6.7669e-01 9.7023e-03 3.2872e-03 5.8175e-01 1.2268e-01 9.2626e-02 4.7078e-02 2.1023e-02 1.4677e-02 1.0718e-01 +6.6400e-01 6.7528e+06 5.5315e+02 1.9039e+03 1.5017e-07 2.7253e-01 7.2747e-01 3.8616e+03 1.6000e+03 4.9598e+02 6.6680e+01 7.1601e-05 1.6717e-05 3.2357e-03 6.4546e-04 1.4877e-01 4.8254e-02 4.9013e-02 3.3387e-02 1.9837e-02 1.8524e-02 6.7833e-01 9.7007e-03 3.2862e-03 5.8161e-01 1.2266e-01 9.2627e-02 4.7084e-02 2.1029e-02 1.4684e-02 1.0731e-01 +6.6600e-01 6.7132e+06 5.5315e+02 1.8926e+03 1.5138e-07 2.7169e-01 7.2831e-01 3.8579e+03 1.5904e+03 4.9642e+02 6.6313e+01 7.1706e-05 1.6700e-05 3.2173e-03 6.4101e-04 1.4784e-01 4.8001e-02 4.8794e-02 3.3265e-02 1.9780e-02 1.8486e-02 6.7998e-01 9.6990e-03 3.2852e-03 5.8146e-01 1.2265e-01 9.2627e-02 4.7091e-02 2.1035e-02 1.4691e-02 1.0746e-01 +6.6800e-01 6.6736e+06 5.5315e+02 1.8812e+03 1.5260e-07 2.7083e-01 7.2917e-01 3.8542e+03 1.5807e+03 4.9685e+02 6.5947e+01 7.1811e-05 1.6683e-05 3.1990e-03 6.3657e-04 1.4691e-01 4.7748e-02 4.8575e-02 3.3141e-02 1.9722e-02 1.8447e-02 6.8163e-01 9.6973e-03 3.2841e-03 5.8132e-01 1.2264e-01 9.2627e-02 4.7098e-02 2.1042e-02 1.4698e-02 1.0760e-01 +6.7000e-01 6.6340e+06 5.5315e+02 1.8698e+03 1.5384e-07 2.6996e-01 7.3004e-01 3.8505e+03 1.5710e+03 4.9729e+02 6.5582e+01 7.1916e-05 1.6666e-05 3.1806e-03 6.3214e-04 1.4597e-01 4.7495e-02 4.8355e-02 3.3017e-02 1.9664e-02 1.8408e-02 6.8328e-01 9.6956e-03 3.2830e-03 5.8116e-01 1.2262e-01 9.2627e-02 4.7104e-02 2.1048e-02 1.4705e-02 1.0775e-01 +6.7200e-01 6.5944e+06 5.5315e+02 1.8584e+03 1.5510e-07 2.6908e-01 7.3092e-01 3.8467e+03 1.5613e+03 4.9772e+02 6.5218e+01 7.2020e-05 1.6650e-05 3.1621e-03 6.2771e-04 1.4504e-01 4.7241e-02 4.8134e-02 3.2892e-02 1.9605e-02 1.8368e-02 6.8493e-01 9.6938e-03 3.2819e-03 5.8101e-01 1.2261e-01 9.2626e-02 4.7110e-02 2.1054e-02 1.4712e-02 1.0791e-01 +6.7400e-01 6.5548e+06 5.5315e+02 1.8470e+03 1.5637e-07 2.6818e-01 7.3182e-01 3.8430e+03 1.5517e+03 4.9816e+02 6.4854e+01 7.2125e-05 1.6633e-05 3.1437e-03 6.2329e-04 1.4411e-01 4.6986e-02 4.7912e-02 3.2766e-02 1.9546e-02 1.8328e-02 6.8659e-01 9.6920e-03 3.2808e-03 5.8085e-01 1.2259e-01 9.2625e-02 4.7116e-02 2.1060e-02 1.4719e-02 1.0807e-01 +6.7600e-01 6.5152e+06 5.5315e+02 1.8356e+03 1.5767e-07 2.6727e-01 7.3273e-01 3.8393e+03 1.5420e+03 4.9860e+02 6.4491e+01 7.2230e-05 1.6616e-05 3.1252e-03 6.1888e-04 1.4317e-01 4.6731e-02 4.7689e-02 3.2640e-02 1.9486e-02 1.8287e-02 6.8825e-01 9.6901e-03 3.2797e-03 5.8069e-01 1.2257e-01 9.2623e-02 4.7122e-02 2.1066e-02 1.4726e-02 1.0823e-01 +6.7800e-01 6.4756e+06 5.5315e+02 1.8241e+03 1.5898e-07 2.6634e-01 7.3366e-01 3.8356e+03 1.5324e+03 4.9903e+02 6.4128e+01 7.2335e-05 1.6600e-05 3.1068e-03 6.1447e-04 1.4224e-01 4.6476e-02 4.7465e-02 3.2513e-02 1.9426e-02 1.8246e-02 6.8991e-01 9.6882e-03 3.2786e-03 5.8053e-01 1.2255e-01 9.2622e-02 4.7128e-02 2.1072e-02 1.4733e-02 1.0840e-01 +6.8000e-01 6.4360e+06 5.5315e+02 1.8126e+03 1.6031e-07 2.6540e-01 7.3460e-01 3.8319e+03 1.5227e+03 4.9946e+02 6.3766e+01 7.2440e-05 1.6583e-05 3.0883e-03 6.1007e-04 1.4131e-01 4.6220e-02 4.7241e-02 3.2385e-02 1.9365e-02 1.8204e-02 6.9158e-01 9.6862e-03 3.2774e-03 5.8036e-01 1.2254e-01 9.2619e-02 4.7134e-02 2.1078e-02 1.4740e-02 1.0857e-01 +6.8200e-01 6.3964e+06 5.5315e+02 1.8011e+03 1.6166e-07 2.6444e-01 7.3556e-01 3.8282e+03 1.5130e+03 4.9990e+02 6.3404e+01 7.2545e-05 1.6567e-05 3.0697e-03 6.0568e-04 1.4038e-01 4.5963e-02 4.7016e-02 3.2256e-02 1.9304e-02 1.8161e-02 6.9325e-01 9.6841e-03 3.2762e-03 5.8019e-01 1.2252e-01 9.2617e-02 4.7139e-02 2.1084e-02 1.4747e-02 1.0874e-01 +6.8400e-01 6.3568e+06 5.5315e+02 1.7895e+03 1.6304e-07 2.6346e-01 7.3654e-01 3.8244e+03 1.5034e+03 5.0033e+02 6.3044e+01 7.2650e-05 1.6550e-05 3.0512e-03 6.0129e-04 1.3944e-01 4.5706e-02 4.6789e-02 3.2126e-02 1.9242e-02 1.8118e-02 6.9492e-01 9.6821e-03 3.2750e-03 5.8002e-01 1.2250e-01 9.2614e-02 4.7145e-02 2.1090e-02 1.4754e-02 1.0892e-01 +6.8600e-01 6.3172e+06 5.5315e+02 1.7780e+03 1.6443e-07 2.6247e-01 7.3753e-01 3.8207e+03 1.4938e+03 5.0076e+02 6.2683e+01 7.2754e-05 1.6534e-05 3.0327e-03 5.9691e-04 1.3851e-01 4.5448e-02 4.6562e-02 3.1995e-02 1.9179e-02 1.8074e-02 6.9660e-01 9.6799e-03 3.2738e-03 5.7984e-01 1.2248e-01 9.2610e-02 4.7150e-02 2.1096e-02 1.4761e-02 1.0911e-01 +6.8800e-01 6.2776e+06 5.5315e+02 1.7664e+03 1.6584e-07 2.6146e-01 7.3854e-01 3.8170e+03 1.4841e+03 5.0120e+02 6.2324e+01 7.2859e-05 1.6517e-05 3.0141e-03 5.9253e-04 1.3758e-01 4.5190e-02 4.6334e-02 3.1864e-02 1.9116e-02 1.8030e-02 6.9828e-01 9.6777e-03 3.2726e-03 5.7966e-01 1.2246e-01 9.2606e-02 4.7155e-02 2.1102e-02 1.4768e-02 1.0930e-01 +6.9000e-01 6.2380e+06 5.5315e+02 1.7548e+03 1.6728e-07 2.6043e-01 7.3957e-01 3.8133e+03 1.4745e+03 5.0163e+02 6.1965e+01 7.2964e-05 1.6501e-05 2.9955e-03 5.8817e-04 1.3665e-01 4.4932e-02 4.6105e-02 3.1732e-02 1.9052e-02 1.7985e-02 6.9996e-01 9.6755e-03 3.2713e-03 5.7948e-01 1.2244e-01 9.2602e-02 4.7160e-02 2.1108e-02 1.4775e-02 1.0949e-01 +6.9200e-01 6.1984e+06 5.5315e+02 1.7431e+03 1.6874e-07 2.5939e-01 7.4061e-01 3.8096e+03 1.4648e+03 5.0206e+02 6.1606e+01 7.3069e-05 1.6484e-05 2.9769e-03 5.8380e-04 1.3572e-01 4.4673e-02 4.5875e-02 3.1599e-02 1.8988e-02 1.7939e-02 7.0164e-01 9.6732e-03 3.2700e-03 5.7929e-01 1.2242e-01 9.2597e-02 4.7165e-02 2.1114e-02 1.4783e-02 1.0969e-01 +6.9400e-01 6.1588e+06 5.5315e+02 1.7315e+03 1.7022e-07 2.5832e-01 7.4168e-01 3.8058e+03 1.4552e+03 5.0249e+02 6.1248e+01 7.3174e-05 1.6468e-05 2.9582e-03 5.7945e-04 1.3479e-01 4.4413e-02 4.5644e-02 3.1465e-02 1.8923e-02 1.7893e-02 7.0333e-01 9.6708e-03 3.2688e-03 5.7910e-01 1.2239e-01 9.2592e-02 4.7169e-02 2.1120e-02 1.4790e-02 1.0989e-01 +6.9600e-01 6.1192e+06 5.5315e+02 1.7198e+03 1.7172e-07 2.5725e-01 7.4275e-01 3.8021e+03 1.4456e+03 5.0292e+02 6.0891e+01 7.3279e-05 1.6451e-05 2.9396e-03 5.7510e-04 1.3386e-01 4.4153e-02 4.5413e-02 3.1330e-02 1.8857e-02 1.7847e-02 7.0503e-01 9.6684e-03 3.2674e-03 5.7891e-01 1.2237e-01 9.2586e-02 4.7174e-02 2.1125e-02 1.4797e-02 1.1010e-01 +6.9800e-01 6.0796e+06 5.5315e+02 1.7081e+03 1.7325e-07 2.5615e-01 7.4385e-01 3.7984e+03 1.4360e+03 5.0335e+02 6.0535e+01 7.3384e-05 1.6435e-05 2.9209e-03 5.7076e-04 1.3293e-01 4.3892e-02 4.5180e-02 3.1195e-02 1.8791e-02 1.7799e-02 7.0672e-01 9.6659e-03 3.2661e-03 5.7871e-01 1.2235e-01 9.2580e-02 4.7178e-02 2.1131e-02 1.4804e-02 1.1032e-01 +7.0000e-01 6.0400e+06 5.5315e+02 1.6964e+03 1.7480e-07 2.5503e-01 7.4497e-01 3.7947e+03 1.4263e+03 5.0378e+02 6.0179e+01 7.3489e-05 1.6418e-05 2.9022e-03 5.6642e-04 1.3200e-01 4.3631e-02 4.4946e-02 3.1059e-02 1.8725e-02 1.7751e-02 7.0842e-01 9.6634e-03 3.2648e-03 5.7851e-01 1.2232e-01 9.2573e-02 4.7182e-02 2.1137e-02 1.4812e-02 1.1054e-01 +7.0200e-01 6.0004e+06 5.5315e+02 1.6846e+03 1.7637e-07 2.5390e-01 7.4610e-01 3.7910e+03 1.4167e+03 5.0421e+02 5.9823e+01 7.3593e-05 1.6402e-05 2.8835e-03 5.6209e-04 1.3107e-01 4.3369e-02 4.4712e-02 3.0921e-02 1.8657e-02 1.7703e-02 7.1012e-01 9.6608e-03 3.2634e-03 5.7831e-01 1.2230e-01 9.2566e-02 4.7186e-02 2.1142e-02 1.4819e-02 1.1076e-01 +7.0400e-01 5.9608e+06 5.5315e+02 1.6728e+03 1.7797e-07 2.5274e-01 7.4726e-01 3.7873e+03 1.4071e+03 5.0464e+02 5.9468e+01 7.3698e-05 1.6385e-05 2.8648e-03 5.5777e-04 1.3014e-01 4.3107e-02 4.4477e-02 3.0783e-02 1.8589e-02 1.7654e-02 7.1183e-01 9.6582e-03 3.2620e-03 5.7810e-01 1.2227e-01 9.2558e-02 4.7189e-02 2.1148e-02 1.4826e-02 1.1099e-01 +7.0600e-01 5.9212e+06 5.5315e+02 1.6610e+03 1.7960e-07 2.5157e-01 7.4843e-01 3.7835e+03 1.3975e+03 5.0506e+02 5.9114e+01 7.3803e-05 1.6369e-05 2.8461e-03 5.5345e-04 1.2921e-01 4.2844e-02 4.4240e-02 3.0645e-02 1.8521e-02 1.7604e-02 7.1353e-01 9.6554e-03 3.2606e-03 5.7789e-01 1.2224e-01 9.2550e-02 4.7193e-02 2.1153e-02 1.4833e-02 1.1122e-01 +7.0800e-01 5.8816e+06 5.5315e+02 1.6492e+03 1.8125e-07 2.5037e-01 7.4963e-01 3.7798e+03 1.3879e+03 5.0549e+02 5.8760e+01 7.3908e-05 1.6353e-05 2.8273e-03 5.4914e-04 1.2828e-01 4.2581e-02 4.4003e-02 3.0505e-02 1.8452e-02 1.7553e-02 7.1525e-01 9.6527e-03 3.2591e-03 5.7767e-01 1.2221e-01 9.2541e-02 4.7196e-02 2.1159e-02 1.4841e-02 1.1146e-01 +7.1000e-01 5.8420e+06 5.5315e+02 1.6373e+03 1.8293e-07 2.4916e-01 7.5084e-01 3.7761e+03 1.3783e+03 5.0592e+02 5.8407e+01 7.4013e-05 1.6336e-05 2.8085e-03 5.4484e-04 1.2736e-01 4.2317e-02 4.3765e-02 3.0364e-02 1.8382e-02 1.7502e-02 7.1696e-01 9.6498e-03 3.2577e-03 5.7745e-01 1.2219e-01 9.2532e-02 4.7199e-02 2.1164e-02 1.4848e-02 1.1171e-01 +7.1200e-01 5.8024e+06 5.5315e+02 1.6255e+03 1.8463e-07 2.4792e-01 7.5208e-01 3.7724e+03 1.3687e+03 5.0635e+02 5.8055e+01 7.4118e-05 1.6320e-05 2.7897e-03 5.4054e-04 1.2643e-01 4.2052e-02 4.3526e-02 3.0223e-02 1.8312e-02 1.7450e-02 7.1868e-01 9.6469e-03 3.2562e-03 5.7723e-01 1.2216e-01 9.2522e-02 4.7202e-02 2.1170e-02 1.4855e-02 1.1196e-01 +7.1400e-01 5.7628e+06 5.5315e+02 1.6136e+03 1.8637e-07 2.4666e-01 7.5334e-01 3.7686e+03 1.3591e+03 5.0677e+02 5.7703e+01 7.4222e-05 1.6304e-05 2.7709e-03 5.3624e-04 1.2550e-01 4.1788e-02 4.3286e-02 3.0080e-02 1.8241e-02 1.7398e-02 7.2040e-01 9.6440e-03 3.2547e-03 5.7700e-01 1.2213e-01 9.2512e-02 4.7204e-02 2.1175e-02 1.4862e-02 1.1222e-01 +7.1600e-01 5.7232e+06 5.5315e+02 1.6017e+03 1.8813e-07 2.4538e-01 7.5462e-01 3.7649e+03 1.3495e+03 5.0720e+02 5.7351e+01 7.4327e-05 1.6287e-05 2.7520e-03 5.3196e-04 1.2457e-01 4.1522e-02 4.3045e-02 2.9937e-02 1.8169e-02 1.7345e-02 7.2213e-01 9.6409e-03 3.2532e-03 5.7677e-01 1.2210e-01 9.2501e-02 4.7207e-02 2.1180e-02 1.4870e-02 1.1248e-01 +7.1800e-01 5.6836e+06 5.5315e+02 1.5897e+03 1.8992e-07 2.4408e-01 7.5592e-01 3.7612e+03 1.3399e+03 5.0762e+02 5.7000e+01 7.4432e-05 1.6271e-05 2.7332e-03 5.2768e-04 1.2364e-01 4.1256e-02 4.2803e-02 2.9793e-02 1.8097e-02 1.7291e-02 7.2386e-01 9.6378e-03 3.2516e-03 5.7654e-01 1.2206e-01 9.2490e-02 4.7209e-02 2.1185e-02 1.4877e-02 1.1275e-01 +7.2000e-01 5.6440e+06 5.5315e+02 1.5777e+03 1.9174e-07 2.4276e-01 7.5724e-01 3.7575e+03 1.3303e+03 5.0805e+02 5.6650e+01 7.4537e-05 1.6254e-05 2.7143e-03 5.2340e-04 1.2272e-01 4.0990e-02 4.2560e-02 2.9648e-02 1.8024e-02 1.7237e-02 7.2559e-01 9.6346e-03 3.2500e-03 5.7630e-01 1.2203e-01 9.2478e-02 4.7211e-02 2.1190e-02 1.4884e-02 1.1303e-01 +7.2200e-01 5.6044e+06 5.5315e+02 1.5658e+03 1.9359e-07 2.4141e-01 7.5859e-01 3.7538e+03 1.3208e+03 5.0847e+02 5.6300e+01 7.4642e-05 1.6238e-05 2.6954e-03 5.1914e-04 1.2179e-01 4.0723e-02 4.2317e-02 2.9502e-02 1.7950e-02 1.7181e-02 7.2732e-01 9.6314e-03 3.2484e-03 5.7605e-01 1.2200e-01 9.2465e-02 4.7212e-02 2.1195e-02 1.4892e-02 1.1331e-01 +7.2400e-01 5.5648e+06 5.5315e+02 1.5537e+03 1.9548e-07 2.4004e-01 7.5996e-01 3.7500e+03 1.3112e+03 5.0890e+02 5.5951e+01 7.4746e-05 1.6221e-05 2.6765e-03 5.1488e-04 1.2086e-01 4.0455e-02 4.2072e-02 2.9356e-02 1.7876e-02 1.7126e-02 7.2906e-01 9.6281e-03 3.2468e-03 5.7580e-01 1.2196e-01 9.2452e-02 4.7213e-02 2.1200e-02 1.4899e-02 1.1359e-01 +7.2600e-01 5.5252e+06 5.5315e+02 1.5417e+03 1.9739e-07 2.3864e-01 7.6136e-01 3.7463e+03 1.3016e+03 5.0932e+02 5.5602e+01 7.4851e-05 1.6205e-05 2.6575e-03 5.1062e-04 1.1994e-01 4.0187e-02 4.1826e-02 2.9208e-02 1.7801e-02 1.7069e-02 7.3080e-01 9.6247e-03 3.2452e-03 5.7555e-01 1.2193e-01 9.2438e-02 4.7214e-02 2.1205e-02 1.4906e-02 1.1389e-01 +7.2800e-01 5.4856e+06 5.5315e+02 1.5296e+03 1.9934e-07 2.3722e-01 7.6278e-01 3.7426e+03 1.2920e+03 5.0975e+02 5.5254e+01 7.4956e-05 1.6189e-05 2.6386e-03 5.0637e-04 1.1901e-01 3.9918e-02 4.1580e-02 2.9060e-02 1.7726e-02 1.7012e-02 7.3255e-01 9.6212e-03 3.2435e-03 5.7529e-01 1.2189e-01 9.2423e-02 4.7215e-02 2.1210e-02 1.4913e-02 1.1419e-01 +7.3000e-01 5.4460e+06 5.5315e+02 1.5175e+03 2.0132e-07 2.3578e-01 7.6422e-01 3.7389e+03 1.2825e+03 5.1017e+02 5.4906e+01 7.5061e-05 1.6172e-05 2.6196e-03 5.0213e-04 1.1808e-01 3.9649e-02 4.1332e-02 2.8910e-02 1.7650e-02 1.6954e-02 7.3430e-01 9.6176e-03 3.2418e-03 5.7503e-01 1.2186e-01 9.2408e-02 4.7216e-02 2.1215e-02 1.4921e-02 1.1450e-01 +7.3200e-01 5.4064e+06 5.5315e+02 1.5054e+03 2.0334e-07 2.3431e-01 7.6569e-01 3.7352e+03 1.2729e+03 5.1059e+02 5.4559e+01 7.5166e-05 1.6156e-05 2.6006e-03 4.9789e-04 1.1716e-01 3.9379e-02 4.1084e-02 2.8760e-02 1.7573e-02 1.6895e-02 7.3605e-01 9.6140e-03 3.2401e-03 5.7476e-01 1.2182e-01 9.2392e-02 4.7216e-02 2.1219e-02 1.4928e-02 1.1481e-01 +7.3400e-01 5.3668e+06 5.5315e+02 1.4933e+03 2.0539e-07 2.3281e-01 7.6719e-01 3.7314e+03 1.2634e+03 5.1102e+02 5.4213e+01 7.5270e-05 1.6139e-05 2.5816e-03 4.9366e-04 1.1623e-01 3.9109e-02 4.0834e-02 2.8609e-02 1.7495e-02 1.6836e-02 7.3781e-01 9.6103e-03 3.2383e-03 5.7449e-01 1.2178e-01 9.2375e-02 4.7216e-02 2.1224e-02 1.4935e-02 1.1513e-01 +7.3600e-01 5.3272e+06 5.5315e+02 1.4811e+03 2.0748e-07 2.3129e-01 7.6871e-01 3.7277e+03 1.2538e+03 5.1144e+02 5.3867e+01 7.5375e-05 1.6123e-05 2.5625e-03 4.8943e-04 1.1531e-01 3.8838e-02 4.0584e-02 2.8456e-02 1.7417e-02 1.6776e-02 7.3957e-01 9.6065e-03 3.2365e-03 5.7421e-01 1.2174e-01 9.2358e-02 4.7215e-02 2.1228e-02 1.4942e-02 1.1546e-01 +7.3800e-01 5.2876e+06 5.5315e+02 1.4690e+03 2.0961e-07 2.2974e-01 7.7026e-01 3.7240e+03 1.2442e+03 5.1186e+02 5.3522e+01 7.5480e-05 1.6106e-05 2.5435e-03 4.8522e-04 1.1438e-01 3.8567e-02 4.0332e-02 2.8303e-02 1.7338e-02 1.6715e-02 7.4133e-01 9.6027e-03 3.2347e-03 5.7393e-01 1.2170e-01 9.2340e-02 4.7214e-02 2.1232e-02 1.4949e-02 1.1580e-01 +7.4000e-01 5.2480e+06 5.5315e+02 1.4568e+03 2.1177e-07 2.2816e-01 7.7184e-01 3.7203e+03 1.2347e+03 5.1228e+02 5.3177e+01 7.5584e-05 1.6090e-05 2.5244e-03 4.8100e-04 1.1346e-01 3.8295e-02 4.0080e-02 2.8149e-02 1.7259e-02 1.6654e-02 7.4310e-01 9.5987e-03 3.2329e-03 5.7365e-01 1.2165e-01 9.2321e-02 4.7213e-02 2.1237e-02 1.4956e-02 1.1614e-01 +7.4200e-01 5.2084e+06 5.5315e+02 1.4445e+03 2.1397e-07 2.2655e-01 7.7345e-01 3.7165e+03 1.2252e+03 5.1270e+02 5.2832e+01 7.5689e-05 1.6073e-05 2.5053e-03 4.7679e-04 1.1253e-01 3.8023e-02 3.9826e-02 2.7994e-02 1.7179e-02 1.6592e-02 7.4487e-01 9.5947e-03 3.2310e-03 5.7335e-01 1.2161e-01 9.2302e-02 4.7212e-02 2.1241e-02 1.4963e-02 1.1649e-01 +7.4400e-01 5.1688e+06 5.5315e+02 1.4323e+03 2.1622e-07 2.2491e-01 7.7509e-01 3.7128e+03 1.2156e+03 5.1312e+02 5.2488e+01 7.5794e-05 1.6056e-05 2.4862e-03 4.7259e-04 1.1161e-01 3.7750e-02 3.9572e-02 2.7838e-02 1.7098e-02 1.6529e-02 7.4665e-01 9.5905e-03 3.2291e-03 5.7306e-01 1.2157e-01 9.2281e-02 4.7210e-02 2.1245e-02 1.4970e-02 1.1685e-01 +7.4600e-01 5.1292e+06 5.5315e+02 1.4200e+03 2.1850e-07 2.2325e-01 7.7675e-01 3.7091e+03 1.2061e+03 5.1354e+02 5.2145e+01 7.5899e-05 1.6040e-05 2.4671e-03 4.6840e-04 1.1068e-01 3.7476e-02 3.9317e-02 2.7682e-02 1.7016e-02 1.6465e-02 7.4843e-01 9.5863e-03 3.2272e-03 5.7275e-01 1.2152e-01 9.2260e-02 4.7208e-02 2.1249e-02 1.4978e-02 1.1722e-01 +7.4800e-01 5.0896e+06 5.5315e+02 1.4077e+03 2.2083e-07 2.2155e-01 7.7845e-01 3.7054e+03 1.1965e+03 5.1396e+02 5.1802e+01 7.6003e-05 1.6023e-05 2.4479e-03 4.6421e-04 1.0976e-01 3.7202e-02 3.9060e-02 2.7524e-02 1.6934e-02 1.6400e-02 7.5021e-01 9.5820e-03 3.2253e-03 5.7245e-01 1.2148e-01 9.2238e-02 4.7206e-02 2.1252e-02 1.4985e-02 1.1759e-01 +7.5000e-01 5.0500e+06 5.5315e+02 1.3954e+03 2.2320e-07 2.1982e-01 7.8018e-01 3.7016e+03 1.1870e+03 5.1438e+02 5.1460e+01 7.6108e-05 1.6006e-05 2.4288e-03 4.6003e-04 1.0883e-01 3.6928e-02 3.8803e-02 2.7365e-02 1.6851e-02 1.6335e-02 7.5200e-01 9.5776e-03 3.2233e-03 5.7213e-01 1.2143e-01 9.2216e-02 4.7203e-02 2.1256e-02 1.4991e-02 1.1797e-01 +7.5200e-01 5.0104e+06 5.5315e+02 1.3830e+03 2.2561e-07 2.1805e-01 7.8195e-01 3.6979e+03 1.1775e+03 5.1480e+02 5.1118e+01 7.6212e-05 1.5990e-05 2.4096e-03 4.5585e-04 1.0791e-01 3.6653e-02 3.8545e-02 2.7206e-02 1.6767e-02 1.6269e-02 7.5379e-01 9.5731e-03 3.2212e-03 5.7181e-01 1.2138e-01 9.2192e-02 4.7200e-02 2.1259e-02 1.4998e-02 1.1836e-01 +7.5400e-01 4.9708e+06 5.5315e+02 1.3707e+03 2.2807e-07 2.1626e-01 7.8374e-01 3.6942e+03 1.1680e+03 5.1522e+02 5.0777e+01 7.6317e-05 1.5973e-05 2.3903e-03 4.5168e-04 1.0699e-01 3.6377e-02 3.8285e-02 2.7045e-02 1.6682e-02 1.6202e-02 7.5558e-01 9.5685e-03 3.2192e-03 5.7149e-01 1.2133e-01 9.2167e-02 4.7196e-02 2.1263e-02 1.5005e-02 1.1876e-01 +7.5600e-01 4.9312e+06 5.5315e+02 1.3583e+03 2.3058e-07 2.1443e-01 7.8557e-01 3.6905e+03 1.1585e+03 5.1564e+02 5.0436e+01 7.6422e-05 1.5956e-05 2.3711e-03 4.4751e-04 1.0606e-01 3.6101e-02 3.8025e-02 2.6883e-02 1.6597e-02 1.6134e-02 7.5738e-01 9.5638e-03 3.2171e-03 5.7116e-01 1.2128e-01 9.2142e-02 4.7192e-02 2.1266e-02 1.5012e-02 1.1917e-01 +7.5800e-01 4.8916e+06 5.5315e+02 1.3459e+03 2.3313e-07 2.1257e-01 7.8743e-01 3.6867e+03 1.1489e+03 5.1606e+02 5.0096e+01 7.6526e-05 1.5939e-05 2.3519e-03 4.4335e-04 1.0514e-01 3.5824e-02 3.7764e-02 2.6721e-02 1.6511e-02 1.6066e-02 7.5918e-01 9.5590e-03 3.2150e-03 5.7082e-01 1.2122e-01 9.2116e-02 4.7188e-02 2.1269e-02 1.5019e-02 1.1959e-01 +7.6000e-01 4.8520e+06 5.5315e+02 1.3334e+03 2.3574e-07 2.1067e-01 7.8933e-01 3.6830e+03 1.1394e+03 5.1647e+02 4.9756e+01 7.6631e-05 1.5922e-05 2.3326e-03 4.3920e-04 1.0422e-01 3.5547e-02 3.7502e-02 2.6557e-02 1.6425e-02 1.5997e-02 7.6098e-01 9.5541e-03 3.2128e-03 5.7048e-01 1.2117e-01 9.2089e-02 4.7183e-02 2.1272e-02 1.5025e-02 1.2002e-01 +7.6200e-01 4.8124e+06 5.5315e+02 1.3210e+03 2.3839e-07 2.0873e-01 7.9127e-01 3.6793e+03 1.1299e+03 5.1689e+02 4.9417e+01 7.6735e-05 1.5905e-05 2.3133e-03 4.3505e-04 1.0329e-01 3.5269e-02 3.7238e-02 2.6393e-02 1.6337e-02 1.5926e-02 7.6279e-01 9.5491e-03 3.2106e-03 5.7013e-01 1.2111e-01 9.2060e-02 4.7177e-02 2.1275e-02 1.5032e-02 1.2045e-01 +7.6400e-01 4.7728e+06 5.5315e+02 1.3085e+03 2.4110e-07 2.0676e-01 7.9324e-01 3.6755e+03 1.1204e+03 5.1731e+02 4.9078e+01 7.6840e-05 1.5888e-05 2.2940e-03 4.3091e-04 1.0237e-01 3.4990e-02 3.6974e-02 2.6227e-02 1.6249e-02 1.5855e-02 7.6461e-01 9.5440e-03 3.2084e-03 5.6977e-01 1.2106e-01 9.2031e-02 4.7172e-02 2.1277e-02 1.5039e-02 1.2090e-01 +7.6600e-01 4.7332e+06 5.5315e+02 1.2960e+03 2.4386e-07 2.0475e-01 7.9525e-01 3.6718e+03 1.1109e+03 5.1773e+02 4.8740e+01 7.6944e-05 1.5871e-05 2.2747e-03 4.2677e-04 1.0145e-01 3.4711e-02 3.6709e-02 2.6061e-02 1.6160e-02 1.5784e-02 7.6642e-01 9.5388e-03 3.2061e-03 5.6941e-01 1.2100e-01 9.2001e-02 4.7165e-02 2.1280e-02 1.5045e-02 1.2136e-01 +7.6800e-01 4.6936e+06 5.5315e+02 1.2835e+03 2.4667e-07 2.0269e-01 7.9731e-01 3.6681e+03 1.1014e+03 5.1814e+02 4.8402e+01 7.7049e-05 1.5854e-05 2.2553e-03 4.2264e-04 1.0053e-01 3.4432e-02 3.6442e-02 2.5893e-02 1.6071e-02 1.5711e-02 7.6825e-01 9.5334e-03 3.2038e-03 5.6904e-01 1.2094e-01 9.1970e-02 4.7159e-02 2.1282e-02 1.5052e-02 1.2182e-01 +7.7000e-01 4.6540e+06 5.5315e+02 1.2709e+03 2.4954e-07 2.0060e-01 7.9940e-01 3.6644e+03 1.0919e+03 5.1856e+02 4.8065e+01 7.7153e-05 1.5837e-05 2.2360e-03 4.1852e-04 9.9605e-02 3.4152e-02 3.6175e-02 2.5725e-02 1.5980e-02 1.5638e-02 7.7007e-01 9.5280e-03 3.2015e-03 5.6866e-01 1.2088e-01 9.1937e-02 4.7151e-02 2.1284e-02 1.5058e-02 1.2230e-01 +7.7200e-01 4.6144e+06 5.5315e+02 1.2583e+03 2.5247e-07 1.9847e-01 8.0153e-01 3.6606e+03 1.0824e+03 5.1897e+02 4.7728e+01 7.7258e-05 1.5819e-05 2.2166e-03 4.1440e-04 9.8684e-02 3.3871e-02 3.5907e-02 2.5555e-02 1.5889e-02 1.5563e-02 7.7190e-01 9.5224e-03 3.1991e-03 5.6828e-01 1.2082e-01 9.1904e-02 4.7144e-02 2.1286e-02 1.5064e-02 1.2279e-01 +7.7400e-01 4.5748e+06 5.5315e+02 1.2458e+03 2.5546e-07 1.9629e-01 8.0371e-01 3.6569e+03 1.0730e+03 5.1939e+02 4.7392e+01 7.7362e-05 1.5802e-05 2.1972e-03 4.1028e-04 9.7762e-02 3.3590e-02 3.5637e-02 2.5385e-02 1.5797e-02 1.5488e-02 7.7373e-01 9.5167e-03 3.1967e-03 5.6789e-01 1.2075e-01 9.1870e-02 4.7135e-02 2.1288e-02 1.5071e-02 1.2328e-01 +7.7600e-01 4.5352e+06 5.5315e+02 1.2331e+03 2.5852e-07 1.9407e-01 8.0593e-01 3.6532e+03 1.0635e+03 5.1980e+02 4.7056e+01 7.7466e-05 1.5785e-05 2.1777e-03 4.0618e-04 9.6841e-02 3.3308e-02 3.5367e-02 2.5214e-02 1.5704e-02 1.5412e-02 7.7557e-01 9.5109e-03 3.1942e-03 5.6749e-01 1.2069e-01 9.1834e-02 4.7127e-02 2.1289e-02 1.5077e-02 1.2379e-01 +7.7800e-01 4.4956e+06 5.5315e+02 1.2205e+03 2.6163e-07 1.9181e-01 8.0819e-01 3.6494e+03 1.0540e+03 5.2022e+02 4.6721e+01 7.7571e-05 1.5767e-05 2.1583e-03 4.0208e-04 9.5920e-02 3.3026e-02 3.5095e-02 2.5041e-02 1.5611e-02 1.5335e-02 7.7741e-01 9.5049e-03 3.1917e-03 5.6708e-01 1.2062e-01 9.1797e-02 4.7117e-02 2.1290e-02 1.5083e-02 1.2431e-01 +7.8000e-01 4.4560e+06 5.5315e+02 1.2078e+03 2.6481e-07 1.8950e-01 8.1050e-01 3.6457e+03 1.0445e+03 5.2063e+02 4.6386e+01 7.7675e-05 1.5750e-05 2.1388e-03 3.9798e-04 9.4999e-02 3.2743e-02 3.4823e-02 2.4868e-02 1.5517e-02 1.5258e-02 7.7926e-01 9.4988e-03 3.1892e-03 5.6667e-01 1.2055e-01 9.1759e-02 4.7107e-02 2.1291e-02 1.5089e-02 1.2485e-01 +7.8200e-01 4.4164e+06 5.5315e+02 1.1952e+03 2.6806e-07 1.8714e-01 8.1286e-01 3.6420e+03 1.0351e+03 5.2105e+02 4.6052e+01 7.7779e-05 1.5732e-05 2.1194e-03 3.9389e-04 9.4079e-02 3.2460e-02 3.4549e-02 2.4693e-02 1.5422e-02 1.5179e-02 7.8111e-01 9.4926e-03 3.1866e-03 5.6625e-01 1.2048e-01 9.1720e-02 4.7097e-02 2.1292e-02 1.5094e-02 1.2539e-01 +7.8400e-01 4.3768e+06 5.5315e+02 1.1825e+03 2.7138e-07 1.8473e-01 8.1527e-01 3.6383e+03 1.0256e+03 5.2146e+02 4.5718e+01 7.7884e-05 1.5714e-05 2.0998e-03 3.8981e-04 9.3159e-02 3.2176e-02 3.4275e-02 2.4518e-02 1.5326e-02 1.5099e-02 7.8296e-01 9.4863e-03 3.1839e-03 5.6582e-01 1.2041e-01 9.1679e-02 4.7086e-02 2.1293e-02 1.5100e-02 1.2595e-01 +7.8600e-01 4.3372e+06 5.5315e+02 1.1698e+03 2.7477e-07 1.8227e-01 8.1773e-01 3.6345e+03 1.0162e+03 5.2188e+02 4.5385e+01 7.7988e-05 1.5696e-05 2.0803e-03 3.8573e-04 9.2238e-02 3.1891e-02 3.3999e-02 2.4341e-02 1.5229e-02 1.5019e-02 7.8482e-01 9.4798e-03 3.1813e-03 5.6538e-01 1.2033e-01 9.1637e-02 4.7074e-02 2.1293e-02 1.5106e-02 1.2652e-01 +7.8800e-01 4.2976e+06 5.5315e+02 1.1570e+03 2.7823e-07 1.7976e-01 8.2024e-01 3.6308e+03 1.0067e+03 5.2229e+02 4.5052e+01 7.8092e-05 1.5679e-05 2.0608e-03 3.8165e-04 9.1319e-02 3.1606e-02 3.3722e-02 2.4163e-02 1.5132e-02 1.4937e-02 7.8668e-01 9.4731e-03 3.1785e-03 5.6493e-01 1.2026e-01 9.1594e-02 4.7062e-02 2.1293e-02 1.5111e-02 1.2710e-01 +7.9000e-01 4.2580e+06 5.5315e+02 1.1443e+03 2.8177e-07 1.7720e-01 8.2280e-01 3.6271e+03 9.9724e+02 5.2270e+02 4.4719e+01 7.8196e-05 1.5661e-05 2.0412e-03 3.7759e-04 9.0399e-02 3.1321e-02 3.3445e-02 2.3985e-02 1.5033e-02 1.4855e-02 7.8854e-01 9.4663e-03 3.1757e-03 5.6447e-01 1.2018e-01 9.1549e-02 4.7049e-02 2.1293e-02 1.5116e-02 1.2770e-01 +7.9200e-01 4.2184e+06 5.5315e+02 1.1315e+03 2.8538e-07 1.7458e-01 8.2542e-01 3.6233e+03 9.8780e+02 5.2312e+02 4.4387e+01 7.8300e-05 1.5642e-05 2.0216e-03 3.7353e-04 8.9479e-02 3.1034e-02 3.3166e-02 2.3805e-02 1.4934e-02 1.4772e-02 7.9041e-01 9.4594e-03 3.1729e-03 5.6401e-01 1.2010e-01 9.1503e-02 4.7035e-02 2.1293e-02 1.5122e-02 1.2830e-01 +7.9400e-01 4.1788e+06 5.5315e+02 1.1187e+03 2.8908e-07 1.7191e-01 8.2809e-01 3.6196e+03 9.7835e+02 5.2353e+02 4.4056e+01 7.8404e-05 1.5624e-05 2.0020e-03 3.6947e-04 8.8560e-02 3.0748e-02 3.2886e-02 2.3624e-02 1.4834e-02 1.4688e-02 7.9229e-01 9.4523e-03 3.1700e-03 5.6353e-01 1.2002e-01 9.1456e-02 4.7020e-02 2.1292e-02 1.5127e-02 1.2893e-01 +7.9600e-01 4.1392e+06 5.5315e+02 1.1059e+03 2.9286e-07 1.6918e-01 8.3082e-01 3.6159e+03 9.6892e+02 5.2394e+02 4.3725e+01 7.8508e-05 1.5606e-05 1.9824e-03 3.6542e-04 8.7641e-02 3.0460e-02 3.2605e-02 2.3442e-02 1.4734e-02 1.4602e-02 7.9417e-01 9.4450e-03 3.1671e-03 5.6305e-01 1.1994e-01 9.1407e-02 4.7005e-02 2.1291e-02 1.5132e-02 1.2957e-01 +7.9800e-01 4.0996e+06 5.5315e+02 1.0930e+03 2.9673e-07 1.6638e-01 8.3362e-01 3.6121e+03 9.5948e+02 5.2435e+02 4.3394e+01 7.8612e-05 1.5587e-05 1.9628e-03 3.6138e-04 8.6722e-02 3.0173e-02 3.2323e-02 2.3259e-02 1.4632e-02 1.4516e-02 7.9605e-01 9.4376e-03 3.1641e-03 5.6256e-01 1.1985e-01 9.1356e-02 4.6989e-02 2.1290e-02 1.5136e-02 1.3022e-01 +8.0000e-01 4.0600e+06 5.5315e+02 1.0802e+03 3.0068e-07 1.6353e-01 8.3647e-01 3.6084e+03 9.5005e+02 5.2476e+02 4.3064e+01 7.8716e-05 1.5569e-05 1.9431e-03 3.5734e-04 8.5803e-02 2.9884e-02 3.2040e-02 2.3075e-02 1.4530e-02 1.4429e-02 7.9794e-01 9.4300e-03 3.1610e-03 5.6205e-01 1.1976e-01 9.1304e-02 4.6973e-02 2.1288e-02 1.5141e-02 1.3089e-01 +8.0200e-01 4.0204e+06 5.5315e+02 1.0673e+03 3.0473e-07 1.6061e-01 8.3939e-01 3.6047e+03 9.4062e+02 5.2517e+02 4.2734e+01 7.8820e-05 1.5550e-05 1.9234e-03 3.5330e-04 8.4885e-02 2.9595e-02 3.1756e-02 2.2890e-02 1.4426e-02 1.4341e-02 7.9983e-01 9.4222e-03 3.1579e-03 5.6154e-01 1.1967e-01 9.1250e-02 4.6955e-02 2.1286e-02 1.5145e-02 1.3157e-01 +8.0400e-01 3.9808e+06 5.5315e+02 1.0544e+03 3.0887e-07 1.5763e-01 8.4237e-01 3.6009e+03 9.3120e+02 5.2559e+02 4.2405e+01 7.8924e-05 1.5531e-05 1.9038e-03 3.4928e-04 8.3967e-02 2.9306e-02 3.1471e-02 2.2704e-02 1.4322e-02 1.4252e-02 8.0173e-01 9.4143e-03 3.1548e-03 5.6101e-01 1.1958e-01 9.1194e-02 4.6937e-02 2.1284e-02 1.5150e-02 1.3227e-01 +8.0600e-01 3.9412e+06 5.5315e+02 1.0415e+03 3.1311e-07 1.5457e-01 8.4543e-01 3.5972e+03 9.2178e+02 5.2600e+02 4.2076e+01 7.9028e-05 1.5513e-05 1.8840e-03 3.4525e-04 8.3049e-02 2.9015e-02 3.1185e-02 2.2517e-02 1.4217e-02 1.4162e-02 8.0363e-01 9.4061e-03 3.1515e-03 5.6048e-01 1.1948e-01 9.1137e-02 4.6917e-02 2.1281e-02 1.5154e-02 1.3299e-01 +8.0800e-01 3.9016e+06 5.5315e+02 1.0286e+03 3.1745e-07 1.5145e-01 8.4855e-01 3.5935e+03 9.1237e+02 5.2641e+02 4.1748e+01 7.9132e-05 1.5493e-05 1.8643e-03 3.4124e-04 8.2131e-02 2.8725e-02 3.0898e-02 2.2329e-02 1.4111e-02 1.4071e-02 8.0553e-01 9.3978e-03 3.1482e-03 5.5993e-01 1.1939e-01 9.1078e-02 4.6897e-02 2.1278e-02 1.5157e-02 1.3372e-01 +8.1000e-01 3.8620e+06 5.5315e+02 1.0157e+03 3.2190e-07 1.4826e-01 8.5174e-01 3.5897e+03 9.0296e+02 5.2682e+02 4.1420e+01 7.9236e-05 1.5474e-05 1.8445e-03 3.3723e-04 8.1213e-02 2.8433e-02 3.0609e-02 2.2139e-02 1.4004e-02 1.3979e-02 8.0744e-01 9.3893e-03 3.1449e-03 5.5937e-01 1.1929e-01 9.1017e-02 4.6876e-02 2.1275e-02 1.5161e-02 1.3448e-01 +8.1200e-01 3.8224e+06 5.5315e+02 1.0027e+03 3.2645e-07 1.4499e-01 8.5501e-01 3.5860e+03 8.9355e+02 5.2723e+02 4.1093e+01 7.9339e-05 1.5455e-05 1.8248e-03 3.3322e-04 8.0296e-02 2.8142e-02 3.0320e-02 2.1949e-02 1.3897e-02 1.3885e-02 8.0935e-01 9.3806e-03 3.1414e-03 5.5880e-01 1.1919e-01 9.0954e-02 4.6854e-02 2.1271e-02 1.5164e-02 1.3525e-01 +8.1400e-01 3.7828e+06 5.5315e+02 9.8973e+02 3.3112e-07 1.4164e-01 8.5836e-01 3.5823e+03 8.8415e+02 5.2764e+02 4.0766e+01 7.9443e-05 1.5435e-05 1.8050e-03 3.2922e-04 7.9379e-02 2.7849e-02 3.0029e-02 2.1757e-02 1.3788e-02 1.3791e-02 8.1127e-01 9.3717e-03 3.1380e-03 5.5822e-01 1.1908e-01 9.0889e-02 4.6832e-02 2.1267e-02 1.5168e-02 1.3603e-01 +8.1600e-01 3.7432e+06 5.5315e+02 9.7675e+02 3.3590e-07 1.3821e-01 8.6179e-01 3.5785e+03 8.7475e+02 5.2805e+02 4.0439e+01 7.9547e-05 1.5416e-05 1.7852e-03 3.2523e-04 7.8462e-02 2.7556e-02 2.9737e-02 2.1564e-02 1.3679e-02 1.3696e-02 8.1319e-01 9.3625e-03 3.1344e-03 5.5762e-01 1.1897e-01 9.0822e-02 4.6808e-02 2.1263e-02 1.5171e-02 1.3684e-01 +8.1800e-01 3.7036e+06 5.5315e+02 9.6375e+02 3.4080e-07 1.3470e-01 8.6530e-01 3.5748e+03 8.6536e+02 5.2846e+02 4.0113e+01 7.9650e-05 1.5396e-05 1.7653e-03 3.2124e-04 7.7545e-02 2.7263e-02 2.9445e-02 2.1370e-02 1.3569e-02 1.3600e-02 8.1512e-01 9.3531e-03 3.1308e-03 5.5702e-01 1.1886e-01 9.0753e-02 4.6783e-02 2.1258e-02 1.5173e-02 1.3767e-01 +8.2000e-01 3.6640e+06 5.5315e+02 9.5074e+02 3.4583e-07 1.3110e-01 8.6890e-01 3.5711e+03 8.5597e+02 5.2886e+02 3.9788e+01 7.9754e-05 1.5376e-05 1.7455e-03 3.1726e-04 7.6629e-02 2.6969e-02 2.9151e-02 2.1175e-02 1.3457e-02 1.3502e-02 8.1705e-01 9.3436e-03 3.1270e-03 5.5639e-01 1.1875e-01 9.0682e-02 4.6757e-02 2.1252e-02 1.5176e-02 1.3852e-01 +8.2200e-01 3.6244e+06 5.5315e+02 9.3771e+02 3.5098e-07 1.2742e-01 8.7258e-01 3.5673e+03 8.4658e+02 5.2927e+02 3.9462e+01 7.9857e-05 1.5356e-05 1.7256e-03 3.1328e-04 7.5712e-02 2.6674e-02 2.8856e-02 2.0979e-02 1.3345e-02 1.3404e-02 8.1899e-01 9.3337e-03 3.1233e-03 5.5576e-01 1.1863e-01 9.0609e-02 4.6730e-02 2.1247e-02 1.5178e-02 1.3939e-01 +8.2400e-01 3.5848e+06 5.5315e+02 9.2467e+02 3.5627e-07 1.2364e-01 8.7636e-01 3.5636e+03 8.3720e+02 5.2968e+02 3.9138e+01 7.9961e-05 1.5335e-05 1.7057e-03 3.0931e-04 7.4796e-02 2.6379e-02 2.8560e-02 2.0782e-02 1.3232e-02 1.3304e-02 8.2093e-01 9.3237e-03 3.1194e-03 5.5511e-01 1.1851e-01 9.0533e-02 4.6701e-02 2.1240e-02 1.5180e-02 1.4028e-01 +8.2600e-01 3.5452e+06 5.5315e+02 9.1162e+02 3.6170e-07 1.1977e-01 8.8023e-01 3.5598e+03 8.2782e+02 5.3009e+02 3.8813e+01 8.0064e-05 1.5315e-05 1.6858e-03 3.0534e-04 7.3880e-02 2.6083e-02 2.8263e-02 2.0584e-02 1.3118e-02 1.3204e-02 8.2288e-01 9.3134e-03 3.1154e-03 5.5444e-01 1.1839e-01 9.0455e-02 4.6672e-02 2.1233e-02 1.5181e-02 1.4119e-01 +8.2800e-01 3.5056e+06 5.5315e+02 8.9855e+02 3.6727e-07 1.1580e-01 8.8420e-01 3.5561e+03 8.1845e+02 5.3050e+02 3.8489e+01 8.0167e-05 1.5294e-05 1.6659e-03 3.0138e-04 7.2965e-02 2.5787e-02 2.7964e-02 2.0384e-02 1.3003e-02 1.3102e-02 8.2483e-01 9.3028e-03 3.1114e-03 5.5376e-01 1.1827e-01 9.0374e-02 4.6641e-02 2.1226e-02 1.5182e-02 1.4213e-01 +8.3000e-01 3.4660e+06 5.5315e+02 8.8548e+02 3.7299e-07 1.1172e-01 8.8828e-01 3.5524e+03 8.0908e+02 5.3091e+02 3.8166e+01 8.0271e-05 1.5273e-05 1.6459e-03 2.9742e-04 7.2049e-02 2.5490e-02 2.7665e-02 2.0184e-02 1.2888e-02 1.2999e-02 8.2678e-01 9.2920e-03 3.1073e-03 5.5307e-01 1.1814e-01 9.0291e-02 4.6609e-02 2.1218e-02 1.5183e-02 1.4309e-01 +8.3200e-01 3.4264e+06 5.5315e+02 8.7240e+02 3.7887e-07 1.0754e-01 8.9246e-01 3.5486e+03 7.9972e+02 5.3131e+02 3.7843e+01 8.0374e-05 1.5252e-05 1.6260e-03 2.9347e-04 7.1134e-02 2.5192e-02 2.7365e-02 1.9982e-02 1.2771e-02 1.2895e-02 8.2874e-01 9.2808e-03 3.1031e-03 5.5236e-01 1.1801e-01 9.0206e-02 4.6576e-02 2.1210e-02 1.5184e-02 1.4408e-01 +8.3400e-01 3.3868e+06 5.5315e+02 8.5930e+02 3.8490e-07 1.0325e-01 8.9675e-01 3.5449e+03 7.9036e+02 5.3172e+02 3.7520e+01 8.0477e-05 1.5231e-05 1.6060e-03 2.8953e-04 7.0219e-02 2.4894e-02 2.7063e-02 1.9779e-02 1.2653e-02 1.2790e-02 8.3071e-01 9.2695e-03 3.0988e-03 5.5163e-01 1.1787e-01 9.0117e-02 4.6541e-02 2.1201e-02 1.5184e-02 1.4509e-01 +8.3600e-01 3.3472e+06 5.5315e+02 8.4620e+02 3.9111e-07 9.8849e-02 9.0115e-01 3.5412e+03 7.8100e+02 5.3213e+02 3.7198e+01 8.0580e-05 1.5209e-05 1.5860e-03 2.8559e-04 6.9304e-02 2.4595e-02 2.6760e-02 1.9574e-02 1.2535e-02 1.2683e-02 8.3268e-01 9.2578e-03 3.0944e-03 5.5088e-01 1.1773e-01 9.0026e-02 4.6505e-02 2.1191e-02 1.5184e-02 1.4613e-01 +8.3800e-01 3.3076e+06 5.5315e+02 8.3309e+02 3.9749e-07 9.4324e-02 9.0568e-01 3.5374e+03 7.7165e+02 5.3253e+02 3.6876e+01 8.0683e-05 1.5187e-05 1.5659e-03 2.8166e-04 6.8390e-02 2.4296e-02 2.6456e-02 1.9369e-02 1.2415e-02 1.2576e-02 8.3465e-01 9.2458e-03 3.0899e-03 5.5012e-01 1.1759e-01 8.9931e-02 4.6467e-02 2.1181e-02 1.5183e-02 1.4720e-01 +8.4000e-01 3.2680e+06 5.5315e+02 8.1998e+02 4.0405e-07 8.9676e-02 9.1032e-01 3.5337e+03 7.6231e+02 5.3294e+02 3.6555e+01 8.0786e-05 1.5165e-05 1.5459e-03 2.7773e-04 6.7475e-02 2.3996e-02 2.6151e-02 1.9163e-02 1.2294e-02 1.2467e-02 8.3663e-01 9.2335e-03 3.0853e-03 5.4933e-01 1.1744e-01 8.9834e-02 4.6428e-02 2.1170e-02 1.5182e-02 1.4830e-01 +8.4200e-01 3.2284e+06 5.5315e+02 8.0685e+02 4.1080e-07 8.4898e-02 9.1510e-01 3.5299e+03 7.5296e+02 5.3335e+02 3.6234e+01 8.0889e-05 1.5143e-05 1.5258e-03 2.7381e-04 6.6561e-02 2.3696e-02 2.5845e-02 1.8955e-02 1.2173e-02 1.2357e-02 8.3861e-01 9.2208e-03 3.0806e-03 5.4853e-01 1.1729e-01 8.9734e-02 4.6387e-02 2.1158e-02 1.5181e-02 1.4942e-01 +8.4400e-01 3.1888e+06 5.5315e+02 7.9372e+02 4.1774e-07 7.9986e-02 9.2001e-01 3.5262e+03 7.4363e+02 5.3375e+02 3.5914e+01 8.0992e-05 1.5120e-05 1.5058e-03 2.6989e-04 6.5647e-02 2.3395e-02 2.5538e-02 1.8746e-02 1.2050e-02 1.2246e-02 8.4060e-01 9.2079e-03 3.0757e-03 5.4771e-01 1.1713e-01 8.9630e-02 4.6345e-02 2.1145e-02 1.5179e-02 1.5058e-01 +8.4600e-01 3.1492e+06 5.5315e+02 7.8059e+02 4.2489e-07 7.4935e-02 9.2507e-01 3.5224e+03 7.3429e+02 5.3416e+02 3.5594e+01 8.1094e-05 1.5097e-05 1.4857e-03 2.6598e-04 6.4733e-02 2.3093e-02 2.5229e-02 1.8536e-02 1.1927e-02 1.2134e-02 8.4260e-01 9.1946e-03 3.0708e-03 5.4687e-01 1.1697e-01 8.9523e-02 4.6301e-02 2.1132e-02 1.5177e-02 1.5176e-01 +8.4800e-01 3.1096e+06 5.5315e+02 7.6746e+02 4.3226e-07 6.9737e-02 9.3026e-01 3.5187e+03 7.2496e+02 5.3456e+02 3.5274e+01 8.1197e-05 1.5074e-05 1.4655e-03 2.6207e-04 6.3820e-02 2.2791e-02 2.4920e-02 1.8325e-02 1.1802e-02 1.2020e-02 8.4459e-01 9.1809e-03 3.0657e-03 5.4601e-01 1.1680e-01 8.9412e-02 4.6255e-02 2.1118e-02 1.5174e-02 1.5298e-01 +8.5000e-01 3.0700e+06 5.5315e+02 7.5432e+02 4.3984e-07 6.4388e-02 9.3561e-01 3.5150e+03 7.1564e+02 5.3497e+02 3.4955e+01 8.1300e-05 1.5050e-05 1.4454e-03 2.5817e-04 6.2907e-02 2.2488e-02 2.4609e-02 1.8112e-02 1.1677e-02 1.1906e-02 8.4660e-01 9.1668e-03 3.0606e-03 5.4512e-01 1.1663e-01 8.9298e-02 4.6207e-02 2.1104e-02 1.5171e-02 1.5424e-01 +8.5200e-01 3.0304e+06 5.5315e+02 7.4118e+02 4.4766e-07 5.8880e-02 9.4112e-01 3.5112e+03 7.0632e+02 5.3538e+02 3.4636e+01 8.1402e-05 1.5026e-05 1.4252e-03 2.5428e-04 6.1994e-02 2.2185e-02 2.4297e-02 1.7898e-02 1.1550e-02 1.1790e-02 8.4861e-01 9.1524e-03 3.0552e-03 5.4421e-01 1.1646e-01 8.9180e-02 4.6157e-02 2.1088e-02 1.5167e-02 1.5553e-01 +8.5400e-01 2.9908e+06 5.5315e+02 7.2804e+02 4.5572e-07 5.3206e-02 9.4679e-01 3.5075e+03 6.9700e+02 5.3578e+02 3.4317e+01 8.1505e-05 1.5002e-05 1.4051e-03 2.5039e-04 6.1081e-02 2.1881e-02 2.3984e-02 1.7683e-02 1.1422e-02 1.1672e-02 8.5062e-01 9.1376e-03 3.0498e-03 5.4328e-01 1.1628e-01 8.9058e-02 4.6106e-02 2.1072e-02 1.5162e-02 1.5686e-01 +8.5600e-01 2.9512e+06 5.5315e+02 7.1490e+02 4.6404e-07 4.7360e-02 9.5264e-01 3.5037e+03 6.8769e+02 5.3619e+02 3.3999e+01 8.1607e-05 1.4978e-05 1.3849e-03 2.4650e-04 6.0168e-02 2.1577e-02 2.3670e-02 1.7467e-02 1.1294e-02 1.1554e-02 8.5264e-01 9.1223e-03 3.0442e-03 5.4232e-01 1.1609e-01 8.8932e-02 4.6052e-02 2.1054e-02 1.5157e-02 1.5822e-01 +8.5800e-01 2.9116e+06 5.5315e+02 7.0177e+02 4.7262e-07 4.1332e-02 9.5867e-01 3.5000e+03 6.7838e+02 5.3659e+02 3.3682e+01 8.1709e-05 1.4953e-05 1.3646e-03 2.4262e-04 5.9256e-02 2.1272e-02 2.3355e-02 1.7250e-02 1.1164e-02 1.1434e-02 8.5466e-01 9.1066e-03 3.0385e-03 5.4134e-01 1.1590e-01 8.8801e-02 4.5996e-02 2.1036e-02 1.5151e-02 1.5963e-01 +8.6000e-01 2.8720e+06 5.5315e+02 6.8864e+02 4.8147e-07 3.5115e-02 9.6488e-01 3.4962e+03 6.6908e+02 5.3699e+02 3.3364e+01 8.1811e-05 1.4928e-05 1.3444e-03 2.3875e-04 5.8344e-02 2.0966e-02 2.3038e-02 1.7031e-02 1.1033e-02 1.1313e-02 8.5669e-01 9.0905e-03 3.0326e-03 5.4033e-01 1.1571e-01 8.8666e-02 4.5938e-02 2.1017e-02 1.5145e-02 1.6108e-01 +8.6200e-01 2.8324e+06 5.5315e+02 6.7551e+02 4.9062e-07 2.8700e-02 9.7130e-01 3.4925e+03 6.5978e+02 5.3740e+02 3.3048e+01 8.1913e-05 1.4902e-05 1.3242e-03 2.3488e-04 5.7432e-02 2.0660e-02 2.2721e-02 1.6811e-02 1.0902e-02 1.1190e-02 8.5873e-01 9.0738e-03 3.0266e-03 5.3929e-01 1.1550e-01 8.8527e-02 4.5877e-02 2.0996e-02 1.5138e-02 1.6257e-01 +8.6400e-01 2.7928e+06 5.5315e+02 6.6239e+02 5.0007e-07 2.2078e-02 9.7792e-01 3.4887e+03 6.5049e+02 5.3780e+02 3.2731e+01 8.2015e-05 1.4876e-05 1.3039e-03 2.3102e-04 5.6520e-02 2.0353e-02 2.2402e-02 1.6590e-02 1.0769e-02 1.1067e-02 8.6076e-01 9.0567e-03 3.0204e-03 5.3822e-01 1.1529e-01 8.8383e-02 4.5814e-02 2.0975e-02 1.5130e-02 1.6410e-01 +8.6600e-01 2.7532e+06 5.5315e+02 6.4927e+02 5.0984e-07 1.5238e-02 9.8476e-01 3.4850e+03 6.4120e+02 5.3821e+02 3.2415e+01 8.2117e-05 1.4850e-05 1.2836e-03 2.2716e-04 5.5608e-02 2.0046e-02 2.2082e-02 1.6368e-02 1.0635e-02 1.0941e-02 8.6281e-01 9.0391e-03 3.0140e-03 5.3713e-01 1.1508e-01 8.8233e-02 4.5748e-02 2.0952e-02 1.5121e-02 1.6569e-01 +8.6800e-01 2.7136e+06 5.5315e+02 6.3617e+02 5.1995e-07 8.1691e-03 9.9183e-01 3.4813e+03 6.3192e+02 5.3861e+02 3.2100e+01 8.2219e-05 1.4823e-05 1.2633e-03 2.2331e-04 5.4697e-02 1.9738e-02 2.1761e-02 1.6144e-02 1.0500e-02 1.0815e-02 8.6486e-01 9.0209e-03 3.0075e-03 5.3600e-01 1.1486e-01 8.8079e-02 4.5680e-02 2.0928e-02 1.5112e-02 1.6732e-01 +8.7000e-01 2.6740e+06 5.5315e+02 6.2308e+02 5.3041e-07 8.6069e-04 9.9914e-01 3.4775e+03 6.2264e+02 5.3901e+02 3.1784e+01 8.2321e-05 1.4796e-05 1.2430e-03 2.1946e-04 5.3786e-02 1.9429e-02 2.1438e-02 1.5919e-02 1.0364e-02 1.0687e-02 8.6691e-01 9.0022e-03 3.0008e-03 5.3484e-01 1.1463e-01 8.7919e-02 4.5608e-02 2.0903e-02 1.5101e-02 1.6900e-01 +8.7200e-01 2.6344e+06 5.5315e+02 6.1289e+02 4.0366e-07 0.0000e+00 1.0000e+00 6.1289e+02 6.1289e+02 3.1305e+01 3.1305e+01 1.4781e-05 1.4781e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.7400e-01 2.5948e+06 5.5315e+02 6.0311e+02 4.0951e-07 0.0000e+00 1.0000e+00 6.0311e+02 6.0311e+02 3.0805e+01 3.0805e+01 1.4768e-05 1.4768e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.7600e-01 2.5552e+06 5.5315e+02 5.9333e+02 4.1554e-07 0.0000e+00 1.0000e+00 5.9333e+02 5.9333e+02 3.0306e+01 3.0306e+01 1.4755e-05 1.4755e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.7800e-01 2.5156e+06 5.5315e+02 5.8358e+02 4.2176e-07 0.0000e+00 1.0000e+00 5.8358e+02 5.8358e+02 2.9808e+01 2.9808e+01 1.4743e-05 1.4743e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.8000e-01 2.4760e+06 5.5315e+02 5.7384e+02 4.2818e-07 0.0000e+00 1.0000e+00 5.7384e+02 5.7384e+02 2.9310e+01 2.9310e+01 1.4730e-05 1.4730e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.8200e-01 2.4364e+06 5.5315e+02 5.6412e+02 4.3480e-07 0.0000e+00 1.0000e+00 5.6412e+02 5.6412e+02 2.8814e+01 2.8814e+01 1.4718e-05 1.4718e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.8400e-01 2.3968e+06 5.5315e+02 5.5441e+02 4.4164e-07 0.0000e+00 1.0000e+00 5.5441e+02 5.5441e+02 2.8318e+01 2.8318e+01 1.4705e-05 1.4705e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.8600e-01 2.3572e+06 5.5315e+02 5.4473e+02 4.4871e-07 0.0000e+00 1.0000e+00 5.4473e+02 5.4473e+02 2.7823e+01 2.7823e+01 1.4693e-05 1.4693e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.8800e-01 2.3176e+06 5.5315e+02 5.3506e+02 4.5602e-07 0.0000e+00 1.0000e+00 5.3506e+02 5.3506e+02 2.7329e+01 2.7329e+01 1.4681e-05 1.4681e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.9000e-01 2.2780e+06 5.5315e+02 5.2540e+02 4.6357e-07 0.0000e+00 1.0000e+00 5.2540e+02 5.2540e+02 2.6836e+01 2.6836e+01 1.4669e-05 1.4669e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.9200e-01 2.2384e+06 5.5315e+02 5.1577e+02 4.7140e-07 0.0000e+00 1.0000e+00 5.1577e+02 5.1577e+02 2.6344e+01 2.6344e+01 1.4657e-05 1.4657e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.9400e-01 2.1988e+06 5.5315e+02 5.0615e+02 4.7950e-07 0.0000e+00 1.0000e+00 5.0615e+02 5.0615e+02 2.5853e+01 2.5853e+01 1.4645e-05 1.4645e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.9600e-01 2.1592e+06 5.5315e+02 4.9654e+02 4.8789e-07 0.0000e+00 1.0000e+00 4.9654e+02 4.9654e+02 2.5362e+01 2.5362e+01 1.4634e-05 1.4634e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.9800e-01 2.1196e+06 5.5315e+02 4.8696e+02 4.9660e-07 0.0000e+00 1.0000e+00 4.8696e+02 4.8696e+02 2.4873e+01 2.4873e+01 1.4622e-05 1.4622e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.0000e-01 2.0800e+06 5.5315e+02 4.7739e+02 5.0563e-07 0.0000e+00 1.0000e+00 4.7739e+02 4.7739e+02 2.4384e+01 2.4384e+01 1.4611e-05 1.4611e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.0200e-01 2.0404e+06 5.5315e+02 4.6784e+02 5.1502e-07 0.0000e+00 1.0000e+00 4.6784e+02 4.6784e+02 2.3896e+01 2.3896e+01 1.4600e-05 1.4600e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.0400e-01 2.0008e+06 5.5315e+02 4.5831e+02 5.2477e-07 0.0000e+00 1.0000e+00 4.5831e+02 4.5831e+02 2.3409e+01 2.3409e+01 1.4588e-05 1.4588e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.0600e-01 1.9612e+06 5.5315e+02 4.4879e+02 5.3491e-07 0.0000e+00 1.0000e+00 4.4879e+02 4.4879e+02 2.2923e+01 2.2923e+01 1.4577e-05 1.4577e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.0800e-01 1.9216e+06 5.5315e+02 4.3930e+02 5.4547e-07 0.0000e+00 1.0000e+00 4.3930e+02 4.3930e+02 2.2438e+01 2.2438e+01 1.4566e-05 1.4566e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.1000e-01 1.8820e+06 5.5315e+02 4.2981e+02 5.5647e-07 0.0000e+00 1.0000e+00 4.2981e+02 4.2981e+02 2.1954e+01 2.1954e+01 1.4555e-05 1.4555e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.1200e-01 1.8424e+06 5.5315e+02 4.2035e+02 5.6794e-07 0.0000e+00 1.0000e+00 4.2035e+02 4.2035e+02 2.1470e+01 2.1470e+01 1.4545e-05 1.4545e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.1400e-01 1.8028e+06 5.5315e+02 4.1091e+02 5.7991e-07 0.0000e+00 1.0000e+00 4.1091e+02 4.1091e+02 2.0988e+01 2.0988e+01 1.4534e-05 1.4534e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.1600e-01 1.7632e+06 5.5315e+02 4.0148e+02 5.9242e-07 0.0000e+00 1.0000e+00 4.0148e+02 4.0148e+02 2.0506e+01 2.0506e+01 1.4523e-05 1.4523e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.1800e-01 1.7236e+06 5.5315e+02 3.9207e+02 6.0550e-07 0.0000e+00 1.0000e+00 3.9207e+02 3.9207e+02 2.0026e+01 2.0026e+01 1.4513e-05 1.4513e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.2000e-01 1.6840e+06 5.5315e+02 3.8268e+02 6.1919e-07 0.0000e+00 1.0000e+00 3.8268e+02 3.8268e+02 1.9546e+01 1.9546e+01 1.4503e-05 1.4503e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.2200e-01 1.6444e+06 5.5315e+02 3.7330e+02 6.3354e-07 0.0000e+00 1.0000e+00 3.7330e+02 3.7330e+02 1.9067e+01 1.9067e+01 1.4492e-05 1.4492e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.2400e-01 1.6048e+06 5.5315e+02 3.6395e+02 6.4859e-07 0.0000e+00 1.0000e+00 3.6395e+02 3.6395e+02 1.8589e+01 1.8589e+01 1.4482e-05 1.4482e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.2600e-01 1.5652e+06 5.5315e+02 3.5461e+02 6.6440e-07 0.0000e+00 1.0000e+00 3.5461e+02 3.5461e+02 1.8112e+01 1.8112e+01 1.4472e-05 1.4472e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.2800e-01 1.5256e+06 5.5315e+02 3.4529e+02 6.8103e-07 0.0000e+00 1.0000e+00 3.4529e+02 3.4529e+02 1.7636e+01 1.7636e+01 1.4462e-05 1.4462e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.3000e-01 1.4860e+06 5.5315e+02 3.3598e+02 6.9854e-07 0.0000e+00 1.0000e+00 3.3598e+02 3.3598e+02 1.7161e+01 1.7161e+01 1.4453e-05 1.4453e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.3200e-01 1.4464e+06 5.5315e+02 3.2670e+02 7.1701e-07 0.0000e+00 1.0000e+00 3.2670e+02 3.2670e+02 1.6687e+01 1.6687e+01 1.4443e-05 1.4443e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.3400e-01 1.4068e+06 5.5315e+02 3.1743e+02 7.3652e-07 0.0000e+00 1.0000e+00 3.1743e+02 3.1743e+02 1.6214e+01 1.6214e+01 1.4433e-05 1.4433e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.3600e-01 1.3672e+06 5.5315e+02 3.0818e+02 7.5715e-07 0.0000e+00 1.0000e+00 3.0818e+02 3.0818e+02 1.5741e+01 1.5741e+01 1.4424e-05 1.4424e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.3800e-01 1.3276e+06 5.5315e+02 2.9895e+02 7.7901e-07 0.0000e+00 1.0000e+00 2.9895e+02 2.9895e+02 1.5270e+01 1.5270e+01 1.4414e-05 1.4414e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.4000e-01 1.2880e+06 5.5315e+02 2.8974e+02 8.0221e-07 0.0000e+00 1.0000e+00 2.8974e+02 2.8974e+02 1.4799e+01 1.4799e+01 1.4405e-05 1.4405e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.4200e-01 1.2484e+06 5.5315e+02 2.8054e+02 8.2688e-07 0.0000e+00 1.0000e+00 2.8054e+02 2.8054e+02 1.4329e+01 1.4329e+01 1.4396e-05 1.4396e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.4400e-01 1.2088e+06 5.5315e+02 2.7137e+02 8.5316e-07 0.0000e+00 1.0000e+00 2.7137e+02 2.7137e+02 1.3861e+01 1.3861e+01 1.4387e-05 1.4387e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.4600e-01 1.1692e+06 5.5315e+02 2.6221e+02 8.8122e-07 0.0000e+00 1.0000e+00 2.6221e+02 2.6221e+02 1.3393e+01 1.3393e+01 1.4378e-05 1.4378e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.4800e-01 1.1296e+06 5.5315e+02 2.5307e+02 9.1124e-07 0.0000e+00 1.0000e+00 2.5307e+02 2.5307e+02 1.2926e+01 1.2926e+01 1.4369e-05 1.4369e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.5000e-01 1.0900e+06 5.5315e+02 2.4394e+02 9.4344e-07 0.0000e+00 1.0000e+00 2.4394e+02 2.4394e+02 1.2460e+01 1.2460e+01 1.4360e-05 1.4360e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.5200e-01 1.0504e+06 5.5315e+02 2.3484e+02 9.7807e-07 0.0000e+00 1.0000e+00 2.3484e+02 2.3484e+02 1.1995e+01 1.1995e+01 1.4351e-05 1.4351e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.5400e-01 1.0108e+06 5.5315e+02 2.2575e+02 1.0154e-06 0.0000e+00 1.0000e+00 2.2575e+02 2.2575e+02 1.1531e+01 1.1531e+01 1.4343e-05 1.4343e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.5600e-01 9.7120e+05 5.5315e+02 2.1668e+02 1.0558e-06 0.0000e+00 1.0000e+00 2.1668e+02 2.1668e+02 1.1068e+01 1.1068e+01 1.4334e-05 1.4334e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.5800e-01 9.3160e+05 5.5315e+02 2.0763e+02 1.0996e-06 0.0000e+00 1.0000e+00 2.0763e+02 2.0763e+02 1.0605e+01 1.0605e+01 1.4326e-05 1.4326e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.6000e-01 8.9200e+05 5.5315e+02 1.9860e+02 1.1473e-06 0.0000e+00 1.0000e+00 1.9860e+02 1.9860e+02 1.0144e+01 1.0144e+01 1.4317e-05 1.4317e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.6200e-01 8.5240e+05 5.5315e+02 1.8959e+02 1.1994e-06 0.0000e+00 1.0000e+00 1.8959e+02 1.8959e+02 9.6836e+00 9.6836e+00 1.4309e-05 1.4309e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.6400e-01 8.1280e+05 5.5315e+02 1.8059e+02 1.2566e-06 0.0000e+00 1.0000e+00 1.8059e+02 1.8059e+02 9.2241e+00 9.2241e+00 1.4301e-05 1.4301e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.6600e-01 7.7320e+05 5.5315e+02 1.7161e+02 1.3196e-06 0.0000e+00 1.0000e+00 1.7161e+02 1.7161e+02 8.7656e+00 8.7656e+00 1.4293e-05 1.4293e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.6800e-01 7.3360e+05 5.5315e+02 1.6266e+02 1.3895e-06 0.0000e+00 1.0000e+00 1.6266e+02 1.6266e+02 8.3080e+00 8.3080e+00 1.4285e-05 1.4285e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.7000e-01 6.9400e+05 5.5315e+02 1.5371e+02 1.4673e-06 0.0000e+00 1.0000e+00 1.5371e+02 1.5371e+02 7.8513e+00 7.8513e+00 1.4277e-05 1.4277e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.7200e-01 6.5440e+05 5.5315e+02 1.4479e+02 1.5545e-06 0.0000e+00 1.0000e+00 1.4479e+02 1.4479e+02 7.3956e+00 7.3956e+00 1.4269e-05 1.4269e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.7400e-01 6.1480e+05 5.5315e+02 1.3589e+02 1.6530e-06 0.0000e+00 1.0000e+00 1.3589e+02 1.3589e+02 6.9408e+00 6.9408e+00 1.4261e-05 1.4261e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.7600e-01 5.7520e+05 5.5315e+02 1.2700e+02 1.7650e-06 0.0000e+00 1.0000e+00 1.2700e+02 1.2700e+02 6.4869e+00 6.4869e+00 1.4254e-05 1.4254e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.7800e-01 5.3560e+05 5.5315e+02 1.1813e+02 1.8936e-06 0.0000e+00 1.0000e+00 1.1813e+02 1.1813e+02 6.0340e+00 6.0340e+00 1.4246e-05 1.4246e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.8000e-01 4.9600e+05 5.5315e+02 1.0929e+02 2.0427e-06 0.0000e+00 1.0000e+00 1.0929e+02 1.0929e+02 5.5820e+00 5.5820e+00 1.4239e-05 1.4239e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.8200e-01 4.5640e+05 5.5315e+02 1.0045e+02 2.2176e-06 0.0000e+00 1.0000e+00 1.0045e+02 1.0045e+02 5.1309e+00 5.1309e+00 1.4232e-05 1.4232e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.8400e-01 4.1680e+05 5.5315e+02 9.1642e+01 2.4258e-06 0.0000e+00 1.0000e+00 9.1642e+01 9.1642e+01 4.6808e+00 4.6808e+00 1.4224e-05 1.4224e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.8600e-01 3.7720e+05 5.5315e+02 8.2848e+01 2.6777e-06 0.0000e+00 1.0000e+00 8.2848e+01 8.2848e+01 4.2316e+00 4.2316e+00 1.4217e-05 1.4217e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.8800e-01 3.3760e+05 5.5315e+02 7.4072e+01 2.9887e-06 0.0000e+00 1.0000e+00 7.4072e+01 7.4072e+01 3.7834e+00 3.7834e+00 1.4210e-05 1.4210e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.9000e-01 2.9800e+05 5.5315e+02 6.5314e+01 3.3824e-06 0.0000e+00 1.0000e+00 6.5314e+01 6.5314e+01 3.3361e+00 3.3361e+00 1.4203e-05 1.4203e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.9200e-01 2.5840e+05 5.5315e+02 5.6575e+01 3.8967e-06 0.0000e+00 1.0000e+00 5.6575e+01 5.6575e+01 2.8897e+00 2.8897e+00 1.4196e-05 1.4196e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.9400e-01 2.1880e+05 5.5315e+02 4.7854e+01 4.5971e-06 0.0000e+00 1.0000e+00 4.7854e+01 4.7854e+01 2.4443e+00 2.4443e+00 1.4189e-05 1.4189e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.9600e-01 1.7920e+05 5.5315e+02 3.9152e+01 5.6071e-06 0.0000e+00 1.0000e+00 3.9152e+01 3.9152e+01 1.9998e+00 1.9998e+00 1.4183e-05 1.4183e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.9800e-01 1.3960e+05 5.5315e+02 3.0467e+01 7.1901e-06 0.0000e+00 1.0000e+00 3.0467e+01 3.0467e+01 1.5562e+00 1.5562e+00 1.4176e-05 1.4176e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0000e+00 1.0000e+05 5.5315e+02 2.1802e+01 1.0027e-05 0.0000e+00 1.0000e+00 2.1802e+01 2.1802e+01 1.1136e+00 1.1136e+00 1.4170e-05 1.4170e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0020e+00 1.3960e+05 5.8315e+02 2.8879e+01 7.1848e-06 0.0000e+00 1.0000e+00 2.8879e+01 2.8879e+01 1.4750e+00 1.4750e+00 1.4780e-05 1.4780e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0040e+00 1.7920e+05 5.8315e+02 3.7102e+01 5.6018e-06 0.0000e+00 1.0000e+00 3.7102e+01 3.7102e+01 1.8951e+00 1.8951e+00 1.4786e-05 1.4786e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0060e+00 2.1880e+05 5.8315e+02 4.5339e+01 4.5918e-06 0.0000e+00 1.0000e+00 4.5339e+01 4.5339e+01 2.3158e+00 2.3158e+00 1.4793e-05 1.4793e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0080e+00 2.5840e+05 5.8315e+02 5.3591e+01 3.8913e-06 0.0000e+00 1.0000e+00 5.3591e+01 5.3591e+01 2.7373e+00 2.7373e+00 1.4799e-05 1.4799e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0100e+00 2.9800e+05 5.8315e+02 6.1856e+01 3.3770e-06 0.0000e+00 1.0000e+00 6.1856e+01 6.1856e+01 3.1594e+00 3.1594e+00 1.4806e-05 1.4806e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0120e+00 3.3760e+05 5.8315e+02 7.0135e+01 2.9834e-06 0.0000e+00 1.0000e+00 7.0135e+01 7.0135e+01 3.5823e+00 3.5823e+00 1.4812e-05 1.4812e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0140e+00 3.7720e+05 5.8315e+02 7.8427e+01 2.6724e-06 0.0000e+00 1.0000e+00 7.8427e+01 7.8427e+01 4.0059e+00 4.0059e+00 1.4819e-05 1.4819e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0160e+00 4.1680e+05 5.8315e+02 8.6734e+01 2.4204e-06 0.0000e+00 1.0000e+00 8.6734e+01 8.6734e+01 4.4301e+00 4.4301e+00 1.4826e-05 1.4826e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0180e+00 4.5640e+05 5.8315e+02 9.5054e+01 2.2122e-06 0.0000e+00 1.0000e+00 9.5054e+01 9.5054e+01 4.8551e+00 4.8551e+00 1.4832e-05 1.4832e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0200e+00 4.9600e+05 5.8315e+02 1.0339e+02 2.0372e-06 0.0000e+00 1.0000e+00 1.0339e+02 1.0339e+02 5.2808e+00 5.2808e+00 1.4839e-05 1.4839e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0220e+00 5.3560e+05 5.8315e+02 1.1174e+02 1.8881e-06 0.0000e+00 1.0000e+00 1.1174e+02 1.1174e+02 5.7071e+00 5.7071e+00 1.4846e-05 1.4846e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0240e+00 5.7520e+05 5.8315e+02 1.2010e+02 1.7596e-06 0.0000e+00 1.0000e+00 1.2010e+02 1.2010e+02 6.1342e+00 6.1342e+00 1.4853e-05 1.4853e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0260e+00 6.1480e+05 5.8315e+02 1.2847e+02 1.6475e-06 0.0000e+00 1.0000e+00 1.2847e+02 1.2847e+02 6.5620e+00 6.5620e+00 1.4860e-05 1.4860e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0280e+00 6.5440e+05 5.8315e+02 1.3686e+02 1.5491e-06 0.0000e+00 1.0000e+00 1.3686e+02 1.3686e+02 6.9905e+00 6.9905e+00 1.4868e-05 1.4868e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0300e+00 6.9400e+05 5.8315e+02 1.4526e+02 1.4618e-06 0.0000e+00 1.0000e+00 1.4526e+02 1.4526e+02 7.4196e+00 7.4196e+00 1.4875e-05 1.4875e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0320e+00 7.3360e+05 5.8315e+02 1.5368e+02 1.3840e-06 0.0000e+00 1.0000e+00 1.5368e+02 1.5368e+02 7.8495e+00 7.8495e+00 1.4882e-05 1.4882e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0340e+00 7.7320e+05 5.8315e+02 1.6211e+02 1.3141e-06 0.0000e+00 1.0000e+00 1.6211e+02 1.6211e+02 8.2800e+00 8.2800e+00 1.4890e-05 1.4890e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0360e+00 8.1280e+05 5.8315e+02 1.7055e+02 1.2511e-06 0.0000e+00 1.0000e+00 1.7055e+02 1.7055e+02 8.7113e+00 8.7113e+00 1.4897e-05 1.4897e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0380e+00 8.5240e+05 5.8315e+02 1.7901e+02 1.1939e-06 0.0000e+00 1.0000e+00 1.7901e+02 1.7901e+02 9.1432e+00 9.1432e+00 1.4905e-05 1.4905e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0400e+00 8.9200e+05 5.8315e+02 1.8748e+02 1.1418e-06 0.0000e+00 1.0000e+00 1.8748e+02 1.8748e+02 9.5758e+00 9.5758e+00 1.4912e-05 1.4912e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0420e+00 9.3160e+05 5.8315e+02 1.9596e+02 1.0941e-06 0.0000e+00 1.0000e+00 1.9596e+02 1.9596e+02 1.0009e+01 1.0009e+01 1.4920e-05 1.4920e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0440e+00 9.7120e+05 5.8315e+02 2.0446e+02 1.0502e-06 0.0000e+00 1.0000e+00 2.0446e+02 2.0446e+02 1.0443e+01 1.0443e+01 1.4928e-05 1.4928e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0460e+00 1.0108e+06 5.8315e+02 2.1297e+02 1.0099e-06 0.0000e+00 1.0000e+00 2.1297e+02 2.1297e+02 1.0878e+01 1.0878e+01 1.4936e-05 1.4936e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0480e+00 1.0504e+06 5.8315e+02 2.2149e+02 9.7252e-07 0.0000e+00 1.0000e+00 2.2149e+02 2.2149e+02 1.1313e+01 1.1313e+01 1.4944e-05 1.4944e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0500e+00 1.0900e+06 5.8315e+02 2.3003e+02 9.3789e-07 0.0000e+00 1.0000e+00 2.3003e+02 2.3003e+02 1.1749e+01 1.1749e+01 1.4952e-05 1.4952e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0520e+00 1.1296e+06 5.8315e+02 2.3858e+02 9.0568e-07 0.0000e+00 1.0000e+00 2.3858e+02 2.3858e+02 1.2186e+01 1.2186e+01 1.4960e-05 1.4960e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0540e+00 1.1692e+06 5.8315e+02 2.4714e+02 8.7565e-07 0.0000e+00 1.0000e+00 2.4714e+02 2.4714e+02 1.2623e+01 1.2623e+01 1.4968e-05 1.4968e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0560e+00 1.2088e+06 5.8315e+02 2.5572e+02 8.4758e-07 0.0000e+00 1.0000e+00 2.5572e+02 2.5572e+02 1.3061e+01 1.3061e+01 1.4977e-05 1.4977e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0580e+00 1.2484e+06 5.8315e+02 2.6431e+02 8.2129e-07 0.0000e+00 1.0000e+00 2.6431e+02 2.6431e+02 1.3500e+01 1.3500e+01 1.4985e-05 1.4985e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0600e+00 1.2880e+06 5.8315e+02 2.7291e+02 7.9661e-07 0.0000e+00 1.0000e+00 2.7291e+02 2.7291e+02 1.3939e+01 1.3939e+01 1.4993e-05 1.4993e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0620e+00 1.3276e+06 5.8315e+02 2.8152e+02 7.7341e-07 0.0000e+00 1.0000e+00 2.8152e+02 2.8152e+02 1.4379e+01 1.4379e+01 1.5002e-05 1.5002e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0640e+00 1.3672e+06 5.8315e+02 2.9015e+02 7.5154e-07 0.0000e+00 1.0000e+00 2.9015e+02 2.9015e+02 1.4820e+01 1.4820e+01 1.5011e-05 1.5011e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0660e+00 1.4068e+06 5.8315e+02 2.9879e+02 7.3090e-07 0.0000e+00 1.0000e+00 2.9879e+02 2.9879e+02 1.5262e+01 1.5262e+01 1.5019e-05 1.5019e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0680e+00 1.4464e+06 5.8315e+02 3.0745e+02 7.1139e-07 0.0000e+00 1.0000e+00 3.0745e+02 3.0745e+02 1.5704e+01 1.5704e+01 1.5028e-05 1.5028e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0700e+00 1.4860e+06 5.8315e+02 3.1612e+02 6.9292e-07 0.0000e+00 1.0000e+00 3.1612e+02 3.1612e+02 1.6146e+01 1.6146e+01 1.5037e-05 1.5037e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0720e+00 1.5256e+06 5.8315e+02 3.2480e+02 6.7540e-07 0.0000e+00 1.0000e+00 3.2480e+02 3.2480e+02 1.6590e+01 1.6590e+01 1.5046e-05 1.5046e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0740e+00 1.5652e+06 5.8315e+02 3.3349e+02 6.5876e-07 0.0000e+00 1.0000e+00 3.3349e+02 3.3349e+02 1.7034e+01 1.7034e+01 1.5055e-05 1.5055e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0760e+00 1.6048e+06 5.8315e+02 3.4220e+02 6.4295e-07 0.0000e+00 1.0000e+00 3.4220e+02 3.4220e+02 1.7478e+01 1.7478e+01 1.5064e-05 1.5064e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0780e+00 1.6444e+06 5.8315e+02 3.5092e+02 6.2789e-07 0.0000e+00 1.0000e+00 3.5092e+02 3.5092e+02 1.7924e+01 1.7924e+01 1.5074e-05 1.5074e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0800e+00 1.6840e+06 5.8315e+02 3.5965e+02 6.1354e-07 0.0000e+00 1.0000e+00 3.5965e+02 3.5965e+02 1.8370e+01 1.8370e+01 1.5083e-05 1.5083e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0820e+00 1.7236e+06 5.8315e+02 3.6839e+02 5.9984e-07 0.0000e+00 1.0000e+00 3.6839e+02 3.6839e+02 1.8816e+01 1.8816e+01 1.5092e-05 1.5092e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0840e+00 1.7632e+06 5.8315e+02 3.7715e+02 5.8676e-07 0.0000e+00 1.0000e+00 3.7715e+02 3.7715e+02 1.9264e+01 1.9264e+01 1.5102e-05 1.5102e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0860e+00 1.8028e+06 5.8315e+02 3.8592e+02 5.7425e-07 0.0000e+00 1.0000e+00 3.8592e+02 3.8592e+02 1.9712e+01 1.9712e+01 1.5111e-05 1.5111e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0880e+00 1.8424e+06 5.8315e+02 3.9470e+02 5.6227e-07 0.0000e+00 1.0000e+00 3.9470e+02 3.9470e+02 2.0160e+01 2.0160e+01 1.5121e-05 1.5121e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0900e+00 1.8820e+06 5.8315e+02 4.0349e+02 5.5079e-07 0.0000e+00 1.0000e+00 4.0349e+02 4.0349e+02 2.0609e+01 2.0609e+01 1.5131e-05 1.5131e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0920e+00 1.9216e+06 5.8315e+02 4.1230e+02 5.3979e-07 0.0000e+00 1.0000e+00 4.1230e+02 4.1230e+02 2.1059e+01 2.1059e+01 1.5141e-05 1.5141e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0940e+00 1.9612e+06 5.8315e+02 4.2112e+02 5.2923e-07 0.0000e+00 1.0000e+00 4.2112e+02 4.2112e+02 2.1510e+01 2.1510e+01 1.5151e-05 1.5151e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0960e+00 2.0008e+06 5.8315e+02 4.2995e+02 5.1908e-07 0.0000e+00 1.0000e+00 4.2995e+02 4.2995e+02 2.1961e+01 2.1961e+01 1.5161e-05 1.5161e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0980e+00 2.0404e+06 5.8315e+02 4.3880e+02 5.0932e-07 0.0000e+00 1.0000e+00 4.3880e+02 4.3880e+02 2.2413e+01 2.2413e+01 1.5171e-05 1.5171e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1000e+00 2.0800e+06 5.8315e+02 4.4765e+02 4.9994e-07 0.0000e+00 1.0000e+00 4.4765e+02 4.4765e+02 2.2865e+01 2.2865e+01 1.5181e-05 1.5181e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1020e+00 2.1196e+06 5.8315e+02 4.5652e+02 4.9090e-07 0.0000e+00 1.0000e+00 4.5652e+02 4.5652e+02 2.3318e+01 2.3318e+01 1.5192e-05 1.5192e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1040e+00 2.1592e+06 5.8315e+02 4.6540e+02 4.8219e-07 0.0000e+00 1.0000e+00 4.6540e+02 4.6540e+02 2.3771e+01 2.3771e+01 1.5202e-05 1.5202e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1060e+00 2.1988e+06 5.8315e+02 4.7429e+02 4.7379e-07 0.0000e+00 1.0000e+00 4.7429e+02 4.7429e+02 2.4226e+01 2.4226e+01 1.5212e-05 1.5212e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1080e+00 2.2384e+06 5.8315e+02 4.8320e+02 4.6569e-07 0.0000e+00 1.0000e+00 4.8320e+02 4.8320e+02 2.4681e+01 2.4681e+01 1.5223e-05 1.5223e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1100e+00 2.2780e+06 5.8315e+02 4.9212e+02 4.5786e-07 0.0000e+00 1.0000e+00 4.9212e+02 4.9212e+02 2.5136e+01 2.5136e+01 1.5234e-05 1.5234e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1120e+00 2.3176e+06 5.8315e+02 5.0104e+02 4.5030e-07 0.0000e+00 1.0000e+00 5.0104e+02 5.0104e+02 2.5592e+01 2.5592e+01 1.5244e-05 1.5244e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1140e+00 2.3572e+06 5.8315e+02 5.0999e+02 4.4300e-07 0.0000e+00 1.0000e+00 5.0999e+02 5.0999e+02 2.6049e+01 2.6049e+01 1.5255e-05 1.5255e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1160e+00 2.3968e+06 5.8315e+02 5.1894e+02 4.3593e-07 0.0000e+00 1.0000e+00 5.1894e+02 5.1894e+02 2.6506e+01 2.6506e+01 1.5266e-05 1.5266e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1180e+00 2.4364e+06 5.8315e+02 5.2790e+02 4.2909e-07 0.0000e+00 1.0000e+00 5.2790e+02 5.2790e+02 2.6964e+01 2.6964e+01 1.5277e-05 1.5277e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1200e+00 2.4760e+06 5.8315e+02 5.3688e+02 4.2246e-07 0.0000e+00 1.0000e+00 5.3688e+02 5.3688e+02 2.7422e+01 2.7422e+01 1.5289e-05 1.5289e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1220e+00 2.5156e+06 5.8315e+02 5.4587e+02 4.1604e-07 0.0000e+00 1.0000e+00 5.4587e+02 5.4587e+02 2.7881e+01 2.7881e+01 1.5300e-05 1.5300e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1240e+00 2.5552e+06 5.8315e+02 5.5486e+02 4.0982e-07 0.0000e+00 1.0000e+00 5.5486e+02 5.5486e+02 2.8341e+01 2.8341e+01 1.5311e-05 1.5311e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1260e+00 2.5948e+06 5.8315e+02 5.6388e+02 4.0379e-07 0.0000e+00 1.0000e+00 5.6388e+02 5.6388e+02 2.8801e+01 2.8801e+01 1.5323e-05 1.5323e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1280e+00 2.6344e+06 5.8315e+02 5.7290e+02 3.9794e-07 0.0000e+00 1.0000e+00 5.7290e+02 5.7290e+02 2.9262e+01 2.9262e+01 1.5334e-05 1.5334e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1300e+00 2.6740e+06 5.8315e+02 5.8193e+02 3.9225e-07 0.0000e+00 1.0000e+00 5.8193e+02 5.8193e+02 2.9723e+01 2.9723e+01 1.5346e-05 1.5346e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1320e+00 2.7136e+06 5.8315e+02 5.9098e+02 3.8673e-07 0.0000e+00 1.0000e+00 5.9098e+02 5.9098e+02 3.0185e+01 3.0185e+01 1.5357e-05 1.5357e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1340e+00 2.7532e+06 5.8315e+02 6.0003e+02 3.8137e-07 0.0000e+00 1.0000e+00 6.0003e+02 6.0003e+02 3.0648e+01 3.0648e+01 1.5369e-05 1.5369e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1360e+00 2.7928e+06 5.8315e+02 6.0910e+02 3.7616e-07 0.0000e+00 1.0000e+00 6.0910e+02 6.0910e+02 3.1111e+01 3.1111e+01 1.5381e-05 1.5381e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1380e+00 2.8324e+06 5.8315e+02 6.1818e+02 3.7109e-07 0.0000e+00 1.0000e+00 6.1818e+02 6.1818e+02 3.1575e+01 3.1575e+01 1.5393e-05 1.5393e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1400e+00 2.8720e+06 5.8315e+02 6.2727e+02 3.6616e-07 0.0000e+00 1.0000e+00 6.2727e+02 6.2727e+02 3.2039e+01 3.2039e+01 1.5405e-05 1.5405e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1420e+00 2.9116e+06 5.8315e+02 6.3637e+02 3.6136e-07 0.0000e+00 1.0000e+00 6.3637e+02 6.3637e+02 3.2504e+01 3.2504e+01 1.5418e-05 1.5418e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1440e+00 2.9512e+06 5.8315e+02 6.4548e+02 3.5668e-07 0.0000e+00 1.0000e+00 6.4548e+02 6.4548e+02 3.2969e+01 3.2969e+01 1.5430e-05 1.5430e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1460e+00 2.9908e+06 5.8315e+02 6.5460e+02 3.5213e-07 0.0000e+00 1.0000e+00 6.5460e+02 6.5460e+02 3.3435e+01 3.3435e+01 1.5442e-05 1.5442e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1480e+00 3.0304e+06 5.8315e+02 6.6374e+02 3.4770e-07 0.0000e+00 1.0000e+00 6.6374e+02 6.6374e+02 3.3902e+01 3.3902e+01 1.5455e-05 1.5455e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1500e+00 3.0700e+06 5.8315e+02 6.7288e+02 3.4337e-07 0.0000e+00 1.0000e+00 6.7288e+02 6.7288e+02 3.4369e+01 3.4369e+01 1.5467e-05 1.5467e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1520e+00 3.1096e+06 5.8315e+02 6.8204e+02 3.3916e-07 0.0000e+00 1.0000e+00 6.8204e+02 6.8204e+02 3.4837e+01 3.4837e+01 1.5480e-05 1.5480e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1540e+00 3.1492e+06 5.8315e+02 6.9120e+02 3.3505e-07 0.0000e+00 1.0000e+00 6.9120e+02 6.9120e+02 3.5305e+01 3.5305e+01 1.5493e-05 1.5493e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1560e+00 3.1888e+06 5.8315e+02 7.0038e+02 3.3104e-07 0.0000e+00 1.0000e+00 7.0038e+02 7.0038e+02 3.5773e+01 3.5773e+01 1.5506e-05 1.5506e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1580e+00 3.2284e+06 5.8315e+02 7.0956e+02 3.2713e-07 0.0000e+00 1.0000e+00 7.0956e+02 7.0956e+02 3.6243e+01 3.6243e+01 1.5519e-05 1.5519e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1600e+00 3.2680e+06 5.8315e+02 7.1876e+02 3.2331e-07 0.0000e+00 1.0000e+00 7.1876e+02 7.1876e+02 3.6712e+01 3.6712e+01 1.5532e-05 1.5532e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1620e+00 3.3076e+06 5.8315e+02 7.2797e+02 3.1957e-07 0.0000e+00 1.0000e+00 7.2797e+02 7.2797e+02 3.7183e+01 3.7183e+01 1.5545e-05 1.5545e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1640e+00 3.3472e+06 5.8315e+02 7.3719e+02 3.1593e-07 0.0000e+00 1.0000e+00 7.3719e+02 7.3719e+02 3.7653e+01 3.7653e+01 1.5558e-05 1.5558e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1660e+00 3.3868e+06 5.8315e+02 7.4641e+02 3.1237e-07 0.0000e+00 1.0000e+00 7.4641e+02 7.4641e+02 3.8125e+01 3.8125e+01 1.5572e-05 1.5572e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1680e+00 3.4264e+06 5.8315e+02 7.5565e+02 3.0889e-07 0.0000e+00 1.0000e+00 7.5565e+02 7.5565e+02 3.8597e+01 3.8597e+01 1.5585e-05 1.5585e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1700e+00 3.4660e+06 5.8315e+02 7.6490e+02 3.0548e-07 0.0000e+00 1.0000e+00 7.6490e+02 7.6490e+02 3.9069e+01 3.9069e+01 1.5599e-05 1.5599e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1720e+00 3.5056e+06 5.8315e+02 7.7416e+02 3.0215e-07 0.0000e+00 1.0000e+00 7.7416e+02 7.7416e+02 3.9542e+01 3.9542e+01 1.5613e-05 1.5613e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1740e+00 3.5452e+06 5.8315e+02 7.8343e+02 2.9890e-07 0.0000e+00 1.0000e+00 7.8343e+02 7.8343e+02 4.0015e+01 4.0015e+01 1.5626e-05 1.5626e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1760e+00 3.5848e+06 5.8315e+02 7.9270e+02 2.9571e-07 0.0000e+00 1.0000e+00 7.9270e+02 7.9270e+02 4.0489e+01 4.0489e+01 1.5640e-05 1.5640e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1780e+00 3.6244e+06 5.8315e+02 8.0199e+02 2.9259e-07 0.0000e+00 1.0000e+00 8.0199e+02 8.0199e+02 4.0964e+01 4.0964e+01 1.5654e-05 1.5654e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1800e+00 3.6640e+06 5.8315e+02 8.1129e+02 2.8954e-07 0.0000e+00 1.0000e+00 8.1129e+02 8.1129e+02 4.1438e+01 4.1438e+01 1.5668e-05 1.5668e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1820e+00 3.7036e+06 5.8315e+02 8.2060e+02 2.8655e-07 0.0000e+00 1.0000e+00 8.2060e+02 8.2060e+02 4.1914e+01 4.1914e+01 1.5683e-05 1.5683e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1840e+00 3.7432e+06 5.8315e+02 8.2991e+02 2.8362e-07 0.0000e+00 1.0000e+00 8.2991e+02 8.2991e+02 4.2390e+01 4.2390e+01 1.5697e-05 1.5697e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1860e+00 3.7828e+06 5.8315e+02 8.3924e+02 2.8075e-07 0.0000e+00 1.0000e+00 8.3924e+02 8.3924e+02 4.2866e+01 4.2866e+01 1.5711e-05 1.5711e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1880e+00 3.8224e+06 5.8315e+02 8.4857e+02 2.7794e-07 0.0000e+00 1.0000e+00 8.4857e+02 8.4857e+02 4.3343e+01 4.3343e+01 1.5726e-05 1.5726e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1900e+00 3.8620e+06 5.8315e+02 8.5792e+02 2.7519e-07 0.0000e+00 1.0000e+00 8.5792e+02 8.5792e+02 4.3820e+01 4.3820e+01 1.5741e-05 1.5741e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1920e+00 3.9016e+06 5.8315e+02 8.6727e+02 2.7249e-07 0.0000e+00 1.0000e+00 8.6727e+02 8.6727e+02 4.4298e+01 4.4298e+01 1.5755e-05 1.5755e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1940e+00 3.9412e+06 5.8315e+02 8.7663e+02 2.6984e-07 0.0000e+00 1.0000e+00 8.7663e+02 8.7663e+02 4.4776e+01 4.4776e+01 1.5770e-05 1.5770e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1960e+00 3.9808e+06 5.8315e+02 8.8601e+02 2.6724e-07 0.0000e+00 1.0000e+00 8.8601e+02 8.8601e+02 4.5255e+01 4.5255e+01 1.5785e-05 1.5785e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1980e+00 4.0204e+06 5.8315e+02 8.9539e+02 2.6469e-07 0.0000e+00 1.0000e+00 8.9539e+02 8.9539e+02 4.5734e+01 4.5734e+01 1.5800e-05 1.5800e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2000e+00 4.0600e+06 5.8315e+02 9.0478e+02 2.6219e-07 0.0000e+00 1.0000e+00 9.0478e+02 9.0478e+02 4.6214e+01 4.6214e+01 1.5816e-05 1.5816e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2020e+00 4.0996e+06 5.8315e+02 9.1417e+02 2.5974e-07 0.0000e+00 1.0000e+00 9.1417e+02 9.1417e+02 4.6694e+01 4.6694e+01 1.5831e-05 1.5831e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2040e+00 4.1392e+06 5.8315e+02 9.2358e+02 2.5733e-07 0.0000e+00 1.0000e+00 9.2358e+02 9.2358e+02 4.7174e+01 4.7174e+01 1.5846e-05 1.5846e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2060e+00 4.1788e+06 5.8315e+02 9.3300e+02 2.5496e-07 0.0000e+00 1.0000e+00 9.3300e+02 9.3300e+02 4.7655e+01 4.7655e+01 1.5862e-05 1.5862e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2080e+00 4.2184e+06 5.8315e+02 9.4242e+02 2.5264e-07 0.0000e+00 1.0000e+00 9.4242e+02 9.4242e+02 4.8136e+01 4.8136e+01 1.5877e-05 1.5877e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2100e+00 4.2580e+06 5.8315e+02 9.5185e+02 2.5036e-07 0.0000e+00 1.0000e+00 9.5185e+02 9.5185e+02 4.8618e+01 4.8618e+01 1.5893e-05 1.5893e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2120e+00 4.2976e+06 5.8315e+02 9.6130e+02 2.4812e-07 0.0000e+00 1.0000e+00 9.6130e+02 9.6130e+02 4.9100e+01 4.9100e+01 1.5909e-05 1.5909e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2140e+00 4.3372e+06 5.8315e+02 9.7074e+02 2.4592e-07 0.0000e+00 1.0000e+00 9.7074e+02 9.7074e+02 4.9583e+01 4.9583e+01 1.5925e-05 1.5925e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2160e+00 4.3768e+06 5.8315e+02 9.8020e+02 2.4376e-07 0.0000e+00 1.0000e+00 9.8020e+02 9.8020e+02 5.0066e+01 5.0066e+01 1.5941e-05 1.5941e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2180e+00 4.4164e+06 5.8315e+02 9.8967e+02 2.4163e-07 0.0000e+00 1.0000e+00 9.8967e+02 9.8967e+02 5.0550e+01 5.0550e+01 1.5957e-05 1.5957e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2200e+00 4.4560e+06 5.8315e+02 9.9914e+02 2.3954e-07 0.0000e+00 1.0000e+00 9.9914e+02 9.9914e+02 5.1033e+01 5.1033e+01 1.5973e-05 1.5973e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2220e+00 4.4956e+06 5.8315e+02 1.0086e+03 2.3749e-07 0.0000e+00 1.0000e+00 1.0086e+03 1.0086e+03 5.1518e+01 5.1518e+01 1.5990e-05 1.5990e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2240e+00 4.5352e+06 5.8315e+02 1.0181e+03 2.3546e-07 0.0000e+00 1.0000e+00 1.0181e+03 1.0181e+03 5.2002e+01 5.2002e+01 1.6006e-05 1.6006e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2260e+00 4.5748e+06 5.8315e+02 1.0276e+03 2.3348e-07 0.0000e+00 1.0000e+00 1.0276e+03 1.0276e+03 5.2488e+01 5.2488e+01 1.6023e-05 1.6023e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2280e+00 4.6144e+06 5.8315e+02 1.0371e+03 2.3152e-07 0.0000e+00 1.0000e+00 1.0371e+03 1.0371e+03 5.2973e+01 5.2973e+01 1.6039e-05 1.6039e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2300e+00 4.6540e+06 5.8315e+02 1.0466e+03 2.2960e-07 0.0000e+00 1.0000e+00 1.0466e+03 1.0466e+03 5.3459e+01 5.3459e+01 1.6056e-05 1.6056e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2320e+00 4.6936e+06 5.8315e+02 1.0561e+03 2.2771e-07 0.0000e+00 1.0000e+00 1.0561e+03 1.0561e+03 5.3945e+01 5.3945e+01 1.6073e-05 1.6073e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2340e+00 4.7332e+06 5.8315e+02 1.0657e+03 2.2584e-07 0.0000e+00 1.0000e+00 1.0657e+03 1.0657e+03 5.4432e+01 5.4432e+01 1.6090e-05 1.6090e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2360e+00 4.7728e+06 5.8315e+02 1.0752e+03 2.2401e-07 0.0000e+00 1.0000e+00 1.0752e+03 1.0752e+03 5.4919e+01 5.4919e+01 1.6107e-05 1.6107e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2380e+00 4.8124e+06 5.8315e+02 1.0847e+03 2.2221e-07 0.0000e+00 1.0000e+00 1.0847e+03 1.0847e+03 5.5406e+01 5.5406e+01 1.6125e-05 1.6125e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2400e+00 4.8520e+06 5.8315e+02 1.0943e+03 2.2043e-07 0.0000e+00 1.0000e+00 1.0943e+03 1.0943e+03 5.5894e+01 5.5894e+01 1.6142e-05 1.6142e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2420e+00 4.8916e+06 5.8315e+02 1.1039e+03 2.1868e-07 0.0000e+00 1.0000e+00 1.1039e+03 1.1039e+03 5.6382e+01 5.6382e+01 1.6159e-05 1.6159e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2440e+00 4.9312e+06 5.8315e+02 1.1134e+03 2.1696e-07 0.0000e+00 1.0000e+00 1.1134e+03 1.1134e+03 5.6870e+01 5.6870e+01 1.6177e-05 1.6177e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2460e+00 4.9708e+06 5.8315e+02 1.1230e+03 2.1526e-07 0.0000e+00 1.0000e+00 1.1230e+03 1.1230e+03 5.7359e+01 5.7359e+01 1.6195e-05 1.6195e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2480e+00 5.0104e+06 5.8315e+02 1.1326e+03 2.1359e-07 0.0000e+00 1.0000e+00 1.1326e+03 1.1326e+03 5.7848e+01 5.7848e+01 1.6212e-05 1.6212e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2500e+00 5.0500e+06 5.8315e+02 1.1421e+03 2.1194e-07 0.0000e+00 1.0000e+00 1.1421e+03 1.1421e+03 5.8338e+01 5.8338e+01 1.6230e-05 1.6230e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2520e+00 5.0896e+06 5.8315e+02 1.1517e+03 2.1032e-07 0.0000e+00 1.0000e+00 1.1517e+03 1.1517e+03 5.8827e+01 5.8827e+01 1.6248e-05 1.6248e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2540e+00 5.1292e+06 5.8315e+02 1.1613e+03 2.0872e-07 0.0000e+00 1.0000e+00 1.1613e+03 1.1613e+03 5.9318e+01 5.9318e+01 1.6267e-05 1.6267e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2560e+00 5.1688e+06 5.8315e+02 1.1709e+03 2.0714e-07 0.0000e+00 1.0000e+00 1.1709e+03 1.1709e+03 5.9808e+01 5.9808e+01 1.6285e-05 1.6285e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2580e+00 5.2084e+06 5.8315e+02 1.1805e+03 2.0559e-07 0.0000e+00 1.0000e+00 1.1805e+03 1.1805e+03 6.0299e+01 6.0299e+01 1.6303e-05 1.6303e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2600e+00 5.2480e+06 5.8315e+02 1.1902e+03 2.0406e-07 0.0000e+00 1.0000e+00 1.1902e+03 1.1902e+03 6.0790e+01 6.0790e+01 1.6322e-05 1.6322e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2620e+00 5.2876e+06 5.8315e+02 1.1998e+03 2.0255e-07 0.0000e+00 1.0000e+00 1.1998e+03 1.1998e+03 6.1281e+01 6.1281e+01 1.6340e-05 1.6340e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2640e+00 5.3272e+06 5.8315e+02 1.2094e+03 2.0106e-07 0.0000e+00 1.0000e+00 1.2094e+03 1.2094e+03 6.1773e+01 6.1773e+01 1.6359e-05 1.6359e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2660e+00 5.3668e+06 5.8315e+02 1.2190e+03 1.9959e-07 0.0000e+00 1.0000e+00 1.2190e+03 1.2190e+03 6.2265e+01 6.2265e+01 1.6378e-05 1.6378e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2680e+00 5.4064e+06 5.8315e+02 1.2287e+03 1.9814e-07 0.0000e+00 1.0000e+00 1.2287e+03 1.2287e+03 6.2757e+01 6.2757e+01 1.6397e-05 1.6397e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2700e+00 5.4460e+06 5.8315e+02 1.2383e+03 1.9671e-07 0.0000e+00 1.0000e+00 1.2383e+03 1.2383e+03 6.3250e+01 6.3250e+01 1.6416e-05 1.6416e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2720e+00 5.4856e+06 5.8315e+02 1.2480e+03 1.9530e-07 0.0000e+00 1.0000e+00 1.2480e+03 1.2480e+03 6.3743e+01 6.3743e+01 1.6435e-05 1.6435e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2740e+00 5.5252e+06 5.8315e+02 1.2576e+03 1.9391e-07 0.0000e+00 1.0000e+00 1.2576e+03 1.2576e+03 6.4236e+01 6.4236e+01 1.6454e-05 1.6454e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2760e+00 5.5648e+06 5.8315e+02 1.2673e+03 1.9253e-07 0.0000e+00 1.0000e+00 1.2673e+03 1.2673e+03 6.4729e+01 6.4729e+01 1.6474e-05 1.6474e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2780e+00 5.6044e+06 5.8315e+02 1.2769e+03 1.9118e-07 0.0000e+00 1.0000e+00 1.2769e+03 1.2769e+03 6.5223e+01 6.5223e+01 1.6493e-05 1.6493e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2800e+00 5.6440e+06 5.8315e+02 1.2866e+03 1.8984e-07 0.0000e+00 1.0000e+00 1.2866e+03 1.2866e+03 6.5717e+01 6.5717e+01 1.6513e-05 1.6513e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2820e+00 5.6836e+06 5.8315e+02 1.2963e+03 1.8852e-07 0.0000e+00 1.0000e+00 1.2963e+03 1.2963e+03 6.6211e+01 6.6211e+01 1.6533e-05 1.6533e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2840e+00 5.7232e+06 5.8315e+02 1.3060e+03 1.8721e-07 0.0000e+00 1.0000e+00 1.3060e+03 1.3060e+03 6.6705e+01 6.6705e+01 1.6553e-05 1.6553e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2860e+00 5.7628e+06 5.8315e+02 1.3156e+03 1.8593e-07 0.0000e+00 1.0000e+00 1.3156e+03 1.3156e+03 6.7200e+01 6.7200e+01 1.6572e-05 1.6572e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2880e+00 5.8024e+06 5.8315e+02 1.3253e+03 1.8466e-07 0.0000e+00 1.0000e+00 1.3253e+03 1.3253e+03 6.7695e+01 6.7695e+01 1.6593e-05 1.6593e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2900e+00 5.8420e+06 5.8315e+02 1.3350e+03 1.8340e-07 0.0000e+00 1.0000e+00 1.3350e+03 1.3350e+03 6.8190e+01 6.8190e+01 1.6613e-05 1.6613e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2920e+00 5.8816e+06 5.8315e+02 1.3447e+03 1.8216e-07 0.0000e+00 1.0000e+00 1.3447e+03 1.3447e+03 6.8685e+01 6.8685e+01 1.6633e-05 1.6633e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2940e+00 5.9212e+06 5.8315e+02 1.3544e+03 1.8094e-07 0.0000e+00 1.0000e+00 1.3544e+03 1.3544e+03 6.9181e+01 6.9181e+01 1.6654e-05 1.6654e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2960e+00 5.9608e+06 5.8315e+02 1.3641e+03 1.7973e-07 0.0000e+00 1.0000e+00 1.3641e+03 1.3641e+03 6.9677e+01 6.9677e+01 1.6674e-05 1.6674e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2980e+00 6.0004e+06 5.8315e+02 1.3738e+03 1.7853e-07 0.0000e+00 1.0000e+00 1.3738e+03 1.3738e+03 7.0173e+01 7.0173e+01 1.6695e-05 1.6695e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3000e+00 6.0400e+06 5.8315e+02 1.3836e+03 1.7735e-07 0.0000e+00 1.0000e+00 1.3836e+03 1.3836e+03 7.0669e+01 7.0669e+01 1.6716e-05 1.6716e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3020e+00 6.0796e+06 5.8315e+02 1.3933e+03 1.7619e-07 0.0000e+00 1.0000e+00 1.3933e+03 1.3933e+03 7.1165e+01 7.1165e+01 1.6736e-05 1.6736e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3040e+00 6.1192e+06 5.8315e+02 1.4030e+03 1.7503e-07 0.0000e+00 1.0000e+00 1.4030e+03 1.4030e+03 7.1662e+01 7.1662e+01 1.6757e-05 1.6757e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3060e+00 6.1588e+06 5.8315e+02 1.4127e+03 1.7389e-07 0.0000e+00 1.0000e+00 1.4127e+03 1.4127e+03 7.2159e+01 7.2159e+01 1.6779e-05 1.6779e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3080e+00 6.1984e+06 5.8315e+02 1.4225e+03 1.7277e-07 0.0000e+00 1.0000e+00 1.4225e+03 1.4225e+03 7.2656e+01 7.2656e+01 1.6800e-05 1.6800e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3100e+00 6.2380e+06 5.8315e+02 1.4322e+03 1.7165e-07 0.0000e+00 1.0000e+00 1.4322e+03 1.4322e+03 7.3153e+01 7.3153e+01 1.6821e-05 1.6821e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3120e+00 6.2776e+06 5.8315e+02 1.4419e+03 1.7055e-07 0.0000e+00 1.0000e+00 1.4419e+03 1.4419e+03 7.3650e+01 7.3650e+01 1.6843e-05 1.6843e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3140e+00 6.3172e+06 5.8315e+02 1.4517e+03 1.6947e-07 0.0000e+00 1.0000e+00 1.4517e+03 1.4517e+03 7.4148e+01 7.4148e+01 1.6864e-05 1.6864e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3160e+00 6.3568e+06 5.8315e+02 1.4614e+03 1.6839e-07 0.0000e+00 1.0000e+00 1.4614e+03 1.4614e+03 7.4645e+01 7.4645e+01 1.6886e-05 1.6886e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3180e+00 6.3964e+06 5.8315e+02 1.4712e+03 1.6733e-07 0.0000e+00 1.0000e+00 1.4712e+03 1.4712e+03 7.5143e+01 7.5143e+01 1.6908e-05 1.6908e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3200e+00 6.4360e+06 5.8315e+02 1.4809e+03 1.6627e-07 0.0000e+00 1.0000e+00 1.4809e+03 1.4809e+03 7.5641e+01 7.5641e+01 1.6930e-05 1.6930e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3220e+00 6.4756e+06 5.8315e+02 1.4907e+03 1.6523e-07 0.0000e+00 1.0000e+00 1.4907e+03 1.4907e+03 7.6139e+01 7.6139e+01 1.6952e-05 1.6952e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3240e+00 6.5152e+06 5.8315e+02 1.5004e+03 1.6421e-07 0.0000e+00 1.0000e+00 1.5004e+03 1.5004e+03 7.6637e+01 7.6637e+01 1.6974e-05 1.6974e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3260e+00 6.5548e+06 5.8315e+02 1.5102e+03 1.6319e-07 0.0000e+00 1.0000e+00 1.5102e+03 1.5102e+03 7.7136e+01 7.7136e+01 1.6996e-05 1.6996e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3280e+00 6.5944e+06 5.8315e+02 1.5199e+03 1.6218e-07 0.0000e+00 1.0000e+00 1.5199e+03 1.5199e+03 7.7634e+01 7.7634e+01 1.7019e-05 1.7019e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3300e+00 6.6340e+06 5.8315e+02 1.5297e+03 1.6119e-07 0.0000e+00 1.0000e+00 1.5297e+03 1.5297e+03 7.8133e+01 7.8133e+01 1.7041e-05 1.7041e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3320e+00 6.6736e+06 5.8315e+02 1.5395e+03 1.6020e-07 0.0000e+00 1.0000e+00 1.5395e+03 1.5395e+03 7.8632e+01 7.8632e+01 1.7064e-05 1.7064e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3340e+00 6.7132e+06 5.8315e+02 1.5492e+03 1.5923e-07 0.0000e+00 1.0000e+00 1.5492e+03 1.5492e+03 7.9131e+01 7.9131e+01 1.7087e-05 1.7087e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3360e+00 6.7528e+06 5.8315e+02 1.5590e+03 1.5826e-07 0.0000e+00 1.0000e+00 1.5590e+03 1.5590e+03 7.9630e+01 7.9630e+01 1.7110e-05 1.7110e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3380e+00 6.7924e+06 5.8315e+02 1.5688e+03 1.5731e-07 0.0000e+00 1.0000e+00 1.5688e+03 1.5688e+03 8.0129e+01 8.0129e+01 1.7133e-05 1.7133e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3400e+00 6.8320e+06 5.8315e+02 1.5785e+03 1.5636e-07 0.0000e+00 1.0000e+00 1.5785e+03 1.5785e+03 8.0628e+01 8.0628e+01 1.7156e-05 1.7156e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3420e+00 6.8716e+06 5.8315e+02 1.5883e+03 1.5543e-07 0.0000e+00 1.0000e+00 1.5883e+03 1.5883e+03 8.1127e+01 8.1127e+01 1.7179e-05 1.7179e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3440e+00 6.9112e+06 5.8315e+02 1.5981e+03 1.5450e-07 0.0000e+00 1.0000e+00 1.5981e+03 1.5981e+03 8.1627e+01 8.1627e+01 1.7202e-05 1.7202e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3460e+00 6.9508e+06 5.8315e+02 1.6079e+03 1.5359e-07 0.0000e+00 1.0000e+00 1.6079e+03 1.6079e+03 8.2126e+01 8.2126e+01 1.7226e-05 1.7226e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3480e+00 6.9904e+06 5.8315e+02 1.6177e+03 1.5268e-07 0.0000e+00 1.0000e+00 1.6177e+03 1.6177e+03 8.2626e+01 8.2626e+01 1.7249e-05 1.7249e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3500e+00 7.0300e+06 5.8315e+02 1.6274e+03 1.5178e-07 0.0000e+00 1.0000e+00 1.6274e+03 1.6274e+03 8.3125e+01 8.3125e+01 1.7273e-05 1.7273e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3520e+00 7.0696e+06 5.8315e+02 1.6372e+03 1.5089e-07 0.0000e+00 1.0000e+00 1.6372e+03 1.6372e+03 8.3625e+01 8.3625e+01 1.7297e-05 1.7297e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3540e+00 7.1092e+06 5.8315e+02 1.6470e+03 1.5001e-07 0.0000e+00 1.0000e+00 1.6470e+03 1.6470e+03 8.4125e+01 8.4125e+01 1.7321e-05 1.7321e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3560e+00 7.1488e+06 5.8315e+02 1.6568e+03 1.4914e-07 0.0000e+00 1.0000e+00 1.6568e+03 1.6568e+03 8.4624e+01 8.4624e+01 1.7345e-05 1.7345e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3580e+00 7.1884e+06 5.8315e+02 1.6666e+03 1.4828e-07 0.0000e+00 1.0000e+00 1.6666e+03 1.6666e+03 8.5124e+01 8.5124e+01 1.7369e-05 1.7369e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3600e+00 7.2280e+06 5.8315e+02 1.6764e+03 1.4743e-07 0.0000e+00 1.0000e+00 1.6764e+03 1.6764e+03 8.5624e+01 8.5624e+01 1.7393e-05 1.7393e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3620e+00 7.2676e+06 5.8315e+02 1.6862e+03 1.4658e-07 0.0000e+00 1.0000e+00 1.6862e+03 1.6862e+03 8.6124e+01 8.6124e+01 1.7417e-05 1.7417e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3640e+00 7.3072e+06 5.8315e+02 1.6959e+03 1.4574e-07 0.0000e+00 1.0000e+00 1.6959e+03 1.6959e+03 8.6624e+01 8.6624e+01 1.7442e-05 1.7442e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3660e+00 7.3468e+06 5.8315e+02 1.7057e+03 1.4491e-07 0.0000e+00 1.0000e+00 1.7057e+03 1.7057e+03 8.7124e+01 8.7124e+01 1.7467e-05 1.7467e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3680e+00 7.3864e+06 5.8315e+02 1.7155e+03 1.4409e-07 0.0000e+00 1.0000e+00 1.7155e+03 1.7155e+03 8.7624e+01 8.7624e+01 1.7491e-05 1.7491e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3700e+00 7.4260e+06 5.8315e+02 1.7253e+03 1.4328e-07 0.0000e+00 1.0000e+00 1.7253e+03 1.7253e+03 8.8124e+01 8.8124e+01 1.7516e-05 1.7516e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3720e+00 7.4656e+06 5.8315e+02 1.7351e+03 1.4247e-07 0.0000e+00 1.0000e+00 1.7351e+03 1.7351e+03 8.8624e+01 8.8624e+01 1.7541e-05 1.7541e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3740e+00 7.5052e+06 5.8315e+02 1.7449e+03 1.4167e-07 0.0000e+00 1.0000e+00 1.7449e+03 1.7449e+03 8.9124e+01 8.9124e+01 1.7566e-05 1.7566e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3760e+00 7.5448e+06 5.8315e+02 1.7547e+03 1.4088e-07 0.0000e+00 1.0000e+00 1.7547e+03 1.7547e+03 8.9624e+01 8.9624e+01 1.7591e-05 1.7591e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3780e+00 7.5844e+06 5.8315e+02 1.7645e+03 1.4009e-07 0.0000e+00 1.0000e+00 1.7645e+03 1.7645e+03 9.0124e+01 9.0124e+01 1.7617e-05 1.7617e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3800e+00 7.6240e+06 5.8315e+02 1.7742e+03 1.3931e-07 0.0000e+00 1.0000e+00 1.7742e+03 1.7742e+03 9.0624e+01 9.0624e+01 1.7642e-05 1.7642e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3820e+00 7.6636e+06 5.8315e+02 1.7840e+03 1.3854e-07 0.0000e+00 1.0000e+00 1.7840e+03 1.7840e+03 9.1124e+01 9.1124e+01 1.7668e-05 1.7668e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3840e+00 7.7032e+06 5.8315e+02 1.7938e+03 1.3778e-07 0.0000e+00 1.0000e+00 1.7938e+03 1.7938e+03 9.1624e+01 9.1624e+01 1.7693e-05 1.7693e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3860e+00 7.7428e+06 5.8315e+02 1.8036e+03 1.3702e-07 0.0000e+00 1.0000e+00 1.8036e+03 1.8036e+03 9.2124e+01 9.2124e+01 1.7719e-05 1.7719e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3880e+00 7.7824e+06 5.8315e+02 1.8134e+03 1.3627e-07 0.0000e+00 1.0000e+00 1.8134e+03 1.8134e+03 9.2623e+01 9.2623e+01 1.7745e-05 1.7745e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3900e+00 7.8220e+06 5.8315e+02 1.8232e+03 1.3553e-07 0.0000e+00 1.0000e+00 1.8232e+03 1.8232e+03 9.3123e+01 9.3123e+01 1.7771e-05 1.7771e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3920e+00 7.8616e+06 5.8315e+02 1.8330e+03 1.3479e-07 0.0000e+00 1.0000e+00 1.8330e+03 1.8330e+03 9.3623e+01 9.3623e+01 1.7797e-05 1.7797e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3940e+00 7.9012e+06 5.8315e+02 1.8427e+03 1.3406e-07 0.0000e+00 1.0000e+00 1.8427e+03 1.8427e+03 9.4123e+01 9.4123e+01 1.7823e-05 1.7823e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3960e+00 7.9408e+06 5.8315e+02 1.8525e+03 1.3334e-07 0.0000e+00 1.0000e+00 1.8525e+03 1.8525e+03 9.4622e+01 9.4622e+01 1.7850e-05 1.7850e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3980e+00 7.9804e+06 5.8315e+02 1.8623e+03 1.3262e-07 0.0000e+00 1.0000e+00 1.8623e+03 1.8623e+03 9.5122e+01 9.5122e+01 1.7876e-05 1.7876e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4000e+00 8.0200e+06 5.8315e+02 1.8721e+03 1.3191e-07 0.0000e+00 1.0000e+00 1.8721e+03 1.8721e+03 9.5621e+01 9.5621e+01 1.7902e-05 1.7902e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4020e+00 8.0596e+06 5.8315e+02 1.8819e+03 1.3120e-07 0.0000e+00 1.0000e+00 1.8819e+03 1.8819e+03 9.6121e+01 9.6121e+01 1.7929e-05 1.7929e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4040e+00 8.0992e+06 5.8315e+02 1.8916e+03 1.3050e-07 0.0000e+00 1.0000e+00 1.8916e+03 1.8916e+03 9.6620e+01 9.6620e+01 1.7956e-05 1.7956e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4060e+00 8.1388e+06 5.8315e+02 1.9014e+03 1.2981e-07 0.0000e+00 1.0000e+00 1.9014e+03 1.9014e+03 9.7120e+01 9.7120e+01 1.7983e-05 1.7983e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4080e+00 8.1784e+06 5.8315e+02 1.9112e+03 1.2912e-07 0.0000e+00 1.0000e+00 1.9112e+03 1.9112e+03 9.7619e+01 9.7619e+01 1.8010e-05 1.8010e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4100e+00 8.2180e+06 5.8315e+02 1.9210e+03 1.2844e-07 0.0000e+00 1.0000e+00 1.9210e+03 1.9210e+03 9.8118e+01 9.8118e+01 1.8037e-05 1.8037e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4120e+00 8.2576e+06 5.8315e+02 1.9307e+03 1.2776e-07 0.0000e+00 1.0000e+00 1.9307e+03 1.9307e+03 9.8617e+01 9.8617e+01 1.8064e-05 1.8064e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4140e+00 8.2972e+06 5.8315e+02 1.9405e+03 1.2709e-07 0.0000e+00 1.0000e+00 1.9405e+03 1.9405e+03 9.9116e+01 9.9116e+01 1.8091e-05 1.8091e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4160e+00 8.3368e+06 5.8315e+02 1.9503e+03 1.2643e-07 0.0000e+00 1.0000e+00 1.9503e+03 1.9503e+03 9.9615e+01 9.9615e+01 1.8119e-05 1.8119e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4180e+00 8.3764e+06 5.8315e+02 1.9600e+03 1.2577e-07 0.0000e+00 1.0000e+00 1.9600e+03 1.9600e+03 1.0011e+02 1.0011e+02 1.8146e-05 1.8146e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4200e+00 8.4160e+06 5.8315e+02 1.9698e+03 1.2511e-07 0.0000e+00 1.0000e+00 1.9698e+03 1.9698e+03 1.0061e+02 1.0061e+02 1.8174e-05 1.8174e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4220e+00 8.4556e+06 5.8315e+02 1.9795e+03 1.2446e-07 0.0000e+00 1.0000e+00 1.9795e+03 1.9795e+03 1.0111e+02 1.0111e+02 1.8202e-05 1.8202e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4240e+00 8.4952e+06 5.8315e+02 1.9893e+03 1.2382e-07 0.0000e+00 1.0000e+00 1.9893e+03 1.9893e+03 1.0161e+02 1.0161e+02 1.8230e-05 1.8230e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4260e+00 8.5348e+06 5.8315e+02 1.9991e+03 1.2318e-07 0.0000e+00 1.0000e+00 1.9991e+03 1.9991e+03 1.0211e+02 1.0211e+02 1.8258e-05 1.8258e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4280e+00 8.5744e+06 5.8315e+02 2.0088e+03 1.2255e-07 0.0000e+00 1.0000e+00 2.0088e+03 2.0088e+03 1.0260e+02 1.0260e+02 1.8286e-05 1.8286e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4300e+00 8.6140e+06 5.8315e+02 2.0186e+03 1.2192e-07 0.0000e+00 1.0000e+00 2.0186e+03 2.0186e+03 1.0310e+02 1.0310e+02 1.8314e-05 1.8314e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4320e+00 8.6536e+06 5.8315e+02 2.0283e+03 1.2129e-07 0.0000e+00 1.0000e+00 2.0283e+03 2.0283e+03 1.0360e+02 1.0360e+02 1.8342e-05 1.8342e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4340e+00 8.6932e+06 5.8315e+02 2.0380e+03 1.2067e-07 0.0000e+00 1.0000e+00 2.0380e+03 2.0380e+03 1.0410e+02 1.0410e+02 1.8371e-05 1.8371e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4360e+00 8.7328e+06 5.8315e+02 2.0478e+03 1.2006e-07 0.0000e+00 1.0000e+00 2.0478e+03 2.0478e+03 1.0459e+02 1.0459e+02 1.8399e-05 1.8399e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4380e+00 8.7724e+06 5.8315e+02 2.0575e+03 1.1945e-07 0.0000e+00 1.0000e+00 2.0575e+03 2.0575e+03 1.0509e+02 1.0509e+02 1.8428e-05 1.8428e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4400e+00 8.8120e+06 5.8315e+02 2.0672e+03 1.1885e-07 0.0000e+00 1.0000e+00 2.0672e+03 2.0672e+03 1.0559e+02 1.0559e+02 1.8457e-05 1.8457e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4420e+00 8.8516e+06 5.8315e+02 2.0770e+03 1.1825e-07 0.0000e+00 1.0000e+00 2.0770e+03 2.0770e+03 1.0609e+02 1.0609e+02 1.8486e-05 1.8486e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4440e+00 8.8912e+06 5.8315e+02 2.0867e+03 1.1765e-07 0.0000e+00 1.0000e+00 2.0867e+03 2.0867e+03 1.0658e+02 1.0658e+02 1.8514e-05 1.8514e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4460e+00 8.9308e+06 5.8315e+02 2.0964e+03 1.1706e-07 0.0000e+00 1.0000e+00 2.0964e+03 2.0964e+03 1.0708e+02 1.0708e+02 1.8544e-05 1.8544e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4480e+00 8.9704e+06 5.8315e+02 2.1061e+03 1.1647e-07 0.0000e+00 1.0000e+00 2.1061e+03 2.1061e+03 1.0758e+02 1.0758e+02 1.8573e-05 1.8573e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4500e+00 9.0100e+06 5.8315e+02 2.1158e+03 1.1589e-07 0.0000e+00 1.0000e+00 2.1158e+03 2.1158e+03 1.0807e+02 1.0807e+02 1.8602e-05 1.8602e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4520e+00 9.0496e+06 5.8315e+02 2.1255e+03 1.1531e-07 0.0000e+00 1.0000e+00 2.1255e+03 2.1255e+03 1.0857e+02 1.0857e+02 1.8631e-05 1.8631e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4540e+00 9.0892e+06 5.8315e+02 2.1353e+03 1.1474e-07 0.0000e+00 1.0000e+00 2.1353e+03 2.1353e+03 1.0906e+02 1.0906e+02 1.8661e-05 1.8661e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4560e+00 9.1288e+06 5.8315e+02 2.1450e+03 1.1417e-07 0.0000e+00 1.0000e+00 2.1450e+03 2.1450e+03 1.0956e+02 1.0956e+02 1.8690e-05 1.8690e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4580e+00 9.1684e+06 5.8315e+02 2.1546e+03 1.1361e-07 0.0000e+00 1.0000e+00 2.1546e+03 2.1546e+03 1.1005e+02 1.1005e+02 1.8720e-05 1.8720e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4600e+00 9.2080e+06 5.8315e+02 2.1643e+03 1.1305e-07 0.0000e+00 1.0000e+00 2.1643e+03 2.1643e+03 1.1055e+02 1.1055e+02 1.8750e-05 1.8750e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4620e+00 9.2476e+06 5.8315e+02 2.1740e+03 1.1249e-07 0.0000e+00 1.0000e+00 2.1740e+03 2.1740e+03 1.1104e+02 1.1104e+02 1.8780e-05 1.8780e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4640e+00 9.2872e+06 5.8315e+02 2.1837e+03 1.1194e-07 0.0000e+00 1.0000e+00 2.1837e+03 2.1837e+03 1.1154e+02 1.1154e+02 1.8810e-05 1.8810e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4660e+00 9.3268e+06 5.8315e+02 2.1934e+03 1.1139e-07 0.0000e+00 1.0000e+00 2.1934e+03 2.1934e+03 1.1203e+02 1.1203e+02 1.8840e-05 1.8840e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4680e+00 9.3664e+06 5.8315e+02 2.2031e+03 1.1085e-07 0.0000e+00 1.0000e+00 2.2031e+03 2.2031e+03 1.1253e+02 1.1253e+02 1.8870e-05 1.8870e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4700e+00 9.4060e+06 5.8315e+02 2.2127e+03 1.1031e-07 0.0000e+00 1.0000e+00 2.2127e+03 2.2127e+03 1.1302e+02 1.1302e+02 1.8900e-05 1.8900e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4720e+00 9.4456e+06 5.8315e+02 2.2224e+03 1.0977e-07 0.0000e+00 1.0000e+00 2.2224e+03 2.2224e+03 1.1351e+02 1.1351e+02 1.8931e-05 1.8931e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4740e+00 9.4852e+06 5.8315e+02 2.2320e+03 1.0924e-07 0.0000e+00 1.0000e+00 2.2320e+03 2.2320e+03 1.1401e+02 1.1401e+02 1.8961e-05 1.8961e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4760e+00 9.5248e+06 5.8315e+02 2.2417e+03 1.0871e-07 0.0000e+00 1.0000e+00 2.2417e+03 2.2417e+03 1.1450e+02 1.1450e+02 1.8992e-05 1.8992e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4780e+00 9.5644e+06 5.8315e+02 2.2513e+03 1.0818e-07 0.0000e+00 1.0000e+00 2.2513e+03 2.2513e+03 1.1499e+02 1.1499e+02 1.9023e-05 1.9023e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4800e+00 9.6040e+06 5.8315e+02 2.2610e+03 1.0766e-07 0.0000e+00 1.0000e+00 2.2610e+03 2.2610e+03 1.1549e+02 1.1549e+02 1.9053e-05 1.9053e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4820e+00 9.6436e+06 5.8315e+02 2.2706e+03 1.0714e-07 0.0000e+00 1.0000e+00 2.2706e+03 2.2706e+03 1.1598e+02 1.1598e+02 1.9084e-05 1.9084e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4840e+00 9.6832e+06 5.8315e+02 2.2803e+03 1.0663e-07 0.0000e+00 1.0000e+00 2.2803e+03 2.2803e+03 1.1647e+02 1.1647e+02 1.9115e-05 1.9115e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4860e+00 9.7228e+06 5.8315e+02 2.2899e+03 1.0612e-07 0.0000e+00 1.0000e+00 2.2899e+03 2.2899e+03 1.1696e+02 1.1696e+02 1.9147e-05 1.9147e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4880e+00 9.7624e+06 5.8315e+02 2.2995e+03 1.0561e-07 0.0000e+00 1.0000e+00 2.2995e+03 2.2995e+03 1.1745e+02 1.1745e+02 1.9178e-05 1.9178e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4900e+00 9.8020e+06 5.8315e+02 2.3091e+03 1.0511e-07 0.0000e+00 1.0000e+00 2.3091e+03 2.3091e+03 1.1794e+02 1.1794e+02 1.9209e-05 1.9209e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4920e+00 9.8416e+06 5.8315e+02 2.3187e+03 1.0461e-07 0.0000e+00 1.0000e+00 2.3187e+03 2.3187e+03 1.1843e+02 1.1843e+02 1.9240e-05 1.9240e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4940e+00 9.8812e+06 5.8315e+02 2.3283e+03 1.0411e-07 0.0000e+00 1.0000e+00 2.3283e+03 2.3283e+03 1.1892e+02 1.1892e+02 1.9272e-05 1.9272e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4960e+00 9.9208e+06 5.8315e+02 2.3379e+03 1.0362e-07 0.0000e+00 1.0000e+00 2.3379e+03 2.3379e+03 1.1941e+02 1.1941e+02 1.9304e-05 1.9304e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.4980e+00 9.9604e+06 5.8315e+02 2.3475e+03 1.0313e-07 0.0000e+00 1.0000e+00 2.3475e+03 2.3475e+03 1.1990e+02 1.1990e+02 1.9335e-05 1.9335e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5000e+00 1.0000e+07 5.8315e+02 2.3571e+03 1.0264e-07 0.0000e+00 1.0000e+00 2.3571e+03 2.3571e+03 1.2039e+02 1.2039e+02 1.9367e-05 1.9367e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5020e+00 1.0100e+07 5.8315e+02 2.3813e+03 1.0143e-07 0.0000e+00 1.0000e+00 2.3813e+03 2.3813e+03 1.2163e+02 1.2163e+02 1.9448e-05 1.9448e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5040e+00 1.0200e+07 5.8315e+02 2.4054e+03 1.0024e-07 0.0000e+00 1.0000e+00 2.4054e+03 2.4054e+03 1.2286e+02 1.2286e+02 1.9529e-05 1.9529e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5060e+00 1.0300e+07 5.8315e+02 2.4295e+03 9.9067e-08 0.0000e+00 1.0000e+00 2.4295e+03 2.4295e+03 1.2409e+02 1.2409e+02 1.9611e-05 1.9611e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5080e+00 1.0400e+07 5.8315e+02 2.4535e+03 9.7914e-08 0.0000e+00 1.0000e+00 2.4535e+03 2.4535e+03 1.2532e+02 1.2532e+02 1.9693e-05 1.9693e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5100e+00 1.0500e+07 5.8315e+02 2.4775e+03 9.6780e-08 0.0000e+00 1.0000e+00 2.4775e+03 2.4775e+03 1.2655e+02 1.2655e+02 1.9776e-05 1.9776e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5120e+00 1.0600e+07 5.8315e+02 2.5015e+03 9.5665e-08 0.0000e+00 1.0000e+00 2.5015e+03 2.5015e+03 1.2777e+02 1.2777e+02 1.9860e-05 1.9860e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5140e+00 1.0700e+07 5.8315e+02 2.5254e+03 9.4567e-08 0.0000e+00 1.0000e+00 2.5254e+03 2.5254e+03 1.2899e+02 1.2899e+02 1.9944e-05 1.9944e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5160e+00 1.0800e+07 5.8315e+02 2.5493e+03 9.3488e-08 0.0000e+00 1.0000e+00 2.5493e+03 2.5493e+03 1.3021e+02 1.3021e+02 2.0029e-05 2.0029e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5180e+00 1.0900e+07 5.8315e+02 2.5731e+03 9.2426e-08 0.0000e+00 1.0000e+00 2.5731e+03 2.5731e+03 1.3143e+02 1.3143e+02 2.0114e-05 2.0114e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5200e+00 1.1000e+07 5.8315e+02 2.5968e+03 9.1381e-08 0.0000e+00 1.0000e+00 2.5968e+03 2.5968e+03 1.3264e+02 1.3264e+02 2.0200e-05 2.0200e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5220e+00 1.1100e+07 5.8315e+02 2.6205e+03 9.0352e-08 0.0000e+00 1.0000e+00 2.6205e+03 2.6205e+03 1.3385e+02 1.3385e+02 2.0286e-05 2.0286e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5240e+00 1.1200e+07 5.8315e+02 2.6442e+03 8.9340e-08 0.0000e+00 1.0000e+00 2.6442e+03 2.6442e+03 1.3506e+02 1.3506e+02 2.0373e-05 2.0373e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5260e+00 1.1300e+07 5.8315e+02 2.6678e+03 8.8343e-08 0.0000e+00 1.0000e+00 2.6678e+03 2.6678e+03 1.3626e+02 1.3626e+02 2.0460e-05 2.0460e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5280e+00 1.1400e+07 5.8315e+02 2.6913e+03 8.7362e-08 0.0000e+00 1.0000e+00 2.6913e+03 2.6913e+03 1.3747e+02 1.3747e+02 2.0548e-05 2.0548e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5300e+00 1.1500e+07 5.8315e+02 2.7148e+03 8.6396e-08 0.0000e+00 1.0000e+00 2.7148e+03 2.7148e+03 1.3866e+02 1.3866e+02 2.0636e-05 2.0636e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5320e+00 1.1600e+07 5.8315e+02 2.7382e+03 8.5444e-08 0.0000e+00 1.0000e+00 2.7382e+03 2.7382e+03 1.3986e+02 1.3986e+02 2.0725e-05 2.0725e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5340e+00 1.1700e+07 5.8315e+02 2.7616e+03 8.4507e-08 0.0000e+00 1.0000e+00 2.7616e+03 2.7616e+03 1.4105e+02 1.4105e+02 2.0814e-05 2.0814e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5360e+00 1.1800e+07 5.8315e+02 2.7849e+03 8.3585e-08 0.0000e+00 1.0000e+00 2.7849e+03 2.7849e+03 1.4225e+02 1.4225e+02 2.0904e-05 2.0904e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5380e+00 1.1900e+07 5.8315e+02 2.8081e+03 8.2676e-08 0.0000e+00 1.0000e+00 2.8081e+03 2.8081e+03 1.4343e+02 1.4343e+02 2.0994e-05 2.0994e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5400e+00 1.2000e+07 5.8315e+02 2.8313e+03 8.1781e-08 0.0000e+00 1.0000e+00 2.8313e+03 2.8313e+03 1.4462e+02 1.4462e+02 2.1085e-05 2.1085e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5420e+00 1.2100e+07 5.8315e+02 2.8545e+03 8.0899e-08 0.0000e+00 1.0000e+00 2.8545e+03 2.8545e+03 1.4580e+02 1.4580e+02 2.1176e-05 2.1176e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5440e+00 1.2200e+07 5.8315e+02 2.8775e+03 8.0030e-08 0.0000e+00 1.0000e+00 2.8775e+03 2.8775e+03 1.4698e+02 1.4698e+02 2.1267e-05 2.1267e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5460e+00 1.2300e+07 5.8315e+02 2.9005e+03 7.9174e-08 0.0000e+00 1.0000e+00 2.9005e+03 2.9005e+03 1.4815e+02 1.4815e+02 2.1359e-05 2.1359e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5480e+00 1.2400e+07 5.8315e+02 2.9234e+03 7.8331e-08 0.0000e+00 1.0000e+00 2.9234e+03 2.9234e+03 1.4932e+02 1.4932e+02 2.1452e-05 2.1452e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5500e+00 1.2500e+07 5.8315e+02 2.9463e+03 7.7500e-08 0.0000e+00 1.0000e+00 2.9463e+03 2.9463e+03 1.5049e+02 1.5049e+02 2.1544e-05 2.1544e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5520e+00 1.2600e+07 5.8315e+02 2.9691e+03 7.6681e-08 0.0000e+00 1.0000e+00 2.9691e+03 2.9691e+03 1.5165e+02 1.5165e+02 2.1637e-05 2.1637e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5540e+00 1.2700e+07 5.8315e+02 2.9918e+03 7.5874e-08 0.0000e+00 1.0000e+00 2.9918e+03 2.9918e+03 1.5282e+02 1.5282e+02 2.1731e-05 2.1731e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5560e+00 1.2800e+07 5.8315e+02 3.0145e+03 7.5078e-08 0.0000e+00 1.0000e+00 3.0145e+03 3.0145e+03 1.5397e+02 1.5397e+02 2.1825e-05 2.1825e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5580e+00 1.2900e+07 5.8315e+02 3.0371e+03 7.4294e-08 0.0000e+00 1.0000e+00 3.0371e+03 3.0371e+03 1.5513e+02 1.5513e+02 2.1919e-05 2.1919e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5600e+00 1.3000e+07 5.8315e+02 3.0596e+03 7.3522e-08 0.0000e+00 1.0000e+00 3.0596e+03 3.0596e+03 1.5628e+02 1.5628e+02 2.2013e-05 2.2013e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5620e+00 1.3100e+07 5.8315e+02 3.0821e+03 7.2760e-08 0.0000e+00 1.0000e+00 3.0821e+03 3.0821e+03 1.5743e+02 1.5743e+02 2.2108e-05 2.2108e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5640e+00 1.3200e+07 5.8315e+02 3.1045e+03 7.2009e-08 0.0000e+00 1.0000e+00 3.1045e+03 3.1045e+03 1.5857e+02 1.5857e+02 2.2204e-05 2.2204e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5660e+00 1.3300e+07 5.8315e+02 3.1268e+03 7.1268e-08 0.0000e+00 1.0000e+00 3.1268e+03 3.1268e+03 1.5971e+02 1.5971e+02 2.2299e-05 2.2299e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5680e+00 1.3400e+07 5.8315e+02 3.1491e+03 7.0538e-08 0.0000e+00 1.0000e+00 3.1491e+03 3.1491e+03 1.6085e+02 1.6085e+02 2.2395e-05 2.2395e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5700e+00 1.3500e+07 5.8315e+02 3.1712e+03 6.9819e-08 0.0000e+00 1.0000e+00 3.1712e+03 3.1712e+03 1.6198e+02 1.6198e+02 2.2491e-05 2.2491e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5720e+00 1.3600e+07 5.8315e+02 3.1933e+03 6.9109e-08 0.0000e+00 1.0000e+00 3.1933e+03 3.1933e+03 1.6311e+02 1.6311e+02 2.2588e-05 2.2588e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5740e+00 1.3700e+07 5.8315e+02 3.2154e+03 6.8409e-08 0.0000e+00 1.0000e+00 3.2154e+03 3.2154e+03 1.6423e+02 1.6423e+02 2.2684e-05 2.2684e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5760e+00 1.3800e+07 5.8315e+02 3.2373e+03 6.7719e-08 0.0000e+00 1.0000e+00 3.2373e+03 3.2373e+03 1.6535e+02 1.6535e+02 2.2781e-05 2.2781e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5780e+00 1.3900e+07 5.8315e+02 3.2592e+03 6.7038e-08 0.0000e+00 1.0000e+00 3.2592e+03 3.2592e+03 1.6647e+02 1.6647e+02 2.2879e-05 2.2879e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5800e+00 1.4000e+07 5.8315e+02 3.2810e+03 6.6367e-08 0.0000e+00 1.0000e+00 3.2810e+03 3.2810e+03 1.6759e+02 1.6759e+02 2.2976e-05 2.2976e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5820e+00 1.4100e+07 5.8315e+02 3.3028e+03 6.5705e-08 0.0000e+00 1.0000e+00 3.3028e+03 3.3028e+03 1.6870e+02 1.6870e+02 2.3074e-05 2.3074e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5840e+00 1.4200e+07 5.8315e+02 3.3244e+03 6.5052e-08 0.0000e+00 1.0000e+00 3.3244e+03 3.3244e+03 1.6980e+02 1.6980e+02 2.3172e-05 2.3172e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5860e+00 1.4300e+07 5.8315e+02 3.3460e+03 6.4408e-08 0.0000e+00 1.0000e+00 3.3460e+03 3.3460e+03 1.7091e+02 1.7091e+02 2.3271e-05 2.3271e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5880e+00 1.4400e+07 5.8315e+02 3.3675e+03 6.3773e-08 0.0000e+00 1.0000e+00 3.3675e+03 3.3675e+03 1.7200e+02 1.7200e+02 2.3369e-05 2.3369e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5900e+00 1.4500e+07 5.8315e+02 3.3890e+03 6.3147e-08 0.0000e+00 1.0000e+00 3.3890e+03 3.3890e+03 1.7310e+02 1.7310e+02 2.3468e-05 2.3468e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5920e+00 1.4600e+07 5.8315e+02 3.4103e+03 6.2528e-08 0.0000e+00 1.0000e+00 3.4103e+03 3.4103e+03 1.7419e+02 1.7419e+02 2.3567e-05 2.3567e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5940e+00 1.4700e+07 5.8315e+02 3.4316e+03 6.1919e-08 0.0000e+00 1.0000e+00 3.4316e+03 3.4316e+03 1.7528e+02 1.7528e+02 2.3666e-05 2.3666e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5960e+00 1.4800e+07 5.8315e+02 3.4528e+03 6.1317e-08 0.0000e+00 1.0000e+00 3.4528e+03 3.4528e+03 1.7636e+02 1.7636e+02 2.3765e-05 2.3765e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5980e+00 1.4900e+07 5.8315e+02 3.4740e+03 6.0724e-08 0.0000e+00 1.0000e+00 3.4740e+03 3.4740e+03 1.7744e+02 1.7744e+02 2.3865e-05 2.3865e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6000e+00 1.5000e+07 5.8315e+02 3.4950e+03 6.0138e-08 0.0000e+00 1.0000e+00 3.4950e+03 3.4950e+03 1.7852e+02 1.7852e+02 2.3964e-05 2.3964e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6020e+00 1.5100e+07 5.8315e+02 3.5160e+03 5.9560e-08 0.0000e+00 1.0000e+00 3.5160e+03 3.5160e+03 1.7959e+02 1.7959e+02 2.4064e-05 2.4064e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6040e+00 1.5200e+07 5.8315e+02 3.5369e+03 5.8990e-08 0.0000e+00 1.0000e+00 3.5369e+03 3.5369e+03 1.8066e+02 1.8066e+02 2.4164e-05 2.4164e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6060e+00 1.5300e+07 5.8315e+02 3.5577e+03 5.8428e-08 0.0000e+00 1.0000e+00 3.5577e+03 3.5577e+03 1.8172e+02 1.8172e+02 2.4265e-05 2.4265e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6080e+00 1.5400e+07 5.8315e+02 3.5785e+03 5.7872e-08 0.0000e+00 1.0000e+00 3.5785e+03 3.5785e+03 1.8278e+02 1.8278e+02 2.4365e-05 2.4365e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6100e+00 1.5500e+07 5.8315e+02 3.5991e+03 5.7325e-08 0.0000e+00 1.0000e+00 3.5991e+03 3.5991e+03 1.8383e+02 1.8383e+02 2.4465e-05 2.4465e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6120e+00 1.5600e+07 5.8315e+02 3.6197e+03 5.6784e-08 0.0000e+00 1.0000e+00 3.6197e+03 3.6197e+03 1.8489e+02 1.8489e+02 2.4566e-05 2.4566e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6140e+00 1.5700e+07 5.8315e+02 3.6403e+03 5.6251e-08 0.0000e+00 1.0000e+00 3.6403e+03 3.6403e+03 1.8593e+02 1.8593e+02 2.4667e-05 2.4667e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6160e+00 1.5800e+07 5.8315e+02 3.6607e+03 5.5724e-08 0.0000e+00 1.0000e+00 3.6607e+03 3.6607e+03 1.8698e+02 1.8698e+02 2.4768e-05 2.4768e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6180e+00 1.5900e+07 5.8315e+02 3.6811e+03 5.5204e-08 0.0000e+00 1.0000e+00 3.6811e+03 3.6811e+03 1.8802e+02 1.8802e+02 2.4869e-05 2.4869e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6200e+00 1.6000e+07 5.8315e+02 3.7013e+03 5.4692e-08 0.0000e+00 1.0000e+00 3.7013e+03 3.7013e+03 1.8905e+02 1.8905e+02 2.4970e-05 2.4970e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6220e+00 1.6100e+07 5.8315e+02 3.7215e+03 5.4185e-08 0.0000e+00 1.0000e+00 3.7215e+03 3.7215e+03 1.9009e+02 1.9009e+02 2.5071e-05 2.5071e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6240e+00 1.6200e+07 5.8315e+02 3.7417e+03 5.3686e-08 0.0000e+00 1.0000e+00 3.7417e+03 3.7417e+03 1.9111e+02 1.9111e+02 2.5172e-05 2.5172e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6260e+00 1.6300e+07 5.8315e+02 3.7617e+03 5.3192e-08 0.0000e+00 1.0000e+00 3.7617e+03 3.7617e+03 1.9214e+02 1.9214e+02 2.5273e-05 2.5273e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6280e+00 1.6400e+07 5.8315e+02 3.7817e+03 5.2706e-08 0.0000e+00 1.0000e+00 3.7817e+03 3.7817e+03 1.9316e+02 1.9316e+02 2.5375e-05 2.5375e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6300e+00 1.6500e+07 5.8315e+02 3.8016e+03 5.2225e-08 0.0000e+00 1.0000e+00 3.8016e+03 3.8016e+03 1.9417e+02 1.9417e+02 2.5476e-05 2.5476e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6320e+00 1.6600e+07 5.8315e+02 3.8214e+03 5.1751e-08 0.0000e+00 1.0000e+00 3.8214e+03 3.8214e+03 1.9519e+02 1.9519e+02 2.5578e-05 2.5578e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6340e+00 1.6700e+07 5.8315e+02 3.8411e+03 5.1282e-08 0.0000e+00 1.0000e+00 3.8411e+03 3.8411e+03 1.9619e+02 1.9619e+02 2.5679e-05 2.5679e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6360e+00 1.6800e+07 5.8315e+02 3.8608e+03 5.0820e-08 0.0000e+00 1.0000e+00 3.8608e+03 3.8608e+03 1.9720e+02 1.9720e+02 2.5781e-05 2.5781e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6380e+00 1.6900e+07 5.8315e+02 3.8804e+03 5.0363e-08 0.0000e+00 1.0000e+00 3.8804e+03 3.8804e+03 1.9820e+02 1.9820e+02 2.5882e-05 2.5882e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6400e+00 1.7000e+07 5.8315e+02 3.8999e+03 4.9912e-08 0.0000e+00 1.0000e+00 3.8999e+03 3.8999e+03 1.9920e+02 1.9920e+02 2.5984e-05 2.5984e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6420e+00 1.7100e+07 5.8315e+02 3.9193e+03 4.9467e-08 0.0000e+00 1.0000e+00 3.9193e+03 3.9193e+03 2.0019e+02 2.0019e+02 2.6086e-05 2.6086e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6440e+00 1.7200e+07 5.8315e+02 3.9386e+03 4.9028e-08 0.0000e+00 1.0000e+00 3.9386e+03 3.9386e+03 2.0118e+02 2.0118e+02 2.6187e-05 2.6187e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6460e+00 1.7300e+07 5.8315e+02 3.9579e+03 4.8594e-08 0.0000e+00 1.0000e+00 3.9579e+03 3.9579e+03 2.0216e+02 2.0216e+02 2.6289e-05 2.6289e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6480e+00 1.7400e+07 5.8315e+02 3.9771e+03 4.8166e-08 0.0000e+00 1.0000e+00 3.9771e+03 3.9771e+03 2.0314e+02 2.0314e+02 2.6391e-05 2.6391e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6500e+00 1.7500e+07 5.8315e+02 3.9962e+03 4.7743e-08 0.0000e+00 1.0000e+00 3.9962e+03 3.9962e+03 2.0412e+02 2.0412e+02 2.6493e-05 2.6493e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6520e+00 1.7600e+07 5.8315e+02 4.0153e+03 4.7325e-08 0.0000e+00 1.0000e+00 4.0153e+03 4.0153e+03 2.0509e+02 2.0509e+02 2.6595e-05 2.6595e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6540e+00 1.7700e+07 5.8315e+02 4.0342e+03 4.6912e-08 0.0000e+00 1.0000e+00 4.0342e+03 4.0342e+03 2.0606e+02 2.0606e+02 2.6696e-05 2.6696e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6560e+00 1.7800e+07 5.8315e+02 4.0531e+03 4.6505e-08 0.0000e+00 1.0000e+00 4.0531e+03 4.0531e+03 2.0702e+02 2.0702e+02 2.6798e-05 2.6798e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6580e+00 1.7900e+07 5.8315e+02 4.0719e+03 4.6102e-08 0.0000e+00 1.0000e+00 4.0719e+03 4.0719e+03 2.0798e+02 2.0798e+02 2.6900e-05 2.6900e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6600e+00 1.8000e+07 5.8315e+02 4.0907e+03 4.5705e-08 0.0000e+00 1.0000e+00 4.0907e+03 4.0907e+03 2.0894e+02 2.0894e+02 2.7002e-05 2.7002e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6620e+00 1.8100e+07 5.8315e+02 4.1093e+03 4.5312e-08 0.0000e+00 1.0000e+00 4.1093e+03 4.1093e+03 2.0989e+02 2.0989e+02 2.7103e-05 2.7103e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6640e+00 1.8200e+07 5.8315e+02 4.1279e+03 4.4925e-08 0.0000e+00 1.0000e+00 4.1279e+03 4.1279e+03 2.1084e+02 2.1084e+02 2.7205e-05 2.7205e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6660e+00 1.8300e+07 5.8315e+02 4.1464e+03 4.4542e-08 0.0000e+00 1.0000e+00 4.1464e+03 4.1464e+03 2.1179e+02 2.1179e+02 2.7307e-05 2.7307e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6680e+00 1.8400e+07 5.8315e+02 4.1648e+03 4.4164e-08 0.0000e+00 1.0000e+00 4.1648e+03 4.1648e+03 2.1273e+02 2.1273e+02 2.7408e-05 2.7408e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6700e+00 1.8500e+07 5.8315e+02 4.1832e+03 4.3790e-08 0.0000e+00 1.0000e+00 4.1832e+03 4.1832e+03 2.1367e+02 2.1367e+02 2.7510e-05 2.7510e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6720e+00 1.8600e+07 5.8315e+02 4.2015e+03 4.3421e-08 0.0000e+00 1.0000e+00 4.2015e+03 4.2015e+03 2.1460e+02 2.1460e+02 2.7611e-05 2.7611e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6740e+00 1.8700e+07 5.8315e+02 4.2197e+03 4.3056e-08 0.0000e+00 1.0000e+00 4.2197e+03 4.2197e+03 2.1553e+02 2.1553e+02 2.7713e-05 2.7713e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6760e+00 1.8800e+07 5.8315e+02 4.2378e+03 4.2696e-08 0.0000e+00 1.0000e+00 4.2378e+03 4.2378e+03 2.1646e+02 2.1646e+02 2.7814e-05 2.7814e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6780e+00 1.8900e+07 5.8315e+02 4.2559e+03 4.2340e-08 0.0000e+00 1.0000e+00 4.2559e+03 4.2559e+03 2.1738e+02 2.1738e+02 2.7915e-05 2.7915e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6800e+00 1.9000e+07 5.8315e+02 4.2739e+03 4.1989e-08 0.0000e+00 1.0000e+00 4.2739e+03 4.2739e+03 2.1830e+02 2.1830e+02 2.8017e-05 2.8017e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6820e+00 1.9100e+07 5.8315e+02 4.2918e+03 4.1642e-08 0.0000e+00 1.0000e+00 4.2918e+03 4.2918e+03 2.1921e+02 2.1921e+02 2.8118e-05 2.8118e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6840e+00 1.9200e+07 5.8315e+02 4.3096e+03 4.1299e-08 0.0000e+00 1.0000e+00 4.3096e+03 4.3096e+03 2.2012e+02 2.2012e+02 2.8219e-05 2.8219e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6860e+00 1.9300e+07 5.8315e+02 4.3274e+03 4.0960e-08 0.0000e+00 1.0000e+00 4.3274e+03 4.3274e+03 2.2103e+02 2.2103e+02 2.8320e-05 2.8320e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6880e+00 1.9400e+07 5.8315e+02 4.3451e+03 4.0625e-08 0.0000e+00 1.0000e+00 4.3451e+03 4.3451e+03 2.2193e+02 2.2193e+02 2.8421e-05 2.8421e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6900e+00 1.9500e+07 5.8315e+02 4.3627e+03 4.0294e-08 0.0000e+00 1.0000e+00 4.3627e+03 4.3627e+03 2.2283e+02 2.2283e+02 2.8522e-05 2.8522e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6920e+00 1.9600e+07 5.8315e+02 4.3802e+03 3.9967e-08 0.0000e+00 1.0000e+00 4.3802e+03 4.3802e+03 2.2373e+02 2.2373e+02 2.8623e-05 2.8623e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6940e+00 1.9700e+07 5.8315e+02 4.3977e+03 3.9643e-08 0.0000e+00 1.0000e+00 4.3977e+03 4.3977e+03 2.2462e+02 2.2462e+02 2.8723e-05 2.8723e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6960e+00 1.9800e+07 5.8315e+02 4.4151e+03 3.9324e-08 0.0000e+00 1.0000e+00 4.4151e+03 4.4151e+03 2.2551e+02 2.2551e+02 2.8824e-05 2.8824e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6980e+00 1.9900e+07 5.8315e+02 4.4324e+03 3.9008e-08 0.0000e+00 1.0000e+00 4.4324e+03 4.4324e+03 2.2640e+02 2.2640e+02 2.8925e-05 2.8925e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7000e+00 2.0000e+07 5.8315e+02 4.4497e+03 3.8697e-08 0.0000e+00 1.0000e+00 4.4497e+03 4.4497e+03 2.2728e+02 2.2728e+02 2.9025e-05 2.9025e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7020e+00 2.0100e+07 5.8315e+02 4.4668e+03 3.8388e-08 0.0000e+00 1.0000e+00 4.4668e+03 4.4668e+03 2.2815e+02 2.2815e+02 2.9125e-05 2.9125e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7040e+00 2.0200e+07 5.8315e+02 4.4840e+03 3.8084e-08 0.0000e+00 1.0000e+00 4.4840e+03 4.4840e+03 2.2903e+02 2.2903e+02 2.9226e-05 2.9226e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7060e+00 2.0300e+07 5.8315e+02 4.5010e+03 3.7783e-08 0.0000e+00 1.0000e+00 4.5010e+03 4.5010e+03 2.2990e+02 2.2990e+02 2.9326e-05 2.9326e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7080e+00 2.0400e+07 5.8315e+02 4.5180e+03 3.7485e-08 0.0000e+00 1.0000e+00 4.5180e+03 4.5180e+03 2.3077e+02 2.3077e+02 2.9426e-05 2.9426e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7100e+00 2.0500e+07 5.8315e+02 4.5349e+03 3.7191e-08 0.0000e+00 1.0000e+00 4.5349e+03 4.5349e+03 2.3163e+02 2.3163e+02 2.9526e-05 2.9526e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7120e+00 2.0600e+07 5.8315e+02 4.5517e+03 3.6900e-08 0.0000e+00 1.0000e+00 4.5517e+03 4.5517e+03 2.3249e+02 2.3249e+02 2.9625e-05 2.9625e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7140e+00 2.0700e+07 5.8315e+02 4.5685e+03 3.6613e-08 0.0000e+00 1.0000e+00 4.5685e+03 4.5685e+03 2.3334e+02 2.3334e+02 2.9725e-05 2.9725e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7160e+00 2.0800e+07 5.8315e+02 4.5852e+03 3.6329e-08 0.0000e+00 1.0000e+00 4.5852e+03 4.5852e+03 2.3420e+02 2.3420e+02 2.9824e-05 2.9824e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7180e+00 2.0900e+07 5.8315e+02 4.6018e+03 3.6048e-08 0.0000e+00 1.0000e+00 4.6018e+03 4.6018e+03 2.3505e+02 2.3505e+02 2.9924e-05 2.9924e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7200e+00 2.1000e+07 5.8315e+02 4.6183e+03 3.5771e-08 0.0000e+00 1.0000e+00 4.6183e+03 4.6183e+03 2.3589e+02 2.3589e+02 3.0023e-05 3.0023e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7220e+00 2.1100e+07 5.8315e+02 4.6348e+03 3.5496e-08 0.0000e+00 1.0000e+00 4.6348e+03 4.6348e+03 2.3673e+02 2.3673e+02 3.0122e-05 3.0122e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7240e+00 2.1200e+07 5.8315e+02 4.6512e+03 3.5225e-08 0.0000e+00 1.0000e+00 4.6512e+03 4.6512e+03 2.3757e+02 2.3757e+02 3.0221e-05 3.0221e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7260e+00 2.1300e+07 5.8315e+02 4.6676e+03 3.4957e-08 0.0000e+00 1.0000e+00 4.6676e+03 4.6676e+03 2.3841e+02 2.3841e+02 3.0320e-05 3.0320e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7280e+00 2.1400e+07 5.8315e+02 4.6839e+03 3.4691e-08 0.0000e+00 1.0000e+00 4.6839e+03 4.6839e+03 2.3924e+02 2.3924e+02 3.0419e-05 3.0419e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7300e+00 2.1500e+07 5.8315e+02 4.7001e+03 3.4429e-08 0.0000e+00 1.0000e+00 4.7001e+03 4.7001e+03 2.4007e+02 2.4007e+02 3.0518e-05 3.0518e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7320e+00 2.1600e+07 5.8315e+02 4.7162e+03 3.4170e-08 0.0000e+00 1.0000e+00 4.7162e+03 4.7162e+03 2.4089e+02 2.4089e+02 3.0616e-05 3.0616e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7340e+00 2.1700e+07 5.8315e+02 4.7323e+03 3.3914e-08 0.0000e+00 1.0000e+00 4.7323e+03 4.7323e+03 2.4171e+02 2.4171e+02 3.0714e-05 3.0714e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7360e+00 2.1800e+07 5.8315e+02 4.7483e+03 3.3660e-08 0.0000e+00 1.0000e+00 4.7483e+03 4.7483e+03 2.4253e+02 2.4253e+02 3.0813e-05 3.0813e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7380e+00 2.1900e+07 5.8315e+02 4.7643e+03 3.3410e-08 0.0000e+00 1.0000e+00 4.7643e+03 4.7643e+03 2.4335e+02 2.4335e+02 3.0911e-05 3.0911e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7400e+00 2.2000e+07 5.8315e+02 4.7802e+03 3.3162e-08 0.0000e+00 1.0000e+00 4.7802e+03 4.7802e+03 2.4416e+02 2.4416e+02 3.1009e-05 3.1009e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7420e+00 2.2100e+07 5.8315e+02 4.7960e+03 3.2917e-08 0.0000e+00 1.0000e+00 4.7960e+03 4.7960e+03 2.4497e+02 2.4497e+02 3.1106e-05 3.1106e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7440e+00 2.2200e+07 5.8315e+02 4.8117e+03 3.2674e-08 0.0000e+00 1.0000e+00 4.8117e+03 4.8117e+03 2.4577e+02 2.4577e+02 3.1204e-05 3.1204e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7460e+00 2.2300e+07 5.8315e+02 4.8274e+03 3.2435e-08 0.0000e+00 1.0000e+00 4.8274e+03 4.8274e+03 2.4657e+02 2.4657e+02 3.1301e-05 3.1301e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7480e+00 2.2400e+07 5.8315e+02 4.8431e+03 3.2198e-08 0.0000e+00 1.0000e+00 4.8431e+03 4.8431e+03 2.4737e+02 2.4737e+02 3.1399e-05 3.1399e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7500e+00 2.2500e+07 5.8315e+02 4.8586e+03 3.1963e-08 0.0000e+00 1.0000e+00 4.8586e+03 4.8586e+03 2.4816e+02 2.4816e+02 3.1496e-05 3.1496e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7520e+00 2.2600e+07 5.8315e+02 4.8741e+03 3.1731e-08 0.0000e+00 1.0000e+00 4.8741e+03 4.8741e+03 2.4896e+02 2.4896e+02 3.1593e-05 3.1593e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7540e+00 2.2700e+07 5.8315e+02 4.8895e+03 3.1502e-08 0.0000e+00 1.0000e+00 4.8895e+03 4.8895e+03 2.4974e+02 2.4974e+02 3.1690e-05 3.1690e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7560e+00 2.2800e+07 5.8315e+02 4.9049e+03 3.1275e-08 0.0000e+00 1.0000e+00 4.9049e+03 4.9049e+03 2.5053e+02 2.5053e+02 3.1786e-05 3.1786e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7580e+00 2.2900e+07 5.8315e+02 4.9202e+03 3.1051e-08 0.0000e+00 1.0000e+00 4.9202e+03 4.9202e+03 2.5131e+02 2.5131e+02 3.1883e-05 3.1883e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7600e+00 2.3000e+07 5.8315e+02 4.9355e+03 3.0829e-08 0.0000e+00 1.0000e+00 4.9355e+03 4.9355e+03 2.5209e+02 2.5209e+02 3.1979e-05 3.1979e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7620e+00 2.3100e+07 5.8315e+02 4.9507e+03 3.0609e-08 0.0000e+00 1.0000e+00 4.9507e+03 4.9507e+03 2.5287e+02 2.5287e+02 3.2076e-05 3.2076e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7640e+00 2.3200e+07 5.8315e+02 4.9658e+03 3.0392e-08 0.0000e+00 1.0000e+00 4.9658e+03 4.9658e+03 2.5364e+02 2.5364e+02 3.2172e-05 3.2172e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7660e+00 2.3300e+07 5.8315e+02 4.9808e+03 3.0177e-08 0.0000e+00 1.0000e+00 4.9808e+03 4.9808e+03 2.5441e+02 2.5441e+02 3.2268e-05 3.2268e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7680e+00 2.3400e+07 5.8315e+02 4.9958e+03 2.9965e-08 0.0000e+00 1.0000e+00 4.9958e+03 4.9958e+03 2.5517e+02 2.5517e+02 3.2363e-05 3.2363e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7700e+00 2.3500e+07 5.8315e+02 5.0108e+03 2.9754e-08 0.0000e+00 1.0000e+00 5.0108e+03 5.0108e+03 2.5594e+02 2.5594e+02 3.2459e-05 3.2459e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7720e+00 2.3600e+07 5.8315e+02 5.0257e+03 2.9546e-08 0.0000e+00 1.0000e+00 5.0257e+03 5.0257e+03 2.5670e+02 2.5670e+02 3.2554e-05 3.2554e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7740e+00 2.3700e+07 5.8315e+02 5.0405e+03 2.9340e-08 0.0000e+00 1.0000e+00 5.0405e+03 5.0405e+03 2.5745e+02 2.5745e+02 3.2650e-05 3.2650e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7760e+00 2.3800e+07 5.8315e+02 5.0552e+03 2.9137e-08 0.0000e+00 1.0000e+00 5.0552e+03 5.0552e+03 2.5821e+02 2.5821e+02 3.2745e-05 3.2745e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7780e+00 2.3900e+07 5.8315e+02 5.0699e+03 2.8935e-08 0.0000e+00 1.0000e+00 5.0699e+03 5.0699e+03 2.5896e+02 2.5896e+02 3.2840e-05 3.2840e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7800e+00 2.4000e+07 5.8315e+02 5.0846e+03 2.8736e-08 0.0000e+00 1.0000e+00 5.0846e+03 5.0846e+03 2.5971e+02 2.5971e+02 3.2934e-05 3.2934e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7820e+00 2.4100e+07 5.8315e+02 5.0992e+03 2.8539e-08 0.0000e+00 1.0000e+00 5.0992e+03 5.0992e+03 2.6045e+02 2.6045e+02 3.3029e-05 3.3029e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7840e+00 2.4200e+07 5.8315e+02 5.1137e+03 2.8343e-08 0.0000e+00 1.0000e+00 5.1137e+03 5.1137e+03 2.6119e+02 2.6119e+02 3.3123e-05 3.3123e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7860e+00 2.4300e+07 5.8315e+02 5.1281e+03 2.8150e-08 0.0000e+00 1.0000e+00 5.1281e+03 5.1281e+03 2.6193e+02 2.6193e+02 3.3218e-05 3.3218e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7880e+00 2.4400e+07 5.8315e+02 5.1426e+03 2.7959e-08 0.0000e+00 1.0000e+00 5.1426e+03 5.1426e+03 2.6267e+02 2.6267e+02 3.3312e-05 3.3312e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7900e+00 2.4500e+07 5.8315e+02 5.1569e+03 2.7770e-08 0.0000e+00 1.0000e+00 5.1569e+03 5.1569e+03 2.6340e+02 2.6340e+02 3.3406e-05 3.3406e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7920e+00 2.4600e+07 5.8315e+02 5.1712e+03 2.7583e-08 0.0000e+00 1.0000e+00 5.1712e+03 5.1712e+03 2.6413e+02 2.6413e+02 3.3499e-05 3.3499e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7940e+00 2.4700e+07 5.8315e+02 5.1854e+03 2.7397e-08 0.0000e+00 1.0000e+00 5.1854e+03 5.1854e+03 2.6486e+02 2.6486e+02 3.3593e-05 3.3593e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7960e+00 2.4800e+07 5.8315e+02 5.1996e+03 2.7214e-08 0.0000e+00 1.0000e+00 5.1996e+03 5.1996e+03 2.6558e+02 2.6558e+02 3.3686e-05 3.3686e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7980e+00 2.4900e+07 5.8315e+02 5.2137e+03 2.7032e-08 0.0000e+00 1.0000e+00 5.2137e+03 5.2137e+03 2.6630e+02 2.6630e+02 3.3780e-05 3.3780e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8000e+00 2.5000e+07 5.8315e+02 5.2278e+03 2.6853e-08 0.0000e+00 1.0000e+00 5.2278e+03 5.2278e+03 2.6702e+02 2.6702e+02 3.3873e-05 3.3873e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8020e+00 2.5100e+07 5.8315e+02 5.2418e+03 2.6675e-08 0.0000e+00 1.0000e+00 5.2418e+03 5.2418e+03 2.6774e+02 2.6774e+02 3.3966e-05 3.3966e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8040e+00 2.5200e+07 5.8315e+02 5.2558e+03 2.6499e-08 0.0000e+00 1.0000e+00 5.2558e+03 5.2558e+03 2.6845e+02 2.6845e+02 3.4058e-05 3.4058e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8060e+00 2.5300e+07 5.8315e+02 5.2697e+03 2.6325e-08 0.0000e+00 1.0000e+00 5.2697e+03 5.2697e+03 2.6916e+02 2.6916e+02 3.4151e-05 3.4151e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8080e+00 2.5400e+07 5.8315e+02 5.2835e+03 2.6152e-08 0.0000e+00 1.0000e+00 5.2835e+03 5.2835e+03 2.6987e+02 2.6987e+02 3.4243e-05 3.4243e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8100e+00 2.5500e+07 5.8315e+02 5.2973e+03 2.5981e-08 0.0000e+00 1.0000e+00 5.2973e+03 5.2973e+03 2.7057e+02 2.7057e+02 3.4336e-05 3.4336e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8120e+00 2.5600e+07 5.8315e+02 5.3110e+03 2.5812e-08 0.0000e+00 1.0000e+00 5.3110e+03 5.3110e+03 2.7127e+02 2.7127e+02 3.4428e-05 3.4428e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8140e+00 2.5700e+07 5.8315e+02 5.3247e+03 2.5645e-08 0.0000e+00 1.0000e+00 5.3247e+03 5.3247e+03 2.7197e+02 2.7197e+02 3.4520e-05 3.4520e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8160e+00 2.5800e+07 5.8315e+02 5.3383e+03 2.5479e-08 0.0000e+00 1.0000e+00 5.3383e+03 5.3383e+03 2.7267e+02 2.7267e+02 3.4611e-05 3.4611e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8180e+00 2.5900e+07 5.8315e+02 5.3519e+03 2.5315e-08 0.0000e+00 1.0000e+00 5.3519e+03 5.3519e+03 2.7336e+02 2.7336e+02 3.4703e-05 3.4703e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8200e+00 2.6000e+07 5.8315e+02 5.3654e+03 2.5153e-08 0.0000e+00 1.0000e+00 5.3654e+03 5.3654e+03 2.7405e+02 2.7405e+02 3.4794e-05 3.4794e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8220e+00 2.6100e+07 5.8315e+02 5.3789e+03 2.4992e-08 0.0000e+00 1.0000e+00 5.3789e+03 5.3789e+03 2.7474e+02 2.7474e+02 3.4885e-05 3.4885e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8240e+00 2.6200e+07 5.8315e+02 5.3923e+03 2.4833e-08 0.0000e+00 1.0000e+00 5.3923e+03 5.3923e+03 2.7543e+02 2.7543e+02 3.4976e-05 3.4976e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8260e+00 2.6300e+07 5.8315e+02 5.4057e+03 2.4675e-08 0.0000e+00 1.0000e+00 5.4057e+03 5.4057e+03 2.7611e+02 2.7611e+02 3.5067e-05 3.5067e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8280e+00 2.6400e+07 5.8315e+02 5.4190e+03 2.4519e-08 0.0000e+00 1.0000e+00 5.4190e+03 5.4190e+03 2.7679e+02 2.7679e+02 3.5158e-05 3.5158e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8300e+00 2.6500e+07 5.8315e+02 5.4323e+03 2.4365e-08 0.0000e+00 1.0000e+00 5.4323e+03 5.4323e+03 2.7747e+02 2.7747e+02 3.5248e-05 3.5248e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8320e+00 2.6600e+07 5.8315e+02 5.4455e+03 2.4212e-08 0.0000e+00 1.0000e+00 5.4455e+03 5.4455e+03 2.7814e+02 2.7814e+02 3.5339e-05 3.5339e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8340e+00 2.6700e+07 5.8315e+02 5.4586e+03 2.4060e-08 0.0000e+00 1.0000e+00 5.4586e+03 5.4586e+03 2.7881e+02 2.7881e+02 3.5429e-05 3.5429e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8360e+00 2.6800e+07 5.8315e+02 5.4717e+03 2.3910e-08 0.0000e+00 1.0000e+00 5.4717e+03 5.4717e+03 2.7948e+02 2.7948e+02 3.5519e-05 3.5519e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8380e+00 2.6900e+07 5.8315e+02 5.4848e+03 2.3762e-08 0.0000e+00 1.0000e+00 5.4848e+03 5.4848e+03 2.8015e+02 2.8015e+02 3.5609e-05 3.5609e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8400e+00 2.7000e+07 5.8315e+02 5.4978e+03 2.3615e-08 0.0000e+00 1.0000e+00 5.4978e+03 5.4978e+03 2.8081e+02 2.8081e+02 3.5699e-05 3.5699e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8420e+00 2.7100e+07 5.8315e+02 5.5108e+03 2.3469e-08 0.0000e+00 1.0000e+00 5.5108e+03 5.5108e+03 2.8148e+02 2.8148e+02 3.5788e-05 3.5788e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8440e+00 2.7200e+07 5.8315e+02 5.5237e+03 2.3324e-08 0.0000e+00 1.0000e+00 5.5237e+03 5.5237e+03 2.8213e+02 2.8213e+02 3.5877e-05 3.5877e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8460e+00 2.7300e+07 5.8315e+02 5.5365e+03 2.3181e-08 0.0000e+00 1.0000e+00 5.5365e+03 5.5365e+03 2.8279e+02 2.8279e+02 3.5967e-05 3.5967e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8480e+00 2.7400e+07 5.8315e+02 5.5493e+03 2.3040e-08 0.0000e+00 1.0000e+00 5.5493e+03 5.5493e+03 2.8345e+02 2.8345e+02 3.6056e-05 3.6056e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8500e+00 2.7500e+07 5.8315e+02 5.5621e+03 2.2900e-08 0.0000e+00 1.0000e+00 5.5621e+03 5.5621e+03 2.8410e+02 2.8410e+02 3.6144e-05 3.6144e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8520e+00 2.7600e+07 5.8315e+02 5.5748e+03 2.2761e-08 0.0000e+00 1.0000e+00 5.5748e+03 5.5748e+03 2.8475e+02 2.8475e+02 3.6233e-05 3.6233e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8540e+00 2.7700e+07 5.8315e+02 5.5875e+03 2.2623e-08 0.0000e+00 1.0000e+00 5.5875e+03 5.5875e+03 2.8539e+02 2.8539e+02 3.6322e-05 3.6322e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8560e+00 2.7800e+07 5.8315e+02 5.6001e+03 2.2487e-08 0.0000e+00 1.0000e+00 5.6001e+03 5.6001e+03 2.8604e+02 2.8604e+02 3.6410e-05 3.6410e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8580e+00 2.7900e+07 5.8315e+02 5.6127e+03 2.2352e-08 0.0000e+00 1.0000e+00 5.6127e+03 5.6127e+03 2.8668e+02 2.8668e+02 3.6498e-05 3.6498e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8600e+00 2.8000e+07 5.8315e+02 5.6252e+03 2.2218e-08 0.0000e+00 1.0000e+00 5.6252e+03 5.6252e+03 2.8732e+02 2.8732e+02 3.6586e-05 3.6586e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8620e+00 2.8100e+07 5.8315e+02 5.6377e+03 2.2085e-08 0.0000e+00 1.0000e+00 5.6377e+03 5.6377e+03 2.8796e+02 2.8796e+02 3.6674e-05 3.6674e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8640e+00 2.8200e+07 5.8315e+02 5.6501e+03 2.1954e-08 0.0000e+00 1.0000e+00 5.6501e+03 5.6501e+03 2.8859e+02 2.8859e+02 3.6762e-05 3.6762e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8660e+00 2.8300e+07 5.8315e+02 5.6625e+03 2.1824e-08 0.0000e+00 1.0000e+00 5.6625e+03 5.6625e+03 2.8922e+02 2.8922e+02 3.6849e-05 3.6849e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8680e+00 2.8400e+07 5.8315e+02 5.6748e+03 2.1695e-08 0.0000e+00 1.0000e+00 5.6748e+03 5.6748e+03 2.8985e+02 2.8985e+02 3.6937e-05 3.6937e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8700e+00 2.8500e+07 5.8315e+02 5.6871e+03 2.1568e-08 0.0000e+00 1.0000e+00 5.6871e+03 5.6871e+03 2.9048e+02 2.9048e+02 3.7024e-05 3.7024e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8720e+00 2.8600e+07 5.8315e+02 5.6993e+03 2.1441e-08 0.0000e+00 1.0000e+00 5.6993e+03 5.6993e+03 2.9111e+02 2.9111e+02 3.7111e-05 3.7111e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8740e+00 2.8700e+07 5.8315e+02 5.7115e+03 2.1316e-08 0.0000e+00 1.0000e+00 5.7115e+03 5.7115e+03 2.9173e+02 2.9173e+02 3.7198e-05 3.7198e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8760e+00 2.8800e+07 5.8315e+02 5.7237e+03 2.1192e-08 0.0000e+00 1.0000e+00 5.7237e+03 5.7237e+03 2.9235e+02 2.9235e+02 3.7284e-05 3.7284e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8780e+00 2.8900e+07 5.8315e+02 5.7358e+03 2.1069e-08 0.0000e+00 1.0000e+00 5.7358e+03 5.7358e+03 2.9297e+02 2.9297e+02 3.7371e-05 3.7371e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8800e+00 2.9000e+07 5.8315e+02 5.7479e+03 2.0947e-08 0.0000e+00 1.0000e+00 5.7479e+03 5.7479e+03 2.9359e+02 2.9359e+02 3.7457e-05 3.7457e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8820e+00 2.9100e+07 5.8315e+02 5.7599e+03 2.0826e-08 0.0000e+00 1.0000e+00 5.7599e+03 5.7599e+03 2.9420e+02 2.9420e+02 3.7544e-05 3.7544e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8840e+00 2.9200e+07 5.8315e+02 5.7718e+03 2.0706e-08 0.0000e+00 1.0000e+00 5.7718e+03 5.7718e+03 2.9481e+02 2.9481e+02 3.7630e-05 3.7630e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8860e+00 2.9300e+07 5.8315e+02 5.7838e+03 2.0588e-08 0.0000e+00 1.0000e+00 5.7838e+03 5.7838e+03 2.9542e+02 2.9542e+02 3.7716e-05 3.7716e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8880e+00 2.9400e+07 5.8315e+02 5.7957e+03 2.0470e-08 0.0000e+00 1.0000e+00 5.7957e+03 5.7957e+03 2.9603e+02 2.9603e+02 3.7801e-05 3.7801e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8900e+00 2.9500e+07 5.8315e+02 5.8075e+03 2.0354e-08 0.0000e+00 1.0000e+00 5.8075e+03 5.8075e+03 2.9663e+02 2.9663e+02 3.7887e-05 3.7887e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8920e+00 2.9600e+07 5.8315e+02 5.8193e+03 2.0238e-08 0.0000e+00 1.0000e+00 5.8193e+03 5.8193e+03 2.9723e+02 2.9723e+02 3.7972e-05 3.7972e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8940e+00 2.9700e+07 5.8315e+02 5.8311e+03 2.0124e-08 0.0000e+00 1.0000e+00 5.8311e+03 5.8311e+03 2.9784e+02 2.9784e+02 3.8058e-05 3.8058e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8960e+00 2.9800e+07 5.8315e+02 5.8428e+03 2.0010e-08 0.0000e+00 1.0000e+00 5.8428e+03 5.8428e+03 2.9843e+02 2.9843e+02 3.8143e-05 3.8143e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8980e+00 2.9900e+07 5.8315e+02 5.8544e+03 1.9898e-08 0.0000e+00 1.0000e+00 5.8544e+03 5.8544e+03 2.9903e+02 2.9903e+02 3.8228e-05 3.8228e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9000e+00 3.0000e+07 5.8315e+02 5.8661e+03 1.9787e-08 0.0000e+00 1.0000e+00 5.8661e+03 5.8661e+03 2.9962e+02 2.9962e+02 3.8313e-05 3.8313e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9020e+00 3.0100e+07 5.8315e+02 5.8777e+03 1.9676e-08 0.0000e+00 1.0000e+00 5.8777e+03 5.8777e+03 3.0022e+02 3.0022e+02 3.8397e-05 3.8397e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9040e+00 3.0200e+07 5.8315e+02 5.8892e+03 1.9567e-08 0.0000e+00 1.0000e+00 5.8892e+03 5.8892e+03 3.0080e+02 3.0080e+02 3.8482e-05 3.8482e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9060e+00 3.0300e+07 5.8315e+02 5.9007e+03 1.9458e-08 0.0000e+00 1.0000e+00 5.9007e+03 5.9007e+03 3.0139e+02 3.0139e+02 3.8566e-05 3.8566e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9080e+00 3.0400e+07 5.8315e+02 5.9122e+03 1.9351e-08 0.0000e+00 1.0000e+00 5.9122e+03 5.9122e+03 3.0198e+02 3.0198e+02 3.8651e-05 3.8651e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9100e+00 3.0500e+07 5.8315e+02 5.9236e+03 1.9244e-08 0.0000e+00 1.0000e+00 5.9236e+03 5.9236e+03 3.0256e+02 3.0256e+02 3.8735e-05 3.8735e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9120e+00 3.0600e+07 5.8315e+02 5.9350e+03 1.9138e-08 0.0000e+00 1.0000e+00 5.9350e+03 5.9350e+03 3.0314e+02 3.0314e+02 3.8819e-05 3.8819e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9140e+00 3.0700e+07 5.8315e+02 5.9463e+03 1.9034e-08 0.0000e+00 1.0000e+00 5.9463e+03 5.9463e+03 3.0372e+02 3.0372e+02 3.8902e-05 3.8902e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9160e+00 3.0800e+07 5.8315e+02 5.9576e+03 1.8930e-08 0.0000e+00 1.0000e+00 5.9576e+03 5.9576e+03 3.0430e+02 3.0430e+02 3.8986e-05 3.8986e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9180e+00 3.0900e+07 5.8315e+02 5.9689e+03 1.8827e-08 0.0000e+00 1.0000e+00 5.9689e+03 5.9689e+03 3.0487e+02 3.0487e+02 3.9069e-05 3.9069e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9200e+00 3.1000e+07 5.8315e+02 5.9801e+03 1.8725e-08 0.0000e+00 1.0000e+00 5.9801e+03 5.9801e+03 3.0545e+02 3.0545e+02 3.9153e-05 3.9153e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9220e+00 3.1100e+07 5.8315e+02 5.9913e+03 1.8624e-08 0.0000e+00 1.0000e+00 5.9913e+03 5.9913e+03 3.0602e+02 3.0602e+02 3.9236e-05 3.9236e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9240e+00 3.1200e+07 5.8315e+02 6.0024e+03 1.8523e-08 0.0000e+00 1.0000e+00 6.0024e+03 6.0024e+03 3.0659e+02 3.0659e+02 3.9319e-05 3.9319e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9260e+00 3.1300e+07 5.8315e+02 6.0135e+03 1.8424e-08 0.0000e+00 1.0000e+00 6.0135e+03 6.0135e+03 3.0715e+02 3.0715e+02 3.9402e-05 3.9402e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9280e+00 3.1400e+07 5.8315e+02 6.0246e+03 1.8325e-08 0.0000e+00 1.0000e+00 6.0246e+03 6.0246e+03 3.0772e+02 3.0772e+02 3.9485e-05 3.9485e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9300e+00 3.1500e+07 5.8315e+02 6.0356e+03 1.8228e-08 0.0000e+00 1.0000e+00 6.0356e+03 6.0356e+03 3.0828e+02 3.0828e+02 3.9567e-05 3.9567e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9320e+00 3.1600e+07 5.8315e+02 6.0466e+03 1.8131e-08 0.0000e+00 1.0000e+00 6.0466e+03 6.0466e+03 3.0884e+02 3.0884e+02 3.9650e-05 3.9650e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9340e+00 3.1700e+07 5.8315e+02 6.0575e+03 1.8035e-08 0.0000e+00 1.0000e+00 6.0575e+03 6.0575e+03 3.0940e+02 3.0940e+02 3.9732e-05 3.9732e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9360e+00 3.1800e+07 5.8315e+02 6.0684e+03 1.7939e-08 0.0000e+00 1.0000e+00 6.0684e+03 6.0684e+03 3.0996e+02 3.0996e+02 3.9814e-05 3.9814e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9380e+00 3.1900e+07 5.8315e+02 6.0793e+03 1.7845e-08 0.0000e+00 1.0000e+00 6.0793e+03 6.0793e+03 3.1051e+02 3.1051e+02 3.9896e-05 3.9896e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9400e+00 3.2000e+07 5.8315e+02 6.0901e+03 1.7751e-08 0.0000e+00 1.0000e+00 6.0901e+03 6.0901e+03 3.1107e+02 3.1107e+02 3.9978e-05 3.9978e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9420e+00 3.2100e+07 5.8315e+02 6.1009e+03 1.7658e-08 0.0000e+00 1.0000e+00 6.1009e+03 6.1009e+03 3.1162e+02 3.1162e+02 4.0060e-05 4.0060e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9440e+00 3.2200e+07 5.8315e+02 6.1116e+03 1.7566e-08 0.0000e+00 1.0000e+00 6.1116e+03 6.1116e+03 3.1217e+02 3.1217e+02 4.0142e-05 4.0142e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9460e+00 3.2300e+07 5.8315e+02 6.1224e+03 1.7475e-08 0.0000e+00 1.0000e+00 6.1224e+03 6.1224e+03 3.1271e+02 3.1271e+02 4.0223e-05 4.0223e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9480e+00 3.2400e+07 5.8315e+02 6.1330e+03 1.7384e-08 0.0000e+00 1.0000e+00 6.1330e+03 6.1330e+03 3.1326e+02 3.1326e+02 4.0305e-05 4.0305e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9500e+00 3.2500e+07 5.8315e+02 6.1437e+03 1.7294e-08 0.0000e+00 1.0000e+00 6.1437e+03 6.1437e+03 3.1380e+02 3.1380e+02 4.0386e-05 4.0386e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9520e+00 3.2600e+07 5.8315e+02 6.1543e+03 1.7205e-08 0.0000e+00 1.0000e+00 6.1543e+03 6.1543e+03 3.1434e+02 3.1434e+02 4.0467e-05 4.0467e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9540e+00 3.2700e+07 5.8315e+02 6.1649e+03 1.7117e-08 0.0000e+00 1.0000e+00 6.1649e+03 6.1649e+03 3.1488e+02 3.1488e+02 4.0548e-05 4.0548e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9560e+00 3.2800e+07 5.8315e+02 6.1754e+03 1.7029e-08 0.0000e+00 1.0000e+00 6.1754e+03 6.1754e+03 3.1542e+02 3.1542e+02 4.0629e-05 4.0629e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9580e+00 3.2900e+07 5.8315e+02 6.1859e+03 1.6942e-08 0.0000e+00 1.0000e+00 6.1859e+03 6.1859e+03 3.1596e+02 3.1596e+02 4.0709e-05 4.0709e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9600e+00 3.3000e+07 5.8315e+02 6.1964e+03 1.6856e-08 0.0000e+00 1.0000e+00 6.1964e+03 6.1964e+03 3.1649e+02 3.1649e+02 4.0790e-05 4.0790e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9620e+00 3.3100e+07 5.8315e+02 6.2068e+03 1.6770e-08 0.0000e+00 1.0000e+00 6.2068e+03 6.2068e+03 3.1703e+02 3.1703e+02 4.0871e-05 4.0871e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9640e+00 3.3200e+07 5.8315e+02 6.2172e+03 1.6685e-08 0.0000e+00 1.0000e+00 6.2172e+03 6.2172e+03 3.1756e+02 3.1756e+02 4.0951e-05 4.0951e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9660e+00 3.3300e+07 5.8315e+02 6.2275e+03 1.6601e-08 0.0000e+00 1.0000e+00 6.2275e+03 6.2275e+03 3.1809e+02 3.1809e+02 4.1031e-05 4.1031e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9680e+00 3.3400e+07 5.8315e+02 6.2379e+03 1.6517e-08 0.0000e+00 1.0000e+00 6.2379e+03 6.2379e+03 3.1861e+02 3.1861e+02 4.1111e-05 4.1111e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9700e+00 3.3500e+07 5.8315e+02 6.2481e+03 1.6435e-08 0.0000e+00 1.0000e+00 6.2481e+03 6.2481e+03 3.1914e+02 3.1914e+02 4.1191e-05 4.1191e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9720e+00 3.3600e+07 5.8315e+02 6.2584e+03 1.6352e-08 0.0000e+00 1.0000e+00 6.2584e+03 6.2584e+03 3.1966e+02 3.1966e+02 4.1271e-05 4.1271e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9740e+00 3.3700e+07 5.8315e+02 6.2686e+03 1.6271e-08 0.0000e+00 1.0000e+00 6.2686e+03 6.2686e+03 3.2018e+02 3.2018e+02 4.1350e-05 4.1350e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9760e+00 3.3800e+07 5.8315e+02 6.2788e+03 1.6190e-08 0.0000e+00 1.0000e+00 6.2788e+03 6.2788e+03 3.2070e+02 3.2070e+02 4.1430e-05 4.1430e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9780e+00 3.3900e+07 5.8315e+02 6.2889e+03 1.6110e-08 0.0000e+00 1.0000e+00 6.2889e+03 6.2889e+03 3.2122e+02 3.2122e+02 4.1509e-05 4.1509e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9800e+00 3.4000e+07 5.8315e+02 6.2991e+03 1.6030e-08 0.0000e+00 1.0000e+00 6.2991e+03 6.2991e+03 3.2174e+02 3.2174e+02 4.1589e-05 4.1589e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9820e+00 3.4100e+07 5.8315e+02 6.3091e+03 1.5951e-08 0.0000e+00 1.0000e+00 6.3091e+03 6.3091e+03 3.2225e+02 3.2225e+02 4.1668e-05 4.1668e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9840e+00 3.4200e+07 5.8315e+02 6.3192e+03 1.5873e-08 0.0000e+00 1.0000e+00 6.3192e+03 6.3192e+03 3.2277e+02 3.2277e+02 4.1747e-05 4.1747e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9860e+00 3.4300e+07 5.8315e+02 6.3292e+03 1.5795e-08 0.0000e+00 1.0000e+00 6.3292e+03 6.3292e+03 3.2328e+02 3.2328e+02 4.1826e-05 4.1826e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9880e+00 3.4400e+07 5.8315e+02 6.3392e+03 1.5718e-08 0.0000e+00 1.0000e+00 6.3392e+03 6.3392e+03 3.2379e+02 3.2379e+02 4.1905e-05 4.1905e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9900e+00 3.4500e+07 5.8315e+02 6.3491e+03 1.5642e-08 0.0000e+00 1.0000e+00 6.3491e+03 6.3491e+03 3.2430e+02 3.2430e+02 4.1983e-05 4.1983e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9920e+00 3.4600e+07 5.8315e+02 6.3590e+03 1.5566e-08 0.0000e+00 1.0000e+00 6.3590e+03 6.3590e+03 3.2480e+02 3.2480e+02 4.2062e-05 4.2062e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9940e+00 3.4700e+07 5.8315e+02 6.3689e+03 1.5490e-08 0.0000e+00 1.0000e+00 6.3689e+03 6.3689e+03 3.2531e+02 3.2531e+02 4.2141e-05 4.2141e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9960e+00 3.4800e+07 5.8315e+02 6.3788e+03 1.5416e-08 0.0000e+00 1.0000e+00 6.3788e+03 6.3788e+03 3.2581e+02 3.2581e+02 4.2219e-05 4.2219e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9980e+00 3.4900e+07 5.8315e+02 6.3886e+03 1.5342e-08 0.0000e+00 1.0000e+00 6.3886e+03 6.3886e+03 3.2631e+02 3.2631e+02 4.2297e-05 4.2297e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0000e+00 3.5000e+07 5.8315e+02 6.3984e+03 1.5268e-08 0.0000e+00 1.0000e+00 6.3984e+03 6.3984e+03 3.2681e+02 3.2681e+02 4.2375e-05 4.2375e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT_Compositional_liveOilSRK.txt b/src/coreComponents/unitTests/constitutiveTests/testPVT_Compositional_liveOilSRK.txt new file mode 100644 index 00000000000..b2034f4c56a --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT_Compositional_liveOilSRK.txt @@ -0,0 +1,112 @@ +# column 1 = time +# column 2 = pressure +# column 3 = temperature +# column 4 = density +# column 5 = total compressibility +# columns 6-7 = phase fractions +# columns 8-9 = phase densities +# columns 10-11 = phase mass densities +# columns 12-13 = phase viscosities +# columns 14-22 = oil phase fractions [CO2, N2, C1, C2, C3, C4, C5, C6, C7+] +# columns 23-31 = gas phase fractions [CO2, N2, C1, C2, C3, C4, C5, C6, C7+] +0.0000e+00 3.5000e+07 5.5315e+02 6.3045e+03 1.3265e-08 1.0000e+00 0.0000e+00 6.3045e+03 6.3045e+03 3.2202e+02 3.2202e+02 1.0000e-03 1.0000e-03 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +2.0000e-02 3.4000e+07 5.5315e+02 6.2193e+03 1.3936e-08 1.0000e+00 0.0000e+00 6.2193e+03 6.2193e+03 3.1767e+02 3.1767e+02 1.0000e-03 1.0000e-03 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +4.0000e-02 3.3000e+07 5.5315e+02 6.1311e+03 1.4665e-08 1.0000e+00 0.0000e+00 6.1311e+03 6.1311e+03 3.1316e+02 3.1316e+02 1.0000e-03 1.0000e-03 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +6.0000e-02 3.2000e+07 5.5315e+02 6.0394e+03 1.5459e-08 1.0000e+00 0.0000e+00 6.0394e+03 6.0394e+03 3.0848e+02 3.0848e+02 1.0000e-03 1.0000e-03 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +8.0000e-02 3.1000e+07 5.5315e+02 5.9442e+03 1.6327e-08 1.0000e+00 0.0000e+00 5.9442e+03 5.9442e+03 3.0362e+02 3.0362e+02 1.0000e-03 1.0000e-03 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.0000e-01 3.0000e+07 5.5315e+02 5.8453e+03 1.7277e-08 1.0000e+00 0.0000e+00 5.8453e+03 5.8453e+03 2.9856e+02 2.9856e+02 1.0000e-03 1.0000e-03 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.2000e-01 2.9000e+07 5.5315e+02 5.7422e+03 1.8321e-08 1.0000e+00 0.0000e+00 5.7422e+03 5.7422e+03 2.9330e+02 2.9330e+02 1.0000e-03 1.0000e-03 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.4000e-01 2.8000e+07 5.5315e+02 5.6347e+03 1.9473e-08 1.0000e+00 0.0000e+00 5.6347e+03 5.6347e+03 2.8781e+02 2.8781e+02 1.0000e-03 1.0000e-03 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.6000e-01 2.7000e+07 5.5315e+02 5.5226e+03 2.0746e-08 0.0000e+00 1.0000e+00 5.5226e+03 5.5226e+03 2.8208e+02 2.8208e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8000e-01 2.6000e+07 5.5315e+02 5.4055e+03 2.2159e-08 0.0000e+00 1.0000e+00 5.4055e+03 5.4055e+03 2.7610e+02 2.7610e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0000e-01 2.5000e+07 5.5315e+02 5.2829e+03 2.3733e-08 0.0000e+00 1.0000e+00 5.2829e+03 5.2829e+03 2.6984e+02 2.6984e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.2000e-01 2.4000e+07 5.5315e+02 5.1546e+03 2.5493e-08 0.0000e+00 1.0000e+00 5.1546e+03 5.1546e+03 2.6328e+02 2.6328e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.4000e-01 2.3000e+07 5.5315e+02 5.0200e+03 2.7469e-08 0.0000e+00 1.0000e+00 5.0200e+03 5.0200e+03 2.5641e+02 2.5641e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.6000e-01 2.2000e+07 5.5315e+02 4.8786e+03 2.9694e-08 0.0000e+00 1.0000e+00 4.8786e+03 4.8786e+03 2.4919e+02 2.4919e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.8000e-01 2.1000e+07 5.5315e+02 4.7301e+03 3.2211e-08 0.0000e+00 1.0000e+00 4.7301e+03 4.7301e+03 2.4160e+02 2.4160e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.0000e-01 2.0000e+07 5.5315e+02 4.5737e+03 3.5068e-08 0.0000e+00 1.0000e+00 4.5737e+03 4.5737e+03 2.3361e+02 2.3361e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.2000e-01 1.9000e+07 5.5315e+02 4.4091e+03 3.8325e-08 0.0000e+00 1.0000e+00 4.4091e+03 4.4091e+03 2.2520e+02 2.2520e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.4000e-01 1.8000e+07 5.5315e+02 4.2347e+03 4.1795e-08 2.3675e-01 7.6325e-01 4.4993e+03 4.1589e+03 3.0206e+02 1.9775e+02 1.0000e-03 1.0000e-03 7.9266e-03 2.3296e-03 4.4197e-01 1.0420e-01 8.5138e-02 4.6987e-02 2.2860e-02 1.7555e-02 2.7104e-01 9.2358e-03 3.1473e-03 5.5507e-01 1.1688e-01 8.8507e-02 4.5295e-02 2.0469e-02 1.4561e-02 1.4683e-01 +3.6000e-01 1.7000e+07 5.5315e+02 4.0560e+03 4.4524e-08 3.0609e-01 6.9391e-01 4.4207e+03 3.9136e+03 3.2372e+02 1.7636e+02 1.0000e-03 1.0000e-03 7.5002e-03 2.0982e-03 4.0806e-01 9.9831e-02 8.3535e-02 4.7156e-02 2.3431e-02 1.8367e-02 3.1002e-01 9.4071e-03 3.2448e-03 5.6908e-01 1.1861e-01 8.9085e-02 4.5177e-02 2.0213e-02 1.4213e-02 1.3097e-01 +3.8000e-01 1.6000e+07 5.5315e+02 3.8734e+03 4.7696e-08 3.3422e-01 6.6578e-01 4.3320e+03 3.6779e+03 3.4060e+02 1.5976e+02 1.0000e-03 1.0000e-03 7.1117e-03 1.9066e-03 3.7885e-01 9.5701e-02 8.1761e-02 4.7069e-02 2.3818e-02 1.9001e-02 3.4479e-01 9.5237e-03 3.3032e-03 5.7792e-01 1.1984e-01 8.9603e-02 4.5193e-02 2.0091e-02 1.4018e-02 1.2050e-01 +4.0000e-01 1.5000e+07 5.5315e+02 3.6863e+03 5.1419e-08 3.4849e-01 6.5151e-01 4.2392e+03 3.4459e+03 3.5504e+02 1.4562e+02 1.0000e-03 1.0000e-03 6.7341e-03 1.7363e-03 3.5186e-01 9.1554e-02 7.9750e-02 4.6759e-02 2.4068e-02 1.9517e-02 3.7803e-01 9.6116e-03 3.3411e-03 5.8405e-01 1.2082e-01 9.0100e-02 4.5287e-02 2.0045e-02 1.3908e-02 1.1284e-01 +4.2000e-01 1.4000e+07 5.5315e+02 3.4940e+03 5.5834e-08 3.5574e-01 6.4426e-01 4.1447e+03 3.2153e+03 3.6794e+02 1.3304e+02 1.0000e-03 1.0000e-03 6.3570e-03 1.5798e-03 3.2615e-01 8.7288e-02 7.7465e-02 4.6228e-02 2.4191e-02 1.9928e-02 4.1082e-01 9.6802e-03 3.3655e-03 5.8837e-01 1.2163e-01 9.0586e-02 4.5438e-02 2.0053e-02 1.3857e-02 1.0702e-01 +4.4000e-01 1.3000e+07 5.5315e+02 3.2958e+03 6.1133e-08 3.5852e-01 6.4148e-01 4.0495e+03 2.9853e+03 3.7978e+02 1.2155e+02 1.0000e-03 1.0000e-03 5.9751e-03 1.4335e-03 3.0124e-01 8.2844e-02 7.4873e-02 4.5463e-02 2.4183e-02 2.0235e-02 4.4376e-01 9.7340e-03 3.3801e-03 5.9135e-01 1.2231e-01 9.1061e-02 4.5633e-02 2.0103e-02 1.3854e-02 1.0258e-01 +4.6000e-01 1.2000e+07 5.5315e+02 3.0907e+03 6.7578e-08 3.5790e-01 6.4210e-01 3.9540e+03 2.7554e+03 3.9082e+02 1.1087e+02 1.0000e-03 1.0000e-03 5.5849e-03 1.2951e-03 2.7684e-01 7.8182e-02 7.1946e-02 4.4447e-02 2.4033e-02 2.0429e-02 4.7724e-01 9.7750e-03 3.3869e-03 5.9321e-01 1.2286e-01 9.1520e-02 4.5862e-02 2.0189e-02 1.3891e-02 9.9300e-02 +4.8000e-01 1.1000e+07 5.5315e+02 2.8777e+03 7.5541e-08 3.5429e-01 6.4571e-01 3.8587e+03 2.5254e+03 4.0126e+02 1.0084e+02 1.0000e-03 1.0000e-03 5.1842e-03 1.1631e-03 2.5279e-01 7.3272e-02 6.8649e-02 4.3152e-02 2.3725e-02 2.0495e-02 5.1157e-01 9.8039e-03 3.3870e-03 5.9409e-01 1.2331e-01 9.1956e-02 4.6116e-02 2.0305e-02 1.3963e-02 9.7067e-02 +5.0000e-01 1.0000e+07 5.5315e+02 2.6555e+03 8.5560e-08 3.4770e-01 6.5230e-01 3.7636e+03 2.2953e+03 4.1122e+02 9.1318e+01 1.0000e-03 1.0000e-03 4.7715e-03 1.0365e-03 2.2895e-01 6.8089e-02 6.4950e-02 4.1548e-02 2.3236e-02 2.0409e-02 5.4701e-01 9.8207e-03 3.3811e-03 5.9404e-01 1.2363e-01 9.2354e-02 4.6386e-02 2.0447e-02 1.4070e-02 9.5871e-02 +5.2000e-01 9.6040e+06 5.5315e+02 2.5647e+03 9.0263e-08 3.4420e-01 6.5580e-01 3.7261e+03 2.2041e+03 4.1505e+02 8.7668e+01 1.0000e-03 1.0000e-03 4.6044e-03 9.8766e-04 2.1955e-01 6.5955e-02 6.3366e-02 4.0820e-02 2.2986e-02 2.0327e-02 5.6140e-01 9.8238e-03 3.3771e-03 5.9376e-01 1.2372e-01 9.2498e-02 4.6496e-02 2.0509e-02 1.4120e-02 9.5699e-02 +5.4000e-01 9.2080e+06 5.5315e+02 2.4722e+03 9.5476e-08 3.4014e-01 6.5986e-01 3.6887e+03 2.1130e+03 4.1883e+02 8.4080e+01 1.0000e-03 1.0000e-03 4.4352e-03 9.3955e-04 2.1017e-01 6.3774e-02 6.1711e-02 4.0036e-02 2.2702e-02 2.0215e-02 5.7602e-01 9.8246e-03 3.3722e-03 5.9333e-01 1.2378e-01 9.2631e-02 4.6605e-02 2.0574e-02 1.4176e-02 9.5709e-02 +5.6000e-01 8.8120e+06 5.5315e+02 2.3778e+03 1.0128e-07 3.3548e-01 6.6452e-01 3.6513e+03 2.0218e+03 4.2256e+02 8.0548e+01 1.0000e-03 1.0000e-03 4.2638e-03 8.9211e-04 2.0080e-01 6.1544e-02 5.9982e-02 3.9192e-02 2.2381e-02 2.0070e-02 5.9088e-01 9.8232e-03 3.3663e-03 5.9273e-01 1.2382e-01 9.2752e-02 4.6714e-02 2.0643e-02 1.4236e-02 9.5913e-02 +5.8000e-01 8.4160e+06 5.5315e+02 2.2814e+03 1.0777e-07 3.3016e-01 6.6984e-01 3.6140e+03 1.9305e+03 4.2624e+02 7.7071e+01 1.0000e-03 1.0000e-03 4.0901e-03 8.4530e-04 1.9144e-01 5.9264e-02 5.8178e-02 3.8287e-02 2.2021e-02 1.9889e-02 6.0599e-01 9.8192e-03 3.3595e-03 5.9197e-01 1.2383e-01 9.2859e-02 4.6820e-02 2.0713e-02 1.4301e-02 9.6328e-02 +6.0000e-01 8.0200e+06 5.5315e+02 2.1830e+03 1.1506e-07 3.2409e-01 6.7591e-01 3.5767e+03 1.8393e+03 4.2988e+02 7.3643e+01 1.0000e-03 1.0000e-03 3.9141e-03 7.9910e-04 1.8209e-01 5.6933e-02 5.6295e-02 3.7317e-02 2.1620e-02 1.9671e-02 6.2137e-01 9.8124e-03 3.3516e-03 5.9102e-01 1.2381e-01 9.2948e-02 4.6923e-02 2.0785e-02 1.4370e-02 9.6973e-02 +6.2000e-01 7.6240e+06 5.5315e+02 2.0824e+03 1.2330e-07 3.1719e-01 6.8281e-01 3.5396e+03 1.7481e+03 4.3348e+02 7.0262e+01 1.0000e-03 1.0000e-03 3.7357e-03 7.5349e-04 1.7274e-01 5.4549e-02 5.4330e-02 3.6279e-02 2.1174e-02 1.9410e-02 6.3703e-01 9.8026e-03 3.3425e-03 5.8989e-01 1.2376e-01 9.3018e-02 4.7021e-02 2.0858e-02 1.4443e-02 9.7873e-02 +6.4000e-01 7.2280e+06 5.5315e+02 1.9796e+03 1.3267e-07 3.0934e-01 6.9066e-01 3.5025e+03 1.6569e+03 4.3704e+02 6.6926e+01 1.0000e-03 1.0000e-03 3.5550e-03 7.0844e-04 1.6339e-01 5.2111e-02 5.2282e-02 3.5169e-02 2.0681e-02 1.9105e-02 6.5300e-01 9.7894e-03 3.3322e-03 5.8853e-01 1.2366e-01 9.3064e-02 4.7112e-02 2.0932e-02 1.4519e-02 9.9057e-02 +6.6000e-01 6.8320e+06 5.5315e+02 1.8744e+03 1.4339e-07 3.0037e-01 6.9963e-01 3.4655e+03 1.5657e+03 4.4057e+02 6.3631e+01 1.0000e-03 1.0000e-03 3.3719e-03 6.6393e-04 1.5405e-01 4.9619e-02 5.0148e-02 3.3986e-02 2.0138e-02 1.8751e-02 6.6928e-01 9.7724e-03 3.3206e-03 5.8694e-01 1.2352e-01 9.3081e-02 4.7194e-02 2.1005e-02 1.4599e-02 1.0057e-01 +6.8000e-01 6.4360e+06 5.5315e+02 1.7667e+03 1.5574e-07 2.9011e-01 7.0989e-01 3.4286e+03 1.4746e+03 4.4406e+02 6.0375e+01 1.0000e-03 1.0000e-03 3.1863e-03 6.1996e-04 1.4470e-01 4.7071e-02 4.7924e-02 3.2724e-02 1.9542e-02 1.8343e-02 6.8589e-01 9.7511e-03 3.3075e-03 5.8508e-01 1.2332e-01 9.3064e-02 4.7263e-02 2.1075e-02 1.4681e-02 1.0245e-01 +7.0000e-01 6.0400e+06 5.5315e+02 1.6564e+03 1.7008e-07 2.7830e-01 7.2170e-01 3.3917e+03 1.3835e+03 4.4753e+02 5.7157e+01 1.0000e-03 1.0000e-03 2.9982e-03 5.7649e-04 1.3535e-01 4.4467e-02 4.5609e-02 3.1380e-02 1.8888e-02 1.7878e-02 7.0285e-01 9.7246e-03 3.2926e-03 5.8291e-01 1.2307e-01 9.3006e-02 4.7317e-02 2.1143e-02 1.4765e-02 1.0477e-01 +7.2000e-01 5.6440e+06 5.5315e+02 1.5435e+03 1.8691e-07 2.6461e-01 7.3539e-01 3.3549e+03 1.2924e+03 4.5098e+02 5.3973e+01 1.0000e-03 1.0000e-03 2.8076e-03 5.3353e-04 1.2600e-01 4.1804e-02 4.3198e-02 2.9950e-02 1.8174e-02 1.7349e-02 7.2018e-01 9.6922e-03 3.2757e-03 5.8039e-01 1.2274e-01 9.2897e-02 4.7349e-02 2.1205e-02 1.4849e-02 1.0761e-01 +7.4000e-01 5.2480e+06 5.5315e+02 1.4279e+03 2.0685e-07 2.4862e-01 7.5138e-01 3.3182e+03 1.2015e+03 4.5440e+02 5.0823e+01 1.0000e-03 1.0000e-03 2.6145e-03 4.9105e-04 1.1665e-01 3.9083e-02 4.0689e-02 2.8430e-02 1.7394e-02 1.6752e-02 7.3790e-01 9.6527e-03 3.2564e-03 5.7743e-01 1.2232e-01 9.2726e-02 4.7355e-02 2.1258e-02 1.4931e-02 1.1107e-01 +7.6000e-01 4.8520e+06 5.5315e+02 1.3096e+03 2.3076e-07 2.2976e-01 7.7024e-01 3.2816e+03 1.1106e+03 4.5780e+02 4.7704e+01 1.0000e-03 1.0000e-03 2.4189e-03 4.4905e-04 1.0729e-01 3.6303e-02 3.8078e-02 2.6816e-02 1.6545e-02 1.6080e-02 7.5602e-01 9.6045e-03 3.2343e-03 5.7396e-01 1.2179e-01 9.2476e-02 4.7325e-02 2.1300e-02 1.5010e-02 1.1530e-01 +7.8000e-01 4.4560e+06 5.5315e+02 1.1886e+03 2.5984e-07 2.0720e-01 7.9280e-01 3.2450e+03 1.0197e+03 4.6118e+02 4.4615e+01 1.0000e-03 1.0000e-03 2.2207e-03 4.0751e-04 9.7930e-02 3.3461e-02 3.5364e-02 2.5103e-02 1.5621e-02 1.5325e-02 7.7457e-01 9.5455e-03 3.2086e-03 5.6984e-01 1.2113e-01 9.2127e-02 4.7249e-02 2.1325e-02 1.5082e-02 1.2049e-01 +8.0000e-01 4.0600e+06 5.5315e+02 1.0651e+03 2.9580e-07 1.7982e-01 8.2018e-01 3.2085e+03 9.2899e+02 4.6454e+02 4.1554e+01 1.0000e-03 1.0000e-03 2.0200e-03 3.6643e-04 8.8564e-02 3.0559e-02 3.2542e-02 2.3287e-02 1.4618e-02 1.4480e-02 7.9356e-01 9.4728e-03 3.1784e-03 5.6492e-01 1.2029e-01 9.1650e-02 4.7111e-02 2.1326e-02 1.5142e-02 1.2691e-01 +8.2000e-01 3.6640e+06 5.5315e+02 9.3920e+02 3.4116e-07 1.4592e-01 8.5408e-01 3.1720e+03 8.3838e+02 4.6788e+02 3.8520e+01 1.0000e-03 1.0000e-03 1.8167e-03 3.2579e-04 7.9193e-02 2.7594e-02 2.9610e-02 2.1362e-02 1.3529e-02 1.3537e-02 8.1303e-01 9.3823e-03 3.1423e-03 5.5894e-01 1.1923e-01 9.1002e-02 4.6890e-02 2.1292e-02 1.5183e-02 1.3494e-01 +8.4000e-01 3.2680e+06 5.5315e+02 8.1147e+02 3.9978e-07 1.0291e-01 8.9709e-01 3.1356e+03 7.4788e+02 4.7122e+02 3.5511e+01 1.0000e-03 1.0000e-03 1.6109e-03 2.8560e-04 6.9819e-02 2.4566e-02 2.6564e-02 1.9322e-02 1.2350e-02 1.2486e-02 8.3300e-01 9.2678e-03 3.0984e-03 5.5155e-01 1.1786e-01 9.0123e-02 4.6552e-02 2.1210e-02 1.5195e-02 1.4514e-01 +8.6000e-01 2.8720e+06 5.5315e+02 6.8256e+02 4.7788e-07 4.6565e-02 9.5343e-01 3.0992e+03 6.5752e+02 4.7454e+02 3.2526e+01 1.0000e-03 1.0000e-03 1.4025e-03 2.4585e-04 6.0440e-02 2.1475e-02 2.3401e-02 1.7164e-02 1.1073e-02 1.1316e-02 8.5348e-01 9.1199e-03 3.0435e-03 5.4218e-01 1.1607e-01 8.8918e-02 4.6049e-02 2.1055e-02 1.5160e-02 1.5840e-01 +8.8000e-01 2.4760e+06 5.5315e+02 5.6562e+02 4.2278e-07 0.0000e+00 1.0000e+00 5.6562e+02 5.6562e+02 2.8890e+01 2.8890e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.0000e-01 2.0800e+06 5.5315e+02 4.7157e+02 5.0008e-07 0.0000e+00 1.0000e+00 4.7157e+02 4.7157e+02 2.4087e+01 2.4087e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.2000e-01 1.6840e+06 5.5315e+02 3.7886e+02 6.1350e-07 0.0000e+00 1.0000e+00 3.7886e+02 3.7886e+02 1.9351e+01 1.9351e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.4000e-01 1.2880e+06 5.5315e+02 2.8750e+02 7.9638e-07 0.0000e+00 1.0000e+00 2.8750e+02 2.8750e+02 1.4685e+01 1.4685e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.6000e-01 8.9200e+05 5.5315e+02 1.9753e+02 1.1413e-06 0.0000e+00 1.0000e+00 1.9753e+02 1.9753e+02 1.0089e+01 1.0089e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.8000e-01 4.9600e+05 5.5315e+02 1.0895e+02 2.0366e-06 0.0000e+00 1.0000e+00 1.0895e+02 1.0895e+02 5.5650e+00 5.5650e+00 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0000e+00 1.0000e+05 5.5315e+02 2.1788e+01 1.0021e-05 0.0000e+00 1.0000e+00 2.1788e+01 2.1788e+01 1.1129e+00 1.1129e+00 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0200e+00 4.9600e+05 5.8315e+02 1.0310e+02 2.0316e-06 0.0000e+00 1.0000e+00 1.0310e+02 1.0310e+02 5.2658e+00 5.2658e+00 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0400e+00 8.9200e+05 5.8315e+02 1.8653e+02 1.1362e-06 0.0000e+00 1.0000e+00 1.8653e+02 1.8653e+02 9.5276e+00 9.5276e+00 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0600e+00 1.2880e+06 5.8315e+02 2.7095e+02 7.9121e-07 0.0000e+00 1.0000e+00 2.7095e+02 2.7095e+02 1.3839e+01 1.3839e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0800e+00 1.6840e+06 5.8315e+02 3.5631e+02 6.0826e-07 0.0000e+00 1.0000e+00 3.5631e+02 3.5631e+02 1.8199e+01 1.8199e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1000e+00 2.0800e+06 5.8315e+02 4.4259e+02 4.9480e-07 0.0000e+00 1.0000e+00 4.4259e+02 4.4259e+02 2.2606e+01 2.2606e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1200e+00 2.4760e+06 5.8315e+02 5.2974e+02 4.1747e-07 0.0000e+00 1.0000e+00 5.2974e+02 5.2974e+02 2.7058e+01 2.7058e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1400e+00 2.8720e+06 5.8315e+02 6.1772e+02 3.6131e-07 0.0000e+00 1.0000e+00 6.1772e+02 6.1772e+02 3.1552e+01 3.1552e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1600e+00 3.2680e+06 5.8315e+02 7.0649e+02 3.1862e-07 0.0000e+00 1.0000e+00 7.0649e+02 7.0649e+02 3.6085e+01 3.6085e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1800e+00 3.6640e+06 5.8315e+02 7.9598e+02 2.8501e-07 0.0000e+00 1.0000e+00 7.9598e+02 7.9598e+02 4.0656e+01 4.0656e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2000e+00 4.0600e+06 5.8315e+02 8.8614e+02 2.5781e-07 0.0000e+00 1.0000e+00 8.8614e+02 8.8614e+02 4.5262e+01 4.5262e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2200e+00 4.4560e+06 5.8315e+02 9.7690e+02 2.3532e-07 0.0000e+00 1.0000e+00 9.7690e+02 9.7690e+02 4.9897e+01 4.9897e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2400e+00 4.8520e+06 5.8315e+02 1.0682e+03 2.1637e-07 0.0000e+00 1.0000e+00 1.0682e+03 1.0682e+03 5.4560e+01 5.4560e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2600e+00 5.2480e+06 5.8315e+02 1.1599e+03 2.0016e-07 0.0000e+00 1.0000e+00 1.1599e+03 1.1599e+03 5.9246e+01 5.9246e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2800e+00 5.6440e+06 5.8315e+02 1.2520e+03 1.8609e-07 0.0000e+00 1.0000e+00 1.2520e+03 1.2520e+03 6.3950e+01 6.3950e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3000e+00 6.0400e+06 5.8315e+02 1.3444e+03 1.7376e-07 0.0000e+00 1.0000e+00 1.3444e+03 1.3444e+03 6.8670e+01 6.8670e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3200e+00 6.4360e+06 5.8315e+02 1.4370e+03 1.6283e-07 0.0000e+00 1.0000e+00 1.4370e+03 1.4370e+03 7.3399e+01 7.3399e+01 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3400e+00 6.8320e+06 5.8315e+02 1.5350e+03 1.6531e-07 9.9906e-03 9.9001e-01 3.1587e+03 1.5271e+03 3.9889e+02 7.7535e+01 1.0000e-03 1.0000e-03 3.4224e-03 7.4676e-04 1.6566e-01 4.9631e-02 4.8032e-02 3.1356e-02 1.8029e-02 1.6397e-02 6.6673e-01 9.0226e-03 3.0091e-03 5.3620e-01 1.1486e-01 8.8062e-02 4.5658e-02 2.0912e-02 1.5095e-02 1.6718e-01 +1.3600e+00 7.2280e+06 5.8315e+02 1.6347e+03 1.5254e-07 2.3264e-02 9.7674e-01 3.1909e+03 1.6159e+03 3.9472e+02 8.1397e+01 1.0000e-03 1.0000e-03 3.6195e-03 7.9902e-04 1.7618e-01 5.2282e-02 5.0247e-02 3.2572e-02 1.8594e-02 1.6785e-02 6.4892e-01 9.0522e-03 3.0213e-03 5.3818e-01 1.1520e-01 8.8265e-02 4.5726e-02 2.0922e-02 1.5084e-02 1.6455e-01 +1.3800e+00 7.6240e+06 5.8315e+02 1.7325e+03 1.4139e-07 3.3973e-02 9.6603e-01 3.2230e+03 1.7048e+03 3.9047e+02 8.5341e+01 1.0000e-03 1.0000e-03 3.8148e-03 8.5209e-04 1.8674e-01 5.4885e-02 5.2382e-02 3.3719e-02 1.9113e-02 1.7127e-02 6.3137e-01 9.0753e-03 3.0312e-03 5.3976e-01 1.1547e-01 8.8416e-02 4.5773e-02 2.0926e-02 1.5071e-02 1.6248e-01 +1.4000e+00 8.0200e+06 5.8315e+02 1.8287e+03 1.3160e-07 4.2388e-02 9.5761e-01 3.2551e+03 1.7939e+03 3.8614e+02 8.9374e+01 1.0000e-03 1.0000e-03 4.0084e-03 9.0604e-04 1.9734e-01 5.7441e-02 5.4439e-02 3.4800e-02 1.9586e-02 1.7425e-02 6.1405e-01 9.0928e-03 3.0389e-03 5.4097e-01 1.1566e-01 8.8522e-02 4.5801e-02 2.0924e-02 1.5057e-02 1.6093e-01 +1.4200e+00 8.4160e+06 5.8315e+02 1.9231e+03 1.2294e-07 4.8699e-02 9.5130e-01 3.2871e+03 1.8831e+03 3.8171e+02 9.3504e+01 1.0000e-03 1.0000e-03 4.2003e-03 9.6092e-04 2.0799e-01 5.9953e-02 5.6423e-02 3.5817e-02 2.0018e-02 1.7682e-02 5.9696e-01 9.1051e-03 3.0446e-03 5.4185e-01 1.1580e-01 8.8589e-02 4.5814e-02 2.0919e-02 1.5043e-02 1.5984e-01 +1.4400e+00 8.8120e+06 5.8315e+02 2.0159e+03 1.1524e-07 5.3029e-02 9.4697e-01 3.3191e+03 1.9726e+03 3.7719e+02 9.7741e+01 1.0000e-03 1.0000e-03 4.3908e-03 1.0168e-03 2.1870e-01 6.2421e-02 5.8334e-02 3.6772e-02 2.0409e-02 1.7900e-02 5.8006e-01 9.1125e-03 3.0484e-03 5.4242e-01 1.1587e-01 8.8622e-02 4.5816e-02 2.0912e-02 1.5032e-02 1.5917e-01 +1.4600e+00 9.2080e+06 5.8315e+02 2.1072e+03 1.0837e-07 5.5445e-02 9.4456e-01 3.3510e+03 2.0622e+03 3.7256e+02 1.0209e+02 1.0000e-03 1.0000e-03 4.5799e-03 1.0738e-03 2.2947e-01 6.4848e-02 6.0176e-02 3.7670e-02 2.0762e-02 1.8083e-02 5.6333e-01 9.1155e-03 3.0503e-03 5.4268e-01 1.1590e-01 8.8625e-02 4.5807e-02 2.0904e-02 1.5022e-02 1.5890e-01 +1.4800e+00 9.6040e+06 5.8315e+02 2.1968e+03 1.0221e-07 5.5953e-02 9.4405e-01 3.3827e+03 2.1521e+03 3.6780e+02 1.0657e+02 1.0000e-03 1.0000e-03 4.7678e-03 1.1319e-03 2.4033e-01 6.7236e-02 6.1951e-02 3.8510e-02 2.1079e-02 1.8232e-02 5.4676e-01 9.1142e-03 3.0504e-03 5.4265e-01 1.1588e-01 8.8600e-02 4.5791e-02 2.0895e-02 1.5015e-02 1.5901e-01 +1.5000e+00 1.0000e+07 5.8315e+02 2.2850e+03 9.6662e-08 5.4503e-02 9.4550e-01 3.4142e+03 2.2423e+03 3.6290e+02 1.1120e+02 1.0000e-03 1.0000e-03 4.9547e-03 1.1914e-03 2.5129e-01 6.9588e-02 6.3661e-02 3.9297e-02 2.1361e-02 1.8349e-02 5.3031e-01 9.1088e-03 3.0486e-03 5.4232e-01 1.1581e-01 8.8552e-02 4.5770e-02 2.0888e-02 1.5013e-02 1.5949e-01 +1.5200e+00 1.1000e+07 5.8315e+02 2.5015e+03 8.4869e-08 4.1127e-02 9.5887e-01 3.4926e+03 2.4714e+03 3.4980e+02 1.2364e+02 1.0000e-03 1.0000e-03 5.4241e-03 1.3483e-03 2.7951e-01 7.5387e-02 6.7713e-02 4.1056e-02 2.1929e-02 1.8512e-02 4.8912e-01 9.0766e-03 3.0354e-03 5.4017e-01 1.1544e-01 8.8332e-02 4.5697e-02 2.0878e-02 1.5027e-02 1.6235e-01 +1.5400e+00 1.2000e+07 5.8315e+02 2.7099e+03 7.5536e-08 9.4342e-03 9.9057e-01 3.5683e+03 2.7037e+03 3.3530e+02 1.3750e+02 1.0000e-03 1.0000e-03 5.8943e-03 1.5176e-03 3.0890e-01 8.1041e-02 7.1421e-02 4.2512e-02 2.2304e-02 1.8499e-02 4.4791e-01 9.0160e-03 3.0076e-03 5.3586e-01 1.1477e-01 8.7985e-02 4.5616e-02 2.0893e-02 1.5082e-02 1.6776e-01 +1.5600e+00 1.3000e+07 5.8315e+02 2.9203e+03 7.1624e-08 0.0000e+00 1.0000e+00 2.9203e+03 2.9203e+03 1.4916e+02 1.4916e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5800e+00 1.4000e+07 5.8315e+02 3.1258e+03 6.4571e-08 0.0000e+00 1.0000e+00 3.1258e+03 3.1258e+03 1.5966e+02 1.5966e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6000e+00 1.5000e+07 5.8315e+02 3.3239e+03 5.8427e-08 0.0000e+00 1.0000e+00 3.3239e+03 3.3239e+03 1.6977e+02 1.6977e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6200e+00 1.6000e+07 5.8315e+02 3.5142e+03 5.3055e-08 0.0000e+00 1.0000e+00 3.5142e+03 3.5142e+03 1.7950e+02 1.7950e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6400e+00 1.7000e+07 5.8315e+02 3.6968e+03 4.8343e-08 0.0000e+00 1.0000e+00 3.6968e+03 3.6968e+03 1.8882e+02 1.8882e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6600e+00 1.8000e+07 5.8315e+02 3.8717e+03 4.4199e-08 0.0000e+00 1.0000e+00 3.8717e+03 3.8717e+03 1.9776e+02 1.9776e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6800e+00 1.9000e+07 5.8315e+02 4.0391e+03 4.0543e-08 0.0000e+00 1.0000e+00 4.0391e+03 4.0391e+03 2.0631e+02 2.0631e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7000e+00 2.0000e+07 5.8315e+02 4.1993e+03 3.7310e-08 0.0000e+00 1.0000e+00 4.1993e+03 4.1993e+03 2.1449e+02 2.1449e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7200e+00 2.1000e+07 5.8315e+02 4.3526e+03 3.4441e-08 0.0000e+00 1.0000e+00 4.3526e+03 4.3526e+03 2.2232e+02 2.2232e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7400e+00 2.2000e+07 5.8315e+02 4.4992e+03 3.1889e-08 0.0000e+00 1.0000e+00 4.4992e+03 4.4992e+03 2.2981e+02 2.2981e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7600e+00 2.3000e+07 5.8315e+02 4.6396e+03 2.9611e-08 0.0000e+00 1.0000e+00 4.6396e+03 4.6396e+03 2.3698e+02 2.3698e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7800e+00 2.4000e+07 5.8315e+02 4.7741e+03 2.7572e-08 0.0000e+00 1.0000e+00 4.7741e+03 4.7741e+03 2.4385e+02 2.4385e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8000e+00 2.5000e+07 5.8315e+02 4.9030e+03 2.5740e-08 0.0000e+00 1.0000e+00 4.9030e+03 4.9030e+03 2.5043e+02 2.5043e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8200e+00 2.6000e+07 5.8315e+02 5.0266e+03 2.4091e-08 0.0000e+00 1.0000e+00 5.0266e+03 5.0266e+03 2.5675e+02 2.5675e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8400e+00 2.7000e+07 5.8315e+02 5.1453e+03 2.2601e-08 0.0000e+00 1.0000e+00 5.1453e+03 5.1453e+03 2.6281e+02 2.6281e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8600e+00 2.8000e+07 5.8315e+02 5.2593e+03 2.1251e-08 0.0000e+00 1.0000e+00 5.2593e+03 5.2593e+03 2.6863e+02 2.6863e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8800e+00 2.9000e+07 5.8315e+02 5.3689e+03 2.0024e-08 0.0000e+00 1.0000e+00 5.3689e+03 5.3689e+03 2.7423e+02 2.7423e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9000e+00 3.0000e+07 5.8315e+02 5.4744e+03 1.8906e-08 0.0000e+00 1.0000e+00 5.4744e+03 5.4744e+03 2.7962e+02 2.7962e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9200e+00 3.1000e+07 5.8315e+02 5.5760e+03 1.7885e-08 0.0000e+00 1.0000e+00 5.5760e+03 5.5760e+03 2.8481e+02 2.8481e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9400e+00 3.2000e+07 5.8315e+02 5.6739e+03 1.6949e-08 0.0000e+00 1.0000e+00 5.6739e+03 5.6739e+03 2.8981e+02 2.8981e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9600e+00 3.3000e+07 5.8315e+02 5.7684e+03 1.6090e-08 0.0000e+00 1.0000e+00 5.7684e+03 5.7684e+03 2.9463e+02 2.9463e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9800e+00 3.4000e+07 5.8315e+02 5.8596e+03 1.5299e-08 0.0000e+00 1.0000e+00 5.8596e+03 5.8596e+03 2.9929e+02 2.9929e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0000e+00 3.5000e+07 5.8315e+02 5.9477e+03 1.4569e-08 0.0000e+00 1.0000e+00 5.9477e+03 5.9477e+03 3.0379e+02 3.0379e+02 1.0000e-03 1.0000e-03 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT_Compositional_liveOilSRKLBC.txt b/src/coreComponents/unitTests/constitutiveTests/testPVT_Compositional_liveOilSRKLBC.txt new file mode 100644 index 00000000000..aad47b3119c --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT_Compositional_liveOilSRKLBC.txt @@ -0,0 +1,1012 @@ +# column 1 = time +# column 2 = pressure +# column 3 = temperature +# column 4 = density +# column 5 = total compressibility +# columns 6-7 = phase fractions +# columns 8-9 = phase densities +# columns 10-11 = phase mass densities +# columns 12-13 = phase viscosities +# columns 14-22 = oil phase fractions [CO2, N2, C1, C2, C3, C4, C5, C6, C7+] +# columns 23-31 = gas phase fractions [CO2, N2, C1, C2, C3, C4, C5, C6, C7+] +0.0000e+00 3.5000e+07 5.5315e+02 6.3045e+03 1.3265e-08 1.0000e+00 0.0000e+00 6.3045e+03 6.3045e+03 3.2202e+02 3.2202e+02 4.1026e-05 4.1026e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +2.0000e-03 3.4900e+07 5.5315e+02 6.2961e+03 1.3330e-08 1.0000e+00 0.0000e+00 6.2961e+03 6.2961e+03 3.2159e+02 3.2159e+02 4.0960e-05 4.0960e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +4.0000e-03 3.4800e+07 5.5315e+02 6.2877e+03 1.3395e-08 1.0000e+00 0.0000e+00 6.2877e+03 6.2877e+03 3.2116e+02 3.2116e+02 4.0894e-05 4.0894e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +6.0000e-03 3.4700e+07 5.5315e+02 6.2792e+03 1.3461e-08 1.0000e+00 0.0000e+00 6.2792e+03 6.2792e+03 3.2073e+02 3.2073e+02 4.0828e-05 4.0828e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +8.0000e-03 3.4600e+07 5.5315e+02 6.2708e+03 1.3527e-08 1.0000e+00 0.0000e+00 6.2708e+03 6.2708e+03 3.2029e+02 3.2029e+02 4.0762e-05 4.0762e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.0000e-02 3.4500e+07 5.5315e+02 6.2623e+03 1.3594e-08 1.0000e+00 0.0000e+00 6.2623e+03 6.2623e+03 3.1986e+02 3.1986e+02 4.0696e-05 4.0696e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.2000e-02 3.4400e+07 5.5315e+02 6.2537e+03 1.3661e-08 1.0000e+00 0.0000e+00 6.2537e+03 6.2537e+03 3.1942e+02 3.1942e+02 4.0629e-05 4.0629e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.4000e-02 3.4300e+07 5.5315e+02 6.2452e+03 1.3729e-08 1.0000e+00 0.0000e+00 6.2452e+03 6.2452e+03 3.1899e+02 3.1899e+02 4.0563e-05 4.0563e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.6000e-02 3.4200e+07 5.5315e+02 6.2366e+03 1.3797e-08 1.0000e+00 0.0000e+00 6.2366e+03 6.2366e+03 3.1855e+02 3.1855e+02 4.0496e-05 4.0496e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.8000e-02 3.4100e+07 5.5315e+02 6.2280e+03 1.3866e-08 1.0000e+00 0.0000e+00 6.2280e+03 6.2280e+03 3.1811e+02 3.1811e+02 4.0429e-05 4.0429e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +2.0000e-02 3.4000e+07 5.5315e+02 6.2193e+03 1.3936e-08 1.0000e+00 0.0000e+00 6.2193e+03 6.2193e+03 3.1767e+02 3.1767e+02 4.0362e-05 4.0362e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +2.2000e-02 3.3900e+07 5.5315e+02 6.2106e+03 1.4006e-08 1.0000e+00 0.0000e+00 6.2106e+03 6.2106e+03 3.1722e+02 3.1722e+02 4.0295e-05 4.0295e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +2.4000e-02 3.3800e+07 5.5315e+02 6.2019e+03 1.4077e-08 1.0000e+00 0.0000e+00 6.2019e+03 6.2019e+03 3.1678e+02 3.1678e+02 4.0228e-05 4.0228e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +2.6000e-02 3.3700e+07 5.5315e+02 6.1932e+03 1.4148e-08 1.0000e+00 0.0000e+00 6.1932e+03 6.1932e+03 3.1633e+02 3.1633e+02 4.0160e-05 4.0160e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +2.8000e-02 3.3600e+07 5.5315e+02 6.1844e+03 1.4220e-08 1.0000e+00 0.0000e+00 6.1844e+03 6.1844e+03 3.1588e+02 3.1588e+02 4.0093e-05 4.0093e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +3.0000e-02 3.3500e+07 5.5315e+02 6.1756e+03 1.4293e-08 1.0000e+00 0.0000e+00 6.1756e+03 6.1756e+03 3.1543e+02 3.1543e+02 4.0025e-05 4.0025e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +3.2000e-02 3.3400e+07 5.5315e+02 6.1668e+03 1.4366e-08 1.0000e+00 0.0000e+00 6.1668e+03 6.1668e+03 3.1498e+02 3.1498e+02 3.9957e-05 3.9957e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +3.4000e-02 3.3300e+07 5.5315e+02 6.1579e+03 1.4440e-08 1.0000e+00 0.0000e+00 6.1579e+03 6.1579e+03 3.1453e+02 3.1453e+02 3.9889e-05 3.9889e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +3.6000e-02 3.3200e+07 5.5315e+02 6.1490e+03 1.4514e-08 1.0000e+00 0.0000e+00 6.1490e+03 6.1490e+03 3.1407e+02 3.1407e+02 3.9821e-05 3.9821e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +3.8000e-02 3.3100e+07 5.5315e+02 6.1400e+03 1.4589e-08 1.0000e+00 0.0000e+00 6.1400e+03 6.1400e+03 3.1362e+02 3.1362e+02 3.9753e-05 3.9753e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +4.0000e-02 3.3000e+07 5.5315e+02 6.1311e+03 1.4665e-08 1.0000e+00 0.0000e+00 6.1311e+03 6.1311e+03 3.1316e+02 3.1316e+02 3.9684e-05 3.9684e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +4.2000e-02 3.2900e+07 5.5315e+02 6.1220e+03 1.4741e-08 1.0000e+00 0.0000e+00 6.1220e+03 6.1220e+03 3.1270e+02 3.1270e+02 3.9616e-05 3.9616e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +4.4000e-02 3.2800e+07 5.5315e+02 6.1130e+03 1.4818e-08 1.0000e+00 0.0000e+00 6.1130e+03 6.1130e+03 3.1224e+02 3.1224e+02 3.9547e-05 3.9547e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +4.6000e-02 3.2700e+07 5.5315e+02 6.1039e+03 1.4896e-08 1.0000e+00 0.0000e+00 6.1039e+03 6.1039e+03 3.1177e+02 3.1177e+02 3.9478e-05 3.9478e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +4.8000e-02 3.2600e+07 5.5315e+02 6.0948e+03 1.4974e-08 1.0000e+00 0.0000e+00 6.0948e+03 6.0948e+03 3.1131e+02 3.1131e+02 3.9409e-05 3.9409e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +5.0000e-02 3.2500e+07 5.5315e+02 6.0857e+03 1.5053e-08 1.0000e+00 0.0000e+00 6.0857e+03 6.0857e+03 3.1084e+02 3.1084e+02 3.9340e-05 3.9340e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +5.2000e-02 3.2400e+07 5.5315e+02 6.0765e+03 1.5133e-08 1.0000e+00 0.0000e+00 6.0765e+03 6.0765e+03 3.1037e+02 3.1037e+02 3.9270e-05 3.9270e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +5.4000e-02 3.2300e+07 5.5315e+02 6.0673e+03 1.5213e-08 1.0000e+00 0.0000e+00 6.0673e+03 6.0673e+03 3.0990e+02 3.0990e+02 3.9201e-05 3.9201e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +5.6000e-02 3.2200e+07 5.5315e+02 6.0580e+03 1.5295e-08 1.0000e+00 0.0000e+00 6.0580e+03 6.0580e+03 3.0943e+02 3.0943e+02 3.9131e-05 3.9131e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +5.8000e-02 3.2100e+07 5.5315e+02 6.0488e+03 1.5376e-08 1.0000e+00 0.0000e+00 6.0488e+03 6.0488e+03 3.0895e+02 3.0895e+02 3.9061e-05 3.9061e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +6.0000e-02 3.2000e+07 5.5315e+02 6.0394e+03 1.5459e-08 1.0000e+00 0.0000e+00 6.0394e+03 6.0394e+03 3.0848e+02 3.0848e+02 3.8991e-05 3.8991e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +6.2000e-02 3.1900e+07 5.5315e+02 6.0301e+03 1.5542e-08 1.0000e+00 0.0000e+00 6.0301e+03 6.0301e+03 3.0800e+02 3.0800e+02 3.8921e-05 3.8921e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +6.4000e-02 3.1800e+07 5.5315e+02 6.0207e+03 1.5626e-08 1.0000e+00 0.0000e+00 6.0207e+03 6.0207e+03 3.0752e+02 3.0752e+02 3.8851e-05 3.8851e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +6.6000e-02 3.1700e+07 5.5315e+02 6.0113e+03 1.5711e-08 1.0000e+00 0.0000e+00 6.0113e+03 6.0113e+03 3.0704e+02 3.0704e+02 3.8780e-05 3.8780e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +6.8000e-02 3.1600e+07 5.5315e+02 6.0018e+03 1.5797e-08 1.0000e+00 0.0000e+00 6.0018e+03 6.0018e+03 3.0656e+02 3.0656e+02 3.8709e-05 3.8709e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +7.0000e-02 3.1500e+07 5.5315e+02 5.9923e+03 1.5883e-08 1.0000e+00 0.0000e+00 5.9923e+03 5.9923e+03 3.0607e+02 3.0607e+02 3.8639e-05 3.8639e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +7.2000e-02 3.1400e+07 5.5315e+02 5.9828e+03 1.5970e-08 1.0000e+00 0.0000e+00 5.9828e+03 5.9828e+03 3.0558e+02 3.0558e+02 3.8568e-05 3.8568e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +7.4000e-02 3.1300e+07 5.5315e+02 5.9732e+03 1.6058e-08 1.0000e+00 0.0000e+00 5.9732e+03 5.9732e+03 3.0509e+02 3.0509e+02 3.8496e-05 3.8496e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +7.6000e-02 3.1200e+07 5.5315e+02 5.9636e+03 1.6147e-08 1.0000e+00 0.0000e+00 5.9636e+03 5.9636e+03 3.0460e+02 3.0460e+02 3.8425e-05 3.8425e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +7.8000e-02 3.1100e+07 5.5315e+02 5.9539e+03 1.6236e-08 1.0000e+00 0.0000e+00 5.9539e+03 5.9539e+03 3.0411e+02 3.0411e+02 3.8354e-05 3.8354e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +8.0000e-02 3.1000e+07 5.5315e+02 5.9442e+03 1.6327e-08 1.0000e+00 0.0000e+00 5.9442e+03 5.9442e+03 3.0362e+02 3.0362e+02 3.8282e-05 3.8282e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +8.2000e-02 3.0900e+07 5.5315e+02 5.9345e+03 1.6418e-08 1.0000e+00 0.0000e+00 5.9345e+03 5.9345e+03 3.0312e+02 3.0312e+02 3.8210e-05 3.8210e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +8.4000e-02 3.0800e+07 5.5315e+02 5.9248e+03 1.6510e-08 1.0000e+00 0.0000e+00 5.9248e+03 5.9248e+03 3.0262e+02 3.0262e+02 3.8138e-05 3.8138e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +8.6000e-02 3.0700e+07 5.5315e+02 5.9150e+03 1.6602e-08 1.0000e+00 0.0000e+00 5.9150e+03 5.9150e+03 3.0212e+02 3.0212e+02 3.8066e-05 3.8066e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +8.8000e-02 3.0600e+07 5.5315e+02 5.9051e+03 1.6696e-08 1.0000e+00 0.0000e+00 5.9051e+03 5.9051e+03 3.0162e+02 3.0162e+02 3.7993e-05 3.7993e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +9.0000e-02 3.0500e+07 5.5315e+02 5.8952e+03 1.6791e-08 1.0000e+00 0.0000e+00 5.8952e+03 5.8952e+03 3.0111e+02 3.0111e+02 3.7921e-05 3.7921e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +9.2000e-02 3.0400e+07 5.5315e+02 5.8853e+03 1.6886e-08 1.0000e+00 0.0000e+00 5.8853e+03 5.8853e+03 3.0061e+02 3.0061e+02 3.7848e-05 3.7848e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +9.4000e-02 3.0300e+07 5.5315e+02 5.8754e+03 1.6982e-08 1.0000e+00 0.0000e+00 5.8754e+03 5.8754e+03 3.0010e+02 3.0010e+02 3.7775e-05 3.7775e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +9.6000e-02 3.0200e+07 5.5315e+02 5.8654e+03 1.7080e-08 1.0000e+00 0.0000e+00 5.8654e+03 5.8654e+03 2.9959e+02 2.9959e+02 3.7702e-05 3.7702e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +9.8000e-02 3.0100e+07 5.5315e+02 5.8553e+03 1.7178e-08 1.0000e+00 0.0000e+00 5.8553e+03 5.8553e+03 2.9907e+02 2.9907e+02 3.7629e-05 3.7629e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.0000e-01 3.0000e+07 5.5315e+02 5.8453e+03 1.7277e-08 1.0000e+00 0.0000e+00 5.8453e+03 5.8453e+03 2.9856e+02 2.9856e+02 3.7556e-05 3.7556e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.0200e-01 2.9900e+07 5.5315e+02 5.8351e+03 1.7377e-08 1.0000e+00 0.0000e+00 5.8351e+03 5.8351e+03 2.9804e+02 2.9804e+02 3.7482e-05 3.7482e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.0400e-01 2.9800e+07 5.5315e+02 5.8250e+03 1.7478e-08 1.0000e+00 0.0000e+00 5.8250e+03 5.8250e+03 2.9752e+02 2.9752e+02 3.7408e-05 3.7408e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.0600e-01 2.9700e+07 5.5315e+02 5.8148e+03 1.7580e-08 1.0000e+00 0.0000e+00 5.8148e+03 5.8148e+03 2.9700e+02 2.9700e+02 3.7334e-05 3.7334e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.0800e-01 2.9600e+07 5.5315e+02 5.8045e+03 1.7683e-08 1.0000e+00 0.0000e+00 5.8045e+03 5.8045e+03 2.9648e+02 2.9648e+02 3.7260e-05 3.7260e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.1000e-01 2.9500e+07 5.5315e+02 5.7942e+03 1.7787e-08 1.0000e+00 0.0000e+00 5.7942e+03 5.7942e+03 2.9595e+02 2.9595e+02 3.7186e-05 3.7186e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.1200e-01 2.9400e+07 5.5315e+02 5.7839e+03 1.7891e-08 1.0000e+00 0.0000e+00 5.7839e+03 5.7839e+03 2.9543e+02 2.9543e+02 3.7111e-05 3.7111e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.1400e-01 2.9300e+07 5.5315e+02 5.7735e+03 1.7997e-08 1.0000e+00 0.0000e+00 5.7735e+03 5.7735e+03 2.9490e+02 2.9490e+02 3.7037e-05 3.7037e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.1600e-01 2.9200e+07 5.5315e+02 5.7631e+03 1.8104e-08 1.0000e+00 0.0000e+00 5.7631e+03 5.7631e+03 2.9437e+02 2.9437e+02 3.6962e-05 3.6962e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.1800e-01 2.9100e+07 5.5315e+02 5.7527e+03 1.8212e-08 1.0000e+00 0.0000e+00 5.7527e+03 5.7527e+03 2.9383e+02 2.9383e+02 3.6887e-05 3.6887e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.2000e-01 2.9000e+07 5.5315e+02 5.7422e+03 1.8321e-08 1.0000e+00 0.0000e+00 5.7422e+03 5.7422e+03 2.9330e+02 2.9330e+02 3.6811e-05 3.6811e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.2200e-01 2.8900e+07 5.5315e+02 5.7316e+03 1.8431e-08 1.0000e+00 0.0000e+00 5.7316e+03 5.7316e+03 2.9276e+02 2.9276e+02 3.6736e-05 3.6736e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.2400e-01 2.8800e+07 5.5315e+02 5.7211e+03 1.8543e-08 1.0000e+00 0.0000e+00 5.7211e+03 5.7211e+03 2.9222e+02 2.9222e+02 3.6660e-05 3.6660e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.2600e-01 2.8700e+07 5.5315e+02 5.7104e+03 1.8655e-08 1.0000e+00 0.0000e+00 5.7104e+03 5.7104e+03 2.9167e+02 2.9167e+02 3.6584e-05 3.6584e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.2800e-01 2.8600e+07 5.5315e+02 5.6997e+03 1.8768e-08 1.0000e+00 0.0000e+00 5.6997e+03 5.6997e+03 2.9113e+02 2.9113e+02 3.6508e-05 3.6508e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.3000e-01 2.8500e+07 5.5315e+02 5.6890e+03 1.8883e-08 1.0000e+00 0.0000e+00 5.6890e+03 5.6890e+03 2.9058e+02 2.9058e+02 3.6432e-05 3.6432e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.3200e-01 2.8400e+07 5.5315e+02 5.6783e+03 1.8998e-08 1.0000e+00 0.0000e+00 5.6783e+03 5.6783e+03 2.9003e+02 2.9003e+02 3.6356e-05 3.6356e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.3400e-01 2.8300e+07 5.5315e+02 5.6675e+03 1.9115e-08 1.0000e+00 0.0000e+00 5.6675e+03 5.6675e+03 2.8948e+02 2.8948e+02 3.6279e-05 3.6279e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.3600e-01 2.8200e+07 5.5315e+02 5.6566e+03 1.9233e-08 1.0000e+00 0.0000e+00 5.6566e+03 5.6566e+03 2.8892e+02 2.8892e+02 3.6202e-05 3.6202e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.3800e-01 2.8100e+07 5.5315e+02 5.6457e+03 1.9352e-08 1.0000e+00 0.0000e+00 5.6457e+03 5.6457e+03 2.8837e+02 2.8837e+02 3.6125e-05 3.6125e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.4000e-01 2.8000e+07 5.5315e+02 5.6347e+03 1.9473e-08 1.0000e+00 0.0000e+00 5.6347e+03 5.6347e+03 2.8781e+02 2.8781e+02 3.6048e-05 3.6048e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.4200e-01 2.7900e+07 5.5315e+02 5.6237e+03 1.9594e-08 1.0000e+00 0.0000e+00 5.6237e+03 5.6237e+03 2.8725e+02 2.8725e+02 3.5971e-05 3.5971e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.4400e-01 2.7800e+07 5.5315e+02 5.6127e+03 1.9717e-08 1.0000e+00 0.0000e+00 5.6127e+03 5.6127e+03 2.8668e+02 2.8668e+02 3.5893e-05 3.5893e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.4600e-01 2.7700e+07 5.5315e+02 5.6016e+03 1.9841e-08 1.0000e+00 0.0000e+00 5.6016e+03 5.6016e+03 2.8612e+02 2.8612e+02 3.5815e-05 3.5815e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.4800e-01 2.7600e+07 5.5315e+02 5.5905e+03 1.9966e-08 1.0000e+00 0.0000e+00 5.5905e+03 5.5905e+03 2.8555e+02 2.8555e+02 3.5737e-05 3.5737e-05 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 +1.5000e-01 2.7500e+07 5.5315e+02 5.5793e+03 2.0093e-08 0.0000e+00 1.0000e+00 5.5793e+03 5.5793e+03 2.8498e+02 2.8498e+02 3.5659e-05 3.5659e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5200e-01 2.7400e+07 5.5315e+02 5.5681e+03 2.0221e-08 0.0000e+00 1.0000e+00 5.5681e+03 5.5681e+03 2.8440e+02 2.8440e+02 3.5581e-05 3.5581e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5400e-01 2.7300e+07 5.5315e+02 5.5568e+03 2.0350e-08 0.0000e+00 1.0000e+00 5.5568e+03 5.5568e+03 2.8383e+02 2.8383e+02 3.5502e-05 3.5502e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5600e-01 2.7200e+07 5.5315e+02 5.5454e+03 2.0481e-08 0.0000e+00 1.0000e+00 5.5454e+03 5.5454e+03 2.8325e+02 2.8325e+02 3.5423e-05 3.5423e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5800e-01 2.7100e+07 5.5315e+02 5.5341e+03 2.0613e-08 0.0000e+00 1.0000e+00 5.5341e+03 5.5341e+03 2.8266e+02 2.8266e+02 3.5344e-05 3.5344e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6000e-01 2.7000e+07 5.5315e+02 5.5226e+03 2.0746e-08 0.0000e+00 1.0000e+00 5.5226e+03 5.5226e+03 2.8208e+02 2.8208e+02 3.5265e-05 3.5265e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6200e-01 2.6900e+07 5.5315e+02 5.5111e+03 2.0881e-08 0.0000e+00 1.0000e+00 5.5111e+03 5.5111e+03 2.8149e+02 2.8149e+02 3.5185e-05 3.5185e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6400e-01 2.6800e+07 5.5315e+02 5.4996e+03 2.1017e-08 0.0000e+00 1.0000e+00 5.4996e+03 5.4996e+03 2.8091e+02 2.8091e+02 3.5106e-05 3.5106e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6600e-01 2.6700e+07 5.5315e+02 5.4880e+03 2.1154e-08 0.0000e+00 1.0000e+00 5.4880e+03 5.4880e+03 2.8031e+02 2.8031e+02 3.5026e-05 3.5026e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6800e-01 2.6600e+07 5.5315e+02 5.4764e+03 2.1293e-08 0.0000e+00 1.0000e+00 5.4764e+03 5.4764e+03 2.7972e+02 2.7972e+02 3.4946e-05 3.4946e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7000e-01 2.6500e+07 5.5315e+02 5.4647e+03 2.1434e-08 0.0000e+00 1.0000e+00 5.4647e+03 5.4647e+03 2.7912e+02 2.7912e+02 3.4865e-05 3.4865e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7200e-01 2.6400e+07 5.5315e+02 5.4530e+03 2.1576e-08 0.0000e+00 1.0000e+00 5.4530e+03 5.4530e+03 2.7852e+02 2.7852e+02 3.4785e-05 3.4785e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7400e-01 2.6300e+07 5.5315e+02 5.4412e+03 2.1719e-08 0.0000e+00 1.0000e+00 5.4412e+03 5.4412e+03 2.7792e+02 2.7792e+02 3.4704e-05 3.4704e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7600e-01 2.6200e+07 5.5315e+02 5.4293e+03 2.1864e-08 0.0000e+00 1.0000e+00 5.4293e+03 5.4293e+03 2.7732e+02 2.7732e+02 3.4623e-05 3.4623e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7800e-01 2.6100e+07 5.5315e+02 5.4174e+03 2.2011e-08 0.0000e+00 1.0000e+00 5.4174e+03 5.4174e+03 2.7671e+02 2.7671e+02 3.4542e-05 3.4542e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8000e-01 2.6000e+07 5.5315e+02 5.4055e+03 2.2159e-08 0.0000e+00 1.0000e+00 5.4055e+03 5.4055e+03 2.7610e+02 2.7610e+02 3.4461e-05 3.4461e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8200e-01 2.5900e+07 5.5315e+02 5.3935e+03 2.2309e-08 0.0000e+00 1.0000e+00 5.3935e+03 5.3935e+03 2.7548e+02 2.7548e+02 3.4379e-05 3.4379e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8400e-01 2.5800e+07 5.5315e+02 5.3814e+03 2.2460e-08 0.0000e+00 1.0000e+00 5.3814e+03 5.3814e+03 2.7487e+02 2.7487e+02 3.4297e-05 3.4297e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8600e-01 2.5700e+07 5.5315e+02 5.3693e+03 2.2613e-08 0.0000e+00 1.0000e+00 5.3693e+03 5.3693e+03 2.7425e+02 2.7425e+02 3.4215e-05 3.4215e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8800e-01 2.5600e+07 5.5315e+02 5.3571e+03 2.2768e-08 0.0000e+00 1.0000e+00 5.3571e+03 5.3571e+03 2.7363e+02 2.7363e+02 3.4133e-05 3.4133e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9000e-01 2.5500e+07 5.5315e+02 5.3449e+03 2.2925e-08 0.0000e+00 1.0000e+00 5.3449e+03 5.3449e+03 2.7300e+02 2.7300e+02 3.4050e-05 3.4050e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9200e-01 2.5400e+07 5.5315e+02 5.3326e+03 2.3083e-08 0.0000e+00 1.0000e+00 5.3326e+03 5.3326e+03 2.7238e+02 2.7238e+02 3.3967e-05 3.3967e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9400e-01 2.5300e+07 5.5315e+02 5.3203e+03 2.3243e-08 0.0000e+00 1.0000e+00 5.3203e+03 5.3203e+03 2.7175e+02 2.7175e+02 3.3884e-05 3.3884e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9600e-01 2.5200e+07 5.5315e+02 5.3079e+03 2.3405e-08 0.0000e+00 1.0000e+00 5.3079e+03 5.3079e+03 2.7111e+02 2.7111e+02 3.3801e-05 3.3801e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9800e-01 2.5100e+07 5.5315e+02 5.2954e+03 2.3568e-08 0.0000e+00 1.0000e+00 5.2954e+03 5.2954e+03 2.7048e+02 2.7048e+02 3.3718e-05 3.3718e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0000e-01 2.5000e+07 5.5315e+02 5.2829e+03 2.3733e-08 0.0000e+00 1.0000e+00 5.2829e+03 5.2829e+03 2.6984e+02 2.6984e+02 3.3634e-05 3.3634e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0200e-01 2.4900e+07 5.5315e+02 5.2704e+03 2.3901e-08 0.0000e+00 1.0000e+00 5.2704e+03 5.2704e+03 2.6920e+02 2.6920e+02 3.3550e-05 3.3550e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0400e-01 2.4800e+07 5.5315e+02 5.2577e+03 2.4070e-08 0.0000e+00 1.0000e+00 5.2577e+03 5.2577e+03 2.6855e+02 2.6855e+02 3.3466e-05 3.3466e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0600e-01 2.4700e+07 5.5315e+02 5.2451e+03 2.4241e-08 0.0000e+00 1.0000e+00 5.2451e+03 5.2451e+03 2.6790e+02 2.6790e+02 3.3382e-05 3.3382e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0800e-01 2.4600e+07 5.5315e+02 5.2323e+03 2.4414e-08 0.0000e+00 1.0000e+00 5.2323e+03 5.2323e+03 2.6725e+02 2.6725e+02 3.3297e-05 3.3297e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.1000e-01 2.4500e+07 5.5315e+02 5.2195e+03 2.4588e-08 0.0000e+00 1.0000e+00 5.2195e+03 5.2195e+03 2.6660e+02 2.6660e+02 3.3213e-05 3.3213e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.1200e-01 2.4400e+07 5.5315e+02 5.2066e+03 2.4765e-08 0.0000e+00 1.0000e+00 5.2066e+03 5.2066e+03 2.6594e+02 2.6594e+02 3.3128e-05 3.3128e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.1400e-01 2.4300e+07 5.5315e+02 5.1937e+03 2.4944e-08 0.0000e+00 1.0000e+00 5.1937e+03 5.1937e+03 2.6528e+02 2.6528e+02 3.3042e-05 3.3042e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.1600e-01 2.4200e+07 5.5315e+02 5.1807e+03 2.5125e-08 0.0000e+00 1.0000e+00 5.1807e+03 5.1807e+03 2.6462e+02 2.6462e+02 3.2957e-05 3.2957e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.1800e-01 2.4100e+07 5.5315e+02 5.1677e+03 2.5308e-08 0.0000e+00 1.0000e+00 5.1677e+03 5.1677e+03 2.6395e+02 2.6395e+02 3.2871e-05 3.2871e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.2000e-01 2.4000e+07 5.5315e+02 5.1546e+03 2.5493e-08 0.0000e+00 1.0000e+00 5.1546e+03 5.1546e+03 2.6328e+02 2.6328e+02 3.2785e-05 3.2785e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.2200e-01 2.3900e+07 5.5315e+02 5.1414e+03 2.5681e-08 0.0000e+00 1.0000e+00 5.1414e+03 5.1414e+03 2.6261e+02 2.6261e+02 3.2699e-05 3.2699e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.2400e-01 2.3800e+07 5.5315e+02 5.1282e+03 2.5870e-08 0.0000e+00 1.0000e+00 5.1282e+03 5.1282e+03 2.6193e+02 2.6193e+02 3.2613e-05 3.2613e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.2600e-01 2.3700e+07 5.5315e+02 5.1149e+03 2.6062e-08 0.0000e+00 1.0000e+00 5.1149e+03 5.1149e+03 2.6125e+02 2.6125e+02 3.2526e-05 3.2526e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.2800e-01 2.3600e+07 5.5315e+02 5.1015e+03 2.6256e-08 0.0000e+00 1.0000e+00 5.1015e+03 5.1015e+03 2.6057e+02 2.6057e+02 3.2439e-05 3.2439e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.3000e-01 2.3500e+07 5.5315e+02 5.0881e+03 2.6452e-08 0.0000e+00 1.0000e+00 5.0881e+03 5.0881e+03 2.5989e+02 2.5989e+02 3.2352e-05 3.2352e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.3200e-01 2.3400e+07 5.5315e+02 5.0746e+03 2.6651e-08 0.0000e+00 1.0000e+00 5.0746e+03 5.0746e+03 2.5920e+02 2.5920e+02 3.2264e-05 3.2264e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.3400e-01 2.3300e+07 5.5315e+02 5.0610e+03 2.6851e-08 0.0000e+00 1.0000e+00 5.0610e+03 5.0610e+03 2.5850e+02 2.5850e+02 3.2177e-05 3.2177e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.3600e-01 2.3200e+07 5.5315e+02 5.0474e+03 2.7055e-08 0.0000e+00 1.0000e+00 5.0474e+03 5.0474e+03 2.5781e+02 2.5781e+02 3.2089e-05 3.2089e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.3800e-01 2.3100e+07 5.5315e+02 5.0337e+03 2.7260e-08 0.0000e+00 1.0000e+00 5.0337e+03 5.0337e+03 2.5711e+02 2.5711e+02 3.2001e-05 3.2001e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.4000e-01 2.3000e+07 5.5315e+02 5.0200e+03 2.7469e-08 0.0000e+00 1.0000e+00 5.0200e+03 5.0200e+03 2.5641e+02 2.5641e+02 3.1913e-05 3.1913e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.4200e-01 2.2900e+07 5.5315e+02 5.0061e+03 2.7679e-08 0.0000e+00 1.0000e+00 5.0061e+03 5.0061e+03 2.5570e+02 2.5570e+02 3.1824e-05 3.1824e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.4400e-01 2.2800e+07 5.5315e+02 4.9923e+03 2.7892e-08 0.0000e+00 1.0000e+00 4.9923e+03 4.9923e+03 2.5499e+02 2.5499e+02 3.1735e-05 3.1735e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.4600e-01 2.2700e+07 5.5315e+02 4.9783e+03 2.8108e-08 0.0000e+00 1.0000e+00 4.9783e+03 4.9783e+03 2.5428e+02 2.5428e+02 3.1646e-05 3.1646e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.4800e-01 2.2600e+07 5.5315e+02 4.9643e+03 2.8326e-08 0.0000e+00 1.0000e+00 4.9643e+03 4.9643e+03 2.5356e+02 2.5356e+02 3.1557e-05 3.1557e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.5000e-01 2.2500e+07 5.5315e+02 4.9502e+03 2.8547e-08 0.0000e+00 1.0000e+00 4.9502e+03 4.9502e+03 2.5284e+02 2.5284e+02 3.1467e-05 3.1467e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.5200e-01 2.2400e+07 5.5315e+02 4.9360e+03 2.8771e-08 0.0000e+00 1.0000e+00 4.9360e+03 4.9360e+03 2.5212e+02 2.5212e+02 3.1377e-05 3.1377e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.5400e-01 2.2300e+07 5.5315e+02 4.9218e+03 2.8998e-08 0.0000e+00 1.0000e+00 4.9218e+03 4.9218e+03 2.5139e+02 2.5139e+02 3.1287e-05 3.1287e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.5600e-01 2.2200e+07 5.5315e+02 4.9075e+03 2.9227e-08 0.0000e+00 1.0000e+00 4.9075e+03 4.9075e+03 2.5066e+02 2.5066e+02 3.1197e-05 3.1197e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.5800e-01 2.2100e+07 5.5315e+02 4.8931e+03 2.9459e-08 0.0000e+00 1.0000e+00 4.8931e+03 4.8931e+03 2.4993e+02 2.4993e+02 3.1107e-05 3.1107e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.6000e-01 2.2000e+07 5.5315e+02 4.8786e+03 2.9694e-08 0.0000e+00 1.0000e+00 4.8786e+03 4.8786e+03 2.4919e+02 2.4919e+02 3.1016e-05 3.1016e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.6200e-01 2.1900e+07 5.5315e+02 4.8641e+03 2.9932e-08 0.0000e+00 1.0000e+00 4.8641e+03 4.8641e+03 2.4845e+02 2.4845e+02 3.0925e-05 3.0925e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.6400e-01 2.1800e+07 5.5315e+02 4.8495e+03 3.0172e-08 0.0000e+00 1.0000e+00 4.8495e+03 4.8495e+03 2.4770e+02 2.4770e+02 3.0834e-05 3.0834e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.6600e-01 2.1700e+07 5.5315e+02 4.8348e+03 3.0416e-08 0.0000e+00 1.0000e+00 4.8348e+03 4.8348e+03 2.4695e+02 2.4695e+02 3.0742e-05 3.0742e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.6800e-01 2.1600e+07 5.5315e+02 4.8201e+03 3.0663e-08 0.0000e+00 1.0000e+00 4.8201e+03 4.8201e+03 2.4620e+02 2.4620e+02 3.0651e-05 3.0651e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.7000e-01 2.1500e+07 5.5315e+02 4.8053e+03 3.0913e-08 0.0000e+00 1.0000e+00 4.8053e+03 4.8053e+03 2.4544e+02 2.4544e+02 3.0559e-05 3.0559e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.7200e-01 2.1400e+07 5.5315e+02 4.7904e+03 3.1166e-08 0.0000e+00 1.0000e+00 4.7904e+03 4.7904e+03 2.4468e+02 2.4468e+02 3.0466e-05 3.0466e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.7400e-01 2.1300e+07 5.5315e+02 4.7754e+03 3.1422e-08 0.0000e+00 1.0000e+00 4.7754e+03 4.7754e+03 2.4392e+02 2.4392e+02 3.0374e-05 3.0374e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.7600e-01 2.1200e+07 5.5315e+02 4.7604e+03 3.1682e-08 0.0000e+00 1.0000e+00 4.7604e+03 4.7604e+03 2.4315e+02 2.4315e+02 3.0281e-05 3.0281e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.7800e-01 2.1100e+07 5.5315e+02 4.7453e+03 3.1945e-08 0.0000e+00 1.0000e+00 4.7453e+03 4.7453e+03 2.4238e+02 2.4238e+02 3.0189e-05 3.0189e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.8000e-01 2.1000e+07 5.5315e+02 4.7301e+03 3.2211e-08 0.0000e+00 1.0000e+00 4.7301e+03 4.7301e+03 2.4160e+02 2.4160e+02 3.0095e-05 3.0095e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.8200e-01 2.0900e+07 5.5315e+02 4.7148e+03 3.2480e-08 0.0000e+00 1.0000e+00 4.7148e+03 4.7148e+03 2.4082e+02 2.4082e+02 3.0002e-05 3.0002e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.8400e-01 2.0800e+07 5.5315e+02 4.6994e+03 3.2753e-08 0.0000e+00 1.0000e+00 4.6994e+03 4.6994e+03 2.4003e+02 2.4003e+02 2.9908e-05 2.9908e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.8600e-01 2.0700e+07 5.5315e+02 4.6840e+03 3.3030e-08 0.0000e+00 1.0000e+00 4.6840e+03 4.6840e+03 2.3925e+02 2.3925e+02 2.9815e-05 2.9815e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.8800e-01 2.0600e+07 5.5315e+02 4.6685e+03 3.3310e-08 0.0000e+00 1.0000e+00 4.6685e+03 4.6685e+03 2.3845e+02 2.3845e+02 2.9720e-05 2.9720e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.9000e-01 2.0500e+07 5.5315e+02 4.6529e+03 3.3593e-08 0.0000e+00 1.0000e+00 4.6529e+03 4.6529e+03 2.3766e+02 2.3766e+02 2.9626e-05 2.9626e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.9200e-01 2.0400e+07 5.5315e+02 4.6372e+03 3.3881e-08 0.0000e+00 1.0000e+00 4.6372e+03 4.6372e+03 2.3686e+02 2.3686e+02 2.9532e-05 2.9532e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.9400e-01 2.0300e+07 5.5315e+02 4.6215e+03 3.4172e-08 0.0000e+00 1.0000e+00 4.6215e+03 4.6215e+03 2.3605e+02 2.3605e+02 2.9437e-05 2.9437e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.9600e-01 2.0200e+07 5.5315e+02 4.6056e+03 3.4467e-08 0.0000e+00 1.0000e+00 4.6056e+03 4.6056e+03 2.3524e+02 2.3524e+02 2.9342e-05 2.9342e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.9800e-01 2.0100e+07 5.5315e+02 4.5897e+03 3.4766e-08 0.0000e+00 1.0000e+00 4.5897e+03 4.5897e+03 2.3443e+02 2.3443e+02 2.9247e-05 2.9247e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.0000e-01 2.0000e+07 5.5315e+02 4.5737e+03 3.5068e-08 0.0000e+00 1.0000e+00 4.5737e+03 4.5737e+03 2.3361e+02 2.3361e+02 2.9151e-05 2.9151e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.0200e-01 1.9900e+07 5.5315e+02 4.5577e+03 3.5375e-08 0.0000e+00 1.0000e+00 4.5577e+03 4.5577e+03 2.3279e+02 2.3279e+02 2.9055e-05 2.9055e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.0400e-01 1.9800e+07 5.5315e+02 4.5415e+03 3.5686e-08 0.0000e+00 1.0000e+00 4.5415e+03 4.5415e+03 2.3197e+02 2.3197e+02 2.8959e-05 2.8959e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.0600e-01 1.9700e+07 5.5315e+02 4.5252e+03 3.6000e-08 0.0000e+00 1.0000e+00 4.5252e+03 4.5252e+03 2.3114e+02 2.3114e+02 2.8863e-05 2.8863e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.0800e-01 1.9600e+07 5.5315e+02 4.5089e+03 3.6319e-08 0.0000e+00 1.0000e+00 4.5089e+03 4.5089e+03 2.3030e+02 2.3030e+02 2.8767e-05 2.8767e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.1000e-01 1.9500e+07 5.5315e+02 4.4925e+03 3.6643e-08 0.0000e+00 1.0000e+00 4.4925e+03 4.4925e+03 2.2946e+02 2.2946e+02 2.8670e-05 2.8670e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.1200e-01 1.9400e+07 5.5315e+02 4.4760e+03 3.6970e-08 0.0000e+00 1.0000e+00 4.4760e+03 4.4760e+03 2.2862e+02 2.2862e+02 2.8573e-05 2.8573e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.1400e-01 1.9300e+07 5.5315e+02 4.4594e+03 3.7302e-08 0.0000e+00 1.0000e+00 4.4594e+03 4.4594e+03 2.2777e+02 2.2777e+02 2.8476e-05 2.8476e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.1600e-01 1.9200e+07 5.5315e+02 4.4427e+03 3.7639e-08 0.0000e+00 1.0000e+00 4.4427e+03 4.4427e+03 2.2692e+02 2.2692e+02 2.8379e-05 2.8379e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.1800e-01 1.9100e+07 5.5315e+02 4.4259e+03 3.7979e-08 0.0000e+00 1.0000e+00 4.4259e+03 4.4259e+03 2.2607e+02 2.2607e+02 2.8282e-05 2.8282e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.2000e-01 1.9000e+07 5.5315e+02 4.4091e+03 3.8325e-08 0.0000e+00 1.0000e+00 4.4091e+03 4.4091e+03 2.2520e+02 2.2520e+02 2.8184e-05 2.8184e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.2200e-01 1.8900e+07 5.5315e+02 4.3922e+03 3.8675e-08 0.0000e+00 1.0000e+00 4.3922e+03 4.3922e+03 2.2434e+02 2.2434e+02 2.8086e-05 2.8086e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.2400e-01 1.8800e+07 5.5315e+02 4.3751e+03 3.9030e-08 0.0000e+00 1.0000e+00 4.3751e+03 4.3751e+03 2.2347e+02 2.2347e+02 2.7988e-05 2.7988e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +3.2600e-01 1.8700e+07 5.5315e+02 4.3578e+03 4.0105e-08 3.9013e-02 9.6099e-01 4.5336e+03 4.3510e+03 2.7893e+02 2.2072e+02 3.4075e-05 2.7707e-05 8.3083e-03 2.5562e-03 4.7396e-01 1.0798e-01 8.6281e-02 4.6615e-02 2.2228e-02 1.6734e-02 2.3534e-01 9.0232e-03 3.0149e-03 5.3673e-01 1.1482e-01 8.7954e-02 4.5566e-02 2.0856e-02 1.5045e-02 1.6699e-01 +3.2800e-01 1.8600e+07 5.5315e+02 4.3403e+03 4.0336e-08 9.6700e-02 9.0330e-01 4.5314e+03 4.3208e+03 2.8320e+02 2.1646e+02 3.4587e-05 2.7288e-05 8.2428e-03 2.5161e-03 4.6836e-01 1.0734e-01 8.6103e-02 4.6692e-02 2.2344e-02 1.6880e-02 2.4152e-01 9.0650e-03 3.0415e-03 5.4039e-01 1.1522e-01 8.8054e-02 4.5506e-02 2.0776e-02 1.4947e-02 1.6299e-01 +3.3000e-01 1.8500e+07 5.5315e+02 4.3228e+03 4.0571e-08 1.3663e-01 8.6337e-01 4.5279e+03 4.2921e+03 2.8700e+02 2.1269e+02 3.5046e-05 2.6921e-05 8.1828e-03 2.4798e-03 4.6328e-01 1.0675e-01 8.5933e-02 4.6758e-02 2.2447e-02 1.7013e-02 2.4716e-01 9.1011e-03 3.0644e-03 5.4354e-01 1.1557e-01 8.8143e-02 4.5457e-02 2.0709e-02 1.4863e-02 1.5955e-01 +3.3200e-01 1.8400e+07 5.5315e+02 4.3053e+03 4.0809e-08 1.6633e-01 8.3367e-01 4.5234e+03 4.2643e+03 2.9045e+02 2.0927e+02 3.5467e-05 2.6592e-05 8.1268e-03 2.4462e-03 4.5856e-01 1.0620e-01 8.5769e-02 4.6816e-02 2.2542e-02 1.7134e-02 2.5241e-01 9.1331e-03 3.0844e-03 5.4631e-01 1.1588e-01 8.8225e-02 4.5415e-02 2.0650e-02 1.4790e-02 1.5651e-01 +3.3400e-01 1.8300e+07 5.5315e+02 4.2877e+03 4.1050e-08 1.8949e-01 8.1051e-01 4.5181e+03 4.2372e+03 2.9363e+02 2.0611e+02 3.5859e-05 2.6293e-05 8.0737e-03 2.4148e-03 4.5412e-01 1.0567e-01 8.5609e-02 4.6867e-02 2.2629e-02 1.7248e-02 2.5737e-01 9.1621e-03 3.1024e-03 5.4880e-01 1.1616e-01 8.8301e-02 4.5378e-02 2.0597e-02 1.4724e-02 1.5377e-01 +3.3600e-01 1.8200e+07 5.5315e+02 4.2701e+03 4.1295e-08 2.0819e-01 7.9181e-01 4.5123e+03 4.2106e+03 2.9661e+02 2.0316e+02 3.6228e-05 2.6016e-05 8.0230e-03 2.3851e-03 4.4990e-01 1.0517e-01 8.5451e-02 4.6912e-02 2.2710e-02 1.7356e-02 2.6210e-01 9.1886e-03 3.1187e-03 5.5107e-01 1.1642e-01 8.8373e-02 4.5347e-02 2.0551e-02 1.4665e-02 1.5127e-01 +3.3800e-01 1.8100e+07 5.5315e+02 4.2524e+03 4.1543e-08 2.2367e-01 7.7633e-01 4.5060e+03 4.1846e+03 2.9941e+02 2.0038e+02 3.6578e-05 2.5759e-05 7.9740e-03 2.3568e-03 4.4586e-01 1.0468e-01 8.5294e-02 4.6951e-02 2.2787e-02 1.7458e-02 2.6665e-01 9.2130e-03 3.1336e-03 5.5315e-01 1.1666e-01 8.8441e-02 4.5319e-02 2.0508e-02 1.4610e-02 1.4897e-01 +3.4000e-01 1.8000e+07 5.5315e+02 4.2347e+03 4.1795e-08 2.3675e-01 7.6325e-01 4.4993e+03 4.1589e+03 3.0206e+02 1.9775e+02 3.6912e-05 2.5519e-05 7.9266e-03 2.3296e-03 4.4197e-01 1.0420e-01 8.5138e-02 4.6987e-02 2.2860e-02 1.7555e-02 2.7104e-01 9.2358e-03 3.1473e-03 5.5507e-01 1.1688e-01 8.8507e-02 4.5295e-02 2.0469e-02 1.4561e-02 1.4683e-01 +3.4200e-01 1.7900e+07 5.5315e+02 4.2170e+03 4.2051e-08 2.4797e-01 7.5203e-01 4.4923e+03 4.1335e+03 3.0459e+02 1.9525e+02 3.7232e-05 2.5291e-05 7.8805e-03 2.3035e-03 4.3820e-01 1.0374e-01 8.4981e-02 4.7018e-02 2.2929e-02 1.7648e-02 2.7530e-01 9.2572e-03 3.1600e-03 5.5687e-01 1.1710e-01 8.8570e-02 4.5274e-02 2.0434e-02 1.4515e-02 1.4483e-01 +3.4400e-01 1.7800e+07 5.5315e+02 4.1993e+03 4.2310e-08 2.5772e-01 7.4228e-01 4.4851e+03 4.1084e+03 3.0702e+02 1.9285e+02 3.7541e-05 2.5076e-05 7.8355e-03 2.2782e-03 4.3455e-01 1.0328e-01 8.4825e-02 4.7046e-02 2.2994e-02 1.7738e-02 2.7945e-01 9.2773e-03 3.1718e-03 5.5854e-01 1.1729e-01 8.8632e-02 4.5256e-02 2.0401e-02 1.4472e-02 1.4295e-01 +3.4600e-01 1.7700e+07 5.5315e+02 4.1815e+03 4.2572e-08 2.6629e-01 7.3371e-01 4.4776e+03 4.0835e+03 3.0935e+02 1.9054e+02 3.7839e-05 2.4872e-05 7.7914e-03 2.2537e-03 4.3100e-01 1.0283e-01 8.4668e-02 4.7070e-02 2.3057e-02 1.7825e-02 2.8350e-01 9.2963e-03 3.1829e-03 5.6012e-01 1.1748e-01 8.8692e-02 4.5240e-02 2.0371e-02 1.4432e-02 1.4118e-01 +3.4800e-01 1.7600e+07 5.5315e+02 4.1637e+03 4.2839e-08 2.7389e-01 7.2611e-01 4.4699e+03 4.0588e+03 3.1159e+02 1.8833e+02 3.8128e-05 2.4676e-05 7.7481e-03 2.2299e-03 4.2753e-01 1.0239e-01 8.4510e-02 4.7091e-02 2.3117e-02 1.7909e-02 2.8747e-01 9.3143e-03 3.1933e-03 5.6161e-01 1.1766e-01 8.8751e-02 4.5226e-02 2.0343e-02 1.4395e-02 1.3951e-01 +3.5000e-01 1.7500e+07 5.5315e+02 4.1458e+03 4.3110e-08 2.8067e-01 7.1933e-01 4.4621e+03 4.0342e+03 3.1376e+02 1.8618e+02 3.8409e-05 2.4490e-05 7.7054e-03 2.2067e-03 4.2413e-01 1.0196e-01 8.4351e-02 4.7109e-02 2.3175e-02 1.7991e-02 2.9137e-01 9.3315e-03 3.2031e-03 5.6301e-01 1.1784e-01 8.8809e-02 4.5214e-02 2.0317e-02 1.4360e-02 1.3791e-01 +3.5200e-01 1.7400e+07 5.5315e+02 4.1279e+03 4.3384e-08 2.8678e-01 7.1322e-01 4.4540e+03 4.0099e+03 3.1587e+02 1.8410e+02 3.8682e-05 2.4310e-05 7.6634e-03 2.1841e-03 4.2081e-01 1.0152e-01 8.4191e-02 4.7124e-02 2.3230e-02 1.8070e-02 2.9521e-01 9.3479e-03 3.2124e-03 5.6435e-01 1.1800e-01 8.8866e-02 4.5203e-02 2.0293e-02 1.4327e-02 1.3640e-01 +3.5400e-01 1.7300e+07 5.5315e+02 4.1100e+03 4.3663e-08 2.9230e-01 7.0770e-01 4.4459e+03 3.9856e+03 3.1791e+02 1.8209e+02 3.8949e-05 2.4138e-05 7.6220e-03 2.1619e-03 4.1754e-01 1.0110e-01 8.4029e-02 4.7136e-02 2.3283e-02 1.8147e-02 2.9898e-01 9.3636e-03 3.2212e-03 5.6562e-01 1.1816e-01 8.8921e-02 4.5195e-02 2.0271e-02 1.4296e-02 1.3495e-01 +3.5600e-01 1.7200e+07 5.5315e+02 4.0920e+03 4.3945e-08 2.9732e-01 7.0268e-01 4.4376e+03 3.9615e+03 3.1989e+02 1.8013e+02 3.9210e-05 2.3972e-05 7.5810e-03 2.1403e-03 4.1433e-01 1.0067e-01 8.3866e-02 4.7145e-02 2.3334e-02 1.8223e-02 3.0270e-01 9.3787e-03 3.2294e-03 5.6682e-01 1.1832e-01 8.8977e-02 4.5188e-02 2.0250e-02 1.4267e-02 1.3357e-01 +3.5800e-01 1.7100e+07 5.5315e+02 4.0740e+03 4.4232e-08 3.0190e-01 6.9810e-01 4.4292e+03 3.9375e+03 3.2183e+02 1.7822e+02 3.9465e-05 2.3812e-05 7.5404e-03 2.1190e-03 4.1118e-01 1.0025e-01 8.3702e-02 4.7152e-02 2.3384e-02 1.8296e-02 3.0638e-01 9.3932e-03 3.2373e-03 5.6798e-01 1.1847e-01 8.9031e-02 4.5182e-02 2.0231e-02 1.4239e-02 1.3224e-01 +3.6000e-01 1.7000e+07 5.5315e+02 4.0560e+03 4.4524e-08 3.0609e-01 6.9391e-01 4.4207e+03 3.9136e+03 3.2372e+02 1.7636e+02 3.9714e-05 2.3657e-05 7.5002e-03 2.0982e-03 4.0806e-01 9.9831e-02 8.3535e-02 4.7156e-02 2.3431e-02 1.8367e-02 3.1002e-01 9.4071e-03 3.2448e-03 5.6908e-01 1.1861e-01 8.9085e-02 4.5177e-02 2.0213e-02 1.4213e-02 1.3097e-01 +3.6200e-01 1.6900e+07 5.5315e+02 4.0379e+03 4.4819e-08 3.0995e-01 6.9005e-01 4.4121e+03 3.8897e+03 3.2556e+02 1.7455e+02 3.9959e-05 2.3507e-05 7.4603e-03 2.0777e-03 4.0499e-01 9.9414e-02 8.3367e-02 4.7158e-02 2.3477e-02 1.8437e-02 3.1361e-01 9.4206e-03 3.2519e-03 5.7013e-01 1.1875e-01 8.9138e-02 4.5174e-02 2.0196e-02 1.4188e-02 1.2975e-01 +3.6400e-01 1.6800e+07 5.5315e+02 4.0198e+03 4.5120e-08 3.1351e-01 6.8649e-01 4.4035e+03 3.8660e+03 3.2736e+02 1.7277e+02 4.0200e-05 2.3362e-05 7.4208e-03 2.0576e-03 4.0196e-01 9.8998e-02 8.3197e-02 4.7158e-02 2.3521e-02 1.8505e-02 3.1718e-01 9.4336e-03 3.2587e-03 5.7114e-01 1.1888e-01 8.9191e-02 4.5172e-02 2.0180e-02 1.4165e-02 1.2857e-01 +3.6600e-01 1.6700e+07 5.5315e+02 4.0016e+03 4.5425e-08 3.1681e-01 6.8319e-01 4.3947e+03 3.8423e+03 3.2913e+02 1.7103e+02 4.0437e-05 2.3221e-05 7.3815e-03 2.0378e-03 3.9897e-01 9.8584e-02 8.3025e-02 4.7155e-02 2.3563e-02 1.8572e-02 3.2071e-01 9.4461e-03 3.2652e-03 5.7211e-01 1.1901e-01 8.9244e-02 4.5172e-02 2.0166e-02 1.4143e-02 1.2744e-01 +3.6800e-01 1.6600e+07 5.5315e+02 3.9834e+03 4.5734e-08 3.1986e-01 6.8014e-01 4.3859e+03 3.8186e+03 3.3086e+02 1.6933e+02 4.0669e-05 2.3084e-05 7.3424e-03 2.0183e-03 3.9601e-01 9.8170e-02 8.2851e-02 4.7149e-02 2.3604e-02 1.8637e-02 3.2422e-01 9.4582e-03 3.2714e-03 5.7304e-01 1.1914e-01 8.9296e-02 4.5172e-02 2.0152e-02 1.4122e-02 1.2635e-01 +3.7000e-01 1.6500e+07 5.5315e+02 3.9652e+03 4.6048e-08 3.2269e-01 6.7731e-01 4.3771e+03 3.7951e+03 3.3255e+02 1.6766e+02 4.0898e-05 2.2950e-05 7.3035e-03 1.9991e-03 3.9308e-01 9.7758e-02 8.2675e-02 4.7141e-02 2.3643e-02 1.8701e-02 3.2770e-01 9.4700e-03 3.2773e-03 5.7393e-01 1.1927e-01 8.9348e-02 4.5173e-02 2.0140e-02 1.4102e-02 1.2529e-01 +3.7200e-01 1.6400e+07 5.5315e+02 3.9469e+03 4.6368e-08 3.2533e-01 6.7467e-01 4.3681e+03 3.7716e+03 3.3422e+02 1.6603e+02 4.1124e-05 2.2821e-05 7.2649e-03 1.9801e-03 3.9018e-01 9.7346e-02 8.2497e-02 4.7131e-02 2.3681e-02 1.8764e-02 3.3115e-01 9.4814e-03 3.2830e-03 5.7479e-01 1.1939e-01 8.9399e-02 4.5175e-02 2.0128e-02 1.4084e-02 1.2427e-01 +3.7400e-01 1.6300e+07 5.5315e+02 3.9286e+03 4.6692e-08 3.2778e-01 6.7222e-01 4.3592e+03 3.7481e+03 3.3585e+02 1.6442e+02 4.1346e-05 2.2695e-05 7.2264e-03 1.9614e-03 3.8731e-01 9.6934e-02 8.2316e-02 4.7119e-02 2.3718e-02 1.8825e-02 3.3459e-01 9.4924e-03 3.2884e-03 5.7562e-01 1.1950e-01 8.9450e-02 4.5178e-02 2.0118e-02 1.4066e-02 1.2328e-01 +3.7600e-01 1.6200e+07 5.5315e+02 3.9102e+03 4.7021e-08 3.3008e-01 6.6992e-01 4.3501e+03 3.7247e+03 3.3746e+02 1.6284e+02 4.1565e-05 2.2572e-05 7.1880e-03 1.9429e-03 3.8447e-01 9.6523e-02 8.2133e-02 4.7105e-02 2.3752e-02 1.8885e-02 3.3800e-01 9.5032e-03 3.2935e-03 5.7642e-01 1.1962e-01 8.9501e-02 4.5182e-02 2.0108e-02 1.4049e-02 1.2233e-01 +3.7800e-01 1.6100e+07 5.5315e+02 3.8918e+03 4.7356e-08 3.3222e-01 6.6778e-01 4.3411e+03 3.7013e+03 3.3904e+02 1.6129e+02 4.1782e-05 2.2451e-05 7.1498e-03 1.9247e-03 3.8164e-01 9.6112e-02 8.1948e-02 4.7088e-02 2.3786e-02 1.8944e-02 3.4140e-01 9.5136e-03 3.2985e-03 5.7718e-01 1.1973e-01 8.9552e-02 4.5187e-02 2.0099e-02 1.4033e-02 1.2140e-01 +3.8000e-01 1.6000e+07 5.5315e+02 3.8734e+03 4.7696e-08 3.3422e-01 6.6578e-01 4.3320e+03 3.6779e+03 3.4060e+02 1.5976e+02 4.1995e-05 2.2334e-05 7.1117e-03 1.9066e-03 3.7885e-01 9.5701e-02 8.1761e-02 4.7069e-02 2.3818e-02 1.9001e-02 3.4479e-01 9.5237e-03 3.3032e-03 5.7792e-01 1.1984e-01 8.9603e-02 4.5193e-02 2.0091e-02 1.4018e-02 1.2050e-01 +3.8200e-01 1.5900e+07 5.5315e+02 3.8549e+03 4.8042e-08 3.3610e-01 6.6390e-01 4.3228e+03 3.6546e+03 3.4213e+02 1.5825e+02 4.2207e-05 2.2220e-05 7.0737e-03 1.8888e-03 3.7607e-01 9.5289e-02 8.1571e-02 4.7048e-02 2.3849e-02 1.9058e-02 3.4815e-01 9.5336e-03 3.3078e-03 5.7864e-01 1.1995e-01 8.9653e-02 4.5199e-02 2.0083e-02 1.4004e-02 1.1963e-01 +3.8400e-01 1.5800e+07 5.5315e+02 3.8363e+03 4.8393e-08 3.3786e-01 6.6214e-01 4.3136e+03 3.6313e+03 3.4364e+02 1.5677e+02 4.2415e-05 2.2108e-05 7.0357e-03 1.8712e-03 3.7331e-01 9.4877e-02 8.1379e-02 4.7024e-02 2.3879e-02 1.9113e-02 3.5151e-01 9.5432e-03 3.3121e-03 5.7933e-01 1.2005e-01 8.9703e-02 4.5206e-02 2.0076e-02 1.3990e-02 1.1879e-01 +3.8600e-01 1.5700e+07 5.5315e+02 3.8177e+03 4.8749e-08 3.3950e-01 6.6050e-01 4.3044e+03 3.6081e+03 3.4513e+02 1.5531e+02 4.2622e-05 2.1999e-05 6.9979e-03 1.8537e-03 3.7057e-01 9.4464e-02 8.1184e-02 4.6999e-02 2.3907e-02 1.9167e-02 3.5485e-01 9.5525e-03 3.3163e-03 5.7999e-01 1.2016e-01 8.9753e-02 4.5214e-02 2.0070e-02 1.3978e-02 1.1797e-01 +3.8800e-01 1.5600e+07 5.5315e+02 3.7991e+03 4.9112e-08 3.4105e-01 6.5895e-01 4.2952e+03 3.5848e+03 3.4660e+02 1.5387e+02 4.2826e-05 2.1892e-05 6.9601e-03 1.8365e-03 3.6785e-01 9.4051e-02 8.0987e-02 4.6971e-02 2.3934e-02 1.9220e-02 3.5819e-01 9.5616e-03 3.3203e-03 5.8063e-01 1.2026e-01 8.9803e-02 4.5223e-02 2.0065e-02 1.3966e-02 1.1717e-01 +3.9000e-01 1.5500e+07 5.5315e+02 3.7804e+03 4.9481e-08 3.4250e-01 6.5750e-01 4.2859e+03 3.5616e+03 3.4805e+02 1.5245e+02 4.3028e-05 2.1787e-05 6.9223e-03 1.8194e-03 3.6515e-01 9.3638e-02 8.0788e-02 4.6941e-02 2.3959e-02 1.9272e-02 3.6151e-01 9.5705e-03 3.3242e-03 5.8125e-01 1.2036e-01 8.9853e-02 4.5232e-02 2.0060e-02 1.3954e-02 1.1640e-01 +3.9200e-01 1.5400e+07 5.5315e+02 3.7617e+03 4.9856e-08 3.4385e-01 6.5615e-01 4.2766e+03 3.5384e+03 3.4948e+02 1.5105e+02 4.3228e-05 2.1684e-05 6.8846e-03 1.8025e-03 3.6246e-01 9.3223e-02 8.0585e-02 4.6909e-02 2.3984e-02 1.9323e-02 3.6483e-01 9.5791e-03 3.3278e-03 5.8185e-01 1.2045e-01 8.9902e-02 4.5242e-02 2.0056e-02 1.3944e-02 1.1565e-01 +3.9400e-01 1.5300e+07 5.5315e+02 3.7429e+03 5.0237e-08 3.4513e-01 6.5487e-01 4.2673e+03 3.5153e+03 3.5090e+02 1.4967e+02 4.3426e-05 2.1584e-05 6.8470e-03 1.7857e-03 3.5979e-01 9.2807e-02 8.0380e-02 4.6875e-02 2.4007e-02 1.9373e-02 3.6814e-01 9.5875e-03 3.3314e-03 5.8243e-01 1.2055e-01 8.9952e-02 4.5252e-02 2.0052e-02 1.3934e-02 1.1491e-01 +3.9600e-01 1.5200e+07 5.5315e+02 3.7241e+03 5.0624e-08 3.4632e-01 6.5368e-01 4.2580e+03 3.4921e+03 3.5229e+02 1.4830e+02 4.3622e-05 2.1486e-05 6.8093e-03 1.7691e-03 3.5713e-01 9.2391e-02 8.0173e-02 4.6839e-02 2.4028e-02 1.9422e-02 3.7144e-01 9.5957e-03 3.3347e-03 5.8299e-01 1.2064e-01 9.0001e-02 4.5263e-02 2.0049e-02 1.3925e-02 1.1420e-01 +3.9800e-01 1.5100e+07 5.5315e+02 3.7052e+03 5.1018e-08 3.4744e-01 6.5256e-01 4.2486e+03 3.4690e+03 3.5367e+02 1.4695e+02 4.3816e-05 2.1389e-05 6.7717e-03 1.7526e-03 3.5449e-01 9.1973e-02 7.9963e-02 4.6800e-02 2.4049e-02 1.9470e-02 3.7473e-01 9.6037e-03 3.3380e-03 5.8353e-01 1.2073e-01 9.0051e-02 4.5275e-02 2.0047e-02 1.3916e-02 1.1351e-01 +4.0000e-01 1.5000e+07 5.5315e+02 3.6863e+03 5.1419e-08 3.4849e-01 6.5151e-01 4.2392e+03 3.4459e+03 3.5504e+02 1.4562e+02 4.4009e-05 2.1294e-05 6.7341e-03 1.7363e-03 3.5186e-01 9.1554e-02 7.9750e-02 4.6759e-02 2.4068e-02 1.9517e-02 3.7803e-01 9.6116e-03 3.3411e-03 5.8405e-01 1.2082e-01 9.0100e-02 4.5287e-02 2.0045e-02 1.3908e-02 1.1284e-01 +4.0200e-01 1.4900e+07 5.5315e+02 3.6673e+03 5.1827e-08 3.4947e-01 6.5053e-01 4.2298e+03 3.4228e+03 3.5639e+02 1.4430e+02 4.4200e-05 2.1201e-05 6.6965e-03 1.7201e-03 3.4924e-01 9.1134e-02 7.9534e-02 4.6716e-02 2.4086e-02 1.9562e-02 3.8131e-01 9.6192e-03 3.3440e-03 5.8455e-01 1.2091e-01 9.0149e-02 4.5300e-02 2.0044e-02 1.3900e-02 1.1218e-01 +4.0400e-01 1.4800e+07 5.5315e+02 3.6483e+03 5.2241e-08 3.5039e-01 6.4961e-01 4.2204e+03 3.3997e+03 3.5772e+02 1.4300e+02 4.4389e-05 2.1110e-05 6.6589e-03 1.7040e-03 3.4663e-01 9.0713e-02 7.9316e-02 4.6671e-02 2.4103e-02 1.9607e-02 3.8460e-01 9.6266e-03 3.3469e-03 5.8504e-01 1.2099e-01 9.0198e-02 4.5313e-02 2.0043e-02 1.3894e-02 1.1155e-01 +4.0600e-01 1.4700e+07 5.5315e+02 3.6292e+03 5.2663e-08 3.5124e-01 6.4876e-01 4.2110e+03 3.3766e+03 3.5904e+02 1.4171e+02 4.4577e-05 2.1021e-05 6.6212e-03 1.6881e-03 3.4404e-01 9.0290e-02 7.9095e-02 4.6623e-02 2.4118e-02 1.9651e-02 3.8788e-01 9.6339e-03 3.3496e-03 5.8551e-01 1.2108e-01 9.0247e-02 4.5327e-02 2.0042e-02 1.3887e-02 1.1093e-01 +4.0800e-01 1.4600e+07 5.5315e+02 3.6100e+03 5.3093e-08 3.5204e-01 6.4796e-01 4.2016e+03 3.3535e+03 3.6035e+02 1.4043e+02 4.4763e-05 2.0933e-05 6.5836e-03 1.6723e-03 3.4145e-01 8.9866e-02 7.8871e-02 4.6574e-02 2.4132e-02 1.9693e-02 3.9116e-01 9.6410e-03 3.3522e-03 5.8596e-01 1.2116e-01 9.0295e-02 4.5342e-02 2.0043e-02 1.3881e-02 1.1032e-01 +4.1000e-01 1.4500e+07 5.5315e+02 3.5909e+03 5.3530e-08 3.5279e-01 6.4721e-01 4.1921e+03 3.3305e+03 3.6165e+02 1.3917e+02 4.4948e-05 2.0846e-05 6.5459e-03 1.6566e-03 3.3888e-01 8.9441e-02 7.8644e-02 4.6522e-02 2.4145e-02 1.9735e-02 3.9443e-01 9.6479e-03 3.3547e-03 5.8640e-01 1.2124e-01 9.0344e-02 4.5357e-02 2.0043e-02 1.3876e-02 1.0973e-01 +4.1200e-01 1.4400e+07 5.5315e+02 3.5716e+03 5.3974e-08 3.5347e-01 6.4653e-01 4.1827e+03 3.3074e+03 3.6293e+02 1.3792e+02 4.5132e-05 2.0761e-05 6.5082e-03 1.6410e-03 3.3631e-01 8.9013e-02 7.8414e-02 4.6467e-02 2.4157e-02 1.9776e-02 3.9771e-01 9.6547e-03 3.3571e-03 5.8682e-01 1.2132e-01 9.0392e-02 4.5372e-02 2.0044e-02 1.3871e-02 1.0916e-01 +4.1400e-01 1.4300e+07 5.5315e+02 3.5523e+03 5.4427e-08 3.5411e-01 6.4589e-01 4.1732e+03 3.2844e+03 3.6420e+02 1.3668e+02 4.5314e-05 2.0678e-05 6.4705e-03 1.6256e-03 3.3376e-01 8.8585e-02 7.8181e-02 4.6411e-02 2.4167e-02 1.9815e-02 4.0099e-01 9.6613e-03 3.3593e-03 5.8723e-01 1.2140e-01 9.0441e-02 4.5388e-02 2.0046e-02 1.3867e-02 1.0860e-01 +4.1600e-01 1.4200e+07 5.5315e+02 3.5329e+03 5.4887e-08 3.5470e-01 6.4530e-01 4.1637e+03 3.2614e+03 3.6546e+02 1.3545e+02 4.5495e-05 2.0596e-05 6.4327e-03 1.6102e-03 3.3121e-01 8.8154e-02 7.7945e-02 4.6352e-02 2.4177e-02 1.9854e-02 4.0426e-01 9.6678e-03 3.3615e-03 5.8763e-01 1.2148e-01 9.0489e-02 4.5404e-02 2.0048e-02 1.3864e-02 1.0806e-01 +4.1800e-01 1.4100e+07 5.5315e+02 3.5135e+03 5.5357e-08 3.5525e-01 6.4475e-01 4.1542e+03 3.2383e+03 3.6671e+02 1.3424e+02 4.5674e-05 2.0515e-05 6.3949e-03 1.5950e-03 3.2867e-01 8.7722e-02 7.7706e-02 4.6291e-02 2.4184e-02 1.9891e-02 4.0754e-01 9.6740e-03 3.3635e-03 5.8801e-01 1.2155e-01 9.0538e-02 4.5421e-02 2.0050e-02 1.3860e-02 1.0753e-01 +4.2000e-01 1.4000e+07 5.5315e+02 3.4940e+03 5.5834e-08 3.5574e-01 6.4426e-01 4.1447e+03 3.2153e+03 3.6794e+02 1.3304e+02 4.5853e-05 2.0436e-05 6.3570e-03 1.5798e-03 3.2615e-01 8.7288e-02 7.7465e-02 4.6228e-02 2.4191e-02 1.9928e-02 4.1082e-01 9.6802e-03 3.3655e-03 5.8837e-01 1.2163e-01 9.0586e-02 4.5438e-02 2.0053e-02 1.3857e-02 1.0702e-01 +4.2200e-01 1.3900e+07 5.5315e+02 3.4745e+03 5.6321e-08 3.5620e-01 6.4380e-01 4.1352e+03 3.1923e+03 3.6917e+02 1.3184e+02 4.6030e-05 2.0358e-05 6.3191e-03 1.5648e-03 3.2362e-01 8.6853e-02 7.7220e-02 4.6162e-02 2.4196e-02 1.9964e-02 4.1410e-01 9.6862e-03 3.3674e-03 5.8873e-01 1.2170e-01 9.0634e-02 4.5456e-02 2.0056e-02 1.3855e-02 1.0652e-01 +4.2400e-01 1.3800e+07 5.5315e+02 3.4549e+03 5.6816e-08 3.5661e-01 6.4339e-01 4.1257e+03 3.1693e+03 3.7038e+02 1.3066e+02 4.6206e-05 2.0281e-05 6.2812e-03 1.5498e-03 3.2111e-01 8.6415e-02 7.6972e-02 4.6094e-02 2.4200e-02 1.9998e-02 4.1738e-01 9.6920e-03 3.3691e-03 5.8907e-01 1.2177e-01 9.0682e-02 4.5474e-02 2.0060e-02 1.3853e-02 1.0603e-01 +4.2600e-01 1.3700e+07 5.5315e+02 3.4352e+03 5.7321e-08 3.5698e-01 6.4302e-01 4.1162e+03 3.1463e+03 3.7159e+02 1.2949e+02 4.6381e-05 2.0205e-05 6.2432e-03 1.5350e-03 3.1860e-01 8.5976e-02 7.6721e-02 4.6024e-02 2.4203e-02 2.0031e-02 4.2066e-01 9.6978e-03 3.3708e-03 5.8939e-01 1.2184e-01 9.0729e-02 4.5493e-02 2.0064e-02 1.3852e-02 1.0555e-01 +4.2800e-01 1.3600e+07 5.5315e+02 3.4155e+03 5.7835e-08 3.5731e-01 6.4269e-01 4.1067e+03 3.1233e+03 3.7279e+02 1.2833e+02 4.6554e-05 2.0131e-05 6.2051e-03 1.5202e-03 3.1610e-01 8.5535e-02 7.6467e-02 4.5951e-02 2.4204e-02 2.0064e-02 4.2395e-01 9.7033e-03 3.3724e-03 5.8971e-01 1.2191e-01 9.0777e-02 4.5512e-02 2.0069e-02 1.3851e-02 1.0509e-01 +4.3000e-01 1.3500e+07 5.5315e+02 3.3957e+03 5.8359e-08 3.5761e-01 6.4239e-01 4.0971e+03 3.1003e+03 3.7397e+02 1.2717e+02 4.6727e-05 2.0057e-05 6.1669e-03 1.5056e-03 3.1361e-01 8.5091e-02 7.6209e-02 4.5876e-02 2.4204e-02 2.0095e-02 4.2724e-01 9.7088e-03 3.3739e-03 5.9001e-01 1.2198e-01 9.0825e-02 4.5531e-02 2.0073e-02 1.3850e-02 1.0464e-01 +4.3200e-01 1.3400e+07 5.5315e+02 3.3759e+03 5.8892e-08 3.5786e-01 6.4214e-01 4.0876e+03 3.0773e+03 3.7515e+02 1.2603e+02 4.6899e-05 1.9985e-05 6.1287e-03 1.4910e-03 3.1112e-01 8.4646e-02 7.5949e-02 4.5798e-02 2.4202e-02 2.0125e-02 4.3054e-01 9.7141e-03 3.3753e-03 5.9030e-01 1.2205e-01 9.0872e-02 4.5551e-02 2.0079e-02 1.3850e-02 1.0421e-01 +4.3400e-01 1.3300e+07 5.5315e+02 3.3560e+03 5.9436e-08 3.5808e-01 6.4192e-01 4.0781e+03 3.0543e+03 3.7632e+02 1.2490e+02 4.7069e-05 1.9914e-05 6.0904e-03 1.4765e-03 3.0864e-01 8.4199e-02 7.5685e-02 4.5718e-02 2.4200e-02 2.0154e-02 4.3383e-01 9.7192e-03 3.3766e-03 5.9058e-01 1.2212e-01 9.0920e-02 4.5571e-02 2.0084e-02 1.3851e-02 1.0378e-01 +4.3600e-01 1.3200e+07 5.5315e+02 3.3360e+03 5.9991e-08 3.5826e-01 6.4174e-01 4.0685e+03 3.0313e+03 3.7748e+02 1.2377e+02 4.7239e-05 1.9844e-05 6.0520e-03 1.4621e-03 3.0617e-01 8.3749e-02 7.5418e-02 4.5636e-02 2.4195e-02 2.0182e-02 4.3714e-01 9.7243e-03 3.3778e-03 5.9085e-01 1.2218e-01 9.0967e-02 4.5591e-02 2.0090e-02 1.3851e-02 1.0337e-01 +4.3800e-01 1.3100e+07 5.5315e+02 3.3159e+03 6.0556e-08 3.5841e-01 6.4159e-01 4.0590e+03 3.0083e+03 3.7863e+02 1.2266e+02 4.7408e-05 1.9774e-05 6.0136e-03 1.4477e-03 3.0370e-01 8.3298e-02 7.5147e-02 4.5551e-02 2.4190e-02 2.0209e-02 4.4044e-01 9.7292e-03 3.3790e-03 5.9110e-01 1.2224e-01 9.1014e-02 4.5612e-02 2.0097e-02 1.3852e-02 1.0297e-01 +4.4000e-01 1.3000e+07 5.5315e+02 3.2958e+03 6.1133e-08 3.5852e-01 6.4148e-01 4.0495e+03 2.9853e+03 3.7978e+02 1.2155e+02 4.7576e-05 1.9706e-05 5.9751e-03 1.4335e-03 3.0124e-01 8.2844e-02 7.4873e-02 4.5463e-02 2.4183e-02 2.0235e-02 4.4376e-01 9.7340e-03 3.3801e-03 5.9135e-01 1.2231e-01 9.1061e-02 4.5633e-02 2.0103e-02 1.3854e-02 1.0258e-01 +4.4200e-01 1.2900e+07 5.5315e+02 3.2756e+03 6.1720e-08 3.5860e-01 6.4140e-01 4.0399e+03 2.9623e+03 3.8091e+02 1.2045e+02 4.7742e-05 1.9639e-05 5.9365e-03 1.4193e-03 2.9878e-01 8.2388e-02 7.4596e-02 4.5373e-02 2.4175e-02 2.0260e-02 4.4707e-01 9.7386e-03 3.3811e-03 5.9158e-01 1.2237e-01 9.1107e-02 4.5655e-02 2.0111e-02 1.3856e-02 1.0220e-01 +4.4400e-01 1.2800e+07 5.5315e+02 3.2554e+03 6.2320e-08 3.5865e-01 6.4135e-01 4.0304e+03 2.9393e+03 3.8204e+02 1.1935e+02 4.7908e-05 1.9573e-05 5.8978e-03 1.4052e-03 2.9632e-01 8.1930e-02 7.4316e-02 4.5281e-02 2.4165e-02 2.0284e-02 4.5040e-01 9.7431e-03 3.3820e-03 5.9180e-01 1.2243e-01 9.1154e-02 4.5676e-02 2.0118e-02 1.3858e-02 1.0184e-01 +4.4600e-01 1.2700e+07 5.5315e+02 3.2351e+03 6.2931e-08 3.5867e-01 6.4133e-01 4.0208e+03 2.9163e+03 3.8316e+02 1.1827e+02 4.8073e-05 1.9507e-05 5.8590e-03 1.3912e-03 2.9387e-01 8.1470e-02 7.4032e-02 4.5186e-02 2.4153e-02 2.0306e-02 4.5373e-01 9.7475e-03 3.3829e-03 5.9202e-01 1.2248e-01 9.1201e-02 4.5699e-02 2.0126e-02 1.3861e-02 1.0148e-01 +4.4800e-01 1.2600e+07 5.5315e+02 3.2147e+03 6.3555e-08 3.5865e-01 6.4135e-01 4.0113e+03 2.8934e+03 3.8428e+02 1.1719e+02 4.8238e-05 1.9443e-05 5.8201e-03 1.3773e-03 2.9143e-01 8.1008e-02 7.3744e-02 4.5088e-02 2.4141e-02 2.0327e-02 4.5707e-01 9.7518e-03 3.3837e-03 5.9222e-01 1.2254e-01 9.1247e-02 4.5721e-02 2.0134e-02 1.3864e-02 1.0114e-01 +4.5000e-01 1.2500e+07 5.5315e+02 3.1942e+03 6.4192e-08 3.5860e-01 6.4140e-01 4.0017e+03 2.8704e+03 3.8539e+02 1.1612e+02 4.8401e-05 1.9379e-05 5.7812e-03 1.3634e-03 2.8899e-01 8.0543e-02 7.3454e-02 4.4988e-02 2.4127e-02 2.0347e-02 4.6041e-01 9.7560e-03 3.3844e-03 5.9241e-01 1.2260e-01 9.1293e-02 4.5744e-02 2.0142e-02 1.3868e-02 1.0081e-01 +4.5200e-01 1.2400e+07 5.5315e+02 3.1737e+03 6.4841e-08 3.5852e-01 6.4148e-01 3.9922e+03 2.8474e+03 3.8649e+02 1.1506e+02 4.8564e-05 1.9317e-05 5.7421e-03 1.3496e-03 2.8655e-01 8.0075e-02 7.3159e-02 4.4885e-02 2.4111e-02 2.0366e-02 4.6376e-01 9.7600e-03 3.3850e-03 5.9259e-01 1.2265e-01 9.1339e-02 4.5767e-02 2.0151e-02 1.3871e-02 1.0048e-01 +4.5400e-01 1.2300e+07 5.5315e+02 3.1531e+03 6.5504e-08 3.5841e-01 6.4159e-01 3.9826e+03 2.8244e+03 3.8758e+02 1.1400e+02 4.8725e-05 1.9255e-05 5.7030e-03 1.3359e-03 2.8412e-01 7.9606e-02 7.2861e-02 4.4780e-02 2.4094e-02 2.0384e-02 4.6712e-01 9.7639e-03 3.3856e-03 5.9276e-01 1.2271e-01 9.1385e-02 4.5790e-02 2.0160e-02 1.3876e-02 1.0017e-01 +4.5600e-01 1.2200e+07 5.5315e+02 3.1324e+03 6.6181e-08 3.5827e-01 6.4173e-01 3.9731e+03 2.8014e+03 3.8867e+02 1.1295e+02 4.8886e-05 1.9194e-05 5.6637e-03 1.3222e-03 2.8169e-01 7.9134e-02 7.2560e-02 4.4671e-02 2.4075e-02 2.0400e-02 4.7048e-01 9.7677e-03 3.3861e-03 5.9292e-01 1.2276e-01 9.1430e-02 4.5814e-02 2.0169e-02 1.3880e-02 9.9871e-02 +4.5800e-01 1.2100e+07 5.5315e+02 3.1116e+03 6.6872e-08 3.5810e-01 6.4190e-01 3.9635e+03 2.7784e+03 3.8975e+02 1.1191e+02 4.9046e-05 1.9133e-05 5.6243e-03 1.3086e-03 2.7926e-01 7.8659e-02 7.2254e-02 4.4560e-02 2.4055e-02 2.0416e-02 4.7386e-01 9.7714e-03 3.3865e-03 5.9307e-01 1.2281e-01 9.1475e-02 4.5838e-02 2.0179e-02 1.3885e-02 9.9580e-02 +4.6000e-01 1.2000e+07 5.5315e+02 3.0907e+03 6.7578e-08 3.5790e-01 6.4210e-01 3.9540e+03 2.7554e+03 3.9082e+02 1.1087e+02 4.9206e-05 1.9074e-05 5.5849e-03 1.2951e-03 2.7684e-01 7.8182e-02 7.1946e-02 4.4447e-02 2.4033e-02 2.0429e-02 4.7724e-01 9.7750e-03 3.3869e-03 5.9321e-01 1.2286e-01 9.1520e-02 4.5862e-02 2.0189e-02 1.3891e-02 9.9300e-02 +4.6200e-01 1.1900e+07 5.5315e+02 3.0698e+03 6.8298e-08 3.5768e-01 6.4232e-01 3.9445e+03 2.7324e+03 3.9189e+02 1.0984e+02 4.9364e-05 1.9015e-05 5.5453e-03 1.2816e-03 2.7442e-01 7.7703e-02 7.1633e-02 4.4330e-02 2.4010e-02 2.0442e-02 4.8063e-01 9.7784e-03 3.3872e-03 5.9334e-01 1.2291e-01 9.1565e-02 4.5886e-02 2.0199e-02 1.3896e-02 9.9031e-02 +4.6400e-01 1.1800e+07 5.5315e+02 3.0488e+03 6.9034e-08 3.5742e-01 6.4258e-01 3.9349e+03 2.7094e+03 3.9295e+02 1.0882e+02 4.9522e-05 1.8957e-05 5.5056e-03 1.2682e-03 2.7201e-01 7.7221e-02 7.1317e-02 4.4211e-02 2.3985e-02 2.0453e-02 4.8403e-01 9.7817e-03 3.3874e-03 5.9346e-01 1.2296e-01 9.1610e-02 4.5911e-02 2.0210e-02 1.3902e-02 9.8771e-02 +4.6600e-01 1.1700e+07 5.5315e+02 3.0277e+03 6.9787e-08 3.5713e-01 6.4287e-01 3.9254e+03 2.6864e+03 3.9401e+02 1.0780e+02 4.9679e-05 1.8899e-05 5.4659e-03 1.2548e-03 2.6960e-01 7.6737e-02 7.0997e-02 4.4089e-02 2.3958e-02 2.0463e-02 4.8744e-01 9.7849e-03 3.3876e-03 5.9358e-01 1.2301e-01 9.1654e-02 4.5936e-02 2.0221e-02 1.3909e-02 9.8522e-02 +4.6800e-01 1.1600e+07 5.5315e+02 3.0066e+03 7.0555e-08 3.5681e-01 6.4319e-01 3.9158e+03 2.6634e+03 3.9506e+02 1.0679e+02 4.9835e-05 1.8843e-05 5.4260e-03 1.2416e-03 2.6719e-01 7.6250e-02 7.0673e-02 4.3964e-02 2.3930e-02 2.0472e-02 4.9086e-01 9.7880e-03 3.3877e-03 5.9368e-01 1.2306e-01 9.1698e-02 4.5961e-02 2.0232e-02 1.3916e-02 9.8284e-02 +4.7000e-01 1.1500e+07 5.5315e+02 2.9853e+03 7.1341e-08 3.5647e-01 6.4353e-01 3.9063e+03 2.6405e+03 3.9611e+02 1.0579e+02 4.9991e-05 1.8787e-05 5.3860e-03 1.2283e-03 2.6478e-01 7.5760e-02 7.0345e-02 4.3836e-02 2.3900e-02 2.0479e-02 4.9428e-01 9.7909e-03 3.3877e-03 5.9377e-01 1.2310e-01 9.1742e-02 4.5986e-02 2.0243e-02 1.3923e-02 9.8055e-02 +4.7200e-01 1.1400e+07 5.5315e+02 2.9640e+03 7.2143e-08 3.5609e-01 6.4391e-01 3.8968e+03 2.6175e+03 3.9715e+02 1.0479e+02 5.0146e-05 1.8731e-05 5.3458e-03 1.2152e-03 2.6238e-01 7.5268e-02 7.0014e-02 4.3705e-02 2.3868e-02 2.0485e-02 4.9772e-01 9.7938e-03 3.3877e-03 5.9386e-01 1.2314e-01 9.1785e-02 4.6012e-02 2.0255e-02 1.3930e-02 9.7837e-02 +4.7400e-01 1.1300e+07 5.5315e+02 2.9425e+03 7.2964e-08 3.5568e-01 6.4432e-01 3.8872e+03 2.5945e+03 3.9818e+02 1.0379e+02 5.0300e-05 1.8677e-05 5.3056e-03 1.2020e-03 2.5998e-01 7.4773e-02 6.9679e-02 4.3571e-02 2.3835e-02 2.0490e-02 5.0117e-01 9.7965e-03 3.3876e-03 5.9393e-01 1.2319e-01 9.1828e-02 4.6037e-02 2.0267e-02 1.3938e-02 9.7629e-02 +4.7600e-01 1.1200e+07 5.5315e+02 2.9210e+03 7.3804e-08 3.5525e-01 6.4475e-01 3.8777e+03 2.5715e+03 3.9921e+02 1.0280e+02 5.0454e-05 1.8622e-05 5.2653e-03 1.1890e-03 2.5758e-01 7.4275e-02 6.9339e-02 4.3434e-02 2.3800e-02 2.0493e-02 5.0462e-01 9.7991e-03 3.3875e-03 5.9399e-01 1.2323e-01 9.1871e-02 4.6063e-02 2.0279e-02 1.3946e-02 9.7432e-02 +4.7800e-01 1.1100e+07 5.5315e+02 2.8994e+03 7.4662e-08 3.5479e-01 6.4521e-01 3.8682e+03 2.5485e+03 4.0024e+02 1.0182e+02 5.0607e-05 1.8569e-05 5.2248e-03 1.1760e-03 2.5518e-01 7.3775e-02 6.8996e-02 4.3295e-02 2.3763e-02 2.0495e-02 5.0809e-01 9.8016e-03 3.3873e-03 5.9405e-01 1.2327e-01 9.1914e-02 4.6089e-02 2.0292e-02 1.3955e-02 9.7244e-02 +4.8000e-01 1.1000e+07 5.5315e+02 2.8777e+03 7.5541e-08 3.5429e-01 6.4571e-01 3.8587e+03 2.5254e+03 4.0126e+02 1.0084e+02 5.0759e-05 1.8516e-05 5.1842e-03 1.1631e-03 2.5279e-01 7.3272e-02 6.8649e-02 4.3152e-02 2.3725e-02 2.0495e-02 5.1157e-01 9.8039e-03 3.3870e-03 5.9409e-01 1.2331e-01 9.1956e-02 4.6116e-02 2.0305e-02 1.3963e-02 9.7067e-02 +4.8200e-01 1.0900e+07 5.5315e+02 2.8559e+03 7.6439e-08 3.5377e-01 6.4623e-01 3.8491e+03 2.5024e+03 4.0228e+02 9.9866e+01 5.0911e-05 1.8464e-05 5.1435e-03 1.1502e-03 2.5040e-01 7.2767e-02 6.8298e-02 4.3006e-02 2.3684e-02 2.0493e-02 5.1506e-01 9.8062e-03 3.3867e-03 5.9413e-01 1.2334e-01 9.1998e-02 4.6142e-02 2.0318e-02 1.3973e-02 9.6900e-02 +4.8400e-01 1.0800e+07 5.5315e+02 2.8341e+03 7.7359e-08 3.5322e-01 6.4678e-01 3.8396e+03 2.4794e+03 4.0329e+02 9.8898e+01 5.1061e-05 1.8412e-05 5.1027e-03 1.1373e-03 2.4801e-01 7.2258e-02 6.7942e-02 4.2857e-02 2.3642e-02 2.0491e-02 5.1856e-01 9.8083e-03 3.3863e-03 5.9416e-01 1.2338e-01 9.2039e-02 4.6169e-02 2.0331e-02 1.3982e-02 9.6744e-02 +4.8600e-01 1.0700e+07 5.5315e+02 2.8121e+03 7.8300e-08 3.5264e-01 6.4736e-01 3.8301e+03 2.4564e+03 4.0429e+02 9.7934e+01 5.1212e-05 1.8361e-05 5.0617e-03 1.1245e-03 2.4562e-01 7.1747e-02 6.7583e-02 4.2705e-02 2.3598e-02 2.0486e-02 5.2208e-01 9.8103e-03 3.3859e-03 5.9418e-01 1.2342e-01 9.2080e-02 4.6196e-02 2.0345e-02 1.3992e-02 9.6598e-02 +4.8800e-01 1.0600e+07 5.5315e+02 2.7900e+03 7.9264e-08 3.5203e-01 6.4797e-01 3.8206e+03 2.4334e+03 4.0530e+02 9.6975e+01 5.1361e-05 1.8311e-05 5.0206e-03 1.1118e-03 2.4323e-01 7.1233e-02 6.7220e-02 4.2549e-02 2.3552e-02 2.0480e-02 5.2560e-01 9.8122e-03 3.3854e-03 5.9419e-01 1.2345e-01 9.2121e-02 4.6223e-02 2.0359e-02 1.4002e-02 9.6462e-02 +4.9000e-01 1.0500e+07 5.5315e+02 2.7679e+03 8.0251e-08 3.5138e-01 6.4862e-01 3.8111e+03 2.4104e+03 4.0629e+02 9.6021e+01 5.1510e-05 1.8261e-05 4.9794e-03 1.0991e-03 2.4085e-01 7.0716e-02 6.6852e-02 4.2391e-02 2.3504e-02 2.0472e-02 5.2914e-01 9.8139e-03 3.3848e-03 5.9419e-01 1.2348e-01 9.2161e-02 4.6250e-02 2.0373e-02 1.4012e-02 9.6337e-02 +4.9200e-01 1.0400e+07 5.5315e+02 2.7456e+03 8.1262e-08 3.5071e-01 6.4929e-01 3.8016e+03 2.3874e+03 4.0729e+02 9.5072e+01 5.1658e-05 1.8211e-05 4.9381e-03 1.0865e-03 2.3847e-01 7.0196e-02 6.6480e-02 4.2229e-02 2.3455e-02 2.0463e-02 5.3269e-01 9.8155e-03 3.3842e-03 5.9418e-01 1.2351e-01 9.2201e-02 4.6277e-02 2.0387e-02 1.4023e-02 9.6222e-02 +4.9400e-01 1.0300e+07 5.5315e+02 2.7232e+03 8.2297e-08 3.5000e-01 6.5000e-01 3.7921e+03 2.3644e+03 4.0828e+02 9.4127e+01 5.1806e-05 1.8162e-05 4.8966e-03 1.0739e-03 2.3609e-01 6.9674e-02 6.6104e-02 4.2064e-02 2.3403e-02 2.0452e-02 5.3625e-01 9.8170e-03 3.3835e-03 5.9416e-01 1.2355e-01 9.2240e-02 4.6304e-02 2.0402e-02 1.4034e-02 9.6118e-02 +4.9600e-01 1.0200e+07 5.5315e+02 2.7008e+03 8.3358e-08 3.4927e-01 6.5073e-01 3.7826e+03 2.3414e+03 4.0926e+02 9.3186e+01 5.1953e-05 1.8113e-05 4.8550e-03 1.0614e-03 2.3371e-01 6.9148e-02 6.5723e-02 4.1895e-02 2.3349e-02 2.0440e-02 5.3982e-01 9.8184e-03 3.3828e-03 5.9413e-01 1.2357e-01 9.2278e-02 4.6331e-02 2.0416e-02 1.4046e-02 9.6025e-02 +4.9800e-01 1.0100e+07 5.5315e+02 2.6782e+03 8.4446e-08 3.4850e-01 6.5150e-01 3.7731e+03 2.3183e+03 4.1024e+02 9.2250e+01 5.2100e-05 1.8065e-05 4.8133e-03 1.0489e-03 2.3133e-01 6.8620e-02 6.5339e-02 4.1724e-02 2.3293e-02 2.0425e-02 5.4341e-01 9.8196e-03 3.3820e-03 5.9409e-01 1.2360e-01 9.2317e-02 4.6359e-02 2.0431e-02 1.4057e-02 9.5943e-02 +5.0000e-01 1.0000e+07 5.5315e+02 2.6555e+03 8.5560e-08 3.4770e-01 6.5230e-01 3.7636e+03 2.2953e+03 4.1122e+02 9.1318e+01 5.2245e-05 1.8018e-05 4.7715e-03 1.0365e-03 2.2895e-01 6.8089e-02 6.4950e-02 4.1548e-02 2.3236e-02 2.0409e-02 5.4701e-01 9.8207e-03 3.3811e-03 5.9404e-01 1.2363e-01 9.2354e-02 4.6386e-02 2.0447e-02 1.4070e-02 9.5871e-02 +5.0200e-01 9.9604e+06 5.5315e+02 2.6465e+03 8.6010e-08 3.4737e-01 6.5263e-01 3.7599e+03 2.2862e+03 4.1161e+02 9.0950e+01 5.2303e-05 1.7999e-05 4.7549e-03 1.0315e-03 2.2801e-01 6.7877e-02 6.4794e-02 4.1478e-02 2.3212e-02 2.0402e-02 5.4844e-01 9.8211e-03 3.3807e-03 5.9402e-01 1.2364e-01 9.2369e-02 4.6397e-02 2.0453e-02 1.4074e-02 9.5846e-02 +5.0400e-01 9.9208e+06 5.5315e+02 2.6375e+03 8.6463e-08 3.4704e-01 6.5296e-01 3.7561e+03 2.2771e+03 4.1199e+02 9.0583e+01 5.2360e-05 1.7981e-05 4.7382e-03 1.0266e-03 2.2707e-01 6.7666e-02 6.4639e-02 4.1407e-02 2.3188e-02 2.0395e-02 5.4987e-01 9.8215e-03 3.3804e-03 5.9400e-01 1.2365e-01 9.2384e-02 4.6408e-02 2.0459e-02 1.4079e-02 9.5823e-02 +5.0600e-01 9.8812e+06 5.5315e+02 2.6285e+03 8.6922e-08 3.4670e-01 6.5330e-01 3.7524e+03 2.2680e+03 4.1238e+02 9.0216e+01 5.2418e-05 1.7962e-05 4.7216e-03 1.0217e-03 2.2613e-01 6.7454e-02 6.4482e-02 4.1336e-02 2.3164e-02 2.0388e-02 5.5130e-01 9.8219e-03 3.3800e-03 5.9397e-01 1.2366e-01 9.2398e-02 4.6419e-02 2.0465e-02 1.4084e-02 9.5801e-02 +5.0800e-01 9.8416e+06 5.5315e+02 2.6194e+03 8.7385e-08 3.4636e-01 6.5364e-01 3.7486e+03 2.2589e+03 4.1276e+02 8.9850e+01 5.2475e-05 1.7944e-05 4.7049e-03 1.0169e-03 2.2519e-01 6.7241e-02 6.4325e-02 4.1264e-02 2.3140e-02 2.0380e-02 5.5274e-01 9.8222e-03 3.3796e-03 5.9395e-01 1.2367e-01 9.2413e-02 4.6430e-02 2.0471e-02 1.4089e-02 9.5781e-02 +5.1000e-01 9.8020e+06 5.5315e+02 2.6103e+03 8.7852e-08 3.4601e-01 6.5399e-01 3.7449e+03 2.2497e+03 4.1314e+02 8.9485e+01 5.2532e-05 1.7925e-05 4.6882e-03 1.0120e-03 2.2425e-01 6.7028e-02 6.4166e-02 4.1191e-02 2.3115e-02 2.0372e-02 5.5418e-01 9.8225e-03 3.3792e-03 5.9392e-01 1.2367e-01 9.2427e-02 4.6441e-02 2.0477e-02 1.4094e-02 9.5763e-02 +5.1200e-01 9.7624e+06 5.5315e+02 2.6013e+03 8.8325e-08 3.4566e-01 6.5434e-01 3.7411e+03 2.2406e+03 4.1353e+02 8.9121e+01 5.2589e-05 1.7907e-05 4.6715e-03 1.0071e-03 2.2331e-01 6.6814e-02 6.4008e-02 4.1118e-02 2.3090e-02 2.0363e-02 5.5562e-01 9.8228e-03 3.3788e-03 5.9389e-01 1.2368e-01 9.2442e-02 4.6452e-02 2.0484e-02 1.4099e-02 9.5746e-02 +5.1400e-01 9.7228e+06 5.5315e+02 2.5921e+03 8.8802e-08 3.4530e-01 6.5470e-01 3.7374e+03 2.2315e+03 4.1391e+02 8.8756e+01 5.2646e-05 1.7888e-05 4.6547e-03 1.0022e-03 2.2237e-01 6.6600e-02 6.3848e-02 4.1045e-02 2.3064e-02 2.0355e-02 5.5706e-01 9.8231e-03 3.3784e-03 5.9386e-01 1.2369e-01 9.2456e-02 4.6463e-02 2.0490e-02 1.4105e-02 9.5732e-02 +5.1600e-01 9.6832e+06 5.5315e+02 2.5830e+03 8.9284e-08 3.4494e-01 6.5506e-01 3.7336e+03 2.2224e+03 4.1429e+02 8.8393e+01 5.2703e-05 1.7870e-05 4.6380e-03 9.9736e-04 2.2143e-01 6.6386e-02 6.3688e-02 4.0971e-02 2.3039e-02 2.0346e-02 5.5851e-01 9.8233e-03 3.3780e-03 5.9383e-01 1.2370e-01 9.2470e-02 4.6474e-02 2.0496e-02 1.4110e-02 9.5719e-02 +5.1800e-01 9.6436e+06 5.5315e+02 2.5739e+03 8.9771e-08 3.4457e-01 6.5543e-01 3.7299e+03 2.2133e+03 4.1467e+02 8.8030e+01 5.2760e-05 1.7852e-05 4.6212e-03 9.9251e-04 2.2049e-01 6.6171e-02 6.3527e-02 4.0896e-02 2.3013e-02 2.0337e-02 5.5995e-01 9.8236e-03 3.3776e-03 5.9380e-01 1.2371e-01 9.2484e-02 4.6485e-02 2.0503e-02 1.4115e-02 9.5708e-02 +5.2000e-01 9.6040e+06 5.5315e+02 2.5647e+03 9.0263e-08 3.4420e-01 6.5580e-01 3.7261e+03 2.2041e+03 4.1505e+02 8.7668e+01 5.2817e-05 1.7834e-05 4.6044e-03 9.8766e-04 2.1955e-01 6.5955e-02 6.3366e-02 4.0820e-02 2.2986e-02 2.0327e-02 5.6140e-01 9.8238e-03 3.3771e-03 5.9376e-01 1.2372e-01 9.2498e-02 4.6496e-02 2.0509e-02 1.4120e-02 9.5699e-02 +5.2200e-01 9.5644e+06 5.5315e+02 2.5555e+03 9.0760e-08 3.4382e-01 6.5618e-01 3.7224e+03 2.1950e+03 4.1543e+02 8.7307e+01 5.2873e-05 1.7816e-05 4.5876e-03 9.8282e-04 2.1861e-01 6.5739e-02 6.3203e-02 4.0745e-02 2.2959e-02 2.0317e-02 5.6285e-01 9.8240e-03 3.3767e-03 5.9372e-01 1.2372e-01 9.2512e-02 4.6507e-02 2.0515e-02 1.4126e-02 9.5691e-02 +5.2400e-01 9.5248e+06 5.5315e+02 2.5464e+03 9.1262e-08 3.4343e-01 6.5657e-01 3.7186e+03 2.1859e+03 4.1581e+02 8.6946e+01 5.2930e-05 1.7798e-05 4.5707e-03 9.7798e-04 2.1767e-01 6.5523e-02 6.3041e-02 4.0668e-02 2.2932e-02 2.0307e-02 5.6431e-01 9.8241e-03 3.3762e-03 5.9369e-01 1.2373e-01 9.2525e-02 4.6518e-02 2.0522e-02 1.4131e-02 9.5686e-02 +5.2600e-01 9.4852e+06 5.5315e+02 2.5371e+03 9.1770e-08 3.4304e-01 6.5696e-01 3.7149e+03 2.1768e+03 4.1619e+02 8.6585e+01 5.2986e-05 1.7780e-05 4.5539e-03 9.7315e-04 2.1674e-01 6.5306e-02 6.2877e-02 4.0591e-02 2.2905e-02 2.0297e-02 5.6576e-01 9.8243e-03 3.3758e-03 5.9365e-01 1.2374e-01 9.2539e-02 4.6529e-02 2.0528e-02 1.4137e-02 9.5682e-02 +5.2800e-01 9.4456e+06 5.5315e+02 2.5279e+03 9.2283e-08 3.4264e-01 6.5736e-01 3.7111e+03 2.1677e+03 4.1657e+02 8.6226e+01 5.3042e-05 1.7762e-05 4.5370e-03 9.6833e-04 2.1580e-01 6.5089e-02 6.2712e-02 4.0514e-02 2.2877e-02 2.0286e-02 5.6722e-01 9.8244e-03 3.3753e-03 5.9361e-01 1.2375e-01 9.2553e-02 4.6540e-02 2.0535e-02 1.4142e-02 9.5680e-02 +5.3000e-01 9.4060e+06 5.5315e+02 2.5187e+03 9.2801e-08 3.4224e-01 6.5776e-01 3.7074e+03 2.1586e+03 4.1695e+02 8.5867e+01 5.3099e-05 1.7745e-05 4.5201e-03 9.6352e-04 2.1486e-01 6.4871e-02 6.2547e-02 4.0435e-02 2.2848e-02 2.0275e-02 5.6868e-01 9.8245e-03 3.3748e-03 5.9356e-01 1.2375e-01 9.2566e-02 4.6550e-02 2.0541e-02 1.4148e-02 9.5680e-02 +5.3200e-01 9.3664e+06 5.5315e+02 2.5094e+03 9.3325e-08 3.4183e-01 6.5817e-01 3.7036e+03 2.1494e+03 4.1733e+02 8.5508e+01 5.3155e-05 1.7727e-05 4.5031e-03 9.5871e-04 2.1392e-01 6.4653e-02 6.2381e-02 4.0357e-02 2.2820e-02 2.0264e-02 5.7014e-01 9.8246e-03 3.3743e-03 5.9352e-01 1.2376e-01 9.2579e-02 4.6561e-02 2.0548e-02 1.4153e-02 9.5682e-02 +5.3400e-01 9.3268e+06 5.5315e+02 2.5001e+03 9.3854e-08 3.4142e-01 6.5858e-01 3.6999e+03 2.1403e+03 4.1770e+02 8.5150e+01 5.3211e-05 1.7709e-05 4.4862e-03 9.5391e-04 2.1298e-01 6.4434e-02 6.2215e-02 4.0277e-02 2.2791e-02 2.0252e-02 5.7161e-01 9.8246e-03 3.3738e-03 5.9347e-01 1.2376e-01 9.2592e-02 4.6572e-02 2.0555e-02 1.4159e-02 9.5686e-02 +5.3600e-01 9.2872e+06 5.5315e+02 2.4908e+03 9.4389e-08 3.4100e-01 6.5900e-01 3.6961e+03 2.1312e+03 4.1808e+02 8.4793e+01 5.3267e-05 1.7692e-05 4.4692e-03 9.4912e-04 2.1204e-01 6.4214e-02 6.2047e-02 4.0198e-02 2.2762e-02 2.0240e-02 5.7308e-01 9.8246e-03 3.3733e-03 5.9343e-01 1.2377e-01 9.2605e-02 4.6583e-02 2.0561e-02 1.4164e-02 9.5691e-02 +5.3800e-01 9.2476e+06 5.5315e+02 2.4815e+03 9.4930e-08 3.4057e-01 6.5943e-01 3.6924e+03 2.1221e+03 4.1846e+02 8.4436e+01 5.3323e-05 1.7674e-05 4.4522e-03 9.4433e-04 2.1111e-01 6.3995e-02 6.1879e-02 4.0117e-02 2.2732e-02 2.0228e-02 5.7455e-01 9.8246e-03 3.3728e-03 5.9338e-01 1.2378e-01 9.2618e-02 4.6594e-02 2.0568e-02 1.4170e-02 9.5699e-02 +5.4000e-01 9.2080e+06 5.5315e+02 2.4722e+03 9.5476e-08 3.4014e-01 6.5986e-01 3.6887e+03 2.1130e+03 4.1883e+02 8.4080e+01 5.3378e-05 1.7657e-05 4.4352e-03 9.3955e-04 2.1017e-01 6.3774e-02 6.1711e-02 4.0036e-02 2.2702e-02 2.0215e-02 5.7602e-01 9.8246e-03 3.3722e-03 5.9333e-01 1.2378e-01 9.2631e-02 4.6605e-02 2.0574e-02 1.4176e-02 9.5709e-02 +5.4200e-01 9.1684e+06 5.5315e+02 2.4628e+03 9.6028e-08 3.3970e-01 6.6030e-01 3.6849e+03 2.1038e+03 4.1921e+02 8.3724e+01 5.3434e-05 1.7639e-05 4.4181e-03 9.3478e-04 2.0923e-01 6.3554e-02 6.1541e-02 3.9954e-02 2.2671e-02 2.0202e-02 5.7749e-01 9.8246e-03 3.3717e-03 5.9327e-01 1.2379e-01 9.2644e-02 4.6616e-02 2.0581e-02 1.4182e-02 9.5720e-02 +5.4400e-01 9.1288e+06 5.5315e+02 2.4534e+03 9.6587e-08 3.3926e-01 6.6074e-01 3.6812e+03 2.0947e+03 4.1958e+02 8.3369e+01 5.3489e-05 1.7622e-05 4.4011e-03 9.3001e-04 2.0829e-01 6.3332e-02 6.1371e-02 3.9872e-02 2.2641e-02 2.0189e-02 5.7897e-01 9.8245e-03 3.3711e-03 5.9322e-01 1.2379e-01 9.2656e-02 4.6627e-02 2.0588e-02 1.4188e-02 9.5733e-02 +5.4600e-01 9.0892e+06 5.5315e+02 2.4440e+03 9.7151e-08 3.3881e-01 6.6119e-01 3.6774e+03 2.0856e+03 4.1995e+02 8.3014e+01 5.3545e-05 1.7605e-05 4.3840e-03 9.2525e-04 2.0736e-01 6.3111e-02 6.1200e-02 3.9789e-02 2.2610e-02 2.0175e-02 5.8045e-01 9.8244e-03 3.3706e-03 5.9317e-01 1.2380e-01 9.2669e-02 4.6638e-02 2.0595e-02 1.4194e-02 9.5749e-02 +5.4800e-01 9.0496e+06 5.5315e+02 2.4346e+03 9.7722e-08 3.3835e-01 6.6165e-01 3.6737e+03 2.0765e+03 4.2033e+02 8.2660e+01 5.3600e-05 1.7587e-05 4.3669e-03 9.2050e-04 2.0642e-01 6.2888e-02 6.1028e-02 3.9706e-02 2.2578e-02 2.0161e-02 5.8193e-01 9.8243e-03 3.3700e-03 5.9311e-01 1.2380e-01 9.2681e-02 4.6649e-02 2.0601e-02 1.4200e-02 9.5766e-02 +5.5000e-01 9.0100e+06 5.5315e+02 2.4252e+03 9.8299e-08 3.3789e-01 6.6211e-01 3.6700e+03 2.0674e+03 4.2070e+02 8.2307e+01 5.3656e-05 1.7570e-05 4.3497e-03 9.1575e-04 2.0548e-01 6.2666e-02 6.0856e-02 3.9622e-02 2.2546e-02 2.0147e-02 5.8342e-01 9.8242e-03 3.3694e-03 5.9305e-01 1.2380e-01 9.2693e-02 4.6660e-02 2.0608e-02 1.4206e-02 9.5786e-02 +5.5200e-01 8.9704e+06 5.5315e+02 2.4157e+03 9.8882e-08 3.3742e-01 6.6258e-01 3.6662e+03 2.0582e+03 4.2107e+02 8.1954e+01 5.3711e-05 1.7553e-05 4.3326e-03 9.1101e-04 2.0455e-01 6.2442e-02 6.0683e-02 3.9537e-02 2.2514e-02 2.0132e-02 5.8490e-01 9.8240e-03 3.3688e-03 5.9299e-01 1.2381e-01 9.2705e-02 4.6670e-02 2.0615e-02 1.4212e-02 9.5807e-02 +5.5400e-01 8.9308e+06 5.5315e+02 2.4063e+03 9.9471e-08 3.3695e-01 6.6305e-01 3.6625e+03 2.0491e+03 4.2145e+02 8.1602e+01 5.3766e-05 1.7536e-05 4.3154e-03 9.0627e-04 2.0361e-01 6.2219e-02 6.0509e-02 3.9452e-02 2.2481e-02 2.0117e-02 5.8639e-01 9.8239e-03 3.3682e-03 5.9293e-01 1.2381e-01 9.2717e-02 4.6681e-02 2.0622e-02 1.4218e-02 9.5831e-02 +5.5600e-01 8.8912e+06 5.5315e+02 2.3968e+03 1.0007e-07 3.3646e-01 6.6354e-01 3.6587e+03 2.0400e+03 4.2182e+02 8.1250e+01 5.3821e-05 1.7519e-05 4.2982e-03 9.0155e-04 2.0267e-01 6.1994e-02 6.0334e-02 3.9366e-02 2.2448e-02 2.0102e-02 5.8788e-01 9.8236e-03 3.3676e-03 5.9286e-01 1.2382e-01 9.2729e-02 4.6692e-02 2.0629e-02 1.4224e-02 9.5856e-02 +5.5800e-01 8.8516e+06 5.5315e+02 2.3873e+03 1.0067e-07 3.3598e-01 6.6402e-01 3.6550e+03 2.0309e+03 4.2219e+02 8.0899e+01 5.3876e-05 1.7502e-05 4.2810e-03 8.9682e-04 2.0174e-01 6.1770e-02 6.0158e-02 3.9280e-02 2.2415e-02 2.0086e-02 5.8938e-01 9.8234e-03 3.3670e-03 5.9280e-01 1.2382e-01 9.2741e-02 4.6703e-02 2.0636e-02 1.4230e-02 9.5884e-02 +5.6000e-01 8.8120e+06 5.5315e+02 2.3778e+03 1.0128e-07 3.3548e-01 6.6452e-01 3.6513e+03 2.0218e+03 4.2256e+02 8.0548e+01 5.3930e-05 1.7485e-05 4.2638e-03 8.9211e-04 2.0080e-01 6.1544e-02 5.9982e-02 3.9192e-02 2.2381e-02 2.0070e-02 5.9088e-01 9.8232e-03 3.3663e-03 5.9273e-01 1.2382e-01 9.2752e-02 4.6714e-02 2.0643e-02 1.4236e-02 9.5913e-02 +5.6200e-01 8.7724e+06 5.5315e+02 2.3682e+03 1.0190e-07 3.3498e-01 6.6502e-01 3.6475e+03 2.0126e+03 4.2293e+02 8.0198e+01 5.3985e-05 1.7468e-05 4.2465e-03 8.8740e-04 1.9986e-01 6.1319e-02 5.9805e-02 3.9105e-02 2.2347e-02 2.0053e-02 5.9237e-01 9.8229e-03 3.3657e-03 5.9266e-01 1.2382e-01 9.2763e-02 4.6724e-02 2.0650e-02 1.4243e-02 9.5945e-02 +5.6400e-01 8.7328e+06 5.5315e+02 2.3586e+03 1.0252e-07 3.3447e-01 6.6553e-01 3.6438e+03 2.0035e+03 4.2330e+02 7.9849e+01 5.4040e-05 1.7451e-05 4.2292e-03 8.8270e-04 1.9893e-01 6.1092e-02 5.9627e-02 3.9016e-02 2.2312e-02 2.0037e-02 5.9388e-01 9.8226e-03 3.3651e-03 5.9259e-01 1.2383e-01 9.2775e-02 4.6735e-02 2.0657e-02 1.4249e-02 9.5979e-02 +5.6600e-01 8.6932e+06 5.5315e+02 2.3491e+03 1.0315e-07 3.3396e-01 6.6604e-01 3.6401e+03 1.9944e+03 4.2367e+02 7.9500e+01 5.4094e-05 1.7435e-05 4.2119e-03 8.7800e-04 1.9799e-01 6.0866e-02 5.9449e-02 3.8927e-02 2.2277e-02 2.0020e-02 5.9538e-01 9.8222e-03 3.3644e-03 5.9252e-01 1.2383e-01 9.2786e-02 4.6746e-02 2.0663e-02 1.4255e-02 9.6015e-02 +5.6800e-01 8.6536e+06 5.5315e+02 2.3394e+03 1.0379e-07 3.3344e-01 6.6656e-01 3.6363e+03 1.9853e+03 4.2404e+02 7.9151e+01 5.4149e-05 1.7418e-05 4.1946e-03 8.7331e-04 1.9705e-01 6.0638e-02 5.9270e-02 3.8838e-02 2.2242e-02 2.0002e-02 5.9689e-01 9.8219e-03 3.3637e-03 5.9245e-01 1.2383e-01 9.2797e-02 4.6757e-02 2.0671e-02 1.4262e-02 9.6053e-02 +5.7000e-01 8.6140e+06 5.5315e+02 2.3298e+03 1.0443e-07 3.3291e-01 6.6709e-01 3.6326e+03 1.9761e+03 4.2440e+02 7.8803e+01 5.4203e-05 1.7401e-05 4.1772e-03 8.6863e-04 1.9612e-01 6.0411e-02 5.9089e-02 3.8748e-02 2.2206e-02 1.9984e-02 5.9840e-01 9.8215e-03 3.3630e-03 5.9237e-01 1.2383e-01 9.2807e-02 4.6767e-02 2.0678e-02 1.4268e-02 9.6093e-02 +5.7200e-01 8.5744e+06 5.5315e+02 2.3202e+03 1.0508e-07 3.3237e-01 6.6763e-01 3.6289e+03 1.9670e+03 4.2477e+02 7.8455e+01 5.4257e-05 1.7385e-05 4.1598e-03 8.6395e-04 1.9518e-01 6.0182e-02 5.8909e-02 3.8657e-02 2.2170e-02 1.9966e-02 5.9991e-01 9.8211e-03 3.3624e-03 5.9229e-01 1.2383e-01 9.2818e-02 4.6778e-02 2.0685e-02 1.4275e-02 9.6136e-02 +5.7400e-01 8.5348e+06 5.5315e+02 2.3105e+03 1.0574e-07 3.3183e-01 6.6817e-01 3.6251e+03 1.9579e+03 4.2514e+02 7.8108e+01 5.4311e-05 1.7368e-05 4.1424e-03 8.5928e-04 1.9425e-01 5.9954e-02 5.8727e-02 3.8565e-02 2.2133e-02 1.9947e-02 6.0143e-01 9.8206e-03 3.3616e-03 5.9222e-01 1.2383e-01 9.2828e-02 4.6788e-02 2.0692e-02 1.4281e-02 9.6181e-02 +5.7600e-01 8.4952e+06 5.5315e+02 2.3008e+03 1.0641e-07 3.3128e-01 6.6872e-01 3.6214e+03 1.9488e+03 4.2551e+02 7.7762e+01 5.4365e-05 1.7352e-05 4.1250e-03 8.5461e-04 1.9331e-01 5.9724e-02 5.8545e-02 3.8473e-02 2.2096e-02 1.9928e-02 6.0294e-01 9.8202e-03 3.3609e-03 5.9213e-01 1.2383e-01 9.2839e-02 4.6799e-02 2.0699e-02 1.4288e-02 9.6228e-02 +5.7800e-01 8.4556e+06 5.5315e+02 2.2911e+03 1.0709e-07 3.3072e-01 6.6928e-01 3.6177e+03 1.9397e+03 4.2587e+02 7.7416e+01 5.4419e-05 1.7335e-05 4.1075e-03 8.4995e-04 1.9237e-01 5.9495e-02 5.8362e-02 3.8380e-02 2.2059e-02 1.9909e-02 6.0446e-01 9.8197e-03 3.3602e-03 5.9205e-01 1.2383e-01 9.2849e-02 4.6810e-02 2.0706e-02 1.4294e-02 9.6277e-02 +5.8000e-01 8.4160e+06 5.5315e+02 2.2814e+03 1.0777e-07 3.3016e-01 6.6984e-01 3.6140e+03 1.9305e+03 4.2624e+02 7.7071e+01 5.4473e-05 1.7319e-05 4.0901e-03 8.4530e-04 1.9144e-01 5.9264e-02 5.8178e-02 3.8287e-02 2.2021e-02 1.9889e-02 6.0599e-01 9.8192e-03 3.3595e-03 5.9197e-01 1.2383e-01 9.2859e-02 4.6820e-02 2.0713e-02 1.4301e-02 9.6328e-02 +5.8200e-01 8.3764e+06 5.5315e+02 2.2717e+03 1.0846e-07 3.2959e-01 6.7041e-01 3.6102e+03 1.9214e+03 4.2661e+02 7.6726e+01 5.4527e-05 1.7302e-05 4.0726e-03 8.4065e-04 1.9050e-01 5.9033e-02 5.7993e-02 3.8193e-02 2.1983e-02 1.9869e-02 6.0751e-01 9.8186e-03 3.3587e-03 5.9188e-01 1.2383e-01 9.2869e-02 4.6831e-02 2.0720e-02 1.4308e-02 9.6382e-02 +5.8400e-01 8.3368e+06 5.5315e+02 2.2619e+03 1.0916e-07 3.2901e-01 6.7099e-01 3.6065e+03 1.9123e+03 4.2697e+02 7.6381e+01 5.4580e-05 1.7286e-05 4.0551e-03 8.3601e-04 1.8957e-01 5.8802e-02 5.7807e-02 3.8098e-02 2.1944e-02 1.9849e-02 6.0904e-01 9.8180e-03 3.3580e-03 5.9179e-01 1.2383e-01 9.2878e-02 4.6841e-02 2.0727e-02 1.4314e-02 9.6438e-02 +5.8600e-01 8.2972e+06 5.5315e+02 2.2521e+03 1.0987e-07 3.2842e-01 6.7158e-01 3.6028e+03 1.9032e+03 4.2734e+02 7.6037e+01 5.4634e-05 1.7270e-05 4.0375e-03 8.3138e-04 1.8863e-01 5.8570e-02 5.7621e-02 3.8003e-02 2.1905e-02 1.9828e-02 6.1057e-01 9.8174e-03 3.3572e-03 5.9170e-01 1.2383e-01 9.2888e-02 4.6851e-02 2.0734e-02 1.4321e-02 9.6497e-02 +5.8800e-01 8.2576e+06 5.5315e+02 2.2423e+03 1.1058e-07 3.2783e-01 6.7217e-01 3.5991e+03 1.8941e+03 4.2770e+02 7.5694e+01 5.4687e-05 1.7253e-05 4.0199e-03 8.2675e-04 1.8770e-01 5.8338e-02 5.7434e-02 3.7907e-02 2.1866e-02 1.9807e-02 6.1211e-01 9.8168e-03 3.3564e-03 5.9161e-01 1.2383e-01 9.2897e-02 4.6862e-02 2.0742e-02 1.4328e-02 9.6557e-02 +5.9000e-01 8.2180e+06 5.5315e+02 2.2325e+03 1.1131e-07 3.2722e-01 6.7278e-01 3.5953e+03 1.8849e+03 4.2806e+02 7.5351e+01 5.4741e-05 1.7237e-05 4.0024e-03 8.2213e-04 1.8676e-01 5.8105e-02 5.7246e-02 3.7810e-02 2.1826e-02 1.9785e-02 6.1364e-01 9.8161e-03 3.3557e-03 5.9152e-01 1.2383e-01 9.2906e-02 4.6872e-02 2.0749e-02 1.4335e-02 9.6621e-02 +5.9200e-01 8.1784e+06 5.5315e+02 2.2226e+03 1.1204e-07 3.2661e-01 6.7339e-01 3.5916e+03 1.8758e+03 4.2843e+02 7.5008e+01 5.4794e-05 1.7221e-05 3.9847e-03 8.1751e-04 1.8583e-01 5.7872e-02 5.7057e-02 3.7713e-02 2.1785e-02 1.9763e-02 6.1518e-01 9.8154e-03 3.3549e-03 5.9142e-01 1.2382e-01 9.2915e-02 4.6882e-02 2.0756e-02 1.4342e-02 9.6686e-02 +5.9400e-01 8.1388e+06 5.5315e+02 2.2127e+03 1.1278e-07 3.2600e-01 6.7400e-01 3.5879e+03 1.8667e+03 4.2879e+02 7.4666e+01 5.4847e-05 1.7205e-05 3.9671e-03 8.1290e-04 1.8489e-01 5.7638e-02 5.6868e-02 3.7615e-02 2.1745e-02 1.9740e-02 6.1672e-01 9.8147e-03 3.3541e-03 5.9133e-01 1.2382e-01 9.2924e-02 4.6893e-02 2.0763e-02 1.4349e-02 9.6754e-02 +5.9600e-01 8.0992e+06 5.5315e+02 2.2028e+03 1.1353e-07 3.2537e-01 6.7463e-01 3.5842e+03 1.8576e+03 4.2915e+02 7.4325e+01 5.4900e-05 1.7189e-05 3.9495e-03 8.0829e-04 1.8396e-01 5.7403e-02 5.6678e-02 3.7516e-02 2.1703e-02 1.9718e-02 6.1827e-01 9.8140e-03 3.3532e-03 5.9123e-01 1.2382e-01 9.2932e-02 4.6903e-02 2.0771e-02 1.4356e-02 9.6825e-02 +5.9800e-01 8.0596e+06 5.5315e+02 2.1929e+03 1.1429e-07 3.2474e-01 6.7526e-01 3.5804e+03 1.8484e+03 4.2952e+02 7.3983e+01 5.4953e-05 1.7173e-05 3.9318e-03 8.0370e-04 1.8302e-01 5.7168e-02 5.6486e-02 3.7417e-02 2.1662e-02 1.9694e-02 6.1982e-01 9.8132e-03 3.3524e-03 5.9113e-01 1.2382e-01 9.2940e-02 4.6913e-02 2.0778e-02 1.4363e-02 9.6898e-02 +6.0000e-01 8.0200e+06 5.5315e+02 2.1830e+03 1.1506e-07 3.2409e-01 6.7591e-01 3.5767e+03 1.8393e+03 4.2988e+02 7.3643e+01 5.5006e-05 1.7157e-05 3.9141e-03 7.9910e-04 1.8209e-01 5.6933e-02 5.6295e-02 3.7317e-02 2.1620e-02 1.9671e-02 6.2137e-01 9.8124e-03 3.3516e-03 5.9102e-01 1.2381e-01 9.2948e-02 4.6923e-02 2.0785e-02 1.4370e-02 9.6973e-02 +6.0200e-01 7.9804e+06 5.5315e+02 2.1730e+03 1.1584e-07 3.2344e-01 6.7656e-01 3.5730e+03 1.8302e+03 4.3024e+02 7.3303e+01 5.5059e-05 1.7141e-05 3.8963e-03 7.9452e-04 1.8115e-01 5.6697e-02 5.6102e-02 3.7216e-02 2.1577e-02 1.9646e-02 6.2292e-01 9.8116e-03 3.3507e-03 5.9092e-01 1.2381e-01 9.2956e-02 4.6933e-02 2.0792e-02 1.4377e-02 9.7051e-02 +6.0400e-01 7.9408e+06 5.5315e+02 2.1631e+03 1.1663e-07 3.2278e-01 6.7722e-01 3.5693e+03 1.8211e+03 4.3060e+02 7.2963e+01 5.5111e-05 1.7125e-05 3.8786e-03 7.8993e-04 1.8022e-01 5.6460e-02 5.5908e-02 3.7115e-02 2.1534e-02 1.9622e-02 6.2448e-01 9.8107e-03 3.3498e-03 5.9081e-01 1.2380e-01 9.2964e-02 4.6943e-02 2.0800e-02 1.4384e-02 9.7132e-02 +6.0600e-01 7.9012e+06 5.5315e+02 2.1531e+03 1.1743e-07 3.2212e-01 6.7788e-01 3.5656e+03 1.8120e+03 4.3096e+02 7.2624e+01 5.5164e-05 1.7109e-05 3.8608e-03 7.8536e-04 1.7928e-01 5.6223e-02 5.5714e-02 3.7013e-02 2.1491e-02 1.9597e-02 6.2604e-01 9.8098e-03 3.3490e-03 5.9070e-01 1.2380e-01 9.2972e-02 4.6953e-02 2.0807e-02 1.4391e-02 9.7215e-02 +6.0800e-01 7.8616e+06 5.5315e+02 2.1430e+03 1.1824e-07 3.2144e-01 6.7856e-01 3.5619e+03 1.8028e+03 4.3132e+02 7.2285e+01 5.5216e-05 1.7093e-05 3.8430e-03 7.8079e-04 1.7835e-01 5.5986e-02 5.5519e-02 3.6910e-02 2.1447e-02 1.9572e-02 6.2760e-01 9.8089e-03 3.3481e-03 5.9059e-01 1.2379e-01 9.2979e-02 4.6963e-02 2.0814e-02 1.4399e-02 9.7301e-02 +6.1000e-01 7.8220e+06 5.5315e+02 2.1330e+03 1.1906e-07 3.2076e-01 6.7924e-01 3.5581e+03 1.7937e+03 4.3168e+02 7.1947e+01 5.5268e-05 1.7077e-05 3.8252e-03 7.7622e-04 1.7741e-01 5.5748e-02 5.5323e-02 3.6806e-02 2.1402e-02 1.9546e-02 6.2916e-01 9.8079e-03 3.3472e-03 5.9048e-01 1.2379e-01 9.2986e-02 4.6973e-02 2.0822e-02 1.4406e-02 9.7389e-02 +6.1200e-01 7.7824e+06 5.5315e+02 2.1229e+03 1.1988e-07 3.2006e-01 6.7994e-01 3.5544e+03 1.7846e+03 4.3204e+02 7.1609e+01 5.5321e-05 1.7061e-05 3.8074e-03 7.7167e-04 1.7648e-01 5.5509e-02 5.5126e-02 3.6702e-02 2.1358e-02 1.9520e-02 6.3073e-01 9.8069e-03 3.3463e-03 5.9037e-01 1.2378e-01 9.2993e-02 4.6983e-02 2.0829e-02 1.4413e-02 9.7480e-02 +6.1400e-01 7.7428e+06 5.5315e+02 2.1128e+03 1.2072e-07 3.1936e-01 6.8064e-01 3.5507e+03 1.7755e+03 4.3240e+02 7.1272e+01 5.5373e-05 1.7046e-05 3.7895e-03 7.6711e-04 1.7554e-01 5.5270e-02 5.4928e-02 3.6597e-02 2.1312e-02 1.9493e-02 6.3230e-01 9.8059e-03 3.3453e-03 5.9025e-01 1.2378e-01 9.3000e-02 4.6992e-02 2.0836e-02 1.4421e-02 9.7574e-02 +6.1600e-01 7.7032e+06 5.5315e+02 2.1027e+03 1.2157e-07 3.1865e-01 6.8135e-01 3.5470e+03 1.7664e+03 4.3276e+02 7.0935e+01 5.5425e-05 1.7030e-05 3.7716e-03 7.6257e-04 1.7461e-01 5.5030e-02 5.4730e-02 3.6492e-02 2.1267e-02 1.9466e-02 6.3388e-01 9.8048e-03 3.3444e-03 5.9013e-01 1.2377e-01 9.3006e-02 4.7002e-02 2.0844e-02 1.4428e-02 9.7671e-02 +6.1800e-01 7.6636e+06 5.5315e+02 2.0926e+03 1.2243e-07 3.1793e-01 6.8207e-01 3.5433e+03 1.7572e+03 4.3312e+02 7.0598e+01 5.5477e-05 1.7014e-05 3.7537e-03 7.5802e-04 1.7367e-01 5.4790e-02 5.4531e-02 3.6386e-02 2.1221e-02 1.9438e-02 6.3545e-01 9.8037e-03 3.3435e-03 5.9001e-01 1.2376e-01 9.3012e-02 4.7012e-02 2.0851e-02 1.4435e-02 9.7770e-02 +6.2000e-01 7.6240e+06 5.5315e+02 2.0824e+03 1.2330e-07 3.1719e-01 6.8281e-01 3.5396e+03 1.7481e+03 4.3348e+02 7.0262e+01 5.5529e-05 1.6998e-05 3.7357e-03 7.5349e-04 1.7274e-01 5.4549e-02 5.4330e-02 3.6279e-02 2.1174e-02 1.9410e-02 6.3703e-01 9.8026e-03 3.3425e-03 5.8989e-01 1.2376e-01 9.3018e-02 4.7021e-02 2.0858e-02 1.4443e-02 9.7873e-02 +6.2200e-01 7.5844e+06 5.5315e+02 2.0722e+03 1.2419e-07 3.1645e-01 6.8355e-01 3.5359e+03 1.7390e+03 4.3383e+02 6.9927e+01 5.5580e-05 1.6983e-05 3.7178e-03 7.4896e-04 1.7180e-01 5.4308e-02 5.4129e-02 3.6171e-02 2.1127e-02 1.9382e-02 6.3861e-01 9.8015e-03 3.3415e-03 5.8976e-01 1.2375e-01 9.3024e-02 4.7031e-02 2.0866e-02 1.4450e-02 9.7978e-02 +6.2400e-01 7.5448e+06 5.5315e+02 2.0620e+03 1.2508e-07 3.1570e-01 6.8430e-01 3.5321e+03 1.7299e+03 4.3419e+02 6.9591e+01 5.5632e-05 1.6967e-05 3.6998e-03 7.4443e-04 1.7087e-01 5.4066e-02 5.3928e-02 3.6063e-02 2.1079e-02 1.9353e-02 6.4020e-01 9.8003e-03 3.3406e-03 5.8963e-01 1.2374e-01 9.3029e-02 4.7040e-02 2.0873e-02 1.4458e-02 9.8086e-02 +6.2600e-01 7.5052e+06 5.5315e+02 2.0518e+03 1.2599e-07 3.1494e-01 6.8506e-01 3.5284e+03 1.7208e+03 4.3455e+02 6.9257e+01 5.5684e-05 1.6951e-05 3.6818e-03 7.3992e-04 1.6993e-01 5.3823e-02 5.3725e-02 3.5953e-02 2.1031e-02 1.9324e-02 6.4179e-01 9.7990e-03 3.3396e-03 5.8950e-01 1.2373e-01 9.3035e-02 4.7049e-02 2.0880e-02 1.4465e-02 9.8196e-02 +6.2800e-01 7.4656e+06 5.5315e+02 2.0416e+03 1.2691e-07 3.1417e-01 6.8583e-01 3.5247e+03 1.7116e+03 4.3490e+02 6.8922e+01 5.5735e-05 1.6936e-05 3.6637e-03 7.3540e-04 1.6900e-01 5.3580e-02 5.3521e-02 3.5844e-02 2.0983e-02 1.9294e-02 6.4338e-01 9.7978e-03 3.3386e-03 5.8937e-01 1.2372e-01 9.3040e-02 4.7059e-02 2.0888e-02 1.4473e-02 9.8310e-02 +6.3000e-01 7.4260e+06 5.5315e+02 2.0313e+03 1.2783e-07 3.1339e-01 6.8661e-01 3.5210e+03 1.7025e+03 4.3526e+02 6.8589e+01 5.5786e-05 1.6920e-05 3.6457e-03 7.3089e-04 1.6806e-01 5.3337e-02 5.3317e-02 3.5733e-02 2.0934e-02 1.9263e-02 6.4498e-01 9.7965e-03 3.3375e-03 5.8924e-01 1.2371e-01 9.3044e-02 4.7068e-02 2.0895e-02 1.4481e-02 9.8427e-02 +6.3200e-01 7.3864e+06 5.5315e+02 2.0210e+03 1.2878e-07 3.1260e-01 6.8740e-01 3.5173e+03 1.6934e+03 4.3562e+02 6.8255e+01 5.5838e-05 1.6905e-05 3.6276e-03 7.2639e-04 1.6713e-01 5.3093e-02 5.3112e-02 3.5622e-02 2.0884e-02 1.9233e-02 6.4657e-01 9.7951e-03 3.3365e-03 5.8910e-01 1.2370e-01 9.3049e-02 4.7077e-02 2.0902e-02 1.4488e-02 9.8547e-02 +6.3400e-01 7.3468e+06 5.5315e+02 2.0107e+03 1.2973e-07 3.1180e-01 6.8820e-01 3.5136e+03 1.6843e+03 4.3597e+02 6.7922e+01 5.5889e-05 1.6889e-05 3.6095e-03 7.2190e-04 1.6619e-01 5.2848e-02 5.2906e-02 3.5510e-02 2.0834e-02 1.9201e-02 6.4817e-01 9.7938e-03 3.3355e-03 5.8896e-01 1.2369e-01 9.3053e-02 4.7086e-02 2.0910e-02 1.4496e-02 9.8670e-02 +6.3600e-01 7.3072e+06 5.5315e+02 2.0003e+03 1.3070e-07 3.1099e-01 6.8901e-01 3.5099e+03 1.6752e+03 4.3633e+02 6.7590e+01 5.5940e-05 1.6874e-05 3.5913e-03 7.1740e-04 1.6526e-01 5.2603e-02 5.2699e-02 3.5397e-02 2.0784e-02 1.9170e-02 6.4978e-01 9.7924e-03 3.3344e-03 5.8882e-01 1.2368e-01 9.3057e-02 4.7095e-02 2.0917e-02 1.4504e-02 9.8796e-02 +6.3800e-01 7.2676e+06 5.5315e+02 1.9900e+03 1.3168e-07 3.1017e-01 6.8983e-01 3.5062e+03 1.6660e+03 4.3668e+02 6.7258e+01 5.5991e-05 1.6858e-05 3.5732e-03 7.1292e-04 1.6432e-01 5.2358e-02 5.2491e-02 3.5284e-02 2.0733e-02 1.9138e-02 6.5139e-01 9.7909e-03 3.3333e-03 5.8868e-01 1.2367e-01 9.3061e-02 4.7104e-02 2.0924e-02 1.4512e-02 9.8925e-02 +6.4000e-01 7.2280e+06 5.5315e+02 1.9796e+03 1.3267e-07 3.0934e-01 6.9066e-01 3.5025e+03 1.6569e+03 4.3704e+02 6.6926e+01 5.6041e-05 1.6843e-05 3.5550e-03 7.0844e-04 1.6339e-01 5.2111e-02 5.2282e-02 3.5169e-02 2.0681e-02 1.9105e-02 6.5300e-01 9.7894e-03 3.3322e-03 5.8853e-01 1.2366e-01 9.3064e-02 4.7112e-02 2.0932e-02 1.4519e-02 9.9057e-02 +6.4200e-01 7.1884e+06 5.5315e+02 1.9692e+03 1.3368e-07 3.0849e-01 6.9151e-01 3.4988e+03 1.6478e+03 4.3739e+02 6.6594e+01 5.6092e-05 1.6828e-05 3.5368e-03 7.0396e-04 1.6246e-01 5.1865e-02 5.2073e-02 3.5054e-02 2.0629e-02 1.9072e-02 6.5461e-01 9.7879e-03 3.3311e-03 5.8839e-01 1.2365e-01 9.3067e-02 4.7121e-02 2.0939e-02 1.4527e-02 9.9193e-02 +6.4400e-01 7.1488e+06 5.5315e+02 1.9587e+03 1.3470e-07 3.0764e-01 6.9236e-01 3.4951e+03 1.6387e+03 4.3775e+02 6.6264e+01 5.6143e-05 1.6812e-05 3.5186e-03 6.9950e-04 1.6152e-01 5.1617e-02 5.1863e-02 3.4939e-02 2.0577e-02 1.9038e-02 6.5623e-01 9.7864e-03 3.3300e-03 5.8824e-01 1.2364e-01 9.3070e-02 4.7129e-02 2.0946e-02 1.4535e-02 9.9332e-02 +6.4600e-01 7.1092e+06 5.5315e+02 1.9483e+03 1.3573e-07 3.0677e-01 6.9323e-01 3.4914e+03 1.6296e+03 4.3810e+02 6.5933e+01 5.6193e-05 1.6797e-05 3.5003e-03 6.9503e-04 1.6059e-01 5.1370e-02 5.1651e-02 3.4822e-02 2.0524e-02 1.9004e-02 6.5785e-01 9.7848e-03 3.3289e-03 5.8808e-01 1.2362e-01 9.3072e-02 4.7138e-02 2.0954e-02 1.4543e-02 9.9474e-02 +6.4800e-01 7.0696e+06 5.5315e+02 1.9378e+03 1.3678e-07 3.0590e-01 6.9410e-01 3.4877e+03 1.6204e+03 4.3845e+02 6.5603e+01 5.6244e-05 1.6781e-05 3.4820e-03 6.9057e-04 1.5965e-01 5.1121e-02 5.1439e-02 3.4705e-02 2.0470e-02 1.8969e-02 6.5947e-01 9.7831e-03 3.3278e-03 5.8793e-01 1.2361e-01 9.3075e-02 4.7146e-02 2.0961e-02 1.4551e-02 9.9620e-02 +6.5000e-01 7.0300e+06 5.5315e+02 1.9273e+03 1.3784e-07 3.0501e-01 6.9499e-01 3.4840e+03 1.6113e+03 4.3881e+02 6.5273e+01 5.6294e-05 1.6766e-05 3.4637e-03 6.8612e-04 1.5872e-01 5.0872e-02 5.1226e-02 3.4587e-02 2.0416e-02 1.8934e-02 6.6110e-01 9.7814e-03 3.3266e-03 5.8777e-01 1.2360e-01 9.3077e-02 4.7154e-02 2.0968e-02 1.4559e-02 9.9769e-02 +6.5200e-01 6.9904e+06 5.5315e+02 1.9168e+03 1.3892e-07 3.0410e-01 6.9590e-01 3.4803e+03 1.6022e+03 4.3916e+02 6.4944e+01 5.6344e-05 1.6751e-05 3.4454e-03 6.8167e-04 1.5778e-01 5.0623e-02 5.1012e-02 3.4468e-02 2.0362e-02 1.8899e-02 6.6273e-01 9.7797e-03 3.3254e-03 5.8761e-01 1.2358e-01 9.3078e-02 4.7163e-02 2.0976e-02 1.4567e-02 9.9921e-02 +6.5400e-01 6.9508e+06 5.5315e+02 1.9062e+03 1.4002e-07 3.0319e-01 6.9681e-01 3.4766e+03 1.5931e+03 4.3951e+02 6.4615e+01 5.6394e-05 1.6735e-05 3.4271e-03 6.7723e-04 1.5685e-01 5.0373e-02 5.0798e-02 3.4349e-02 2.0307e-02 1.8862e-02 6.6436e-01 9.7780e-03 3.3243e-03 5.8745e-01 1.2357e-01 9.3079e-02 4.7171e-02 2.0983e-02 1.4575e-02 1.0008e-01 +6.5600e-01 6.9112e+06 5.5315e+02 1.8956e+03 1.4112e-07 3.0226e-01 6.9774e-01 3.4729e+03 1.5840e+03 4.3986e+02 6.4287e+01 5.6444e-05 1.6720e-05 3.4087e-03 6.7279e-04 1.5591e-01 5.0122e-02 5.0582e-02 3.4228e-02 2.0251e-02 1.8826e-02 6.6599e-01 9.7762e-03 3.3231e-03 5.8728e-01 1.2355e-01 9.3080e-02 4.7179e-02 2.0990e-02 1.4583e-02 1.0024e-01 +6.5800e-01 6.8716e+06 5.5315e+02 1.8850e+03 1.4225e-07 3.0133e-01 6.9867e-01 3.4692e+03 1.5749e+03 4.4021e+02 6.3959e+01 5.6494e-05 1.6705e-05 3.3903e-03 6.6836e-04 1.5498e-01 4.9871e-02 5.0366e-02 3.4107e-02 2.0195e-02 1.8788e-02 6.6763e-01 9.7743e-03 3.3218e-03 5.8711e-01 1.2353e-01 9.3081e-02 4.7186e-02 2.0997e-02 1.4591e-02 1.0040e-01 +6.6000e-01 6.8320e+06 5.5315e+02 1.8744e+03 1.4339e-07 3.0037e-01 6.9963e-01 3.4655e+03 1.5657e+03 4.4057e+02 6.3631e+01 5.6544e-05 1.6690e-05 3.3719e-03 6.6393e-04 1.5405e-01 4.9619e-02 5.0148e-02 3.3986e-02 2.0138e-02 1.8751e-02 6.6928e-01 9.7724e-03 3.3206e-03 5.8694e-01 1.2352e-01 9.3081e-02 4.7194e-02 2.1005e-02 1.4599e-02 1.0057e-01 +6.6200e-01 6.7924e+06 5.5315e+02 1.8637e+03 1.4454e-07 2.9941e-01 7.0059e-01 3.4618e+03 1.5566e+03 4.4092e+02 6.3304e+01 5.6593e-05 1.6674e-05 3.3534e-03 6.5951e-04 1.5311e-01 4.9367e-02 4.9930e-02 3.3863e-02 2.0081e-02 1.8712e-02 6.7092e-01 9.7705e-03 3.3194e-03 5.8677e-01 1.2350e-01 9.3081e-02 4.7202e-02 2.1012e-02 1.4607e-02 1.0074e-01 +6.6400e-01 6.7528e+06 5.5315e+02 1.8530e+03 1.4572e-07 2.9843e-01 7.0157e-01 3.4581e+03 1.5475e+03 4.4127e+02 6.2977e+01 5.6643e-05 1.6659e-05 3.3349e-03 6.5510e-04 1.5218e-01 4.9114e-02 4.9711e-02 3.3740e-02 2.0023e-02 1.8674e-02 6.7257e-01 9.7685e-03 3.3181e-03 5.8659e-01 1.2348e-01 9.3081e-02 4.7209e-02 2.1019e-02 1.4615e-02 1.0091e-01 +6.6600e-01 6.7132e+06 5.5315e+02 1.8423e+03 1.4691e-07 2.9744e-01 7.0256e-01 3.4544e+03 1.5384e+03 4.4162e+02 6.2650e+01 5.6692e-05 1.6644e-05 3.3164e-03 6.5069e-04 1.5124e-01 4.8861e-02 4.9490e-02 3.3615e-02 1.9965e-02 1.8634e-02 6.7423e-01 9.7665e-03 3.3168e-03 5.8642e-01 1.2347e-01 9.3080e-02 4.7216e-02 2.1026e-02 1.4623e-02 1.0109e-01 +6.6800e-01 6.6736e+06 5.5315e+02 1.8316e+03 1.4811e-07 2.9644e-01 7.0356e-01 3.4507e+03 1.5293e+03 4.4197e+02 6.2324e+01 5.6742e-05 1.6629e-05 3.2979e-03 6.4628e-04 1.5031e-01 4.8607e-02 4.9269e-02 3.3490e-02 1.9906e-02 1.8594e-02 6.7588e-01 9.7644e-03 3.3156e-03 5.8623e-01 1.2345e-01 9.3079e-02 4.7223e-02 2.1033e-02 1.4632e-02 1.0127e-01 +6.7000e-01 6.6340e+06 5.5315e+02 1.8209e+03 1.4934e-07 2.9542e-01 7.0458e-01 3.4470e+03 1.5202e+03 4.4232e+02 6.1998e+01 5.6791e-05 1.6614e-05 3.2794e-03 6.4188e-04 1.4937e-01 4.8352e-02 4.9048e-02 3.3365e-02 1.9847e-02 1.8554e-02 6.7754e-01 9.7623e-03 3.3142e-03 5.8605e-01 1.2343e-01 9.3078e-02 4.7230e-02 2.1040e-02 1.4640e-02 1.0146e-01 +6.7200e-01 6.5944e+06 5.5315e+02 1.8101e+03 1.5058e-07 2.9439e-01 7.0561e-01 3.4433e+03 1.5111e+03 4.4267e+02 6.1673e+01 5.6840e-05 1.6598e-05 3.2608e-03 6.3749e-04 1.4844e-01 4.8097e-02 4.8825e-02 3.3238e-02 1.9787e-02 1.8513e-02 6.7920e-01 9.7602e-03 3.3129e-03 5.8586e-01 1.2341e-01 9.3076e-02 4.7237e-02 2.1047e-02 1.4648e-02 1.0165e-01 +6.7400e-01 6.5548e+06 5.5315e+02 1.7993e+03 1.5184e-07 2.9334e-01 7.0666e-01 3.4396e+03 1.5019e+03 4.4302e+02 6.1348e+01 5.6889e-05 1.6583e-05 3.2422e-03 6.3310e-04 1.4750e-01 4.7842e-02 4.8601e-02 3.3111e-02 1.9727e-02 1.8471e-02 6.8087e-01 9.7580e-03 3.3116e-03 5.8567e-01 1.2339e-01 9.3073e-02 4.7244e-02 2.1054e-02 1.4656e-02 1.0184e-01 +6.7600e-01 6.5152e+06 5.5315e+02 1.7884e+03 1.5312e-07 2.9228e-01 7.0772e-01 3.4359e+03 1.4928e+03 4.4337e+02 6.1024e+01 5.6938e-05 1.6568e-05 3.2236e-03 6.2871e-04 1.4657e-01 4.7585e-02 4.8376e-02 3.2982e-02 1.9666e-02 1.8429e-02 6.8254e-01 9.7557e-03 3.3102e-03 5.8548e-01 1.2337e-01 9.3071e-02 4.7251e-02 2.1062e-02 1.4664e-02 1.0204e-01 +6.7800e-01 6.4756e+06 5.5315e+02 1.7776e+03 1.5442e-07 2.9120e-01 7.0880e-01 3.4322e+03 1.4837e+03 4.4372e+02 6.0699e+01 5.6986e-05 1.6553e-05 3.2049e-03 6.2433e-04 1.4563e-01 4.7329e-02 4.8151e-02 3.2853e-02 1.9604e-02 1.8386e-02 6.8421e-01 9.7534e-03 3.3089e-03 5.8528e-01 1.2335e-01 9.3068e-02 4.7257e-02 2.1069e-02 1.4673e-02 1.0224e-01 +6.8000e-01 6.4360e+06 5.5315e+02 1.7667e+03 1.5574e-07 2.9011e-01 7.0989e-01 3.4286e+03 1.4746e+03 4.4406e+02 6.0375e+01 5.7035e-05 1.6538e-05 3.1863e-03 6.1996e-04 1.4470e-01 4.7071e-02 4.7924e-02 3.2724e-02 1.9542e-02 1.8343e-02 6.8589e-01 9.7511e-03 3.3075e-03 5.8508e-01 1.2332e-01 9.3064e-02 4.7263e-02 2.1075e-02 1.4681e-02 1.0245e-01 +6.8200e-01 6.3964e+06 5.5315e+02 1.7558e+03 1.5707e-07 2.8900e-01 7.1100e-01 3.4249e+03 1.4655e+03 4.4441e+02 6.0052e+01 5.7084e-05 1.6522e-05 3.1676e-03 6.1559e-04 1.4377e-01 4.6813e-02 4.7697e-02 3.2593e-02 1.9479e-02 1.8299e-02 6.8757e-01 9.7487e-03 3.3061e-03 5.8488e-01 1.2330e-01 9.3061e-02 4.7270e-02 2.1082e-02 1.4689e-02 1.0266e-01 +6.8400e-01 6.3568e+06 5.5315e+02 1.7449e+03 1.5843e-07 2.8788e-01 7.1212e-01 3.4212e+03 1.4564e+03 4.4476e+02 5.9729e+01 5.7132e-05 1.6507e-05 3.1488e-03 6.1123e-04 1.4283e-01 4.6555e-02 4.7469e-02 3.2462e-02 1.9416e-02 1.8255e-02 6.8925e-01 9.7462e-03 3.3046e-03 5.8468e-01 1.2328e-01 9.3056e-02 4.7276e-02 2.1089e-02 1.4698e-02 1.0288e-01 +6.8600e-01 6.3172e+06 5.5315e+02 1.7339e+03 1.5981e-07 2.8674e-01 7.1326e-01 3.4175e+03 1.4473e+03 4.4511e+02 5.9406e+01 5.7180e-05 1.6492e-05 3.1301e-03 6.0687e-04 1.4190e-01 4.6296e-02 4.7239e-02 3.2329e-02 1.9352e-02 1.8210e-02 6.9094e-01 9.7437e-03 3.3032e-03 5.8447e-01 1.2325e-01 9.3052e-02 4.7281e-02 2.1096e-02 1.4706e-02 1.0310e-01 +6.8800e-01 6.2776e+06 5.5315e+02 1.7229e+03 1.6121e-07 2.8559e-01 7.1441e-01 3.4138e+03 1.4382e+03 4.4545e+02 5.9084e+01 5.7228e-05 1.6477e-05 3.1113e-03 6.0251e-04 1.4096e-01 4.6036e-02 4.7009e-02 3.2196e-02 1.9287e-02 1.8164e-02 6.9263e-01 9.7411e-03 3.3017e-03 5.8426e-01 1.2323e-01 9.3046e-02 4.7287e-02 2.1103e-02 1.4714e-02 1.0332e-01 +6.9000e-01 6.2380e+06 5.5315e+02 1.7119e+03 1.6263e-07 2.8441e-01 7.1559e-01 3.4101e+03 1.4290e+03 4.4580e+02 5.8762e+01 5.7277e-05 1.6462e-05 3.0925e-03 5.9816e-04 1.4003e-01 4.5776e-02 4.6778e-02 3.2062e-02 1.9222e-02 1.8118e-02 6.9433e-01 9.7385e-03 3.3003e-03 5.8404e-01 1.2320e-01 9.3041e-02 4.7292e-02 2.1110e-02 1.4723e-02 1.0355e-01 +6.9200e-01 6.1984e+06 5.5315e+02 1.7009e+03 1.6408e-07 2.8323e-01 7.1677e-01 3.4064e+03 1.4199e+03 4.4615e+02 5.8440e+01 5.7324e-05 1.6446e-05 3.0737e-03 5.9382e-04 1.3909e-01 4.5515e-02 4.6546e-02 3.1927e-02 1.9157e-02 1.8071e-02 6.9602e-01 9.7359e-03 3.2988e-03 5.8382e-01 1.2318e-01 9.3035e-02 4.7298e-02 2.1116e-02 1.4731e-02 1.0378e-01 +6.9400e-01 6.1588e+06 5.5315e+02 1.6898e+03 1.6554e-07 2.8202e-01 7.1798e-01 3.4028e+03 1.4108e+03 4.4650e+02 5.8119e+01 5.7372e-05 1.6431e-05 3.0549e-03 5.8948e-04 1.3816e-01 4.5254e-02 4.6313e-02 3.1792e-02 1.9090e-02 1.8024e-02 6.9773e-01 9.7331e-03 3.2973e-03 5.8360e-01 1.2315e-01 9.3028e-02 4.7303e-02 2.1123e-02 1.4739e-02 1.0402e-01 +6.9600e-01 6.1192e+06 5.5315e+02 1.6787e+03 1.6703e-07 2.8080e-01 7.1920e-01 3.3991e+03 1.4017e+03 4.4684e+02 5.7798e+01 5.7420e-05 1.6416e-05 3.0360e-03 5.8515e-04 1.3722e-01 4.4992e-02 4.6079e-02 3.1655e-02 1.9024e-02 1.7976e-02 6.9943e-01 9.7304e-03 3.2957e-03 5.8338e-01 1.2312e-01 9.3021e-02 4.7308e-02 2.1130e-02 1.4748e-02 1.0427e-01 +6.9800e-01 6.0796e+06 5.5315e+02 1.6676e+03 1.6855e-07 2.7955e-01 7.2045e-01 3.3954e+03 1.3926e+03 4.4719e+02 5.7477e+01 5.7468e-05 1.6401e-05 3.0171e-03 5.8082e-04 1.3629e-01 4.4730e-02 4.5844e-02 3.1518e-02 1.8956e-02 1.7927e-02 7.0114e-01 9.7275e-03 3.2942e-03 5.8315e-01 1.2310e-01 9.3014e-02 4.7312e-02 2.1136e-02 1.4756e-02 1.0452e-01 +7.0000e-01 6.0400e+06 5.5315e+02 1.6564e+03 1.7008e-07 2.7830e-01 7.2170e-01 3.3917e+03 1.3835e+03 4.4753e+02 5.7157e+01 5.7515e-05 1.6386e-05 2.9982e-03 5.7649e-04 1.3535e-01 4.4467e-02 4.5609e-02 3.1380e-02 1.8888e-02 1.7878e-02 7.0285e-01 9.7246e-03 3.2926e-03 5.8291e-01 1.2307e-01 9.3006e-02 4.7317e-02 2.1143e-02 1.4765e-02 1.0477e-01 +7.0200e-01 6.0004e+06 5.5315e+02 1.6453e+03 1.7165e-07 2.7702e-01 7.2298e-01 3.3880e+03 1.3744e+03 4.4788e+02 5.6837e+01 5.7562e-05 1.6370e-05 2.9792e-03 5.7218e-04 1.3442e-01 4.4203e-02 4.5372e-02 3.1241e-02 1.8819e-02 1.7828e-02 7.0457e-01 9.7217e-03 3.2910e-03 5.8268e-01 1.2304e-01 9.2998e-02 4.7321e-02 2.1149e-02 1.4773e-02 1.0503e-01 +7.0400e-01 5.9608e+06 5.5315e+02 1.6341e+03 1.7323e-07 2.7572e-01 7.2428e-01 3.3843e+03 1.3653e+03 4.4822e+02 5.6518e+01 5.7610e-05 1.6355e-05 2.9603e-03 5.6786e-04 1.3348e-01 4.3939e-02 4.5134e-02 3.1101e-02 1.8750e-02 1.7777e-02 7.0629e-01 9.7187e-03 3.2894e-03 5.8244e-01 1.2301e-01 9.2989e-02 4.7325e-02 2.1156e-02 1.4781e-02 1.0529e-01 +7.0600e-01 5.9212e+06 5.5315e+02 1.6229e+03 1.7485e-07 2.7440e-01 7.2560e-01 3.3807e+03 1.3562e+03 4.4857e+02 5.6198e+01 5.7657e-05 1.6340e-05 2.9413e-03 5.6355e-04 1.3255e-01 4.3674e-02 4.4895e-02 3.0960e-02 1.8680e-02 1.7726e-02 7.0801e-01 9.7156e-03 3.2878e-03 5.8220e-01 1.2298e-01 9.2979e-02 4.7329e-02 2.1162e-02 1.4790e-02 1.0556e-01 +7.0800e-01 5.8816e+06 5.5315e+02 1.6116e+03 1.7649e-07 2.7307e-01 7.2693e-01 3.3770e+03 1.3471e+03 4.4891e+02 5.5879e+01 5.7704e-05 1.6325e-05 2.9223e-03 5.5925e-04 1.3161e-01 4.3409e-02 4.4656e-02 3.0818e-02 1.8610e-02 1.7674e-02 7.0974e-01 9.7124e-03 3.2861e-03 5.8195e-01 1.2295e-01 9.2969e-02 4.7333e-02 2.1168e-02 1.4798e-02 1.0584e-01 +7.1000e-01 5.8420e+06 5.5315e+02 1.6003e+03 1.7815e-07 2.7171e-01 7.2829e-01 3.3733e+03 1.3380e+03 4.4926e+02 5.5561e+01 5.7750e-05 1.6309e-05 2.9032e-03 5.5495e-04 1.3068e-01 4.3143e-02 4.4415e-02 3.0676e-02 1.8539e-02 1.7622e-02 7.1147e-01 9.7092e-03 3.2844e-03 5.8170e-01 1.2291e-01 9.2959e-02 4.7336e-02 2.1175e-02 1.4807e-02 1.0612e-01 +7.1200e-01 5.8024e+06 5.5315e+02 1.5890e+03 1.7985e-07 2.7033e-01 7.2967e-01 3.3696e+03 1.3289e+03 4.4960e+02 5.5243e+01 5.7797e-05 1.6294e-05 2.8841e-03 5.5066e-04 1.2974e-01 4.2876e-02 4.4174e-02 3.0533e-02 1.8467e-02 1.7569e-02 7.1320e-01 9.7060e-03 3.2827e-03 5.8144e-01 1.2288e-01 9.2947e-02 4.7339e-02 2.1181e-02 1.4815e-02 1.0640e-01 +7.1400e-01 5.7628e+06 5.5315e+02 1.5777e+03 1.8157e-07 2.6893e-01 7.3107e-01 3.3659e+03 1.3198e+03 4.4995e+02 5.4925e+01 5.7844e-05 1.6279e-05 2.8650e-03 5.4637e-04 1.2881e-01 4.2609e-02 4.3931e-02 3.0388e-02 1.8395e-02 1.7515e-02 7.1494e-01 9.7026e-03 3.2810e-03 5.8119e-01 1.2285e-01 9.2936e-02 4.7342e-02 2.1187e-02 1.4823e-02 1.0670e-01 +7.1600e-01 5.7232e+06 5.5315e+02 1.5663e+03 1.8332e-07 2.6752e-01 7.3248e-01 3.3623e+03 1.3107e+03 4.5029e+02 5.4607e+01 5.7890e-05 1.6263e-05 2.8459e-03 5.4208e-04 1.2787e-01 4.2342e-02 4.3688e-02 3.0243e-02 1.8322e-02 1.7460e-02 7.1669e-01 9.6992e-03 3.2793e-03 5.8092e-01 1.2281e-01 9.2923e-02 4.7345e-02 2.1193e-02 1.4832e-02 1.0699e-01 +7.1800e-01 5.6836e+06 5.5315e+02 1.5550e+03 1.8510e-07 2.6607e-01 7.3393e-01 3.3586e+03 1.3016e+03 4.5063e+02 5.4290e+01 5.7937e-05 1.6248e-05 2.8268e-03 5.3780e-04 1.2694e-01 4.2073e-02 4.3443e-02 3.0097e-02 1.8248e-02 1.7405e-02 7.1843e-01 9.6958e-03 3.2775e-03 5.8066e-01 1.2277e-01 9.2911e-02 4.7347e-02 2.1199e-02 1.4840e-02 1.0730e-01 +7.2000e-01 5.6440e+06 5.5315e+02 1.5435e+03 1.8691e-07 2.6461e-01 7.3539e-01 3.3549e+03 1.2924e+03 4.5098e+02 5.3973e+01 5.7983e-05 1.6233e-05 2.8076e-03 5.3353e-04 1.2600e-01 4.1804e-02 4.3198e-02 2.9950e-02 1.8174e-02 1.7349e-02 7.2018e-01 9.6922e-03 3.2757e-03 5.8039e-01 1.2274e-01 9.2897e-02 4.7349e-02 2.1205e-02 1.4849e-02 1.0761e-01 +7.2200e-01 5.6044e+06 5.5315e+02 1.5321e+03 1.8875e-07 2.6312e-01 7.3688e-01 3.3512e+03 1.2833e+03 4.5132e+02 5.3657e+01 5.8029e-05 1.6217e-05 2.7884e-03 5.2926e-04 1.2507e-01 4.1535e-02 4.2951e-02 2.9802e-02 1.8099e-02 1.7293e-02 7.2194e-01 9.6886e-03 3.2739e-03 5.8011e-01 1.2270e-01 9.2883e-02 4.7351e-02 2.1211e-02 1.4857e-02 1.0792e-01 +7.2400e-01 5.5648e+06 5.5315e+02 1.5206e+03 1.9062e-07 2.6161e-01 7.3839e-01 3.3476e+03 1.2742e+03 4.5166e+02 5.3341e+01 5.8075e-05 1.6202e-05 2.7692e-03 5.2500e-04 1.2413e-01 4.1265e-02 4.2704e-02 2.9654e-02 1.8023e-02 1.7236e-02 7.2369e-01 9.6849e-03 3.2721e-03 5.7983e-01 1.2266e-01 9.2868e-02 4.7353e-02 2.1216e-02 1.4865e-02 1.0825e-01 +7.2600e-01 5.5252e+06 5.5315e+02 1.5091e+03 1.9253e-07 2.6008e-01 7.3992e-01 3.3439e+03 1.2651e+03 4.5200e+02 5.3025e+01 5.8121e-05 1.6186e-05 2.7499e-03 5.2074e-04 1.2320e-01 4.0994e-02 4.2455e-02 2.9504e-02 1.7947e-02 1.7178e-02 7.2545e-01 9.6812e-03 3.2702e-03 5.7955e-01 1.2262e-01 9.2853e-02 4.7354e-02 2.1222e-02 1.4874e-02 1.0858e-01 +7.2800e-01 5.4856e+06 5.5315e+02 1.4976e+03 1.9447e-07 2.5852e-01 7.4148e-01 3.3402e+03 1.2560e+03 4.5235e+02 5.2709e+01 5.8166e-05 1.6171e-05 2.7307e-03 5.1648e-04 1.2226e-01 4.0723e-02 4.2206e-02 2.9353e-02 1.7870e-02 1.7119e-02 7.2722e-01 9.6773e-03 3.2683e-03 5.7926e-01 1.2258e-01 9.2837e-02 4.7355e-02 2.1227e-02 1.4882e-02 1.0891e-01 +7.3000e-01 5.4460e+06 5.5315e+02 1.4861e+03 1.9644e-07 2.5694e-01 7.4306e-01 3.3366e+03 1.2469e+03 4.5269e+02 5.2394e+01 5.8212e-05 1.6155e-05 2.7114e-03 5.1223e-04 1.2133e-01 4.0451e-02 4.1956e-02 2.9202e-02 1.7792e-02 1.7060e-02 7.2899e-01 9.6734e-03 3.2664e-03 5.7897e-01 1.2254e-01 9.2820e-02 4.7356e-02 2.1233e-02 1.4890e-02 1.0925e-01 +7.3200e-01 5.4064e+06 5.5315e+02 1.4745e+03 1.9845e-07 2.5533e-01 7.4467e-01 3.3329e+03 1.2378e+03 4.5303e+02 5.2079e+01 5.8258e-05 1.6140e-05 2.6921e-03 5.0798e-04 1.2039e-01 4.0179e-02 4.1704e-02 2.9049e-02 1.7714e-02 1.7000e-02 7.3076e-01 9.6694e-03 3.2645e-03 5.7867e-01 1.2250e-01 9.2803e-02 4.7356e-02 2.1238e-02 1.4898e-02 1.0960e-01 +7.3400e-01 5.3668e+06 5.5315e+02 1.4629e+03 2.0049e-07 2.5369e-01 7.4631e-01 3.3292e+03 1.2288e+03 4.5337e+02 5.1765e+01 5.8303e-05 1.6124e-05 2.6727e-03 5.0374e-04 1.1946e-01 3.9906e-02 4.1452e-02 2.8896e-02 1.7635e-02 1.6939e-02 7.3254e-01 9.6654e-03 3.2625e-03 5.7837e-01 1.2245e-01 9.2784e-02 4.7357e-02 2.1243e-02 1.4907e-02 1.0996e-01 +7.3600e-01 5.3272e+06 5.5315e+02 1.4513e+03 2.0257e-07 2.5203e-01 7.4797e-01 3.3255e+03 1.2197e+03 4.5371e+02 5.1451e+01 5.8348e-05 1.6108e-05 2.6533e-03 4.9951e-04 1.1852e-01 3.9632e-02 4.1198e-02 2.8742e-02 1.7555e-02 1.6877e-02 7.3432e-01 9.6612e-03 3.2605e-03 5.7806e-01 1.2241e-01 9.2766e-02 4.7356e-02 2.1248e-02 1.4915e-02 1.1032e-01 +7.3800e-01 5.2876e+06 5.5315e+02 1.4396e+03 2.0469e-07 2.5034e-01 7.4966e-01 3.3219e+03 1.2106e+03 4.5406e+02 5.1137e+01 5.8393e-05 1.6093e-05 2.6339e-03 4.9528e-04 1.1758e-01 3.9358e-02 4.0944e-02 2.8587e-02 1.7475e-02 1.6815e-02 7.3611e-01 9.6570e-03 3.2585e-03 5.7775e-01 1.2237e-01 9.2746e-02 4.7356e-02 2.1253e-02 1.4923e-02 1.1069e-01 +7.4000e-01 5.2480e+06 5.5315e+02 1.4279e+03 2.0685e-07 2.4862e-01 7.5138e-01 3.3182e+03 1.2015e+03 4.5440e+02 5.0823e+01 5.8438e-05 1.6077e-05 2.6145e-03 4.9105e-04 1.1665e-01 3.9083e-02 4.0689e-02 2.8430e-02 1.7394e-02 1.6752e-02 7.3790e-01 9.6527e-03 3.2564e-03 5.7743e-01 1.2232e-01 9.2726e-02 4.7355e-02 2.1258e-02 1.4931e-02 1.1107e-01 +7.4200e-01 5.2084e+06 5.5315e+02 1.4162e+03 2.0904e-07 2.4688e-01 7.5312e-01 3.3145e+03 1.1924e+03 4.5474e+02 5.0510e+01 5.8483e-05 1.6061e-05 2.5951e-03 4.8683e-04 1.1571e-01 3.8808e-02 4.0432e-02 2.8273e-02 1.7312e-02 1.6688e-02 7.3969e-01 9.6483e-03 3.2544e-03 5.7711e-01 1.2227e-01 9.2704e-02 4.7354e-02 2.1263e-02 1.4939e-02 1.1146e-01 +7.4400e-01 5.1688e+06 5.5315e+02 1.4045e+03 2.1128e-07 2.4510e-01 7.5490e-01 3.3109e+03 1.1833e+03 4.5508e+02 5.0197e+01 5.8527e-05 1.6045e-05 2.5756e-03 4.8261e-04 1.1478e-01 3.8532e-02 4.0175e-02 2.8115e-02 1.7230e-02 1.6624e-02 7.4149e-01 9.6438e-03 3.2523e-03 5.7678e-01 1.2222e-01 9.2683e-02 4.7352e-02 2.1268e-02 1.4947e-02 1.1185e-01 +7.4600e-01 5.1292e+06 5.5315e+02 1.3927e+03 2.1356e-07 2.4330e-01 7.5670e-01 3.3072e+03 1.1742e+03 4.5542e+02 4.9884e+01 5.8572e-05 1.6030e-05 2.5561e-03 4.7840e-04 1.1384e-01 3.8255e-02 3.9916e-02 2.7956e-02 1.7147e-02 1.6558e-02 7.4329e-01 9.6392e-03 3.2501e-03 5.7645e-01 1.2217e-01 9.2660e-02 4.7350e-02 2.1272e-02 1.4955e-02 1.1225e-01 +7.4800e-01 5.0896e+06 5.5315e+02 1.3809e+03 2.1588e-07 2.4146e-01 7.5854e-01 3.3035e+03 1.1651e+03 4.5576e+02 4.9572e+01 5.8616e-05 1.6014e-05 2.5366e-03 4.7419e-04 1.1291e-01 3.7978e-02 3.9657e-02 2.7796e-02 1.7063e-02 1.6492e-02 7.4510e-01 9.6345e-03 3.2480e-03 5.7611e-01 1.2212e-01 9.2636e-02 4.7348e-02 2.1277e-02 1.4963e-02 1.1266e-01 +7.5000e-01 5.0500e+06 5.5315e+02 1.3691e+03 2.1824e-07 2.3959e-01 7.6041e-01 3.2999e+03 1.1560e+03 4.5610e+02 4.9260e+01 5.8661e-05 1.5998e-05 2.5170e-03 4.6999e-04 1.1197e-01 3.7700e-02 3.9396e-02 2.7635e-02 1.6978e-02 1.6426e-02 7.4691e-01 9.6298e-03 3.2458e-03 5.7576e-01 1.2207e-01 9.2612e-02 4.7345e-02 2.1281e-02 1.4971e-02 1.1308e-01 +7.5200e-01 5.0104e+06 5.5315e+02 1.3573e+03 2.2065e-07 2.3769e-01 7.6231e-01 3.2962e+03 1.1469e+03 4.5644e+02 4.8948e+01 5.8705e-05 1.5982e-05 2.4974e-03 4.6579e-04 1.1103e-01 3.7422e-02 3.9135e-02 2.7474e-02 1.6893e-02 1.6358e-02 7.4872e-01 9.6249e-03 3.2435e-03 5.7541e-01 1.2202e-01 9.2586e-02 4.7342e-02 2.1285e-02 1.4979e-02 1.1351e-01 +7.5400e-01 4.9708e+06 5.5315e+02 1.3454e+03 2.2310e-07 2.3576e-01 7.6424e-01 3.2926e+03 1.1378e+03 4.5678e+02 4.8637e+01 5.8749e-05 1.5966e-05 2.4778e-03 4.6160e-04 1.1010e-01 3.7143e-02 3.8872e-02 2.7311e-02 1.6807e-02 1.6290e-02 7.5054e-01 9.6199e-03 3.2413e-03 5.7506e-01 1.2196e-01 9.2560e-02 4.7338e-02 2.1289e-02 1.4987e-02 1.1394e-01 +7.5600e-01 4.9312e+06 5.5315e+02 1.3335e+03 2.2561e-07 2.3379e-01 7.6621e-01 3.2889e+03 1.1287e+03 4.5712e+02 4.8326e+01 5.8792e-05 1.5949e-05 2.4582e-03 4.5741e-04 1.0916e-01 3.6864e-02 3.8609e-02 2.7147e-02 1.6720e-02 1.6220e-02 7.5236e-01 9.6149e-03 3.2390e-03 5.7470e-01 1.2191e-01 9.2533e-02 4.7334e-02 2.1293e-02 1.4995e-02 1.1439e-01 +7.5800e-01 4.8916e+06 5.5315e+02 1.3216e+03 2.2816e-07 2.3179e-01 7.6821e-01 3.2852e+03 1.1196e+03 4.5746e+02 4.8015e+01 5.8836e-05 1.5933e-05 2.4386e-03 4.5323e-04 1.0823e-01 3.6583e-02 3.8344e-02 2.6982e-02 1.6633e-02 1.6150e-02 7.5419e-01 9.6097e-03 3.2367e-03 5.7433e-01 1.2185e-01 9.2505e-02 4.7330e-02 2.1297e-02 1.5002e-02 1.1484e-01 +7.6000e-01 4.8520e+06 5.5315e+02 1.3096e+03 2.3076e-07 2.2976e-01 7.7024e-01 3.2816e+03 1.1106e+03 4.5780e+02 4.7704e+01 5.8880e-05 1.5917e-05 2.4189e-03 4.4905e-04 1.0729e-01 3.6303e-02 3.8078e-02 2.6816e-02 1.6545e-02 1.6080e-02 7.5602e-01 9.6045e-03 3.2343e-03 5.7396e-01 1.2179e-01 9.2476e-02 4.7325e-02 2.1300e-02 1.5010e-02 1.1530e-01 +7.6200e-01 4.8124e+06 5.5315e+02 1.2976e+03 2.3341e-07 2.2768e-01 7.7232e-01 3.2779e+03 1.1015e+03 4.5813e+02 4.7394e+01 5.8923e-05 1.5901e-05 2.3992e-03 4.4487e-04 1.0636e-01 3.6021e-02 3.7812e-02 2.6650e-02 1.6456e-02 1.6008e-02 7.5785e-01 9.5991e-03 3.2319e-03 5.7358e-01 1.2173e-01 9.2446e-02 4.7320e-02 2.1303e-02 1.5018e-02 1.1577e-01 +7.6400e-01 4.7728e+06 5.5315e+02 1.2856e+03 2.3611e-07 2.2557e-01 7.7443e-01 3.2742e+03 1.0924e+03 4.5847e+02 4.7084e+01 5.8966e-05 1.5884e-05 2.3795e-03 4.4070e-04 1.0542e-01 3.5739e-02 3.7544e-02 2.6482e-02 1.6366e-02 1.5935e-02 7.5969e-01 9.5936e-03 3.2295e-03 5.7319e-01 1.2167e-01 9.2415e-02 4.7314e-02 2.1307e-02 1.5025e-02 1.1626e-01 +7.6600e-01 4.7332e+06 5.5315e+02 1.2736e+03 2.3887e-07 2.2342e-01 7.7658e-01 3.2706e+03 1.0833e+03 4.5881e+02 4.6774e+01 5.9009e-05 1.5868e-05 2.3597e-03 4.3654e-04 1.0448e-01 3.5457e-02 3.7275e-02 2.6313e-02 1.6275e-02 1.5862e-02 7.6154e-01 9.5880e-03 3.2270e-03 5.7280e-01 1.2161e-01 9.2383e-02 4.7308e-02 2.1310e-02 1.5033e-02 1.1675e-01 +7.6800e-01 4.6936e+06 5.5315e+02 1.2615e+03 2.4169e-07 2.2123e-01 7.7877e-01 3.2669e+03 1.0742e+03 4.5915e+02 4.6465e+01 5.9052e-05 1.5851e-05 2.3399e-03 4.3238e-04 1.0355e-01 3.5173e-02 3.7005e-02 2.6143e-02 1.6184e-02 1.5788e-02 7.6339e-01 9.5823e-03 3.2245e-03 5.7240e-01 1.2154e-01 9.2350e-02 4.7301e-02 2.1312e-02 1.5040e-02 1.1725e-01 +7.7000e-01 4.6540e+06 5.5315e+02 1.2494e+03 2.4456e-07 2.1900e-01 7.8100e-01 3.2633e+03 1.0651e+03 4.5949e+02 4.6156e+01 5.9095e-05 1.5835e-05 2.3201e-03 4.2822e-04 1.0261e-01 3.4890e-02 3.6735e-02 2.5973e-02 1.6092e-02 1.5713e-02 7.6524e-01 9.5765e-03 3.2219e-03 5.7199e-01 1.2148e-01 9.2316e-02 4.7294e-02 2.1315e-02 1.5047e-02 1.1776e-01 +7.7200e-01 4.6144e+06 5.5315e+02 1.2373e+03 2.4749e-07 2.1673e-01 7.8327e-01 3.2596e+03 1.0560e+03 4.5983e+02 4.5847e+01 5.9138e-05 1.5818e-05 2.3003e-03 4.2407e-04 1.0168e-01 3.4605e-02 3.6463e-02 2.5801e-02 1.6000e-02 1.5637e-02 7.6710e-01 9.5705e-03 3.2194e-03 5.7157e-01 1.2141e-01 9.2280e-02 4.7286e-02 2.1317e-02 1.5054e-02 1.1829e-01 +7.7400e-01 4.5748e+06 5.5315e+02 1.2252e+03 2.5048e-07 2.1442e-01 7.8558e-01 3.2560e+03 1.0470e+03 4.6016e+02 4.5539e+01 5.9180e-05 1.5801e-05 2.2804e-03 4.1992e-04 1.0074e-01 3.4320e-02 3.6190e-02 2.5628e-02 1.5906e-02 1.5560e-02 7.6896e-01 9.5644e-03 3.2167e-03 5.7115e-01 1.2134e-01 9.2244e-02 4.7278e-02 2.1319e-02 1.5061e-02 1.1882e-01 +7.7600e-01 4.5352e+06 5.5315e+02 1.2130e+03 2.5354e-07 2.1206e-01 7.8794e-01 3.2523e+03 1.0379e+03 4.6050e+02 4.5230e+01 5.9223e-05 1.5784e-05 2.2606e-03 4.1578e-04 9.9803e-02 3.4035e-02 3.5915e-02 2.5454e-02 1.5812e-02 1.5483e-02 7.7082e-01 9.5583e-03 3.2141e-03 5.7072e-01 1.2127e-01 9.2206e-02 4.7269e-02 2.1321e-02 1.5068e-02 1.1937e-01 +7.7800e-01 4.4956e+06 5.5315e+02 1.2008e+03 2.5666e-07 2.0966e-01 7.9034e-01 3.2486e+03 1.0288e+03 4.6084e+02 4.4923e+01 5.9265e-05 1.5767e-05 2.2407e-03 4.1164e-04 9.8866e-02 3.3748e-02 3.5640e-02 2.5279e-02 1.5717e-02 1.5404e-02 7.7269e-01 9.5519e-03 3.2113e-03 5.7029e-01 1.2120e-01 9.2167e-02 4.7259e-02 2.1323e-02 1.5075e-02 1.1992e-01 +7.8000e-01 4.4560e+06 5.5315e+02 1.1886e+03 2.5984e-07 2.0720e-01 7.9280e-01 3.2450e+03 1.0197e+03 4.6118e+02 4.4615e+01 5.9307e-05 1.5750e-05 2.2207e-03 4.0751e-04 9.7930e-02 3.3461e-02 3.5364e-02 2.5103e-02 1.5621e-02 1.5325e-02 7.7457e-01 9.5455e-03 3.2086e-03 5.6984e-01 1.2113e-01 9.2127e-02 4.7249e-02 2.1325e-02 1.5082e-02 1.2049e-01 +7.8200e-01 4.4164e+06 5.5315e+02 1.1764e+03 2.6309e-07 2.0471e-01 7.9529e-01 3.2413e+03 1.0106e+03 4.6151e+02 4.4308e+01 5.9349e-05 1.5733e-05 2.2008e-03 4.0338e-04 9.6993e-02 3.3174e-02 3.5087e-02 2.4927e-02 1.5524e-02 1.5245e-02 7.7645e-01 9.5389e-03 3.2058e-03 5.6939e-01 1.2105e-01 9.2086e-02 4.7238e-02 2.1326e-02 1.5089e-02 1.2107e-01 +7.8400e-01 4.3768e+06 5.5315e+02 1.1641e+03 2.6642e-07 2.0216e-01 7.9784e-01 3.2377e+03 1.0016e+03 4.6185e+02 4.4001e+01 5.9390e-05 1.5716e-05 2.1808e-03 3.9926e-04 9.6057e-02 3.2886e-02 3.4808e-02 2.4749e-02 1.5427e-02 1.5163e-02 7.7833e-01 9.5321e-03 3.2029e-03 5.6893e-01 1.2098e-01 9.2043e-02 4.7227e-02 2.1327e-02 1.5095e-02 1.2167e-01 +7.8600e-01 4.3372e+06 5.5315e+02 1.1518e+03 2.6981e-07 1.9956e-01 8.0044e-01 3.2340e+03 9.9249e+02 4.6219e+02 4.3694e+01 5.9432e-05 1.5699e-05 2.1608e-03 3.9514e-04 9.5120e-02 3.2597e-02 3.4529e-02 2.4570e-02 1.5328e-02 1.5081e-02 7.8022e-01 9.5253e-03 3.2001e-03 5.6846e-01 1.2090e-01 9.1999e-02 4.7215e-02 2.1328e-02 1.5101e-02 1.2227e-01 +7.8800e-01 4.2976e+06 5.5315e+02 1.1395e+03 2.7328e-07 1.9691e-01 8.0309e-01 3.2304e+03 9.8342e+02 4.6252e+02 4.3387e+01 5.9473e-05 1.5681e-05 2.1407e-03 3.9102e-04 9.4184e-02 3.2308e-02 3.4249e-02 2.4390e-02 1.5229e-02 1.4998e-02 7.8211e-01 9.5182e-03 3.1971e-03 5.6798e-01 1.2082e-01 9.1954e-02 4.7203e-02 2.1328e-02 1.5108e-02 1.2289e-01 +7.9000e-01 4.2580e+06 5.5315e+02 1.1271e+03 2.7683e-07 1.9421e-01 8.0579e-01 3.2267e+03 9.7435e+02 4.6286e+02 4.3081e+01 5.9515e-05 1.5663e-05 2.1207e-03 3.8691e-04 9.3247e-02 3.2018e-02 3.3967e-02 2.4208e-02 1.5129e-02 1.4914e-02 7.8401e-01 9.5111e-03 3.1941e-03 5.6750e-01 1.2074e-01 9.1907e-02 4.7189e-02 2.1329e-02 1.5114e-02 1.2353e-01 +7.9200e-01 4.2184e+06 5.5315e+02 1.1148e+03 2.8045e-07 1.9145e-01 8.0855e-01 3.2231e+03 9.6527e+02 4.6319e+02 4.2775e+01 5.9556e-05 1.5646e-05 2.1006e-03 3.8281e-04 9.2311e-02 3.1727e-02 3.3684e-02 2.4026e-02 1.5029e-02 1.4829e-02 7.8591e-01 9.5037e-03 3.1911e-03 5.6700e-01 1.2065e-01 9.1858e-02 4.7175e-02 2.1329e-02 1.5120e-02 1.2417e-01 +7.9400e-01 4.1788e+06 5.5315e+02 1.1024e+03 2.8416e-07 1.8863e-01 8.1137e-01 3.2194e+03 9.5620e+02 4.6353e+02 4.2469e+01 5.9597e-05 1.5628e-05 2.0805e-03 3.7870e-04 9.1374e-02 3.1436e-02 3.3400e-02 2.3843e-02 1.4927e-02 1.4744e-02 7.8782e-01 9.4962e-03 3.1880e-03 5.6649e-01 1.2056e-01 9.1809e-02 4.7160e-02 2.1328e-02 1.5126e-02 1.2483e-01 +7.9600e-01 4.1392e+06 5.5315e+02 1.0900e+03 2.8795e-07 1.8576e-01 8.1424e-01 3.2158e+03 9.4713e+02 4.6387e+02 4.2164e+01 5.9637e-05 1.5610e-05 2.0603e-03 3.7461e-04 9.0437e-02 3.1144e-02 3.3116e-02 2.3659e-02 1.4825e-02 1.4657e-02 7.8973e-01 9.4886e-03 3.1848e-03 5.6598e-01 1.2048e-01 9.1757e-02 4.7145e-02 2.1328e-02 1.5131e-02 1.2551e-01 +7.9800e-01 4.0996e+06 5.5315e+02 1.0775e+03 2.9183e-07 1.8282e-01 8.1718e-01 3.2121e+03 9.3806e+02 4.6420e+02 4.1859e+01 5.9678e-05 1.5592e-05 2.0402e-03 3.7051e-04 8.9501e-02 3.0852e-02 3.2830e-02 2.3473e-02 1.4722e-02 1.4569e-02 7.9164e-01 9.4808e-03 3.1816e-03 5.6545e-01 1.2039e-01 9.1704e-02 4.7129e-02 2.1327e-02 1.5137e-02 1.2620e-01 +8.0000e-01 4.0600e+06 5.5315e+02 1.0651e+03 2.9580e-07 1.7982e-01 8.2018e-01 3.2085e+03 9.2899e+02 4.6454e+02 4.1554e+01 5.9718e-05 1.5574e-05 2.0200e-03 3.6643e-04 8.8564e-02 3.0559e-02 3.2542e-02 2.3287e-02 1.4618e-02 1.4480e-02 7.9356e-01 9.4728e-03 3.1784e-03 5.6492e-01 1.2029e-01 9.1650e-02 4.7111e-02 2.1326e-02 1.5142e-02 1.2691e-01 +8.0200e-01 4.0204e+06 5.5315e+02 1.0526e+03 2.9987e-07 1.7676e-01 8.2324e-01 3.2048e+03 9.1993e+02 4.6487e+02 4.1249e+01 5.9759e-05 1.5556e-05 1.9998e-03 3.6234e-04 8.7627e-02 3.0265e-02 3.2254e-02 2.3099e-02 1.4513e-02 1.4391e-02 7.9549e-01 9.4646e-03 3.1751e-03 5.6437e-01 1.2020e-01 9.1593e-02 4.7093e-02 2.1324e-02 1.5147e-02 1.2763e-01 +8.0400e-01 3.9808e+06 5.5315e+02 1.0401e+03 3.0402e-07 1.7363e-01 8.2637e-01 3.2012e+03 9.1086e+02 4.6521e+02 4.0945e+01 5.9799e-05 1.5537e-05 1.9795e-03 3.5826e-04 8.6690e-02 2.9971e-02 3.1965e-02 2.2911e-02 1.4407e-02 1.4300e-02 7.9742e-01 9.4563e-03 3.1717e-03 5.6382e-01 1.2010e-01 9.1535e-02 4.7075e-02 2.1322e-02 1.5152e-02 1.2837e-01 +8.0600e-01 3.9412e+06 5.5315e+02 1.0275e+03 3.0828e-07 1.7043e-01 8.2957e-01 3.1975e+03 9.0180e+02 4.6554e+02 4.0641e+01 5.9839e-05 1.5518e-05 1.9593e-03 3.5419e-04 8.5753e-02 2.9676e-02 3.1675e-02 2.2721e-02 1.4300e-02 1.4208e-02 7.9935e-01 9.4477e-03 3.1683e-03 5.6325e-01 1.2000e-01 9.1476e-02 4.7055e-02 2.1320e-02 1.5157e-02 1.2913e-01 +8.0800e-01 3.9016e+06 5.5315e+02 1.0150e+03 3.1264e-07 1.6717e-01 8.3283e-01 3.1939e+03 8.9273e+02 4.6588e+02 4.0337e+01 5.9879e-05 1.5500e-05 1.9390e-03 3.5012e-04 8.4816e-02 2.9380e-02 3.1383e-02 2.2530e-02 1.4193e-02 1.4115e-02 8.0129e-01 9.4390e-03 3.1648e-03 5.6267e-01 1.1990e-01 9.1414e-02 4.7034e-02 2.1317e-02 1.5161e-02 1.2990e-01 +8.1000e-01 3.8620e+06 5.5315e+02 1.0024e+03 3.1711e-07 1.6382e-01 8.3618e-01 3.1902e+03 8.8367e+02 4.6621e+02 4.0033e+01 5.9918e-05 1.5481e-05 1.9187e-03 3.4605e-04 8.3879e-02 2.9084e-02 3.1090e-02 2.2338e-02 1.4084e-02 1.4022e-02 8.0324e-01 9.4301e-03 3.1612e-03 5.6208e-01 1.1979e-01 9.1350e-02 4.7013e-02 2.1314e-02 1.5165e-02 1.3069e-01 +8.1200e-01 3.8224e+06 5.5315e+02 9.8980e+02 3.2168e-07 1.6041e-01 8.3959e-01 3.1866e+03 8.7461e+02 4.6655e+02 3.9730e+01 5.9958e-05 1.5462e-05 1.8983e-03 3.4199e-04 8.2942e-02 2.8787e-02 3.0797e-02 2.2145e-02 1.3975e-02 1.3927e-02 8.0519e-01 9.4210e-03 3.1576e-03 5.6148e-01 1.1969e-01 9.1285e-02 4.6990e-02 2.1310e-02 1.5170e-02 1.3150e-01 +8.1400e-01 3.7828e+06 5.5315e+02 9.7718e+02 3.2637e-07 1.5691e-01 8.4309e-01 3.1829e+03 8.6555e+02 4.6688e+02 3.9427e+01 5.9997e-05 1.5442e-05 1.8780e-03 3.3794e-04 8.2005e-02 2.8490e-02 3.0502e-02 2.1951e-02 1.3865e-02 1.3831e-02 8.0714e-01 9.4116e-03 3.1539e-03 5.6086e-01 1.1958e-01 9.1217e-02 4.6967e-02 2.1307e-02 1.5173e-02 1.3233e-01 +8.1600e-01 3.7432e+06 5.5315e+02 9.6454e+02 3.3118e-07 1.5333e-01 8.4667e-01 3.1793e+03 8.5649e+02 4.6722e+02 3.9124e+01 6.0036e-05 1.5423e-05 1.8576e-03 3.3388e-04 8.1068e-02 2.8192e-02 3.0206e-02 2.1756e-02 1.3754e-02 1.3734e-02 8.0910e-01 9.4021e-03 3.1501e-03 5.6024e-01 1.1946e-01 9.1148e-02 4.6942e-02 2.1302e-02 1.5177e-02 1.3318e-01 +8.1800e-01 3.7036e+06 5.5315e+02 9.5188e+02 3.3611e-07 1.4967e-01 8.5033e-01 3.1757e+03 8.4743e+02 4.6755e+02 3.8822e+01 6.0075e-05 1.5403e-05 1.8372e-03 3.2984e-04 8.0130e-02 2.7893e-02 2.9909e-02 2.1559e-02 1.3642e-02 1.3636e-02 8.1106e-01 9.3923e-03 3.1462e-03 5.5960e-01 1.1935e-01 9.1076e-02 4.6917e-02 2.1298e-02 1.5180e-02 1.3405e-01 +8.2000e-01 3.6640e+06 5.5315e+02 9.3920e+02 3.4116e-07 1.4592e-01 8.5408e-01 3.1720e+03 8.3838e+02 4.6788e+02 3.8520e+01 6.0114e-05 1.5384e-05 1.8167e-03 3.2579e-04 7.9193e-02 2.7594e-02 2.9610e-02 2.1362e-02 1.3529e-02 1.3537e-02 8.1303e-01 9.3823e-03 3.1423e-03 5.5894e-01 1.1923e-01 9.1002e-02 4.6890e-02 2.1292e-02 1.5183e-02 1.3494e-01 +8.2200e-01 3.6244e+06 5.5315e+02 9.2651e+02 3.4635e-07 1.4209e-01 8.5791e-01 3.1684e+03 8.2932e+02 4.6822e+02 3.8218e+01 6.0152e-05 1.5364e-05 1.7962e-03 3.2175e-04 7.8256e-02 2.7294e-02 2.9311e-02 2.1163e-02 1.3415e-02 1.3437e-02 8.1501e-01 9.3720e-03 3.1383e-03 5.5827e-01 1.1911e-01 9.0926e-02 4.6862e-02 2.1287e-02 1.5186e-02 1.3585e-01 +8.2400e-01 3.5848e+06 5.5315e+02 9.1379e+02 3.5167e-07 1.3816e-01 8.6184e-01 3.1647e+03 8.2027e+02 4.6855e+02 3.7916e+01 6.0190e-05 1.5343e-05 1.7758e-03 3.1772e-04 7.7319e-02 2.6994e-02 2.9010e-02 2.0963e-02 1.3301e-02 1.3336e-02 8.1698e-01 9.3616e-03 3.1342e-03 5.5759e-01 1.1898e-01 9.0847e-02 4.6833e-02 2.1280e-02 1.5188e-02 1.3678e-01 +8.2600e-01 3.5452e+06 5.5315e+02 9.0106e+02 3.5713e-07 1.3413e-01 8.6587e-01 3.1611e+03 8.1121e+02 4.6889e+02 3.7614e+01 6.0229e-05 1.5323e-05 1.7552e-03 3.1369e-04 7.6381e-02 2.6692e-02 2.8709e-02 2.0762e-02 1.3185e-02 1.3234e-02 8.1897e-01 9.3508e-03 3.1301e-03 5.5689e-01 1.1886e-01 9.0766e-02 4.6803e-02 2.1274e-02 1.5190e-02 1.3774e-01 +8.2800e-01 3.5056e+06 5.5315e+02 8.8830e+02 3.6274e-07 1.3000e-01 8.7000e-01 3.1574e+03 8.0216e+02 4.6922e+02 3.7313e+01 6.0267e-05 1.5302e-05 1.7347e-03 3.0966e-04 7.5444e-02 2.6391e-02 2.8406e-02 2.0560e-02 1.3069e-02 1.3130e-02 8.2096e-01 9.3398e-03 3.1258e-03 5.5618e-01 1.1873e-01 9.0683e-02 4.6771e-02 2.1266e-02 1.5192e-02 1.3872e-01 +8.3000e-01 3.4660e+06 5.5315e+02 8.7554e+02 3.6850e-07 1.2577e-01 8.7423e-01 3.1538e+03 7.9311e+02 4.6955e+02 3.7012e+01 6.0304e-05 1.5282e-05 1.7141e-03 3.0564e-04 7.4506e-02 2.6088e-02 2.8102e-02 2.0357e-02 1.2951e-02 1.3026e-02 8.2295e-01 9.3285e-03 3.1215e-03 5.5545e-01 1.1859e-01 9.0596e-02 4.6738e-02 2.1258e-02 1.5194e-02 1.3972e-01 +8.3200e-01 3.4264e+06 5.5315e+02 8.6275e+02 3.7442e-07 1.2143e-01 8.7857e-01 3.1502e+03 7.8406e+02 4.6989e+02 3.6711e+01 6.0342e-05 1.5261e-05 1.6935e-03 3.0163e-04 7.3569e-02 2.5785e-02 2.7796e-02 2.0152e-02 1.2833e-02 1.2920e-02 8.2495e-01 9.3170e-03 3.1171e-03 5.5471e-01 1.1845e-01 9.0508e-02 4.6704e-02 2.1250e-02 1.5195e-02 1.4075e-01 +8.3400e-01 3.3868e+06 5.5315e+02 8.4995e+02 3.8050e-07 1.1698e-01 8.8302e-01 3.1465e+03 7.7501e+02 4.7022e+02 3.6411e+01 6.0380e-05 1.5239e-05 1.6729e-03 2.9761e-04 7.2631e-02 2.5481e-02 2.7490e-02 1.9946e-02 1.2714e-02 1.2813e-02 8.2695e-01 9.3052e-03 3.1125e-03 5.5394e-01 1.1831e-01 9.0416e-02 4.6668e-02 2.1241e-02 1.5195e-02 1.4181e-01 +8.3600e-01 3.3472e+06 5.5315e+02 8.3714e+02 3.8675e-07 1.1241e-01 8.8759e-01 3.1429e+03 7.6597e+02 4.7055e+02 3.6110e+01 6.0417e-05 1.5218e-05 1.6522e-03 2.9361e-04 7.1694e-02 2.5177e-02 2.7183e-02 1.9740e-02 1.2593e-02 1.2705e-02 8.2896e-01 9.2930e-03 3.1079e-03 5.5316e-01 1.1817e-01 9.0321e-02 4.6631e-02 2.1231e-02 1.5195e-02 1.4289e-01 +8.3800e-01 3.3076e+06 5.5315e+02 8.2431e+02 3.9317e-07 1.0772e-01 8.9228e-01 3.1392e+03 7.5692e+02 4.7089e+02 3.5810e+01 6.0454e-05 1.5196e-05 1.6316e-03 2.8960e-04 7.0756e-02 2.4872e-02 2.6874e-02 1.9532e-02 1.2472e-02 1.2596e-02 8.3098e-01 9.2806e-03 3.1032e-03 5.5237e-01 1.1802e-01 9.0224e-02 4.6593e-02 2.1221e-02 1.5195e-02 1.4400e-01 +8.4000e-01 3.2680e+06 5.5315e+02 8.1147e+02 3.9978e-07 1.0291e-01 8.9709e-01 3.1356e+03 7.4788e+02 4.7122e+02 3.5511e+01 6.0491e-05 1.5174e-05 1.6109e-03 2.8560e-04 6.9819e-02 2.4566e-02 2.6564e-02 1.9322e-02 1.2350e-02 1.2486e-02 8.3300e-01 9.2678e-03 3.0984e-03 5.5155e-01 1.1786e-01 9.0123e-02 4.6552e-02 2.1210e-02 1.5195e-02 1.4514e-01 +8.4200e-01 3.2284e+06 5.5315e+02 7.9862e+02 4.0658e-07 9.7964e-02 9.0204e-01 3.1320e+03 7.3884e+02 4.7155e+02 3.5211e+01 6.0527e-05 1.5152e-05 1.5902e-03 2.8161e-04 6.8881e-02 2.4260e-02 2.6253e-02 1.9112e-02 1.2227e-02 1.2375e-02 8.3502e-01 9.2547e-03 3.0934e-03 5.5071e-01 1.1771e-01 9.0019e-02 4.6511e-02 2.1198e-02 1.5194e-02 1.4631e-01 +8.4400e-01 3.1888e+06 5.5315e+02 7.8575e+02 4.1359e-07 9.2883e-02 9.0712e-01 3.1283e+03 7.2980e+02 4.7188e+02 3.4912e+01 6.0564e-05 1.5129e-05 1.5694e-03 2.7762e-04 6.7943e-02 2.3953e-02 2.5941e-02 1.8900e-02 1.2102e-02 1.2262e-02 8.3705e-01 9.2413e-03 3.0884e-03 5.4986e-01 1.1754e-01 8.9912e-02 4.6467e-02 2.1186e-02 1.5192e-02 1.4751e-01 +8.4600e-01 3.1492e+06 5.5315e+02 7.7288e+02 4.2079e-07 8.7659e-02 9.1234e-01 3.1247e+03 7.2076e+02 4.7222e+02 3.4613e+01 6.0600e-05 1.5106e-05 1.5486e-03 2.7363e-04 6.7005e-02 2.3646e-02 2.5628e-02 1.8688e-02 1.1977e-02 1.2148e-02 8.3909e-01 9.2275e-03 3.0832e-03 5.4898e-01 1.1738e-01 8.9801e-02 4.6422e-02 2.1172e-02 1.5190e-02 1.4875e-01 +8.4800e-01 3.1096e+06 5.5315e+02 7.6000e+02 4.2822e-07 8.2288e-02 9.1771e-01 3.1211e+03 7.1172e+02 4.7255e+02 3.4314e+01 6.0636e-05 1.5083e-05 1.5278e-03 2.6965e-04 6.6068e-02 2.3338e-02 2.5313e-02 1.8474e-02 1.1851e-02 1.2033e-02 8.4113e-01 9.2133e-03 3.0780e-03 5.4808e-01 1.1721e-01 8.9687e-02 4.6375e-02 2.1158e-02 1.5188e-02 1.5001e-01 +8.5000e-01 3.0700e+06 5.5315e+02 7.4710e+02 4.3587e-07 7.6762e-02 9.2324e-01 3.1174e+03 7.0268e+02 4.7288e+02 3.4015e+01 6.0672e-05 1.5059e-05 1.5070e-03 2.6567e-04 6.5130e-02 2.3029e-02 2.4998e-02 1.8258e-02 1.1724e-02 1.1917e-02 8.4317e-01 9.1988e-03 3.0726e-03 5.4716e-01 1.1703e-01 8.9569e-02 4.6325e-02 2.1143e-02 1.5184e-02 1.5132e-01 +8.5200e-01 3.0304e+06 5.5315e+02 7.3421e+02 4.4376e-07 7.1074e-02 9.2893e-01 3.1138e+03 6.9365e+02 4.7321e+02 3.3717e+01 6.0708e-05 1.5035e-05 1.4861e-03 2.6170e-04 6.4192e-02 2.2719e-02 2.4681e-02 1.8042e-02 1.1596e-02 1.1799e-02 8.4522e-01 9.1839e-03 3.0670e-03 5.4621e-01 1.1685e-01 8.9447e-02 4.6274e-02 2.1128e-02 1.5181e-02 1.5266e-01 +8.5400e-01 2.9908e+06 5.5315e+02 7.2130e+02 4.5189e-07 6.5219e-02 9.3478e-01 3.1101e+03 6.8461e+02 4.7355e+02 3.3419e+01 6.0743e-05 1.5011e-05 1.4653e-03 2.5773e-04 6.3254e-02 2.2409e-02 2.4363e-02 1.7824e-02 1.1467e-02 1.1680e-02 8.4728e-01 9.1685e-03 3.0613e-03 5.4525e-01 1.1666e-01 8.9321e-02 4.6221e-02 2.1111e-02 1.5176e-02 1.5403e-01 +8.5600e-01 2.9512e+06 5.5315e+02 7.0839e+02 4.6028e-07 5.9188e-02 9.4081e-01 3.1065e+03 6.7558e+02 4.7388e+02 3.3121e+01 6.0779e-05 1.4987e-05 1.4444e-03 2.5376e-04 6.2316e-02 2.2098e-02 2.4043e-02 1.7605e-02 1.1336e-02 1.1560e-02 8.4934e-01 9.1528e-03 3.0555e-03 5.4425e-01 1.1647e-01 8.9191e-02 4.6166e-02 2.1093e-02 1.5172e-02 1.5545e-01 +8.5800e-01 2.9116e+06 5.5315e+02 6.9548e+02 4.6894e-07 5.2973e-02 9.4703e-01 3.1029e+03 6.6655e+02 4.7421e+02 3.2823e+01 6.0814e-05 1.4962e-05 1.4234e-03 2.4980e-04 6.1378e-02 2.1787e-02 2.3723e-02 1.7385e-02 1.1205e-02 1.1439e-02 8.5141e-01 9.1366e-03 3.0496e-03 5.4323e-01 1.1627e-01 8.9057e-02 4.6109e-02 2.1075e-02 1.5166e-02 1.5690e-01 +8.6000e-01 2.8720e+06 5.5315e+02 6.8256e+02 4.7788e-07 4.6565e-02 9.5343e-01 3.0992e+03 6.5752e+02 4.7454e+02 3.2526e+01 6.0849e-05 1.4936e-05 1.4025e-03 2.4585e-04 6.0440e-02 2.1475e-02 2.3401e-02 1.7164e-02 1.1073e-02 1.1316e-02 8.5348e-01 9.1199e-03 3.0435e-03 5.4218e-01 1.1607e-01 8.8918e-02 4.6049e-02 2.1055e-02 1.5160e-02 1.5840e-01 +8.6200e-01 2.8324e+06 5.5315e+02 6.6964e+02 4.8711e-07 3.9957e-02 9.6004e-01 3.0956e+03 6.4849e+02 4.7487e+02 3.2229e+01 6.0883e-05 1.4911e-05 1.3815e-03 2.4190e-04 5.9502e-02 2.1162e-02 2.3078e-02 1.6941e-02 1.0940e-02 1.1192e-02 8.5556e-01 9.1027e-03 3.0372e-03 5.4111e-01 1.1586e-01 8.8774e-02 4.5986e-02 2.1034e-02 1.5153e-02 1.5995e-01 +8.6400e-01 2.7928e+06 5.5315e+02 6.5673e+02 4.9665e-07 3.3136e-02 9.6686e-01 3.0920e+03 6.3947e+02 4.7520e+02 3.1932e+01 6.0918e-05 1.4885e-05 1.3605e-03 2.3795e-04 5.8564e-02 2.0849e-02 2.2754e-02 1.6717e-02 1.0805e-02 1.1067e-02 8.5764e-01 9.0851e-03 3.0308e-03 5.4000e-01 1.1564e-01 8.8625e-02 4.5922e-02 2.1012e-02 1.5145e-02 1.6153e-01 +8.6600e-01 2.7532e+06 5.5315e+02 6.4381e+02 5.0652e-07 2.6095e-02 9.7391e-01 3.0883e+03 6.3044e+02 4.7554e+02 3.1635e+01 6.0952e-05 1.4858e-05 1.3395e-03 2.3401e-04 5.7626e-02 2.0535e-02 2.2429e-02 1.6492e-02 1.0670e-02 1.0940e-02 8.5973e-01 9.0669e-03 3.0242e-03 5.3887e-01 1.1542e-01 8.8472e-02 4.5854e-02 2.0989e-02 1.5136e-02 1.6317e-01 +8.6800e-01 2.7136e+06 5.5315e+02 6.3090e+02 5.1672e-07 1.8821e-02 9.8118e-01 3.0847e+03 6.2142e+02 4.7587e+02 3.1338e+01 6.0986e-05 1.4831e-05 1.3184e-03 2.3007e-04 5.6688e-02 2.0221e-02 2.2102e-02 1.6266e-02 1.0533e-02 1.0812e-02 8.6183e-01 9.0482e-03 3.0174e-03 5.3770e-01 1.1519e-01 8.8313e-02 4.5784e-02 2.0965e-02 1.5127e-02 1.6486e-01 +8.7000e-01 2.6740e+06 5.5315e+02 6.1799e+02 5.2728e-07 1.1303e-02 9.8870e-01 3.0811e+03 6.1240e+02 4.7620e+02 3.1042e+01 6.1020e-05 1.4804e-05 1.2973e-03 2.2613e-04 5.5750e-02 1.9905e-02 2.1775e-02 1.6038e-02 1.0396e-02 1.0683e-02 8.6393e-01 9.0289e-03 3.0104e-03 5.3650e-01 1.1496e-01 8.8148e-02 4.5711e-02 2.0939e-02 1.5117e-02 1.6660e-01 +8.7200e-01 2.6344e+06 5.5315e+02 6.0509e+02 5.3822e-07 3.5289e-03 9.9647e-01 3.0774e+03 6.0338e+02 4.7653e+02 3.0746e+01 6.1053e-05 1.4776e-05 1.2762e-03 2.2220e-04 5.4811e-02 1.9589e-02 2.1446e-02 1.5809e-02 1.0257e-02 1.0552e-02 8.6604e-01 9.0090e-03 3.0032e-03 5.3526e-01 1.1471e-01 8.7977e-02 4.5635e-02 2.0912e-02 1.5105e-02 1.6839e-01 +8.7400e-01 2.5948e+06 5.5315e+02 5.9408e+02 4.0416e-07 0.0000e+00 1.0000e+00 5.9408e+02 5.9408e+02 3.0344e+01 3.0344e+01 1.4756e-05 1.4756e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.7600e-01 2.5552e+06 5.5315e+02 5.8458e+02 4.1018e-07 0.0000e+00 1.0000e+00 5.8458e+02 5.8458e+02 2.9859e+01 2.9859e+01 1.4744e-05 1.4744e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.7800e-01 2.5156e+06 5.5315e+02 5.7509e+02 4.1638e-07 0.0000e+00 1.0000e+00 5.7509e+02 5.7509e+02 2.9374e+01 2.9374e+01 1.4732e-05 1.4732e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.8000e-01 2.4760e+06 5.5315e+02 5.6562e+02 4.2278e-07 0.0000e+00 1.0000e+00 5.6562e+02 5.6562e+02 2.8890e+01 2.8890e+01 1.4719e-05 1.4719e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.8200e-01 2.4364e+06 5.5315e+02 5.5615e+02 4.2939e-07 0.0000e+00 1.0000e+00 5.5615e+02 5.5615e+02 2.8407e+01 2.8407e+01 1.4707e-05 1.4707e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.8400e-01 2.3968e+06 5.5315e+02 5.4670e+02 4.3622e-07 0.0000e+00 1.0000e+00 5.4670e+02 5.4670e+02 2.7924e+01 2.7924e+01 1.4696e-05 1.4696e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.8600e-01 2.3572e+06 5.5315e+02 5.3727e+02 4.4327e-07 0.0000e+00 1.0000e+00 5.3727e+02 5.3727e+02 2.7442e+01 2.7442e+01 1.4684e-05 1.4684e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.8800e-01 2.3176e+06 5.5315e+02 5.2784e+02 4.5056e-07 0.0000e+00 1.0000e+00 5.2784e+02 5.2784e+02 2.6961e+01 2.6961e+01 1.4672e-05 1.4672e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.9000e-01 2.2780e+06 5.5315e+02 5.1843e+02 4.5810e-07 0.0000e+00 1.0000e+00 5.1843e+02 5.1843e+02 2.6480e+01 2.6480e+01 1.4660e-05 1.4660e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.9200e-01 2.2384e+06 5.5315e+02 5.0903e+02 4.6590e-07 0.0000e+00 1.0000e+00 5.0903e+02 5.0903e+02 2.6000e+01 2.6000e+01 1.4649e-05 1.4649e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.9400e-01 2.1988e+06 5.5315e+02 4.9965e+02 4.7399e-07 0.0000e+00 1.0000e+00 4.9965e+02 4.9965e+02 2.5521e+01 2.5521e+01 1.4638e-05 1.4638e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.9600e-01 2.1592e+06 5.5315e+02 4.9028e+02 4.8237e-07 0.0000e+00 1.0000e+00 4.9028e+02 4.9028e+02 2.5042e+01 2.5042e+01 1.4626e-05 1.4626e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +8.9800e-01 2.1196e+06 5.5315e+02 4.8092e+02 4.9106e-07 0.0000e+00 1.0000e+00 4.8092e+02 4.8092e+02 2.4564e+01 2.4564e+01 1.4615e-05 1.4615e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.0000e-01 2.0800e+06 5.5315e+02 4.7157e+02 5.0008e-07 0.0000e+00 1.0000e+00 4.7157e+02 4.7157e+02 2.4087e+01 2.4087e+01 1.4604e-05 1.4604e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.0200e-01 2.0404e+06 5.5315e+02 4.6224e+02 5.0945e-07 0.0000e+00 1.0000e+00 4.6224e+02 4.6224e+02 2.3610e+01 2.3610e+01 1.4593e-05 1.4593e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.0400e-01 2.0008e+06 5.5315e+02 4.5292e+02 5.1919e-07 0.0000e+00 1.0000e+00 4.5292e+02 4.5292e+02 2.3134e+01 2.3134e+01 1.4582e-05 1.4582e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.0600e-01 1.9612e+06 5.5315e+02 4.4362e+02 5.2932e-07 0.0000e+00 1.0000e+00 4.4362e+02 4.4362e+02 2.2659e+01 2.2659e+01 1.4571e-05 1.4571e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.0800e-01 1.9216e+06 5.5315e+02 4.3432e+02 5.3986e-07 0.0000e+00 1.0000e+00 4.3432e+02 4.3432e+02 2.2184e+01 2.2184e+01 1.4561e-05 1.4561e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.1000e-01 1.8820e+06 5.5315e+02 4.2505e+02 5.5085e-07 0.0000e+00 1.0000e+00 4.2505e+02 4.2505e+02 2.1710e+01 2.1710e+01 1.4550e-05 1.4550e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.1200e-01 1.8424e+06 5.5315e+02 4.1578e+02 5.6230e-07 0.0000e+00 1.0000e+00 4.1578e+02 4.1578e+02 2.1237e+01 2.1237e+01 1.4539e-05 1.4539e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.1400e-01 1.8028e+06 5.5315e+02 4.0653e+02 5.7426e-07 0.0000e+00 1.0000e+00 4.0653e+02 4.0653e+02 2.0764e+01 2.0764e+01 1.4529e-05 1.4529e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.1600e-01 1.7632e+06 5.5315e+02 3.9729e+02 5.8675e-07 0.0000e+00 1.0000e+00 3.9729e+02 3.9729e+02 2.0293e+01 2.0293e+01 1.4519e-05 1.4519e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.1800e-01 1.7236e+06 5.5315e+02 3.8807e+02 5.9982e-07 0.0000e+00 1.0000e+00 3.8807e+02 3.8807e+02 1.9821e+01 1.9821e+01 1.4509e-05 1.4509e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.2000e-01 1.6840e+06 5.5315e+02 3.7886e+02 6.1350e-07 0.0000e+00 1.0000e+00 3.7886e+02 3.7886e+02 1.9351e+01 1.9351e+01 1.4498e-05 1.4498e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.2200e-01 1.6444e+06 5.5315e+02 3.6966e+02 6.2783e-07 0.0000e+00 1.0000e+00 3.6966e+02 3.6966e+02 1.8881e+01 1.8881e+01 1.4488e-05 1.4488e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.2400e-01 1.6048e+06 5.5315e+02 3.6047e+02 6.4287e-07 0.0000e+00 1.0000e+00 3.6047e+02 3.6047e+02 1.8412e+01 1.8412e+01 1.4479e-05 1.4479e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.2600e-01 1.5652e+06 5.5315e+02 3.5130e+02 6.5867e-07 0.0000e+00 1.0000e+00 3.5130e+02 3.5130e+02 1.7944e+01 1.7944e+01 1.4469e-05 1.4469e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.2800e-01 1.5256e+06 5.5315e+02 3.4215e+02 6.7528e-07 0.0000e+00 1.0000e+00 3.4215e+02 3.4215e+02 1.7476e+01 1.7476e+01 1.4459e-05 1.4459e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.3000e-01 1.4860e+06 5.5315e+02 3.3301e+02 6.9278e-07 0.0000e+00 1.0000e+00 3.3301e+02 3.3301e+02 1.7009e+01 1.7009e+01 1.4449e-05 1.4449e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.3200e-01 1.4464e+06 5.5315e+02 3.2388e+02 7.1123e-07 0.0000e+00 1.0000e+00 3.2388e+02 3.2388e+02 1.6543e+01 1.6543e+01 1.4440e-05 1.4440e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.3400e-01 1.4068e+06 5.5315e+02 3.1476e+02 7.3073e-07 0.0000e+00 1.0000e+00 3.1476e+02 3.1476e+02 1.6077e+01 1.6077e+01 1.4430e-05 1.4430e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.3600e-01 1.3672e+06 5.5315e+02 3.0566e+02 7.5135e-07 0.0000e+00 1.0000e+00 3.0566e+02 3.0566e+02 1.5612e+01 1.5612e+01 1.4421e-05 1.4421e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.3800e-01 1.3276e+06 5.5315e+02 2.9657e+02 7.7319e-07 0.0000e+00 1.0000e+00 2.9657e+02 2.9657e+02 1.5148e+01 1.5148e+01 1.4412e-05 1.4412e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.4000e-01 1.2880e+06 5.5315e+02 2.8750e+02 7.9638e-07 0.0000e+00 1.0000e+00 2.8750e+02 2.8750e+02 1.4685e+01 1.4685e+01 1.4403e-05 1.4403e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.4200e-01 1.2484e+06 5.5315e+02 2.7844e+02 8.2104e-07 0.0000e+00 1.0000e+00 2.7844e+02 2.7844e+02 1.4222e+01 1.4222e+01 1.4394e-05 1.4394e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.4400e-01 1.2088e+06 5.5315e+02 2.6939e+02 8.4731e-07 0.0000e+00 1.0000e+00 2.6939e+02 2.6939e+02 1.3760e+01 1.3760e+01 1.4385e-05 1.4385e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.4600e-01 1.1692e+06 5.5315e+02 2.6036e+02 8.7535e-07 0.0000e+00 1.0000e+00 2.6036e+02 2.6036e+02 1.3299e+01 1.3299e+01 1.4376e-05 1.4376e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.4800e-01 1.1296e+06 5.5315e+02 2.5134e+02 9.0536e-07 0.0000e+00 1.0000e+00 2.5134e+02 2.5134e+02 1.2838e+01 1.2838e+01 1.4367e-05 1.4367e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.5000e-01 1.0900e+06 5.5315e+02 2.4234e+02 9.3755e-07 0.0000e+00 1.0000e+00 2.4234e+02 2.4234e+02 1.2378e+01 1.2378e+01 1.4358e-05 1.4358e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.5200e-01 1.0504e+06 5.5315e+02 2.3335e+02 9.7216e-07 0.0000e+00 1.0000e+00 2.3335e+02 2.3335e+02 1.1919e+01 1.1919e+01 1.4350e-05 1.4350e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.5400e-01 1.0108e+06 5.5315e+02 2.2437e+02 1.0095e-06 0.0000e+00 1.0000e+00 2.2437e+02 2.2437e+02 1.1460e+01 1.1460e+01 1.4341e-05 1.4341e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.5600e-01 9.7120e+05 5.5315e+02 2.1541e+02 1.0499e-06 0.0000e+00 1.0000e+00 2.1541e+02 2.1541e+02 1.1003e+01 1.1003e+01 1.4333e-05 1.4333e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.5800e-01 9.3160e+05 5.5315e+02 2.0646e+02 1.0936e-06 0.0000e+00 1.0000e+00 2.0646e+02 2.0646e+02 1.0545e+01 1.0545e+01 1.4324e-05 1.4324e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.6000e-01 8.9200e+05 5.5315e+02 1.9753e+02 1.1413e-06 0.0000e+00 1.0000e+00 1.9753e+02 1.9753e+02 1.0089e+01 1.0089e+01 1.4316e-05 1.4316e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.6200e-01 8.5240e+05 5.5315e+02 1.8861e+02 1.1934e-06 0.0000e+00 1.0000e+00 1.8861e+02 1.8861e+02 9.6335e+00 9.6335e+00 1.4308e-05 1.4308e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.6400e-01 8.1280e+05 5.5315e+02 1.7970e+02 1.2506e-06 0.0000e+00 1.0000e+00 1.7970e+02 1.7970e+02 9.1786e+00 9.1786e+00 1.4300e-05 1.4300e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.6600e-01 7.7320e+05 5.5315e+02 1.7081e+02 1.3136e-06 0.0000e+00 1.0000e+00 1.7081e+02 1.7081e+02 8.7244e+00 8.7244e+00 1.4292e-05 1.4292e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.6800e-01 7.3360e+05 5.5315e+02 1.6193e+02 1.3835e-06 0.0000e+00 1.0000e+00 1.6193e+02 1.6193e+02 8.2709e+00 8.2709e+00 1.4284e-05 1.4284e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.7000e-01 6.9400e+05 5.5315e+02 1.5306e+02 1.4613e-06 0.0000e+00 1.0000e+00 1.5306e+02 1.5306e+02 7.8181e+00 7.8181e+00 1.4276e-05 1.4276e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.7200e-01 6.5440e+05 5.5315e+02 1.4421e+02 1.5485e-06 0.0000e+00 1.0000e+00 1.4421e+02 1.4421e+02 7.3661e+00 7.3661e+00 1.4269e-05 1.4269e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.7400e-01 6.1480e+05 5.5315e+02 1.3538e+02 1.6470e-06 0.0000e+00 1.0000e+00 1.3538e+02 1.3538e+02 6.9147e+00 6.9147e+00 1.4261e-05 1.4261e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.7600e-01 5.7520e+05 5.5315e+02 1.2656e+02 1.7590e-06 0.0000e+00 1.0000e+00 1.2656e+02 1.2656e+02 6.4641e+00 6.4641e+00 1.4253e-05 1.4253e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.7800e-01 5.3560e+05 5.5315e+02 1.1775e+02 1.8875e-06 0.0000e+00 1.0000e+00 1.1775e+02 1.1775e+02 6.0142e+00 6.0142e+00 1.4246e-05 1.4246e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.8000e-01 4.9600e+05 5.5315e+02 1.0895e+02 2.0366e-06 0.0000e+00 1.0000e+00 1.0895e+02 1.0895e+02 5.5650e+00 5.5650e+00 1.4239e-05 1.4239e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.8200e-01 4.5640e+05 5.5315e+02 1.0017e+02 2.2116e-06 0.0000e+00 1.0000e+00 1.0017e+02 1.0017e+02 5.1166e+00 5.1166e+00 1.4231e-05 1.4231e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.8400e-01 4.1680e+05 5.5315e+02 9.1407e+01 2.4197e-06 0.0000e+00 1.0000e+00 9.1407e+01 9.1407e+01 4.6688e+00 4.6688e+00 1.4224e-05 1.4224e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.8600e-01 3.7720e+05 5.5315e+02 8.2656e+01 2.6716e-06 0.0000e+00 1.0000e+00 8.2656e+01 8.2656e+01 4.2218e+00 4.2218e+00 1.4217e-05 1.4217e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.8800e-01 3.3760e+05 5.5315e+02 7.3918e+01 2.9826e-06 0.0000e+00 1.0000e+00 7.3918e+01 7.3918e+01 3.7755e+00 3.7755e+00 1.4210e-05 1.4210e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.9000e-01 2.9800e+05 5.5315e+02 6.5194e+01 3.3763e-06 0.0000e+00 1.0000e+00 6.5194e+01 6.5194e+01 3.3300e+00 3.3300e+00 1.4203e-05 1.4203e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.9200e-01 2.5840e+05 5.5315e+02 5.6485e+01 3.8906e-06 0.0000e+00 1.0000e+00 5.6485e+01 5.6485e+01 2.8851e+00 2.8851e+00 1.4196e-05 1.4196e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.9400e-01 2.1880e+05 5.5315e+02 4.7790e+01 4.5910e-06 0.0000e+00 1.0000e+00 4.7790e+01 4.7790e+01 2.4410e+00 2.4410e+00 1.4189e-05 1.4189e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.9600e-01 1.7920e+05 5.5315e+02 3.9108e+01 5.6010e-06 0.0000e+00 1.0000e+00 3.9108e+01 3.9108e+01 1.9975e+00 1.9975e+00 1.4183e-05 1.4183e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +9.9800e-01 1.3960e+05 5.5315e+02 3.0441e+01 7.1840e-06 0.0000e+00 1.0000e+00 3.0441e+01 3.0441e+01 1.5549e+00 1.5549e+00 1.4176e-05 1.4176e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0000e+00 1.0000e+05 5.5315e+02 2.1788e+01 1.0021e-05 0.0000e+00 1.0000e+00 2.1788e+01 2.1788e+01 1.1129e+00 1.1129e+00 1.4170e-05 1.4170e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0020e+00 1.3960e+05 5.8315e+02 2.8855e+01 7.1791e-06 0.0000e+00 1.0000e+00 2.8855e+01 2.8855e+01 1.4739e+00 1.4739e+00 1.4780e-05 1.4780e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0040e+00 1.7920e+05 5.8315e+02 3.7064e+01 5.5961e-06 0.0000e+00 1.0000e+00 3.7064e+01 3.7064e+01 1.8931e+00 1.8931e+00 1.4786e-05 1.4786e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0060e+00 2.1880e+05 5.8315e+02 4.5282e+01 4.5861e-06 0.0000e+00 1.0000e+00 4.5282e+01 4.5282e+01 2.3129e+00 2.3129e+00 1.4793e-05 1.4793e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0080e+00 2.5840e+05 5.8315e+02 5.3511e+01 3.8856e-06 0.0000e+00 1.0000e+00 5.3511e+01 5.3511e+01 2.7332e+00 2.7332e+00 1.4799e-05 1.4799e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0100e+00 2.9800e+05 5.8315e+02 6.1750e+01 3.3713e-06 0.0000e+00 1.0000e+00 6.1750e+01 6.1750e+01 3.1540e+00 3.1540e+00 1.4806e-05 1.4806e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0120e+00 3.3760e+05 5.8315e+02 6.9999e+01 2.9777e-06 0.0000e+00 1.0000e+00 6.9999e+01 6.9999e+01 3.5754e+00 3.5754e+00 1.4812e-05 1.4812e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0140e+00 3.7720e+05 5.8315e+02 7.8258e+01 2.6667e-06 0.0000e+00 1.0000e+00 7.8258e+01 7.8258e+01 3.9972e+00 3.9972e+00 1.4819e-05 1.4819e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0160e+00 4.1680e+05 5.8315e+02 8.6527e+01 2.4148e-06 0.0000e+00 1.0000e+00 8.6527e+01 8.6527e+01 4.4196e+00 4.4196e+00 1.4825e-05 1.4825e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0180e+00 4.5640e+05 5.8315e+02 9.4806e+01 2.2066e-06 0.0000e+00 1.0000e+00 9.4806e+01 9.4806e+01 4.8424e+00 4.8424e+00 1.4832e-05 1.4832e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0200e+00 4.9600e+05 5.8315e+02 1.0310e+02 2.0316e-06 0.0000e+00 1.0000e+00 1.0310e+02 1.0310e+02 5.2658e+00 5.2658e+00 1.4839e-05 1.4839e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0220e+00 5.3560e+05 5.8315e+02 1.1139e+02 1.8825e-06 0.0000e+00 1.0000e+00 1.1139e+02 1.1139e+02 5.6897e+00 5.6897e+00 1.4846e-05 1.4846e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0240e+00 5.7520e+05 5.8315e+02 1.1970e+02 1.7539e-06 0.0000e+00 1.0000e+00 1.1970e+02 1.1970e+02 6.1141e+00 6.1141e+00 1.4853e-05 1.4853e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0260e+00 6.1480e+05 5.8315e+02 1.2802e+02 1.6419e-06 0.0000e+00 1.0000e+00 1.2802e+02 1.2802e+02 6.5391e+00 6.5391e+00 1.4860e-05 1.4860e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0280e+00 6.5440e+05 5.8315e+02 1.3635e+02 1.5435e-06 0.0000e+00 1.0000e+00 1.3635e+02 1.3635e+02 6.9645e+00 6.9645e+00 1.4867e-05 1.4867e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0300e+00 6.9400e+05 5.8315e+02 1.4469e+02 1.4562e-06 0.0000e+00 1.0000e+00 1.4469e+02 1.4469e+02 7.3904e+00 7.3904e+00 1.4874e-05 1.4874e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0320e+00 7.3360e+05 5.8315e+02 1.5304e+02 1.3784e-06 0.0000e+00 1.0000e+00 1.5304e+02 1.5304e+02 7.8168e+00 7.8168e+00 1.4882e-05 1.4882e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0340e+00 7.7320e+05 5.8315e+02 1.6140e+02 1.3086e-06 0.0000e+00 1.0000e+00 1.6140e+02 1.6140e+02 8.2438e+00 8.2438e+00 1.4889e-05 1.4889e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0360e+00 8.1280e+05 5.8315e+02 1.6977e+02 1.2455e-06 0.0000e+00 1.0000e+00 1.6977e+02 1.6977e+02 8.6712e+00 8.6712e+00 1.4896e-05 1.4896e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0380e+00 8.5240e+05 5.8315e+02 1.7814e+02 1.1883e-06 0.0000e+00 1.0000e+00 1.7814e+02 1.7814e+02 9.0992e+00 9.0992e+00 1.4904e-05 1.4904e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0400e+00 8.9200e+05 5.8315e+02 1.8653e+02 1.1362e-06 0.0000e+00 1.0000e+00 1.8653e+02 1.8653e+02 9.5276e+00 9.5276e+00 1.4911e-05 1.4911e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0420e+00 9.3160e+05 5.8315e+02 1.9493e+02 1.0885e-06 0.0000e+00 1.0000e+00 1.9493e+02 1.9493e+02 9.9566e+00 9.9566e+00 1.4919e-05 1.4919e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0440e+00 9.7120e+05 5.8315e+02 2.0334e+02 1.0447e-06 0.0000e+00 1.0000e+00 2.0334e+02 2.0334e+02 1.0386e+01 1.0386e+01 1.4927e-05 1.4927e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0460e+00 1.0108e+06 5.8315e+02 2.1176e+02 1.0044e-06 0.0000e+00 1.0000e+00 2.1176e+02 2.1176e+02 1.0816e+01 1.0816e+01 1.4935e-05 1.4935e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0480e+00 1.0504e+06 5.8315e+02 2.2018e+02 9.6704e-07 0.0000e+00 1.0000e+00 2.2018e+02 2.2018e+02 1.1246e+01 1.1246e+01 1.4943e-05 1.4943e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0500e+00 1.0900e+06 5.8315e+02 2.2862e+02 9.3242e-07 0.0000e+00 1.0000e+00 2.2862e+02 2.2862e+02 1.1677e+01 1.1677e+01 1.4951e-05 1.4951e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0520e+00 1.1296e+06 5.8315e+02 2.3707e+02 9.0022e-07 0.0000e+00 1.0000e+00 2.3707e+02 2.3707e+02 1.2109e+01 1.2109e+01 1.4959e-05 1.4959e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0540e+00 1.1692e+06 5.8315e+02 2.4552e+02 8.7021e-07 0.0000e+00 1.0000e+00 2.4552e+02 2.4552e+02 1.2541e+01 1.2541e+01 1.4967e-05 1.4967e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0560e+00 1.2088e+06 5.8315e+02 2.5399e+02 8.4215e-07 0.0000e+00 1.0000e+00 2.5399e+02 2.5399e+02 1.2973e+01 1.2973e+01 1.4975e-05 1.4975e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0580e+00 1.2484e+06 5.8315e+02 2.6246e+02 8.1588e-07 0.0000e+00 1.0000e+00 2.6246e+02 2.6246e+02 1.3406e+01 1.3406e+01 1.4983e-05 1.4983e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0600e+00 1.2880e+06 5.8315e+02 2.7095e+02 7.9121e-07 0.0000e+00 1.0000e+00 2.7095e+02 2.7095e+02 1.3839e+01 1.3839e+01 1.4991e-05 1.4991e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0620e+00 1.3276e+06 5.8315e+02 2.7944e+02 7.6802e-07 0.0000e+00 1.0000e+00 2.7944e+02 2.7944e+02 1.4273e+01 1.4273e+01 1.5000e-05 1.5000e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0640e+00 1.3672e+06 5.8315e+02 2.8794e+02 7.4616e-07 0.0000e+00 1.0000e+00 2.8794e+02 2.8794e+02 1.4707e+01 1.4707e+01 1.5008e-05 1.5008e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0660e+00 1.4068e+06 5.8315e+02 2.9646e+02 7.2554e-07 0.0000e+00 1.0000e+00 2.9646e+02 2.9646e+02 1.5142e+01 1.5142e+01 1.5017e-05 1.5017e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0680e+00 1.4464e+06 5.8315e+02 3.0498e+02 7.0604e-07 0.0000e+00 1.0000e+00 3.0498e+02 3.0498e+02 1.5578e+01 1.5578e+01 1.5026e-05 1.5026e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0700e+00 1.4860e+06 5.8315e+02 3.1351e+02 6.8758e-07 0.0000e+00 1.0000e+00 3.1351e+02 3.1351e+02 1.6013e+01 1.6013e+01 1.5034e-05 1.5034e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0720e+00 1.5256e+06 5.8315e+02 3.2205e+02 6.7007e-07 0.0000e+00 1.0000e+00 3.2205e+02 3.2205e+02 1.6450e+01 1.6450e+01 1.5043e-05 1.5043e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0740e+00 1.5652e+06 5.8315e+02 3.3060e+02 6.5345e-07 0.0000e+00 1.0000e+00 3.3060e+02 3.3060e+02 1.6886e+01 1.6886e+01 1.5052e-05 1.5052e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0760e+00 1.6048e+06 5.8315e+02 3.3916e+02 6.3765e-07 0.0000e+00 1.0000e+00 3.3916e+02 3.3916e+02 1.7324e+01 1.7324e+01 1.5061e-05 1.5061e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0780e+00 1.6444e+06 5.8315e+02 3.4773e+02 6.2260e-07 0.0000e+00 1.0000e+00 3.4773e+02 3.4773e+02 1.7761e+01 1.7761e+01 1.5070e-05 1.5070e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0800e+00 1.6840e+06 5.8315e+02 3.5631e+02 6.0826e-07 0.0000e+00 1.0000e+00 3.5631e+02 3.5631e+02 1.8199e+01 1.8199e+01 1.5079e-05 1.5079e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0820e+00 1.7236e+06 5.8315e+02 3.6490e+02 5.9458e-07 0.0000e+00 1.0000e+00 3.6490e+02 3.6490e+02 1.8638e+01 1.8638e+01 1.5089e-05 1.5089e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0840e+00 1.7632e+06 5.8315e+02 3.7349e+02 5.8151e-07 0.0000e+00 1.0000e+00 3.7349e+02 3.7349e+02 1.9077e+01 1.9077e+01 1.5098e-05 1.5098e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0860e+00 1.8028e+06 5.8315e+02 3.8210e+02 5.6901e-07 0.0000e+00 1.0000e+00 3.8210e+02 3.8210e+02 1.9517e+01 1.9517e+01 1.5107e-05 1.5107e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0880e+00 1.8424e+06 5.8315e+02 3.9071e+02 5.5705e-07 0.0000e+00 1.0000e+00 3.9071e+02 3.9071e+02 1.9957e+01 1.9957e+01 1.5117e-05 1.5117e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0900e+00 1.8820e+06 5.8315e+02 3.9934e+02 5.4559e-07 0.0000e+00 1.0000e+00 3.9934e+02 3.9934e+02 2.0397e+01 2.0397e+01 1.5126e-05 1.5126e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0920e+00 1.9216e+06 5.8315e+02 4.0797e+02 5.3460e-07 0.0000e+00 1.0000e+00 4.0797e+02 4.0797e+02 2.0838e+01 2.0838e+01 1.5136e-05 1.5136e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0940e+00 1.9612e+06 5.8315e+02 4.1661e+02 5.2405e-07 0.0000e+00 1.0000e+00 4.1661e+02 4.1661e+02 2.1279e+01 2.1279e+01 1.5146e-05 1.5146e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0960e+00 2.0008e+06 5.8315e+02 4.2526e+02 5.1392e-07 0.0000e+00 1.0000e+00 4.2526e+02 4.2526e+02 2.1721e+01 2.1721e+01 1.5155e-05 1.5155e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.0980e+00 2.0404e+06 5.8315e+02 4.3392e+02 5.0418e-07 0.0000e+00 1.0000e+00 4.3392e+02 4.3392e+02 2.2163e+01 2.2163e+01 1.5165e-05 1.5165e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1000e+00 2.0800e+06 5.8315e+02 4.4259e+02 4.9480e-07 0.0000e+00 1.0000e+00 4.4259e+02 4.4259e+02 2.2606e+01 2.2606e+01 1.5175e-05 1.5175e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1020e+00 2.1196e+06 5.8315e+02 4.5126e+02 4.8578e-07 0.0000e+00 1.0000e+00 4.5126e+02 4.5126e+02 2.3049e+01 2.3049e+01 1.5185e-05 1.5185e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1040e+00 2.1592e+06 5.8315e+02 4.5995e+02 4.7708e-07 0.0000e+00 1.0000e+00 4.5995e+02 4.5995e+02 2.3493e+01 2.3493e+01 1.5196e-05 1.5196e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1060e+00 2.1988e+06 5.8315e+02 4.6864e+02 4.6870e-07 0.0000e+00 1.0000e+00 4.6864e+02 4.6864e+02 2.3937e+01 2.3937e+01 1.5206e-05 1.5206e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1080e+00 2.2384e+06 5.8315e+02 4.7734e+02 4.6061e-07 0.0000e+00 1.0000e+00 4.7734e+02 4.7734e+02 2.4381e+01 2.4381e+01 1.5216e-05 1.5216e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1100e+00 2.2780e+06 5.8315e+02 4.8605e+02 4.5280e-07 0.0000e+00 1.0000e+00 4.8605e+02 4.8605e+02 2.4826e+01 2.4826e+01 1.5226e-05 1.5226e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1120e+00 2.3176e+06 5.8315e+02 4.9477e+02 4.4526e-07 0.0000e+00 1.0000e+00 4.9477e+02 4.9477e+02 2.5272e+01 2.5272e+01 1.5237e-05 1.5237e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1140e+00 2.3572e+06 5.8315e+02 5.0350e+02 4.3796e-07 0.0000e+00 1.0000e+00 5.0350e+02 5.0350e+02 2.5718e+01 2.5718e+01 1.5247e-05 1.5247e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1160e+00 2.3968e+06 5.8315e+02 5.1224e+02 4.3091e-07 0.0000e+00 1.0000e+00 5.1224e+02 5.1224e+02 2.6164e+01 2.6164e+01 1.5258e-05 1.5258e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1180e+00 2.4364e+06 5.8315e+02 5.2098e+02 4.2408e-07 0.0000e+00 1.0000e+00 5.2098e+02 5.2098e+02 2.6610e+01 2.6610e+01 1.5269e-05 1.5269e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1200e+00 2.4760e+06 5.8315e+02 5.2974e+02 4.1747e-07 0.0000e+00 1.0000e+00 5.2974e+02 5.2974e+02 2.7058e+01 2.7058e+01 1.5280e-05 1.5280e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1220e+00 2.5156e+06 5.8315e+02 5.3850e+02 4.1107e-07 0.0000e+00 1.0000e+00 5.3850e+02 5.3850e+02 2.7505e+01 2.7505e+01 1.5291e-05 1.5291e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1240e+00 2.5552e+06 5.8315e+02 5.4727e+02 4.0486e-07 0.0000e+00 1.0000e+00 5.4727e+02 5.4727e+02 2.7953e+01 2.7953e+01 1.5302e-05 1.5302e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1260e+00 2.5948e+06 5.8315e+02 5.5605e+02 3.9884e-07 0.0000e+00 1.0000e+00 5.5605e+02 5.5605e+02 2.8401e+01 2.8401e+01 1.5313e-05 1.5313e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1280e+00 2.6344e+06 5.8315e+02 5.6483e+02 3.9300e-07 0.0000e+00 1.0000e+00 5.6483e+02 5.6483e+02 2.8850e+01 2.8850e+01 1.5324e-05 1.5324e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1300e+00 2.6740e+06 5.8315e+02 5.7363e+02 3.8733e-07 0.0000e+00 1.0000e+00 5.7363e+02 5.7363e+02 2.9299e+01 2.9299e+01 1.5335e-05 1.5335e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1320e+00 2.7136e+06 5.8315e+02 5.8243e+02 3.8183e-07 0.0000e+00 1.0000e+00 5.8243e+02 5.8243e+02 2.9749e+01 2.9749e+01 1.5346e-05 1.5346e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1340e+00 2.7532e+06 5.8315e+02 5.9124e+02 3.7648e-07 0.0000e+00 1.0000e+00 5.9124e+02 5.9124e+02 3.0199e+01 3.0199e+01 1.5358e-05 1.5358e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1360e+00 2.7928e+06 5.8315e+02 6.0006e+02 3.7128e-07 0.0000e+00 1.0000e+00 6.0006e+02 6.0006e+02 3.0649e+01 3.0649e+01 1.5369e-05 1.5369e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1380e+00 2.8324e+06 5.8315e+02 6.0889e+02 3.6623e-07 0.0000e+00 1.0000e+00 6.0889e+02 6.0889e+02 3.1100e+01 3.1100e+01 1.5381e-05 1.5381e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1400e+00 2.8720e+06 5.8315e+02 6.1772e+02 3.6131e-07 0.0000e+00 1.0000e+00 6.1772e+02 6.1772e+02 3.1552e+01 3.1552e+01 1.5393e-05 1.5393e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1420e+00 2.9116e+06 5.8315e+02 6.2656e+02 3.5653e-07 0.0000e+00 1.0000e+00 6.2656e+02 6.2656e+02 3.2003e+01 3.2003e+01 1.5404e-05 1.5404e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1440e+00 2.9512e+06 5.8315e+02 6.3541e+02 3.5187e-07 0.0000e+00 1.0000e+00 6.3541e+02 6.3541e+02 3.2455e+01 3.2455e+01 1.5416e-05 1.5416e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1460e+00 2.9908e+06 5.8315e+02 6.4427e+02 3.4733e-07 0.0000e+00 1.0000e+00 6.4427e+02 6.4427e+02 3.2908e+01 3.2908e+01 1.5428e-05 1.5428e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1480e+00 3.0304e+06 5.8315e+02 6.5314e+02 3.4291e-07 0.0000e+00 1.0000e+00 6.5314e+02 6.5314e+02 3.3360e+01 3.3360e+01 1.5440e-05 1.5440e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1500e+00 3.0700e+06 5.8315e+02 6.6201e+02 3.3861e-07 0.0000e+00 1.0000e+00 6.6201e+02 6.6201e+02 3.3814e+01 3.3814e+01 1.5452e-05 1.5452e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1520e+00 3.1096e+06 5.8315e+02 6.7089e+02 3.3441e-07 0.0000e+00 1.0000e+00 6.7089e+02 6.7089e+02 3.4267e+01 3.4267e+01 1.5465e-05 1.5465e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1540e+00 3.1492e+06 5.8315e+02 6.7978e+02 3.3031e-07 0.0000e+00 1.0000e+00 6.7978e+02 6.7978e+02 3.4721e+01 3.4721e+01 1.5477e-05 1.5477e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1560e+00 3.1888e+06 5.8315e+02 6.8867e+02 3.2632e-07 0.0000e+00 1.0000e+00 6.8867e+02 6.8867e+02 3.5176e+01 3.5176e+01 1.5489e-05 1.5489e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1580e+00 3.2284e+06 5.8315e+02 6.9758e+02 3.2242e-07 0.0000e+00 1.0000e+00 6.9758e+02 6.9758e+02 3.5630e+01 3.5630e+01 1.5502e-05 1.5502e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1600e+00 3.2680e+06 5.8315e+02 7.0649e+02 3.1862e-07 0.0000e+00 1.0000e+00 7.0649e+02 7.0649e+02 3.6085e+01 3.6085e+01 1.5514e-05 1.5514e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1620e+00 3.3076e+06 5.8315e+02 7.1540e+02 3.1490e-07 0.0000e+00 1.0000e+00 7.1540e+02 7.1540e+02 3.6541e+01 3.6541e+01 1.5527e-05 1.5527e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1640e+00 3.3472e+06 5.8315e+02 7.2433e+02 3.1127e-07 0.0000e+00 1.0000e+00 7.2433e+02 7.2433e+02 3.6997e+01 3.6997e+01 1.5540e-05 1.5540e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1660e+00 3.3868e+06 5.8315e+02 7.3326e+02 3.0772e-07 0.0000e+00 1.0000e+00 7.3326e+02 7.3326e+02 3.7453e+01 3.7453e+01 1.5553e-05 1.5553e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1680e+00 3.4264e+06 5.8315e+02 7.4220e+02 3.0426e-07 0.0000e+00 1.0000e+00 7.4220e+02 7.4220e+02 3.7910e+01 3.7910e+01 1.5566e-05 1.5566e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1700e+00 3.4660e+06 5.8315e+02 7.5115e+02 3.0087e-07 0.0000e+00 1.0000e+00 7.5115e+02 7.5115e+02 3.8367e+01 3.8367e+01 1.5579e-05 1.5579e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1720e+00 3.5056e+06 5.8315e+02 7.6010e+02 2.9756e-07 0.0000e+00 1.0000e+00 7.6010e+02 7.6010e+02 3.8824e+01 3.8824e+01 1.5592e-05 1.5592e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1740e+00 3.5452e+06 5.8315e+02 7.6906e+02 2.9432e-07 0.0000e+00 1.0000e+00 7.6906e+02 7.6906e+02 3.9281e+01 3.9281e+01 1.5605e-05 1.5605e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1760e+00 3.5848e+06 5.8315e+02 7.7803e+02 2.9115e-07 0.0000e+00 1.0000e+00 7.7803e+02 7.7803e+02 3.9739e+01 3.9739e+01 1.5618e-05 1.5618e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1780e+00 3.6244e+06 5.8315e+02 7.8700e+02 2.8804e-07 0.0000e+00 1.0000e+00 7.8700e+02 7.8700e+02 4.0198e+01 4.0198e+01 1.5632e-05 1.5632e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1800e+00 3.6640e+06 5.8315e+02 7.9598e+02 2.8501e-07 0.0000e+00 1.0000e+00 7.9598e+02 7.9598e+02 4.0656e+01 4.0656e+01 1.5645e-05 1.5645e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1820e+00 3.7036e+06 5.8315e+02 8.0497e+02 2.8203e-07 0.0000e+00 1.0000e+00 8.0497e+02 8.0497e+02 4.1116e+01 4.1116e+01 1.5659e-05 1.5659e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1840e+00 3.7432e+06 5.8315e+02 8.1396e+02 2.7912e-07 0.0000e+00 1.0000e+00 8.1396e+02 8.1396e+02 4.1575e+01 4.1575e+01 1.5673e-05 1.5673e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1860e+00 3.7828e+06 5.8315e+02 8.2296e+02 2.7627e-07 0.0000e+00 1.0000e+00 8.2296e+02 8.2296e+02 4.2035e+01 4.2035e+01 1.5686e-05 1.5686e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1880e+00 3.8224e+06 5.8315e+02 8.3197e+02 2.7347e-07 0.0000e+00 1.0000e+00 8.3197e+02 8.3197e+02 4.2495e+01 4.2495e+01 1.5700e-05 1.5700e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1900e+00 3.8620e+06 5.8315e+02 8.4098e+02 2.7073e-07 0.0000e+00 1.0000e+00 8.4098e+02 8.4098e+02 4.2955e+01 4.2955e+01 1.5714e-05 1.5714e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1920e+00 3.9016e+06 5.8315e+02 8.5000e+02 2.6805e-07 0.0000e+00 1.0000e+00 8.5000e+02 8.5000e+02 4.3416e+01 4.3416e+01 1.5728e-05 1.5728e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1940e+00 3.9412e+06 5.8315e+02 8.5902e+02 2.6541e-07 0.0000e+00 1.0000e+00 8.5902e+02 8.5902e+02 4.3877e+01 4.3877e+01 1.5742e-05 1.5742e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1960e+00 3.9808e+06 5.8315e+02 8.6806e+02 2.6283e-07 0.0000e+00 1.0000e+00 8.6806e+02 8.6806e+02 4.4338e+01 4.4338e+01 1.5757e-05 1.5757e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.1980e+00 4.0204e+06 5.8315e+02 8.7709e+02 2.6030e-07 0.0000e+00 1.0000e+00 8.7709e+02 8.7709e+02 4.4800e+01 4.4800e+01 1.5771e-05 1.5771e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2000e+00 4.0600e+06 5.8315e+02 8.8614e+02 2.5781e-07 0.0000e+00 1.0000e+00 8.8614e+02 8.8614e+02 4.5262e+01 4.5262e+01 1.5785e-05 1.5785e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2020e+00 4.0996e+06 5.8315e+02 8.9519e+02 2.5538e-07 0.0000e+00 1.0000e+00 8.9519e+02 8.9519e+02 4.5724e+01 4.5724e+01 1.5800e-05 1.5800e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2040e+00 4.1392e+06 5.8315e+02 9.0424e+02 2.5298e-07 0.0000e+00 1.0000e+00 9.0424e+02 9.0424e+02 4.6186e+01 4.6186e+01 1.5815e-05 1.5815e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2060e+00 4.1788e+06 5.8315e+02 9.1330e+02 2.5063e-07 0.0000e+00 1.0000e+00 9.1330e+02 9.1330e+02 4.6649e+01 4.6649e+01 1.5829e-05 1.5829e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2080e+00 4.2184e+06 5.8315e+02 9.2237e+02 2.4833e-07 0.0000e+00 1.0000e+00 9.2237e+02 9.2237e+02 4.7112e+01 4.7112e+01 1.5844e-05 1.5844e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2100e+00 4.2580e+06 5.8315e+02 9.3145e+02 2.4606e-07 0.0000e+00 1.0000e+00 9.3145e+02 9.3145e+02 4.7576e+01 4.7576e+01 1.5859e-05 1.5859e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2120e+00 4.2976e+06 5.8315e+02 9.4052e+02 2.4384e-07 0.0000e+00 1.0000e+00 9.4052e+02 9.4052e+02 4.8039e+01 4.8039e+01 1.5874e-05 1.5874e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2140e+00 4.3372e+06 5.8315e+02 9.4961e+02 2.4165e-07 0.0000e+00 1.0000e+00 9.4961e+02 9.4961e+02 4.8503e+01 4.8503e+01 1.5889e-05 1.5889e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2160e+00 4.3768e+06 5.8315e+02 9.5870e+02 2.3951e-07 0.0000e+00 1.0000e+00 9.5870e+02 9.5870e+02 4.8968e+01 4.8968e+01 1.5905e-05 1.5905e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2180e+00 4.4164e+06 5.8315e+02 9.6779e+02 2.3740e-07 0.0000e+00 1.0000e+00 9.6779e+02 9.6779e+02 4.9432e+01 4.9432e+01 1.5920e-05 1.5920e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2200e+00 4.4560e+06 5.8315e+02 9.7690e+02 2.3532e-07 0.0000e+00 1.0000e+00 9.7690e+02 9.7690e+02 4.9897e+01 4.9897e+01 1.5935e-05 1.5935e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2220e+00 4.4956e+06 5.8315e+02 9.8600e+02 2.3328e-07 0.0000e+00 1.0000e+00 9.8600e+02 9.8600e+02 5.0362e+01 5.0362e+01 1.5951e-05 1.5951e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2240e+00 4.5352e+06 5.8315e+02 9.9511e+02 2.3128e-07 0.0000e+00 1.0000e+00 9.9511e+02 9.9511e+02 5.0828e+01 5.0828e+01 1.5966e-05 1.5966e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2260e+00 4.5748e+06 5.8315e+02 1.0042e+03 2.2931e-07 0.0000e+00 1.0000e+00 1.0042e+03 1.0042e+03 5.1293e+01 5.1293e+01 1.5982e-05 1.5982e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2280e+00 4.6144e+06 5.8315e+02 1.0134e+03 2.2737e-07 0.0000e+00 1.0000e+00 1.0134e+03 1.0134e+03 5.1759e+01 5.1759e+01 1.5998e-05 1.5998e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2300e+00 4.6540e+06 5.8315e+02 1.0225e+03 2.2546e-07 0.0000e+00 1.0000e+00 1.0225e+03 1.0225e+03 5.2225e+01 5.2225e+01 1.6014e-05 1.6014e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2320e+00 4.6936e+06 5.8315e+02 1.0316e+03 2.2358e-07 0.0000e+00 1.0000e+00 1.0316e+03 1.0316e+03 5.2692e+01 5.2692e+01 1.6030e-05 1.6030e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2340e+00 4.7332e+06 5.8315e+02 1.0407e+03 2.2174e-07 0.0000e+00 1.0000e+00 1.0407e+03 1.0407e+03 5.3158e+01 5.3158e+01 1.6046e-05 1.6046e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2360e+00 4.7728e+06 5.8315e+02 1.0499e+03 2.1992e-07 0.0000e+00 1.0000e+00 1.0499e+03 1.0499e+03 5.3625e+01 5.3625e+01 1.6062e-05 1.6062e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2380e+00 4.8124e+06 5.8315e+02 1.0590e+03 2.1813e-07 0.0000e+00 1.0000e+00 1.0590e+03 1.0590e+03 5.4092e+01 5.4092e+01 1.6078e-05 1.6078e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2400e+00 4.8520e+06 5.8315e+02 1.0682e+03 2.1637e-07 0.0000e+00 1.0000e+00 1.0682e+03 1.0682e+03 5.4560e+01 5.4560e+01 1.6095e-05 1.6095e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2420e+00 4.8916e+06 5.8315e+02 1.0773e+03 2.1464e-07 0.0000e+00 1.0000e+00 1.0773e+03 1.0773e+03 5.5027e+01 5.5027e+01 1.6111e-05 1.6111e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2440e+00 4.9312e+06 5.8315e+02 1.0865e+03 2.1293e-07 0.0000e+00 1.0000e+00 1.0865e+03 1.0865e+03 5.5495e+01 5.5495e+01 1.6128e-05 1.6128e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2460e+00 4.9708e+06 5.8315e+02 1.0957e+03 2.1125e-07 0.0000e+00 1.0000e+00 1.0957e+03 1.0957e+03 5.5963e+01 5.5963e+01 1.6144e-05 1.6144e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2480e+00 5.0104e+06 5.8315e+02 1.1048e+03 2.0959e-07 0.0000e+00 1.0000e+00 1.1048e+03 1.1048e+03 5.6432e+01 5.6432e+01 1.6161e-05 1.6161e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2500e+00 5.0500e+06 5.8315e+02 1.1140e+03 2.0796e-07 0.0000e+00 1.0000e+00 1.1140e+03 1.1140e+03 5.6900e+01 5.6900e+01 1.6178e-05 1.6178e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2520e+00 5.0896e+06 5.8315e+02 1.1232e+03 2.0636e-07 0.0000e+00 1.0000e+00 1.1232e+03 1.1232e+03 5.7369e+01 5.7369e+01 1.6195e-05 1.6195e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2540e+00 5.1292e+06 5.8315e+02 1.1324e+03 2.0477e-07 0.0000e+00 1.0000e+00 1.1324e+03 1.1324e+03 5.7838e+01 5.7838e+01 1.6212e-05 1.6212e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2560e+00 5.1688e+06 5.8315e+02 1.1415e+03 2.0321e-07 0.0000e+00 1.0000e+00 1.1415e+03 1.1415e+03 5.8307e+01 5.8307e+01 1.6229e-05 1.6229e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2580e+00 5.2084e+06 5.8315e+02 1.1507e+03 2.0167e-07 0.0000e+00 1.0000e+00 1.1507e+03 1.1507e+03 5.8776e+01 5.8776e+01 1.6247e-05 1.6247e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2600e+00 5.2480e+06 5.8315e+02 1.1599e+03 2.0016e-07 0.0000e+00 1.0000e+00 1.1599e+03 1.1599e+03 5.9246e+01 5.9246e+01 1.6264e-05 1.6264e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2620e+00 5.2876e+06 5.8315e+02 1.1691e+03 1.9866e-07 0.0000e+00 1.0000e+00 1.1691e+03 1.1691e+03 5.9715e+01 5.9715e+01 1.6281e-05 1.6281e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2640e+00 5.3272e+06 5.8315e+02 1.1783e+03 1.9719e-07 0.0000e+00 1.0000e+00 1.1783e+03 1.1783e+03 6.0185e+01 6.0185e+01 1.6299e-05 1.6299e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2660e+00 5.3668e+06 5.8315e+02 1.1875e+03 1.9573e-07 0.0000e+00 1.0000e+00 1.1875e+03 1.1875e+03 6.0655e+01 6.0655e+01 1.6317e-05 1.6317e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2680e+00 5.4064e+06 5.8315e+02 1.1967e+03 1.9430e-07 0.0000e+00 1.0000e+00 1.1967e+03 1.1967e+03 6.1125e+01 6.1125e+01 1.6334e-05 1.6334e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2700e+00 5.4460e+06 5.8315e+02 1.2059e+03 1.9289e-07 0.0000e+00 1.0000e+00 1.2059e+03 1.2059e+03 6.1596e+01 6.1596e+01 1.6352e-05 1.6352e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2720e+00 5.4856e+06 5.8315e+02 1.2151e+03 1.9149e-07 0.0000e+00 1.0000e+00 1.2151e+03 1.2151e+03 6.2066e+01 6.2066e+01 1.6370e-05 1.6370e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2740e+00 5.5252e+06 5.8315e+02 1.2244e+03 1.9011e-07 0.0000e+00 1.0000e+00 1.2244e+03 1.2244e+03 6.2537e+01 6.2537e+01 1.6388e-05 1.6388e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2760e+00 5.5648e+06 5.8315e+02 1.2336e+03 1.8876e-07 0.0000e+00 1.0000e+00 1.2336e+03 1.2336e+03 6.3008e+01 6.3008e+01 1.6407e-05 1.6407e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2780e+00 5.6044e+06 5.8315e+02 1.2428e+03 1.8742e-07 0.0000e+00 1.0000e+00 1.2428e+03 1.2428e+03 6.3479e+01 6.3479e+01 1.6425e-05 1.6425e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2800e+00 5.6440e+06 5.8315e+02 1.2520e+03 1.8609e-07 0.0000e+00 1.0000e+00 1.2520e+03 1.2520e+03 6.3950e+01 6.3950e+01 1.6443e-05 1.6443e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2820e+00 5.6836e+06 5.8315e+02 1.2613e+03 1.8479e-07 0.0000e+00 1.0000e+00 1.2613e+03 1.2613e+03 6.4422e+01 6.4422e+01 1.6462e-05 1.6462e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2840e+00 5.7232e+06 5.8315e+02 1.2705e+03 1.8350e-07 0.0000e+00 1.0000e+00 1.2705e+03 1.2705e+03 6.4893e+01 6.4893e+01 1.6480e-05 1.6480e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2860e+00 5.7628e+06 5.8315e+02 1.2797e+03 1.8223e-07 0.0000e+00 1.0000e+00 1.2797e+03 1.2797e+03 6.5365e+01 6.5365e+01 1.6499e-05 1.6499e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2880e+00 5.8024e+06 5.8315e+02 1.2890e+03 1.8097e-07 0.0000e+00 1.0000e+00 1.2890e+03 1.2890e+03 6.5836e+01 6.5836e+01 1.6518e-05 1.6518e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2900e+00 5.8420e+06 5.8315e+02 1.2982e+03 1.7973e-07 0.0000e+00 1.0000e+00 1.2982e+03 1.2982e+03 6.6308e+01 6.6308e+01 1.6537e-05 1.6537e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2920e+00 5.8816e+06 5.8315e+02 1.3074e+03 1.7851e-07 0.0000e+00 1.0000e+00 1.3074e+03 1.3074e+03 6.6780e+01 6.6780e+01 1.6556e-05 1.6556e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2940e+00 5.9212e+06 5.8315e+02 1.3167e+03 1.7730e-07 0.0000e+00 1.0000e+00 1.3167e+03 1.3167e+03 6.7252e+01 6.7252e+01 1.6575e-05 1.6575e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2960e+00 5.9608e+06 5.8315e+02 1.3259e+03 1.7611e-07 0.0000e+00 1.0000e+00 1.3259e+03 1.3259e+03 6.7725e+01 6.7725e+01 1.6594e-05 1.6594e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.2980e+00 6.0004e+06 5.8315e+02 1.3352e+03 1.7493e-07 0.0000e+00 1.0000e+00 1.3352e+03 1.3352e+03 6.8197e+01 6.8197e+01 1.6613e-05 1.6613e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3000e+00 6.0400e+06 5.8315e+02 1.3444e+03 1.7376e-07 0.0000e+00 1.0000e+00 1.3444e+03 1.3444e+03 6.8670e+01 6.8670e+01 1.6632e-05 1.6632e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3020e+00 6.0796e+06 5.8315e+02 1.3537e+03 1.7261e-07 0.0000e+00 1.0000e+00 1.3537e+03 1.3537e+03 6.9142e+01 6.9142e+01 1.6652e-05 1.6652e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3040e+00 6.1192e+06 5.8315e+02 1.3629e+03 1.7147e-07 0.0000e+00 1.0000e+00 1.3629e+03 1.3629e+03 6.9615e+01 6.9615e+01 1.6672e-05 1.6672e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3060e+00 6.1588e+06 5.8315e+02 1.3722e+03 1.7035e-07 0.0000e+00 1.0000e+00 1.3722e+03 1.3722e+03 7.0088e+01 7.0088e+01 1.6691e-05 1.6691e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3080e+00 6.1984e+06 5.8315e+02 1.3814e+03 1.6924e-07 0.0000e+00 1.0000e+00 1.3814e+03 1.3814e+03 7.0560e+01 7.0560e+01 1.6711e-05 1.6711e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3100e+00 6.2380e+06 5.8315e+02 1.3907e+03 1.6814e-07 0.0000e+00 1.0000e+00 1.3907e+03 1.3907e+03 7.1033e+01 7.1033e+01 1.6731e-05 1.6731e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3120e+00 6.2776e+06 5.8315e+02 1.4000e+03 1.6705e-07 0.0000e+00 1.0000e+00 1.4000e+03 1.4000e+03 7.1506e+01 7.1506e+01 1.6751e-05 1.6751e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3140e+00 6.3172e+06 5.8315e+02 1.4092e+03 1.6598e-07 0.0000e+00 1.0000e+00 1.4092e+03 1.4092e+03 7.1979e+01 7.1979e+01 1.6771e-05 1.6771e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3160e+00 6.3568e+06 5.8315e+02 1.4185e+03 1.6492e-07 0.0000e+00 1.0000e+00 1.4185e+03 1.4185e+03 7.2452e+01 7.2452e+01 1.6791e-05 1.6791e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3180e+00 6.3964e+06 5.8315e+02 1.4278e+03 1.6387e-07 0.0000e+00 1.0000e+00 1.4278e+03 1.4278e+03 7.2926e+01 7.2926e+01 1.6811e-05 1.6811e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3200e+00 6.4360e+06 5.8315e+02 1.4370e+03 1.6283e-07 0.0000e+00 1.0000e+00 1.4370e+03 1.4370e+03 7.3399e+01 7.3399e+01 1.6832e-05 1.6832e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3220e+00 6.4756e+06 5.8315e+02 1.4463e+03 1.6181e-07 0.0000e+00 1.0000e+00 1.4463e+03 1.4463e+03 7.3872e+01 7.3872e+01 1.6852e-05 1.6852e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3240e+00 6.5152e+06 5.8315e+02 1.4556e+03 1.6079e-07 0.0000e+00 1.0000e+00 1.4556e+03 1.4556e+03 7.4346e+01 7.4346e+01 1.6873e-05 1.6873e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3260e+00 6.5548e+06 5.8315e+02 1.4648e+03 1.5979e-07 0.0000e+00 1.0000e+00 1.4648e+03 1.4648e+03 7.4819e+01 7.4819e+01 1.6894e-05 1.6894e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.3280e+00 6.5944e+06 5.8315e+02 1.4744e+03 1.7389e-07 6.4830e-04 9.9935e-01 3.1394e+03 1.4739e+03 4.0136e+02 7.5255e+01 4.8988e-05 1.6914e-05 3.3032e-03 7.1578e-04 1.5935e-01 4.8016e-02 4.6664e-02 3.0592e-02 1.7667e-02 1.6140e-02 6.7755e-01 9.0015e-03 3.0006e-03 5.3480e-01 1.1462e-01 8.7911e-02 4.5604e-02 2.0901e-02 1.5100e-02 1.6907e-01 +1.3300e+00 6.6340e+06 5.8315e+02 1.4846e+03 1.7240e-07 2.2825e-03 9.9772e-01 3.1426e+03 1.4828e+03 4.0095e+02 7.5633e+01 4.8940e-05 1.6935e-05 3.3231e-03 7.2092e-04 1.6040e-01 4.8286e-02 4.6894e-02 3.0721e-02 1.7728e-02 1.6184e-02 6.7574e-01 9.0052e-03 3.0021e-03 5.3504e-01 1.1466e-01 8.7938e-02 4.5614e-02 2.0903e-02 1.5099e-02 1.6874e-01 +1.3320e+00 6.6736e+06 5.8315e+02 1.4947e+03 1.7094e-07 3.8852e-03 9.9611e-01 3.1458e+03 1.4917e+03 4.0054e+02 7.6012e+01 4.8891e-05 1.6955e-05 3.3430e-03 7.2607e-04 1.6145e-01 4.8556e-02 4.7123e-02 3.0849e-02 1.7790e-02 1.6228e-02 6.7393e-01 9.0088e-03 3.0035e-03 5.3528e-01 1.1470e-01 8.7964e-02 4.5623e-02 2.0905e-02 1.5098e-02 1.6841e-01 +1.3340e+00 6.7132e+06 5.8315e+02 1.5048e+03 1.6950e-07 5.4569e-03 9.9454e-01 3.1490e+03 1.5005e+03 4.0013e+02 7.6392e+01 4.8843e-05 1.6976e-05 3.3628e-03 7.3123e-04 1.6250e-01 4.8825e-02 4.7351e-02 3.0977e-02 1.7850e-02 1.6271e-02 6.7213e-01 9.0124e-03 3.0050e-03 5.3552e-01 1.1474e-01 8.7989e-02 4.5632e-02 2.0907e-02 1.5097e-02 1.6809e-01 +1.3360e+00 6.7528e+06 5.8315e+02 1.5149e+03 1.6809e-07 6.9981e-03 9.9300e-01 3.1523e+03 1.5094e+03 3.9972e+02 7.6772e+01 4.8794e-05 1.6997e-05 3.3827e-03 7.3640e-04 1.6355e-01 4.9094e-02 4.7579e-02 3.1104e-02 1.7911e-02 1.6313e-02 6.7033e-01 9.0159e-03 3.0064e-03 5.3575e-01 1.1479e-01 8.8014e-02 4.5641e-02 2.0908e-02 1.5097e-02 1.6778e-01 +1.3380e+00 6.7924e+06 5.8315e+02 1.5250e+03 1.6669e-07 8.5092e-03 9.9149e-01 3.1555e+03 1.5183e+03 3.9931e+02 7.7153e+01 4.8746e-05 1.7017e-05 3.4025e-03 7.4158e-04 1.6460e-01 4.9363e-02 4.7806e-02 3.1230e-02 1.7970e-02 1.6355e-02 6.6853e-01 9.0193e-03 3.0078e-03 5.3598e-01 1.1482e-01 8.8038e-02 4.5650e-02 2.0910e-02 1.5096e-02 1.6748e-01 +1.3400e+00 6.8320e+06 5.8315e+02 1.5350e+03 1.6531e-07 9.9906e-03 9.9001e-01 3.1587e+03 1.5271e+03 3.9889e+02 7.7535e+01 4.8697e-05 1.7038e-05 3.4224e-03 7.4676e-04 1.6566e-01 4.9631e-02 4.8032e-02 3.1356e-02 1.8029e-02 1.6397e-02 6.6673e-01 9.0226e-03 3.0091e-03 5.3620e-01 1.1486e-01 8.8062e-02 4.5658e-02 2.0912e-02 1.5095e-02 1.6718e-01 +1.3420e+00 6.8716e+06 5.8315e+02 1.5451e+03 1.6395e-07 1.1443e-02 9.8856e-01 3.1619e+03 1.5360e+03 3.9848e+02 7.7918e+01 4.8648e-05 1.7059e-05 3.4422e-03 7.5195e-04 1.6671e-01 4.9898e-02 4.8257e-02 3.1481e-02 1.8088e-02 1.6438e-02 6.6494e-01 9.0259e-03 3.0105e-03 5.3641e-01 1.1490e-01 8.8085e-02 4.5666e-02 2.0913e-02 1.5094e-02 1.6689e-01 +1.3440e+00 6.9112e+06 5.8315e+02 1.5551e+03 1.6261e-07 1.2866e-02 9.8713e-01 3.1651e+03 1.5449e+03 3.9806e+02 7.8301e+01 4.8599e-05 1.7079e-05 3.4619e-03 7.5715e-04 1.6776e-01 5.0165e-02 4.8481e-02 3.1605e-02 1.8146e-02 1.6478e-02 6.6315e-01 9.0291e-03 3.0118e-03 5.3663e-01 1.1494e-01 8.8107e-02 4.5674e-02 2.0914e-02 1.5093e-02 1.6661e-01 +1.3460e+00 6.9508e+06 5.8315e+02 1.5651e+03 1.6129e-07 1.4261e-02 9.8574e-01 3.1683e+03 1.5537e+03 3.9765e+02 7.8685e+01 4.8549e-05 1.7100e-05 3.4817e-03 7.6235e-04 1.6881e-01 5.0431e-02 4.8705e-02 3.1728e-02 1.8204e-02 1.6519e-02 6.6136e-01 9.0322e-03 3.0131e-03 5.3684e-01 1.1497e-01 8.8129e-02 4.5681e-02 2.0916e-02 1.5092e-02 1.6633e-01 +1.3480e+00 6.9904e+06 5.8315e+02 1.5751e+03 1.5999e-07 1.5628e-02 9.8437e-01 3.1716e+03 1.5626e+03 3.9723e+02 7.9070e+01 4.8500e-05 1.7121e-05 3.5014e-03 7.6757e-04 1.6986e-01 5.0697e-02 4.8927e-02 3.1851e-02 1.8261e-02 1.6558e-02 6.5957e-01 9.0353e-03 3.0143e-03 5.3704e-01 1.1501e-01 8.8150e-02 4.5688e-02 2.0917e-02 1.5091e-02 1.6605e-01 +1.3500e+00 7.0300e+06 5.8315e+02 1.5851e+03 1.5870e-07 1.6968e-02 9.8303e-01 3.1748e+03 1.5715e+03 3.9682e+02 7.9456e+01 4.8450e-05 1.7142e-05 3.5212e-03 7.7279e-04 1.7091e-01 5.0963e-02 4.9149e-02 3.1973e-02 1.8318e-02 1.6597e-02 6.5779e-01 9.0383e-03 3.0156e-03 5.3724e-01 1.1504e-01 8.8171e-02 4.5695e-02 2.0918e-02 1.5090e-02 1.6579e-01 +1.3520e+00 7.0696e+06 5.8315e+02 1.5950e+03 1.5744e-07 1.8280e-02 9.8172e-01 3.1780e+03 1.5804e+03 3.9640e+02 7.9843e+01 4.8400e-05 1.7162e-05 3.5409e-03 7.7802e-04 1.7197e-01 5.1227e-02 4.9370e-02 3.2094e-02 1.8374e-02 1.6636e-02 6.5601e-01 9.0412e-03 3.0168e-03 5.3744e-01 1.1508e-01 8.8191e-02 4.5702e-02 2.0919e-02 1.5088e-02 1.6553e-01 +1.3540e+00 7.1092e+06 5.8315e+02 1.6050e+03 1.5619e-07 1.9565e-02 9.8043e-01 3.1812e+03 1.5892e+03 3.9598e+02 8.0230e+01 4.8350e-05 1.7183e-05 3.5606e-03 7.8326e-04 1.7302e-01 5.1492e-02 4.9591e-02 3.2215e-02 1.8430e-02 1.6674e-02 6.5423e-01 9.0440e-03 3.0179e-03 5.3763e-01 1.1511e-01 8.8210e-02 4.5708e-02 2.0920e-02 1.5087e-02 1.6527e-01 +1.3560e+00 7.1488e+06 5.8315e+02 1.6149e+03 1.5496e-07 2.0824e-02 9.7918e-01 3.1844e+03 1.5981e+03 3.9556e+02 8.0618e+01 4.8300e-05 1.7204e-05 3.5802e-03 7.8850e-04 1.7407e-01 5.1756e-02 4.9810e-02 3.2334e-02 1.8485e-02 1.6711e-02 6.5246e-01 9.0468e-03 3.0191e-03 5.3781e-01 1.1514e-01 8.8229e-02 4.5715e-02 2.0921e-02 1.5086e-02 1.6503e-01 +1.3580e+00 7.1884e+06 5.8315e+02 1.6248e+03 1.5374e-07 2.2057e-02 9.7794e-01 3.1876e+03 1.6070e+03 3.9514e+02 8.1007e+01 4.8249e-05 1.7225e-05 3.5999e-03 7.9375e-04 1.7513e-01 5.2019e-02 5.0029e-02 3.2454e-02 1.8540e-02 1.6749e-02 6.5069e-01 9.0495e-03 3.0202e-03 5.3800e-01 1.1517e-01 8.8247e-02 4.5721e-02 2.0922e-02 1.5085e-02 1.6478e-01 +1.3600e+00 7.2280e+06 5.8315e+02 1.6347e+03 1.5254e-07 2.3264e-02 9.7674e-01 3.1909e+03 1.6159e+03 3.9472e+02 8.1397e+01 4.8199e-05 1.7246e-05 3.6195e-03 7.9902e-04 1.7618e-01 5.2282e-02 5.0247e-02 3.2572e-02 1.8594e-02 1.6785e-02 6.4892e-01 9.0522e-03 3.0213e-03 5.3818e-01 1.1520e-01 8.8265e-02 4.5726e-02 2.0922e-02 1.5084e-02 1.6455e-01 +1.3620e+00 7.2676e+06 5.8315e+02 1.6445e+03 1.5136e-07 2.4445e-02 9.7556e-01 3.1941e+03 1.6248e+03 3.9430e+02 8.1788e+01 4.8148e-05 1.7267e-05 3.6391e-03 8.0429e-04 1.7724e-01 5.2545e-02 5.0464e-02 3.2690e-02 1.8648e-02 1.6821e-02 6.4715e-01 9.0548e-03 3.0224e-03 5.3835e-01 1.1523e-01 8.8283e-02 4.5732e-02 2.0923e-02 1.5082e-02 1.6432e-01 +1.3640e+00 7.3072e+06 5.8315e+02 1.6544e+03 1.5019e-07 2.5601e-02 9.7440e-01 3.1973e+03 1.6337e+03 3.9388e+02 8.2179e+01 4.8097e-05 1.7288e-05 3.6587e-03 8.0956e-04 1.7829e-01 5.2807e-02 5.0680e-02 3.2807e-02 1.8702e-02 1.6857e-02 6.4539e-01 9.0573e-03 3.0235e-03 5.3852e-01 1.1526e-01 8.8299e-02 4.5737e-02 2.0924e-02 1.5081e-02 1.6409e-01 +1.3660e+00 7.3468e+06 5.8315e+02 1.6642e+03 1.4904e-07 2.6732e-02 9.7327e-01 3.2005e+03 1.6425e+03 3.9345e+02 8.2571e+01 4.8046e-05 1.7309e-05 3.6783e-03 8.1485e-04 1.7935e-01 5.3068e-02 5.0895e-02 3.2923e-02 1.8755e-02 1.6892e-02 6.4363e-01 9.0598e-03 3.0245e-03 5.3869e-01 1.1529e-01 8.8316e-02 4.5742e-02 2.0924e-02 1.5080e-02 1.6387e-01 +1.3680e+00 7.3864e+06 5.8315e+02 1.6740e+03 1.4790e-07 2.7838e-02 9.7216e-01 3.2037e+03 1.6514e+03 3.9303e+02 8.2964e+01 4.7995e-05 1.7331e-05 3.6978e-03 8.2015e-04 1.8040e-01 5.3329e-02 5.1110e-02 3.3039e-02 1.8807e-02 1.6927e-02 6.4187e-01 9.0622e-03 3.0256e-03 5.3885e-01 1.1532e-01 8.8331e-02 4.5747e-02 2.0925e-02 1.5079e-02 1.6366e-01 +1.3700e+00 7.4260e+06 5.8315e+02 1.6838e+03 1.4678e-07 2.8920e-02 9.7108e-01 3.2069e+03 1.6603e+03 3.9261e+02 8.3358e+01 4.7943e-05 1.7352e-05 3.7174e-03 8.2545e-04 1.8146e-01 5.3590e-02 5.1324e-02 3.3154e-02 1.8859e-02 1.6962e-02 6.4011e-01 9.0645e-03 3.0266e-03 5.3901e-01 1.1535e-01 8.8347e-02 4.5752e-02 2.0925e-02 1.5077e-02 1.6345e-01 +1.3720e+00 7.4656e+06 5.8315e+02 1.6936e+03 1.4568e-07 2.9978e-02 9.7002e-01 3.2101e+03 1.6692e+03 3.9218e+02 8.3753e+01 4.7892e-05 1.7373e-05 3.7369e-03 8.3076e-04 1.8251e-01 5.3850e-02 5.1537e-02 3.3268e-02 1.8911e-02 1.6996e-02 6.3836e-01 9.0668e-03 3.0275e-03 5.3917e-01 1.1537e-01 8.8362e-02 4.5757e-02 2.0925e-02 1.5076e-02 1.6325e-01 +1.3740e+00 7.5052e+06 5.8315e+02 1.7034e+03 1.4459e-07 3.1012e-02 9.6899e-01 3.2134e+03 1.6781e+03 3.9175e+02 8.4149e+01 4.7840e-05 1.7394e-05 3.7564e-03 8.3608e-04 1.8357e-01 5.4109e-02 5.1749e-02 3.3382e-02 1.8962e-02 1.7029e-02 6.3661e-01 9.0690e-03 3.0285e-03 5.3932e-01 1.1540e-01 8.8376e-02 4.5761e-02 2.0926e-02 1.5075e-02 1.6305e-01 +1.3760e+00 7.5448e+06 5.8315e+02 1.7131e+03 1.4351e-07 3.2022e-02 9.6798e-01 3.2166e+03 1.6870e+03 3.9133e+02 8.4545e+01 4.7788e-05 1.7416e-05 3.7759e-03 8.4141e-04 1.8463e-01 5.4368e-02 5.1961e-02 3.3495e-02 1.9013e-02 1.7062e-02 6.3486e-01 9.0712e-03 3.0294e-03 5.3947e-01 1.1542e-01 8.8390e-02 4.5765e-02 2.0926e-02 1.5073e-02 1.6285e-01 +1.3780e+00 7.5844e+06 5.8315e+02 1.7228e+03 1.4244e-07 3.3009e-02 9.6699e-01 3.2198e+03 1.6959e+03 3.9090e+02 8.4943e+01 4.7736e-05 1.7437e-05 3.7954e-03 8.4675e-04 1.8568e-01 5.4627e-02 5.2172e-02 3.3607e-02 1.9063e-02 1.7095e-02 6.3311e-01 9.0733e-03 3.0303e-03 5.3962e-01 1.1544e-01 8.8403e-02 4.5769e-02 2.0926e-02 1.5072e-02 1.6267e-01 +1.3800e+00 7.6240e+06 5.8315e+02 1.7325e+03 1.4139e-07 3.3973e-02 9.6603e-01 3.2230e+03 1.7048e+03 3.9047e+02 8.5341e+01 4.7684e-05 1.7459e-05 3.8148e-03 8.5209e-04 1.8674e-01 5.4885e-02 5.2382e-02 3.3719e-02 1.9113e-02 1.7127e-02 6.3137e-01 9.0753e-03 3.0312e-03 5.3976e-01 1.1547e-01 8.8416e-02 4.5773e-02 2.0926e-02 1.5071e-02 1.6248e-01 +1.3820e+00 7.6636e+06 5.8315e+02 1.7422e+03 1.4036e-07 3.4914e-02 9.6509e-01 3.2262e+03 1.7137e+03 3.9004e+02 8.5740e+01 4.7631e-05 1.7480e-05 3.8343e-03 8.5745e-04 1.8780e-01 5.5143e-02 5.2591e-02 3.3830e-02 1.9162e-02 1.7158e-02 6.2962e-01 9.0773e-03 3.0321e-03 5.3989e-01 1.1549e-01 8.8429e-02 4.5776e-02 2.0926e-02 1.5069e-02 1.6231e-01 +1.3840e+00 7.7032e+06 5.8315e+02 1.7519e+03 1.3933e-07 3.5833e-02 9.6417e-01 3.2294e+03 1.7226e+03 3.8961e+02 8.6140e+01 4.7579e-05 1.7502e-05 3.8537e-03 8.6281e-04 1.8886e-01 5.5400e-02 5.2799e-02 3.3940e-02 1.9211e-02 1.7190e-02 6.2789e-01 9.0793e-03 3.0329e-03 5.4003e-01 1.1551e-01 8.8441e-02 4.5780e-02 2.0926e-02 1.5068e-02 1.6213e-01 +1.3860e+00 7.7428e+06 5.8315e+02 1.7616e+03 1.3832e-07 3.6728e-02 9.6327e-01 3.2326e+03 1.7315e+03 3.8918e+02 8.6541e+01 4.7526e-05 1.7523e-05 3.8731e-03 8.6818e-04 1.8992e-01 5.5657e-02 5.3007e-02 3.4050e-02 1.9259e-02 1.7221e-02 6.2615e-01 9.0812e-03 3.0337e-03 5.4016e-01 1.1553e-01 8.8452e-02 4.5783e-02 2.0926e-02 1.5066e-02 1.6197e-01 +1.3880e+00 7.7824e+06 5.8315e+02 1.7712e+03 1.3733e-07 3.7602e-02 9.6240e-01 3.2358e+03 1.7404e+03 3.8875e+02 8.6943e+01 4.7473e-05 1.7545e-05 3.8925e-03 8.7356e-04 1.9098e-01 5.5913e-02 5.3214e-02 3.4159e-02 1.9307e-02 1.7251e-02 6.2441e-01 9.0830e-03 3.0345e-03 5.4028e-01 1.1555e-01 8.8464e-02 4.5786e-02 2.0926e-02 1.5065e-02 1.6180e-01 +1.3900e+00 7.8220e+06 5.8315e+02 1.7808e+03 1.3634e-07 3.8454e-02 9.6155e-01 3.2391e+03 1.7493e+03 3.8832e+02 8.7346e+01 4.7420e-05 1.7567e-05 3.9118e-03 8.7895e-04 1.9204e-01 5.6169e-02 5.3420e-02 3.4267e-02 1.9355e-02 1.7281e-02 6.2268e-01 9.0847e-03 3.0353e-03 5.4041e-01 1.1557e-01 8.8474e-02 4.5789e-02 2.0926e-02 1.5064e-02 1.6165e-01 +1.3920e+00 7.8616e+06 5.8315e+02 1.7904e+03 1.3537e-07 3.9284e-02 9.6072e-01 3.2423e+03 1.7582e+03 3.8788e+02 8.7750e+01 4.7367e-05 1.7589e-05 3.9312e-03 8.8435e-04 1.9310e-01 5.6424e-02 5.3625e-02 3.4375e-02 1.9402e-02 1.7311e-02 6.2095e-01 9.0865e-03 3.0361e-03 5.4053e-01 1.1559e-01 8.8485e-02 4.5791e-02 2.0926e-02 1.5062e-02 1.6149e-01 +1.3940e+00 7.9012e+06 5.8315e+02 1.8000e+03 1.3441e-07 4.0092e-02 9.5991e-01 3.2455e+03 1.7671e+03 3.8745e+02 8.8154e+01 4.7313e-05 1.7611e-05 3.9505e-03 8.8976e-04 1.9416e-01 5.6679e-02 5.3830e-02 3.4482e-02 1.9449e-02 1.7340e-02 6.1922e-01 9.0881e-03 3.0368e-03 5.4064e-01 1.1561e-01 8.8495e-02 4.5794e-02 2.0925e-02 1.5061e-02 1.6135e-01 +1.3960e+00 7.9408e+06 5.8315e+02 1.8096e+03 1.3346e-07 4.0878e-02 9.5912e-01 3.2487e+03 1.7761e+03 3.8701e+02 8.8560e+01 4.7260e-05 1.7633e-05 3.9698e-03 8.9518e-04 1.9522e-01 5.6934e-02 5.4034e-02 3.4589e-02 1.9495e-02 1.7368e-02 6.1750e-01 9.0897e-03 3.0375e-03 5.4076e-01 1.1563e-01 8.8504e-02 4.5796e-02 2.0925e-02 1.5060e-02 1.6120e-01 +1.3980e+00 7.9804e+06 5.8315e+02 1.8191e+03 1.3252e-07 4.1644e-02 9.5836e-01 3.2519e+03 1.7850e+03 3.8658e+02 8.8967e+01 4.7206e-05 1.7655e-05 3.9891e-03 9.0060e-04 1.9628e-01 5.7188e-02 5.4237e-02 3.4694e-02 1.9541e-02 1.7397e-02 6.1577e-01 9.0913e-03 3.0382e-03 5.4087e-01 1.1565e-01 8.8513e-02 4.5799e-02 2.0925e-02 1.5058e-02 1.6106e-01 +1.4000e+00 8.0200e+06 5.8315e+02 1.8287e+03 1.3160e-07 4.2388e-02 9.5761e-01 3.2551e+03 1.7939e+03 3.8614e+02 8.9374e+01 4.7152e-05 1.7677e-05 4.0084e-03 9.0604e-04 1.9734e-01 5.7441e-02 5.4439e-02 3.4800e-02 1.9586e-02 1.7425e-02 6.1405e-01 9.0928e-03 3.0389e-03 5.4097e-01 1.1566e-01 8.8522e-02 4.5801e-02 2.0924e-02 1.5057e-02 1.6093e-01 +1.4020e+00 8.0596e+06 5.8315e+02 1.8382e+03 1.3068e-07 4.3111e-02 9.5689e-01 3.2583e+03 1.8028e+03 3.8570e+02 8.9783e+01 4.7098e-05 1.7699e-05 4.0277e-03 9.1148e-04 1.9840e-01 5.7695e-02 5.4641e-02 3.4904e-02 1.9631e-02 1.7452e-02 6.1233e-01 9.0942e-03 3.0396e-03 5.4107e-01 1.1568e-01 8.8530e-02 4.5803e-02 2.0924e-02 1.5055e-02 1.6080e-01 +1.4040e+00 8.0992e+06 5.8315e+02 1.8477e+03 1.2978e-07 4.3814e-02 9.5619e-01 3.2615e+03 1.8117e+03 3.8526e+02 9.0192e+01 4.7043e-05 1.7721e-05 4.0469e-03 9.1694e-04 1.9947e-01 5.7947e-02 5.4842e-02 3.5008e-02 1.9676e-02 1.7479e-02 6.1062e-01 9.0957e-03 3.0402e-03 5.4117e-01 1.1569e-01 8.8538e-02 4.5805e-02 2.0924e-02 1.5054e-02 1.6068e-01 +1.4060e+00 8.1388e+06 5.8315e+02 1.8572e+03 1.2889e-07 4.4495e-02 9.5550e-01 3.2647e+03 1.8206e+03 3.8482e+02 9.0603e+01 4.6989e-05 1.7744e-05 4.0661e-03 9.2240e-04 2.0053e-01 5.8199e-02 5.5042e-02 3.5111e-02 1.9720e-02 1.7506e-02 6.0890e-01 9.0970e-03 3.0408e-03 5.4127e-01 1.1571e-01 8.8546e-02 4.5806e-02 2.0923e-02 1.5053e-02 1.6056e-01 +1.4080e+00 8.1784e+06 5.8315e+02 1.8667e+03 1.2801e-07 4.5157e-02 9.5484e-01 3.2679e+03 1.8296e+03 3.8438e+02 9.1014e+01 4.6934e-05 1.7766e-05 4.0854e-03 9.2788e-04 2.0160e-01 5.8451e-02 5.5242e-02 3.5214e-02 1.9764e-02 1.7532e-02 6.0719e-01 9.0983e-03 3.0414e-03 5.4136e-01 1.1572e-01 8.8553e-02 4.5808e-02 2.0923e-02 1.5051e-02 1.6044e-01 +1.4100e+00 8.2180e+06 5.8315e+02 1.8761e+03 1.2714e-07 4.5797e-02 9.5420e-01 3.2711e+03 1.8385e+03 3.8394e+02 9.1427e+01 4.6879e-05 1.7789e-05 4.1046e-03 9.3336e-04 2.0266e-01 5.8703e-02 5.5440e-02 3.5316e-02 1.9807e-02 1.7558e-02 6.0548e-01 9.0995e-03 3.0420e-03 5.4145e-01 1.1574e-01 8.8560e-02 4.5809e-02 2.0922e-02 1.5050e-02 1.6033e-01 +1.4120e+00 8.2576e+06 5.8315e+02 1.8856e+03 1.2628e-07 4.6418e-02 9.5358e-01 3.2743e+03 1.8474e+03 3.8350e+02 9.1840e+01 4.6824e-05 1.7811e-05 4.1238e-03 9.3885e-04 2.0373e-01 5.8953e-02 5.5638e-02 3.5417e-02 1.9850e-02 1.7584e-02 6.0377e-01 9.1007e-03 3.0426e-03 5.4154e-01 1.1575e-01 8.8567e-02 4.5810e-02 2.0922e-02 1.5049e-02 1.6022e-01 +1.4140e+00 8.2972e+06 5.8315e+02 1.8950e+03 1.2543e-07 4.7018e-02 9.5298e-01 3.2775e+03 1.8563e+03 3.8305e+02 9.2255e+01 4.6769e-05 1.7834e-05 4.1429e-03 9.4435e-04 2.0479e-01 5.9204e-02 5.5835e-02 3.5518e-02 1.9892e-02 1.7609e-02 6.0206e-01 9.1019e-03 3.0431e-03 5.4162e-01 1.1576e-01 8.8573e-02 4.5812e-02 2.0921e-02 1.5047e-02 1.6012e-01 +1.4160e+00 8.3368e+06 5.8315e+02 1.9044e+03 1.2459e-07 4.7598e-02 9.5240e-01 3.2807e+03 1.8653e+03 3.8261e+02 9.2670e+01 4.6714e-05 1.7856e-05 4.1621e-03 9.4987e-04 2.0586e-01 5.9454e-02 5.6032e-02 3.5618e-02 1.9935e-02 1.7633e-02 6.0036e-01 9.1030e-03 3.0436e-03 5.4170e-01 1.1577e-01 8.8578e-02 4.5813e-02 2.0921e-02 1.5046e-02 1.6002e-01 +1.4180e+00 8.3764e+06 5.8315e+02 1.9138e+03 1.2376e-07 4.8158e-02 9.5184e-01 3.2839e+03 1.8742e+03 3.8216e+02 9.3087e+01 4.6658e-05 1.7879e-05 4.1812e-03 9.5539e-04 2.0692e-01 5.9703e-02 5.6228e-02 3.5718e-02 1.9976e-02 1.7658e-02 5.9866e-01 9.1041e-03 3.0442e-03 5.4178e-01 1.1579e-01 8.8584e-02 4.5813e-02 2.0920e-02 1.5045e-02 1.5993e-01 +1.4200e+00 8.4160e+06 5.8315e+02 1.9231e+03 1.2294e-07 4.8699e-02 9.5130e-01 3.2871e+03 1.8831e+03 3.8171e+02 9.3504e+01 4.6603e-05 1.7902e-05 4.2003e-03 9.6092e-04 2.0799e-01 5.9953e-02 5.6423e-02 3.5817e-02 2.0018e-02 1.7682e-02 5.9696e-01 9.1051e-03 3.0446e-03 5.4185e-01 1.1580e-01 8.8589e-02 4.5814e-02 2.0919e-02 1.5043e-02 1.5984e-01 +1.4220e+00 8.4556e+06 5.8315e+02 1.9325e+03 1.2213e-07 4.9219e-02 9.5078e-01 3.2903e+03 1.8921e+03 3.8127e+02 9.3923e+01 4.6547e-05 1.7925e-05 4.2195e-03 9.6646e-04 2.0906e-01 6.0201e-02 5.6617e-02 3.5915e-02 2.0059e-02 1.7705e-02 5.9526e-01 9.1060e-03 3.0451e-03 5.4192e-01 1.1581e-01 8.8594e-02 4.5815e-02 2.0919e-02 1.5042e-02 1.5975e-01 +1.4240e+00 8.4952e+06 5.8315e+02 1.9418e+03 1.2133e-07 4.9720e-02 9.5028e-01 3.2935e+03 1.9010e+03 3.8082e+02 9.4343e+01 4.6491e-05 1.7948e-05 4.2385e-03 9.7201e-04 2.1013e-01 6.0450e-02 5.6811e-02 3.6013e-02 2.0099e-02 1.7728e-02 5.9356e-01 9.1069e-03 3.0455e-03 5.4199e-01 1.1582e-01 8.8598e-02 4.5815e-02 2.0918e-02 1.5041e-02 1.5967e-01 +1.4260e+00 8.5348e+06 5.8315e+02 1.9512e+03 1.2054e-07 5.0202e-02 9.4980e-01 3.2967e+03 1.9099e+03 3.8037e+02 9.4764e+01 4.6434e-05 1.7971e-05 4.2576e-03 9.7758e-04 2.1120e-01 6.0697e-02 5.7004e-02 3.6110e-02 2.0139e-02 1.7751e-02 5.9187e-01 9.1078e-03 3.0460e-03 5.4205e-01 1.1583e-01 8.8602e-02 4.5816e-02 2.0917e-02 1.5040e-02 1.5959e-01 +1.4280e+00 8.5744e+06 5.8315e+02 1.9605e+03 1.1975e-07 5.0664e-02 9.4934e-01 3.2999e+03 1.9189e+03 3.7992e+02 9.5186e+01 4.6378e-05 1.7995e-05 4.2767e-03 9.8315e-04 2.1227e-01 6.0945e-02 5.7196e-02 3.6206e-02 2.0179e-02 1.7774e-02 5.9017e-01 9.1086e-03 3.0464e-03 5.4211e-01 1.1583e-01 8.8606e-02 4.5816e-02 2.0917e-02 1.5039e-02 1.5952e-01 +1.4300e+00 8.6140e+06 5.8315e+02 1.9697e+03 1.1898e-07 5.1106e-02 9.4889e-01 3.3031e+03 1.9278e+03 3.7947e+02 9.5609e+01 4.6322e-05 1.8018e-05 4.2957e-03 9.8873e-04 2.1334e-01 6.1192e-02 5.7387e-02 3.6302e-02 2.0218e-02 1.7796e-02 5.8848e-01 9.1094e-03 3.0468e-03 5.4217e-01 1.1584e-01 8.8609e-02 4.5816e-02 2.0916e-02 1.5037e-02 1.5945e-01 +1.4320e+00 8.6536e+06 5.8315e+02 1.9790e+03 1.1822e-07 5.1529e-02 9.4847e-01 3.3063e+03 1.9368e+03 3.7901e+02 9.6033e+01 4.6265e-05 1.8041e-05 4.3148e-03 9.9433e-04 2.1441e-01 6.1438e-02 5.7578e-02 3.6397e-02 2.0257e-02 1.7817e-02 5.8679e-01 9.1101e-03 3.0471e-03 5.4223e-01 1.1585e-01 8.8613e-02 4.5816e-02 2.0915e-02 1.5036e-02 1.5939e-01 +1.4340e+00 8.6932e+06 5.8315e+02 1.9883e+03 1.1746e-07 5.1933e-02 9.4807e-01 3.3095e+03 1.9457e+03 3.7856e+02 9.6458e+01 4.6208e-05 1.8065e-05 4.3338e-03 9.9993e-04 2.1548e-01 6.1685e-02 5.7768e-02 3.6492e-02 2.0296e-02 1.7839e-02 5.8511e-01 9.1108e-03 3.0475e-03 5.4228e-01 1.1586e-01 8.8615e-02 4.5816e-02 2.0914e-02 1.5035e-02 1.5933e-01 +1.4360e+00 8.7328e+06 5.8315e+02 1.9975e+03 1.1671e-07 5.2318e-02 9.4768e-01 3.3127e+03 1.9547e+03 3.7810e+02 9.6884e+01 4.6151e-05 1.8089e-05 4.3528e-03 1.0055e-03 2.1655e-01 6.1930e-02 5.7957e-02 3.6586e-02 2.0334e-02 1.7860e-02 5.8342e-01 9.1114e-03 3.0478e-03 5.4233e-01 1.1586e-01 8.8618e-02 4.5816e-02 2.0914e-02 1.5034e-02 1.5927e-01 +1.4380e+00 8.7724e+06 5.8315e+02 2.0067e+03 1.1597e-07 5.2683e-02 9.4732e-01 3.3159e+03 1.9636e+03 3.7765e+02 9.7312e+01 4.6093e-05 1.8112e-05 4.3718e-03 1.0112e-03 2.1763e-01 6.2176e-02 5.8146e-02 3.6680e-02 2.0372e-02 1.7880e-02 5.8174e-01 9.1120e-03 3.0481e-03 5.4237e-01 1.1587e-01 8.8620e-02 4.5816e-02 2.0913e-02 1.5033e-02 1.5922e-01 +1.4400e+00 8.8120e+06 5.8315e+02 2.0159e+03 1.1524e-07 5.3029e-02 9.4697e-01 3.3191e+03 1.9726e+03 3.7719e+02 9.7741e+01 4.6036e-05 1.8136e-05 4.3908e-03 1.0168e-03 2.1870e-01 6.2421e-02 5.8334e-02 3.6772e-02 2.0409e-02 1.7900e-02 5.8006e-01 9.1125e-03 3.0484e-03 5.4242e-01 1.1587e-01 8.8622e-02 4.5816e-02 2.0912e-02 1.5032e-02 1.5917e-01 +1.4420e+00 8.8516e+06 5.8315e+02 2.0251e+03 1.1452e-07 5.3356e-02 9.4664e-01 3.3223e+03 1.9815e+03 3.7673e+02 9.8171e+01 4.5978e-05 1.8160e-05 4.4098e-03 1.0225e-03 2.1977e-01 6.2665e-02 5.8521e-02 3.6865e-02 2.0446e-02 1.7920e-02 5.7838e-01 9.1130e-03 3.0487e-03 5.4246e-01 1.1588e-01 8.8623e-02 4.5815e-02 2.0911e-02 1.5031e-02 1.5912e-01 +1.4440e+00 8.8912e+06 5.8315e+02 2.0343e+03 1.1381e-07 5.3665e-02 9.4634e-01 3.3255e+03 1.9905e+03 3.7627e+02 9.8602e+01 4.5920e-05 1.8184e-05 4.4287e-03 1.0281e-03 2.2085e-01 6.2909e-02 5.8708e-02 3.6956e-02 2.0483e-02 1.7940e-02 5.7670e-01 9.1135e-03 3.0490e-03 5.4249e-01 1.1588e-01 8.8625e-02 4.5815e-02 2.0910e-02 1.5029e-02 1.5908e-01 +1.4460e+00 8.9308e+06 5.8315e+02 2.0435e+03 1.1310e-07 5.3954e-02 9.4605e-01 3.3287e+03 1.9995e+03 3.7581e+02 9.9034e+01 4.5862e-05 1.8208e-05 4.4477e-03 1.0338e-03 2.2192e-01 6.3153e-02 5.8894e-02 3.7048e-02 2.0519e-02 1.7959e-02 5.7502e-01 9.1139e-03 3.0492e-03 5.4253e-01 1.1589e-01 8.8626e-02 4.5814e-02 2.0910e-02 1.5028e-02 1.5905e-01 +1.4480e+00 8.9704e+06 5.8315e+02 2.0526e+03 1.1240e-07 5.4224e-02 9.4578e-01 3.3319e+03 2.0084e+03 3.7535e+02 9.9467e+01 4.5804e-05 1.8232e-05 4.4666e-03 1.0395e-03 2.2300e-01 6.3396e-02 5.9079e-02 3.7138e-02 2.0555e-02 1.7978e-02 5.7335e-01 9.1143e-03 3.0494e-03 5.4256e-01 1.1589e-01 8.8626e-02 4.5813e-02 2.0909e-02 1.5027e-02 1.5901e-01 +1.4500e+00 9.0100e+06 5.8315e+02 2.0618e+03 1.1171e-07 5.4475e-02 9.4553e-01 3.3350e+03 2.0174e+03 3.7489e+02 9.9902e+01 4.5746e-05 1.8257e-05 4.4855e-03 1.0452e-03 2.2408e-01 6.3639e-02 5.9263e-02 3.7228e-02 2.0590e-02 1.7996e-02 5.7167e-01 9.1146e-03 3.0496e-03 5.4258e-01 1.1589e-01 8.8627e-02 4.5812e-02 2.0908e-02 1.5026e-02 1.5898e-01 +1.4520e+00 9.0496e+06 5.8315e+02 2.0709e+03 1.1103e-07 5.4707e-02 9.4529e-01 3.3382e+03 2.0263e+03 3.7442e+02 1.0034e+02 4.5687e-05 1.8281e-05 4.5044e-03 1.0509e-03 2.2516e-01 6.3882e-02 5.9447e-02 3.7318e-02 2.0625e-02 1.8014e-02 5.7000e-01 9.1149e-03 3.0498e-03 5.4261e-01 1.1590e-01 8.8627e-02 4.5812e-02 2.0907e-02 1.5026e-02 1.5896e-01 +1.4540e+00 9.0892e+06 5.8315e+02 2.0800e+03 1.1036e-07 5.4920e-02 9.4508e-01 3.3414e+03 2.0353e+03 3.7396e+02 1.0077e+02 4.5628e-05 1.8306e-05 4.5233e-03 1.0566e-03 2.2623e-01 6.4124e-02 5.9630e-02 3.7406e-02 2.0660e-02 1.8032e-02 5.6833e-01 9.1151e-03 3.0500e-03 5.4263e-01 1.1590e-01 8.8627e-02 4.5811e-02 2.0906e-02 1.5025e-02 1.5894e-01 +1.4560e+00 9.1288e+06 5.8315e+02 2.0890e+03 1.0969e-07 5.5114e-02 9.4489e-01 3.3446e+03 2.0443e+03 3.7349e+02 1.0121e+02 4.5569e-05 1.8331e-05 4.5422e-03 1.0623e-03 2.2731e-01 6.4365e-02 5.9813e-02 3.7495e-02 2.0694e-02 1.8049e-02 5.6667e-01 9.1153e-03 3.0501e-03 5.4265e-01 1.1590e-01 8.8626e-02 4.5810e-02 2.0905e-02 1.5024e-02 1.5892e-01 +1.4580e+00 9.1684e+06 5.8315e+02 2.0981e+03 1.0903e-07 5.5289e-02 9.4471e-01 3.3478e+03 2.0533e+03 3.7302e+02 1.0165e+02 4.5510e-05 1.8355e-05 4.5610e-03 1.0680e-03 2.2839e-01 6.4607e-02 5.9995e-02 3.7582e-02 2.0728e-02 1.8066e-02 5.6500e-01 9.1154e-03 3.0502e-03 5.4267e-01 1.1590e-01 8.8626e-02 4.5808e-02 2.0904e-02 1.5023e-02 1.5891e-01 +1.4600e+00 9.2080e+06 5.8315e+02 2.1072e+03 1.0837e-07 5.5445e-02 9.4456e-01 3.3510e+03 2.0622e+03 3.7256e+02 1.0209e+02 4.5451e-05 1.8380e-05 4.5799e-03 1.0738e-03 2.2947e-01 6.4848e-02 6.0176e-02 3.7670e-02 2.0762e-02 1.8083e-02 5.6333e-01 9.1155e-03 3.0503e-03 5.4268e-01 1.1590e-01 8.8625e-02 4.5807e-02 2.0904e-02 1.5022e-02 1.5890e-01 +1.4620e+00 9.2476e+06 5.8315e+02 2.1162e+03 1.0773e-07 5.5582e-02 9.4442e-01 3.3541e+03 2.0712e+03 3.7209e+02 1.0254e+02 4.5391e-05 1.8405e-05 4.5987e-03 1.0795e-03 2.3056e-01 6.5088e-02 6.0356e-02 3.7756e-02 2.0795e-02 1.8100e-02 5.6167e-01 9.1156e-03 3.0504e-03 5.4269e-01 1.1590e-01 8.8623e-02 4.5806e-02 2.0903e-02 1.5021e-02 1.5889e-01 +1.4640e+00 9.2872e+06 5.8315e+02 2.1252e+03 1.0709e-07 5.5700e-02 9.4430e-01 3.3573e+03 2.0802e+03 3.7161e+02 1.0298e+02 4.5332e-05 1.8430e-05 4.6176e-03 1.0853e-03 2.3164e-01 6.5328e-02 6.0536e-02 3.7842e-02 2.0828e-02 1.8116e-02 5.6001e-01 9.1156e-03 3.0505e-03 5.4269e-01 1.1590e-01 8.8622e-02 4.5805e-02 2.0902e-02 1.5020e-02 1.5889e-01 +1.4660e+00 9.3268e+06 5.8315e+02 2.1342e+03 1.0646e-07 5.5798e-02 9.4420e-01 3.3605e+03 2.0892e+03 3.7114e+02 1.0342e+02 4.5272e-05 1.8456e-05 4.6364e-03 1.0911e-03 2.3272e-01 6.5568e-02 6.0715e-02 3.7928e-02 2.0861e-02 1.8131e-02 5.5835e-01 9.1156e-03 3.0506e-03 5.4270e-01 1.1590e-01 8.8620e-02 4.5803e-02 2.0901e-02 1.5020e-02 1.5889e-01 +1.4680e+00 9.3664e+06 5.8315e+02 2.1432e+03 1.0583e-07 5.5878e-02 9.4412e-01 3.3637e+03 2.0982e+03 3.7067e+02 1.0387e+02 4.5212e-05 1.8481e-05 4.6552e-03 1.0969e-03 2.3381e-01 6.5807e-02 6.0894e-02 3.8013e-02 2.0893e-02 1.8147e-02 5.5669e-01 9.1155e-03 3.0506e-03 5.4270e-01 1.1590e-01 8.8618e-02 4.5802e-02 2.0900e-02 1.5019e-02 1.5890e-01 +1.4700e+00 9.4060e+06 5.8315e+02 2.1522e+03 1.0521e-07 5.5939e-02 9.4406e-01 3.3668e+03 2.1071e+03 3.7019e+02 1.0432e+02 4.5151e-05 1.8507e-05 4.6740e-03 1.1027e-03 2.3489e-01 6.6046e-02 6.1071e-02 3.8097e-02 2.0925e-02 1.8162e-02 5.5503e-01 9.1154e-03 3.0506e-03 5.4270e-01 1.1590e-01 8.8616e-02 4.5800e-02 2.0899e-02 1.5018e-02 1.5891e-01 +1.4720e+00 9.4456e+06 5.8315e+02 2.1611e+03 1.0460e-07 5.5980e-02 9.4402e-01 3.3700e+03 2.1161e+03 3.6972e+02 1.0477e+02 4.5091e-05 1.8532e-05 4.6928e-03 1.1085e-03 2.3598e-01 6.6285e-02 6.1249e-02 3.8181e-02 2.0957e-02 1.8176e-02 5.5337e-01 9.1153e-03 3.0506e-03 5.4269e-01 1.1589e-01 8.8613e-02 4.5799e-02 2.0898e-02 1.5018e-02 1.5892e-01 +1.4740e+00 9.4852e+06 5.8315e+02 2.1701e+03 1.0399e-07 5.6002e-02 9.4400e-01 3.3732e+03 2.1251e+03 3.6924e+02 1.0522e+02 4.5030e-05 1.8558e-05 4.7115e-03 1.1144e-03 2.3707e-01 6.6523e-02 6.1425e-02 3.8264e-02 2.0988e-02 1.8191e-02 5.5172e-01 9.1151e-03 3.0506e-03 5.4269e-01 1.1589e-01 8.8610e-02 4.5797e-02 2.0898e-02 1.5017e-02 1.5894e-01 +1.4760e+00 9.5248e+06 5.8315e+02 2.1790e+03 1.0339e-07 5.6005e-02 9.4399e-01 3.3763e+03 2.1341e+03 3.6876e+02 1.0567e+02 4.4969e-05 1.8584e-05 4.7303e-03 1.1202e-03 2.3815e-01 6.6761e-02 6.1601e-02 3.8347e-02 2.1019e-02 1.8205e-02 5.5006e-01 9.1148e-03 3.0506e-03 5.4268e-01 1.1589e-01 8.8607e-02 4.5795e-02 2.0897e-02 1.5016e-02 1.5896e-01 +1.4780e+00 9.5644e+06 5.8315e+02 2.1879e+03 1.0280e-07 5.5989e-02 9.4401e-01 3.3795e+03 2.1431e+03 3.6828e+02 1.0612e+02 4.4908e-05 1.8610e-05 4.7491e-03 1.1261e-03 2.3924e-01 6.6999e-02 6.1776e-02 3.8429e-02 2.1049e-02 1.8219e-02 5.4841e-01 9.1146e-03 3.0505e-03 5.4266e-01 1.1588e-01 8.8604e-02 4.5793e-02 2.0896e-02 1.5016e-02 1.5898e-01 +1.4800e+00 9.6040e+06 5.8315e+02 2.1968e+03 1.0221e-07 5.5953e-02 9.4405e-01 3.3827e+03 2.1521e+03 3.6780e+02 1.0657e+02 4.4847e-05 1.8636e-05 4.7678e-03 1.1319e-03 2.4033e-01 6.7236e-02 6.1951e-02 3.8510e-02 2.1079e-02 1.8232e-02 5.4676e-01 9.1142e-03 3.0504e-03 5.4265e-01 1.1588e-01 8.8600e-02 4.5791e-02 2.0895e-02 1.5015e-02 1.5901e-01 +1.4820e+00 9.6436e+06 5.8315e+02 2.2057e+03 1.0163e-07 5.5897e-02 9.4410e-01 3.3858e+03 2.1611e+03 3.6731e+02 1.0703e+02 4.4785e-05 1.8663e-05 4.7865e-03 1.1378e-03 2.4142e-01 6.7473e-02 6.2125e-02 3.8591e-02 2.1109e-02 1.8245e-02 5.4511e-01 9.1139e-03 3.0503e-03 5.4263e-01 1.1587e-01 8.8597e-02 4.5789e-02 2.0894e-02 1.5015e-02 1.5904e-01 +1.4840e+00 9.6832e+06 5.8315e+02 2.2146e+03 1.0106e-07 5.5822e-02 9.4418e-01 3.3890e+03 2.1701e+03 3.6683e+02 1.0749e+02 4.4724e-05 1.8689e-05 4.8053e-03 1.1437e-03 2.4251e-01 6.7709e-02 6.2298e-02 3.8672e-02 2.1138e-02 1.8258e-02 5.4346e-01 9.1135e-03 3.0502e-03 5.4260e-01 1.1587e-01 8.8593e-02 4.5787e-02 2.0894e-02 1.5015e-02 1.5907e-01 +1.4860e+00 9.7228e+06 5.8315e+02 2.2234e+03 1.0049e-07 5.5727e-02 9.4427e-01 3.3921e+03 2.1791e+03 3.6634e+02 1.0795e+02 4.4662e-05 1.8716e-05 4.8240e-03 1.1496e-03 2.4361e-01 6.7945e-02 6.2470e-02 3.8752e-02 2.1167e-02 1.8270e-02 5.4181e-01 9.1130e-03 3.0501e-03 5.4258e-01 1.1586e-01 8.8588e-02 4.5785e-02 2.0893e-02 1.5014e-02 1.5911e-01 +1.4880e+00 9.7624e+06 5.8315e+02 2.2323e+03 9.9923e-08 5.5613e-02 9.4439e-01 3.3953e+03 2.1881e+03 3.6586e+02 1.0841e+02 4.4600e-05 1.8742e-05 4.8427e-03 1.1556e-03 2.4470e-01 6.8181e-02 6.2642e-02 3.8831e-02 2.1196e-02 1.8283e-02 5.4017e-01 9.1126e-03 3.0499e-03 5.4255e-01 1.1586e-01 8.8584e-02 4.5783e-02 2.0892e-02 1.5014e-02 1.5916e-01 +1.4900e+00 9.8020e+06 5.8315e+02 2.2411e+03 9.9365e-08 5.5478e-02 9.4452e-01 3.3984e+03 2.1972e+03 3.6537e+02 1.0887e+02 4.4538e-05 1.8769e-05 4.8614e-03 1.1615e-03 2.4580e-01 6.8416e-02 6.2814e-02 3.8910e-02 2.1224e-02 1.8294e-02 5.3852e-01 9.1120e-03 3.0498e-03 5.4252e-01 1.1585e-01 8.8579e-02 4.5781e-02 2.0891e-02 1.5014e-02 1.5920e-01 +1.4920e+00 9.8416e+06 5.8315e+02 2.2499e+03 9.8813e-08 5.5324e-02 9.4468e-01 3.4016e+03 2.2062e+03 3.6488e+02 1.0933e+02 4.4475e-05 1.8796e-05 4.8801e-03 1.1674e-03 2.4689e-01 6.8651e-02 6.2985e-02 3.8989e-02 2.1252e-02 1.8306e-02 5.3688e-01 9.1115e-03 3.0496e-03 5.4249e-01 1.1584e-01 8.8574e-02 4.5779e-02 2.0890e-02 1.5013e-02 1.5925e-01 +1.4940e+00 9.8812e+06 5.8315e+02 2.2587e+03 9.8267e-08 5.5149e-02 9.4485e-01 3.4047e+03 2.2152e+03 3.6439e+02 1.0980e+02 4.4412e-05 1.8823e-05 4.8987e-03 1.1734e-03 2.4799e-01 6.8886e-02 6.3155e-02 3.9067e-02 2.1280e-02 1.8317e-02 5.3524e-01 9.1109e-03 3.0494e-03 5.4245e-01 1.1584e-01 8.8569e-02 4.5777e-02 2.0890e-02 1.5013e-02 1.5931e-01 +1.4960e+00 9.9208e+06 5.8315e+02 2.2675e+03 9.7727e-08 5.4954e-02 9.4505e-01 3.4079e+03 2.2242e+03 3.6389e+02 1.1026e+02 4.4349e-05 1.8851e-05 4.9174e-03 1.1794e-03 2.4909e-01 6.9120e-02 6.3324e-02 3.9144e-02 2.1308e-02 1.8328e-02 5.3359e-01 9.1102e-03 3.0492e-03 5.4241e-01 1.1583e-01 8.8563e-02 4.5774e-02 2.0889e-02 1.5013e-02 1.5936e-01 +1.4980e+00 9.9604e+06 5.8315e+02 2.2763e+03 9.7191e-08 5.4739e-02 9.4526e-01 3.4110e+03 2.2332e+03 3.6340e+02 1.1073e+02 4.4286e-05 1.8878e-05 4.9361e-03 1.1854e-03 2.5019e-01 6.9354e-02 6.3493e-02 3.9221e-02 2.1335e-02 1.8339e-02 5.3195e-01 9.1095e-03 3.0489e-03 5.4237e-01 1.1582e-01 8.8558e-02 4.5772e-02 2.0888e-02 1.5013e-02 1.5942e-01 +1.5000e+00 1.0000e+07 5.8315e+02 2.2850e+03 9.6662e-08 5.4503e-02 9.4550e-01 3.4142e+03 2.2423e+03 3.6290e+02 1.1120e+02 4.4223e-05 1.8906e-05 4.9547e-03 1.1914e-03 2.5129e-01 6.9588e-02 6.3661e-02 3.9297e-02 2.1361e-02 1.8349e-02 5.3031e-01 9.1088e-03 3.0486e-03 5.4232e-01 1.1581e-01 8.8552e-02 4.5770e-02 2.0888e-02 1.5013e-02 1.5949e-01 +1.5020e+00 1.0100e+07 5.8315e+02 2.3071e+03 9.5347e-08 5.3815e-02 9.4618e-01 3.4221e+03 2.2651e+03 3.6164e+02 1.1239e+02 4.4062e-05 1.8976e-05 5.0018e-03 1.2066e-03 2.5407e-01 7.0176e-02 6.4083e-02 3.9487e-02 2.1427e-02 1.8374e-02 5.2617e-01 9.1068e-03 3.0479e-03 5.4219e-01 1.1579e-01 8.8536e-02 4.5763e-02 2.0886e-02 1.5013e-02 1.5967e-01 +1.5040e+00 1.0200e+07 5.8315e+02 2.3290e+03 9.4066e-08 5.2993e-02 9.4701e-01 3.4300e+03 2.2879e+03 3.6037e+02 1.1359e+02 4.3900e-05 1.9048e-05 5.0488e-03 1.2220e-03 2.5686e-01 7.0763e-02 6.4502e-02 3.9674e-02 2.1491e-02 1.8396e-02 5.2204e-01 9.1045e-03 3.0470e-03 5.4205e-01 1.1576e-01 8.8519e-02 4.5757e-02 2.0884e-02 1.5013e-02 1.5987e-01 +1.5060e+00 1.0300e+07 5.8315e+02 2.3509e+03 9.2816e-08 5.2033e-02 9.4797e-01 3.4379e+03 2.3108e+03 3.5909e+02 1.1481e+02 4.3736e-05 1.9121e-05 5.0958e-03 1.2374e-03 2.5966e-01 7.1347e-02 6.4916e-02 3.9858e-02 2.1553e-02 1.8417e-02 5.1792e-01 9.1019e-03 3.0460e-03 5.4188e-01 1.1573e-01 8.8500e-02 4.5750e-02 2.0883e-02 1.5013e-02 1.6010e-01 +1.5080e+00 1.0400e+07 5.8315e+02 2.3727e+03 9.1596e-08 5.0932e-02 9.4907e-01 3.4458e+03 2.3336e+03 3.5780e+02 1.1603e+02 4.3571e-05 1.9194e-05 5.1428e-03 1.2529e-03 2.6247e-01 7.1930e-02 6.5327e-02 4.0039e-02 2.1613e-02 1.8436e-02 5.1379e-01 9.0991e-03 3.0449e-03 5.4170e-01 1.1570e-01 8.8480e-02 4.5743e-02 2.0882e-02 1.5014e-02 1.6034e-01 +1.5100e+00 1.0500e+07 5.8315e+02 2.3943e+03 9.0407e-08 4.9686e-02 9.5031e-01 3.4536e+03 2.3565e+03 3.5650e+02 1.1727e+02 4.3404e-05 1.9269e-05 5.1897e-03 1.2685e-03 2.6528e-01 7.2511e-02 6.5734e-02 4.0216e-02 2.1670e-02 1.8453e-02 5.0968e-01 9.0960e-03 3.0436e-03 5.4149e-01 1.1566e-01 8.8459e-02 4.5736e-02 2.0881e-02 1.5015e-02 1.6062e-01 +1.5120e+00 1.0600e+07 5.8315e+02 2.4159e+03 8.9245e-08 4.8292e-02 9.5171e-01 3.4615e+03 2.3795e+03 3.5518e+02 1.1852e+02 4.3236e-05 1.9345e-05 5.2366e-03 1.2843e-03 2.6811e-01 7.3089e-02 6.6137e-02 4.0390e-02 2.1726e-02 1.8468e-02 5.0556e-01 9.0927e-03 3.0423e-03 5.4127e-01 1.1562e-01 8.8436e-02 4.5728e-02 2.0880e-02 1.5017e-02 1.6092e-01 +1.5140e+00 1.0700e+07 5.8315e+02 2.4375e+03 8.8112e-08 4.6744e-02 9.5326e-01 3.4693e+03 2.4024e+03 3.5386e+02 1.1978e+02 4.3066e-05 1.9423e-05 5.2835e-03 1.3001e-03 2.7094e-01 7.3666e-02 6.6536e-02 4.0561e-02 2.1780e-02 1.8482e-02 5.0145e-01 9.0891e-03 3.0407e-03 5.4102e-01 1.1558e-01 8.8412e-02 4.5721e-02 2.0879e-02 1.5019e-02 1.6124e-01 +1.5160e+00 1.0800e+07 5.8315e+02 2.4589e+03 8.7005e-08 4.5038e-02 9.5496e-01 3.4771e+03 2.4254e+03 3.5252e+02 1.2105e+02 4.2895e-05 1.9502e-05 5.3304e-03 1.3160e-03 2.7379e-01 7.4242e-02 6.6932e-02 4.0729e-02 2.1832e-02 1.8494e-02 4.9734e-01 9.0852e-03 3.0391e-03 5.4076e-01 1.1554e-01 8.8387e-02 4.5713e-02 2.0878e-02 1.5021e-02 1.6158e-01 +1.5180e+00 1.0900e+07 5.8315e+02 2.4803e+03 8.5925e-08 4.3168e-02 9.5683e-01 3.4849e+03 2.4484e+03 3.5116e+02 1.2234e+02 4.2722e-05 1.9582e-05 5.3772e-03 1.3321e-03 2.7664e-01 7.4815e-02 6.7325e-02 4.0894e-02 2.1881e-02 1.8504e-02 4.9323e-01 9.0810e-03 3.0373e-03 5.4047e-01 1.1549e-01 8.8360e-02 4.5705e-02 2.0878e-02 1.5024e-02 1.6195e-01 +1.5200e+00 1.1000e+07 5.8315e+02 2.5015e+03 8.4869e-08 4.1127e-02 9.5887e-01 3.4926e+03 2.4714e+03 3.4980e+02 1.2364e+02 4.2547e-05 1.9663e-05 5.4241e-03 1.3483e-03 2.7951e-01 7.5387e-02 6.7713e-02 4.1056e-02 2.1929e-02 1.8512e-02 4.8912e-01 9.0766e-03 3.0354e-03 5.4017e-01 1.1544e-01 8.8332e-02 4.5697e-02 2.0878e-02 1.5027e-02 1.6235e-01 +1.5220e+00 1.1100e+07 5.8315e+02 2.5227e+03 8.3838e-08 3.8910e-02 9.6109e-01 3.5003e+03 2.4945e+03 3.4842e+02 1.2495e+02 4.2371e-05 1.9746e-05 5.4710e-03 1.3646e-03 2.8238e-01 7.5958e-02 6.8099e-02 4.1215e-02 2.1975e-02 1.8518e-02 4.8502e-01 9.0719e-03 3.0333e-03 5.3984e-01 1.1539e-01 8.8303e-02 4.5689e-02 2.0878e-02 1.5030e-02 1.6277e-01 +1.5240e+00 1.1200e+07 5.8315e+02 2.5438e+03 8.2830e-08 3.6507e-02 9.6349e-01 3.5080e+03 2.5176e+03 3.4703e+02 1.2628e+02 4.2193e-05 1.9830e-05 5.5179e-03 1.3810e-03 2.8527e-01 7.6527e-02 6.8481e-02 4.1370e-02 2.2019e-02 1.8523e-02 4.8091e-01 9.0669e-03 3.0311e-03 5.3949e-01 1.1533e-01 8.8273e-02 4.5681e-02 2.0878e-02 1.5034e-02 1.6321e-01 +1.5260e+00 1.1300e+07 5.8315e+02 2.5649e+03 8.1845e-08 3.3912e-02 9.6609e-01 3.5157e+03 2.5407e+03 3.4562e+02 1.2762e+02 4.2013e-05 1.9916e-05 5.5647e-03 1.3976e-03 2.8817e-01 7.7095e-02 6.8859e-02 4.1523e-02 2.2061e-02 1.8526e-02 4.7680e-01 9.0616e-03 3.0287e-03 5.3912e-01 1.1527e-01 8.8241e-02 4.5673e-02 2.0879e-02 1.5039e-02 1.6368e-01 +1.5280e+00 1.1400e+07 5.8315e+02 2.5858e+03 8.0883e-08 3.1114e-02 9.6889e-01 3.5233e+03 2.5639e+03 3.4420e+02 1.2898e+02 4.1831e-05 2.0004e-05 5.6117e-03 1.4143e-03 2.9109e-01 7.7662e-02 6.9235e-02 4.1673e-02 2.2102e-02 1.8527e-02 4.7269e-01 9.0560e-03 3.0262e-03 5.3873e-01 1.1521e-01 8.8209e-02 4.5665e-02 2.0880e-02 1.5043e-02 1.6418e-01 +1.5300e+00 1.1500e+07 5.8315e+02 2.6067e+03 7.9942e-08 2.8104e-02 9.7190e-01 3.5309e+03 2.5871e+03 3.4276e+02 1.3036e+02 4.1647e-05 2.0093e-05 5.6586e-03 1.4311e-03 2.9402e-01 7.8227e-02 6.9607e-02 4.1820e-02 2.2140e-02 1.8526e-02 4.6857e-01 9.0502e-03 3.0235e-03 5.3831e-01 1.1515e-01 8.8175e-02 4.5657e-02 2.0881e-02 1.5049e-02 1.6471e-01 +1.5320e+00 1.1600e+07 5.8315e+02 2.6275e+03 7.9021e-08 2.4871e-02 9.7513e-01 3.5385e+03 2.6103e+03 3.4130e+02 1.3175e+02 4.1461e-05 2.0184e-05 5.7056e-03 1.4481e-03 2.9696e-01 7.8791e-02 6.9976e-02 4.1964e-02 2.2177e-02 1.8524e-02 4.6445e-01 9.0440e-03 3.0207e-03 5.3787e-01 1.1508e-01 8.8139e-02 4.5649e-02 2.0883e-02 1.5054e-02 1.6526e-01 +1.5340e+00 1.1700e+07 5.8315e+02 2.6482e+03 7.8121e-08 2.1402e-02 9.7860e-01 3.5460e+03 2.6336e+03 3.3983e+02 1.3316e+02 4.1273e-05 2.0277e-05 5.7527e-03 1.4652e-03 2.9992e-01 7.9355e-02 7.0341e-02 4.2105e-02 2.2211e-02 1.8520e-02 4.6033e-01 9.0375e-03 3.0177e-03 5.3741e-01 1.1501e-01 8.8103e-02 4.5640e-02 2.0885e-02 1.5061e-02 1.6584e-01 +1.5360e+00 1.1800e+07 5.8315e+02 2.6689e+03 7.7241e-08 1.7683e-02 9.8232e-01 3.5535e+03 2.6570e+03 3.3834e+02 1.3459e+02 4.1083e-05 2.0372e-05 5.7998e-03 1.4825e-03 3.0290e-01 7.9917e-02 7.0704e-02 4.2244e-02 2.2244e-02 1.8515e-02 4.5620e-01 9.0306e-03 3.0145e-03 5.3692e-01 1.1493e-01 8.8065e-02 4.5632e-02 2.0887e-02 1.5067e-02 1.6645e-01 +1.5380e+00 1.1900e+07 5.8315e+02 2.6894e+03 7.6379e-08 1.3699e-02 9.8630e-01 3.5609e+03 2.6803e+03 3.3683e+02 1.3603e+02 4.0891e-05 2.0469e-05 5.8470e-03 1.5000e-03 3.0589e-01 8.0479e-02 7.1064e-02 4.2379e-02 2.2275e-02 1.8508e-02 4.5206e-01 9.0235e-03 3.0112e-03 5.3641e-01 1.1485e-01 8.8025e-02 4.5624e-02 2.0890e-02 1.5075e-02 1.6709e-01 +1.5400e+00 1.2000e+07 5.8315e+02 2.7099e+03 7.5536e-08 9.4342e-03 9.9057e-01 3.5683e+03 2.7037e+03 3.3530e+02 1.3750e+02 4.0696e-05 2.0568e-05 5.8943e-03 1.5176e-03 3.0890e-01 8.1041e-02 7.1421e-02 4.2512e-02 2.2304e-02 1.8499e-02 4.4791e-01 9.0160e-03 3.0076e-03 5.3586e-01 1.1477e-01 8.7985e-02 4.5616e-02 2.0893e-02 1.5082e-02 1.6776e-01 +1.5420e+00 1.2100e+07 5.8315e+02 2.7304e+03 7.4711e-08 4.8688e-03 9.9513e-01 3.5756e+03 2.7272e+03 3.3375e+02 1.3899e+02 4.0500e-05 2.0669e-05 5.9417e-03 1.5354e-03 3.1193e-01 8.1601e-02 7.1775e-02 4.2642e-02 2.2332e-02 1.8488e-02 4.4376e-01 9.0082e-03 3.0039e-03 5.3530e-01 1.1469e-01 8.7943e-02 4.5608e-02 2.0896e-02 1.5091e-02 1.6847e-01 +1.5440e+00 1.2200e+07 5.8315e+02 2.7507e+03 7.8035e-08 0.0000e+00 1.0000e+00 2.7507e+03 2.7507e+03 1.4050e+02 1.4050e+02 2.0773e-05 2.0773e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5460e+00 1.2300e+07 5.8315e+02 2.7722e+03 7.7192e-08 0.0000e+00 1.0000e+00 2.7722e+03 2.7722e+03 1.4160e+02 1.4160e+02 2.0855e-05 2.0855e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5480e+00 1.2400e+07 5.8315e+02 2.7935e+03 7.6362e-08 0.0000e+00 1.0000e+00 2.7935e+03 2.7935e+03 1.4269e+02 1.4269e+02 2.0938e-05 2.0938e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5500e+00 1.2500e+07 5.8315e+02 2.8148e+03 7.5543e-08 0.0000e+00 1.0000e+00 2.8148e+03 2.8148e+03 1.4377e+02 1.4377e+02 2.1020e-05 2.1020e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5520e+00 1.2600e+07 5.8315e+02 2.8361e+03 7.4737e-08 0.0000e+00 1.0000e+00 2.8361e+03 2.8361e+03 1.4486e+02 1.4486e+02 2.1104e-05 2.1104e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5540e+00 1.2700e+07 5.8315e+02 2.8572e+03 7.3942e-08 0.0000e+00 1.0000e+00 2.8572e+03 2.8572e+03 1.4594e+02 1.4594e+02 2.1187e-05 2.1187e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5560e+00 1.2800e+07 5.8315e+02 2.8783e+03 7.3158e-08 0.0000e+00 1.0000e+00 2.8783e+03 2.8783e+03 1.4702e+02 1.4702e+02 2.1271e-05 2.1271e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5580e+00 1.2900e+07 5.8315e+02 2.8993e+03 7.2386e-08 0.0000e+00 1.0000e+00 2.8993e+03 2.8993e+03 1.4809e+02 1.4809e+02 2.1355e-05 2.1355e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5600e+00 1.3000e+07 5.8315e+02 2.9203e+03 7.1624e-08 0.0000e+00 1.0000e+00 2.9203e+03 2.9203e+03 1.4916e+02 1.4916e+02 2.1439e-05 2.1439e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5620e+00 1.3100e+07 5.8315e+02 2.9412e+03 7.0873e-08 0.0000e+00 1.0000e+00 2.9412e+03 2.9412e+03 1.5023e+02 1.5023e+02 2.1523e-05 2.1523e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5640e+00 1.3200e+07 5.8315e+02 2.9620e+03 7.0133e-08 0.0000e+00 1.0000e+00 2.9620e+03 2.9620e+03 1.5129e+02 1.5129e+02 2.1608e-05 2.1608e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5660e+00 1.3300e+07 5.8315e+02 2.9827e+03 6.9403e-08 0.0000e+00 1.0000e+00 2.9827e+03 2.9827e+03 1.5235e+02 1.5235e+02 2.1693e-05 2.1693e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5680e+00 1.3400e+07 5.8315e+02 3.0034e+03 6.8684e-08 0.0000e+00 1.0000e+00 3.0034e+03 3.0034e+03 1.5341e+02 1.5341e+02 2.1779e-05 2.1779e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5700e+00 1.3500e+07 5.8315e+02 3.0240e+03 6.7974e-08 0.0000e+00 1.0000e+00 3.0240e+03 3.0240e+03 1.5446e+02 1.5446e+02 2.1864e-05 2.1864e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5720e+00 1.3600e+07 5.8315e+02 3.0445e+03 6.7275e-08 0.0000e+00 1.0000e+00 3.0445e+03 3.0445e+03 1.5551e+02 1.5551e+02 2.1950e-05 2.1950e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5740e+00 1.3700e+07 5.8315e+02 3.0649e+03 6.6585e-08 0.0000e+00 1.0000e+00 3.0649e+03 3.0649e+03 1.5655e+02 1.5655e+02 2.2036e-05 2.2036e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5760e+00 1.3800e+07 5.8315e+02 3.0853e+03 6.5904e-08 0.0000e+00 1.0000e+00 3.0853e+03 3.0853e+03 1.5759e+02 1.5759e+02 2.2122e-05 2.2122e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5780e+00 1.3900e+07 5.8315e+02 3.1056e+03 6.5233e-08 0.0000e+00 1.0000e+00 3.1056e+03 3.1056e+03 1.5863e+02 1.5863e+02 2.2208e-05 2.2208e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5800e+00 1.4000e+07 5.8315e+02 3.1258e+03 6.4571e-08 0.0000e+00 1.0000e+00 3.1258e+03 3.1258e+03 1.5966e+02 1.5966e+02 2.2295e-05 2.2295e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5820e+00 1.4100e+07 5.8315e+02 3.1460e+03 6.3919e-08 0.0000e+00 1.0000e+00 3.1460e+03 3.1460e+03 1.6069e+02 1.6069e+02 2.2382e-05 2.2382e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5840e+00 1.4200e+07 5.8315e+02 3.1661e+03 6.3275e-08 0.0000e+00 1.0000e+00 3.1661e+03 3.1661e+03 1.6171e+02 1.6171e+02 2.2469e-05 2.2469e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5860e+00 1.4300e+07 5.8315e+02 3.1860e+03 6.2639e-08 0.0000e+00 1.0000e+00 3.1860e+03 3.1860e+03 1.6273e+02 1.6273e+02 2.2556e-05 2.2556e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5880e+00 1.4400e+07 5.8315e+02 3.2060e+03 6.2013e-08 0.0000e+00 1.0000e+00 3.2060e+03 3.2060e+03 1.6375e+02 1.6375e+02 2.2643e-05 2.2643e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5900e+00 1.4500e+07 5.8315e+02 3.2258e+03 6.1395e-08 0.0000e+00 1.0000e+00 3.2258e+03 3.2258e+03 1.6477e+02 1.6477e+02 2.2731e-05 2.2731e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5920e+00 1.4600e+07 5.8315e+02 3.2456e+03 6.0785e-08 0.0000e+00 1.0000e+00 3.2456e+03 3.2456e+03 1.6578e+02 1.6578e+02 2.2818e-05 2.2818e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5940e+00 1.4700e+07 5.8315e+02 3.2653e+03 6.0184e-08 0.0000e+00 1.0000e+00 3.2653e+03 3.2653e+03 1.6678e+02 1.6678e+02 2.2906e-05 2.2906e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5960e+00 1.4800e+07 5.8315e+02 3.2849e+03 5.9590e-08 0.0000e+00 1.0000e+00 3.2849e+03 3.2849e+03 1.6778e+02 1.6778e+02 2.2994e-05 2.2994e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.5980e+00 1.4900e+07 5.8315e+02 3.3044e+03 5.9005e-08 0.0000e+00 1.0000e+00 3.3044e+03 3.3044e+03 1.6878e+02 1.6878e+02 2.3082e-05 2.3082e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6000e+00 1.5000e+07 5.8315e+02 3.3239e+03 5.8427e-08 0.0000e+00 1.0000e+00 3.3239e+03 3.3239e+03 1.6977e+02 1.6977e+02 2.3170e-05 2.3170e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6020e+00 1.5100e+07 5.8315e+02 3.3433e+03 5.7857e-08 0.0000e+00 1.0000e+00 3.3433e+03 3.3433e+03 1.7076e+02 1.7076e+02 2.3258e-05 2.3258e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6040e+00 1.5200e+07 5.8315e+02 3.3626e+03 5.7295e-08 0.0000e+00 1.0000e+00 3.3626e+03 3.3626e+03 1.7175e+02 1.7175e+02 2.3346e-05 2.3346e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6060e+00 1.5300e+07 5.8315e+02 3.3818e+03 5.6740e-08 0.0000e+00 1.0000e+00 3.3818e+03 3.3818e+03 1.7273e+02 1.7273e+02 2.3435e-05 2.3435e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6080e+00 1.5400e+07 5.8315e+02 3.4009e+03 5.6192e-08 0.0000e+00 1.0000e+00 3.4009e+03 3.4009e+03 1.7371e+02 1.7371e+02 2.3523e-05 2.3523e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6100e+00 1.5500e+07 5.8315e+02 3.4200e+03 5.5652e-08 0.0000e+00 1.0000e+00 3.4200e+03 3.4200e+03 1.7468e+02 1.7468e+02 2.3612e-05 2.3612e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6120e+00 1.5600e+07 5.8315e+02 3.4390e+03 5.5119e-08 0.0000e+00 1.0000e+00 3.4390e+03 3.4390e+03 1.7566e+02 1.7566e+02 2.3700e-05 2.3700e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6140e+00 1.5700e+07 5.8315e+02 3.4579e+03 5.4593e-08 0.0000e+00 1.0000e+00 3.4579e+03 3.4579e+03 1.7662e+02 1.7662e+02 2.3789e-05 2.3789e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6160e+00 1.5800e+07 5.8315e+02 3.4768e+03 5.4073e-08 0.0000e+00 1.0000e+00 3.4768e+03 3.4768e+03 1.7758e+02 1.7758e+02 2.3878e-05 2.3878e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6180e+00 1.5900e+07 5.8315e+02 3.4955e+03 5.3561e-08 0.0000e+00 1.0000e+00 3.4955e+03 3.4955e+03 1.7854e+02 1.7854e+02 2.3967e-05 2.3967e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6200e+00 1.6000e+07 5.8315e+02 3.5142e+03 5.3055e-08 0.0000e+00 1.0000e+00 3.5142e+03 3.5142e+03 1.7950e+02 1.7950e+02 2.4056e-05 2.4056e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6220e+00 1.6100e+07 5.8315e+02 3.5328e+03 5.2556e-08 0.0000e+00 1.0000e+00 3.5328e+03 3.5328e+03 1.8045e+02 1.8045e+02 2.4145e-05 2.4145e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6240e+00 1.6200e+07 5.8315e+02 3.5513e+03 5.2063e-08 0.0000e+00 1.0000e+00 3.5513e+03 3.5513e+03 1.8139e+02 1.8139e+02 2.4234e-05 2.4234e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6260e+00 1.6300e+07 5.8315e+02 3.5698e+03 5.1577e-08 0.0000e+00 1.0000e+00 3.5698e+03 3.5698e+03 1.8234e+02 1.8234e+02 2.4323e-05 2.4323e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6280e+00 1.6400e+07 5.8315e+02 3.5882e+03 5.1097e-08 0.0000e+00 1.0000e+00 3.5882e+03 3.5882e+03 1.8327e+02 1.8327e+02 2.4412e-05 2.4412e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6300e+00 1.6500e+07 5.8315e+02 3.6065e+03 5.0623e-08 0.0000e+00 1.0000e+00 3.6065e+03 3.6065e+03 1.8421e+02 1.8421e+02 2.4501e-05 2.4501e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6320e+00 1.6600e+07 5.8315e+02 3.6247e+03 5.0155e-08 0.0000e+00 1.0000e+00 3.6247e+03 3.6247e+03 1.8514e+02 1.8514e+02 2.4590e-05 2.4590e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6340e+00 1.6700e+07 5.8315e+02 3.6428e+03 4.9693e-08 0.0000e+00 1.0000e+00 3.6428e+03 3.6428e+03 1.8607e+02 1.8607e+02 2.4679e-05 2.4679e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6360e+00 1.6800e+07 5.8315e+02 3.6609e+03 4.9237e-08 0.0000e+00 1.0000e+00 3.6609e+03 3.6609e+03 1.8699e+02 1.8699e+02 2.4768e-05 2.4768e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6380e+00 1.6900e+07 5.8315e+02 3.6789e+03 4.8787e-08 0.0000e+00 1.0000e+00 3.6789e+03 3.6789e+03 1.8791e+02 1.8791e+02 2.4858e-05 2.4858e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6400e+00 1.7000e+07 5.8315e+02 3.6968e+03 4.8343e-08 0.0000e+00 1.0000e+00 3.6968e+03 3.6968e+03 1.8882e+02 1.8882e+02 2.4947e-05 2.4947e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6420e+00 1.7100e+07 5.8315e+02 3.7146e+03 4.7905e-08 0.0000e+00 1.0000e+00 3.7146e+03 3.7146e+03 1.8973e+02 1.8973e+02 2.5036e-05 2.5036e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6440e+00 1.7200e+07 5.8315e+02 3.7324e+03 4.7472e-08 0.0000e+00 1.0000e+00 3.7324e+03 3.7324e+03 1.9064e+02 1.9064e+02 2.5125e-05 2.5125e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6460e+00 1.7300e+07 5.8315e+02 3.7500e+03 4.7044e-08 0.0000e+00 1.0000e+00 3.7500e+03 3.7500e+03 1.9154e+02 1.9154e+02 2.5214e-05 2.5214e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6480e+00 1.7400e+07 5.8315e+02 3.7676e+03 4.6622e-08 0.0000e+00 1.0000e+00 3.7676e+03 3.7676e+03 1.9244e+02 1.9244e+02 2.5303e-05 2.5303e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6500e+00 1.7500e+07 5.8315e+02 3.7852e+03 4.6205e-08 0.0000e+00 1.0000e+00 3.7852e+03 3.7852e+03 1.9334e+02 1.9334e+02 2.5392e-05 2.5392e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6520e+00 1.7600e+07 5.8315e+02 3.8026e+03 4.5794e-08 0.0000e+00 1.0000e+00 3.8026e+03 3.8026e+03 1.9423e+02 1.9423e+02 2.5481e-05 2.5481e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6540e+00 1.7700e+07 5.8315e+02 3.8200e+03 4.5387e-08 0.0000e+00 1.0000e+00 3.8200e+03 3.8200e+03 1.9512e+02 1.9512e+02 2.5570e-05 2.5570e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6560e+00 1.7800e+07 5.8315e+02 3.8373e+03 4.4986e-08 0.0000e+00 1.0000e+00 3.8373e+03 3.8373e+03 1.9600e+02 1.9600e+02 2.5659e-05 2.5659e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6580e+00 1.7900e+07 5.8315e+02 3.8545e+03 4.4590e-08 0.0000e+00 1.0000e+00 3.8545e+03 3.8545e+03 1.9688e+02 1.9688e+02 2.5748e-05 2.5748e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6600e+00 1.8000e+07 5.8315e+02 3.8717e+03 4.4199e-08 0.0000e+00 1.0000e+00 3.8717e+03 3.8717e+03 1.9776e+02 1.9776e+02 2.5837e-05 2.5837e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6620e+00 1.8100e+07 5.8315e+02 3.8888e+03 4.3812e-08 0.0000e+00 1.0000e+00 3.8888e+03 3.8888e+03 1.9863e+02 1.9863e+02 2.5926e-05 2.5926e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6640e+00 1.8200e+07 5.8315e+02 3.9058e+03 4.3431e-08 0.0000e+00 1.0000e+00 3.9058e+03 3.9058e+03 1.9950e+02 1.9950e+02 2.6015e-05 2.6015e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6660e+00 1.8300e+07 5.8315e+02 3.9227e+03 4.3054e-08 0.0000e+00 1.0000e+00 3.9227e+03 3.9227e+03 2.0036e+02 2.0036e+02 2.6104e-05 2.6104e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6680e+00 1.8400e+07 5.8315e+02 3.9395e+03 4.2682e-08 0.0000e+00 1.0000e+00 3.9395e+03 3.9395e+03 2.0122e+02 2.0122e+02 2.6192e-05 2.6192e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6700e+00 1.8500e+07 5.8315e+02 3.9563e+03 4.2314e-08 0.0000e+00 1.0000e+00 3.9563e+03 3.9563e+03 2.0208e+02 2.0208e+02 2.6281e-05 2.6281e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6720e+00 1.8600e+07 5.8315e+02 3.9730e+03 4.1951e-08 0.0000e+00 1.0000e+00 3.9730e+03 3.9730e+03 2.0293e+02 2.0293e+02 2.6369e-05 2.6369e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6740e+00 1.8700e+07 5.8315e+02 3.9896e+03 4.1593e-08 0.0000e+00 1.0000e+00 3.9896e+03 3.9896e+03 2.0378e+02 2.0378e+02 2.6458e-05 2.6458e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6760e+00 1.8800e+07 5.8315e+02 4.0062e+03 4.1239e-08 0.0000e+00 1.0000e+00 4.0062e+03 4.0062e+03 2.0463e+02 2.0463e+02 2.6546e-05 2.6546e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6780e+00 1.8900e+07 5.8315e+02 4.0227e+03 4.0889e-08 0.0000e+00 1.0000e+00 4.0227e+03 4.0227e+03 2.0547e+02 2.0547e+02 2.6634e-05 2.6634e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6800e+00 1.9000e+07 5.8315e+02 4.0391e+03 4.0543e-08 0.0000e+00 1.0000e+00 4.0391e+03 4.0391e+03 2.0631e+02 2.0631e+02 2.6722e-05 2.6722e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6820e+00 1.9100e+07 5.8315e+02 4.0554e+03 4.0202e-08 0.0000e+00 1.0000e+00 4.0554e+03 4.0554e+03 2.0714e+02 2.0714e+02 2.6811e-05 2.6811e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6840e+00 1.9200e+07 5.8315e+02 4.0717e+03 3.9865e-08 0.0000e+00 1.0000e+00 4.0717e+03 4.0717e+03 2.0797e+02 2.0797e+02 2.6899e-05 2.6899e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6860e+00 1.9300e+07 5.8315e+02 4.0879e+03 3.9532e-08 0.0000e+00 1.0000e+00 4.0879e+03 4.0879e+03 2.0880e+02 2.0880e+02 2.6986e-05 2.6986e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6880e+00 1.9400e+07 5.8315e+02 4.1040e+03 3.9203e-08 0.0000e+00 1.0000e+00 4.1040e+03 4.1040e+03 2.0962e+02 2.0962e+02 2.7074e-05 2.7074e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6900e+00 1.9500e+07 5.8315e+02 4.1201e+03 3.8878e-08 0.0000e+00 1.0000e+00 4.1201e+03 4.1201e+03 2.1044e+02 2.1044e+02 2.7162e-05 2.7162e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6920e+00 1.9600e+07 5.8315e+02 4.1361e+03 3.8556e-08 0.0000e+00 1.0000e+00 4.1361e+03 4.1361e+03 2.1126e+02 2.1126e+02 2.7250e-05 2.7250e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6940e+00 1.9700e+07 5.8315e+02 4.1520e+03 3.8239e-08 0.0000e+00 1.0000e+00 4.1520e+03 4.1520e+03 2.1207e+02 2.1207e+02 2.7337e-05 2.7337e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6960e+00 1.9800e+07 5.8315e+02 4.1678e+03 3.7926e-08 0.0000e+00 1.0000e+00 4.1678e+03 4.1678e+03 2.1288e+02 2.1288e+02 2.7425e-05 2.7425e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.6980e+00 1.9900e+07 5.8315e+02 4.1836e+03 3.7616e-08 0.0000e+00 1.0000e+00 4.1836e+03 4.1836e+03 2.1369e+02 2.1369e+02 2.7512e-05 2.7512e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7000e+00 2.0000e+07 5.8315e+02 4.1993e+03 3.7310e-08 0.0000e+00 1.0000e+00 4.1993e+03 4.1993e+03 2.1449e+02 2.1449e+02 2.7599e-05 2.7599e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7020e+00 2.0100e+07 5.8315e+02 4.2149e+03 3.7007e-08 0.0000e+00 1.0000e+00 4.2149e+03 4.2149e+03 2.1529e+02 2.1529e+02 2.7686e-05 2.7686e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7040e+00 2.0200e+07 5.8315e+02 4.2305e+03 3.6709e-08 0.0000e+00 1.0000e+00 4.2305e+03 4.2305e+03 2.1608e+02 2.1608e+02 2.7773e-05 2.7773e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7060e+00 2.0300e+07 5.8315e+02 4.2460e+03 3.6413e-08 0.0000e+00 1.0000e+00 4.2460e+03 4.2460e+03 2.1687e+02 2.1687e+02 2.7860e-05 2.7860e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7080e+00 2.0400e+07 5.8315e+02 4.2614e+03 3.6121e-08 0.0000e+00 1.0000e+00 4.2614e+03 4.2614e+03 2.1766e+02 2.1766e+02 2.7946e-05 2.7946e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7100e+00 2.0500e+07 5.8315e+02 4.2768e+03 3.5833e-08 0.0000e+00 1.0000e+00 4.2768e+03 4.2768e+03 2.1845e+02 2.1845e+02 2.8033e-05 2.8033e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7120e+00 2.0600e+07 5.8315e+02 4.2921e+03 3.5548e-08 0.0000e+00 1.0000e+00 4.2921e+03 4.2921e+03 2.1923e+02 2.1923e+02 2.8119e-05 2.8119e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7140e+00 2.0700e+07 5.8315e+02 4.3073e+03 3.5267e-08 0.0000e+00 1.0000e+00 4.3073e+03 4.3073e+03 2.2000e+02 2.2000e+02 2.8206e-05 2.8206e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7160e+00 2.0800e+07 5.8315e+02 4.3224e+03 3.4988e-08 0.0000e+00 1.0000e+00 4.3224e+03 4.3224e+03 2.2078e+02 2.2078e+02 2.8292e-05 2.8292e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7180e+00 2.0900e+07 5.8315e+02 4.3375e+03 3.4713e-08 0.0000e+00 1.0000e+00 4.3375e+03 4.3375e+03 2.2155e+02 2.2155e+02 2.8378e-05 2.8378e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7200e+00 2.1000e+07 5.8315e+02 4.3526e+03 3.4441e-08 0.0000e+00 1.0000e+00 4.3526e+03 4.3526e+03 2.2232e+02 2.2232e+02 2.8464e-05 2.8464e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7220e+00 2.1100e+07 5.8315e+02 4.3675e+03 3.4172e-08 0.0000e+00 1.0000e+00 4.3675e+03 4.3675e+03 2.2308e+02 2.2308e+02 2.8550e-05 2.8550e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7240e+00 2.1200e+07 5.8315e+02 4.3824e+03 3.3907e-08 0.0000e+00 1.0000e+00 4.3824e+03 4.3824e+03 2.2384e+02 2.2384e+02 2.8635e-05 2.8635e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7260e+00 2.1300e+07 5.8315e+02 4.3972e+03 3.3644e-08 0.0000e+00 1.0000e+00 4.3972e+03 4.3972e+03 2.2460e+02 2.2460e+02 2.8721e-05 2.8721e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7280e+00 2.1400e+07 5.8315e+02 4.4120e+03 3.3385e-08 0.0000e+00 1.0000e+00 4.4120e+03 4.4120e+03 2.2535e+02 2.2535e+02 2.8806e-05 2.8806e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7300e+00 2.1500e+07 5.8315e+02 4.4267e+03 3.3128e-08 0.0000e+00 1.0000e+00 4.4267e+03 4.4267e+03 2.2610e+02 2.2610e+02 2.8891e-05 2.8891e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7320e+00 2.1600e+07 5.8315e+02 4.4413e+03 3.2875e-08 0.0000e+00 1.0000e+00 4.4413e+03 4.4413e+03 2.2685e+02 2.2685e+02 2.8976e-05 2.8976e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7340e+00 2.1700e+07 5.8315e+02 4.4559e+03 3.2624e-08 0.0000e+00 1.0000e+00 4.4559e+03 4.4559e+03 2.2759e+02 2.2759e+02 2.9061e-05 2.9061e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7360e+00 2.1800e+07 5.8315e+02 4.4704e+03 3.2376e-08 0.0000e+00 1.0000e+00 4.4704e+03 4.4704e+03 2.2834e+02 2.2834e+02 2.9146e-05 2.9146e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7380e+00 2.1900e+07 5.8315e+02 4.4848e+03 3.2131e-08 0.0000e+00 1.0000e+00 4.4848e+03 4.4848e+03 2.2907e+02 2.2907e+02 2.9231e-05 2.9231e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7400e+00 2.2000e+07 5.8315e+02 4.4992e+03 3.1889e-08 0.0000e+00 1.0000e+00 4.4992e+03 4.4992e+03 2.2981e+02 2.2981e+02 2.9315e-05 2.9315e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7420e+00 2.2100e+07 5.8315e+02 4.5135e+03 3.1649e-08 0.0000e+00 1.0000e+00 4.5135e+03 4.5135e+03 2.3054e+02 2.3054e+02 2.9399e-05 2.9399e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7440e+00 2.2200e+07 5.8315e+02 4.5278e+03 3.1413e-08 0.0000e+00 1.0000e+00 4.5278e+03 4.5278e+03 2.3127e+02 2.3127e+02 2.9484e-05 2.9484e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7460e+00 2.2300e+07 5.8315e+02 4.5420e+03 3.1178e-08 0.0000e+00 1.0000e+00 4.5420e+03 4.5420e+03 2.3199e+02 2.3199e+02 2.9568e-05 2.9568e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7480e+00 2.2400e+07 5.8315e+02 4.5561e+03 3.0947e-08 0.0000e+00 1.0000e+00 4.5561e+03 4.5561e+03 2.3271e+02 2.3271e+02 2.9651e-05 2.9651e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7500e+00 2.2500e+07 5.8315e+02 4.5702e+03 3.0718e-08 0.0000e+00 1.0000e+00 4.5702e+03 4.5702e+03 2.3343e+02 2.3343e+02 2.9735e-05 2.9735e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7520e+00 2.2600e+07 5.8315e+02 4.5842e+03 3.0492e-08 0.0000e+00 1.0000e+00 4.5842e+03 4.5842e+03 2.3415e+02 2.3415e+02 2.9819e-05 2.9819e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7540e+00 2.2700e+07 5.8315e+02 4.5981e+03 3.0268e-08 0.0000e+00 1.0000e+00 4.5981e+03 4.5981e+03 2.3486e+02 2.3486e+02 2.9902e-05 2.9902e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7560e+00 2.2800e+07 5.8315e+02 4.6120e+03 3.0046e-08 0.0000e+00 1.0000e+00 4.6120e+03 4.6120e+03 2.3557e+02 2.3557e+02 2.9985e-05 2.9985e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7580e+00 2.2900e+07 5.8315e+02 4.6258e+03 2.9827e-08 0.0000e+00 1.0000e+00 4.6258e+03 4.6258e+03 2.3628e+02 2.3628e+02 3.0068e-05 3.0068e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7600e+00 2.3000e+07 5.8315e+02 4.6396e+03 2.9611e-08 0.0000e+00 1.0000e+00 4.6396e+03 4.6396e+03 2.3698e+02 2.3698e+02 3.0151e-05 3.0151e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7620e+00 2.3100e+07 5.8315e+02 4.6533e+03 2.9397e-08 0.0000e+00 1.0000e+00 4.6533e+03 4.6533e+03 2.3768e+02 2.3768e+02 3.0234e-05 3.0234e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7640e+00 2.3200e+07 5.8315e+02 4.6670e+03 2.9185e-08 0.0000e+00 1.0000e+00 4.6670e+03 4.6670e+03 2.3838e+02 2.3838e+02 3.0317e-05 3.0317e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7660e+00 2.3300e+07 5.8315e+02 4.6806e+03 2.8976e-08 0.0000e+00 1.0000e+00 4.6806e+03 4.6806e+03 2.3907e+02 2.3907e+02 3.0399e-05 3.0399e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7680e+00 2.3400e+07 5.8315e+02 4.6941e+03 2.8768e-08 0.0000e+00 1.0000e+00 4.6941e+03 4.6941e+03 2.3976e+02 2.3976e+02 3.0481e-05 3.0481e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7700e+00 2.3500e+07 5.8315e+02 4.7076e+03 2.8563e-08 0.0000e+00 1.0000e+00 4.7076e+03 4.7076e+03 2.4045e+02 2.4045e+02 3.0563e-05 3.0563e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7720e+00 2.3600e+07 5.8315e+02 4.7210e+03 2.8361e-08 0.0000e+00 1.0000e+00 4.7210e+03 4.7210e+03 2.4114e+02 2.4114e+02 3.0645e-05 3.0645e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7740e+00 2.3700e+07 5.8315e+02 4.7344e+03 2.8160e-08 0.0000e+00 1.0000e+00 4.7344e+03 4.7344e+03 2.4182e+02 2.4182e+02 3.0727e-05 3.0727e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7760e+00 2.3800e+07 5.8315e+02 4.7477e+03 2.7962e-08 0.0000e+00 1.0000e+00 4.7477e+03 4.7477e+03 2.4250e+02 2.4250e+02 3.0809e-05 3.0809e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7780e+00 2.3900e+07 5.8315e+02 4.7609e+03 2.7766e-08 0.0000e+00 1.0000e+00 4.7609e+03 4.7609e+03 2.4317e+02 2.4317e+02 3.0890e-05 3.0890e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7800e+00 2.4000e+07 5.8315e+02 4.7741e+03 2.7572e-08 0.0000e+00 1.0000e+00 4.7741e+03 4.7741e+03 2.4385e+02 2.4385e+02 3.0971e-05 3.0971e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7820e+00 2.4100e+07 5.8315e+02 4.7872e+03 2.7380e-08 0.0000e+00 1.0000e+00 4.7872e+03 4.7872e+03 2.4452e+02 2.4452e+02 3.1052e-05 3.1052e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7840e+00 2.4200e+07 5.8315e+02 4.8003e+03 2.7190e-08 0.0000e+00 1.0000e+00 4.8003e+03 4.8003e+03 2.4519e+02 2.4519e+02 3.1133e-05 3.1133e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7860e+00 2.4300e+07 5.8315e+02 4.8133e+03 2.7002e-08 0.0000e+00 1.0000e+00 4.8133e+03 4.8133e+03 2.4585e+02 2.4585e+02 3.1214e-05 3.1214e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7880e+00 2.4400e+07 5.8315e+02 4.8263e+03 2.6816e-08 0.0000e+00 1.0000e+00 4.8263e+03 4.8263e+03 2.4651e+02 2.4651e+02 3.1294e-05 3.1294e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7900e+00 2.4500e+07 5.8315e+02 4.8392e+03 2.6632e-08 0.0000e+00 1.0000e+00 4.8392e+03 4.8392e+03 2.4717e+02 2.4717e+02 3.1375e-05 3.1375e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7920e+00 2.4600e+07 5.8315e+02 4.8521e+03 2.6450e-08 0.0000e+00 1.0000e+00 4.8521e+03 4.8521e+03 2.4783e+02 2.4783e+02 3.1455e-05 3.1455e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7940e+00 2.4700e+07 5.8315e+02 4.8649e+03 2.6270e-08 0.0000e+00 1.0000e+00 4.8649e+03 4.8649e+03 2.4849e+02 2.4849e+02 3.1535e-05 3.1535e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7960e+00 2.4800e+07 5.8315e+02 4.8776e+03 2.6091e-08 0.0000e+00 1.0000e+00 4.8776e+03 4.8776e+03 2.4914e+02 2.4914e+02 3.1615e-05 3.1615e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.7980e+00 2.4900e+07 5.8315e+02 4.8903e+03 2.5915e-08 0.0000e+00 1.0000e+00 4.8903e+03 4.8903e+03 2.4979e+02 2.4979e+02 3.1695e-05 3.1695e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8000e+00 2.5000e+07 5.8315e+02 4.9030e+03 2.5740e-08 0.0000e+00 1.0000e+00 4.9030e+03 4.9030e+03 2.5043e+02 2.5043e+02 3.1774e-05 3.1774e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8020e+00 2.5100e+07 5.8315e+02 4.9156e+03 2.5568e-08 0.0000e+00 1.0000e+00 4.9156e+03 4.9156e+03 2.5107e+02 2.5107e+02 3.1854e-05 3.1854e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8040e+00 2.5200e+07 5.8315e+02 4.9281e+03 2.5397e-08 0.0000e+00 1.0000e+00 4.9281e+03 4.9281e+03 2.5172e+02 2.5172e+02 3.1933e-05 3.1933e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8060e+00 2.5300e+07 5.8315e+02 4.9406e+03 2.5228e-08 0.0000e+00 1.0000e+00 4.9406e+03 4.9406e+03 2.5235e+02 2.5235e+02 3.2012e-05 3.2012e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8080e+00 2.5400e+07 5.8315e+02 4.9530e+03 2.5060e-08 0.0000e+00 1.0000e+00 4.9530e+03 4.9530e+03 2.5299e+02 2.5299e+02 3.2091e-05 3.2091e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8100e+00 2.5500e+07 5.8315e+02 4.9654e+03 2.4894e-08 0.0000e+00 1.0000e+00 4.9654e+03 4.9654e+03 2.5362e+02 2.5362e+02 3.2170e-05 3.2170e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8120e+00 2.5600e+07 5.8315e+02 4.9778e+03 2.4730e-08 0.0000e+00 1.0000e+00 4.9778e+03 4.9778e+03 2.5425e+02 2.5425e+02 3.2248e-05 3.2248e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8140e+00 2.5700e+07 5.8315e+02 4.9901e+03 2.4568e-08 0.0000e+00 1.0000e+00 4.9901e+03 4.9901e+03 2.5488e+02 2.5488e+02 3.2326e-05 3.2326e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8160e+00 2.5800e+07 5.8315e+02 5.0023e+03 2.4407e-08 0.0000e+00 1.0000e+00 5.0023e+03 5.0023e+03 2.5550e+02 2.5550e+02 3.2405e-05 3.2405e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8180e+00 2.5900e+07 5.8315e+02 5.0145e+03 2.4248e-08 0.0000e+00 1.0000e+00 5.0145e+03 5.0145e+03 2.5613e+02 2.5613e+02 3.2483e-05 3.2483e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8200e+00 2.6000e+07 5.8315e+02 5.0266e+03 2.4091e-08 0.0000e+00 1.0000e+00 5.0266e+03 5.0266e+03 2.5675e+02 2.5675e+02 3.2560e-05 3.2560e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8220e+00 2.6100e+07 5.8315e+02 5.0387e+03 2.3935e-08 0.0000e+00 1.0000e+00 5.0387e+03 5.0387e+03 2.5736e+02 2.5736e+02 3.2638e-05 3.2638e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8240e+00 2.6200e+07 5.8315e+02 5.0507e+03 2.3781e-08 0.0000e+00 1.0000e+00 5.0507e+03 5.0507e+03 2.5798e+02 2.5798e+02 3.2716e-05 3.2716e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8260e+00 2.6300e+07 5.8315e+02 5.0627e+03 2.3628e-08 0.0000e+00 1.0000e+00 5.0627e+03 5.0627e+03 2.5859e+02 2.5859e+02 3.2793e-05 3.2793e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8280e+00 2.6400e+07 5.8315e+02 5.0747e+03 2.3477e-08 0.0000e+00 1.0000e+00 5.0747e+03 5.0747e+03 2.5920e+02 2.5920e+02 3.2870e-05 3.2870e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8300e+00 2.6500e+07 5.8315e+02 5.0865e+03 2.3327e-08 0.0000e+00 1.0000e+00 5.0865e+03 5.0865e+03 2.5981e+02 2.5981e+02 3.2947e-05 3.2947e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8320e+00 2.6600e+07 5.8315e+02 5.0984e+03 2.3179e-08 0.0000e+00 1.0000e+00 5.0984e+03 5.0984e+03 2.6041e+02 2.6041e+02 3.3024e-05 3.3024e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8340e+00 2.6700e+07 5.8315e+02 5.1102e+03 2.3032e-08 0.0000e+00 1.0000e+00 5.1102e+03 5.1102e+03 2.6101e+02 2.6101e+02 3.3101e-05 3.3101e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8360e+00 2.6800e+07 5.8315e+02 5.1219e+03 2.2887e-08 0.0000e+00 1.0000e+00 5.1219e+03 5.1219e+03 2.6161e+02 2.6161e+02 3.3177e-05 3.3177e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8380e+00 2.6900e+07 5.8315e+02 5.1336e+03 2.2743e-08 0.0000e+00 1.0000e+00 5.1336e+03 5.1336e+03 2.6221e+02 2.6221e+02 3.3253e-05 3.3253e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8400e+00 2.7000e+07 5.8315e+02 5.1453e+03 2.2601e-08 0.0000e+00 1.0000e+00 5.1453e+03 5.1453e+03 2.6281e+02 2.6281e+02 3.3330e-05 3.3330e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8420e+00 2.7100e+07 5.8315e+02 5.1569e+03 2.2460e-08 0.0000e+00 1.0000e+00 5.1569e+03 5.1569e+03 2.6340e+02 2.6340e+02 3.3406e-05 3.3406e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8440e+00 2.7200e+07 5.8315e+02 5.1684e+03 2.2320e-08 0.0000e+00 1.0000e+00 5.1684e+03 5.1684e+03 2.6399e+02 2.6399e+02 3.3481e-05 3.3481e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8460e+00 2.7300e+07 5.8315e+02 5.1800e+03 2.2182e-08 0.0000e+00 1.0000e+00 5.1800e+03 5.1800e+03 2.6458e+02 2.6458e+02 3.3557e-05 3.3557e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8480e+00 2.7400e+07 5.8315e+02 5.1914e+03 2.2045e-08 0.0000e+00 1.0000e+00 5.1914e+03 5.1914e+03 2.6516e+02 2.6516e+02 3.3632e-05 3.3632e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8500e+00 2.7500e+07 5.8315e+02 5.2028e+03 2.1909e-08 0.0000e+00 1.0000e+00 5.2028e+03 5.2028e+03 2.6575e+02 2.6575e+02 3.3708e-05 3.3708e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8520e+00 2.7600e+07 5.8315e+02 5.2142e+03 2.1775e-08 0.0000e+00 1.0000e+00 5.2142e+03 5.2142e+03 2.6633e+02 2.6633e+02 3.3783e-05 3.3783e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8540e+00 2.7700e+07 5.8315e+02 5.2256e+03 2.1642e-08 0.0000e+00 1.0000e+00 5.2256e+03 5.2256e+03 2.6691e+02 2.6691e+02 3.3858e-05 3.3858e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8560e+00 2.7800e+07 5.8315e+02 5.2368e+03 2.1510e-08 0.0000e+00 1.0000e+00 5.2368e+03 5.2368e+03 2.6748e+02 2.6748e+02 3.3933e-05 3.3933e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8580e+00 2.7900e+07 5.8315e+02 5.2481e+03 2.1380e-08 0.0000e+00 1.0000e+00 5.2481e+03 5.2481e+03 2.6806e+02 2.6806e+02 3.4007e-05 3.4007e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8600e+00 2.8000e+07 5.8315e+02 5.2593e+03 2.1251e-08 0.0000e+00 1.0000e+00 5.2593e+03 5.2593e+03 2.6863e+02 2.6863e+02 3.4082e-05 3.4082e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8620e+00 2.8100e+07 5.8315e+02 5.2704e+03 2.1123e-08 0.0000e+00 1.0000e+00 5.2704e+03 5.2704e+03 2.6920e+02 2.6920e+02 3.4156e-05 3.4156e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8640e+00 2.8200e+07 5.8315e+02 5.2815e+03 2.0996e-08 0.0000e+00 1.0000e+00 5.2815e+03 5.2815e+03 2.6977e+02 2.6977e+02 3.4230e-05 3.4230e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8660e+00 2.8300e+07 5.8315e+02 5.2926e+03 2.0870e-08 0.0000e+00 1.0000e+00 5.2926e+03 5.2926e+03 2.7033e+02 2.7033e+02 3.4304e-05 3.4304e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8680e+00 2.8400e+07 5.8315e+02 5.3036e+03 2.0746e-08 0.0000e+00 1.0000e+00 5.3036e+03 5.3036e+03 2.7090e+02 2.7090e+02 3.4378e-05 3.4378e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8700e+00 2.8500e+07 5.8315e+02 5.3146e+03 2.0623e-08 0.0000e+00 1.0000e+00 5.3146e+03 5.3146e+03 2.7146e+02 2.7146e+02 3.4452e-05 3.4452e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8720e+00 2.8600e+07 5.8315e+02 5.3256e+03 2.0501e-08 0.0000e+00 1.0000e+00 5.3256e+03 5.3256e+03 2.7202e+02 2.7202e+02 3.4525e-05 3.4525e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8740e+00 2.8700e+07 5.8315e+02 5.3365e+03 2.0380e-08 0.0000e+00 1.0000e+00 5.3365e+03 5.3365e+03 2.7257e+02 2.7257e+02 3.4599e-05 3.4599e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8760e+00 2.8800e+07 5.8315e+02 5.3473e+03 2.0260e-08 0.0000e+00 1.0000e+00 5.3473e+03 5.3473e+03 2.7313e+02 2.7313e+02 3.4672e-05 3.4672e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8780e+00 2.8900e+07 5.8315e+02 5.3581e+03 2.0141e-08 0.0000e+00 1.0000e+00 5.3581e+03 5.3581e+03 2.7368e+02 2.7368e+02 3.4745e-05 3.4745e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8800e+00 2.9000e+07 5.8315e+02 5.3689e+03 2.0024e-08 0.0000e+00 1.0000e+00 5.3689e+03 5.3689e+03 2.7423e+02 2.7423e+02 3.4818e-05 3.4818e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8820e+00 2.9100e+07 5.8315e+02 5.3796e+03 1.9907e-08 0.0000e+00 1.0000e+00 5.3796e+03 5.3796e+03 2.7478e+02 2.7478e+02 3.4890e-05 3.4890e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8840e+00 2.9200e+07 5.8315e+02 5.3903e+03 1.9792e-08 0.0000e+00 1.0000e+00 5.3903e+03 5.3903e+03 2.7532e+02 2.7532e+02 3.4963e-05 3.4963e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8860e+00 2.9300e+07 5.8315e+02 5.4010e+03 1.9678e-08 0.0000e+00 1.0000e+00 5.4010e+03 5.4010e+03 2.7587e+02 2.7587e+02 3.5035e-05 3.5035e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8880e+00 2.9400e+07 5.8315e+02 5.4116e+03 1.9564e-08 0.0000e+00 1.0000e+00 5.4116e+03 5.4116e+03 2.7641e+02 2.7641e+02 3.5107e-05 3.5107e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8900e+00 2.9500e+07 5.8315e+02 5.4221e+03 1.9452e-08 0.0000e+00 1.0000e+00 5.4221e+03 5.4221e+03 2.7695e+02 2.7695e+02 3.5179e-05 3.5179e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8920e+00 2.9600e+07 5.8315e+02 5.4327e+03 1.9341e-08 0.0000e+00 1.0000e+00 5.4327e+03 5.4327e+03 2.7749e+02 2.7749e+02 3.5251e-05 3.5251e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8940e+00 2.9700e+07 5.8315e+02 5.4431e+03 1.9231e-08 0.0000e+00 1.0000e+00 5.4431e+03 5.4431e+03 2.7802e+02 2.7802e+02 3.5323e-05 3.5323e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8960e+00 2.9800e+07 5.8315e+02 5.4536e+03 1.9121e-08 0.0000e+00 1.0000e+00 5.4536e+03 5.4536e+03 2.7856e+02 2.7856e+02 3.5394e-05 3.5394e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.8980e+00 2.9900e+07 5.8315e+02 5.4640e+03 1.9013e-08 0.0000e+00 1.0000e+00 5.4640e+03 5.4640e+03 2.7909e+02 2.7909e+02 3.5466e-05 3.5466e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9000e+00 3.0000e+07 5.8315e+02 5.4744e+03 1.8906e-08 0.0000e+00 1.0000e+00 5.4744e+03 5.4744e+03 2.7962e+02 2.7962e+02 3.5537e-05 3.5537e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9020e+00 3.0100e+07 5.8315e+02 5.4847e+03 1.8800e-08 0.0000e+00 1.0000e+00 5.4847e+03 5.4847e+03 2.8014e+02 2.8014e+02 3.5608e-05 3.5608e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9040e+00 3.0200e+07 5.8315e+02 5.4950e+03 1.8694e-08 0.0000e+00 1.0000e+00 5.4950e+03 5.4950e+03 2.8067e+02 2.8067e+02 3.5679e-05 3.5679e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9060e+00 3.0300e+07 5.8315e+02 5.5053e+03 1.8590e-08 0.0000e+00 1.0000e+00 5.5053e+03 5.5053e+03 2.8119e+02 2.8119e+02 3.5750e-05 3.5750e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9080e+00 3.0400e+07 5.8315e+02 5.5155e+03 1.8486e-08 0.0000e+00 1.0000e+00 5.5155e+03 5.5155e+03 2.8172e+02 2.8172e+02 3.5821e-05 3.5821e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9100e+00 3.0500e+07 5.8315e+02 5.5256e+03 1.8384e-08 0.0000e+00 1.0000e+00 5.5256e+03 5.5256e+03 2.8224e+02 2.8224e+02 3.5891e-05 3.5891e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9120e+00 3.0600e+07 5.8315e+02 5.5358e+03 1.8282e-08 0.0000e+00 1.0000e+00 5.5358e+03 5.5358e+03 2.8275e+02 2.8275e+02 3.5961e-05 3.5961e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9140e+00 3.0700e+07 5.8315e+02 5.5459e+03 1.8182e-08 0.0000e+00 1.0000e+00 5.5459e+03 5.5459e+03 2.8327e+02 2.8327e+02 3.6032e-05 3.6032e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9160e+00 3.0800e+07 5.8315e+02 5.5559e+03 1.8082e-08 0.0000e+00 1.0000e+00 5.5559e+03 5.5559e+03 2.8378e+02 2.8378e+02 3.6102e-05 3.6102e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9180e+00 3.0900e+07 5.8315e+02 5.5660e+03 1.7983e-08 0.0000e+00 1.0000e+00 5.5660e+03 5.5660e+03 2.8430e+02 2.8430e+02 3.6171e-05 3.6171e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9200e+00 3.1000e+07 5.8315e+02 5.5760e+03 1.7885e-08 0.0000e+00 1.0000e+00 5.5760e+03 5.5760e+03 2.8481e+02 2.8481e+02 3.6241e-05 3.6241e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9220e+00 3.1100e+07 5.8315e+02 5.5859e+03 1.7787e-08 0.0000e+00 1.0000e+00 5.5859e+03 5.5859e+03 2.8531e+02 2.8531e+02 3.6311e-05 3.6311e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9240e+00 3.1200e+07 5.8315e+02 5.5958e+03 1.7691e-08 0.0000e+00 1.0000e+00 5.5958e+03 5.5958e+03 2.8582e+02 2.8582e+02 3.6380e-05 3.6380e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9260e+00 3.1300e+07 5.8315e+02 5.6057e+03 1.7595e-08 0.0000e+00 1.0000e+00 5.6057e+03 5.6057e+03 2.8633e+02 2.8633e+02 3.6449e-05 3.6449e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9280e+00 3.1400e+07 5.8315e+02 5.6156e+03 1.7501e-08 0.0000e+00 1.0000e+00 5.6156e+03 5.6156e+03 2.8683e+02 2.8683e+02 3.6518e-05 3.6518e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9300e+00 3.1500e+07 5.8315e+02 5.6254e+03 1.7407e-08 0.0000e+00 1.0000e+00 5.6254e+03 5.6254e+03 2.8733e+02 2.8733e+02 3.6587e-05 3.6587e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9320e+00 3.1600e+07 5.8315e+02 5.6352e+03 1.7314e-08 0.0000e+00 1.0000e+00 5.6352e+03 5.6352e+03 2.8783e+02 2.8783e+02 3.6656e-05 3.6656e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9340e+00 3.1700e+07 5.8315e+02 5.6449e+03 1.7221e-08 0.0000e+00 1.0000e+00 5.6449e+03 5.6449e+03 2.8833e+02 2.8833e+02 3.6725e-05 3.6725e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9360e+00 3.1800e+07 5.8315e+02 5.6546e+03 1.7130e-08 0.0000e+00 1.0000e+00 5.6546e+03 5.6546e+03 2.8882e+02 2.8882e+02 3.6793e-05 3.6793e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9380e+00 3.1900e+07 5.8315e+02 5.6643e+03 1.7039e-08 0.0000e+00 1.0000e+00 5.6643e+03 5.6643e+03 2.8932e+02 2.8932e+02 3.6862e-05 3.6862e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9400e+00 3.2000e+07 5.8315e+02 5.6739e+03 1.6949e-08 0.0000e+00 1.0000e+00 5.6739e+03 5.6739e+03 2.8981e+02 2.8981e+02 3.6930e-05 3.6930e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9420e+00 3.2100e+07 5.8315e+02 5.6835e+03 1.6860e-08 0.0000e+00 1.0000e+00 5.6835e+03 5.6835e+03 2.9030e+02 2.9030e+02 3.6998e-05 3.6998e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9440e+00 3.2200e+07 5.8315e+02 5.6931e+03 1.6771e-08 0.0000e+00 1.0000e+00 5.6931e+03 5.6931e+03 2.9079e+02 2.9079e+02 3.7066e-05 3.7066e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9460e+00 3.2300e+07 5.8315e+02 5.7026e+03 1.6684e-08 0.0000e+00 1.0000e+00 5.7026e+03 5.7026e+03 2.9127e+02 2.9127e+02 3.7134e-05 3.7134e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9480e+00 3.2400e+07 5.8315e+02 5.7121e+03 1.6597e-08 0.0000e+00 1.0000e+00 5.7121e+03 5.7121e+03 2.9176e+02 2.9176e+02 3.7202e-05 3.7202e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9500e+00 3.2500e+07 5.8315e+02 5.7216e+03 1.6510e-08 0.0000e+00 1.0000e+00 5.7216e+03 5.7216e+03 2.9224e+02 2.9224e+02 3.7269e-05 3.7269e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9520e+00 3.2600e+07 5.8315e+02 5.7310e+03 1.6425e-08 0.0000e+00 1.0000e+00 5.7310e+03 5.7310e+03 2.9272e+02 2.9272e+02 3.7337e-05 3.7337e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9540e+00 3.2700e+07 5.8315e+02 5.7404e+03 1.6340e-08 0.0000e+00 1.0000e+00 5.7404e+03 5.7404e+03 2.9320e+02 2.9320e+02 3.7404e-05 3.7404e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9560e+00 3.2800e+07 5.8315e+02 5.7497e+03 1.6256e-08 0.0000e+00 1.0000e+00 5.7497e+03 5.7497e+03 2.9368e+02 2.9368e+02 3.7471e-05 3.7471e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9580e+00 3.2900e+07 5.8315e+02 5.7591e+03 1.6173e-08 0.0000e+00 1.0000e+00 5.7591e+03 5.7591e+03 2.9416e+02 2.9416e+02 3.7538e-05 3.7538e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9600e+00 3.3000e+07 5.8315e+02 5.7684e+03 1.6090e-08 0.0000e+00 1.0000e+00 5.7684e+03 5.7684e+03 2.9463e+02 2.9463e+02 3.7605e-05 3.7605e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9620e+00 3.3100e+07 5.8315e+02 5.7776e+03 1.6008e-08 0.0000e+00 1.0000e+00 5.7776e+03 5.7776e+03 2.9511e+02 2.9511e+02 3.7671e-05 3.7671e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9640e+00 3.3200e+07 5.8315e+02 5.7869e+03 1.5927e-08 0.0000e+00 1.0000e+00 5.7869e+03 5.7869e+03 2.9558e+02 2.9558e+02 3.7738e-05 3.7738e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9660e+00 3.3300e+07 5.8315e+02 5.7961e+03 1.5846e-08 0.0000e+00 1.0000e+00 5.7961e+03 5.7961e+03 2.9605e+02 2.9605e+02 3.7804e-05 3.7804e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9680e+00 3.3400e+07 5.8315e+02 5.8052e+03 1.5766e-08 0.0000e+00 1.0000e+00 5.8052e+03 5.8052e+03 2.9652e+02 2.9652e+02 3.7871e-05 3.7871e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9700e+00 3.3500e+07 5.8315e+02 5.8144e+03 1.5686e-08 0.0000e+00 1.0000e+00 5.8144e+03 5.8144e+03 2.9698e+02 2.9698e+02 3.7937e-05 3.7937e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9720e+00 3.3600e+07 5.8315e+02 5.8235e+03 1.5608e-08 0.0000e+00 1.0000e+00 5.8235e+03 5.8235e+03 2.9745e+02 2.9745e+02 3.8003e-05 3.8003e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9740e+00 3.3700e+07 5.8315e+02 5.8326e+03 1.5530e-08 0.0000e+00 1.0000e+00 5.8326e+03 5.8326e+03 2.9791e+02 2.9791e+02 3.8069e-05 3.8069e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9760e+00 3.3800e+07 5.8315e+02 5.8416e+03 1.5452e-08 0.0000e+00 1.0000e+00 5.8416e+03 5.8416e+03 2.9837e+02 2.9837e+02 3.8134e-05 3.8134e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9780e+00 3.3900e+07 5.8315e+02 5.8506e+03 1.5375e-08 0.0000e+00 1.0000e+00 5.8506e+03 5.8506e+03 2.9883e+02 2.9883e+02 3.8200e-05 3.8200e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9800e+00 3.4000e+07 5.8315e+02 5.8596e+03 1.5299e-08 0.0000e+00 1.0000e+00 5.8596e+03 5.8596e+03 2.9929e+02 2.9929e+02 3.8265e-05 3.8265e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9820e+00 3.4100e+07 5.8315e+02 5.8685e+03 1.5223e-08 0.0000e+00 1.0000e+00 5.8685e+03 5.8685e+03 2.9975e+02 2.9975e+02 3.8331e-05 3.8331e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9840e+00 3.4200e+07 5.8315e+02 5.8775e+03 1.5148e-08 0.0000e+00 1.0000e+00 5.8775e+03 5.8775e+03 3.0020e+02 3.0020e+02 3.8396e-05 3.8396e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9860e+00 3.4300e+07 5.8315e+02 5.8863e+03 1.5074e-08 0.0000e+00 1.0000e+00 5.8863e+03 5.8863e+03 3.0066e+02 3.0066e+02 3.8461e-05 3.8461e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9880e+00 3.4400e+07 5.8315e+02 5.8952e+03 1.5000e-08 0.0000e+00 1.0000e+00 5.8952e+03 5.8952e+03 3.0111e+02 3.0111e+02 3.8526e-05 3.8526e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9900e+00 3.4500e+07 5.8315e+02 5.9040e+03 1.4927e-08 0.0000e+00 1.0000e+00 5.9040e+03 5.9040e+03 3.0156e+02 3.0156e+02 3.8591e-05 3.8591e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9920e+00 3.4600e+07 5.8315e+02 5.9128e+03 1.4854e-08 0.0000e+00 1.0000e+00 5.9128e+03 5.9128e+03 3.0201e+02 3.0201e+02 3.8655e-05 3.8655e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9940e+00 3.4700e+07 5.8315e+02 5.9216e+03 1.4782e-08 0.0000e+00 1.0000e+00 5.9216e+03 5.9216e+03 3.0246e+02 3.0246e+02 3.8720e-05 3.8720e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9960e+00 3.4800e+07 5.8315e+02 5.9303e+03 1.4711e-08 0.0000e+00 1.0000e+00 5.9303e+03 5.9303e+03 3.0291e+02 3.0291e+02 3.8784e-05 3.8784e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +1.9980e+00 3.4900e+07 5.8315e+02 5.9390e+03 1.4640e-08 0.0000e+00 1.0000e+00 5.9390e+03 5.9390e+03 3.0335e+02 3.0335e+02 3.8849e-05 3.8849e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 +2.0000e+00 3.5000e+07 5.8315e+02 5.9477e+03 1.4569e-08 0.0000e+00 1.0000e+00 5.9477e+03 5.9477e+03 3.0379e+02 3.0379e+02 3.8913e-05 3.8913e-05 4.9060e-03 2.5695e-03 7.9973e-01 9.1430e-02 4.7818e-02 1.8822e-02 6.9494e-03 4.3126e-03 2.3463e-02 9.0000e-03 3.0000e-03 5.3470e-01 1.1460e-01 8.7900e-02 4.5600e-02 2.0900e-02 1.5100e-02 1.6920e-01 diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT_PhaseComposition.xml b/src/coreComponents/unitTests/constitutiveTests/testPVT_PhaseComposition.xml index 75d490e6a50..5207c9746d9 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testPVT_PhaseComposition.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT_PhaseComposition.xml @@ -149,7 +149,7 @@ diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT_ThreePhaseCompositional.xml b/src/coreComponents/unitTests/constitutiveTests/testPVT_ThreePhaseCompositional.xml new file mode 100644 index 00000000000..79c4892078e --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT_ThreePhaseCompositional.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT_ThreePhaseCompositional_blackOil.txt b/src/coreComponents/unitTests/constitutiveTests/testPVT_ThreePhaseCompositional_blackOil.txt new file mode 100644 index 00000000000..53e20dce320 --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT_ThreePhaseCompositional_blackOil.txt @@ -0,0 +1,113 @@ +# column 1 = time +# column 2 = pressure +# column 3 = temperature +# column 4 = density +# column 5 = total compressibility +# columns 6-8 = phase fractions +# columns 9-11 = phase densities +# columns 12-14 = phase mass densities +# columns 15-17 = phase viscosities +# columns 18-20 = oil phase fractions [C1, C7+, H2O] +# columns 21-23 = gas phase fractions [C1, C7+, H2O] +# columns 24-26 = water phase fractions [C1, C7+, H2O] +0.0000e+00 3.5000e+07 5.5315e+02 6.1560e+03 6.0169e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.5295e+03 5.5295e+03 5.6953e+04 5.2265e+02 5.2265e+02 1.0257e+03 1.0240e-04 1.0240e-04 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +2.0000e-02 3.4000e+07 5.5315e+02 6.1183e+03 6.2707e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.4953e+03 5.4953e+03 5.6930e+04 5.1941e+02 5.1941e+02 1.0253e+03 1.0027e-04 1.0027e-04 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +4.0000e-02 3.3000e+07 5.5315e+02 6.0792e+03 6.5439e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.4598e+03 5.4598e+03 5.6906e+04 5.1606e+02 5.1606e+02 1.0249e+03 9.8135e-05 9.8135e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +6.0000e-02 3.2000e+07 5.5315e+02 6.0387e+03 6.8385e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.4230e+03 5.4230e+03 5.6882e+04 5.1258e+02 5.1258e+02 1.0245e+03 9.6007e-05 9.6007e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +8.0000e-02 3.1000e+07 5.5315e+02 5.9966e+03 7.1573e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.3847e+03 5.3847e+03 5.6859e+04 5.0896e+02 5.0896e+02 1.0240e+03 9.3883e-05 9.3883e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.0000e-01 3.0000e+07 5.5315e+02 5.9528e+03 7.5032e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.3450e+03 5.3450e+03 5.6835e+04 5.0521e+02 5.0521e+02 1.0236e+03 9.1761e-05 9.1761e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.2000e-01 2.9000e+07 5.5315e+02 5.9072e+03 7.8796e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.3036e+03 5.3036e+03 5.6812e+04 5.0129e+02 5.0129e+02 1.0232e+03 8.9642e-05 8.9642e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.4000e-01 2.8000e+07 5.5315e+02 5.8597e+03 8.2906e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.2604e+03 5.2604e+03 5.6788e+04 4.9721e+02 4.9721e+02 1.0228e+03 8.7525e-05 8.7525e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.6000e-01 2.7000e+07 5.5315e+02 5.8100e+03 8.7412e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.2153e+03 5.2153e+03 5.6765e+04 4.9295e+02 4.9295e+02 1.0223e+03 8.5409e-05 8.5409e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.8000e-01 2.6000e+07 5.5315e+02 5.7580e+03 9.2370e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.1682e+03 5.1682e+03 5.6741e+04 4.8849e+02 4.8849e+02 1.0219e+03 8.3293e-05 8.3293e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +2.0000e-01 2.5000e+07 5.5315e+02 5.7036e+03 9.7851e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.1187e+03 5.1187e+03 5.6717e+04 4.8382e+02 4.8382e+02 1.0215e+03 8.1175e-05 8.1175e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +2.2000e-01 2.4000e+07 5.5315e+02 5.6174e+03 1.7179e-08 8.8110e-01 6.1877e-03 1.1271e-01 5.0414e+03 4.9180e+03 5.6694e+04 4.8521e+02 1.3086e+02 1.0211e+03 8.1572e-05 2.1495e-05 3.2929e-04 4.8901e-01 5.1099e-01 0.0000e+00 9.3267e-01 6.7327e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +2.4000e-01 2.3000e+07 5.5315e+02 5.5204e+03 1.7647e-08 8.7325e-01 1.4036e-02 1.1271e-01 4.9562e+03 4.7398e+03 5.6670e+04 4.8864e+02 1.2549e+02 1.0206e+03 8.2813e-05 2.1134e-05 3.2929e-04 4.7405e-01 5.2595e-01 0.0000e+00 9.3352e-01 6.6484e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +2.6000e-01 2.2000e+07 5.5315e+02 5.4225e+03 1.8162e-08 8.6581e-01 2.1475e-02 1.1271e-01 4.8719e+03 4.5585e+03 5.6647e+04 4.9205e+02 1.2016e+02 1.0202e+03 8.4061e-05 2.0788e-05 3.2929e-04 4.5873e-01 5.4127e-01 0.0000e+00 9.3426e-01 6.5741e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +2.8000e-01 2.1000e+07 5.5315e+02 5.3234e+03 1.8732e-08 8.5874e-01 2.8551e-02 1.1271e-01 4.7885e+03 4.3743e+03 5.6623e+04 4.9543e+02 1.1486e+02 1.0198e+03 8.5316e-05 2.0456e-05 3.2929e-04 4.4303e-01 5.5697e-01 0.0000e+00 9.3490e-01 6.5103e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +3.0000e-01 2.0000e+07 5.5315e+02 5.2230e+03 1.9369e-08 8.5198e-01 3.5311e-02 1.1271e-01 4.7061e+03 4.1872e+03 5.6600e+04 4.9880e+02 1.0961e+02 1.0194e+03 8.6578e-05 2.0139e-05 3.2929e-04 4.2693e-01 5.7307e-01 0.0000e+00 9.3542e-01 6.4579e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +3.2000e-01 1.9000e+07 5.5315e+02 5.1210e+03 2.0089e-08 8.4549e-01 4.1796e-02 1.1271e-01 4.6246e+03 3.9973e+03 5.6576e+04 5.0214e+02 1.0438e+02 1.0189e+03 8.7844e-05 1.9835e-05 3.2929e-04 4.1042e-01 5.8958e-01 0.0000e+00 9.3582e-01 6.4178e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +3.4000e-01 1.8000e+07 5.5315e+02 5.0171e+03 2.0911e-08 8.3924e-01 4.8049e-02 1.1271e-01 4.5439e+03 3.8047e+03 5.6553e+04 5.0547e+02 9.9197e+01 1.0185e+03 8.9115e-05 1.9544e-05 3.2929e-04 3.9347e-01 6.0653e-01 0.0000e+00 9.3609e-01 6.3914e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +3.6000e-01 1.7000e+07 5.5315e+02 4.9110e+03 2.1861e-08 8.3318e-01 5.4111e-02 1.1271e-01 4.4641e+03 3.6096e+03 5.6530e+04 5.0878e+02 9.4045e+01 1.0181e+03 9.0389e-05 1.9265e-05 3.2929e-04 3.7608e-01 6.2392e-01 0.0000e+00 9.3620e-01 6.3802e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +3.8000e-01 1.6000e+07 5.5315e+02 4.8022e+03 2.2976e-08 8.2726e-01 6.0026e-02 1.1271e-01 4.3852e+03 3.4119e+03 5.6506e+04 5.1208e+02 8.8928e+01 1.0177e+03 9.1664e-05 1.8998e-05 3.2929e-04 3.5822e-01 6.4178e-01 0.0000e+00 9.3614e-01 6.3864e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +4.0000e-01 1.5000e+07 5.5315e+02 4.6901e+03 2.4303e-08 8.2145e-01 6.5840e-02 1.1271e-01 4.3071e+03 3.2118e+03 5.6483e+04 5.1536e+02 8.3846e+01 1.0173e+03 9.2939e-05 1.8741e-05 3.2929e-04 3.3987e-01 6.6013e-01 0.0000e+00 9.3587e-01 6.4127e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +4.2000e-01 1.4000e+07 5.5315e+02 4.5740e+03 2.5910e-08 8.1568e-01 7.1608e-02 1.1271e-01 4.2299e+03 3.0095e+03 5.6459e+04 5.1864e+02 7.8800e+01 1.0168e+03 9.4210e-05 1.8494e-05 3.2929e-04 3.2102e-01 6.7898e-01 0.0000e+00 9.3537e-01 6.4625e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +4.4000e-01 1.3000e+07 5.5315e+02 4.4527e+03 2.7893e-08 8.0990e-01 7.7391e-02 1.1271e-01 4.1535e+03 2.8050e+03 5.6436e+04 5.2190e+02 7.3789e+01 1.0164e+03 9.5475e-05 1.8255e-05 3.2929e-04 3.0163e-01 6.9837e-01 0.0000e+00 9.3459e-01 6.5406e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +4.6000e-01 1.2000e+07 5.5315e+02 4.3251e+03 3.0392e-08 8.0402e-01 8.3265e-02 1.1271e-01 4.0779e+03 2.5984e+03 5.6412e+04 5.2516e+02 6.8814e+01 1.0160e+03 9.6732e-05 1.8022e-05 3.2929e-04 2.8170e-01 7.1830e-01 0.0000e+00 9.3347e-01 6.6532e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +4.8000e-01 1.1000e+07 5.5315e+02 4.1891e+03 3.3618e-08 7.9796e-01 8.9328e-02 1.1271e-01 4.0031e+03 2.3899e+03 5.6389e+04 5.2841e+02 6.3876e+01 1.0156e+03 9.7975e-05 1.7795e-05 3.2929e-04 2.6120e-01 7.3880e-01 0.0000e+00 9.3191e-01 6.8088e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +5.0000e-01 1.0000e+07 5.5315e+02 4.0424e+03 3.7901e-08 7.9158e-01 9.5711e-02 1.1271e-01 3.9291e+03 2.1796e+03 5.6366e+04 5.3165e+02 5.8976e+01 1.0151e+03 9.9202e-05 1.7569e-05 3.2929e-04 2.4011e-01 7.5989e-01 0.0000e+00 9.2981e-01 7.0194e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +5.2000e-01 9.6040e+06 5.5315e+02 3.9806e+03 3.9996e-08 7.8892e-01 9.8365e-02 1.1271e-01 3.9000e+03 2.0959e+03 5.6356e+04 5.3293e+02 5.7046e+01 1.0150e+03 9.9682e-05 1.7479e-05 3.2929e-04 2.3159e-01 7.6841e-01 0.0000e+00 9.2878e-01 7.1215e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +5.4000e-01 9.2080e+06 5.5315e+02 3.9162e+03 4.2382e-08 7.8618e-01 1.0111e-01 1.1271e-01 3.8710e+03 2.0119e+03 5.6347e+04 5.3421e+02 5.5122e+01 1.0148e+03 1.0016e-04 1.7389e-05 3.2929e-04 2.2297e-01 7.7703e-01 0.0000e+00 9.2764e-01 7.2363e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +5.6000e-01 8.8120e+06 5.5315e+02 3.8490e+03 4.5115e-08 7.8332e-01 1.0397e-01 1.1271e-01 3.8422e+03 1.9277e+03 5.6338e+04 5.3549e+02 5.3205e+01 1.0146e+03 1.0063e-04 1.7299e-05 3.2929e-04 2.1425e-01 7.8575e-01 0.0000e+00 9.2635e-01 7.3653e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +5.8000e-01 8.4160e+06 5.5315e+02 3.7785e+03 4.8266e-08 7.8033e-01 1.0696e-01 1.1271e-01 3.8135e+03 1.8432e+03 5.6329e+04 5.3677e+02 5.1293e+01 1.0145e+03 1.0110e-04 1.7207e-05 3.2929e-04 2.0543e-01 7.9457e-01 0.0000e+00 9.2489e-01 7.5105e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +6.0000e-01 8.0200e+06 5.5315e+02 3.7044e+03 5.1924e-08 7.7719e-01 1.1010e-01 1.1271e-01 3.7849e+03 1.7585e+03 5.6319e+04 5.3805e+02 4.9388e+01 1.0143e+03 1.0156e-04 1.7113e-05 3.2929e-04 1.9650e-01 8.0350e-01 0.0000e+00 9.2326e-01 7.6743e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +6.2000e-01 7.6240e+06 5.5315e+02 3.6260e+03 5.6202e-08 7.7386e-01 1.1343e-01 1.1271e-01 3.7565e+03 1.6736e+03 5.6310e+04 5.3933e+02 4.7489e+01 1.0141e+03 1.0202e-04 1.7018e-05 3.2929e-04 1.8748e-01 8.1252e-01 0.0000e+00 9.2141e-01 7.8594e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +6.4000e-01 7.2280e+06 5.5315e+02 3.5428e+03 6.1247e-08 7.7031e-01 1.1698e-01 1.1271e-01 3.7281e+03 1.5884e+03 5.6301e+04 5.4061e+02 4.5597e+01 1.0140e+03 1.0247e-04 1.6920e-05 3.2929e-04 1.7834e-01 8.2166e-01 0.0000e+00 9.1931e-01 8.0692e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +6.6000e-01 6.8320e+06 5.5315e+02 3.4539e+03 6.7247e-08 7.6650e-01 1.2079e-01 1.1271e-01 3.6999e+03 1.5031e+03 5.6292e+04 5.4188e+02 4.3711e+01 1.0138e+03 1.0292e-04 1.6818e-05 3.2929e-04 1.6910e-01 8.3090e-01 0.0000e+00 9.1692e-01 8.3080e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +6.8000e-01 6.4360e+06 5.5315e+02 3.3585e+03 7.4453e-08 7.6236e-01 1.2493e-01 1.1271e-01 3.6718e+03 1.4176e+03 5.6282e+04 5.4316e+02 4.1832e+01 1.0136e+03 1.0335e-04 1.6713e-05 3.2929e-04 1.5975e-01 8.4025e-01 0.0000e+00 9.1419e-01 8.5810e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +7.0000e-01 6.0400e+06 5.5315e+02 3.2554e+03 8.3199e-08 7.5783e-01 1.2946e-01 1.1271e-01 3.6438e+03 1.3319e+03 5.6273e+04 5.4443e+02 3.9959e+01 1.0135e+03 1.0379e-04 1.6602e-05 3.2929e-04 1.5029e-01 8.4971e-01 0.0000e+00 9.1105e-01 8.8948e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +7.2000e-01 5.6440e+06 5.5315e+02 3.1435e+03 9.3938e-08 7.5281e-01 1.3448e-01 1.1271e-01 3.6160e+03 1.2460e+03 5.6264e+04 5.4570e+02 3.8093e+01 1.0133e+03 1.0421e-04 1.6485e-05 3.2929e-04 1.4071e-01 8.5929e-01 0.0000e+00 9.0742e-01 9.2579e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +7.4000e-01 5.2480e+06 5.5315e+02 3.0210e+03 1.0730e-07 7.4718e-01 1.4011e-01 1.1271e-01 3.5883e+03 1.1600e+03 5.6255e+04 5.4698e+02 3.6233e+01 1.0131e+03 1.0463e-04 1.6359e-05 3.2929e-04 1.3102e-01 8.6898e-01 0.0000e+00 9.0319e-01 9.6812e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +7.6000e-01 4.8520e+06 5.5315e+02 2.8861e+03 1.2415e-07 7.4077e-01 1.4652e-01 1.1271e-01 3.5607e+03 1.0738e+03 5.6245e+04 5.4825e+02 3.4381e+01 1.0130e+03 1.0503e-04 1.6224e-05 3.2929e-04 1.2122e-01 8.7878e-01 0.0000e+00 8.9821e-01 1.0179e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +7.8000e-01 4.4560e+06 5.5315e+02 2.7364e+03 1.4578e-07 7.3336e-01 1.5393e-01 1.1271e-01 3.5332e+03 9.8750e+02 5.6236e+04 5.4952e+02 3.2535e+01 1.0128e+03 1.0543e-04 1.6076e-05 3.2929e-04 1.1129e-01 8.8871e-01 0.0000e+00 8.9228e-01 1.0772e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +8.0000e-01 4.0600e+06 5.5315e+02 2.5691e+03 1.7403e-07 7.2461e-01 1.6268e-01 1.1271e-01 3.5058e+03 9.0104e+02 5.6227e+04 5.5079e+02 3.0696e+01 1.0126e+03 1.0582e-04 1.5911e-05 3.2929e-04 1.0125e-01 8.9875e-01 0.0000e+00 8.8514e-01 1.1486e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +8.2000e-01 3.6640e+06 5.5315e+02 2.3811e+03 2.1172e-07 7.1406e-01 1.7323e-01 1.1271e-01 3.4786e+03 8.1446e+02 5.6218e+04 5.5206e+02 2.8865e+01 1.0125e+03 1.0619e-04 1.5725e-05 3.2929e-04 9.1082e-02 9.0892e-01 0.0000e+00 8.7640e-01 1.2360e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +8.4000e-01 3.2680e+06 5.5315e+02 2.1686e+03 2.6326e-07 7.0095e-01 1.8634e-01 1.1271e-01 3.4515e+03 7.2776e+02 5.6208e+04 5.5333e+02 2.7040e+01 1.0123e+03 1.0656e-04 1.5512e-05 3.2929e-04 8.0792e-02 9.1921e-01 0.0000e+00 8.6548e-01 1.3452e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +8.6000e-01 2.8720e+06 5.5315e+02 1.9276e+03 3.3583e-07 6.8411e-01 2.0318e-01 1.1271e-01 3.4245e+03 6.4096e+02 5.6199e+04 5.5460e+02 2.5222e+01 1.0121e+03 1.0691e-04 1.5261e-05 3.2929e-04 7.0376e-02 9.2962e-01 0.0000e+00 8.5148e-01 1.4852e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +8.8000e-01 2.4760e+06 5.5315e+02 1.6549e+03 4.4172e-07 6.6146e-01 2.2583e-01 1.1271e-01 3.3976e+03 5.5407e+02 5.6190e+04 5.5587e+02 2.3412e+01 1.0120e+03 1.0725e-04 1.4958e-05 3.2929e-04 5.9832e-02 9.4017e-01 0.0000e+00 8.3298e-01 1.6702e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +9.0000e-01 2.0800e+06 5.5315e+02 1.3487e+03 6.0350e-07 6.2908e-01 2.5821e-01 1.1271e-01 3.3708e+03 4.6709e+02 5.6181e+04 5.5714e+02 2.1609e+01 1.0118e+03 1.0757e-04 1.4583e-05 3.2929e-04 4.9159e-02 9.5084e-01 0.0000e+00 8.0745e-01 1.9255e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +9.2000e-01 1.6840e+06 5.5315e+02 1.0126e+03 8.6704e-07 5.7850e-01 3.0879e-01 1.1271e-01 3.3442e+03 3.8004e+02 5.6172e+04 5.5841e+02 1.9813e+01 1.0116e+03 1.0788e-04 1.4097e-05 3.2929e-04 3.8354e-02 9.6165e-01 0.0000e+00 7.7004e-01 2.2996e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +9.4000e-01 1.2880e+06 5.5315e+02 6.6052e+02 1.3428e-06 4.8744e-01 3.9985e-01 1.1271e-01 3.3176e+03 2.9292e+02 5.6162e+04 5.5968e+02 1.8025e+01 1.0115e+03 1.0818e-04 1.3437e-05 3.2929e-04 2.7415e-02 9.7259e-01 0.0000e+00 7.1015e-01 2.8985e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +9.6000e-01 8.9200e+05 5.5315e+02 3.2534e+02 2.3985e-06 2.7229e-01 6.1500e-01 1.1271e-01 3.2912e+03 2.0575e+02 5.6153e+04 5.6094e+02 1.6244e+01 1.0113e+03 1.0845e-04 1.2477e-05 3.2929e-04 1.6340e-02 9.8366e-01 0.0000e+00 5.9920e-01 4.0080e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +9.8000e-01 4.9600e+05 5.5315e+02 1.2779e+02 2.1211e-06 8.8729e-01 0.0000e+00 1.1271e-01 1.1342e+02 1.1342e+02 5.6144e+04 1.0720e+01 1.0720e+01 1.0112e+03 1.1716e-05 1.1716e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.0000e+00 1.0000e+05 5.5315e+02 2.4746e+01 1.0099e-05 8.8729e-01 0.0000e+00 1.1271e-01 2.1958e+01 2.1958e+01 5.6135e+04 2.0755e+00 2.0755e+00 1.0110e+03 1.1560e-05 1.1560e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.0200e+00 4.9600e+05 5.8315e+02 1.2012e+02 2.1009e-06 8.8729e-01 0.0000e+00 1.1271e-01 1.0660e+02 1.0660e+02 5.6144e+04 1.0076e+01 1.0076e+01 1.0112e+03 1.2221e-05 1.2221e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.0400e+00 8.9200e+05 5.8315e+02 2.2354e+02 1.2093e-06 8.8729e-01 0.0000e+00 1.1271e-01 1.9843e+02 1.9843e+02 5.6153e+04 1.8756e+01 1.8756e+01 1.0113e+03 1.2405e-05 1.2405e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.0600e+00 1.2880e+06 5.8315e+02 3.4774e+02 1.7667e-06 4.3627e-02 8.4366e-01 1.1271e-01 3.0621e+03 2.9504e+02 5.6162e+04 5.1804e+02 2.7265e+01 1.0115e+03 8.2939e-05 1.2695e-05 3.2929e-04 2.4366e-02 9.7563e-01 0.0000e+00 5.1344e-01 4.8656e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.0800e+00 1.6840e+06 5.8315e+02 6.0704e+02 1.1265e-06 3.0186e-01 5.8543e-01 1.1271e-01 3.0890e+03 3.7828e+02 5.6172e+04 5.1649e+02 2.9209e+01 1.0116e+03 8.2756e-05 1.3409e-05 3.2929e-04 3.6932e-02 9.6307e-01 0.0000e+00 6.1026e-01 3.8974e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.1000e+00 2.0800e+06 5.8315e+02 8.8181e+02 7.8965e-07 4.2838e-01 4.5891e-01 1.1271e-01 3.1161e+03 4.6143e+02 5.6181e+04 5.1495e+02 3.1163e+01 1.0118e+03 8.2556e-05 1.3965e-05 3.2929e-04 4.9339e-02 9.5066e-01 0.0000e+00 6.7192e-01 3.2808e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.1200e+00 2.4760e+06 5.8315e+02 1.1539e+03 5.8364e-07 5.0379e-01 3.8350e-01 1.1271e-01 3.1432e+03 5.4447e+02 5.6190e+04 5.1339e+02 3.3128e+01 1.0120e+03 8.2339e-05 1.4414e-05 3.2929e-04 6.1589e-02 9.3841e-01 0.0000e+00 7.1454e-01 2.8546e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.1400e+00 2.8720e+06 5.8315e+02 1.4127e+03 4.4720e-07 5.5409e-01 3.3320e-01 1.1271e-01 3.1706e+03 6.2740e+02 5.6199e+04 5.1184e+02 3.5105e+01 1.0121e+03 8.2106e-05 1.4788e-05 3.2929e-04 7.3685e-02 9.2632e-01 0.0000e+00 7.4571e-01 2.5429e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.1600e+00 3.2680e+06 5.8315e+02 1.6532e+03 3.5221e-07 5.9019e-01 2.9710e-01 1.1271e-01 3.1980e+03 7.1021e+02 5.6208e+04 5.1028e+02 3.7093e+01 1.0123e+03 8.1860e-05 1.5107e-05 3.2929e-04 8.5630e-02 9.1437e-01 0.0000e+00 7.6944e-01 2.3056e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.1800e+00 3.6640e+06 5.8315e+02 1.8738e+03 2.8372e-07 6.1751e-01 2.6978e-01 1.1271e-01 3.2257e+03 7.9289e+02 5.6218e+04 5.0871e+02 3.9092e+01 1.0125e+03 8.1599e-05 1.5383e-05 3.2929e-04 9.7426e-02 9.0257e-01 0.0000e+00 7.8808e-01 2.1192e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.2000e+00 4.0600e+06 5.8315e+02 2.0746e+03 2.3298e-07 6.3902e-01 2.4827e-01 1.1271e-01 3.2534e+03 8.7543e+02 5.6227e+04 5.0714e+02 4.1103e+01 1.0126e+03 8.1325e-05 1.5628e-05 3.2929e-04 1.0908e-01 8.9092e-01 0.0000e+00 8.0306e-01 1.9694e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.2200e+00 4.4560e+06 5.8315e+02 2.2571e+03 1.9456e-07 6.5648e-01 2.3081e-01 1.1271e-01 3.2813e+03 9.5783e+02 5.6236e+04 5.0557e+02 4.3124e+01 1.0128e+03 8.1039e-05 1.5847e-05 3.2929e-04 1.2058e-01 8.7942e-01 0.0000e+00 8.1535e-01 1.8465e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.2400e+00 4.8520e+06 5.8315e+02 2.4230e+03 1.6492e-07 6.7102e-01 2.1627e-01 1.1271e-01 3.3094e+03 1.0401e+03 5.6245e+04 5.0399e+02 4.5158e+01 1.0130e+03 8.0742e-05 1.6047e-05 3.2929e-04 1.3195e-01 8.6805e-01 0.0000e+00 8.2557e-01 1.7443e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.2600e+00 5.2480e+06 5.8315e+02 2.5742e+03 1.4168e-07 6.8338e-01 2.0390e-01 1.1271e-01 3.3376e+03 1.1221e+03 5.6255e+04 5.0240e+02 4.7203e+01 1.0131e+03 8.0433e-05 1.6230e-05 3.2929e-04 1.4318e-01 8.5682e-01 0.0000e+00 8.3419e-01 1.6581e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.2800e+00 5.6440e+06 5.8315e+02 2.7125e+03 1.2319e-07 6.9409e-01 1.9320e-01 1.1271e-01 3.3660e+03 1.2040e+03 5.6264e+04 5.0081e+02 4.9259e+01 1.0133e+03 8.0115e-05 1.6401e-05 3.2929e-04 1.5427e-01 8.4573e-01 0.0000e+00 8.4154e-01 1.5846e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.3000e+00 6.0400e+06 5.8315e+02 2.8394e+03 1.0830e-07 7.0351e-01 1.8378e-01 1.1271e-01 3.3945e+03 1.2857e+03 5.6273e+04 4.9921e+02 5.1327e+01 1.0135e+03 7.9786e-05 1.6561e-05 3.2929e-04 1.6523e-01 8.3477e-01 0.0000e+00 8.4786e-01 1.5214e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.3200e+00 6.4360e+06 5.8315e+02 2.9565e+03 9.6164e-08 7.1191e-01 1.7538e-01 1.1271e-01 3.4232e+03 1.3673e+03 5.6282e+04 4.9761e+02 5.3407e+01 1.0136e+03 7.9448e-05 1.6713e-05 3.2929e-04 1.7606e-01 8.2394e-01 0.0000e+00 8.5333e-01 1.4667e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.3400e+00 6.8320e+06 5.8315e+02 3.0649e+03 8.6168e-08 7.1948e-01 1.6781e-01 1.1271e-01 3.4520e+03 1.4486e+03 5.6292e+04 4.9600e+02 5.5498e+01 1.0138e+03 7.9102e-05 1.6858e-05 3.2929e-04 1.8676e-01 8.1324e-01 0.0000e+00 8.5811e-01 1.4189e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.3600e+00 7.2280e+06 5.8315e+02 3.1660e+03 7.7854e-08 7.2640e-01 1.6089e-01 1.1271e-01 3.4809e+03 1.5297e+03 5.6301e+04 4.9439e+02 5.7601e+01 1.0140e+03 7.8748e-05 1.6997e-05 3.2929e-04 1.9733e-01 8.0267e-01 0.0000e+00 8.6229e-01 1.3771e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.3800e+00 7.6240e+06 5.8315e+02 3.2605e+03 7.0879e-08 7.3276e-01 1.5453e-01 1.1271e-01 3.5101e+03 1.6106e+03 5.6310e+04 4.9277e+02 5.9717e+01 1.0141e+03 7.8386e-05 1.7132e-05 3.2929e-04 2.0778e-01 7.9222e-01 0.0000e+00 8.6597e-01 1.3403e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.4000e+00 8.0200e+06 5.8315e+02 3.3492e+03 6.4979e-08 7.3868e-01 1.4861e-01 1.1271e-01 3.5394e+03 1.6913e+03 5.6319e+04 4.9114e+02 6.1844e+01 1.0143e+03 7.8016e-05 1.7263e-05 3.2929e-04 2.1811e-01 7.8189e-01 0.0000e+00 8.6923e-01 1.3077e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.4200e+00 8.4160e+06 5.8315e+02 3.4330e+03 5.9949e-08 7.4422e-01 1.4307e-01 1.1271e-01 3.5688e+03 1.7717e+03 5.6329e+04 4.8951e+02 6.3983e+01 1.0145e+03 7.7640e-05 1.7391e-05 3.2929e-04 2.2831e-01 7.7169e-01 0.0000e+00 8.7211e-01 1.2789e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.4400e+00 8.8120e+06 5.8315e+02 3.5124e+03 5.5632e-08 7.4946e-01 1.3783e-01 1.1271e-01 3.5984e+03 1.8519e+03 5.6338e+04 4.8787e+02 6.6135e+01 1.0146e+03 7.7258e-05 1.7517e-05 3.2929e-04 2.3840e-01 7.6160e-01 0.0000e+00 8.7467e-01 1.2533e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.4600e+00 9.2080e+06 5.8315e+02 3.5880e+03 5.1902e-08 7.5444e-01 1.3285e-01 1.1271e-01 3.6282e+03 1.9319e+03 5.6347e+04 4.8623e+02 6.8299e+01 1.0148e+03 7.6869e-05 1.7641e-05 3.2929e-04 2.4838e-01 7.5162e-01 0.0000e+00 8.7695e-01 1.2305e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.4800e+00 9.6040e+06 5.8315e+02 3.6601e+03 4.8659e-08 7.5920e-01 1.2809e-01 1.1271e-01 3.6581e+03 2.0115e+03 5.6356e+04 4.8457e+02 7.0476e+01 1.0150e+03 7.6475e-05 1.7765e-05 3.2929e-04 2.5824e-01 7.4176e-01 0.0000e+00 8.7898e-01 1.2102e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.5000e+00 1.0000e+07 5.8315e+02 3.7291e+03 4.5824e-08 7.6378e-01 1.2351e-01 1.1271e-01 3.6882e+03 2.0910e+03 5.6366e+04 4.8291e+02 7.2665e+01 1.0151e+03 7.6075e-05 1.7888e-05 3.2929e-04 2.6799e-01 7.3201e-01 0.0000e+00 8.8078e-01 1.1922e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.5200e+00 1.1000e+07 5.8315e+02 3.8922e+03 4.0073e-08 7.7474e-01 1.1254e-01 1.1271e-01 3.7648e+03 2.2903e+03 5.6389e+04 4.7869e+02 7.8250e+01 1.0156e+03 7.5043e-05 1.8197e-05 3.2929e-04 2.9214e-01 7.0786e-01 0.0000e+00 8.8451e-01 1.1549e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.5400e+00 1.2000e+07 5.8315e+02 4.0423e+03 3.5793e-08 7.8515e-01 1.0214e-01 1.1271e-01 3.8426e+03 2.4877e+03 5.6412e+04 4.7441e+02 8.3920e+01 1.0160e+03 7.3984e-05 1.8510e-05 3.2929e-04 3.1562e-01 6.8438e-01 0.0000e+00 8.8727e-01 1.1273e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.5600e+00 1.3000e+07 5.8315e+02 4.1824e+03 3.2518e-08 7.9527e-01 9.2016e-02 1.1271e-01 3.9214e+03 2.6831e+03 5.6436e+04 4.7007e+02 8.9678e+01 1.0164e+03 7.2901e-05 1.8830e-05 3.2929e-04 3.3847e-01 6.6153e-01 0.0000e+00 8.8925e-01 1.1075e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.5800e+00 1.4000e+07 5.8315e+02 4.3149e+03 2.9952e-08 8.0535e-01 8.1944e-02 1.1271e-01 4.0014e+03 2.8763e+03 5.6459e+04 4.6568e+02 9.5527e+01 1.0168e+03 7.1797e-05 1.9161e-05 3.2929e-04 3.6073e-01 6.3927e-01 0.0000e+00 8.9060e-01 1.0940e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.6000e+00 1.5000e+07 5.8315e+02 4.4414e+03 2.7899e-08 8.1555e-01 7.1735e-02 1.1271e-01 4.0824e+03 3.0673e+03 5.6483e+04 4.6121e+02 1.0147e+02 1.0173e+03 7.0674e-05 1.9505e-05 3.2929e-04 3.8242e-01 6.1758e-01 0.0000e+00 8.9143e-01 1.0857e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.6200e+00 1.6000e+07 5.8315e+02 4.5631e+03 2.6223e-08 8.2607e-01 6.1222e-02 1.1271e-01 4.1647e+03 3.2559e+03 5.6506e+04 4.5668e+02 1.0752e+02 1.0177e+03 6.9535e-05 1.9866e-05 3.2929e-04 4.0358e-01 5.9642e-01 0.0000e+00 8.9180e-01 1.0820e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.6400e+00 1.7000e+07 5.8315e+02 4.6810e+03 2.4832e-08 8.3705e-01 5.0240e-02 1.1271e-01 4.2481e+03 3.4420e+03 5.6530e+04 4.5206e+02 1.1367e+02 1.0181e+03 6.8382e-05 2.0245e-05 3.2929e-04 4.2423e-01 5.7577e-01 0.0000e+00 8.9179e-01 1.0821e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.6600e+00 1.8000e+07 5.8315e+02 4.7958e+03 2.3660e-08 8.4867e-01 3.8624e-02 1.1271e-01 4.3328e+03 3.6254e+03 5.6553e+04 4.4735e+02 1.1994e+02 1.0185e+03 6.7214e-05 2.0645e-05 3.2929e-04 4.4441e-01 5.5559e-01 0.0000e+00 8.9142e-01 1.0858e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.6800e+00 1.9000e+07 5.8315e+02 4.9081e+03 2.2657e-08 8.6110e-01 2.6192e-02 1.1271e-01 4.4188e+03 3.8061e+03 5.6576e+04 4.4254e+02 1.2633e+02 1.0189e+03 6.6034e-05 2.1068e-05 3.2929e-04 4.6414e-01 5.3586e-01 0.0000e+00 8.9072e-01 1.0928e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.7000e+00 2.0000e+07 5.8315e+02 5.0183e+03 2.1788e-08 8.7455e-01 1.2742e-02 1.1271e-01 4.5061e+03 3.9839e+03 5.6600e+04 4.3761e+02 1.3286e+02 1.0194e+03 6.4840e-05 2.1517e-05 3.2929e-04 4.8347e-01 5.1653e-01 0.0000e+00 8.8972e-01 1.1028e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.7200e+00 2.1000e+07 5.8315e+02 5.1233e+03 1.5507e-08 8.8729e-01 0.0000e+00 1.1271e-01 4.5927e+03 4.5927e+03 5.6623e+04 4.3410e+02 4.3410e+02 1.0198e+03 6.4038e-05 6.4038e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.7400e+00 2.2000e+07 5.8315e+02 5.2003e+03 1.4379e-08 8.8729e-01 0.0000e+00 1.1271e-01 4.6625e+03 4.6625e+03 5.6647e+04 4.4069e+02 4.4069e+02 1.0202e+03 6.5972e-05 6.5972e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.7600e+00 2.3000e+07 5.8315e+02 5.2730e+03 1.3388e-08 8.8729e-01 0.0000e+00 1.1271e-01 4.7283e+03 4.7283e+03 5.6670e+04 4.4691e+02 4.4691e+02 1.0206e+03 6.7891e-05 6.7891e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.7800e+00 2.4000e+07 5.8315e+02 5.3417e+03 1.2511e-08 8.8729e-01 0.0000e+00 1.1271e-01 4.7905e+03 4.7905e+03 5.6694e+04 4.5280e+02 4.5280e+02 1.0211e+03 6.9797e-05 6.9797e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.8000e+00 2.5000e+07 5.8315e+02 5.4068e+03 1.1730e-08 8.8729e-01 0.0000e+00 1.1271e-01 4.8495e+03 4.8495e+03 5.6717e+04 4.5837e+02 4.5837e+02 1.0215e+03 7.1695e-05 7.1695e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.8200e+00 2.6000e+07 5.8315e+02 5.4686e+03 1.1031e-08 8.8729e-01 0.0000e+00 1.1271e-01 4.9055e+03 4.9055e+03 5.6741e+04 4.6367e+02 4.6367e+02 1.0219e+03 7.3587e-05 7.3587e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.8400e+00 2.7000e+07 5.8315e+02 5.5275e+03 1.0402e-08 8.8729e-01 0.0000e+00 1.1271e-01 4.9589e+03 4.9589e+03 5.6765e+04 4.6872e+02 4.6872e+02 1.0223e+03 7.5475e-05 7.5475e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.8600e+00 2.8000e+07 5.8315e+02 5.5837e+03 9.8334e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.0099e+03 5.0099e+03 5.6788e+04 4.7353e+02 4.7353e+02 1.0228e+03 7.7360e-05 7.7360e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.8800e+00 2.9000e+07 5.8315e+02 5.6374e+03 9.3169e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.0586e+03 5.0586e+03 5.6812e+04 4.7814e+02 4.7814e+02 1.0232e+03 7.9245e-05 7.9245e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.9000e+00 3.0000e+07 5.8315e+02 5.6888e+03 8.8460e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.1052e+03 5.1052e+03 5.6835e+04 4.8254e+02 4.8254e+02 1.0236e+03 8.1131e-05 8.1131e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.9200e+00 3.1000e+07 5.8315e+02 5.7381e+03 8.4151e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.1499e+03 5.1499e+03 5.6859e+04 4.8677e+02 4.8677e+02 1.0240e+03 8.3018e-05 8.3018e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.9400e+00 3.2000e+07 5.8315e+02 5.7854e+03 8.0196e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.1929e+03 5.1929e+03 5.6882e+04 4.9083e+02 4.9083e+02 1.0245e+03 8.4907e-05 8.4907e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.9600e+00 3.3000e+07 5.8315e+02 5.8309e+03 7.6552e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.2342e+03 5.2342e+03 5.6906e+04 4.9473e+02 4.9473e+02 1.0249e+03 8.6800e-05 8.6800e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +1.9800e+00 3.4000e+07 5.8315e+02 5.8747e+03 7.3187e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.2739e+03 5.2739e+03 5.6930e+04 4.9849e+02 4.9849e+02 1.0253e+03 8.8696e-05 8.8696e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 +2.0000e+00 3.5000e+07 5.8315e+02 5.9169e+03 7.0071e-09 8.8729e-01 0.0000e+00 1.1271e-01 5.3122e+03 5.3122e+03 5.6953e+04 5.0211e+02 5.0211e+02 1.0257e+03 9.0597e-05 9.0597e-05 3.2929e-04 5.0000e-01 5.0000e-01 0.0000e+00 9.1515e-01 8.4850e-02 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e+00 diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT_data/carbonDioxideSpycherPruessFlash.txt b/src/coreComponents/unitTests/constitutiveTests/testPVT_data/carbonDioxideSpycherPruessFlash.txt new file mode 100644 index 00000000000..98f2cb18927 --- /dev/null +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT_data/carbonDioxideSpycherPruessFlash.txt @@ -0,0 +1 @@ +FlashModel CO2Solubility 0.99e6 5.01e7 4.911e6 339 351 1 0 1.0e-10 SpycherPruess diff --git a/src/coreComponents/unitTests/constitutiveTests/testPVT_docExample.xml b/src/coreComponents/unitTests/constitutiveTests/testPVT_docExample.xml index b1747d41dd3..872a6a54a4c 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testPVT_docExample.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testPVT_docExample.xml @@ -70,7 +70,7 @@ diff --git a/src/coreComponents/unitTests/constitutiveTests/testReactiveFluid.cpp b/src/coreComponents/unitTests/constitutiveTests/testReactiveFluid.cpp index 009380c05d8..8ad1df7c3b5 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testReactiveFluid.cpp +++ b/src/coreComponents/unitTests/constitutiveTests/testReactiveFluid.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,7 +22,7 @@ #include #include -// this unit test basically launches a full geosx instance, and then uses the +// this unit test basically launches a full geos instance, and then uses the // input xml to launch a ReactiveFluidDriver task TEST( testReactiveFluid, testReactiveFluid ) diff --git a/src/coreComponents/unitTests/constitutiveTests/testReactiveFluid.xml b/src/coreComponents/unitTests/constitutiveTests/testReactiveFluid.xml index 65a3c58cf4f..d37ed605c49 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testReactiveFluid.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testReactiveFluid.xml @@ -74,7 +74,7 @@ diff --git a/src/coreComponents/unitTests/constitutiveTests/testRelPerm.cpp b/src/coreComponents/unitTests/constitutiveTests/testRelPerm.cpp index 48e995d367e..b8aeeb671f1 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testRelPerm.cpp +++ b/src/coreComponents/unitTests/constitutiveTests/testRelPerm.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -45,7 +46,7 @@ RelativePermeabilityBase & makeBrooksCoreyRelPerm( string const & name, Group & phaseRelPermMaxVal.resize( 2 ); phaseRelPermMaxVal[0] = 0.8; phaseRelPermMaxVal[1] = 0.9; - relPerm.postProcessInputRecursive(); + relPerm.postInputInitializationRecursive(); return relPerm; } @@ -70,7 +71,7 @@ RelativePermeabilityBase & makeBrooksCoreyBakerRelPermTwoPhase( string const & n waterOilRelPermMaxVal.resize( 2 ); waterOilRelPermMaxVal[0] = 0.8; waterOilRelPermMaxVal[1] = 0.75; - relPerm.postProcessInputRecursive(); + relPerm.postInputInitializationRecursive(); return relPerm; } @@ -103,7 +104,7 @@ RelativePermeabilityBase & makeBrooksCoreyBakerRelPermThreePhase( string const & gasOilRelPermMaxVal.resize( 2 ); gasOilRelPermMaxVal[0] = 0.8; gasOilRelPermMaxVal[1] = 0.95; - relPerm.postProcessInputRecursive(); + relPerm.postInputInitializationRecursive(); return relPerm; } @@ -136,7 +137,7 @@ RelativePermeabilityBase & makeBrooksCoreyStone2RelPermThreePhase( string const gasOilRelPermMaxVal.resize( 2 ); gasOilRelPermMaxVal[0] = 0.8; gasOilRelPermMaxVal[1] = 0.95; - relPerm.postProcessInputRecursive(); + relPerm.postInputInitializationRecursive(); return relPerm; } @@ -161,7 +162,7 @@ RelativePermeabilityBase & makeVanGenuchtenBakerRelPermTwoPhase( string const & gasOilRelPermMaxVal.resize( 2 ); gasOilRelPermMaxVal[0] = 0.5; gasOilRelPermMaxVal[1] = 0.75; - relPerm.postProcessInputRecursive(); + relPerm.postInputInitializationRecursive(); return relPerm; } @@ -196,7 +197,7 @@ RelativePermeabilityBase & makeVanGenuchtenBakerRelPermThreePhase( string const gasOilRelPermMaxVal.resize( 2 ); gasOilRelPermMaxVal[0] = 0.8; gasOilRelPermMaxVal[1] = 0.75; - relPerm.postProcessInputRecursive(); + relPerm.postInputInitializationRecursive(); return relPerm; } @@ -231,7 +232,7 @@ RelativePermeabilityBase & makeVanGenuchtenStone2RelPermThreePhase( string const gasOilRelPermMaxVal.resize( 2 ); gasOilRelPermMaxVal[0] = 0.8; gasOilRelPermMaxVal[1] = 0.75; - relPerm.postProcessInputRecursive(); + relPerm.postInputInitializationRecursive(); return relPerm; } @@ -440,7 +441,7 @@ RelativePermeabilityBase & makeTableRelPermTwoPhase( string const & name, Group waterOilTableNames.resize( 2 ); waterOilTableNames[0] = "water_swg"; waterOilTableNames[1] = "gas_swg"; - relPerm.postProcessInputRecursive(); + relPerm.postInputInitializationRecursive(); relPerm.initialize(); // to test all the checks return relPerm; } @@ -750,7 +751,7 @@ RelativePermeabilityBase & makeTableRelPermHysteresisTwoPhase( string const & na auto & imbibitionGasTableName = relPerm.getReference< string >( keys::imbibitionNonWettingRelPermTableNameString() ); imbibitionGasTableName = "imbibitionGas_swg"; - relPerm.postProcessInputRecursive(); + relPerm.postInputInitializationRecursive(); relPerm.initialize(); // to test all the checks return relPerm; } @@ -832,7 +833,7 @@ RelativePermeabilityBase & makeTableRelPermThreePhase( string const & name, Grou gasOilTableNames.resize( 2 ); gasOilTableNames[0] = "gas_sgof"; gasOilTableNames[1] = "oil_sgof"; - relPerm.postProcessInputRecursive(); + relPerm.postInputInitializationRecursive(); relPerm.initialize(); // to test all the checks return relPerm; } diff --git a/src/coreComponents/unitTests/constitutiveTests/testRelPermHysteresis.cpp b/src/coreComponents/unitTests/constitutiveTests/testRelPermHysteresis.cpp index b4b8147c670..f6476d1d978 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testRelPermHysteresis.cpp +++ b/src/coreComponents/unitTests/constitutiveTests/testRelPermHysteresis.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -229,7 +230,7 @@ TableRelativePermeabilityHysteresis & makeTableRelPermHysteresisTwoPhase( string auto & imbibitionGasTableName = relPerm.getReference< string >( keys::imbibitionNonWettingRelPermTableNameString() ); imbibitionGasTableName = "imbibitionGas_swg"; - relPerm.postProcessInputRecursive(); + relPerm.postInputInitializationRecursive(); relPerm.initialize(); // to test all the checks return relPerm; } diff --git a/src/coreComponents/unitTests/constitutiveTests/testTriaxial.cpp b/src/coreComponents/unitTests/constitutiveTests/testTriaxial.cpp index 55d13951802..9dd8301388c 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testTriaxial.cpp +++ b/src/coreComponents/unitTests/constitutiveTests/testTriaxial.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -21,7 +22,7 @@ #include #include -// this unit test basically launches a full geosx instance, and then uses the +// this unit test basically launches a full geos instance, and then uses the // input xml to drive a triaxial (or similar) loading test TEST( testTriaxial, testTriaxial ) diff --git a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggCase1.xml b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggCase1.xml index b88f0be473f..f60770dd5e0 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggCase1.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggCase1.xml @@ -66,7 +66,7 @@ diff --git a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggCase2.xml b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggCase2.xml index f61bf8507bc..f89a07a98cf 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggCase2.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggCase2.xml @@ -65,7 +65,7 @@ diff --git a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggLoadPathDryUseLinear.xml b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggLoadPathDryUseLinear.xml index 4fb6558ae89..10ca3761690 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggLoadPathDryUseLinear.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggLoadPathDryUseLinear.xml @@ -66,7 +66,7 @@ diff --git a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggLoadPathWetUseLinear.xml b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggLoadPathWetUseLinear.xml index d365bb0e506..f8e2dd37298 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggLoadPathWetUseLinear.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggLoadPathWetUseLinear.xml @@ -66,7 +66,7 @@ diff --git a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggUseLinear.xml b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggUseLinear.xml index 69703b7ad1f..dd42c6b0330 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggUseLinear.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_delftEggUseLinear.xml @@ -66,7 +66,7 @@ diff --git a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_druckerPragerExtended.xml b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_druckerPragerExtended.xml index cd4849ab65b..f92445a9639 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_druckerPragerExtended.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_druckerPragerExtended.xml @@ -66,7 +66,7 @@ diff --git a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_elasticIsotropic.xml b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_elasticIsotropic.xml index 57beb56efc0..dde6e2b9a66 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_elasticIsotropic.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_elasticIsotropic.xml @@ -61,7 +61,7 @@ diff --git a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_elasticIsotropicPressureDependent.xml b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_elasticIsotropicPressureDependent.xml index 585599a36e3..beb0a7f5d99 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_elasticIsotropicPressureDependent.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_elasticIsotropicPressureDependent.xml @@ -57,7 +57,7 @@ diff --git a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_modifiedCamClay.xml b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_modifiedCamClay.xml index c1ae1b25dec..03b171303db 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_modifiedCamClay.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_modifiedCamClay.xml @@ -66,7 +66,7 @@ diff --git a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_modifiedCamClayVolumetric.xml b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_modifiedCamClayVolumetric.xml index d6075857430..b55ed3a520a 100644 --- a/src/coreComponents/unitTests/constitutiveTests/testTriaxial_modifiedCamClayVolumetric.xml +++ b/src/coreComponents/unitTests/constitutiveTests/testTriaxial_modifiedCamClayVolumetric.xml @@ -60,7 +60,7 @@ diff --git a/src/coreComponents/unitTests/dataRepositoryTests/CMakeLists.txt b/src/coreComponents/unitTests/dataRepositoryTests/CMakeLists.txt index 56a290d20b9..47b3b63d0a0 100644 --- a/src/coreComponents/unitTests/dataRepositoryTests/CMakeLists.txt +++ b/src/coreComponents/unitTests/dataRepositoryTests/CMakeLists.txt @@ -3,33 +3,15 @@ set( dataRepository_tests testObjectCatalog.cpp testRestartBasic.cpp testRestartExtended.cpp - testPacking.cpp testWrapperHelpers.cpp testGroupPath.cpp ) -set( dependencyList ${parallelDeps} gtest ) +set( tplDependencyList ${parallelDeps} gtest ) -if ( GEOSX_BUILD_SHARED_LIBS ) - list( APPEND dependencyList geosx_core ) -else() - list( APPEND dependencyList ${geosx_core_libs} ) -endif() +set( dependencyList mainInterface ) -if (TARGET pugixml::pugixml) - list( APPEND dependencyList pugixml::pugixml ) -endif() - -if (TARGET pugixml) - list( APPEND dependencyList pugixml ) -endif() - -if (TARGET fmt::fmt) - list( APPEND dependencyList fmt::fmt ) -endif() - -if (TARGET fmt) - list( APPEND dependencyList fmt ) -endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) # Add gtest C++ based tests foreach(test ${dataRepository_tests}) @@ -37,7 +19,7 @@ foreach(test ${dataRepository_tests}) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} ) + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} ) geos_add_test( NAME ${test_name} COMMAND ${test_name} ) diff --git a/src/coreComponents/unitTests/dataRepositoryTests/testGroupPath.cpp b/src/coreComponents/unitTests/dataRepositoryTests/testGroupPath.cpp index 71db7a13ddd..00e05ab421a 100644 --- a/src/coreComponents/unitTests/dataRepositoryTests/testGroupPath.cpp +++ b/src/coreComponents/unitTests/dataRepositoryTests/testGroupPath.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -66,7 +67,7 @@ TEST( testGroupPath, testGlobalPaths ) diff --git a/src/coreComponents/unitTests/dataRepositoryTests/testObjectCatalog.cpp b/src/coreComponents/unitTests/dataRepositoryTests/testObjectCatalog.cpp index 1fef5477fa4..586e4fb3bc3 100644 --- a/src/coreComponents/unitTests/dataRepositoryTests/testObjectCatalog.cpp +++ b/src/coreComponents/unitTests/dataRepositoryTests/testObjectCatalog.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,7 +17,7 @@ // Source includes #include "dataRepository/ObjectCatalog.hpp" -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" #include "mainInterface/initialization.hpp" // TPL includes diff --git a/src/coreComponents/unitTests/dataRepositoryTests/testRestartBasic.cpp b/src/coreComponents/unitTests/dataRepositoryTests/testRestartBasic.cpp index 829a0abff95..e7e061384cb 100644 --- a/src/coreComponents/unitTests/dataRepositoryTests/testRestartBasic.cpp +++ b/src/coreComponents/unitTests/dataRepositoryTests/testRestartBasic.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -67,7 +68,7 @@ class SingleWrapperTest : public ::testing::Test writeTree( m_fileName, *m_node ); m_group->finishWriting(); - // Delete geosx tree and reset the conduit tree. + // Delete geos tree and reset the conduit tree. m_group = nullptr; m_node = std::make_unique< conduit::Node >(); diff --git a/src/coreComponents/unitTests/dataRepositoryTests/testRestartExtended.cpp b/src/coreComponents/unitTests/dataRepositoryTests/testRestartExtended.cpp index 8a44b9f6db6..7acc2d9b07f 100644 --- a/src/coreComponents/unitTests/dataRepositoryTests/testRestartExtended.cpp +++ b/src/coreComponents/unitTests/dataRepositoryTests/testRestartExtended.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/unitTests/dataRepositoryTests/testWrapperHelpers.cpp b/src/coreComponents/unitTests/dataRepositoryTests/testWrapperHelpers.cpp index 47d24fb9fea..b93b4615e8c 100644 --- a/src/coreComponents/unitTests/dataRepositoryTests/testWrapperHelpers.cpp +++ b/src/coreComponents/unitTests/dataRepositoryTests/testWrapperHelpers.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/unitTests/dataRepositoryTests/utils.hpp b/src/coreComponents/unitTests/dataRepositoryTests/utils.hpp index a2618342263..9757182f66d 100644 --- a/src/coreComponents/unitTests/dataRepositoryTests/utils.hpp +++ b/src/coreComponents/unitTests/dataRepositoryTests/utils.hpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + /// Source includes #include "common/DataTypes.hpp" @@ -131,4 +146,4 @@ void compare( SortedArray< T > const & val, } // namespace testing } // namespace dataRepository -} // namesapce geosx +} // namespace geos diff --git a/src/coreComponents/unitTests/fieldSpecificationTests/CMakeLists.txt b/src/coreComponents/unitTests/fieldSpecificationTests/CMakeLists.txt index a49b0723762..d66f6661e22 100644 --- a/src/coreComponents/unitTests/fieldSpecificationTests/CMakeLists.txt +++ b/src/coreComponents/unitTests/fieldSpecificationTests/CMakeLists.txt @@ -5,37 +5,20 @@ set( gtest_geosx_tests testRecursiveFieldApplication.cpp ) -set( dependencyList ${parallelDeps} gtest ) +set( tplDependencyList ${parallelDeps} gtest ) -if ( GEOSX_BUILD_SHARED_LIBS ) - list( APPEND dependencyList geosx_core ) -else() - list( APPEND dependencyList ${geosx_core_libs} ) -endif() - -if (TARGET pugixml::pugixml) - list( APPEND dependencyList pugixml::pugixml ) -endif() - -if (TARGET pugixml) - list( APPEND dependencyList pugixml ) -endif() - -if (TARGET fmt::fmt) - list( APPEND dependencyList fmt::fmt ) -endif() - -if (TARGET fmt) - list( APPEND dependencyList fmt ) -endif() +set( dependencyList mainInterface ) +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) + # Add gtest C++ based tests foreach(test ${gtest_geosx_tests}) get_filename_component( test_name ${test} NAME_WE ) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} ) + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} ) geos_add_test( NAME ${test_name} COMMAND ${test_name} ) diff --git a/src/coreComponents/unitTests/fieldSpecificationTests/testAquiferBoundaryCondition.cpp b/src/coreComponents/unitTests/fieldSpecificationTests/testAquiferBoundaryCondition.cpp index 13b44c36d6a..9d20070af07 100644 --- a/src/coreComponents/unitTests/fieldSpecificationTests/testAquiferBoundaryCondition.cpp +++ b/src/coreComponents/unitTests/fieldSpecificationTests/testAquiferBoundaryCondition.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -36,7 +37,7 @@ TEST( FieldSpecification, Aquifer ) AquiferBoundaryCondition & aquiferBC = dynamicCast< AquiferBoundaryCondition & >( *fieldSpecificationManager.createChild( "Aquifer", "aquiferBoundaryCondition" ) ); - // set up the aquifer as in the simulation matched against IX + // set up the aquifer auto & aquiferPorosity = aquiferBC.getReference< real64 >( AquiferBoundaryCondition::viewKeyStruct::aquiferPorosityString() ); aquiferPorosity = 2e-1; @@ -68,7 +69,7 @@ TEST( FieldSpecification, Aquifer ) auto & aquiferAngle = aquiferBC.getReference< real64 >( AquiferBoundaryCondition::viewKeyStruct::aquiferAngleString() ); aquiferAngle = 20.0; - aquiferBC.postProcessInputRecursive(); + aquiferBC.postInputInitializationRecursive(); AquiferBoundaryCondition::KernelWrapper aquiferBCWrapper = aquiferBC.createKernelWrapper(); @@ -88,7 +89,7 @@ TEST( FieldSpecification, Aquifer ) areaFraction, dAquiferVolFlux_dPres ); - // observed flux value in the simulation matched against IX + // observed flux value real64 const refAquiferVolFlux = -0.2043541482797776; ASSERT_NEAR( refAquiferVolFlux, aquiferVolFlux, 1e-10 ); diff --git a/src/coreComponents/unitTests/fieldSpecificationTests/testFieldSpecificationsEnums.cpp b/src/coreComponents/unitTests/fieldSpecificationTests/testFieldSpecificationsEnums.cpp index 7ca39a7fbcd..0f800b4e8aa 100644 --- a/src/coreComponents/unitTests/fieldSpecificationTests/testFieldSpecificationsEnums.cpp +++ b/src/coreComponents/unitTests/fieldSpecificationTests/testFieldSpecificationsEnums.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2020- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/unitTests/fieldSpecificationTests/testRecursiveFieldApplication.cpp b/src/coreComponents/unitTests/fieldSpecificationTests/testRecursiveFieldApplication.cpp index b6fb7916eee..0e948a64332 100644 --- a/src/coreComponents/unitTests/fieldSpecificationTests/testRecursiveFieldApplication.cpp +++ b/src/coreComponents/unitTests/fieldSpecificationTests/testRecursiveFieldApplication.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -19,6 +20,7 @@ #include "fieldSpecification/FieldSpecificationManager.hpp" #include "mesh/DomainPartition.hpp" #include "mesh/generators/CellBlockManager.hpp" +#include "mesh/CellElementRegionSelector.hpp" #include "common/GEOS_RAJA_Interface.hpp" #include "common/DataTypes.hpp" #include "common/TimingMacros.hpp" @@ -97,13 +99,15 @@ TEST( FieldSpecification, Recursive ) reg1Tet.setElementType( geos::ElementType::Tetrahedron ); reg1Tet.resize( nbTetReg1 ); + Group const & cellBlocks = cellBlockManager.getCellBlocks(); + reg0.addCellBlockName( reg0Hex.getName() ); reg0.addCellBlockName( reg0Tet.getName() ); - reg0.generateMesh( cellBlockManager.getCellBlocks() ); + reg0.generateMesh( cellBlocks ); reg1.addCellBlockName( reg1Hex.getName() ); reg1.addCellBlockName( reg1Tet.getName() ); - reg1.generateMesh( cellBlockManager.getCellBlocks() ); + reg1.generateMesh( cellBlocks ); // The cell block manager should not be used anymore. domain.deregisterGroup( keys::cellManager ); diff --git a/src/coreComponents/unitTests/fileIOTests/CMakeLists.txt b/src/coreComponents/unitTests/fileIOTests/CMakeLists.txt index a5caf07fcd7..7bf5498da5b 100644 --- a/src/coreComponents/unitTests/fileIOTests/CMakeLists.txt +++ b/src/coreComponents/unitTests/fileIOTests/CMakeLists.txt @@ -1,13 +1,12 @@ # Specify list of tests set( geosx_fileio_tests testHDFFile.cpp ) -set( dependencyList ${parallelDeps} gtest hdf5 ) +set( tplDependencyList ${parallelDeps} gtest ) -if ( GEOSX_BUILD_SHARED_LIBS ) - list( APPEND dependencyList geosx_core ) -else() - list( APPEND dependencyList ${geosx_core_libs} ) -endif() +set( dependencyList mainInterface ) + +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) # Add gtest C++ based tests foreach(test ${geosx_fileio_tests}) @@ -15,7 +14,7 @@ foreach(test ${geosx_fileio_tests}) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} ) + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} ) geos_add_test( NAME ${test_name} COMMAND ${test_name} ) @@ -32,7 +31,7 @@ if ( ENABLE_MPI ) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} ) + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} ) geos_add_test( NAME ${test_name} COMMAND ${test_name} diff --git a/src/coreComponents/unitTests/fileIOTests/testHDFFile.cpp b/src/coreComponents/unitTests/fileIOTests/testHDFFile.cpp index 8cacbc775d9..52ca62882cf 100644 --- a/src/coreComponents/unitTests/fileIOTests/testHDFFile.cpp +++ b/src/coreComponents/unitTests/fileIOTests/testHDFFile.cpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #include "fileIO/timeHistory/HDFHistoryIO.hpp" #include "fileIO/timeHistory/HDFFile.hpp" #include "mainInterface/initialization.hpp" diff --git a/src/coreComponents/unitTests/fileIOTests/testHDFParallelFile.cpp b/src/coreComponents/unitTests/fileIOTests/testHDFParallelFile.cpp index 0a45233b6bc..cbe2d9ae140 100644 --- a/src/coreComponents/unitTests/fileIOTests/testHDFParallelFile.cpp +++ b/src/coreComponents/unitTests/fileIOTests/testHDFParallelFile.cpp @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #include "fileIO/timeHistory/HDFHistoryIO.hpp" #include "common/TimingMacros.hpp" #include "mainInterface/initialization.hpp" diff --git a/src/coreComponents/unitTests/finiteVolumeTests/CMakeLists.txt b/src/coreComponents/unitTests/finiteVolumeTests/CMakeLists.txt index e83e9f2cbb1..d809c09d7c3 100644 --- a/src/coreComponents/unitTests/finiteVolumeTests/CMakeLists.txt +++ b/src/coreComponents/unitTests/finiteVolumeTests/CMakeLists.txt @@ -2,21 +2,20 @@ set( gtest_geosx_tests testMimeticInnerProducts.cpp ) -set( dependencyList ${parallelDeps} gtest ) - -if ( GEOSX_BUILD_SHARED_LIBS ) - list( APPEND dependencyList geosx_core ) -else() - list( APPEND dependencyList ${geosx_core_libs} ) -endif() +set( tplDependencyList ${parallelDeps} gtest ) +set( dependencyList mainInterface ) + +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) + # Add gtest C++ based tests foreach(test ${gtest_geosx_tests}) get_filename_component( test_name ${test} NAME_WE ) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} ) + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} ) # Guard to prevent GCC (version 8) from giving warnings due # to some sort of possible conversion from int to long unsigned. diff --git a/src/coreComponents/unitTests/finiteVolumeTests/testMimeticInnerProducts.cpp b/src/coreComponents/unitTests/finiteVolumeTests/testMimeticInnerProducts.cpp index 3e9c1830ae0..b00f24fc4e3 100644 --- a/src/coreComponents/unitTests/finiteVolumeTests/testMimeticInnerProducts.cpp +++ b/src/coreComponents/unitTests/finiteVolumeTests/testMimeticInnerProducts.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -14,7 +15,7 @@ // Source includes #include "codingUtilities/UnitTestUtilities.hpp" -#include "common/Logger.hpp" +#include "common/logger/Logger.hpp" #include "finiteVolume/mimeticInnerProducts/MimeticInnerProductBase.hpp" #include "finiteVolume/mimeticInnerProducts/TPFAInnerProduct.hpp" #include "finiteVolume/mimeticInnerProducts/QuasiTPFAInnerProduct.hpp" diff --git a/src/coreComponents/unitTests/fluidFlowTests/CMakeLists.txt b/src/coreComponents/unitTests/fluidFlowTests/CMakeLists.txt index 597d97dff87..800fae6f0db 100644 --- a/src/coreComponents/unitTests/fluidFlowTests/CMakeLists.txt +++ b/src/coreComponents/unitTests/fluidFlowTests/CMakeLists.txt @@ -1,42 +1,24 @@ # Specify list of tests set( gtest_geosx_tests - testSinglePhaseBaseKernels.cpp + testSinglePhaseMobilityKernel.cpp testThermalCompMultiphaseFlow.cpp - testThermalSinglePhaseFlow.cpp ) - -set( dependencyList ${parallelDeps} gtest ) - -if ( GEOSX_BUILD_SHARED_LIBS ) - list( APPEND dependencyList geosx_core ) -else() - list( APPEND dependencyList ${geosx_core_libs} ) -endif() - + testThermalSinglePhaseFlow.cpp + testFlowStatistics.cpp + testTransmissibility.cpp ) if( ENABLE_PVTPackage ) list( APPEND gtest_geosx_tests testCompMultiphaseFlow.cpp testCompMultiphaseFlowHybrid.cpp testReactiveCompositionalMultiphaseOBL.cpp ) - - list( APPEND dependencyList PVTPackage ) endif() -if (TARGET pugixml::pugixml) - list( APPEND dependencyList pugixml::pugixml ) -endif() +set( tplDependencyList ${parallelDeps} gtest ) -if (TARGET pugixml) - list( APPEND dependencyList pugixml ) -endif() +set( dependencyList mainInterface testingUtilities ) -if (TARGET fmt::fmt) - list( APPEND dependencyList fmt::fmt ) -endif() - -if (TARGET fmt) - list( APPEND dependencyList fmt ) -endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) # Add gtest C++ based tests foreach(test ${gtest_geosx_tests}) @@ -45,7 +27,7 @@ foreach(test ${gtest_geosx_tests}) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} ) + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} ) geos_add_test( NAME ${test_name} COMMAND ${test_name} ) diff --git a/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp b/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp index 5b336a0481a..d9790a2aa7b 100644 --- a/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp +++ b/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -24,6 +25,7 @@ #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "testFlowUtils.hpp" namespace geos { @@ -31,139 +33,7 @@ namespace geos namespace testing { -using namespace geos::constitutive; -using namespace geos::constitutive::multifluid; - -void checkDerivative( real64 const valueEps, - real64 const value, - real64 const deriv, - real64 const eps, - real64 const relTol, - real64 const absTol, - string const & name, - string const & var ) -{ - real64 const numDeriv = (valueEps - value) / eps; - checkRelativeError( deriv, numDeriv, relTol, absTol, "d(" + name + ")/d(" + var + ")" ); -} - -void checkDerivative( real64 const valueEps, - real64 const value, - real64 const deriv, - real64 const eps, - real64 const relTol, - string const & name, - string const & var ) -{ return checkDerivative( valueEps, value, deriv, eps, relTol, DEFAULT_ABS_TOL, name, var ); } - -template< int USD1, int USD2, int USD3 > -void checkDerivative( arraySlice1d< real64 const, USD1 > const & valueEps, - arraySlice1d< real64 const, USD2 > const & value, - arraySlice1d< real64 const, USD3 > const & deriv, - real64 const eps, - real64 const relTol, - real64 const absTol, - string const & name, - string const & var, - arrayView1d< string const > const & labels ) -{ - localIndex const size = labels.size( 0 ); - - for( localIndex i = 0; i < size; ++i ) - { - checkDerivative( valueEps[i], value[i], deriv[i], eps, relTol, absTol, - name + "[" + labels[i] + "]", var ); - } -} - -template< int DIM, int USD1, int USD2, int USD3, typename ... Args > -void checkDerivative( ArraySlice< real64 const, DIM, USD1 > const & valueEps, - ArraySlice< real64 const, DIM, USD2 > const & value, - ArraySlice< real64 const, DIM, USD3 > const & deriv, - real64 const eps, - real64 const relTol, - real64 const absTol, - string const & name, - string const & var, - arrayView1d< string const > const & labels, - Args ... label_lists ) -{ - localIndex const size = labels.size( 0 ); - - for( localIndex i = 0; i < size; ++i ) - { - checkDerivative( valueEps[i], value[i], deriv[i], eps, relTol, absTol, - name + "[" + labels[i] + "]", var, label_lists ... ); - } -} - -template< int DIM, int USD1, int USD2, int USD3, typename ... Args > -void checkDerivative( ArraySlice< real64 const, DIM, USD1 > const & valueEps, - ArraySlice< real64 const, DIM, USD2 > const & value, - ArraySlice< real64 const, DIM, USD3 > const & deriv, - real64 const eps, - real64 const relTol, - string const & name, - string const & var, - arrayView1d< string const > const & labels, - Args ... label_lists ) -{ return checkDerivative( valueEps, value, deriv, eps, relTol, DEFAULT_ABS_TOL, name, var, labels, label_lists ... ); } - -// invert compositional derivative array layout to move innermost slice on the top -// (this is needed so we can use checkDerivative() to check derivative w.r.t. for each compositional var) -template< int USD > -array1d< real64 > invertLayout( arraySlice1d< real64 const, USD > const & input, - localIndex N ) -{ - array1d< real64 > output( N ); - for( int i = 0; i < N; ++i ) - { - output[i] = input[i]; - } - - return output; -} - -template< int USD > -array2d< real64 > invertLayout( arraySlice2d< real64 const, USD > const & input, - localIndex N1, - localIndex N2 ) -{ - array2d< real64 > output( N2, N1 ); - - for( localIndex i = 0; i < N1; ++i ) - { - for( localIndex j = 0; j < N2; ++j ) - { - output( j, i ) = input( i, j ); - } - } - - return output; -} - -template< int USD > -array3d< real64 > invertLayout( arraySlice3d< real64 const, USD > const & input, - localIndex N1, - localIndex N2, - localIndex N3 ) -{ - array3d< real64 > output( N3, N1, N2 ); - - for( localIndex i = 0; i < N1; ++i ) - { - for( localIndex j = 0; j < N2; ++j ) - { - for( localIndex k = 0; k < N3; ++k ) - { - output( k, i, j ) = input( i, j, k ); - } - } - } - - return output; -} - +inline void fillNumericalJacobian( arrayView1d< real64 const > const & residual, arrayView1d< real64 const > const & residualOrig, globalIndex const dofIndex, @@ -180,6 +50,20 @@ void fillNumericalJacobian( arrayView1d< real64 const > const & residual, } ); } +inline +void setNumericalJacobianValue( localIndex const rowIndex, + globalIndex const colIndex, + real64 const val, + CRSMatrixView< real64, const globalIndex > const jacobian ) +{ + forAll< parallelDevicePolicy<> >( 1, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + GEOS_UNUSED_VAR( k ); + jacobian.addToRow< parallelDeviceAtomic >( rowIndex, &colIndex, &val, 1 ); + } ); +} + +inline void setupProblemFromXML( ProblemManager & problemManager, char const * const xmlInput ) { xmlWrapper::xmlDocument xmlDocument; @@ -191,7 +75,7 @@ void setupProblemFromXML( ProblemManager & problemManager, char const * const xm GEOS_LOG_RANK_0( "Error offset: " << xmlResult.offset ); } - int mpiSize = MpiWrapper::commSize( MPI_COMM_GEOSX ); + int mpiSize = MpiWrapper::commSize( MPI_COMM_GEOS ); dataRepository::Group & commandLine = problemManager.getGroup< dataRepository::Group >( problemManager.groupKeys.commandLine ); @@ -219,6 +103,7 @@ void setupProblemFromXML( ProblemManager & problemManager, char const * const xm problemManager.applyInitialConditions(); } +inline void testCompositionNumericalDerivatives( CompositionalMultiphaseFVM & solver, DomainPartition & domain, real64 const perturbParameter, @@ -239,7 +124,7 @@ void testCompositionNumericalDerivatives( CompositionalMultiphaseFVM & solver, SCOPED_TRACE( subRegion.getParent().getParent().getName() + "/" + subRegion.getName() ); string const & fluidName = subRegion.getReference< string >( CompositionalMultiphaseBase::viewKeyStruct::fluidNamesString() ); - MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); + constitutive::MultiFluidBase const & fluid = subRegion.getConstitutiveModel< constitutive::MultiFluidBase >( fluidName ); arrayView1d< string const > const & components = fluid.componentNames(); arrayView2d< real64, compflow::USD_COMP > const compDens = @@ -299,13 +184,14 @@ void testCompositionNumericalDerivatives( CompositionalMultiphaseFVM & solver, } ); } +inline void testPhaseVolumeFractionNumericalDerivatives( CompositionalMultiphaseFVM & solver, DomainPartition & domain, bool const isThermal, real64 const perturbParameter, real64 const relTol ) { - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; integer const numComp = solver.numFluidComponents(); integer const numPhase = solver.numFluidPhases(); @@ -323,7 +209,7 @@ void testPhaseVolumeFractionNumericalDerivatives( CompositionalMultiphaseFVM & s SCOPED_TRACE( subRegion.getParent().getParent().getName() + "/" + subRegion.getName() ); string const & fluidName = subRegion.getReference< string >( CompositionalMultiphaseFVM::viewKeyStruct::fluidNamesString() ); - MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); + constitutive::MultiFluidBase const & fluid = subRegion.getConstitutiveModel< constitutive::MultiFluidBase >( fluidName ); arrayView1d< string const > const & components = fluid.componentNames(); arrayView1d< string const > const & phases = fluid.phaseNames(); @@ -463,13 +349,14 @@ void testPhaseVolumeFractionNumericalDerivatives( CompositionalMultiphaseFVM & s } ); } +inline void testPhaseMobilityNumericalDerivatives( CompositionalMultiphaseFVM & solver, DomainPartition & domain, bool const isThermal, real64 const perturbParameter, real64 const relTol ) { - using Deriv = multifluid::DerivativeOffset; + using Deriv = constitutive::multifluid::DerivativeOffset; integer const numComp = solver.numFluidComponents(); integer const numPhase = solver.numFluidPhases(); @@ -487,7 +374,7 @@ void testPhaseMobilityNumericalDerivatives( CompositionalMultiphaseFVM & solver, SCOPED_TRACE( subRegion.getParent().getParent().getName() + "/" + subRegion.getName() ); string const & fluidName = subRegion.getReference< string >( CompositionalMultiphaseFVM::viewKeyStruct::fluidNamesString() ); - MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); + constitutive::MultiFluidBase const & fluid = subRegion.getConstitutiveModel< constitutive::MultiFluidBase >( fluidName ); arrayView1d< string const > const & components = fluid.componentNames(); arrayView1d< string const > const & phases = fluid.phaseNames(); @@ -628,16 +515,17 @@ void testPhaseMobilityNumericalDerivatives( CompositionalMultiphaseFVM & solver, } ); } + template< typename COMPOSITIONAL_SOLVER, typename LAMBDA > -void fillCellCenteredNumericalJacobian( COMPOSITIONAL_SOLVER & solver, - DomainPartition & domain, - bool const isThermal, - real64 const perturbParameter, - arrayView1d< real64 > residual, - arrayView1d< real64 > residualOrig, - CRSMatrixView< real64, globalIndex > jacobian, - CRSMatrixView< real64, globalIndex > jacobianFD, - LAMBDA assembleFunction ) +inline void fillCellCenteredNumericalJacobian( COMPOSITIONAL_SOLVER & solver, + DomainPartition & domain, + bool const isThermal, + real64 const perturbParameter, + arrayView1d< real64 > residual, + arrayView1d< real64 > residualOrig, + CRSMatrixView< real64, globalIndex > jacobian, + CRSMatrixView< real64, globalIndex > jacobianFD, + LAMBDA assembleFunction ) { integer const numComp = solver.numFluidComponents(); diff --git a/src/coreComponents/unitTests/fluidFlowTests/testCompMultiphaseFlow.cpp b/src/coreComponents/unitTests/fluidFlowTests/testCompMultiphaseFlow.cpp index ebac3870bb1..0bb997307cc 100644 --- a/src/coreComponents/unitTests/fluidFlowTests/testCompMultiphaseFlow.cpp +++ b/src/coreComponents/unitTests/fluidFlowTests/testCompMultiphaseFlow.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -67,7 +68,7 @@ char const * xmlInput = - + - + + + +using namespace geos; +using namespace geos::dataRepository; +using namespace geos::testing; + +CommandLineOptions g_commandLineOptions; + + +//////////////////////////////// Test base utilities //////////////////////////////// + + +/** + * @brief this struct is used to provide the input data of each flow tests + */ +struct TestInputs +{ + string xmlInput; + std::map< string, string > tableFiles; + + string sourceFluxName; + string sinkFluxName; + string timeStepCheckerPath; + string timeStepFluxStatsPath; + string wholeSimFluxStatsPath; + string flowSolverPath; + + // rates for each timesteps, for each phases + array2d< real64 > sourceRates; + array2d< real64 > sinkRates; + + // parameters for precomputing results + real64 dt; + real64 sourceRateFactor; + real64 sinkRateFactor; + integer sourceElementsCount; + integer sinkElementsCount; + + /// In order to be sure that sub-timestepping is supported, requires the test to have at least one sub-timestep. + /// At least one simulation should test the timestep cuts ! + integer requiredSubTimeStep = 0; +}; + +/** + * @brief this struct computes from the test inputs the values to expect from the simulation. + */ +struct TestSet +{ + TestInputs const inputs; + + integer timestepCount; + integer totalElementsCount; + integer phaseCount; + + // stats for each timesteps, for each phases + array2d< real64 > sourceRates; + array2d< real64 > sinkRates; + array2d< real64 > sourceMassProd; + array2d< real64 > sinkMassProd; + array2d< real64 > massDeltas; + + // overall simulation stats for each phases + array1d< real64 > sourceMeanRate; + array1d< real64 > sinkMeanRate; + array1d< real64 > totalSourceMassProd; + array1d< real64 > totalSinkMassProd; + array1d< real64 > totalMassProd; + array1d< real64 > totalMeanRate; + + /** + * @brief Compute the expected statistics set for the tested simulation. + * @param inputParams the test simulation input parameters + */ + TestSet( TestInputs const & inputParams ): + inputs( inputParams ) + { + // tables must provide the same timestep & phase rates + EXPECT_EQ( inputs.sourceRates.size( 0 ), inputs.sinkRates.size( 0 )); + EXPECT_EQ( inputs.sourceRates.size( 1 ), inputs.sinkRates.size( 1 )); + + timestepCount = inputs.sourceRates.size( 0 ); + phaseCount = inputs.sourceRates.size( 1 ); + totalElementsCount = inputs.sourceElementsCount + inputs.sinkElementsCount; + + sourceRates.resize( timestepCount, phaseCount ); + sinkRates.resize( timestepCount, phaseCount ); + sourceMassProd.resize( timestepCount, phaseCount ); + sinkMassProd.resize( timestepCount, phaseCount ); + massDeltas.resize( timestepCount, phaseCount ); + sourceMeanRate.resize( phaseCount ); + sinkMeanRate.resize( phaseCount ); + totalSourceMassProd.resize( phaseCount ); + totalSinkMassProd.resize( phaseCount ); + totalMassProd.resize( phaseCount ); + totalMeanRate.resize( phaseCount ); + + for( integer ip = 0; ip < phaseCount; ++ip ) + { + for( integer timestepId = 0; timestepId < timestepCount; ++timestepId ) + { + // mass production / injection calculation + sourceRates[timestepId][ip] = inputs.sourceRates[timestepId][ip] * inputs.sourceRateFactor; + sourceMassProd[timestepId][ip] = inputs.sourceRates[timestepId][ip] * inputs.dt * inputs.sourceRateFactor; + totalSourceMassProd[ip] += sourceMassProd[timestepId][ip]; + sinkRates[timestepId][ip] = inputs.sinkRates[timestepId][ip] * inputs.sinkRateFactor; + sinkMassProd[timestepId][ip] = inputs.sinkRates[timestepId][ip] * inputs.dt * inputs.sinkRateFactor; + massDeltas[timestepId][ip] = -( sourceMassProd[timestepId][ip] + sinkMassProd[timestepId][ip] ); + totalSinkMassProd[ip] += sinkMassProd[timestepId][ip]; + // rates accumulations + sourceMeanRate[ip] += inputs.sourceRates[timestepId][ip] * inputs.sourceRateFactor; + sinkMeanRate[ip] += inputs.sinkRates[timestepId][ip] * inputs.sinkRateFactor; + } + // mean rates calculation + real64 const ratesMeanDivisor = 1.0 / double( timestepCount - 1 ); + sourceMeanRate[ip] *= ratesMeanDivisor; + sinkMeanRate[ip] *= ratesMeanDivisor; + // totals + totalMassProd[ip] = totalSinkMassProd[ip] + totalSourceMassProd[ip]; + totalMeanRate[ip] = sinkMeanRate[ip] + sourceMeanRate[ip]; + } + } +}; + + +class FlowStatisticsTest : public ::testing::Test +{ +public: + + void writeTableFiles( std::map< string, string > const & files ) + { + for( auto const & [fileName, content] : files ) + { + std::ofstream os( fileName ); + ASSERT_TRUE( os.is_open() ); + os << content; + os.close(); + + m_tableFileNames.push_back( fileName ); + } + } + + void TearDown() override + { + // removing temp table files + for( string const & fileName : m_tableFileNames ) + { + ASSERT_TRUE( std::remove( fileName.c_str() ) == 0 ); + } + m_tableFileNames.clear(); + } + +private: + std::vector< string > m_tableFileNames; +}; + + +void setRateTable( array2d< real64 > & rateTable, std::initializer_list< std::initializer_list< real64 > > timestepPhaseValues ) +{ + rateTable.resize( timestepPhaseValues.size(), timestepPhaseValues.begin()->size() ); + integer timestepId = 0; + for( auto const & phaseValues : timestepPhaseValues ) + { + integer ip = 0; + for( auto const & phaseValue : phaseValues ) + { + rateTable[timestepId][ip++] = phaseValue; + } + ++timestepId; + } +} + +real64 getTotalFluidMass( ProblemManager & problem, string_view flowSolverPath ) +{ + real64 totalMass = 0.0; + PhysicsSolverBase const & solver = problem.getGroupByPath< PhysicsSolverBase >( string( flowSolverPath ) ); + solver.forDiscretizationOnMeshTargets( problem.getDomainPartition().getMeshBodies(), + [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & ) + { + mesh.getElemManager().forElementRegions( [&]( ElementRegionBase & region ) + { + SinglePhaseStatistics::RegionStatistics & regionStats = region.getReference< SinglePhaseStatistics::RegionStatistics >( + SinglePhaseStatistics::viewKeyStruct::regionStatisticsString() ); + + totalMass += regionStats.totalMass; + } ); + } ); + return totalMass; +} + + +/** + * @brief Verification that the source flux statistics are correct for the current timestep + * @param expectedMasses the expected mass values per phase + * @param expectedRates the expected rate values per phase + * @param expectedElementCount the number of expected targeted elements + * @param stats the timestep stats + * @param context a context string to provide in any error message. + */ +void checkFluxStats( arraySlice1d< real64 > const & expectedMasses, + arraySlice1d< real64 > const & expectedRates, + integer const expectedElementCount, + SourceFluxStatsAggregator::WrappedStats const & stats, + string_view context ) +{ + for( int ip = 0; ip < stats.stats().getPhaseCount(); ++ip ) + { + EXPECT_DOUBLE_EQ( stats.stats().m_producedMass[ip], expectedMasses[ip] ) << GEOS_FMT( "The flux named '{}' did not produce the expected mass ({}, phase = {}).", + stats.getFluxName(), context, ip ); + EXPECT_DOUBLE_EQ( stats.stats().m_productionRate[ip], expectedRates[ip] ) << GEOS_FMT( "The flux named '{}' did not produce at the expected rate ({}, phase = {}).", + stats.getFluxName(), context, ip ); + } + EXPECT_DOUBLE_EQ( stats.stats().m_elementCount, expectedElementCount ) << GEOS_FMT( "The flux named '{}' did not produce in the expected elements ({}).", + stats.getFluxName(), context ); +} + +/** + * @brief Verification that the source flux statistics are correct over the whole simulation + * @param problem the simulation ProblemManager + * @param testSet the simulation TestSet + */ +void checkWholeSimFluxStats( ProblemManager & problem, TestSet const & testSet ) +{ + DomainPartition & domain = problem.getDomainPartition(); + SourceFluxStatsAggregator & wholeSimStats = + problem.getGroupByPath< SourceFluxStatsAggregator >( testSet.inputs.wholeSimFluxStatsPath ); + + wholeSimStats.forMeshLevelStatsWrapper( domain, + [&] ( MeshLevel & meshLevel, + SourceFluxStatsAggregator::WrappedStats & meshLevelStats ) + { + wholeSimStats.forAllFluxStatsWrappers( meshLevel, + [&] ( MeshLevel &, + SourceFluxStatsAggregator::WrappedStats & fluxStats ) + { + if( fluxStats.getFluxName() == testSet.inputs.sourceFluxName ) + { + checkFluxStats( testSet.totalSourceMassProd, + testSet.sourceMeanRate, + testSet.inputs.sourceElementsCount, + fluxStats, "over whole simulation" ); + } + else if( fluxStats.getFluxName() == testSet.inputs.sinkFluxName ) + { + checkFluxStats( testSet.totalSinkMassProd, + testSet.sinkMeanRate, + testSet.inputs.sinkElementsCount, + fluxStats, "over whole simulation" ); + } + else + { + FAIL() << "Unexpected SourceFlux found!"; + } + } ); + + for( int ip = 0; ip < meshLevelStats.stats().getPhaseCount(); ++ip ) + { + EXPECT_DOUBLE_EQ( meshLevelStats.stats().m_producedMass[ip], testSet.totalMassProd[ip] ) << "The fluxes did not produce the expected total mass (over whole simulation, phase = " << ip << ")."; + EXPECT_DOUBLE_EQ( meshLevelStats.stats().m_productionRate[ip], testSet.totalMeanRate[ip] ) << "The fluxes did not produce at the expected rate (over whole simulation, phase = " << ip << ")."; + } + } ); +} + +/** + * @brief Verification that the source flux statistics are correct for a given timestep + * @param problem the simulation ProblemManager + * @param testSet the simulation TestSet + * @param time_n the current timestep start + * @param timestepId the current timestep id (= cycle) + */ +void checkTimeStepFluxStats( ProblemManager & problem, TestSet const & testSet, + real64 const time_n, integer const timestepId ) +{ + DomainPartition & domain = problem.getDomainPartition(); + SourceFluxStatsAggregator & timestepStats = + problem.getGroupByPath< SourceFluxStatsAggregator >( testSet.inputs.timeStepFluxStatsPath ); + + timestepStats.forMeshLevelStatsWrapper( domain, + [&] ( MeshLevel & meshLevel, + SourceFluxStatsAggregator::WrappedStats & ) + { + timestepStats.forAllFluxStatsWrappers( meshLevel, + [&] ( MeshLevel &, + SourceFluxStatsAggregator::WrappedStats & fluxStats ) + { + if( fluxStats.getFluxName() == testSet.inputs.sourceFluxName ) + { + checkFluxStats( testSet.sourceMassProd[timestepId], + testSet.sourceRates[timestepId], + testSet.inputs.sourceElementsCount, + fluxStats, GEOS_FMT( "for timestep at t = {} s", time_n ) ); + } + else if( fluxStats.getFluxName() == testSet.inputs.sinkFluxName ) + { + checkFluxStats( testSet.sinkMassProd[timestepId], + testSet.sinkRates[timestepId], + testSet.inputs.sinkElementsCount, + fluxStats, GEOS_FMT( "for timestep at t = {} s", time_n ) ); + } + else + { + FAIL() << "Unexpected SourceFlux found!"; + } + } ); + } ); +} + +void checkTimeStepStats( TestSet const & testSet, + real64 const time_n, + integer const timestepId ) +{ + EXPECT_LT( timestepId, testSet.timestepCount ) << GEOS_FMT( "The tested time-step count were higher than expected (t = {} s).", + time_n ); +} + +void checkWholeSimTimeStepStats( ProblemManager & problem, + TestSet const & testSet, + TimeStepChecker const & timeStepChecker ) +{ + EXPECT_EQ( timeStepChecker.getTestedTimeStepCount(), testSet.timestepCount ) << "The tested time-step were different than expected."; + + PhysicsSolverBase const & solver = problem.getGroupByPath< PhysicsSolverBase >( testSet.inputs.flowSolverPath ); + SolverStatistics const & solverStats = solver.getSolverStatistics(); + EXPECT_GE( solverStats.getNumTimeStepCuts(), testSet.inputs.requiredSubTimeStep ) << "The test did not encountered any timestep cut, but were expected to. " + "Consider adapting the simulation so a timestep cut occurs to check they work as expected."; +} + + +//////////////////////////////// SinglePhase Flux Statistics Test //////////////////////////////// +namespace SinglePhaseFluxStatisticsTest +{ + + +TestSet getTestSet() +{ + TestInputs testInputs; + + testInputs.xmlInput = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +)xml"; + + + testInputs.sourceFluxName = "sourceFlux"; + testInputs.sinkFluxName = "sinkFlux"; + testInputs.timeStepCheckerPath = "/Tasks/timeStepChecker"; + testInputs.timeStepFluxStatsPath = "/Tasks/timeStepFluxStats"; + testInputs.wholeSimFluxStatsPath = "/Tasks/wholeSimFluxStats"; + testInputs.flowSolverPath = "/Solvers/testSolver"; + + testInputs.dt = 500.0; + testInputs.sourceElementsCount = 2; + testInputs.sinkElementsCount = 5; + + // FluxRate table from 0.0s to 5000.0s + setRateTable( testInputs.sourceRates, + { { 0.000 }, + { 0.000 }, + { 0.767 }, + { 0.894 }, + { 0.561 }, + { 0.234 }, + { 0.194 }, + { 0.178 }, + { 0.162 }, + { 0.059 }, + { 0.000 } } ); + testInputs.sinkRates=testInputs.sourceRates; + + // sink is 3x source production + testInputs.sourceRateFactor = -1.0; + testInputs.sinkRateFactor = 3.0; + + return TestSet( testInputs ); +} + +TEST_F( FlowStatisticsTest, checkSinglePhaseFluxStatistics ) +{ + TestSet const testSet = getTestSet(); + + GeosxState state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ); + ProblemManager & problem = state.getProblemManager(); + + setupProblemFromXML( problem, testSet.inputs.xmlInput.data() ); + + real64 firstMass; + + TimeStepChecker & timeStepChecker = problem.getGroupByPath< TimeStepChecker >( testSet.inputs.timeStepCheckerPath ); + timeStepChecker.setTimeStepCheckingFunction( [&]( real64 const time_n ) + { + integer const timestepId = timeStepChecker.getTestedTimeStepCount(); + checkTimeStepStats( testSet, time_n, timestepId ); + checkTimeStepFluxStats( problem, testSet, time_n, timestepId ); + + static bool passedFirstTimeStep = false; + if( !passedFirstTimeStep ) + { + passedFirstTimeStep = true; + firstMass = getTotalFluidMass( problem, testSet.inputs.flowSolverPath ); + } + } ); + + // run simulation + EXPECT_FALSE( problem.runSimulation() ) << "Simulation exited early."; + + checkWholeSimFluxStats( problem, testSet ); + checkWholeSimTimeStepStats( problem, testSet, timeStepChecker ); + + // check singlephasestatistics results + real64 const lastMass = getTotalFluidMass( problem, testSet.inputs.flowSolverPath ); + real64 const massDiffTol = 1e-7; + EXPECT_NEAR( lastMass - firstMass, + -testSet.totalMassProd[0], + massDiffTol * std::abs( testSet.totalMassProd[0] ) ) << GEOS_FMT( "{} total mass difference from start to end is not consistent with fluxes production.", + SinglePhaseStatistics::catalogName() ); +} + + +} /* namespace SinglePhaseFluxStatisticsTest */ + + +//////////////////////////////// Multiphase Flux Statistics Test //////////////////////////////// +namespace MultiPhaseFluxStatisticsTestMass +{ + + +TestSet getTestSet() +{ + TestInputs testInputs; + + testInputs.xmlInput = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +)xml"; + + testInputs.tableFiles["pvtgas.txt"] = "DensityFun SpanWagnerCO2Density 1.5e7 2.5e7 1e5 370.15 400.15 2\n" + "ViscosityFun FenghourCO2Viscosity 1.5e7 2.5e7 1e5 370.15 400.15 2\n"; + + testInputs.tableFiles["pvtliquid.txt"] = "DensityFun EzrokhiBrineDensity 0.1033 -2.2991e-5 -2.3658e-6\n" + "ViscosityFun EzrokhiBrineViscosity 0 0 0\n"; + + testInputs.tableFiles["co2flash.txt"] = "FlashModel CO2Solubility 1.5e7 2.5e7 1e5 370.15 400.15 2 0\n"; + + + testInputs.sourceFluxName = "sourceFlux"; + testInputs.sinkFluxName = "sinkFlux"; + testInputs.timeStepCheckerPath = "/Tasks/timeStepChecker"; + testInputs.timeStepFluxStatsPath = "/Tasks/timeStepFluxStats"; + testInputs.wholeSimFluxStatsPath = "/Tasks/wholeSimFluxStats"; + testInputs.flowSolverPath = "/Solvers/testSolver"; + + testInputs.dt = 500.0; + testInputs.sourceElementsCount = 1; + testInputs.sinkElementsCount = 1; + + // FluxInjectionRate & FluxProductionRate table from 0.0s to 5000.0s + setRateTable( testInputs.sourceRates, + { { 0.000, 0.0 }, + { 0.000, 0.0 }, + { 0.267, 0.0 }, + { 0.561, 0.0 }, + { 0.194, 0.0 }, + { 0.102, 0.0 }, + { 0.059, 0.0 }, + { 0.000, 0.0 }, + { 0.000, 0.0 }, + { 0.000, 0.0 }, + { 0.000, 0.0 } } ); + setRateTable( testInputs.sinkRates, + { { 0.0, 0.000 }, + { 0.0, 0.000 }, + { 0.0, 0.003 }, + { 0.0, 0.062 }, + { 0.0, 0.121 }, + { 0.0, 0.427 }, + { 0.0, 0.502 }, + { 0.0, 0.199 }, + { 0.0, 0.083 }, + { 0.0, 0.027 }, + { 0.0, 0.000 } } ); + + testInputs.sourceRateFactor = -44e-3; + testInputs.sinkRateFactor = 18e-3; + + return TestSet( testInputs ); +} + + +TEST_F( FlowStatisticsTest, checkMultiPhaseFluxStatisticsMass ) +{ + TestSet const testSet = getTestSet(); + writeTableFiles( testSet.inputs.tableFiles ); + + GeosxState state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ); + ProblemManager & problem = state.getProblemManager(); + + setupProblemFromXML( problem, testSet.inputs.xmlInput.data() ); + + TimeStepChecker & timeStepChecker = problem.getGroupByPath< TimeStepChecker >( testSet.inputs.timeStepCheckerPath ); + timeStepChecker.setTimeStepCheckingFunction( [&]( real64 const time_n ) + { + integer const timestepId = timeStepChecker.getTestedTimeStepCount(); + checkTimeStepStats( testSet, time_n, timestepId ); + checkTimeStepFluxStats( problem, testSet, time_n, timestepId ); + } ); + + // run simulation + EXPECT_FALSE( problem.runSimulation() ) << "Simulation exited early."; + + checkWholeSimFluxStats( problem, testSet ); + checkWholeSimTimeStepStats( problem, testSet, timeStepChecker ); +} + + +} /* namespace MultiPhaseFluxStatisticsTest */ + + +//////////////////////////////// Multiphase Flux Statistics Test //////////////////////////////// +namespace MultiPhaseFluxStatisticsTestMol +{ + + +TestSet getTestSet() +{ + TestInputs testInputs; + + testInputs.xmlInput = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +)xml"; + + testInputs.tableFiles["pvtgas.txt"] = "DensityFun SpanWagnerCO2Density 1.5e7 2.5e7 1e5 370.15 400.15 2\n" + "ViscosityFun FenghourCO2Viscosity 1.5e7 2.5e7 1e5 370.15 400.15 2\n"; + + testInputs.tableFiles["pvtliquid.txt"] = "DensityFun EzrokhiBrineDensity 0.1033 -2.2991e-5 -2.3658e-6\n" + "ViscosityFun EzrokhiBrineViscosity 0 0 0\n"; + + testInputs.tableFiles["co2flash.txt"] = "FlashModel CO2Solubility 1.5e7 2.5e7 1e5 370.15 400.15 2 0\n"; + + + testInputs.sourceFluxName = "sourceFlux"; + testInputs.sinkFluxName = "sinkFlux"; + testInputs.timeStepCheckerPath = "/Tasks/timeStepChecker"; + testInputs.timeStepFluxStatsPath = "/Tasks/timeStepFluxStats"; + testInputs.wholeSimFluxStatsPath = "/Tasks/wholeSimFluxStats"; + testInputs.flowSolverPath = "/Solvers/testSolver"; + + testInputs.dt = 500.0; + testInputs.sourceElementsCount = 1; + testInputs.sinkElementsCount = 1; + + // FluxInjectionRate & FluxProductionRate table from 0.0s to 5000.0s + setRateTable( testInputs.sourceRates, + { { 0.000, 0.0 }, + { 0.000, 0.0 }, + { 0.267, 0.0 }, + { 0.561, 0.0 }, + { 0.194, 0.0 }, + { 0.102, 0.0 }, + { 0.059, 0.0 }, + { 0.000, 0.0 }, + { 0.000, 0.0 }, + { 0.000, 0.0 }, + { 0.000, 0.0 } } ); + setRateTable( testInputs.sinkRates, + { { 0.0, 0.000 }, + { 0.0, 0.000 }, + { 0.0, 0.003 }, + { 0.0, 0.062 }, + { 0.0, 0.121 }, + { 0.0, 0.427 }, + { 0.0, 0.502 }, + { 0.0, 0.199 }, + { 0.0, 0.083 }, + { 0.0, 0.027 }, + { 0.0, 0.000 } } ); + + // scale is set to high values to make the solver generate timestep cuts + testInputs.sourceRateFactor = -8.0; + testInputs.sinkRateFactor = 8.0; + + // this simulation is set-up to have at least one timestep cut. + testInputs.requiredSubTimeStep = 2; + + return TestSet( testInputs ); +} + + +TEST_F( FlowStatisticsTest, checkMultiPhaseFluxStatisticsMol ) +{ + TestSet const testSet = getTestSet(); + writeTableFiles( testSet.inputs.tableFiles ); + + GeosxState state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ); + ProblemManager & problem = state.getProblemManager(); + + setupProblemFromXML( problem, testSet.inputs.xmlInput.data() ); + + TimeStepChecker & timeStepChecker = problem.getGroupByPath< TimeStepChecker >( testSet.inputs.timeStepCheckerPath ); + timeStepChecker.setTimeStepCheckingFunction( [&]( real64 const time_n ) + { + integer const timestepId = timeStepChecker.getTestedTimeStepCount(); + checkTimeStepStats( testSet, time_n, timestepId ); + checkTimeStepFluxStats( problem, testSet, time_n, timestepId ); + } ); + + // run simulation + EXPECT_FALSE( problem.runSimulation() ) << "Simulation exited early."; + + checkWholeSimFluxStats( problem, testSet ); + checkWholeSimTimeStepStats( problem, testSet, timeStepChecker ); +} + + +} /* namespace MultiPhaseFluxStatisticsTest */ + + +//////////////////////////////// Main //////////////////////////////// + + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + g_commandLineOptions = *geos::basicSetup( argc, argv ); + int const result = RUN_ALL_TESTS(); + geos::basicCleanup(); + return result; +} diff --git a/src/coreComponents/unitTests/fluidFlowTests/testFlowUtils.hpp b/src/coreComponents/unitTests/fluidFlowTests/testFlowUtils.hpp new file mode 100644 index 00000000000..d1408c90c44 --- /dev/null +++ b/src/coreComponents/unitTests/fluidFlowTests/testFlowUtils.hpp @@ -0,0 +1,161 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#ifndef GEOS_UNITTESTS_FLUIDFLOWTESTS_TESTFLOWUTILS_HPP +#define GEOS_UNITTESTS_FLUIDFLOWTESTS_TESTFLOWUTILS_HPP + +#include "codingUtilities/UnitTestUtilities.hpp" + +namespace geos +{ + +namespace testing +{ + +void checkDerivative( real64 const valueEps, + real64 const value, + real64 const deriv, + real64 const eps, + real64 const relTol, + real64 const absTol, + string const & name, + string const & var ) +{ + real64 const numDeriv = (valueEps - value) / eps; + checkRelativeError( deriv, numDeriv, relTol, absTol, "d(" + name + ")/d(" + var + ")" ); +} + +void checkDerivative( real64 const valueEps, + real64 const value, + real64 const deriv, + real64 const eps, + real64 const relTol, + string const & name, + string const & var ) +{ return checkDerivative( valueEps, value, deriv, eps, relTol, DEFAULT_ABS_TOL, name, var ); } + +template< int USD1, int USD2, int USD3 > +void checkDerivative( arraySlice1d< real64 const, USD1 > const & valueEps, + arraySlice1d< real64 const, USD2 > const & value, + arraySlice1d< real64 const, USD3 > const & deriv, + real64 const eps, + real64 const relTol, + real64 const absTol, + string const & name, + string const & var, + arrayView1d< string const > const & labels ) +{ + localIndex const size = labels.size( 0 ); + + for( localIndex i = 0; i < size; ++i ) + { + checkDerivative( valueEps[i], value[i], deriv[i], eps, relTol, absTol, + name + "[" + labels[i] + "]", var ); + } +} + +template< int DIM, int USD1, int USD2, int USD3, typename ... Args > +void checkDerivative( ArraySlice< real64 const, DIM, USD1 > const & valueEps, + ArraySlice< real64 const, DIM, USD2 > const & value, + ArraySlice< real64 const, DIM, USD3 > const & deriv, + real64 const eps, + real64 const relTol, + real64 const absTol, + string const & name, + string const & var, + arrayView1d< string const > const & labels, + Args ... label_lists ) +{ + localIndex const size = labels.size( 0 ); + + for( localIndex i = 0; i < size; ++i ) + { + checkDerivative( valueEps[i], value[i], deriv[i], eps, relTol, absTol, + name + "[" + labels[i] + "]", var, label_lists ... ); + } +} + +template< int DIM, int USD1, int USD2, int USD3, typename ... Args > +void checkDerivative( ArraySlice< real64 const, DIM, USD1 > const & valueEps, + ArraySlice< real64 const, DIM, USD2 > const & value, + ArraySlice< real64 const, DIM, USD3 > const & deriv, + real64 const eps, + real64 const relTol, + string const & name, + string const & var, + arrayView1d< string const > const & labels, + Args ... label_lists ) +{ return checkDerivative( valueEps, value, deriv, eps, relTol, DEFAULT_ABS_TOL, name, var, labels, label_lists ... ); } + +// invert compositional derivative array layout to move innermost slice on the top +// (this is needed so we can use checkDerivative() to check derivative w.r.t. for each compositional var) +template< int USD > +array1d< real64 > invertLayout( arraySlice1d< real64 const, USD > const & input, + localIndex N ) +{ + array1d< real64 > output( N ); + for( int i = 0; i < N; ++i ) + { + output[i] = input[i]; + } + + return output; +} + +template< int USD > +array2d< real64 > invertLayout( arraySlice2d< real64 const, USD > const & input, + localIndex N1, + localIndex N2 ) +{ + array2d< real64 > output( N2, N1 ); + + for( localIndex i = 0; i < N1; ++i ) + { + for( localIndex j = 0; j < N2; ++j ) + { + output( j, i ) = input( i, j ); + } + } + + return output; +} + +template< int USD > +array3d< real64 > invertLayout( arraySlice3d< real64 const, USD > const & input, + localIndex N1, + localIndex N2, + localIndex N3 ) +{ + array3d< real64 > output( N3, N1, N2 ); + + for( localIndex i = 0; i < N1; ++i ) + { + for( localIndex j = 0; j < N2; ++j ) + { + for( localIndex k = 0; k < N3; ++k ) + { + output( k, i, j ) = input( i, j, k ); + } + } + } + + return output; +} + +} // namespace testing + +} // namespace geos + +#endif //GEOS_UNITTESTS_FLUIDFLOWTESTS_TESTFLOWUTILS_HPP diff --git a/src/coreComponents/unitTests/fluidFlowTests/testReactiveCompositionalMultiphaseOBL.cpp b/src/coreComponents/unitTests/fluidFlowTests/testReactiveCompositionalMultiphaseOBL.cpp index 05cdad5d2b4..cc46cda8af9 100644 --- a/src/coreComponents/unitTests/fluidFlowTests/testReactiveCompositionalMultiphaseOBL.cpp +++ b/src/coreComponents/unitTests/fluidFlowTests/testReactiveCompositionalMultiphaseOBL.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -71,7 +72,7 @@ char const * xmlInput = - + const & residual, arrayView1d< real64 const > const & residualOrig, globalIndex const dofIndex, @@ -83,7 +60,7 @@ void setupProblemFromXML( ProblemManager & problemManager, char const * const xm GEOS_LOG_RANK_0( "Error offset: " << xmlResult.offset ); } - int mpiSize = MpiWrapper::commSize( MPI_COMM_GEOSX ); + int mpiSize = MpiWrapper::commSize( MPI_COMM_GEOS ); dataRepository::Group & commandLine = problemManager.getGroup< dataRepository::Group >( problemManager.groupKeys.commandLine ); @@ -111,7 +88,7 @@ void setupProblemFromXML( ProblemManager & problemManager, char const * const xm problemManager.applyInitialConditions(); } -void testMobilityNumericalDerivatives( SinglePhaseFVM< SinglePhaseBase > & solver, +void testMobilityNumericalDerivatives( SinglePhaseFVM<> & solver, DomainPartition & domain, bool const isThermal, real64 const perturbParameter, diff --git a/src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseBaseKernels.cpp b/src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseBaseKernels.cpp deleted file mode 100644 index 163da585aaa..00000000000 --- a/src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseBaseKernels.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -// Source includes -#include "mainInterface/initialization.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseBaseKernels.hpp" - -// TPL includes -#include - -using namespace geos; -using namespace geos::singlePhaseBaseKernels; - -// Sphinx start after test mobility - -TEST( SinglePhaseBaseKernels, mobility ) -{ - int constexpr NTEST = 3; - - real64 const dens[NTEST] = { 800.0, 1000.0, 1500.0 }; - real64 const dDens_dPres[NTEST] = { 1e-5, 1e-10, 0.0 }; - real64 const visc[NTEST] = { 5.0, 2.0, 1.0 }; - real64 const dVisc_dPres[NTEST] = { 1e-7, 0.0, 0.0 }; - - for( int i = 0; i < NTEST; ++i ) - { - SCOPED_TRACE( "Input # " + std::to_string( i ) ); - - real64 mob; - real64 dMob_dPres; - - MobilityKernel::compute( dens[i], dDens_dPres[i], visc[i], dVisc_dPres[i], mob, dMob_dPres ); - - // compute etalon - real64 const mob_et = dens[i] / visc[i]; - real64 const dMob_dPres_et = mob_et * (dDens_dPres[i] / dens[i] - dVisc_dPres[i] / visc[i]); - - EXPECT_DOUBLE_EQ( mob, mob_et ); - EXPECT_DOUBLE_EQ( dMob_dPres, dMob_dPres_et ); - } -} - -// Sphinx end before test mobility - -int main( int argc, char * * argv ) -{ - ::testing::InitGoogleTest( &argc, argv ); - - geos::basicSetup( argc, argv ); - - int const result = RUN_ALL_TESTS(); - - geos::basicCleanup(); - - return result; -} diff --git a/src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseFVMKernels.cpp b/src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseFVMKernels.cpp index 898f0db4e08..6e9302a4ad3 100644 --- a/src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseFVMKernels.cpp +++ b/src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseFVMKernels.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseMobilityKernel.cpp b/src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseMobilityKernel.cpp new file mode 100644 index 00000000000..6b10d8a3d31 --- /dev/null +++ b/src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseMobilityKernel.cpp @@ -0,0 +1,68 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// Source includes +#include "mainInterface/initialization.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/MobilityKernel.hpp" + +// TPL includes +#include + +using namespace geos; +using namespace geos::singlePhaseBaseKernels; + +// Sphinx start after test mobility + +TEST( SinglePhaseBaseKernels, mobility ) +{ + int constexpr NTEST = 3; + + real64 const dens[NTEST] = { 800.0, 1000.0, 1500.0 }; + real64 const dDens_dPres[NTEST] = { 1e-5, 1e-10, 0.0 }; + real64 const visc[NTEST] = { 5.0, 2.0, 1.0 }; + real64 const dVisc_dPres[NTEST] = { 1e-7, 0.0, 0.0 }; + + for( int i = 0; i < NTEST; ++i ) + { + SCOPED_TRACE( "Input # " + std::to_string( i ) ); + + real64 mob; + real64 dMob_dPres; + + MobilityKernel::compute( dens[i], dDens_dPres[i], visc[i], dVisc_dPres[i], mob, dMob_dPres ); + + // compute etalon + real64 const mob_et = dens[i] / visc[i]; + real64 const dMob_dPres_et = mob_et * (dDens_dPres[i] / dens[i] - dVisc_dPres[i] / visc[i]); + + EXPECT_DOUBLE_EQ( mob, mob_et ); + EXPECT_DOUBLE_EQ( dMob_dPres, dMob_dPres_et ); + } +} + +// Sphinx end before test mobility + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + + geos::basicSetup( argc, argv ); + + int const result = RUN_ALL_TESTS(); + + geos::basicCleanup(); + + return result; +} diff --git a/src/coreComponents/unitTests/fluidFlowTests/testThermalCompMultiphaseFlow.cpp b/src/coreComponents/unitTests/fluidFlowTests/testThermalCompMultiphaseFlow.cpp index dc8a342ff69..90a8e454cd2 100644 --- a/src/coreComponents/unitTests/fluidFlowTests/testThermalCompMultiphaseFlow.cpp +++ b/src/coreComponents/unitTests/fluidFlowTests/testThermalCompMultiphaseFlow.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -94,7 +95,7 @@ char const * xmlInput = @@ -102,14 +103,14 @@ char const * xmlInput = solidModelName="nullSolid" porosityModelName="rockPorosity" permeabilityModelName="rockPerm" - solidInternalEnergyModelName="rockInternalEnergy" /> + solidInternalEnergyModelName="rockInternalEnergy"/> @@ -94,7 +95,7 @@ char const * xmlInput = referencePressure="0.0" compressibility="1.0e-9" /> - + -void testNumericalJacobian( SinglePhaseFVM< SinglePhaseBase > & solver, +void testNumericalJacobian( SinglePhaseFVM<> & solver, DomainPartition & domain, real64 const perturbParameter, real64 const relTol, @@ -211,7 +212,7 @@ class ThermalSinglePhaseFlowTest : public ::testing::Test { setupProblemFromXML( state.getProblemManager(), xmlInput ); - solver = &state.getProblemManager().getPhysicsSolverManager().getGroup< SinglePhaseFVM< SinglePhaseBase > >( "singleflow" ); + solver = &state.getProblemManager().getPhysicsSolverManager().getGroup< SinglePhaseFVM<> >( "singleflow" ); DomainPartition & domain = state.getProblemManager().getDomainPartition(); @@ -229,7 +230,7 @@ class ThermalSinglePhaseFlowTest : public ::testing::Test static real64 constexpr eps = std::numeric_limits< real64 >::epsilon(); GeosxState state; - SinglePhaseFVM< SinglePhaseBase > * solver; + SinglePhaseFVM<> * solver; }; real64 constexpr ThermalSinglePhaseFlowTest::time; diff --git a/src/coreComponents/unitTests/fluidFlowTests/testTransmissibility.cpp b/src/coreComponents/unitTests/fluidFlowTests/testTransmissibility.cpp new file mode 100644 index 00000000000..ddc0d074630 --- /dev/null +++ b/src/coreComponents/unitTests/fluidFlowTests/testTransmissibility.cpp @@ -0,0 +1,333 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + + +#include "mainInterface/initialization.hpp" +#include "mainInterface/GeosxState.hpp" +#include "codingUtilities/UnitTestUtilities.hpp" +#include "unitTests/fluidFlowTests/testSingleFlowUtils.hpp" +#include "physicsSolvers/fluidFlow/StencilDataCollection.hpp" +#include "mainInterface/ProblemManager.hpp" + + +using namespace geos; +using namespace geos::dataRepository; +using namespace geos::testing; + + +CommandLineOptions g_commandLineOptions; + + +/// Provide every common xml input for the transmissibility tests +constexpr string_view xmlInputCommon = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +)xml"; + +/// Provide the ending of the xml input for the transmissibility tests +static string_view constexpr xmlInputEnd = + R"xml( + +)xml"; + +/// Path of the StencilDataCollection in the hierarchy +static string_view constexpr stencilDataCollectionPath = "/Tasks/cellToCellDataCollection"; + + +/// a "stack" array to represent 3d floating point data (ie. coords) +using Float3 = std::array< real64, 3 >; +/// a "stack" array to represent 3d integer data (ie. cell count / axis) +using Int3 = std::array< integer, 3 >; + +/// Enumeration of the 3D axis to take into account for a structured mesh. +enum class Axis : integer { X = 0, Y = 1, Z = 2 }; + +/** + * @brief a map of the half transmissibilities, from the first to the second cell identified by the + * key global id. + */ +using TransmissibilityMap = std::map< std::pair< globalIndex, globalIndex >, real64 >; + +/** + * @brief the parameters for a given test instance. + */ +struct TestParams +{ + Int3 m_cellCount; + Float3 m_meshSize; + Float3 m_cellDistance; + + constexpr TestParams( Int3 cellCount, Float3 meshSize ): + m_cellCount( cellCount ), + m_meshSize( meshSize ), + m_cellDistance( { meshSize[0] / real64( cellCount[0] ), + meshSize[1] / real64( cellCount[1] ), + meshSize[2] / real64( cellCount[2] ) } ) + {} +}; + +static real64 constexpr g_transmissibilityTolerance = 1.0e-11; +static Float3 constexpr g_testPermeability = { 2.0e-16, 2.0e-16, 2.0e-16 }; +static real64 constexpr g_testNetToGross = 1.0; + + +void verifyStencilOutputStructured( string_view xmlInput, TestParams const & params ); + + +TEST( TransmissibilityTest, stencilOutputVerificationIso ) +{ + static string_view constexpr meshInput = + R"xml( + + + + +)xml"; + std::ostringstream xmlInput; + xmlInput << xmlInputCommon << meshInput << xmlInputEnd; + + static TestParams constexpr params { + { 3, 3, 3 }, // cellCount + { 30.0, 30.0, 30.0 }, // meshSize + }; + + verifyStencilOutputStructured( xmlInput.str(), params ); +} + +TEST( TransmissibilityTest, StencilOutputVerificationAniso ) +{ + static string_view constexpr meshInput = + R"xml( + + + + +)xml"; + std::ostringstream xmlInput; + xmlInput << xmlInputCommon << meshInput << xmlInputEnd; + + static TestParams constexpr params { + { 3, 4, 5 }, // cellCount + { 70.0, 10.0, 54.321 }, // meshSize + }; + + verifyStencilOutputStructured( xmlInput.str(), params ); +} + + + +/** + * @return The theorical half transmissiblity (from A to B or B to A) within a structured mesh. + * @param params The test parameters + * @param axis The axis in which we want to compute the transmissibility (structured mesh). + */ +real64 computeTransmissiblityStructured( TestParams const & params, Axis axis ) +{ + real64 const faceArea = axis == Axis::X ? params.m_cellDistance[1]*params.m_cellDistance[2]: + axis == Axis::Y ? params.m_cellDistance[0]*params.m_cellDistance[2]: + params.m_cellDistance[0]*params.m_cellDistance[1]; + real64 const halfDistance = 0.5 * params.m_cellDistance[integer( axis )]; + + real64 const transmissibility = g_testPermeability[integer( axis )] * g_testNetToGross * ( faceArea / halfDistance ); + // return half transmissibility + return g_testNetToGross * transmissibility * 0.5; +} + +/** + * @brief Verify the transmissibility data from the StencilDataCollection for each connection + * within a structured mesh. + * @param transmissibilities The transmissibility map + * @param axis The axis in which we want to verify the transmissibility (structured mesh). + * @param params The test parameters + */ +void verifyTransmissibilityDataStructured( TransmissibilityMap transmissibilities, Axis axis, + TestParams const & params ) +{ + integer const cellBIdOffset = axis == Axis::X ? 1: + axis == Axis::Y ? params.m_cellCount[0]: + params.m_cellCount[0]*params.m_cellCount[1]; + integer const endX = axis == Axis::X ? params.m_cellCount[0] - 1 : params.m_cellCount[0]; + integer const endY = axis == Axis::Y ? params.m_cellCount[1] - 1 : params.m_cellCount[1]; + integer const endZ = axis == Axis::Z ? params.m_cellCount[2] - 1 : params.m_cellCount[2]; + real64 const expectedAxisTransmissibility = computeTransmissiblityStructured( params, axis ); + + for( integer z = 0; z < endZ; ++z ) + { + for( integer y = 0; y < endY; ++y ) + { + for( integer x = 0; x < endX; ++x ) + { + integer const cellAId = x + params.m_cellCount[0] * (y + z * params.m_cellCount[1]); + integer const cellBId = cellAId + cellBIdOffset; + real64 const transmissibilityOutput = transmissibilities[std::make_pair( cellAId, cellBId )]; + real64 const transmissibilityTolerance = g_transmissibilityTolerance * std::abs( transmissibilityOutput ); + EXPECT_NEAR( transmissibilityOutput, expectedAxisTransmissibility, + transmissibilityTolerance )<< GEOS_FMT( "Transmissibility data from {} does not match with expectation.", + StencilDataCollection::catalogName() ); + } + } + } +} + +/** + * @brief Verify the source data consistency and return a transmissibility map for easy further data access. + * @param stencilData A StencilDataCollection object which contains the data gathered for the stencil. + * @param params The test parameters + * @return a TransmissibilityMap object containing the stencil data. + */ +TransmissibilityMap getTransmissibilityMap( StencilDataCollection const & stencilData, + TestParams const & params ) +{ + using VK = StencilDataCollection::viewKeyStruct; + auto const & cellAGlobalId = stencilData.getReference< array1d< globalIndex > >( VK::cellAGlobalIdString() ); + auto const & cellBGlobalId = stencilData.getReference< array1d< globalIndex > >( VK::cellBGlobalIdString() ); + auto const & transmissibilityAB = stencilData.getReference< array1d< real64 > >( VK::transmissibilityABString() ); + auto const & transmissibilityBA = stencilData.getReference< array1d< real64 > >( VK::transmissibilityBAString() ); + + // verify data size + integer const nx = params.m_cellCount[0]; + integer const ny = params.m_cellCount[1]; + integer const nz = params.m_cellCount[2]; + integer const arraySize = transmissibilityAB.size(); + EXPECT_EQ( arraySize, 3*nx*ny*nz - nx*ny - ny*nz - nx*nz ); + // verify that array size is always equal for all buffers + EXPECT_EQ( cellAGlobalId.size(), arraySize ); + EXPECT_EQ( cellBGlobalId.size(), arraySize ); + EXPECT_EQ( transmissibilityBA.size(), arraySize ); + + TransmissibilityMap transmissibilities; + for( int i = 0; i < arraySize; ++i ) + { + transmissibilities[std::make_pair( cellAGlobalId[i], cellBGlobalId[i] )] = transmissibilityAB[i]; + } + return transmissibilities; +} + + +/** + * @brief Launch a test to verify if: + * - data of the output of the stencil is consistent, + * - output transmissiblity values are conform to computed expectations. + * @param xmlInput The XML input to launch the test on. + * @param params The test parameters. + */ +void verifyStencilOutputStructured( string_view xmlInput, TestParams const & params ) +{ + GeosxState state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ); + ProblemManager & problem = state.getProblemManager(); + setupProblemFromXML( problem, xmlInput.data() ); + + EXPECT_FALSE( problem.runSimulation() ) << "Simulation exited early."; + + { // checking results + StencilDataCollection const & stencilData = + problem.getGroupByPath< StencilDataCollection >( string( stencilDataCollectionPath ) ); + TransmissibilityMap const transmissibilities = getTransmissibilityMap( stencilData, params ); + + // let's check each couple of cell in the x direction + verifyTransmissibilityDataStructured( transmissibilities, Axis::X, params ); + verifyTransmissibilityDataStructured( transmissibilities, Axis::Y, params ); + verifyTransmissibilityDataStructured( transmissibilities, Axis::Z, params ); + } +} + + + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + g_commandLineOptions = *geos::basicSetup( argc, argv ); + int const result = RUN_ALL_TESTS(); + geos::basicCleanup(); + return result; +} diff --git a/src/coreComponents/unitTests/linearAlgebraTests/CMakeLists.txt b/src/coreComponents/unitTests/linearAlgebraTests/CMakeLists.txt index d05530ef8a0..f14fe910eac 100644 --- a/src/coreComponents/unitTests/linearAlgebraTests/CMakeLists.txt +++ b/src/coreComponents/unitTests/linearAlgebraTests/CMakeLists.txt @@ -6,29 +6,13 @@ set( LAI_tests set( nranks 2 ) # Add gtest C++ based tests -set( dependencyList ${parallelDeps} gtest ) +set( tplDependencyList ${parallelDeps} gtest ) -if ( GEOSX_BUILD_SHARED_LIBS ) - list( APPEND dependencyList geosx_core ) -else() - list( APPEND dependencyList ${geosx_core_libs} ) -endif() - -if (TARGET pugixml::pugixml) - set( dependencyList ${dependencyList} pugixml::pugixml ) -endif() +set( dependencyList mainInterface ) -if (TARGET pugixml) - set( dependencyList ${dependencyList} pugixml ) -endif() - -if (TARGET fmt::fmt) - set( dependencyList ${dependencyList} fmt::fmt ) -endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) -if (TARGET fmt) - set( dependencyList ${dependencyList} fmt ) -endif() foreach(test ${LAI_tests}) get_filename_component( test_name ${test} NAME_WE ) @@ -36,7 +20,7 @@ foreach(test ${LAI_tests}) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} ) if ( ENABLE_MPI ) diff --git a/src/coreComponents/unitTests/linearAlgebraTests/testDofManager.cpp b/src/coreComponents/unitTests/linearAlgebraTests/testDofManager.cpp index bc8359844a7..d707e9a06e9 100644 --- a/src/coreComponents/unitTests/linearAlgebraTests/testDofManager.cpp +++ b/src/coreComponents/unitTests/linearAlgebraTests/testDofManager.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -587,7 +588,7 @@ void DofManagerSparsityTest< LAI >::test( std::vector< FieldDesc > fields, dofManager.setSparsityPattern( localPattern ); CRSMatrix< real64, globalIndex > localMatrix; localMatrix.assimilate< parallelHostPolicy >( std::move( localPattern ) ); - pattern.create( localMatrix.toViewConst(), dofManager.numLocalDofs(), MPI_COMM_GEOSX ); + pattern.create( localMatrix.toViewConst(), dofManager.numLocalDofs(), MPI_COMM_GEOS ); pattern.set( 1.0 ); } @@ -625,7 +626,7 @@ void DofManagerSparsityTest< LAI >::test( std::vector< FieldDesc > fields, f2.components, localPatternExpected ); } - patternExpected.create( localPatternExpected.toViewConst(), dofManager.numLocalDofs(), MPI_COMM_GEOSX ); + patternExpected.create( localPatternExpected.toViewConst(), dofManager.numLocalDofs(), MPI_COMM_GEOS ); // Compare the sparsity patterns pattern.set( 1.0 ); @@ -823,15 +824,15 @@ REGISTER_TYPED_TEST_SUITE_P( DofManagerSparsityTest, FEM_TPFA_Full, FEM_TPFA_Partial ); -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS INSTANTIATE_TYPED_TEST_SUITE_P( Trilinos, DofManagerSparsityTest, TrilinosInterface, ); #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE INSTANTIATE_TYPED_TEST_SUITE_P( Hypre, DofManagerSparsityTest, HypreInterface, ); #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC INSTANTIATE_TYPED_TEST_SUITE_P( Petsc, DofManagerSparsityTest, PetscInterface, ); #endif @@ -872,7 +873,7 @@ void DofManagerRestrictorTest< LAI >::test( std::vector< FieldDesc > fields, dofManager.setSparsityPattern( localPattern ); CRSMatrix< real64, globalIndex > localMatrix; localMatrix.assimilate< parallelHostPolicy >( std::move( localPattern ) ); - A.create( localMatrix.toViewConst(), dofManager.numLocalDofs(), MPI_COMM_GEOSX ); + A.create( localMatrix.toViewConst(), dofManager.numLocalDofs(), MPI_COMM_GEOS ); A.set( 1.0 ); } @@ -924,7 +925,7 @@ void DofManagerRestrictorTest< LAI >::test( std::vector< FieldDesc > fields, dofManager.setSparsityPattern( localPattern ); CRSMatrix< real64, globalIndex > localMatrix; localMatrix.assimilate< parallelHostPolicy >( std::move( localPattern ) ); - B.create( localMatrix.toViewConst(), dofManager.numLocalDofs(), MPI_COMM_GEOSX ); + B.create( localMatrix.toViewConst(), dofManager.numLocalDofs(), MPI_COMM_GEOS ); B.set( 1.0 ); } @@ -1061,15 +1062,15 @@ REGISTER_TYPED_TEST_SUITE_P( DofManagerRestrictorTest, MultiBlock_Second, MultiBlock_Both ); -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS INSTANTIATE_TYPED_TEST_SUITE_P( Trilinos, DofManagerRestrictorTest, TrilinosInterface, ); #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE INSTANTIATE_TYPED_TEST_SUITE_P( Hypre, DofManagerRestrictorTest, HypreInterface, ); #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC INSTANTIATE_TYPED_TEST_SUITE_P( Petsc, DofManagerRestrictorTest, PetscInterface, ); #endif diff --git a/src/coreComponents/unitTests/linearAlgebraTests/testDofManagerUtils.hpp b/src/coreComponents/unitTests/linearAlgebraTests/testDofManagerUtils.hpp index e63c90f7631..4c6c41ad02e 100644 --- a/src/coreComponents/unitTests/linearAlgebraTests/testDofManagerUtils.hpp +++ b/src/coreComponents/unitTests/linearAlgebraTests/testDofManagerUtils.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -46,7 +47,7 @@ void setupProblemFromXML( ProblemManager * const problemManager, char const * co GEOS_LOG_RANK_0( "Error offset: " << xmlResult.offset ); } - int mpiSize = MpiWrapper::commSize( MPI_COMM_GEOSX ); + int mpiSize = MpiWrapper::commSize( MPI_COMM_GEOS ); dataRepository::Group & commandLine = problemManager->getGroup< dataRepository::Group >( problemManager->groupKeys.commandLine ); commandLine.registerWrapper< integer >( problemManager->viewKeys.xPartitionsOverride.key() ). @@ -63,7 +64,7 @@ void setupProblemFromXML( ProblemManager * const problemManager, char const * co ElementRegionManager & elementManager = domain.getMeshBody( 0 ).getBaseDiscretization().getElemManager(); xmlWrapper::xmlNode topLevelNode = xmlProblemNode.child( elementManager.getName().c_str() ); elementManager.processInputFileRecursive( xmlDocument, topLevelNode ); - elementManager.postProcessInputRecursive(); + elementManager.postInputInitializationRecursive(); problemManager->problemSetup(); problemManager->applyInitialConditions(); diff --git a/src/coreComponents/unitTests/linearAlgebraTests/testLAIHelperFunctions.cpp b/src/coreComponents/unitTests/linearAlgebraTests/testLAIHelperFunctions.cpp index a7d6ebaada5..dc63258877f 100644 --- a/src/coreComponents/unitTests/linearAlgebraTests/testLAIHelperFunctions.cpp +++ b/src/coreComponents/unitTests/linearAlgebraTests/testLAIHelperFunctions.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -115,7 +116,7 @@ TYPED_TEST_P( LAIHelperFunctionsTest, nodalVectorPermutation ) dofManager.reorderByRank(); Vector nodalVariable; - nodalVariable.create( dofManager.numLocalDofs(), MPI_COMM_GEOSX ); + nodalVariable.create( dofManager.numLocalDofs(), MPI_COMM_GEOS ); globalIndex const rankOffset = dofManager.rankOffset(); arrayView1d< real64 > const nodalVariableView = nodalVariable.open(); @@ -166,7 +167,7 @@ TYPED_TEST_P( LAIHelperFunctionsTest, cellCenteredVectorPermutation ) dofManager.reorderByRank(); Vector cellCenteredVariable; - cellCenteredVariable.create( dofManager.numLocalDofs(), MPI_COMM_GEOSX ); + cellCenteredVariable.create( dofManager.numLocalDofs(), MPI_COMM_GEOS ); globalIndex const rankOffset = dofManager.rankOffset(); arrayView1d< real64 > const cellCenteredVariableView = cellCenteredVariable.open(); @@ -200,15 +201,15 @@ REGISTER_TYPED_TEST_SUITE_P( LAIHelperFunctionsTest, nodalVectorPermutation, cellCenteredVectorPermutation ); -#ifdef GEOSX_USE_TRILINOS +#ifdef GEOS_USE_TRILINOS INSTANTIATE_TYPED_TEST_SUITE_P( Trilinos, LAIHelperFunctionsTest, TrilinosInterface, ); #endif -#ifdef GEOSX_USE_HYPRE +#ifdef GEOS_USE_HYPRE INSTANTIATE_TYPED_TEST_SUITE_P( Hypre, LAIHelperFunctionsTest, HypreInterface, ); #endif -#ifdef GEOSX_USE_PETSC +#ifdef GEOS_USE_PETSC INSTANTIATE_TYPED_TEST_SUITE_P( Petsc, LAIHelperFunctionsTest, PetscInterface, ); #endif diff --git a/src/coreComponents/unitTests/meshTests/CMakeLists.txt b/src/coreComponents/unitTests/meshTests/CMakeLists.txt index c9903e0e5c6..1bd39c09f11 100644 --- a/src/coreComponents/unitTests/meshTests/CMakeLists.txt +++ b/src/coreComponents/unitTests/meshTests/CMakeLists.txt @@ -2,7 +2,8 @@ set( gtest_geosx_tests testMeshEnums.cpp testMeshGeneration.cpp - testNeighborCommunicator.cpp ) + testNeighborCommunicator.cpp + testElementRegions.cpp ) set( gtest_geosx_mpi_tests testNeighborCommunicator.cpp ) @@ -19,29 +20,13 @@ if( ENABLE_VTK ) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/meshDirName.hpp.in ${CMAKE_BINARY_DIR}/include/tests/meshDirName.hpp ) endif() -set( dependencyList ${parallelDeps} gtest ) - -if( GEOSX_BUILD_SHARED_LIBS ) - list( APPEND dependencyList geosx_core ) -else() - list( APPEND dependencyList ${geosx_core_libs} ) -endif() - -if (TARGET pugixml::pugixml) - list( APPEND dependencyList pugixml::pugixml ) -endif() +set( tplDependencyList ${parallelDeps} gtest ) -if (TARGET pugixml) - list( APPEND dependencyList pugixml ) -endif() +set( dependencyList mainInterface ) -if (TARGET fmt::fmt) - list( APPEND dependencyList fmt::fmt ) -endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) -if (TARGET fmt) - list( APPEND dependencyList fmt ) -endif() # Add gtest C++ based tests foreach( test ${gtest_geosx_tests} ) @@ -49,7 +34,7 @@ foreach( test ${gtest_geosx_tests} ) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} ) + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} ) geos_add_test( NAME ${test_name} COMMAND ${test_name} ${CMAKE_CURRENT_LIST_DIR} ) @@ -75,7 +60,7 @@ if( ENABLE_MPI ) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} ) + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} ) geos_add_test( NAME ${test_name} COMMAND ${test_name} -x ${nranks} diff --git a/src/coreComponents/unitTests/meshTests/box_hybrid_mesh.vtu b/src/coreComponents/unitTests/meshTests/box_hybrid_mesh.vtu new file mode 100644 index 00000000000..60d2c15b5de Binary files /dev/null and b/src/coreComponents/unitTests/meshTests/box_hybrid_mesh.vtu differ diff --git a/src/coreComponents/unitTests/meshTests/meshDirName.hpp.in b/src/coreComponents/unitTests/meshTests/meshDirName.hpp.in index ba5be88b45c..68b452a2726 100644 --- a/src/coreComponents/unitTests/meshTests/meshDirName.hpp.in +++ b/src/coreComponents/unitTests/meshTests/meshDirName.hpp.in @@ -1,3 +1,18 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + #include "common/DataTypes.hpp" namespace geos diff --git a/src/coreComponents/unitTests/meshTests/testElementRegions.cpp b/src/coreComponents/unitTests/meshTests/testElementRegions.cpp new file mode 100644 index 00000000000..571fe59973c --- /dev/null +++ b/src/coreComponents/unitTests/meshTests/testElementRegions.cpp @@ -0,0 +1,236 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// TPL includes +#include + +// Source includes +#include "codingUtilities/UnitTestUtilities.hpp" +#include "dataRepository/xmlWrapper.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mainInterface/initialization.hpp" +#include "mainInterface/ProblemManager.hpp" +#include "mesh/generators/CellBlockManagerABC.hpp" +#include "mesh/generators/CellBlockABC.hpp" + +// special CMake-generated include +#include "tests/meshDirName.hpp" + +using namespace geos; +using namespace geos::testing; +using namespace geos::dataRepository; + + +CommandLineOptions g_commandLineOptions; + +struct TestCase +{ + string name; + bool isExpectedToPass = true; + std::vector< string > stringsToMention; + string_view xmlRegions; +}; + +class ElementRegionTestFixture : public ::testing::TestWithParam< TestCase > +{ +public: + ElementRegionTestFixture(): + state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ) + {} + + virtual ~ElementRegionTestFixture() = default; +private: + GeosxState state; +}; + +TEST_P( ElementRegionTestFixture, testVTKImportRegionSyntaxes ) +{ + TestCase const testCase = GetParam(); + + string const pattern = + R"xml( + + + + + + {} + + + )xml"; + string const xmlInput = GEOS_FMT( pattern, + testMeshDir + "/box_hybrid_mesh.vtu", + testCase.xmlRegions ); + + ProblemManager & problem = getGlobalState().getProblemManager(); + problem.parseInputString( xmlInput ); + + if( testCase.isExpectedToPass ) + { + try + { + EXPECT_NO_FATAL_FAILURE( problem.problemSetup() ) << GEOS_FMT( "Test case '{}' did throw an error.", + testCase.name ); + } + catch( std::exception const & e ) + { + GTEST_FAIL() << GEOS_FMT( "Test case '{}' did throw an exception ({}) but was not expected to :\n{}", + testCase.name, LvArray::system::demangle( typeid( e ).name() ), e.what() ); + } + } + else + { + try + { + EXPECT_NO_FATAL_FAILURE( problem.problemSetup() ) << GEOS_FMT( "Test case '{}' did throw an error.", + testCase.name ); + GTEST_FAIL() << GEOS_FMT( "Test case '{}' did not thrown any exception but was expected to.", + testCase.name ); + } + catch( InputError const & e ) + { + string const expStr = e.what(); + for( auto const & str : testCase.stringsToMention ) + { + bool isExceptionContainingStr = expStr.find( str ) != string::npos; + EXPECT_TRUE( isExceptionContainingStr ) << GEOS_FMT( "Test case '{}' exception did not mention the string '{}'. Exception string:\n{}", + testCase.name, str, e.what() ); + } + } + catch( std::exception const & e ) + { + GTEST_FAIL() << GEOS_FMT( "Test case '{}' did throw an exception ({}) but was not expected to :\n{}", + testCase.name, LvArray::system::demangle( typeid( e ).name() ), e.what() ); + } + catch( ... ) + { + GTEST_FAIL() << GEOS_FMT( "Test case '{}': Unexpected exception.", + testCase.name ); + } + } +} + +TestCase const vtkImportRegionSyntaxCases[] = { + { // should not crash + "regular cell-block list", true, { }, + R"xml( + + + )xml" + }, + { // crash because of not existing primitive (2_pendecagonalPrism) + "non existing 2_pendecagonalPrism", false, { "reservoir", "2_pendecagonalPrism" }, + R"xml( + + + )xml" + }, + { // crash because of not unknown primitive name (helloWorld) + "non existing helloWorld", false, { "overburden", "helloWorld" }, + R"xml( + + + )xml" + }, + { // crash because of lacking one primitive (1_hexahedra) + "lacking 1_hexahedra", false, { "1_hexahedra" }, + R"xml( + + + )xml" + }, + { // mentioning the same cell-blocks in multiple regions (1_hexahedra) + "multiple 1_hexahedra", false, { "overburden", "reservoir", "1_hexahedra" }, + R"xml( + + + )xml" + }, + { // should not crash + "regular region attribute list", true, { }, + R"xml( + + + )xml" + }, + { // mentioning the same region attribute in multiple cellBlocks (6 in overburden & reservoir) + "multiple region 1", false, { "6", "region attribute", "overburden", "reservoir" }, + R"xml( + + + )xml" + }, + { // forgetting a region attribute (5) + "forget region 5", false, { "5", "region attribute" }, + R"xml( + + + )xml" + }, + { // should not crash + "regular * wildcard", true, { }, + R"xml( + + )xml" + }, + { // mentioning the same regions in multiple cellBlocks (because of "*") + "* wildcard + region list", false, { "2", "6", "everything", "reservoir" }, + R"xml( + + + )xml" + }, + { // should not crash + "mixing selection methods on 2 regions", true, { }, + R"xml( + + + )xml" + }, + { // should not crash + "mixing all selection methods on 1 region", true, { }, + R"xml( + + )xml" + } +}; +INSTANTIATE_TEST_SUITE_P( testElementRegions, ElementRegionTestFixture, + ::testing::ValuesIn( vtkImportRegionSyntaxCases ) ); + + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + g_commandLineOptions = *geos::basicSetup( argc, argv ); + + int const result = RUN_ALL_TESTS(); + + geos::basicCleanup(); + + return result; +} diff --git a/src/coreComponents/unitTests/meshTests/testMeshEnums.cpp b/src/coreComponents/unitTests/meshTests/testMeshEnums.cpp index ca3645a2be6..b014e193437 100644 --- a/src/coreComponents/unitTests/meshTests/testMeshEnums.cpp +++ b/src/coreComponents/unitTests/meshTests/testMeshEnums.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2020- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/unitTests/meshTests/testMeshGeneration.cpp b/src/coreComponents/unitTests/meshTests/testMeshGeneration.cpp index ab91b136ee2..2655a93c491 100644 --- a/src/coreComponents/unitTests/meshTests/testMeshGeneration.cpp +++ b/src/coreComponents/unitTests/meshTests/testMeshGeneration.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -43,11 +44,14 @@ constexpr double dx = maxCoordInX / numElemsInX; constexpr double dy = maxCoordInY / numElemsInY; constexpr double dz = maxCoordInZ / numElemsInZ; -constexpr localIndex node_dI = numNodesInY * numNodesInZ; -constexpr localIndex node_dJ = numNodesInZ; +constexpr localIndex node_dJ = numNodesInX; +constexpr localIndex node_dK = numNodesInX * numNodesInY; -constexpr localIndex elem_dI = numElemsInY * numElemsInZ; -constexpr localIndex elem_dJ = numElemsInZ; +constexpr localIndex elem_dJ = numElemsInX; +constexpr localIndex elem_dK = numElemsInX * numElemsInY; + +constexpr localIndex minOrder = 1; +constexpr localIndex maxOrder = 5; class MeshGenerationTest : public ::testing::Test { @@ -114,7 +118,7 @@ class MeshGenerationTest : public ::testing::Test ElementRegionManager & elementManager = domain.getMeshBody( 0 ).getBaseDiscretization().getElemManager(); xmlWrapper::xmlNode topLevelNode = xmlProblemNode.child( elementManager.getName().c_str() ); elementManager.processInputFileRecursive( xmlDocument, topLevelNode ); - elementManager.postProcessInputRecursive(); + elementManager.postInputInitializationRecursive(); problemManager.problemSetup(); problemManager.applyInitialConditions(); @@ -148,11 +152,11 @@ TEST_F( MeshGenerationTest, nodePositions ) arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & X = m_nodeManager->referencePosition(); localIndex nodeIndex = 0; - for( localIndex i = 0; i < numNodesInX; ++i ) + for( localIndex k = 0; k < numNodesInZ; ++k ) { for( localIndex j = 0; j < numNodesInY; ++j ) { - for( localIndex k = 0; k < numNodesInZ; ++k ) + for( localIndex i = 0; i < numNodesInX; ++i ) { EXPECT_DOUBLE_EQ( X( nodeIndex, 0 ), i * dx ); EXPECT_DOUBLE_EQ( X( nodeIndex, 1 ), j * dy ); @@ -171,11 +175,11 @@ TEST_F( MeshGenerationTest, elementCentersAndVolumes ) constexpr double VOLUME = dx * dy * dz; localIndex elemID = 0; - for( localIndex i = 0; i < numElemsInX; ++i ) + for( localIndex k = 0; k < numElemsInZ; ++k ) { for( localIndex j = 0; j < numElemsInY; ++j ) { - for( localIndex k = 0; k < numElemsInZ; ++k ) + for( localIndex i = 0; i < numElemsInX; ++i ) { EXPECT_DOUBLE_EQ( centers[ elemID ][ 0 ], i * dx + dx / 2.0 ); EXPECT_DOUBLE_EQ( centers[ elemID ][ 1 ], j * dy + dy / 2.0 ); @@ -193,23 +197,23 @@ TEST_F( MeshGenerationTest, elemToNodeMap ) GEOS_ERROR_IF_NE( nodeMap.size( 1 ), 8 ); localIndex elemID = 0; - for( localIndex i = 0; i < numElemsInX; ++i ) + for( localIndex k = 0; k < numElemsInZ; ++k ) { for( localIndex j = 0; j < numElemsInY; ++j ) { - for( localIndex k = 0; k < numElemsInZ; ++k ) + for( localIndex i = 0; i < numElemsInX; ++i ) { - localIndex const firstNodeID = i * node_dI + j * node_dJ + k; + localIndex const firstNodeID = i + j * node_dJ + k * node_dK; EXPECT_EQ( firstNodeID, nodeMap( elemID, 0 ) ); - EXPECT_EQ( firstNodeID + node_dI, nodeMap( elemID, 1 ) ); - EXPECT_EQ( firstNodeID + node_dI + node_dJ, nodeMap( elemID, 3 ) ); + EXPECT_EQ( firstNodeID + 1, nodeMap( elemID, 1 ) ); + EXPECT_EQ( firstNodeID + 1 + node_dJ, nodeMap( elemID, 3 ) ); EXPECT_EQ( firstNodeID + node_dJ, nodeMap( elemID, 2 ) ); - EXPECT_EQ( firstNodeID + 1, nodeMap( elemID, 4 ) ); - EXPECT_EQ( firstNodeID + 1 + node_dI, nodeMap( elemID, 5 ) ); - EXPECT_EQ( firstNodeID + 1 + node_dI + node_dJ, nodeMap( elemID, 7 ) ); - EXPECT_EQ( firstNodeID + 1 + node_dJ, nodeMap( elemID, 6 ) ); + EXPECT_EQ( firstNodeID + node_dK, nodeMap( elemID, 4 ) ); + EXPECT_EQ( firstNodeID + node_dK + 1, nodeMap( elemID, 5 ) ); + EXPECT_EQ( firstNodeID + node_dK + 1 + node_dJ, nodeMap( elemID, 7 ) ); + EXPECT_EQ( firstNodeID + node_dK + node_dJ, nodeMap( elemID, 6 ) ); ++elemID; } } @@ -221,13 +225,13 @@ TEST_F( MeshGenerationTest, nodeToElemMap ) ArrayOfArraysView< localIndex const > const & nodeToElemMap = m_nodeManager->elementList().toViewConst(); localIndex nodeIndex = 0; - for( localIndex i = 0; i < numNodesInX; ++i ) + for( localIndex k = 0; k < numNodesInZ; ++k ) { for( localIndex j = 0; j < numNodesInY; ++j ) { - for( localIndex k = 0; k < numNodesInZ; ++k ) + for( localIndex i = 0; i < numNodesInX; ++i ) { - localIndex const elemID = i * elem_dI + j * elem_dJ + k; + localIndex const elemID = i + j * elem_dJ + k * elem_dK; std::vector< localIndex > expectedElems; if( k < numElemsInZ ) @@ -235,9 +239,9 @@ TEST_F( MeshGenerationTest, nodeToElemMap ) if( i < numElemsInX && j < numElemsInY ) expectedElems.push_back( elemID ); if( i > 0 && j < numElemsInY ) - expectedElems.push_back( elemID - elem_dI ); + expectedElems.push_back( elemID - 1 ); if( i > 0 && j > 0 ) - expectedElems.push_back( elemID - elem_dI - elem_dJ ); + expectedElems.push_back( elemID - 1 - elem_dJ ); if( i < numElemsInX && j > 0 ) expectedElems.push_back( elemID - elem_dJ ); } @@ -245,13 +249,13 @@ TEST_F( MeshGenerationTest, nodeToElemMap ) if( k > 0 ) { if( i < numElemsInX && j < numElemsInY ) - expectedElems.push_back( elemID - 1 ); + expectedElems.push_back( elemID - elem_dK ); if( i > 0 && j < numElemsInY ) - expectedElems.push_back( elemID - elem_dI - 1 ); + expectedElems.push_back( elemID - elem_dK - 1 ); if( i > 0 && j > 0 ) - expectedElems.push_back( elemID - elem_dI - elem_dJ - 1 ); + expectedElems.push_back( elemID - 1 - elem_dJ - elem_dK ); if( i < numElemsInX && j > 0 ) - expectedElems.push_back( elemID - elem_dJ - 1 ); + expectedElems.push_back( elemID - elem_dJ - elem_dK ); } localIndex const numElems = expectedElems.size(); @@ -287,11 +291,11 @@ TEST_F( MeshGenerationTest, faceNodeMaps ) array1d< localIndex > faceNodesFromFace( 4 ); localIndex elemID = 0; - for( localIndex i = 0; i < numElemsInX; ++i ) + for( localIndex k = 0; k < numElemsInZ; ++k ) { for( localIndex j = 0; j < numElemsInY; ++j ) { - for( localIndex k = 0; k < numElemsInZ; ++k ) + for( localIndex i = 0; i < numElemsInX; ++i ) { for( localIndex f = 0; f < 6; ++f ) { @@ -337,14 +341,14 @@ TEST_F( MeshGenerationTest, faceElementMaps ) GEOS_ERROR_IF_NE( elementToFaceMap.size( 1 ), 6 ); - localIndex const elemIDOffset[6] = { -elem_dJ, -1, -elem_dI, elem_dI, elem_dJ, 1 }; + localIndex const elemIDOffset[6] = { -elem_dJ, -elem_dK, -1, 1, elem_dJ, elem_dK }; localIndex elemID = 0; - for( localIndex i = 0; i < numElemsInX; ++i ) + for( localIndex k = 0; k < numElemsInZ; ++k ) { for( localIndex j = 0; j < numElemsInY; ++j ) { - for( localIndex k = 0; k < numElemsInZ; ++k ) + for( localIndex i = 0; i < numElemsInX; ++i ) { for( localIndex f = 0; f < 6; ++f ) { @@ -418,21 +422,21 @@ TEST_F( MeshGenerationTest, edgeNodeMaps ) GEOS_ERROR_IF_NE( edgeToNodeMap.size( 1 ), 2 ); localIndex nodeIndex = 0; - for( localIndex i = 0; i < numNodesInX; ++i ) + for( localIndex k = 0; k < numNodesInZ; ++k ) { for( localIndex j = 0; j < numNodesInY; ++j ) { - for( localIndex k = 0; k < numNodesInZ; ++k ) + for( localIndex i = 0; i < numNodesInX; ++i ) { localIndex numEdges = 0; if( i != 0 ) { - EXPECT_TRUE( walkEdgesToFindNeighbor( nodeIndex, nodeIndex - node_dI, nodeToEdgeMap[ nodeIndex ], edgeToNodeMap ) ); + EXPECT_TRUE( walkEdgesToFindNeighbor( nodeIndex, nodeIndex - 1, nodeToEdgeMap[ nodeIndex ], edgeToNodeMap ) ); ++numEdges; } if( i != numNodesInX - 1 ) { - EXPECT_TRUE( walkEdgesToFindNeighbor( nodeIndex, nodeIndex + node_dI, nodeToEdgeMap[ nodeIndex ], edgeToNodeMap ) ); + EXPECT_TRUE( walkEdgesToFindNeighbor( nodeIndex, nodeIndex + 1, nodeToEdgeMap[ nodeIndex ], edgeToNodeMap ) ); ++numEdges; } if( j != 0 ) @@ -447,12 +451,12 @@ TEST_F( MeshGenerationTest, edgeNodeMaps ) } if( k != 0 ) { - EXPECT_TRUE( walkEdgesToFindNeighbor( nodeIndex, nodeIndex - 1, nodeToEdgeMap[ nodeIndex ], edgeToNodeMap ) ); + EXPECT_TRUE( walkEdgesToFindNeighbor( nodeIndex, nodeIndex - node_dK, nodeToEdgeMap[ nodeIndex ], edgeToNodeMap ) ); ++numEdges; } if( k != numNodesInZ - 1 ) { - EXPECT_TRUE( walkEdgesToFindNeighbor( nodeIndex, nodeIndex + 1, nodeToEdgeMap[ nodeIndex ], edgeToNodeMap ) ); + EXPECT_TRUE( walkEdgesToFindNeighbor( nodeIndex, nodeIndex + node_dK, nodeToEdgeMap[ nodeIndex ], edgeToNodeMap ) ); ++numEdges; } @@ -474,11 +478,11 @@ TEST_F( MeshGenerationTest, edgeFaceMaps ) GEOS_ERROR_IF_NE( elementToFaceMap.size( 1 ), 6 ); localIndex elemID = 0; - for( localIndex i = 0; i < numElemsInX; ++i ) + for( localIndex k = 0; k < numElemsInZ; ++k ) { for( localIndex j = 0; j < numElemsInY; ++j ) { - for( localIndex k = 0; k < numElemsInZ; ++k ) + for( localIndex i = 0; i < numElemsInX; ++i ) { for( localIndex f = 0; f < 6; ++f ) { @@ -514,6 +518,54 @@ TEST_F( MeshGenerationTest, edgeFaceMaps ) } } +TEST_F( MeshGenerationTest, highOrderMapsSizes ) +{ + ProblemManager & problemManager = getGlobalState().getProblemManager(); + DomainPartition & domain = problemManager.getDomainPartition(); + MeshBody & meshBody = domain.getMeshBody( 0 ); + MeshManager & meshManager = problemManager.getGroup< MeshManager >( problemManager.groupKeys.meshManager ); + meshManager.generateMeshes( domain ); + for( int order = minOrder; order < maxOrder; order++ ) + { + MeshLevel & meshLevel = meshBody.createMeshLevel( MeshBody::groupStructKeys::baseDiscretizationString(), GEOS_FMT( "TestLevel{}", order ), order ); + ElementRegionManager & elemManager = meshLevel.getElemManager(); + NodeManager & nodeManager = meshLevel.getNodeManager(); + FaceManager & faceManager = meshLevel.getFaceManager(); + EdgeManager & edgeManager = meshLevel.getEdgeManager(); + CellBlockManagerABC const & cellBlockManager = meshBody.getCellBlockManager(); + nodeManager.setGeometricalRelations( cellBlockManager, elemManager, false ); + edgeManager.setGeometricalRelations( cellBlockManager, false ); + faceManager.setGeometricalRelations( cellBlockManager, elemManager, nodeManager, false ); + + ASSERT_EQ( elemManager.numRegions(), 1 ); + + ElementRegionBase & elemRegion = elemManager.getRegion( 0 ); + ASSERT_EQ( elemRegion.numSubRegions(), 1 ); + + CellElementSubRegion & subRegion = elemRegion.getSubRegion< CellElementSubRegion >( 0 ); + + EXPECT_EQ( subRegion.numNodesPerElement(), pow( order + 1, 3 ) ); + + localIndex const numVertices = numNodesInX * numNodesInY * numNodesInZ; + localIndex const numEdges = numNodesInX * numNodesInY * numElemsInZ + numNodesInX * numElemsInY * numNodesInZ + numElemsInX * numNodesInY *numNodesInZ; + localIndex const numFaces = numNodesInX * numElemsInY * numElemsInZ + numElemsInX * numElemsInY * numNodesInZ + numElemsInX * numNodesInY *numElemsInZ; + localIndex const numElems = numElemsInX * numElemsInY * numElemsInZ; + localIndex const numNodes = numVertices + numEdges * (order-1) + numFaces * pow((order-1), 2 ) + numElems * pow((order-1), 3 ); + + EXPECT_EQ( numNodes, nodeManager.size() ); + + arrayView2d< localIndex const, cells::NODE_MAP_USD > const & nodeMap = subRegion.nodeList(); + EXPECT_EQ( nodeMap.size( 1 ), pow( order+1, 3 ) ); + arrayView2d< localIndex const > const & edgeToNodeMap = edgeManager.nodeList(); + EXPECT_EQ( edgeToNodeMap.size( 1 ), order+1 ); + ArrayOfArraysView< localIndex const > const & faceToNodeMap = faceManager.nodeList().toViewConst(); + for( localIndex f = 0; f < faceManager.size(); ++f ) + { + EXPECT_EQ( faceToNodeMap.sizeOfArray( f ), pow( order+1, 2 ) ); + } + } +} + int main( int argc, char * * argv ) { ::testing::InitGoogleTest( &argc, argv ); diff --git a/src/coreComponents/unitTests/meshTests/testNeighborCommunicator.cpp b/src/coreComponents/unitTests/meshTests/testNeighborCommunicator.cpp index 54555a26309..cc7200e9229 100644 --- a/src/coreComponents/unitTests/meshTests/testNeighborCommunicator.cpp +++ b/src/coreComponents/unitTests/meshTests/testNeighborCommunicator.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -84,7 +85,7 @@ TEST( TestNeighborComms, testMPICommunication_fromPinnedSetOnDevice ) { SKIP_TEST_IN_SERIAL( "Parallel test" ); { - int rnk = MpiWrapper::commRank( MPI_COMM_GEOSX ); + int rnk = MpiWrapper::commRank( MPI_COMM_GEOS ); constexpr localIndex size = 1000; constexpr localIndex byte_size = 1000 * sizeof(int); @@ -103,11 +104,11 @@ TEST( TestNeighborComms, testMPICommunication_fromPinnedSetOnDevice ) veloc.move( parallelDeviceMemorySpace ); auto veloc_view = veloc.toViewConst(); pack( buf, veloc_view, size ); - MpiWrapper::iSend( buf, byte_size, 1, 0, MPI_COMM_GEOSX, &request ); + MpiWrapper::iSend( buf, byte_size, 1, 0, MPI_COMM_GEOS, &request ); } else { - int err = MpiWrapper::iRecv( buf, byte_size, 0, 0, MPI_COMM_GEOSX, &request ); + int err = MpiWrapper::iRecv( buf, byte_size, 0, 0, MPI_COMM_GEOS, &request ); EXPECT_EQ( err, MPI_SUCCESS ); MPI_Status status; err = MpiWrapper::Wait( &request, &status ); diff --git a/src/coreComponents/unitTests/meshTests/testVTKImport.cpp b/src/coreComponents/unitTests/meshTests/testVTKImport.cpp index 39a333b7e84..5ca9043b0c3 100644 --- a/src/coreComponents/unitTests/meshTests/testVTKImport.cpp +++ b/src/coreComponents/unitTests/meshTests/testVTKImport.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -16,6 +17,7 @@ // Source includes #include "codingUtilities/UnitTestUtilities.hpp" #include "dataRepository/xmlWrapper.hpp" +#include "LvArray/src/system.hpp" #include "mainInterface/GeosxState.hpp" #include "mainInterface/initialization.hpp" #include "mesh/MeshManager.hpp" @@ -40,6 +42,8 @@ #include +#include + using namespace geos; using namespace geos::testing; @@ -69,7 +73,7 @@ void TestMeshImport( string const & meshFilePath, V const & validate, string con MeshManager meshManager( "mesh", &root ); meshManager.processInputFileRecursive( xmlDocument, xmlMeshNode ); - meshManager.postProcessInputRecursive(); + meshManager.postInputInitializationRecursive(); DomainPartition domain( "domain", &root ); meshManager.generateMeshes( domain ); @@ -96,6 +100,9 @@ class TestFractureImport : public ::testing::Test void SetUp() override { + // Disable floating point exceptions for the tests. + // clang15 on x86_64 does throws an FPE. + LvArray::system::disableFloatingPointExceptions( FE_ALL_EXCEPT ); if( MpiWrapper::commRank() == 0 ) { namespace fs = std::filesystem; diff --git a/src/coreComponents/unitTests/testingUtilities/CMakeLists.txt b/src/coreComponents/unitTests/testingUtilities/CMakeLists.txt new file mode 100644 index 00000000000..7534c11b82d --- /dev/null +++ b/src/coreComponents/unitTests/testingUtilities/CMakeLists.txt @@ -0,0 +1,33 @@ +# +# Specify all headers +# +set( testingUtilities_headers + TestingTasks.hpp + ) + +# +# Specify all sources +# +set( testingUtilities_sources + TestingTasks.cpp + ) + +# +# Specify all dependencies +# +set( tplDependencyList ${parallelDeps} gtest ) + +set( dependencyList events ) +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) + +blt_add_library( NAME testingUtilities + SOURCES ${testingUtilities_sources} + HEADERS ${testingUtilities_headers} + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} + OBJECT ${GEOS_BUILD_OBJ_LIBS} + SHARED ${GEOS_BUILD_SHARED_LIBS} + ) + +target_include_directories( testingUtilities PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +target_include_directories( testingUtilities PUBLIC ${CMAKE_BINARY_DIR}/include ) diff --git a/src/coreComponents/unitTests/testingUtilities/TestingTasks.cpp b/src/coreComponents/unitTests/testingUtilities/TestingTasks.cpp new file mode 100644 index 00000000000..0a1e4644f97 --- /dev/null +++ b/src/coreComponents/unitTests/testingUtilities/TestingTasks.cpp @@ -0,0 +1,51 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file TestingTasks.cpp + */ + +#include "TestingTasks.hpp" + +namespace geos +{ +namespace testing +{ + + +TimeStepChecker::TimeStepChecker( string const & name, Group * const parent ): + TaskBase( name, parent ) +{} + +bool TimeStepChecker::execute( real64 const time_n, + real64 const GEOS_UNUSED_PARAM( dt ), + integer const GEOS_UNUSED_PARAM( cycleNumber ), + integer const GEOS_UNUSED_PARAM( eventCounter ), + real64 const GEOS_UNUSED_PARAM( eventProgress ), + DomainPartition & GEOS_UNUSED_PARAM( domain ) ) +{ + EXPECT_TRUE( m_checkTimeStepFunction ); + m_checkTimeStepFunction( time_n ); + + ++m_timestepId; + return false; +} + +REGISTER_CATALOG_ENTRY( TaskBase, TimeStepChecker, string const &, geos::dataRepository::Group * const ) + + +} // namespace testing + +} // namespace geos diff --git a/src/coreComponents/unitTests/testingUtilities/TestingTasks.hpp b/src/coreComponents/unitTests/testingUtilities/TestingTasks.hpp new file mode 100644 index 00000000000..fb4dfa359f8 --- /dev/null +++ b/src/coreComponents/unitTests/testingUtilities/TestingTasks.hpp @@ -0,0 +1,81 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/* + * @file TestingTasks.hpp + */ + +#ifndef GEOS_EVENTS_TASKS_TESTINGTASKS_HPP_ +#define GEOS_EVENTS_TASKS_TESTINGTASKS_HPP_ + +#include "events/tasks/TaskBase.hpp" +#include "codingUtilities/UnitTestUtilities.hpp" + +namespace geos +{ +namespace testing +{ + + +/** + * @brief This Task allows to do checks each timestep during the simulation by calling a provided functor. + * To be executed, it must be - as every task - declared in the provided xmlInput within the Tasks node and called by an even. + * As this Group is designed for developpers and not user oriented, it should not appear in the documentation nor in the xsd. + * Question: could this task be used in the integratedTests ? + */ +class TimeStepChecker : public TaskBase +{ +public: + /** + * @brief Construct a new TimeStepChecker Task + * @param name name in xsd + * @param parent parent group in hierarchy + */ + TimeStepChecker( string const & name, Group * const parent ); + + /** + * @brief Set the functor that must be called each time this Task is executed. + * @param func the functor to execute + */ + void setTimeStepCheckingFunction( std::function< void(real64) > func ) + { m_checkTimeStepFunction = std::function< void(real64) >( func ); } + + /** + * @return Get the tested time-step count + */ + integer getTestedTimeStepCount() const + { return m_timestepId; } + + /** + * @brief Catalog name interface + * @return This type's catalog name + */ + static string catalogName() { return "TimeStepChecker"; } + + virtual bool execute( real64 time_n, real64 dt, integer cycleNumber, + integer eventCounter, real64 eventProgress, + DomainPartition & domain ); + +private: + std::function< void(real64) > m_checkTimeStepFunction; + int m_timestepId = 0; +}; + + +} // namespace testing + +} // namespace geos + +#endif //GEOS_EVENTS_TASKS_TESTINGTASKS_HPP_ diff --git a/src/coreComponents/unitTests/toolchain/CMakeLists.txt b/src/coreComponents/unitTests/toolchain/CMakeLists.txt index 7a3b6e5c688..e8b25319ad9 100644 --- a/src/coreComponents/unitTests/toolchain/CMakeLists.txt +++ b/src/coreComponents/unitTests/toolchain/CMakeLists.txt @@ -2,7 +2,10 @@ set( gtest_geosx_tests testToolchain.cpp ) # NOTE: we explicitly depend on internal libraries in order to check for the spurious addition of -DNDEBUG flag -set( dependencyList ${parallelDeps} gtest physicsSolvers discretizationMethods fieldSpecification linearAlgebra dataRepository events fileIO optionparser ) +set( dependencyList ${parallelDeps} physicsSolvers ) +set( tplDependencyList ${parallelDeps} gtest HDF5::HDF5 optionparser ) +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) # Add gtest C++ based tests foreach(test ${gtest_geosx_tests}) @@ -11,7 +14,7 @@ foreach(test ${gtest_geosx_tests}) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} ) + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} ) geos_add_test( NAME ${test_name} COMMAND ${test_name} ) diff --git a/src/coreComponents/unitTests/toolchain/testToolchain.cpp b/src/coreComponents/unitTests/toolchain/testToolchain.cpp index ec81e510ff9..5bb8eb0ccc5 100644 --- a/src/coreComponents/unitTests/toolchain/testToolchain.cpp +++ b/src/coreComponents/unitTests/toolchain/testToolchain.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2020- GEOS Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -23,7 +24,7 @@ TEST( Toolchain, NDEBUGfromTPls ) * we check that we are in RelWithDebInfo or Release build type when NDEBUG is defined and in Debug * configuration when NDEBUG is not defined: thus, LvArray assertions remain in Debug builds. */ - bool constexpr isDebug = std::string_view( GEOSX_CMAKE_BUILD_TYPE ) == std::string_view( "Debug" ); + bool constexpr isDebug = std::string_view( GEOS_CMAKE_BUILD_TYPE ) == std::string_view( "Debug" ); #ifdef NDEBUG ASSERT_FALSE( isDebug ); // RelWithDebInfo or Release builds only diff --git a/src/coreComponents/unitTests/virtualElementTests/CMakeLists.txt b/src/coreComponents/unitTests/virtualElementTests/CMakeLists.txt index ad301d299ba..0d99a9b63ca 100644 --- a/src/coreComponents/unitTests/virtualElementTests/CMakeLists.txt +++ b/src/coreComponents/unitTests/virtualElementTests/CMakeLists.txt @@ -2,29 +2,13 @@ set( testSources testConformingVirtualElementOrder1.cpp ) -set( dependencyList ${parallelDeps} gtest ) +set( tplDependencyList ${parallelDeps} gtest ) -if ( GEOSX_BUILD_SHARED_LIBS ) - list( APPEND dependencyList geosx_core) -else() - list( APPEND dependencyList ${geosx_core_libs} ) -endif() - -if (TARGET pugixml::pugixml) - list( APPEND dependencyList pugixml::pugixml ) -endif() +set( dependencyList mainInterface ) -if (TARGET pugixml) - list( APPEND dependencyList pugixml ) -endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) -if (TARGET fmt::fmt) - list( APPEND dependencyList fmt::fmt ) -endif() - -if (TARGET fmt) - list( APPEND dependencyList fmt ) -endif() # Add gtest C++ based tests foreach(test ${testSources}) @@ -32,7 +16,7 @@ foreach(test ${testSources}) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} ) + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} ) geos_add_test( NAME ${test_name} COMMAND ${test_name} ) diff --git a/src/coreComponents/unitTests/virtualElementTests/testConformingVirtualElementOrder1.cpp b/src/coreComponents/unitTests/virtualElementTests/testConformingVirtualElementOrder1.cpp index 1120fd74bec..266ce88d436 100644 --- a/src/coreComponents/unitTests/virtualElementTests/testConformingVirtualElementOrder1.cpp +++ b/src/coreComponents/unitTests/virtualElementTests/testConformingVirtualElementOrder1.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -303,7 +304,7 @@ TEST( ConformingVirtualElementOrder1, hexahedra ) ElementRegionManager & elementManager = mesh.getElemManager(); xmlWrapper::xmlNode topLevelNode = xmlProblemNode.child( elementManager.getName().c_str() ); elementManager.processInputFileRecursive( inputFile, topLevelNode ); - elementManager.postProcessInputRecursive(); + elementManager.postInputInitializationRecursive(); problemManager.problemSetup(); // Test computed projectors for all cells in MeshLevel @@ -356,7 +357,7 @@ TEST( ConformingVirtualElementOrder1, wedges ) ElementRegionManager & elementManager = mesh.getElemManager(); xmlWrapper::xmlNode topLevelNode = xmlProblemNode.child( elementManager.getName().c_str() ); elementManager.processInputFileRecursive( inputFile, topLevelNode ); - elementManager.postProcessInputRecursive(); + elementManager.postInputInitializationRecursive(); problemManager.problemSetup(); // Test computed projectors for all cells in MeshLevel diff --git a/src/coreComponents/unitTests/wavePropagationTests/CMakeLists.txt b/src/coreComponents/unitTests/wavePropagationTests/CMakeLists.txt index a555936aeaf..c1296f06b10 100644 --- a/src/coreComponents/unitTests/wavePropagationTests/CMakeLists.txt +++ b/src/coreComponents/unitTests/wavePropagationTests/CMakeLists.txt @@ -1,33 +1,21 @@ # Specify list of tests set( gtest_geosx_tests testWavePropagation.cpp + testWavePropagationQ2.cpp testWavePropagationElasticFirstOrder.cpp testWavePropagationDAS.cpp - testWavePropagationAcousticFirstOrder.cpp ) + testWavePropagationElasticVTI.cpp + testWavePropagationAttenuation.cpp + testWavePropagationAcousticFirstOrder.cpp + testWavePropagationAdjoint1.cpp + ) -set( dependencyList ${parallelDeps} gtest ) +set( tplDependencyList ${parallelDeps} gtest ) -if ( GEOSX_BUILD_SHARED_LIBS ) - list( APPEND dependencyList geosx_core ) -else() - list( APPEND dependencyList ${geosx_core_libs} ) -endif() - -if (TARGET pugixml::pugixml) - list( APPEND dependencyList pugixml::pugixml ) -endif() - -if (TARGET pugixml) - list( APPEND dependencyList pugixml ) -endif() - -if (TARGET fmt::fmt) - list( APPEND dependencyList fmt::fmt ) -endif() +set( dependencyList mainInterface ) -if (TARGET fmt) - list( APPEND dependencyList fmt ) -endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) # Add gtest C++ based tests foreach(test ${gtest_geosx_tests}) @@ -35,7 +23,7 @@ foreach(test ${gtest_geosx_tests}) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} ) + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} ) # Guard to prevent GCC (version 8) from giving warnings due # to some sort of possible conversion from int to long unsigned. diff --git a/src/coreComponents/unitTests/wavePropagationTests/testWavePropagation.cpp b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagation.cpp index 4edd9e63d6f..18902b383c2 100644 --- a/src/coreComponents/unitTests/wavePropagationTests/testWavePropagation.cpp +++ b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagation.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2020- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -15,14 +16,16 @@ // using some utility classes from the following unit test #include "unitTests/fluidFlowTests/testCompFlowUtils.hpp" +#include +#include #include "common/DataTypes.hpp" #include "mainInterface/initialization.hpp" #include "mainInterface/ProblemManager.hpp" #include "mesh/DomainPartition.hpp" #include "mainInterface/GeosxState.hpp" #include "physicsSolvers/PhysicsSolverManager.hpp" -#include "physicsSolvers/wavePropagation/WaveSolverBase.hpp" -#include "physicsSolvers/wavePropagation/AcousticWaveEquationSEM.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp" +#include "physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEM.hpp" #include @@ -40,7 +43,6 @@ char const * xmlInput = @@ -98,7 +102,7 @@ char const * xmlInput = @@ -190,6 +194,16 @@ TEST_F( AcousticWaveEquationSEMTest, SeismoTrace ) DomainPartition & domain = state.getProblemManager().getDomainPartition(); propagator = &state.getProblemManager().getPhysicsSolverManager().getGroup< AcousticWaveEquationSEM >( "acousticSolver" ); + + + //Assert on time-step computed with the automatci time-step routine + real64 const dtOut = propagator->getReference< real64 >( AcousticWaveEquationSEM::viewKeyStruct::timeStepString() ); + real64 const Vp = 1500.0; + real64 const h = 100.0; + real64 const cflConstant = 1/sqrt( 3 ); + real64 const dtTheo = (cflConstant*h)/Vp; + ASSERT_TRUE( dtOut < dtTheo ); + real64 time_n = time; // run for 1s (10 steps) for( int i=0; i<10; i++ ) diff --git a/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationAcousticFirstOrder.cpp b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationAcousticFirstOrder.cpp index 2da611b46e7..a161fcd24c3 100644 --- a/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationAcousticFirstOrder.cpp +++ b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationAcousticFirstOrder.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2020- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -21,8 +22,8 @@ #include "mesh/DomainPartition.hpp" #include "mainInterface/GeosxState.hpp" #include "physicsSolvers/PhysicsSolverManager.hpp" -#include "physicsSolvers/wavePropagation/WaveSolverBase.hpp" -#include "physicsSolvers/wavePropagation/AcousticFirstOrderWaveEquationSEM.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp" +#include "physicsSolvers/wavePropagation/sem/acoustic/firstOrderEqn/isotropic/AcousticFirstOrderWaveEquationSEM.hpp" #include @@ -105,7 +106,7 @@ char const * xmlInput = diff --git a/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationAdjoint1.cpp b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationAdjoint1.cpp new file mode 100644 index 00000000000..fb4bcd943e3 --- /dev/null +++ b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationAdjoint1.cpp @@ -0,0 +1,404 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// using some utility classes from the following unit test +#include "unitTests/fluidFlowTests/testCompFlowUtils.hpp" + +#include "common/DataTypes.hpp" +#include "mainInterface/initialization.hpp" +#include "mainInterface/ProblemManager.hpp" +#include "mesh/DomainPartition.hpp" +#include "mainInterface/GeosxState.hpp" +#include "physicsSolvers/PhysicsSolverManager.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp" +#include "physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEM.hpp" + +#include + +using namespace geos; +using namespace geos::dataRepository; +using namespace geos::testing; + +CommandLineOptions g_commandLineOptions; + +// This unit test checks the interpolation done to extract seismic traces from a wavefield. +// It computes a seismogram at a receiver co-located with the source and compares it to the surrounding receivers. +char const * xmlInput = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )xml"; + +class AcousticWaveEquationSEMTest : public ::testing::Test +{ +public: + + AcousticWaveEquationSEMTest(): + state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ) + {} + +protected: + + void SetUp() override + { + setupProblemFromXML( state.getProblemManager(), xmlInput ); + } + + static real64 constexpr time = 0.0; + static real64 constexpr dt = 5e-3; + static real64 constexpr eps = std::numeric_limits< real64 >::epsilon(); + + GeosxState state; + AcousticWaveEquationSEM * propagator; +}; + +real64 constexpr AcousticWaveEquationSEMTest::time; +real64 constexpr AcousticWaveEquationSEMTest::dt; +real64 constexpr AcousticWaveEquationSEMTest::eps; + +TEST_F( AcousticWaveEquationSEMTest, SeismoTrace ) +{ + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + propagator = &state.getProblemManager().getPhysicsSolverManager().getGroup< AcousticWaveEquationSEM >( "acousticSolver" ); + + // Check source term (sourceCoordinates and sourceValue) + array2d< real32 > rhsForward; + rhsForward.resize( 51, 1 ); + real32 * ptrTimeSourceFrequency = &propagator->getReference< real32 >( AcousticWaveEquationSEM::viewKeyStruct::timeSourceFrequencyString() ); + real32 * ptrTimeSourceDelay = &propagator->getReference< real32 >( AcousticWaveEquationSEM::viewKeyStruct::timeSourceDelayString() ); + localIndex * ptrRickerOrder = &propagator->getReference< localIndex >( AcousticWaveEquationSEM::viewKeyStruct::rickerOrderString() ); + + real64 time_n = time; + std::cout << "Begin forward:" << time_n << std::endl; + // run for 0.25s (100 steps) + for( int i=0; i<50; i++ ) + { + rhsForward[i][0]=WaveSolverUtils::evaluateRicker( time_n, *ptrTimeSourceFrequency, *ptrTimeSourceDelay, *ptrRickerOrder ); + propagator->explicitStepForward( time_n, dt, i, domain, false ); + time_n += dt; + } + // cleanup (triggers calculation of the remaining seismograms data points) + propagator->cleanup( 1.0, 50, 0, 0, domain ); + + // retrieve seismo + arrayView2d< real32 > const pReceivers = propagator->getReference< array2d< real32 > >( AcousticWaveEquationSEM::viewKeyStruct::pressureNp1AtReceiversString() ).toView(); + + // move it to CPU, if needed + pReceivers.move( hostMemorySpace, false ); + + // check number of seismos and trace length + ASSERT_EQ( pReceivers.size( 1 ), 5 ); + ASSERT_EQ( pReceivers.size( 0 ), 51 ); + + /*----------Save receiver forward----------------------*/ + array2d< real32 > uForward; + uForward.resize( 51, 1 ); + + // save receiver value forward on uForward. + for( int i = 0; i < 51; i++ ) + { + /*std::cout << "time: " << i*dt << std::endl; + std::cout << "pReceivers1 " << i << ":" << pReceivers[i][0] << std::endl; + std::cout << "pReceivers2 " << i << ":" << pReceivers[i][1] << std::endl; + std::cout << "pReceivers3 " << i << ":" << pReceivers[i][2] << std::endl; + std::cout << "pReceivers4 " << i << ":" << pReceivers[i][3] << std::endl; + std::cout << "rhsForward " << i << ":" << rhsForward[i][0] << std::endl;*/ + uForward[i][0] = pReceivers[i][0]; + pReceivers[i][0] = 0.; + pReceivers[i][1] = 0.; + pReceivers[i][2] = 0.; + pReceivers[i][3] = 0.; + } + + ASSERT_EQ( rhsForward.size( 1 ), 1 ); + ASSERT_EQ( rhsForward.size( 0 ), 51 ); + + arrayView2d< localIndex > const rNodeIds = propagator->getReference< array2d< localIndex > >( AcousticWaveEquationSEM::viewKeyStruct::receiverNodeIdsString() ).toView(); + rNodeIds.move( hostMemorySpace, false ); + localIndex sNodesIdsAfterModif=rNodeIds[0][0]; + std::cout << "ref back sNodeIds[0][0]:" << sNodesIdsAfterModif << std::endl; + + /*---------------------------------------------------*/ + + std::cout << "Begin backward:" << time_n << std::endl; + + //----------Switch source and receiver1 position for backward----------------------// + arrayView2d< real64 > const sCoord = propagator->getReference< array2d< real64 > >( AcousticWaveEquationSEM::viewKeyStruct::sourceCoordinatesString() ).toView(); + arrayView2d< real64 > const rCoord = propagator->getReference< array2d< real64 > >( AcousticWaveEquationSEM::viewKeyStruct::receiverCoordinatesString() ).toView(); + + for( int i = 0; i < 3; i++ ) + { + real64 tmp_double; + tmp_double=rCoord[0][i]; + rCoord[0][i]=sCoord[0][i]; + sCoord[0][i]=tmp_double; + } + + sCoord.registerTouch( hostMemorySpace ); + rCoord.registerTouch( hostMemorySpace ); + + std::cout << "sCoord :" << sCoord[0][0] <<" "<< sCoord[0][1] <<" "<< sCoord[0][2] << std::endl; + std::cout << "rCoord1 :" << rCoord[0][0] <<" "<< rCoord[0][1] <<" "<< rCoord[0][2] << std::endl; + std::cout << "rCoord2 :" << rCoord[1][0] <<" "<< rCoord[1][1] <<" "<< rCoord[1][2] << std::endl; + std::cout << "rCoord3 :" << rCoord[2][0] <<" "<< rCoord[2][1] <<" "<< rCoord[2][2] << std::endl; + std::cout << "rCoord4 :" << rCoord[3][0] <<" "<< rCoord[3][1] <<" "<< rCoord[3][2] << std::endl; + + //change timeSourceFrequency + std::cout << "timeSourceFrequency forward:" << *ptrTimeSourceFrequency << std::endl; + real32 newTimeFreq=2; + *ptrTimeSourceFrequency = newTimeFreq; + std::cout << "timeSourceFrequency backward:" << *ptrTimeSourceFrequency << std::endl; + + //reinit m_indexSeismoTrace + localIndex * ptrISeismo = &propagator->getReference< localIndex >( AcousticWaveEquationSEM::viewKeyStruct::indexSeismoTraceString() ); + *ptrISeismo = pReceivers.size( 0 )-1; + //reinit m_forward + localIndex * ptrForward = &propagator->getReference< localIndex >( AcousticWaveEquationSEM::viewKeyStruct::forwardString() ); + *ptrForward = 0; + + //"propagator->reinit()" not enough because state field not reinit to zero + //propagator->reinit(); + state.getProblemManager().applyInitialConditions(); + + array2d< real32 > rhsBackward; + rhsBackward.resize( 51, 1 ); + + arrayView2d< localIndex > const sNodeIds_new2 = propagator->getReference< array2d< localIndex > >( AcousticWaveEquationSEM::viewKeyStruct::sourceNodeIdsString() ).toView(); + sNodeIds_new2.move( hostMemorySpace, false ); + std::cout << "sNodeIds[0][0] second get2:" << sNodeIds_new2[0][0] << std::endl; + ASSERT_TRUE( sNodeIds_new2[0][0] == sNodesIdsAfterModif ); + + /*---------------------------------------------------*/ + // run backward solver + for( int i = 50; i > 0; i-- ) + { + rhsBackward[i][0]=WaveSolverUtils::evaluateRicker( time_n, *ptrTimeSourceFrequency, *ptrTimeSourceDelay, *ptrRickerOrder ); + propagator->explicitStepBackward( time_n, dt, i, domain, false ); + time_n -= dt; + //check source node in backward loop + arrayView2d< localIndex > const sNodeIds_loop = propagator->getReference< array2d< localIndex > >( AcousticWaveEquationSEM::viewKeyStruct::sourceNodeIdsString() ).toView(); + sNodeIds_loop.move( hostMemorySpace, false ); + ASSERT_TRUE( sNodeIds_loop[0][0] == sNodesIdsAfterModif ); + } + + // move it to CPU, if needed + pReceivers.move( hostMemorySpace, false ); + + localIndex mForward2 = propagator->getReference< localIndex >( AcousticWaveEquationSEM::viewKeyStruct::forwardString() ); + std::cout << "m_forward second get:" << mForward2 << std::endl; + ASSERT_TRUE( mForward2 == 0 ); + + arrayView2d< localIndex > const sNodeIds_new3 = propagator->getReference< array2d< localIndex > >( AcousticWaveEquationSEM::viewKeyStruct::sourceNodeIdsString() ).toView(); + sNodeIds_new3.move( hostMemorySpace, false ); + std::cout << "sNodeIds[0][0] get3:" << sNodeIds_new3[0][0] << std::endl; + ASSERT_TRUE( sNodeIds_new3[0][0] == sNodesIdsAfterModif ); + + real32 const timeSourceFrequency_new = propagator->getReference< real32 >( AcousticWaveEquationSEM::viewKeyStruct::timeSourceFrequencyString() ); + ASSERT_TRUE( std::abs( timeSourceFrequency_new - newTimeFreq ) < 1.e-8 ); + + /*std::cout << "pReceiver size(0):" << pReceivers.size(0) << std::endl; + std::cout << "pReceiver size(1):" << pReceivers.size(1) << std::endl;*/ + + + /*----------Save receiver backward----------------------*/ + array2d< real32 > qBackward; + qBackward.resize( 51, 1 ); + + real32 sum_ufb=0.; + real32 sum_qff=0.; + real32 sum_u2=0.; + real32 sum_q2=0.; + real32 sum_ff2=0.; + real32 sum_fb2=0.; + + // fill backward field at receiver. + for( int i=50; i > 0; i-- ) + { + /*std::cout << "back time: " << i*dt << std::endl; + std::cout << "back pReceivers1 " << i << ":" << pReceivers[i][0] << std::endl; + std::cout << "back pReceivers2 " << i << ":" << pReceivers[i][1] << std::endl; + std::cout << "back pReceivers3 " << i << ":" << pReceivers[i][2] << std::endl; + std::cout << "back pReceivers4 " << i << ":" << pReceivers[i][3] << std::endl; + std::cout << "back rhsBackward " << i << ":" << rhsBackward[i][0] << std::endl;*/ + qBackward[i][0] = pReceivers[i][0]; + } + + //check transitivity with sum + for( int i=0; i<51; i++ ) + { + sum_ufb += uForward[i][0]*rhsBackward[i][0]; + sum_qff += qBackward[i][0]*rhsForward[i][0]; + + sum_u2 += uForward[i][0]*uForward[i][0]; + sum_q2 += qBackward[i][0]*qBackward[i][0]; + sum_ff2 += rhsForward[i][0]*rhsForward[i][0]; + sum_fb2 += rhsBackward[i][0]*rhsBackward[i][0]; + /*std::cout << "sum evol sum_ufb:" << sum_ufb << " / sum_qff:" << sum_qff << std::endl; + std::cout << "uForward:" << uForward[i][0] << " / qBackward:" << qBackward[i][0] << std::endl; + std::cout << "ufb:" << uForward[i][0]*rhsBackward[i][0] << " / qff:" << qBackward[i][0]*rhsForward[i][0] << std::endl;*/ + } + + // check scalar products and are non null + ASSERT_TRUE( sum_ufb > 1.e-8 ); + ASSERT_TRUE( sum_qff > 1.e-8 ); + + // check || - ||/max(||f||.||q||,||f'||.||u||) < 10^1or2 x epsilon_machine with f rhs direct and f' rhs backward + std::cout << ": " << sum_ufb << " / : " << sum_qff << std::endl; + std::cout << "|| - ||=" << std::abs( sum_ufb-sum_qff ) << " / ||f||.||q||=" << std::sqrt( sum_q2*sum_ff2 ); + std::cout << " / ||f'||.||u||=" << std::sqrt( sum_fb2*sum_u2 ) << " / ||f||.||f'||=" << std::sqrt( sum_ff2*sum_fb2 ) << std::endl; + real32 diffToCheck; + diffToCheck=std::abs( sum_ufb-sum_qff ) / std::max( std::sqrt( sum_fb2*sum_u2 ), std::sqrt( sum_q2*sum_ff2 )); + std::cout << " Diff to compare with 2.e-4: " << diffToCheck << std::endl; + ASSERT_TRUE( diffToCheck < 2.e-4 ); +} + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + g_commandLineOptions = *geos::basicSetup( argc, argv ); + int const result = RUN_ALL_TESTS(); + geos::basicCleanup(); + return result; +} diff --git a/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationAttenuation.cpp b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationAttenuation.cpp new file mode 100644 index 00000000000..8f6e2ccbc57 --- /dev/null +++ b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationAttenuation.cpp @@ -0,0 +1,241 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// using some utility classes from the following unit test +#include "unitTests/fluidFlowTests/testCompFlowUtils.hpp" + +#include "common/DataTypes.hpp" +#include "mainInterface/initialization.hpp" +#include "mainInterface/ProblemManager.hpp" +#include "mesh/DomainPartition.hpp" +#include "mainInterface/GeosxState.hpp" +#include "physicsSolvers/PhysicsSolverManager.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp" +#include "physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEM.hpp" + +#include + +using namespace geos; +using namespace geos::dataRepository; +using namespace geos::testing; + +CommandLineOptions g_commandLineOptions; + +// This unit test checks the interpolation done to extract seismic traces from a wavefield. +// It computes a seismogram at a receiver co-located with the source and compares it to the surrounding receivers. +char const * xmlInput = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )xml"; + +class ElasticWaveEquationSEMTest : public ::testing::Test +{ +public: + + ElasticWaveEquationSEMTest(): + state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ) + {} + +protected: + + void SetUp() override + { + setupProblemFromXML( state.getProblemManager(), xmlInput ); + } + + static real64 constexpr time = 0.0; + static real64 constexpr dt = 1e-1; + static real64 constexpr eps = std::numeric_limits< real64 >::epsilon(); + + GeosxState state; + ElasticWaveEquationSEM * propagator; +}; + +real64 constexpr ElasticWaveEquationSEMTest::time; +real64 constexpr ElasticWaveEquationSEMTest::dt; +real64 constexpr ElasticWaveEquationSEMTest::eps; + +TEST_F( ElasticWaveEquationSEMTest, SeismoTrace ) +{ + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + propagator = &state.getProblemManager().getPhysicsSolverManager().getGroup< ElasticWaveEquationSEM >( "elasticSolver" ); + real64 time_n = time; + // run for 1s (10 steps) + for( int i=0; i<10; i++ ) + { + propagator->explicitStepForward( time_n, dt, i, domain, false ); + time_n += dt; + } + // cleanup (triggers calculation of the remaining seismograms data points) + propagator->cleanup( 1.0, 10, 0, 0, domain ); + + // retrieve seismo + arrayView2d< real32 > const dasReceivers = propagator->getReference< array2d< real32 > >( ElasticWaveEquationSEM::viewKeyStruct::dasSignalNp1AtReceiversString() ).toView(); + + // move it to CPU, if needed + dasReceivers.move( hostMemorySpace, false ); + + // check number of seismos and trace length + ASSERT_EQ( dasReceivers.size( 1 ), 10 ); + ASSERT_EQ( dasReceivers.size( 0 ), 11 ); + + // check das content. The signal values cannot be directly checked as the problem is too small. + // Since the basis is linear, check that the seismograms are nonzero (for t>0) and the seismogram at the center is equal + // to the average of the others. + for( int i = 0; i < 11; i++ ) + { + if( i > 0 ) + { + ASSERT_TRUE( std::abs( dasReceivers[i][8] ) > 0 ); + } + double avg = 0; + for( int r=0; r<8; r++ ) + { + avg += dasReceivers[i][r]; + } + avg /= 8.0; + ASSERT_TRUE( std::abs( dasReceivers[i][8] - avg ) < 0.00001 ); + } +} + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + g_commandLineOptions = *geos::basicSetup( argc, argv ); + int const result = RUN_ALL_TESTS(); + geos::basicCleanup(); + return result; +} diff --git a/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationDAS.cpp b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationDAS.cpp index 2ea5aa70170..e63c563095d 100644 --- a/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationDAS.cpp +++ b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationDAS.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2020- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -21,8 +22,8 @@ #include "mesh/DomainPartition.hpp" #include "mainInterface/GeosxState.hpp" #include "physicsSolvers/PhysicsSolverManager.hpp" -#include "physicsSolvers/wavePropagation/WaveSolverBase.hpp" -#include "physicsSolvers/wavePropagation/ElasticWaveEquationSEM.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp" +#include "physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEM.hpp" #include @@ -40,7 +41,6 @@ char const * xmlInput = @@ -103,7 +105,7 @@ char const * xmlInput = @@ -184,6 +186,11 @@ TEST_F( ElasticWaveEquationSEMTest, SeismoTrace ) // cleanup (triggers calculation of the remaining seismograms data points) propagator->cleanup( 1.0, 10, 0, 0, domain ); + //Assert on time-step computed with the automatci time-step routine + real64 const dtOut = propagator->getReference< real64 >( ElasticWaveEquationSEM::viewKeyStruct::timeStepString() ); + ASSERT_TRUE( dtOut < 0.05 ); + + // retrieve seismo arrayView2d< real32 > const dasReceivers = propagator->getReference< array2d< real32 > >( ElasticWaveEquationSEM::viewKeyStruct::dasSignalNp1AtReceiversString() ).toView(); diff --git a/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationElasticFirstOrder.cpp b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationElasticFirstOrder.cpp index f34f65d7a92..294cf5eafce 100644 --- a/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationElasticFirstOrder.cpp +++ b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationElasticFirstOrder.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2020- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ @@ -21,8 +22,8 @@ #include "mesh/DomainPartition.hpp" #include "mainInterface/GeosxState.hpp" #include "physicsSolvers/PhysicsSolverManager.hpp" -#include "physicsSolvers/wavePropagation/WaveSolverBase.hpp" -#include "physicsSolvers/wavePropagation/ElasticFirstOrderWaveEquationSEM.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp" +#include "physicsSolvers/wavePropagation/sem/elastic/firstOrderEqn/isotropic/ElasticFirstOrderWaveEquationSEM.hpp" #include @@ -105,7 +106,7 @@ char const * xmlInput = diff --git a/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationElasticVTI.cpp b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationElasticVTI.cpp new file mode 100644 index 00000000000..85ee6da6dcd --- /dev/null +++ b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationElasticVTI.cpp @@ -0,0 +1,249 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// using some utility classes from the following unit test +#include "unitTests/fluidFlowTests/testCompFlowUtils.hpp" + +#include "common/DataTypes.hpp" +#include "mainInterface/initialization.hpp" +#include "mainInterface/ProblemManager.hpp" +#include "mesh/DomainPartition.hpp" +#include "mainInterface/GeosxState.hpp" +#include "physicsSolvers/PhysicsSolverManager.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp" +#include "physicsSolvers/wavePropagation/sem/elastic/secondOrderEqn/isotropic/ElasticWaveEquationSEM.hpp" + +#include + +using namespace geos; +using namespace geos::dataRepository; +using namespace geos::testing; + +CommandLineOptions g_commandLineOptions; + +// This unit test checks the interpolation done to extract seismic traces from a wavefield. +// It computes a seismogram at a receiver co-located with the source and compares it to the surrounding receivers. +char const * xmlInput = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )xml"; + +class ElasticWaveEquationSEMTest : public ::testing::Test +{ +public: + + ElasticWaveEquationSEMTest(): + state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ) + {} + +protected: + + void SetUp() override + { + setupProblemFromXML( state.getProblemManager(), xmlInput ); + } + + static real64 constexpr time = 0.0; + static real64 constexpr dt = 1e-1; + static real64 constexpr eps = std::numeric_limits< real64 >::epsilon(); + + GeosxState state; + ElasticWaveEquationSEM * propagator; +}; + +real64 constexpr ElasticWaveEquationSEMTest::time; +real64 constexpr ElasticWaveEquationSEMTest::dt; +real64 constexpr ElasticWaveEquationSEMTest::eps; + +TEST_F( ElasticWaveEquationSEMTest, SeismoTrace ) +{ + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + propagator = &state.getProblemManager().getPhysicsSolverManager().getGroup< ElasticWaveEquationSEM >( "elasticSolver" ); + real64 time_n = time; + // run for 1s (10 steps) + for( int i=0; i<10; i++ ) + { + propagator->explicitStepForward( time_n, dt, i, domain, false ); + time_n += dt; + } + // cleanup (triggers calculation of the remaining seismograms data points) + propagator->cleanup( 1.0, 10, 0, 0, domain ); + + // retrieve seismo + arrayView2d< real32 > const dasReceivers = propagator->getReference< array2d< real32 > >( ElasticWaveEquationSEM::viewKeyStruct::dasSignalNp1AtReceiversString() ).toView(); + + // move it to CPU, if needed + dasReceivers.move( hostMemorySpace, false ); + + // check number of seismos and trace length + ASSERT_EQ( dasReceivers.size( 1 ), 10 ); + ASSERT_EQ( dasReceivers.size( 0 ), 11 ); + + // check das content. The signal values cannot be directly checked as the problem is too small. + // Since the basis is linear, check that the seismograms are nonzero (for t>0) and the seismogram at the center is equal + // to the average of the others. + for( int i = 0; i < 11; i++ ) + { + if( i > 0 ) + { + ASSERT_TRUE( std::abs( dasReceivers[i][8] ) > 0 ); + } + double avg = 0; + for( int r=0; r<8; r++ ) + { + avg += dasReceivers[i][r]; + } + avg /= 8.0; + ASSERT_TRUE( std::abs( dasReceivers[i][8] - avg ) < 0.00001 ); + } +} + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + g_commandLineOptions = *geos::basicSetup( argc, argv ); + int const result = RUN_ALL_TESTS(); + geos::basicCleanup(); + return result; +} diff --git a/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationQ2.cpp b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationQ2.cpp new file mode 100644 index 00000000000..bbb0352d6f1 --- /dev/null +++ b/src/coreComponents/unitTests/wavePropagationTests/testWavePropagationQ2.cpp @@ -0,0 +1,243 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// using some utility classes from the following unit test +#include "unitTests/fluidFlowTests/testCompFlowUtils.hpp" + +#include "common/DataTypes.hpp" +#include "mainInterface/initialization.hpp" +#include "mainInterface/ProblemManager.hpp" +#include "mesh/DomainPartition.hpp" +#include "mainInterface/GeosxState.hpp" +#include "physicsSolvers/PhysicsSolverManager.hpp" +#include "physicsSolvers/wavePropagation/shared/WaveSolverBase.hpp" +#include "physicsSolvers/wavePropagation/sem/acoustic/secondOrderEqn/isotropic/AcousticWaveEquationSEM.hpp" + +#include + +using namespace geos; +using namespace geos::dataRepository; +using namespace geos::testing; + +CommandLineOptions g_commandLineOptions; + +// This unit test checks the interpolation done to extract seismic traces from a wavefield. +// It computes a seismogram at a receiver co-located with the source and compares it to the surrounding receivers. +char const * xmlInput = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )xml"; + +class AcousticWaveEquationSEMTest : public ::testing::Test +{ +public: + + AcousticWaveEquationSEMTest(): + state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ) + {} + +protected: + + void SetUp() override + { + setupProblemFromXML( state.getProblemManager(), xmlInput ); + } + + static real64 constexpr time = 0.0; + static real64 constexpr dt = 5e-4; + static real64 constexpr eps = std::numeric_limits< real64 >::epsilon(); + + GeosxState state; + AcousticWaveEquationSEM * propagator; +}; + +real64 constexpr AcousticWaveEquationSEMTest::time; +real64 constexpr AcousticWaveEquationSEMTest::dt; +real64 constexpr AcousticWaveEquationSEMTest::eps; + +TEST_F( AcousticWaveEquationSEMTest, SeismoTrace ) +{ + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + propagator = &state.getProblemManager().getPhysicsSolverManager().getGroup< AcousticWaveEquationSEM >( "acousticSolver" ); + real64 time_n = time; + // run for 1s (10 steps) + for( int i=0; i<10; i++ ) + { + propagator->explicitStepForward( time_n, dt, i, domain, false ); + time_n += dt; + } + // cleanup (triggers calculation of the remaining seismograms data points) + propagator->cleanup( 1.0, 10, 0, 0, domain ); + + // retrieve seismo + arrayView2d< real32 > const pReceivers = propagator->getReference< array2d< real32 > >( AcousticWaveEquationSEM::viewKeyStruct::pressureNp1AtReceiversString() ).toView(); + + // move it to CPU, if needed + pReceivers.move( hostMemorySpace, false ); + + // check number of seismos and trace length + ASSERT_EQ( pReceivers.size( 1 ), 10 ); + ASSERT_EQ( pReceivers.size( 0 ), 11 ); + + // check seismo content. The pressure values cannot be directly checked as the problem is too small. + // Since the basis is linear, check that the seismograms are nonzero (for t>0) and the seismogram at the center is equal + // to the average of the others. + for( int i = 0; i < 11; i++ ) + { + if( i > 0 ) + { + ASSERT_TRUE( std::abs( pReceivers[i][8] ) > 0 ); + } + double avg = 0; + for( int r=0; r<8; r++ ) + { + avg += pReceivers[i][r]; + } + avg /= 8.0; + std::cout << "p= "<< pReceivers[i][8] << std::endl; + std::cout << "avg= "<explicitStepBackward( time_n, dt, i, domain, false ); + time_n += dt; + } + // check again the seismo content. + for( int i = 0; i < 11; i++ ) + { + if( i > 0 ) + { + ASSERT_TRUE( std::abs( pReceivers[i][8] ) > 0 ); + } + double avg = 0; + for( int r=0; r<8; r++ ) + { + avg += pReceivers[i][r]; + } + avg /= 8.0; + ASSERT_TRUE( std::abs( pReceivers[i][8] - avg ) < 0.00001 ); + } +} + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + g_commandLineOptions = *geos::basicSetup( argc, argv ); + int const result = RUN_ALL_TESTS(); + geos::basicCleanup(); + return result; +} diff --git a/src/coreComponents/unitTests/wellsTests/CMakeLists.txt b/src/coreComponents/unitTests/wellsTests/CMakeLists.txt index dcf6a699034..1420b47ec78 100644 --- a/src/coreComponents/unitTests/wellsTests/CMakeLists.txt +++ b/src/coreComponents/unitTests/wellsTests/CMakeLists.txt @@ -3,37 +3,21 @@ set( gtest_geosx_tests testReservoirSinglePhaseMSWells.cpp testWellEnums.cpp ) -set( dependencyList ${parallelDeps} gtest ) +set( tplDependencyList ${parallelDeps} gtest ) -if ( GEOSX_BUILD_SHARED_LIBS ) - list( APPEND dependencyList geosx_core ${parallelDeps} ) -else() - list( APPEND dependencyList ${geosx_core_libs} ${parallelDeps} ) -endif() +set( dependencyList mainInterface ) if( ENABLE_PVTPackage ) list( APPEND gtest_geosx_tests - testReservoirCompositionalMultiphaseMSWells.cpp ) - - list( APPEND dependencyList PVTPackage ) -endif() - -if (TARGET pugixml::pugixml) - list( APPEND dependencyList pugixml::pugixml ) -endif() - -if (TARGET pugixml) - list( APPEND dependencyList pugixml ) -endif() - -if (TARGET fmt::fmt) - list( APPEND dependencyList fmt::fmt ) -endif() - -if (TARGET fmt) - list( APPEND dependencyList fmt ) + testReservoirCompositionalMultiphaseMSWells.cpp + testIsothermalReservoirCompositionalMultiphaseMSWells.cpp + testIsothermalReservoirCompositionalMultiphaseSSWells.cpp + testThermalReservoirCompositionalMultiphaseSSWells.cpp + testThermalReservoirCompositionalMultiphaseMSWells.cpp ) endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) # Add gtest C++ based tests foreach(test ${gtest_geosx_tests}) get_filename_component( test_name ${test} NAME_WE ) @@ -41,7 +25,7 @@ foreach(test ${gtest_geosx_tests}) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} ) + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} ) geos_add_test( NAME ${test_name} COMMAND ${test_name} ) diff --git a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp new file mode 100644 index 00000000000..d329810880d --- /dev/null +++ b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp @@ -0,0 +1,678 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "unitTests/fluidFlowTests/testCompFlowUtils.hpp" + +#include "common/DataTypes.hpp" +#include "mainInterface/initialization.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "mainInterface/ProblemManager.hpp" +#include "mesh/DomainPartition.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mesh/WellElementSubRegion.hpp" +#include "physicsSolvers/PhysicsSolverManager.hpp" +#include "physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" +#include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp" + +using namespace geos; +using namespace geos::dataRepository; +using namespace geos::constitutive; +using namespace geos::testing; + +CommandLineOptions g_commandLineOptions; +void writeTableToFile( string const & filename, char const * str ) +{ + std::ofstream os( filename ); + ASSERT_TRUE( os.is_open() ); + os << str; + os.close(); +} + +void removeFile( string const & filename ) +{ + int const ret = std::remove( filename.c_str() ); + ASSERT_TRUE( ret == 0 ); +} +char const * co2flash = "FlashModel CO2Solubility 1e6 7.5e7 5e5 299.15 369.15 10 0"; +char const * pvtLiquid = "DensityFun PhillipsBrineDensity 1e6 7.5e7 5e5 299.15 369.15 10 0\n" + "ViscosityFun PhillipsBrineViscosity 0\n" + "EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0\n"; + +char const * pvtGas = "DensityFun SpanWagnerCO2Density 1e6 7.5e7 5e5 299.15 369.15 10\n" + "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" + "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; +char const * xmlInput = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )xml"; + +template< typename LAMBDA > +void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > & solver, + DomainPartition & domain, + real64 const perturbParameter, + real64 const relTol, + LAMBDA && assembleFunction ) +{ + CompositionalMultiphaseWell & wellSolver = *solver.wellSolver(); + CompositionalMultiphaseFVM & flowSolver = dynamicCast< CompositionalMultiphaseFVM & >( *solver.reservoirSolver() ); + + localIndex const NC = flowSolver.numFluidComponents(); + + CRSMatrix< real64, globalIndex > const & jacobian = solver.getLocalMatrix(); + array1d< real64 > residual( jacobian.numRows() ); + DofManager const & dofManager = solver.getDofManager(); + + // assemble the analytical residual + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.move( hostMemorySpace, false ); + + // copy the analytical residual + array1d< real64 > residualOrig( residual ); + + // create the numerical jacobian + jacobian.move( hostMemorySpace ); + CRSMatrix< real64, globalIndex > jacobianFD( jacobian ); + jacobianFD.zero(); + + string const resDofKey = dofManager.getKey( wellSolver.resElementDofName() ); + string const wellDofKey = dofManager.getKey( wellSolver.wellElementDofName() ); + + // at this point we start assembling the finite-difference block by block + + //////////////////////////////////////////////// + // Step 1) Compute the terms in J_RR and J_WR // + //////////////////////////////////////////////// + domain.forMeshBodies( [&] ( MeshBody & meshBody ) + { + meshBody.forMeshLevels( [&] ( MeshLevel & mesh ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + for( localIndex er = 0; er < elemManager.numRegions(); ++er ) + { + ElementRegionBase & elemRegion = elemManager.getRegion( er ); + elemRegion.forElementSubRegionsIndex< CellElementSubRegion >( [&]( localIndex const, CellElementSubRegion & subRegion ) + { + // get the degrees of freedom and ghosting information + arrayView1d< globalIndex const > const & dofNumber = + subRegion.getReference< array1d< globalIndex > >( resDofKey ); + + // get the primary variables on the reservoir elements + arrayView1d< real64 > const & pres = + subRegion.getField< fields::well::pressure >(); + pres.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & compDens = + subRegion.getField< fields::well::globalCompDensity >(); + compDens.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in RESERVOIR elem ei + for( localIndex ei = 0; ei < subRegion.size(); ++ei ) + { + real64 totalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + totalDensity += compDens[ei][ic]; + } + + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the element + real64 const dP = perturbParameter * (pres[ei] + perturbParameter); + pres.move( hostMemorySpace, true ); + pres[ei] += dP; + + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei], + dP, + jacobianFD.toViewConstSizes() ); + } + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter * totalDensity; + compDens.move( hostMemorySpace, true ); + compDens[ei][jc] += dRho; + + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei] + jc + 1, + dRho, + jacobianFD.toViewConstSizes() ); + } + } + } ); + } + } ); + } ); + + ///////////////////////////////////////////////// + // Step 2) Compute the terms in J_RW and J_WW // + ///////////////////////////////////////////////// + + // loop over the wells + wellSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + // get the degrees of freedom, ghosting info and next well elem index + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + + // get the primary variables on the well elements + arrayView1d< real64 > const & wellElemPressure = + subRegion.getField< fields::well::pressure >(); + wellElemPressure.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = + subRegion.getField< fields::well::globalCompDensity >(); + wellElemCompDens.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & connRate = + subRegion.getField< fields::well::mixtureConnectionRate >(); + connRate.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in WELL elem iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + real64 wellElemTotalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + wellElemTotalDensity += wellElemCompDens[iwelem][ic]; + } + + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the well element + real64 const dP = perturbParameter * ( wellElemPressure[iwelem] + perturbParameter ); + wellElemPressure.move( hostMemorySpace, true ); + wellElemPressure[iwelem] += dP; + + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DPRES, + dP, + jacobianFD.toViewConstSizes() ); + } + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter * wellElemTotalDensity; + wellElemCompDens.move( hostMemorySpace, true ); + wellElemCompDens[iwelem][jc] += dRho; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + jc, + dRho, + jacobianFD.toViewConstSizes() ); + } + } + + // b) compute all the derivatives wrt to the connection in WELL elem iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the rate of the well element + real64 const dRate = perturbParameter * ( connRate[iwelem] + perturbParameter ); + connRate.move( hostMemorySpace, true ); + connRate[iwelem] += dRate; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC, + dRate, + jacobianFD.toViewConstSizes() ); + } + } + } ); + } ); + + // assemble the analytical jacobian + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + //printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); + compareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst(), relTol ); +} + +class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test +{ +public: + + CompositionalMultiphaseReservoirSolverTest(): + state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ) + {} + +protected: + + void SetUp() override + { + setupProblemFromXML( state.getProblemManager(), xmlInput ); + solver = &state.getProblemManager().getPhysicsSolverManager().getGroup< CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > >( "reservoirSystem" ); + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + solver->setupSystem( domain, + solver->getDofManager(), + solver->getLocalMatrix(), + solver->getSystemRhs(), + solver->getSystemSolution() ); + + solver->implicitStepSetup( time, dt, domain ); + } + + static real64 constexpr time = 0.0; + static real64 constexpr dt = 1e4; + static real64 constexpr eps = std::numeric_limits< real64 >::epsilon(); + + GeosxState state; + CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > * solver; +}; + +real64 constexpr CompositionalMultiphaseReservoirSolverTest::time; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::dt; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::eps; + +#if 0 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Perforation ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = *state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->assembleCouplingTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#endif + +#if 0 +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Flux ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleFluxTerms( dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Accum ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleAccumulationTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#if 0 +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_PressureRel ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assemblePressureRelations( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif + +int main( int argc, char * * argv ) +{ + writeTableToFile( "co2flash.txt", co2flash ); + writeTableToFile( "pvtliquid.txt", pvtLiquid ); + writeTableToFile( "pvtgas.txt", pvtGas ); + ::testing::InitGoogleTest( &argc, argv ); + g_commandLineOptions = *geos::basicSetup( argc, argv ); + int const result = RUN_ALL_TESTS(); + geos::basicCleanup(); + removeFile( "co2flash.txt" ); + removeFile( "pvtliquid.txt" ); + removeFile( "pvtgas.txt" ); + return result; +} diff --git a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp new file mode 100644 index 00000000000..35551790c50 --- /dev/null +++ b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp @@ -0,0 +1,770 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "unitTests/fluidFlowTests/testCompFlowUtils.hpp" + +#include "common/DataTypes.hpp" +#include "mainInterface/initialization.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "mainInterface/ProblemManager.hpp" +#include "mesh/DomainPartition.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mesh/WellElementSubRegion.hpp" +#include "physicsSolvers/PhysicsSolverManager.hpp" +#include "physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" +#include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp" + +using namespace geos; +using namespace geos::dataRepository; +using namespace geos::constitutive; +using namespace geos::testing; + +CommandLineOptions g_commandLineOptions; +void writeTableToFile( string const & filename, char const * str ) +{ + std::ofstream os( filename ); + ASSERT_TRUE( os.is_open() ); + os << str; + os.close(); +} + +void removeFile( string const & filename ) +{ + int const ret = std::remove( filename.c_str() ); + ASSERT_TRUE( ret == 0 ); +} +char const * co2flash = "FlashModel CO2Solubility 1e6 7.5e7 5e5 299.15 369.15 10 0"; +char const * pvtLiquid = "DensityFun PhillipsBrineDensity 1e6 7.5e7 5e5 299.15 369.15 10 0\n" + "ViscosityFun PhillipsBrineViscosity 0\n" + "EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0\n"; + +char const * pvtGas = "DensityFun SpanWagnerCO2Density 1e6 7.5e7 5e5 299.15 369.15 10\n" + "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" + "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; +char const * xmlInput = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )xml"; + + + +template< typename LAMBDA > +void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > & solver, + DomainPartition & domain, + real64 const perturbParameter, + real64 const relTol, + LAMBDA && assembleFunction ) +{ + CompositionalMultiphaseWell & wellSolver = *solver.wellSolver(); + CompositionalMultiphaseFVM & flowSolver = dynamicCast< CompositionalMultiphaseFVM & >( *solver.reservoirSolver() ); + + localIndex const NC = flowSolver.numFluidComponents(); + + CRSMatrix< real64, globalIndex > const & jacobian = solver.getLocalMatrix(); + array1d< real64 > residual( jacobian.numRows() ); + DofManager const & dofManager = solver.getDofManager(); + + // assemble the analytical residual + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.move( hostMemorySpace, false ); + + // copy the analytical residual + array1d< real64 > residualOrig( residual ); + + // create the numerical jacobian + jacobian.move( hostMemorySpace ); + CRSMatrix< real64, globalIndex > jacobianFD( jacobian ); + jacobianFD.zero(); + + string const resDofKey = dofManager.getKey( wellSolver.resElementDofName() ); + string const wellDofKey = dofManager.getKey( wellSolver.wellElementDofName() ); + + // at this point we start assembling the finite-difference block by block + + //////////////////////////////////////////////// + // Step 1) Compute the terms in J_RR and J_WR // + //////////////////////////////////////////////// + if( 1 ) + domain.forMeshBodies( [&] ( MeshBody & meshBody ) + { + meshBody.forMeshLevels( [&] ( MeshLevel & mesh ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + for( localIndex er = 0; er < elemManager.numRegions(); ++er ) + { + ElementRegionBase & elemRegion = elemManager.getRegion( er ); + elemRegion.forElementSubRegionsIndex< CellElementSubRegion >( [&]( localIndex const, CellElementSubRegion & subRegion ) + { + // get the degrees of freedom and ghosting information + arrayView1d< globalIndex const > const & dofNumber = + subRegion.getReference< array1d< globalIndex > >( resDofKey ); + + // get the primary variables on the reservoir elements + arrayView1d< real64 > const & pres = + subRegion.getField< fields::well::pressure >(); + pres.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & temp = + subRegion.getField< fields::well::temperature >(); + temp.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & compDens = + subRegion.getField< fields::well::globalCompDensity >(); + compDens.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in RESERVOIR elem ei + for( localIndex ei = 0; ei < subRegion.size(); ++ei ) + { + real64 totalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + totalDensity += compDens[ei][ic]; + } + + if( 1 ) + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the element + real64 const dP = perturbParameter * (pres[ei] + perturbParameter); + pres.move( hostMemorySpace, true ); + pres[ei] += dP; + + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei], + dP, + jacobianFD.toViewConstSizes() ); + } + + if( 0 ) + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the temperature of the element + real64 const dT = perturbParameter * (temp[ei] + perturbParameter); + temp.move( hostMemorySpace, true ); + temp[ei] += dT; + + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei], + dT, + jacobianFD.toViewConstSizes() ); + } + + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter * totalDensity; + compDens.move( hostMemorySpace, true ); + compDens[ei][jc] += dRho; + + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei] + jc + 1, + dRho, + jacobianFD.toViewConstSizes() ); + } + } + } ); + } + } ); + } ); + + ///////////////////////////////////////////////// + // Step 2) Compute the terms in J_RW and J_WW // + ///////////////////////////////////////////////// + + // loop over the wells + wellSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + // get the degrees of freedom, ghosting info and next well elem index + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + + // get the primary variables on the well elements + arrayView1d< real64 > const & wellElemPressure = + subRegion.getField< fields::well::pressure >(); + wellElemPressure.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & wellElemTemperature = + subRegion.getField< fields::well::temperature >(); + wellElemTemperature.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = + subRegion.getField< fields::well::globalCompDensity >(); + wellElemCompDens.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & connRate = + subRegion.getField< fields::well::mixtureConnectionRate >(); + connRate.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in WELL elem iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + + real64 wellElemTotalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + wellElemTotalDensity += wellElemCompDens[iwelem][ic]; + } + + if( 1 ) + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the well element + real64 const dP = perturbParameter * ( wellElemPressure[iwelem] + perturbParameter ); + wellElemPressure.move( hostMemorySpace, true ); + wellElemPressure[iwelem] += dP; + + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DPRES, + dP, + jacobianFD.toViewConstSizes() ); + } + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter*wellElemTotalDensity; + wellElemCompDens.move( hostMemorySpace, true ); + wellElemCompDens[iwelem][jc] += dRho; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + jc, + dRho, + jacobianFD.toViewConstSizes() ); + } + if( 0 ) + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the well element + real64 const dT = perturbParameter * ( wellElemTemperature[iwelem] + perturbParameter ); + wellElemTemperature.move( hostMemorySpace, true ); + wellElemTemperature[iwelem] += dT; + + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1, + dT, + jacobianFD.toViewConstSizes() ); + } + } + + // b) compute all the derivatives wrt to the connection in WELL elem iwelem + if( 1 ) + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the rate of the well element + real64 const dRate = perturbParameter * ( connRate[iwelem] + perturbParameter ); + connRate.move( hostMemorySpace, true ); + connRate[iwelem] += dRate; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC, + dRate, + jacobianFD.toViewConstSizes() ); + } + } + } ); + } ); + + // assemble the analytical jacobian + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + //printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); + compareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst(), relTol ); +} + +class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test +{ +public: + + CompositionalMultiphaseReservoirSolverTest(): + state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ) + {} + +protected: + + void SetUp() override + { + setupProblemFromXML( state.getProblemManager(), xmlInput ); + solver = &state.getProblemManager().getPhysicsSolverManager().getGroup< CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > >( "reservoirSystem" ); + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + solver->setupSystem( domain, + solver->getDofManager(), + solver->getLocalMatrix(), + solver->getSystemRhs(), + solver->getSystemSolution() ); + + solver->implicitStepSetup( time, dt, domain ); + } + + static real64 constexpr time = 0.0; + static real64 constexpr dt = 1e4; + static real64 constexpr eps = std::numeric_limits< real64 >::epsilon(); + + GeosxState state; + CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > * solver; +}; + +real64 constexpr CompositionalMultiphaseReservoirSolverTest::time; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::dt; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::eps; + +#if 0 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Perforation ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + //solver->assembleCouplingTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + solver->assembleSystem( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + //solver->assembleCouplingTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#endif + +#if 1 +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Accum ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleAccumulationTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif + +#if 0 +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Flux ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleFluxTerms( dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#endif +#if 0 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_VolumeBalance ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleVolumeBalanceTerms( domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif +#if 0 +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_PressureRel ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assemblePressureRelations( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif +int main( int argc, char * * argv ) +{ + writeTableToFile( "co2flash.txt", co2flash ); + writeTableToFile( "pvtliquid.txt", pvtLiquid ); + writeTableToFile( "pvtgas.txt", pvtGas ); + ::testing::InitGoogleTest( &argc, argv ); + g_commandLineOptions = *geos::basicSetup( argc, argv ); + int const result = RUN_ALL_TESTS(); + geos::basicCleanup(); + removeFile( "co2flash.txt" ); + removeFile( "pvtliquid.txt" ); + removeFile( "pvtgas.txt" ); + return result; +} diff --git a/src/coreComponents/unitTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp index ecda9cd636d..e16b651723b 100644 --- a/src/coreComponents/unitTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -25,7 +26,7 @@ #include "physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp" -#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" +#include "physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" @@ -196,7 +197,7 @@ char const * xmlInput = )xml"; template< typename LAMBDA > -void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > & solver, +void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells<> & solver, DomainPartition & domain, real64 const perturbParameter, real64 const relTol, @@ -471,7 +472,7 @@ class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test void SetUp() override { setupProblemFromXML( state.getProblemManager(), xmlInput ); - solver = &state.getProblemManager().getPhysicsSolverManager().getGroup< CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > >( "reservoirSystem" ); + solver = &state.getProblemManager().getPhysicsSolverManager().getGroup< CompositionalMultiphaseReservoirAndWells<> >( "reservoirSystem" ); DomainPartition & domain = state.getProblemManager().getDomainPartition(); @@ -489,7 +490,7 @@ class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test static real64 constexpr eps = std::numeric_limits< real64 >::epsilon(); GeosxState state; - CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > * solver; + CompositionalMultiphaseReservoirAndWells<> * solver; }; real64 constexpr CompositionalMultiphaseReservoirSolverTest::time; @@ -527,25 +528,11 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Flux [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - solver->wellSolver()->assembleFluxTerms( dt, domain, solver->getDofManager(), localMatrix, localRhs ); + solver->wellSolver()->assembleFluxTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); } ); } -TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_VolumeBalance ) -{ - real64 const perturb = std::sqrt( eps ); - real64 const tol = 1e-1; // 10% error margin - - DomainPartition & domain = state.getProblemManager().getDomainPartition(); - - testNumericalJacobian( *solver, domain, perturb, tol, - [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - solver->wellSolver()->assembleVolumeBalanceTerms( domain, solver->getDofManager(), localMatrix, localRhs ); - } ); -} TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_PressureRel ) { diff --git a/src/coreComponents/unitTests/wellsTests/testReservoirSinglePhaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testReservoirSinglePhaseMSWells.cpp index 2948d71f72c..948dbc5017f 100644 --- a/src/coreComponents/unitTests/wellsTests/testReservoirSinglePhaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testReservoirSinglePhaseMSWells.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -26,7 +27,7 @@ #include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseFVM.hpp" #include "physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp" -#include "physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp" +#include "physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" @@ -96,7 +97,7 @@ char const * PostXmlInput = @@ -136,7 +137,7 @@ char const * PostXmlInput = )xml"; template< typename LAMBDA > -void testNumericalJacobian( SinglePhaseReservoirAndWells< SinglePhaseBase > & solver, +void testNumericalJacobian( SinglePhaseReservoirAndWells<> & solver, DomainPartition & domain, real64 const perturbParameter, real64 const relTol, @@ -345,7 +346,7 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test void SetUp() override { - solver = &state.getProblemManager().getPhysicsSolverManager().getGroup< SinglePhaseReservoirAndWells< SinglePhaseBase > >( "reservoirSystem" ); + solver = &state.getProblemManager().getPhysicsSolverManager().getGroup< SinglePhaseReservoirAndWells<> >( "reservoirSystem" ); DomainPartition & domain = state.getProblemManager().getDomainPartition(); @@ -384,7 +385,7 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - solver->wellSolver()->assembleFluxTerms( DT, domain, solver->getDofManager(), localMatrix, localRhs ); + solver->wellSolver()->assembleFluxTerms( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs ); } ); } @@ -414,7 +415,7 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - solver->wellSolver()->assembleAccumulationTerms( domain, solver->getDofManager(), localMatrix, localRhs ); + solver->wellSolver()->assembleAccumulationTerms( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs ); } ); } @@ -423,7 +424,7 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test static real64 constexpr EPS = std::numeric_limits< real64 >::epsilon(); GeosxState state; - SinglePhaseReservoirAndWells< SinglePhaseBase > * solver; + SinglePhaseReservoirAndWells<> * solver; }; real64 constexpr SinglePhaseReservoirSolverTest::TIME; @@ -496,7 +497,7 @@ TEST_F( SinglePhaseReservoirSolverInternalWellTest, jacobianNumericalCheck_Flux [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - solver->wellSolver()->assembleFluxTerms( DT, domain, solver->getDofManager(), localMatrix, localRhs ); + solver->wellSolver()->assembleFluxTerms( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs ); } ); } diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp new file mode 100644 index 00000000000..c28abf070bd --- /dev/null +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp @@ -0,0 +1,819 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "unitTests/fluidFlowTests/testCompFlowUtils.hpp" + +#include "common/DataTypes.hpp" +#include "mainInterface/initialization.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "mainInterface/ProblemManager.hpp" +#include "mesh/DomainPartition.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mesh/WellElementSubRegion.hpp" +#include "physicsSolvers/PhysicsSolverManager.hpp" +#include "physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" +#include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp" + +using namespace geos; +using namespace geos::dataRepository; +using namespace geos::constitutive; +using namespace geos::testing; + +CommandLineOptions g_commandLineOptions; + +void writeTableToFile( string const & filename, char const * str ) +{ + std::ofstream os( filename ); + ASSERT_TRUE( os.is_open() ); + os << str; + os.close(); +} + +void removeFile( string const & filename ) +{ + int const ret = std::remove( filename.c_str() ); + ASSERT_TRUE( ret == 0 ); +} +char const * co2flash = "FlashModel CO2Solubility 1e6 7.5e7 5e5 299.15 369.15 10 0"; +char const * pvtLiquid = "DensityFun PhillipsBrineDensity 1e6 7.5e7 5e5 299.15 369.15 10 0\n" + "ViscosityFun PhillipsBrineViscosity 0\n" + "EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0\n"; + +char const * pvtGas = "DensityFun SpanWagnerCO2Density 1e6 7.5e7 5e5 299.15 369.15 10\n" + "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" + "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; +char const * xmlInput = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )xml"; + + + +template< typename LAMBDA > +void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > & solver, + DomainPartition & domain, + real64 const perturbParameter, + real64 const relTol, bool diag_check, + LAMBDA && assembleFunction ) +{ + CompositionalMultiphaseWell & wellSolver = *solver.wellSolver(); + CompositionalMultiphaseFVM & flowSolver = dynamicCast< CompositionalMultiphaseFVM & >( *solver.reservoirSolver() ); + + localIndex const NC = flowSolver.numFluidComponents(); + + CRSMatrix< real64, globalIndex > const & jacobian = solver.getLocalMatrix(); + array1d< real64 > residual( jacobian.numRows() ); + DofManager const & dofManager = solver.getDofManager(); + + // assemble the analytical residual + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.move( hostMemorySpace, false ); + + // copy the analytical residual + array1d< real64 > residualOrig( residual ); + + // create the numerical jacobian + jacobian.move( hostMemorySpace ); + CRSMatrix< real64, globalIndex > jacobianFD( jacobian ); + jacobianFD.zero(); + + string const resDofKey = dofManager.getKey( wellSolver.resElementDofName() ); + string const wellDofKey = dofManager.getKey( wellSolver.wellElementDofName() ); + + // at this point we start assembling the finite-difference block by block + + //////////////////////////////////////////////// + // Step 1) Compute the terms in J_RR and J_WR // + //////////////////////////////////////////////// + if( 1 ) + domain.forMeshBodies( [&] ( MeshBody & meshBody ) + { + meshBody.forMeshLevels( [&] ( MeshLevel & mesh ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + for( localIndex er = 0; er < elemManager.numRegions(); ++er ) + { + ElementRegionBase & elemRegion = elemManager.getRegion( er ); + elemRegion.forElementSubRegionsIndex< CellElementSubRegion >( [&]( localIndex const, CellElementSubRegion & subRegion ) + { + // get the degrees of freedom and ghosting information + arrayView1d< globalIndex const > const & dofNumber = + subRegion.getReference< array1d< globalIndex > >( resDofKey ); + + // get the primary variables on the reservoir elements + arrayView1d< real64 > const & pres = + subRegion.getField< fields::flow::pressure >(); + pres.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & compDens = + subRegion.getField< fields::flow::globalCompDensity >(); + compDens.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & temp = + subRegion.getField< fields::flow::temperature >(); + temp.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in RESERVOIR elem ei + for( localIndex ei = 0; ei < subRegion.size(); ++ei ) + { + if( ei !=0 ) + break; + real64 totalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + totalDensity += compDens[ei][ic]; + } + + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the element + real64 const dP = perturbParameter * (pres[ei] + perturbParameter); + pres.move( hostMemorySpace, true ); + pres[ei] += dP; + + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei], + dP, + jacobianFD.toViewConstSizes() ); + } + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter * totalDensity; + compDens.move( hostMemorySpace, true ); + compDens[ei][jc] += dRho; + + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + wellSolver.updateState( domain ); + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei] + jc + 1, + dRho, + jacobianFD.toViewConstSizes() ); + } + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the element + real64 const dTemp = perturbParameter * (temp[ei] + perturbParameter); + temp.move( hostMemorySpace, true ); + temp[ei] += dTemp; + + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei]+NC+1, + dTemp, + jacobianFD.toViewConstSizes() ); + } + } + } ); + } + } ); + return; + } ); + + ///////////////////////////////////////////////// + // Step 2) Compute the terms in J_RW and J_WW // + ///////////////////////////////////////////////// + + // loop over the wells + if( 1 ) + wellSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + // get the degrees of freedom, ghosting info and next well elem index + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + + // get the primary variables on the well elements + arrayView1d< real64 > const & wellElemPressure = + subRegion.getField< fields::well::pressure >(); + wellElemPressure.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & wellElemTemperature = + subRegion.getField< fields::well::temperature >(); + wellElemTemperature.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = + subRegion.getField< fields::well::globalCompDensity >(); + wellElemCompDens.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & connRate = + subRegion.getField< fields::well::mixtureConnectionRate >(); + connRate.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in WELL elem iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + + real64 wellElemTotalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + wellElemTotalDensity += wellElemCompDens[iwelem][ic]; + } + + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the well element + real64 const dP = perturbParameter * ( wellElemPressure[iwelem] + perturbParameter ); + wellElemPressure.move( hostMemorySpace, true ); + wellElemPressure[iwelem] += dP; + + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DPRES, + dP, + jacobianFD.toViewConstSizes() ); + } + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter * wellElemTotalDensity; + wellElemCompDens.move( hostMemorySpace, true ); + wellElemCompDens[iwelem][jc] += dRho; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + jc, + dRho, + jacobianFD.toViewConstSizes() ); + } + { + solver.resetStateToBeginningOfStep( domain ); + residual.zero(); + jacobian.zero(); + if( diag_check || iwelem > 0 ) + { + // here is the perturbation in the temperature of the well element + real64 const dT = perturbParameter * ( wellElemTemperature[iwelem] + perturbParameter ); + wellElemTemperature.move( hostMemorySpace, true ); + wellElemTemperature[iwelem] += dT; + + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); + + + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1, + dT, + jacobianFD.toViewConstSizes() ); + if( iwelem == 1 ) + { + real64 dRdX = 0.0; + localIndex rowIndex = wellElemDofNumber[0] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; + for( integer ider=0; ider< 3; ider++ ) + { + globalIndex colIndex = wellElemDofNumber[0]+ ider; + setNumericalJacobianValue( rowIndex, colIndex, dRdX, jacobianFD.toViewConstSizes() ); + } + globalIndex colIndex = wellElemDofNumber[1]+3; + setNumericalJacobianValue( rowIndex, colIndex, dRdX, jacobianFD.toViewConstSizes() ); + } + } + else + { + localIndex rowIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; + globalIndex colIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; + setNumericalJacobianValue( rowIndex, colIndex, 1.0, jacobianFD.toViewConstSizes() ); + } + + } + } + + + // b) compute all the derivatives wrt to the connection in WELL elem + // iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the rate of the well element + real64 const dRate = perturbParameter * ( connRate[iwelem] + perturbParameter ); + connRate.move( hostMemorySpace, true ); + connRate[iwelem] += dRate; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC, + dRate, + jacobianFD.toViewConstSizes() ); + } + } + } ); + } ); + + // assemble the analytical jacobian + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + //printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); + compareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst(), relTol ); +} + +class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test +{ +public: + + CompositionalMultiphaseReservoirSolverTest(): + state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ) + {} + +protected: + + void SetUp() override + { + setupProblemFromXML( state.getProblemManager(), xmlInput ); + solver = &state.getProblemManager().getPhysicsSolverManager().getGroup< CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > >( "reservoirSystem" ); + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + solver->setupSystem( domain, + solver->getDofManager(), + solver->getLocalMatrix(), + solver->getSystemRhs(), + solver->getSystemSolution() ); + + solver->implicitStepSetup( time, dt, domain ); + } + + static real64 constexpr time = 0.0; + static real64 constexpr dt = 1e4; + static real64 constexpr eps = std::numeric_limits< real64 >::epsilon(); + + GeosxState state; + CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > * solver; +}; + +real64 constexpr CompositionalMultiphaseReservoirSolverTest::time; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::dt; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::eps; + +#if 0 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Perforation ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->assembleCouplingTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + //solver->assembleSystem( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#endif + +#if 0 +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Flux ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, false, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleSystem( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + //solver->assembleSystem( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + //solver->assembleCouplingTerms( time,dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#endif +#if 0 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_flux ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, true, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->computePerforationRates( time, dt, domain ); + solver->wellSolver()->assembleFluxTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + solver->assembleCouplingTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif +#if 1 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Accum_Vol_Energy_Bal ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, false, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleAccumulationTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_PressureRel ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, true, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assemblePressureRelations( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif +int main( int argc, char * * argv ) +{ + writeTableToFile( "co2flash.txt", co2flash ); + writeTableToFile( "pvtliquid.txt", pvtLiquid ); + writeTableToFile( "pvtgas.txt", pvtGas ); + ::testing::InitGoogleTest( &argc, argv ); + g_commandLineOptions = *geos::basicSetup( argc, argv ); + int const result = RUN_ALL_TESTS(); + geos::basicCleanup(); + removeFile( "co2flash.txt" ); + removeFile( "pvtliquid.txt" ); + removeFile( "pvtgas.txt" ); + + return result; +} diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp new file mode 100644 index 00000000000..3c26e4d9f68 --- /dev/null +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp @@ -0,0 +1,808 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "unitTests/fluidFlowTests/testCompFlowUtils.hpp" + +#include "common/DataTypes.hpp" +#include "mainInterface/initialization.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "mainInterface/ProblemManager.hpp" +#include "mesh/DomainPartition.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mesh/WellElementSubRegion.hpp" +#include "physicsSolvers/PhysicsSolverManager.hpp" +#include "physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" +#include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp" + +using namespace geos; +using namespace geos::dataRepository; +using namespace geos::constitutive; +using namespace geos::testing; + +CommandLineOptions g_commandLineOptions; + +void writeTableToFile( string const & filename, char const * str ) +{ + std::ofstream os( filename ); + ASSERT_TRUE( os.is_open() ); + os << str; + os.close(); +} + +void removeFile( string const & filename ) +{ + int const ret = std::remove( filename.c_str() ); + ASSERT_TRUE( ret == 0 ); +} +char const * co2flash = "FlashModel CO2Solubility 1e6 7.5e7 5e5 299.15 369.15 10 0"; +char const * pvtLiquid = "DensityFun PhillipsBrineDensity 1e6 7.5e7 5e5 299.15 369.15 10 0\n" + "ViscosityFun PhillipsBrineViscosity 0\n" + "EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0\n"; + +char const * pvtGas = "DensityFun SpanWagnerCO2Density 1e6 7.5e7 5e5 299.15 369.15 10\n" + "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" + "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; + +char const * xmlInput = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )xml"; + + + +template< typename LAMBDA > +void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > & solver, + DomainPartition & domain, + real64 const perturbParameter, + real64 const relTol, bool diag_check, + LAMBDA && assembleFunction ) +{ + CompositionalMultiphaseWell & wellSolver = *solver.wellSolver(); + CompositionalMultiphaseFVM & flowSolver = dynamicCast< CompositionalMultiphaseFVM & >( *solver.reservoirSolver() ); + + localIndex const NC = flowSolver.numFluidComponents(); + + CRSMatrix< real64, globalIndex > const & jacobian = solver.getLocalMatrix(); + array1d< real64 > residual( jacobian.numRows() ); + DofManager const & dofManager = solver.getDofManager(); + + // assemble the analytical residual + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.move( hostMemorySpace, false ); + + // copy the analytical residual + array1d< real64 > residualOrig( residual ); + + // create the numerical jacobian + jacobian.move( hostMemorySpace ); + CRSMatrix< real64, globalIndex > jacobianFD( jacobian ); + jacobianFD.zero(); + + string const resDofKey = dofManager.getKey( wellSolver.resElementDofName() ); + string const wellDofKey = dofManager.getKey( wellSolver.wellElementDofName() ); + + // at this point we start assembling the finite-difference block by block + + //////////////////////////////////////////////// + // Step 1) Compute the terms in J_RR and J_WR // + //////////////////////////////////////////////// + if( 1 ) + domain.forMeshBodies( [&] ( MeshBody & meshBody ) + { + meshBody.forMeshLevels( [&] ( MeshLevel & mesh ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + for( localIndex er = 0; er < elemManager.numRegions(); ++er ) + { + ElementRegionBase & elemRegion = elemManager.getRegion( er ); + elemRegion.forElementSubRegionsIndex< CellElementSubRegion >( [&]( localIndex const, CellElementSubRegion & subRegion ) + { + // get the degrees of freedom and ghosting information + arrayView1d< globalIndex const > const & dofNumber = + subRegion.getReference< array1d< globalIndex > >( resDofKey ); + + // get the primary variables on the reservoir elements + arrayView1d< real64 > const & pres = + subRegion.getField< fields::flow::pressure >(); + pres.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & compDens = + subRegion.getField< fields::flow::globalCompDensity >(); + compDens.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & temp = + subRegion.getField< fields::flow::temperature >(); + temp.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in RESERVOIR elem ei + for( localIndex ei = 0; ei < subRegion.size(); ++ei ) + { + if( ei ==0 ) + { + real64 totalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + totalDensity += compDens[ei][ic]; + } + + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the element + real64 const dP = perturbParameter * (pres[ei] + perturbParameter); + pres.move( hostMemorySpace, true ); + pres[ei] += dP; + + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei], + dP, + jacobianFD.toViewConstSizes() ); + } + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter * totalDensity; + compDens.move( hostMemorySpace, true ); + compDens[ei][jc] += dRho; + + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + wellSolver.updateState( domain ); + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei] + jc + 1, + dRho, + jacobianFD.toViewConstSizes() ); + } + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the element + real64 const dTemp = perturbParameter * (temp[ei] + perturbParameter); + temp.move( hostMemorySpace, true ); + temp[ei] += dTemp; + + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei]+NC+1, + dTemp, + jacobianFD.toViewConstSizes() ); + } + } + } + } ); + } + } ); + return; + } ); + + ///////////////////////////////////////////////// + // Step 2) Compute the terms in J_RW and J_WW // + ///////////////////////////////////////////////// + + // loop over the wells + if( 1 ) + wellSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + // get the degrees of freedom, ghosting info and next well elem index + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + + // get the primary variables on the well elements + arrayView1d< real64 > const & wellElemPressure = + subRegion.getField< fields::well::pressure >(); + wellElemPressure.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & wellElemTemperature = + subRegion.getField< fields::well::temperature >(); + wellElemTemperature.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = + subRegion.getField< fields::well::globalCompDensity >(); + wellElemCompDens.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & connRate = + subRegion.getField< fields::well::mixtureConnectionRate >(); + connRate.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in WELL elem iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + + real64 wellElemTotalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + wellElemTotalDensity += wellElemCompDens[iwelem][ic]; + } + + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the well element + real64 const dP = perturbParameter * ( wellElemPressure[iwelem] + perturbParameter ); + wellElemPressure.move( hostMemorySpace, true ); + wellElemPressure[iwelem] += dP; + + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DPRES, + dP, + jacobianFD.toViewConstSizes() ); + } + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter * wellElemTotalDensity; + wellElemCompDens.move( hostMemorySpace, true ); + wellElemCompDens[iwelem][jc] += dRho; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + jc, + dRho, + jacobianFD.toViewConstSizes() ); + } + { + solver.resetStateToBeginningOfStep( domain ); + residual.zero(); + jacobian.zero(); + if( diag_check || iwelem > 0 ) + { + // here is the perturbation in the temperature of the well element + real64 const dT = perturbParameter * ( wellElemTemperature[iwelem] + perturbParameter ); + wellElemTemperature.move( hostMemorySpace, true ); + wellElemTemperature[iwelem] += dT; + + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); + + + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1, + dT, + jacobianFD.toViewConstSizes() ); + } + else + { + localIndex rowIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; + globalIndex colIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; + setNumericalJacobianValue( rowIndex, colIndex, 1.0, jacobianFD.toViewConstSizes() ); + } + } + } + + + // b) compute all the derivatives wrt to the connection in WELL elem + // iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the rate of the well element + real64 const dRate = perturbParameter * ( connRate[iwelem] + perturbParameter ); + connRate.move( hostMemorySpace, true ); + connRate[iwelem] += dRate; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC, + dRate, + jacobianFD.toViewConstSizes() ); + } + } + } ); + } ); + + // assemble the analytical jacobian + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + //printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); + compareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst(), relTol ); +} + +class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test +{ +public: + + CompositionalMultiphaseReservoirSolverTest(): + state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ) + {} + +protected: + + void SetUp() override + { + setupProblemFromXML( state.getProblemManager(), xmlInput ); + solver = &state.getProblemManager().getPhysicsSolverManager().getGroup< CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > >( "reservoirSystem" ); + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + solver->setupSystem( domain, + solver->getDofManager(), + solver->getLocalMatrix(), + solver->getSystemRhs(), + solver->getSystemSolution() ); + + solver->implicitStepSetup( time, dt, domain ); + } + + static real64 constexpr time = 0.0; + static real64 constexpr dt = 1e4; + static real64 constexpr eps = std::numeric_limits< real64 >::epsilon(); + + GeosxState state; + CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > * solver; +}; + +real64 constexpr CompositionalMultiphaseReservoirSolverTest::time; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::dt; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::eps; + +#if 0 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Perforation ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->assembleCouplingTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + //solver->assembleSystem( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#endif + +#if 1 +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Flux ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, false, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleSystem( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + //solver->assembleSystem( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + //solver->assembleCouplingTerms( time,dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#endif +#if 0 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_flux ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, true, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->computePerforationRates( time, dt, domain ); + solver->wellSolver()->assembleFluxTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + solver->assembleCouplingTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif +#if 1 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Accum_Vol_Energy_Bal ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, false, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleAccumulationTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_PressureRel ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, true, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assemblePressureRelations( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif +int main( int argc, char * * argv ) +{ + writeTableToFile( "co2flash.txt", co2flash ); + writeTableToFile( "pvtliquid.txt", pvtLiquid ); + writeTableToFile( "pvtgas.txt", pvtGas ); + ::testing::InitGoogleTest( &argc, argv ); + g_commandLineOptions = *geos::basicSetup( argc, argv ); + int const result = RUN_ALL_TESTS(); + geos::basicCleanup(); + removeFile( "co2flash.txt" ); + removeFile( "pvtliquid.txt" ); + removeFile( "pvtgas.txt" ); + + return result; +} diff --git a/src/coreComponents/unitTests/wellsTests/testWellEnums.cpp b/src/coreComponents/unitTests/wellsTests/testWellEnums.cpp index 21b046363c0..27b318e4511 100644 --- a/src/coreComponents/unitTests/wellsTests/testWellEnums.cpp +++ b/src/coreComponents/unitTests/wellsTests/testWellEnums.cpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2020- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/coreComponents/unitTests/xmlTests/CMakeLists.txt b/src/coreComponents/unitTests/xmlTests/CMakeLists.txt index f2b1c7bb5fc..28d5cc772ae 100644 --- a/src/coreComponents/unitTests/xmlTests/CMakeLists.txt +++ b/src/coreComponents/unitTests/xmlTests/CMakeLists.txt @@ -15,22 +15,12 @@ set( multi_files multifile_input/outputs.xml multifile_input/solver.xml ) -# Add gtest C++ based tests -set( dependencyList ${parallelDeps} gtest optionparser ) +set( tplDependencyList ${parallelDeps} gtest ) -if ( GEOSX_BUILD_SHARED_LIBS ) - list( APPEND dependencyList geosx_core ) -else() - list( APPEND dependencyList ${geosx_core_libs} ) -endif() +set( dependencyList mainInterface ) -if (TARGET pugixml::pugixml) - set( dependencyList ${dependencyList} pugixml::pugixml ) -endif() - -if (TARGET pugixml) - set( dependencyList ${dependencyList} pugixml ) -endif() +geos_decorate_link_dependencies( LIST decoratedDependencies + DEPENDENCIES ${dependencyList} ) # create test executables foreach(test ${gtest_geosx_tests} ${gtest_tests_with_input}) @@ -38,7 +28,7 @@ foreach(test ${gtest_geosx_tests} ${gtest_tests_with_input}) blt_add_executable( NAME ${test_name} SOURCES ${test} OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} - DEPENDS_ON ${dependencyList} "-lz" ) + DEPENDS_ON ${decoratedDependencies} ${tplDependencyList} "-lz" ) endforeach() # add tests that don't require input files diff --git a/src/coreComponents/unitTests/xmlTests/basic_input.xml b/src/coreComponents/unitTests/xmlTests/basic_input.xml index 37c611aa479..3735d47c0f4 100644 --- a/src/coreComponents/unitTests/xmlTests/basic_input.xml +++ b/src/coreComponents/unitTests/xmlTests/basic_input.xml @@ -46,7 +46,7 @@ diff --git a/src/coreComponents/unitTests/xmlTests/multifile_input/solver.xml b/src/coreComponents/unitTests/xmlTests/multifile_input/solver.xml index c1e25343bc3..9b2bc1e11e2 100644 --- a/src/coreComponents/unitTests/xmlTests/multifile_input/solver.xml +++ b/src/coreComponents/unitTests/xmlTests/multifile_input/solver.xml @@ -29,7 +29,7 @@ diff --git a/src/coreComponents/unitTests/xmlTests/testXML.cpp b/src/coreComponents/unitTests/xmlTests/testXML.cpp index 4e9f3ebc31d..0f2e4c90d67 100644 --- a/src/coreComponents/unitTests/xmlTests/testXML.cpp +++ b/src/coreComponents/unitTests/xmlTests/testXML.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -63,7 +64,7 @@ TEST( testXML, testXMLString ) diff --git a/src/coreComponents/unitTests/xmlTests/testXMLFile.cpp b/src/coreComponents/unitTests/xmlTests/testXMLFile.cpp index 88fed5c4a7e..274a5d52e9b 100644 --- a/src/coreComponents/unitTests/xmlTests/testXMLFile.cpp +++ b/src/coreComponents/unitTests/xmlTests/testXMLFile.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/docs/doxygen/Doxyfile.in b/src/docs/doxygen/Doxyfile.in index f872f18f60c..f3869f78f70 100644 --- a/src/docs/doxygen/Doxyfile.in +++ b/src/docs/doxygen/Doxyfile.in @@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = "GEOSX" +PROJECT_NAME = "GEOS" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version @@ -767,6 +767,7 @@ INPUT = @PROJECT_SOURCE_DIR@/coreComponents/common \ @PROJECT_SOURCE_DIR@/coreComponents/finiteElement/elementFormulations \ @PROJECT_SOURCE_DIR@/coreComponents/finiteElement/kernelInterface \ @PROJECT_SOURCE_DIR@/coreComponents/mesh/MeshFields.hpp \ + @PROJECT_SOURCE_DIR@/coreComponents/physicsSolvers/PhysicsSolverBase.hpp \ @PROJECT_SOURCE_DIR@/coreComponents/physicsSolvers/simplePDE/LaplaceFEMKernels.hpp \ @PROJECT_SOURCE_DIR@/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitFiniteStrain.hpp \ @PROJECT_SOURCE_DIR@/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitSmallStrain.hpp \ diff --git a/src/docs/doxygen/GeosxConfig.hpp b/src/docs/doxygen/GeosxConfig.hpp index 4ad4fd61164..44a7b9be831 100644 --- a/src/docs/doxygen/GeosxConfig.hpp +++ b/src/docs/doxygen/GeosxConfig.hpp @@ -9,28 +9,28 @@ #define GEOS_COMMON_CONFIG_HPP /// Enables floating point exceptions -#define GEOSX_USE_FPE +#define GEOS_USE_FPE /// Enables bounds check in LvArray classes (CMake option ARRAY_BOUNDS_CHECK) -/* #undef GEOSX_USE_ARRAY_BOUNDS_CHECK */ +/* #undef GEOS_USE_ARRAY_BOUNDS_CHECK */ /// Enables use of Caliper (CMake option ENABLE_CALIPER) -#define GEOSX_USE_CALIPER +#define GEOS_USE_CALIPER /// Enables use of Caliper (CMake option ENABLE_ADIAK) -/* #undef GEOSX_USE_ADIAK */ +/* #undef GEOS_USE_ADIAK */ /// Enables use of CHAI (CMake option ENABLE_CHAI) -#define GEOSX_USE_CHAI +#define GEOS_USE_CHAI /// Enables use of Mathpresso library (CMake option ENABLE_MATHPRESSO) -#define GEOSX_USE_MATHPRESSO +#define GEOS_USE_MATHPRESSO /// Enables use of MPI (CMake option ENABLE_MPI) -#define GEOSX_USE_MPI +#define GEOS_USE_MPI /// Enables use of OpenMP (CMake option ENABLE_OPENMP) -#define GEOSX_USE_OPENMP +/* #undef GEOS_USE_OPENMP */ /// Enables use of CUDA (CMake option ENABLE_CUDA) /* #undef GEOS_USE_CUDA */ @@ -45,28 +45,28 @@ /* #undef GEOS_USE_FMT_CONST_FORMATTER_WORKAROUND */ /// Enables use of PVTPackage (CMake option ENABLE_PVTPackage) -#define GEOSX_USE_PVTPackage +#define GEOS_USE_PVTPackage /// Enables use of Python (CMake option ENABLE_PYTHON) -/* #undef GEOSX_USE_PYGEOSX */ +/* #undef GEOS_USE_PYGEOSX */ /// Enables use of RAJA (CMake option ENABLE_RAJA) -#define GEOSX_USE_RAJA +#define GEOS_USE_RAJA /// Enables use of sys/time.h based timers (CMake option ENABLE_TIMERS) -/* #undef GEOSX_USE_TIMERS */ +/* #undef GEOS_USE_TIMERS */ /// Enables use of additional debugging interface for TotalView (Cmake option ENABLE_TOTALVIEW_OUTPUT) -/* #undef GEOSX_USE_TOTALVIEW_OUTPUT */ +/* #undef GEOS_USE_TOTALVIEW_OUTPUT */ /// Enables use of Intel MKL (CMake option ENABLE_MKL) -/* #undef GEOSX_USE_MKL */ +/* #undef GEOS_USE_MKL */ /// Enables use of Trilinos library (CMake option ENABLE_TRILINOS) -#define GEOSX_USE_TRILINOS +#define GEOS_USE_TRILINOS /// Enables use of Hypre library (CMake option ENABLE_HYPRE) -#define GEOSX_USE_HYPRE +#define GEOS_USE_HYPRE /// Denotes HYPRE using CPU #define GEOS_USE_HYPRE_CPU 0 @@ -78,46 +78,46 @@ #define GEOS_USE_HYPRE_DEVICE GEOS_USE_HYPRE_CPU /// Enables use of SuperLU_dist library through HYPRE (CMake option ENABLE_SUPERLU_DIST) -#define GEOSX_USE_SUPERLU_DIST +#define GEOS_USE_SUPERLU_DIST /// Enables use of PETSc library (CMake option ENABLE_PETSC) -#define GEOSX_USE_PETSC +#define GEOS_USE_PETSC /// Enables use of Scotch library (CMake option ENABLE_SCOTCH) -#define GEOSX_USE_SCOTCH +#define GEOS_USE_SCOTCH -/// Choice of global linear algebra interface (CMake option GEOSX_LA_INTERFACE) -#define GEOSX_LA_INTERFACE Hypre +/// Choice of global linear algebra interface (CMake option GEOS_LA_INTERFACE) +#define GEOS_LA_INTERFACE Hypre /// Macro defined when Trilinos interface is selected -/* #undef GEOSX_LA_INTERFACE_TRILINOS */ +/* #undef GEOS_LA_INTERFACE_TRILINOS */ /// Macro defined when Hypre interface is selected -#define GEOSX_LA_INTERFACE_HYPRE +#define GEOS_LA_INTERFACE_HYPRE /// Macro defined when PETSc interface is selected -/* #undef GEOSX_LA_INTERFACE_PETSC */ +/* #undef GEOS_LA_INTERFACE_PETSC */ /// Platform-dependent mangling of fortran function names (CMake option FORTRAN_MANGLE_NO_UNDERSCORE) /* #undef FORTRAN_MANGLE_NO_UNDERSCORE */ /// USE OF SEPARATION COEFFICIENT IN FRACTURE FLOW -/* #undef GEOSX_USE_SEPARATION_COEFFICIENT */ +/* #undef GEOS_USE_SEPARATION_COEFFICIENT */ /// CMake option CMAKE_BUILD_TYPE -#define GEOSX_CMAKE_BUILD_TYPE "Release" +#define GEOS_CMAKE_BUILD_TYPE "Release" /// The type that localIndex will be aliased to. -#define GEOSX_LOCALINDEX_TYPE int +#define GEOS_LOCALINDEX_TYPE int /// An integer flag representing the type that localIndex will be aliased to. -#define GEOSX_LOCALINDEX_TYPE_FLAG 0 +#define GEOS_LOCALINDEX_TYPE_FLAG 0 /// The type that globalIndex will be aliased to. -#define GEOSX_GLOBALINDEX_TYPE long long int +#define GEOS_GLOBALINDEX_TYPE long long int /// An integer flag representing the type that globalIndex will be aliased to. -#define GEOSX_GLOBALINDEX_TYPE_FLAG 2 +#define GEOS_GLOBALINDEX_TYPE_FLAG 2 /// The default block size for GEOSX on this platform -#define GEOSX_BLOCK_SIZE 32 +#define GEOS_BLOCK_SIZE 32 /// Version information for HDF5 #define HDF5_VERSION 1.12.1 @@ -126,10 +126,10 @@ #define Conduit_VERSION 0.8.2 /// Version information for RAJA -#define RAJA_VERSION 2023.6.1 +#define RAJA_VERSION 2022.10.5 /// Version information for umpire -#define umpire_VERSION 2023.6.0 +#define umpire_VERSION 2022.10.0 /// Version information for chai /* #undef chai_VERSION */ @@ -138,7 +138,7 @@ #define adiak_VERSION .. /// Version information for caliper -#define caliper_VERSION 2.10.0 +#define caliper_VERSION 2.8.0 /// Version information for Metis #define metis_VERSION 5.1.0 @@ -147,7 +147,7 @@ #define parmetis_VERSION 4.0.0 /// Version information for scotch -#define scotch_VERSION 7.0.3 +#define scotch_VERSION 6.0.9 /// Version information for superlu_dist #define superlu_dist_VERSION 6.3.0 diff --git a/src/docs/sphinx/CompleteXMLSchema.rst b/src/docs/sphinx/CompleteXMLSchema.rst deleted file mode 100644 index 73517d48697..00000000000 --- a/src/docs/sphinx/CompleteXMLSchema.rst +++ /dev/null @@ -1,2955 +0,0 @@ -###################### -Datastructure Index -###################### - -************************** - -Input Schema Definitions -************************** - -:download:`XML Schema <../../coreComponents/schema/docs/../schema.xsd>` - - -.. _XML_AcousticElasticSEM: - -Element: AcousticElasticSEM -=========================== -.. include:: ../../coreComponents/schema/docs/AcousticElasticSEM.rst - - -.. _XML_AcousticFirstOrderSEM: - -Element: AcousticFirstOrderSEM -============================== -.. include:: ../../coreComponents/schema/docs/AcousticFirstOrderSEM.rst - - -.. _XML_AcousticSEM: - -Element: AcousticSEM -==================== -.. include:: ../../coreComponents/schema/docs/AcousticSEM.rst - - -.. _XML_AcousticVTISEM: - -Element: AcousticVTISEM -======================= -.. include:: ../../coreComponents/schema/docs/AcousticVTISEM.rst - - -.. _XML_Aquifer: - -Element: Aquifer -================ -.. include:: ../../coreComponents/schema/docs/Aquifer.rst - - -.. _XML_Benchmarks: - -Element: Benchmarks -=================== -.. include:: ../../coreComponents/schema/docs/Benchmarks.rst - - -.. _XML_BiotPorosity: - -Element: BiotPorosity -===================== -.. include:: ../../coreComponents/schema/docs/BiotPorosity.rst - - -.. _XML_BlackOilFluid: - -Element: BlackOilFluid -====================== -.. include:: ../../coreComponents/schema/docs/BlackOilFluid.rst - - -.. _XML_Blueprint: - -Element: Blueprint -================== -.. include:: ../../coreComponents/schema/docs/Blueprint.rst - - -.. _XML_Box: - -Element: Box -============ -.. include:: ../../coreComponents/schema/docs/Box.rst - - -.. _XML_BrooksCoreyBakerRelativePermeability: - -Element: BrooksCoreyBakerRelativePermeability -============================================= -.. include:: ../../coreComponents/schema/docs/BrooksCoreyBakerRelativePermeability.rst - - -.. _XML_BrooksCoreyCapillaryPressure: - -Element: BrooksCoreyCapillaryPressure -===================================== -.. include:: ../../coreComponents/schema/docs/BrooksCoreyCapillaryPressure.rst - - -.. _XML_BrooksCoreyRelativePermeability: - -Element: BrooksCoreyRelativePermeability -======================================== -.. include:: ../../coreComponents/schema/docs/BrooksCoreyRelativePermeability.rst - - -.. _XML_BrooksCoreyStone2RelativePermeability: - -Element: BrooksCoreyStone2RelativePermeability -============================================== -.. include:: ../../coreComponents/schema/docs/BrooksCoreyStone2RelativePermeability.rst - - -.. _XML_CO2BrineEzrokhiFluid: - -Element: CO2BrineEzrokhiFluid -============================= -.. include:: ../../coreComponents/schema/docs/CO2BrineEzrokhiFluid.rst - - -.. _XML_CO2BrineEzrokhiThermalFluid: - -Element: CO2BrineEzrokhiThermalFluid -==================================== -.. include:: ../../coreComponents/schema/docs/CO2BrineEzrokhiThermalFluid.rst - - -.. _XML_CO2BrinePhillipsFluid: - -Element: CO2BrinePhillipsFluid -============================== -.. include:: ../../coreComponents/schema/docs/CO2BrinePhillipsFluid.rst - - -.. _XML_CO2BrinePhillipsThermalFluid: - -Element: CO2BrinePhillipsThermalFluid -===================================== -.. include:: ../../coreComponents/schema/docs/CO2BrinePhillipsThermalFluid.rst - - -.. _XML_CarmanKozenyPermeability: - -Element: CarmanKozenyPermeability -================================= -.. include:: ../../coreComponents/schema/docs/CarmanKozenyPermeability.rst - - -.. _XML_CellElementRegion: - -Element: CellElementRegion -========================== -.. include:: ../../coreComponents/schema/docs/CellElementRegion.rst - - -.. _XML_CeramicDamage: - -Element: CeramicDamage -====================== -.. include:: ../../coreComponents/schema/docs/CeramicDamage.rst - - -.. _XML_ChomboIO: - -Element: ChomboIO -================= -.. include:: ../../coreComponents/schema/docs/ChomboIO.rst - - -.. _XML_CompositeFunction: - -Element: CompositeFunction -========================== -.. include:: ../../coreComponents/schema/docs/CompositeFunction.rst - - -.. _XML_CompositionalMultiphaseFVM: - -Element: CompositionalMultiphaseFVM -=================================== -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseFVM.rst - - -.. _XML_CompositionalMultiphaseFluid: - -Element: CompositionalMultiphaseFluid -===================================== -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseFluid.rst - - -.. _XML_CompositionalMultiphaseHybridFVM: - -Element: CompositionalMultiphaseHybridFVM -========================================= -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseHybridFVM.rst - - -.. _XML_CompositionalMultiphaseReservoir: - -Element: CompositionalMultiphaseReservoir -========================================= -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseReservoir.rst - - -.. _XML_CompositionalMultiphaseReservoirPoromechanics: - -Element: CompositionalMultiphaseReservoirPoromechanics -====================================================== -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanics.rst - - -.. _XML_CompositionalMultiphaseReservoirPoromechanicsInitialization: - -Element: CompositionalMultiphaseReservoirPoromechanicsInitialization -==================================================================== -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanicsInitialization.rst - - -.. _XML_CompositionalMultiphaseStatistics: - -Element: CompositionalMultiphaseStatistics -========================================== -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseStatistics.rst - - -.. _XML_CompositionalMultiphaseWell: - -Element: CompositionalMultiphaseWell -==================================== -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseWell.rst - - -.. _XML_CompositonalTwoPhaseFluidPengRobinson: - -Element: CompositonalTwoPhaseFluidPengRobinson -============================================== -.. include:: ../../coreComponents/schema/docs/CompositonalTwoPhaseFluidPengRobinson.rst - - -.. _XML_CompositonalTwoPhaseFluidSoaveRedlichKwong: - -Element: CompositonalTwoPhaseFluidSoaveRedlichKwong -=================================================== -.. include:: ../../coreComponents/schema/docs/CompositonalTwoPhaseFluidSoaveRedlichKwong.rst - - -.. _XML_CompressibleSinglePhaseFluid: - -Element: CompressibleSinglePhaseFluid -===================================== -.. include:: ../../coreComponents/schema/docs/CompressibleSinglePhaseFluid.rst - - -.. _XML_CompressibleSolidCarmanKozenyPermeability: - -Element: CompressibleSolidCarmanKozenyPermeability -================================================== -.. include:: ../../coreComponents/schema/docs/CompressibleSolidCarmanKozenyPermeability.rst - - -.. _XML_CompressibleSolidConstantPermeability: - -Element: CompressibleSolidConstantPermeability -============================================== -.. include:: ../../coreComponents/schema/docs/CompressibleSolidConstantPermeability.rst - - -.. _XML_CompressibleSolidExponentialDecayPermeability: - -Element: CompressibleSolidExponentialDecayPermeability -====================================================== -.. include:: ../../coreComponents/schema/docs/CompressibleSolidExponentialDecayPermeability.rst - - -.. _XML_CompressibleSolidParallelPlatesPermeability: - -Element: CompressibleSolidParallelPlatesPermeability -==================================================== -.. include:: ../../coreComponents/schema/docs/CompressibleSolidParallelPlatesPermeability.rst - - -.. _XML_CompressibleSolidSlipDependentPermeability: - -Element: CompressibleSolidSlipDependentPermeability -=================================================== -.. include:: ../../coreComponents/schema/docs/CompressibleSolidSlipDependentPermeability.rst - - -.. _XML_CompressibleSolidWillisRichardsPermeability: - -Element: CompressibleSolidWillisRichardsPermeability -==================================================== -.. include:: ../../coreComponents/schema/docs/CompressibleSolidWillisRichardsPermeability.rst - - -.. _XML_ConstantDiffusion: - -Element: ConstantDiffusion -========================== -.. include:: ../../coreComponents/schema/docs/ConstantDiffusion.rst - - -.. _XML_ConstantPermeability: - -Element: ConstantPermeability -============================= -.. include:: ../../coreComponents/schema/docs/ConstantPermeability.rst - - -.. _XML_Constitutive: - -Element: Constitutive -===================== -.. include:: ../../coreComponents/schema/docs/Constitutive.rst - - -.. _XML_Coulomb: - -Element: Coulomb -================ -.. include:: ../../coreComponents/schema/docs/Coulomb.rst - - -.. _XML_CustomPolarObject: - -Element: CustomPolarObject -========================== -.. include:: ../../coreComponents/schema/docs/CustomPolarObject.rst - - -.. _XML_Cylinder: - -Element: Cylinder -================= -.. include:: ../../coreComponents/schema/docs/Cylinder.rst - - -.. _XML_DamageElasticIsotropic: - -Element: DamageElasticIsotropic -=============================== -.. include:: ../../coreComponents/schema/docs/DamageElasticIsotropic.rst - - -.. _XML_DamageSpectralElasticIsotropic: - -Element: DamageSpectralElasticIsotropic -======================================= -.. include:: ../../coreComponents/schema/docs/DamageSpectralElasticIsotropic.rst - - -.. _XML_DamageVolDevElasticIsotropic: - -Element: DamageVolDevElasticIsotropic -===================================== -.. include:: ../../coreComponents/schema/docs/DamageVolDevElasticIsotropic.rst - - -.. _XML_DeadOilFluid: - -Element: DeadOilFluid -===================== -.. include:: ../../coreComponents/schema/docs/DeadOilFluid.rst - - -.. _XML_DelftEgg: - -Element: DelftEgg -================= -.. include:: ../../coreComponents/schema/docs/DelftEgg.rst - - -.. _XML_Dirichlet: - -Element: Dirichlet -================== -.. include:: ../../coreComponents/schema/docs/Dirichlet.rst - - -.. _XML_Disc: - -Element: Disc -============= -.. include:: ../../coreComponents/schema/docs/Disc.rst - - -.. _XML_DruckerPrager: - -Element: DruckerPrager -====================== -.. include:: ../../coreComponents/schema/docs/DruckerPrager.rst - - -.. _XML_ElasticFirstOrderSEM: - -Element: ElasticFirstOrderSEM -============================= -.. include:: ../../coreComponents/schema/docs/ElasticFirstOrderSEM.rst - - -.. _XML_ElasticIsotropic: - -Element: ElasticIsotropic -========================= -.. include:: ../../coreComponents/schema/docs/ElasticIsotropic.rst - - -.. _XML_ElasticIsotropicPressureDependent: - -Element: ElasticIsotropicPressureDependent -========================================== -.. include:: ../../coreComponents/schema/docs/ElasticIsotropicPressureDependent.rst - - -.. _XML_ElasticOrthotropic: - -Element: ElasticOrthotropic -=========================== -.. include:: ../../coreComponents/schema/docs/ElasticOrthotropic.rst - - -.. _XML_ElasticSEM: - -Element: ElasticSEM -=================== -.. include:: ../../coreComponents/schema/docs/ElasticSEM.rst - - -.. _XML_ElasticTransverseIsotropic: - -Element: ElasticTransverseIsotropic -=================================== -.. include:: ../../coreComponents/schema/docs/ElasticTransverseIsotropic.rst - - -.. _XML_ElementRegions: - -Element: ElementRegions -======================= -.. include:: ../../coreComponents/schema/docs/ElementRegions.rst - - -.. _XML_EmbeddedSurfaceGenerator: - -Element: EmbeddedSurfaceGenerator -================================= -.. include:: ../../coreComponents/schema/docs/EmbeddedSurfaceGenerator.rst - - -.. _XML_Events: - -Element: Events -=============== -.. include:: ../../coreComponents/schema/docs/Events.rst - - -.. _XML_ExponentialDecayPermeability: - -Element: ExponentialDecayPermeability -===================================== -.. include:: ../../coreComponents/schema/docs/ExponentialDecayPermeability.rst - - -.. _XML_ExtendedDruckerPrager: - -Element: ExtendedDruckerPrager -============================== -.. include:: ../../coreComponents/schema/docs/ExtendedDruckerPrager.rst - - -.. _XML_FieldSpecification: - -Element: FieldSpecification -=========================== -.. include:: ../../coreComponents/schema/docs/FieldSpecification.rst - - -.. _XML_FieldSpecifications: - -Element: FieldSpecifications -============================ -.. include:: ../../coreComponents/schema/docs/FieldSpecifications.rst - - -.. _XML_File: - -Element: File -============= -.. include:: ../../coreComponents/schema/docs/File.rst - - -.. _XML_FiniteElementSpace: - -Element: FiniteElementSpace -=========================== -.. include:: ../../coreComponents/schema/docs/FiniteElementSpace.rst - - -.. _XML_FiniteElements: - -Element: FiniteElements -======================= -.. include:: ../../coreComponents/schema/docs/FiniteElements.rst - - -.. _XML_FiniteVolume: - -Element: FiniteVolume -===================== -.. include:: ../../coreComponents/schema/docs/FiniteVolume.rst - - -.. _XML_FlowProppantTransport: - -Element: FlowProppantTransport -============================== -.. include:: ../../coreComponents/schema/docs/FlowProppantTransport.rst - - -.. _XML_FrictionlessContact: - -Element: FrictionlessContact -============================ -.. include:: ../../coreComponents/schema/docs/FrictionlessContact.rst - - -.. _XML_Functions: - -Element: Functions -================== -.. include:: ../../coreComponents/schema/docs/Functions.rst - - -.. _XML_Geometry: - -Element: Geometry -================= -.. include:: ../../coreComponents/schema/docs/Geometry.rst - - -.. _XML_HaltEvent: - -Element: HaltEvent -================== -.. include:: ../../coreComponents/schema/docs/HaltEvent.rst - - -.. _XML_HybridMimeticDiscretization: - -Element: HybridMimeticDiscretization -==================================== -.. include:: ../../coreComponents/schema/docs/HybridMimeticDiscretization.rst - - -.. _XML_Hydrofracture: - -Element: Hydrofracture -====================== -.. include:: ../../coreComponents/schema/docs/Hydrofracture.rst - - -.. _XML_HydrostaticEquilibrium: - -Element: HydrostaticEquilibrium -=============================== -.. include:: ../../coreComponents/schema/docs/HydrostaticEquilibrium.rst - - -.. _XML_Included: - -Element: Included -================= -.. include:: ../../coreComponents/schema/docs/Included.rst - - -.. _XML_InternalMesh: - -Element: InternalMesh -===================== -.. include:: ../../coreComponents/schema/docs/InternalMesh.rst - - -.. _XML_InternalWell: - -Element: InternalWell -===================== -.. include:: ../../coreComponents/schema/docs/InternalWell.rst - - -.. _XML_InternalWellbore: - -Element: InternalWellbore -========================= -.. include:: ../../coreComponents/schema/docs/InternalWellbore.rst - - -.. _XML_JFunctionCapillaryPressure: - -Element: JFunctionCapillaryPressure -=================================== -.. include:: ../../coreComponents/schema/docs/JFunctionCapillaryPressure.rst - - -.. _XML_LaplaceFEM: - -Element: LaplaceFEM -=================== -.. include:: ../../coreComponents/schema/docs/LaplaceFEM.rst - - -.. _XML_LinearIsotropicDispersion: - -Element: LinearIsotropicDispersion -================================== -.. include:: ../../coreComponents/schema/docs/LinearIsotropicDispersion.rst - - -.. _XML_LinearSolverParameters: - -Element: LinearSolverParameters -=============================== -.. include:: ../../coreComponents/schema/docs/LinearSolverParameters.rst - - -.. _XML_Mesh: - -Element: Mesh -============= -.. include:: ../../coreComponents/schema/docs/Mesh.rst - - -.. _XML_ModifiedCamClay: - -Element: ModifiedCamClay -======================== -.. include:: ../../coreComponents/schema/docs/ModifiedCamClay.rst - - -.. _XML_MultiPhaseConstantThermalConductivity: - -Element: MultiPhaseConstantThermalConductivity -============================================== -.. include:: ../../coreComponents/schema/docs/MultiPhaseConstantThermalConductivity.rst - - -.. _XML_MultiPhaseVolumeWeightedThermalConductivity: - -Element: MultiPhaseVolumeWeightedThermalConductivity -==================================================== -.. include:: ../../coreComponents/schema/docs/MultiPhaseVolumeWeightedThermalConductivity.rst - - -.. _XML_MultiphasePoromechanics: - -Element: MultiphasePoromechanics -================================ -.. include:: ../../coreComponents/schema/docs/MultiphasePoromechanics.rst - - -.. _XML_MultiphasePoromechanicsInitialization: - -Element: MultiphasePoromechanicsInitialization -============================================== -.. include:: ../../coreComponents/schema/docs/MultiphasePoromechanicsInitialization.rst - - -.. _XML_MultiphasePoromechanicsReservoir: - -Element: MultiphasePoromechanicsReservoir -========================================= -.. include:: ../../coreComponents/schema/docs/MultiphasePoromechanicsReservoir.rst - - -.. _XML_MultivariableTableFunction: - -Element: MultivariableTableFunction -=================================== -.. include:: ../../coreComponents/schema/docs/MultivariableTableFunction.rst - - -.. _XML_NonlinearSolverParameters: - -Element: NonlinearSolverParameters -================================== -.. include:: ../../coreComponents/schema/docs/NonlinearSolverParameters.rst - - -.. _XML_NullModel: - -Element: NullModel -================== -.. include:: ../../coreComponents/schema/docs/NullModel.rst - - -.. _XML_NumericalMethods: - -Element: NumericalMethods -========================= -.. include:: ../../coreComponents/schema/docs/NumericalMethods.rst - - -.. _XML_Outputs: - -Element: Outputs -================ -.. include:: ../../coreComponents/schema/docs/Outputs.rst - - -.. _XML_PML: - -Element: PML -============ -.. include:: ../../coreComponents/schema/docs/PML.rst - - -.. _XML_PVTDriver: - -Element: PVTDriver -================== -.. include:: ../../coreComponents/schema/docs/PVTDriver.rst - - -.. _XML_PackCollection: - -Element: PackCollection -======================= -.. include:: ../../coreComponents/schema/docs/PackCollection.rst - - -.. _XML_ParallelPlatesPermeability: - -Element: ParallelPlatesPermeability -=================================== -.. include:: ../../coreComponents/schema/docs/ParallelPlatesPermeability.rst - - -.. _XML_Parameter: - -Element: Parameter -================== -.. include:: ../../coreComponents/schema/docs/Parameter.rst - - -.. _XML_Parameters: - -Element: Parameters -=================== -.. include:: ../../coreComponents/schema/docs/Parameters.rst - - -.. _XML_ParticleFluid: - -Element: ParticleFluid -====================== -.. include:: ../../coreComponents/schema/docs/ParticleFluid.rst - - -.. _XML_ParticleMesh: - -Element: ParticleMesh -===================== -.. include:: ../../coreComponents/schema/docs/ParticleMesh.rst - - -.. _XML_ParticleRegion: - -Element: ParticleRegion -======================= -.. include:: ../../coreComponents/schema/docs/ParticleRegion.rst - - -.. _XML_ParticleRegions: - -Element: ParticleRegions -======================== -.. include:: ../../coreComponents/schema/docs/ParticleRegions.rst - - -.. _XML_PerfectlyPlastic: - -Element: PerfectlyPlastic -========================= -.. include:: ../../coreComponents/schema/docs/PerfectlyPlastic.rst - - -.. _XML_Perforation: - -Element: Perforation -==================== -.. include:: ../../coreComponents/schema/docs/Perforation.rst - - -.. _XML_PeriodicEvent: - -Element: PeriodicEvent -====================== -.. include:: ../../coreComponents/schema/docs/PeriodicEvent.rst - - -.. _XML_PermeabilityBase: - -Element: PermeabilityBase -========================= -.. include:: ../../coreComponents/schema/docs/PermeabilityBase.rst - - -.. _XML_PhaseFieldDamageFEM: - -Element: PhaseFieldDamageFEM -============================ -.. include:: ../../coreComponents/schema/docs/PhaseFieldDamageFEM.rst - - -.. _XML_PhaseFieldFracture: - -Element: PhaseFieldFracture -=========================== -.. include:: ../../coreComponents/schema/docs/PhaseFieldFracture.rst - - -.. _XML_PorousDamageElasticIsotropic: - -Element: PorousDamageElasticIsotropic -===================================== -.. include:: ../../coreComponents/schema/docs/PorousDamageElasticIsotropic.rst - - -.. _XML_PorousDamageSpectralElasticIsotropic: - -Element: PorousDamageSpectralElasticIsotropic -============================================= -.. include:: ../../coreComponents/schema/docs/PorousDamageSpectralElasticIsotropic.rst - - -.. _XML_PorousDamageVolDevElasticIsotropic: - -Element: PorousDamageVolDevElasticIsotropic -=========================================== -.. include:: ../../coreComponents/schema/docs/PorousDamageVolDevElasticIsotropic.rst - - -.. _XML_PorousDelftEgg: - -Element: PorousDelftEgg -======================= -.. include:: ../../coreComponents/schema/docs/PorousDelftEgg.rst - - -.. _XML_PorousDruckerPrager: - -Element: PorousDruckerPrager -============================ -.. include:: ../../coreComponents/schema/docs/PorousDruckerPrager.rst - - -.. _XML_PorousElasticIsotropic: - -Element: PorousElasticIsotropic -=============================== -.. include:: ../../coreComponents/schema/docs/PorousElasticIsotropic.rst - - -.. _XML_PorousElasticOrthotropic: - -Element: PorousElasticOrthotropic -================================= -.. include:: ../../coreComponents/schema/docs/PorousElasticOrthotropic.rst - - -.. _XML_PorousElasticTransverseIsotropic: - -Element: PorousElasticTransverseIsotropic -========================================= -.. include:: ../../coreComponents/schema/docs/PorousElasticTransverseIsotropic.rst - - -.. _XML_PorousExtendedDruckerPrager: - -Element: PorousExtendedDruckerPrager -==================================== -.. include:: ../../coreComponents/schema/docs/PorousExtendedDruckerPrager.rst - - -.. _XML_PorousModifiedCamClay: - -Element: PorousModifiedCamClay -============================== -.. include:: ../../coreComponents/schema/docs/PorousModifiedCamClay.rst - - -.. _XML_PorousViscoDruckerPrager: - -Element: PorousViscoDruckerPrager -================================= -.. include:: ../../coreComponents/schema/docs/PorousViscoDruckerPrager.rst - - -.. _XML_PorousViscoExtendedDruckerPrager: - -Element: PorousViscoExtendedDruckerPrager -========================================= -.. include:: ../../coreComponents/schema/docs/PorousViscoExtendedDruckerPrager.rst - - -.. _XML_PorousViscoModifiedCamClay: - -Element: PorousViscoModifiedCamClay -=================================== -.. include:: ../../coreComponents/schema/docs/PorousViscoModifiedCamClay.rst - - -.. _XML_PressurePorosity: - -Element: PressurePorosity -========================= -.. include:: ../../coreComponents/schema/docs/PressurePorosity.rst - - -.. _XML_Problem: - -Element: Problem -================ -.. include:: ../../coreComponents/schema/docs/Problem.rst - - -.. _XML_ProppantPermeability: - -Element: ProppantPermeability -============================= -.. include:: ../../coreComponents/schema/docs/ProppantPermeability.rst - - -.. _XML_ProppantPorosity: - -Element: ProppantPorosity -========================= -.. include:: ../../coreComponents/schema/docs/ProppantPorosity.rst - - -.. _XML_ProppantSlurryFluid: - -Element: ProppantSlurryFluid -============================ -.. include:: ../../coreComponents/schema/docs/ProppantSlurryFluid.rst - - -.. _XML_ProppantSolidProppantPermeability: - -Element: ProppantSolidProppantPermeability -========================================== -.. include:: ../../coreComponents/schema/docs/ProppantSolidProppantPermeability.rst - - -.. _XML_ProppantTransport: - -Element: ProppantTransport -========================== -.. include:: ../../coreComponents/schema/docs/ProppantTransport.rst - - -.. _XML_Python: - -Element: Python -=============== -.. include:: ../../coreComponents/schema/docs/Python.rst - - -.. _XML_ReactiveBrine: - -Element: ReactiveBrine -====================== -.. include:: ../../coreComponents/schema/docs/ReactiveBrine.rst - - -.. _XML_ReactiveBrineThermal: - -Element: ReactiveBrineThermal -============================= -.. include:: ../../coreComponents/schema/docs/ReactiveBrineThermal.rst - - -.. _XML_ReactiveCompositionalMultiphaseOBL: - -Element: ReactiveCompositionalMultiphaseOBL -=========================================== -.. include:: ../../coreComponents/schema/docs/ReactiveCompositionalMultiphaseOBL.rst - - -.. _XML_ReactiveFluidDriver: - -Element: ReactiveFluidDriver -============================ -.. include:: ../../coreComponents/schema/docs/ReactiveFluidDriver.rst - - -.. _XML_Rectangle: - -Element: Rectangle -================== -.. include:: ../../coreComponents/schema/docs/Rectangle.rst - - -.. _XML_RelpermDriver: - -Element: RelpermDriver -====================== -.. include:: ../../coreComponents/schema/docs/RelpermDriver.rst - - -.. _XML_Restart: - -Element: Restart -================ -.. include:: ../../coreComponents/schema/docs/Restart.rst - - -.. _XML_Run: - -Element: Run -============ -.. include:: ../../coreComponents/schema/docs/Run.rst - - -.. _XML_Silo: - -Element: Silo -============= -.. include:: ../../coreComponents/schema/docs/Silo.rst - - -.. _XML_SinglePhaseConstantThermalConductivity: - -Element: SinglePhaseConstantThermalConductivity -=============================================== -.. include:: ../../coreComponents/schema/docs/SinglePhaseConstantThermalConductivity.rst - - -.. _XML_SinglePhaseFVM: - -Element: SinglePhaseFVM -======================= -.. include:: ../../coreComponents/schema/docs/SinglePhaseFVM.rst - - -.. _XML_SinglePhaseHybridFVM: - -Element: SinglePhaseHybridFVM -============================= -.. include:: ../../coreComponents/schema/docs/SinglePhaseHybridFVM.rst - - -.. _XML_SinglePhasePoromechanics: - -Element: SinglePhasePoromechanics -================================= -.. include:: ../../coreComponents/schema/docs/SinglePhasePoromechanics.rst - - -.. _XML_SinglePhasePoromechanicsConformingFractures: - -Element: SinglePhasePoromechanicsConformingFractures -==================================================== -.. include:: ../../coreComponents/schema/docs/SinglePhasePoromechanicsConformingFractures.rst - - -.. _XML_SinglePhasePoromechanicsEmbeddedFractures: - -Element: SinglePhasePoromechanicsEmbeddedFractures -================================================== -.. include:: ../../coreComponents/schema/docs/SinglePhasePoromechanicsEmbeddedFractures.rst - - -.. _XML_SinglePhasePoromechanicsInitialization: - -Element: SinglePhasePoromechanicsInitialization -=============================================== -.. include:: ../../coreComponents/schema/docs/SinglePhasePoromechanicsInitialization.rst - - -.. _XML_SinglePhasePoromechanicsReservoir: - -Element: SinglePhasePoromechanicsReservoir -========================================== -.. include:: ../../coreComponents/schema/docs/SinglePhasePoromechanicsReservoir.rst - - -.. _XML_SinglePhaseProppantFVM: - -Element: SinglePhaseProppantFVM -=============================== -.. include:: ../../coreComponents/schema/docs/SinglePhaseProppantFVM.rst - - -.. _XML_SinglePhaseReservoir: - -Element: SinglePhaseReservoir -============================= -.. include:: ../../coreComponents/schema/docs/SinglePhaseReservoir.rst - - -.. _XML_SinglePhaseReservoirPoromechanics: - -Element: SinglePhaseReservoirPoromechanics -========================================== -.. include:: ../../coreComponents/schema/docs/SinglePhaseReservoirPoromechanics.rst - - -.. _XML_SinglePhaseReservoirPoromechanicsInitialization: - -Element: SinglePhaseReservoirPoromechanicsInitialization -======================================================== -.. include:: ../../coreComponents/schema/docs/SinglePhaseReservoirPoromechanicsInitialization.rst - - -.. _XML_SinglePhaseStatistics: - -Element: SinglePhaseStatistics -============================== -.. include:: ../../coreComponents/schema/docs/SinglePhaseStatistics.rst - - -.. _XML_SinglePhaseWell: - -Element: SinglePhaseWell -======================== -.. include:: ../../coreComponents/schema/docs/SinglePhaseWell.rst - - -.. _XML_SlipDependentPermeability: - -Element: SlipDependentPermeability -================================== -.. include:: ../../coreComponents/schema/docs/SlipDependentPermeability.rst - - -.. _XML_SolidInternalEnergy: - -Element: SolidInternalEnergy -============================ -.. include:: ../../coreComponents/schema/docs/SolidInternalEnergy.rst - - -.. _XML_SolidMechanicsEmbeddedFractures: - -Element: SolidMechanicsEmbeddedFractures -======================================== -.. include:: ../../coreComponents/schema/docs/SolidMechanicsEmbeddedFractures.rst - - -.. _XML_SolidMechanicsLagrangeContact: - -Element: SolidMechanicsLagrangeContact -====================================== -.. include:: ../../coreComponents/schema/docs/SolidMechanicsLagrangeContact.rst - - -.. _XML_SolidMechanicsLagrangianSSLE: - -Element: SolidMechanicsLagrangianSSLE -===================================== -.. include:: ../../coreComponents/schema/docs/SolidMechanicsLagrangianSSLE.rst - - -.. _XML_SolidMechanicsStateReset: - -Element: SolidMechanicsStateReset -================================= -.. include:: ../../coreComponents/schema/docs/SolidMechanicsStateReset.rst - - -.. _XML_SolidMechanicsStatistics: - -Element: SolidMechanicsStatistics -================================= -.. include:: ../../coreComponents/schema/docs/SolidMechanicsStatistics.rst - - -.. _XML_SolidMechanics_LagrangianFEM: - -Element: SolidMechanics_LagrangianFEM -===================================== -.. include:: ../../coreComponents/schema/docs/SolidMechanics_LagrangianFEM.rst - - -.. _XML_SolidMechanics_MPM: - -Element: SolidMechanics_MPM -=========================== -.. include:: ../../coreComponents/schema/docs/SolidMechanics_MPM.rst - - -.. _XML_SoloEvent: - -Element: SoloEvent -================== -.. include:: ../../coreComponents/schema/docs/SoloEvent.rst - - -.. _XML_Solvers: - -Element: Solvers -================ -.. include:: ../../coreComponents/schema/docs/Solvers.rst - - -.. _XML_SourceFlux: - -Element: SourceFlux -=================== -.. include:: ../../coreComponents/schema/docs/SourceFlux.rst - - -.. _XML_SurfaceElementRegion: - -Element: SurfaceElementRegion -============================= -.. include:: ../../coreComponents/schema/docs/SurfaceElementRegion.rst - - -.. _XML_SurfaceGenerator: - -Element: SurfaceGenerator -========================= -.. include:: ../../coreComponents/schema/docs/SurfaceGenerator.rst - - -.. _XML_SymbolicFunction: - -Element: SymbolicFunction -========================= -.. include:: ../../coreComponents/schema/docs/SymbolicFunction.rst - - -.. _XML_TableCapillaryPressure: - -Element: TableCapillaryPressure -=============================== -.. include:: ../../coreComponents/schema/docs/TableCapillaryPressure.rst - - -.. _XML_TableFunction: - -Element: TableFunction -====================== -.. include:: ../../coreComponents/schema/docs/TableFunction.rst - - -.. _XML_TableRelativePermeability: - -Element: TableRelativePermeability -================================== -.. include:: ../../coreComponents/schema/docs/TableRelativePermeability.rst - - -.. _XML_TableRelativePermeabilityHysteresis: - -Element: TableRelativePermeabilityHysteresis -============================================ -.. include:: ../../coreComponents/schema/docs/TableRelativePermeabilityHysteresis.rst - - -.. _XML_Tasks: - -Element: Tasks -============== -.. include:: ../../coreComponents/schema/docs/Tasks.rst - - -.. _XML_ThermalCompressibleSinglePhaseFluid: - -Element: ThermalCompressibleSinglePhaseFluid -============================================ -.. include:: ../../coreComponents/schema/docs/ThermalCompressibleSinglePhaseFluid.rst - - -.. _XML_ThickPlane: - -Element: ThickPlane -=================== -.. include:: ../../coreComponents/schema/docs/ThickPlane.rst - - -.. _XML_TimeHistory: - -Element: TimeHistory -==================== -.. include:: ../../coreComponents/schema/docs/TimeHistory.rst - - -.. _XML_Traction: - -Element: Traction -================= -.. include:: ../../coreComponents/schema/docs/Traction.rst - - -.. _XML_TriaxialDriver: - -Element: TriaxialDriver -======================= -.. include:: ../../coreComponents/schema/docs/TriaxialDriver.rst - - -.. _XML_TwoPointFluxApproximation: - -Element: TwoPointFluxApproximation -================================== -.. include:: ../../coreComponents/schema/docs/TwoPointFluxApproximation.rst - - -.. _XML_VTK: - -Element: VTK -============ -.. include:: ../../coreComponents/schema/docs/VTK.rst - - -.. _XML_VTKMesh: - -Element: VTKMesh -================ -.. include:: ../../coreComponents/schema/docs/VTKMesh.rst - - -.. _XML_VTKWell: - -Element: VTKWell -================ -.. include:: ../../coreComponents/schema/docs/VTKWell.rst - - -.. _XML_VanGenuchtenBakerRelativePermeability: - -Element: VanGenuchtenBakerRelativePermeability -============================================== -.. include:: ../../coreComponents/schema/docs/VanGenuchtenBakerRelativePermeability.rst - - -.. _XML_VanGenuchtenCapillaryPressure: - -Element: VanGenuchtenCapillaryPressure -====================================== -.. include:: ../../coreComponents/schema/docs/VanGenuchtenCapillaryPressure.rst - - -.. _XML_VanGenuchtenStone2RelativePermeability: - -Element: VanGenuchtenStone2RelativePermeability -=============================================== -.. include:: ../../coreComponents/schema/docs/VanGenuchtenStone2RelativePermeability.rst - - -.. _XML_ViscoDruckerPrager: - -Element: ViscoDruckerPrager -=========================== -.. include:: ../../coreComponents/schema/docs/ViscoDruckerPrager.rst - - -.. _XML_ViscoExtendedDruckerPrager: - -Element: ViscoExtendedDruckerPrager -=================================== -.. include:: ../../coreComponents/schema/docs/ViscoExtendedDruckerPrager.rst - - -.. _XML_ViscoModifiedCamClay: - -Element: ViscoModifiedCamClay -============================= -.. include:: ../../coreComponents/schema/docs/ViscoModifiedCamClay.rst - - -.. _XML_WellControls: - -Element: WellControls -===================== -.. include:: ../../coreComponents/schema/docs/WellControls.rst - - -.. _XML_WellElementRegion: - -Element: WellElementRegion -========================== -.. include:: ../../coreComponents/schema/docs/WellElementRegion.rst - - -.. _XML_WillisRichardsPermeability: - -Element: WillisRichardsPermeability -=================================== -.. include:: ../../coreComponents/schema/docs/WillisRichardsPermeability.rst - - -.. _XML_crusher: - -Element: crusher -================ -.. include:: ../../coreComponents/schema/docs/crusher.rst - - -.. _XML_lassen: - -Element: lassen -=============== -.. include:: ../../coreComponents/schema/docs/lassen.rst - - -.. _XML_quartz: - -Element: quartz -=============== -.. include:: ../../coreComponents/schema/docs/quartz.rst - -******************************** -Datastructure Definitions -******************************** - - -.. _DATASTRUCTURE_AcousticElasticSEM: - -Datastructure: AcousticElasticSEM -================================= -.. include:: ../../coreComponents/schema/docs/AcousticElasticSEM_other.rst - - -.. _DATASTRUCTURE_AcousticFirstOrderSEM: - -Datastructure: AcousticFirstOrderSEM -==================================== -.. include:: ../../coreComponents/schema/docs/AcousticFirstOrderSEM_other.rst - - -.. _DATASTRUCTURE_AcousticSEM: - -Datastructure: AcousticSEM -========================== -.. include:: ../../coreComponents/schema/docs/AcousticSEM_other.rst - - -.. _DATASTRUCTURE_AcousticVTISEM: - -Datastructure: AcousticVTISEM -============================= -.. include:: ../../coreComponents/schema/docs/AcousticVTISEM_other.rst - - -.. _DATASTRUCTURE_Aquifer: - -Datastructure: Aquifer -====================== -.. include:: ../../coreComponents/schema/docs/Aquifer_other.rst - - -.. _DATASTRUCTURE_Benchmarks: - -Datastructure: Benchmarks -========================= -.. include:: ../../coreComponents/schema/docs/Benchmarks_other.rst - - -.. _DATASTRUCTURE_BiotPorosity: - -Datastructure: BiotPorosity -=========================== -.. include:: ../../coreComponents/schema/docs/BiotPorosity_other.rst - - -.. _DATASTRUCTURE_BlackOilFluid: - -Datastructure: BlackOilFluid -============================ -.. include:: ../../coreComponents/schema/docs/BlackOilFluid_other.rst - - -.. _DATASTRUCTURE_Blueprint: - -Datastructure: Blueprint -======================== -.. include:: ../../coreComponents/schema/docs/Blueprint_other.rst - - -.. _DATASTRUCTURE_Box: - -Datastructure: Box -================== -.. include:: ../../coreComponents/schema/docs/Box_other.rst - - -.. _DATASTRUCTURE_BrooksCoreyBakerRelativePermeability: - -Datastructure: BrooksCoreyBakerRelativePermeability -=================================================== -.. include:: ../../coreComponents/schema/docs/BrooksCoreyBakerRelativePermeability_other.rst - - -.. _DATASTRUCTURE_BrooksCoreyCapillaryPressure: - -Datastructure: BrooksCoreyCapillaryPressure -=========================================== -.. include:: ../../coreComponents/schema/docs/BrooksCoreyCapillaryPressure_other.rst - - -.. _DATASTRUCTURE_BrooksCoreyRelativePermeability: - -Datastructure: BrooksCoreyRelativePermeability -============================================== -.. include:: ../../coreComponents/schema/docs/BrooksCoreyRelativePermeability_other.rst - - -.. _DATASTRUCTURE_BrooksCoreyStone2RelativePermeability: - -Datastructure: BrooksCoreyStone2RelativePermeability -==================================================== -.. include:: ../../coreComponents/schema/docs/BrooksCoreyStone2RelativePermeability_other.rst - - -.. _DATASTRUCTURE_CO2BrineEzrokhiFluid: - -Datastructure: CO2BrineEzrokhiFluid -=================================== -.. include:: ../../coreComponents/schema/docs/CO2BrineEzrokhiFluid_other.rst - - -.. _DATASTRUCTURE_CO2BrineEzrokhiThermalFluid: - -Datastructure: CO2BrineEzrokhiThermalFluid -========================================== -.. include:: ../../coreComponents/schema/docs/CO2BrineEzrokhiThermalFluid_other.rst - - -.. _DATASTRUCTURE_CO2BrinePhillipsFluid: - -Datastructure: CO2BrinePhillipsFluid -==================================== -.. include:: ../../coreComponents/schema/docs/CO2BrinePhillipsFluid_other.rst - - -.. _DATASTRUCTURE_CO2BrinePhillipsThermalFluid: - -Datastructure: CO2BrinePhillipsThermalFluid -=========================================== -.. include:: ../../coreComponents/schema/docs/CO2BrinePhillipsThermalFluid_other.rst - - -.. _DATASTRUCTURE_CarmanKozenyPermeability: - -Datastructure: CarmanKozenyPermeability -======================================= -.. include:: ../../coreComponents/schema/docs/CarmanKozenyPermeability_other.rst - - -.. _DATASTRUCTURE_CellElementRegion: - -Datastructure: CellElementRegion -================================ -.. include:: ../../coreComponents/schema/docs/CellElementRegion_other.rst - - -.. _DATASTRUCTURE_CeramicDamage: - -Datastructure: CeramicDamage -============================ -.. include:: ../../coreComponents/schema/docs/CeramicDamage_other.rst - - -.. _DATASTRUCTURE_ChomboIO: - -Datastructure: ChomboIO -======================= -.. include:: ../../coreComponents/schema/docs/ChomboIO_other.rst - - -.. _DATASTRUCTURE_CompositeFunction: - -Datastructure: CompositeFunction -================================ -.. include:: ../../coreComponents/schema/docs/CompositeFunction_other.rst - - -.. _DATASTRUCTURE_CompositionalMultiphaseFVM: - -Datastructure: CompositionalMultiphaseFVM -========================================= -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseFVM_other.rst - - -.. _DATASTRUCTURE_CompositionalMultiphaseFluid: - -Datastructure: CompositionalMultiphaseFluid -=========================================== -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseFluid_other.rst - - -.. _DATASTRUCTURE_CompositionalMultiphaseHybridFVM: - -Datastructure: CompositionalMultiphaseHybridFVM -=============================================== -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseHybridFVM_other.rst - - -.. _DATASTRUCTURE_CompositionalMultiphaseReservoir: - -Datastructure: CompositionalMultiphaseReservoir -=============================================== -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseReservoir_other.rst - - -.. _DATASTRUCTURE_CompositionalMultiphaseReservoirPoromechanics: - -Datastructure: CompositionalMultiphaseReservoirPoromechanics -============================================================ -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanics_other.rst - - -.. _DATASTRUCTURE_CompositionalMultiphaseReservoirPoromechanicsInitialization: - -Datastructure: CompositionalMultiphaseReservoirPoromechanicsInitialization -========================================================================== -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseReservoirPoromechanicsInitialization_other.rst - - -.. _DATASTRUCTURE_CompositionalMultiphaseStatistics: - -Datastructure: CompositionalMultiphaseStatistics -================================================ -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseStatistics_other.rst - - -.. _DATASTRUCTURE_CompositionalMultiphaseWell: - -Datastructure: CompositionalMultiphaseWell -========================================== -.. include:: ../../coreComponents/schema/docs/CompositionalMultiphaseWell_other.rst - - -.. _DATASTRUCTURE_CompositonalTwoPhaseFluidPengRobinson: - -Datastructure: CompositonalTwoPhaseFluidPengRobinson -==================================================== -.. include:: ../../coreComponents/schema/docs/CompositonalTwoPhaseFluidPengRobinson_other.rst - - -.. _DATASTRUCTURE_CompositonalTwoPhaseFluidSoaveRedlichKwong: - -Datastructure: CompositonalTwoPhaseFluidSoaveRedlichKwong -========================================================= -.. include:: ../../coreComponents/schema/docs/CompositonalTwoPhaseFluidSoaveRedlichKwong_other.rst - - -.. _DATASTRUCTURE_CompressibleSinglePhaseFluid: - -Datastructure: CompressibleSinglePhaseFluid -=========================================== -.. include:: ../../coreComponents/schema/docs/CompressibleSinglePhaseFluid_other.rst - - -.. _DATASTRUCTURE_CompressibleSolidCarmanKozenyPermeability: - -Datastructure: CompressibleSolidCarmanKozenyPermeability -======================================================== -.. include:: ../../coreComponents/schema/docs/CompressibleSolidCarmanKozenyPermeability_other.rst - - -.. _DATASTRUCTURE_CompressibleSolidConstantPermeability: - -Datastructure: CompressibleSolidConstantPermeability -==================================================== -.. include:: ../../coreComponents/schema/docs/CompressibleSolidConstantPermeability_other.rst - - -.. _DATASTRUCTURE_CompressibleSolidExponentialDecayPermeability: - -Datastructure: CompressibleSolidExponentialDecayPermeability -============================================================ -.. include:: ../../coreComponents/schema/docs/CompressibleSolidExponentialDecayPermeability_other.rst - - -.. _DATASTRUCTURE_CompressibleSolidParallelPlatesPermeability: - -Datastructure: CompressibleSolidParallelPlatesPermeability -========================================================== -.. include:: ../../coreComponents/schema/docs/CompressibleSolidParallelPlatesPermeability_other.rst - - -.. _DATASTRUCTURE_CompressibleSolidSlipDependentPermeability: - -Datastructure: CompressibleSolidSlipDependentPermeability -========================================================= -.. include:: ../../coreComponents/schema/docs/CompressibleSolidSlipDependentPermeability_other.rst - - -.. _DATASTRUCTURE_CompressibleSolidWillisRichardsPermeability: - -Datastructure: CompressibleSolidWillisRichardsPermeability -========================================================== -.. include:: ../../coreComponents/schema/docs/CompressibleSolidWillisRichardsPermeability_other.rst - - -.. _DATASTRUCTURE_ConstantDiffusion: - -Datastructure: ConstantDiffusion -================================ -.. include:: ../../coreComponents/schema/docs/ConstantDiffusion_other.rst - - -.. _DATASTRUCTURE_ConstantPermeability: - -Datastructure: ConstantPermeability -=================================== -.. include:: ../../coreComponents/schema/docs/ConstantPermeability_other.rst - - -.. _DATASTRUCTURE_Constitutive: - -Datastructure: Constitutive -=========================== -.. include:: ../../coreComponents/schema/docs/Constitutive_other.rst - - -.. _DATASTRUCTURE_ConstitutiveModels: - -Datastructure: ConstitutiveModels -================================= -.. include:: ../../coreComponents/schema/docs/ConstitutiveModels_other.rst - - -.. _DATASTRUCTURE_Coulomb: - -Datastructure: Coulomb -====================== -.. include:: ../../coreComponents/schema/docs/Coulomb_other.rst - - -.. _DATASTRUCTURE_CustomPolarObject: - -Datastructure: CustomPolarObject -================================ -.. include:: ../../coreComponents/schema/docs/CustomPolarObject_other.rst - - -.. _DATASTRUCTURE_Cylinder: - -Datastructure: Cylinder -======================= -.. include:: ../../coreComponents/schema/docs/Cylinder_other.rst - - -.. _DATASTRUCTURE_DamageElasticIsotropic: - -Datastructure: DamageElasticIsotropic -===================================== -.. include:: ../../coreComponents/schema/docs/DamageElasticIsotropic_other.rst - - -.. _DATASTRUCTURE_DamageSpectralElasticIsotropic: - -Datastructure: DamageSpectralElasticIsotropic -============================================= -.. include:: ../../coreComponents/schema/docs/DamageSpectralElasticIsotropic_other.rst - - -.. _DATASTRUCTURE_DamageVolDevElasticIsotropic: - -Datastructure: DamageVolDevElasticIsotropic -=========================================== -.. include:: ../../coreComponents/schema/docs/DamageVolDevElasticIsotropic_other.rst - - -.. _DATASTRUCTURE_DeadOilFluid: - -Datastructure: DeadOilFluid -=========================== -.. include:: ../../coreComponents/schema/docs/DeadOilFluid_other.rst - - -.. _DATASTRUCTURE_DelftEgg: - -Datastructure: DelftEgg -======================= -.. include:: ../../coreComponents/schema/docs/DelftEgg_other.rst - - -.. _DATASTRUCTURE_Dirichlet: - -Datastructure: Dirichlet -======================== -.. include:: ../../coreComponents/schema/docs/Dirichlet_other.rst - - -.. _DATASTRUCTURE_Disc: - -Datastructure: Disc -=================== -.. include:: ../../coreComponents/schema/docs/Disc_other.rst - - -.. _DATASTRUCTURE_DruckerPrager: - -Datastructure: DruckerPrager -============================ -.. include:: ../../coreComponents/schema/docs/DruckerPrager_other.rst - - -.. _DATASTRUCTURE_ElasticFirstOrderSEM: - -Datastructure: ElasticFirstOrderSEM -=================================== -.. include:: ../../coreComponents/schema/docs/ElasticFirstOrderSEM_other.rst - - -.. _DATASTRUCTURE_ElasticIsotropic: - -Datastructure: ElasticIsotropic -=============================== -.. include:: ../../coreComponents/schema/docs/ElasticIsotropic_other.rst - - -.. _DATASTRUCTURE_ElasticIsotropicPressureDependent: - -Datastructure: ElasticIsotropicPressureDependent -================================================ -.. include:: ../../coreComponents/schema/docs/ElasticIsotropicPressureDependent_other.rst - - -.. _DATASTRUCTURE_ElasticOrthotropic: - -Datastructure: ElasticOrthotropic -================================= -.. include:: ../../coreComponents/schema/docs/ElasticOrthotropic_other.rst - - -.. _DATASTRUCTURE_ElasticSEM: - -Datastructure: ElasticSEM -========================= -.. include:: ../../coreComponents/schema/docs/ElasticSEM_other.rst - - -.. _DATASTRUCTURE_ElasticTransverseIsotropic: - -Datastructure: ElasticTransverseIsotropic -========================================= -.. include:: ../../coreComponents/schema/docs/ElasticTransverseIsotropic_other.rst - - -.. _DATASTRUCTURE_ElementRegions: - -Datastructure: ElementRegions -============================= -.. include:: ../../coreComponents/schema/docs/ElementRegions_other.rst - - -.. _DATASTRUCTURE_EmbeddedSurfaceGenerator: - -Datastructure: EmbeddedSurfaceGenerator -======================================= -.. include:: ../../coreComponents/schema/docs/EmbeddedSurfaceGenerator_other.rst - - -.. _DATASTRUCTURE_Events: - -Datastructure: Events -===================== -.. include:: ../../coreComponents/schema/docs/Events_other.rst - - -.. _DATASTRUCTURE_ExponentialDecayPermeability: - -Datastructure: ExponentialDecayPermeability -=========================================== -.. include:: ../../coreComponents/schema/docs/ExponentialDecayPermeability_other.rst - - -.. _DATASTRUCTURE_ExtendedDruckerPrager: - -Datastructure: ExtendedDruckerPrager -==================================== -.. include:: ../../coreComponents/schema/docs/ExtendedDruckerPrager_other.rst - - -.. _DATASTRUCTURE_FieldSpecification: - -Datastructure: FieldSpecification -================================= -.. include:: ../../coreComponents/schema/docs/FieldSpecification_other.rst - - -.. _DATASTRUCTURE_FieldSpecifications: - -Datastructure: FieldSpecifications -================================== -.. include:: ../../coreComponents/schema/docs/FieldSpecifications_other.rst - - -.. _DATASTRUCTURE_File: - -Datastructure: File -=================== -.. include:: ../../coreComponents/schema/docs/File_other.rst - - -.. _DATASTRUCTURE_FiniteElementSpace: - -Datastructure: FiniteElementSpace -================================= -.. include:: ../../coreComponents/schema/docs/FiniteElementSpace_other.rst - - -.. _DATASTRUCTURE_FiniteElements: - -Datastructure: FiniteElements -============================= -.. include:: ../../coreComponents/schema/docs/FiniteElements_other.rst - - -.. _DATASTRUCTURE_FiniteVolume: - -Datastructure: FiniteVolume -=========================== -.. include:: ../../coreComponents/schema/docs/FiniteVolume_other.rst - - -.. _DATASTRUCTURE_FlowProppantTransport: - -Datastructure: FlowProppantTransport -==================================== -.. include:: ../../coreComponents/schema/docs/FlowProppantTransport_other.rst - - -.. _DATASTRUCTURE_FrictionlessContact: - -Datastructure: FrictionlessContact -================================== -.. include:: ../../coreComponents/schema/docs/FrictionlessContact_other.rst - - -.. _DATASTRUCTURE_Functions: - -Datastructure: Functions -======================== -.. include:: ../../coreComponents/schema/docs/Functions_other.rst - - -.. _DATASTRUCTURE_Geometry: - -Datastructure: Geometry -======================= -.. include:: ../../coreComponents/schema/docs/Geometry_other.rst - - -.. _DATASTRUCTURE_HaltEvent: - -Datastructure: HaltEvent -======================== -.. include:: ../../coreComponents/schema/docs/HaltEvent_other.rst - - -.. _DATASTRUCTURE_HybridMimeticDiscretization: - -Datastructure: HybridMimeticDiscretization -========================================== -.. include:: ../../coreComponents/schema/docs/HybridMimeticDiscretization_other.rst - - -.. _DATASTRUCTURE_Hydrofracture: - -Datastructure: Hydrofracture -============================ -.. include:: ../../coreComponents/schema/docs/Hydrofracture_other.rst - - -.. _DATASTRUCTURE_HydrostaticEquilibrium: - -Datastructure: HydrostaticEquilibrium -===================================== -.. include:: ../../coreComponents/schema/docs/HydrostaticEquilibrium_other.rst - - -.. _DATASTRUCTURE_Included: - -Datastructure: Included -======================= -.. include:: ../../coreComponents/schema/docs/Included_other.rst - - -.. _DATASTRUCTURE_InternalMesh: - -Datastructure: InternalMesh -=========================== -.. include:: ../../coreComponents/schema/docs/InternalMesh_other.rst - - -.. _DATASTRUCTURE_InternalWell: - -Datastructure: InternalWell -=========================== -.. include:: ../../coreComponents/schema/docs/InternalWell_other.rst - - -.. _DATASTRUCTURE_InternalWellbore: - -Datastructure: InternalWellbore -=============================== -.. include:: ../../coreComponents/schema/docs/InternalWellbore_other.rst - - -.. _DATASTRUCTURE_JFunctionCapillaryPressure: - -Datastructure: JFunctionCapillaryPressure -========================================= -.. include:: ../../coreComponents/schema/docs/JFunctionCapillaryPressure_other.rst - - -.. _DATASTRUCTURE_LaplaceFEM: - -Datastructure: LaplaceFEM -========================= -.. include:: ../../coreComponents/schema/docs/LaplaceFEM_other.rst - - -.. _DATASTRUCTURE_Level0: - -Datastructure: Level0 -===================== -.. include:: ../../coreComponents/schema/docs/Level0_other.rst - - -.. _DATASTRUCTURE_LinearIsotropicDispersion: - -Datastructure: LinearIsotropicDispersion -======================================== -.. include:: ../../coreComponents/schema/docs/LinearIsotropicDispersion_other.rst - - -.. _DATASTRUCTURE_LinearSolverParameters: - -Datastructure: LinearSolverParameters -===================================== -.. include:: ../../coreComponents/schema/docs/LinearSolverParameters_other.rst - - -.. _DATASTRUCTURE_Mesh: - -Datastructure: Mesh -=================== -.. include:: ../../coreComponents/schema/docs/Mesh_other.rst - - -.. _DATASTRUCTURE_MeshBodies: - -Datastructure: MeshBodies -========================= -.. include:: ../../coreComponents/schema/docs/MeshBodies_other.rst - - -.. _DATASTRUCTURE_ModifiedCamClay: - -Datastructure: ModifiedCamClay -============================== -.. include:: ../../coreComponents/schema/docs/ModifiedCamClay_other.rst - - -.. _DATASTRUCTURE_MultiPhaseConstantThermalConductivity: - -Datastructure: MultiPhaseConstantThermalConductivity -==================================================== -.. include:: ../../coreComponents/schema/docs/MultiPhaseConstantThermalConductivity_other.rst - - -.. _DATASTRUCTURE_MultiPhaseVolumeWeightedThermalConductivity: - -Datastructure: MultiPhaseVolumeWeightedThermalConductivity -========================================================== -.. include:: ../../coreComponents/schema/docs/MultiPhaseVolumeWeightedThermalConductivity_other.rst - - -.. _DATASTRUCTURE_MultiphasePoromechanics: - -Datastructure: MultiphasePoromechanics -====================================== -.. include:: ../../coreComponents/schema/docs/MultiphasePoromechanics_other.rst - - -.. _DATASTRUCTURE_MultiphasePoromechanicsInitialization: - -Datastructure: MultiphasePoromechanicsInitialization -==================================================== -.. include:: ../../coreComponents/schema/docs/MultiphasePoromechanicsInitialization_other.rst - - -.. _DATASTRUCTURE_MultiphasePoromechanicsReservoir: - -Datastructure: MultiphasePoromechanicsReservoir -=============================================== -.. include:: ../../coreComponents/schema/docs/MultiphasePoromechanicsReservoir_other.rst - - -.. _DATASTRUCTURE_MultivariableTableFunction: - -Datastructure: MultivariableTableFunction -========================================= -.. include:: ../../coreComponents/schema/docs/MultivariableTableFunction_other.rst - - -.. _DATASTRUCTURE_NonlinearSolverParameters: - -Datastructure: NonlinearSolverParameters -======================================== -.. include:: ../../coreComponents/schema/docs/NonlinearSolverParameters_other.rst - - -.. _DATASTRUCTURE_NullModel: - -Datastructure: NullModel -======================== -.. include:: ../../coreComponents/schema/docs/NullModel_other.rst - - -.. _DATASTRUCTURE_NumericalMethods: - -Datastructure: NumericalMethods -=============================== -.. include:: ../../coreComponents/schema/docs/NumericalMethods_other.rst - - -.. _DATASTRUCTURE_Outputs: - -Datastructure: Outputs -====================== -.. include:: ../../coreComponents/schema/docs/Outputs_other.rst - - -.. _DATASTRUCTURE_PML: - -Datastructure: PML -================== -.. include:: ../../coreComponents/schema/docs/PML_other.rst - - -.. _DATASTRUCTURE_PVTDriver: - -Datastructure: PVTDriver -======================== -.. include:: ../../coreComponents/schema/docs/PVTDriver_other.rst - - -.. _DATASTRUCTURE_PackCollection: - -Datastructure: PackCollection -============================= -.. include:: ../../coreComponents/schema/docs/PackCollection_other.rst - - -.. _DATASTRUCTURE_ParallelPlatesPermeability: - -Datastructure: ParallelPlatesPermeability -========================================= -.. include:: ../../coreComponents/schema/docs/ParallelPlatesPermeability_other.rst - - -.. _DATASTRUCTURE_Parameter: - -Datastructure: Parameter -======================== -.. include:: ../../coreComponents/schema/docs/Parameter_other.rst - - -.. _DATASTRUCTURE_Parameters: - -Datastructure: Parameters -========================= -.. include:: ../../coreComponents/schema/docs/Parameters_other.rst - - -.. _DATASTRUCTURE_ParticleFluid: - -Datastructure: ParticleFluid -============================ -.. include:: ../../coreComponents/schema/docs/ParticleFluid_other.rst - - -.. _DATASTRUCTURE_ParticleMesh: - -Datastructure: ParticleMesh -=========================== -.. include:: ../../coreComponents/schema/docs/ParticleMesh_other.rst - - -.. _DATASTRUCTURE_ParticleRegion: - -Datastructure: ParticleRegion -============================= -.. include:: ../../coreComponents/schema/docs/ParticleRegion_other.rst - - -.. _DATASTRUCTURE_ParticleRegions: - -Datastructure: ParticleRegions -============================== -.. include:: ../../coreComponents/schema/docs/ParticleRegions_other.rst - - -.. _DATASTRUCTURE_PerfectlyPlastic: - -Datastructure: PerfectlyPlastic -=============================== -.. include:: ../../coreComponents/schema/docs/PerfectlyPlastic_other.rst - - -.. _DATASTRUCTURE_Perforation: - -Datastructure: Perforation -========================== -.. include:: ../../coreComponents/schema/docs/Perforation_other.rst - - -.. _DATASTRUCTURE_PeriodicEvent: - -Datastructure: PeriodicEvent -============================ -.. include:: ../../coreComponents/schema/docs/PeriodicEvent_other.rst - - -.. _DATASTRUCTURE_PermeabilityBase: - -Datastructure: PermeabilityBase -=============================== -.. include:: ../../coreComponents/schema/docs/PermeabilityBase_other.rst - - -.. _DATASTRUCTURE_PhaseFieldDamageFEM: - -Datastructure: PhaseFieldDamageFEM -================================== -.. include:: ../../coreComponents/schema/docs/PhaseFieldDamageFEM_other.rst - - -.. _DATASTRUCTURE_PhaseFieldFracture: - -Datastructure: PhaseFieldFracture -================================= -.. include:: ../../coreComponents/schema/docs/PhaseFieldFracture_other.rst - - -.. _DATASTRUCTURE_PorousDamageElasticIsotropic: - -Datastructure: PorousDamageElasticIsotropic -=========================================== -.. include:: ../../coreComponents/schema/docs/PorousDamageElasticIsotropic_other.rst - - -.. _DATASTRUCTURE_PorousDamageSpectralElasticIsotropic: - -Datastructure: PorousDamageSpectralElasticIsotropic -=================================================== -.. include:: ../../coreComponents/schema/docs/PorousDamageSpectralElasticIsotropic_other.rst - - -.. _DATASTRUCTURE_PorousDamageVolDevElasticIsotropic: - -Datastructure: PorousDamageVolDevElasticIsotropic -================================================= -.. include:: ../../coreComponents/schema/docs/PorousDamageVolDevElasticIsotropic_other.rst - - -.. _DATASTRUCTURE_PorousDelftEgg: - -Datastructure: PorousDelftEgg -============================= -.. include:: ../../coreComponents/schema/docs/PorousDelftEgg_other.rst - - -.. _DATASTRUCTURE_PorousDruckerPrager: - -Datastructure: PorousDruckerPrager -================================== -.. include:: ../../coreComponents/schema/docs/PorousDruckerPrager_other.rst - - -.. _DATASTRUCTURE_PorousElasticIsotropic: - -Datastructure: PorousElasticIsotropic -===================================== -.. include:: ../../coreComponents/schema/docs/PorousElasticIsotropic_other.rst - - -.. _DATASTRUCTURE_PorousElasticOrthotropic: - -Datastructure: PorousElasticOrthotropic -======================================= -.. include:: ../../coreComponents/schema/docs/PorousElasticOrthotropic_other.rst - - -.. _DATASTRUCTURE_PorousElasticTransverseIsotropic: - -Datastructure: PorousElasticTransverseIsotropic -=============================================== -.. include:: ../../coreComponents/schema/docs/PorousElasticTransverseIsotropic_other.rst - - -.. _DATASTRUCTURE_PorousExtendedDruckerPrager: - -Datastructure: PorousExtendedDruckerPrager -========================================== -.. include:: ../../coreComponents/schema/docs/PorousExtendedDruckerPrager_other.rst - - -.. _DATASTRUCTURE_PorousModifiedCamClay: - -Datastructure: PorousModifiedCamClay -==================================== -.. include:: ../../coreComponents/schema/docs/PorousModifiedCamClay_other.rst - - -.. _DATASTRUCTURE_PorousViscoDruckerPrager: - -Datastructure: PorousViscoDruckerPrager -======================================= -.. include:: ../../coreComponents/schema/docs/PorousViscoDruckerPrager_other.rst - - -.. _DATASTRUCTURE_PorousViscoExtendedDruckerPrager: - -Datastructure: PorousViscoExtendedDruckerPrager -=============================================== -.. include:: ../../coreComponents/schema/docs/PorousViscoExtendedDruckerPrager_other.rst - - -.. _DATASTRUCTURE_PorousViscoModifiedCamClay: - -Datastructure: PorousViscoModifiedCamClay -========================================= -.. include:: ../../coreComponents/schema/docs/PorousViscoModifiedCamClay_other.rst - - -.. _DATASTRUCTURE_PressurePorosity: - -Datastructure: PressurePorosity -=============================== -.. include:: ../../coreComponents/schema/docs/PressurePorosity_other.rst - - -.. _DATASTRUCTURE_Problem: - -Datastructure: Problem -====================== -.. include:: ../../coreComponents/schema/docs/Problem_other.rst - - -.. _DATASTRUCTURE_ProppantPermeability: - -Datastructure: ProppantPermeability -=================================== -.. include:: ../../coreComponents/schema/docs/ProppantPermeability_other.rst - - -.. _DATASTRUCTURE_ProppantPorosity: - -Datastructure: ProppantPorosity -=============================== -.. include:: ../../coreComponents/schema/docs/ProppantPorosity_other.rst - - -.. _DATASTRUCTURE_ProppantSlurryFluid: - -Datastructure: ProppantSlurryFluid -================================== -.. include:: ../../coreComponents/schema/docs/ProppantSlurryFluid_other.rst - - -.. _DATASTRUCTURE_ProppantSolidProppantPermeability: - -Datastructure: ProppantSolidProppantPermeability -================================================ -.. include:: ../../coreComponents/schema/docs/ProppantSolidProppantPermeability_other.rst - - -.. _DATASTRUCTURE_ProppantTransport: - -Datastructure: ProppantTransport -================================ -.. include:: ../../coreComponents/schema/docs/ProppantTransport_other.rst - - -.. _DATASTRUCTURE_Python: - -Datastructure: Python -===================== -.. include:: ../../coreComponents/schema/docs/Python_other.rst - - -.. _DATASTRUCTURE_ReactiveBrine: - -Datastructure: ReactiveBrine -============================ -.. include:: ../../coreComponents/schema/docs/ReactiveBrine_other.rst - - -.. _DATASTRUCTURE_ReactiveBrineThermal: - -Datastructure: ReactiveBrineThermal -=================================== -.. include:: ../../coreComponents/schema/docs/ReactiveBrineThermal_other.rst - - -.. _DATASTRUCTURE_ReactiveCompositionalMultiphaseOBL: - -Datastructure: ReactiveCompositionalMultiphaseOBL -================================================= -.. include:: ../../coreComponents/schema/docs/ReactiveCompositionalMultiphaseOBL_other.rst - - -.. _DATASTRUCTURE_ReactiveFluidDriver: - -Datastructure: ReactiveFluidDriver -================================== -.. include:: ../../coreComponents/schema/docs/ReactiveFluidDriver_other.rst - - -.. _DATASTRUCTURE_Rectangle: - -Datastructure: Rectangle -======================== -.. include:: ../../coreComponents/schema/docs/Rectangle_other.rst - - -.. _DATASTRUCTURE_RelpermDriver: - -Datastructure: RelpermDriver -============================ -.. include:: ../../coreComponents/schema/docs/RelpermDriver_other.rst - - -.. _DATASTRUCTURE_Restart: - -Datastructure: Restart -====================== -.. include:: ../../coreComponents/schema/docs/Restart_other.rst - - -.. _DATASTRUCTURE_Run: - -Datastructure: Run -================== -.. include:: ../../coreComponents/schema/docs/Run_other.rst - - -.. _DATASTRUCTURE_Silo: - -Datastructure: Silo -=================== -.. include:: ../../coreComponents/schema/docs/Silo_other.rst - - -.. _DATASTRUCTURE_SinglePhaseConstantThermalConductivity: - -Datastructure: SinglePhaseConstantThermalConductivity -===================================================== -.. include:: ../../coreComponents/schema/docs/SinglePhaseConstantThermalConductivity_other.rst - - -.. _DATASTRUCTURE_SinglePhaseFVM: - -Datastructure: SinglePhaseFVM -============================= -.. include:: ../../coreComponents/schema/docs/SinglePhaseFVM_other.rst - - -.. _DATASTRUCTURE_SinglePhaseHybridFVM: - -Datastructure: SinglePhaseHybridFVM -=================================== -.. include:: ../../coreComponents/schema/docs/SinglePhaseHybridFVM_other.rst - - -.. _DATASTRUCTURE_SinglePhasePoromechanics: - -Datastructure: SinglePhasePoromechanics -======================================= -.. include:: ../../coreComponents/schema/docs/SinglePhasePoromechanics_other.rst - - -.. _DATASTRUCTURE_SinglePhasePoromechanicsConformingFractures: - -Datastructure: SinglePhasePoromechanicsConformingFractures -========================================================== -.. include:: ../../coreComponents/schema/docs/SinglePhasePoromechanicsConformingFractures_other.rst - - -.. _DATASTRUCTURE_SinglePhasePoromechanicsEmbeddedFractures: - -Datastructure: SinglePhasePoromechanicsEmbeddedFractures -======================================================== -.. include:: ../../coreComponents/schema/docs/SinglePhasePoromechanicsEmbeddedFractures_other.rst - - -.. _DATASTRUCTURE_SinglePhasePoromechanicsInitialization: - -Datastructure: SinglePhasePoromechanicsInitialization -===================================================== -.. include:: ../../coreComponents/schema/docs/SinglePhasePoromechanicsInitialization_other.rst - - -.. _DATASTRUCTURE_SinglePhasePoromechanicsReservoir: - -Datastructure: SinglePhasePoromechanicsReservoir -================================================ -.. include:: ../../coreComponents/schema/docs/SinglePhasePoromechanicsReservoir_other.rst - - -.. _DATASTRUCTURE_SinglePhaseProppantFVM: - -Datastructure: SinglePhaseProppantFVM -===================================== -.. include:: ../../coreComponents/schema/docs/SinglePhaseProppantFVM_other.rst - - -.. _DATASTRUCTURE_SinglePhaseReservoir: - -Datastructure: SinglePhaseReservoir -=================================== -.. include:: ../../coreComponents/schema/docs/SinglePhaseReservoir_other.rst - - -.. _DATASTRUCTURE_SinglePhaseReservoirPoromechanics: - -Datastructure: SinglePhaseReservoirPoromechanics -================================================ -.. include:: ../../coreComponents/schema/docs/SinglePhaseReservoirPoromechanics_other.rst - - -.. _DATASTRUCTURE_SinglePhaseReservoirPoromechanicsInitialization: - -Datastructure: SinglePhaseReservoirPoromechanicsInitialization -============================================================== -.. include:: ../../coreComponents/schema/docs/SinglePhaseReservoirPoromechanicsInitialization_other.rst - - -.. _DATASTRUCTURE_SinglePhaseStatistics: - -Datastructure: SinglePhaseStatistics -==================================== -.. include:: ../../coreComponents/schema/docs/SinglePhaseStatistics_other.rst - - -.. _DATASTRUCTURE_SinglePhaseWell: - -Datastructure: SinglePhaseWell -============================== -.. include:: ../../coreComponents/schema/docs/SinglePhaseWell_other.rst - - -.. _DATASTRUCTURE_SlipDependentPermeability: - -Datastructure: SlipDependentPermeability -======================================== -.. include:: ../../coreComponents/schema/docs/SlipDependentPermeability_other.rst - - -.. _DATASTRUCTURE_SolidInternalEnergy: - -Datastructure: SolidInternalEnergy -================================== -.. include:: ../../coreComponents/schema/docs/SolidInternalEnergy_other.rst - - -.. _DATASTRUCTURE_SolidMechanicsEmbeddedFractures: - -Datastructure: SolidMechanicsEmbeddedFractures -============================================== -.. include:: ../../coreComponents/schema/docs/SolidMechanicsEmbeddedFractures_other.rst - - -.. _DATASTRUCTURE_SolidMechanicsLagrangeContact: - -Datastructure: SolidMechanicsLagrangeContact -============================================ -.. include:: ../../coreComponents/schema/docs/SolidMechanicsLagrangeContact_other.rst - - -.. _DATASTRUCTURE_SolidMechanicsLagrangianSSLE: - -Datastructure: SolidMechanicsLagrangianSSLE -=========================================== -.. include:: ../../coreComponents/schema/docs/SolidMechanicsLagrangianSSLE_other.rst - - -.. _DATASTRUCTURE_SolidMechanicsStateReset: - -Datastructure: SolidMechanicsStateReset -======================================= -.. include:: ../../coreComponents/schema/docs/SolidMechanicsStateReset_other.rst - - -.. _DATASTRUCTURE_SolidMechanicsStatistics: - -Datastructure: SolidMechanicsStatistics -======================================= -.. include:: ../../coreComponents/schema/docs/SolidMechanicsStatistics_other.rst - - -.. _DATASTRUCTURE_SolidMechanics_LagrangianFEM: - -Datastructure: SolidMechanics_LagrangianFEM -=========================================== -.. include:: ../../coreComponents/schema/docs/SolidMechanics_LagrangianFEM_other.rst - - -.. _DATASTRUCTURE_SolidMechanics_MPM: - -Datastructure: SolidMechanics_MPM -================================= -.. include:: ../../coreComponents/schema/docs/SolidMechanics_MPM_other.rst - - -.. _DATASTRUCTURE_SoloEvent: - -Datastructure: SoloEvent -======================== -.. include:: ../../coreComponents/schema/docs/SoloEvent_other.rst - - -.. _DATASTRUCTURE_SolverStatistics: - -Datastructure: SolverStatistics -=============================== -.. include:: ../../coreComponents/schema/docs/SolverStatistics_other.rst - - -.. _DATASTRUCTURE_Solvers: - -Datastructure: Solvers -====================== -.. include:: ../../coreComponents/schema/docs/Solvers_other.rst - - -.. _DATASTRUCTURE_SourceFlux: - -Datastructure: SourceFlux -========================= -.. include:: ../../coreComponents/schema/docs/SourceFlux_other.rst - - -.. _DATASTRUCTURE_SurfaceElementRegion: - -Datastructure: SurfaceElementRegion -=================================== -.. include:: ../../coreComponents/schema/docs/SurfaceElementRegion_other.rst - - -.. _DATASTRUCTURE_SurfaceGenerator: - -Datastructure: SurfaceGenerator -=============================== -.. include:: ../../coreComponents/schema/docs/SurfaceGenerator_other.rst - - -.. _DATASTRUCTURE_SymbolicFunction: - -Datastructure: SymbolicFunction -=============================== -.. include:: ../../coreComponents/schema/docs/SymbolicFunction_other.rst - - -.. _DATASTRUCTURE_TableCapillaryPressure: - -Datastructure: TableCapillaryPressure -===================================== -.. include:: ../../coreComponents/schema/docs/TableCapillaryPressure_other.rst - - -.. _DATASTRUCTURE_TableFunction: - -Datastructure: TableFunction -============================ -.. include:: ../../coreComponents/schema/docs/TableFunction_other.rst - - -.. _DATASTRUCTURE_TableRelativePermeability: - -Datastructure: TableRelativePermeability -======================================== -.. include:: ../../coreComponents/schema/docs/TableRelativePermeability_other.rst - - -.. _DATASTRUCTURE_TableRelativePermeabilityHysteresis: - -Datastructure: TableRelativePermeabilityHysteresis -================================================== -.. include:: ../../coreComponents/schema/docs/TableRelativePermeabilityHysteresis_other.rst - - -.. _DATASTRUCTURE_Tasks: - -Datastructure: Tasks -==================== -.. include:: ../../coreComponents/schema/docs/Tasks_other.rst - - -.. _DATASTRUCTURE_ThermalCompressibleSinglePhaseFluid: - -Datastructure: ThermalCompressibleSinglePhaseFluid -================================================== -.. include:: ../../coreComponents/schema/docs/ThermalCompressibleSinglePhaseFluid_other.rst - - -.. _DATASTRUCTURE_ThickPlane: - -Datastructure: ThickPlane -========================= -.. include:: ../../coreComponents/schema/docs/ThickPlane_other.rst - - -.. _DATASTRUCTURE_TimeHistory: - -Datastructure: TimeHistory -========================== -.. include:: ../../coreComponents/schema/docs/TimeHistory_other.rst - - -.. _DATASTRUCTURE_Traction: - -Datastructure: Traction -======================= -.. include:: ../../coreComponents/schema/docs/Traction_other.rst - - -.. _DATASTRUCTURE_TriaxialDriver: - -Datastructure: TriaxialDriver -============================= -.. include:: ../../coreComponents/schema/docs/TriaxialDriver_other.rst - - -.. _DATASTRUCTURE_TwoPointFluxApproximation: - -Datastructure: TwoPointFluxApproximation -======================================== -.. include:: ../../coreComponents/schema/docs/TwoPointFluxApproximation_other.rst - - -.. _DATASTRUCTURE_VTK: - -Datastructure: VTK -================== -.. include:: ../../coreComponents/schema/docs/VTK_other.rst - - -.. _DATASTRUCTURE_VTKMesh: - -Datastructure: VTKMesh -====================== -.. include:: ../../coreComponents/schema/docs/VTKMesh_other.rst - - -.. _DATASTRUCTURE_VTKWell: - -Datastructure: VTKWell -====================== -.. include:: ../../coreComponents/schema/docs/VTKWell_other.rst - - -.. _DATASTRUCTURE_VanGenuchtenBakerRelativePermeability: - -Datastructure: VanGenuchtenBakerRelativePermeability -==================================================== -.. include:: ../../coreComponents/schema/docs/VanGenuchtenBakerRelativePermeability_other.rst - - -.. _DATASTRUCTURE_VanGenuchtenCapillaryPressure: - -Datastructure: VanGenuchtenCapillaryPressure -============================================ -.. include:: ../../coreComponents/schema/docs/VanGenuchtenCapillaryPressure_other.rst - - -.. _DATASTRUCTURE_VanGenuchtenStone2RelativePermeability: - -Datastructure: VanGenuchtenStone2RelativePermeability -===================================================== -.. include:: ../../coreComponents/schema/docs/VanGenuchtenStone2RelativePermeability_other.rst - - -.. _DATASTRUCTURE_ViscoDruckerPrager: - -Datastructure: ViscoDruckerPrager -================================= -.. include:: ../../coreComponents/schema/docs/ViscoDruckerPrager_other.rst - - -.. _DATASTRUCTURE_ViscoExtendedDruckerPrager: - -Datastructure: ViscoExtendedDruckerPrager -========================================= -.. include:: ../../coreComponents/schema/docs/ViscoExtendedDruckerPrager_other.rst - - -.. _DATASTRUCTURE_ViscoModifiedCamClay: - -Datastructure: ViscoModifiedCamClay -=================================== -.. include:: ../../coreComponents/schema/docs/ViscoModifiedCamClay_other.rst - - -.. _DATASTRUCTURE_WellControls: - -Datastructure: WellControls -=========================== -.. include:: ../../coreComponents/schema/docs/WellControls_other.rst - - -.. _DATASTRUCTURE_WellElementRegion: - -Datastructure: WellElementRegion -================================ -.. include:: ../../coreComponents/schema/docs/WellElementRegion_other.rst - - -.. _DATASTRUCTURE_WellElementRegionUniqueSubRegion: - -Datastructure: WellElementRegionUniqueSubRegion -=============================================== -.. include:: ../../coreComponents/schema/docs/WellElementRegionUniqueSubRegion_other.rst - - -.. _DATASTRUCTURE_WillisRichardsPermeability: - -Datastructure: WillisRichardsPermeability -========================================= -.. include:: ../../coreComponents/schema/docs/WillisRichardsPermeability_other.rst - - -.. _DATASTRUCTURE_commandLine: - -Datastructure: commandLine -========================== -.. include:: ../../coreComponents/schema/docs/commandLine_other.rst - - -.. _DATASTRUCTURE_crusher: - -Datastructure: crusher -====================== -.. include:: ../../coreComponents/schema/docs/crusher_other.rst - - -.. _DATASTRUCTURE_domain: - -Datastructure: domain -===================== -.. include:: ../../coreComponents/schema/docs/domain_other.rst - - -.. _DATASTRUCTURE_edgeManager: - -Datastructure: edgeManager -========================== -.. include:: ../../coreComponents/schema/docs/edgeManager_other.rst - - -.. _DATASTRUCTURE_elementRegionsGroup: - -Datastructure: elementRegionsGroup -================================== -.. include:: ../../coreComponents/schema/docs/elementRegionsGroup_other.rst - - -.. _DATASTRUCTURE_elementSubRegions: - -Datastructure: elementSubRegions -================================ -.. include:: ../../coreComponents/schema/docs/elementSubRegions_other.rst - - -.. _DATASTRUCTURE_embeddedSurfacesEdgeManager: - -Datastructure: embeddedSurfacesEdgeManager -========================================== -.. include:: ../../coreComponents/schema/docs/embeddedSurfacesEdgeManager_other.rst - - -.. _DATASTRUCTURE_embeddedSurfacesNodeManager: - -Datastructure: embeddedSurfacesNodeManager -========================================== -.. include:: ../../coreComponents/schema/docs/embeddedSurfacesNodeManager_other.rst - - -.. _DATASTRUCTURE_faceManager: - -Datastructure: faceManager -========================== -.. include:: ../../coreComponents/schema/docs/faceManager_other.rst - - -.. _DATASTRUCTURE_lassen: - -Datastructure: lassen -===================== -.. include:: ../../coreComponents/schema/docs/lassen_other.rst - - -.. _DATASTRUCTURE_meshLevels: - -Datastructure: meshLevels -========================= -.. include:: ../../coreComponents/schema/docs/meshLevels_other.rst - - -.. _DATASTRUCTURE_neighborData: - -Datastructure: neighborData -=========================== -.. include:: ../../coreComponents/schema/docs/neighborData_other.rst - - -.. _DATASTRUCTURE_nodeManager: - -Datastructure: nodeManager -========================== -.. include:: ../../coreComponents/schema/docs/nodeManager_other.rst - - -.. _DATASTRUCTURE_particleRegionsGroup: - -Datastructure: particleRegionsGroup -=================================== -.. include:: ../../coreComponents/schema/docs/particleRegionsGroup_other.rst - - -.. _DATASTRUCTURE_particleSubRegions: - -Datastructure: particleSubRegions -================================= -.. include:: ../../coreComponents/schema/docs/particleSubRegions_other.rst - - -.. _DATASTRUCTURE_quartz: - -Datastructure: quartz -===================== -.. include:: ../../coreComponents/schema/docs/quartz_other.rst - - -.. _DATASTRUCTURE_sets: - -Datastructure: sets -=================== -.. include:: ../../coreComponents/schema/docs/sets_other.rst - - -.. _DATASTRUCTURE_wellElementSubRegion: - -Datastructure: wellElementSubRegion -=================================== -.. include:: ../../coreComponents/schema/docs/wellElementSubRegion_other.rst - diff --git a/src/docs/sphinx/Doxygen.rst b/src/docs/sphinx/Doxygen.rst index 6e541b988e0..bd23a682dab 100644 --- a/src/docs/sphinx/Doxygen.rst +++ b/src/docs/sphinx/Doxygen.rst @@ -2,11 +2,17 @@ Doxygen ############################################################################### -The c++ source in GEOS is annotated using doxygen. Our doxygen pages are -linked below. +The GEOS c++ API in is documented using doxygen. +The doxygen `class list pages <../../doxygen_output/html/classes.html>`_ -.. raw:: html +Developers may find it helpful to review the :ref:`KeyComponents` described in the Developer Guide before diving into the doxygen. - GEOS Doxygen Pages +Some key doxygen pages are linked below: -Developers may find it helpful to review the key code components described in the Developer Guide before diving into the doxygen. +`Group API <../../doxygen_output/html/classgeos_1_1data_repository_1_1_group.html>`_ + +`Wrapper API <../../doxygen_output/html/classgeos_1_1data_repository_1_1_wrapper.html>`_ + +`ObjectManagerBase API <../../doxygen_output/html/classgeos_1_1_object_manager_base.html>`_ + +`PhysicsSolverBase API <../../doxygen_output/html/classgeos_1_1_physics_solver_base.html>`_ \ No newline at end of file diff --git a/src/docs/sphinx/Publications.rst b/src/docs/sphinx/Publications.rst index d550927c21b..57df228cddb 100644 --- a/src/docs/sphinx/Publications.rst +++ b/src/docs/sphinx/Publications.rst @@ -2,18 +2,75 @@ Publications ############################################################################### -Last updated 5-September-2023 +Last updated 26-August-2024 Preprints and Early-Views ========================= +2024 +==== + +.. list-table:: + :widths: 100 + :header-rows: 0 + + * - | **A benchmark study on reactive two-phase flow in porous media: Part II - results and discussion** + | E Ahusborde, B Amaziane, S de Hoop, M El Ossmani, E Flauraud, FP Hamon, M Kern, A Socié, D Su, KU Mayer, M Tóth, D Voskov + | Computational Geosciences + | `doi.org/10.1007/s10596-024-10269-y `_ + + * - | **Pressure-stabilized fixed-stress iterative solutions of compositional poromechanics** + | RM Aronson, N Castelletto, FP Hamon, JA White, HA Tchelepi + | Computer Methods in Applied Mechanics and Engineering + | `doi:10.1016/j.cma.2024.117008 `_ + + * - | **Managing reservoir dynamics when converting natural gas fields to underground hydrogen storage** + | JT Camargo, JA White, FP Hamon, V Fakeye, TA Buscheck, N Huerta + | International Journal of Hydrogen Energy + | `doi.org/10.1016/j.ijhydene.2023.09.165 `_ + + * - | **Constrained pressure-temperature residual (CPTR) preconditioner performance for large-scale thermal CO2 injection simulation** + | MA Cremon, J Franc, FP Hamon + | Computational Geosciences + | `doi.org/10.1007/s10596-024-10292-z `_ + + * - | **Surrogate model for geological CO2 storage and its use in hierarchical MCMC history matching** + | Y Han, FP Hamon, S Jiang, LJ Durlofsky + | Advances in Water Resources + | `doi:10.1016/j.advwatres.2024.104678 `_ + + * - | **Simulation of Multiphase Flow and Poromechanical Effects Around Injection Wells in CO2 Storage Sites** + | J Huang, F Hamon, M Cusini, T Gazzola, RR Settgast, JA White, H Gross + | Rock Mechanics and Rock Engineering + | `doi:10.1007/s00603-024-04051-w `_ + + * - | **Multilevel well modeling in aggregation-based nonlinear multigrid for multiphase flow in porous media** + | CS Lee, FP Hamon, N Castelletto, PS Vassilevski, JA White + | Journal of Computational Physics + | `doi:10.1016/j.jcp.2024.113163 `_ + + * - | **Theory and analytical solutions to wellbore problems with hardening/softening Drucker-Prager models** + | T Nguyen-Sy, J Huang, H Gross + | International Journal of Rock Mechanics and Mining Sciences + | `doi:10.1016/j.ijrmms.2024.105878 `_ + 2023 ==== -* - | **A phase-field model for hydraulic fracture nucleation and propagation in porous media** - | F Fei, A Costa, JE Dolbow, R Settgast, M Cusini - | International Journal for Numerical and Analytical Methods in Geomechanics - | `doi.org/10.1002/nag.3612 `_ +.. list-table:: + :widths: 100 + :header-rows: 0 + + * - | **A phase-field model for hydraulic fracture nucleation and propagation in porous media** + | F Fei, A Costa, JE Dolbow, R Settgast, M Cusini + | International Journal for Numerical and Analytical Methods in Geomechanics + | `doi.org/10.1002/nag.3612 `_ + + * - | **Validation and Application of a Three-Dimensional Model for Simulating Proppant Transport and Fracture Conductivity** + | J Huang, Y Hao, RR Settgast, JA White, K Mateen, H Gross + | Rock Mechanics and Rock Engineering + | `doi:10.1007/s00603-022-03092-3 `_ + 2022 ==== @@ -52,13 +109,8 @@ Preprints and Early-Views | Computers & Mathematics with Applications | `doi:10.1016/j.camwa.2021.11.015 `_ - * - | **Validation and Application of a Three-Dimensional Model for Simulating Proppant Transport and Fracture Conductivity** - | J Huang, Y Hao, RR Settgast, JA White, K Mateen, H Gross - | Rock Mechanics and Rock Engineering - | `doi:10.1007/s00603-022-03092-3 `_ - * - | **An aggregation-based nonlinear multigrid solver for two-phase flow and transport in porous media** - | CS Lee, F Hamon, N Castelletto, PS Vassilevski, JA White + | CS Lee, FP Hamon, N Castelletto, PS Vassilevski, JA White | Computers & Mathematics with Applications | `doi:10.1016/j.camwa.2022.03.026 `_ diff --git a/src/docs/sphinx/QuickStart.rst b/src/docs/sphinx/QuickStart.rst index 111918a8aa8..71a74716fad 100644 --- a/src/docs/sphinx/QuickStart.rst +++ b/src/docs/sphinx/QuickStart.rst @@ -164,8 +164,6 @@ First, using a terminal, create the ``codes`` directory wherever you like. Inside this directory, we can clone the GEOS repository. We will also use some Git commands to initialize and download the submodules (e.g. ``LvArray``). -Note that most users will not have access to our integrated tests repository, and so we "deinit" (deactivate) this submodule. -Developers who will be working with the integratedTests repository should skip this line. .. code-block:: sh @@ -173,7 +171,6 @@ Developers who will be working with the integratedTests repository should skip t cd GEOS git lfs install git submodule init - git submodule deinit integratedTests git submodule update cd .. @@ -181,10 +178,10 @@ If all goes well, you should have a complete copy of the GEOS source at this poi The most common errors people encounter here have to do with Github not recognizing their authentication settings and/or repository permissions. See the previous section for tips on ensuring your SSH is working properly. -*Note*: The integratedTests submodule is not publicly available, with access limited to the core development team. -This may cause the ``git submodule update`` command to fail -if you forget the ``git submodule deinit integratedTests`` step above. -This submodule is not required for building GEOS. If you see an error message here, however, you may need to initialize and update the submodules manually: +*Note*: Previous versions of GEOS also imported the integratedTests submodule, which is not publicly available (access is limited to the core development team). +This may cause the ``git submodule update`` command to fail. +In that case, run ``git submodule deinit integratedTests`` before ``git submodule update``. +This submodule is not required for building GEOS. .. code-block:: sh @@ -218,11 +215,10 @@ If you are using an older version, you may need to add ``git lfs pull`` after `` The clone ``https://github.com/GEOS-DEV/GEOS.git`` becomes ``git clone git@github.com:GEOS-DEV/GEOS.git``. You may also be willing to insert your credentials in the command line (less secure) ``git clone https://${USER}:${TOKEN}@github.com/GEOS-DEV/GEOS.git``. -Configuration -================ +Configuration +============= -At a minimum, you will need a relatively recent compiler suite installed on your system (e.g. `GCC `_, `Clang `_) as well as `CMake `_. -If you want to run jobs using MPI-based parallelism, you will also need an MPI implementation (e.g. `OpenMPI `_, `MVAPICH `_). +Before proceeding, make sure to have installed all the minimal prerequisites as described in :ref:`Prerequisites` Note that GEOS supports a variety of parallel computing models, depending on the hardware and software environment. Advanced users are referred to the :ref:`BuildGuide` for a discussion of the available configuration options. @@ -237,120 +233,109 @@ If something goes wrong, the first thing the support team will ask you for is th Here, you may need to replace ``cpp`` with the full path to the C++ compiler you would like to use, depending on how your path and any aliases are configured. -GEOS compilations are driven by a cmake ``host-config`` file, which tells the build system about the compilers you are using, where various packages reside, and what options you want to enable. -We have created a number of default hostconfig files for common systems. -You should browse them to see if any are close to your needs: +Defining a Host-Config File +--------------------------- -.. code-block:: sh +GEOS compilations are driven by a CMake ``host-config`` file, which informs the build system about the compilers you are using, where various packages reside, and what options you want to enable. - cd GEOS/host-configs +A template for creating a simple ``host-config`` is provided in ``host-configs/quick-start-template.cmake``. -We maintain host configs (ending in ``.cmake``) for HPC systems at various institutions, as well as ones for common personal systems. -If you cannot find one that matches your needs, we suggest beginning with one of the shorter ones and modifying as needed. -A typical one may look like: +.. literalinclude:: ../../../host-configs/quick-start-template.cmake + :language: sh -.. code-block:: sh +The various ``set()`` commands are used to set variables that control the build. To begin, make a copy of the template file and modify the paths according to the installation locations on your system. - # file: your-platform.cmake - - # detect host and name the configuration file - site_name(HOST_NAME) - set(CONFIG_NAME "your-platform" CACHE PATH "") - message("CONFIG_NAME = ${CONFIG_NAME}") - - # set paths to C, C++, and Fortran compilers. Note that while GEOS does not contain any Fortran code, - # some of the third-party libraries do contain Fortran code. Thus a Fortran compiler must be specified. - set(CMAKE_C_COMPILER "/usr/bin/clang" CACHE PATH "") - set(CMAKE_CXX_COMPILER "/usr/bin/clang++" CACHE PATH "") - set(CMAKE_Fortran_COMPILER "/usr/local/bin/gfortran" CACHE PATH "") - set(ENABLE_FORTRAN OFF CACHE BOOL "" FORCE) - - # enable MPI and set paths to compilers and executable. - # Note that the MPI compilers are wrappers around standard serial compilers. - # Therefore, the MPI compilers must wrap the appropriate serial compilers specified - # in CMAKE_C_COMPILER, CMAKE_CXX_COMPILER, and CMAKE_Fortran_COMPILER. - set(ENABLE_MPI ON CACHE BOOL "") - set(MPI_C_COMPILER "/usr/local/bin/mpicc" CACHE PATH "") - set(MPI_CXX_COMPILER "/usr/local/bin/mpicxx" CACHE PATH "") - set(MPI_Fortran_COMPILER "/usr/local/bin/mpifort" CACHE PATH "") - set(MPIEXEC "/usr/local/bin/mpirun" CACHE PATH "") - - # disable CUDA and OpenMP - set(ENABLE_CUDA OFF CACHE BOOL "" FORCE) - set(ENABLE_OPENMP OFF CACHE BOOL "" FORCE) - - # enable PVTPackage - set(ENABLE_PVTPackage ON CACHE BOOL "" FORCE) - - # enable tests - set(ENABLE_GTEST_DEATH_TESTS ON CACHE BOOL "" FORCE ) - - # define the path to your compiled installation directory - set(GEOSX_TPL_DIR "/path/to/your/TPL/installation/dir" CACHE PATH "") - # let GEOS define some third party libraries information for you - include(${CMAKE_CURRENT_LIST_DIR}/tpls.cmake) - -The various ``set()`` commands are used to set environment variables that control the build. -You will see in the above example that we set the C++ compiler to ``/user/bin/clang++`` and so forth. -We also disable CUDA and OpenMP, but enable PVTPackage. -The final line is related to our unit test suite. See the :ref:`BuildGuide` for more details on available options. +We have created a number of default host-config files for common systems. You should browse them to see if any are close to your needs: +We maintain host configuration files (ending in ``.cmake``) for HPC systems at various institutions, as well as for common personal systems. +If you cannot find one that matches your needs, we suggest starting with one of the shorter ones and modifying it as needed. .. note:: If you develop a new ``host-config`` for a particular platform that may be useful for other users, please consider sharing it with the developer team. Compilation -================== +=========== + +The configuration process for both the third-party libraries (TPLs) and GEOS is managed through a Python script called ``config-build.py``. This script simplifies and automates the setup by configuring the build and install directories and by running CMake based on the options set in the host-config file +which is passed as a command-lne argument. The ``config-build.py`` script has several command-line options. Here, we will only use some basic options and rely on default values for many others. During this build process there wil be automatically generated build and install directories for both the TPLs and the main code, +with names consistent with the name specified in the host-config by the variable ``CONFIG_NAME``, i.e. ``build-your-platform-release`` and ``install-your-platform-release``. + +All options can be visualized by running + +.. code-block:: sh -We will begin by compiling the TPLs, followed by the main code. -If you work on an HPC system with other GEOS developers, check with them to see if the TPLs have already been compiled in a shared directory. -If this is the case, you can skip ahead to just compiling the main code. -If you are working on your own machine, you will need to compile both. + cd thirdPartyLibs + python scripts/config-build.py -h -We strongly suggest that GEOS and TPLs be built with the same hostconfig file. -Below, we assume that you keep it in, say, ``GEOS/host-configs/your-platform.cmake``, but this is up to you. +.. note:: -We begin with the third-party libraries, and use a python ``config-build.py`` script to configure and build all of the TPLs. -Note that we will request a Release build type, which will enable various optimizations. -The other option is a Debug build, which allows for debugging but will be much slower in production mode. -The TPLS will then be built in a build directory named consistently with your hostconfig file. + It is strongly recommended that GEOS and TPLs be configured using the same host configuration file. Below, we assume that you keep this file in, for example, ``GEOS/host-configs/your-platform.cmake``, but the exact location is up to you. + +Compiling the TPLs +------------------- + +.. note:: + + If you are working on an HPC system with other GEOS developers, check with them to see if the TPLs have already been compiled in a shared directory. If this is the case, you can skip ahead to just compiling the main code. + If you are working on your own machine, you will need to configure and compile both the TPLs and the main code. + +We begin by configuring the third-party libraries (TPLs) using the ``config-build.py`` script. This script sets up the build directory and runs CMake to generate the necessary build files. .. code-block:: sh cd thirdPartyLibs python scripts/config-build.py -hc ../GEOS/host-configs/your-platform.cmake -bt Release + +The TPLs will be configured in a build directory named consistently with your host configuration file, i.e., ``build-your-platform-release``. + +.. code-block:: sh + cd build-your-platform-release make -Note that building all of the TPLs can take quite a while, so you may want to go get a cup of coffee at this point. -Also note that you should *not* use a parallel ``make -j N`` command to try and speed up the build time. +.. note:: + + Building all of the TPLs can take quite a while, so you may want to go get a cup of coffee at this point. + Also note that you should *not* use a parallel ``make -j N`` command to try and speed up the build time. -The next step is to compile the main code. -Again, the ``config-build.py`` sets up cmake for you, so the process is very similar. +Compiling GEOS +------------------- + +Once the TPLs have been compiler, the next step is to compile the main code. The ``config-build.py`` script is used to configure the build directory. Before running the configuration script, ensure that the path to the TPLs is correctly set in the host configuration file by setting + +.. code-block:: sh + + set(GEOS_TPL_DIR "/path/to/your/TPL/installation/dir" CACHE PATH "") + +If you have followed these instructions, the TPLs are installed at the default location, i.e. ``/path/to/your/TPL/thirdPartyLibs/install-your-platform-release``. .. code-block:: sh cd ../../GEOS python scripts/config-build.py -hc host-configs/your-platform.cmake -bt Release - cd build-your-platform-release - make -j4 - make install -The host-config file is the place to set all relevant configuration options. -Note that the path to the previously installed third party libraries is typically specified within this file. -An alternative is to set the path ``GEOSX_TPL_DIR`` via a cmake command line option, e.g. +An alternative is to set the path ``GEOS_TPL_DIR`` via a cmake command line option, e.g. + +.. code-block:: sh + + python scripts/config-build.py -hc host-configs/your-platform.cmake -bt Release -D GEOS_TPL_DIR=/full/path/to/thirdPartyLibs + +.. note:: + + We highly recommend using full paths, rather than relative paths, whenever possible. + +Once the configuration process is completed, we proceed with the compilation of the main code and the instalation of geos. .. code-block:: sh - python scripts/config-build.py -hc host-configs/your-platform.cmake -bt Release -D GEOSX_TPL_DIR=/full/path/to/thirdPartyLibs + cd build-your-platform-release + make -j4 + make install -We highly recommend using full paths, rather than relative paths, whenever possible. The parallel ``make -j 4`` will use four processes for compilation, which can substantially speed up the build if you have a multi-processor machine. You can adjust this value to match the number of processors available on your machine. The ``make install`` command then installs GEOS to a default location unless otherwise specified. - - -If all goes well, a ``geosx`` executable should now be available: +If all goes well, a ``geosx`` executable should now be available .. code-block:: sh diff --git a/src/docs/sphinx/advancedExamples/performanceBenchmarks/Index.rst b/src/docs/sphinx/advancedExamples/performanceBenchmarks/Index.rst index ed9671bbc64..8d75689daf8 100644 --- a/src/docs/sphinx/advancedExamples/performanceBenchmarks/Index.rst +++ b/src/docs/sphinx/advancedExamples/performanceBenchmarks/Index.rst @@ -4,4 +4,156 @@ Performance Benchmarks ######################## +==================================== +Wellbore problem scaling on Frontier +==================================== +.. _wellboreProblemScaling: +The wellbore problem described here was used to test the weak scaling of GEOS on the +`Frontier supercomputer ` at Oak Ridge National +Laboratory. The hardware details of the Frontier system are described in the `Frontier +User Guide `_. + +The wellbore problem consists of a single wellbore with an internal radius of 0.057m, a +casing thickness of 0.006m, with varying length and number elements depending level in the +scaling study. There are 6 levels of scaling summarized in the table below. The number of +ranks used for each level is dependent on the physics solver applied, as the number of +degrees of freedom in the problem changes. + ++-------+------+------+-------+----------------+ +| Level | nr | nt | nz | nelem | ++=======+======+======+=======+================+ +| 1 | 33 | 64 | 391 | 825,792 | ++-------+------+------+-------+----------------+ +| 2 | 33 | 64 | 3125 | 6,600,000 | ++-------+------+------+-------+----------------+ +| 3 | 66 | 128 | 6250 | 52,800,000 | ++-------+------+------+-------+----------------+ +| 4 | 132 | 256 | 12500 | 422,400,000 | ++-------+------+------+-------+----------------+ +| 5 | 264 | 512 | 25000 | 3,379,200,000 | ++-------+------+------+-------+----------------+ +| 6 | 528 | 1024 | 50000 | 27,033,600,000 | ++-------+------+------+-------+----------------+ + +An image of the wellbore geometry is give below: + +.. .. figure:: /coreComponents/physics/docs/Wellbore.png +.. :align: center +.. :width: 500 +.. :figclass: align-center + + +The scaling results for the wellbore problem applied to different physics models on the +Frontier supercomputer are shown below: + +Mechanics +--------- + +.. figure:: weakscal_frontier_mechanics.png + :align: center + :width: 500 + :figclass: align-center + + Weak scaling results for the mechanics model on Frontier. + +Single Phase Flow +----------------- + +.. figure:: weakscal_frontier_singlePhaseFlow.png + :align: center + :width: 500 + :figclass: align-center + + Weak scaling results for the single phase flow model on Frontier. + +Compositional Multiphase Flow +----------------------------- + +.. figure:: weakscal_frontier_compositionalMultiphaseFlow.png + :align: center + :width: 500 + :figclass: align-center + + Weak scaling results for the compositional multiphase flow model on Frontier. + +.. _wellboreRunning: + +Running the Performance Study +----------------------------- + +To execute a performance study across different GPU configurations and problem levels for +the wellbore problem on the Frontier supercomputer, follow these steps: + +Prerequisites +~~~~~~~~~~~~~ +Ensure you have access to the Frontier system and that you have access to a valid job +allocation account. For detailed instructions on system access and environment setup, +refer to the `Frontier User Guide +`_. + +Directory Structure +~~~~~~~~~~~~~~~~~~~ +The input files for different problem levels and configurations are organized under +``${GEOS_DIR}/inputFiles/wellboreECP/``. Each physical problem (e.g., +``mechanics``, ``compositionalMultiphaseFlow``, ``singlePhaseFlow``) has its own directory +containing multiple levels of problem refinement as described in the table above. + +Dispatching Jobs +~~~~~~~~~~~~~~~~ +Use the ``dispatch.py`` script to automate the setup and submission of jobs for different +levels of problem refinement and physics models. + +**Usage:** + +.. code-block:: bash + + python3 dispatch.py --acount [account_id] --binary [path_to_binary] --model [model_type] --levels + [specific_levels_to_run] --caliper [def] + +- **--account**: Account name for running jobs on compute nodes. +- **--binary**: Path to the geos executable. +- **--model**: Physics model type, such as ``mechanics``, ``singlePhaseFlow`` or ``compositionalMultiphaseFlow``. +- **--levels**: (optional) Specific levels to run, e.g., ``1 3 5``. If omitted, all levels + are run. +- **--caliper**: (optional) Turn on profiling with `caliper `_. + +**Example:** + +.. code-block:: bash + + python3 dispatch.py --binary /path/to/geos --model mechanics --levels 1 2 3 + +This command launches jobs for levels 1, 2, and 3 under the mechanics problem configuration. + +Analyzing Output +~~~~~~~~~~~~~~~~ +After job completion, utilize the ``postprocess.py`` script to extract and plot performance metrics from the output files. + +**Usage:** + +.. code-block:: bash + + python3 postprocess.py --model [model_type] --levels [specific_levels_to_plot] + +- **--model**: Physics model type, such as ``mechanics``, ``singlePhaseFlow`` or ``compositionalMultiphaseFlow``. +- **--levels**: (optional) Specific levels to plot, e.g., ``2 3 4 5``. If omitted, results + for all available levels are plotted. + +**Example:** + +.. code-block:: bash + + python3 postprocess.py --model mechanics --levels 2 3 4 5 + +This command parses the latest output files in the mechanics directory, selected by the +highest ``[jobID]``. It matches files with the pattern +``[machine_name]-[jobID]-[model_type]-geom[level].out``, extracting average +execution times per non-linear step for the following phases: GEOS, matrix creation, Hypre +setup, and Hypre solve. + +Note +~~~~ +The job scripts designed for Frontier are likely compatible with other Slurm-based +systems, making them reusable across different high-performance computing environments +with minimal adjustments. diff --git a/src/docs/sphinx/advancedExamples/performanceBenchmarks/weakscal_frontier_compositionalMultiphaseFlow.png b/src/docs/sphinx/advancedExamples/performanceBenchmarks/weakscal_frontier_compositionalMultiphaseFlow.png new file mode 100644 index 00000000000..ae2442bcf5c Binary files /dev/null and b/src/docs/sphinx/advancedExamples/performanceBenchmarks/weakscal_frontier_compositionalMultiphaseFlow.png differ diff --git a/src/docs/sphinx/advancedExamples/performanceBenchmarks/weakscal_frontier_mechanics.png b/src/docs/sphinx/advancedExamples/performanceBenchmarks/weakscal_frontier_mechanics.png new file mode 100644 index 00000000000..b797b43a440 Binary files /dev/null and b/src/docs/sphinx/advancedExamples/performanceBenchmarks/weakscal_frontier_mechanics.png differ diff --git a/src/docs/sphinx/advancedExamples/performanceBenchmarks/weakscal_frontier_singlePhaseFlow.png b/src/docs/sphinx/advancedExamples/performanceBenchmarks/weakscal_frontier_singlePhaseFlow.png new file mode 100644 index 00000000000..7944cbba173 Binary files /dev/null and b/src/docs/sphinx/advancedExamples/performanceBenchmarks/weakscal_frontier_singlePhaseFlow.png differ diff --git a/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/buckleyLeverett/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/buckleyLeverett/Example.rst index 0259759d569..9aedba305d5 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/buckleyLeverett/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/buckleyLeverett/Example.rst @@ -154,9 +154,9 @@ Either the entire field or specified named sets of indices in the field can be c In this example, ``phaseVolumeFractionCollection`` is specified to output the time history of phase saturations ``fieldName="phaseVolumeFraction"`` across the computational domain. .. literalinclude:: ../../../../../../../inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverett_base.xml - :language: xml - :start-after: - :end-before: + :language: xml + :start-after: + :end-before: This task is triggered using the ``Event`` manager with a ``PeriodicEvent`` defined for the recurring tasks. GEOS writes one file named after the string defined in the ``filename`` keyword, formatted as a HDF5 file (saturationHistory.hdf5). The TimeHistory file contains the collected time history information from the specified time history collector. diff --git a/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/buckleyLeverett/buckleyLeverettFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/buckleyLeverett/buckleyLeverettFigure.py index 507ffc44cb3..f4faa2eaeae 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/buckleyLeverett/buckleyLeverettFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/buckleyLeverett/buckleyLeverettFigure.py @@ -3,6 +3,8 @@ import xml.etree.ElementTree as ElementTree import numpy as np import h5py +import os +import argparse def getMaxTime(xmlFilePath): @@ -118,12 +120,25 @@ def computeFractionalFlow( phaseVolFrac, \ def main(): + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + + # File paths - hdf5FilePath = "saturationHistory.hdf5" - pvdgFilePath = "../../../../../../../inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverett_table/pvdg.txt" - pvtwFilePath = "../../../../../../../inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverett_table/pvtw.txt" - xmlFile1Path = "../../../../../../../inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverett_base.xml" - xmlFile2Path = "../../../../../../../inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverett_benchmark.xml" + outputDir = args.outputDir + geosDir = args.geosDir + hdf5FilePath = outputDir + "/saturationHistory.hdf5" + pvdgFilePath = geosDir + "/inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverett_table/pvdg.txt" + pvtwFilePath = geosDir + "/inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverett_table/pvtw.txt" + xmlFile1Path = geosDir + "/inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverett_base.xml" + xmlFile2Path = geosDir + "/inputFiles/compositionalMultiphaseFlow/benchmarks/buckleyLeverettProblem/buckleyLeverett_benchmark.xml" # Read simulation parameters from XML file xMin, xMax, yMin, yMax, zMin, zMax = getDomainMaxMinCoords(xmlFile2Path) @@ -138,11 +153,11 @@ def main(): # Read simulation output from HDF5 file hf = h5py.File(hdf5FilePath, 'r') time = hf.get('phaseVolumeFraction Time') - time = np.array(time) + time = np.asarray(time) center = hf.get('phaseVolumeFraction elementCenter') - center = np.array(center) + center = np.asarray(center) phaseVolFracFromGEOSX = hf.get('phaseVolumeFraction') - phaseVolFracFromGEOSX = np.array(phaseVolFracFromGEOSX) + phaseVolFracFromGEOSX = np.asarray(phaseVolFracFromGEOSX) n = 100000 # sampling value, will decide the accuracy of front detection in the BL analytical solution minDiff = 1e99 diff --git a/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/isothermalLeakyWell/isothermalLeakyWellFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/isothermalLeakyWell/isothermalLeakyWellFigure.py index fc67ae8b080..a116c42d825 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/isothermalLeakyWell/isothermalLeakyWellFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/isothermalLeakyWell/isothermalLeakyWellFigure.py @@ -14,9 +14,10 @@ def main(): # Read HDF5 hf = h5py.File(hdf5FilePath, 'r') time = hf.get('phaseOutflux Time') - time = np.array(time) phaseOutflux = hf.get('phaseOutflux') - phaseOutflux = np.array(phaseOutflux) + + time = np.asarray(time) + phaseOutflux = np.asarray(phaseOutflux) # Conversions inKilograms = 479.0 diff --git a/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/thermalLeakyWell/thermalLeakyWell.py b/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/thermalLeakyWell/thermalLeakyWell.py index bc28a9aeccb..95e6ddac052 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/thermalLeakyWell/thermalLeakyWell.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/carbonStorage/thermalLeakyWell/thermalLeakyWell.py @@ -15,15 +15,15 @@ def main(): # Read HDF5 hf = h5py.File(hdf5FilePathRefined, 'r') timeRefined = hf.get('componentOutflux Time') - timeRefined = np.array(timeRefined) + timeRefined = np.asarray(timeRefined) compOutfluxRefined = hf.get('componentOutflux') - compOutfluxRefined = np.array(compOutfluxRefined) + compOutfluxRefined = np.asarray(compOutfluxRefined) hf = h5py.File(hdf5FilePathCoarse, 'r') timeCoarse = hf.get('componentOutflux Time') - timeCoarse = np.array(timeCoarse) + timeCoarse = np.asarray(timeCoarse) compOutfluxCoarse = hf.get('componentOutflux') - compOutfluxCoarse = np.array(compOutfluxCoarse) + compOutfluxCoarse = np.asarray(compOutfluxCoarse) # Conversions inDays = 1.0 / 86400.0 diff --git a/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/faultVerification/faultVerificationFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/faultVerification/faultVerificationFigure.py index 09e5db15f3d..20c937e0d34 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/faultVerification/faultVerificationFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/faultVerification/faultVerificationFigure.py @@ -4,6 +4,8 @@ from matplotlib.ticker import (MultipleLocator, FormatStrFormatter, AutoMinorLocator) import xml.etree.ElementTree as ElementTree import csv +import os +import argparse def getHydromechanicalParametersFromXML(xmlFilePath): @@ -25,7 +27,7 @@ def getHydromechanicalParametersFromXML(xmlFilePath): G = E / 2.0 / (1.0 + nu) hydromechanicalParameters["bulkModulus"] = K hydromechanicalParameters["shearModulus"] = G - Ks = float(param2.get("grainBulkModulus")) + Ks = float(param2.get("defaultGrainBulkModulus")) hydromechanicalParameters["biotCoefficient"] = 1.0 - K / Ks hydromechanicalParameters["porosity"] = float(param2.get("defaultReferencePorosity")) @@ -73,8 +75,21 @@ def getCompressiveStressFromXML(xmlFilePath): def main(): + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + # File path - xmlFilePath = "../../../../../../../inputFiles/poromechanics/faultPoroelastic_base.xml" + outputDir = args.outputDir + geosDir = args.geosDir + xmlFilePath = geosDir + "/inputFiles/poromechanics/faultPoroelastic_base.xml" # Extract info from XML hydromechanicalParameters = getHydromechanicalParametersFromXML(xmlFilePath) @@ -82,7 +97,7 @@ def main(): Stress, Pr_i = getCompressiveStressFromXML(xmlFilePath) # Load simulation result for case with impermeable fault - file = open("result_imp.csv") + file = open(outputDir + "/result_imp.csv") csvreader = csv.reader(file) header = next(csvreader) rows = [] @@ -104,7 +119,7 @@ def main(): y_imp[i] = float(rows[i, 26]) # Load simulation result for case with permeable fault - file = open("result_per.csv") + file = open( outputDir + "/result_per.csv") csvreader = csv.reader(file) header = next(csvreader) rows = [] diff --git a/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/intersectFrac/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/intersectFrac/Example.rst index a1019bac817..6714806e81f 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/intersectFrac/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/intersectFrac/Example.rst @@ -14,11 +14,15 @@ method `(Phan et al., 2003) :end-before: @@ -78,7 +82,7 @@ with one group of cell blocks named here ``cb1``. Refinement is necessary to conform with the fracture geometry specified in the ``Geometry`` section. -.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_base.xml +.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/TFrac_base.xml :language: xml :start-after: :end-before: @@ -124,7 +128,7 @@ A homogeneous and isotropic domain with one solid material is assumed, and its m Fracture surface slippage is assumed to be governed by the Coulomb failure criterion. The contact constitutive behavior is named ``fractureMaterial`` in the ``Coulomb`` block, where cohesion ``cohesion="0.0"`` and friction coefficient ``frictionCoefficient="0.577350269"`` are specified. -.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_base.xml +.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/TFrac_base.xml :language: xml :start-after: :end-before: @@ -145,7 +149,7 @@ In the ``Tasks`` section, ``PackCollection`` tasks are defined to collect time h Either the entire field or specified named sets of indices in the field can be collected. In this example, ``tractionCollection`` and ``displacementJumpCollection`` tasks are specified to output the local traction ``fieldName="traction"`` and relative displacement ``fieldName="displacementJump"`` on the fracture surface. -.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_base.xml +.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/TFrac_base.xml :language: xml :start-after: :end-before: @@ -171,7 +175,7 @@ The remaining parts of the outer boundaries are subjected to roller constraints. These boundary conditions are set up through the ``FieldSpecifications`` section. -.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_base.xml +.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/TFrac_base.xml :language: xml :start-after: :end-before: diff --git a/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/intersectFrac/intersectFracFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/intersectFrac/intersectFracFigure.py index 63ad214a36f..ac6f796ed04 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/intersectFrac/intersectFracFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/intersectFrac/intersectFracFigure.py @@ -7,6 +7,8 @@ import math from math import sin, cos, tan, exp, atan, asin from mpl_toolkits.mplot3d import axes3d +import os +import argparse class Sneddon: @@ -87,29 +89,42 @@ def getFractureGeometryFromXML(xmlFilePath): def main(): + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + # File path - hdf5File1Path = "traction_history.hdf5" - hdf5File2Path = "displacementJump_history.hdf5" - xmlFilePath = "../../../../../../../inputFiles/lagrangianContactMechanics/ContactMechanics_TFrac_base.xml" + outputDir = args.outputDir + geosDir = args.geosDir + hdf5File1Path = outputDir + "/traction_history.hdf5" + hdf5File2Path = outputDir + "/displacementJump_history.hdf5" + xmlFilePath = geosDir + "/inputFiles/lagrangianContactMechanics/TFrac_base.xml" # Read HDF5 # Global Coordinate of Fracture Element Center hf = h5py.File(hdf5File1Path, 'r') xl = hf.get('traction elementCenter') - xl = np.array(xl) + xl = np.asarray(xl) xcord = xl[0, :, 0] ycord = xl[0, :, 1] zcord = xl[0, :, 2] # Local Normal Traction trac = hf.get('traction') - trac = np.array(trac) + trac = np.asarray(trac) normalTraction = trac[-1, :, 0] # Local Shear Displacement hf = h5py.File(hdf5File2Path, 'r') jump = hf.get('displacementJump') - jump = np.array(jump) + jump = np.asarray(jump) displacementJump = jump[-1, :, 1] aperture = jump[-1, :, 0] diff --git a/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/singleFracCompression/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/singleFracCompression/Example.rst index c34a6cf30cb..4b29541ce9d 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/singleFracCompression/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/singleFracCompression/Example.rst @@ -13,11 +13,15 @@ In this example, a single fracture is simulated using a Lagrange contact model i **Input file** -Everything required is contained within two GEOS input files and one mesh file located at: +Everything required is contained within these GEOS input files and one mesh file located at: .. code-block:: console - inputFiles/lagrangianContactMechanics/ContactMechanics_SingleFracCompression_base.xml + inputFiles/lagrangianContactMechanics/SingleFracCompression_base.xml + +.. code-block:: console + + inputFiles/lagrangianContactMechanics/SingleFracCompression_benchmark.xml .. code-block:: console @@ -79,7 +83,7 @@ The syntax to import external meshes is simple: in the XML file, the mesh file ``crackInPlane_benchmark.vtu`` is included with its relative or absolute path to the location of the GEOS XML file and a user-specified label (here ``CubeHex``) is given to the mesh object. This unstructured mesh contains quadrilaterals elements and interface elements. Refinement is performed to conform with the fracture geometry specified in the ``Geometry`` section. -.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/ContactMechanics_SingleFracCompression_benchmark.xml +.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/SingleFracCompression_benchmark.xml :language: xml :start-after: :end-before: @@ -110,7 +114,7 @@ To setup a coupling between rock and fracture deformations, we define three diff - The solver ``SurfaceGenerator`` defines the fracture region and rock toughness. -.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/ContactMechanics_SingleFracCompression_base.xml +.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/ContactMechanics_SingleFracCompression_benchmark.xml :language: xml :start-after: :end-before: @@ -124,7 +128,7 @@ For this specific problem, we simulate the elastic deformation and fracture slip Fracture surface slippage is assumed to be governed by the Coulomb failure criterion. The contact constitutive behavior is named ``fractureMaterial`` in the ``Coulomb`` block, where cohesion ``cohesion="0.0"`` and friction coefficient ``frictionCoefficient="0.577350269"`` are specified. -.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/ContactMechanics_SingleFracCompression_base.xml +.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/SingleFracCompression_base.xml :language: xml :start-after: :end-before: @@ -145,7 +149,7 @@ In the ``Tasks`` section, ``PackCollection`` tasks are defined to collect time h Either the entire field or specified named sets of indices in the field can be collected. In this example, ``tractionCollection`` and ``displacementJumpCollection`` tasks are specified to output the local traction ``fieldName="traction"`` and relative displacement ``fieldName="displacementJump"`` on the fracture surface. -.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/ContactMechanics_SingleFracCompression_base.xml +.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/SingleFracCompression_base.xml :language: xml :start-after: :end-before: @@ -170,7 +174,7 @@ The remaining parts of the outer boundaries are subjected to roller constraints. These boundary conditions are set up through the ``FieldSpecifications`` section. -.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/ContactMechanics_SingleFracCompression_base.xml +.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/SingleFracCompression_base.xml :language: xml :start-after: :end-before: diff --git a/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/singleFracCompression/singleFracCompressionFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/singleFracCompression/singleFracCompressionFigure.py index e4c5f331e8c..32afe5d42b2 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/singleFracCompression/singleFracCompressionFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/singleFracCompression/singleFracCompressionFigure.py @@ -7,6 +7,8 @@ import math from math import sin, cos, tan, exp, atan, asin from mpl_toolkits.mplot3d import axes3d +import os +import argparse class Analytical: @@ -78,17 +80,30 @@ def getFractureGeometryFromXML(xmlFilePath): def main(): + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + # File path - hdf5File1Path = "traction_history.hdf5" - hdf5File2Path = "displacementJump_history.hdf5" - xmlFile1Path = "../../../../../../../inputFiles/lagrangianContactMechanics/ContactMechanics_SingleFracCompression_base.xml" - xmlFile2Path = "../../../../../../../inputFiles/lagrangianContactMechanics/ContactMechanics_SingleFracCompression_benchmark.xml" + outputDir = args.outputDir + geosDir = args.geosDir + hdf5File1Path = outputDir + "/traction_history.hdf5" + hdf5File2Path = outputDir + "/displacementJump_history.hdf5" + xmlFile1Path = geosDir + "/inputFiles/lagrangianContactMechanics/SingleFracCompression_base.xml" + xmlFile2Path = geosDir + "/inputFiles/lagrangianContactMechanics/SingleFracCompression_benchmark.xml" # Read HDF5 # Global Coordinate of Fracture Element Center hf = h5py.File(hdf5File1Path, 'r') xl = hf.get('traction elementCenter') - xl = np.array(xl) + xl = np.asarray(xl) xcord = xl[0, :, 0] ycord = xl[0, :, 1] zcord = xl[0, :, 2] @@ -96,13 +111,13 @@ def main(): # Local Normal Traction hf = h5py.File(hdf5File1Path, 'r') trac = hf.get('traction') - trac = np.array(trac) + trac = np.asarray(trac) normalTraction = trac[0, :, 0] # Local Shear Displacement hf = h5py.File(hdf5File2Path, 'r') jump = hf.get('displacementJump') - jump = np.array(jump) + jump = np.asarray(jump) displacementJump = jump[0, :, 1] # Extract Local Inform for The Middle Layer diff --git a/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/sneddon/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/sneddon/Example.rst index 65a1ad48d5e..c8a81833630 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/sneddon/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/sneddon/Example.rst @@ -29,8 +29,9 @@ The xml input files for the case with LagrangianContact solver are located at: .. code-block:: console - inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_base.xml - inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_benchmark.xml + inputFiles/lagrangianContactMechanics/Sneddon_base.xml + inputFiles/lagrangianContactMechanics/Sneddon_benchmark.xml + inputFiles/lagrangianContactMechanics/ContactMechanics_Sneddon_benchmark.xml The xml input files for the case with HydroFracture solver are located at: @@ -99,7 +100,7 @@ To setup a coupling between rock and fracture deformations in LagrangianContact - The solver ``SurfaceGenerator`` defines the fracture region and rock toughness. -.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_benchmark.xml +.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/ContactMechanics_Sneddon_benchmark.xml :language: xml :start-after: :end-before: @@ -155,7 +156,7 @@ along the Z axes, 121 elements along the X axis and 921 elements along the Y axi The mesh for the case with LagrangianContact solver was also created using the internal mesh generator, as parametrized in the ``InternalMesh`` XML tag. The mesh discretizes the same compational domain (:math:`40\, m \, \times 40 \, m \, \times 1 \, m`) with 300 x 300 x 2 eight-node brick elements in the x, y, and z directions respectively. -.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_benchmark.xml +.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/Sneddon_benchmark.xml :language: xml :start-after: :end-before: @@ -209,7 +210,7 @@ The static fracture is defined by a nodeset occupying a small region within the - The test case with LagrangianContact solver: -.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_base.xml +.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/Sneddon_base.xml :language: xml :start-after: :end-before: @@ -242,7 +243,7 @@ In this example, a task is specified to output fracture aperture (normal opening - The test case with LagrangianContact solver: -.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_base.xml +.. literalinclude:: ../../../../../../../inputFiles/lagrangianContactMechanics/Sneddon_base.xml :language: xml :start-after: :end-before: @@ -271,7 +272,7 @@ To run these three cases, use the following commands: ``path/to/geos -i inputFiles/efemFractureMechanics/Sneddon_embeddedFrac_verification.xml`` -``path/to/geos -i inputFiles/lagrangianContactMechanics/Sneddon_contactMechanics_benchmark.xml`` +``path/to/geos -i inputFiles/lagrangianContactMechanics/ContactMechanics_Sneddon_benchmark.xml`` ``path/to/geos -i inputFiles/hydraulicFracturing/Sneddon_hydroFrac_benchmark.xml`` diff --git a/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/sneddon/sneddonFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/sneddon/sneddonFigure.py index 5d3db7e4687..6562cfdc8e9 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/sneddon/sneddonFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/faultMechanics/sneddon/sneddonFigure.py @@ -5,6 +5,8 @@ import xml.etree.ElementTree as ElementTree from mpmath import * import math +import os +import argparse class Sneddon: @@ -62,13 +64,26 @@ def getFractureLengthFromXML(xmlFilePath): def main(): + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + #-------- EmbeddeFrac File path - hdf5File1Path = "displacementJump_embeddedFrac.hdf5" + outputDir = args.outputDir + geosDir = args.geosDir + hdf5File1Path = outputDir + "/displacementJump_embeddedFrac.hdf5" # Read HDF5 hf = h5py.File(hdf5File1Path, 'r') jump = hf.get('displacementJump') - jump = np.array(jump) + jump = np.asarray(jump) aperture_EmbeddeFrac = jump[0, :, 0] x = hf.get('displacementJump elementCenter') loc_EmbeddeFrac = x[0, :, 1] @@ -79,7 +94,7 @@ def main(): # Read HDF5 hf = h5py.File(hdf5File2Path, 'r') jump = hf.get('displacementJump') - jump = np.array(jump) + jump = np.asarray(jump) aperture_Contact = jump[0, :, 0] x = hf.get('displacementJump elementCenter') loc_Contact = x[0, :, 1] @@ -90,13 +105,13 @@ def main(): # Read HDF5 hf = h5py.File(hdf5File3Path, 'r') jump = hf.get('elementAperture') - jump = np.array(jump) + jump = np.asarray(jump) aperture_HydroFrac = jump[0, :] x = hf.get('elementAperture elementCenter') loc_HydroFrac = x[0, :, 1] #-------- Extract info from XML - xmlFilePath = "../../../../../../../inputFiles/efemFractureMechanics/Sneddon_embeddedFrac" + xmlFilePath = geosDir + "/inputFiles/efemFractureMechanics/Sneddon_embeddedFrac" mechanicalParameters = getMechanicalParametersFromXML(xmlFilePath+"_base.xml") appliedPressure = getFracturePressureFromXML(xmlFilePath+"_base.xml") diff --git a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdToughnessDominated/kgdToughnessDominatedFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdToughnessDominated/kgdToughnessDominatedFigure.py index ce6deb2112c..98c7e241dd7 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdToughnessDominated/kgdToughnessDominatedFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdToughnessDominated/kgdToughnessDominatedFigure.py @@ -1,6 +1,9 @@ import sys +import os +import argparse + sys.path.append('../../../../../../../inputFiles/hydraulicFracturing/scripts') import hydrofractureFigure -hydrofractureFigure.main(xmlFilePathPrefix='kgdToughnessDominated') +hydrofractureFigure.main( geosDir='../../../../../../..',xmlFilePrefix='kgdToughnessDominated') diff --git a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdValidation/kgdValidationFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdValidation/kgdValidationFigure.py index 5ef9337d72a..e16cbbaba83 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdValidation/kgdValidationFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdValidation/kgdValidationFigure.py @@ -1,10 +1,23 @@ import matplotlib import numpy as np import matplotlib.pyplot as plt +import os +import argparse def main(): + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + outputDir = args.outputDir + + # Experiments (Rubin, 1983) H = 0.055 Tinj = 3.7 @@ -16,7 +29,7 @@ def main(): P58list = [1.677, 4.145, 4.134, 3.507, 3.381, 2.827, 2.292, 1.894, 1.557, 1.345, 1.172, 1.050, 0.949] # Load GEOSX results - GTime, GWellP, G58P, G57P, GAper, GArea = np.loadtxt("model_results.txt", skiprows=1, unpack=True) + GTime, GWellP, G58P, G57P, GAper, GArea = np.loadtxt(outputDir + "/model_results.txt", skiprows=1, unpack=True) GLength = GArea / H * 1000 GTime = GTime + Tinj diff --git a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdValidation/kgdValidationQueries.py b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdValidation/kgdValidationQueries.py index 18354b98f23..f46826d4c03 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdValidation/kgdValidationQueries.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdValidation/kgdValidationQueries.py @@ -43,9 +43,20 @@ def getMeshSettings(xmlFilePath): def main(): + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + # Load and process GEOSX results # File path - prefix = "../../../../../../../inputFiles/hydraulicFracturing/" + prefix = geosDir + "/inputFiles/hydraulicFracturing/" hdf5File = prefix + "KGD_validation_output.hdf5" xmlFile1Path = prefix + "kgdValidation_base.xml" xmlFile2Path = prefix + "kgdValidation_benchmark.xml" @@ -62,21 +73,21 @@ def main(): # Global Coordinate of Element Center hf = hdf5_wrapper.hdf5_wrapper(hdf5File) xl = hf['pressure elementCenter'] - xl = np.array(xl) + xl = np.asarray(xl) xcord = xl[-1, :, 0] ycord = xl[-1, :, 1] zcord = xl[-1, :, 2] tl = hf['pressure Time'] - tl = np.array(tl) + tl = np.asarray(tl) # Load pressure fpre = hf['pressure'] - fpre = np.array(fpre) + fpre = np.asarray(fpre) # Load elementAperture aper = hf['elementAperture'] - aper = np.array(aper) + aper = np.asarray(aper) # Load elementArea area = hf['elementArea'] - area = np.array(area) + area = np.asarray(area) # Query simulation results xloc_58 = 0.015 diff --git a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdViscosityDominated/kgdViscosityDominatedFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdViscosityDominated/kgdViscosityDominatedFigure.py index f27bdd261c4..94fca42b18e 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdViscosityDominated/kgdViscosityDominatedFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/kgdViscosityDominated/kgdViscosityDominatedFigure.py @@ -1,6 +1,8 @@ import sys +import os +import argparse sys.path.append('../../../../../../../inputFiles/hydraulicFracturing/scripts') import hydrofractureFigure -hydrofractureFigure.main(xmlFilePathPrefix='kgdViscosityDominated') +hydrofractureFigure.main( geosDir='../../../../../../..',xmlFilePrefix='kgdViscosityDominated') diff --git a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/pennyFracToughnessDominated/pennyShapedToughnessDominatedFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/pennyFracToughnessDominated/pennyShapedToughnessDominatedFigure.py index 79da99b2b64..1fbe44c6ddf 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/pennyFracToughnessDominated/pennyShapedToughnessDominatedFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/pennyFracToughnessDominated/pennyShapedToughnessDominatedFigure.py @@ -1,6 +1,8 @@ import sys +import os +import argparse sys.path.append('../../../../../../../inputFiles/hydraulicFracturing/scripts') import hydrofractureFigure -hydrofractureFigure.main(xmlFilePathPrefix='pennyShapedToughnessDominated') +hydrofractureFigure.main( geosDir='../../../../../../..',xmlFilePrefix='pennyShapedToughnessDominated') diff --git a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/pennyFracViscosityDominated/pennyShapedViscosityDominatedFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/pennyFracViscosityDominated/pennyShapedViscosityDominatedFigure.py index 8f1e331a3c4..a2ca7bea56f 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/pennyFracViscosityDominated/pennyShapedViscosityDominatedFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/pennyFracViscosityDominated/pennyShapedViscosityDominatedFigure.py @@ -1,6 +1,8 @@ import sys +import os +import argparse sys.path.append('../../../../../../../inputFiles/hydraulicFracturing/scripts') import hydrofractureFigure -hydrofractureFigure.main(xmlFilePathPrefix='pennyShapedViscosityDominated') +hydrofractureFigure.main( geosDir='../../../../../../..',xmlFilePrefix='pennyShapedViscosityDominated') diff --git a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/pknFracViscosityDominated/pknViscosityDominatedFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/pknFracViscosityDominated/pknViscosityDominatedFigure.py index 3fe908fb9f8..824b5c3dfe8 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/pknFracViscosityDominated/pknViscosityDominatedFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/pknFracViscosityDominated/pknViscosityDominatedFigure.py @@ -1,6 +1,8 @@ import sys +import os +import argparse sys.path.append('../../../../../../../inputFiles/hydraulicFracturing/scripts') import hydrofractureFigure -hydrofractureFigure.main(xmlFilePathPrefix='pknViscosityDominated') +hydrofractureFigure.main( geosDir='../../../../../../..',xmlFilePrefix='pknViscosityDominated') diff --git a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/proppantSlotTest/proppantSlotTestFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/proppantSlotTest/proppantSlotTestFigure.py index 39e494eb0e0..5a528ad123e 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/proppantSlotTest/proppantSlotTestFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/hydraulicFracture/proppantSlotTest/proppantSlotTestFigure.py @@ -2,14 +2,27 @@ import matplotlib import numpy as np import matplotlib.pyplot as plt +import os +import argparse def main(): - eTime, eLength, eArea = np.loadtxt("experiment-data.txt", skiprows=0, unpack=True) - esTime, esArea = np.loadtxt("experiment-data2.txt", skiprows=0, unpack=True) - dTime, dLength, dArea = np.loadtxt("model-results.txt", skiprows=1, unpack=True) - sTime, sArea = np.loadtxt("model-results2.txt", skiprows=1, unpack=True) + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + outputDir = args.outputDir + + eTime, eLength, eArea = np.loadtxt(outputDir + "/experiment-data.txt", skiprows=0, unpack=True) + esTime, esArea = np.loadtxt(outputDir + "/experiment-data2.txt", skiprows=0, unpack=True) + + dTime, dLength, dArea = np.loadtxt(outputDir + "/model-results.txt", skiprows=1, unpack=True) + sTime, sArea = np.loadtxt(outputDir + "/model-results2.txt", skiprows=1, unpack=True) # offSize is the size of the bounday cell which should be excluded from the model domain offSize = 0.0127 diff --git a/src/docs/sphinx/advancedExamples/validationStudies/poromechanics/Index.rst b/src/docs/sphinx/advancedExamples/validationStudies/poromechanics/Index.rst index 46eda39040d..3b5ff0a73ca 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/poromechanics/Index.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/poromechanics/Index.rst @@ -1,4 +1,4 @@ -.. _ValidationStudiesFaultMechanics: +.. _ValidationStudiesPoromechanics: Poromechanics diff --git a/src/docs/sphinx/advancedExamples/validationStudies/poromechanics/mandel/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/poromechanics/mandel/Example.rst index ea1107077f7..3e0cf3e0710 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/poromechanics/mandel/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/poromechanics/mandel/Example.rst @@ -30,7 +30,7 @@ Description of the case We simulate the consolidation of a poroelastic slab between two rigid and impermeable plates subjected to a constant normal force. The slab is assumed to be fully saturated, homogeneous, isotropic, and infinitely long in the y-direction. We apply a uniform compressive load in the vertical direction. This force leads to a change of pore pressure and mechanical deformations of the sample, evolving with time due to fluid diffusion and coupling effects. The numerical model represents a plane strain deformation and lateral drainage without confinement, showing only a quarter of the computational domain in the x-z plane (the rest follows by symmetry). -.. _problemSketchFig: +.. _mandelProblemSketchFig: .. figure:: sketch.png :align: center :width: 500 @@ -119,7 +119,7 @@ As demonstrated in this example, to setup a poromechanical coupling, we need to - the mechanics solver, a solver of type ``SolidMechanicsLagrangianSSLE`` called here ``lagsolve`` (more information here: :ref:`SolidMechanicsLagrangianFEM`), -.. literalinclude:: ../../../../../../../inputFiles/poromechanics/PoroElastic_Mandel_base.xml +.. literalinclude:: ../../../../../../../inputFiles/poromechanics/PoroElastic_Mandel_smoke_sequential.xml :language: xml :start-after: :end-before: @@ -127,7 +127,7 @@ As demonstrated in this example, to setup a poromechanical coupling, we need to - the single-phase flow solver, a solver of type ``SinglePhaseFVM`` called here ``SinglePhaseFlow`` (more information on these solvers at :ref:`SinglePhaseFlow`), -.. literalinclude:: ../../../../../../../inputFiles/poromechanics/PoroElastic_Mandel_base.xml +.. literalinclude:: ../../../../../../../inputFiles/poromechanics/PoroElastic_Mandel_smoke_sequential.xml :language: xml :start-after: :end-before: @@ -135,7 +135,7 @@ As demonstrated in this example, to setup a poromechanical coupling, we need to - the coupling solver (``SinglePhasePoromechanics``) that will bind the two single-physics solvers above, which is named as ``poroSolve`` (more information at :ref:`PoroelasticSolver`). -.. literalinclude:: ../../../../../../../inputFiles/poromechanics/PoroElastic_Mandel_base.xml +.. literalinclude:: ../../../../../../../inputFiles/poromechanics/PoroElastic_Mandel_smoke_sequential.xml :language: xml :start-after: :end-before: @@ -267,6 +267,7 @@ The figure below compares the results from GEOS (marks) and the corresponding an .. plot:: docs/sphinx/advancedExamples/validationStudies/poromechanics/mandel/mandelFigure.py +.. note:: The python script included above is used to generate the figure shown here. If you want to run this script to verify your results, you will need to run the script from your output directory, and modify the path to the variables `xmlFile1Path` and `xmlFile1Path` in the script to point to the location of the input files on your system. diff --git a/src/docs/sphinx/advancedExamples/validationStudies/poromechanics/mandel/mandelFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/poromechanics/mandel/mandelFigure.py index c031d6ab19a..737c8680836 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/poromechanics/mandel/mandelFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/poromechanics/mandel/mandelFigure.py @@ -7,7 +7,8 @@ import math from math import sin, cos, tan, exp, atan, asin from scipy.optimize import newton - +import os +import argparse class Mandel: @@ -90,7 +91,7 @@ def getHydromechanicalParametersFromXML(xmlFilePath): G = hydromechanicalParameters["shearModulus"] E = (9.0 * K * G) / (3.0 * K + G) nu = E / (2.0 * G) - 1.0 - Ks = float(param2.get("grainBulkModulus")) + Ks = float(param2.get("defaultGrainBulkModulus")) hydromechanicalParameters["biotCoefficient"] = 1.0 - K / Ks hydromechanicalParameters["porosity"] = float(param2.get("defaultReferencePorosity")) @@ -140,11 +141,25 @@ def getGeometryFromXML(xmlFilePath): def main(): + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + + # File path - hdf5File1Path = "pressure_history.hdf5" - hdf5File2Path = "displacement_history.hdf5" - xmlFile1Path = "../../../../../../../inputFiles/poromechanics/PoroElastic_Mandel_base.xml" - xmlFile2Path = "../../../../../../../inputFiles/poromechanics/PoroElastic_Mandel_benchmark_fim.xml" + outputDir = args.outputDir + geosDir = args.geosDir + hdf5File1Path = outputDir + "/pressure_history.hdf5" + hdf5File2Path = outputDir + "/displacement_history.hdf5" + xmlFile1Path = geosDir + "/inputFiles/poromechanics/PoroElastic_Mandel_base.xml" + xmlFile2Path = geosDir + "/inputFiles/poromechanics/PoroElastic_Mandel_benchmark_fim.xml" # Read HDF5 # Global Coordinate of Element Center diff --git a/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/Example.rst index 74e9a10750d..7e67e01d820 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/Example.rst @@ -31,7 +31,7 @@ The initial temperature of the saturated soil is 0 degrees Celsius. The soil column is insulated and sealed everywhere, except at the top surface. The problem setup is illustrated below. -.. _problemSketchFig: +.. _thermoPoroMechanicsProblemSketchFig: .. figure:: sketch.png :align: center :width: 350 diff --git a/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/thermalConsolidationDisplacementFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/thermalConsolidationDisplacementFigure.py index 210bfd27a8c..285a7b15706 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/thermalConsolidationDisplacementFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/thermalConsolidationDisplacementFigure.py @@ -15,11 +15,11 @@ def main(): # Read simulation output from HDF5 file hf = h5py.File(hdf5FilePathDisplacement, 'r') timeDisplacement = hf.get('totalDisplacement Time') - timeDisplacement = np.array(timeDisplacement) + timeDisplacement = np.asarray(timeDisplacement) centerDisplacement = hf.get('totalDisplacement ReferencePosition') - centerDisplacement = np.array(centerDisplacement) + centerDisplacement = np.asarray(centerDisplacement) displacement = hf.get('totalDisplacement') - displacement = np.array(displacement) + displacement = np.asarray(displacement) time = 1 posVertex1 = -1 diff --git a/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/thermalConsolidationPressureFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/thermalConsolidationPressureFigure.py index 90a074889f1..d72455e6020 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/thermalConsolidationPressureFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/thermalConsolidationPressureFigure.py @@ -15,11 +15,11 @@ def main(): # Read simulation output from HDF5 file hf = h5py.File(hdf5FilePathPressure, 'r') timePressure = hf.get('pressure Time') - timePressure = np.array(timePressure) + timePressure = np.asarray(timePressure) centerPressure = hf.get('pressure elementCenter') - centerPressure = np.array(centerPressure) + centerPressure = np.asarray(centerPressure) pressure = hf.get('pressure') - pressure = np.array(pressure) + pressure = np.asarray(pressure) time = 1 posElement1 = -1 diff --git a/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/thermalConsolidationTemperatureFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/thermalConsolidationTemperatureFigure.py index 65b4dd710d5..ee60cf94ab5 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/thermalConsolidationTemperatureFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/thermoPoromechanics/thermalConsolidation/thermalConsolidationTemperatureFigure.py @@ -15,11 +15,11 @@ def main(): # Read simulation output from HDF5 file hf = h5py.File(hdf5FilePathTemperature, 'r') timeTemperature = hf.get('temperature Time') - timeTemperature = np.array(timeTemperature) + timeTemperature = np.asarray(timeTemperature) centerTemperature = hf.get('temperature elementCenter') - centerTemperature = np.array(centerTemperature) + centerTemperature = np.asarray(centerTemperature) temperature = hf.get('temperature') - temperature = np.array(temperature) + temperature = np.asarray(temperature) time = 1 posElement1 = -1 diff --git a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/DruckerPrager/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/DruckerPrager/Example.rst index 7eec2c3f25c..e02f57bc2b7 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/DruckerPrager/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/DruckerPrager/Example.rst @@ -121,4 +121,4 @@ To go further **Feedback on this example** -For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. +For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. diff --git a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/DruckerPrager/TriaxialDriver_vs_SemiAnalytic_DruckerPrager.py b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/DruckerPrager/TriaxialDriver_vs_SemiAnalytic_DruckerPrager.py index 4c15b4b910f..454ba85d837 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/DruckerPrager/TriaxialDriver_vs_SemiAnalytic_DruckerPrager.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/DruckerPrager/TriaxialDriver_vs_SemiAnalytic_DruckerPrager.py @@ -3,240 +3,255 @@ import numpy as np import matplotlib.pyplot as plt import xml.etree.ElementTree as ElementTree +import os +import argparse def main(): - # File paths - path = "DruckerPragerResults.txt" - xmlFilePath = "../../../../../../../inputFiles/triaxialDriver/triaxialDriver_base.xml" - xmlFilePath_case = "../../../../../../../inputFiles/triaxialDriver/triaxialDriver_DruckerPrager.xml" - imposedStrainFilePath = "../../../../../../../inputFiles/triaxialDriver/tables/axialStrain.geos" - imposedStressFilePath = "../../../../../../../inputFiles/triaxialDriver/tables/radialStress.geos" - - # Load GEOSX results - time, ax_strain, ra_strain1, ra_strain2, ax_stress, ra_stress1, ra_stress2, newton_iter, residual_norm = np.loadtxt( - path, skiprows=5, unpack=True) - - # Extract mechanical parameters from XML files - tree = ElementTree.parse(xmlFilePath) - tree_case = ElementTree.parse(xmlFilePath_case) - model = tree_case.find('Tasks/TriaxialDriver') - param = tree.find('Constitutive/DruckerPrager') - - bulkModulus = float(param.get("defaultBulkModulus")) - shearModulus = float(param.get("defaultShearModulus")) - cohesion = float(param.get("defaultCohesion")) - frictionAngle = float(param.get("defaultFrictionAngle")) - dilationAngle = float(param.get("defaultDilationAngle")) - hardeningRate = float(param.get("defaultHardeningRate")) - initialStress = float(model.get("initialStress")) - - # Compute Lame modulus and Young modulus - lameModulus = bulkModulus - 2.0/3.0*shearModulus - youngModulus = 1.0 / ( 1.0/9.0/bulkModulus + 1.0/3.0/shearModulus ) - - # Friction and cohesion parameters - frictionAngleRad = frictionAngle*3.1416/180.0 - cosFrictionAngle = np.cos(frictionAngleRad) - sinFrictionAngle = np.sin(frictionAngleRad) - a = 6.0*cohesion*cosFrictionAngle/(3.0-sinFrictionAngle) - b = 6.0*sinFrictionAngle/(3.0-sinFrictionAngle) - - # Dilation parameter - dilationAngleRad = dilationAngle*np.pi/180.0 - cosDilationAngle = np.cos(dilationAngleRad) - sinDilationAngle = np.sin(dilationAngleRad) - b_dilation = 6.0*sinDilationAngle/(3.0-sinDilationAngle) - - # Elasto-plastic moduli for plastic yield during the loading period - plasticYoungModulus = 1.0 / ( 1.0/youngModulus + (b_dilation-3.0)*(b-3.0)/9.0/hardeningRate ) - plasticModulusForRaStrain = 1.0 / ( 1.0/2.0/shearModulus - (b-3.0)/2.0/hardeningRate ) - - # Elasto-plastic moduli for plastic yield during the unloading period - plasticYoungModulus_unload = 1.0 / ( 1.0/youngModulus + (b_dilation+3.0)*(b+3.0)/9.0/hardeningRate ) - plasticModulusForRaStrain_unload = 1.0 / ( 1.0/2.0/shearModulus + (b+3.0)/2.0/hardeningRate ) - - # Extract axial strain loading from input tables - imp_strain = np.loadtxt( - imposedStrainFilePath, skiprows=0, unpack=True) - - list_ax_strain_anal = [] - numStepPerLoadingPeriod = 1000 - - for i in range(0,len(imp_strain)-1): - dStrainPerStep = (imp_strain[i+1]-imp_strain[i])/numStepPerLoadingPeriod - loadingPeriod = np.arange(imp_strain[i],imp_strain[i+1]+dStrainPerStep,dStrainPerStep) - list_ax_strain_anal = np.concatenate((list_ax_strain_anal, loadingPeriod), axis=0) - - # Extract radial stress loading from input tables - imp_stress = np.loadtxt( - imposedStressFilePath, skiprows=0, unpack=True) - - list_ra_stress_anal = imp_stress[0]*np.ones(len(list_ax_strain_anal)) #constant radial confining stress - - # Initiate radial strain and axial stress arrays - list_ra_strain_anal = np.zeros(len(list_ax_strain_anal)) - list_ax_stress_anal = np.zeros(len(list_ax_strain_anal)) - list_ax_stress_anal[0] = initialStress - list_ra_strain_anal[0] = 0 - - # Loop over the loading/unloading steps - for idx in range(1,len(list_ax_strain_anal)): - delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] - delta_ra_stress_anal = 0 # constant radial confining stress - - # Elastic trial - delta_ra_strain_anal = ( delta_ra_stress_anal - lameModulus*delta_ax_strain_anal ) / ( 2.0*lameModulus + 2.0*shearModulus ) - delta_ax_stress_anal = ( lameModulus + 2.0*shearModulus )*delta_ax_strain_anal + lameModulus/( lameModulus + shearModulus ) * ( delta_ra_stress_anal - lameModulus*delta_ax_strain_anal ) - - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal - - # Compute mean and shear stresses - ra_stress_anal = list_ra_stress_anal[idx] - - p_anal = (ax_stress_anal + 2.0 * ra_stress_anal) / 3.0 - q_anal = -(ax_stress_anal - ra_stress_anal) - - # Plastic correction - if(q_anal>=0): #loading - F_anal = q_anal + b*p_anal - a - - if(F_anal>=0): - # Compute stress and strain variations - delta_ax_stress_anal = delta_ax_strain_anal * plasticYoungModulus - delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / plasticModulusForRaStrain - - # Compute stress and strain at actual loading step - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal - - # Update plastic cohesion - delta_a = (b-3.0)/3.0*delta_ax_stress_anal - a += delta_a - - else: #unloading - F_anal = -q_anal + b*p_anal - a # negative sign added to q for q<0 to obtain the absolute value - - if(F_anal>=0): - # Compute stress and strain variations - delta_ax_stress_anal = delta_ax_strain_anal * plasticYoungModulus_unload - delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / plasticModulusForRaStrain_unload - - # Compute stress and strain at actual loading step - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal - - # Update plastic cohesion - delta_a = (b+3.0)/3.0*delta_ax_stress_anal - a += delta_a - - list_ax_stress_anal[idx] = ax_stress_anal - list_ra_strain_anal[idx] = ra_strain_anal - - # Preparing data for visualizing semi-analytical results - list_p_anal = (list_ax_stress_anal + 2.0 * list_ra_stress_anal) / 3.0 - list_q_anal = -(list_ax_stress_anal - list_ra_stress_anal) - - list_strain_vol_anal = list_ax_strain_anal + 2.0 * list_ra_strain_anal - - p_num = (ax_stress + 2.0 * ra_stress1) / 3.0 - q_num = -(ax_stress - ra_stress1) - - strain_vol = ax_strain + 2.0 * ra_strain1 - - #Visualization parameters - fsize = 30 - msize = 12 - lw = 6 - malpha = 0.5 - fig, ax = plt.subplots(1, 3, figsize=(37, 10)) - cmap = plt.get_cmap("tab10") - - # Plot strain versus shear stress - ax[0].plot(-ax_strain * 100, #convert to % - q_num*1e-6, #convert to MPa - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[0].plot(-ra_strain1 * 100, - q_num*1e-6, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha) - ax[0].plot(-list_ax_strain_anal* 100, - list_q_anal*1e-6, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[0].plot(-list_ra_strain_anal * 100, - list_q_anal*1e-6, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - linewidth=6) - ax[0].set_xlabel(r'Strain (%)', size=fsize, weight="bold") - ax[0].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") - ax[0].xaxis.set_tick_params(labelsize=fsize) - ax[0].yaxis.set_tick_params(labelsize=fsize) - - # Plot axial strain versus volumetric strain - ax[1].plot(-ax_strain * 100, - -strain_vol * 100, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[1].plot(-list_ax_strain_anal* 100, - -list_strain_vol_anal* 100, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[1].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") - ax[1].set_ylabel(r'Volumetric Strain (%)', size=fsize, weight="bold") - #ax[1].legend(loc='lower right', fontsize=fsize) - ax[1].xaxis.set_tick_params(labelsize=fsize) - ax[1].yaxis.set_tick_params(labelsize=fsize) - - # Plot shear stress versus mean stress - ax[2].plot(-p_num*1e-6, - q_num*1e-6, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[2].plot(-list_p_anal*1e-6, - list_q_anal*1e-6, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[2].set_xlabel(r'Mean stress (MPa)', size=fsize, weight="bold") - ax[2].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") - ax[2].legend(loc='lower right', fontsize=fsize) - ax[2].xaxis.set_tick_params(labelsize=fsize) - ax[2].yaxis.set_tick_params(labelsize=fsize) - - plt.subplots_adjust(left=0.2, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4) - plt.show() + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + + # File paths + outputDir = args.outputDir + geosDir = args.geosDir + path = outputDir + "/DruckerPragerResults.txt" + xmlFilePath = geosDir + "/inputFiles/triaxialDriver/triaxialDriver_base.xml" + xmlFilePath_case = geosDir + "/inputFiles/triaxialDriver/triaxialDriver_DruckerPrager.xml" + imposedStrainFilePath = geosDir + "/inputFiles/triaxialDriver/tables/axialStrain.geos" + imposedStressFilePath = geosDir + "/inputFiles/triaxialDriver/tables/radialStress.geos" + + # Load GEOSX results + time, ax_strain, ra_strain1, ra_strain2, ax_stress, ra_stress1, ra_stress2, newton_iter, residual_norm = np.loadtxt( + path, skiprows=5, unpack=True) + + # Extract mechanical parameters from XML files + tree = ElementTree.parse(xmlFilePath) + tree_case = ElementTree.parse(xmlFilePath_case) + model = tree_case.find('Tasks/TriaxialDriver') + param = tree.find('Constitutive/DruckerPrager') + + bulkModulus = float(param.get("defaultBulkModulus")) + shearModulus = float(param.get("defaultShearModulus")) + cohesion = float(param.get("defaultCohesion")) + frictionAngle = float(param.get("defaultFrictionAngle")) + dilationAngle = float(param.get("defaultDilationAngle")) + hardeningRate = float(param.get("defaultHardeningRate")) + initialStress = float(model.get("initialStress")) + + # Compute Lame modulus and Young modulus + lameModulus = bulkModulus - 2.0/3.0*shearModulus + youngModulus = 1.0 / ( 1.0/9.0/bulkModulus + 1.0/3.0/shearModulus ) + + # Friction and cohesion parameters + frictionAngleRad = frictionAngle*3.1416/180.0 + cosFrictionAngle = np.cos(frictionAngleRad) + sinFrictionAngle = np.sin(frictionAngleRad) + a = 6.0*cohesion*cosFrictionAngle/(3.0-sinFrictionAngle) + b = 6.0*sinFrictionAngle/(3.0-sinFrictionAngle) + + # Dilation parameter + dilationAngleRad = dilationAngle*np.pi/180.0 + cosDilationAngle = np.cos(dilationAngleRad) + sinDilationAngle = np.sin(dilationAngleRad) + b_dilation = 6.0*sinDilationAngle/(3.0-sinDilationAngle) + + # Elasto-plastic moduli for plastic yield during the loading period + plasticYoungModulus = 1.0 / ( 1.0/youngModulus + (b_dilation-3.0)*(b-3.0)/9.0/hardeningRate ) + plasticModulusForRaStrain = 1.0 / ( 1.0/2.0/shearModulus - (b-3.0)/2.0/hardeningRate ) + + # Elasto-plastic moduli for plastic yield during the unloading period + plasticYoungModulus_unload = 1.0 / ( 1.0/youngModulus + (b_dilation+3.0)*(b+3.0)/9.0/hardeningRate ) + plasticModulusForRaStrain_unload = 1.0 / ( 1.0/2.0/shearModulus + (b+3.0)/2.0/hardeningRate ) + + # Extract axial strain loading from input tables + imp_strain = np.loadtxt( + imposedStrainFilePath, skiprows=0, unpack=True) + + list_ax_strain_anal = [] + numStepPerLoadingPeriod = 1000 + + for i in range(0,len(imp_strain)-1): + dStrainPerStep = (imp_strain[i+1]-imp_strain[i])/numStepPerLoadingPeriod + loadingPeriod = np.arange(imp_strain[i],imp_strain[i+1]+dStrainPerStep,dStrainPerStep) + list_ax_strain_anal = np.concatenate((list_ax_strain_anal, loadingPeriod), axis=0) + + # Extract radial stress loading from input tables + imp_stress = np.loadtxt( + imposedStressFilePath, skiprows=0, unpack=True) + + list_ra_stress_anal = imp_stress[0]*np.ones(len(list_ax_strain_anal)) #constant radial confining stress + + # Initiate radial strain and axial stress arrays + list_ra_strain_anal = np.zeros(len(list_ax_strain_anal)) + list_ax_stress_anal = np.zeros(len(list_ax_strain_anal)) + list_ax_stress_anal[0] = initialStress + list_ra_strain_anal[0] = 0 + + # Loop over the loading/unloading steps + for idx in range(1,len(list_ax_strain_anal)): + delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] + delta_ra_stress_anal = 0 # constant radial confining stress + + # Elastic trial + delta_ra_strain_anal = ( delta_ra_stress_anal - lameModulus*delta_ax_strain_anal ) / ( 2.0*lameModulus + 2.0*shearModulus ) + delta_ax_stress_anal = ( lameModulus + 2.0*shearModulus )*delta_ax_strain_anal + lameModulus/( lameModulus + shearModulus ) * ( delta_ra_stress_anal - lameModulus*delta_ax_strain_anal ) + + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal + + # Compute mean and shear stresses + ra_stress_anal = list_ra_stress_anal[idx] + + p_anal = (ax_stress_anal + 2.0 * ra_stress_anal) / 3.0 + q_anal = -(ax_stress_anal - ra_stress_anal) + + # Plastic correction + if(q_anal>=0): #loading + F_anal = q_anal + b*p_anal - a + + if(F_anal>=0): + # Compute stress and strain variations + delta_ax_stress_anal = delta_ax_strain_anal * plasticYoungModulus + delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / plasticModulusForRaStrain + + # Compute stress and strain at actual loading step + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal + + # Update plastic cohesion + delta_a = (b-3.0)/3.0*delta_ax_stress_anal + a += delta_a + + else: #unloading + F_anal = -q_anal + b*p_anal - a # negative sign added to q for q<0 to obtain the absolute value + + if(F_anal>=0): + # Compute stress and strain variations + delta_ax_stress_anal = delta_ax_strain_anal * plasticYoungModulus_unload + delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / plasticModulusForRaStrain_unload + + # Compute stress and strain at actual loading step + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal + + # Update plastic cohesion + delta_a = (b+3.0)/3.0*delta_ax_stress_anal + a += delta_a + + list_ax_stress_anal[idx] = ax_stress_anal + list_ra_strain_anal[idx] = ra_strain_anal + + # Preparing data for visualizing semi-analytical results + list_p_anal = (list_ax_stress_anal + 2.0 * list_ra_stress_anal) / 3.0 + list_q_anal = -(list_ax_stress_anal - list_ra_stress_anal) + + list_strain_vol_anal = list_ax_strain_anal + 2.0 * list_ra_strain_anal + + p_num = (ax_stress + 2.0 * ra_stress1) / 3.0 + q_num = -(ax_stress - ra_stress1) + + strain_vol = ax_strain + 2.0 * ra_strain1 + + #Visualization parameters + fsize = 30 + msize = 12 + lw = 6 + malpha = 0.5 + fig, ax = plt.subplots(1, 3, figsize=(37, 10)) + cmap = plt.get_cmap("tab10") + + # Plot strain versus shear stress + ax[0].plot(-ax_strain * 100, #convert to % + q_num*1e-6, #convert to MPa + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[0].plot(-ra_strain1 * 100, + q_num*1e-6, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha) + ax[0].plot(-list_ax_strain_anal* 100, + list_q_anal*1e-6, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[0].plot(-list_ra_strain_anal * 100, + list_q_anal*1e-6, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + linewidth=6) + ax[0].set_xlabel(r'Strain (%)', size=fsize, weight="bold") + ax[0].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") + ax[0].xaxis.set_tick_params(labelsize=fsize) + ax[0].yaxis.set_tick_params(labelsize=fsize) + + # Plot axial strain versus volumetric strain + ax[1].plot(-ax_strain * 100, + -strain_vol * 100, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[1].plot(-list_ax_strain_anal* 100, + -list_strain_vol_anal* 100, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[1].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") + ax[1].set_ylabel(r'Volumetric Strain (%)', size=fsize, weight="bold") + #ax[1].legend(loc='lower right', fontsize=fsize) + ax[1].xaxis.set_tick_params(labelsize=fsize) + ax[1].yaxis.set_tick_params(labelsize=fsize) + + # Plot shear stress versus mean stress + ax[2].plot(-p_num*1e-6, + q_num*1e-6, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[2].plot(-list_p_anal*1e-6, + list_q_anal*1e-6, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[2].set_xlabel(r'Mean stress (MPa)', size=fsize, weight="bold") + ax[2].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") + ax[2].legend(loc='lower right', fontsize=fsize) + ax[2].xaxis.set_tick_params(labelsize=fsize) + ax[2].yaxis.set_tick_params(labelsize=fsize) + + plt.subplots_adjust(left=0.2, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4) + plt.show() if __name__ == "__main__": main() diff --git a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ExtendedDruckerPrager/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ExtendedDruckerPrager/Example.rst index ceaf5963b8d..4c51b85d703 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ExtendedDruckerPrager/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ExtendedDruckerPrager/Example.rst @@ -126,4 +126,4 @@ To go further **Feedback on this example** -For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. +For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. diff --git a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ExtendedDruckerPrager/TriaxialDriver_vs_SemiAnalytic_ExtendedDruckerPrager.py b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ExtendedDruckerPrager/TriaxialDriver_vs_SemiAnalytic_ExtendedDruckerPrager.py index e55ccc04526..6589ac70c4a 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ExtendedDruckerPrager/TriaxialDriver_vs_SemiAnalytic_ExtendedDruckerPrager.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ExtendedDruckerPrager/TriaxialDriver_vs_SemiAnalytic_ExtendedDruckerPrager.py @@ -3,258 +3,273 @@ import numpy as np import matplotlib.pyplot as plt import xml.etree.ElementTree as ElementTree +import os +import argparse def main(): - # File paths - path = "ExtendedDruckerPragerResults.txt" - xmlFilePath = "../../../../../../../inputFiles/triaxialDriver/triaxialDriver_base.xml" - xmlFilePath_case = "../../../../../../../inputFiles/triaxialDriver/triaxialDriver_ExtendedDruckerPrager.xml" - imposedStrainFilePath = "../../../../../../../inputFiles/triaxialDriver/tables/axialStrain.geos" - imposedStressFilePath = "../../../../../../../inputFiles/triaxialDriver/tables/radialStress.geos" - - # Load GEOSX results - time, ax_strain, ra_strain1, ra_strain2, ax_stress, ra_stress1, ra_stress2, newton_iter, residual_norm = np.loadtxt( - path, skiprows=5, unpack=True) - - # Extract mechanical parameters from XML file - tree = ElementTree.parse(xmlFilePath) - tree_case = ElementTree.parse(xmlFilePath_case) - model = tree_case.find('Tasks/TriaxialDriver') - param = tree.find('Constitutive/ExtendedDruckerPrager') - - bulkModulus = float(param.get("defaultBulkModulus")) - shearModulus = float(param.get("defaultShearModulus")) - cohesion = float(param.get("defaultCohesion")) - initialFrictionAngle = float(param.get("defaultInitialFrictionAngle")) - residualFrictionAngle = float(param.get("defaultResidualFrictionAngle")) - hardeningParameter = float(param.get("defaultHardening")) - dilationRatio = float(param.get("defaultDilationRatio")) - initialStress = float(model.get("initialStress")) - - # Compute Lame modulus and Young modulus - lameModulus = bulkModulus - 2.0/3.0*shearModulus - youngModulus = 1.0 / ( 1.0/9.0/bulkModulus + 1.0/3.0/shearModulus ) - - # Friction and cohesion parameters - initialFrictionAngleRad = initialFrictionAngle * np.pi / 180.0 - cosInitialFrictionAngle = np.cos(initialFrictionAngleRad) - sinInitialFrictionAngle = np.sin(initialFrictionAngleRad) - a_init = 6.0*cohesion*cosInitialFrictionAngle / ( 3.0 - sinInitialFrictionAngle ) - b_init = 6.0*sinInitialFrictionAngle / ( 3.0 - sinInitialFrictionAngle ) - - residualFrictionAngleRad = residualFrictionAngle * np.pi / 180.0 - sinResidualFrictionAngle = np.sin(residualFrictionAngleRad) - b_resi = 6.0*sinResidualFrictionAngle/(3.0-sinResidualFrictionAngle) - - # Extract loading from input tables - imp_strain = np.loadtxt( - imposedStrainFilePath, skiprows=0, unpack=True) - - list_ax_strain_anal = [] - numStepPerLoadingPeriod = 1000 - - for i in range(0,len(imp_strain)-1): - dStrainPerStep = (imp_strain[i+1]-imp_strain[i])/numStepPerLoadingPeriod - loadingPeriod = np.arange(imp_strain[i],imp_strain[i+1]+dStrainPerStep,dStrainPerStep) - list_ax_strain_anal = np.concatenate((list_ax_strain_anal, loadingPeriod), axis=0) - - # Extract radial stress loading from input tables - imp_stress = np.loadtxt( - imposedStressFilePath, skiprows=0, unpack=True) - - list_ra_stress_anal = imp_stress[0]*np.ones(len(list_ax_strain_anal)) #constant radial confining stress - - # Initiate radial strain and axial stress arrays - list_ra_strain_anal = np.zeros(len(list_ax_strain_anal)) - list_ax_stress_anal = np.zeros(len(list_ax_strain_anal)) - list_ax_stress_anal[0] = initialStress - list_ra_strain_anal[0] = 0 - - - # Loop over the loading/unloading steps - plasticMultiplier = 0 - b = b_init - - for idx in range(1,len(list_ax_strain_anal)): - delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] - delta_ra_stress_anal = 0 # constant lateral confining stress - - # Elastic trial - delta_ra_strain_anal = ( delta_ra_stress_anal - lameModulus*delta_ax_strain_anal ) / ( 2.0*lameModulus + 2.0*shearModulus ) - delta_ax_stress_anal = ( lameModulus + 2.0*shearModulus )*delta_ax_strain_anal + lameModulus/( lameModulus + shearModulus )*( delta_ra_stress_anal - lameModulus*delta_ax_strain_anal ) - - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal - - # Compute mean and shear stresses - ra_stress_anal = list_ra_stress_anal[idx] - - p_anal = (ax_stress_anal + 2.0 * ra_stress_anal) / 3.0 - q_anal = -(ax_stress_anal - ra_stress_anal) - - # Plastic correction - if(q_anal>=0): #loading - - F_anal = q_anal + b*p_anal - b*a_init/b_init - - if(F_anal>=0): - b = b_init + plasticMultiplier/(hardeningParameter+plasticMultiplier) * (b_resi - b_init) - dF_db = p_anal - a_init/b_init - db_dlambda = hardeningParameter * (b_resi - b_init) / ( hardeningParameter + plasticMultiplier ) / ( hardeningParameter + plasticMultiplier ) - hardeningRate = -dF_db*db_dlambda - - # Elasto-plastic moduli for plastic yield during the loading period - plasticYoungModulus = 1.0 / ( 1.0/youngModulus + (b*dilationRatio-3.0)*(b-3.0)/9.0/hardeningRate ) - plasticModulusForRaStrain = 1.0 / ( 1.0/2.0/shearModulus - (b-3.0)/2.0/hardeningRate ) - - # Compute stress and strain variations - delta_ax_stress_anal = delta_ax_strain_anal*plasticYoungModulus - delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / plasticModulusForRaStrain - - # Compute stress and strain at actual loading step - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal - - # Update plastic multiplier - delta_lambda = (b-3.0)/3.0/hardeningRate*delta_ax_stress_anal - plasticMultiplier += delta_lambda - - else: #unloading - - F_anal = -q_anal + b*p_anal - b*a_init/b_init # negative sign added to q for q<0 to obtain the absolute value - - if(F_anal>=0): - b = b_init + plasticMultiplier/(hardeningParameter+plasticMultiplier) * (b_resi - b_init) - dF_db = p_anal - a_init/b_init - db_dlambda = hardeningParameter * (b_resi - b_init) / (hardeningParameter+plasticMultiplier) / (hardeningParameter+plasticMultiplier) - hardeningRate = -dF_db*db_dlambda - - # Elasto-plastic moduli for plastic yield during the unloading period - plasticYoungModulus_unload = 1.0/(1.0/youngModulus + (b*dilationRatio+3.0)*(b+3.0)/9.0/hardeningRate) - plasticModulusForRaStrain_unload = 1.0/(1.0/2.0/shearModulus + (b+3.0)/2.0/hardeningRate) - - # Compute stress and strain variations - delta_ax_stress_anal = delta_ax_strain_anal*plasticYoungModulus_unload - delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / plasticModulusForRaStrain_unload - - # Compute stress and strain at actual loading step - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal - - # Update plastic multiplier - delta_lambda = (b+3.0)/3.0/hardeningRate*delta_ax_stress_anal - plasticMultiplier += delta_lambda - - list_ax_stress_anal[idx] = ax_stress_anal - list_ra_strain_anal[idx] = ra_strain_anal - - # Preparing data for visualizing semi-analytical results - list_p_anal = -(list_ax_stress_anal + 2.0 * list_ra_stress_anal) / 3.0 - list_q_anal = -(list_ax_stress_anal - list_ra_stress_anal) - - list_strain_vol_anal = list_ax_strain_anal + 2.0 * list_ra_strain_anal - - p_num = -(ax_stress + 2.0 * ra_stress1) / 3.0 - q_num = -(ax_stress - ra_stress1) - - strain_vol = ax_strain + 2.0 * ra_strain1 - - #Visualization parameters - fsize = 30 - msize = 12 - lw = 6 - malpha = 0.5 - fig, ax = plt.subplots(1, 3, figsize=(37, 10)) - cmap = plt.get_cmap("tab10") - - # Plot strain versus shear stress - ax[0].plot(-ax_strain * 100, #convert to % - q_num*1e-6, #convert to MPa - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[0].plot(-ra_strain1 * 100, - q_num*1e-6, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha) - ax[0].plot(-list_ax_strain_anal* 100, - list_q_anal*1e-6, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[0].plot(-list_ra_strain_anal * 100, - list_q_anal*1e-6, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - linewidth=6) - ax[0].set_xlabel(r'Strain (%)', size=fsize, weight="bold") - ax[0].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") - #ax[0].legend(loc='lower right', fontsize=fsize) - ax[0].xaxis.set_tick_params(labelsize=fsize) - ax[0].yaxis.set_tick_params(labelsize=fsize) - - # Plot axial strain versus volumetric strain - ax[1].plot(-ax_strain * 100, - -strain_vol * 100, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[1].plot(-list_ax_strain_anal* 100, - -list_strain_vol_anal* 100, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[1].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") - ax[1].set_ylabel(r'Volumetric Strain (%)', size=fsize, weight="bold") - #ax[1].legend(loc='lower right', fontsize=fsize) - ax[1].xaxis.set_tick_params(labelsize=fsize) - ax[1].yaxis.set_tick_params(labelsize=fsize) - - - # Plot shear stress versus mean stress - ax[2].plot(p_num*1e-6, - q_num*1e-6, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[2].plot(list_p_anal*1e-6, - list_q_anal*1e-6, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[2].set_xlabel(r'Mean stress (MPa)', size=fsize, weight="bold") - ax[2].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") - ax[2].legend(loc='lower right', fontsize=fsize) - ax[2].xaxis.set_tick_params(labelsize=fsize) - ax[2].yaxis.set_tick_params(labelsize=fsize) - - plt.subplots_adjust(left=0.2, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4) - - plt.show() + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + + # File paths + outputDir = args.outputDir + geosDir = args.geosDir + path = outputDir + "/ExtendedDruckerPragerResults.txt" + xmlFilePath = geosDir + "/inputFiles/triaxialDriver/triaxialDriver_base.xml" + xmlFilePath_case = geosDir + "/inputFiles/triaxialDriver/triaxialDriver_ExtendedDruckerPrager.xml" + imposedStrainFilePath = geosDir + "/inputFiles/triaxialDriver/tables/axialStrain.geos" + imposedStressFilePath = geosDir + "/inputFiles/triaxialDriver/tables/radialStress.geos" + + # Load GEOSX results + time, ax_strain, ra_strain1, ra_strain2, ax_stress, ra_stress1, ra_stress2, newton_iter, residual_norm = np.loadtxt( + path, skiprows=5, unpack=True) + + # Extract mechanical parameters from XML file + tree = ElementTree.parse(xmlFilePath) + tree_case = ElementTree.parse(xmlFilePath_case) + model = tree_case.find('Tasks/TriaxialDriver') + param = tree.find('Constitutive/ExtendedDruckerPrager') + + bulkModulus = float(param.get("defaultBulkModulus")) + shearModulus = float(param.get("defaultShearModulus")) + cohesion = float(param.get("defaultCohesion")) + initialFrictionAngle = float(param.get("defaultInitialFrictionAngle")) + residualFrictionAngle = float(param.get("defaultResidualFrictionAngle")) + hardeningParameter = float(param.get("defaultHardening")) + dilationRatio = float(param.get("defaultDilationRatio")) + initialStress = float(model.get("initialStress")) + + # Compute Lame modulus and Young modulus + lameModulus = bulkModulus - 2.0/3.0*shearModulus + youngModulus = 1.0 / ( 1.0/9.0/bulkModulus + 1.0/3.0/shearModulus ) + + # Friction and cohesion parameters + initialFrictionAngleRad = initialFrictionAngle * np.pi / 180.0 + cosInitialFrictionAngle = np.cos(initialFrictionAngleRad) + sinInitialFrictionAngle = np.sin(initialFrictionAngleRad) + a_init = 6.0*cohesion*cosInitialFrictionAngle / ( 3.0 - sinInitialFrictionAngle ) + b_init = 6.0*sinInitialFrictionAngle / ( 3.0 - sinInitialFrictionAngle ) + + residualFrictionAngleRad = residualFrictionAngle * np.pi / 180.0 + sinResidualFrictionAngle = np.sin(residualFrictionAngleRad) + b_resi = 6.0*sinResidualFrictionAngle/(3.0-sinResidualFrictionAngle) + + # Extract loading from input tables + imp_strain = np.loadtxt( + imposedStrainFilePath, skiprows=0, unpack=True) + + list_ax_strain_anal = [] + numStepPerLoadingPeriod = 1000 + + for i in range(0,len(imp_strain)-1): + dStrainPerStep = (imp_strain[i+1]-imp_strain[i])/numStepPerLoadingPeriod + loadingPeriod = np.arange(imp_strain[i],imp_strain[i+1]+dStrainPerStep,dStrainPerStep) + list_ax_strain_anal = np.concatenate((list_ax_strain_anal, loadingPeriod), axis=0) + + # Extract radial stress loading from input tables + imp_stress = np.loadtxt( + imposedStressFilePath, skiprows=0, unpack=True) + + list_ra_stress_anal = imp_stress[0]*np.ones(len(list_ax_strain_anal)) #constant radial confining stress + + # Initiate radial strain and axial stress arrays + list_ra_strain_anal = np.zeros(len(list_ax_strain_anal)) + list_ax_stress_anal = np.zeros(len(list_ax_strain_anal)) + list_ax_stress_anal[0] = initialStress + list_ra_strain_anal[0] = 0 + + + # Loop over the loading/unloading steps + plasticMultiplier = 0 + b = b_init + + for idx in range(1,len(list_ax_strain_anal)): + delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] + delta_ra_stress_anal = 0 # constant lateral confining stress + + # Elastic trial + delta_ra_strain_anal = ( delta_ra_stress_anal - lameModulus*delta_ax_strain_anal ) / ( 2.0*lameModulus + 2.0*shearModulus ) + delta_ax_stress_anal = ( lameModulus + 2.0*shearModulus )*delta_ax_strain_anal + lameModulus/( lameModulus + shearModulus )*( delta_ra_stress_anal - lameModulus*delta_ax_strain_anal ) + + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal + + # Compute mean and shear stresses + ra_stress_anal = list_ra_stress_anal[idx] + + p_anal = (ax_stress_anal + 2.0 * ra_stress_anal) / 3.0 + q_anal = -(ax_stress_anal - ra_stress_anal) + + # Plastic correction + if(q_anal>=0): #loading + + F_anal = q_anal + b*p_anal - b*a_init/b_init + + if(F_anal>=0): + b = b_init + plasticMultiplier/(hardeningParameter+plasticMultiplier) * (b_resi - b_init) + dF_db = p_anal - a_init/b_init + db_dlambda = hardeningParameter * (b_resi - b_init) / ( hardeningParameter + plasticMultiplier ) / ( hardeningParameter + plasticMultiplier ) + hardeningRate = -dF_db*db_dlambda + + # Elasto-plastic moduli for plastic yield during the loading period + plasticYoungModulus = 1.0 / ( 1.0/youngModulus + (b*dilationRatio-3.0)*(b-3.0)/9.0/hardeningRate ) + plasticModulusForRaStrain = 1.0 / ( 1.0/2.0/shearModulus - (b-3.0)/2.0/hardeningRate ) + + # Compute stress and strain variations + delta_ax_stress_anal = delta_ax_strain_anal*plasticYoungModulus + delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / plasticModulusForRaStrain + + # Compute stress and strain at actual loading step + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal + + # Update plastic multiplier + delta_lambda = (b-3.0)/3.0/hardeningRate*delta_ax_stress_anal + plasticMultiplier += delta_lambda + + else: #unloading + + F_anal = -q_anal + b*p_anal - b*a_init/b_init # negative sign added to q for q<0 to obtain the absolute value + + if(F_anal>=0): + b = b_init + plasticMultiplier/(hardeningParameter+plasticMultiplier) * (b_resi - b_init) + dF_db = p_anal - a_init/b_init + db_dlambda = hardeningParameter * (b_resi - b_init) / (hardeningParameter+plasticMultiplier) / (hardeningParameter+plasticMultiplier) + hardeningRate = -dF_db*db_dlambda + + # Elasto-plastic moduli for plastic yield during the unloading period + plasticYoungModulus_unload = 1.0/(1.0/youngModulus + (b*dilationRatio+3.0)*(b+3.0)/9.0/hardeningRate) + plasticModulusForRaStrain_unload = 1.0/(1.0/2.0/shearModulus + (b+3.0)/2.0/hardeningRate) + + # Compute stress and strain variations + delta_ax_stress_anal = delta_ax_strain_anal*plasticYoungModulus_unload + delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / plasticModulusForRaStrain_unload + + # Compute stress and strain at actual loading step + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal + + # Update plastic multiplier + delta_lambda = (b+3.0)/3.0/hardeningRate*delta_ax_stress_anal + plasticMultiplier += delta_lambda + + list_ax_stress_anal[idx] = ax_stress_anal + list_ra_strain_anal[idx] = ra_strain_anal + + # Preparing data for visualizing semi-analytical results + list_p_anal = -(list_ax_stress_anal + 2.0 * list_ra_stress_anal) / 3.0 + list_q_anal = -(list_ax_stress_anal - list_ra_stress_anal) + + list_strain_vol_anal = list_ax_strain_anal + 2.0 * list_ra_strain_anal + + p_num = -(ax_stress + 2.0 * ra_stress1) / 3.0 + q_num = -(ax_stress - ra_stress1) + + strain_vol = ax_strain + 2.0 * ra_strain1 + + #Visualization parameters + fsize = 30 + msize = 12 + lw = 6 + malpha = 0.5 + fig, ax = plt.subplots(1, 3, figsize=(37, 10)) + cmap = plt.get_cmap("tab10") + + # Plot strain versus shear stress + ax[0].plot(-ax_strain * 100, #convert to % + q_num*1e-6, #convert to MPa + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[0].plot(-ra_strain1 * 100, + q_num*1e-6, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha) + ax[0].plot(-list_ax_strain_anal* 100, + list_q_anal*1e-6, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[0].plot(-list_ra_strain_anal * 100, + list_q_anal*1e-6, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + linewidth=6) + ax[0].set_xlabel(r'Strain (%)', size=fsize, weight="bold") + ax[0].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") + #ax[0].legend(loc='lower right', fontsize=fsize) + ax[0].xaxis.set_tick_params(labelsize=fsize) + ax[0].yaxis.set_tick_params(labelsize=fsize) + + # Plot axial strain versus volumetric strain + ax[1].plot(-ax_strain * 100, + -strain_vol * 100, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[1].plot(-list_ax_strain_anal* 100, + -list_strain_vol_anal* 100, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[1].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") + ax[1].set_ylabel(r'Volumetric Strain (%)', size=fsize, weight="bold") + #ax[1].legend(loc='lower right', fontsize=fsize) + ax[1].xaxis.set_tick_params(labelsize=fsize) + ax[1].yaxis.set_tick_params(labelsize=fsize) + + + # Plot shear stress versus mean stress + ax[2].plot(p_num*1e-6, + q_num*1e-6, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[2].plot(list_p_anal*1e-6, + list_q_anal*1e-6, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[2].set_xlabel(r'Mean stress (MPa)', size=fsize, weight="bold") + ax[2].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") + ax[2].legend(loc='lower right', fontsize=fsize) + ax[2].xaxis.set_tick_params(labelsize=fsize) + ax[2].yaxis.set_tick_params(labelsize=fsize) + + plt.subplots_adjust(left=0.2, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4) + + plt.show() if __name__ == "__main__": main() diff --git a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ModifiedCamClay/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ModifiedCamClay/Example.rst index b9c3d9a3a09..48760a4f70d 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ModifiedCamClay/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ModifiedCamClay/Example.rst @@ -97,4 +97,4 @@ To go further **Feedback on this example** -For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. +For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. diff --git a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ModifiedCamClay/TriaxialDriver_vs_SemiAnalytic_ModifiedCamClay.py b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ModifiedCamClay/TriaxialDriver_vs_SemiAnalytic_ModifiedCamClay.py index d87be34dcad..440c44b3474 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ModifiedCamClay/TriaxialDriver_vs_SemiAnalytic_ModifiedCamClay.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ModifiedCamClay/TriaxialDriver_vs_SemiAnalytic_ModifiedCamClay.py @@ -3,206 +3,221 @@ import numpy as np import matplotlib.pyplot as plt import xml.etree.ElementTree as ElementTree +import os +import argparse def main(): - # File paths - path = "ModifiedCamClayResults.txt" - xmlFilePath = "../../../../../../../inputFiles/triaxialDriver/triaxialDriver_base.xml" - xmlFilePath_case = "../../../../../../../inputFiles/triaxialDriver/triaxialDriver_ModifiedCamClay.xml" - imposedStrainFilePath = "../../../../../../../inputFiles/triaxialDriver/tables/axialStrain.geos" - - # Load GEOSX results - time, ax_strain, ra_strain1, ra_strain2, ax_stress, ra_stress1, ra_stress2, newton_iter, residual_norm = np.loadtxt( - path, skiprows=5, unpack=True) - - # Extract mechanical parameters from XML file - tree = ElementTree.parse(xmlFilePath) - tree_case = ElementTree.parse(xmlFilePath_case) - model = tree_case.find('Tasks/TriaxialDriver') - param = tree.find('Constitutive/ModifiedCamClay') - - refPressure = float(param.get("defaultRefPressure")) - refStrainVol = float(param.get("defaultRefStrainVol")) - shearModulus = float(param.get("defaultShearModulus")) - preConsolidationPressure = float(param.get("defaultPreConsolidationPressure")) - cslSlope = float(param.get("defaultCslSlope")) - virginCompressionIndex = float(param.get("defaultVirginCompressionIndex")) - recompressionIndex = float(param.get("defaultRecompressionIndex")) - initialStress = float(model.get("initialStress")) - - # Extract loading from input tables - imp_strain = np.loadtxt( - imposedStrainFilePath, skiprows=0, unpack=True) - - list_ax_strain_anal = [] - numStepPerLoadingPeriod = 10000 - - for i in range(0,len(imp_strain)-1): - dStrainPerStep = (imp_strain[i+1]-imp_strain[i])/numStepPerLoadingPeriod - loadingPeriod = np.arange(imp_strain[i],imp_strain[i+1]+dStrainPerStep,dStrainPerStep) - list_ax_strain_anal = np.concatenate((list_ax_strain_anal, loadingPeriod), axis=0) - - list_ax_stress_anal = np.zeros(len(list_ax_strain_anal)) - list_ra_stress_anal = np.zeros(len(list_ax_strain_anal)) - list_ra_strain_anal = np.zeros(len(list_ax_strain_anal)) - - p_anal = refPressure - list_ax_strain_anal += refStrainVol # Oedometric compaction: zero lateral strain - list_ax_stress_anal += initialStress # Assuming isotropic initial stress condition - list_ra_stress_anal += initialStress - - for idx in range(1,len(list_ax_strain_anal)): - delta_ax_strain_anal = list_ax_strain_anal[idx]-list_ax_strain_anal[idx-1] - delta_ra_strain_anal = 0 - - # Compute elastic moduli - bulkModulus = - p_anal/recompressionIndex - lameModulus = bulkModulus - 2.0/3.0*shearModulus - - # Elastic trial - delta_ax_stress_anal = (lameModulus+2.0*shearModulus)*delta_ax_strain_anal + 2.0*lameModulus*delta_ra_strain_anal - delta_ra_stress_anal = lameModulus*delta_ax_strain_anal + (2.0*lameModulus+2.0*shearModulus)*delta_ra_strain_anal - - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_stress_anal = list_ra_stress_anal[idx-1] + delta_ra_stress_anal - - p_anal = (ax_stress_anal + 2.0*ra_stress_anal)/3.0 - q_anal = -(ax_stress_anal - ra_stress_anal) - - # Plastic correction - F_anal = q_anal*q_anal + cslSlope*cslSlope*p_anal*(p_anal-preConsolidationPressure) - - if(F_anal>=0): - # Derivatives - dF_dp = cslSlope*cslSlope*(2.0*p_anal-preConsolidationPressure) - dF_dq = 2.0*q_anal - dF_dpc = -cslSlope*cslSlope*p_anal - - dG_dp = dF_dp # associated plastic rule was considered - dG_dq = dF_dq - - dpc_dlambda = -preConsolidationPressure/(virginCompressionIndex-recompressionIndex)*dG_dp - hardeningRate = -dF_dpc*dpc_dlambda - - # Elasto-plastic coefficients - coeff_1 = 1.0/bulkModulus + dG_dp*dF_dp/hardeningRate - coeff_2 = dG_dp*dF_dq/hardeningRate - coeff_3 = 3.0/2.0*dG_dq*dF_dp/hardeningRate - coeff_4 = 1.0/2.0/shearModulus + 3.0/2.0*dG_dq*dF_dq/hardeningRate - denom = coeff_1*coeff_4 - coeff_2*coeff_3 - - # Compute stress variations - delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] - - delta_strain_vol = delta_ax_strain_anal - delta_strain_shear = -delta_ax_strain_anal - delta_p_anal = (coeff_4*delta_strain_vol - coeff_2*delta_strain_shear)/denom - delta_q_anal = (coeff_1*delta_strain_shear - coeff_3*delta_strain_vol)/denom - - delta_ax_stress_anal = (3.0*delta_p_anal-2*delta_q_anal)/3.0 - delta_ra_stress_anal = delta_ax_stress_anal+delta_q_anal - - # Update stress - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_stress_anal = list_ra_stress_anal[idx-1] + delta_ra_stress_anal - - delta_lambda = (dF_dq*delta_q_anal + dF_dp*delta_p_anal)/hardeningRate - delta_pc = dpc_dlambda * delta_lambda - preConsolidationPressure += delta_pc - - p_anal = (ax_stress_anal + 2.0*ra_stress_anal)/3.0 - q_anal = -(ax_stress_anal - ra_stress_anal) - - list_ax_stress_anal[idx] = ax_stress_anal - list_ra_stress_anal[idx] = ra_stress_anal - - list_p_anal = (list_ax_stress_anal + 2.0 * list_ra_stress_anal) / 3.0 - list_q_anal = -(list_ax_stress_anal - list_ra_stress_anal) - - list_strain_vol_anal = list_ax_strain_anal + 2.0 * list_ra_strain_anal - - p_num = (ax_stress + 2.0 * ra_stress1) / 3.0 - q_num = -(ax_stress - ra_stress1) - - #Visualization parameters - fsize = 30 - msize = 12 - lw = 6 - malpha = 0.5 - fig, ax = plt.subplots(1, 3, figsize=(37, 10)) - cmap = plt.get_cmap("tab10") - - ax[0].plot(-ax_strain * 100, #convert to % - -ax_stress*1e-3, #convert to kPa - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[0].plot(-list_ax_strain_anal* 100, - -list_ax_stress_anal*1e-3, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - - ax[0].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") - ax[0].set_ylabel(r'Axial Stress (kPa)', size=fsize, weight="bold") - #ax[0].legend(loc='lower right', fontsize=fsize) - ax[0].xaxis.set_tick_params(labelsize=fsize) - ax[0].yaxis.set_tick_params(labelsize=fsize) - - ax[1].plot(-ax_strain * 100, - -ra_stress1 * 1e-3, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[1].plot(-list_ax_strain_anal* 100, - -list_ra_stress_anal* 1e-3, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[1].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") - ax[1].set_ylabel(r'Radial stress (kPa)', size=fsize, weight="bold") - #ax[1].legend(loc='lower right', fontsize=fsize) - ax[1].xaxis.set_tick_params(labelsize=fsize) - ax[1].yaxis.set_tick_params(labelsize=fsize) - - # Plan p-q - ax[2].plot(-p_num*1e-3, - q_num*1e-3, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[2].plot(-list_p_anal*1e-3, - list_q_anal*1e-3, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[2].set_xlabel(r'Mean stress (kPa)', size=fsize, weight="bold") - ax[2].set_ylabel(r'Deviatoric Stress (kPa)', size=fsize, weight="bold") - ax[2].legend(loc='lower right', fontsize=fsize) - ax[2].xaxis.set_tick_params(labelsize=fsize) - ax[2].yaxis.set_tick_params(labelsize=fsize) - - plt.subplots_adjust(left=0.2, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4) - - plt.show() - + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + + # File paths + outputDir = args.outputDir + geosDir = args.geosDir + path = outputDir + "/ModifiedCamClayResults.txt" + xmlFilePath = geosDir + "/inputFiles/triaxialDriver/triaxialDriver_base.xml" + xmlFilePath_case = geosDir + "/inputFiles/triaxialDriver/triaxialDriver_ModifiedCamClay.xml" + imposedStrainFilePath = geosDir + "/inputFiles/triaxialDriver/tables/axialStrain.geos" + + # Load GEOSX results + time, ax_strain, ra_strain1, ra_strain2, ax_stress, ra_stress1, ra_stress2, newton_iter, residual_norm = np.loadtxt( + path, skiprows=5, unpack=True) + + # Extract mechanical parameters from XML file + tree = ElementTree.parse(xmlFilePath) + tree_case = ElementTree.parse(xmlFilePath_case) + model = tree_case.find('Tasks/TriaxialDriver') + param = tree.find('Constitutive/ModifiedCamClay') + + refPressure = float(param.get("defaultRefPressure")) + refStrainVol = float(param.get("defaultRefStrainVol")) + shearModulus = float(param.get("defaultShearModulus")) + preConsolidationPressure = float(param.get("defaultPreConsolidationPressure")) + cslSlope = float(param.get("defaultCslSlope")) + virginCompressionIndex = float(param.get("defaultVirginCompressionIndex")) + recompressionIndex = float(param.get("defaultRecompressionIndex")) + initialStress = float(model.get("initialStress")) + + # Extract loading from input tables + imp_strain = np.loadtxt( + imposedStrainFilePath, skiprows=0, unpack=True) + + list_ax_strain_anal = [] + numStepPerLoadingPeriod = 10000 + + for i in range(0,len(imp_strain)-1): + dStrainPerStep = (imp_strain[i+1]-imp_strain[i])/numStepPerLoadingPeriod + loadingPeriod = np.arange(imp_strain[i],imp_strain[i+1]+dStrainPerStep,dStrainPerStep) + list_ax_strain_anal = np.concatenate((list_ax_strain_anal, loadingPeriod), axis=0) + + list_ax_stress_anal = np.zeros(len(list_ax_strain_anal)) + list_ra_stress_anal = np.zeros(len(list_ax_strain_anal)) + list_ra_strain_anal = np.zeros(len(list_ax_strain_anal)) + + p_anal = refPressure + list_ax_strain_anal += refStrainVol # Oedometric compaction: zero lateral strain + list_ax_stress_anal += initialStress # Assuming isotropic initial stress condition + list_ra_stress_anal += initialStress + + for idx in range(1,len(list_ax_strain_anal)): + delta_ax_strain_anal = list_ax_strain_anal[idx]-list_ax_strain_anal[idx-1] + delta_ra_strain_anal = 0 + + # Compute elastic moduli + bulkModulus = - p_anal/recompressionIndex + lameModulus = bulkModulus - 2.0/3.0*shearModulus + + # Elastic trial + delta_ax_stress_anal = (lameModulus+2.0*shearModulus)*delta_ax_strain_anal + 2.0*lameModulus*delta_ra_strain_anal + delta_ra_stress_anal = lameModulus*delta_ax_strain_anal + (2.0*lameModulus+2.0*shearModulus)*delta_ra_strain_anal + + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_stress_anal = list_ra_stress_anal[idx-1] + delta_ra_stress_anal + + p_anal = (ax_stress_anal + 2.0*ra_stress_anal)/3.0 + q_anal = -(ax_stress_anal - ra_stress_anal) + + # Plastic correction + F_anal = q_anal*q_anal + cslSlope*cslSlope*p_anal*(p_anal-preConsolidationPressure) + + if(F_anal>=0): + # Derivatives + dF_dp = cslSlope*cslSlope*(2.0*p_anal-preConsolidationPressure) + dF_dq = 2.0*q_anal + dF_dpc = -cslSlope*cslSlope*p_anal + + dG_dp = dF_dp # associated plastic rule was considered + dG_dq = dF_dq + + dpc_dlambda = -preConsolidationPressure/(virginCompressionIndex-recompressionIndex)*dG_dp + hardeningRate = -dF_dpc*dpc_dlambda + + # Elasto-plastic coefficients + coeff_1 = 1.0/bulkModulus + dG_dp*dF_dp/hardeningRate + coeff_2 = dG_dp*dF_dq/hardeningRate + coeff_3 = 3.0/2.0*dG_dq*dF_dp/hardeningRate + coeff_4 = 1.0/2.0/shearModulus + 3.0/2.0*dG_dq*dF_dq/hardeningRate + denom = coeff_1*coeff_4 - coeff_2*coeff_3 + + # Compute stress variations + delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] + + delta_strain_vol = delta_ax_strain_anal + delta_strain_shear = -delta_ax_strain_anal + delta_p_anal = (coeff_4*delta_strain_vol - coeff_2*delta_strain_shear)/denom + delta_q_anal = (coeff_1*delta_strain_shear - coeff_3*delta_strain_vol)/denom + + delta_ax_stress_anal = (3.0*delta_p_anal-2*delta_q_anal)/3.0 + delta_ra_stress_anal = delta_ax_stress_anal+delta_q_anal + + # Update stress + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_stress_anal = list_ra_stress_anal[idx-1] + delta_ra_stress_anal + + delta_lambda = (dF_dq*delta_q_anal + dF_dp*delta_p_anal)/hardeningRate + delta_pc = dpc_dlambda * delta_lambda + preConsolidationPressure += delta_pc + + p_anal = (ax_stress_anal + 2.0*ra_stress_anal)/3.0 + q_anal = -(ax_stress_anal - ra_stress_anal) + + list_ax_stress_anal[idx] = ax_stress_anal + list_ra_stress_anal[idx] = ra_stress_anal + + list_p_anal = (list_ax_stress_anal + 2.0 * list_ra_stress_anal) / 3.0 + list_q_anal = -(list_ax_stress_anal - list_ra_stress_anal) + + list_strain_vol_anal = list_ax_strain_anal + 2.0 * list_ra_strain_anal + + p_num = (ax_stress + 2.0 * ra_stress1) / 3.0 + q_num = -(ax_stress - ra_stress1) + + #Visualization parameters + fsize = 30 + msize = 12 + lw = 6 + malpha = 0.5 + fig, ax = plt.subplots(1, 3, figsize=(37, 10)) + cmap = plt.get_cmap("tab10") + + ax[0].plot(-ax_strain * 100, #convert to % + -ax_stress*1e-3, #convert to kPa + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[0].plot(-list_ax_strain_anal* 100, + -list_ax_stress_anal*1e-3, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + + ax[0].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") + ax[0].set_ylabel(r'Axial Stress (kPa)', size=fsize, weight="bold") + #ax[0].legend(loc='lower right', fontsize=fsize) + ax[0].xaxis.set_tick_params(labelsize=fsize) + ax[0].yaxis.set_tick_params(labelsize=fsize) + + ax[1].plot(-ax_strain * 100, + -ra_stress1 * 1e-3, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[1].plot(-list_ax_strain_anal* 100, + -list_ra_stress_anal* 1e-3, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[1].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") + ax[1].set_ylabel(r'Radial stress (kPa)', size=fsize, weight="bold") + #ax[1].legend(loc='lower right', fontsize=fsize) + ax[1].xaxis.set_tick_params(labelsize=fsize) + ax[1].yaxis.set_tick_params(labelsize=fsize) + + # Plan p-q + ax[2].plot(-p_num*1e-3, + q_num*1e-3, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[2].plot(-list_p_anal*1e-3, + list_q_anal*1e-3, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[2].set_xlabel(r'Mean stress (kPa)', size=fsize, weight="bold") + ax[2].set_ylabel(r'Deviatoric Stress (kPa)', size=fsize, weight="bold") + ax[2].legend(loc='lower right', fontsize=fsize) + ax[2].xaxis.set_tick_params(labelsize=fsize) + ax[2].yaxis.set_tick_params(labelsize=fsize) + + plt.subplots_adjust(left=0.2, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4) + + plt.show() + if __name__ == "__main__": main() diff --git a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/RelaxationTest/relaxationTestFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/RelaxationTest/relaxationTestFigure.py index 842855692f8..abb10fdcaac 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/RelaxationTest/relaxationTestFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/RelaxationTest/relaxationTestFigure.py @@ -5,305 +5,320 @@ import xml.etree.ElementTree as ElementTree from math import sin,cos,tan,exp,atan import h5py +import os +import argparse def getMechanicalParametersFromXML( xmlFilePath ): - tree = ElementTree.parse(xmlFilePath) + tree = ElementTree.parse(xmlFilePath) - param = tree.find('Constitutive/ViscoExtendedDruckerPrager') + param = tree.find('Constitutive/ViscoExtendedDruckerPrager') - mechanicalParameters = dict.fromkeys(["bulkModulus", "shearModulus", "cohesion", "initialFrictionAngle", "residualFrictionAngle", "dilationRatio", "hardening", "relaxationTime"]) - mechanicalParameters["bulkModulus"] = float(param.get("defaultBulkModulus")) - mechanicalParameters["shearModulus"] = float(param.get("defaultShearModulus")) - mechanicalParameters["cohesion"] = float(param.get("defaultCohesion")) - mechanicalParameters["initialFrictionAngle"] = float(param.get("defaultInitialFrictionAngle")) - mechanicalParameters["residualFrictionAngle"] = float(param.get("defaultResidualFrictionAngle")) - mechanicalParameters["dilationRatio"] = float(param.get("defaultDilationRatio")) - mechanicalParameters["hardening"] = float(param.get("defaultHardening")) - mechanicalParameters["relaxationTime"] = float(param.get("relaxationTime")) + mechanicalParameters = dict.fromkeys(["bulkModulus", "shearModulus", "cohesion", "initialFrictionAngle", "residualFrictionAngle", "dilationRatio", "hardening", "relaxationTime"]) + mechanicalParameters["bulkModulus"] = float(param.get("defaultBulkModulus")) + mechanicalParameters["shearModulus"] = float(param.get("defaultShearModulus")) + mechanicalParameters["cohesion"] = float(param.get("defaultCohesion")) + mechanicalParameters["initialFrictionAngle"] = float(param.get("defaultInitialFrictionAngle")) + mechanicalParameters["residualFrictionAngle"] = float(param.get("defaultResidualFrictionAngle")) + mechanicalParameters["dilationRatio"] = float(param.get("defaultDilationRatio")) + mechanicalParameters["hardening"] = float(param.get("defaultHardening")) + mechanicalParameters["relaxationTime"] = float(param.get("relaxationTime")) - return mechanicalParameters + return mechanicalParameters def getLoadingFromXML(xmlFilePath): - tree = ElementTree.parse(xmlFilePath) + tree = ElementTree.parse(xmlFilePath) - param = tree.findall('FieldSpecifications/FieldSpecification') - - for elem in param: - if elem.get("name") == "stressZZ" and elem.get("initialCondition") == "1": - initialStress = float(elem.get("scale")) + param = tree.findall('FieldSpecifications/FieldSpecification') + + for elem in param: + if elem.get("name") == "stressZZ" and elem.get("initialCondition") == "1": + initialStress = float(elem.get("scale")) - elif elem.get("name") == "axialload" and elem.get("fieldName") == "totalDisplacement": - strainScale = float(elem.get("scale")) + elif elem.get("name") == "axialload" and elem.get("fieldName") == "totalDisplacement": + strainScale = float(elem.get("scale")) - param1 = tree.find('Functions/TableFunction') - if param1.get("name") == "timeFunction" and param1.get("inputVarNames") == "{ time }": - load = param1.get("values") - load = [float(i)*strainScale for i in load[1:-1].split(",")] - loadTime = param1.get("coordinates") - loadTime = [float(i) for i in loadTime[1:-1].split(",")] + param1 = tree.find('Functions/TableFunction') + if param1.get("name") == "timeFunction" and param1.get("inputVarNames") == "{ time }": + load = param1.get("values") + load = [float(i)*strainScale for i in load[1:-1].split(",")] + loadTime = param1.get("coordinates") + loadTime = [float(i) for i in loadTime[1:-1].split(",")] - return initialStress, load, loadTime + return initialStress, load, loadTime def semiAnalytical( mechanicalParameters, imp_strain, imp_time, initialStress ): - bulkModulus = mechanicalParameters["bulkModulus"] - shearModulus = mechanicalParameters["shearModulus"] - cohesion = mechanicalParameters["cohesion"] - dilationRatio = mechanicalParameters["dilationRatio"] - hardeningParameter = mechanicalParameters["hardening"] - relaxationTime = mechanicalParameters["relaxationTime"] - # Compute Lame modulus and Young modulus - lameModulus = bulkModulus - 2.0/3.0*shearModulus - youngModulus = 1.0/(1.0/9.0/bulkModulus + 1.0/3.0/shearModulus) - - # Initial friction and cohesion parameters - initialFrictionAngleRad = mechanicalParameters["initialFrictionAngle"]*np.pi/180.0 - cosInitialFrictionAngle = np.cos(initialFrictionAngleRad) - sinInitialFrictionAngle = np.sin(initialFrictionAngleRad) - a_init = 6.0*cohesion*cosInitialFrictionAngle/(3.0-sinInitialFrictionAngle) - b_init = 6.0*sinInitialFrictionAngle/(3.0-sinInitialFrictionAngle) - - # Residual friction parameters - residualFrictionAngleRad = mechanicalParameters["residualFrictionAngle"]*np.pi/180.0 - sinResidualFrictionAngle = np.sin(residualFrictionAngleRad) - b_resi = 6.0*sinResidualFrictionAngle/(3.0-sinResidualFrictionAngle) - - list_ax_strain_anal = [] - numStepPerLoadingPeriod = 1000 - - for i in range(0,len(imp_strain)-1): - loadingPeriod = np.linspace(imp_strain[i],imp_strain[i+1], numStepPerLoadingPeriod, endpoint=False) - list_ax_strain_anal = np.concatenate((list_ax_strain_anal, loadingPeriod), axis=0) - - list_time_anal = [] - for i in range(0,len(imp_time)-1): - timePeriod = np.linspace(imp_time[i],imp_time[i+1], numStepPerLoadingPeriod, endpoint=False) - list_time_anal = np.concatenate((list_time_anal, timePeriod), axis=0) - - list_ra_stress_anal = initialStress*np.ones(len(list_ax_strain_anal)) #constant radial confining stress - - # Initiate radial strain and axial stress arrays - list_ra_strain_anal = np.zeros(len(list_ax_strain_anal)) - list_ax_stress_anal = np.zeros(len(list_ax_strain_anal)) - list_ax_stress_anal[0] = initialStress - - # Loop over the loading/unloading steps - list_ra_strain_anal[0] = 0 - plasticMultiplier = 0 - b = b_init - - for idx in range(1,len(list_ax_strain_anal)): - delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] - delta_time_anal = list_time_anal[idx]-list_time_anal[idx-1] - delta_ra_stress_anal = 0 - - # Elastic trial - delta_ra_strain_anal = (delta_ra_stress_anal-lameModulus*delta_ax_strain_anal)/(2.0*lameModulus+2.0*shearModulus) - delta_ax_stress_anal = (lameModulus+2.0*shearModulus)*delta_ax_strain_anal + lameModulus/(lameModulus+shearModulus)*(delta_ra_stress_anal-lameModulus*delta_ax_strain_anal) - - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal - - # Compute mean and shear stresses - ra_stress_anal = list_ra_stress_anal[idx] - p_anal = (ax_stress_anal + 2.0 * ra_stress_anal) / 3.0 - q_anal = -(ax_stress_anal - ra_stress_anal) - - # Plastic correction - if(q_anal>=0): #loading - - F_anal = q_anal + b*p_anal - b*a_init/b_init - - if(F_anal>=0): - - b = b_init + plasticMultiplier/(hardeningParameter+plasticMultiplier) * (b_resi - b_init) - b_dilation = b*dilationRatio - - dF_db = p_anal - a_init/b_init - db_dlambda = hardeningParameter * (b_resi - b_init) / (hardeningParameter+plasticMultiplier) / (hardeningParameter+plasticMultiplier) - hardeningRate = -dF_db*db_dlambda - - # Variation of Perzyna plastic multiplier, see Runesson et al. 1999, see Eq. 56, 4, 80, 62, 63 - parameter_Aep = 3.0*shearModulus + bulkModulus*b*b_dilation + hardeningRate - delta_lambda = delta_time_anal / relaxationTime * (F_anal/parameter_Aep) - - # Compute stress and strain variations - delta_ax_stress_anal = ( delta_ax_strain_anal-delta_lambda*(b_dilation-3.0)/3.0 ) * youngModulus - delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / 2.0 / shearModulus + 3.0/2.0*delta_lambda - - # Compute stress and strain at actual loading step - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal - - # Update plastic multiplier - plasticMultiplier += delta_lambda - - else: #unloading - - F_anal = -q_anal + b*p_anal - b*a_init/b_init # negative sign added to q for q<0 to obtain the absolute value - - if(F_anal>=0): - b = b_init + plasticMultiplier/(hardeningParameter+plasticMultiplier) * (b_resi - b_init) - b_dilation = b*dilationRatio - - dF_db = p_anal - a_init/b_init - db_dlambda = hardeningParameter * (b_resi - b_init) / (hardeningParameter+plasticMultiplier) / (hardeningParameter+plasticMultiplier) - hardeningRate = -dF_db*db_dlambda - - # Variation of Perzyna plastic multiplier, see Runesson et al. 1999, see Eq. 56, 4, 80, 62, 63 - parameter_Aep = 3.0*shearModulus + bulkModulus*b*b_dilation + hardeningRate - delta_lambda = delta_time_anal / relaxationTime * (F_anal/parameter_Aep) - - # Compute stress and strain variations - delta_ax_stress_anal = ( delta_ax_strain_anal-delta_lambda*(b_dilation+3.0)/3.0 ) * youngModulus - delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / 2.0 / shearModulus - 3.0/2.0*delta_lambda - - # Compute stress and strain at actual loading step - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal - - # Update plastic multiplier - plasticMultiplier += delta_lambda - - list_ax_stress_anal[idx] = ax_stress_anal - list_ra_strain_anal[idx] = ra_strain_anal - - # Preparing data for visualizing semi-analytical results - list_p_anal = (list_ax_stress_anal + 2.0 * list_ra_stress_anal) / 3.0 - list_q_anal = -(list_ax_stress_anal - list_ra_stress_anal) - - return list_ax_stress_anal,list_time_anal,list_ax_strain_anal,list_ra_strain_anal,list_p_anal,list_q_anal + bulkModulus = mechanicalParameters["bulkModulus"] + shearModulus = mechanicalParameters["shearModulus"] + cohesion = mechanicalParameters["cohesion"] + dilationRatio = mechanicalParameters["dilationRatio"] + hardeningParameter = mechanicalParameters["hardening"] + relaxationTime = mechanicalParameters["relaxationTime"] + # Compute Lame modulus and Young modulus + lameModulus = bulkModulus - 2.0/3.0*shearModulus + youngModulus = 1.0/(1.0/9.0/bulkModulus + 1.0/3.0/shearModulus) + + # Initial friction and cohesion parameters + initialFrictionAngleRad = mechanicalParameters["initialFrictionAngle"]*np.pi/180.0 + cosInitialFrictionAngle = np.cos(initialFrictionAngleRad) + sinInitialFrictionAngle = np.sin(initialFrictionAngleRad) + a_init = 6.0*cohesion*cosInitialFrictionAngle/(3.0-sinInitialFrictionAngle) + b_init = 6.0*sinInitialFrictionAngle/(3.0-sinInitialFrictionAngle) + + # Residual friction parameters + residualFrictionAngleRad = mechanicalParameters["residualFrictionAngle"]*np.pi/180.0 + sinResidualFrictionAngle = np.sin(residualFrictionAngleRad) + b_resi = 6.0*sinResidualFrictionAngle/(3.0-sinResidualFrictionAngle) + + list_ax_strain_anal = [] + numStepPerLoadingPeriod = 1000 + + for i in range(0,len(imp_strain)-1): + loadingPeriod = np.linspace(imp_strain[i],imp_strain[i+1], numStepPerLoadingPeriod, endpoint=False) + list_ax_strain_anal = np.concatenate((list_ax_strain_anal, loadingPeriod), axis=0) + + list_time_anal = [] + for i in range(0,len(imp_time)-1): + timePeriod = np.linspace(imp_time[i],imp_time[i+1], numStepPerLoadingPeriod, endpoint=False) + list_time_anal = np.concatenate((list_time_anal, timePeriod), axis=0) + + list_ra_stress_anal = initialStress*np.ones(len(list_ax_strain_anal)) #constant radial confining stress + + # Initiate radial strain and axial stress arrays + list_ra_strain_anal = np.zeros(len(list_ax_strain_anal)) + list_ax_stress_anal = np.zeros(len(list_ax_strain_anal)) + list_ax_stress_anal[0] = initialStress + + # Loop over the loading/unloading steps + list_ra_strain_anal[0] = 0 + plasticMultiplier = 0 + b = b_init + + for idx in range(1,len(list_ax_strain_anal)): + delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] + delta_time_anal = list_time_anal[idx]-list_time_anal[idx-1] + delta_ra_stress_anal = 0 + + # Elastic trial + delta_ra_strain_anal = (delta_ra_stress_anal-lameModulus*delta_ax_strain_anal)/(2.0*lameModulus+2.0*shearModulus) + delta_ax_stress_anal = (lameModulus+2.0*shearModulus)*delta_ax_strain_anal + lameModulus/(lameModulus+shearModulus)*(delta_ra_stress_anal-lameModulus*delta_ax_strain_anal) + + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal + + # Compute mean and shear stresses + ra_stress_anal = list_ra_stress_anal[idx] + p_anal = (ax_stress_anal + 2.0 * ra_stress_anal) / 3.0 + q_anal = -(ax_stress_anal - ra_stress_anal) + + # Plastic correction + if(q_anal>=0): #loading + + F_anal = q_anal + b*p_anal - b*a_init/b_init + + if(F_anal>=0): + + b = b_init + plasticMultiplier/(hardeningParameter+plasticMultiplier) * (b_resi - b_init) + b_dilation = b*dilationRatio + + dF_db = p_anal - a_init/b_init + db_dlambda = hardeningParameter * (b_resi - b_init) / (hardeningParameter+plasticMultiplier) / (hardeningParameter+plasticMultiplier) + hardeningRate = -dF_db*db_dlambda + + # Variation of Perzyna plastic multiplier, see Runesson et al. 1999, see Eq. 56, 4, 80, 62, 63 + parameter_Aep = 3.0*shearModulus + bulkModulus*b*b_dilation + hardeningRate + delta_lambda = delta_time_anal / relaxationTime * (F_anal/parameter_Aep) + + # Compute stress and strain variations + delta_ax_stress_anal = ( delta_ax_strain_anal-delta_lambda*(b_dilation-3.0)/3.0 ) * youngModulus + delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / 2.0 / shearModulus + 3.0/2.0*delta_lambda + + # Compute stress and strain at actual loading step + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal + + # Update plastic multiplier + plasticMultiplier += delta_lambda + + else: #unloading + + F_anal = -q_anal + b*p_anal - b*a_init/b_init # negative sign added to q for q<0 to obtain the absolute value + + if(F_anal>=0): + b = b_init + plasticMultiplier/(hardeningParameter+plasticMultiplier) * (b_resi - b_init) + b_dilation = b*dilationRatio + + dF_db = p_anal - a_init/b_init + db_dlambda = hardeningParameter * (b_resi - b_init) / (hardeningParameter+plasticMultiplier) / (hardeningParameter+plasticMultiplier) + hardeningRate = -dF_db*db_dlambda + + # Variation of Perzyna plastic multiplier, see Runesson et al. 1999, see Eq. 56, 4, 80, 62, 63 + parameter_Aep = 3.0*shearModulus + bulkModulus*b*b_dilation + hardeningRate + delta_lambda = delta_time_anal / relaxationTime * (F_anal/parameter_Aep) + + # Compute stress and strain variations + delta_ax_stress_anal = ( delta_ax_strain_anal-delta_lambda*(b_dilation+3.0)/3.0 ) * youngModulus + delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / 2.0 / shearModulus - 3.0/2.0*delta_lambda + + # Compute stress and strain at actual loading step + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal + + # Update plastic multiplier + plasticMultiplier += delta_lambda + + list_ax_stress_anal[idx] = ax_stress_anal + list_ra_strain_anal[idx] = ra_strain_anal + + # Preparing data for visualizing semi-analytical results + list_p_anal = (list_ax_stress_anal + 2.0 * list_ra_stress_anal) / 3.0 + list_q_anal = -(list_ax_stress_anal - list_ra_stress_anal) + + return list_ax_stress_anal,list_time_anal,list_ax_strain_anal,list_ra_strain_anal,list_p_anal,list_q_anal def main(): - # File path - hdf5File1Path = "displacement_history.hdf5" - hdf5File2Path = "stress_history.hdf5" - xmlFile1Path = "../../../../../../../inputFiles/solidMechanics/viscoExtendedDruckerPrager_relaxation_base.xml" - xmlFile2Path = "../../../../../../../inputFiles/solidMechanics/viscoExtendedDruckerPrager_relaxation_benchmark.xml" - - # Read HDF5 - # Global Coordinate of Nodal Point - hf = h5py.File(hdf5File1Path, 'r') - xl_node = hf.get('totalDisplacement ReferencePosition topPoint') - xcord_node = xl_node[0,:,0] - ycord_node = xl_node[0,:,1] - zcord_node = xl_node[0,:,2] - # Load Displacement Components - disp = hf.get('totalDisplacement topPoint') - - # Global Coordinate of Element Center - hf = h5py.File(hdf5File2Path, 'r') - xl_elm = hf.get('rock_stress elementCenter') - xl_elm = np.array(xl_elm) - xcord_elm = xl_elm[0, :, 0] - ycord_elm = xl_elm[0, :, 1] - zcord_elm = xl_elm[0, :, 2] - time = hf.get('rock_stress Time') - # Load Stress Components - sigma = hf.get('rock_stress') - sigma = np.array(sigma) - sigma_Cart = np.zeros([len(sigma[:,0,0]), len(sigma[0,:,0]), 6]) - for tl in range(0,len(sigma[:,0,0])): - for i in range(0,len(sigma[0,:,0])): - for j in range(0, 6): - for k in range(0, 8): - sigma_Cart[tl,i,j] += sigma[tl, i, j+6*k]/8. - - ax_stress = sigma_Cart[:, -1, 2] - ra_stress = sigma_Cart[:, -1, 0] - p_num = (ax_stress + 2.0 * ra_stress) / 3.0 - q_num = -(ax_stress - ra_stress) - ax_strain = disp[:, -1, 2] - ra_strain = disp[:, -1, 0] - - - # Extract info from XML - mechanicalParameters = getMechanicalParametersFromXML(xmlFile1Path) - initialStress, imp_strain, imp_time = getLoadingFromXML(xmlFile1Path) - list_ax_stress_anal,list_time_anal,list_ax_strain_anal,list_ra_strain_anal,list_p_anal,list_q_anal = semiAnalytical( mechanicalParameters, imp_strain, imp_time, initialStress ) - - - #Visualization parameters - fsize = 20 - msize = 12 - lw = 6 - malpha = 0.5 - N1 = 3 - fig, ax = plt.subplots(3,1,figsize=(10, 18)) - cmap = plt.get_cmap("tab10") - - - # Plot strain versus shear stress - ax[0].plot(-ax_strain[::N1]*100, q_num[::N1]*1e-6, 'o', color=cmap(2), alpha=malpha, fillstyle='full', markersize=msize, label='GEOS') - ax[0].plot(-ra_strain[::N1]*100, q_num[::N1]*1e-6, 'o', color=cmap(2), alpha=malpha, fillstyle='full', markersize=msize) - ax[0].plot(-list_ax_strain_anal*100, list_q_anal*1e-6, lw=lw, alpha=0.8, color=cmap(2), label='Analytical') - ax[0].plot(-list_ra_strain_anal*100, list_q_anal*1e-6, lw=lw, alpha=0.8, color=cmap(2)) - ax[0].set_xlim([-0.12, 0.12]) - ax[0].set_ylim(0, 12) - ax[0].set_xlabel(r'Strain (%)', size=fsize, weight="bold") - ax[0].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") - ax[0].legend(loc='lower left',fontsize=fsize) - ax[0].grid(True, which="both", ls="-") - ax[0].xaxis.set_tick_params(labelsize=fsize) - ax[0].yaxis.set_tick_params(labelsize=fsize) - - - # Plot stress path and yield surfaces - phi_i = mechanicalParameters["initialFrictionAngle"] - phi_r= mechanicalParameters["residualFrictionAngle"] - c_i = mechanicalParameters["cohesion"]/1.0e6 - f_i = atan(6.0*sin(phi_i/180*np.pi)/(3.0-sin(phi_i/180*np.pi)))*180/np.pi - f_r = atan(6.0*sin(phi_r/180*np.pi)/(3.0-sin(phi_r/180*np.pi)))*180/np.pi - d_i = 6.0*c_i*cos(phi_i/180*np.pi)/(3.0-sin(phi_i/180*np.pi)) - po = d_i/tan(f_i/180*np.pi) - d_r = po*tan(f_r/180*np.pi) - - k_i = tan(f_i/180*np.pi) - p_Yield = np.linspace(0, 50, 100) - q_iniYield = k_i*p_Yield+d_i - k_r = tan(f_r/180*np.pi) - q_resYield = k_r*p_Yield+d_r - - ax[1].plot(-p_num[::N1]*1e-6, q_num[::N1]*1e-6, 'o', color=cmap(2), alpha=malpha, fillstyle='full', markersize=msize, label='GEOS') - ax[1].plot(-list_p_anal*1e-6, list_q_anal*1e-6, lw=lw, alpha=0.8, color=cmap(2), label='Analytical') - ax[1].plot(p_Yield, q_iniYield, lw=lw, alpha=0.8, color='k', linestyle= '--', label='Initial Yield Surface') - ax[1].plot(p_Yield, q_resYield, lw=lw, alpha=0.8, color='orange', linestyle= '--', label='Residual Yield Surface') - ax[1].set_xlim([0, 15]) - ax[1].set_ylim([0, 15]) - ax[1].set_xlabel(r'p (MPa)', size=fsize, weight="bold") - ax[1].set_ylabel(r'q (MPa)', size=fsize, weight="bold") - ax[1].legend(loc='upper left',fontsize=fsize) - ax[1].grid(True, which="both", ls="-") - ax[1].xaxis.set_tick_params(labelsize=fsize) - ax[1].yaxis.set_tick_params(labelsize=fsize) - - - - # Plot axial stress and strain with time - ax[2].plot(time[::N1]/86400, -ax_strain[::N1]*100, 'o', color=cmap(1), alpha=malpha, fillstyle='full', markersize=msize, label='Axial Strain_GEOS') - ax[2].plot(list_time_anal/86400, -list_ax_strain_anal*100, lw=lw, alpha=0.8, color=cmap(1), label='Axial Strain_Analytical') - ax[2].set_xlabel(r'Time (D)', size=fsize, weight="bold") - ax[2].set_ylabel(r'Axial Strain (%)', size=fsize, weight="bold") - ax[2].set_ylim([0, 0.2]) - ax[2].legend(loc='upper left',fontsize=fsize) - ax[2].grid(True, which="both", ls="-") - ax[2].xaxis.set_tick_params(labelsize=fsize) - ax[2].yaxis.set_tick_params(labelsize=fsize) - ax2=ax[2].twinx() - ax2.plot(time[::N1]/86400, -ax_stress[::N1]/1.0e6, 'o', color=cmap(0), alpha=malpha, fillstyle='full', markersize=msize, label='Axial Stress_GEOS') - ax2.plot(list_time_anal/86400, -list_ax_stress_anal/1.0e6, lw=lw, alpha=0.8, color=cmap(0), label='Axial Stress_Analytical') - ax2.set_ylabel(r'Stress (MPa)', size=fsize, weight="bold") - ax2.set_ylim([10, 25]) - ax2.legend(loc='lower right',fontsize=fsize) - ax2.yaxis.set_tick_params(labelsize=fsize) - - - - plt.subplots_adjust(left=0.15, bottom=0.1, right=0.85, top=0.95, wspace=0.4, hspace=0.4) - plt.show() - + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + + # File path + outputDir = args.outputDir + geosDir = args.geosDir + hdf5File1Path = outputDir + "/displacement_history.hdf5" + hdf5File2Path = outputDir + "/stress_history.hdf5" + xmlFile1Path = geosDir + "/inputFiles/solidMechanics/viscoExtendedDruckerPrager_relaxation_base.xml" + xmlFile2Path = geosDir + "/inputFiles/solidMechanics/viscoExtendedDruckerPrager_relaxation_benchmark.xml" + + # Read HDF5 + # Global Coordinate of Nodal Point + hf = h5py.File(hdf5File1Path, 'r') + xl_node = hf.get('totalDisplacement ReferencePosition topPoint') + xcord_node = xl_node[0,:,0] + ycord_node = xl_node[0,:,1] + zcord_node = xl_node[0,:,2] + # Load Displacement Components + disp = hf.get('totalDisplacement topPoint') + + # Global Coordinate of Element Center + hf = h5py.File(hdf5File2Path, 'r') + xl_elm = hf.get('rock_stress elementCenter') + xl_elm = np.asarray(xl_elm) + xcord_elm = xl_elm[0, :, 0] + ycord_elm = xl_elm[0, :, 1] + zcord_elm = xl_elm[0, :, 2] + time = hf.get('rock_stress Time') + # Load Stress Components + sigma = hf.get('rock_stress') + sigma = np.asarray(sigma) + sigma_Cart = np.zeros([len(sigma[:,0,0]), len(sigma[0,:,0]), 6]) + for tl in range(0,len(sigma[:,0,0])): + for i in range(0,len(sigma[0,:,0])): + for j in range(0, 6): + for k in range(0, 8): + sigma_Cart[tl,i,j] += sigma[tl, i, j+6*k]/8. + + ax_stress = sigma_Cart[:, -1, 2] + ra_stress = sigma_Cart[:, -1, 0] + p_num = (ax_stress + 2.0 * ra_stress) / 3.0 + q_num = -(ax_stress - ra_stress) + ax_strain = disp[:, -1, 2] + ra_strain = disp[:, -1, 0] + + + # Extract info from XML + mechanicalParameters = getMechanicalParametersFromXML(xmlFile1Path) + initialStress, imp_strain, imp_time = getLoadingFromXML(xmlFile1Path) + list_ax_stress_anal,list_time_anal,list_ax_strain_anal,list_ra_strain_anal,list_p_anal,list_q_anal = semiAnalytical( mechanicalParameters, imp_strain, imp_time, initialStress ) + + + #Visualization parameters + fsize = 20 + msize = 12 + lw = 6 + malpha = 0.5 + N1 = 3 + fig, ax = plt.subplots(3,1,figsize=(10, 18)) + cmap = plt.get_cmap("tab10") + + + # Plot strain versus shear stress + ax[0].plot(-ax_strain[::N1]*100, q_num[::N1]*1e-6, 'o', color=cmap(2), alpha=malpha, fillstyle='full', markersize=msize, label='GEOS') + ax[0].plot(-ra_strain[::N1]*100, q_num[::N1]*1e-6, 'o', color=cmap(2), alpha=malpha, fillstyle='full', markersize=msize) + ax[0].plot(-list_ax_strain_anal*100, list_q_anal*1e-6, lw=lw, alpha=0.8, color=cmap(2), label='Analytical') + ax[0].plot(-list_ra_strain_anal*100, list_q_anal*1e-6, lw=lw, alpha=0.8, color=cmap(2)) + ax[0].set_xlim([-0.12, 0.12]) + ax[0].set_ylim(0, 12) + ax[0].set_xlabel(r'Strain (%)', size=fsize, weight="bold") + ax[0].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") + ax[0].legend(loc='lower left',fontsize=fsize) + ax[0].grid(True, which="both", ls="-") + ax[0].xaxis.set_tick_params(labelsize=fsize) + ax[0].yaxis.set_tick_params(labelsize=fsize) + + + # Plot stress path and yield surfaces + phi_i = mechanicalParameters["initialFrictionAngle"] + phi_r= mechanicalParameters["residualFrictionAngle"] + c_i = mechanicalParameters["cohesion"]/1.0e6 + f_i = atan(6.0*sin(phi_i/180*np.pi)/(3.0-sin(phi_i/180*np.pi)))*180/np.pi + f_r = atan(6.0*sin(phi_r/180*np.pi)/(3.0-sin(phi_r/180*np.pi)))*180/np.pi + d_i = 6.0*c_i*cos(phi_i/180*np.pi)/(3.0-sin(phi_i/180*np.pi)) + po = d_i/tan(f_i/180*np.pi) + d_r = po*tan(f_r/180*np.pi) + + k_i = tan(f_i/180*np.pi) + p_Yield = np.linspace(0, 50, 100) + q_iniYield = k_i*p_Yield+d_i + k_r = tan(f_r/180*np.pi) + q_resYield = k_r*p_Yield+d_r + + ax[1].plot(-p_num[::N1]*1e-6, q_num[::N1]*1e-6, 'o', color=cmap(2), alpha=malpha, fillstyle='full', markersize=msize, label='GEOS') + ax[1].plot(-list_p_anal*1e-6, list_q_anal*1e-6, lw=lw, alpha=0.8, color=cmap(2), label='Analytical') + ax[1].plot(p_Yield, q_iniYield, lw=lw, alpha=0.8, color='k', linestyle= '--', label='Initial Yield Surface') + ax[1].plot(p_Yield, q_resYield, lw=lw, alpha=0.8, color='orange', linestyle= '--', label='Residual Yield Surface') + ax[1].set_xlim([0, 15]) + ax[1].set_ylim([0, 15]) + ax[1].set_xlabel(r'p (MPa)', size=fsize, weight="bold") + ax[1].set_ylabel(r'q (MPa)', size=fsize, weight="bold") + ax[1].legend(loc='upper left',fontsize=fsize) + ax[1].grid(True, which="both", ls="-") + ax[1].xaxis.set_tick_params(labelsize=fsize) + ax[1].yaxis.set_tick_params(labelsize=fsize) + + + + # Plot axial stress and strain with time + ax[2].plot(time[::N1]/86400, -ax_strain[::N1]*100, 'o', color=cmap(1), alpha=malpha, fillstyle='full', markersize=msize, label='Axial Strain_GEOS') + ax[2].plot(list_time_anal/86400, -list_ax_strain_anal*100, lw=lw, alpha=0.8, color=cmap(1), label='Axial Strain_Analytical') + ax[2].set_xlabel(r'Time (D)', size=fsize, weight="bold") + ax[2].set_ylabel(r'Axial Strain (%)', size=fsize, weight="bold") + ax[2].set_ylim([0, 0.2]) + ax[2].legend(loc='upper left',fontsize=fsize) + ax[2].grid(True, which="both", ls="-") + ax[2].xaxis.set_tick_params(labelsize=fsize) + ax[2].yaxis.set_tick_params(labelsize=fsize) + ax2=ax[2].twinx() + ax2.plot(time[::N1]/86400, -ax_stress[::N1]/1.0e6, 'o', color=cmap(0), alpha=malpha, fillstyle='full', markersize=msize, label='Axial Stress_GEOS') + ax2.plot(list_time_anal/86400, -list_ax_stress_anal/1.0e6, lw=lw, alpha=0.8, color=cmap(0), label='Axial Stress_Analytical') + ax2.set_ylabel(r'Stress (MPa)', size=fsize, weight="bold") + ax2.set_ylim([10, 25]) + ax2.legend(loc='lower right',fontsize=fsize) + ax2.yaxis.set_tick_params(labelsize=fsize) + + + + plt.subplots_adjust(left=0.15, bottom=0.1, right=0.85, top=0.95, wspace=0.4, hspace=0.4) + plt.show() + if __name__ == "__main__": main() diff --git a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoDruckerPrager/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoDruckerPrager/Example.rst index ed576585670..323cef2e2fd 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoDruckerPrager/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoDruckerPrager/Example.rst @@ -112,4 +112,4 @@ To go further **Feedback on this example** -For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. +For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. diff --git a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoDruckerPrager/TriaxialDriver_vs_SemiAnalytic_ViscoDruckerPrager.py b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoDruckerPrager/TriaxialDriver_vs_SemiAnalytic_ViscoDruckerPrager.py index 80dc6616163..660f780bd75 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoDruckerPrager/TriaxialDriver_vs_SemiAnalytic_ViscoDruckerPrager.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoDruckerPrager/TriaxialDriver_vs_SemiAnalytic_ViscoDruckerPrager.py @@ -3,257 +3,272 @@ import numpy as np import matplotlib.pyplot as plt import xml.etree.ElementTree as ElementTree +import os +import argparse def main(): - # File paths - path = "ViscoDruckerPragerResults.txt" - timeFilePath = "../../../../../../../inputFiles/triaxialDriver/tables/time.geos" - xmlFilePath = "../../../../../../../inputFiles/triaxialDriver/triaxialDriver_base.xml" - xmlFilePath_case = "../../../../../../../inputFiles/triaxialDriver/triaxialDriver_ViscoDruckerPrager.xml" - imposedStrainFilePath = "../../../../../../../inputFiles/triaxialDriver/tables/axialStrain.geos" - imposedStressFilePath = "../../../../../../../inputFiles/triaxialDriver/tables/radialStress.geos" - - # Load GEOSX results - time, ax_strain, ra_strain1, ra_strain2, ax_stress, ra_stress1, ra_stress2, newton_iter, residual_norm = np.loadtxt( - path, skiprows=5, unpack=True) - - # Extract mechanical parameters from XML file - tree = ElementTree.parse(xmlFilePath) - tree_case = ElementTree.parse(xmlFilePath_case) - model = tree_case.find('Tasks/TriaxialDriver') - param = tree.find('Constitutive/ViscoDruckerPrager') - - bulkModulus = float(param.get("defaultBulkModulus")) - shearModulus = float(param.get("defaultShearModulus")) - cohesion = float(param.get("defaultCohesion")) - frictionAngle = float(param.get("defaultFrictionAngle")) - dilationAngle = float(param.get("defaultDilationAngle")) - hardeningRate = float(param.get("defaultHardeningRate")) - relaxationTime = float(param.get("relaxationTime")) - initialStress = float(model.get("initialStress")) - - # Compute Lame modulus and Young modulus - lameModulus = bulkModulus - 2.0/3.0*shearModulus - youngModulus = 1.0 / ( 1.0/9.0/bulkModulus + 1.0/3.0/shearModulus ) - - # Friction and cohesion parameters - frictionAngleRad = frictionAngle*np.pi/180.0 - cosFrictionAngle = np.cos(frictionAngleRad) - sinFrictionAngle = np.sin(frictionAngleRad) - a = 6.0*cohesion*cosFrictionAngle/(3.0-sinFrictionAngle) - b = 6.0*sinFrictionAngle/(3.0-sinFrictionAngle) - - # Dilation parameter - dilationAngleRad = dilationAngle*np.pi/180.0 - sinDilationAngle = np.sin(dilationAngleRad) - b_dilation = 6.0*sinDilationAngle/(3.0-sinDilationAngle) - - # See Runesson et al. 1999, see Eq. 56 - parameter_Aep = 3.0*shearModulus + bulkModulus*b*b_dilation + hardeningRate - - # Extract loading from input tables - imp_strain = np.loadtxt( - imposedStrainFilePath, skiprows=0, unpack=True) - - list_ax_strain_anal = [] - numStepPerLoadingPeriod = 1000 - - for i in range(0,len(imp_strain)-1): - dStrainPerStep = (imp_strain[i+1]-imp_strain[i])/numStepPerLoadingPeriod - loadingPeriod = np.arange(imp_strain[i],imp_strain[i+1]+dStrainPerStep,dStrainPerStep) - list_ax_strain_anal = np.concatenate((list_ax_strain_anal, loadingPeriod), axis=0) - - # Extract time from input tables - imp_time = np.loadtxt( - timeFilePath, skiprows=0, unpack=True) - - list_time_anal = [] - for i in range(0,len(imp_time)-1): - dTimePerStep = (imp_time[i+1]-imp_time[i])/numStepPerLoadingPeriod - timePeriod = np.arange(imp_time[i],imp_time[i+1]+dTimePerStep,dTimePerStep) - list_time_anal = np.concatenate((list_time_anal, timePeriod), axis=0) - - # Extract radial stress loading from input tables - imp_stress = np.loadtxt( - imposedStressFilePath, skiprows=0, unpack=True) - - list_ra_stress_anal = imp_stress[0]*np.ones(len(list_ax_strain_anal)) #constant radial confining stress - - # Initiate radial strain and axial stress arrays - list_ra_strain_anal = np.zeros(len(list_ax_strain_anal)) - list_ax_stress_anal = np.zeros(len(list_ax_strain_anal)) - list_ax_stress_anal[0] = initialStress - list_ra_strain_anal[0] = 0 - - # Loop over the loading/unloading steps - for idx in range(1,len(list_ax_strain_anal)): - delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] - delta_time_anal = list_time_anal[idx]-list_time_anal[idx-1] - delta_ra_stress_anal = 0 # constant radial confining stress - - # Elastic trial - delta_ra_strain_anal = (delta_ra_stress_anal-lameModulus*delta_ax_strain_anal)/(2.0*lameModulus+2.0*shearModulus) - delta_ax_stress_anal = (lameModulus+2.0*shearModulus)*delta_ax_strain_anal + lameModulus/(lameModulus+shearModulus)*(delta_ra_stress_anal-lameModulus*delta_ax_strain_anal) - - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal - - # Compute mean and shear stresses - ra_stress_anal = list_ra_stress_anal[idx] - p_anal = (ax_stress_anal + 2.0 * ra_stress_anal) / 3.0 - q_anal = -(ax_stress_anal - ra_stress_anal) - - # Plastic correction - if(q_anal>=0): #loading - - F_anal = q_anal + b*p_anal - a - - if(F_anal>=0): - - # Variation of Perzyna visco-plastic multiplier, see Runesson et al. 1999, see Eq. 4, 80, 62, 63 - delta_lambda = delta_time_anal / relaxationTime * (F_anal/parameter_Aep) - - # Compute stress and strain variations - delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] - delta_ax_stress_anal = ( delta_ax_strain_anal-delta_lambda*(b_dilation-3.0)/3.0 ) * youngModulus - delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / 2.0 / shearModulus + 3.0/2.0*delta_lambda - - # Compute stress and strain at actual loading step - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal - - # Update plastic cohesion - delta_a = hardeningRate*delta_lambda - a += delta_a - - else: #unloading - - F_anal = -q_anal + b*p_anal - a # negative sign added to q for q<0 to obtain the absolute value - - if(F_anal>=0): - # Variation of Perzyna visco-plastic multiplier, see Runesson et al. 1999, see Eq. 4, 80, 62, 63 - delta_lambda = delta_time_anal / relaxationTime * (F_anal/parameter_Aep) - - # Compute stress and strain variations - delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] - delta_ax_stress_anal = ( delta_ax_strain_anal-delta_lambda*(b_dilation+3.0)/3.0 ) * youngModulus - delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / 2.0 / shearModulus - 3.0/2.0*delta_lambda - - # Compute stress and strain at actual loading step - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal - - # Update plastic cohesion - delta_a = hardeningRate*delta_lambda - a += delta_a - - list_ax_stress_anal[idx] = ax_stress_anal - list_ra_strain_anal[idx] = ra_strain_anal - - # Preparing data for visualizing semi-analytical results - list_p_anal = (list_ax_stress_anal + 2.0 * list_ra_stress_anal) / 3.0 - list_q_anal = -(list_ax_stress_anal - list_ra_stress_anal) - - list_strain_vol_anal = list_ax_strain_anal + 2.0 * list_ra_strain_anal - - p_num = (ax_stress + 2.0 * ra_stress1) / 3.0 - q_num = -(ax_stress - ra_stress1) - - strain_vol = ax_strain + 2.0 * ra_strain1 - - #Visualization parameters - fsize = 30 - msize = 12 - lw = 6 - malpha = 0.5 - fig, ax = plt.subplots(1, 3, figsize=(37, 10)) - cmap = plt.get_cmap("tab10") - - # Plot strain versus shear stress - ax[0].plot(-ax_strain * 100, #convert to % - q_num*1e-6, #convert to MPa - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[0].plot(-ra_strain1 * 100, - q_num*1e-6, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha) - ax[0].plot(-list_ax_strain_anal* 100, - list_q_anal*1e-6, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[0].plot(-list_ra_strain_anal * 100, - list_q_anal*1e-6, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - linewidth=6) - ax[0].set_xlabel(r'Strain (%)', size=fsize, weight="bold") - ax[0].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") - ax[0].xaxis.set_tick_params(labelsize=fsize) - ax[0].yaxis.set_tick_params(labelsize=fsize) - - # Plot axial strain versus volumetric strain - ax[1].plot(-ax_strain * 100, - -strain_vol * 100, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[1].plot(-list_ax_strain_anal* 100, - -list_strain_vol_anal* 100, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[1].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") - ax[1].set_ylabel(r'Volumetric Strain (%)', size=fsize, weight="bold") - #ax[1].legend(loc='lower right', fontsize=fsize) - ax[1].xaxis.set_tick_params(labelsize=fsize) - ax[1].yaxis.set_tick_params(labelsize=fsize) - - # Plot shear stress versus mean stress - ax[2].plot(-p_num*1e-6, - q_num*1e-6, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[2].plot(-list_p_anal*1e-6, - list_q_anal*1e-6, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[2].set_xlabel(r'Mean stress (MPa)', size=fsize, weight="bold") - ax[2].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") - ax[2].legend(loc='lower right', fontsize=fsize) - ax[2].xaxis.set_tick_params(labelsize=fsize) - ax[2].yaxis.set_tick_params(labelsize=fsize) - - plt.subplots_adjust(left=0.2, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4) - plt.show() - + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + + # File paths + outputDir = args.outputDir + geosDir = args.geosDir + path = outputDir + "/ViscoDruckerPragerResults.txt" + timeFilePath = geosDir + "/inputFiles/triaxialDriver/tables/time.geos" + xmlFilePath = geosDir + "/inputFiles/triaxialDriver/triaxialDriver_base.xml" + xmlFilePath_case = geosDir + "/inputFiles/triaxialDriver/triaxialDriver_ViscoDruckerPrager.xml" + imposedStrainFilePath = geosDir + "/inputFiles/triaxialDriver/tables/axialStrain.geos" + imposedStressFilePath = geosDir + "/inputFiles/triaxialDriver/tables/radialStress.geos" + + # Load GEOSX results + time, ax_strain, ra_strain1, ra_strain2, ax_stress, ra_stress1, ra_stress2, newton_iter, residual_norm = np.loadtxt( + path, skiprows=5, unpack=True) + + # Extract mechanical parameters from XML file + tree = ElementTree.parse(xmlFilePath) + tree_case = ElementTree.parse(xmlFilePath_case) + model = tree_case.find('Tasks/TriaxialDriver') + param = tree.find('Constitutive/ViscoDruckerPrager') + + bulkModulus = float(param.get("defaultBulkModulus")) + shearModulus = float(param.get("defaultShearModulus")) + cohesion = float(param.get("defaultCohesion")) + frictionAngle = float(param.get("defaultFrictionAngle")) + dilationAngle = float(param.get("defaultDilationAngle")) + hardeningRate = float(param.get("defaultHardeningRate")) + relaxationTime = float(param.get("relaxationTime")) + initialStress = float(model.get("initialStress")) + + # Compute Lame modulus and Young modulus + lameModulus = bulkModulus - 2.0/3.0*shearModulus + youngModulus = 1.0 / ( 1.0/9.0/bulkModulus + 1.0/3.0/shearModulus ) + + # Friction and cohesion parameters + frictionAngleRad = frictionAngle*np.pi/180.0 + cosFrictionAngle = np.cos(frictionAngleRad) + sinFrictionAngle = np.sin(frictionAngleRad) + a = 6.0*cohesion*cosFrictionAngle/(3.0-sinFrictionAngle) + b = 6.0*sinFrictionAngle/(3.0-sinFrictionAngle) + + # Dilation parameter + dilationAngleRad = dilationAngle*np.pi/180.0 + sinDilationAngle = np.sin(dilationAngleRad) + b_dilation = 6.0*sinDilationAngle/(3.0-sinDilationAngle) + + # See Runesson et al. 1999, see Eq. 56 + parameter_Aep = 3.0*shearModulus + bulkModulus*b*b_dilation + hardeningRate + + # Extract loading from input tables + imp_strain = np.loadtxt( + imposedStrainFilePath, skiprows=0, unpack=True) + + list_ax_strain_anal = [] + numStepPerLoadingPeriod = 1000 + + for i in range(0,len(imp_strain)-1): + dStrainPerStep = (imp_strain[i+1]-imp_strain[i])/numStepPerLoadingPeriod + loadingPeriod = np.arange(imp_strain[i],imp_strain[i+1]+dStrainPerStep,dStrainPerStep) + list_ax_strain_anal = np.concatenate((list_ax_strain_anal, loadingPeriod), axis=0) + + # Extract time from input tables + imp_time = np.loadtxt( + timeFilePath, skiprows=0, unpack=True) + + list_time_anal = [] + for i in range(0,len(imp_time)-1): + dTimePerStep = (imp_time[i+1]-imp_time[i])/numStepPerLoadingPeriod + timePeriod = np.arange(imp_time[i],imp_time[i+1]+dTimePerStep,dTimePerStep) + list_time_anal = np.concatenate((list_time_anal, timePeriod), axis=0) + + # Extract radial stress loading from input tables + imp_stress = np.loadtxt( + imposedStressFilePath, skiprows=0, unpack=True) + + list_ra_stress_anal = imp_stress[0]*np.ones(len(list_ax_strain_anal)) #constant radial confining stress + + # Initiate radial strain and axial stress arrays + list_ra_strain_anal = np.zeros(len(list_ax_strain_anal)) + list_ax_stress_anal = np.zeros(len(list_ax_strain_anal)) + list_ax_stress_anal[0] = initialStress + list_ra_strain_anal[0] = 0 + + # Loop over the loading/unloading steps + for idx in range(1,len(list_ax_strain_anal)): + delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] + delta_time_anal = list_time_anal[idx]-list_time_anal[idx-1] + delta_ra_stress_anal = 0 # constant radial confining stress + + # Elastic trial + delta_ra_strain_anal = (delta_ra_stress_anal-lameModulus*delta_ax_strain_anal)/(2.0*lameModulus+2.0*shearModulus) + delta_ax_stress_anal = (lameModulus+2.0*shearModulus)*delta_ax_strain_anal + lameModulus/(lameModulus+shearModulus)*(delta_ra_stress_anal-lameModulus*delta_ax_strain_anal) + + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal + + # Compute mean and shear stresses + ra_stress_anal = list_ra_stress_anal[idx] + p_anal = (ax_stress_anal + 2.0 * ra_stress_anal) / 3.0 + q_anal = -(ax_stress_anal - ra_stress_anal) + + # Plastic correction + if(q_anal>=0): #loading + + F_anal = q_anal + b*p_anal - a + + if(F_anal>=0): + + # Variation of Perzyna visco-plastic multiplier, see Runesson et al. 1999, see Eq. 4, 80, 62, 63 + delta_lambda = delta_time_anal / relaxationTime * (F_anal/parameter_Aep) + + # Compute stress and strain variations + delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] + delta_ax_stress_anal = ( delta_ax_strain_anal-delta_lambda*(b_dilation-3.0)/3.0 ) * youngModulus + delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / 2.0 / shearModulus + 3.0/2.0*delta_lambda + + # Compute stress and strain at actual loading step + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal + + # Update plastic cohesion + delta_a = hardeningRate*delta_lambda + a += delta_a + + else: #unloading + + F_anal = -q_anal + b*p_anal - a # negative sign added to q for q<0 to obtain the absolute value + + if(F_anal>=0): + # Variation of Perzyna visco-plastic multiplier, see Runesson et al. 1999, see Eq. 4, 80, 62, 63 + delta_lambda = delta_time_anal / relaxationTime * (F_anal/parameter_Aep) + + # Compute stress and strain variations + delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] + delta_ax_stress_anal = ( delta_ax_strain_anal-delta_lambda*(b_dilation+3.0)/3.0 ) * youngModulus + delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / 2.0 / shearModulus - 3.0/2.0*delta_lambda + + # Compute stress and strain at actual loading step + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal + + # Update plastic cohesion + delta_a = hardeningRate*delta_lambda + a += delta_a + + list_ax_stress_anal[idx] = ax_stress_anal + list_ra_strain_anal[idx] = ra_strain_anal + + # Preparing data for visualizing semi-analytical results + list_p_anal = (list_ax_stress_anal + 2.0 * list_ra_stress_anal) / 3.0 + list_q_anal = -(list_ax_stress_anal - list_ra_stress_anal) + + list_strain_vol_anal = list_ax_strain_anal + 2.0 * list_ra_strain_anal + + p_num = (ax_stress + 2.0 * ra_stress1) / 3.0 + q_num = -(ax_stress - ra_stress1) + + strain_vol = ax_strain + 2.0 * ra_strain1 + + #Visualization parameters + fsize = 30 + msize = 12 + lw = 6 + malpha = 0.5 + fig, ax = plt.subplots(1, 3, figsize=(37, 10)) + cmap = plt.get_cmap("tab10") + + # Plot strain versus shear stress + ax[0].plot(-ax_strain * 100, #convert to % + q_num*1e-6, #convert to MPa + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[0].plot(-ra_strain1 * 100, + q_num*1e-6, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha) + ax[0].plot(-list_ax_strain_anal* 100, + list_q_anal*1e-6, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[0].plot(-list_ra_strain_anal * 100, + list_q_anal*1e-6, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + linewidth=6) + ax[0].set_xlabel(r'Strain (%)', size=fsize, weight="bold") + ax[0].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") + ax[0].xaxis.set_tick_params(labelsize=fsize) + ax[0].yaxis.set_tick_params(labelsize=fsize) + + # Plot axial strain versus volumetric strain + ax[1].plot(-ax_strain * 100, + -strain_vol * 100, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[1].plot(-list_ax_strain_anal* 100, + -list_strain_vol_anal* 100, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[1].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") + ax[1].set_ylabel(r'Volumetric Strain (%)', size=fsize, weight="bold") + #ax[1].legend(loc='lower right', fontsize=fsize) + ax[1].xaxis.set_tick_params(labelsize=fsize) + ax[1].yaxis.set_tick_params(labelsize=fsize) + + # Plot shear stress versus mean stress + ax[2].plot(-p_num*1e-6, + q_num*1e-6, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[2].plot(-list_p_anal*1e-6, + list_q_anal*1e-6, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[2].set_xlabel(r'Mean stress (MPa)', size=fsize, weight="bold") + ax[2].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") + ax[2].legend(loc='lower right', fontsize=fsize) + ax[2].xaxis.set_tick_params(labelsize=fsize) + ax[2].yaxis.set_tick_params(labelsize=fsize) + + plt.subplots_adjust(left=0.2, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4) + plt.show() + if __name__ == "__main__": main() diff --git a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoExtendedDruckerPrager/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoExtendedDruckerPrager/Example.rst index 35c9cef1313..88fba339887 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoExtendedDruckerPrager/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoExtendedDruckerPrager/Example.rst @@ -112,4 +112,4 @@ To go further **Feedback on this example** -For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. +For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. diff --git a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoExtendedDruckerPrager/TriaxialDriver_vs_SemiAnalytic_ViscoExtendedDruckerPrager.py b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoExtendedDruckerPrager/TriaxialDriver_vs_SemiAnalytic_ViscoExtendedDruckerPrager.py index b8c431e94a4..82cccf82ac8 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoExtendedDruckerPrager/TriaxialDriver_vs_SemiAnalytic_ViscoExtendedDruckerPrager.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoExtendedDruckerPrager/TriaxialDriver_vs_SemiAnalytic_ViscoExtendedDruckerPrager.py @@ -3,270 +3,285 @@ import numpy as np import matplotlib.pyplot as plt import xml.etree.ElementTree as ElementTree +import os +import argparse def main(): - # File paths - path = "ViscoExtendedDruckerPragerResults.txt" - timeFilePath = "../../../../../../../inputFiles/triaxialDriver/tables/time.geos" - xmlFilePath = "../../../../../../../inputFiles/triaxialDriver/triaxialDriver_base.xml" - xmlFilePath_case = "../../../../../../../inputFiles/triaxialDriver/triaxialDriver_ViscoExtendedDruckerPrager.xml" - imposedStrainFilePath = "../../../../../../../inputFiles/triaxialDriver/tables/axialStrain.geos" - imposedStressFilePath = "../../../../../../../inputFiles/triaxialDriver/tables/radialStress.geos" - - # Load GEOSX results - time, ax_strain, ra_strain1, ra_strain2, ax_stress, ra_stress1, ra_stress2, newton_iter, residual_norm = np.loadtxt( - path, skiprows=5, unpack=True) - - # Extract mechanical parameters from XML files - tree = ElementTree.parse(xmlFilePath) - tree_case = ElementTree.parse(xmlFilePath_case) - model = tree_case.find('Tasks/TriaxialDriver') - param = tree.find('Constitutive/ViscoExtendedDruckerPrager') - - bulkModulus = float(param.get("defaultBulkModulus")) - shearModulus = float(param.get("defaultShearModulus")) - cohesion = float(param.get("defaultCohesion")) - initialFrictionAngle = float(param.get("defaultInitialFrictionAngle")) - residualFrictionAngle = float(param.get("defaultResidualFrictionAngle")) - hardeningParameter = float(param.get("defaultHardening")) - dilationRatio = float(param.get("defaultDilationRatio")) - relaxationTime = float(param.get("relaxationTime")) - initialStress = float(model.get("initialStress")) - - # Compute Lame modulus and Young modulus - lameModulus = bulkModulus - 2.0/3.0*shearModulus - youngModulus = 1.0/(1.0/9.0/bulkModulus + 1.0/3.0/shearModulus) - - # Initial friction and cohesion parameters - initialFrictionAngleRad = initialFrictionAngle*np.pi/180.0 - cosInitialFrictionAngle = np.cos(initialFrictionAngleRad) - sinInitialFrictionAngle = np.sin(initialFrictionAngleRad) - a_init = 6.0*cohesion*cosInitialFrictionAngle/(3.0-sinInitialFrictionAngle) - b_init = 6.0*sinInitialFrictionAngle/(3.0-sinInitialFrictionAngle) - - # Residual friction parameters - residualFrictionAngleRad = residualFrictionAngle*np.pi/180.0 - sinResidualFrictionAngle = np.sin(residualFrictionAngleRad) - b_resi = 6.0*sinResidualFrictionAngle/(3.0-sinResidualFrictionAngle) - - # Extract loading from input tables - imp_strain = np.loadtxt( - imposedStrainFilePath, skiprows=0, unpack=True) - - list_ax_strain_anal = [] - numStepPerLoadingPeriod = 1000 - - for i in range(0,len(imp_strain)-1): - dStrainPerStep = (imp_strain[i+1]-imp_strain[i])/numStepPerLoadingPeriod - loadingPeriod = np.arange(imp_strain[i],imp_strain[i+1]+dStrainPerStep,dStrainPerStep) - list_ax_strain_anal = np.concatenate((list_ax_strain_anal, loadingPeriod), axis=0) - - # Extract time from input tables - imp_time = np.loadtxt( - timeFilePath, skiprows=0, unpack=True) - - list_time_anal = [] - for i in range(0,len(imp_time)-1): - dTimePerStep = (imp_time[i+1]-imp_time[i])/numStepPerLoadingPeriod - timePeriod = np.arange(imp_time[i],imp_time[i+1]+dTimePerStep,dTimePerStep) - list_time_anal = np.concatenate((list_time_anal, timePeriod), axis=0) - - # Extract radial stress loading from input tables - imp_stress = np.loadtxt( - imposedStressFilePath, skiprows=0, unpack=True) - - list_ra_stress_anal = imp_stress[0]*np.ones(len(list_ax_strain_anal)) #constant radial confining stress - - # Initiate radial strain and axial stress arrays - list_ra_strain_anal = np.zeros(len(list_ax_strain_anal)) - list_ax_stress_anal = np.zeros(len(list_ax_strain_anal)) - list_ax_stress_anal[0] = initialStress - - # Loop over the loading/unloading steps - list_ra_strain_anal[0] = 0 - plasticMultiplier = 0 - b = b_init - - for idx in range(1,len(list_ax_strain_anal)): - delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] - delta_time_anal = list_time_anal[idx]-list_time_anal[idx-1] - delta_ra_stress_anal = 0 - - # Elastic trial - delta_ra_strain_anal = (delta_ra_stress_anal-lameModulus*delta_ax_strain_anal)/(2.0*lameModulus+2.0*shearModulus) - delta_ax_stress_anal = (lameModulus+2.0*shearModulus)*delta_ax_strain_anal + lameModulus/(lameModulus+shearModulus)*(delta_ra_stress_anal-lameModulus*delta_ax_strain_anal) - - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal - - # Compute mean and shear stresses - ra_stress_anal = list_ra_stress_anal[idx] - p_anal = (ax_stress_anal + 2.0 * ra_stress_anal) / 3.0 - q_anal = -(ax_stress_anal - ra_stress_anal) - - # Plastic correction - if(q_anal>=0): #loading - - F_anal = q_anal + b*p_anal - b*a_init/b_init - - if(F_anal>=0): - - b = b_init + plasticMultiplier/(hardeningParameter+plasticMultiplier) * (b_resi - b_init) - b_dilation = b*dilationRatio - - dF_db = p_anal - a_init/b_init - db_dlambda = hardeningParameter * (b_resi - b_init) / (hardeningParameter+plasticMultiplier) / (hardeningParameter+plasticMultiplier) - hardeningRate = -dF_db*db_dlambda - - # Variation of Perzyna plastic multiplier, see Runesson et al. 1999, see Eq. 56, 4, 80, 62, 63 - parameter_Aep = 3.0*shearModulus + bulkModulus*b*b_dilation + hardeningRate - delta_lambda = delta_time_anal / relaxationTime * (F_anal/parameter_Aep) - - # Compute stress and strain variations - delta_ax_stress_anal = ( delta_ax_strain_anal-delta_lambda*(b_dilation-3.0)/3.0 ) * youngModulus - delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / 2.0 / shearModulus + 3.0/2.0*delta_lambda - - # Compute stress and strain at actual loading step - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal - - # Update plastic multiplier - plasticMultiplier += delta_lambda - - else: #unloading - - F_anal = -q_anal + b*p_anal - b*a_init/b_init # negative sign added to q for q<0 to obtain the absolute value - - if(F_anal>=0): - b = b_init + plasticMultiplier/(hardeningParameter+plasticMultiplier) * (b_resi - b_init) - b_dilation = b*dilationRatio - - dF_db = p_anal - a_init/b_init - db_dlambda = hardeningParameter * (b_resi - b_init) / (hardeningParameter+plasticMultiplier) / (hardeningParameter+plasticMultiplier) - hardeningRate = -dF_db*db_dlambda - - # Variation of Perzyna plastic multiplier, see Runesson et al. 1999, see Eq. 56, 4, 80, 62, 63 - parameter_Aep = 3.0*shearModulus + bulkModulus*b*b_dilation + hardeningRate - delta_lambda = delta_time_anal / relaxationTime * (F_anal/parameter_Aep) - - # Compute stress and strain variations - delta_ax_stress_anal = ( delta_ax_strain_anal-delta_lambda*(b_dilation+3.0)/3.0 ) * youngModulus - delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / 2.0 / shearModulus - 3.0/2.0*delta_lambda - - # Compute stress and strain at actual loading step - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal - - # Update plastic multiplier - plasticMultiplier += delta_lambda - - list_ax_stress_anal[idx] = ax_stress_anal - list_ra_strain_anal[idx] = ra_strain_anal - - # Preparing data for visualizing semi-analytical results - list_p_anal = (list_ax_stress_anal + 2.0 * list_ra_stress_anal) / 3.0 - list_q_anal = -(list_ax_stress_anal - list_ra_stress_anal) - - list_strain_vol_anal = list_ax_strain_anal + 2.0 * list_ra_strain_anal - - p_num = (ax_stress + 2.0 * ra_stress1) / 3.0 - q_num = -(ax_stress - ra_stress1) - - strain_vol = ax_strain + 2.0 * ra_strain1 - - #Visualization parameters - fsize = 30 - msize = 12 - lw = 6 - malpha = 0.5 - fig, ax = plt.subplots(1, 3, figsize=(37, 10)) - cmap = plt.get_cmap("tab10") - - # Plot strain versus shear stress - ax[0].plot(-ax_strain * 100, #convert to % - q_num*1e-6, #convert to MPa - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[0].plot(-ra_strain1 * 100, - q_num*1e-6, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha) - ax[0].plot(-list_ax_strain_anal* 100, - list_q_anal*1e-6, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[0].plot(-list_ra_strain_anal * 100, - list_q_anal*1e-6, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - linewidth=6) - ax[0].set_xlabel(r'Strain (%)', size=fsize, weight="bold") - ax[0].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") - ax[0].xaxis.set_tick_params(labelsize=fsize) - ax[0].yaxis.set_tick_params(labelsize=fsize) - - # Plot axial strain versus volumetric strain - ax[1].plot(-ax_strain * 100, - -strain_vol * 100, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[1].plot(-list_ax_strain_anal* 100, - -list_strain_vol_anal* 100, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[1].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") - ax[1].set_ylabel(r'Volumetric Strain (%)', size=fsize, weight="bold") - #ax[1].legend(loc='lower right', fontsize=fsize) - ax[1].xaxis.set_tick_params(labelsize=fsize) - ax[1].yaxis.set_tick_params(labelsize=fsize) - - # Plot shear stress versus mean stress - ax[2].plot(-p_num*1e-6, - q_num*1e-6, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[2].plot(-list_p_anal*1e-6, - list_q_anal*1e-6, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[2].set_xlabel(r'Mean stress (MPa)', size=fsize, weight="bold") - ax[2].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") - ax[2].legend(loc='lower right', fontsize=fsize) - ax[2].xaxis.set_tick_params(labelsize=fsize) - ax[2].yaxis.set_tick_params(labelsize=fsize) - - plt.subplots_adjust(left=0.2, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4) - plt.show() - + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + + # File paths + outputDir = args.outputDir + geosDir = args.geosDir + path = outputDir + "/ViscoExtendedDruckerPragerResults.txt" + timeFilePath = geosDir + "/inputFiles/triaxialDriver/tables/time.geos" + xmlFilePath = geosDir + "/inputFiles/triaxialDriver/triaxialDriver_base.xml" + xmlFilePath_case = geosDir + "/inputFiles/triaxialDriver/triaxialDriver_ViscoExtendedDruckerPrager.xml" + imposedStrainFilePath = geosDir + "/inputFiles/triaxialDriver/tables/axialStrain.geos" + imposedStressFilePath = geosDir + "/inputFiles/triaxialDriver/tables/radialStress.geos" + + # Load GEOSX results + time, ax_strain, ra_strain1, ra_strain2, ax_stress, ra_stress1, ra_stress2, newton_iter, residual_norm = np.loadtxt( + path, skiprows=5, unpack=True) + + # Extract mechanical parameters from XML files + tree = ElementTree.parse(xmlFilePath) + tree_case = ElementTree.parse(xmlFilePath_case) + model = tree_case.find('Tasks/TriaxialDriver') + param = tree.find('Constitutive/ViscoExtendedDruckerPrager') + + bulkModulus = float(param.get("defaultBulkModulus")) + shearModulus = float(param.get("defaultShearModulus")) + cohesion = float(param.get("defaultCohesion")) + initialFrictionAngle = float(param.get("defaultInitialFrictionAngle")) + residualFrictionAngle = float(param.get("defaultResidualFrictionAngle")) + hardeningParameter = float(param.get("defaultHardening")) + dilationRatio = float(param.get("defaultDilationRatio")) + relaxationTime = float(param.get("relaxationTime")) + initialStress = float(model.get("initialStress")) + + # Compute Lame modulus and Young modulus + lameModulus = bulkModulus - 2.0/3.0*shearModulus + youngModulus = 1.0/(1.0/9.0/bulkModulus + 1.0/3.0/shearModulus) + + # Initial friction and cohesion parameters + initialFrictionAngleRad = initialFrictionAngle*np.pi/180.0 + cosInitialFrictionAngle = np.cos(initialFrictionAngleRad) + sinInitialFrictionAngle = np.sin(initialFrictionAngleRad) + a_init = 6.0*cohesion*cosInitialFrictionAngle/(3.0-sinInitialFrictionAngle) + b_init = 6.0*sinInitialFrictionAngle/(3.0-sinInitialFrictionAngle) + + # Residual friction parameters + residualFrictionAngleRad = residualFrictionAngle*np.pi/180.0 + sinResidualFrictionAngle = np.sin(residualFrictionAngleRad) + b_resi = 6.0*sinResidualFrictionAngle/(3.0-sinResidualFrictionAngle) + + # Extract loading from input tables + imp_strain = np.loadtxt( + imposedStrainFilePath, skiprows=0, unpack=True) + + list_ax_strain_anal = [] + numStepPerLoadingPeriod = 1000 + + for i in range(0,len(imp_strain)-1): + dStrainPerStep = (imp_strain[i+1]-imp_strain[i])/numStepPerLoadingPeriod + loadingPeriod = np.arange(imp_strain[i],imp_strain[i+1]+dStrainPerStep,dStrainPerStep) + list_ax_strain_anal = np.concatenate((list_ax_strain_anal, loadingPeriod), axis=0) + + # Extract time from input tables + imp_time = np.loadtxt( + timeFilePath, skiprows=0, unpack=True) + + list_time_anal = [] + for i in range(0,len(imp_time)-1): + dTimePerStep = (imp_time[i+1]-imp_time[i])/numStepPerLoadingPeriod + timePeriod = np.arange(imp_time[i],imp_time[i+1]+dTimePerStep,dTimePerStep) + list_time_anal = np.concatenate((list_time_anal, timePeriod), axis=0) + + # Extract radial stress loading from input tables + imp_stress = np.loadtxt( + imposedStressFilePath, skiprows=0, unpack=True) + + list_ra_stress_anal = imp_stress[0]*np.ones(len(list_ax_strain_anal)) #constant radial confining stress + + # Initiate radial strain and axial stress arrays + list_ra_strain_anal = np.zeros(len(list_ax_strain_anal)) + list_ax_stress_anal = np.zeros(len(list_ax_strain_anal)) + list_ax_stress_anal[0] = initialStress + + # Loop over the loading/unloading steps + list_ra_strain_anal[0] = 0 + plasticMultiplier = 0 + b = b_init + + for idx in range(1,len(list_ax_strain_anal)): + delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] + delta_time_anal = list_time_anal[idx]-list_time_anal[idx-1] + delta_ra_stress_anal = 0 + + # Elastic trial + delta_ra_strain_anal = (delta_ra_stress_anal-lameModulus*delta_ax_strain_anal)/(2.0*lameModulus+2.0*shearModulus) + delta_ax_stress_anal = (lameModulus+2.0*shearModulus)*delta_ax_strain_anal + lameModulus/(lameModulus+shearModulus)*(delta_ra_stress_anal-lameModulus*delta_ax_strain_anal) + + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal + + # Compute mean and shear stresses + ra_stress_anal = list_ra_stress_anal[idx] + p_anal = (ax_stress_anal + 2.0 * ra_stress_anal) / 3.0 + q_anal = -(ax_stress_anal - ra_stress_anal) + + # Plastic correction + if(q_anal>=0): #loading + + F_anal = q_anal + b*p_anal - b*a_init/b_init + + if(F_anal>=0): + + b = b_init + plasticMultiplier/(hardeningParameter+plasticMultiplier) * (b_resi - b_init) + b_dilation = b*dilationRatio + + dF_db = p_anal - a_init/b_init + db_dlambda = hardeningParameter * (b_resi - b_init) / (hardeningParameter+plasticMultiplier) / (hardeningParameter+plasticMultiplier) + hardeningRate = -dF_db*db_dlambda + + # Variation of Perzyna plastic multiplier, see Runesson et al. 1999, see Eq. 56, 4, 80, 62, 63 + parameter_Aep = 3.0*shearModulus + bulkModulus*b*b_dilation + hardeningRate + delta_lambda = delta_time_anal / relaxationTime * (F_anal/parameter_Aep) + + # Compute stress and strain variations + delta_ax_stress_anal = ( delta_ax_strain_anal-delta_lambda*(b_dilation-3.0)/3.0 ) * youngModulus + delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / 2.0 / shearModulus + 3.0/2.0*delta_lambda + + # Compute stress and strain at actual loading step + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal + + # Update plastic multiplier + plasticMultiplier += delta_lambda + + else: #unloading + + F_anal = -q_anal + b*p_anal - b*a_init/b_init # negative sign added to q for q<0 to obtain the absolute value + + if(F_anal>=0): + b = b_init + plasticMultiplier/(hardeningParameter+plasticMultiplier) * (b_resi - b_init) + b_dilation = b*dilationRatio + + dF_db = p_anal - a_init/b_init + db_dlambda = hardeningParameter * (b_resi - b_init) / (hardeningParameter+plasticMultiplier) / (hardeningParameter+plasticMultiplier) + hardeningRate = -dF_db*db_dlambda + + # Variation of Perzyna plastic multiplier, see Runesson et al. 1999, see Eq. 56, 4, 80, 62, 63 + parameter_Aep = 3.0*shearModulus + bulkModulus*b*b_dilation + hardeningRate + delta_lambda = delta_time_anal / relaxationTime * (F_anal/parameter_Aep) + + # Compute stress and strain variations + delta_ax_stress_anal = ( delta_ax_strain_anal-delta_lambda*(b_dilation+3.0)/3.0 ) * youngModulus + delta_ra_strain_anal = delta_ax_strain_anal - delta_ax_stress_anal / 2.0 / shearModulus - 3.0/2.0*delta_lambda + + # Compute stress and strain at actual loading step + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_strain_anal = list_ra_strain_anal[idx-1] + delta_ra_strain_anal + + # Update plastic multiplier + plasticMultiplier += delta_lambda + + list_ax_stress_anal[idx] = ax_stress_anal + list_ra_strain_anal[idx] = ra_strain_anal + + # Preparing data for visualizing semi-analytical results + list_p_anal = (list_ax_stress_anal + 2.0 * list_ra_stress_anal) / 3.0 + list_q_anal = -(list_ax_stress_anal - list_ra_stress_anal) + + list_strain_vol_anal = list_ax_strain_anal + 2.0 * list_ra_strain_anal + + p_num = (ax_stress + 2.0 * ra_stress1) / 3.0 + q_num = -(ax_stress - ra_stress1) + + strain_vol = ax_strain + 2.0 * ra_strain1 + + #Visualization parameters + fsize = 30 + msize = 12 + lw = 6 + malpha = 0.5 + fig, ax = plt.subplots(1, 3, figsize=(37, 10)) + cmap = plt.get_cmap("tab10") + + # Plot strain versus shear stress + ax[0].plot(-ax_strain * 100, #convert to % + q_num*1e-6, #convert to MPa + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[0].plot(-ra_strain1 * 100, + q_num*1e-6, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha) + ax[0].plot(-list_ax_strain_anal* 100, + list_q_anal*1e-6, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[0].plot(-list_ra_strain_anal * 100, + list_q_anal*1e-6, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + linewidth=6) + ax[0].set_xlabel(r'Strain (%)', size=fsize, weight="bold") + ax[0].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") + ax[0].xaxis.set_tick_params(labelsize=fsize) + ax[0].yaxis.set_tick_params(labelsize=fsize) + + # Plot axial strain versus volumetric strain + ax[1].plot(-ax_strain * 100, + -strain_vol * 100, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[1].plot(-list_ax_strain_anal* 100, + -list_strain_vol_anal* 100, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[1].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") + ax[1].set_ylabel(r'Volumetric Strain (%)', size=fsize, weight="bold") + #ax[1].legend(loc='lower right', fontsize=fsize) + ax[1].xaxis.set_tick_params(labelsize=fsize) + ax[1].yaxis.set_tick_params(labelsize=fsize) + + # Plot shear stress versus mean stress + ax[2].plot(-p_num*1e-6, + q_num*1e-6, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[2].plot(-list_p_anal*1e-6, + list_q_anal*1e-6, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[2].set_xlabel(r'Mean stress (MPa)', size=fsize, weight="bold") + ax[2].set_ylabel(r'Deviatoric Stress (MPa)', size=fsize, weight="bold") + ax[2].legend(loc='lower right', fontsize=fsize) + ax[2].xaxis.set_tick_params(labelsize=fsize) + ax[2].yaxis.set_tick_params(labelsize=fsize) + + plt.subplots_adjust(left=0.2, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4) + plt.show() + if __name__ == "__main__": main() diff --git a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoModifiedCamClay/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoModifiedCamClay/Example.rst index 8972eed2f22..964ffbcbb2c 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoModifiedCamClay/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoModifiedCamClay/Example.rst @@ -103,4 +103,4 @@ To go further **Feedback on this example** -For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. +For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. diff --git a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoModifiedCamClay/TriaxialDriver_vs_SemiAnalytic_ViscoModifiedCamClay.py b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoModifiedCamClay/TriaxialDriver_vs_SemiAnalytic_ViscoModifiedCamClay.py index 019252903c8..3b4cc7e8fd8 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoModifiedCamClay/TriaxialDriver_vs_SemiAnalytic_ViscoModifiedCamClay.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/viscoplasticity/ViscoModifiedCamClay/TriaxialDriver_vs_SemiAnalytic_ViscoModifiedCamClay.py @@ -3,214 +3,230 @@ import numpy as np import matplotlib.pyplot as plt import xml.etree.ElementTree as ElementTree +import os +import argparse def main(): - # File paths - path = "ViscoModifiedCamClayResults.txt" - timeFilePath = "../../../../../../../inputFiles/triaxialDriver/tables/time.geos" - xmlFilePath = "../../../../../../../inputFiles/triaxialDriver/triaxialDriver_base.xml" - xmlFilePath_case = "../../../../../../../inputFiles/triaxialDriver/triaxialDriver_ViscoModifiedCamClay.xml" - imposedStrainFilePath = "../../../../../../../inputFiles/triaxialDriver/tables/axialStrain.geos" - - # Load GEOSX results - time, ax_strain, ra_strain1, ra_strain2, ax_stress, ra_stress1, ra_stress2, newton_iter, residual_norm = np.loadtxt( - path, skiprows=5, unpack=True) - - # Extract mechanical parameters from XML file - tree = ElementTree.parse(xmlFilePath) - tree_case = ElementTree.parse(xmlFilePath_case) - model = tree_case.find('Tasks/TriaxialDriver') - param = tree.find('Constitutive/ViscoModifiedCamClay') - - refPressure = float(param.get("defaultRefPressure")) - refStrainVol = float(param.get("defaultRefStrainVol")) - shearModulus = float(param.get("defaultShearModulus")) - preConsolidationPressure = float(param.get("defaultPreConsolidationPressure")) - cslSlope = float(param.get("defaultCslSlope")) - virginCompressionIndex = float(param.get("defaultVirginCompressionIndex")) - recompressionIndex = float(param.get("defaultRecompressionIndex")) - relaxationTime = float(param.get("relaxationTime")) - initialStress = float(model.get("initialStress")) - - # Extract loading from input tables - imp_strain = np.loadtxt( - imposedStrainFilePath, skiprows=0, unpack=True) - - list_ax_strain_anal = [] - numStepPerLoadingPeriod = 10001 - - for i in range(0,len(imp_strain)-1): - dStrainPerStep = (imp_strain[i+1]-imp_strain[i])/numStepPerLoadingPeriod - loadingPeriod = np.arange(imp_strain[i],imp_strain[i+1]+dStrainPerStep,dStrainPerStep) - list_ax_strain_anal = np.concatenate((list_ax_strain_anal, loadingPeriod), axis=0) - - # Extract time from input tables - imp_time = np.loadtxt( - timeFilePath, skiprows=0, unpack=True) - - list_time_anal = [] - for i in range(0,len(imp_time)-1): - dTimePerStep = (imp_time[i+1]-imp_time[i])/numStepPerLoadingPeriod - timePeriod = np.arange(imp_time[i],imp_time[i+1]+dTimePerStep,dTimePerStep) - list_time_anal = np.concatenate((list_time_anal, timePeriod), axis=0) - - list_ax_stress_anal = np.zeros(len(list_ax_strain_anal)) - list_ra_stress_anal = np.zeros(len(list_ax_strain_anal)) - list_ra_strain_anal = np.zeros(len(list_ax_strain_anal)) - - p_anal = refPressure - list_ax_strain_anal += refStrainVol # Oedometric compaction: zero lateral strain - list_ax_stress_anal += initialStress # Assuming isotropic initial stress condition - list_ra_stress_anal += initialStress - - for idx in range(1,len(list_ax_strain_anal)): - delta_ax_strain_anal = list_ax_strain_anal[idx]-list_ax_strain_anal[idx-1] - delta_ra_strain_anal = 0 - - # Compute elastic moduli - bulkModulus = - p_anal/recompressionIndex - lameModulus = bulkModulus - 2.0/3.0*shearModulus - - # Elastic trial - delta_ax_stress_anal = (lameModulus+2.0*shearModulus)*delta_ax_strain_anal + 2.0*lameModulus*delta_ra_strain_anal - delta_ra_stress_anal = lameModulus*delta_ax_strain_anal + (2.0*lameModulus+2.0*shearModulus)*delta_ra_strain_anal - - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_stress_anal = list_ra_stress_anal[idx-1] + delta_ra_stress_anal - - p_anal = (ax_stress_anal + 2.0*ra_stress_anal)/3.0 - q_anal = -(ax_stress_anal - ra_stress_anal) - - # Plastic correction - F_anal = q_anal*q_anal/(cslSlope*cslSlope) + p_anal*(p_anal-preConsolidationPressure) - - if(F_anal>=0): - # Derivatives - dF_dp = 2.0*p_anal-preConsolidationPressure - dF_dq = 2.0*q_anal/(cslSlope*cslSlope) - dF_dpc = -p_anal - - dG_dp = dF_dp # associated plastic rule was considered - dG_dq = dF_dq - - dpc_dlambda = -preConsolidationPressure/(virginCompressionIndex-recompressionIndex)*dG_dp - hardeningRate = -dF_dpc*dpc_dlambda - - # See Runesson et al. 1999, see Eq. 29 - parameter_Aep = 3.0*shearModulus*dF_dq*dG_dq + bulkModulus*dF_dp*dG_dp + hardeningRate - - # Compute stress variations - delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] - delta_time_anal = list_time_anal[idx]-list_time_anal[idx-1] - - delta_strain_vol = delta_ax_strain_anal - delta_strain_shear = -delta_ax_strain_anal #3/2*delta_gamma - - # See Runesson et al. 1999, see Eq. 4, 80, 62, 63 - delta_lambda = delta_time_anal / relaxationTime * (F_anal/parameter_Aep) - delta_p_anal = (delta_strain_vol - delta_lambda*dG_dp)*bulkModulus - delta_q_anal = (delta_strain_shear - 3.0/2.0*delta_lambda*dG_dq)*2.0*shearModulus - - delta_ax_stress_anal = (3.0*delta_p_anal - 2.0*delta_q_anal)/3.0 - delta_ra_stress_anal = delta_ax_stress_anal + delta_q_anal - - # Update stress - ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal - ra_stress_anal = list_ra_stress_anal[idx-1] + delta_ra_stress_anal - - delta_pc = dpc_dlambda * delta_lambda - preConsolidationPressure += delta_pc - - list_ax_stress_anal[idx] = ax_stress_anal - list_ra_stress_anal[idx] = ra_stress_anal - - list_p_anal = (list_ax_stress_anal + 2.0 * list_ra_stress_anal) / 3.0 - list_q_anal = -(list_ax_stress_anal - list_ra_stress_anal) - - list_strain_vol_anal = list_ax_strain_anal + 2.0 * list_ra_strain_anal - - p_num = (ax_stress + 2.0 * ra_stress1) / 3.0 - q_num = -(ax_stress - ra_stress1) - - #Visualization parameters - fsize = 30 - msize = 12 - lw = 6 - malpha = 0.5 - fig, ax = plt.subplots(1, 3, figsize=(37, 10)) - cmap = plt.get_cmap("tab10") - - ax[0].plot(-ax_strain * 100, #convert to % - -ax_stress*1e-3, #convert to kPa - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[0].plot(-list_ax_strain_anal* 100, - -list_ax_stress_anal*1e-3, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - - ax[0].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") - ax[0].set_ylabel(r'Axial Stress (kPa)', size=fsize, weight="bold") - #ax[0].legend(loc='lower right', fontsize=fsize) - ax[0].xaxis.set_tick_params(labelsize=fsize) - ax[0].yaxis.set_tick_params(labelsize=fsize) - - ax[1].plot(-ax_strain * 100, - -ra_stress1 * 1e-3, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[1].plot(-list_ax_strain_anal* 100, - -list_ra_stress_anal* 1e-3, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[1].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") - ax[1].set_ylabel(r'Radial stress (kPa)', size=fsize, weight="bold") - #ax[1].legend(loc='lower right', fontsize=fsize) - ax[1].xaxis.set_tick_params(labelsize=fsize) - ax[1].yaxis.set_tick_params(labelsize=fsize) - - # Plan p-q - ax[2].plot(-p_num*1e-3, - q_num*1e-3, - 'o', - color=cmap(0), - mec='b', - markersize=msize, - alpha=malpha, - label='Triaxial Driver') - ax[2].plot(-list_p_anal*1e-3, - list_q_anal*1e-3, - '-', - color='r', - mec='r', - markersize=msize, - alpha=malpha, - label='Semi-Analytical', linewidth=6) - ax[2].set_xlabel(r'Mean stress (kPa)', size=fsize, weight="bold") - ax[2].set_ylabel(r'Deviatoric Stress (kPa)', size=fsize, weight="bold") - ax[2].legend(loc='lower right', fontsize=fsize) - ax[2].xaxis.set_tick_params(labelsize=fsize) - ax[2].yaxis.set_tick_params(labelsize=fsize) - - plt.subplots_adjust(left=0.2, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4) - - plt.show() + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + + # File paths + outputDir = args.outputDir + geosDir = args.geosDir + + path = outputDir + "/ViscoModifiedCamClayResults.txt" + timeFilePath = geosDir + "/inputFiles/triaxialDriver/tables/time.geos" + xmlFilePath = geosDir + "/inputFiles/triaxialDriver/triaxialDriver_base.xml" + xmlFilePath_case = geosDir + "/inputFiles/triaxialDriver/triaxialDriver_ViscoModifiedCamClay.xml" + imposedStrainFilePath = geosDir + "/inputFiles/triaxialDriver/tables/axialStrain.geos" + + # Load GEOSX results + time, ax_strain, ra_strain1, ra_strain2, ax_stress, ra_stress1, ra_stress2, newton_iter, residual_norm = np.loadtxt( + path, skiprows=5, unpack=True) + + # Extract mechanical parameters from XML file + tree = ElementTree.parse(xmlFilePath) + tree_case = ElementTree.parse(xmlFilePath_case) + model = tree_case.find('Tasks/TriaxialDriver') + param = tree.find('Constitutive/ViscoModifiedCamClay') + + refPressure = float(param.get("defaultRefPressure")) + refStrainVol = float(param.get("defaultRefStrainVol")) + shearModulus = float(param.get("defaultShearModulus")) + preConsolidationPressure = float(param.get("defaultPreConsolidationPressure")) + cslSlope = float(param.get("defaultCslSlope")) + virginCompressionIndex = float(param.get("defaultVirginCompressionIndex")) + recompressionIndex = float(param.get("defaultRecompressionIndex")) + relaxationTime = float(param.get("relaxationTime")) + initialStress = float(model.get("initialStress")) + + # Extract loading from input tables + imp_strain = np.loadtxt( + imposedStrainFilePath, skiprows=0, unpack=True) + + list_ax_strain_anal = [] + numStepPerLoadingPeriod = 10001 + + for i in range(0,len(imp_strain)-1): + dStrainPerStep = (imp_strain[i+1]-imp_strain[i])/numStepPerLoadingPeriod + loadingPeriod = np.arange(imp_strain[i],imp_strain[i+1]+dStrainPerStep,dStrainPerStep) + list_ax_strain_anal = np.concatenate((list_ax_strain_anal, loadingPeriod), axis=0) + + # Extract time from input tables + imp_time = np.loadtxt( + timeFilePath, skiprows=0, unpack=True) + + list_time_anal = [] + for i in range(0,len(imp_time)-1): + dTimePerStep = (imp_time[i+1]-imp_time[i])/numStepPerLoadingPeriod + timePeriod = np.arange(imp_time[i],imp_time[i+1]+dTimePerStep,dTimePerStep) + list_time_anal = np.concatenate((list_time_anal, timePeriod), axis=0) + + list_ax_stress_anal = np.zeros(len(list_ax_strain_anal)) + list_ra_stress_anal = np.zeros(len(list_ax_strain_anal)) + list_ra_strain_anal = np.zeros(len(list_ax_strain_anal)) + + p_anal = refPressure + list_ax_strain_anal += refStrainVol # Oedometric compaction: zero lateral strain + list_ax_stress_anal += initialStress # Assuming isotropic initial stress condition + list_ra_stress_anal += initialStress + + for idx in range(1,len(list_ax_strain_anal)): + delta_ax_strain_anal = list_ax_strain_anal[idx]-list_ax_strain_anal[idx-1] + delta_ra_strain_anal = 0 + + # Compute elastic moduli + bulkModulus = - p_anal/recompressionIndex + lameModulus = bulkModulus - 2.0/3.0*shearModulus + + # Elastic trial + delta_ax_stress_anal = (lameModulus+2.0*shearModulus)*delta_ax_strain_anal + 2.0*lameModulus*delta_ra_strain_anal + delta_ra_stress_anal = lameModulus*delta_ax_strain_anal + (2.0*lameModulus+2.0*shearModulus)*delta_ra_strain_anal + + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_stress_anal = list_ra_stress_anal[idx-1] + delta_ra_stress_anal + + p_anal = (ax_stress_anal + 2.0*ra_stress_anal)/3.0 + q_anal = -(ax_stress_anal - ra_stress_anal) + + # Plastic correction + F_anal = q_anal*q_anal/(cslSlope*cslSlope) + p_anal*(p_anal-preConsolidationPressure) + + if(F_anal>=0): + # Derivatives + dF_dp = 2.0*p_anal-preConsolidationPressure + dF_dq = 2.0*q_anal/(cslSlope*cslSlope) + dF_dpc = -p_anal + + dG_dp = dF_dp # associated plastic rule was considered + dG_dq = dF_dq + + dpc_dlambda = -preConsolidationPressure/(virginCompressionIndex-recompressionIndex)*dG_dp + hardeningRate = -dF_dpc*dpc_dlambda + + # See Runesson et al. 1999, see Eq. 29 + parameter_Aep = 3.0*shearModulus*dF_dq*dG_dq + bulkModulus*dF_dp*dG_dp + hardeningRate + + # Compute stress variations + delta_ax_strain_anal = list_ax_strain_anal[idx] - list_ax_strain_anal[idx-1] + delta_time_anal = list_time_anal[idx]-list_time_anal[idx-1] + + delta_strain_vol = delta_ax_strain_anal + delta_strain_shear = -delta_ax_strain_anal #3/2*delta_gamma + + # See Runesson et al. 1999, see Eq. 4, 80, 62, 63 + delta_lambda = delta_time_anal / relaxationTime * (F_anal/parameter_Aep) + delta_p_anal = (delta_strain_vol - delta_lambda*dG_dp)*bulkModulus + delta_q_anal = (delta_strain_shear - 3.0/2.0*delta_lambda*dG_dq)*2.0*shearModulus + + delta_ax_stress_anal = (3.0*delta_p_anal - 2.0*delta_q_anal)/3.0 + delta_ra_stress_anal = delta_ax_stress_anal + delta_q_anal + + # Update stress + ax_stress_anal = list_ax_stress_anal[idx-1] + delta_ax_stress_anal + ra_stress_anal = list_ra_stress_anal[idx-1] + delta_ra_stress_anal + + delta_pc = dpc_dlambda * delta_lambda + preConsolidationPressure += delta_pc + + list_ax_stress_anal[idx] = ax_stress_anal + list_ra_stress_anal[idx] = ra_stress_anal + + list_p_anal = (list_ax_stress_anal + 2.0 * list_ra_stress_anal) / 3.0 + list_q_anal = -(list_ax_stress_anal - list_ra_stress_anal) + + list_strain_vol_anal = list_ax_strain_anal + 2.0 * list_ra_strain_anal + + p_num = (ax_stress + 2.0 * ra_stress1) / 3.0 + q_num = -(ax_stress - ra_stress1) + + #Visualization parameters + fsize = 30 + msize = 12 + lw = 6 + malpha = 0.5 + fig, ax = plt.subplots(1, 3, figsize=(37, 10)) + cmap = plt.get_cmap("tab10") + + ax[0].plot(-ax_strain * 100, #convert to % + -ax_stress*1e-3, #convert to kPa + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[0].plot(-list_ax_strain_anal* 100, + -list_ax_stress_anal*1e-3, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + + ax[0].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") + ax[0].set_ylabel(r'Axial Stress (kPa)', size=fsize, weight="bold") + #ax[0].legend(loc='lower right', fontsize=fsize) + ax[0].xaxis.set_tick_params(labelsize=fsize) + ax[0].yaxis.set_tick_params(labelsize=fsize) + + ax[1].plot(-ax_strain * 100, + -ra_stress1 * 1e-3, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[1].plot(-list_ax_strain_anal* 100, + -list_ra_stress_anal* 1e-3, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[1].set_xlabel(r'Axial Strain (%)', size=fsize, weight="bold") + ax[1].set_ylabel(r'Radial stress (kPa)', size=fsize, weight="bold") + #ax[1].legend(loc='lower right', fontsize=fsize) + ax[1].xaxis.set_tick_params(labelsize=fsize) + ax[1].yaxis.set_tick_params(labelsize=fsize) + + # Plan p-q + ax[2].plot(-p_num*1e-3, + q_num*1e-3, + 'o', + color=cmap(0), + mec='b', + markersize=msize, + alpha=malpha, + label='Triaxial Driver') + ax[2].plot(-list_p_anal*1e-3, + list_q_anal*1e-3, + '-', + color='r', + mec='r', + markersize=msize, + alpha=malpha, + label='Semi-Analytical', linewidth=6) + ax[2].set_xlabel(r'Mean stress (kPa)', size=fsize, weight="bold") + ax[2].set_ylabel(r'Deviatoric Stress (kPa)', size=fsize, weight="bold") + ax[2].legend(loc='lower right', fontsize=fsize) + ax[2].xaxis.set_tick_params(labelsize=fsize) + ax[2].yaxis.set_tick_params(labelsize=fsize) + + plt.subplots_adjust(left=0.2, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4) + + plt.show() if __name__ == "__main__": main() diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/Index.rst b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/Index.rst index 50db465e790..d56e9e5fe2c 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/Index.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/Index.rst @@ -25,7 +25,11 @@ Wellbore Problems verticalPoroElastoPlasticWellbore/Example - pureThermalDiffusion/Example + linearThermalDiffusion/Example + + nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/Example + + nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/Example casedThermoElasticWellbore/Example @@ -35,5 +39,7 @@ Wellbore Problems casedContactThermoElasticWellbore/Example + + diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactElasticWellbore/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactElasticWellbore/Example.rst index 0fa899e49b3..58b71536263 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactElasticWellbore/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactElasticWellbore/Example.rst @@ -1,9 +1,9 @@ .. _AdvancedExampleCasedElasticWellbore_ImperfectInterfaces: -############################################### +################################################ Cased Elastic Wellbore with Imperfect Interfaces -############################################### +################################################ ------------------------------------------------------------------ Problem description @@ -149,4 +149,4 @@ To go further **Feedback on this example** This concludes the cased wellbore example. -For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. +For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactElasticWellbore/elastic_casedWellbore_displacementJump.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactElasticWellbore/elastic_casedWellbore_displacementJump.py index 54d4738a790..6f319c97a47 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactElasticWellbore/elastic_casedWellbore_displacementJump.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactElasticWellbore/elastic_casedWellbore_displacementJump.py @@ -13,8 +13,8 @@ def main(): # Plot GEOSX results hf = h5py.File(hdf5FilePath, 'r') - time = np.array( hf.get('displacementJump Time') ) - displacementJump = np.array( hf.get('displacementJump') ) + time = np.asarray( hf.get('displacementJump Time') ) + displacementJump = np.asarray( hf.get('displacementJump') ) nTime = time.shape[0] diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/Example.rst index fb56a974211..4003200ef5c 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/Example.rst @@ -111,8 +111,6 @@ The GEOS results of displacement jump across the casing-cement and cement-rock i The GEOS results and analytical results for temperature distribution around the cased wellbore are shown in the figures below: -.. plot:: docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/thermoElastic_casedContactWellbore_temperature.py - .. _problemCasedContactThermoElasticWellbore_Temperature_Fig: .. figure:: temperature.png :align: center @@ -123,8 +121,6 @@ The GEOS results and analytical results for temperature distribution around the and the radial displacement around the wellbore is shown below: -.. plot:: docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/thermoElastic_casedContactWellbore_displacement.py - .. _problemCasedContactThermoElasticWellbore_Displacement_Fig: .. figure:: displacement.png :align: center @@ -135,8 +131,6 @@ and the radial displacement around the wellbore is shown below: The total radial and hoop stress (tangential stress) components computed by GEOS and the reference results are shown in the figure below: -.. plot:: docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/thermoElastic_casedContactWellbore_stress.py - .. _problemCasedContactThermoElasticWellbore_Stresses_Fig: .. figure:: stress.png :align: center diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/displacement.png b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/displacement.png index df01b457dea..33fa56d5f18 100644 Binary files a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/displacement.png and b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/displacement.png differ diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/stress.png b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/stress.png index 56803c8346e..ab374ac4690 100644 Binary files a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/stress.png and b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/stress.png differ diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/temperature.png b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/temperature.png index 4e60f1b8d0e..9ecd9513fd8 100644 Binary files a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/temperature.png and b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/temperature.png differ diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/thermoElastic_casedContactWellbore_displacement.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/thermoElastic_casedContactWellbore_displacement.py index 4dd517042ca..ec2a13f547a 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/thermoElastic_casedContactWellbore_displacement.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/thermoElastic_casedContactWellbore_displacement.py @@ -13,9 +13,9 @@ def main(): # Plot GEOSX results hf = h5py.File(hdf5FilePath, 'r') - time = np.array( hf.get('totalDisplacement Time') ) - center = np.array( hf.get('totalDisplacement ReferencePosition') ) - displacement = np.array( hf.get('totalDisplacement') ) + time = np.asarray( hf.get('totalDisplacement Time') ) + center = np.asarray( hf.get('totalDisplacement ReferencePosition') ) + displacement = np.asarray( hf.get('totalDisplacement') ) nNodes = center.shape[1] xCoord = center[0, 0:nNodes, 0] @@ -49,7 +49,7 @@ def main(): plt.plot( displacement_radial_analytic_1e4s[:,0], displacement_radial_analytic_1e4s[:,1], 'r-', - label='Analytic, no debonding: t = 1e4 (s)') + label='Analytic: t = 1e4 (s)') # Plot radial displacement at 1e5 (s) plt.plot( rCoord, @@ -60,7 +60,7 @@ def main(): plt.plot( displacement_radial_analytic_1e5s[:,0], displacement_radial_analytic_1e5s[:,1], 'b-', - label='Analytic, no debonding: t = 1e5 (s)') + label='Analytic: t = 1e5 (s)') plt.grid() plt.ylabel(r'Displacement [m]') diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/thermoElastic_casedContactWellbore_stress.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/thermoElastic_casedContactWellbore_stress.py index dfdb898838d..6a641106112 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/thermoElastic_casedContactWellbore_stress.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/thermoElastic_casedContactWellbore_stress.py @@ -30,13 +30,13 @@ def main(): # Get stress, time and element center hf_stress = h5py.File(filePath_stress, 'r') - time = np.array( hf_stress.get(stress_field_name + ' Time') ) - center = np.array( hf_stress.get(stress_field_name + ' elementCenter') ) - stress = np.array( hf_stress.get(stress_field_name) ) + time = np.asarray( hf_stress.get(stress_field_name + ' Time') ) + center = np.asarray( hf_stress.get(stress_field_name + ' elementCenter') ) + stress = np.asarray( hf_stress.get(stress_field_name) ) # Get temperature hf_temperature = h5py.File(filePath_temperature, 'r') - temperature = np.array( hf_temperature.get('temperature') ) + temperature = np.asarray( hf_temperature.get('temperature') ) # Compute total stress stress_xx_total = stress[:,:,0] - 3 * bulkModuli[idx] * thermalExpansionCoefficients[idx] * temperature diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/thermoElastic_casedContactWellbore_temperature.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/thermoElastic_casedContactWellbore_temperature.py index 0d93502677d..112a18e726b 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/thermoElastic_casedContactWellbore_temperature.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedContactThermoElasticWellbore/thermoElastic_casedContactWellbore_temperature.py @@ -18,9 +18,9 @@ def main(): for filePath in hdf5FilePath: hf = h5py.File(filePath, 'r') - time = np.array( hf.get('temperature Time') ) - center = np.array( hf.get('temperature elementCenter') ) - temperature = np.array( hf.get('temperature') ) + time = np.asarray( hf.get('temperature Time') ) + center = np.asarray( hf.get('temperature elementCenter') ) + temperature = np.asarray( hf.get('temperature') ) nElements = center.shape[1] xCoord = center[0, 0:nElements, 0] @@ -29,7 +29,7 @@ def main(): if (hasLabel): plt.plot( rCoord, - temperature[10, 0:nElements], + temperature[10, 0:nElements], 'r+', label='GEOS: t = 1e4 (s)') diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/Example.rst index c48146a0053..bad01dcc9a7 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/Example.rst @@ -212,8 +212,6 @@ Results and benchmark A good agreement between the GEOS results and analytical results for temperature distribution around the cased wellbore is shown in the figures below: -.. plot:: docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/thermoElastic_casedWellbore_temperature.py - .. _problemCasedThermoElasticWellbore_Temperature_Fig: .. figure:: temperature.png :align: center @@ -224,8 +222,6 @@ A good agreement between the GEOS results and analytical results for temperature and the validation for the radial displacement around the cased wellbore is shown below: -.. plot:: docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/thermoElastic_casedWellbore_displacement.py - .. _problemCasedThermoElasticWellbore_Displacement_Fig: .. figure:: displacement.png :align: center @@ -236,8 +232,6 @@ and the validation for the radial displacement around the cased wellbore is show The validations of the total radial and hoop stress (tangent stress) components computed by GEOS against reference results are shown in the figure below: -.. plot:: docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/thermoElastic_casedWellbore_stress.py - .. _problemCasedThermoElasticWellbore_Stresses_Fig: .. figure:: stress.png :align: center diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/thermoElastic_casedWellbore_displacement.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/thermoElastic_casedWellbore_displacement.py index e3179d7296b..e6189fe2c71 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/thermoElastic_casedWellbore_displacement.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/thermoElastic_casedWellbore_displacement.py @@ -13,9 +13,9 @@ def main(): # Get GEOS results hf = h5py.File(hdf5FilePath, 'r') - time = np.array( hf.get('totalDisplacement Time') ) - center = np.array( hf.get('totalDisplacement ReferencePosition') ) - displacement = np.array( hf.get('totalDisplacement') ) + time = np.asarray( hf.get('totalDisplacement Time') ) + center = np.asarray( hf.get('totalDisplacement ReferencePosition') ) + displacement = np.asarray( hf.get('totalDisplacement') ) nNodes = center.shape[1] xCoord = center[0, 0:nNodes, 0] diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/thermoElastic_casedWellbore_stress.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/thermoElastic_casedWellbore_stress.py index 54cd5044145..e6ec6e50296 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/thermoElastic_casedWellbore_stress.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/thermoElastic_casedWellbore_stress.py @@ -31,13 +31,13 @@ def main(): # Get stress, time and element center hf_stress = h5py.File(filePath_stress, 'r') - time = np.array( hf_stress.get(stress_field_name + ' Time') ) - center = np.array( hf_stress.get(stress_field_name + ' elementCenter') ) - stress = np.array( hf_stress.get(stress_field_name) ) + time = np.asarray( hf_stress.get(stress_field_name + ' Time') ) + center = np.asarray( hf_stress.get(stress_field_name + ' elementCenter') ) + stress = np.asarray( hf_stress.get(stress_field_name) ) # Get temperature hf_temperature = h5py.File(filePath_temperature, 'r') - temperature = np.array( hf_temperature.get('temperature') ) + temperature = np.asarray( hf_temperature.get('temperature') ) # Compute total stress: # With the actual version of GEOS, the output stress need to be combined with the temperature contribution to obtain the total tress as follows: diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/thermoElastic_casedWellbore_temperature.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/thermoElastic_casedWellbore_temperature.py index 6f942827d58..84c3758b636 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/thermoElastic_casedWellbore_temperature.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/casedThermoElasticWellbore/thermoElastic_casedWellbore_temperature.py @@ -18,9 +18,9 @@ def main(): for filePath in hdf5FilePath: hf = h5py.File(filePath, 'r') - time = np.array( hf.get('temperature Time') ) - center = np.array( hf.get('temperature elementCenter') ) - temperature = np.array( hf.get('temperature') ) + time = np.asarray( hf.get('temperature Time') ) + center = np.asarray( hf.get('temperature elementCenter') ) + temperature = np.asarray( hf.get('temperature') ) nElements = center.shape[1] xCoord = center[0, 0:nElements, 0] diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/deviatedPoroElasticWellbore/deviatedPoroElasticWellboreExample1Figure.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/deviatedPoroElasticWellbore/deviatedPoroElasticWellboreExample1Figure.py index 3ee5c1af5f4..51ba65feb99 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/deviatedPoroElasticWellbore/deviatedPoroElasticWellboreExample1Figure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/deviatedPoroElasticWellbore/deviatedPoroElasticWellboreExample1Figure.py @@ -3,6 +3,8 @@ import numpy as np import matplotlib.pyplot as plt import xml.etree.ElementTree as ElementTree +import os +import argparse def FFunction(s, R): @@ -94,7 +96,7 @@ def getParametersFromXML(xmlFilePath): porosity = float(tree.find('Constitutive/BiotPorosity').get('defaultReferencePorosity')) - skeletonBulkModulus = float(tree.find('Constitutive/BiotPorosity').get('grainBulkModulus')) + skeletonBulkModulus = float(tree.find('Constitutive/BiotPorosity').get('defaultGrainBulkModulus')) fluidCompressibility = float(tree.find('Constitutive/CompressibleSinglePhaseFluid').get('compressibility')) bBiot = 1.0 - bulkModulus / skeletonBulkModulus @@ -131,7 +133,21 @@ def getWellboreGeometryFromXML(xmlFilePath): def main(): - xmlFilePathPrefix = "../../../../../../../inputFiles/wellbore/DeviatedPoroElasticWellbore_Injection" + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + + outputDir = args.outputDir + geosDir = args.geosDir + + xmlFilePathPrefix = geosDir + "/inputFiles/wellbore/DeviatedPoroElasticWellbore_Injection" geometry = getWellboreGeometryFromXML(xmlFilePathPrefix + "_benchmark.xml") parameters = getParametersFromXML(xmlFilePathPrefix + "_base.xml") @@ -187,7 +203,7 @@ def main(): # Get stress_ij and pore pressure # Data are extracted along the y-axis from the wellbore center r, pPore, stress_11, stress_12, stress_13, stress_22, stress_23, stress_33 = [], [], [], [], [], [], [], [] - for line in open('stress_11.curve', 'r'): + for line in open( outputDir + '/stress_11.curve', 'r'): if not (line.strip().startswith("#") or line.strip() == ''): values = [float(s) for s in line.split()] rval = values[0] @@ -195,37 +211,37 @@ def main(): r.append(rval) stress_11.append(sigVal) - for line in open('stress_12.curve', 'r'): + for line in open( outputDir + '/stress_12.curve', 'r'): if not (line.strip().startswith("#") or line.strip() == ''): values = [float(s) for s in line.split()] sigVal = values[1] * 1e-6 # convert to MPa stress_12.append(sigVal) - for line in open('stress_13.curve', 'r'): + for line in open( outputDir + '/stress_13.curve', 'r'): if not (line.strip().startswith("#") or line.strip() == ''): values = [float(s) for s in line.split()] sigVal = values[1] * 1e-6 # convert to MPa stress_13.append(sigVal) - for line in open('stress_22.curve', 'r'): + for line in open( outputDir + '/stress_22.curve', 'r'): if not (line.strip().startswith("#") or line.strip() == ''): values = [float(s) for s in line.split()] sigVal = values[1] * 1e-6 # convert to MPa stress_22.append(sigVal) - for line in open('stress_23.curve', 'r'): + for line in open( outputDir + '/stress_23.curve', 'r'): if not (line.strip().startswith("#") or line.strip() == ''): values = [float(s) for s in line.split()] sigVal = values[1] * 1e-6 # convert to MPa stress_23.append(sigVal) - for line in open('stress_33.curve', 'r'): + for line in open( outputDir + '/stress_33.curve', 'r'): if not (line.strip().startswith("#") or line.strip() == ''): values = [float(s) for s in line.split()] sigVal = values[1] * 1e-6 # convert to MPa stress_33.append(sigVal) - for line in open('pressure.curve', 'r'): + for line in open( outputDir + '/pressure.curve', 'r'): if not (line.strip().startswith("#") or line.strip() == ''): values = [float(s) for s in line.split()] pPore.append(values[1] * 1e-6) diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/deviatedPoroElasticWellbore/deviatedPoroElasticWellboreExample2Figure.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/deviatedPoroElasticWellbore/deviatedPoroElasticWellboreExample2Figure.py index 24c2132409b..4bf3b74370f 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/deviatedPoroElasticWellbore/deviatedPoroElasticWellboreExample2Figure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/deviatedPoroElasticWellbore/deviatedPoroElasticWellboreExample2Figure.py @@ -4,6 +4,8 @@ import matplotlib.pyplot as plt import wellboreAnalyticalSolutions as analytic import xml.etree.ElementTree as ElementTree +import os +import argparse # Rotate stress from local coordinates of an inclined borehole to the global coordinates system @@ -101,7 +103,7 @@ def getParametersFromXML(xmlFilePath): porosity = float(tree.find('Constitutive/BiotPorosity').get('defaultReferencePorosity')) - skeletonBulkModulus = float(tree.find('Constitutive/BiotPorosity').get('grainBulkModulus')) + skeletonBulkModulus = float(tree.find('Constitutive/BiotPorosity').get('defaultGrainBulkModulus')) fluidCompressibility = float(tree.find('Constitutive/CompressibleSinglePhaseFluid').get('compressibility')) bBiot = 1.0 - bulkModulus / skeletonBulkModulus @@ -141,7 +143,21 @@ def getWellboreGeometryFromXML(xmlFilePath): def main(): - xmlFilePathPrefix = "../../../../../../../inputFiles/wellbore/DeviatedPoroElasticWellbore_Drilling" + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + + outputDir = args.outputDir + geosDir = args.geosDir + + xmlFilePathPrefix = geosDir + "/inputFiles/wellbore/DeviatedPoroElasticWellbore_Drilling" geometry = getWellboreGeometryFromXML(xmlFilePathPrefix + "_benchmark.xml") parameters = getParametersFromXML(xmlFilePathPrefix + "_base.xml") @@ -193,7 +209,7 @@ def main(): # Get radial coordinate and compute analytical results r = [] - for line in open('stress_11_drilling.curve', 'r'): + for line in open( outputDir + '/stress_11_drilling.curve', 'r'): if not (line.strip().startswith("#") or line.strip() == ''): values = [float(s) for s in line.split()] rval = values[0] @@ -202,43 +218,43 @@ def main(): # Get stress_ij and pore pressure # These data are extracted along the y-axis from the well center (theta angle = 90°) stress_11, stress_12, stress_13, stress_22, stress_23, stress_33, pPore = [], [], [], [], [], [], [] - for line in open('stress_11_drilling.curve', 'r'): + for line in open( outputDir + '/stress_11_drilling.curve', 'r'): if not (line.strip().startswith("#") or line.strip() == ''): values = [float(s) for s in line.split()] sigVal = values[1] * 1e-6 # convert to MPa stress_11.append(sigVal) - for line in open('stress_12_drilling.curve', 'r'): + for line in open( outputDir + '/stress_12_drilling.curve', 'r'): if not (line.strip().startswith("#") or line.strip() == ''): values = [float(s) for s in line.split()] sigVal = values[1] * 1e-6 # convert to MPa stress_12.append(sigVal) - for line in open('stress_13_drilling.curve', 'r'): + for line in open( outputDir + '/stress_13_drilling.curve', 'r'): if not (line.strip().startswith("#") or line.strip() == ''): values = [float(s) for s in line.split()] sigVal = values[1] * 1e-6 # convert to MPa stress_13.append(sigVal) - for line in open('stress_22_drilling.curve', 'r'): + for line in open( outputDir + '/stress_22_drilling.curve', 'r'): if not (line.strip().startswith("#") or line.strip() == ''): values = [float(s) for s in line.split()] sigVal = values[1] * 1e-6 # convert to MPa stress_22.append(sigVal) - for line in open('stress_23_drilling.curve', 'r'): + for line in open( outputDir + '/stress_23_drilling.curve', 'r'): if not (line.strip().startswith("#") or line.strip() == ''): values = [float(s) for s in line.split()] sigVal = values[1] * 1e-6 # convert to MPa stress_23.append(sigVal) - for line in open('stress_33_drilling.curve', 'r'): + for line in open( outputDir + '/stress_33_drilling.curve', 'r'): if not (line.strip().startswith("#") or line.strip() == ''): values = [float(s) for s in line.split()] sigVal = values[1] * 1e-6 # convert to MPa stress_33.append(sigVal) - for line in open('pressure_drilling.curve', 'r'): + for line in open( outputDir + '/pressure_drilling.curve', 'r'): if not (line.strip().startswith("#") or line.strip() == ''): values = [float(s) for s in line.split()] pPoreVal = values[1] * 1e-6 # convert to MPa diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/dpWellbore/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/dpWellbore/Example.rst index df0e8f5ba23..25ca393373a 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/dpWellbore/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/dpWellbore/Example.rst @@ -68,9 +68,7 @@ The parameters used in the simulation are summarized in the following table. The validation of GEOS results against analytical results is shown in the figure below: -.. plot:: docs/sphinx/advancedExamples/validationStudies/wellboreProblems/dpWellbore/dpWellbore_plot.py - -.. _edpWellboreVerificationFig: +.. _dpWellboreVerificationFig: .. figure:: dpWellboreVerification.png :align: center :width: 1000 diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/dpWellbore/dpWellbore_plot.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/dpWellbore/dpWellbore_plot.py index f4cc634c4b7..24dd2e4eb2e 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/dpWellbore/dpWellbore_plot.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/dpWellbore/dpWellbore_plot.py @@ -76,14 +76,14 @@ def main(): # Get stress, time and element center from GEOSX results stress_field_name = 'rock_stress' hf_stress = h5py.File('stressHistory_rock.hdf5', 'r') - time = np.array( hf_stress.get(stress_field_name + ' Time') ) - center = np.array( hf_stress.get(stress_field_name + ' elementCenter') ) - stress = np.array( hf_stress.get(stress_field_name) ) + time = np.asarray( hf_stress.get(stress_field_name + ' Time') ) + center = np.asarray( hf_stress.get(stress_field_name + ' elementCenter') ) + stress = np.asarray( hf_stress.get(stress_field_name) ) # Get the deformed wellbore radius hf_disp = h5py.File("displacementHistory.hdf5", 'r') - displacement = np.array( hf_disp.get('totalDisplacement') ) - node_position = np.array( hf_disp.get('totalDisplacement ReferencePosition') ) + displacement = np.asarray( hf_disp.get('totalDisplacement') ) + node_position = np.asarray( hf_disp.get('totalDisplacement ReferencePosition') ) da = displacement[:, 0, 0] a = a0 + da diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/edpWellbore/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/edpWellbore/Example.rst index ea699e22054..f691cd73e2d 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/edpWellbore/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/edpWellbore/Example.rst @@ -201,8 +201,6 @@ Inspecting results In the above example, we requested hdf5 output files. We can therefore use python scripts to visualize the outcome. Below figure shows the comparisons between the numerical predictions (marks) and the corresponding analytical solutions (solid curves) with respect to the distributions of principal stress components, stress path on the wellbore surface, the supporting wellbore pressure and wellbore size. It is clear that the GEOS predictions are in excellent agreement with the analytical results. On the top-right figure, we added also a comparison between GEOS results for elasto-plastic material and the anlytical solutions of an elastic material. Note that the elastic solutions are differed from the elasto-plastic results even in the elastic zone (r/a>2). -.. plot:: docs/sphinx/advancedExamples/validationStudies/wellboreProblems/edpWellbore/edpWellbore_plot.py - .. _edpWellboreVerificationFig: .. figure:: edpWellboreVerification.png :align: center diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/edpWellbore/edpWellbore_plot.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/edpWellbore/edpWellbore_plot.py index cfb316156ac..007ce7f6669 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/edpWellbore/edpWellbore_plot.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/edpWellbore/edpWellbore_plot.py @@ -6,240 +6,256 @@ from xml.etree import ElementTree import edpWellbore_analyticalResults as edpAnal import elastoPlasticWellboreAnalyticalSolutions as epwAnal +import os +import argparse def extractDataFromXMLList(paramList): - # Extract data from a list in XML such as "{ 1, 2, 3}" - return paramList.replace('{', '').replace('}', '').strip().split(',') + # Extract data from a list in XML such as "{ 1, 2, 3}" + return paramList.replace('{', '').replace('}', '').strip().split(',') def getDataFromXML(xmlFilePathPrefix): - # Get wellbore inner radius - xmlFilePath = xmlFilePathPrefix + "_benchmark.xml" - tree = ElementTree.parse(xmlFilePath) + # Get wellbore inner radius + xmlFilePath = xmlFilePathPrefix + "_benchmark.xml" + tree = ElementTree.parse(xmlFilePath) - meshParam = tree.find('Mesh/InternalWellbore') - radii = extractDataFromXMLList( meshParam.get("radius") ) - a0 = float(radii[0]) + meshParam = tree.find('Mesh/InternalWellbore') + radii = extractDataFromXMLList( meshParam.get("radius") ) + a0 = float(radii[0]) - # Get the temperature change on the inner surface of the wellbore - xmlFilePath = xmlFilePathPrefix + "_base.xml" - tree = ElementTree.parse(xmlFilePath) + # Get the temperature change on the inner surface of the wellbore + xmlFilePath = xmlFilePathPrefix + "_base.xml" + tree = ElementTree.parse(xmlFilePath) - fsParams = tree.findall('FieldSpecifications/FieldSpecification') - for fsParam in fsParams: - if fsParam.get('name') == 'stressXX': - sh = float( fsParam.get('scale') ) - if fsParam.get('name') == 'stressZZ': - sv = float( fsParam.get('scale') ) + fsParams = tree.findall('FieldSpecifications/FieldSpecification') + for fsParam in fsParams: + if fsParam.get('name') == 'stressXX': + sh = float( fsParam.get('scale') ) + if fsParam.get('name') == 'stressZZ': + sv = float( fsParam.get('scale') ) - pw = float( extractDataFromXMLList(tree.find('Functions/TableFunction').get('values') )[1]) + pw = float( extractDataFromXMLList(tree.find('Functions/TableFunction').get('values') )[1]) - defaultBulkModulus = float( tree.find('Constitutive/ExtendedDruckerPrager').get('defaultBulkModulus') ) - defaultShearModulus = float( tree.find('Constitutive/ExtendedDruckerPrager').get('defaultShearModulus') ) - defaultCohesion = float( tree.find('Constitutive/ExtendedDruckerPrager').get('defaultCohesion') ) - defaultInitialFrictionAngle = float( tree.find('Constitutive/ExtendedDruckerPrager').get('defaultInitialFrictionAngle') ) - defaultResidualFrictionAngle = float( tree.find('Constitutive/ExtendedDruckerPrager').get('defaultResidualFrictionAngle') ) - defaultDilationRatio = float( tree.find('Constitutive/ExtendedDruckerPrager').get('defaultDilationRatio') ) - defaultHardening = float( tree.find('Constitutive/ExtendedDruckerPrager').get('defaultHardening') ) + defaultBulkModulus = float( tree.find('Constitutive/ExtendedDruckerPrager').get('defaultBulkModulus') ) + defaultShearModulus = float( tree.find('Constitutive/ExtendedDruckerPrager').get('defaultShearModulus') ) + defaultCohesion = float( tree.find('Constitutive/ExtendedDruckerPrager').get('defaultCohesion') ) + defaultInitialFrictionAngle = float( tree.find('Constitutive/ExtendedDruckerPrager').get('defaultInitialFrictionAngle') ) + defaultResidualFrictionAngle = float( tree.find('Constitutive/ExtendedDruckerPrager').get('defaultResidualFrictionAngle') ) + defaultDilationRatio = float( tree.find('Constitutive/ExtendedDruckerPrager').get('defaultDilationRatio') ) + defaultHardening = float( tree.find('Constitutive/ExtendedDruckerPrager').get('defaultHardening') ) - return [a0, sh, sv, pw, defaultBulkModulus, defaultShearModulus, defaultCohesion, defaultInitialFrictionAngle, defaultResidualFrictionAngle, defaultDilationRatio, defaultHardening] + return [a0, sh, sv, pw, defaultBulkModulus, defaultShearModulus, defaultCohesion, defaultInitialFrictionAngle, defaultResidualFrictionAngle, defaultDilationRatio, defaultHardening] def stressRotation(stress, phi_x): rotx = np.array([[np.cos(phi_x), np.sin(phi_x), 0.], [-np.sin(phi_x), np.cos(phi_x), 0.], [0., 0., 1.]]) return np.dot(np.dot(np.transpose(rotx), stress), rotx) def main(): - xmlFilePathPrefix = "../../../../../../../inputFiles/solidMechanics/ExtendedDruckerPragerWellbore" - xmlData = getDataFromXML(xmlFilePathPrefix) - - # Initial wellbore radius - a0 = xmlData[0] - - # Initial stresses - sh = -xmlData[1] #negative sign because of positive sign convention for compression stress in the analytical solution - sv = -xmlData[2] #negative sign because of positive sign convention for compression stress in the analytical solution - - # Boundary condition on the wellbore surface - pw = -xmlData[3] #negative sign because of positive sign convention for compression stress in the analytical solution - # Equivalent displacement condition for the analytical solution - a0_a_ratio = 1.075 # This ratio corresponds to pw, extracted from the relationship between pw and a0/a (see bottom-right figure) - - # Elastic moduli - K = xmlData[4] - G = xmlData[5] - nu = (3.0*K-2.0*G) / (6.0*K+2.0*G) - - # Elasto-plastic parameters - cohesion = xmlData[6] - initialFrictionAngle = xmlData[7] # deg - finalFrictionAngle = xmlData[8] # deg - dilationRatio = xmlData[9] - param_m = xmlData[10] # Extended Drucker-Prager hardening parameter, this is noted by c in the ref. Chen and Abousleiman (2017) - - # Note that the solution developed by Chen and Abousleiman (2017) is for an associated elasto-plastic model (i.e. dilationRatio = 1) with zero cohesion - assert dilationRatio == 1.0, "The associated model is considered by the reference solutions, please set the dilation ratio to 1.0" - assert cohesion == 0.0, "Zero cohesion is considered by the reference solutions, please set the cohesion to 0.0" - - # Get stress, time and element center from GEOSX results - stress_field_name = 'rock_stress' - hf_stress = h5py.File('stressHistory_rock.hdf5', 'r') - time = np.array( hf_stress.get(stress_field_name + ' Time') ) - center = np.array( hf_stress.get(stress_field_name + ' elementCenter') ) - stress = np.array( hf_stress.get(stress_field_name) ) - - # Get the deformed wellbore radius - hf_disp = h5py.File("displacementHistory.hdf5", 'r') - displacement = np.array( hf_disp.get('totalDisplacement') ) - node_position = np.array( hf_disp.get('totalDisplacement ReferencePosition') ) - da = displacement[:, 0, 0] - a = a0 + da - - # Compute total stress, the stress of each element is the average value of its eight Gauss points - nTimeSteps = 30 - stress_xx = ( sum(stress[nTimeSteps,:,6*i+0] for i in range(8)) )/8.0 - stress_yy = ( sum(stress[nTimeSteps,:,6*i+1] for i in range(8)) )/8.0 - stress_zz = ( sum(stress[nTimeSteps,:,6*i+2] for i in range(8)) )/8.0 - stress_yz = ( sum(stress[nTimeSteps,:,6*i+3] for i in range(8)) )/8.0 - stress_xz = ( sum(stress[nTimeSteps,:,6*i+4] for i in range(8)) )/8.0 - stress_xy = ( sum(stress[nTimeSteps,:,6*i+5] for i in range(8)) )/8.0 - - # Coordinate of elemnt center - nElements = center.shape[1] - xCoord = center[0, :, 0] - yCoord = center[0, :, 1] - - rCoord = np.sqrt( xCoord*xCoord + yCoord*yCoord ) - - # Compute stress components in cylindrical coordinate system - stress_rr = np.zeros(stress_xx.shape) - stress_tt = np.zeros(stress_xx.shape) - - for idx_elem in range(stress.shape[1]): - stressMatrix_cartesian = np.array([[stress_xx[idx_elem],stress_xy[idx_elem],stress_xz[idx_elem]],\ - [stress_xy[idx_elem],stress_yy[idx_elem],stress_yz[idx_elem]],\ - [stress_xz[idx_elem],stress_yz[idx_elem],stress_zz[idx_elem]]]) - - if(yCoord[idx_elem] != 0): - phi_x = np.arctan( xCoord[idx_elem]/yCoord[idx_elem] ) - else: - phi_x = 0 - - stressMatrix_cylindirical = stressRotation(stressMatrix_cartesian, phi_x) - stress_rr[idx_elem] = stressMatrix_cylindirical[1][1] - stress_tt[idx_elem] = stressMatrix_cylindirical[0][0] - - # Stress invariants at wellbore surface - stress_xx_wellboresurface = ( sum(stress[:,0,6*i+0] for i in range(8)) )/8.0 - stress_yy_wellboresurface = ( sum(stress[:,0,6*i+1] for i in range(8)) )/8.0 - stress_zz_wellboresurface = ( sum(stress[:,0,6*i+2] for i in range(8)) )/8.0 - stress_yz_wellboresurface = ( sum(stress[:,0,6*i+3] for i in range(8)) )/8.0 - stress_xz_wellboresurface = ( sum(stress[:,0,6*i+4] for i in range(8)) )/8.0 - stress_xy_wellboresurface = ( sum(stress[:,0,6*i+5] for i in range(8)) )/8.0 - p = (stress_xx_wellboresurface + stress_yy_wellboresurface + stress_zz_wellboresurface)/3.0 - q = np.sqrt(1.5) * np.sqrt( (stress_xx_wellboresurface-p)**2.0 + (stress_yy_wellboresurface-p)**2.0 + (stress_zz_wellboresurface-p)**2.0 + \ + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + + outputDir = args.outputDir + geosDir = args.geosDir + + xmlFilePathPrefix = geosDir + "/inputFiles/solidMechanics/ExtendedDruckerPragerWellbore" + xmlData = getDataFromXML(xmlFilePathPrefix) + + # Initial wellbore radius + a0 = xmlData[0] + + # Initial stresses + sh = -xmlData[1] #negative sign because of positive sign convention for compression stress in the analytical solution + sv = -xmlData[2] #negative sign because of positive sign convention for compression stress in the analytical solution + + # Boundary condition on the wellbore surface + pw = -xmlData[3] #negative sign because of positive sign convention for compression stress in the analytical solution + # Equivalent displacement condition for the analytical solution + a0_a_ratio = 1.075 # This ratio corresponds to pw, extracted from the relationship between pw and a0/a (see bottom-right figure) + + # Elastic moduli + K = xmlData[4] + G = xmlData[5] + nu = (3.0*K-2.0*G) / (6.0*K+2.0*G) + + # Elasto-plastic parameters + cohesion = xmlData[6] + initialFrictionAngle = xmlData[7] # deg + finalFrictionAngle = xmlData[8] # deg + dilationRatio = xmlData[9] + param_m = xmlData[10] # Extended Drucker-Prager hardening parameter, this is noted by c in the ref. Chen and Abousleiman (2017) + + # Note that the solution developed by Chen and Abousleiman (2017) is for an associated elasto-plastic model (i.e. dilationRatio = 1) with zero cohesion + assert dilationRatio == 1.0, "The associated model is considered by the reference solutions, please set the dilation ratio to 1.0" + assert cohesion == 0.0, "Zero cohesion is considered by the reference solutions, please set the cohesion to 0.0" + + # Get stress, time and element center from GEOSX results + stress_field_name = 'rock_stress' + hf_stress = h5py.File(outputDir + '/stressHistory_rock.hdf5', 'r') + time = np.asarray( hf_stress.get(stress_field_name + ' Time') ) + center = np.asarray( hf_stress.get(stress_field_name + ' elementCenter') ) + stress = np.asarray( hf_stress.get(stress_field_name) ) + + # Get the deformed wellbore radius + hf_disp = h5py.File(outputDir + "/displacementHistory.hdf5", 'r') + displacement = np.asarray( hf_disp.get('totalDisplacement') ) + node_position = np.asarray( hf_disp.get('totalDisplacement ReferencePosition') ) + da = displacement[:, 0, 0] + a = a0 + da + + # Compute total stress, the stress of each element is the average value of its eight Gauss points + nTimeSteps = 30 + stress_xx = ( sum(stress[nTimeSteps,:,6*i+0] for i in range(8)) )/8.0 + stress_yy = ( sum(stress[nTimeSteps,:,6*i+1] for i in range(8)) )/8.0 + stress_zz = ( sum(stress[nTimeSteps,:,6*i+2] for i in range(8)) )/8.0 + stress_yz = ( sum(stress[nTimeSteps,:,6*i+3] for i in range(8)) )/8.0 + stress_xz = ( sum(stress[nTimeSteps,:,6*i+4] for i in range(8)) )/8.0 + stress_xy = ( sum(stress[nTimeSteps,:,6*i+5] for i in range(8)) )/8.0 + + # Coordinate of elemnt center + nElements = center.shape[1] + xCoord = center[0, :, 0] + yCoord = center[0, :, 1] + + rCoord = np.sqrt( xCoord*xCoord + yCoord*yCoord ) + + # Compute stress components in cylindrical coordinate system + stress_rr = np.zeros(stress_xx.shape) + stress_tt = np.zeros(stress_xx.shape) + + for idx_elem in range(stress.shape[1]): + stressMatrix_cartesian = np.array([[stress_xx[idx_elem],stress_xy[idx_elem],stress_xz[idx_elem]],\ + [stress_xy[idx_elem],stress_yy[idx_elem],stress_yz[idx_elem]],\ + [stress_xz[idx_elem],stress_yz[idx_elem],stress_zz[idx_elem]]]) + + if(yCoord[idx_elem] != 0): + phi_x = np.arctan( xCoord[idx_elem]/yCoord[idx_elem] ) + else: + phi_x = 0 + + stressMatrix_cylindirical = stressRotation(stressMatrix_cartesian, phi_x) + stress_rr[idx_elem] = stressMatrix_cylindirical[1][1] + stress_tt[idx_elem] = stressMatrix_cylindirical[0][0] + + # Stress invariants at wellbore surface + stress_xx_wellboresurface = ( sum(stress[:,0,6*i+0] for i in range(8)) )/8.0 + stress_yy_wellboresurface = ( sum(stress[:,0,6*i+1] for i in range(8)) )/8.0 + stress_zz_wellboresurface = ( sum(stress[:,0,6*i+2] for i in range(8)) )/8.0 + stress_yz_wellboresurface = ( sum(stress[:,0,6*i+3] for i in range(8)) )/8.0 + stress_xz_wellboresurface = ( sum(stress[:,0,6*i+4] for i in range(8)) )/8.0 + stress_xy_wellboresurface = ( sum(stress[:,0,6*i+5] for i in range(8)) )/8.0 + p = (stress_xx_wellboresurface + stress_yy_wellboresurface + stress_zz_wellboresurface)/3.0 + q = np.sqrt(1.5) * np.sqrt( (stress_xx_wellboresurface-p)**2.0 + (stress_yy_wellboresurface-p)**2.0 + (stress_zz_wellboresurface-p)**2.0 + \ stress_xy_wellboresurface**2.0 + stress_xz_wellboresurface**2.0 + stress_yz_wellboresurface**2.0 ) - # Analytical results - r_ep_analytic,srr_ep_analytic,stt_ep_analytic,szz_ep_analytic,r_elas_analytic,srr_elas_analytic,stt_elas_analytic,szz_elas_analytic,\ + # Analytical results + r_ep_analytic,srr_ep_analytic,stt_ep_analytic,szz_ep_analytic,r_elas_analytic,srr_elas_analytic,stt_elas_analytic,szz_elas_analytic,\ pw_analytic,p_wellsurface_analytic,q_wellsurface_analytic = edpAnal.EDP(a0_a_ratio, sh, sv, nu, a0, G, initialFrictionAngle, finalFrictionAngle, param_m) - - # Compute pressure at wellbore surface - list_a0_a_ratio = np.arange(1.0,1.1,0.001) - list_pw_analytic = [] - list_p_wellsurface_analytic = [] - list_q_wellsurface_analytic = [] - - for a0_a_ratio_val in list_a0_a_ratio: - tmp = edpAnal.EDP(a0_a_ratio_val, sh, sv, nu, a0, G, initialFrictionAngle, finalFrictionAngle, param_m) - pw_analytic = tmp[8] - p_wellsurface_analytic = tmp[9] - q_wellsurface_analytic = tmp[10] - list_pw_analytic.append(pw_analytic) - list_p_wellsurface_analytic.append(p_wellsurface_analytic) - list_q_wellsurface_analytic.append(q_wellsurface_analytic) - - # Plots - plt.figure(figsize=(15,10)) - - # Plot GEOS results versus analytical results for elasto-plastic material - plt.subplot(2,2,1) - plt.plot( rCoord/rCoord[0],-stress_rr,'r+',label=r'$\sigma_{rr}$: GEOS Plasticity') - plt.plot(r_ep_analytic,srr_ep_analytic, 'r', label=r'$\sigma_{rr}$: Analytical Plasticity') - plt.plot(r_elas_analytic,srr_elas_analytic, 'r') - - plt.plot( rCoord/rCoord[0],-stress_tt,'b+',label=r'$\sigma_{\theta\theta}$: GEOS Plasticity') - plt.plot(r_ep_analytic,stt_ep_analytic, 'b', label=r'$\sigma_{\theta\theta}$: Analytical Plasticity') - plt.plot(r_elas_analytic,stt_elas_analytic, 'b') - - plt.plot( rCoord/rCoord[0],-stress_zz,'g+',label=r'$\sigma_{zz}$: GEOS Plasticity') - plt.plot(r_ep_analytic,szz_ep_analytic, 'g', label=r'$\sigma_{zz}$: Analytical Plasticity') - plt.plot(r_elas_analytic,szz_elas_analytic, 'g') - - plt.plot([r_ep_analytic[0],r_ep_analytic[0]],[0.0,20e6],'k--', label='Elastic-Plastic boundary') - - plt.ylabel('Stresses [Pa]') - plt.xlabel(r'Normalized radial coordinate, $r/a$') - plt.xlim(1.0,10.0) - plt.ylim(0.0,20e6) - plt.yticks(np.linspace(0.0,20e6,11)) - plt.xscale('log', subs=range(2,10)) - plt.legend() - - # Plot GEOS results for elasto-plastic material versus analytical results for elastic material - r_elas_assumed,srr_elas_assumed,stt_elas_assumed,szz_elas_assumed = epwAnal.solution_elastic(sh,sv,1.0,pw) - - plt.subplot(2,2,2) - plt.plot( rCoord/rCoord[0],-stress_rr,'r+',label=r'$\sigma_{rr}$: GEOS Plasticity') - plt.plot(r_elas_assumed,srr_elas_assumed, 'r', label=r'$\sigma_{rr}$: Analytical Elasticity') - - plt.plot( rCoord/rCoord[0],-stress_tt,'b+',label=r'$\sigma_{\theta\theta}$: GEOS Plasticity') - plt.plot(r_elas_assumed,stt_elas_assumed, 'b', label=r'$\sigma_{\theta\theta}$: Analytical Elasticity') - - plt.plot( rCoord/rCoord[0],-stress_zz,'g+',label=r'$\sigma_{zz}$: GEOS Plasticity') - plt.plot(r_elas_assumed,szz_elas_assumed, 'g', label=r'$\sigma_{zz}$: Analytical Elasticity') - - plt.ylabel('Stresses [Pa]') - plt.xlabel(r'Normalized radial coordinate, $r/a$') - plt.xlim(1.0,10.0) - plt.ylim(0.0,20e6) - plt.yticks(np.linspace(0.0,20e6,11)) - plt.xscale('log', subs=range(2,10)) - plt.legend() - - # Plot the stress path on the p-q plan when the well surface pressure decrease from the in-situ condition - initialFrictionAngle *= np.pi/180.0 # converted to rad - finalFrictionAngle *= np.pi/180.0 # converted to rad - param_b_i = edpAnal.compute_param_b(initialFrictionAngle) - param_b_f = edpAnal.compute_param_b(finalFrictionAngle) - p_yieldSurface = np.arange(0,15e6,1) - q_yieldSurface_i = p_yieldSurface*param_b_i - q_yieldSurface_f = p_yieldSurface*param_b_f - - plt.subplot(2,2,3) - plt.plot(-p,q,'ko',label='GEOS') - plt.plot(list_p_wellsurface_analytic,list_q_wellsurface_analytic,'b',label='Analytical') - plt.plot(p_yieldSurface,q_yieldSurface_i,'g--',label='Initial yield surface') - plt.plot(p_yieldSurface,q_yieldSurface_f,'r--',label='Final yield surface') - - plt.xlabel('p (Pa)') - plt.ylabel('q (Pa)') - plt.xlim(0,15e6) - plt.ylim(0,10e6) - plt.legend() - - # Plot the wellbore deformation a0/a versus wellbore surface pressure pw - pw = stress_xx_wellboresurface - - plt.subplot(2,2,4) - plt.plot(a0/a, -pw,'ko',label='GEOS') - plt.plot(list_a0_a_ratio,list_pw_analytic,'b',label='Analytical') - plt.xlabel('a0/a') - plt.ylabel('pw (Pa)') - plt.xlim(1.0,1.1) - plt.ylim(0,12e6) - plt.legend() - - plt.savefig('edpWellboreVerification.png') - + + # Compute pressure at wellbore surface + list_a0_a_ratio = np.arange(1.0,1.1,0.001) + list_pw_analytic = [] + list_p_wellsurface_analytic = [] + list_q_wellsurface_analytic = [] + + for a0_a_ratio_val in list_a0_a_ratio: + tmp = edpAnal.EDP(a0_a_ratio_val, sh, sv, nu, a0, G, initialFrictionAngle, finalFrictionAngle, param_m) + pw_analytic = tmp[8] + p_wellsurface_analytic = tmp[9] + q_wellsurface_analytic = tmp[10] + list_pw_analytic.append(pw_analytic) + list_p_wellsurface_analytic.append(p_wellsurface_analytic) + list_q_wellsurface_analytic.append(q_wellsurface_analytic) + + # Plots + plt.figure(figsize=(15,10)) + + # Plot GEOS results versus analytical results for elasto-plastic material + plt.subplot(2,2,1) + plt.plot( rCoord/rCoord[0],-stress_rr,'r+',label=r'$\sigma_{rr}$: GEOS Plasticity') + plt.plot(r_ep_analytic,srr_ep_analytic, 'r', label=r'$\sigma_{rr}$: Analytical Plasticity') + plt.plot(r_elas_analytic,srr_elas_analytic, 'r') + + plt.plot( rCoord/rCoord[0],-stress_tt,'b+',label=r'$\sigma_{\theta\theta}$: GEOS Plasticity') + plt.plot(r_ep_analytic,stt_ep_analytic, 'b', label=r'$\sigma_{\theta\theta}$: Analytical Plasticity') + plt.plot(r_elas_analytic,stt_elas_analytic, 'b') + + plt.plot( rCoord/rCoord[0],-stress_zz,'g+',label=r'$\sigma_{zz}$: GEOS Plasticity') + plt.plot(r_ep_analytic,szz_ep_analytic, 'g', label=r'$\sigma_{zz}$: Analytical Plasticity') + plt.plot(r_elas_analytic,szz_elas_analytic, 'g') + + plt.plot([r_ep_analytic[0],r_ep_analytic[0]],[0.0,20e6],'k--', label='Elastic-Plastic boundary') + + plt.ylabel('Stresses [Pa]') + plt.xlabel(r'Normalized radial coordinate, $r/a$') + plt.xlim(1.0,10.0) + plt.ylim(0.0,20e6) + plt.yticks(np.linspace(0.0,20e6,11)) + plt.xscale('log', subs=range(2,10)) + plt.legend() + + # Plot GEOS results for elasto-plastic material versus analytical results for elastic material + r_elas_assumed,srr_elas_assumed,stt_elas_assumed,szz_elas_assumed = epwAnal.solution_elastic(sh,sv,1.0,pw) + + plt.subplot(2,2,2) + plt.plot( rCoord/rCoord[0],-stress_rr,'r+',label=r'$\sigma_{rr}$: GEOS Plasticity') + plt.plot(r_elas_assumed,srr_elas_assumed, 'r', label=r'$\sigma_{rr}$: Analytical Elasticity') + + plt.plot( rCoord/rCoord[0],-stress_tt,'b+',label=r'$\sigma_{\theta\theta}$: GEOS Plasticity') + plt.plot(r_elas_assumed,stt_elas_assumed, 'b', label=r'$\sigma_{\theta\theta}$: Analytical Elasticity') + + plt.plot( rCoord/rCoord[0],-stress_zz,'g+',label=r'$\sigma_{zz}$: GEOS Plasticity') + plt.plot(r_elas_assumed,szz_elas_assumed, 'g', label=r'$\sigma_{zz}$: Analytical Elasticity') + + plt.ylabel('Stresses [Pa]') + plt.xlabel(r'Normalized radial coordinate, $r/a$') + plt.xlim(1.0,10.0) + plt.ylim(0.0,20e6) + plt.yticks(np.linspace(0.0,20e6,11)) + plt.xscale('log', subs=range(2,10)) + plt.legend() + + # Plot the stress path on the p-q plan when the well surface pressure decrease from the in-situ condition + initialFrictionAngle *= np.pi/180.0 # converted to rad + finalFrictionAngle *= np.pi/180.0 # converted to rad + param_b_i = edpAnal.compute_param_b(initialFrictionAngle) + param_b_f = edpAnal.compute_param_b(finalFrictionAngle) + p_yieldSurface = np.arange(0,15e6,1) + q_yieldSurface_i = p_yieldSurface*param_b_i + q_yieldSurface_f = p_yieldSurface*param_b_f + + plt.subplot(2,2,3) + plt.plot(-p,q,'ko',label='GEOS') + plt.plot(list_p_wellsurface_analytic,list_q_wellsurface_analytic,'b',label='Analytical') + plt.plot(p_yieldSurface,q_yieldSurface_i,'g--',label='Initial yield surface') + plt.plot(p_yieldSurface,q_yieldSurface_f,'r--',label='Final yield surface') + + plt.xlabel('p (Pa)') + plt.ylabel('q (Pa)') + plt.xlim(0,15e6) + plt.ylim(0,10e6) + plt.legend() + + # Plot the wellbore deformation a0/a versus wellbore surface pressure pw + pw = stress_xx_wellboresurface + + plt.subplot(2,2,4) + plt.plot(a0/a, -pw,'ko',label='GEOS') + plt.plot(list_a0_a_ratio,list_pw_analytic,'b',label='Analytical') + plt.xlabel('a0/a') + plt.ylabel('pw (Pa)') + plt.xlim(1.0,1.1) + plt.ylim(0,12e6) + plt.legend() + + plt.savefig('edpWellboreVerification.png') + if __name__ == "__main__": - main() - + main() + diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/kirschWellbore/kirschWellboreFigure.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/kirschWellbore/kirschWellboreFigure.py index df68ed728e2..e99152255d5 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/kirschWellbore/kirschWellboreFigure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/kirschWellbore/kirschWellboreFigure.py @@ -5,6 +5,8 @@ import xml.etree.ElementTree as ElementTree import math from math import sin, cos, tan, exp, atan, asin +import os +import argparse class Analytical: @@ -112,24 +114,37 @@ def dispRotation(disp, phi_x): def main(): + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + # Load and process GEOSX results # File path - hdf5File1Path = "stress_history.hdf5" - hdf5File2Path = "displacement_history.hdf5" - xmlFile1Path = "../../../../../../../inputFiles/solidMechanics/KirschProblem_base.xml" - xmlFile2Path = "../../../../../../../inputFiles/solidMechanics/KirschProblem_benchmark.xml" + outputDir = args.outputDir + geosDir = args.geosDir + hdf5File1Path = outputDir + "/stress_history.hdf5" + hdf5File2Path = outputDir + "/displacement_history.hdf5" + xmlFile1Path = geosDir + "/inputFiles/solidMechanics/KirschProblem_base.xml" + xmlFile2Path = geosDir + "/inputFiles/solidMechanics/KirschProblem_benchmark.xml" # Read HDF5 # Global Coordinate of Element Center hf = h5py.File(hdf5File1Path, 'r') xl_elm = hf.get('rock_stress elementCenter') - xl_elm = np.array(xl_elm) + xl_elm = np.asarray(xl_elm) xcord_elm = xl_elm[0, :, 0] ycord_elm = xl_elm[0, :, 1] zcord_elm = xl_elm[0, :, 2] # Load Stress Components sigma = hf.get('rock_stress') - sigma = np.array(sigma) + sigma = np.asarray(sigma) sigma_Cart = np.zeros([len(sigma[0, :, 0]), 6]) for i in range(0, len(sigma[0, :, 0])): for j in range(0, 6): @@ -139,13 +154,13 @@ def main(): # Global Coordinate of Nodal Point hf = h5py.File(hdf5File2Path, 'r') xl_node = hf.get('totalDisplacement ReferencePosition') - xl_node = np.array(xl_node) + xl_node = np.asarray(xl_node) xcord_node = xl_node[0, :, 0] ycord_node = xl_node[0, :, 1] zcord_node = xl_node[0, :, 2] # Load Displacement Components disp_load = hf.get('totalDisplacement') - disp_load = np.array(disp_load) + disp_load = np.asarray(disp_load) disp_Cart = disp_load[0, :, :] # Extract Mechanical Properties and Fracture Geometry from XML diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/Example.rst new file mode 100644 index 00000000000..a16e28b359f --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/Example.rst @@ -0,0 +1,113 @@ +.. _AdvancedExamplePureThermalDiffusionWellbore: + + +#################################################### +Pure Thermal Diffusion Around a Wellbore +#################################################### + +------------------------------------------------------------------ +Problem description +------------------------------------------------------------------ + +This example uses the thermal single-phase flow solver to model a pure thermal diffusion problem around a wellbore. To mimic this specific problem, thermal convection and fluid flow are neglected by setting fluid pressure and fluid heat capacity to zero. With a uniform temperature applied on the inner surface of the wellbore, temperature field would radially diffuse as shown in the figure below: + +.. _problemSketchRadialThermalDiffusionWellboreFig: +.. figure:: radialThermalDiffusionSketch.png + :align: center + :width: 500 + :figclass: align-center + + Sketch of the radial thermal diffusion around a wellbore + +Analytical results of the temperature profile along the radial direction is given by `(Wang and Papamichos, 1994) `__ : + +.. math:: + T(r) = T_{in}\sqrt{\frac{R_{in}}{r}}erfc(\frac{r-R_{in}}{2\sqrt{c_{T}t}}) + +where :math:`r` is the radial coordinate, :math:`T_{in}` is the temperature applied on the surface of the wellbore at :math:`r = R_{in}`, :math:`c_{T}` is the thermal diffusion coefficient of rock, which is defined as the ratio between the thermal conductivity and the volumetric heat capacity of rock. + + +**Input file** + +This benchmark example uses no external input file and everything required is +contained within two GEOS xml files that are located at: + +.. code-block:: console + + inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml + +and + +.. code-block:: console + + inputFiles/singlePhaseFlow/thermalCompressible_2d_benchmark.xml + +The corresponding integrated test is + +.. code-block:: console + + inputFiles/singlePhaseFlow/thermalCompressible_2d_smoke.xml + +In this example, we would focus our attention on the ``Constitutive`` and ``FieldSpecifications`` tags. + +----------------------------------------------------------- +Constitutive +----------------------------------------------------------- + +The volumetric heat capacity of the medium around the wellbore is defined in the ``SolidInternalEnergy`` XML block as + +.. literalinclude:: ../../../../../../../inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml + :language: xml + :start-after: + :end-before: + +The thermal conductivity of the medium around the wellbore is defined in the ``SinglePhaseConstantThermalConductivity`` XML block as + +.. literalinclude:: ../../../../../../../inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml + :language: xml + :start-after: + :end-before: + +The volumetric heat capacity of fluid is set to a negligible value to exclude thermal convection effect. It is defined in the ``ThermalCompressibleSinglePhaseFluid`` XML block as + +.. literalinclude:: ../../../../../../../inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml + :language: xml + :start-after: + :end-before: + +-------------------------------------------------------------------- +FieldSpecifications +-------------------------------------------------------------------- + +The initial temperature, the imposed temperature at the curved wellbore surface as well as the far-field temperature are defined as Dirichlet face boundary conditions using ``faceManager`` as + +.. literalinclude:: ../../../../../../../inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml + :language: xml + :start-after: + :end-before: + +Although a pure thermal diffusion problem is considered, it is also required to define specifications for fluid pressure, as thermal transfer is always coupled with fluid flow in GEOS. In this example, fluid pressure is set to zero everywhere to mimic a pure thermal diffusion problem as + +.. literalinclude:: ../../../../../../../inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml + :language: xml + :start-after: + :end-before: + +--------------------------------- +Results and benchmark +--------------------------------- + +A good agreement between the GEOS results and analytical results is shown in the figure below: + + +.. plot:: docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/linearThermalDiffusion_plot.py + + +------------------------------------------------------------------ +To go further +------------------------------------------------------------------ + +**Feedback on this example** + +This concludes the example of pure thermal diffusion problem around a wellbore. +For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/data_1.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/data_1.csv new file mode 100644 index 00000000000..27b265b8428 --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/data_1.csv @@ -0,0 +1,1002 @@ +Time,"elementCenter:0","elementCenter:1","elementCenter:2","temperature" +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,0.07071,0.072112,0.05,-18.996 +10000,0.07071,0.072112,0.05,-18.996 +10000,0.07211,0.07354,0.05,-17.027 +10000,0.07351,0.074968,0.05,-15.096 +10000,0.075155,0.076646,0.05,-12.871 +10000,0.075155,0.076646,0.05,-12.871 +10000,0.077046,0.078574,0.05,-10.378 +10000,0.077046,0.078574,0.05,-10.378 +10000,0.078936,0.080501,0.05,-7.9475 +10000,0.078936,0.080501,0.05,-7.9475 +10000,0.080826,0.082429,0.05,-5.5759 +10000,0.080826,0.082429,0.05,-5.5759 +10000,0.082716,0.084357,0.05,-3.2609 +10000,0.082716,0.084357,0.05,-3.2609 +10000,0.084607,0.086285,0.05,-1.0005 +10000,0.084607,0.086285,0.05,-1.0005 +10000,0.086497,0.088212,0.05,1.2075 +10000,0.086497,0.088212,0.05,1.2075 +10000,0.088387,0.09014,0.05,3.365 +10000,0.088387,0.09014,0.05,3.365 +10000,0.090278,0.092068,0.05,5.4737 +10000,0.090278,0.092068,0.05,5.4737 +10000,0.092168,0.093995,0.05,7.5355 +10000,0.092168,0.093995,0.05,7.5355 +10000,0.094031,0.095896,0.05,9.5228 +10000,0.095885,0.097786,0.05,11.459 +10000,0.095885,0.097786,0.05,11.459 +10000,0.097776,0.099715,0.05,13.391 +10000,0.097776,0.099715,0.05,13.391 +10000,0.099704,0.10168,0.05,15.318 +10000,0.099704,0.10168,0.05,15.318 +10000,0.10167,0.10369,0.05,17.241 +10000,0.10167,0.10369,0.05,17.241 +10000,0.10368,0.10573,0.05,19.159 +10000,0.10368,0.10573,0.05,19.159 +10000,0.10572,0.10782,0.05,21.071 +10000,0.10572,0.10782,0.05,21.071 +10000,0.10781,0.10995,0.05,22.977 +10000,0.10781,0.10995,0.05,22.977 +10000,0.10993,0.11211,0.05,24.877 +10000,0.10993,0.11211,0.05,24.877 +10000,0.10993,0.11211,0.05,24.877 +10000,0.1121,0.11433,0.05,26.769 +10000,0.1121,0.11433,0.05,26.769 +10000,0.11432,0.11658,0.05,28.653 +10000,0.11432,0.11658,0.05,28.653 +10000,0.11657,0.11888,0.05,30.529 +10000,0.11657,0.11888,0.05,30.529 +10000,0.11887,0.12123,0.05,32.396 +10000,0.11887,0.12123,0.05,32.396 +10000,0.11887,0.12123,0.05,32.396 +10000,0.12122,0.12362,0.05,34.254 +10000,0.12122,0.12362,0.05,34.254 +10000,0.12361,0.12607,0.05,36.1 +10000,0.12361,0.12607,0.05,36.1 +10000,0.12361,0.12607,0.05,36.1 +10000,0.12605,0.12855,0.05,37.936 +10000,0.12605,0.12855,0.05,37.936 +10000,0.12854,0.13109,0.05,39.76 +10000,0.12854,0.13109,0.05,39.76 +10000,0.12854,0.13109,0.05,39.76 +10000,0.13108,0.13368,0.05,41.571 +10000,0.13108,0.13368,0.05,41.571 +10000,0.13367,0.13632,0.05,43.368 +10000,0.13367,0.13632,0.05,43.368 +10000,0.13367,0.13632,0.05,43.368 +10000,0.13631,0.13901,0.05,45.152 +10000,0.13631,0.13901,0.05,45.152 +10000,0.13631,0.13901,0.05,45.152 +10000,0.139,0.14176,0.05,46.92 +10000,0.139,0.14176,0.05,46.92 +10000,0.14175,0.14456,0.05,48.672 +10000,0.14175,0.14456,0.05,48.672 +10000,0.14175,0.14456,0.05,48.672 +10000,0.14455,0.14742,0.05,50.407 +10000,0.14455,0.14742,0.05,50.407 +10000,0.14455,0.14742,0.05,50.407 +10000,0.1474,0.15033,0.05,52.125 +10000,0.1474,0.15033,0.05,52.125 +10000,0.1474,0.15033,0.05,52.125 +10000,0.15032,0.1533,0.05,53.824 +10000,0.15032,0.1533,0.05,53.824 +10000,0.15032,0.1533,0.05,53.824 +10000,0.15329,0.15633,0.05,55.503 +10000,0.15329,0.15633,0.05,55.503 +10000,0.15329,0.15633,0.05,55.503 +10000,0.15632,0.15942,0.05,57.161 +10000,0.15632,0.15942,0.05,57.161 +10000,0.15632,0.15942,0.05,57.161 +10000,0.15941,0.16257,0.05,58.797 +10000,0.15941,0.16257,0.05,58.797 +10000,0.15941,0.16257,0.05,58.797 +10000,0.16256,0.16578,0.05,60.411 +10000,0.16256,0.16578,0.05,60.411 +10000,0.16256,0.16578,0.05,60.411 +10000,0.16577,0.16906,0.05,62.001 +10000,0.16577,0.16906,0.05,62.001 +10000,0.16577,0.16906,0.05,62.001 +10000,0.16577,0.16906,0.05,62.001 +10000,0.16905,0.1724,0.05,63.566 +10000,0.16905,0.1724,0.05,63.566 +10000,0.16905,0.1724,0.05,63.566 +10000,0.17239,0.1758,0.05,65.106 +10000,0.17239,0.1758,0.05,65.106 +10000,0.17239,0.1758,0.05,65.106 +10000,0.17579,0.17928,0.05,66.619 +10000,0.17579,0.17928,0.05,66.619 +10000,0.17579,0.17928,0.05,66.619 +10000,0.17579,0.17928,0.05,66.619 +10000,0.17927,0.18282,0.05,68.104 +10000,0.17927,0.18282,0.05,68.104 +10000,0.17927,0.18282,0.05,68.104 +10000,0.18281,0.18644,0.05,69.56 +10000,0.18281,0.18644,0.05,69.56 +10000,0.18281,0.18644,0.05,69.56 +10000,0.18281,0.18644,0.05,69.56 +10000,0.18643,0.19013,0.05,70.986 +10000,0.18643,0.19013,0.05,70.986 +10000,0.18643,0.19013,0.05,70.986 +10000,0.18643,0.19013,0.05,70.986 +10000,0.19011,0.19388,0.05,72.382 +10000,0.19011,0.19388,0.05,72.382 +10000,0.19011,0.19388,0.05,72.382 +10000,0.19387,0.19772,0.05,73.746 +10000,0.19387,0.19772,0.05,73.746 +10000,0.19387,0.19772,0.05,73.746 +10000,0.19387,0.19772,0.05,73.746 +10000,0.19771,0.20163,0.05,75.077 +10000,0.19771,0.20163,0.05,75.077 +10000,0.19771,0.20163,0.05,75.077 +10000,0.19771,0.20163,0.05,75.077 +10000,0.20162,0.20562,0.05,76.375 +10000,0.20162,0.20562,0.05,76.375 +10000,0.20162,0.20562,0.05,76.375 +10000,0.20162,0.20562,0.05,76.375 +10000,0.2056,0.20968,0.05,77.639 +10000,0.2056,0.20968,0.05,77.639 +10000,0.2056,0.20968,0.05,77.639 +10000,0.2056,0.20968,0.05,77.639 +10000,0.20967,0.21383,0.05,78.867 +10000,0.20967,0.21383,0.05,78.867 +10000,0.20967,0.21383,0.05,78.867 +10000,0.20967,0.21383,0.05,78.867 +10000,0.21382,0.21806,0.05,80.06 +10000,0.21382,0.21806,0.05,80.06 +10000,0.21382,0.21806,0.05,80.06 +10000,0.21382,0.21806,0.05,80.06 +10000,0.21382,0.21806,0.05,80.06 +10000,0.21805,0.22237,0.05,81.216 +10000,0.21805,0.22237,0.05,81.216 +10000,0.21805,0.22237,0.05,81.216 +10000,0.21805,0.22237,0.05,81.216 +10000,0.22236,0.22677,0.05,82.334 +10000,0.22236,0.22677,0.05,82.334 +10000,0.22236,0.22677,0.05,82.334 +10000,0.22236,0.22677,0.05,82.334 +10000,0.22676,0.23125,0.05,83.416 +10000,0.22676,0.23125,0.05,83.416 +10000,0.22676,0.23125,0.05,83.416 +10000,0.22676,0.23125,0.05,83.416 +10000,0.22676,0.23125,0.05,83.416 +10000,0.23124,0.23583,0.05,84.459 +10000,0.23124,0.23583,0.05,84.459 +10000,0.23124,0.23583,0.05,84.459 +10000,0.23124,0.23583,0.05,84.459 +10000,0.23582,0.2405,0.05,85.463 +10000,0.23582,0.2405,0.05,85.463 +10000,0.23582,0.2405,0.05,85.463 +10000,0.23582,0.2405,0.05,85.463 +10000,0.23582,0.2405,0.05,85.463 +10000,0.24048,0.24525,0.05,86.429 +10000,0.24048,0.24525,0.05,86.429 +10000,0.24048,0.24525,0.05,86.429 +10000,0.24048,0.24525,0.05,86.429 +10000,0.24048,0.24525,0.05,86.429 +10000,0.24524,0.25011,0.05,87.355 +10000,0.24524,0.25011,0.05,87.355 +10000,0.24524,0.25011,0.05,87.355 +10000,0.24524,0.25011,0.05,87.355 +10000,0.24524,0.25011,0.05,87.355 +10000,0.25009,0.25505,0.05,88.242 +10000,0.25009,0.25505,0.05,88.242 +10000,0.25009,0.25505,0.05,88.242 +10000,0.25009,0.25505,0.05,88.242 +10000,0.25009,0.25505,0.05,88.242 +10000,0.25504,0.2601,0.05,89.09 +10000,0.25504,0.2601,0.05,89.09 +10000,0.25504,0.2601,0.05,89.09 +10000,0.25504,0.2601,0.05,89.09 +10000,0.25504,0.2601,0.05,89.09 +10000,0.26009,0.26525,0.05,89.899 +10000,0.26009,0.26525,0.05,89.899 +10000,0.26009,0.26525,0.05,89.899 +10000,0.26009,0.26525,0.05,89.899 +10000,0.26009,0.26525,0.05,89.899 +10000,0.26524,0.2705,0.05,90.669 +10000,0.26524,0.2705,0.05,90.669 +10000,0.26524,0.2705,0.05,90.669 +10000,0.26524,0.2705,0.05,90.669 +10000,0.26524,0.2705,0.05,90.669 +10000,0.27048,0.27585,0.05,91.4 +10000,0.27048,0.27585,0.05,91.4 +10000,0.27048,0.27585,0.05,91.4 +10000,0.27048,0.27585,0.05,91.4 +10000,0.27048,0.27585,0.05,91.4 +10000,0.27584,0.28131,0.05,92.092 +10000,0.27584,0.28131,0.05,92.092 +10000,0.27584,0.28131,0.05,92.092 +10000,0.27584,0.28131,0.05,92.092 +10000,0.27584,0.28131,0.05,92.092 +10000,0.27584,0.28131,0.05,92.092 +10000,0.2813,0.28687,0.05,92.746 +10000,0.2813,0.28687,0.05,92.746 +10000,0.2813,0.28687,0.05,92.746 +10000,0.2813,0.28687,0.05,92.746 +10000,0.2813,0.28687,0.05,92.746 +10000,0.28686,0.29255,0.05,93.363 +10000,0.28686,0.29255,0.05,93.363 +10000,0.28686,0.29255,0.05,93.363 +10000,0.28686,0.29255,0.05,93.363 +10000,0.28686,0.29255,0.05,93.363 +10000,0.28686,0.29255,0.05,93.363 +10000,0.29254,0.29834,0.05,93.944 +10000,0.29254,0.29834,0.05,93.944 +10000,0.29254,0.29834,0.05,93.944 +10000,0.29254,0.29834,0.05,93.944 +10000,0.29254,0.29834,0.05,93.944 +10000,0.29254,0.29834,0.05,93.944 +10000,0.29833,0.30425,0.05,94.488 +10000,0.29833,0.30425,0.05,94.488 +10000,0.29833,0.30425,0.05,94.488 +10000,0.29833,0.30425,0.05,94.488 +10000,0.29833,0.30425,0.05,94.488 +10000,0.29833,0.30425,0.05,94.488 +10000,0.30424,0.31027,0.05,94.997 +10000,0.30424,0.31027,0.05,94.997 +10000,0.30424,0.31027,0.05,94.997 +10000,0.30424,0.31027,0.05,94.997 +10000,0.30424,0.31027,0.05,94.997 +10000,0.30424,0.31027,0.05,94.997 +10000,0.31026,0.31641,0.05,95.472 +10000,0.31026,0.31641,0.05,95.472 +10000,0.31026,0.31641,0.05,95.472 +10000,0.31026,0.31641,0.05,95.472 +10000,0.31026,0.31641,0.05,95.472 +10000,0.31026,0.31641,0.05,95.472 +10000,0.3164,0.32267,0.05,95.914 +10000,0.3164,0.32267,0.05,95.914 +10000,0.3164,0.32267,0.05,95.914 +10000,0.3164,0.32267,0.05,95.914 +10000,0.3164,0.32267,0.05,95.914 +10000,0.3164,0.32267,0.05,95.914 +10000,0.32266,0.32906,0.05,96.324 +10000,0.32266,0.32906,0.05,96.324 +10000,0.32266,0.32906,0.05,96.324 +10000,0.32266,0.32906,0.05,96.324 +10000,0.32266,0.32906,0.05,96.324 +10000,0.32266,0.32906,0.05,96.324 +10000,0.32266,0.32906,0.05,96.324 +10000,0.32905,0.33558,0.05,96.703 +10000,0.32905,0.33558,0.05,96.703 +10000,0.32905,0.33558,0.05,96.703 +10000,0.32905,0.33558,0.05,96.703 +10000,0.32905,0.33558,0.05,96.703 +10000,0.32905,0.33558,0.05,96.703 +10000,0.33556,0.34222,0.05,97.052 +10000,0.33556,0.34222,0.05,97.052 +10000,0.33556,0.34222,0.05,97.052 +10000,0.33556,0.34222,0.05,97.052 +10000,0.33556,0.34222,0.05,97.052 +10000,0.33556,0.34222,0.05,97.052 +10000,0.33556,0.34222,0.05,97.052 +10000,0.34221,0.34899,0.05,97.373 +10000,0.34221,0.34899,0.05,97.373 +10000,0.34221,0.34899,0.05,97.373 +10000,0.34221,0.34899,0.05,97.373 +10000,0.34221,0.34899,0.05,97.373 +10000,0.34221,0.34899,0.05,97.373 +10000,0.34221,0.34899,0.05,97.373 +10000,0.34898,0.3559,0.05,97.667 +10000,0.34898,0.3559,0.05,97.667 +10000,0.34898,0.3559,0.05,97.667 +10000,0.34898,0.3559,0.05,97.667 +10000,0.34898,0.3559,0.05,97.667 +10000,0.34898,0.3559,0.05,97.667 +10000,0.35589,0.36295,0.05,97.935 +10000,0.35589,0.36295,0.05,97.935 +10000,0.35589,0.36295,0.05,97.935 +10000,0.35589,0.36295,0.05,97.935 +10000,0.35589,0.36295,0.05,97.935 +10000,0.35589,0.36295,0.05,97.935 +10000,0.35589,0.36295,0.05,97.935 +10000,0.36294,0.37013,0.05,98.179 +10000,0.36294,0.37013,0.05,98.179 +10000,0.36294,0.37013,0.05,98.179 +10000,0.36294,0.37013,0.05,98.179 +10000,0.36294,0.37013,0.05,98.179 +10000,0.36294,0.37013,0.05,98.179 +10000,0.36294,0.37013,0.05,98.179 +10000,0.36294,0.37013,0.05,98.179 +10000,0.37012,0.37746,0.05,98.4 +10000,0.37012,0.37746,0.05,98.4 +10000,0.37012,0.37746,0.05,98.4 +10000,0.37012,0.37746,0.05,98.4 +10000,0.37012,0.37746,0.05,98.4 +10000,0.37012,0.37746,0.05,98.4 +10000,0.37012,0.37746,0.05,98.4 +10000,0.37745,0.38494,0.05,98.599 +10000,0.37745,0.38494,0.05,98.599 +10000,0.37745,0.38494,0.05,98.599 +10000,0.37745,0.38494,0.05,98.599 +10000,0.37745,0.38494,0.05,98.599 +10000,0.37745,0.38494,0.05,98.599 +10000,0.37745,0.38494,0.05,98.599 +10000,0.38493,0.39256,0.05,98.778 +10000,0.38493,0.39256,0.05,98.778 +10000,0.38493,0.39256,0.05,98.778 +10000,0.38493,0.39256,0.05,98.778 +10000,0.38493,0.39256,0.05,98.778 +10000,0.38493,0.39256,0.05,98.778 +10000,0.38493,0.39256,0.05,98.778 +10000,0.38493,0.39256,0.05,98.778 +10000,0.39255,0.40033,0.05,98.939 +10000,0.39255,0.40033,0.05,98.939 +10000,0.39255,0.40033,0.05,98.939 +10000,0.39255,0.40033,0.05,98.939 +10000,0.39255,0.40033,0.05,98.939 +10000,0.39255,0.40033,0.05,98.939 +10000,0.39255,0.40033,0.05,98.939 +10000,0.39255,0.40033,0.05,98.939 +10000,0.40032,0.40826,0.05,99.082 +10000,0.40032,0.40826,0.05,99.082 +10000,0.40032,0.40826,0.05,99.082 +10000,0.40032,0.40826,0.05,99.082 +10000,0.40032,0.40826,0.05,99.082 +10000,0.40032,0.40826,0.05,99.082 +10000,0.40032,0.40826,0.05,99.082 +10000,0.40032,0.40826,0.05,99.082 +10000,0.40825,0.41634,0.05,99.209 +10000,0.40825,0.41634,0.05,99.209 +10000,0.40825,0.41634,0.05,99.209 +10000,0.40825,0.41634,0.05,99.209 +10000,0.40825,0.41634,0.05,99.209 +10000,0.40825,0.41634,0.05,99.209 +10000,0.40825,0.41634,0.05,99.209 +10000,0.40825,0.41634,0.05,99.209 +10000,0.41633,0.42459,0.05,99.321 +10000,0.41633,0.42459,0.05,99.321 +10000,0.41633,0.42459,0.05,99.321 +10000,0.41633,0.42459,0.05,99.321 +10000,0.41633,0.42459,0.05,99.321 +10000,0.41633,0.42459,0.05,99.321 +10000,0.41633,0.42459,0.05,99.321 +10000,0.41633,0.42459,0.05,99.321 +10000,0.42458,0.433,0.05,99.42 +10000,0.42458,0.433,0.05,99.42 +10000,0.42458,0.433,0.05,99.42 +10000,0.42458,0.433,0.05,99.42 +10000,0.42458,0.433,0.05,99.42 +10000,0.42458,0.433,0.05,99.42 +10000,0.42458,0.433,0.05,99.42 +10000,0.42458,0.433,0.05,99.42 +10000,0.42458,0.433,0.05,99.42 +10000,0.43298,0.44157,0.05,99.507 +10000,0.43298,0.44157,0.05,99.507 +10000,0.43298,0.44157,0.05,99.507 +10000,0.43298,0.44157,0.05,99.507 +10000,0.43298,0.44157,0.05,99.507 +10000,0.43298,0.44157,0.05,99.507 +10000,0.43298,0.44157,0.05,99.507 +10000,0.43298,0.44157,0.05,99.507 +10000,0.44156,0.45031,0.05,99.583 +10000,0.44156,0.45031,0.05,99.583 +10000,0.44156,0.45031,0.05,99.583 +10000,0.44156,0.45031,0.05,99.583 +10000,0.44156,0.45031,0.05,99.583 +10000,0.44156,0.45031,0.05,99.583 +10000,0.44156,0.45031,0.05,99.583 +10000,0.44156,0.45031,0.05,99.583 +10000,0.44156,0.45031,0.05,99.583 +10000,0.4503,0.45923,0.05,99.649 +10000,0.4503,0.45923,0.05,99.649 +10000,0.4503,0.45923,0.05,99.649 +10000,0.4503,0.45923,0.05,99.649 +10000,0.4503,0.45923,0.05,99.649 +10000,0.4503,0.45923,0.05,99.649 +10000,0.4503,0.45923,0.05,99.649 +10000,0.4503,0.45923,0.05,99.649 +10000,0.4503,0.45923,0.05,99.649 +10000,0.45922,0.46833,0.05,99.706 +10000,0.45922,0.46833,0.05,99.706 +10000,0.45922,0.46833,0.05,99.706 +10000,0.45922,0.46833,0.05,99.706 +10000,0.45922,0.46833,0.05,99.706 +10000,0.45922,0.46833,0.05,99.706 +10000,0.45922,0.46833,0.05,99.706 +10000,0.45922,0.46833,0.05,99.706 +10000,0.45922,0.46833,0.05,99.706 +10000,0.46832,0.4776,0.05,99.754 +10000,0.46832,0.4776,0.05,99.754 +10000,0.46832,0.4776,0.05,99.754 +10000,0.46832,0.4776,0.05,99.754 +10000,0.46832,0.4776,0.05,99.754 +10000,0.46832,0.4776,0.05,99.754 +10000,0.46832,0.4776,0.05,99.754 +10000,0.46832,0.4776,0.05,99.754 +10000,0.46832,0.4776,0.05,99.754 +10000,0.47759,0.48706,0.05,99.796 +10000,0.47759,0.48706,0.05,99.796 +10000,0.47759,0.48706,0.05,99.796 +10000,0.47759,0.48706,0.05,99.796 +10000,0.47759,0.48706,0.05,99.796 +10000,0.47759,0.48706,0.05,99.796 +10000,0.47759,0.48706,0.05,99.796 +10000,0.47759,0.48706,0.05,99.796 +10000,0.47759,0.48706,0.05,99.796 +10000,0.47759,0.48706,0.05,99.796 +10000,0.48705,0.49671,0.05,99.832 +10000,0.48705,0.49671,0.05,99.832 +10000,0.48705,0.49671,0.05,99.832 +10000,0.48705,0.49671,0.05,99.832 +10000,0.48705,0.49671,0.05,99.832 +10000,0.48705,0.49671,0.05,99.832 +10000,0.48705,0.49671,0.05,99.832 +10000,0.48705,0.49671,0.05,99.832 +10000,0.48705,0.49671,0.05,99.832 +10000,0.4967,0.50655,0.05,99.862 +10000,0.4967,0.50655,0.05,99.862 +10000,0.4967,0.50655,0.05,99.862 +10000,0.4967,0.50655,0.05,99.862 +10000,0.4967,0.50655,0.05,99.862 +10000,0.4967,0.50655,0.05,99.862 +10000,0.4967,0.50655,0.05,99.862 +10000,0.4967,0.50655,0.05,99.862 +10000,0.4967,0.50655,0.05,99.862 +10000,0.4967,0.50655,0.05,99.862 +10000,0.50654,0.51658,0.05,99.887 +10000,0.50654,0.51658,0.05,99.887 +10000,0.50654,0.51658,0.05,99.887 +10000,0.50654,0.51658,0.05,99.887 +10000,0.50654,0.51658,0.05,99.887 +10000,0.50654,0.51658,0.05,99.887 +10000,0.50654,0.51658,0.05,99.887 +10000,0.50654,0.51658,0.05,99.887 +10000,0.50654,0.51658,0.05,99.887 +10000,0.50654,0.51658,0.05,99.887 +10000,0.51657,0.52681,0.05,99.908 +10000,0.51657,0.52681,0.05,99.908 +10000,0.51657,0.52681,0.05,99.908 +10000,0.51657,0.52681,0.05,99.908 +10000,0.51657,0.52681,0.05,99.908 +10000,0.51657,0.52681,0.05,99.908 +10000,0.51657,0.52681,0.05,99.908 +10000,0.51657,0.52681,0.05,99.908 +10000,0.51657,0.52681,0.05,99.908 +10000,0.51657,0.52681,0.05,99.908 +10000,0.5268,0.53725,0.05,99.926 +10000,0.5268,0.53725,0.05,99.926 +10000,0.5268,0.53725,0.05,99.926 +10000,0.5268,0.53725,0.05,99.926 +10000,0.5268,0.53725,0.05,99.926 +10000,0.5268,0.53725,0.05,99.926 +10000,0.5268,0.53725,0.05,99.926 +10000,0.5268,0.53725,0.05,99.926 +10000,0.5268,0.53725,0.05,99.926 +10000,0.5268,0.53725,0.05,99.926 +10000,0.5268,0.53725,0.05,99.926 +10000,0.53724,0.54789,0.05,99.941 +10000,0.53724,0.54789,0.05,99.941 +10000,0.53724,0.54789,0.05,99.941 +10000,0.53724,0.54789,0.05,99.941 +10000,0.53724,0.54789,0.05,99.941 +10000,0.53724,0.54789,0.05,99.941 +10000,0.53724,0.54789,0.05,99.941 +10000,0.53724,0.54789,0.05,99.941 +10000,0.53724,0.54789,0.05,99.941 +10000,0.53724,0.54789,0.05,99.941 +10000,0.54788,0.55874,0.05,99.953 +10000,0.54788,0.55874,0.05,99.953 +10000,0.54788,0.55874,0.05,99.953 +10000,0.54788,0.55874,0.05,99.953 +10000,0.54788,0.55874,0.05,99.953 +10000,0.54788,0.55874,0.05,99.953 +10000,0.54788,0.55874,0.05,99.953 +10000,0.54788,0.55874,0.05,99.953 +10000,0.54788,0.55874,0.05,99.953 +10000,0.54788,0.55874,0.05,99.953 +10000,0.54788,0.55874,0.05,99.953 +10000,0.55873,0.56981,0.05,99.962 +10000,0.55873,0.56981,0.05,99.962 +10000,0.55873,0.56981,0.05,99.962 +10000,0.55873,0.56981,0.05,99.962 +10000,0.55873,0.56981,0.05,99.962 +10000,0.55873,0.56981,0.05,99.962 +10000,0.55873,0.56981,0.05,99.962 +10000,0.55873,0.56981,0.05,99.962 +10000,0.55873,0.56981,0.05,99.962 +10000,0.55873,0.56981,0.05,99.962 +10000,0.55873,0.56981,0.05,99.962 +10000,0.5698,0.5811,0.05,99.97 +10000,0.5698,0.5811,0.05,99.97 +10000,0.5698,0.5811,0.05,99.97 +10000,0.5698,0.5811,0.05,99.97 +10000,0.5698,0.5811,0.05,99.97 +10000,0.5698,0.5811,0.05,99.97 +10000,0.5698,0.5811,0.05,99.97 +10000,0.5698,0.5811,0.05,99.97 +10000,0.5698,0.5811,0.05,99.97 +10000,0.5698,0.5811,0.05,99.97 +10000,0.5698,0.5811,0.05,99.97 +10000,0.5698,0.5811,0.05,99.97 +10000,0.58109,0.59261,0.05,99.977 +10000,0.58109,0.59261,0.05,99.977 +10000,0.58109,0.59261,0.05,99.977 +10000,0.58109,0.59261,0.05,99.977 +10000,0.58109,0.59261,0.05,99.977 +10000,0.58109,0.59261,0.05,99.977 +10000,0.58109,0.59261,0.05,99.977 +10000,0.58109,0.59261,0.05,99.977 +10000,0.58109,0.59261,0.05,99.977 +10000,0.58109,0.59261,0.05,99.977 +10000,0.58109,0.59261,0.05,99.977 +10000,0.5926,0.60435,0.05,99.982 +10000,0.5926,0.60435,0.05,99.982 +10000,0.5926,0.60435,0.05,99.982 +10000,0.5926,0.60435,0.05,99.982 +10000,0.5926,0.60435,0.05,99.982 +10000,0.5926,0.60435,0.05,99.982 +10000,0.5926,0.60435,0.05,99.982 +10000,0.5926,0.60435,0.05,99.982 +10000,0.5926,0.60435,0.05,99.982 +10000,0.5926,0.60435,0.05,99.982 +10000,0.5926,0.60435,0.05,99.982 +10000,0.5926,0.60435,0.05,99.982 +10000,0.60434,0.61632,0.05,99.986 +10000,0.60434,0.61632,0.05,99.986 +10000,0.60434,0.61632,0.05,99.986 +10000,0.60434,0.61632,0.05,99.986 +10000,0.60434,0.61632,0.05,99.986 +10000,0.60434,0.61632,0.05,99.986 +10000,0.60434,0.61632,0.05,99.986 +10000,0.60434,0.61632,0.05,99.986 +10000,0.60434,0.61632,0.05,99.986 +10000,0.60434,0.61632,0.05,99.986 +10000,0.60434,0.61632,0.05,99.986 +10000,0.60434,0.61632,0.05,99.986 +10000,0.61631,0.62853,0.05,99.99 +10000,0.61631,0.62853,0.05,99.99 +10000,0.61631,0.62853,0.05,99.99 +10000,0.61631,0.62853,0.05,99.99 +10000,0.61631,0.62853,0.05,99.99 +10000,0.61631,0.62853,0.05,99.99 +10000,0.61631,0.62853,0.05,99.99 +10000,0.61631,0.62853,0.05,99.99 +10000,0.61631,0.62853,0.05,99.99 +10000,0.61631,0.62853,0.05,99.99 +10000,0.61631,0.62853,0.05,99.99 +10000,0.61631,0.62853,0.05,99.99 +10000,0.62852,0.64098,0.05,99.992 +10000,0.62852,0.64098,0.05,99.992 +10000,0.62852,0.64098,0.05,99.992 +10000,0.62852,0.64098,0.05,99.992 +10000,0.62852,0.64098,0.05,99.992 +10000,0.62852,0.64098,0.05,99.992 +10000,0.62852,0.64098,0.05,99.992 +10000,0.62852,0.64098,0.05,99.992 +10000,0.62852,0.64098,0.05,99.992 +10000,0.62852,0.64098,0.05,99.992 +10000,0.62852,0.64098,0.05,99.992 +10000,0.62852,0.64098,0.05,99.992 +10000,0.62852,0.64098,0.05,99.992 +10000,0.64097,0.65368,0.05,99.994 +10000,0.64097,0.65368,0.05,99.994 +10000,0.64097,0.65368,0.05,99.994 +10000,0.64097,0.65368,0.05,99.994 +10000,0.64097,0.65368,0.05,99.994 +10000,0.64097,0.65368,0.05,99.994 +10000,0.64097,0.65368,0.05,99.994 +10000,0.64097,0.65368,0.05,99.994 +10000,0.64097,0.65368,0.05,99.994 +10000,0.64097,0.65368,0.05,99.994 +10000,0.64097,0.65368,0.05,99.994 +10000,0.64097,0.65368,0.05,99.994 +10000,0.65367,0.66663,0.05,99.996 +10000,0.65367,0.66663,0.05,99.996 +10000,0.65367,0.66663,0.05,99.996 +10000,0.65367,0.66663,0.05,99.996 +10000,0.65367,0.66663,0.05,99.996 +10000,0.65367,0.66663,0.05,99.996 +10000,0.65367,0.66663,0.05,99.996 +10000,0.65367,0.66663,0.05,99.996 +10000,0.65367,0.66663,0.05,99.996 +10000,0.65367,0.66663,0.05,99.996 +10000,0.65367,0.66663,0.05,99.996 +10000,0.65367,0.66663,0.05,99.996 +10000,0.65367,0.66663,0.05,99.996 +10000,0.66662,0.67984,0.05,99.997 +10000,0.66662,0.67984,0.05,99.997 +10000,0.66662,0.67984,0.05,99.997 +10000,0.66662,0.67984,0.05,99.997 +10000,0.66662,0.67984,0.05,99.997 +10000,0.66662,0.67984,0.05,99.997 +10000,0.66662,0.67984,0.05,99.997 +10000,0.66662,0.67984,0.05,99.997 +10000,0.66662,0.67984,0.05,99.997 +10000,0.66662,0.67984,0.05,99.997 +10000,0.66662,0.67984,0.05,99.997 +10000,0.66662,0.67984,0.05,99.997 +10000,0.66662,0.67984,0.05,99.997 +10000,0.67983,0.69331,0.05,99.998 +10000,0.67983,0.69331,0.05,99.998 +10000,0.67983,0.69331,0.05,99.998 +10000,0.67983,0.69331,0.05,99.998 +10000,0.67983,0.69331,0.05,99.998 +10000,0.67983,0.69331,0.05,99.998 +10000,0.67983,0.69331,0.05,99.998 +10000,0.67983,0.69331,0.05,99.998 +10000,0.67983,0.69331,0.05,99.998 +10000,0.67983,0.69331,0.05,99.998 +10000,0.67983,0.69331,0.05,99.998 +10000,0.67983,0.69331,0.05,99.998 +10000,0.67983,0.69331,0.05,99.998 +10000,0.67983,0.69331,0.05,99.998 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/data_10.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/data_10.csv new file mode 100644 index 00000000000..7980a3a5bfe --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/data_10.csv @@ -0,0 +1,1002 @@ +Time,"elementCenter:0","elementCenter:1","elementCenter:2","temperature" +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,0.07071,0.072112,0.05,-19.432 +1e+05,0.07071,0.072112,0.05,-19.432 +1e+05,0.07211,0.07354,0.05,-18.317 +1e+05,0.07351,0.074968,0.05,-17.224 +1e+05,0.075155,0.076646,0.05,-15.964 +1e+05,0.075155,0.076646,0.05,-15.964 +1e+05,0.077046,0.078574,0.05,-14.552 +1e+05,0.077046,0.078574,0.05,-14.552 +1e+05,0.078936,0.080501,0.05,-13.175 +1e+05,0.078936,0.080501,0.05,-13.175 +1e+05,0.080826,0.082429,0.05,-11.83 +1e+05,0.080826,0.082429,0.05,-11.83 +1e+05,0.082716,0.084357,0.05,-10.516 +1e+05,0.082716,0.084357,0.05,-10.516 +1e+05,0.084607,0.086285,0.05,-9.2319 +1e+05,0.084607,0.086285,0.05,-9.2319 +1e+05,0.086497,0.088212,0.05,-7.9764 +1e+05,0.086497,0.088212,0.05,-7.9764 +1e+05,0.088387,0.09014,0.05,-6.748 +1e+05,0.088387,0.09014,0.05,-6.748 +1e+05,0.090278,0.092068,0.05,-5.5458 +1e+05,0.090278,0.092068,0.05,-5.5458 +1e+05,0.092168,0.093995,0.05,-4.3685 +1e+05,0.092168,0.093995,0.05,-4.3685 +1e+05,0.094031,0.095896,0.05,-3.2318 +1e+05,0.095885,0.097786,0.05,-2.1226 +1e+05,0.095885,0.097786,0.05,-2.1226 +1e+05,0.097776,0.099715,0.05,-1.0134 +1e+05,0.097776,0.099715,0.05,-1.0134 +1e+05,0.099704,0.10168,0.05,0.095763 +1e+05,0.099704,0.10168,0.05,0.095763 +1e+05,0.10167,0.10369,0.05,1.2049 +1e+05,0.10167,0.10369,0.05,1.2049 +1e+05,0.10368,0.10573,0.05,2.3141 +1e+05,0.10368,0.10573,0.05,2.3141 +1e+05,0.10572,0.10782,0.05,3.4231 +1e+05,0.10572,0.10782,0.05,3.4231 +1e+05,0.10781,0.10995,0.05,4.5321 +1e+05,0.10781,0.10995,0.05,4.5321 +1e+05,0.10993,0.11211,0.05,5.641 +1e+05,0.10993,0.11211,0.05,5.641 +1e+05,0.10993,0.11211,0.05,5.641 +1e+05,0.1121,0.11433,0.05,6.7497 +1e+05,0.1121,0.11433,0.05,6.7497 +1e+05,0.11432,0.11658,0.05,7.8584 +1e+05,0.11432,0.11658,0.05,7.8584 +1e+05,0.11657,0.11888,0.05,8.9668 +1e+05,0.11657,0.11888,0.05,8.9668 +1e+05,0.11887,0.12123,0.05,10.075 +1e+05,0.11887,0.12123,0.05,10.075 +1e+05,0.11887,0.12123,0.05,10.075 +1e+05,0.12122,0.12362,0.05,11.183 +1e+05,0.12122,0.12362,0.05,11.183 +1e+05,0.12361,0.12607,0.05,12.291 +1e+05,0.12361,0.12607,0.05,12.291 +1e+05,0.12361,0.12607,0.05,12.291 +1e+05,0.12605,0.12855,0.05,13.399 +1e+05,0.12605,0.12855,0.05,13.399 +1e+05,0.12854,0.13109,0.05,14.506 +1e+05,0.12854,0.13109,0.05,14.506 +1e+05,0.12854,0.13109,0.05,14.506 +1e+05,0.13108,0.13368,0.05,15.613 +1e+05,0.13108,0.13368,0.05,15.613 +1e+05,0.13367,0.13632,0.05,16.72 +1e+05,0.13367,0.13632,0.05,16.72 +1e+05,0.13367,0.13632,0.05,16.72 +1e+05,0.13631,0.13901,0.05,17.826 +1e+05,0.13631,0.13901,0.05,17.826 +1e+05,0.13631,0.13901,0.05,17.826 +1e+05,0.139,0.14176,0.05,18.932 +1e+05,0.139,0.14176,0.05,18.932 +1e+05,0.14175,0.14456,0.05,20.037 +1e+05,0.14175,0.14456,0.05,20.037 +1e+05,0.14175,0.14456,0.05,20.037 +1e+05,0.14455,0.14742,0.05,21.142 +1e+05,0.14455,0.14742,0.05,21.142 +1e+05,0.14455,0.14742,0.05,21.142 +1e+05,0.1474,0.15033,0.05,22.246 +1e+05,0.1474,0.15033,0.05,22.246 +1e+05,0.1474,0.15033,0.05,22.246 +1e+05,0.15032,0.1533,0.05,23.35 +1e+05,0.15032,0.1533,0.05,23.35 +1e+05,0.15032,0.1533,0.05,23.35 +1e+05,0.15329,0.15633,0.05,24.453 +1e+05,0.15329,0.15633,0.05,24.453 +1e+05,0.15329,0.15633,0.05,24.453 +1e+05,0.15632,0.15942,0.05,25.556 +1e+05,0.15632,0.15942,0.05,25.556 +1e+05,0.15632,0.15942,0.05,25.556 +1e+05,0.15941,0.16257,0.05,26.658 +1e+05,0.15941,0.16257,0.05,26.658 +1e+05,0.15941,0.16257,0.05,26.658 +1e+05,0.16256,0.16578,0.05,27.759 +1e+05,0.16256,0.16578,0.05,27.759 +1e+05,0.16256,0.16578,0.05,27.759 +1e+05,0.16577,0.16906,0.05,28.859 +1e+05,0.16577,0.16906,0.05,28.859 +1e+05,0.16577,0.16906,0.05,28.859 +1e+05,0.16577,0.16906,0.05,28.859 +1e+05,0.16905,0.1724,0.05,29.959 +1e+05,0.16905,0.1724,0.05,29.959 +1e+05,0.16905,0.1724,0.05,29.959 +1e+05,0.17239,0.1758,0.05,31.057 +1e+05,0.17239,0.1758,0.05,31.057 +1e+05,0.17239,0.1758,0.05,31.057 +1e+05,0.17579,0.17928,0.05,32.155 +1e+05,0.17579,0.17928,0.05,32.155 +1e+05,0.17579,0.17928,0.05,32.155 +1e+05,0.17579,0.17928,0.05,32.155 +1e+05,0.17927,0.18282,0.05,33.251 +1e+05,0.17927,0.18282,0.05,33.251 +1e+05,0.17927,0.18282,0.05,33.251 +1e+05,0.18281,0.18644,0.05,34.346 +1e+05,0.18281,0.18644,0.05,34.346 +1e+05,0.18281,0.18644,0.05,34.346 +1e+05,0.18281,0.18644,0.05,34.346 +1e+05,0.18643,0.19013,0.05,35.441 +1e+05,0.18643,0.19013,0.05,35.441 +1e+05,0.18643,0.19013,0.05,35.441 +1e+05,0.18643,0.19013,0.05,35.441 +1e+05,0.19011,0.19388,0.05,36.534 +1e+05,0.19011,0.19388,0.05,36.534 +1e+05,0.19011,0.19388,0.05,36.534 +1e+05,0.19387,0.19772,0.05,37.625 +1e+05,0.19387,0.19772,0.05,37.625 +1e+05,0.19387,0.19772,0.05,37.625 +1e+05,0.19387,0.19772,0.05,37.625 +1e+05,0.19771,0.20163,0.05,38.715 +1e+05,0.19771,0.20163,0.05,38.715 +1e+05,0.19771,0.20163,0.05,38.715 +1e+05,0.19771,0.20163,0.05,38.715 +1e+05,0.20162,0.20562,0.05,39.804 +1e+05,0.20162,0.20562,0.05,39.804 +1e+05,0.20162,0.20562,0.05,39.804 +1e+05,0.20162,0.20562,0.05,39.804 +1e+05,0.2056,0.20968,0.05,40.891 +1e+05,0.2056,0.20968,0.05,40.891 +1e+05,0.2056,0.20968,0.05,40.891 +1e+05,0.2056,0.20968,0.05,40.891 +1e+05,0.20967,0.21383,0.05,41.976 +1e+05,0.20967,0.21383,0.05,41.976 +1e+05,0.20967,0.21383,0.05,41.976 +1e+05,0.20967,0.21383,0.05,41.976 +1e+05,0.21382,0.21806,0.05,43.06 +1e+05,0.21382,0.21806,0.05,43.06 +1e+05,0.21382,0.21806,0.05,43.06 +1e+05,0.21382,0.21806,0.05,43.06 +1e+05,0.21382,0.21806,0.05,43.06 +1e+05,0.21805,0.22237,0.05,44.142 +1e+05,0.21805,0.22237,0.05,44.142 +1e+05,0.21805,0.22237,0.05,44.142 +1e+05,0.21805,0.22237,0.05,44.142 +1e+05,0.22236,0.22677,0.05,45.222 +1e+05,0.22236,0.22677,0.05,45.222 +1e+05,0.22236,0.22677,0.05,45.222 +1e+05,0.22236,0.22677,0.05,45.222 +1e+05,0.22676,0.23125,0.05,46.299 +1e+05,0.22676,0.23125,0.05,46.299 +1e+05,0.22676,0.23125,0.05,46.299 +1e+05,0.22676,0.23125,0.05,46.299 +1e+05,0.22676,0.23125,0.05,46.299 +1e+05,0.23124,0.23583,0.05,47.375 +1e+05,0.23124,0.23583,0.05,47.375 +1e+05,0.23124,0.23583,0.05,47.375 +1e+05,0.23124,0.23583,0.05,47.375 +1e+05,0.23582,0.2405,0.05,48.448 +1e+05,0.23582,0.2405,0.05,48.448 +1e+05,0.23582,0.2405,0.05,48.448 +1e+05,0.23582,0.2405,0.05,48.448 +1e+05,0.23582,0.2405,0.05,48.448 +1e+05,0.24048,0.24525,0.05,49.519 +1e+05,0.24048,0.24525,0.05,49.519 +1e+05,0.24048,0.24525,0.05,49.519 +1e+05,0.24048,0.24525,0.05,49.519 +1e+05,0.24048,0.24525,0.05,49.519 +1e+05,0.24524,0.25011,0.05,50.587 +1e+05,0.24524,0.25011,0.05,50.587 +1e+05,0.24524,0.25011,0.05,50.587 +1e+05,0.24524,0.25011,0.05,50.587 +1e+05,0.24524,0.25011,0.05,50.587 +1e+05,0.25009,0.25505,0.05,51.653 +1e+05,0.25009,0.25505,0.05,51.653 +1e+05,0.25009,0.25505,0.05,51.653 +1e+05,0.25009,0.25505,0.05,51.653 +1e+05,0.25009,0.25505,0.05,51.653 +1e+05,0.25504,0.2601,0.05,52.715 +1e+05,0.25504,0.2601,0.05,52.715 +1e+05,0.25504,0.2601,0.05,52.715 +1e+05,0.25504,0.2601,0.05,52.715 +1e+05,0.25504,0.2601,0.05,52.715 +1e+05,0.26009,0.26525,0.05,53.775 +1e+05,0.26009,0.26525,0.05,53.775 +1e+05,0.26009,0.26525,0.05,53.775 +1e+05,0.26009,0.26525,0.05,53.775 +1e+05,0.26009,0.26525,0.05,53.775 +1e+05,0.26524,0.2705,0.05,54.832 +1e+05,0.26524,0.2705,0.05,54.832 +1e+05,0.26524,0.2705,0.05,54.832 +1e+05,0.26524,0.2705,0.05,54.832 +1e+05,0.26524,0.2705,0.05,54.832 +1e+05,0.27048,0.27585,0.05,55.885 +1e+05,0.27048,0.27585,0.05,55.885 +1e+05,0.27048,0.27585,0.05,55.885 +1e+05,0.27048,0.27585,0.05,55.885 +1e+05,0.27048,0.27585,0.05,55.885 +1e+05,0.27584,0.28131,0.05,56.935 +1e+05,0.27584,0.28131,0.05,56.935 +1e+05,0.27584,0.28131,0.05,56.935 +1e+05,0.27584,0.28131,0.05,56.935 +1e+05,0.27584,0.28131,0.05,56.935 +1e+05,0.27584,0.28131,0.05,56.935 +1e+05,0.2813,0.28687,0.05,57.982 +1e+05,0.2813,0.28687,0.05,57.982 +1e+05,0.2813,0.28687,0.05,57.982 +1e+05,0.2813,0.28687,0.05,57.982 +1e+05,0.2813,0.28687,0.05,57.982 +1e+05,0.28686,0.29255,0.05,59.025 +1e+05,0.28686,0.29255,0.05,59.025 +1e+05,0.28686,0.29255,0.05,59.025 +1e+05,0.28686,0.29255,0.05,59.025 +1e+05,0.28686,0.29255,0.05,59.025 +1e+05,0.28686,0.29255,0.05,59.025 +1e+05,0.29254,0.29834,0.05,60.063 +1e+05,0.29254,0.29834,0.05,60.063 +1e+05,0.29254,0.29834,0.05,60.063 +1e+05,0.29254,0.29834,0.05,60.063 +1e+05,0.29254,0.29834,0.05,60.063 +1e+05,0.29254,0.29834,0.05,60.063 +1e+05,0.29833,0.30425,0.05,61.098 +1e+05,0.29833,0.30425,0.05,61.098 +1e+05,0.29833,0.30425,0.05,61.098 +1e+05,0.29833,0.30425,0.05,61.098 +1e+05,0.29833,0.30425,0.05,61.098 +1e+05,0.29833,0.30425,0.05,61.098 +1e+05,0.30424,0.31027,0.05,62.129 +1e+05,0.30424,0.31027,0.05,62.129 +1e+05,0.30424,0.31027,0.05,62.129 +1e+05,0.30424,0.31027,0.05,62.129 +1e+05,0.30424,0.31027,0.05,62.129 +1e+05,0.30424,0.31027,0.05,62.129 +1e+05,0.31026,0.31641,0.05,63.155 +1e+05,0.31026,0.31641,0.05,63.155 +1e+05,0.31026,0.31641,0.05,63.155 +1e+05,0.31026,0.31641,0.05,63.155 +1e+05,0.31026,0.31641,0.05,63.155 +1e+05,0.31026,0.31641,0.05,63.155 +1e+05,0.3164,0.32267,0.05,64.177 +1e+05,0.3164,0.32267,0.05,64.177 +1e+05,0.3164,0.32267,0.05,64.177 +1e+05,0.3164,0.32267,0.05,64.177 +1e+05,0.3164,0.32267,0.05,64.177 +1e+05,0.3164,0.32267,0.05,64.177 +1e+05,0.32266,0.32906,0.05,65.194 +1e+05,0.32266,0.32906,0.05,65.194 +1e+05,0.32266,0.32906,0.05,65.194 +1e+05,0.32266,0.32906,0.05,65.194 +1e+05,0.32266,0.32906,0.05,65.194 +1e+05,0.32266,0.32906,0.05,65.194 +1e+05,0.32266,0.32906,0.05,65.194 +1e+05,0.32905,0.33558,0.05,66.205 +1e+05,0.32905,0.33558,0.05,66.205 +1e+05,0.32905,0.33558,0.05,66.205 +1e+05,0.32905,0.33558,0.05,66.205 +1e+05,0.32905,0.33558,0.05,66.205 +1e+05,0.32905,0.33558,0.05,66.205 +1e+05,0.33556,0.34222,0.05,67.212 +1e+05,0.33556,0.34222,0.05,67.212 +1e+05,0.33556,0.34222,0.05,67.212 +1e+05,0.33556,0.34222,0.05,67.212 +1e+05,0.33556,0.34222,0.05,67.212 +1e+05,0.33556,0.34222,0.05,67.212 +1e+05,0.33556,0.34222,0.05,67.212 +1e+05,0.34221,0.34899,0.05,68.214 +1e+05,0.34221,0.34899,0.05,68.214 +1e+05,0.34221,0.34899,0.05,68.214 +1e+05,0.34221,0.34899,0.05,68.214 +1e+05,0.34221,0.34899,0.05,68.214 +1e+05,0.34221,0.34899,0.05,68.214 +1e+05,0.34221,0.34899,0.05,68.214 +1e+05,0.34898,0.3559,0.05,69.209 +1e+05,0.34898,0.3559,0.05,69.209 +1e+05,0.34898,0.3559,0.05,69.209 +1e+05,0.34898,0.3559,0.05,69.209 +1e+05,0.34898,0.3559,0.05,69.209 +1e+05,0.34898,0.3559,0.05,69.209 +1e+05,0.35589,0.36295,0.05,70.2 +1e+05,0.35589,0.36295,0.05,70.2 +1e+05,0.35589,0.36295,0.05,70.2 +1e+05,0.35589,0.36295,0.05,70.2 +1e+05,0.35589,0.36295,0.05,70.2 +1e+05,0.35589,0.36295,0.05,70.2 +1e+05,0.35589,0.36295,0.05,70.2 +1e+05,0.36294,0.37013,0.05,71.184 +1e+05,0.36294,0.37013,0.05,71.184 +1e+05,0.36294,0.37013,0.05,71.184 +1e+05,0.36294,0.37013,0.05,71.184 +1e+05,0.36294,0.37013,0.05,71.184 +1e+05,0.36294,0.37013,0.05,71.184 +1e+05,0.36294,0.37013,0.05,71.184 +1e+05,0.36294,0.37013,0.05,71.184 +1e+05,0.37012,0.37746,0.05,72.162 +1e+05,0.37012,0.37746,0.05,72.162 +1e+05,0.37012,0.37746,0.05,72.162 +1e+05,0.37012,0.37746,0.05,72.162 +1e+05,0.37012,0.37746,0.05,72.162 +1e+05,0.37012,0.37746,0.05,72.162 +1e+05,0.37012,0.37746,0.05,72.162 +1e+05,0.37745,0.38494,0.05,73.134 +1e+05,0.37745,0.38494,0.05,73.134 +1e+05,0.37745,0.38494,0.05,73.134 +1e+05,0.37745,0.38494,0.05,73.134 +1e+05,0.37745,0.38494,0.05,73.134 +1e+05,0.37745,0.38494,0.05,73.134 +1e+05,0.37745,0.38494,0.05,73.134 +1e+05,0.38493,0.39256,0.05,74.099 +1e+05,0.38493,0.39256,0.05,74.099 +1e+05,0.38493,0.39256,0.05,74.099 +1e+05,0.38493,0.39256,0.05,74.099 +1e+05,0.38493,0.39256,0.05,74.099 +1e+05,0.38493,0.39256,0.05,74.099 +1e+05,0.38493,0.39256,0.05,74.099 +1e+05,0.38493,0.39256,0.05,74.099 +1e+05,0.39255,0.40033,0.05,75.057 +1e+05,0.39255,0.40033,0.05,75.057 +1e+05,0.39255,0.40033,0.05,75.057 +1e+05,0.39255,0.40033,0.05,75.057 +1e+05,0.39255,0.40033,0.05,75.057 +1e+05,0.39255,0.40033,0.05,75.057 +1e+05,0.39255,0.40033,0.05,75.057 +1e+05,0.39255,0.40033,0.05,75.057 +1e+05,0.40032,0.40826,0.05,76.009 +1e+05,0.40032,0.40826,0.05,76.009 +1e+05,0.40032,0.40826,0.05,76.009 +1e+05,0.40032,0.40826,0.05,76.009 +1e+05,0.40032,0.40826,0.05,76.009 +1e+05,0.40032,0.40826,0.05,76.009 +1e+05,0.40032,0.40826,0.05,76.009 +1e+05,0.40032,0.40826,0.05,76.009 +1e+05,0.40825,0.41634,0.05,76.954 +1e+05,0.40825,0.41634,0.05,76.954 +1e+05,0.40825,0.41634,0.05,76.954 +1e+05,0.40825,0.41634,0.05,76.954 +1e+05,0.40825,0.41634,0.05,76.954 +1e+05,0.40825,0.41634,0.05,76.954 +1e+05,0.40825,0.41634,0.05,76.954 +1e+05,0.40825,0.41634,0.05,76.954 +1e+05,0.41633,0.42459,0.05,77.891 +1e+05,0.41633,0.42459,0.05,77.891 +1e+05,0.41633,0.42459,0.05,77.891 +1e+05,0.41633,0.42459,0.05,77.891 +1e+05,0.41633,0.42459,0.05,77.891 +1e+05,0.41633,0.42459,0.05,77.891 +1e+05,0.41633,0.42459,0.05,77.891 +1e+05,0.41633,0.42459,0.05,77.891 +1e+05,0.42458,0.433,0.05,78.821 +1e+05,0.42458,0.433,0.05,78.821 +1e+05,0.42458,0.433,0.05,78.821 +1e+05,0.42458,0.433,0.05,78.821 +1e+05,0.42458,0.433,0.05,78.821 +1e+05,0.42458,0.433,0.05,78.821 +1e+05,0.42458,0.433,0.05,78.821 +1e+05,0.42458,0.433,0.05,78.821 +1e+05,0.42458,0.433,0.05,78.821 +1e+05,0.43298,0.44157,0.05,79.743 +1e+05,0.43298,0.44157,0.05,79.743 +1e+05,0.43298,0.44157,0.05,79.743 +1e+05,0.43298,0.44157,0.05,79.743 +1e+05,0.43298,0.44157,0.05,79.743 +1e+05,0.43298,0.44157,0.05,79.743 +1e+05,0.43298,0.44157,0.05,79.743 +1e+05,0.43298,0.44157,0.05,79.743 +1e+05,0.44156,0.45031,0.05,80.658 +1e+05,0.44156,0.45031,0.05,80.658 +1e+05,0.44156,0.45031,0.05,80.658 +1e+05,0.44156,0.45031,0.05,80.658 +1e+05,0.44156,0.45031,0.05,80.658 +1e+05,0.44156,0.45031,0.05,80.658 +1e+05,0.44156,0.45031,0.05,80.658 +1e+05,0.44156,0.45031,0.05,80.658 +1e+05,0.44156,0.45031,0.05,80.658 +1e+05,0.4503,0.45923,0.05,81.565 +1e+05,0.4503,0.45923,0.05,81.565 +1e+05,0.4503,0.45923,0.05,81.565 +1e+05,0.4503,0.45923,0.05,81.565 +1e+05,0.4503,0.45923,0.05,81.565 +1e+05,0.4503,0.45923,0.05,81.565 +1e+05,0.4503,0.45923,0.05,81.565 +1e+05,0.4503,0.45923,0.05,81.565 +1e+05,0.4503,0.45923,0.05,81.565 +1e+05,0.45922,0.46833,0.05,82.464 +1e+05,0.45922,0.46833,0.05,82.464 +1e+05,0.45922,0.46833,0.05,82.464 +1e+05,0.45922,0.46833,0.05,82.464 +1e+05,0.45922,0.46833,0.05,82.464 +1e+05,0.45922,0.46833,0.05,82.464 +1e+05,0.45922,0.46833,0.05,82.464 +1e+05,0.45922,0.46833,0.05,82.464 +1e+05,0.45922,0.46833,0.05,82.464 +1e+05,0.46832,0.4776,0.05,83.355 +1e+05,0.46832,0.4776,0.05,83.355 +1e+05,0.46832,0.4776,0.05,83.355 +1e+05,0.46832,0.4776,0.05,83.355 +1e+05,0.46832,0.4776,0.05,83.355 +1e+05,0.46832,0.4776,0.05,83.355 +1e+05,0.46832,0.4776,0.05,83.355 +1e+05,0.46832,0.4776,0.05,83.355 +1e+05,0.46832,0.4776,0.05,83.355 +1e+05,0.47759,0.48706,0.05,84.238 +1e+05,0.47759,0.48706,0.05,84.238 +1e+05,0.47759,0.48706,0.05,84.238 +1e+05,0.47759,0.48706,0.05,84.238 +1e+05,0.47759,0.48706,0.05,84.238 +1e+05,0.47759,0.48706,0.05,84.238 +1e+05,0.47759,0.48706,0.05,84.238 +1e+05,0.47759,0.48706,0.05,84.238 +1e+05,0.47759,0.48706,0.05,84.238 +1e+05,0.47759,0.48706,0.05,84.238 +1e+05,0.48705,0.49671,0.05,85.112 +1e+05,0.48705,0.49671,0.05,85.112 +1e+05,0.48705,0.49671,0.05,85.112 +1e+05,0.48705,0.49671,0.05,85.112 +1e+05,0.48705,0.49671,0.05,85.112 +1e+05,0.48705,0.49671,0.05,85.112 +1e+05,0.48705,0.49671,0.05,85.112 +1e+05,0.48705,0.49671,0.05,85.112 +1e+05,0.48705,0.49671,0.05,85.112 +1e+05,0.4967,0.50655,0.05,85.979 +1e+05,0.4967,0.50655,0.05,85.979 +1e+05,0.4967,0.50655,0.05,85.979 +1e+05,0.4967,0.50655,0.05,85.979 +1e+05,0.4967,0.50655,0.05,85.979 +1e+05,0.4967,0.50655,0.05,85.979 +1e+05,0.4967,0.50655,0.05,85.979 +1e+05,0.4967,0.50655,0.05,85.979 +1e+05,0.4967,0.50655,0.05,85.979 +1e+05,0.4967,0.50655,0.05,85.979 +1e+05,0.50654,0.51658,0.05,86.837 +1e+05,0.50654,0.51658,0.05,86.837 +1e+05,0.50654,0.51658,0.05,86.837 +1e+05,0.50654,0.51658,0.05,86.837 +1e+05,0.50654,0.51658,0.05,86.837 +1e+05,0.50654,0.51658,0.05,86.837 +1e+05,0.50654,0.51658,0.05,86.837 +1e+05,0.50654,0.51658,0.05,86.837 +1e+05,0.50654,0.51658,0.05,86.837 +1e+05,0.50654,0.51658,0.05,86.837 +1e+05,0.51657,0.52681,0.05,87.687 +1e+05,0.51657,0.52681,0.05,87.687 +1e+05,0.51657,0.52681,0.05,87.687 +1e+05,0.51657,0.52681,0.05,87.687 +1e+05,0.51657,0.52681,0.05,87.687 +1e+05,0.51657,0.52681,0.05,87.687 +1e+05,0.51657,0.52681,0.05,87.687 +1e+05,0.51657,0.52681,0.05,87.687 +1e+05,0.51657,0.52681,0.05,87.687 +1e+05,0.51657,0.52681,0.05,87.687 +1e+05,0.5268,0.53725,0.05,88.53 +1e+05,0.5268,0.53725,0.05,88.53 +1e+05,0.5268,0.53725,0.05,88.53 +1e+05,0.5268,0.53725,0.05,88.53 +1e+05,0.5268,0.53725,0.05,88.53 +1e+05,0.5268,0.53725,0.05,88.53 +1e+05,0.5268,0.53725,0.05,88.53 +1e+05,0.5268,0.53725,0.05,88.53 +1e+05,0.5268,0.53725,0.05,88.53 +1e+05,0.5268,0.53725,0.05,88.53 +1e+05,0.5268,0.53725,0.05,88.53 +1e+05,0.53724,0.54789,0.05,89.364 +1e+05,0.53724,0.54789,0.05,89.364 +1e+05,0.53724,0.54789,0.05,89.364 +1e+05,0.53724,0.54789,0.05,89.364 +1e+05,0.53724,0.54789,0.05,89.364 +1e+05,0.53724,0.54789,0.05,89.364 +1e+05,0.53724,0.54789,0.05,89.364 +1e+05,0.53724,0.54789,0.05,89.364 +1e+05,0.53724,0.54789,0.05,89.364 +1e+05,0.53724,0.54789,0.05,89.364 +1e+05,0.54788,0.55874,0.05,90.19 +1e+05,0.54788,0.55874,0.05,90.19 +1e+05,0.54788,0.55874,0.05,90.19 +1e+05,0.54788,0.55874,0.05,90.19 +1e+05,0.54788,0.55874,0.05,90.19 +1e+05,0.54788,0.55874,0.05,90.19 +1e+05,0.54788,0.55874,0.05,90.19 +1e+05,0.54788,0.55874,0.05,90.19 +1e+05,0.54788,0.55874,0.05,90.19 +1e+05,0.54788,0.55874,0.05,90.19 +1e+05,0.54788,0.55874,0.05,90.19 +1e+05,0.55873,0.56981,0.05,91.009 +1e+05,0.55873,0.56981,0.05,91.009 +1e+05,0.55873,0.56981,0.05,91.009 +1e+05,0.55873,0.56981,0.05,91.009 +1e+05,0.55873,0.56981,0.05,91.009 +1e+05,0.55873,0.56981,0.05,91.009 +1e+05,0.55873,0.56981,0.05,91.009 +1e+05,0.55873,0.56981,0.05,91.009 +1e+05,0.55873,0.56981,0.05,91.009 +1e+05,0.55873,0.56981,0.05,91.009 +1e+05,0.55873,0.56981,0.05,91.009 +1e+05,0.5698,0.5811,0.05,91.82 +1e+05,0.5698,0.5811,0.05,91.82 +1e+05,0.5698,0.5811,0.05,91.82 +1e+05,0.5698,0.5811,0.05,91.82 +1e+05,0.5698,0.5811,0.05,91.82 +1e+05,0.5698,0.5811,0.05,91.82 +1e+05,0.5698,0.5811,0.05,91.82 +1e+05,0.5698,0.5811,0.05,91.82 +1e+05,0.5698,0.5811,0.05,91.82 +1e+05,0.5698,0.5811,0.05,91.82 +1e+05,0.5698,0.5811,0.05,91.82 +1e+05,0.5698,0.5811,0.05,91.82 +1e+05,0.58109,0.59261,0.05,92.624 +1e+05,0.58109,0.59261,0.05,92.624 +1e+05,0.58109,0.59261,0.05,92.624 +1e+05,0.58109,0.59261,0.05,92.624 +1e+05,0.58109,0.59261,0.05,92.624 +1e+05,0.58109,0.59261,0.05,92.624 +1e+05,0.58109,0.59261,0.05,92.624 +1e+05,0.58109,0.59261,0.05,92.624 +1e+05,0.58109,0.59261,0.05,92.624 +1e+05,0.58109,0.59261,0.05,92.624 +1e+05,0.58109,0.59261,0.05,92.624 +1e+05,0.5926,0.60435,0.05,93.422 +1e+05,0.5926,0.60435,0.05,93.422 +1e+05,0.5926,0.60435,0.05,93.422 +1e+05,0.5926,0.60435,0.05,93.422 +1e+05,0.5926,0.60435,0.05,93.422 +1e+05,0.5926,0.60435,0.05,93.422 +1e+05,0.5926,0.60435,0.05,93.422 +1e+05,0.5926,0.60435,0.05,93.422 +1e+05,0.5926,0.60435,0.05,93.422 +1e+05,0.5926,0.60435,0.05,93.422 +1e+05,0.5926,0.60435,0.05,93.422 +1e+05,0.5926,0.60435,0.05,93.422 +1e+05,0.60434,0.61632,0.05,94.213 +1e+05,0.60434,0.61632,0.05,94.213 +1e+05,0.60434,0.61632,0.05,94.213 +1e+05,0.60434,0.61632,0.05,94.213 +1e+05,0.60434,0.61632,0.05,94.213 +1e+05,0.60434,0.61632,0.05,94.213 +1e+05,0.60434,0.61632,0.05,94.213 +1e+05,0.60434,0.61632,0.05,94.213 +1e+05,0.60434,0.61632,0.05,94.213 +1e+05,0.60434,0.61632,0.05,94.213 +1e+05,0.60434,0.61632,0.05,94.213 +1e+05,0.60434,0.61632,0.05,94.213 +1e+05,0.61631,0.62853,0.05,94.998 +1e+05,0.61631,0.62853,0.05,94.998 +1e+05,0.61631,0.62853,0.05,94.998 +1e+05,0.61631,0.62853,0.05,94.998 +1e+05,0.61631,0.62853,0.05,94.998 +1e+05,0.61631,0.62853,0.05,94.998 +1e+05,0.61631,0.62853,0.05,94.998 +1e+05,0.61631,0.62853,0.05,94.998 +1e+05,0.61631,0.62853,0.05,94.998 +1e+05,0.61631,0.62853,0.05,94.998 +1e+05,0.61631,0.62853,0.05,94.998 +1e+05,0.61631,0.62853,0.05,94.998 +1e+05,0.62852,0.64098,0.05,95.778 +1e+05,0.62852,0.64098,0.05,95.778 +1e+05,0.62852,0.64098,0.05,95.778 +1e+05,0.62852,0.64098,0.05,95.778 +1e+05,0.62852,0.64098,0.05,95.778 +1e+05,0.62852,0.64098,0.05,95.778 +1e+05,0.62852,0.64098,0.05,95.778 +1e+05,0.62852,0.64098,0.05,95.778 +1e+05,0.62852,0.64098,0.05,95.778 +1e+05,0.62852,0.64098,0.05,95.778 +1e+05,0.62852,0.64098,0.05,95.778 +1e+05,0.62852,0.64098,0.05,95.778 +1e+05,0.62852,0.64098,0.05,95.778 +1e+05,0.64097,0.65368,0.05,96.553 +1e+05,0.64097,0.65368,0.05,96.553 +1e+05,0.64097,0.65368,0.05,96.553 +1e+05,0.64097,0.65368,0.05,96.553 +1e+05,0.64097,0.65368,0.05,96.553 +1e+05,0.64097,0.65368,0.05,96.553 +1e+05,0.64097,0.65368,0.05,96.553 +1e+05,0.64097,0.65368,0.05,96.553 +1e+05,0.64097,0.65368,0.05,96.553 +1e+05,0.64097,0.65368,0.05,96.553 +1e+05,0.64097,0.65368,0.05,96.553 +1e+05,0.64097,0.65368,0.05,96.553 +1e+05,0.65367,0.66663,0.05,97.325 +1e+05,0.65367,0.66663,0.05,97.325 +1e+05,0.65367,0.66663,0.05,97.325 +1e+05,0.65367,0.66663,0.05,97.325 +1e+05,0.65367,0.66663,0.05,97.325 +1e+05,0.65367,0.66663,0.05,97.325 +1e+05,0.65367,0.66663,0.05,97.325 +1e+05,0.65367,0.66663,0.05,97.325 +1e+05,0.65367,0.66663,0.05,97.325 +1e+05,0.65367,0.66663,0.05,97.325 +1e+05,0.65367,0.66663,0.05,97.325 +1e+05,0.65367,0.66663,0.05,97.325 +1e+05,0.65367,0.66663,0.05,97.325 +1e+05,0.66662,0.67984,0.05,98.093 +1e+05,0.66662,0.67984,0.05,98.093 +1e+05,0.66662,0.67984,0.05,98.093 +1e+05,0.66662,0.67984,0.05,98.093 +1e+05,0.66662,0.67984,0.05,98.093 +1e+05,0.66662,0.67984,0.05,98.093 +1e+05,0.66662,0.67984,0.05,98.093 +1e+05,0.66662,0.67984,0.05,98.093 +1e+05,0.66662,0.67984,0.05,98.093 +1e+05,0.66662,0.67984,0.05,98.093 +1e+05,0.66662,0.67984,0.05,98.093 +1e+05,0.66662,0.67984,0.05,98.093 +1e+05,0.66662,0.67984,0.05,98.093 +1e+05,0.67983,0.69331,0.05,98.858 +1e+05,0.67983,0.69331,0.05,98.858 +1e+05,0.67983,0.69331,0.05,98.858 +1e+05,0.67983,0.69331,0.05,98.858 +1e+05,0.67983,0.69331,0.05,98.858 +1e+05,0.67983,0.69331,0.05,98.858 +1e+05,0.67983,0.69331,0.05,98.858 +1e+05,0.67983,0.69331,0.05,98.858 +1e+05,0.67983,0.69331,0.05,98.858 +1e+05,0.67983,0.69331,0.05,98.858 +1e+05,0.67983,0.69331,0.05,98.858 +1e+05,0.67983,0.69331,0.05,98.858 +1e+05,0.67983,0.69331,0.05,98.858 +1e+05,0.67983,0.69331,0.05,98.858 +1e+05,0.6933,0.70704,0.05,99.622 +1e+05,0.6933,0.70704,0.05,99.622 +1e+05,0.6933,0.70704,0.05,99.622 +1e+05,0.6933,0.70704,0.05,99.622 +1e+05,0.6933,0.70704,0.05,99.622 +1e+05,0.6933,0.70704,0.05,99.622 +1e+05,0.6933,0.70704,0.05,99.622 +1e+05,0.6933,0.70704,0.05,99.622 +1e+05,0.6933,0.70704,0.05,99.622 +1e+05,0.6933,0.70704,0.05,99.622 +1e+05,0.6933,0.70704,0.05,99.622 +1e+05,0.6933,0.70704,0.05,99.622 +1e+05,0.6933,0.70704,0.05,99.622 +1e+05,0.6933,0.70704,0.05,99.622 +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/data_2.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/data_2.csv new file mode 100644 index 00000000000..898f12c9d0d --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/data_2.csv @@ -0,0 +1,1002 @@ +Time,"elementCenter:0","elementCenter:1","elementCenter:2","temperature" +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,0.07071,0.072112,0.05,-19.178 +20000,0.07071,0.072112,0.05,-19.178 +20000,0.07211,0.07354,0.05,-17.568 +20000,0.07351,0.074968,0.05,-15.988 +20000,0.075155,0.076646,0.05,-14.167 +20000,0.075155,0.076646,0.05,-14.167 +20000,0.077046,0.078574,0.05,-12.127 +20000,0.077046,0.078574,0.05,-12.127 +20000,0.078936,0.080501,0.05,-10.136 +20000,0.078936,0.080501,0.05,-10.136 +20000,0.080826,0.082429,0.05,-8.1938 +20000,0.080826,0.082429,0.05,-8.1938 +20000,0.082716,0.084357,0.05,-6.2968 +20000,0.082716,0.084357,0.05,-6.2968 +20000,0.084607,0.086285,0.05,-4.4434 +20000,0.084607,0.086285,0.05,-4.4434 +20000,0.086497,0.088212,0.05,-2.6319 +20000,0.086497,0.088212,0.05,-2.6319 +20000,0.088387,0.09014,0.05,-0.86037 +20000,0.088387,0.09014,0.05,-0.86037 +20000,0.090278,0.092068,0.05,0.87259 +20000,0.090278,0.092068,0.05,0.87259 +20000,0.092168,0.093995,0.05,2.5685 +20000,0.092168,0.093995,0.05,2.5685 +20000,0.094031,0.095896,0.05,4.2049 +20000,0.095885,0.097786,0.05,5.8006 +20000,0.095885,0.097786,0.05,5.8006 +20000,0.097776,0.099715,0.05,7.3951 +20000,0.097776,0.099715,0.05,7.3951 +20000,0.099704,0.10168,0.05,8.9883 +20000,0.099704,0.10168,0.05,8.9883 +20000,0.10167,0.10369,0.05,10.58 +20000,0.10167,0.10369,0.05,10.58 +20000,0.10368,0.10573,0.05,12.17 +20000,0.10368,0.10573,0.05,12.17 +20000,0.10572,0.10782,0.05,13.758 +20000,0.10572,0.10782,0.05,13.758 +20000,0.10781,0.10995,0.05,15.344 +20000,0.10781,0.10995,0.05,15.344 +20000,0.10993,0.11211,0.05,16.928 +20000,0.10993,0.11211,0.05,16.928 +20000,0.10993,0.11211,0.05,16.928 +20000,0.1121,0.11433,0.05,18.509 +20000,0.1121,0.11433,0.05,18.509 +20000,0.11432,0.11658,0.05,20.088 +20000,0.11432,0.11658,0.05,20.088 +20000,0.11657,0.11888,0.05,21.664 +20000,0.11657,0.11888,0.05,21.664 +20000,0.11887,0.12123,0.05,23.237 +20000,0.11887,0.12123,0.05,23.237 +20000,0.11887,0.12123,0.05,23.237 +20000,0.12122,0.12362,0.05,24.806 +20000,0.12122,0.12362,0.05,24.806 +20000,0.12361,0.12607,0.05,26.372 +20000,0.12361,0.12607,0.05,26.372 +20000,0.12361,0.12607,0.05,26.372 +20000,0.12605,0.12855,0.05,27.933 +20000,0.12605,0.12855,0.05,27.933 +20000,0.12854,0.13109,0.05,29.491 +20000,0.12854,0.13109,0.05,29.491 +20000,0.12854,0.13109,0.05,29.491 +20000,0.13108,0.13368,0.05,31.044 +20000,0.13108,0.13368,0.05,31.044 +20000,0.13367,0.13632,0.05,32.592 +20000,0.13367,0.13632,0.05,32.592 +20000,0.13367,0.13632,0.05,32.592 +20000,0.13631,0.13901,0.05,34.135 +20000,0.13631,0.13901,0.05,34.135 +20000,0.13631,0.13901,0.05,34.135 +20000,0.139,0.14176,0.05,35.673 +20000,0.139,0.14176,0.05,35.673 +20000,0.14175,0.14456,0.05,37.204 +20000,0.14175,0.14456,0.05,37.204 +20000,0.14175,0.14456,0.05,37.204 +20000,0.14455,0.14742,0.05,38.73 +20000,0.14455,0.14742,0.05,38.73 +20000,0.14455,0.14742,0.05,38.73 +20000,0.1474,0.15033,0.05,40.248 +20000,0.1474,0.15033,0.05,40.248 +20000,0.1474,0.15033,0.05,40.248 +20000,0.15032,0.1533,0.05,41.76 +20000,0.15032,0.1533,0.05,41.76 +20000,0.15032,0.1533,0.05,41.76 +20000,0.15329,0.15633,0.05,43.264 +20000,0.15329,0.15633,0.05,43.264 +20000,0.15329,0.15633,0.05,43.264 +20000,0.15632,0.15942,0.05,44.76 +20000,0.15632,0.15942,0.05,44.76 +20000,0.15632,0.15942,0.05,44.76 +20000,0.15941,0.16257,0.05,46.248 +20000,0.15941,0.16257,0.05,46.248 +20000,0.15941,0.16257,0.05,46.248 +20000,0.16256,0.16578,0.05,47.726 +20000,0.16256,0.16578,0.05,47.726 +20000,0.16256,0.16578,0.05,47.726 +20000,0.16577,0.16906,0.05,49.195 +20000,0.16577,0.16906,0.05,49.195 +20000,0.16577,0.16906,0.05,49.195 +20000,0.16577,0.16906,0.05,49.195 +20000,0.16905,0.1724,0.05,50.655 +20000,0.16905,0.1724,0.05,50.655 +20000,0.16905,0.1724,0.05,50.655 +20000,0.17239,0.1758,0.05,52.103 +20000,0.17239,0.1758,0.05,52.103 +20000,0.17239,0.1758,0.05,52.103 +20000,0.17579,0.17928,0.05,53.541 +20000,0.17579,0.17928,0.05,53.541 +20000,0.17579,0.17928,0.05,53.541 +20000,0.17579,0.17928,0.05,53.541 +20000,0.17927,0.18282,0.05,54.967 +20000,0.17927,0.18282,0.05,54.967 +20000,0.17927,0.18282,0.05,54.967 +20000,0.18281,0.18644,0.05,56.381 +20000,0.18281,0.18644,0.05,56.381 +20000,0.18281,0.18644,0.05,56.381 +20000,0.18281,0.18644,0.05,56.381 +20000,0.18643,0.19013,0.05,57.781 +20000,0.18643,0.19013,0.05,57.781 +20000,0.18643,0.19013,0.05,57.781 +20000,0.18643,0.19013,0.05,57.781 +20000,0.19011,0.19388,0.05,59.169 +20000,0.19011,0.19388,0.05,59.169 +20000,0.19011,0.19388,0.05,59.169 +20000,0.19387,0.19772,0.05,60.542 +20000,0.19387,0.19772,0.05,60.542 +20000,0.19387,0.19772,0.05,60.542 +20000,0.19387,0.19772,0.05,60.542 +20000,0.19771,0.20163,0.05,61.9 +20000,0.19771,0.20163,0.05,61.9 +20000,0.19771,0.20163,0.05,61.9 +20000,0.19771,0.20163,0.05,61.9 +20000,0.20162,0.20562,0.05,63.243 +20000,0.20162,0.20562,0.05,63.243 +20000,0.20162,0.20562,0.05,63.243 +20000,0.20162,0.20562,0.05,63.243 +20000,0.2056,0.20968,0.05,64.57 +20000,0.2056,0.20968,0.05,64.57 +20000,0.2056,0.20968,0.05,64.57 +20000,0.2056,0.20968,0.05,64.57 +20000,0.20967,0.21383,0.05,65.88 +20000,0.20967,0.21383,0.05,65.88 +20000,0.20967,0.21383,0.05,65.88 +20000,0.20967,0.21383,0.05,65.88 +20000,0.21382,0.21806,0.05,67.173 +20000,0.21382,0.21806,0.05,67.173 +20000,0.21382,0.21806,0.05,67.173 +20000,0.21382,0.21806,0.05,67.173 +20000,0.21382,0.21806,0.05,67.173 +20000,0.21805,0.22237,0.05,68.447 +20000,0.21805,0.22237,0.05,68.447 +20000,0.21805,0.22237,0.05,68.447 +20000,0.21805,0.22237,0.05,68.447 +20000,0.22236,0.22677,0.05,69.702 +20000,0.22236,0.22677,0.05,69.702 +20000,0.22236,0.22677,0.05,69.702 +20000,0.22236,0.22677,0.05,69.702 +20000,0.22676,0.23125,0.05,70.938 +20000,0.22676,0.23125,0.05,70.938 +20000,0.22676,0.23125,0.05,70.938 +20000,0.22676,0.23125,0.05,70.938 +20000,0.22676,0.23125,0.05,70.938 +20000,0.23124,0.23583,0.05,72.153 +20000,0.23124,0.23583,0.05,72.153 +20000,0.23124,0.23583,0.05,72.153 +20000,0.23124,0.23583,0.05,72.153 +20000,0.23582,0.2405,0.05,73.347 +20000,0.23582,0.2405,0.05,73.347 +20000,0.23582,0.2405,0.05,73.347 +20000,0.23582,0.2405,0.05,73.347 +20000,0.23582,0.2405,0.05,73.347 +20000,0.24048,0.24525,0.05,74.519 +20000,0.24048,0.24525,0.05,74.519 +20000,0.24048,0.24525,0.05,74.519 +20000,0.24048,0.24525,0.05,74.519 +20000,0.24048,0.24525,0.05,74.519 +20000,0.24524,0.25011,0.05,75.669 +20000,0.24524,0.25011,0.05,75.669 +20000,0.24524,0.25011,0.05,75.669 +20000,0.24524,0.25011,0.05,75.669 +20000,0.24524,0.25011,0.05,75.669 +20000,0.25009,0.25505,0.05,76.796 +20000,0.25009,0.25505,0.05,76.796 +20000,0.25009,0.25505,0.05,76.796 +20000,0.25009,0.25505,0.05,76.796 +20000,0.25009,0.25505,0.05,76.796 +20000,0.25504,0.2601,0.05,77.898 +20000,0.25504,0.2601,0.05,77.898 +20000,0.25504,0.2601,0.05,77.898 +20000,0.25504,0.2601,0.05,77.898 +20000,0.25504,0.2601,0.05,77.898 +20000,0.26009,0.26525,0.05,78.976 +20000,0.26009,0.26525,0.05,78.976 +20000,0.26009,0.26525,0.05,78.976 +20000,0.26009,0.26525,0.05,78.976 +20000,0.26009,0.26525,0.05,78.976 +20000,0.26524,0.2705,0.05,80.029 +20000,0.26524,0.2705,0.05,80.029 +20000,0.26524,0.2705,0.05,80.029 +20000,0.26524,0.2705,0.05,80.029 +20000,0.26524,0.2705,0.05,80.029 +20000,0.27048,0.27585,0.05,81.055 +20000,0.27048,0.27585,0.05,81.055 +20000,0.27048,0.27585,0.05,81.055 +20000,0.27048,0.27585,0.05,81.055 +20000,0.27048,0.27585,0.05,81.055 +20000,0.27584,0.28131,0.05,82.055 +20000,0.27584,0.28131,0.05,82.055 +20000,0.27584,0.28131,0.05,82.055 +20000,0.27584,0.28131,0.05,82.055 +20000,0.27584,0.28131,0.05,82.055 +20000,0.27584,0.28131,0.05,82.055 +20000,0.2813,0.28687,0.05,83.028 +20000,0.2813,0.28687,0.05,83.028 +20000,0.2813,0.28687,0.05,83.028 +20000,0.2813,0.28687,0.05,83.028 +20000,0.2813,0.28687,0.05,83.028 +20000,0.28686,0.29255,0.05,83.973 +20000,0.28686,0.29255,0.05,83.973 +20000,0.28686,0.29255,0.05,83.973 +20000,0.28686,0.29255,0.05,83.973 +20000,0.28686,0.29255,0.05,83.973 +20000,0.28686,0.29255,0.05,83.973 +20000,0.29254,0.29834,0.05,84.89 +20000,0.29254,0.29834,0.05,84.89 +20000,0.29254,0.29834,0.05,84.89 +20000,0.29254,0.29834,0.05,84.89 +20000,0.29254,0.29834,0.05,84.89 +20000,0.29254,0.29834,0.05,84.89 +20000,0.29833,0.30425,0.05,85.779 +20000,0.29833,0.30425,0.05,85.779 +20000,0.29833,0.30425,0.05,85.779 +20000,0.29833,0.30425,0.05,85.779 +20000,0.29833,0.30425,0.05,85.779 +20000,0.29833,0.30425,0.05,85.779 +20000,0.30424,0.31027,0.05,86.638 +20000,0.30424,0.31027,0.05,86.638 +20000,0.30424,0.31027,0.05,86.638 +20000,0.30424,0.31027,0.05,86.638 +20000,0.30424,0.31027,0.05,86.638 +20000,0.30424,0.31027,0.05,86.638 +20000,0.31026,0.31641,0.05,87.468 +20000,0.31026,0.31641,0.05,87.468 +20000,0.31026,0.31641,0.05,87.468 +20000,0.31026,0.31641,0.05,87.468 +20000,0.31026,0.31641,0.05,87.468 +20000,0.31026,0.31641,0.05,87.468 +20000,0.3164,0.32267,0.05,88.268 +20000,0.3164,0.32267,0.05,88.268 +20000,0.3164,0.32267,0.05,88.268 +20000,0.3164,0.32267,0.05,88.268 +20000,0.3164,0.32267,0.05,88.268 +20000,0.3164,0.32267,0.05,88.268 +20000,0.32266,0.32906,0.05,89.038 +20000,0.32266,0.32906,0.05,89.038 +20000,0.32266,0.32906,0.05,89.038 +20000,0.32266,0.32906,0.05,89.038 +20000,0.32266,0.32906,0.05,89.038 +20000,0.32266,0.32906,0.05,89.038 +20000,0.32266,0.32906,0.05,89.038 +20000,0.32905,0.33558,0.05,89.778 +20000,0.32905,0.33558,0.05,89.778 +20000,0.32905,0.33558,0.05,89.778 +20000,0.32905,0.33558,0.05,89.778 +20000,0.32905,0.33558,0.05,89.778 +20000,0.32905,0.33558,0.05,89.778 +20000,0.33556,0.34222,0.05,90.487 +20000,0.33556,0.34222,0.05,90.487 +20000,0.33556,0.34222,0.05,90.487 +20000,0.33556,0.34222,0.05,90.487 +20000,0.33556,0.34222,0.05,90.487 +20000,0.33556,0.34222,0.05,90.487 +20000,0.33556,0.34222,0.05,90.487 +20000,0.34221,0.34899,0.05,91.166 +20000,0.34221,0.34899,0.05,91.166 +20000,0.34221,0.34899,0.05,91.166 +20000,0.34221,0.34899,0.05,91.166 +20000,0.34221,0.34899,0.05,91.166 +20000,0.34221,0.34899,0.05,91.166 +20000,0.34221,0.34899,0.05,91.166 +20000,0.34898,0.3559,0.05,91.815 +20000,0.34898,0.3559,0.05,91.815 +20000,0.34898,0.3559,0.05,91.815 +20000,0.34898,0.3559,0.05,91.815 +20000,0.34898,0.3559,0.05,91.815 +20000,0.34898,0.3559,0.05,91.815 +20000,0.35589,0.36295,0.05,92.433 +20000,0.35589,0.36295,0.05,92.433 +20000,0.35589,0.36295,0.05,92.433 +20000,0.35589,0.36295,0.05,92.433 +20000,0.35589,0.36295,0.05,92.433 +20000,0.35589,0.36295,0.05,92.433 +20000,0.35589,0.36295,0.05,92.433 +20000,0.36294,0.37013,0.05,93.02 +20000,0.36294,0.37013,0.05,93.02 +20000,0.36294,0.37013,0.05,93.02 +20000,0.36294,0.37013,0.05,93.02 +20000,0.36294,0.37013,0.05,93.02 +20000,0.36294,0.37013,0.05,93.02 +20000,0.36294,0.37013,0.05,93.02 +20000,0.36294,0.37013,0.05,93.02 +20000,0.37012,0.37746,0.05,93.578 +20000,0.37012,0.37746,0.05,93.578 +20000,0.37012,0.37746,0.05,93.578 +20000,0.37012,0.37746,0.05,93.578 +20000,0.37012,0.37746,0.05,93.578 +20000,0.37012,0.37746,0.05,93.578 +20000,0.37012,0.37746,0.05,93.578 +20000,0.37745,0.38494,0.05,94.106 +20000,0.37745,0.38494,0.05,94.106 +20000,0.37745,0.38494,0.05,94.106 +20000,0.37745,0.38494,0.05,94.106 +20000,0.37745,0.38494,0.05,94.106 +20000,0.37745,0.38494,0.05,94.106 +20000,0.37745,0.38494,0.05,94.106 +20000,0.38493,0.39256,0.05,94.604 +20000,0.38493,0.39256,0.05,94.604 +20000,0.38493,0.39256,0.05,94.604 +20000,0.38493,0.39256,0.05,94.604 +20000,0.38493,0.39256,0.05,94.604 +20000,0.38493,0.39256,0.05,94.604 +20000,0.38493,0.39256,0.05,94.604 +20000,0.38493,0.39256,0.05,94.604 +20000,0.39255,0.40033,0.05,95.074 +20000,0.39255,0.40033,0.05,95.074 +20000,0.39255,0.40033,0.05,95.074 +20000,0.39255,0.40033,0.05,95.074 +20000,0.39255,0.40033,0.05,95.074 +20000,0.39255,0.40033,0.05,95.074 +20000,0.39255,0.40033,0.05,95.074 +20000,0.39255,0.40033,0.05,95.074 +20000,0.40032,0.40826,0.05,95.515 +20000,0.40032,0.40826,0.05,95.515 +20000,0.40032,0.40826,0.05,95.515 +20000,0.40032,0.40826,0.05,95.515 +20000,0.40032,0.40826,0.05,95.515 +20000,0.40032,0.40826,0.05,95.515 +20000,0.40032,0.40826,0.05,95.515 +20000,0.40032,0.40826,0.05,95.515 +20000,0.40825,0.41634,0.05,95.929 +20000,0.40825,0.41634,0.05,95.929 +20000,0.40825,0.41634,0.05,95.929 +20000,0.40825,0.41634,0.05,95.929 +20000,0.40825,0.41634,0.05,95.929 +20000,0.40825,0.41634,0.05,95.929 +20000,0.40825,0.41634,0.05,95.929 +20000,0.40825,0.41634,0.05,95.929 +20000,0.41633,0.42459,0.05,96.315 +20000,0.41633,0.42459,0.05,96.315 +20000,0.41633,0.42459,0.05,96.315 +20000,0.41633,0.42459,0.05,96.315 +20000,0.41633,0.42459,0.05,96.315 +20000,0.41633,0.42459,0.05,96.315 +20000,0.41633,0.42459,0.05,96.315 +20000,0.41633,0.42459,0.05,96.315 +20000,0.42458,0.433,0.05,96.674 +20000,0.42458,0.433,0.05,96.674 +20000,0.42458,0.433,0.05,96.674 +20000,0.42458,0.433,0.05,96.674 +20000,0.42458,0.433,0.05,96.674 +20000,0.42458,0.433,0.05,96.674 +20000,0.42458,0.433,0.05,96.674 +20000,0.42458,0.433,0.05,96.674 +20000,0.42458,0.433,0.05,96.674 +20000,0.43298,0.44157,0.05,97.009 +20000,0.43298,0.44157,0.05,97.009 +20000,0.43298,0.44157,0.05,97.009 +20000,0.43298,0.44157,0.05,97.009 +20000,0.43298,0.44157,0.05,97.009 +20000,0.43298,0.44157,0.05,97.009 +20000,0.43298,0.44157,0.05,97.009 +20000,0.43298,0.44157,0.05,97.009 +20000,0.44156,0.45031,0.05,97.318 +20000,0.44156,0.45031,0.05,97.318 +20000,0.44156,0.45031,0.05,97.318 +20000,0.44156,0.45031,0.05,97.318 +20000,0.44156,0.45031,0.05,97.318 +20000,0.44156,0.45031,0.05,97.318 +20000,0.44156,0.45031,0.05,97.318 +20000,0.44156,0.45031,0.05,97.318 +20000,0.44156,0.45031,0.05,97.318 +20000,0.4503,0.45923,0.05,97.603 +20000,0.4503,0.45923,0.05,97.603 +20000,0.4503,0.45923,0.05,97.603 +20000,0.4503,0.45923,0.05,97.603 +20000,0.4503,0.45923,0.05,97.603 +20000,0.4503,0.45923,0.05,97.603 +20000,0.4503,0.45923,0.05,97.603 +20000,0.4503,0.45923,0.05,97.603 +20000,0.4503,0.45923,0.05,97.603 +20000,0.45922,0.46833,0.05,97.866 +20000,0.45922,0.46833,0.05,97.866 +20000,0.45922,0.46833,0.05,97.866 +20000,0.45922,0.46833,0.05,97.866 +20000,0.45922,0.46833,0.05,97.866 +20000,0.45922,0.46833,0.05,97.866 +20000,0.45922,0.46833,0.05,97.866 +20000,0.45922,0.46833,0.05,97.866 +20000,0.45922,0.46833,0.05,97.866 +20000,0.46832,0.4776,0.05,98.107 +20000,0.46832,0.4776,0.05,98.107 +20000,0.46832,0.4776,0.05,98.107 +20000,0.46832,0.4776,0.05,98.107 +20000,0.46832,0.4776,0.05,98.107 +20000,0.46832,0.4776,0.05,98.107 +20000,0.46832,0.4776,0.05,98.107 +20000,0.46832,0.4776,0.05,98.107 +20000,0.46832,0.4776,0.05,98.107 +20000,0.47759,0.48706,0.05,98.327 +20000,0.47759,0.48706,0.05,98.327 +20000,0.47759,0.48706,0.05,98.327 +20000,0.47759,0.48706,0.05,98.327 +20000,0.47759,0.48706,0.05,98.327 +20000,0.47759,0.48706,0.05,98.327 +20000,0.47759,0.48706,0.05,98.327 +20000,0.47759,0.48706,0.05,98.327 +20000,0.47759,0.48706,0.05,98.327 +20000,0.47759,0.48706,0.05,98.327 +20000,0.48705,0.49671,0.05,98.527 +20000,0.48705,0.49671,0.05,98.527 +20000,0.48705,0.49671,0.05,98.527 +20000,0.48705,0.49671,0.05,98.527 +20000,0.48705,0.49671,0.05,98.527 +20000,0.48705,0.49671,0.05,98.527 +20000,0.48705,0.49671,0.05,98.527 +20000,0.48705,0.49671,0.05,98.527 +20000,0.48705,0.49671,0.05,98.527 +20000,0.4967,0.50655,0.05,98.708 +20000,0.4967,0.50655,0.05,98.708 +20000,0.4967,0.50655,0.05,98.708 +20000,0.4967,0.50655,0.05,98.708 +20000,0.4967,0.50655,0.05,98.708 +20000,0.4967,0.50655,0.05,98.708 +20000,0.4967,0.50655,0.05,98.708 +20000,0.4967,0.50655,0.05,98.708 +20000,0.4967,0.50655,0.05,98.708 +20000,0.4967,0.50655,0.05,98.708 +20000,0.50654,0.51658,0.05,98.872 +20000,0.50654,0.51658,0.05,98.872 +20000,0.50654,0.51658,0.05,98.872 +20000,0.50654,0.51658,0.05,98.872 +20000,0.50654,0.51658,0.05,98.872 +20000,0.50654,0.51658,0.05,98.872 +20000,0.50654,0.51658,0.05,98.872 +20000,0.50654,0.51658,0.05,98.872 +20000,0.50654,0.51658,0.05,98.872 +20000,0.50654,0.51658,0.05,98.872 +20000,0.51657,0.52681,0.05,99.019 +20000,0.51657,0.52681,0.05,99.019 +20000,0.51657,0.52681,0.05,99.019 +20000,0.51657,0.52681,0.05,99.019 +20000,0.51657,0.52681,0.05,99.019 +20000,0.51657,0.52681,0.05,99.019 +20000,0.51657,0.52681,0.05,99.019 +20000,0.51657,0.52681,0.05,99.019 +20000,0.51657,0.52681,0.05,99.019 +20000,0.51657,0.52681,0.05,99.019 +20000,0.5268,0.53725,0.05,99.152 +20000,0.5268,0.53725,0.05,99.152 +20000,0.5268,0.53725,0.05,99.152 +20000,0.5268,0.53725,0.05,99.152 +20000,0.5268,0.53725,0.05,99.152 +20000,0.5268,0.53725,0.05,99.152 +20000,0.5268,0.53725,0.05,99.152 +20000,0.5268,0.53725,0.05,99.152 +20000,0.5268,0.53725,0.05,99.152 +20000,0.5268,0.53725,0.05,99.152 +20000,0.5268,0.53725,0.05,99.152 +20000,0.53724,0.54789,0.05,99.27 +20000,0.53724,0.54789,0.05,99.27 +20000,0.53724,0.54789,0.05,99.27 +20000,0.53724,0.54789,0.05,99.27 +20000,0.53724,0.54789,0.05,99.27 +20000,0.53724,0.54789,0.05,99.27 +20000,0.53724,0.54789,0.05,99.27 +20000,0.53724,0.54789,0.05,99.27 +20000,0.53724,0.54789,0.05,99.27 +20000,0.53724,0.54789,0.05,99.27 +20000,0.54788,0.55874,0.05,99.374 +20000,0.54788,0.55874,0.05,99.374 +20000,0.54788,0.55874,0.05,99.374 +20000,0.54788,0.55874,0.05,99.374 +20000,0.54788,0.55874,0.05,99.374 +20000,0.54788,0.55874,0.05,99.374 +20000,0.54788,0.55874,0.05,99.374 +20000,0.54788,0.55874,0.05,99.374 +20000,0.54788,0.55874,0.05,99.374 +20000,0.54788,0.55874,0.05,99.374 +20000,0.54788,0.55874,0.05,99.374 +20000,0.55873,0.56981,0.05,99.467 +20000,0.55873,0.56981,0.05,99.467 +20000,0.55873,0.56981,0.05,99.467 +20000,0.55873,0.56981,0.05,99.467 +20000,0.55873,0.56981,0.05,99.467 +20000,0.55873,0.56981,0.05,99.467 +20000,0.55873,0.56981,0.05,99.467 +20000,0.55873,0.56981,0.05,99.467 +20000,0.55873,0.56981,0.05,99.467 +20000,0.55873,0.56981,0.05,99.467 +20000,0.55873,0.56981,0.05,99.467 +20000,0.5698,0.5811,0.05,99.549 +20000,0.5698,0.5811,0.05,99.549 +20000,0.5698,0.5811,0.05,99.549 +20000,0.5698,0.5811,0.05,99.549 +20000,0.5698,0.5811,0.05,99.549 +20000,0.5698,0.5811,0.05,99.549 +20000,0.5698,0.5811,0.05,99.549 +20000,0.5698,0.5811,0.05,99.549 +20000,0.5698,0.5811,0.05,99.549 +20000,0.5698,0.5811,0.05,99.549 +20000,0.5698,0.5811,0.05,99.549 +20000,0.5698,0.5811,0.05,99.549 +20000,0.58109,0.59261,0.05,99.621 +20000,0.58109,0.59261,0.05,99.621 +20000,0.58109,0.59261,0.05,99.621 +20000,0.58109,0.59261,0.05,99.621 +20000,0.58109,0.59261,0.05,99.621 +20000,0.58109,0.59261,0.05,99.621 +20000,0.58109,0.59261,0.05,99.621 +20000,0.58109,0.59261,0.05,99.621 +20000,0.58109,0.59261,0.05,99.621 +20000,0.58109,0.59261,0.05,99.621 +20000,0.58109,0.59261,0.05,99.621 +20000,0.5926,0.60435,0.05,99.685 +20000,0.5926,0.60435,0.05,99.685 +20000,0.5926,0.60435,0.05,99.685 +20000,0.5926,0.60435,0.05,99.685 +20000,0.5926,0.60435,0.05,99.685 +20000,0.5926,0.60435,0.05,99.685 +20000,0.5926,0.60435,0.05,99.685 +20000,0.5926,0.60435,0.05,99.685 +20000,0.5926,0.60435,0.05,99.685 +20000,0.5926,0.60435,0.05,99.685 +20000,0.5926,0.60435,0.05,99.685 +20000,0.5926,0.60435,0.05,99.685 +20000,0.60434,0.61632,0.05,99.74 +20000,0.60434,0.61632,0.05,99.74 +20000,0.60434,0.61632,0.05,99.74 +20000,0.60434,0.61632,0.05,99.74 +20000,0.60434,0.61632,0.05,99.74 +20000,0.60434,0.61632,0.05,99.74 +20000,0.60434,0.61632,0.05,99.74 +20000,0.60434,0.61632,0.05,99.74 +20000,0.60434,0.61632,0.05,99.74 +20000,0.60434,0.61632,0.05,99.74 +20000,0.60434,0.61632,0.05,99.74 +20000,0.60434,0.61632,0.05,99.74 +20000,0.61631,0.62853,0.05,99.789 +20000,0.61631,0.62853,0.05,99.789 +20000,0.61631,0.62853,0.05,99.789 +20000,0.61631,0.62853,0.05,99.789 +20000,0.61631,0.62853,0.05,99.789 +20000,0.61631,0.62853,0.05,99.789 +20000,0.61631,0.62853,0.05,99.789 +20000,0.61631,0.62853,0.05,99.789 +20000,0.61631,0.62853,0.05,99.789 +20000,0.61631,0.62853,0.05,99.789 +20000,0.61631,0.62853,0.05,99.789 +20000,0.61631,0.62853,0.05,99.789 +20000,0.62852,0.64098,0.05,99.832 +20000,0.62852,0.64098,0.05,99.832 +20000,0.62852,0.64098,0.05,99.832 +20000,0.62852,0.64098,0.05,99.832 +20000,0.62852,0.64098,0.05,99.832 +20000,0.62852,0.64098,0.05,99.832 +20000,0.62852,0.64098,0.05,99.832 +20000,0.62852,0.64098,0.05,99.832 +20000,0.62852,0.64098,0.05,99.832 +20000,0.62852,0.64098,0.05,99.832 +20000,0.62852,0.64098,0.05,99.832 +20000,0.62852,0.64098,0.05,99.832 +20000,0.62852,0.64098,0.05,99.832 +20000,0.64097,0.65368,0.05,99.869 +20000,0.64097,0.65368,0.05,99.869 +20000,0.64097,0.65368,0.05,99.869 +20000,0.64097,0.65368,0.05,99.869 +20000,0.64097,0.65368,0.05,99.869 +20000,0.64097,0.65368,0.05,99.869 +20000,0.64097,0.65368,0.05,99.869 +20000,0.64097,0.65368,0.05,99.869 +20000,0.64097,0.65368,0.05,99.869 +20000,0.64097,0.65368,0.05,99.869 +20000,0.64097,0.65368,0.05,99.869 +20000,0.64097,0.65368,0.05,99.869 +20000,0.65367,0.66663,0.05,99.903 +20000,0.65367,0.66663,0.05,99.903 +20000,0.65367,0.66663,0.05,99.903 +20000,0.65367,0.66663,0.05,99.903 +20000,0.65367,0.66663,0.05,99.903 +20000,0.65367,0.66663,0.05,99.903 +20000,0.65367,0.66663,0.05,99.903 +20000,0.65367,0.66663,0.05,99.903 +20000,0.65367,0.66663,0.05,99.903 +20000,0.65367,0.66663,0.05,99.903 +20000,0.65367,0.66663,0.05,99.903 +20000,0.65367,0.66663,0.05,99.903 +20000,0.65367,0.66663,0.05,99.903 +20000,0.66662,0.67984,0.05,99.933 +20000,0.66662,0.67984,0.05,99.933 +20000,0.66662,0.67984,0.05,99.933 +20000,0.66662,0.67984,0.05,99.933 +20000,0.66662,0.67984,0.05,99.933 +20000,0.66662,0.67984,0.05,99.933 +20000,0.66662,0.67984,0.05,99.933 +20000,0.66662,0.67984,0.05,99.933 +20000,0.66662,0.67984,0.05,99.933 +20000,0.66662,0.67984,0.05,99.933 +20000,0.66662,0.67984,0.05,99.933 +20000,0.66662,0.67984,0.05,99.933 +20000,0.66662,0.67984,0.05,99.933 +20000,0.67983,0.69331,0.05,99.961 +20000,0.67983,0.69331,0.05,99.961 +20000,0.67983,0.69331,0.05,99.961 +20000,0.67983,0.69331,0.05,99.961 +20000,0.67983,0.69331,0.05,99.961 +20000,0.67983,0.69331,0.05,99.961 +20000,0.67983,0.69331,0.05,99.961 +20000,0.67983,0.69331,0.05,99.961 +20000,0.67983,0.69331,0.05,99.961 +20000,0.67983,0.69331,0.05,99.961 +20000,0.67983,0.69331,0.05,99.961 +20000,0.67983,0.69331,0.05,99.961 +20000,0.67983,0.69331,0.05,99.961 +20000,0.67983,0.69331,0.05,99.961 +20000,0.6933,0.70704,0.05,99.987 +20000,0.6933,0.70704,0.05,99.987 +20000,0.6933,0.70704,0.05,99.987 +20000,0.6933,0.70704,0.05,99.987 +20000,0.6933,0.70704,0.05,99.987 +20000,0.6933,0.70704,0.05,99.987 +20000,0.6933,0.70704,0.05,99.987 +20000,0.6933,0.70704,0.05,99.987 +20000,0.6933,0.70704,0.05,99.987 +20000,0.6933,0.70704,0.05,99.987 +20000,0.6933,0.70704,0.05,99.987 +20000,0.6933,0.70704,0.05,99.987 +20000,0.6933,0.70704,0.05,99.987 +20000,0.6933,0.70704,0.05,99.987 +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/data_5.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/data_5.csv new file mode 100644 index 00000000000..a0165428e76 --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/data_5.csv @@ -0,0 +1,1002 @@ +Time,"elementCenter:0","elementCenter:1","elementCenter:2","temperature" +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,0.07071,0.072112,0.05,-19.345 +50000,0.07071,0.072112,0.05,-19.345 +50000,0.07211,0.07354,0.05,-18.062 +50000,0.07351,0.074968,0.05,-16.803 +50000,0.075155,0.076646,0.05,-15.352 +50000,0.075155,0.076646,0.05,-15.352 +50000,0.077046,0.078574,0.05,-13.727 +50000,0.077046,0.078574,0.05,-13.727 +50000,0.078936,0.080501,0.05,-12.141 +50000,0.078936,0.080501,0.05,-12.141 +50000,0.080826,0.082429,0.05,-10.592 +50000,0.080826,0.082429,0.05,-10.592 +50000,0.082716,0.084357,0.05,-9.0797 +50000,0.082716,0.084357,0.05,-9.0797 +50000,0.084607,0.086285,0.05,-7.6016 +50000,0.084607,0.086285,0.05,-7.6016 +50000,0.086497,0.088212,0.05,-6.1563 +50000,0.086497,0.088212,0.05,-6.1563 +50000,0.088387,0.09014,0.05,-4.7426 +50000,0.088387,0.09014,0.05,-4.7426 +50000,0.090278,0.092068,0.05,-3.359 +50000,0.090278,0.092068,0.05,-3.359 +50000,0.092168,0.093995,0.05,-2.0045 +50000,0.092168,0.093995,0.05,-2.0045 +50000,0.094031,0.095896,0.05,-0.69679 +50000,0.095885,0.097786,0.05,0.57908 +50000,0.095885,0.097786,0.05,0.57908 +50000,0.097776,0.099715,0.05,1.8547 +50000,0.097776,0.099715,0.05,1.8547 +50000,0.099704,0.10168,0.05,3.1301 +50000,0.099704,0.10168,0.05,3.1301 +50000,0.10167,0.10369,0.05,4.4051 +50000,0.10167,0.10369,0.05,4.4051 +50000,0.10368,0.10573,0.05,5.6798 +50000,0.10368,0.10573,0.05,5.6798 +50000,0.10572,0.10782,0.05,6.9541 +50000,0.10572,0.10782,0.05,6.9541 +50000,0.10781,0.10995,0.05,8.2279 +50000,0.10781,0.10995,0.05,8.2279 +50000,0.10993,0.11211,0.05,9.5012 +50000,0.10993,0.11211,0.05,9.5012 +50000,0.10993,0.11211,0.05,9.5012 +50000,0.1121,0.11433,0.05,10.774 +50000,0.1121,0.11433,0.05,10.774 +50000,0.11432,0.11658,0.05,12.046 +50000,0.11432,0.11658,0.05,12.046 +50000,0.11657,0.11888,0.05,13.317 +50000,0.11657,0.11888,0.05,13.317 +50000,0.11887,0.12123,0.05,14.588 +50000,0.11887,0.12123,0.05,14.588 +50000,0.11887,0.12123,0.05,14.588 +50000,0.12122,0.12362,0.05,15.858 +50000,0.12122,0.12362,0.05,15.858 +50000,0.12361,0.12607,0.05,17.127 +50000,0.12361,0.12607,0.05,17.127 +50000,0.12361,0.12607,0.05,17.127 +50000,0.12605,0.12855,0.05,18.395 +50000,0.12605,0.12855,0.05,18.395 +50000,0.12854,0.13109,0.05,19.662 +50000,0.12854,0.13109,0.05,19.662 +50000,0.12854,0.13109,0.05,19.662 +50000,0.13108,0.13368,0.05,20.927 +50000,0.13108,0.13368,0.05,20.927 +50000,0.13367,0.13632,0.05,22.192 +50000,0.13367,0.13632,0.05,22.192 +50000,0.13367,0.13632,0.05,22.192 +50000,0.13631,0.13901,0.05,23.455 +50000,0.13631,0.13901,0.05,23.455 +50000,0.13631,0.13901,0.05,23.455 +50000,0.139,0.14176,0.05,24.716 +50000,0.139,0.14176,0.05,24.716 +50000,0.14175,0.14456,0.05,25.977 +50000,0.14175,0.14456,0.05,25.977 +50000,0.14175,0.14456,0.05,25.977 +50000,0.14455,0.14742,0.05,27.235 +50000,0.14455,0.14742,0.05,27.235 +50000,0.14455,0.14742,0.05,27.235 +50000,0.1474,0.15033,0.05,28.492 +50000,0.1474,0.15033,0.05,28.492 +50000,0.1474,0.15033,0.05,28.492 +50000,0.15032,0.1533,0.05,29.746 +50000,0.15032,0.1533,0.05,29.746 +50000,0.15032,0.1533,0.05,29.746 +50000,0.15329,0.15633,0.05,30.999 +50000,0.15329,0.15633,0.05,30.999 +50000,0.15329,0.15633,0.05,30.999 +50000,0.15632,0.15942,0.05,32.249 +50000,0.15632,0.15942,0.05,32.249 +50000,0.15632,0.15942,0.05,32.249 +50000,0.15941,0.16257,0.05,33.497 +50000,0.15941,0.16257,0.05,33.497 +50000,0.15941,0.16257,0.05,33.497 +50000,0.16256,0.16578,0.05,34.743 +50000,0.16256,0.16578,0.05,34.743 +50000,0.16256,0.16578,0.05,34.743 +50000,0.16577,0.16906,0.05,35.986 +50000,0.16577,0.16906,0.05,35.986 +50000,0.16577,0.16906,0.05,35.986 +50000,0.16577,0.16906,0.05,35.986 +50000,0.16905,0.1724,0.05,37.226 +50000,0.16905,0.1724,0.05,37.226 +50000,0.16905,0.1724,0.05,37.226 +50000,0.17239,0.1758,0.05,38.464 +50000,0.17239,0.1758,0.05,38.464 +50000,0.17239,0.1758,0.05,38.464 +50000,0.17579,0.17928,0.05,39.698 +50000,0.17579,0.17928,0.05,39.698 +50000,0.17579,0.17928,0.05,39.698 +50000,0.17579,0.17928,0.05,39.698 +50000,0.17927,0.18282,0.05,40.928 +50000,0.17927,0.18282,0.05,40.928 +50000,0.17927,0.18282,0.05,40.928 +50000,0.18281,0.18644,0.05,42.155 +50000,0.18281,0.18644,0.05,42.155 +50000,0.18281,0.18644,0.05,42.155 +50000,0.18281,0.18644,0.05,42.155 +50000,0.18643,0.19013,0.05,43.379 +50000,0.18643,0.19013,0.05,43.379 +50000,0.18643,0.19013,0.05,43.379 +50000,0.18643,0.19013,0.05,43.379 +50000,0.19011,0.19388,0.05,44.598 +50000,0.19011,0.19388,0.05,44.598 +50000,0.19011,0.19388,0.05,44.598 +50000,0.19387,0.19772,0.05,45.813 +50000,0.19387,0.19772,0.05,45.813 +50000,0.19387,0.19772,0.05,45.813 +50000,0.19387,0.19772,0.05,45.813 +50000,0.19771,0.20163,0.05,47.024 +50000,0.19771,0.20163,0.05,47.024 +50000,0.19771,0.20163,0.05,47.024 +50000,0.19771,0.20163,0.05,47.024 +50000,0.20162,0.20562,0.05,48.23 +50000,0.20162,0.20562,0.05,48.23 +50000,0.20162,0.20562,0.05,48.23 +50000,0.20162,0.20562,0.05,48.23 +50000,0.2056,0.20968,0.05,49.431 +50000,0.2056,0.20968,0.05,49.431 +50000,0.2056,0.20968,0.05,49.431 +50000,0.2056,0.20968,0.05,49.431 +50000,0.20967,0.21383,0.05,50.627 +50000,0.20967,0.21383,0.05,50.627 +50000,0.20967,0.21383,0.05,50.627 +50000,0.20967,0.21383,0.05,50.627 +50000,0.21382,0.21806,0.05,51.818 +50000,0.21382,0.21806,0.05,51.818 +50000,0.21382,0.21806,0.05,51.818 +50000,0.21382,0.21806,0.05,51.818 +50000,0.21382,0.21806,0.05,51.818 +50000,0.21805,0.22237,0.05,53.002 +50000,0.21805,0.22237,0.05,53.002 +50000,0.21805,0.22237,0.05,53.002 +50000,0.21805,0.22237,0.05,53.002 +50000,0.22236,0.22677,0.05,54.181 +50000,0.22236,0.22677,0.05,54.181 +50000,0.22236,0.22677,0.05,54.181 +50000,0.22236,0.22677,0.05,54.181 +50000,0.22676,0.23125,0.05,55.353 +50000,0.22676,0.23125,0.05,55.353 +50000,0.22676,0.23125,0.05,55.353 +50000,0.22676,0.23125,0.05,55.353 +50000,0.22676,0.23125,0.05,55.353 +50000,0.23124,0.23583,0.05,56.518 +50000,0.23124,0.23583,0.05,56.518 +50000,0.23124,0.23583,0.05,56.518 +50000,0.23124,0.23583,0.05,56.518 +50000,0.23582,0.2405,0.05,57.677 +50000,0.23582,0.2405,0.05,57.677 +50000,0.23582,0.2405,0.05,57.677 +50000,0.23582,0.2405,0.05,57.677 +50000,0.23582,0.2405,0.05,57.677 +50000,0.24048,0.24525,0.05,58.828 +50000,0.24048,0.24525,0.05,58.828 +50000,0.24048,0.24525,0.05,58.828 +50000,0.24048,0.24525,0.05,58.828 +50000,0.24048,0.24525,0.05,58.828 +50000,0.24524,0.25011,0.05,59.971 +50000,0.24524,0.25011,0.05,59.971 +50000,0.24524,0.25011,0.05,59.971 +50000,0.24524,0.25011,0.05,59.971 +50000,0.24524,0.25011,0.05,59.971 +50000,0.25009,0.25505,0.05,61.107 +50000,0.25009,0.25505,0.05,61.107 +50000,0.25009,0.25505,0.05,61.107 +50000,0.25009,0.25505,0.05,61.107 +50000,0.25009,0.25505,0.05,61.107 +50000,0.25504,0.2601,0.05,62.233 +50000,0.25504,0.2601,0.05,62.233 +50000,0.25504,0.2601,0.05,62.233 +50000,0.25504,0.2601,0.05,62.233 +50000,0.25504,0.2601,0.05,62.233 +50000,0.26009,0.26525,0.05,63.351 +50000,0.26009,0.26525,0.05,63.351 +50000,0.26009,0.26525,0.05,63.351 +50000,0.26009,0.26525,0.05,63.351 +50000,0.26009,0.26525,0.05,63.351 +50000,0.26524,0.2705,0.05,64.46 +50000,0.26524,0.2705,0.05,64.46 +50000,0.26524,0.2705,0.05,64.46 +50000,0.26524,0.2705,0.05,64.46 +50000,0.26524,0.2705,0.05,64.46 +50000,0.27048,0.27585,0.05,65.559 +50000,0.27048,0.27585,0.05,65.559 +50000,0.27048,0.27585,0.05,65.559 +50000,0.27048,0.27585,0.05,65.559 +50000,0.27048,0.27585,0.05,65.559 +50000,0.27584,0.28131,0.05,66.648 +50000,0.27584,0.28131,0.05,66.648 +50000,0.27584,0.28131,0.05,66.648 +50000,0.27584,0.28131,0.05,66.648 +50000,0.27584,0.28131,0.05,66.648 +50000,0.27584,0.28131,0.05,66.648 +50000,0.2813,0.28687,0.05,67.726 +50000,0.2813,0.28687,0.05,67.726 +50000,0.2813,0.28687,0.05,67.726 +50000,0.2813,0.28687,0.05,67.726 +50000,0.2813,0.28687,0.05,67.726 +50000,0.28686,0.29255,0.05,68.794 +50000,0.28686,0.29255,0.05,68.794 +50000,0.28686,0.29255,0.05,68.794 +50000,0.28686,0.29255,0.05,68.794 +50000,0.28686,0.29255,0.05,68.794 +50000,0.28686,0.29255,0.05,68.794 +50000,0.29254,0.29834,0.05,69.85 +50000,0.29254,0.29834,0.05,69.85 +50000,0.29254,0.29834,0.05,69.85 +50000,0.29254,0.29834,0.05,69.85 +50000,0.29254,0.29834,0.05,69.85 +50000,0.29254,0.29834,0.05,69.85 +50000,0.29833,0.30425,0.05,70.894 +50000,0.29833,0.30425,0.05,70.894 +50000,0.29833,0.30425,0.05,70.894 +50000,0.29833,0.30425,0.05,70.894 +50000,0.29833,0.30425,0.05,70.894 +50000,0.29833,0.30425,0.05,70.894 +50000,0.30424,0.31027,0.05,71.926 +50000,0.30424,0.31027,0.05,71.926 +50000,0.30424,0.31027,0.05,71.926 +50000,0.30424,0.31027,0.05,71.926 +50000,0.30424,0.31027,0.05,71.926 +50000,0.30424,0.31027,0.05,71.926 +50000,0.31026,0.31641,0.05,72.945 +50000,0.31026,0.31641,0.05,72.945 +50000,0.31026,0.31641,0.05,72.945 +50000,0.31026,0.31641,0.05,72.945 +50000,0.31026,0.31641,0.05,72.945 +50000,0.31026,0.31641,0.05,72.945 +50000,0.3164,0.32267,0.05,73.951 +50000,0.3164,0.32267,0.05,73.951 +50000,0.3164,0.32267,0.05,73.951 +50000,0.3164,0.32267,0.05,73.951 +50000,0.3164,0.32267,0.05,73.951 +50000,0.3164,0.32267,0.05,73.951 +50000,0.32266,0.32906,0.05,74.943 +50000,0.32266,0.32906,0.05,74.943 +50000,0.32266,0.32906,0.05,74.943 +50000,0.32266,0.32906,0.05,74.943 +50000,0.32266,0.32906,0.05,74.943 +50000,0.32266,0.32906,0.05,74.943 +50000,0.32266,0.32906,0.05,74.943 +50000,0.32905,0.33558,0.05,75.921 +50000,0.32905,0.33558,0.05,75.921 +50000,0.32905,0.33558,0.05,75.921 +50000,0.32905,0.33558,0.05,75.921 +50000,0.32905,0.33558,0.05,75.921 +50000,0.32905,0.33558,0.05,75.921 +50000,0.33556,0.34222,0.05,76.885 +50000,0.33556,0.34222,0.05,76.885 +50000,0.33556,0.34222,0.05,76.885 +50000,0.33556,0.34222,0.05,76.885 +50000,0.33556,0.34222,0.05,76.885 +50000,0.33556,0.34222,0.05,76.885 +50000,0.33556,0.34222,0.05,76.885 +50000,0.34221,0.34899,0.05,77.833 +50000,0.34221,0.34899,0.05,77.833 +50000,0.34221,0.34899,0.05,77.833 +50000,0.34221,0.34899,0.05,77.833 +50000,0.34221,0.34899,0.05,77.833 +50000,0.34221,0.34899,0.05,77.833 +50000,0.34221,0.34899,0.05,77.833 +50000,0.34898,0.3559,0.05,78.766 +50000,0.34898,0.3559,0.05,78.766 +50000,0.34898,0.3559,0.05,78.766 +50000,0.34898,0.3559,0.05,78.766 +50000,0.34898,0.3559,0.05,78.766 +50000,0.34898,0.3559,0.05,78.766 +50000,0.35589,0.36295,0.05,79.683 +50000,0.35589,0.36295,0.05,79.683 +50000,0.35589,0.36295,0.05,79.683 +50000,0.35589,0.36295,0.05,79.683 +50000,0.35589,0.36295,0.05,79.683 +50000,0.35589,0.36295,0.05,79.683 +50000,0.35589,0.36295,0.05,79.683 +50000,0.36294,0.37013,0.05,80.583 +50000,0.36294,0.37013,0.05,80.583 +50000,0.36294,0.37013,0.05,80.583 +50000,0.36294,0.37013,0.05,80.583 +50000,0.36294,0.37013,0.05,80.583 +50000,0.36294,0.37013,0.05,80.583 +50000,0.36294,0.37013,0.05,80.583 +50000,0.36294,0.37013,0.05,80.583 +50000,0.37012,0.37746,0.05,81.466 +50000,0.37012,0.37746,0.05,81.466 +50000,0.37012,0.37746,0.05,81.466 +50000,0.37012,0.37746,0.05,81.466 +50000,0.37012,0.37746,0.05,81.466 +50000,0.37012,0.37746,0.05,81.466 +50000,0.37012,0.37746,0.05,81.466 +50000,0.37745,0.38494,0.05,82.332 +50000,0.37745,0.38494,0.05,82.332 +50000,0.37745,0.38494,0.05,82.332 +50000,0.37745,0.38494,0.05,82.332 +50000,0.37745,0.38494,0.05,82.332 +50000,0.37745,0.38494,0.05,82.332 +50000,0.37745,0.38494,0.05,82.332 +50000,0.38493,0.39256,0.05,83.18 +50000,0.38493,0.39256,0.05,83.18 +50000,0.38493,0.39256,0.05,83.18 +50000,0.38493,0.39256,0.05,83.18 +50000,0.38493,0.39256,0.05,83.18 +50000,0.38493,0.39256,0.05,83.18 +50000,0.38493,0.39256,0.05,83.18 +50000,0.38493,0.39256,0.05,83.18 +50000,0.39255,0.40033,0.05,84.01 +50000,0.39255,0.40033,0.05,84.01 +50000,0.39255,0.40033,0.05,84.01 +50000,0.39255,0.40033,0.05,84.01 +50000,0.39255,0.40033,0.05,84.01 +50000,0.39255,0.40033,0.05,84.01 +50000,0.39255,0.40033,0.05,84.01 +50000,0.39255,0.40033,0.05,84.01 +50000,0.40032,0.40826,0.05,84.821 +50000,0.40032,0.40826,0.05,84.821 +50000,0.40032,0.40826,0.05,84.821 +50000,0.40032,0.40826,0.05,84.821 +50000,0.40032,0.40826,0.05,84.821 +50000,0.40032,0.40826,0.05,84.821 +50000,0.40032,0.40826,0.05,84.821 +50000,0.40032,0.40826,0.05,84.821 +50000,0.40825,0.41634,0.05,85.613 +50000,0.40825,0.41634,0.05,85.613 +50000,0.40825,0.41634,0.05,85.613 +50000,0.40825,0.41634,0.05,85.613 +50000,0.40825,0.41634,0.05,85.613 +50000,0.40825,0.41634,0.05,85.613 +50000,0.40825,0.41634,0.05,85.613 +50000,0.40825,0.41634,0.05,85.613 +50000,0.41633,0.42459,0.05,86.386 +50000,0.41633,0.42459,0.05,86.386 +50000,0.41633,0.42459,0.05,86.386 +50000,0.41633,0.42459,0.05,86.386 +50000,0.41633,0.42459,0.05,86.386 +50000,0.41633,0.42459,0.05,86.386 +50000,0.41633,0.42459,0.05,86.386 +50000,0.41633,0.42459,0.05,86.386 +50000,0.42458,0.433,0.05,87.139 +50000,0.42458,0.433,0.05,87.139 +50000,0.42458,0.433,0.05,87.139 +50000,0.42458,0.433,0.05,87.139 +50000,0.42458,0.433,0.05,87.139 +50000,0.42458,0.433,0.05,87.139 +50000,0.42458,0.433,0.05,87.139 +50000,0.42458,0.433,0.05,87.139 +50000,0.42458,0.433,0.05,87.139 +50000,0.43298,0.44157,0.05,87.872 +50000,0.43298,0.44157,0.05,87.872 +50000,0.43298,0.44157,0.05,87.872 +50000,0.43298,0.44157,0.05,87.872 +50000,0.43298,0.44157,0.05,87.872 +50000,0.43298,0.44157,0.05,87.872 +50000,0.43298,0.44157,0.05,87.872 +50000,0.43298,0.44157,0.05,87.872 +50000,0.44156,0.45031,0.05,88.586 +50000,0.44156,0.45031,0.05,88.586 +50000,0.44156,0.45031,0.05,88.586 +50000,0.44156,0.45031,0.05,88.586 +50000,0.44156,0.45031,0.05,88.586 +50000,0.44156,0.45031,0.05,88.586 +50000,0.44156,0.45031,0.05,88.586 +50000,0.44156,0.45031,0.05,88.586 +50000,0.44156,0.45031,0.05,88.586 +50000,0.4503,0.45923,0.05,89.278 +50000,0.4503,0.45923,0.05,89.278 +50000,0.4503,0.45923,0.05,89.278 +50000,0.4503,0.45923,0.05,89.278 +50000,0.4503,0.45923,0.05,89.278 +50000,0.4503,0.45923,0.05,89.278 +50000,0.4503,0.45923,0.05,89.278 +50000,0.4503,0.45923,0.05,89.278 +50000,0.4503,0.45923,0.05,89.278 +50000,0.45922,0.46833,0.05,89.951 +50000,0.45922,0.46833,0.05,89.951 +50000,0.45922,0.46833,0.05,89.951 +50000,0.45922,0.46833,0.05,89.951 +50000,0.45922,0.46833,0.05,89.951 +50000,0.45922,0.46833,0.05,89.951 +50000,0.45922,0.46833,0.05,89.951 +50000,0.45922,0.46833,0.05,89.951 +50000,0.45922,0.46833,0.05,89.951 +50000,0.46832,0.4776,0.05,90.602 +50000,0.46832,0.4776,0.05,90.602 +50000,0.46832,0.4776,0.05,90.602 +50000,0.46832,0.4776,0.05,90.602 +50000,0.46832,0.4776,0.05,90.602 +50000,0.46832,0.4776,0.05,90.602 +50000,0.46832,0.4776,0.05,90.602 +50000,0.46832,0.4776,0.05,90.602 +50000,0.46832,0.4776,0.05,90.602 +50000,0.47759,0.48706,0.05,91.234 +50000,0.47759,0.48706,0.05,91.234 +50000,0.47759,0.48706,0.05,91.234 +50000,0.47759,0.48706,0.05,91.234 +50000,0.47759,0.48706,0.05,91.234 +50000,0.47759,0.48706,0.05,91.234 +50000,0.47759,0.48706,0.05,91.234 +50000,0.47759,0.48706,0.05,91.234 +50000,0.47759,0.48706,0.05,91.234 +50000,0.47759,0.48706,0.05,91.234 +50000,0.48705,0.49671,0.05,91.844 +50000,0.48705,0.49671,0.05,91.844 +50000,0.48705,0.49671,0.05,91.844 +50000,0.48705,0.49671,0.05,91.844 +50000,0.48705,0.49671,0.05,91.844 +50000,0.48705,0.49671,0.05,91.844 +50000,0.48705,0.49671,0.05,91.844 +50000,0.48705,0.49671,0.05,91.844 +50000,0.48705,0.49671,0.05,91.844 +50000,0.4967,0.50655,0.05,92.434 +50000,0.4967,0.50655,0.05,92.434 +50000,0.4967,0.50655,0.05,92.434 +50000,0.4967,0.50655,0.05,92.434 +50000,0.4967,0.50655,0.05,92.434 +50000,0.4967,0.50655,0.05,92.434 +50000,0.4967,0.50655,0.05,92.434 +50000,0.4967,0.50655,0.05,92.434 +50000,0.4967,0.50655,0.05,92.434 +50000,0.4967,0.50655,0.05,92.434 +50000,0.50654,0.51658,0.05,93.004 +50000,0.50654,0.51658,0.05,93.004 +50000,0.50654,0.51658,0.05,93.004 +50000,0.50654,0.51658,0.05,93.004 +50000,0.50654,0.51658,0.05,93.004 +50000,0.50654,0.51658,0.05,93.004 +50000,0.50654,0.51658,0.05,93.004 +50000,0.50654,0.51658,0.05,93.004 +50000,0.50654,0.51658,0.05,93.004 +50000,0.50654,0.51658,0.05,93.004 +50000,0.51657,0.52681,0.05,93.553 +50000,0.51657,0.52681,0.05,93.553 +50000,0.51657,0.52681,0.05,93.553 +50000,0.51657,0.52681,0.05,93.553 +50000,0.51657,0.52681,0.05,93.553 +50000,0.51657,0.52681,0.05,93.553 +50000,0.51657,0.52681,0.05,93.553 +50000,0.51657,0.52681,0.05,93.553 +50000,0.51657,0.52681,0.05,93.553 +50000,0.51657,0.52681,0.05,93.553 +50000,0.5268,0.53725,0.05,94.083 +50000,0.5268,0.53725,0.05,94.083 +50000,0.5268,0.53725,0.05,94.083 +50000,0.5268,0.53725,0.05,94.083 +50000,0.5268,0.53725,0.05,94.083 +50000,0.5268,0.53725,0.05,94.083 +50000,0.5268,0.53725,0.05,94.083 +50000,0.5268,0.53725,0.05,94.083 +50000,0.5268,0.53725,0.05,94.083 +50000,0.5268,0.53725,0.05,94.083 +50000,0.5268,0.53725,0.05,94.083 +50000,0.53724,0.54789,0.05,94.593 +50000,0.53724,0.54789,0.05,94.593 +50000,0.53724,0.54789,0.05,94.593 +50000,0.53724,0.54789,0.05,94.593 +50000,0.53724,0.54789,0.05,94.593 +50000,0.53724,0.54789,0.05,94.593 +50000,0.53724,0.54789,0.05,94.593 +50000,0.53724,0.54789,0.05,94.593 +50000,0.53724,0.54789,0.05,94.593 +50000,0.53724,0.54789,0.05,94.593 +50000,0.54788,0.55874,0.05,95.084 +50000,0.54788,0.55874,0.05,95.084 +50000,0.54788,0.55874,0.05,95.084 +50000,0.54788,0.55874,0.05,95.084 +50000,0.54788,0.55874,0.05,95.084 +50000,0.54788,0.55874,0.05,95.084 +50000,0.54788,0.55874,0.05,95.084 +50000,0.54788,0.55874,0.05,95.084 +50000,0.54788,0.55874,0.05,95.084 +50000,0.54788,0.55874,0.05,95.084 +50000,0.54788,0.55874,0.05,95.084 +50000,0.55873,0.56981,0.05,95.557 +50000,0.55873,0.56981,0.05,95.557 +50000,0.55873,0.56981,0.05,95.557 +50000,0.55873,0.56981,0.05,95.557 +50000,0.55873,0.56981,0.05,95.557 +50000,0.55873,0.56981,0.05,95.557 +50000,0.55873,0.56981,0.05,95.557 +50000,0.55873,0.56981,0.05,95.557 +50000,0.55873,0.56981,0.05,95.557 +50000,0.55873,0.56981,0.05,95.557 +50000,0.55873,0.56981,0.05,95.557 +50000,0.5698,0.5811,0.05,96.012 +50000,0.5698,0.5811,0.05,96.012 +50000,0.5698,0.5811,0.05,96.012 +50000,0.5698,0.5811,0.05,96.012 +50000,0.5698,0.5811,0.05,96.012 +50000,0.5698,0.5811,0.05,96.012 +50000,0.5698,0.5811,0.05,96.012 +50000,0.5698,0.5811,0.05,96.012 +50000,0.5698,0.5811,0.05,96.012 +50000,0.5698,0.5811,0.05,96.012 +50000,0.5698,0.5811,0.05,96.012 +50000,0.5698,0.5811,0.05,96.012 +50000,0.58109,0.59261,0.05,96.45 +50000,0.58109,0.59261,0.05,96.45 +50000,0.58109,0.59261,0.05,96.45 +50000,0.58109,0.59261,0.05,96.45 +50000,0.58109,0.59261,0.05,96.45 +50000,0.58109,0.59261,0.05,96.45 +50000,0.58109,0.59261,0.05,96.45 +50000,0.58109,0.59261,0.05,96.45 +50000,0.58109,0.59261,0.05,96.45 +50000,0.58109,0.59261,0.05,96.45 +50000,0.58109,0.59261,0.05,96.45 +50000,0.5926,0.60435,0.05,96.872 +50000,0.5926,0.60435,0.05,96.872 +50000,0.5926,0.60435,0.05,96.872 +50000,0.5926,0.60435,0.05,96.872 +50000,0.5926,0.60435,0.05,96.872 +50000,0.5926,0.60435,0.05,96.872 +50000,0.5926,0.60435,0.05,96.872 +50000,0.5926,0.60435,0.05,96.872 +50000,0.5926,0.60435,0.05,96.872 +50000,0.5926,0.60435,0.05,96.872 +50000,0.5926,0.60435,0.05,96.872 +50000,0.5926,0.60435,0.05,96.872 +50000,0.60434,0.61632,0.05,97.279 +50000,0.60434,0.61632,0.05,97.279 +50000,0.60434,0.61632,0.05,97.279 +50000,0.60434,0.61632,0.05,97.279 +50000,0.60434,0.61632,0.05,97.279 +50000,0.60434,0.61632,0.05,97.279 +50000,0.60434,0.61632,0.05,97.279 +50000,0.60434,0.61632,0.05,97.279 +50000,0.60434,0.61632,0.05,97.279 +50000,0.60434,0.61632,0.05,97.279 +50000,0.60434,0.61632,0.05,97.279 +50000,0.60434,0.61632,0.05,97.279 +50000,0.61631,0.62853,0.05,97.673 +50000,0.61631,0.62853,0.05,97.673 +50000,0.61631,0.62853,0.05,97.673 +50000,0.61631,0.62853,0.05,97.673 +50000,0.61631,0.62853,0.05,97.673 +50000,0.61631,0.62853,0.05,97.673 +50000,0.61631,0.62853,0.05,97.673 +50000,0.61631,0.62853,0.05,97.673 +50000,0.61631,0.62853,0.05,97.673 +50000,0.61631,0.62853,0.05,97.673 +50000,0.61631,0.62853,0.05,97.673 +50000,0.61631,0.62853,0.05,97.673 +50000,0.62852,0.64098,0.05,98.054 +50000,0.62852,0.64098,0.05,98.054 +50000,0.62852,0.64098,0.05,98.054 +50000,0.62852,0.64098,0.05,98.054 +50000,0.62852,0.64098,0.05,98.054 +50000,0.62852,0.64098,0.05,98.054 +50000,0.62852,0.64098,0.05,98.054 +50000,0.62852,0.64098,0.05,98.054 +50000,0.62852,0.64098,0.05,98.054 +50000,0.62852,0.64098,0.05,98.054 +50000,0.62852,0.64098,0.05,98.054 +50000,0.62852,0.64098,0.05,98.054 +50000,0.62852,0.64098,0.05,98.054 +50000,0.64097,0.65368,0.05,98.424 +50000,0.64097,0.65368,0.05,98.424 +50000,0.64097,0.65368,0.05,98.424 +50000,0.64097,0.65368,0.05,98.424 +50000,0.64097,0.65368,0.05,98.424 +50000,0.64097,0.65368,0.05,98.424 +50000,0.64097,0.65368,0.05,98.424 +50000,0.64097,0.65368,0.05,98.424 +50000,0.64097,0.65368,0.05,98.424 +50000,0.64097,0.65368,0.05,98.424 +50000,0.64097,0.65368,0.05,98.424 +50000,0.64097,0.65368,0.05,98.424 +50000,0.65367,0.66663,0.05,98.785 +50000,0.65367,0.66663,0.05,98.785 +50000,0.65367,0.66663,0.05,98.785 +50000,0.65367,0.66663,0.05,98.785 +50000,0.65367,0.66663,0.05,98.785 +50000,0.65367,0.66663,0.05,98.785 +50000,0.65367,0.66663,0.05,98.785 +50000,0.65367,0.66663,0.05,98.785 +50000,0.65367,0.66663,0.05,98.785 +50000,0.65367,0.66663,0.05,98.785 +50000,0.65367,0.66663,0.05,98.785 +50000,0.65367,0.66663,0.05,98.785 +50000,0.65367,0.66663,0.05,98.785 +50000,0.66662,0.67984,0.05,99.138 +50000,0.66662,0.67984,0.05,99.138 +50000,0.66662,0.67984,0.05,99.138 +50000,0.66662,0.67984,0.05,99.138 +50000,0.66662,0.67984,0.05,99.138 +50000,0.66662,0.67984,0.05,99.138 +50000,0.66662,0.67984,0.05,99.138 +50000,0.66662,0.67984,0.05,99.138 +50000,0.66662,0.67984,0.05,99.138 +50000,0.66662,0.67984,0.05,99.138 +50000,0.66662,0.67984,0.05,99.138 +50000,0.66662,0.67984,0.05,99.138 +50000,0.66662,0.67984,0.05,99.138 +50000,0.67983,0.69331,0.05,99.486 +50000,0.67983,0.69331,0.05,99.486 +50000,0.67983,0.69331,0.05,99.486 +50000,0.67983,0.69331,0.05,99.486 +50000,0.67983,0.69331,0.05,99.486 +50000,0.67983,0.69331,0.05,99.486 +50000,0.67983,0.69331,0.05,99.486 +50000,0.67983,0.69331,0.05,99.486 +50000,0.67983,0.69331,0.05,99.486 +50000,0.67983,0.69331,0.05,99.486 +50000,0.67983,0.69331,0.05,99.486 +50000,0.67983,0.69331,0.05,99.486 +50000,0.67983,0.69331,0.05,99.486 +50000,0.67983,0.69331,0.05,99.486 +50000,0.6933,0.70704,0.05,99.83 +50000,0.6933,0.70704,0.05,99.83 +50000,0.6933,0.70704,0.05,99.83 +50000,0.6933,0.70704,0.05,99.83 +50000,0.6933,0.70704,0.05,99.83 +50000,0.6933,0.70704,0.05,99.83 +50000,0.6933,0.70704,0.05,99.83 +50000,0.6933,0.70704,0.05,99.83 +50000,0.6933,0.70704,0.05,99.83 +50000,0.6933,0.70704,0.05,99.83 +50000,0.6933,0.70704,0.05,99.83 +50000,0.6933,0.70704,0.05,99.83 +50000,0.6933,0.70704,0.05,99.83 +50000,0.6933,0.70704,0.05,99.83 +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/linearThermalDiffusion_plot.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/linearThermalDiffusion_plot.py new file mode 100644 index 00000000000..67e336576c2 --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/linearThermalDiffusion_plot.py @@ -0,0 +1,147 @@ +import os +import sys +import os +import argparse + +import numpy as np +import matplotlib.pyplot as plt +import pandas as pd +import scipy.linalg +from scipy import special +from xml.etree import ElementTree + +# Analytical results +def steadyState(Tin, Tout, Rin, Rout, radialCoordinate): + return Tin + (Tout - Tin) * (np.log(radialCoordinate) - np.log(Rin)) / (np.log(Rout) - np.log(Rin)) + +def diffusionFunction(radialCoordinate, Rin, diffusionCoefficient, diffusionTime): + return special.erfc( (radialCoordinate - Rin) / 2.0 / np.sqrt( diffusionCoefficient * diffusionTime ) ) + +def computeTransientTemperature(Tin, Tout, Rin, radialCoordinate, thermalDiffusionCoefficient, diffusionTime): + # Ref. Wang and Papamichos (1994), https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/94WR01774 + return Tout + (Tin-Tout) * np.sqrt(Rin/radialCoordinate) * diffusionFunction(radialCoordinate, Rin, thermalDiffusionCoefficient, diffusionTime) + +def computeThermalDiffusionCoefficient(thermalConductivity, volumetricHeatCapacity): + return thermalConductivity / volumetricHeatCapacity + +def extractDataFromXMLList(paramList): + # Extract data from a list in XML such as "{ 1, 2, 3}" + return paramList.replace('{', '').replace('}', '').strip().split(',') + +def getWellboreGeometryFromXML(xmlFilePath): + tree = ElementTree.parse(xmlFilePath) + + meshParam = tree.find('Mesh/InternalWellbore') + radii = extractDataFromXMLList( meshParam.get("radius") ) + + Rin = float(radii[0]) + Rout = float(radii[-1]) + + return [Rin, Rout] + +def getLoadingFromXML(xmlFilePath): + tree = ElementTree.parse(xmlFilePath) + fsParams = tree.findall('FieldSpecifications/FieldSpecification') + + for fsParam in fsParams: + if ( (fsParam.get('fieldName') == "pressure") & (fsParam.get('initialCondition') != "1") ): + if fsParam.get('setNames') == "{ rneg }": + Pin = float(fsParam.get('scale')) + if fsParam.get('setNames') == "{ rpos }": + Pout = float(fsParam.get('scale')) + + for fsParam in fsParams: + if ( (fsParam.get('fieldName') == "temperature") & (fsParam.get('initialCondition') != "1") ): + if fsParam.get('setNames') == "{ rneg }": + Tin = float(fsParam.get('scale')) + if fsParam.get('setNames') == "{ rpos }": + Tout = float(fsParam.get('scale')) + + tree_SinglePhaseThermalConductivities = tree.findall('Constitutive/SinglePhaseThermalConductivity') + + for tree_SinglePhaseThermalConductivity in tree_SinglePhaseThermalConductivities: + if tree_SinglePhaseThermalConductivity.get('name') == "thermalCond_linear": + thermalConductivity = float( extractDataFromXMLList( tree_SinglePhaseThermalConductivity.get('defaultThermalConductivityComponents') )[0] ) + + tree_SolidInternalEnergies = tree.findall('Constitutive/SolidInternalEnergy') + + for tree_SolidInternalEnergy in tree_SolidInternalEnergies: + if tree_SolidInternalEnergy.get('name') == "rockInternalEnergy_linear": + volumetricHeatCapacity = float( tree_SolidInternalEnergy.get('referenceVolumetricHeatCapacity') ) + + permeability = float( extractDataFromXMLList( tree.find('Constitutive/ConstantPermeability').get('permeabilityComponents') )[0] ) + + porosity = float( tree.find('Constitutive/PressurePorosity').get('defaultReferencePorosity') ) + + fluidViscosity = float( tree.find('Constitutive/ThermalCompressibleSinglePhaseFluid').get('defaultViscosity') ) + + fluidCompressibility = float( tree.find('Constitutive/ThermalCompressibleSinglePhaseFluid').get('compressibility') ) + + fluidThermalExpansionCoefficient = float( tree.find('Constitutive/ThermalCompressibleSinglePhaseFluid').get('thermalExpansionCoeff') ) + + return [Pin, Pout, Tin, Tout, thermalConductivity, volumetricHeatCapacity, permeability, porosity, fluidViscosity, fluidCompressibility, fluidThermalExpansionCoefficient] + + +def main(): + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + + # Parse the command-line arguments + args = parser.parse_args() + + geosDir = args.geosDir + + xmlFilePath = geosDir + "/inputFiles/singlePhaseFlow/thermalCompressible_2d" + + Rin, Rout = getWellboreGeometryFromXML(xmlFilePath+"_benchmark.xml") + + Pin, Pout, Tin, Tout, thermalConductivity, volumetricHeatCapacity, permeability, porosity, fluidViscosity, fluidCompressibility, fluidThermalExpansionCoefficient = getLoadingFromXML(xmlFilePath+"_base.xml") + + plt.figure(figsize=(10,7)) + font = {'size' : 16} + plt.rc('font', **font) + + for chart_idx, idx in enumerate([1, 2, 5, 10]): + # Numerical results + data = pd.read_csv(f'data_{idx}.csv') + radialCoordinate = (data['elementCenter:0']**2.0 + data['elementCenter:1']**2.0)**0.5 + temperature = data['temperature'] + diffusionTime = data['Time'][0] + + # Analytical results + thermalDiffusionCoefficient = computeThermalDiffusionCoefficient(thermalConductivity, volumetricHeatCapacity) + + T_transient = computeTransientTemperature(Tin, Tout, Rin, radialCoordinate, thermalDiffusionCoefficient, diffusionTime) + + # Analytical results of the steady state regime for comparison + T_steadyState = steadyState(Tin, Tout, Rin, Rout, radialCoordinate) + + # Visualization + # Temperature + plt.subplot(2,2,chart_idx+1) + plt.plot( radialCoordinate, temperature, 'k+' , label='GEOSX' ) + plt.plot( radialCoordinate, T_transient, 'r-' , label='Analytic, infinite domain' ) + plt.plot( radialCoordinate, T_steadyState, 'b-' , label='Steady State' ) + + if chart_idx==1: + plt.legend() + + if chart_idx in [2,3]: + plt.xlabel('Radial distance from well center') + + if chart_idx in [0,2]: + plt.ylabel('Temperature (°C)') + + plt.ylim(-30,110) + plt.xlim(0,1.0) + plt.title('t = '+str(diffusionTime)+'(s)') + plt.tight_layout() + + plt.show() + +if __name__ == "__main__": + main() diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/radialThermalDiffusionSketch.png b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/radialThermalDiffusionSketch.png similarity index 100% rename from src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/radialThermalDiffusionSketch.png rename to src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/linearThermalDiffusion/radialThermalDiffusionSketch.png diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/mccWellbore/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/mccWellbore/Example.rst index 83ad3e0e8ef..352a17cf1c4 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/mccWellbore/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/mccWellbore/Example.rst @@ -115,7 +115,7 @@ Here, Modified Cam-Clay ``ModifiedCamClay`` is used to simulate the elastoplasti The following material parameters should be defined properly to reproduce the analytical example: -.. include:: ../../../../../../../src/coreComponents/schema/docs/ModifiedCamClay.rst +.. include:: /docs/sphinx/datastructure/ModifiedCamClay.rst The constitutive parameters such as the density, the bulk modulus, and the shear modulus are specified in the International System of Units. diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/Example.rst new file mode 100644 index 00000000000..aa8fbb0677e --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/Example.rst @@ -0,0 +1,62 @@ +.. _AdvancedExampleWellboreNonLinearThermalDiffusionTemperatureDependentSinglePhaseThermalConductivity: + + +##################################################################################################################### +Non-Linear Thermal Diffusion Around a Wellbore: The Case with Temperature Dependent Single Phase Thermal Conductivity +##################################################################################################################### + +------------------------------------------------------------------ +Problem description +------------------------------------------------------------------ + +This example is an extension of the linear thermal diffusion problem presented in :ref:`AdvancedExamplePureThermalDiffusionWellbore` to model wellbore cooling upon CO2 injection. It uses the thermal single-phase flow solver to model a non-linear thermal diffusion problem around a wellbore where the single phase thermal conductivity of the porous rock depends linearly on the temperature. + + +**Input file** + +This benchmark example uses no external input file and everything required is +contained within two GEOS xml files that are located at: + +.. code-block:: console + + inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml + +and + +.. code-block:: console + + inputFiles/singlePhaseFlow/thermalCompressible_temperatureDependentSinglePhaseThermalConductivity_benchmark.xml + + +In this example, we focus on the ``Constitutive`` tag. + +----------------------------------------------------------- +Constitutive +----------------------------------------------------------- + +The reference value of the single phase thermal conductivity of the porous medium around the wellbore and its derivative with respect to temperature are defined in the ``SinglePhaseThermalConductivity`` XML block: + +.. literalinclude:: ../../../../../../../inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml + :language: xml + :start-after: + :end-before: + + +--------------------------------- +Results and benchmark +--------------------------------- + +A good agreement between the results obtained using GEOS and the reference results that are obtained by the classical finite difference method is shown in the figure below: + + +.. plot:: docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/temperatureDependentSinglePhaseThermalConductivity_plot.py + + +------------------------------------------------------------------ +To go further +------------------------------------------------------------------ + +**Feedback on this example** + +This concludes the example of a non-linear thermal diffusion problem around a wellbore due to temperature dependent single phase thermal conductivity of porous rock. +For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/data_1.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/data_1.csv new file mode 100644 index 00000000000..8771183d7fa --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/data_1.csv @@ -0,0 +1,1002 @@ +Time,"elementCenter:0","elementCenter:1","elementCenter:2","temperature" +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,0.07071,0.072112,0.05,-19.002 +10000,0.07071,0.072112,0.05,-19.002 +10000,0.07211,0.07354,0.05,-17.045 +10000,0.07351,0.074968,0.05,-15.122 +10000,0.075155,0.076646,0.05,-12.902 +10000,0.075155,0.076646,0.05,-12.902 +10000,0.077046,0.078574,0.05,-10.412 +10000,0.077046,0.078574,0.05,-10.412 +10000,0.078936,0.080501,0.05,-7.9783 +10000,0.078936,0.080501,0.05,-7.9783 +10000,0.080826,0.082429,0.05,-5.5998 +10000,0.080826,0.082429,0.05,-5.5998 +10000,0.082716,0.084357,0.05,-3.2741 +10000,0.082716,0.084357,0.05,-3.2741 +10000,0.084607,0.086285,0.05,-0.99929 +10000,0.084607,0.086285,0.05,-0.99929 +10000,0.086497,0.088212,0.05,1.2264 +10000,0.086497,0.088212,0.05,1.2264 +10000,0.088387,0.09014,0.05,3.4046 +10000,0.088387,0.09014,0.05,3.4046 +10000,0.090278,0.092068,0.05,5.537 +10000,0.090278,0.092068,0.05,5.537 +10000,0.092168,0.093995,0.05,7.6248 +10000,0.092168,0.093995,0.05,7.6248 +10000,0.094031,0.095896,0.05,9.6402 +10000,0.095885,0.097786,0.05,11.606 +10000,0.095885,0.097786,0.05,11.606 +10000,0.097776,0.099715,0.05,13.57 +10000,0.097776,0.099715,0.05,13.57 +10000,0.099704,0.10168,0.05,15.533 +10000,0.099704,0.10168,0.05,15.533 +10000,0.10167,0.10369,0.05,17.494 +10000,0.10167,0.10369,0.05,17.494 +10000,0.10368,0.10573,0.05,19.451 +10000,0.10368,0.10573,0.05,19.451 +10000,0.10572,0.10782,0.05,21.405 +10000,0.10572,0.10782,0.05,21.405 +10000,0.10781,0.10995,0.05,23.355 +10000,0.10781,0.10995,0.05,23.355 +10000,0.10993,0.11211,0.05,25.301 +10000,0.10993,0.11211,0.05,25.301 +10000,0.10993,0.11211,0.05,25.301 +10000,0.1121,0.11433,0.05,27.241 +10000,0.1121,0.11433,0.05,27.241 +10000,0.11432,0.11658,0.05,29.174 +10000,0.11432,0.11658,0.05,29.174 +10000,0.11657,0.11888,0.05,31.102 +10000,0.11657,0.11888,0.05,31.102 +10000,0.11887,0.12123,0.05,33.021 +10000,0.11887,0.12123,0.05,33.021 +10000,0.11887,0.12123,0.05,33.021 +10000,0.12122,0.12362,0.05,34.932 +10000,0.12122,0.12362,0.05,34.932 +10000,0.12361,0.12607,0.05,36.834 +10000,0.12361,0.12607,0.05,36.834 +10000,0.12361,0.12607,0.05,36.834 +10000,0.12605,0.12855,0.05,38.726 +10000,0.12605,0.12855,0.05,38.726 +10000,0.12854,0.13109,0.05,40.606 +10000,0.12854,0.13109,0.05,40.606 +10000,0.12854,0.13109,0.05,40.606 +10000,0.13108,0.13368,0.05,42.475 +10000,0.13108,0.13368,0.05,42.475 +10000,0.13367,0.13632,0.05,44.33 +10000,0.13367,0.13632,0.05,44.33 +10000,0.13367,0.13632,0.05,44.33 +10000,0.13631,0.13901,0.05,46.171 +10000,0.13631,0.13901,0.05,46.171 +10000,0.13631,0.13901,0.05,46.171 +10000,0.139,0.14176,0.05,47.997 +10000,0.139,0.14176,0.05,47.997 +10000,0.14175,0.14456,0.05,49.807 +10000,0.14175,0.14456,0.05,49.807 +10000,0.14175,0.14456,0.05,49.807 +10000,0.14455,0.14742,0.05,51.599 +10000,0.14455,0.14742,0.05,51.599 +10000,0.14455,0.14742,0.05,51.599 +10000,0.1474,0.15033,0.05,53.373 +10000,0.1474,0.15033,0.05,53.373 +10000,0.1474,0.15033,0.05,53.373 +10000,0.15032,0.1533,0.05,55.127 +10000,0.15032,0.1533,0.05,55.127 +10000,0.15032,0.1533,0.05,55.127 +10000,0.15329,0.15633,0.05,56.86 +10000,0.15329,0.15633,0.05,56.86 +10000,0.15329,0.15633,0.05,56.86 +10000,0.15632,0.15942,0.05,58.57 +10000,0.15632,0.15942,0.05,58.57 +10000,0.15632,0.15942,0.05,58.57 +10000,0.15941,0.16257,0.05,60.257 +10000,0.15941,0.16257,0.05,60.257 +10000,0.15941,0.16257,0.05,60.257 +10000,0.16256,0.16578,0.05,61.92 +10000,0.16256,0.16578,0.05,61.92 +10000,0.16256,0.16578,0.05,61.92 +10000,0.16577,0.16906,0.05,63.556 +10000,0.16577,0.16906,0.05,63.556 +10000,0.16577,0.16906,0.05,63.556 +10000,0.16577,0.16906,0.05,63.556 +10000,0.16905,0.1724,0.05,65.165 +10000,0.16905,0.1724,0.05,65.165 +10000,0.16905,0.1724,0.05,65.165 +10000,0.17239,0.1758,0.05,66.746 +10000,0.17239,0.1758,0.05,66.746 +10000,0.17239,0.1758,0.05,66.746 +10000,0.17579,0.17928,0.05,68.296 +10000,0.17579,0.17928,0.05,68.296 +10000,0.17579,0.17928,0.05,68.296 +10000,0.17579,0.17928,0.05,68.296 +10000,0.17927,0.18282,0.05,69.816 +10000,0.17927,0.18282,0.05,69.816 +10000,0.17927,0.18282,0.05,69.816 +10000,0.18281,0.18644,0.05,71.303 +10000,0.18281,0.18644,0.05,71.303 +10000,0.18281,0.18644,0.05,71.303 +10000,0.18281,0.18644,0.05,71.303 +10000,0.18643,0.19013,0.05,72.756 +10000,0.18643,0.19013,0.05,72.756 +10000,0.18643,0.19013,0.05,72.756 +10000,0.18643,0.19013,0.05,72.756 +10000,0.19011,0.19388,0.05,74.175 +10000,0.19011,0.19388,0.05,74.175 +10000,0.19011,0.19388,0.05,74.175 +10000,0.19387,0.19772,0.05,75.558 +10000,0.19387,0.19772,0.05,75.558 +10000,0.19387,0.19772,0.05,75.558 +10000,0.19387,0.19772,0.05,75.558 +10000,0.19771,0.20163,0.05,76.904 +10000,0.19771,0.20163,0.05,76.904 +10000,0.19771,0.20163,0.05,76.904 +10000,0.19771,0.20163,0.05,76.904 +10000,0.20162,0.20562,0.05,78.213 +10000,0.20162,0.20562,0.05,78.213 +10000,0.20162,0.20562,0.05,78.213 +10000,0.20162,0.20562,0.05,78.213 +10000,0.2056,0.20968,0.05,79.482 +10000,0.2056,0.20968,0.05,79.482 +10000,0.2056,0.20968,0.05,79.482 +10000,0.2056,0.20968,0.05,79.482 +10000,0.20967,0.21383,0.05,80.712 +10000,0.20967,0.21383,0.05,80.712 +10000,0.20967,0.21383,0.05,80.712 +10000,0.20967,0.21383,0.05,80.712 +10000,0.21382,0.21806,0.05,81.901 +10000,0.21382,0.21806,0.05,81.901 +10000,0.21382,0.21806,0.05,81.901 +10000,0.21382,0.21806,0.05,81.901 +10000,0.21382,0.21806,0.05,81.901 +10000,0.21805,0.22237,0.05,83.048 +10000,0.21805,0.22237,0.05,83.048 +10000,0.21805,0.22237,0.05,83.048 +10000,0.21805,0.22237,0.05,83.048 +10000,0.22236,0.22677,0.05,84.154 +10000,0.22236,0.22677,0.05,84.154 +10000,0.22236,0.22677,0.05,84.154 +10000,0.22236,0.22677,0.05,84.154 +10000,0.22676,0.23125,0.05,85.218 +10000,0.22676,0.23125,0.05,85.218 +10000,0.22676,0.23125,0.05,85.218 +10000,0.22676,0.23125,0.05,85.218 +10000,0.22676,0.23125,0.05,85.218 +10000,0.23124,0.23583,0.05,86.239 +10000,0.23124,0.23583,0.05,86.239 +10000,0.23124,0.23583,0.05,86.239 +10000,0.23124,0.23583,0.05,86.239 +10000,0.23582,0.2405,0.05,87.216 +10000,0.23582,0.2405,0.05,87.216 +10000,0.23582,0.2405,0.05,87.216 +10000,0.23582,0.2405,0.05,87.216 +10000,0.23582,0.2405,0.05,87.216 +10000,0.24048,0.24525,0.05,88.15 +10000,0.24048,0.24525,0.05,88.15 +10000,0.24048,0.24525,0.05,88.15 +10000,0.24048,0.24525,0.05,88.15 +10000,0.24048,0.24525,0.05,88.15 +10000,0.24524,0.25011,0.05,89.041 +10000,0.24524,0.25011,0.05,89.041 +10000,0.24524,0.25011,0.05,89.041 +10000,0.24524,0.25011,0.05,89.041 +10000,0.24524,0.25011,0.05,89.041 +10000,0.25009,0.25505,0.05,89.889 +10000,0.25009,0.25505,0.05,89.889 +10000,0.25009,0.25505,0.05,89.889 +10000,0.25009,0.25505,0.05,89.889 +10000,0.25009,0.25505,0.05,89.889 +10000,0.25504,0.2601,0.05,90.694 +10000,0.25504,0.2601,0.05,90.694 +10000,0.25504,0.2601,0.05,90.694 +10000,0.25504,0.2601,0.05,90.694 +10000,0.25504,0.2601,0.05,90.694 +10000,0.26009,0.26525,0.05,91.456 +10000,0.26009,0.26525,0.05,91.456 +10000,0.26009,0.26525,0.05,91.456 +10000,0.26009,0.26525,0.05,91.456 +10000,0.26009,0.26525,0.05,91.456 +10000,0.26524,0.2705,0.05,92.175 +10000,0.26524,0.2705,0.05,92.175 +10000,0.26524,0.2705,0.05,92.175 +10000,0.26524,0.2705,0.05,92.175 +10000,0.26524,0.2705,0.05,92.175 +10000,0.27048,0.27585,0.05,92.853 +10000,0.27048,0.27585,0.05,92.853 +10000,0.27048,0.27585,0.05,92.853 +10000,0.27048,0.27585,0.05,92.853 +10000,0.27048,0.27585,0.05,92.853 +10000,0.27584,0.28131,0.05,93.49 +10000,0.27584,0.28131,0.05,93.49 +10000,0.27584,0.28131,0.05,93.49 +10000,0.27584,0.28131,0.05,93.49 +10000,0.27584,0.28131,0.05,93.49 +10000,0.27584,0.28131,0.05,93.49 +10000,0.2813,0.28687,0.05,94.087 +10000,0.2813,0.28687,0.05,94.087 +10000,0.2813,0.28687,0.05,94.087 +10000,0.2813,0.28687,0.05,94.087 +10000,0.2813,0.28687,0.05,94.087 +10000,0.28686,0.29255,0.05,94.644 +10000,0.28686,0.29255,0.05,94.644 +10000,0.28686,0.29255,0.05,94.644 +10000,0.28686,0.29255,0.05,94.644 +10000,0.28686,0.29255,0.05,94.644 +10000,0.28686,0.29255,0.05,94.644 +10000,0.29254,0.29834,0.05,95.164 +10000,0.29254,0.29834,0.05,95.164 +10000,0.29254,0.29834,0.05,95.164 +10000,0.29254,0.29834,0.05,95.164 +10000,0.29254,0.29834,0.05,95.164 +10000,0.29254,0.29834,0.05,95.164 +10000,0.29833,0.30425,0.05,95.646 +10000,0.29833,0.30425,0.05,95.646 +10000,0.29833,0.30425,0.05,95.646 +10000,0.29833,0.30425,0.05,95.646 +10000,0.29833,0.30425,0.05,95.646 +10000,0.29833,0.30425,0.05,95.646 +10000,0.30424,0.31027,0.05,96.092 +10000,0.30424,0.31027,0.05,96.092 +10000,0.30424,0.31027,0.05,96.092 +10000,0.30424,0.31027,0.05,96.092 +10000,0.30424,0.31027,0.05,96.092 +10000,0.30424,0.31027,0.05,96.092 +10000,0.31026,0.31641,0.05,96.504 +10000,0.31026,0.31641,0.05,96.504 +10000,0.31026,0.31641,0.05,96.504 +10000,0.31026,0.31641,0.05,96.504 +10000,0.31026,0.31641,0.05,96.504 +10000,0.31026,0.31641,0.05,96.504 +10000,0.3164,0.32267,0.05,96.883 +10000,0.3164,0.32267,0.05,96.883 +10000,0.3164,0.32267,0.05,96.883 +10000,0.3164,0.32267,0.05,96.883 +10000,0.3164,0.32267,0.05,96.883 +10000,0.3164,0.32267,0.05,96.883 +10000,0.32266,0.32906,0.05,97.23 +10000,0.32266,0.32906,0.05,97.23 +10000,0.32266,0.32906,0.05,97.23 +10000,0.32266,0.32906,0.05,97.23 +10000,0.32266,0.32906,0.05,97.23 +10000,0.32266,0.32906,0.05,97.23 +10000,0.32266,0.32906,0.05,97.23 +10000,0.32905,0.33558,0.05,97.548 +10000,0.32905,0.33558,0.05,97.548 +10000,0.32905,0.33558,0.05,97.548 +10000,0.32905,0.33558,0.05,97.548 +10000,0.32905,0.33558,0.05,97.548 +10000,0.32905,0.33558,0.05,97.548 +10000,0.33556,0.34222,0.05,97.836 +10000,0.33556,0.34222,0.05,97.836 +10000,0.33556,0.34222,0.05,97.836 +10000,0.33556,0.34222,0.05,97.836 +10000,0.33556,0.34222,0.05,97.836 +10000,0.33556,0.34222,0.05,97.836 +10000,0.33556,0.34222,0.05,97.836 +10000,0.34221,0.34899,0.05,98.098 +10000,0.34221,0.34899,0.05,98.098 +10000,0.34221,0.34899,0.05,98.098 +10000,0.34221,0.34899,0.05,98.098 +10000,0.34221,0.34899,0.05,98.098 +10000,0.34221,0.34899,0.05,98.098 +10000,0.34221,0.34899,0.05,98.098 +10000,0.34898,0.3559,0.05,98.334 +10000,0.34898,0.3559,0.05,98.334 +10000,0.34898,0.3559,0.05,98.334 +10000,0.34898,0.3559,0.05,98.334 +10000,0.34898,0.3559,0.05,98.334 +10000,0.34898,0.3559,0.05,98.334 +10000,0.35589,0.36295,0.05,98.547 +10000,0.35589,0.36295,0.05,98.547 +10000,0.35589,0.36295,0.05,98.547 +10000,0.35589,0.36295,0.05,98.547 +10000,0.35589,0.36295,0.05,98.547 +10000,0.35589,0.36295,0.05,98.547 +10000,0.35589,0.36295,0.05,98.547 +10000,0.36294,0.37013,0.05,98.738 +10000,0.36294,0.37013,0.05,98.738 +10000,0.36294,0.37013,0.05,98.738 +10000,0.36294,0.37013,0.05,98.738 +10000,0.36294,0.37013,0.05,98.738 +10000,0.36294,0.37013,0.05,98.738 +10000,0.36294,0.37013,0.05,98.738 +10000,0.36294,0.37013,0.05,98.738 +10000,0.37012,0.37746,0.05,98.908 +10000,0.37012,0.37746,0.05,98.908 +10000,0.37012,0.37746,0.05,98.908 +10000,0.37012,0.37746,0.05,98.908 +10000,0.37012,0.37746,0.05,98.908 +10000,0.37012,0.37746,0.05,98.908 +10000,0.37012,0.37746,0.05,98.908 +10000,0.37745,0.38494,0.05,99.059 +10000,0.37745,0.38494,0.05,99.059 +10000,0.37745,0.38494,0.05,99.059 +10000,0.37745,0.38494,0.05,99.059 +10000,0.37745,0.38494,0.05,99.059 +10000,0.37745,0.38494,0.05,99.059 +10000,0.37745,0.38494,0.05,99.059 +10000,0.38493,0.39256,0.05,99.193 +10000,0.38493,0.39256,0.05,99.193 +10000,0.38493,0.39256,0.05,99.193 +10000,0.38493,0.39256,0.05,99.193 +10000,0.38493,0.39256,0.05,99.193 +10000,0.38493,0.39256,0.05,99.193 +10000,0.38493,0.39256,0.05,99.193 +10000,0.38493,0.39256,0.05,99.193 +10000,0.39255,0.40033,0.05,99.31 +10000,0.39255,0.40033,0.05,99.31 +10000,0.39255,0.40033,0.05,99.31 +10000,0.39255,0.40033,0.05,99.31 +10000,0.39255,0.40033,0.05,99.31 +10000,0.39255,0.40033,0.05,99.31 +10000,0.39255,0.40033,0.05,99.31 +10000,0.39255,0.40033,0.05,99.31 +10000,0.40032,0.40826,0.05,99.414 +10000,0.40032,0.40826,0.05,99.414 +10000,0.40032,0.40826,0.05,99.414 +10000,0.40032,0.40826,0.05,99.414 +10000,0.40032,0.40826,0.05,99.414 +10000,0.40032,0.40826,0.05,99.414 +10000,0.40032,0.40826,0.05,99.414 +10000,0.40032,0.40826,0.05,99.414 +10000,0.40825,0.41634,0.05,99.504 +10000,0.40825,0.41634,0.05,99.504 +10000,0.40825,0.41634,0.05,99.504 +10000,0.40825,0.41634,0.05,99.504 +10000,0.40825,0.41634,0.05,99.504 +10000,0.40825,0.41634,0.05,99.504 +10000,0.40825,0.41634,0.05,99.504 +10000,0.40825,0.41634,0.05,99.504 +10000,0.41633,0.42459,0.05,99.582 +10000,0.41633,0.42459,0.05,99.582 +10000,0.41633,0.42459,0.05,99.582 +10000,0.41633,0.42459,0.05,99.582 +10000,0.41633,0.42459,0.05,99.582 +10000,0.41633,0.42459,0.05,99.582 +10000,0.41633,0.42459,0.05,99.582 +10000,0.41633,0.42459,0.05,99.582 +10000,0.42458,0.433,0.05,99.65 +10000,0.42458,0.433,0.05,99.65 +10000,0.42458,0.433,0.05,99.65 +10000,0.42458,0.433,0.05,99.65 +10000,0.42458,0.433,0.05,99.65 +10000,0.42458,0.433,0.05,99.65 +10000,0.42458,0.433,0.05,99.65 +10000,0.42458,0.433,0.05,99.65 +10000,0.42458,0.433,0.05,99.65 +10000,0.43298,0.44157,0.05,99.708 +10000,0.43298,0.44157,0.05,99.708 +10000,0.43298,0.44157,0.05,99.708 +10000,0.43298,0.44157,0.05,99.708 +10000,0.43298,0.44157,0.05,99.708 +10000,0.43298,0.44157,0.05,99.708 +10000,0.43298,0.44157,0.05,99.708 +10000,0.43298,0.44157,0.05,99.708 +10000,0.44156,0.45031,0.05,99.758 +10000,0.44156,0.45031,0.05,99.758 +10000,0.44156,0.45031,0.05,99.758 +10000,0.44156,0.45031,0.05,99.758 +10000,0.44156,0.45031,0.05,99.758 +10000,0.44156,0.45031,0.05,99.758 +10000,0.44156,0.45031,0.05,99.758 +10000,0.44156,0.45031,0.05,99.758 +10000,0.44156,0.45031,0.05,99.758 +10000,0.4503,0.45923,0.05,99.8 +10000,0.4503,0.45923,0.05,99.8 +10000,0.4503,0.45923,0.05,99.8 +10000,0.4503,0.45923,0.05,99.8 +10000,0.4503,0.45923,0.05,99.8 +10000,0.4503,0.45923,0.05,99.8 +10000,0.4503,0.45923,0.05,99.8 +10000,0.4503,0.45923,0.05,99.8 +10000,0.4503,0.45923,0.05,99.8 +10000,0.45922,0.46833,0.05,99.836 +10000,0.45922,0.46833,0.05,99.836 +10000,0.45922,0.46833,0.05,99.836 +10000,0.45922,0.46833,0.05,99.836 +10000,0.45922,0.46833,0.05,99.836 +10000,0.45922,0.46833,0.05,99.836 +10000,0.45922,0.46833,0.05,99.836 +10000,0.45922,0.46833,0.05,99.836 +10000,0.45922,0.46833,0.05,99.836 +10000,0.46832,0.4776,0.05,99.866 +10000,0.46832,0.4776,0.05,99.866 +10000,0.46832,0.4776,0.05,99.866 +10000,0.46832,0.4776,0.05,99.866 +10000,0.46832,0.4776,0.05,99.866 +10000,0.46832,0.4776,0.05,99.866 +10000,0.46832,0.4776,0.05,99.866 +10000,0.46832,0.4776,0.05,99.866 +10000,0.46832,0.4776,0.05,99.866 +10000,0.47759,0.48706,0.05,99.891 +10000,0.47759,0.48706,0.05,99.891 +10000,0.47759,0.48706,0.05,99.891 +10000,0.47759,0.48706,0.05,99.891 +10000,0.47759,0.48706,0.05,99.891 +10000,0.47759,0.48706,0.05,99.891 +10000,0.47759,0.48706,0.05,99.891 +10000,0.47759,0.48706,0.05,99.891 +10000,0.47759,0.48706,0.05,99.891 +10000,0.47759,0.48706,0.05,99.891 +10000,0.48705,0.49671,0.05,99.912 +10000,0.48705,0.49671,0.05,99.912 +10000,0.48705,0.49671,0.05,99.912 +10000,0.48705,0.49671,0.05,99.912 +10000,0.48705,0.49671,0.05,99.912 +10000,0.48705,0.49671,0.05,99.912 +10000,0.48705,0.49671,0.05,99.912 +10000,0.48705,0.49671,0.05,99.912 +10000,0.48705,0.49671,0.05,99.912 +10000,0.4967,0.50655,0.05,99.93 +10000,0.4967,0.50655,0.05,99.93 +10000,0.4967,0.50655,0.05,99.93 +10000,0.4967,0.50655,0.05,99.93 +10000,0.4967,0.50655,0.05,99.93 +10000,0.4967,0.50655,0.05,99.93 +10000,0.4967,0.50655,0.05,99.93 +10000,0.4967,0.50655,0.05,99.93 +10000,0.4967,0.50655,0.05,99.93 +10000,0.4967,0.50655,0.05,99.93 +10000,0.50654,0.51658,0.05,99.944 +10000,0.50654,0.51658,0.05,99.944 +10000,0.50654,0.51658,0.05,99.944 +10000,0.50654,0.51658,0.05,99.944 +10000,0.50654,0.51658,0.05,99.944 +10000,0.50654,0.51658,0.05,99.944 +10000,0.50654,0.51658,0.05,99.944 +10000,0.50654,0.51658,0.05,99.944 +10000,0.50654,0.51658,0.05,99.944 +10000,0.50654,0.51658,0.05,99.944 +10000,0.51657,0.52681,0.05,99.955 +10000,0.51657,0.52681,0.05,99.955 +10000,0.51657,0.52681,0.05,99.955 +10000,0.51657,0.52681,0.05,99.955 +10000,0.51657,0.52681,0.05,99.955 +10000,0.51657,0.52681,0.05,99.955 +10000,0.51657,0.52681,0.05,99.955 +10000,0.51657,0.52681,0.05,99.955 +10000,0.51657,0.52681,0.05,99.955 +10000,0.51657,0.52681,0.05,99.955 +10000,0.5268,0.53725,0.05,99.965 +10000,0.5268,0.53725,0.05,99.965 +10000,0.5268,0.53725,0.05,99.965 +10000,0.5268,0.53725,0.05,99.965 +10000,0.5268,0.53725,0.05,99.965 +10000,0.5268,0.53725,0.05,99.965 +10000,0.5268,0.53725,0.05,99.965 +10000,0.5268,0.53725,0.05,99.965 +10000,0.5268,0.53725,0.05,99.965 +10000,0.5268,0.53725,0.05,99.965 +10000,0.5268,0.53725,0.05,99.965 +10000,0.53724,0.54789,0.05,99.973 +10000,0.53724,0.54789,0.05,99.973 +10000,0.53724,0.54789,0.05,99.973 +10000,0.53724,0.54789,0.05,99.973 +10000,0.53724,0.54789,0.05,99.973 +10000,0.53724,0.54789,0.05,99.973 +10000,0.53724,0.54789,0.05,99.973 +10000,0.53724,0.54789,0.05,99.973 +10000,0.53724,0.54789,0.05,99.973 +10000,0.53724,0.54789,0.05,99.973 +10000,0.54788,0.55874,0.05,99.979 +10000,0.54788,0.55874,0.05,99.979 +10000,0.54788,0.55874,0.05,99.979 +10000,0.54788,0.55874,0.05,99.979 +10000,0.54788,0.55874,0.05,99.979 +10000,0.54788,0.55874,0.05,99.979 +10000,0.54788,0.55874,0.05,99.979 +10000,0.54788,0.55874,0.05,99.979 +10000,0.54788,0.55874,0.05,99.979 +10000,0.54788,0.55874,0.05,99.979 +10000,0.54788,0.55874,0.05,99.979 +10000,0.55873,0.56981,0.05,99.984 +10000,0.55873,0.56981,0.05,99.984 +10000,0.55873,0.56981,0.05,99.984 +10000,0.55873,0.56981,0.05,99.984 +10000,0.55873,0.56981,0.05,99.984 +10000,0.55873,0.56981,0.05,99.984 +10000,0.55873,0.56981,0.05,99.984 +10000,0.55873,0.56981,0.05,99.984 +10000,0.55873,0.56981,0.05,99.984 +10000,0.55873,0.56981,0.05,99.984 +10000,0.55873,0.56981,0.05,99.984 +10000,0.5698,0.5811,0.05,99.987 +10000,0.5698,0.5811,0.05,99.987 +10000,0.5698,0.5811,0.05,99.987 +10000,0.5698,0.5811,0.05,99.987 +10000,0.5698,0.5811,0.05,99.987 +10000,0.5698,0.5811,0.05,99.987 +10000,0.5698,0.5811,0.05,99.987 +10000,0.5698,0.5811,0.05,99.987 +10000,0.5698,0.5811,0.05,99.987 +10000,0.5698,0.5811,0.05,99.987 +10000,0.5698,0.5811,0.05,99.987 +10000,0.5698,0.5811,0.05,99.987 +10000,0.58109,0.59261,0.05,99.99 +10000,0.58109,0.59261,0.05,99.99 +10000,0.58109,0.59261,0.05,99.99 +10000,0.58109,0.59261,0.05,99.99 +10000,0.58109,0.59261,0.05,99.99 +10000,0.58109,0.59261,0.05,99.99 +10000,0.58109,0.59261,0.05,99.99 +10000,0.58109,0.59261,0.05,99.99 +10000,0.58109,0.59261,0.05,99.99 +10000,0.58109,0.59261,0.05,99.99 +10000,0.58109,0.59261,0.05,99.99 +10000,0.5926,0.60435,0.05,99.993 +10000,0.5926,0.60435,0.05,99.993 +10000,0.5926,0.60435,0.05,99.993 +10000,0.5926,0.60435,0.05,99.993 +10000,0.5926,0.60435,0.05,99.993 +10000,0.5926,0.60435,0.05,99.993 +10000,0.5926,0.60435,0.05,99.993 +10000,0.5926,0.60435,0.05,99.993 +10000,0.5926,0.60435,0.05,99.993 +10000,0.5926,0.60435,0.05,99.993 +10000,0.5926,0.60435,0.05,99.993 +10000,0.5926,0.60435,0.05,99.993 +10000,0.60434,0.61632,0.05,99.995 +10000,0.60434,0.61632,0.05,99.995 +10000,0.60434,0.61632,0.05,99.995 +10000,0.60434,0.61632,0.05,99.995 +10000,0.60434,0.61632,0.05,99.995 +10000,0.60434,0.61632,0.05,99.995 +10000,0.60434,0.61632,0.05,99.995 +10000,0.60434,0.61632,0.05,99.995 +10000,0.60434,0.61632,0.05,99.995 +10000,0.60434,0.61632,0.05,99.995 +10000,0.60434,0.61632,0.05,99.995 +10000,0.60434,0.61632,0.05,99.995 +10000,0.61631,0.62853,0.05,99.996 +10000,0.61631,0.62853,0.05,99.996 +10000,0.61631,0.62853,0.05,99.996 +10000,0.61631,0.62853,0.05,99.996 +10000,0.61631,0.62853,0.05,99.996 +10000,0.61631,0.62853,0.05,99.996 +10000,0.61631,0.62853,0.05,99.996 +10000,0.61631,0.62853,0.05,99.996 +10000,0.61631,0.62853,0.05,99.996 +10000,0.61631,0.62853,0.05,99.996 +10000,0.61631,0.62853,0.05,99.996 +10000,0.61631,0.62853,0.05,99.996 +10000,0.62852,0.64098,0.05,99.997 +10000,0.62852,0.64098,0.05,99.997 +10000,0.62852,0.64098,0.05,99.997 +10000,0.62852,0.64098,0.05,99.997 +10000,0.62852,0.64098,0.05,99.997 +10000,0.62852,0.64098,0.05,99.997 +10000,0.62852,0.64098,0.05,99.997 +10000,0.62852,0.64098,0.05,99.997 +10000,0.62852,0.64098,0.05,99.997 +10000,0.62852,0.64098,0.05,99.997 +10000,0.62852,0.64098,0.05,99.997 +10000,0.62852,0.64098,0.05,99.997 +10000,0.62852,0.64098,0.05,99.997 +10000,0.64097,0.65368,0.05,99.998 +10000,0.64097,0.65368,0.05,99.998 +10000,0.64097,0.65368,0.05,99.998 +10000,0.64097,0.65368,0.05,99.998 +10000,0.64097,0.65368,0.05,99.998 +10000,0.64097,0.65368,0.05,99.998 +10000,0.64097,0.65368,0.05,99.998 +10000,0.64097,0.65368,0.05,99.998 +10000,0.64097,0.65368,0.05,99.998 +10000,0.64097,0.65368,0.05,99.998 +10000,0.64097,0.65368,0.05,99.998 +10000,0.64097,0.65368,0.05,99.998 +10000,0.65367,0.66663,0.05,99.999 +10000,0.65367,0.66663,0.05,99.999 +10000,0.65367,0.66663,0.05,99.999 +10000,0.65367,0.66663,0.05,99.999 +10000,0.65367,0.66663,0.05,99.999 +10000,0.65367,0.66663,0.05,99.999 +10000,0.65367,0.66663,0.05,99.999 +10000,0.65367,0.66663,0.05,99.999 +10000,0.65367,0.66663,0.05,99.999 +10000,0.65367,0.66663,0.05,99.999 +10000,0.65367,0.66663,0.05,99.999 +10000,0.65367,0.66663,0.05,99.999 +10000,0.65367,0.66663,0.05,99.999 +10000,0.66662,0.67984,0.05,99.999 +10000,0.66662,0.67984,0.05,99.999 +10000,0.66662,0.67984,0.05,99.999 +10000,0.66662,0.67984,0.05,99.999 +10000,0.66662,0.67984,0.05,99.999 +10000,0.66662,0.67984,0.05,99.999 +10000,0.66662,0.67984,0.05,99.999 +10000,0.66662,0.67984,0.05,99.999 +10000,0.66662,0.67984,0.05,99.999 +10000,0.66662,0.67984,0.05,99.999 +10000,0.66662,0.67984,0.05,99.999 +10000,0.66662,0.67984,0.05,99.999 +10000,0.66662,0.67984,0.05,99.999 +10000,0.67983,0.69331,0.05,99.999 +10000,0.67983,0.69331,0.05,99.999 +10000,0.67983,0.69331,0.05,99.999 +10000,0.67983,0.69331,0.05,99.999 +10000,0.67983,0.69331,0.05,99.999 +10000,0.67983,0.69331,0.05,99.999 +10000,0.67983,0.69331,0.05,99.999 +10000,0.67983,0.69331,0.05,99.999 +10000,0.67983,0.69331,0.05,99.999 +10000,0.67983,0.69331,0.05,99.999 +10000,0.67983,0.69331,0.05,99.999 +10000,0.67983,0.69331,0.05,99.999 +10000,0.67983,0.69331,0.05,99.999 +10000,0.67983,0.69331,0.05,99.999 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/data_10.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/data_10.csv new file mode 100644 index 00000000000..f84f6a0a181 --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/data_10.csv @@ -0,0 +1,1002 @@ +Time,"elementCenter:0","elementCenter:1","elementCenter:2","temperature" +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,0.07071,0.072112,0.05,-19.444 +1e+05,0.07071,0.072112,0.05,-19.444 +1e+05,0.07211,0.07354,0.05,-18.353 +1e+05,0.07351,0.074968,0.05,-17.283 +1e+05,0.075155,0.076646,0.05,-16.048 +1e+05,0.075155,0.076646,0.05,-16.048 +1e+05,0.077046,0.078574,0.05,-14.662 +1e+05,0.077046,0.078574,0.05,-14.662 +1e+05,0.078936,0.080501,0.05,-13.309 +1e+05,0.078936,0.080501,0.05,-13.309 +1e+05,0.080826,0.082429,0.05,-11.987 +1e+05,0.080826,0.082429,0.05,-11.987 +1e+05,0.082716,0.084357,0.05,-10.693 +1e+05,0.082716,0.084357,0.05,-10.693 +1e+05,0.084607,0.086285,0.05,-9.4284 +1e+05,0.084607,0.086285,0.05,-9.4284 +1e+05,0.086497,0.088212,0.05,-8.1901 +1e+05,0.086497,0.088212,0.05,-8.1901 +1e+05,0.088387,0.09014,0.05,-6.9775 +1e+05,0.088387,0.09014,0.05,-6.9775 +1e+05,0.090278,0.092068,0.05,-5.7896 +1e+05,0.090278,0.092068,0.05,-5.7896 +1e+05,0.092168,0.093995,0.05,-4.6253 +1e+05,0.092168,0.093995,0.05,-4.6253 +1e+05,0.094031,0.095896,0.05,-3.5002 +1e+05,0.095885,0.097786,0.05,-2.4013 +1e+05,0.095885,0.097786,0.05,-2.4013 +1e+05,0.097776,0.099715,0.05,-1.3015 +1e+05,0.097776,0.099715,0.05,-1.3015 +1e+05,0.099704,0.10168,0.05,-0.20076 +1e+05,0.099704,0.10168,0.05,-0.20076 +1e+05,0.10167,0.10369,0.05,0.90087 +1e+05,0.10167,0.10369,0.05,0.90087 +1e+05,0.10368,0.10573,0.05,2.0034 +1e+05,0.10368,0.10573,0.05,2.0034 +1e+05,0.10572,0.10782,0.05,3.1067 +1e+05,0.10572,0.10782,0.05,3.1067 +1e+05,0.10781,0.10995,0.05,4.2109 +1e+05,0.10781,0.10995,0.05,4.2109 +1e+05,0.10993,0.11211,0.05,5.316 +1e+05,0.10993,0.11211,0.05,5.316 +1e+05,0.10993,0.11211,0.05,5.316 +1e+05,0.1121,0.11433,0.05,6.4218 +1e+05,0.1121,0.11433,0.05,6.4218 +1e+05,0.11432,0.11658,0.05,7.5284 +1e+05,0.11432,0.11658,0.05,7.5284 +1e+05,0.11657,0.11888,0.05,8.6358 +1e+05,0.11657,0.11888,0.05,8.6358 +1e+05,0.11887,0.12123,0.05,9.7439 +1e+05,0.11887,0.12123,0.05,9.7439 +1e+05,0.11887,0.12123,0.05,9.7439 +1e+05,0.12122,0.12362,0.05,10.853 +1e+05,0.12122,0.12362,0.05,10.853 +1e+05,0.12361,0.12607,0.05,11.962 +1e+05,0.12361,0.12607,0.05,11.962 +1e+05,0.12361,0.12607,0.05,11.962 +1e+05,0.12605,0.12855,0.05,13.072 +1e+05,0.12605,0.12855,0.05,13.072 +1e+05,0.12854,0.13109,0.05,14.183 +1e+05,0.12854,0.13109,0.05,14.183 +1e+05,0.12854,0.13109,0.05,14.183 +1e+05,0.13108,0.13368,0.05,15.294 +1e+05,0.13108,0.13368,0.05,15.294 +1e+05,0.13367,0.13632,0.05,16.406 +1e+05,0.13367,0.13632,0.05,16.406 +1e+05,0.13367,0.13632,0.05,16.406 +1e+05,0.13631,0.13901,0.05,17.518 +1e+05,0.13631,0.13901,0.05,17.518 +1e+05,0.13631,0.13901,0.05,17.518 +1e+05,0.139,0.14176,0.05,18.631 +1e+05,0.139,0.14176,0.05,18.631 +1e+05,0.14175,0.14456,0.05,19.744 +1e+05,0.14175,0.14456,0.05,19.744 +1e+05,0.14175,0.14456,0.05,19.744 +1e+05,0.14455,0.14742,0.05,20.858 +1e+05,0.14455,0.14742,0.05,20.858 +1e+05,0.14455,0.14742,0.05,20.858 +1e+05,0.1474,0.15033,0.05,21.972 +1e+05,0.1474,0.15033,0.05,21.972 +1e+05,0.1474,0.15033,0.05,21.972 +1e+05,0.15032,0.1533,0.05,23.086 +1e+05,0.15032,0.1533,0.05,23.086 +1e+05,0.15032,0.1533,0.05,23.086 +1e+05,0.15329,0.15633,0.05,24.201 +1e+05,0.15329,0.15633,0.05,24.201 +1e+05,0.15329,0.15633,0.05,24.201 +1e+05,0.15632,0.15942,0.05,25.315 +1e+05,0.15632,0.15942,0.05,25.315 +1e+05,0.15632,0.15942,0.05,25.315 +1e+05,0.15941,0.16257,0.05,26.43 +1e+05,0.15941,0.16257,0.05,26.43 +1e+05,0.15941,0.16257,0.05,26.43 +1e+05,0.16256,0.16578,0.05,27.544 +1e+05,0.16256,0.16578,0.05,27.544 +1e+05,0.16256,0.16578,0.05,27.544 +1e+05,0.16577,0.16906,0.05,28.659 +1e+05,0.16577,0.16906,0.05,28.659 +1e+05,0.16577,0.16906,0.05,28.659 +1e+05,0.16577,0.16906,0.05,28.659 +1e+05,0.16905,0.1724,0.05,29.774 +1e+05,0.16905,0.1724,0.05,29.774 +1e+05,0.16905,0.1724,0.05,29.774 +1e+05,0.17239,0.1758,0.05,30.888 +1e+05,0.17239,0.1758,0.05,30.888 +1e+05,0.17239,0.1758,0.05,30.888 +1e+05,0.17579,0.17928,0.05,32.002 +1e+05,0.17579,0.17928,0.05,32.002 +1e+05,0.17579,0.17928,0.05,32.002 +1e+05,0.17579,0.17928,0.05,32.002 +1e+05,0.17927,0.18282,0.05,33.116 +1e+05,0.17927,0.18282,0.05,33.116 +1e+05,0.17927,0.18282,0.05,33.116 +1e+05,0.18281,0.18644,0.05,34.229 +1e+05,0.18281,0.18644,0.05,34.229 +1e+05,0.18281,0.18644,0.05,34.229 +1e+05,0.18281,0.18644,0.05,34.229 +1e+05,0.18643,0.19013,0.05,35.342 +1e+05,0.18643,0.19013,0.05,35.342 +1e+05,0.18643,0.19013,0.05,35.342 +1e+05,0.18643,0.19013,0.05,35.342 +1e+05,0.19011,0.19388,0.05,36.454 +1e+05,0.19011,0.19388,0.05,36.454 +1e+05,0.19011,0.19388,0.05,36.454 +1e+05,0.19387,0.19772,0.05,37.566 +1e+05,0.19387,0.19772,0.05,37.566 +1e+05,0.19387,0.19772,0.05,37.566 +1e+05,0.19387,0.19772,0.05,37.566 +1e+05,0.19771,0.20163,0.05,38.676 +1e+05,0.19771,0.20163,0.05,38.676 +1e+05,0.19771,0.20163,0.05,38.676 +1e+05,0.19771,0.20163,0.05,38.676 +1e+05,0.20162,0.20562,0.05,39.786 +1e+05,0.20162,0.20562,0.05,39.786 +1e+05,0.20162,0.20562,0.05,39.786 +1e+05,0.20162,0.20562,0.05,39.786 +1e+05,0.2056,0.20968,0.05,40.895 +1e+05,0.2056,0.20968,0.05,40.895 +1e+05,0.2056,0.20968,0.05,40.895 +1e+05,0.2056,0.20968,0.05,40.895 +1e+05,0.20967,0.21383,0.05,42.002 +1e+05,0.20967,0.21383,0.05,42.002 +1e+05,0.20967,0.21383,0.05,42.002 +1e+05,0.20967,0.21383,0.05,42.002 +1e+05,0.21382,0.21806,0.05,43.108 +1e+05,0.21382,0.21806,0.05,43.108 +1e+05,0.21382,0.21806,0.05,43.108 +1e+05,0.21382,0.21806,0.05,43.108 +1e+05,0.21382,0.21806,0.05,43.108 +1e+05,0.21805,0.22237,0.05,44.213 +1e+05,0.21805,0.22237,0.05,44.213 +1e+05,0.21805,0.22237,0.05,44.213 +1e+05,0.21805,0.22237,0.05,44.213 +1e+05,0.22236,0.22677,0.05,45.316 +1e+05,0.22236,0.22677,0.05,45.316 +1e+05,0.22236,0.22677,0.05,45.316 +1e+05,0.22236,0.22677,0.05,45.316 +1e+05,0.22676,0.23125,0.05,46.418 +1e+05,0.22676,0.23125,0.05,46.418 +1e+05,0.22676,0.23125,0.05,46.418 +1e+05,0.22676,0.23125,0.05,46.418 +1e+05,0.22676,0.23125,0.05,46.418 +1e+05,0.23124,0.23583,0.05,47.517 +1e+05,0.23124,0.23583,0.05,47.517 +1e+05,0.23124,0.23583,0.05,47.517 +1e+05,0.23124,0.23583,0.05,47.517 +1e+05,0.23582,0.2405,0.05,48.615 +1e+05,0.23582,0.2405,0.05,48.615 +1e+05,0.23582,0.2405,0.05,48.615 +1e+05,0.23582,0.2405,0.05,48.615 +1e+05,0.23582,0.2405,0.05,48.615 +1e+05,0.24048,0.24525,0.05,49.71 +1e+05,0.24048,0.24525,0.05,49.71 +1e+05,0.24048,0.24525,0.05,49.71 +1e+05,0.24048,0.24525,0.05,49.71 +1e+05,0.24048,0.24525,0.05,49.71 +1e+05,0.24524,0.25011,0.05,50.804 +1e+05,0.24524,0.25011,0.05,50.804 +1e+05,0.24524,0.25011,0.05,50.804 +1e+05,0.24524,0.25011,0.05,50.804 +1e+05,0.24524,0.25011,0.05,50.804 +1e+05,0.25009,0.25505,0.05,51.894 +1e+05,0.25009,0.25505,0.05,51.894 +1e+05,0.25009,0.25505,0.05,51.894 +1e+05,0.25009,0.25505,0.05,51.894 +1e+05,0.25009,0.25505,0.05,51.894 +1e+05,0.25504,0.2601,0.05,52.982 +1e+05,0.25504,0.2601,0.05,52.982 +1e+05,0.25504,0.2601,0.05,52.982 +1e+05,0.25504,0.2601,0.05,52.982 +1e+05,0.25504,0.2601,0.05,52.982 +1e+05,0.26009,0.26525,0.05,54.067 +1e+05,0.26009,0.26525,0.05,54.067 +1e+05,0.26009,0.26525,0.05,54.067 +1e+05,0.26009,0.26525,0.05,54.067 +1e+05,0.26009,0.26525,0.05,54.067 +1e+05,0.26524,0.2705,0.05,55.149 +1e+05,0.26524,0.2705,0.05,55.149 +1e+05,0.26524,0.2705,0.05,55.149 +1e+05,0.26524,0.2705,0.05,55.149 +1e+05,0.26524,0.2705,0.05,55.149 +1e+05,0.27048,0.27585,0.05,56.227 +1e+05,0.27048,0.27585,0.05,56.227 +1e+05,0.27048,0.27585,0.05,56.227 +1e+05,0.27048,0.27585,0.05,56.227 +1e+05,0.27048,0.27585,0.05,56.227 +1e+05,0.27584,0.28131,0.05,57.302 +1e+05,0.27584,0.28131,0.05,57.302 +1e+05,0.27584,0.28131,0.05,57.302 +1e+05,0.27584,0.28131,0.05,57.302 +1e+05,0.27584,0.28131,0.05,57.302 +1e+05,0.27584,0.28131,0.05,57.302 +1e+05,0.2813,0.28687,0.05,58.373 +1e+05,0.2813,0.28687,0.05,58.373 +1e+05,0.2813,0.28687,0.05,58.373 +1e+05,0.2813,0.28687,0.05,58.373 +1e+05,0.2813,0.28687,0.05,58.373 +1e+05,0.28686,0.29255,0.05,59.44 +1e+05,0.28686,0.29255,0.05,59.44 +1e+05,0.28686,0.29255,0.05,59.44 +1e+05,0.28686,0.29255,0.05,59.44 +1e+05,0.28686,0.29255,0.05,59.44 +1e+05,0.28686,0.29255,0.05,59.44 +1e+05,0.29254,0.29834,0.05,60.503 +1e+05,0.29254,0.29834,0.05,60.503 +1e+05,0.29254,0.29834,0.05,60.503 +1e+05,0.29254,0.29834,0.05,60.503 +1e+05,0.29254,0.29834,0.05,60.503 +1e+05,0.29254,0.29834,0.05,60.503 +1e+05,0.29833,0.30425,0.05,61.562 +1e+05,0.29833,0.30425,0.05,61.562 +1e+05,0.29833,0.30425,0.05,61.562 +1e+05,0.29833,0.30425,0.05,61.562 +1e+05,0.29833,0.30425,0.05,61.562 +1e+05,0.29833,0.30425,0.05,61.562 +1e+05,0.30424,0.31027,0.05,62.615 +1e+05,0.30424,0.31027,0.05,62.615 +1e+05,0.30424,0.31027,0.05,62.615 +1e+05,0.30424,0.31027,0.05,62.615 +1e+05,0.30424,0.31027,0.05,62.615 +1e+05,0.30424,0.31027,0.05,62.615 +1e+05,0.31026,0.31641,0.05,63.664 +1e+05,0.31026,0.31641,0.05,63.664 +1e+05,0.31026,0.31641,0.05,63.664 +1e+05,0.31026,0.31641,0.05,63.664 +1e+05,0.31026,0.31641,0.05,63.664 +1e+05,0.31026,0.31641,0.05,63.664 +1e+05,0.3164,0.32267,0.05,64.708 +1e+05,0.3164,0.32267,0.05,64.708 +1e+05,0.3164,0.32267,0.05,64.708 +1e+05,0.3164,0.32267,0.05,64.708 +1e+05,0.3164,0.32267,0.05,64.708 +1e+05,0.3164,0.32267,0.05,64.708 +1e+05,0.32266,0.32906,0.05,65.746 +1e+05,0.32266,0.32906,0.05,65.746 +1e+05,0.32266,0.32906,0.05,65.746 +1e+05,0.32266,0.32906,0.05,65.746 +1e+05,0.32266,0.32906,0.05,65.746 +1e+05,0.32266,0.32906,0.05,65.746 +1e+05,0.32266,0.32906,0.05,65.746 +1e+05,0.32905,0.33558,0.05,66.778 +1e+05,0.32905,0.33558,0.05,66.778 +1e+05,0.32905,0.33558,0.05,66.778 +1e+05,0.32905,0.33558,0.05,66.778 +1e+05,0.32905,0.33558,0.05,66.778 +1e+05,0.32905,0.33558,0.05,66.778 +1e+05,0.33556,0.34222,0.05,67.804 +1e+05,0.33556,0.34222,0.05,67.804 +1e+05,0.33556,0.34222,0.05,67.804 +1e+05,0.33556,0.34222,0.05,67.804 +1e+05,0.33556,0.34222,0.05,67.804 +1e+05,0.33556,0.34222,0.05,67.804 +1e+05,0.33556,0.34222,0.05,67.804 +1e+05,0.34221,0.34899,0.05,68.824 +1e+05,0.34221,0.34899,0.05,68.824 +1e+05,0.34221,0.34899,0.05,68.824 +1e+05,0.34221,0.34899,0.05,68.824 +1e+05,0.34221,0.34899,0.05,68.824 +1e+05,0.34221,0.34899,0.05,68.824 +1e+05,0.34221,0.34899,0.05,68.824 +1e+05,0.34898,0.3559,0.05,69.838 +1e+05,0.34898,0.3559,0.05,69.838 +1e+05,0.34898,0.3559,0.05,69.838 +1e+05,0.34898,0.3559,0.05,69.838 +1e+05,0.34898,0.3559,0.05,69.838 +1e+05,0.34898,0.3559,0.05,69.838 +1e+05,0.35589,0.36295,0.05,70.844 +1e+05,0.35589,0.36295,0.05,70.844 +1e+05,0.35589,0.36295,0.05,70.844 +1e+05,0.35589,0.36295,0.05,70.844 +1e+05,0.35589,0.36295,0.05,70.844 +1e+05,0.35589,0.36295,0.05,70.844 +1e+05,0.35589,0.36295,0.05,70.844 +1e+05,0.36294,0.37013,0.05,71.844 +1e+05,0.36294,0.37013,0.05,71.844 +1e+05,0.36294,0.37013,0.05,71.844 +1e+05,0.36294,0.37013,0.05,71.844 +1e+05,0.36294,0.37013,0.05,71.844 +1e+05,0.36294,0.37013,0.05,71.844 +1e+05,0.36294,0.37013,0.05,71.844 +1e+05,0.36294,0.37013,0.05,71.844 +1e+05,0.37012,0.37746,0.05,72.835 +1e+05,0.37012,0.37746,0.05,72.835 +1e+05,0.37012,0.37746,0.05,72.835 +1e+05,0.37012,0.37746,0.05,72.835 +1e+05,0.37012,0.37746,0.05,72.835 +1e+05,0.37012,0.37746,0.05,72.835 +1e+05,0.37012,0.37746,0.05,72.835 +1e+05,0.37745,0.38494,0.05,73.819 +1e+05,0.37745,0.38494,0.05,73.819 +1e+05,0.37745,0.38494,0.05,73.819 +1e+05,0.37745,0.38494,0.05,73.819 +1e+05,0.37745,0.38494,0.05,73.819 +1e+05,0.37745,0.38494,0.05,73.819 +1e+05,0.37745,0.38494,0.05,73.819 +1e+05,0.38493,0.39256,0.05,74.795 +1e+05,0.38493,0.39256,0.05,74.795 +1e+05,0.38493,0.39256,0.05,74.795 +1e+05,0.38493,0.39256,0.05,74.795 +1e+05,0.38493,0.39256,0.05,74.795 +1e+05,0.38493,0.39256,0.05,74.795 +1e+05,0.38493,0.39256,0.05,74.795 +1e+05,0.38493,0.39256,0.05,74.795 +1e+05,0.39255,0.40033,0.05,75.763 +1e+05,0.39255,0.40033,0.05,75.763 +1e+05,0.39255,0.40033,0.05,75.763 +1e+05,0.39255,0.40033,0.05,75.763 +1e+05,0.39255,0.40033,0.05,75.763 +1e+05,0.39255,0.40033,0.05,75.763 +1e+05,0.39255,0.40033,0.05,75.763 +1e+05,0.39255,0.40033,0.05,75.763 +1e+05,0.40032,0.40826,0.05,76.722 +1e+05,0.40032,0.40826,0.05,76.722 +1e+05,0.40032,0.40826,0.05,76.722 +1e+05,0.40032,0.40826,0.05,76.722 +1e+05,0.40032,0.40826,0.05,76.722 +1e+05,0.40032,0.40826,0.05,76.722 +1e+05,0.40032,0.40826,0.05,76.722 +1e+05,0.40032,0.40826,0.05,76.722 +1e+05,0.40825,0.41634,0.05,77.672 +1e+05,0.40825,0.41634,0.05,77.672 +1e+05,0.40825,0.41634,0.05,77.672 +1e+05,0.40825,0.41634,0.05,77.672 +1e+05,0.40825,0.41634,0.05,77.672 +1e+05,0.40825,0.41634,0.05,77.672 +1e+05,0.40825,0.41634,0.05,77.672 +1e+05,0.40825,0.41634,0.05,77.672 +1e+05,0.41633,0.42459,0.05,78.614 +1e+05,0.41633,0.42459,0.05,78.614 +1e+05,0.41633,0.42459,0.05,78.614 +1e+05,0.41633,0.42459,0.05,78.614 +1e+05,0.41633,0.42459,0.05,78.614 +1e+05,0.41633,0.42459,0.05,78.614 +1e+05,0.41633,0.42459,0.05,78.614 +1e+05,0.41633,0.42459,0.05,78.614 +1e+05,0.42458,0.433,0.05,79.545 +1e+05,0.42458,0.433,0.05,79.545 +1e+05,0.42458,0.433,0.05,79.545 +1e+05,0.42458,0.433,0.05,79.545 +1e+05,0.42458,0.433,0.05,79.545 +1e+05,0.42458,0.433,0.05,79.545 +1e+05,0.42458,0.433,0.05,79.545 +1e+05,0.42458,0.433,0.05,79.545 +1e+05,0.42458,0.433,0.05,79.545 +1e+05,0.43298,0.44157,0.05,80.467 +1e+05,0.43298,0.44157,0.05,80.467 +1e+05,0.43298,0.44157,0.05,80.467 +1e+05,0.43298,0.44157,0.05,80.467 +1e+05,0.43298,0.44157,0.05,80.467 +1e+05,0.43298,0.44157,0.05,80.467 +1e+05,0.43298,0.44157,0.05,80.467 +1e+05,0.43298,0.44157,0.05,80.467 +1e+05,0.44156,0.45031,0.05,81.379 +1e+05,0.44156,0.45031,0.05,81.379 +1e+05,0.44156,0.45031,0.05,81.379 +1e+05,0.44156,0.45031,0.05,81.379 +1e+05,0.44156,0.45031,0.05,81.379 +1e+05,0.44156,0.45031,0.05,81.379 +1e+05,0.44156,0.45031,0.05,81.379 +1e+05,0.44156,0.45031,0.05,81.379 +1e+05,0.44156,0.45031,0.05,81.379 +1e+05,0.4503,0.45923,0.05,82.282 +1e+05,0.4503,0.45923,0.05,82.282 +1e+05,0.4503,0.45923,0.05,82.282 +1e+05,0.4503,0.45923,0.05,82.282 +1e+05,0.4503,0.45923,0.05,82.282 +1e+05,0.4503,0.45923,0.05,82.282 +1e+05,0.4503,0.45923,0.05,82.282 +1e+05,0.4503,0.45923,0.05,82.282 +1e+05,0.4503,0.45923,0.05,82.282 +1e+05,0.45922,0.46833,0.05,83.173 +1e+05,0.45922,0.46833,0.05,83.173 +1e+05,0.45922,0.46833,0.05,83.173 +1e+05,0.45922,0.46833,0.05,83.173 +1e+05,0.45922,0.46833,0.05,83.173 +1e+05,0.45922,0.46833,0.05,83.173 +1e+05,0.45922,0.46833,0.05,83.173 +1e+05,0.45922,0.46833,0.05,83.173 +1e+05,0.45922,0.46833,0.05,83.173 +1e+05,0.46832,0.4776,0.05,84.055 +1e+05,0.46832,0.4776,0.05,84.055 +1e+05,0.46832,0.4776,0.05,84.055 +1e+05,0.46832,0.4776,0.05,84.055 +1e+05,0.46832,0.4776,0.05,84.055 +1e+05,0.46832,0.4776,0.05,84.055 +1e+05,0.46832,0.4776,0.05,84.055 +1e+05,0.46832,0.4776,0.05,84.055 +1e+05,0.46832,0.4776,0.05,84.055 +1e+05,0.47759,0.48706,0.05,84.926 +1e+05,0.47759,0.48706,0.05,84.926 +1e+05,0.47759,0.48706,0.05,84.926 +1e+05,0.47759,0.48706,0.05,84.926 +1e+05,0.47759,0.48706,0.05,84.926 +1e+05,0.47759,0.48706,0.05,84.926 +1e+05,0.47759,0.48706,0.05,84.926 +1e+05,0.47759,0.48706,0.05,84.926 +1e+05,0.47759,0.48706,0.05,84.926 +1e+05,0.47759,0.48706,0.05,84.926 +1e+05,0.48705,0.49671,0.05,85.786 +1e+05,0.48705,0.49671,0.05,85.786 +1e+05,0.48705,0.49671,0.05,85.786 +1e+05,0.48705,0.49671,0.05,85.786 +1e+05,0.48705,0.49671,0.05,85.786 +1e+05,0.48705,0.49671,0.05,85.786 +1e+05,0.48705,0.49671,0.05,85.786 +1e+05,0.48705,0.49671,0.05,85.786 +1e+05,0.48705,0.49671,0.05,85.786 +1e+05,0.4967,0.50655,0.05,86.636 +1e+05,0.4967,0.50655,0.05,86.636 +1e+05,0.4967,0.50655,0.05,86.636 +1e+05,0.4967,0.50655,0.05,86.636 +1e+05,0.4967,0.50655,0.05,86.636 +1e+05,0.4967,0.50655,0.05,86.636 +1e+05,0.4967,0.50655,0.05,86.636 +1e+05,0.4967,0.50655,0.05,86.636 +1e+05,0.4967,0.50655,0.05,86.636 +1e+05,0.4967,0.50655,0.05,86.636 +1e+05,0.50654,0.51658,0.05,87.475 +1e+05,0.50654,0.51658,0.05,87.475 +1e+05,0.50654,0.51658,0.05,87.475 +1e+05,0.50654,0.51658,0.05,87.475 +1e+05,0.50654,0.51658,0.05,87.475 +1e+05,0.50654,0.51658,0.05,87.475 +1e+05,0.50654,0.51658,0.05,87.475 +1e+05,0.50654,0.51658,0.05,87.475 +1e+05,0.50654,0.51658,0.05,87.475 +1e+05,0.50654,0.51658,0.05,87.475 +1e+05,0.51657,0.52681,0.05,88.303 +1e+05,0.51657,0.52681,0.05,88.303 +1e+05,0.51657,0.52681,0.05,88.303 +1e+05,0.51657,0.52681,0.05,88.303 +1e+05,0.51657,0.52681,0.05,88.303 +1e+05,0.51657,0.52681,0.05,88.303 +1e+05,0.51657,0.52681,0.05,88.303 +1e+05,0.51657,0.52681,0.05,88.303 +1e+05,0.51657,0.52681,0.05,88.303 +1e+05,0.51657,0.52681,0.05,88.303 +1e+05,0.5268,0.53725,0.05,89.121 +1e+05,0.5268,0.53725,0.05,89.121 +1e+05,0.5268,0.53725,0.05,89.121 +1e+05,0.5268,0.53725,0.05,89.121 +1e+05,0.5268,0.53725,0.05,89.121 +1e+05,0.5268,0.53725,0.05,89.121 +1e+05,0.5268,0.53725,0.05,89.121 +1e+05,0.5268,0.53725,0.05,89.121 +1e+05,0.5268,0.53725,0.05,89.121 +1e+05,0.5268,0.53725,0.05,89.121 +1e+05,0.5268,0.53725,0.05,89.121 +1e+05,0.53724,0.54789,0.05,89.928 +1e+05,0.53724,0.54789,0.05,89.928 +1e+05,0.53724,0.54789,0.05,89.928 +1e+05,0.53724,0.54789,0.05,89.928 +1e+05,0.53724,0.54789,0.05,89.928 +1e+05,0.53724,0.54789,0.05,89.928 +1e+05,0.53724,0.54789,0.05,89.928 +1e+05,0.53724,0.54789,0.05,89.928 +1e+05,0.53724,0.54789,0.05,89.928 +1e+05,0.53724,0.54789,0.05,89.928 +1e+05,0.54788,0.55874,0.05,90.724 +1e+05,0.54788,0.55874,0.05,90.724 +1e+05,0.54788,0.55874,0.05,90.724 +1e+05,0.54788,0.55874,0.05,90.724 +1e+05,0.54788,0.55874,0.05,90.724 +1e+05,0.54788,0.55874,0.05,90.724 +1e+05,0.54788,0.55874,0.05,90.724 +1e+05,0.54788,0.55874,0.05,90.724 +1e+05,0.54788,0.55874,0.05,90.724 +1e+05,0.54788,0.55874,0.05,90.724 +1e+05,0.54788,0.55874,0.05,90.724 +1e+05,0.55873,0.56981,0.05,91.511 +1e+05,0.55873,0.56981,0.05,91.511 +1e+05,0.55873,0.56981,0.05,91.511 +1e+05,0.55873,0.56981,0.05,91.511 +1e+05,0.55873,0.56981,0.05,91.511 +1e+05,0.55873,0.56981,0.05,91.511 +1e+05,0.55873,0.56981,0.05,91.511 +1e+05,0.55873,0.56981,0.05,91.511 +1e+05,0.55873,0.56981,0.05,91.511 +1e+05,0.55873,0.56981,0.05,91.511 +1e+05,0.55873,0.56981,0.05,91.511 +1e+05,0.5698,0.5811,0.05,92.288 +1e+05,0.5698,0.5811,0.05,92.288 +1e+05,0.5698,0.5811,0.05,92.288 +1e+05,0.5698,0.5811,0.05,92.288 +1e+05,0.5698,0.5811,0.05,92.288 +1e+05,0.5698,0.5811,0.05,92.288 +1e+05,0.5698,0.5811,0.05,92.288 +1e+05,0.5698,0.5811,0.05,92.288 +1e+05,0.5698,0.5811,0.05,92.288 +1e+05,0.5698,0.5811,0.05,92.288 +1e+05,0.5698,0.5811,0.05,92.288 +1e+05,0.5698,0.5811,0.05,92.288 +1e+05,0.58109,0.59261,0.05,93.055 +1e+05,0.58109,0.59261,0.05,93.055 +1e+05,0.58109,0.59261,0.05,93.055 +1e+05,0.58109,0.59261,0.05,93.055 +1e+05,0.58109,0.59261,0.05,93.055 +1e+05,0.58109,0.59261,0.05,93.055 +1e+05,0.58109,0.59261,0.05,93.055 +1e+05,0.58109,0.59261,0.05,93.055 +1e+05,0.58109,0.59261,0.05,93.055 +1e+05,0.58109,0.59261,0.05,93.055 +1e+05,0.58109,0.59261,0.05,93.055 +1e+05,0.5926,0.60435,0.05,93.814 +1e+05,0.5926,0.60435,0.05,93.814 +1e+05,0.5926,0.60435,0.05,93.814 +1e+05,0.5926,0.60435,0.05,93.814 +1e+05,0.5926,0.60435,0.05,93.814 +1e+05,0.5926,0.60435,0.05,93.814 +1e+05,0.5926,0.60435,0.05,93.814 +1e+05,0.5926,0.60435,0.05,93.814 +1e+05,0.5926,0.60435,0.05,93.814 +1e+05,0.5926,0.60435,0.05,93.814 +1e+05,0.5926,0.60435,0.05,93.814 +1e+05,0.5926,0.60435,0.05,93.814 +1e+05,0.60434,0.61632,0.05,94.564 +1e+05,0.60434,0.61632,0.05,94.564 +1e+05,0.60434,0.61632,0.05,94.564 +1e+05,0.60434,0.61632,0.05,94.564 +1e+05,0.60434,0.61632,0.05,94.564 +1e+05,0.60434,0.61632,0.05,94.564 +1e+05,0.60434,0.61632,0.05,94.564 +1e+05,0.60434,0.61632,0.05,94.564 +1e+05,0.60434,0.61632,0.05,94.564 +1e+05,0.60434,0.61632,0.05,94.564 +1e+05,0.60434,0.61632,0.05,94.564 +1e+05,0.60434,0.61632,0.05,94.564 +1e+05,0.61631,0.62853,0.05,95.306 +1e+05,0.61631,0.62853,0.05,95.306 +1e+05,0.61631,0.62853,0.05,95.306 +1e+05,0.61631,0.62853,0.05,95.306 +1e+05,0.61631,0.62853,0.05,95.306 +1e+05,0.61631,0.62853,0.05,95.306 +1e+05,0.61631,0.62853,0.05,95.306 +1e+05,0.61631,0.62853,0.05,95.306 +1e+05,0.61631,0.62853,0.05,95.306 +1e+05,0.61631,0.62853,0.05,95.306 +1e+05,0.61631,0.62853,0.05,95.306 +1e+05,0.61631,0.62853,0.05,95.306 +1e+05,0.62852,0.64098,0.05,96.042 +1e+05,0.62852,0.64098,0.05,96.042 +1e+05,0.62852,0.64098,0.05,96.042 +1e+05,0.62852,0.64098,0.05,96.042 +1e+05,0.62852,0.64098,0.05,96.042 +1e+05,0.62852,0.64098,0.05,96.042 +1e+05,0.62852,0.64098,0.05,96.042 +1e+05,0.62852,0.64098,0.05,96.042 +1e+05,0.62852,0.64098,0.05,96.042 +1e+05,0.62852,0.64098,0.05,96.042 +1e+05,0.62852,0.64098,0.05,96.042 +1e+05,0.62852,0.64098,0.05,96.042 +1e+05,0.62852,0.64098,0.05,96.042 +1e+05,0.64097,0.65368,0.05,96.771 +1e+05,0.64097,0.65368,0.05,96.771 +1e+05,0.64097,0.65368,0.05,96.771 +1e+05,0.64097,0.65368,0.05,96.771 +1e+05,0.64097,0.65368,0.05,96.771 +1e+05,0.64097,0.65368,0.05,96.771 +1e+05,0.64097,0.65368,0.05,96.771 +1e+05,0.64097,0.65368,0.05,96.771 +1e+05,0.64097,0.65368,0.05,96.771 +1e+05,0.64097,0.65368,0.05,96.771 +1e+05,0.64097,0.65368,0.05,96.771 +1e+05,0.64097,0.65368,0.05,96.771 +1e+05,0.65367,0.66663,0.05,97.495 +1e+05,0.65367,0.66663,0.05,97.495 +1e+05,0.65367,0.66663,0.05,97.495 +1e+05,0.65367,0.66663,0.05,97.495 +1e+05,0.65367,0.66663,0.05,97.495 +1e+05,0.65367,0.66663,0.05,97.495 +1e+05,0.65367,0.66663,0.05,97.495 +1e+05,0.65367,0.66663,0.05,97.495 +1e+05,0.65367,0.66663,0.05,97.495 +1e+05,0.65367,0.66663,0.05,97.495 +1e+05,0.65367,0.66663,0.05,97.495 +1e+05,0.65367,0.66663,0.05,97.495 +1e+05,0.65367,0.66663,0.05,97.495 +1e+05,0.66662,0.67984,0.05,98.214 +1e+05,0.66662,0.67984,0.05,98.214 +1e+05,0.66662,0.67984,0.05,98.214 +1e+05,0.66662,0.67984,0.05,98.214 +1e+05,0.66662,0.67984,0.05,98.214 +1e+05,0.66662,0.67984,0.05,98.214 +1e+05,0.66662,0.67984,0.05,98.214 +1e+05,0.66662,0.67984,0.05,98.214 +1e+05,0.66662,0.67984,0.05,98.214 +1e+05,0.66662,0.67984,0.05,98.214 +1e+05,0.66662,0.67984,0.05,98.214 +1e+05,0.66662,0.67984,0.05,98.214 +1e+05,0.66662,0.67984,0.05,98.214 +1e+05,0.67983,0.69331,0.05,98.931 +1e+05,0.67983,0.69331,0.05,98.931 +1e+05,0.67983,0.69331,0.05,98.931 +1e+05,0.67983,0.69331,0.05,98.931 +1e+05,0.67983,0.69331,0.05,98.931 +1e+05,0.67983,0.69331,0.05,98.931 +1e+05,0.67983,0.69331,0.05,98.931 +1e+05,0.67983,0.69331,0.05,98.931 +1e+05,0.67983,0.69331,0.05,98.931 +1e+05,0.67983,0.69331,0.05,98.931 +1e+05,0.67983,0.69331,0.05,98.931 +1e+05,0.67983,0.69331,0.05,98.931 +1e+05,0.67983,0.69331,0.05,98.931 +1e+05,0.67983,0.69331,0.05,98.931 +1e+05,0.6933,0.70704,0.05,99.646 +1e+05,0.6933,0.70704,0.05,99.646 +1e+05,0.6933,0.70704,0.05,99.646 +1e+05,0.6933,0.70704,0.05,99.646 +1e+05,0.6933,0.70704,0.05,99.646 +1e+05,0.6933,0.70704,0.05,99.646 +1e+05,0.6933,0.70704,0.05,99.646 +1e+05,0.6933,0.70704,0.05,99.646 +1e+05,0.6933,0.70704,0.05,99.646 +1e+05,0.6933,0.70704,0.05,99.646 +1e+05,0.6933,0.70704,0.05,99.646 +1e+05,0.6933,0.70704,0.05,99.646 +1e+05,0.6933,0.70704,0.05,99.646 +1e+05,0.6933,0.70704,0.05,99.646 +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/data_2.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/data_2.csv new file mode 100644 index 00000000000..7645d62f469 --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/data_2.csv @@ -0,0 +1,1002 @@ +Time,"elementCenter:0","elementCenter:1","elementCenter:2","temperature" +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,0.07071,0.072112,0.05,-19.187 +20000,0.07071,0.072112,0.05,-19.187 +20000,0.07211,0.07354,0.05,-17.591 +20000,0.07351,0.074968,0.05,-16.025 +20000,0.075155,0.076646,0.05,-14.216 +20000,0.075155,0.076646,0.05,-14.216 +20000,0.077046,0.078574,0.05,-12.188 +20000,0.077046,0.078574,0.05,-12.188 +20000,0.078936,0.080501,0.05,-10.206 +20000,0.078936,0.080501,0.05,-10.206 +20000,0.080826,0.082429,0.05,-8.2679 +20000,0.080826,0.082429,0.05,-8.2679 +20000,0.082716,0.084357,0.05,-6.373 +20000,0.082716,0.084357,0.05,-6.373 +20000,0.084607,0.086285,0.05,-4.519 +20000,0.084607,0.086285,0.05,-4.519 +20000,0.086497,0.088212,0.05,-2.7043 +20000,0.086497,0.088212,0.05,-2.7043 +20000,0.088387,0.09014,0.05,-0.92736 +20000,0.088387,0.09014,0.05,-0.92736 +20000,0.090278,0.092068,0.05,0.81323 +20000,0.090278,0.092068,0.05,0.81323 +20000,0.092168,0.093995,0.05,2.5188 +20000,0.092168,0.093995,0.05,2.5188 +20000,0.094031,0.095896,0.05,4.1665 +20000,0.095885,0.097786,0.05,5.7753 +20000,0.095885,0.097786,0.05,5.7753 +20000,0.097776,0.099715,0.05,7.3847 +20000,0.097776,0.099715,0.05,7.3847 +20000,0.099704,0.10168,0.05,8.9946 +20000,0.099704,0.10168,0.05,8.9946 +20000,0.10167,0.10369,0.05,10.605 +20000,0.10167,0.10369,0.05,10.605 +20000,0.10368,0.10573,0.05,12.215 +20000,0.10368,0.10573,0.05,12.215 +20000,0.10572,0.10782,0.05,13.825 +20000,0.10572,0.10782,0.05,13.825 +20000,0.10781,0.10995,0.05,15.435 +20000,0.10781,0.10995,0.05,15.435 +20000,0.10993,0.11211,0.05,17.045 +20000,0.10993,0.11211,0.05,17.045 +20000,0.10993,0.11211,0.05,17.045 +20000,0.1121,0.11433,0.05,18.654 +20000,0.1121,0.11433,0.05,18.654 +20000,0.11432,0.11658,0.05,20.261 +20000,0.11432,0.11658,0.05,20.261 +20000,0.11657,0.11888,0.05,21.868 +20000,0.11657,0.11888,0.05,21.868 +20000,0.11887,0.12123,0.05,23.473 +20000,0.11887,0.12123,0.05,23.473 +20000,0.11887,0.12123,0.05,23.473 +20000,0.12122,0.12362,0.05,25.076 +20000,0.12122,0.12362,0.05,25.076 +20000,0.12361,0.12607,0.05,26.677 +20000,0.12361,0.12607,0.05,26.677 +20000,0.12361,0.12607,0.05,26.677 +20000,0.12605,0.12855,0.05,28.275 +20000,0.12605,0.12855,0.05,28.275 +20000,0.12854,0.13109,0.05,29.871 +20000,0.12854,0.13109,0.05,29.871 +20000,0.12854,0.13109,0.05,29.871 +20000,0.13108,0.13368,0.05,31.463 +20000,0.13108,0.13368,0.05,31.463 +20000,0.13367,0.13632,0.05,33.052 +20000,0.13367,0.13632,0.05,33.052 +20000,0.13367,0.13632,0.05,33.052 +20000,0.13631,0.13901,0.05,34.637 +20000,0.13631,0.13901,0.05,34.637 +20000,0.13631,0.13901,0.05,34.637 +20000,0.139,0.14176,0.05,36.217 +20000,0.139,0.14176,0.05,36.217 +20000,0.14175,0.14456,0.05,37.793 +20000,0.14175,0.14456,0.05,37.793 +20000,0.14175,0.14456,0.05,37.793 +20000,0.14455,0.14742,0.05,39.363 +20000,0.14455,0.14742,0.05,39.363 +20000,0.14455,0.14742,0.05,39.363 +20000,0.1474,0.15033,0.05,40.927 +20000,0.1474,0.15033,0.05,40.927 +20000,0.1474,0.15033,0.05,40.927 +20000,0.15032,0.1533,0.05,42.484 +20000,0.15032,0.1533,0.05,42.484 +20000,0.15032,0.1533,0.05,42.484 +20000,0.15329,0.15633,0.05,44.035 +20000,0.15329,0.15633,0.05,44.035 +20000,0.15329,0.15633,0.05,44.035 +20000,0.15632,0.15942,0.05,45.578 +20000,0.15632,0.15942,0.05,45.578 +20000,0.15632,0.15942,0.05,45.578 +20000,0.15941,0.16257,0.05,47.113 +20000,0.15941,0.16257,0.05,47.113 +20000,0.15941,0.16257,0.05,47.113 +20000,0.16256,0.16578,0.05,48.64 +20000,0.16256,0.16578,0.05,48.64 +20000,0.16256,0.16578,0.05,48.64 +20000,0.16577,0.16906,0.05,50.157 +20000,0.16577,0.16906,0.05,50.157 +20000,0.16577,0.16906,0.05,50.157 +20000,0.16577,0.16906,0.05,50.157 +20000,0.16905,0.1724,0.05,51.664 +20000,0.16905,0.1724,0.05,51.664 +20000,0.16905,0.1724,0.05,51.664 +20000,0.17239,0.1758,0.05,53.16 +20000,0.17239,0.1758,0.05,53.16 +20000,0.17239,0.1758,0.05,53.16 +20000,0.17579,0.17928,0.05,54.645 +20000,0.17579,0.17928,0.05,54.645 +20000,0.17579,0.17928,0.05,54.645 +20000,0.17579,0.17928,0.05,54.645 +20000,0.17927,0.18282,0.05,56.118 +20000,0.17927,0.18282,0.05,56.118 +20000,0.17927,0.18282,0.05,56.118 +20000,0.18281,0.18644,0.05,57.578 +20000,0.18281,0.18644,0.05,57.578 +20000,0.18281,0.18644,0.05,57.578 +20000,0.18281,0.18644,0.05,57.578 +20000,0.18643,0.19013,0.05,59.024 +20000,0.18643,0.19013,0.05,59.024 +20000,0.18643,0.19013,0.05,59.024 +20000,0.18643,0.19013,0.05,59.024 +20000,0.19011,0.19388,0.05,60.456 +20000,0.19011,0.19388,0.05,60.456 +20000,0.19011,0.19388,0.05,60.456 +20000,0.19387,0.19772,0.05,61.873 +20000,0.19387,0.19772,0.05,61.873 +20000,0.19387,0.19772,0.05,61.873 +20000,0.19387,0.19772,0.05,61.873 +20000,0.19771,0.20163,0.05,63.273 +20000,0.19771,0.20163,0.05,63.273 +20000,0.19771,0.20163,0.05,63.273 +20000,0.19771,0.20163,0.05,63.273 +20000,0.20162,0.20562,0.05,64.657 +20000,0.20162,0.20562,0.05,64.657 +20000,0.20162,0.20562,0.05,64.657 +20000,0.20162,0.20562,0.05,64.657 +20000,0.2056,0.20968,0.05,66.023 +20000,0.2056,0.20968,0.05,66.023 +20000,0.2056,0.20968,0.05,66.023 +20000,0.2056,0.20968,0.05,66.023 +20000,0.20967,0.21383,0.05,67.37 +20000,0.20967,0.21383,0.05,67.37 +20000,0.20967,0.21383,0.05,67.37 +20000,0.20967,0.21383,0.05,67.37 +20000,0.21382,0.21806,0.05,68.698 +20000,0.21382,0.21806,0.05,68.698 +20000,0.21382,0.21806,0.05,68.698 +20000,0.21382,0.21806,0.05,68.698 +20000,0.21382,0.21806,0.05,68.698 +20000,0.21805,0.22237,0.05,70.005 +20000,0.21805,0.22237,0.05,70.005 +20000,0.21805,0.22237,0.05,70.005 +20000,0.21805,0.22237,0.05,70.005 +20000,0.22236,0.22677,0.05,71.291 +20000,0.22236,0.22677,0.05,71.291 +20000,0.22236,0.22677,0.05,71.291 +20000,0.22236,0.22677,0.05,71.291 +20000,0.22676,0.23125,0.05,72.555 +20000,0.22676,0.23125,0.05,72.555 +20000,0.22676,0.23125,0.05,72.555 +20000,0.22676,0.23125,0.05,72.555 +20000,0.22676,0.23125,0.05,72.555 +20000,0.23124,0.23583,0.05,73.796 +20000,0.23124,0.23583,0.05,73.796 +20000,0.23124,0.23583,0.05,73.796 +20000,0.23124,0.23583,0.05,73.796 +20000,0.23582,0.2405,0.05,75.013 +20000,0.23582,0.2405,0.05,75.013 +20000,0.23582,0.2405,0.05,75.013 +20000,0.23582,0.2405,0.05,75.013 +20000,0.23582,0.2405,0.05,75.013 +20000,0.24048,0.24525,0.05,76.205 +20000,0.24048,0.24525,0.05,76.205 +20000,0.24048,0.24525,0.05,76.205 +20000,0.24048,0.24525,0.05,76.205 +20000,0.24048,0.24525,0.05,76.205 +20000,0.24524,0.25011,0.05,77.371 +20000,0.24524,0.25011,0.05,77.371 +20000,0.24524,0.25011,0.05,77.371 +20000,0.24524,0.25011,0.05,77.371 +20000,0.24524,0.25011,0.05,77.371 +20000,0.25009,0.25505,0.05,78.511 +20000,0.25009,0.25505,0.05,78.511 +20000,0.25009,0.25505,0.05,78.511 +20000,0.25009,0.25505,0.05,78.511 +20000,0.25009,0.25505,0.05,78.511 +20000,0.25504,0.2601,0.05,79.624 +20000,0.25504,0.2601,0.05,79.624 +20000,0.25504,0.2601,0.05,79.624 +20000,0.25504,0.2601,0.05,79.624 +20000,0.25504,0.2601,0.05,79.624 +20000,0.26009,0.26525,0.05,80.708 +20000,0.26009,0.26525,0.05,80.708 +20000,0.26009,0.26525,0.05,80.708 +20000,0.26009,0.26525,0.05,80.708 +20000,0.26009,0.26525,0.05,80.708 +20000,0.26524,0.2705,0.05,81.764 +20000,0.26524,0.2705,0.05,81.764 +20000,0.26524,0.2705,0.05,81.764 +20000,0.26524,0.2705,0.05,81.764 +20000,0.26524,0.2705,0.05,81.764 +20000,0.27048,0.27585,0.05,82.79 +20000,0.27048,0.27585,0.05,82.79 +20000,0.27048,0.27585,0.05,82.79 +20000,0.27048,0.27585,0.05,82.79 +20000,0.27048,0.27585,0.05,82.79 +20000,0.27584,0.28131,0.05,83.785 +20000,0.27584,0.28131,0.05,83.785 +20000,0.27584,0.28131,0.05,83.785 +20000,0.27584,0.28131,0.05,83.785 +20000,0.27584,0.28131,0.05,83.785 +20000,0.27584,0.28131,0.05,83.785 +20000,0.2813,0.28687,0.05,84.75 +20000,0.2813,0.28687,0.05,84.75 +20000,0.2813,0.28687,0.05,84.75 +20000,0.2813,0.28687,0.05,84.75 +20000,0.2813,0.28687,0.05,84.75 +20000,0.28686,0.29255,0.05,85.684 +20000,0.28686,0.29255,0.05,85.684 +20000,0.28686,0.29255,0.05,85.684 +20000,0.28686,0.29255,0.05,85.684 +20000,0.28686,0.29255,0.05,85.684 +20000,0.28686,0.29255,0.05,85.684 +20000,0.29254,0.29834,0.05,86.585 +20000,0.29254,0.29834,0.05,86.585 +20000,0.29254,0.29834,0.05,86.585 +20000,0.29254,0.29834,0.05,86.585 +20000,0.29254,0.29834,0.05,86.585 +20000,0.29254,0.29834,0.05,86.585 +20000,0.29833,0.30425,0.05,87.454 +20000,0.29833,0.30425,0.05,87.454 +20000,0.29833,0.30425,0.05,87.454 +20000,0.29833,0.30425,0.05,87.454 +20000,0.29833,0.30425,0.05,87.454 +20000,0.29833,0.30425,0.05,87.454 +20000,0.30424,0.31027,0.05,88.291 +20000,0.30424,0.31027,0.05,88.291 +20000,0.30424,0.31027,0.05,88.291 +20000,0.30424,0.31027,0.05,88.291 +20000,0.30424,0.31027,0.05,88.291 +20000,0.30424,0.31027,0.05,88.291 +20000,0.31026,0.31641,0.05,89.094 +20000,0.31026,0.31641,0.05,89.094 +20000,0.31026,0.31641,0.05,89.094 +20000,0.31026,0.31641,0.05,89.094 +20000,0.31026,0.31641,0.05,89.094 +20000,0.31026,0.31641,0.05,89.094 +20000,0.3164,0.32267,0.05,89.864 +20000,0.3164,0.32267,0.05,89.864 +20000,0.3164,0.32267,0.05,89.864 +20000,0.3164,0.32267,0.05,89.864 +20000,0.3164,0.32267,0.05,89.864 +20000,0.3164,0.32267,0.05,89.864 +20000,0.32266,0.32906,0.05,90.6 +20000,0.32266,0.32906,0.05,90.6 +20000,0.32266,0.32906,0.05,90.6 +20000,0.32266,0.32906,0.05,90.6 +20000,0.32266,0.32906,0.05,90.6 +20000,0.32266,0.32906,0.05,90.6 +20000,0.32266,0.32906,0.05,90.6 +20000,0.32905,0.33558,0.05,91.303 +20000,0.32905,0.33558,0.05,91.303 +20000,0.32905,0.33558,0.05,91.303 +20000,0.32905,0.33558,0.05,91.303 +20000,0.32905,0.33558,0.05,91.303 +20000,0.32905,0.33558,0.05,91.303 +20000,0.33556,0.34222,0.05,91.973 +20000,0.33556,0.34222,0.05,91.973 +20000,0.33556,0.34222,0.05,91.973 +20000,0.33556,0.34222,0.05,91.973 +20000,0.33556,0.34222,0.05,91.973 +20000,0.33556,0.34222,0.05,91.973 +20000,0.33556,0.34222,0.05,91.973 +20000,0.34221,0.34899,0.05,92.609 +20000,0.34221,0.34899,0.05,92.609 +20000,0.34221,0.34899,0.05,92.609 +20000,0.34221,0.34899,0.05,92.609 +20000,0.34221,0.34899,0.05,92.609 +20000,0.34221,0.34899,0.05,92.609 +20000,0.34221,0.34899,0.05,92.609 +20000,0.34898,0.3559,0.05,93.212 +20000,0.34898,0.3559,0.05,93.212 +20000,0.34898,0.3559,0.05,93.212 +20000,0.34898,0.3559,0.05,93.212 +20000,0.34898,0.3559,0.05,93.212 +20000,0.34898,0.3559,0.05,93.212 +20000,0.35589,0.36295,0.05,93.782 +20000,0.35589,0.36295,0.05,93.782 +20000,0.35589,0.36295,0.05,93.782 +20000,0.35589,0.36295,0.05,93.782 +20000,0.35589,0.36295,0.05,93.782 +20000,0.35589,0.36295,0.05,93.782 +20000,0.35589,0.36295,0.05,93.782 +20000,0.36294,0.37013,0.05,94.32 +20000,0.36294,0.37013,0.05,94.32 +20000,0.36294,0.37013,0.05,94.32 +20000,0.36294,0.37013,0.05,94.32 +20000,0.36294,0.37013,0.05,94.32 +20000,0.36294,0.37013,0.05,94.32 +20000,0.36294,0.37013,0.05,94.32 +20000,0.36294,0.37013,0.05,94.32 +20000,0.37012,0.37746,0.05,94.825 +20000,0.37012,0.37746,0.05,94.825 +20000,0.37012,0.37746,0.05,94.825 +20000,0.37012,0.37746,0.05,94.825 +20000,0.37012,0.37746,0.05,94.825 +20000,0.37012,0.37746,0.05,94.825 +20000,0.37012,0.37746,0.05,94.825 +20000,0.37745,0.38494,0.05,95.3 +20000,0.37745,0.38494,0.05,95.3 +20000,0.37745,0.38494,0.05,95.3 +20000,0.37745,0.38494,0.05,95.3 +20000,0.37745,0.38494,0.05,95.3 +20000,0.37745,0.38494,0.05,95.3 +20000,0.37745,0.38494,0.05,95.3 +20000,0.38493,0.39256,0.05,95.743 +20000,0.38493,0.39256,0.05,95.743 +20000,0.38493,0.39256,0.05,95.743 +20000,0.38493,0.39256,0.05,95.743 +20000,0.38493,0.39256,0.05,95.743 +20000,0.38493,0.39256,0.05,95.743 +20000,0.38493,0.39256,0.05,95.743 +20000,0.38493,0.39256,0.05,95.743 +20000,0.39255,0.40033,0.05,96.157 +20000,0.39255,0.40033,0.05,96.157 +20000,0.39255,0.40033,0.05,96.157 +20000,0.39255,0.40033,0.05,96.157 +20000,0.39255,0.40033,0.05,96.157 +20000,0.39255,0.40033,0.05,96.157 +20000,0.39255,0.40033,0.05,96.157 +20000,0.39255,0.40033,0.05,96.157 +20000,0.40032,0.40826,0.05,96.541 +20000,0.40032,0.40826,0.05,96.541 +20000,0.40032,0.40826,0.05,96.541 +20000,0.40032,0.40826,0.05,96.541 +20000,0.40032,0.40826,0.05,96.541 +20000,0.40032,0.40826,0.05,96.541 +20000,0.40032,0.40826,0.05,96.541 +20000,0.40032,0.40826,0.05,96.541 +20000,0.40825,0.41634,0.05,96.898 +20000,0.40825,0.41634,0.05,96.898 +20000,0.40825,0.41634,0.05,96.898 +20000,0.40825,0.41634,0.05,96.898 +20000,0.40825,0.41634,0.05,96.898 +20000,0.40825,0.41634,0.05,96.898 +20000,0.40825,0.41634,0.05,96.898 +20000,0.40825,0.41634,0.05,96.898 +20000,0.41633,0.42459,0.05,97.227 +20000,0.41633,0.42459,0.05,97.227 +20000,0.41633,0.42459,0.05,97.227 +20000,0.41633,0.42459,0.05,97.227 +20000,0.41633,0.42459,0.05,97.227 +20000,0.41633,0.42459,0.05,97.227 +20000,0.41633,0.42459,0.05,97.227 +20000,0.41633,0.42459,0.05,97.227 +20000,0.42458,0.433,0.05,97.53 +20000,0.42458,0.433,0.05,97.53 +20000,0.42458,0.433,0.05,97.53 +20000,0.42458,0.433,0.05,97.53 +20000,0.42458,0.433,0.05,97.53 +20000,0.42458,0.433,0.05,97.53 +20000,0.42458,0.433,0.05,97.53 +20000,0.42458,0.433,0.05,97.53 +20000,0.42458,0.433,0.05,97.53 +20000,0.43298,0.44157,0.05,97.807 +20000,0.43298,0.44157,0.05,97.807 +20000,0.43298,0.44157,0.05,97.807 +20000,0.43298,0.44157,0.05,97.807 +20000,0.43298,0.44157,0.05,97.807 +20000,0.43298,0.44157,0.05,97.807 +20000,0.43298,0.44157,0.05,97.807 +20000,0.43298,0.44157,0.05,97.807 +20000,0.44156,0.45031,0.05,98.061 +20000,0.44156,0.45031,0.05,98.061 +20000,0.44156,0.45031,0.05,98.061 +20000,0.44156,0.45031,0.05,98.061 +20000,0.44156,0.45031,0.05,98.061 +20000,0.44156,0.45031,0.05,98.061 +20000,0.44156,0.45031,0.05,98.061 +20000,0.44156,0.45031,0.05,98.061 +20000,0.44156,0.45031,0.05,98.061 +20000,0.4503,0.45923,0.05,98.292 +20000,0.4503,0.45923,0.05,98.292 +20000,0.4503,0.45923,0.05,98.292 +20000,0.4503,0.45923,0.05,98.292 +20000,0.4503,0.45923,0.05,98.292 +20000,0.4503,0.45923,0.05,98.292 +20000,0.4503,0.45923,0.05,98.292 +20000,0.4503,0.45923,0.05,98.292 +20000,0.4503,0.45923,0.05,98.292 +20000,0.45922,0.46833,0.05,98.502 +20000,0.45922,0.46833,0.05,98.502 +20000,0.45922,0.46833,0.05,98.502 +20000,0.45922,0.46833,0.05,98.502 +20000,0.45922,0.46833,0.05,98.502 +20000,0.45922,0.46833,0.05,98.502 +20000,0.45922,0.46833,0.05,98.502 +20000,0.45922,0.46833,0.05,98.502 +20000,0.45922,0.46833,0.05,98.502 +20000,0.46832,0.4776,0.05,98.691 +20000,0.46832,0.4776,0.05,98.691 +20000,0.46832,0.4776,0.05,98.691 +20000,0.46832,0.4776,0.05,98.691 +20000,0.46832,0.4776,0.05,98.691 +20000,0.46832,0.4776,0.05,98.691 +20000,0.46832,0.4776,0.05,98.691 +20000,0.46832,0.4776,0.05,98.691 +20000,0.46832,0.4776,0.05,98.691 +20000,0.47759,0.48706,0.05,98.861 +20000,0.47759,0.48706,0.05,98.861 +20000,0.47759,0.48706,0.05,98.861 +20000,0.47759,0.48706,0.05,98.861 +20000,0.47759,0.48706,0.05,98.861 +20000,0.47759,0.48706,0.05,98.861 +20000,0.47759,0.48706,0.05,98.861 +20000,0.47759,0.48706,0.05,98.861 +20000,0.47759,0.48706,0.05,98.861 +20000,0.47759,0.48706,0.05,98.861 +20000,0.48705,0.49671,0.05,99.013 +20000,0.48705,0.49671,0.05,99.013 +20000,0.48705,0.49671,0.05,99.013 +20000,0.48705,0.49671,0.05,99.013 +20000,0.48705,0.49671,0.05,99.013 +20000,0.48705,0.49671,0.05,99.013 +20000,0.48705,0.49671,0.05,99.013 +20000,0.48705,0.49671,0.05,99.013 +20000,0.48705,0.49671,0.05,99.013 +20000,0.4967,0.50655,0.05,99.149 +20000,0.4967,0.50655,0.05,99.149 +20000,0.4967,0.50655,0.05,99.149 +20000,0.4967,0.50655,0.05,99.149 +20000,0.4967,0.50655,0.05,99.149 +20000,0.4967,0.50655,0.05,99.149 +20000,0.4967,0.50655,0.05,99.149 +20000,0.4967,0.50655,0.05,99.149 +20000,0.4967,0.50655,0.05,99.149 +20000,0.4967,0.50655,0.05,99.149 +20000,0.50654,0.51658,0.05,99.27 +20000,0.50654,0.51658,0.05,99.27 +20000,0.50654,0.51658,0.05,99.27 +20000,0.50654,0.51658,0.05,99.27 +20000,0.50654,0.51658,0.05,99.27 +20000,0.50654,0.51658,0.05,99.27 +20000,0.50654,0.51658,0.05,99.27 +20000,0.50654,0.51658,0.05,99.27 +20000,0.50654,0.51658,0.05,99.27 +20000,0.50654,0.51658,0.05,99.27 +20000,0.51657,0.52681,0.05,99.377 +20000,0.51657,0.52681,0.05,99.377 +20000,0.51657,0.52681,0.05,99.377 +20000,0.51657,0.52681,0.05,99.377 +20000,0.51657,0.52681,0.05,99.377 +20000,0.51657,0.52681,0.05,99.377 +20000,0.51657,0.52681,0.05,99.377 +20000,0.51657,0.52681,0.05,99.377 +20000,0.51657,0.52681,0.05,99.377 +20000,0.51657,0.52681,0.05,99.377 +20000,0.5268,0.53725,0.05,99.47 +20000,0.5268,0.53725,0.05,99.47 +20000,0.5268,0.53725,0.05,99.47 +20000,0.5268,0.53725,0.05,99.47 +20000,0.5268,0.53725,0.05,99.47 +20000,0.5268,0.53725,0.05,99.47 +20000,0.5268,0.53725,0.05,99.47 +20000,0.5268,0.53725,0.05,99.47 +20000,0.5268,0.53725,0.05,99.47 +20000,0.5268,0.53725,0.05,99.47 +20000,0.5268,0.53725,0.05,99.47 +20000,0.53724,0.54789,0.05,99.552 +20000,0.53724,0.54789,0.05,99.552 +20000,0.53724,0.54789,0.05,99.552 +20000,0.53724,0.54789,0.05,99.552 +20000,0.53724,0.54789,0.05,99.552 +20000,0.53724,0.54789,0.05,99.552 +20000,0.53724,0.54789,0.05,99.552 +20000,0.53724,0.54789,0.05,99.552 +20000,0.53724,0.54789,0.05,99.552 +20000,0.53724,0.54789,0.05,99.552 +20000,0.54788,0.55874,0.05,99.624 +20000,0.54788,0.55874,0.05,99.624 +20000,0.54788,0.55874,0.05,99.624 +20000,0.54788,0.55874,0.05,99.624 +20000,0.54788,0.55874,0.05,99.624 +20000,0.54788,0.55874,0.05,99.624 +20000,0.54788,0.55874,0.05,99.624 +20000,0.54788,0.55874,0.05,99.624 +20000,0.54788,0.55874,0.05,99.624 +20000,0.54788,0.55874,0.05,99.624 +20000,0.54788,0.55874,0.05,99.624 +20000,0.55873,0.56981,0.05,99.686 +20000,0.55873,0.56981,0.05,99.686 +20000,0.55873,0.56981,0.05,99.686 +20000,0.55873,0.56981,0.05,99.686 +20000,0.55873,0.56981,0.05,99.686 +20000,0.55873,0.56981,0.05,99.686 +20000,0.55873,0.56981,0.05,99.686 +20000,0.55873,0.56981,0.05,99.686 +20000,0.55873,0.56981,0.05,99.686 +20000,0.55873,0.56981,0.05,99.686 +20000,0.55873,0.56981,0.05,99.686 +20000,0.5698,0.5811,0.05,99.739 +20000,0.5698,0.5811,0.05,99.739 +20000,0.5698,0.5811,0.05,99.739 +20000,0.5698,0.5811,0.05,99.739 +20000,0.5698,0.5811,0.05,99.739 +20000,0.5698,0.5811,0.05,99.739 +20000,0.5698,0.5811,0.05,99.739 +20000,0.5698,0.5811,0.05,99.739 +20000,0.5698,0.5811,0.05,99.739 +20000,0.5698,0.5811,0.05,99.739 +20000,0.5698,0.5811,0.05,99.739 +20000,0.5698,0.5811,0.05,99.739 +20000,0.58109,0.59261,0.05,99.785 +20000,0.58109,0.59261,0.05,99.785 +20000,0.58109,0.59261,0.05,99.785 +20000,0.58109,0.59261,0.05,99.785 +20000,0.58109,0.59261,0.05,99.785 +20000,0.58109,0.59261,0.05,99.785 +20000,0.58109,0.59261,0.05,99.785 +20000,0.58109,0.59261,0.05,99.785 +20000,0.58109,0.59261,0.05,99.785 +20000,0.58109,0.59261,0.05,99.785 +20000,0.58109,0.59261,0.05,99.785 +20000,0.5926,0.60435,0.05,99.825 +20000,0.5926,0.60435,0.05,99.825 +20000,0.5926,0.60435,0.05,99.825 +20000,0.5926,0.60435,0.05,99.825 +20000,0.5926,0.60435,0.05,99.825 +20000,0.5926,0.60435,0.05,99.825 +20000,0.5926,0.60435,0.05,99.825 +20000,0.5926,0.60435,0.05,99.825 +20000,0.5926,0.60435,0.05,99.825 +20000,0.5926,0.60435,0.05,99.825 +20000,0.5926,0.60435,0.05,99.825 +20000,0.5926,0.60435,0.05,99.825 +20000,0.60434,0.61632,0.05,99.858 +20000,0.60434,0.61632,0.05,99.858 +20000,0.60434,0.61632,0.05,99.858 +20000,0.60434,0.61632,0.05,99.858 +20000,0.60434,0.61632,0.05,99.858 +20000,0.60434,0.61632,0.05,99.858 +20000,0.60434,0.61632,0.05,99.858 +20000,0.60434,0.61632,0.05,99.858 +20000,0.60434,0.61632,0.05,99.858 +20000,0.60434,0.61632,0.05,99.858 +20000,0.60434,0.61632,0.05,99.858 +20000,0.60434,0.61632,0.05,99.858 +20000,0.61631,0.62853,0.05,99.887 +20000,0.61631,0.62853,0.05,99.887 +20000,0.61631,0.62853,0.05,99.887 +20000,0.61631,0.62853,0.05,99.887 +20000,0.61631,0.62853,0.05,99.887 +20000,0.61631,0.62853,0.05,99.887 +20000,0.61631,0.62853,0.05,99.887 +20000,0.61631,0.62853,0.05,99.887 +20000,0.61631,0.62853,0.05,99.887 +20000,0.61631,0.62853,0.05,99.887 +20000,0.61631,0.62853,0.05,99.887 +20000,0.61631,0.62853,0.05,99.887 +20000,0.62852,0.64098,0.05,99.911 +20000,0.62852,0.64098,0.05,99.911 +20000,0.62852,0.64098,0.05,99.911 +20000,0.62852,0.64098,0.05,99.911 +20000,0.62852,0.64098,0.05,99.911 +20000,0.62852,0.64098,0.05,99.911 +20000,0.62852,0.64098,0.05,99.911 +20000,0.62852,0.64098,0.05,99.911 +20000,0.62852,0.64098,0.05,99.911 +20000,0.62852,0.64098,0.05,99.911 +20000,0.62852,0.64098,0.05,99.911 +20000,0.62852,0.64098,0.05,99.911 +20000,0.62852,0.64098,0.05,99.911 +20000,0.64097,0.65368,0.05,99.932 +20000,0.64097,0.65368,0.05,99.932 +20000,0.64097,0.65368,0.05,99.932 +20000,0.64097,0.65368,0.05,99.932 +20000,0.64097,0.65368,0.05,99.932 +20000,0.64097,0.65368,0.05,99.932 +20000,0.64097,0.65368,0.05,99.932 +20000,0.64097,0.65368,0.05,99.932 +20000,0.64097,0.65368,0.05,99.932 +20000,0.64097,0.65368,0.05,99.932 +20000,0.64097,0.65368,0.05,99.932 +20000,0.64097,0.65368,0.05,99.932 +20000,0.65367,0.66663,0.05,99.95 +20000,0.65367,0.66663,0.05,99.95 +20000,0.65367,0.66663,0.05,99.95 +20000,0.65367,0.66663,0.05,99.95 +20000,0.65367,0.66663,0.05,99.95 +20000,0.65367,0.66663,0.05,99.95 +20000,0.65367,0.66663,0.05,99.95 +20000,0.65367,0.66663,0.05,99.95 +20000,0.65367,0.66663,0.05,99.95 +20000,0.65367,0.66663,0.05,99.95 +20000,0.65367,0.66663,0.05,99.95 +20000,0.65367,0.66663,0.05,99.95 +20000,0.65367,0.66663,0.05,99.95 +20000,0.66662,0.67984,0.05,99.966 +20000,0.66662,0.67984,0.05,99.966 +20000,0.66662,0.67984,0.05,99.966 +20000,0.66662,0.67984,0.05,99.966 +20000,0.66662,0.67984,0.05,99.966 +20000,0.66662,0.67984,0.05,99.966 +20000,0.66662,0.67984,0.05,99.966 +20000,0.66662,0.67984,0.05,99.966 +20000,0.66662,0.67984,0.05,99.966 +20000,0.66662,0.67984,0.05,99.966 +20000,0.66662,0.67984,0.05,99.966 +20000,0.66662,0.67984,0.05,99.966 +20000,0.66662,0.67984,0.05,99.966 +20000,0.67983,0.69331,0.05,99.98 +20000,0.67983,0.69331,0.05,99.98 +20000,0.67983,0.69331,0.05,99.98 +20000,0.67983,0.69331,0.05,99.98 +20000,0.67983,0.69331,0.05,99.98 +20000,0.67983,0.69331,0.05,99.98 +20000,0.67983,0.69331,0.05,99.98 +20000,0.67983,0.69331,0.05,99.98 +20000,0.67983,0.69331,0.05,99.98 +20000,0.67983,0.69331,0.05,99.98 +20000,0.67983,0.69331,0.05,99.98 +20000,0.67983,0.69331,0.05,99.98 +20000,0.67983,0.69331,0.05,99.98 +20000,0.67983,0.69331,0.05,99.98 +20000,0.6933,0.70704,0.05,99.994 +20000,0.6933,0.70704,0.05,99.994 +20000,0.6933,0.70704,0.05,99.994 +20000,0.6933,0.70704,0.05,99.994 +20000,0.6933,0.70704,0.05,99.994 +20000,0.6933,0.70704,0.05,99.994 +20000,0.6933,0.70704,0.05,99.994 +20000,0.6933,0.70704,0.05,99.994 +20000,0.6933,0.70704,0.05,99.994 +20000,0.6933,0.70704,0.05,99.994 +20000,0.6933,0.70704,0.05,99.994 +20000,0.6933,0.70704,0.05,99.994 +20000,0.6933,0.70704,0.05,99.994 +20000,0.6933,0.70704,0.05,99.994 +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/data_5.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/data_5.csv new file mode 100644 index 00000000000..03f9eb13744 --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/data_5.csv @@ -0,0 +1,1002 @@ +Time,"elementCenter:0","elementCenter:1","elementCenter:2","temperature" +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,0.07071,0.072112,0.05,-19.355 +50000,0.07071,0.072112,0.05,-19.355 +50000,0.07211,0.07354,0.05,-18.09 +50000,0.07351,0.074968,0.05,-16.848 +50000,0.075155,0.076646,0.05,-15.415 +50000,0.075155,0.076646,0.05,-15.415 +50000,0.077046,0.078574,0.05,-13.807 +50000,0.077046,0.078574,0.05,-13.807 +50000,0.078936,0.080501,0.05,-12.236 +50000,0.078936,0.080501,0.05,-12.236 +50000,0.080826,0.082429,0.05,-10.701 +50000,0.080826,0.082429,0.05,-10.701 +50000,0.082716,0.084357,0.05,-9.2003 +50000,0.082716,0.084357,0.05,-9.2003 +50000,0.084607,0.086285,0.05,-7.7316 +50000,0.084607,0.086285,0.05,-7.7316 +50000,0.086497,0.088212,0.05,-6.294 +50000,0.086497,0.088212,0.05,-6.294 +50000,0.088387,0.09014,0.05,-4.8861 +50000,0.088387,0.09014,0.05,-4.8861 +50000,0.090278,0.092068,0.05,-3.5069 +50000,0.090278,0.092068,0.05,-3.5069 +50000,0.092168,0.093995,0.05,-2.1551 +50000,0.092168,0.093995,0.05,-2.1551 +50000,0.094031,0.095896,0.05,-0.84874 +50000,0.095885,0.097786,0.05,0.42708 +50000,0.095885,0.097786,0.05,0.42708 +50000,0.097776,0.099715,0.05,1.7039 +50000,0.097776,0.099715,0.05,1.7039 +50000,0.099704,0.10168,0.05,2.9817 +50000,0.099704,0.10168,0.05,2.9817 +50000,0.10167,0.10369,0.05,4.2604 +50000,0.10167,0.10369,0.05,4.2604 +50000,0.10368,0.10573,0.05,5.54 +50000,0.10368,0.10573,0.05,5.54 +50000,0.10572,0.10782,0.05,6.8204 +50000,0.10572,0.10782,0.05,6.8204 +50000,0.10781,0.10995,0.05,8.1016 +50000,0.10781,0.10995,0.05,8.1016 +50000,0.10993,0.11211,0.05,9.3835 +50000,0.10993,0.11211,0.05,9.3835 +50000,0.10993,0.11211,0.05,9.3835 +50000,0.1121,0.11433,0.05,10.666 +50000,0.1121,0.11433,0.05,10.666 +50000,0.11432,0.11658,0.05,11.949 +50000,0.11432,0.11658,0.05,11.949 +50000,0.11657,0.11888,0.05,13.233 +50000,0.11657,0.11888,0.05,13.233 +50000,0.11887,0.12123,0.05,14.517 +50000,0.11887,0.12123,0.05,14.517 +50000,0.11887,0.12123,0.05,14.517 +50000,0.12122,0.12362,0.05,15.801 +50000,0.12122,0.12362,0.05,15.801 +50000,0.12361,0.12607,0.05,17.086 +50000,0.12361,0.12607,0.05,17.086 +50000,0.12361,0.12607,0.05,17.086 +50000,0.12605,0.12855,0.05,18.371 +50000,0.12605,0.12855,0.05,18.371 +50000,0.12854,0.13109,0.05,19.655 +50000,0.12854,0.13109,0.05,19.655 +50000,0.12854,0.13109,0.05,19.655 +50000,0.13108,0.13368,0.05,20.94 +50000,0.13108,0.13368,0.05,20.94 +50000,0.13367,0.13632,0.05,22.225 +50000,0.13367,0.13632,0.05,22.225 +50000,0.13367,0.13632,0.05,22.225 +50000,0.13631,0.13901,0.05,23.51 +50000,0.13631,0.13901,0.05,23.51 +50000,0.13631,0.13901,0.05,23.51 +50000,0.139,0.14176,0.05,24.794 +50000,0.139,0.14176,0.05,24.794 +50000,0.14175,0.14456,0.05,26.077 +50000,0.14175,0.14456,0.05,26.077 +50000,0.14175,0.14456,0.05,26.077 +50000,0.14455,0.14742,0.05,27.36 +50000,0.14455,0.14742,0.05,27.36 +50000,0.14455,0.14742,0.05,27.36 +50000,0.1474,0.15033,0.05,28.642 +50000,0.1474,0.15033,0.05,28.642 +50000,0.1474,0.15033,0.05,28.642 +50000,0.15032,0.1533,0.05,29.924 +50000,0.15032,0.1533,0.05,29.924 +50000,0.15032,0.1533,0.05,29.924 +50000,0.15329,0.15633,0.05,31.204 +50000,0.15329,0.15633,0.05,31.204 +50000,0.15329,0.15633,0.05,31.204 +50000,0.15632,0.15942,0.05,32.483 +50000,0.15632,0.15942,0.05,32.483 +50000,0.15632,0.15942,0.05,32.483 +50000,0.15941,0.16257,0.05,33.761 +50000,0.15941,0.16257,0.05,33.761 +50000,0.15941,0.16257,0.05,33.761 +50000,0.16256,0.16578,0.05,35.037 +50000,0.16256,0.16578,0.05,35.037 +50000,0.16256,0.16578,0.05,35.037 +50000,0.16577,0.16906,0.05,36.311 +50000,0.16577,0.16906,0.05,36.311 +50000,0.16577,0.16906,0.05,36.311 +50000,0.16577,0.16906,0.05,36.311 +50000,0.16905,0.1724,0.05,37.583 +50000,0.16905,0.1724,0.05,37.583 +50000,0.16905,0.1724,0.05,37.583 +50000,0.17239,0.1758,0.05,38.853 +50000,0.17239,0.1758,0.05,38.853 +50000,0.17239,0.1758,0.05,38.853 +50000,0.17579,0.17928,0.05,40.12 +50000,0.17579,0.17928,0.05,40.12 +50000,0.17579,0.17928,0.05,40.12 +50000,0.17579,0.17928,0.05,40.12 +50000,0.17927,0.18282,0.05,41.385 +50000,0.17927,0.18282,0.05,41.385 +50000,0.17927,0.18282,0.05,41.385 +50000,0.18281,0.18644,0.05,42.647 +50000,0.18281,0.18644,0.05,42.647 +50000,0.18281,0.18644,0.05,42.647 +50000,0.18281,0.18644,0.05,42.647 +50000,0.18643,0.19013,0.05,43.906 +50000,0.18643,0.19013,0.05,43.906 +50000,0.18643,0.19013,0.05,43.906 +50000,0.18643,0.19013,0.05,43.906 +50000,0.19011,0.19388,0.05,45.161 +50000,0.19011,0.19388,0.05,45.161 +50000,0.19011,0.19388,0.05,45.161 +50000,0.19387,0.19772,0.05,46.413 +50000,0.19387,0.19772,0.05,46.413 +50000,0.19387,0.19772,0.05,46.413 +50000,0.19387,0.19772,0.05,46.413 +50000,0.19771,0.20163,0.05,47.66 +50000,0.19771,0.20163,0.05,47.66 +50000,0.19771,0.20163,0.05,47.66 +50000,0.19771,0.20163,0.05,47.66 +50000,0.20162,0.20562,0.05,48.904 +50000,0.20162,0.20562,0.05,48.904 +50000,0.20162,0.20562,0.05,48.904 +50000,0.20162,0.20562,0.05,48.904 +50000,0.2056,0.20968,0.05,50.142 +50000,0.2056,0.20968,0.05,50.142 +50000,0.2056,0.20968,0.05,50.142 +50000,0.2056,0.20968,0.05,50.142 +50000,0.20967,0.21383,0.05,51.376 +50000,0.20967,0.21383,0.05,51.376 +50000,0.20967,0.21383,0.05,51.376 +50000,0.20967,0.21383,0.05,51.376 +50000,0.21382,0.21806,0.05,52.604 +50000,0.21382,0.21806,0.05,52.604 +50000,0.21382,0.21806,0.05,52.604 +50000,0.21382,0.21806,0.05,52.604 +50000,0.21382,0.21806,0.05,52.604 +50000,0.21805,0.22237,0.05,53.826 +50000,0.21805,0.22237,0.05,53.826 +50000,0.21805,0.22237,0.05,53.826 +50000,0.21805,0.22237,0.05,53.826 +50000,0.22236,0.22677,0.05,55.043 +50000,0.22236,0.22677,0.05,55.043 +50000,0.22236,0.22677,0.05,55.043 +50000,0.22236,0.22677,0.05,55.043 +50000,0.22676,0.23125,0.05,56.253 +50000,0.22676,0.23125,0.05,56.253 +50000,0.22676,0.23125,0.05,56.253 +50000,0.22676,0.23125,0.05,56.253 +50000,0.22676,0.23125,0.05,56.253 +50000,0.23124,0.23583,0.05,57.456 +50000,0.23124,0.23583,0.05,57.456 +50000,0.23124,0.23583,0.05,57.456 +50000,0.23124,0.23583,0.05,57.456 +50000,0.23582,0.2405,0.05,58.652 +50000,0.23582,0.2405,0.05,58.652 +50000,0.23582,0.2405,0.05,58.652 +50000,0.23582,0.2405,0.05,58.652 +50000,0.23582,0.2405,0.05,58.652 +50000,0.24048,0.24525,0.05,59.84 +50000,0.24048,0.24525,0.05,59.84 +50000,0.24048,0.24525,0.05,59.84 +50000,0.24048,0.24525,0.05,59.84 +50000,0.24048,0.24525,0.05,59.84 +50000,0.24524,0.25011,0.05,61.019 +50000,0.24524,0.25011,0.05,61.019 +50000,0.24524,0.25011,0.05,61.019 +50000,0.24524,0.25011,0.05,61.019 +50000,0.24524,0.25011,0.05,61.019 +50000,0.25009,0.25505,0.05,62.191 +50000,0.25009,0.25505,0.05,62.191 +50000,0.25009,0.25505,0.05,62.191 +50000,0.25009,0.25505,0.05,62.191 +50000,0.25009,0.25505,0.05,62.191 +50000,0.25504,0.2601,0.05,63.353 +50000,0.25504,0.2601,0.05,63.353 +50000,0.25504,0.2601,0.05,63.353 +50000,0.25504,0.2601,0.05,63.353 +50000,0.25504,0.2601,0.05,63.353 +50000,0.26009,0.26525,0.05,64.505 +50000,0.26009,0.26525,0.05,64.505 +50000,0.26009,0.26525,0.05,64.505 +50000,0.26009,0.26525,0.05,64.505 +50000,0.26009,0.26525,0.05,64.505 +50000,0.26524,0.2705,0.05,65.647 +50000,0.26524,0.2705,0.05,65.647 +50000,0.26524,0.2705,0.05,65.647 +50000,0.26524,0.2705,0.05,65.647 +50000,0.26524,0.2705,0.05,65.647 +50000,0.27048,0.27585,0.05,66.779 +50000,0.27048,0.27585,0.05,66.779 +50000,0.27048,0.27585,0.05,66.779 +50000,0.27048,0.27585,0.05,66.779 +50000,0.27048,0.27585,0.05,66.779 +50000,0.27584,0.28131,0.05,67.9 +50000,0.27584,0.28131,0.05,67.9 +50000,0.27584,0.28131,0.05,67.9 +50000,0.27584,0.28131,0.05,67.9 +50000,0.27584,0.28131,0.05,67.9 +50000,0.27584,0.28131,0.05,67.9 +50000,0.2813,0.28687,0.05,69.008 +50000,0.2813,0.28687,0.05,69.008 +50000,0.2813,0.28687,0.05,69.008 +50000,0.2813,0.28687,0.05,69.008 +50000,0.2813,0.28687,0.05,69.008 +50000,0.28686,0.29255,0.05,70.105 +50000,0.28686,0.29255,0.05,70.105 +50000,0.28686,0.29255,0.05,70.105 +50000,0.28686,0.29255,0.05,70.105 +50000,0.28686,0.29255,0.05,70.105 +50000,0.28686,0.29255,0.05,70.105 +50000,0.29254,0.29834,0.05,71.189 +50000,0.29254,0.29834,0.05,71.189 +50000,0.29254,0.29834,0.05,71.189 +50000,0.29254,0.29834,0.05,71.189 +50000,0.29254,0.29834,0.05,71.189 +50000,0.29254,0.29834,0.05,71.189 +50000,0.29833,0.30425,0.05,72.259 +50000,0.29833,0.30425,0.05,72.259 +50000,0.29833,0.30425,0.05,72.259 +50000,0.29833,0.30425,0.05,72.259 +50000,0.29833,0.30425,0.05,72.259 +50000,0.29833,0.30425,0.05,72.259 +50000,0.30424,0.31027,0.05,73.315 +50000,0.30424,0.31027,0.05,73.315 +50000,0.30424,0.31027,0.05,73.315 +50000,0.30424,0.31027,0.05,73.315 +50000,0.30424,0.31027,0.05,73.315 +50000,0.30424,0.31027,0.05,73.315 +50000,0.31026,0.31641,0.05,74.357 +50000,0.31026,0.31641,0.05,74.357 +50000,0.31026,0.31641,0.05,74.357 +50000,0.31026,0.31641,0.05,74.357 +50000,0.31026,0.31641,0.05,74.357 +50000,0.31026,0.31641,0.05,74.357 +50000,0.3164,0.32267,0.05,75.384 +50000,0.3164,0.32267,0.05,75.384 +50000,0.3164,0.32267,0.05,75.384 +50000,0.3164,0.32267,0.05,75.384 +50000,0.3164,0.32267,0.05,75.384 +50000,0.3164,0.32267,0.05,75.384 +50000,0.32266,0.32906,0.05,76.395 +50000,0.32266,0.32906,0.05,76.395 +50000,0.32266,0.32906,0.05,76.395 +50000,0.32266,0.32906,0.05,76.395 +50000,0.32266,0.32906,0.05,76.395 +50000,0.32266,0.32906,0.05,76.395 +50000,0.32266,0.32906,0.05,76.395 +50000,0.32905,0.33558,0.05,77.389 +50000,0.32905,0.33558,0.05,77.389 +50000,0.32905,0.33558,0.05,77.389 +50000,0.32905,0.33558,0.05,77.389 +50000,0.32905,0.33558,0.05,77.389 +50000,0.32905,0.33558,0.05,77.389 +50000,0.33556,0.34222,0.05,78.367 +50000,0.33556,0.34222,0.05,78.367 +50000,0.33556,0.34222,0.05,78.367 +50000,0.33556,0.34222,0.05,78.367 +50000,0.33556,0.34222,0.05,78.367 +50000,0.33556,0.34222,0.05,78.367 +50000,0.33556,0.34222,0.05,78.367 +50000,0.34221,0.34899,0.05,79.327 +50000,0.34221,0.34899,0.05,79.327 +50000,0.34221,0.34899,0.05,79.327 +50000,0.34221,0.34899,0.05,79.327 +50000,0.34221,0.34899,0.05,79.327 +50000,0.34221,0.34899,0.05,79.327 +50000,0.34221,0.34899,0.05,79.327 +50000,0.34898,0.3559,0.05,80.269 +50000,0.34898,0.3559,0.05,80.269 +50000,0.34898,0.3559,0.05,80.269 +50000,0.34898,0.3559,0.05,80.269 +50000,0.34898,0.3559,0.05,80.269 +50000,0.34898,0.3559,0.05,80.269 +50000,0.35589,0.36295,0.05,81.192 +50000,0.35589,0.36295,0.05,81.192 +50000,0.35589,0.36295,0.05,81.192 +50000,0.35589,0.36295,0.05,81.192 +50000,0.35589,0.36295,0.05,81.192 +50000,0.35589,0.36295,0.05,81.192 +50000,0.35589,0.36295,0.05,81.192 +50000,0.36294,0.37013,0.05,82.097 +50000,0.36294,0.37013,0.05,82.097 +50000,0.36294,0.37013,0.05,82.097 +50000,0.36294,0.37013,0.05,82.097 +50000,0.36294,0.37013,0.05,82.097 +50000,0.36294,0.37013,0.05,82.097 +50000,0.36294,0.37013,0.05,82.097 +50000,0.36294,0.37013,0.05,82.097 +50000,0.37012,0.37746,0.05,82.981 +50000,0.37012,0.37746,0.05,82.981 +50000,0.37012,0.37746,0.05,82.981 +50000,0.37012,0.37746,0.05,82.981 +50000,0.37012,0.37746,0.05,82.981 +50000,0.37012,0.37746,0.05,82.981 +50000,0.37012,0.37746,0.05,82.981 +50000,0.37745,0.38494,0.05,83.845 +50000,0.37745,0.38494,0.05,83.845 +50000,0.37745,0.38494,0.05,83.845 +50000,0.37745,0.38494,0.05,83.845 +50000,0.37745,0.38494,0.05,83.845 +50000,0.37745,0.38494,0.05,83.845 +50000,0.37745,0.38494,0.05,83.845 +50000,0.38493,0.39256,0.05,84.688 +50000,0.38493,0.39256,0.05,84.688 +50000,0.38493,0.39256,0.05,84.688 +50000,0.38493,0.39256,0.05,84.688 +50000,0.38493,0.39256,0.05,84.688 +50000,0.38493,0.39256,0.05,84.688 +50000,0.38493,0.39256,0.05,84.688 +50000,0.38493,0.39256,0.05,84.688 +50000,0.39255,0.40033,0.05,85.51 +50000,0.39255,0.40033,0.05,85.51 +50000,0.39255,0.40033,0.05,85.51 +50000,0.39255,0.40033,0.05,85.51 +50000,0.39255,0.40033,0.05,85.51 +50000,0.39255,0.40033,0.05,85.51 +50000,0.39255,0.40033,0.05,85.51 +50000,0.39255,0.40033,0.05,85.51 +50000,0.40032,0.40826,0.05,86.311 +50000,0.40032,0.40826,0.05,86.311 +50000,0.40032,0.40826,0.05,86.311 +50000,0.40032,0.40826,0.05,86.311 +50000,0.40032,0.40826,0.05,86.311 +50000,0.40032,0.40826,0.05,86.311 +50000,0.40032,0.40826,0.05,86.311 +50000,0.40032,0.40826,0.05,86.311 +50000,0.40825,0.41634,0.05,87.089 +50000,0.40825,0.41634,0.05,87.089 +50000,0.40825,0.41634,0.05,87.089 +50000,0.40825,0.41634,0.05,87.089 +50000,0.40825,0.41634,0.05,87.089 +50000,0.40825,0.41634,0.05,87.089 +50000,0.40825,0.41634,0.05,87.089 +50000,0.40825,0.41634,0.05,87.089 +50000,0.41633,0.42459,0.05,87.845 +50000,0.41633,0.42459,0.05,87.845 +50000,0.41633,0.42459,0.05,87.845 +50000,0.41633,0.42459,0.05,87.845 +50000,0.41633,0.42459,0.05,87.845 +50000,0.41633,0.42459,0.05,87.845 +50000,0.41633,0.42459,0.05,87.845 +50000,0.41633,0.42459,0.05,87.845 +50000,0.42458,0.433,0.05,88.577 +50000,0.42458,0.433,0.05,88.577 +50000,0.42458,0.433,0.05,88.577 +50000,0.42458,0.433,0.05,88.577 +50000,0.42458,0.433,0.05,88.577 +50000,0.42458,0.433,0.05,88.577 +50000,0.42458,0.433,0.05,88.577 +50000,0.42458,0.433,0.05,88.577 +50000,0.42458,0.433,0.05,88.577 +50000,0.43298,0.44157,0.05,89.287 +50000,0.43298,0.44157,0.05,89.287 +50000,0.43298,0.44157,0.05,89.287 +50000,0.43298,0.44157,0.05,89.287 +50000,0.43298,0.44157,0.05,89.287 +50000,0.43298,0.44157,0.05,89.287 +50000,0.43298,0.44157,0.05,89.287 +50000,0.43298,0.44157,0.05,89.287 +50000,0.44156,0.45031,0.05,89.973 +50000,0.44156,0.45031,0.05,89.973 +50000,0.44156,0.45031,0.05,89.973 +50000,0.44156,0.45031,0.05,89.973 +50000,0.44156,0.45031,0.05,89.973 +50000,0.44156,0.45031,0.05,89.973 +50000,0.44156,0.45031,0.05,89.973 +50000,0.44156,0.45031,0.05,89.973 +50000,0.44156,0.45031,0.05,89.973 +50000,0.4503,0.45923,0.05,90.636 +50000,0.4503,0.45923,0.05,90.636 +50000,0.4503,0.45923,0.05,90.636 +50000,0.4503,0.45923,0.05,90.636 +50000,0.4503,0.45923,0.05,90.636 +50000,0.4503,0.45923,0.05,90.636 +50000,0.4503,0.45923,0.05,90.636 +50000,0.4503,0.45923,0.05,90.636 +50000,0.4503,0.45923,0.05,90.636 +50000,0.45922,0.46833,0.05,91.275 +50000,0.45922,0.46833,0.05,91.275 +50000,0.45922,0.46833,0.05,91.275 +50000,0.45922,0.46833,0.05,91.275 +50000,0.45922,0.46833,0.05,91.275 +50000,0.45922,0.46833,0.05,91.275 +50000,0.45922,0.46833,0.05,91.275 +50000,0.45922,0.46833,0.05,91.275 +50000,0.45922,0.46833,0.05,91.275 +50000,0.46832,0.4776,0.05,91.89 +50000,0.46832,0.4776,0.05,91.89 +50000,0.46832,0.4776,0.05,91.89 +50000,0.46832,0.4776,0.05,91.89 +50000,0.46832,0.4776,0.05,91.89 +50000,0.46832,0.4776,0.05,91.89 +50000,0.46832,0.4776,0.05,91.89 +50000,0.46832,0.4776,0.05,91.89 +50000,0.46832,0.4776,0.05,91.89 +50000,0.47759,0.48706,0.05,92.481 +50000,0.47759,0.48706,0.05,92.481 +50000,0.47759,0.48706,0.05,92.481 +50000,0.47759,0.48706,0.05,92.481 +50000,0.47759,0.48706,0.05,92.481 +50000,0.47759,0.48706,0.05,92.481 +50000,0.47759,0.48706,0.05,92.481 +50000,0.47759,0.48706,0.05,92.481 +50000,0.47759,0.48706,0.05,92.481 +50000,0.47759,0.48706,0.05,92.481 +50000,0.48705,0.49671,0.05,93.049 +50000,0.48705,0.49671,0.05,93.049 +50000,0.48705,0.49671,0.05,93.049 +50000,0.48705,0.49671,0.05,93.049 +50000,0.48705,0.49671,0.05,93.049 +50000,0.48705,0.49671,0.05,93.049 +50000,0.48705,0.49671,0.05,93.049 +50000,0.48705,0.49671,0.05,93.049 +50000,0.48705,0.49671,0.05,93.049 +50000,0.4967,0.50655,0.05,93.593 +50000,0.4967,0.50655,0.05,93.593 +50000,0.4967,0.50655,0.05,93.593 +50000,0.4967,0.50655,0.05,93.593 +50000,0.4967,0.50655,0.05,93.593 +50000,0.4967,0.50655,0.05,93.593 +50000,0.4967,0.50655,0.05,93.593 +50000,0.4967,0.50655,0.05,93.593 +50000,0.4967,0.50655,0.05,93.593 +50000,0.4967,0.50655,0.05,93.593 +50000,0.50654,0.51658,0.05,94.113 +50000,0.50654,0.51658,0.05,94.113 +50000,0.50654,0.51658,0.05,94.113 +50000,0.50654,0.51658,0.05,94.113 +50000,0.50654,0.51658,0.05,94.113 +50000,0.50654,0.51658,0.05,94.113 +50000,0.50654,0.51658,0.05,94.113 +50000,0.50654,0.51658,0.05,94.113 +50000,0.50654,0.51658,0.05,94.113 +50000,0.50654,0.51658,0.05,94.113 +50000,0.51657,0.52681,0.05,94.611 +50000,0.51657,0.52681,0.05,94.611 +50000,0.51657,0.52681,0.05,94.611 +50000,0.51657,0.52681,0.05,94.611 +50000,0.51657,0.52681,0.05,94.611 +50000,0.51657,0.52681,0.05,94.611 +50000,0.51657,0.52681,0.05,94.611 +50000,0.51657,0.52681,0.05,94.611 +50000,0.51657,0.52681,0.05,94.611 +50000,0.51657,0.52681,0.05,94.611 +50000,0.5268,0.53725,0.05,95.086 +50000,0.5268,0.53725,0.05,95.086 +50000,0.5268,0.53725,0.05,95.086 +50000,0.5268,0.53725,0.05,95.086 +50000,0.5268,0.53725,0.05,95.086 +50000,0.5268,0.53725,0.05,95.086 +50000,0.5268,0.53725,0.05,95.086 +50000,0.5268,0.53725,0.05,95.086 +50000,0.5268,0.53725,0.05,95.086 +50000,0.5268,0.53725,0.05,95.086 +50000,0.5268,0.53725,0.05,95.086 +50000,0.53724,0.54789,0.05,95.539 +50000,0.53724,0.54789,0.05,95.539 +50000,0.53724,0.54789,0.05,95.539 +50000,0.53724,0.54789,0.05,95.539 +50000,0.53724,0.54789,0.05,95.539 +50000,0.53724,0.54789,0.05,95.539 +50000,0.53724,0.54789,0.05,95.539 +50000,0.53724,0.54789,0.05,95.539 +50000,0.53724,0.54789,0.05,95.539 +50000,0.53724,0.54789,0.05,95.539 +50000,0.54788,0.55874,0.05,95.971 +50000,0.54788,0.55874,0.05,95.971 +50000,0.54788,0.55874,0.05,95.971 +50000,0.54788,0.55874,0.05,95.971 +50000,0.54788,0.55874,0.05,95.971 +50000,0.54788,0.55874,0.05,95.971 +50000,0.54788,0.55874,0.05,95.971 +50000,0.54788,0.55874,0.05,95.971 +50000,0.54788,0.55874,0.05,95.971 +50000,0.54788,0.55874,0.05,95.971 +50000,0.54788,0.55874,0.05,95.971 +50000,0.55873,0.56981,0.05,96.382 +50000,0.55873,0.56981,0.05,96.382 +50000,0.55873,0.56981,0.05,96.382 +50000,0.55873,0.56981,0.05,96.382 +50000,0.55873,0.56981,0.05,96.382 +50000,0.55873,0.56981,0.05,96.382 +50000,0.55873,0.56981,0.05,96.382 +50000,0.55873,0.56981,0.05,96.382 +50000,0.55873,0.56981,0.05,96.382 +50000,0.55873,0.56981,0.05,96.382 +50000,0.55873,0.56981,0.05,96.382 +50000,0.5698,0.5811,0.05,96.773 +50000,0.5698,0.5811,0.05,96.773 +50000,0.5698,0.5811,0.05,96.773 +50000,0.5698,0.5811,0.05,96.773 +50000,0.5698,0.5811,0.05,96.773 +50000,0.5698,0.5811,0.05,96.773 +50000,0.5698,0.5811,0.05,96.773 +50000,0.5698,0.5811,0.05,96.773 +50000,0.5698,0.5811,0.05,96.773 +50000,0.5698,0.5811,0.05,96.773 +50000,0.5698,0.5811,0.05,96.773 +50000,0.5698,0.5811,0.05,96.773 +50000,0.58109,0.59261,0.05,97.145 +50000,0.58109,0.59261,0.05,97.145 +50000,0.58109,0.59261,0.05,97.145 +50000,0.58109,0.59261,0.05,97.145 +50000,0.58109,0.59261,0.05,97.145 +50000,0.58109,0.59261,0.05,97.145 +50000,0.58109,0.59261,0.05,97.145 +50000,0.58109,0.59261,0.05,97.145 +50000,0.58109,0.59261,0.05,97.145 +50000,0.58109,0.59261,0.05,97.145 +50000,0.58109,0.59261,0.05,97.145 +50000,0.5926,0.60435,0.05,97.499 +50000,0.5926,0.60435,0.05,97.499 +50000,0.5926,0.60435,0.05,97.499 +50000,0.5926,0.60435,0.05,97.499 +50000,0.5926,0.60435,0.05,97.499 +50000,0.5926,0.60435,0.05,97.499 +50000,0.5926,0.60435,0.05,97.499 +50000,0.5926,0.60435,0.05,97.499 +50000,0.5926,0.60435,0.05,97.499 +50000,0.5926,0.60435,0.05,97.499 +50000,0.5926,0.60435,0.05,97.499 +50000,0.5926,0.60435,0.05,97.499 +50000,0.60434,0.61632,0.05,97.837 +50000,0.60434,0.61632,0.05,97.837 +50000,0.60434,0.61632,0.05,97.837 +50000,0.60434,0.61632,0.05,97.837 +50000,0.60434,0.61632,0.05,97.837 +50000,0.60434,0.61632,0.05,97.837 +50000,0.60434,0.61632,0.05,97.837 +50000,0.60434,0.61632,0.05,97.837 +50000,0.60434,0.61632,0.05,97.837 +50000,0.60434,0.61632,0.05,97.837 +50000,0.60434,0.61632,0.05,97.837 +50000,0.60434,0.61632,0.05,97.837 +50000,0.61631,0.62853,0.05,98.159 +50000,0.61631,0.62853,0.05,98.159 +50000,0.61631,0.62853,0.05,98.159 +50000,0.61631,0.62853,0.05,98.159 +50000,0.61631,0.62853,0.05,98.159 +50000,0.61631,0.62853,0.05,98.159 +50000,0.61631,0.62853,0.05,98.159 +50000,0.61631,0.62853,0.05,98.159 +50000,0.61631,0.62853,0.05,98.159 +50000,0.61631,0.62853,0.05,98.159 +50000,0.61631,0.62853,0.05,98.159 +50000,0.61631,0.62853,0.05,98.159 +50000,0.62852,0.64098,0.05,98.468 +50000,0.62852,0.64098,0.05,98.468 +50000,0.62852,0.64098,0.05,98.468 +50000,0.62852,0.64098,0.05,98.468 +50000,0.62852,0.64098,0.05,98.468 +50000,0.62852,0.64098,0.05,98.468 +50000,0.62852,0.64098,0.05,98.468 +50000,0.62852,0.64098,0.05,98.468 +50000,0.62852,0.64098,0.05,98.468 +50000,0.62852,0.64098,0.05,98.468 +50000,0.62852,0.64098,0.05,98.468 +50000,0.62852,0.64098,0.05,98.468 +50000,0.62852,0.64098,0.05,98.468 +50000,0.64097,0.65368,0.05,98.764 +50000,0.64097,0.65368,0.05,98.764 +50000,0.64097,0.65368,0.05,98.764 +50000,0.64097,0.65368,0.05,98.764 +50000,0.64097,0.65368,0.05,98.764 +50000,0.64097,0.65368,0.05,98.764 +50000,0.64097,0.65368,0.05,98.764 +50000,0.64097,0.65368,0.05,98.764 +50000,0.64097,0.65368,0.05,98.764 +50000,0.64097,0.65368,0.05,98.764 +50000,0.64097,0.65368,0.05,98.764 +50000,0.64097,0.65368,0.05,98.764 +50000,0.65367,0.66663,0.05,99.05 +50000,0.65367,0.66663,0.05,99.05 +50000,0.65367,0.66663,0.05,99.05 +50000,0.65367,0.66663,0.05,99.05 +50000,0.65367,0.66663,0.05,99.05 +50000,0.65367,0.66663,0.05,99.05 +50000,0.65367,0.66663,0.05,99.05 +50000,0.65367,0.66663,0.05,99.05 +50000,0.65367,0.66663,0.05,99.05 +50000,0.65367,0.66663,0.05,99.05 +50000,0.65367,0.66663,0.05,99.05 +50000,0.65367,0.66663,0.05,99.05 +50000,0.65367,0.66663,0.05,99.05 +50000,0.66662,0.67984,0.05,99.328 +50000,0.66662,0.67984,0.05,99.328 +50000,0.66662,0.67984,0.05,99.328 +50000,0.66662,0.67984,0.05,99.328 +50000,0.66662,0.67984,0.05,99.328 +50000,0.66662,0.67984,0.05,99.328 +50000,0.66662,0.67984,0.05,99.328 +50000,0.66662,0.67984,0.05,99.328 +50000,0.66662,0.67984,0.05,99.328 +50000,0.66662,0.67984,0.05,99.328 +50000,0.66662,0.67984,0.05,99.328 +50000,0.66662,0.67984,0.05,99.328 +50000,0.66662,0.67984,0.05,99.328 +50000,0.67983,0.69331,0.05,99.6 +50000,0.67983,0.69331,0.05,99.6 +50000,0.67983,0.69331,0.05,99.6 +50000,0.67983,0.69331,0.05,99.6 +50000,0.67983,0.69331,0.05,99.6 +50000,0.67983,0.69331,0.05,99.6 +50000,0.67983,0.69331,0.05,99.6 +50000,0.67983,0.69331,0.05,99.6 +50000,0.67983,0.69331,0.05,99.6 +50000,0.67983,0.69331,0.05,99.6 +50000,0.67983,0.69331,0.05,99.6 +50000,0.67983,0.69331,0.05,99.6 +50000,0.67983,0.69331,0.05,99.6 +50000,0.67983,0.69331,0.05,99.6 +50000,0.6933,0.70704,0.05,99.868 +50000,0.6933,0.70704,0.05,99.868 +50000,0.6933,0.70704,0.05,99.868 +50000,0.6933,0.70704,0.05,99.868 +50000,0.6933,0.70704,0.05,99.868 +50000,0.6933,0.70704,0.05,99.868 +50000,0.6933,0.70704,0.05,99.868 +50000,0.6933,0.70704,0.05,99.868 +50000,0.6933,0.70704,0.05,99.868 +50000,0.6933,0.70704,0.05,99.868 +50000,0.6933,0.70704,0.05,99.868 +50000,0.6933,0.70704,0.05,99.868 +50000,0.6933,0.70704,0.05,99.868 +50000,0.6933,0.70704,0.05,99.868 +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/temperatureDependentSinglePhaseThermalConductivity_plot.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/temperatureDependentSinglePhaseThermalConductivity_plot.py new file mode 100644 index 00000000000..74dc2483e90 --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentSinglePhaseThermalConductivity/temperatureDependentSinglePhaseThermalConductivity_plot.py @@ -0,0 +1,218 @@ +import os +import sys +import os +import argparse + +import numpy as np +import matplotlib.pyplot as plt +import pandas as pd +import scipy.linalg +from scipy import special + +from scipy.sparse import diags +from scipy.sparse.linalg import spsolve + +from xml.etree import ElementTree + +# Analytical results for linear thermal behavior +def steadyState(Tin, Tout, Rin, Rout, radialCoordinate): + return Tin + (Tout - Tin) * (np.log(radialCoordinate) - np.log(Rin)) / (np.log(Rout) - np.log(Rin)) + +def diffusionFunction(radialCoordinate, Rin, diffusionCoefficient, diffusionTime): + return special.erfc( (radialCoordinate - Rin) / 2.0 / np.sqrt( diffusionCoefficient * diffusionTime ) ) + +def computeTransientTemperature(Tin, Tout, Rin, radialCoordinate, thermalDiffusionCoefficient, diffusionTime): + # Ref. Wang and Papamichos (1994), https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/94WR01774 + return Tout + (Tin-Tout) * np.sqrt(Rin/radialCoordinate) * diffusionFunction(radialCoordinate, Rin, thermalDiffusionCoefficient, diffusionTime) + +def computeThermalDiffusionCoefficient(thermalConductivity, volumetricHeatCapacity): + return thermalConductivity / volumetricHeatCapacity + +# Finite difference results for non-linear thermal behavior +def temperatureDependentThermalConductivity(lambda0, lambda_gradient, T, Treference): + return lambda0 + lambda_gradient*(T-Treference) + +def temperatureDependentVolumetricHeat(c0, c_gradient, T, Treference): + return c0 + c_gradient*(T-Treference) + +def coefficientMatrix(thermalConductivity, volumetricHeatCapacity, r, dt, N): + # Coefficients for the matrix + A = np.zeros((N+1, N+1)) + + for i in range(1,N): + dr = r[i] - r[i-1] + r_i = r[i] + + diffusivity_i = thermalConductivity[i]/volumetricHeatCapacity[i] + A[i, i-1] = - diffusivity_i * (dt/(dr**2) - dt/(2 * r_i * dr)) \ + + (thermalConductivity[i+1] - thermalConductivity[i-1])/volumetricHeatCapacity[i]*dt/4/(dr**2) + A[i, i] = 1.0 + 2.0 * diffusivity_i * dt / (dr**2) + A[i, i+1] = - diffusivity_i * (dt/(dr**2) + dt/(2 * r_i * dr)) \ + - (thermalConductivity[i+1] - thermalConductivity[i-1])/volumetricHeatCapacity[i]*dt/4/(dr**2) + + # Boundary conditions + # No-flux at r=0 approximated by setting the flux between the first two cells to zero + A[0, 0] = 1.0 + A[N, N] = 1.0 + return A + +def solve_radial_diffusion(r, tmax, dt, Tin, Tout, lambda0, lambda_gradient, c0, c_gradient, Treference): + N = len(r)-1 + # Time setup + n_steps = int(tmax / dt) + + # Time-stepping + T = np.zeros(N+1) + Tout # initial condition u(r, 0) + T[0] = Tin + for step in range(n_steps): + thermalConductivity = temperatureDependentThermalConductivity(lambda0, lambda_gradient, T, Treference) + + volumetricHeatCapacity = temperatureDependentVolumetricHeat(c0, c_gradient, T, Treference) + + A = coefficientMatrix(thermalConductivity, volumetricHeatCapacity, r, dt, N) + T = spsolve(A, T) + + return T + + +def extractDataFromXMLList(paramList): + # Extract data from a list in XML such as "{ 1, 2, 3}" + return paramList.replace('{', '').replace('}', '').strip().split(',') + +def getWellboreGeometryFromXML(xmlFilePath): + tree = ElementTree.parse(xmlFilePath) + + meshParam = tree.find('Mesh/InternalWellbore') + radii = extractDataFromXMLList( meshParam.get("radius") ) + + Rin = float(radii[0]) + Rout = float(radii[-1]) + + return [Rin, Rout] + +def getLoadingFromXML(xmlFilePath): + tree = ElementTree.parse(xmlFilePath) + fsParams = tree.findall('FieldSpecifications/FieldSpecification') + + for fsParam in fsParams: + if ( (fsParam.get('fieldName') == "pressure") & (fsParam.get('initialCondition') != "1") ): + if fsParam.get('setNames') == "{ rneg }": + Pin = float(fsParam.get('scale')) + if fsParam.get('setNames') == "{ rpos }": + Pout = float(fsParam.get('scale')) + + for fsParam in fsParams: + if ( (fsParam.get('fieldName') == "temperature") & (fsParam.get('initialCondition') != "1") ): + if fsParam.get('setNames') == "{ rneg }": + Tin = float(fsParam.get('scale')) + if fsParam.get('setNames') == "{ rpos }": + Tout = float(fsParam.get('scale')) + + + tree_SinglePhaseThermalConductivities = tree.findall('Constitutive/SinglePhaseThermalConductivity') + + for tree_SinglePhaseThermalConductivity in tree_SinglePhaseThermalConductivities: + if tree_SinglePhaseThermalConductivity.get('name') == "thermalCond_nonLinear": + defaultThermalConductivity = float( extractDataFromXMLList( tree_SinglePhaseThermalConductivity.get('defaultThermalConductivityComponents') )[0] ) + + thermalConductivityGradient = float( extractDataFromXMLList( tree_SinglePhaseThermalConductivity.get('thermalConductivityGradientComponents') )[0] ) + referenceTemperature = float( tree_SinglePhaseThermalConductivity.get('referenceTemperature') ) + + + tree_SolidInternalEnergies = tree.findall('Constitutive/SolidInternalEnergy') + + for tree_SolidInternalEnergy in tree_SolidInternalEnergies: + if tree_SolidInternalEnergy.get('name') == "rockInternalEnergy_linear": + volumetricHeatCapacity = float( tree_SolidInternalEnergy.get('referenceVolumetricHeatCapacity') ) + dVolumetricHeatCapacity_dTemperature = 0.0 + + + permeability = float( extractDataFromXMLList( tree.find('Constitutive/ConstantPermeability').get('permeabilityComponents') )[0] ) + + porosity = float( tree.find('Constitutive/PressurePorosity').get('defaultReferencePorosity') ) + + fluidViscosity = float( tree.find('Constitutive/ThermalCompressibleSinglePhaseFluid').get('defaultViscosity') ) + + fluidCompressibility = float( tree.find('Constitutive/ThermalCompressibleSinglePhaseFluid').get('compressibility') ) + + fluidThermalExpansionCoefficient = float( tree.find('Constitutive/ThermalCompressibleSinglePhaseFluid').get('thermalExpansionCoeff') ) + + return [Pin, Pout, Tin, Tout, defaultThermalConductivity, thermalConductivityGradient, referenceTemperature, volumetricHeatCapacity, dVolumetricHeatCapacity_dTemperature, permeability, porosity, fluidViscosity, fluidCompressibility, fluidThermalExpansionCoefficient] + + +def main(): + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + + # Parse the command-line arguments + args = parser.parse_args() + + geosDir = args.geosDir + + xmlFilePath = geosDir + "/inputFiles/singlePhaseFlow/" + + Rin, Rout = getWellboreGeometryFromXML(xmlFilePath+"thermalCompressible_temperatureDependentSinglePhaseThermalConductivity_benchmark.xml") + + Pin, Pout, Tin, Tout, defaultThermalConductivity, thermalConductivityGradient, referenceTemperature, volumetricHeatCapacity, dVolumetricHeatCapacity_dTemperature, permeability, porosity, fluidViscosity, fluidCompressibility, fluidThermalExpansionCoefficient = getLoadingFromXML(xmlFilePath+"thermalCompressible_2d_base.xml") + + plt.figure(figsize=(10,7)) + font = {'size' : 16} + plt.rc('font', **font) + + for chart_idx, idx in enumerate([1, 2, 5, 10]): + # Numerical results + data = pd.read_csv(f'data_{idx}.csv') + data.dropna(inplace=True) + data.drop_duplicates(inplace=True) + data.reset_index(drop=True, inplace=True) + + radialCoordinate = (data['elementCenter:0']**2.0 + data['elementCenter:1']**2.0)**0.5 + temperature = data['temperature'] + #pressure = data['pressure'] + diffusionTime = data['Time'][0] + + # Analytical results for linear thermal behavior, for comparison + radialCoordinate_anal = np.arange(Rin, Rout, (Rout-Rin)/100) + + thermalDiffusionCoefficient = computeThermalDiffusionCoefficient(defaultThermalConductivity, volumetricHeatCapacity) + + T_transient_linear = computeTransientTemperature(Tin, Tout, Rin, radialCoordinate_anal, thermalDiffusionCoefficient, diffusionTime) + + # Analytical results of the steady state regime for comparison + T_steadyState = steadyState(Tin, Tout, Rin, Rout, radialCoordinate_anal) + + # Finite different results for non-linear thermal behavior + + T_transient_nonLinear = solve_radial_diffusion(radialCoordinate_anal, diffusionTime, diffusionTime/1000, Tin, Tout, defaultThermalConductivity, thermalConductivityGradient, volumetricHeatCapacity, dVolumetricHeatCapacity_dTemperature, referenceTemperature) + + # Visualization + # Temperature + plt.subplot(2,2,chart_idx+1) + plt.plot( radialCoordinate, temperature, 'k+' , label='GEOS' ) + plt.plot( radialCoordinate_anal, T_transient_nonLinear, 'g.' , label='FDM Non-Linear' ) + plt.plot( radialCoordinate_anal, T_transient_linear, 'r-' , label='Analytic Linear' ) + plt.plot( radialCoordinate_anal, T_steadyState, 'b-' , label='Steady State' ) + + if chart_idx==1: + plt.legend() + + if chart_idx in [2,3]: + plt.xlabel('Radial distance from well center') + + if chart_idx in [0,2]: + plt.ylabel('Temperature (°C)') + + plt.ylim(Tin-10,Tout+10) + plt.xlim(0.1,0.3) + plt.title('t = '+str(diffusionTime)+'(s)') + plt.tight_layout() + + plt.show() + +if __name__ == "__main__": + main() + diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/Example.rst new file mode 100644 index 00000000000..959302bd7a2 --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/Example.rst @@ -0,0 +1,62 @@ +.. _AdvancedWellboreExampleNonLinearThermalDiffusionTemperatureDependentVolumetricHeatCapacity: + + +############################################################################################################ +Non-Linear Thermal Diffusion Around a Wellbore: The Case with Temperature Dependent Volumetric Heat Capacity +############################################################################################################ + +------------------------------------------------------------------ +Problem description +------------------------------------------------------------------ + +This example is an extension of the linear thermal diffusion problem presented in :ref:`AdvancedExamplePureThermalDiffusionWellbore`. It uses the thermal single-phase flow solver to model a non-linear thermal diffusion problem around a wellbore where the volumetric heat capacity of the solid rock depends linearly on the temperature. + + +**Input file** + +This benchmark example uses no external input file and everything required is +contained within two GEOS xml files that are located at: + +.. code-block:: console + + inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml + +and + +.. code-block:: console + + inputFiles/singlePhaseFlow/thermalCompressible_temperatureDependentVolumetricHeatCapacity_benchmark.xml + + +In this example, we focus on the ``Constitutive`` tag. + +----------------------------------------------------------- +Constitutive +----------------------------------------------------------- + +The reference value of the volumetric heat capacity of the medium around the wellbore and its derivative with respect to temperature are defined in the ``SolidInternalEnergy`` XML block: + +.. literalinclude:: ../../../../../../../inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml + :language: xml + :start-after: + :end-before: + + +--------------------------------- +Results and benchmark +--------------------------------- + +A good agreement between the results obtained using GEOS and the reference results that are obtained by the classical finite difference method is shown in the figure below: + + +.. plot:: docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/temperatureDependentVolumetricHeatCapacity_plot.py + + +------------------------------------------------------------------ +To go further +------------------------------------------------------------------ + +**Feedback on this example** + +This concludes the example of a non-linear thermal diffusion problem around a wellbore due to temperature dependent volumetric heat capacity of rock. +For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/data_1.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/data_1.csv new file mode 100644 index 00000000000..92fbae1a86a --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/data_1.csv @@ -0,0 +1,1002 @@ +Time,"elementCenter:0","elementCenter:1","elementCenter:2","temperature" +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,0.07071,0.072112,0.05,-13.76 +10000,0.07071,0.072112,0.05,-13.76 +10000,0.07211,0.07354,0.05,-1.5083 +10000,0.07351,0.074968,0.05,10.502 +10000,0.075155,0.076646,0.05,24.239 +10000,0.075155,0.076646,0.05,24.239 +10000,0.077046,0.078574,0.05,39.135 +10000,0.077046,0.078574,0.05,39.135 +10000,0.078936,0.080501,0.05,52.698 +10000,0.078936,0.080501,0.05,52.698 +10000,0.080826,0.082429,0.05,64.497 +10000,0.080826,0.082429,0.05,64.497 +10000,0.082716,0.084357,0.05,74.262 +10000,0.082716,0.084357,0.05,74.262 +10000,0.084607,0.086285,0.05,81.944 +10000,0.084607,0.086285,0.05,81.944 +10000,0.086497,0.088212,0.05,87.71 +10000,0.086497,0.088212,0.05,87.71 +10000,0.088387,0.09014,0.05,91.858 +10000,0.088387,0.09014,0.05,91.858 +10000,0.090278,0.092068,0.05,94.735 +10000,0.090278,0.092068,0.05,94.735 +10000,0.092168,0.093995,0.05,96.667 +10000,0.092168,0.093995,0.05,96.667 +10000,0.094031,0.095896,0.05,97.913 +10000,0.095885,0.097786,0.05,98.714 +10000,0.095885,0.097786,0.05,98.714 +10000,0.097776,0.099715,0.05,99.227 +10000,0.097776,0.099715,0.05,99.227 +10000,0.099704,0.10168,0.05,99.547 +10000,0.099704,0.10168,0.05,99.547 +10000,0.10167,0.10369,0.05,99.741 +10000,0.10167,0.10369,0.05,99.741 +10000,0.10368,0.10573,0.05,99.855 +10000,0.10368,0.10573,0.05,99.855 +10000,0.10572,0.10782,0.05,99.921 +10000,0.10572,0.10782,0.05,99.921 +10000,0.10781,0.10995,0.05,99.958 +10000,0.10781,0.10995,0.05,99.958 +10000,0.10993,0.11211,0.05,99.978 +10000,0.10993,0.11211,0.05,99.978 +10000,0.10993,0.11211,0.05,99.978 +10000,0.1121,0.11433,0.05,99.989 +10000,0.1121,0.11433,0.05,99.989 +10000,0.11432,0.11658,0.05,99.995 +10000,0.11432,0.11658,0.05,99.995 +10000,0.11657,0.11888,0.05,99.997 +10000,0.11657,0.11888,0.05,99.997 +10000,0.11887,0.12123,0.05,99.999 +10000,0.11887,0.12123,0.05,99.999 +10000,0.11887,0.12123,0.05,99.999 +10000,0.12122,0.12362,0.05,99.999 +10000,0.12122,0.12362,0.05,99.999 +10000,0.12361,0.12607,0.05,100 +10000,0.12361,0.12607,0.05,100 +10000,0.12361,0.12607,0.05,100 +10000,0.12605,0.12855,0.05,100 +10000,0.12605,0.12855,0.05,100 +10000,0.12854,0.13109,0.05,100 +10000,0.12854,0.13109,0.05,100 +10000,0.12854,0.13109,0.05,100 +10000,0.13108,0.13368,0.05,100 +10000,0.13108,0.13368,0.05,100 +10000,0.13367,0.13632,0.05,100 +10000,0.13367,0.13632,0.05,100 +10000,0.13367,0.13632,0.05,100 +10000,0.13631,0.13901,0.05,100 +10000,0.13631,0.13901,0.05,100 +10000,0.13631,0.13901,0.05,100 +10000,0.139,0.14176,0.05,100 +10000,0.139,0.14176,0.05,100 +10000,0.14175,0.14456,0.05,100 +10000,0.14175,0.14456,0.05,100 +10000,0.14175,0.14456,0.05,100 +10000,0.14455,0.14742,0.05,100 +10000,0.14455,0.14742,0.05,100 +10000,0.14455,0.14742,0.05,100 +10000,0.1474,0.15033,0.05,100 +10000,0.1474,0.15033,0.05,100 +10000,0.1474,0.15033,0.05,100 +10000,0.15032,0.1533,0.05,100 +10000,0.15032,0.1533,0.05,100 +10000,0.15032,0.1533,0.05,100 +10000,0.15329,0.15633,0.05,100 +10000,0.15329,0.15633,0.05,100 +10000,0.15329,0.15633,0.05,100 +10000,0.15632,0.15942,0.05,100 +10000,0.15632,0.15942,0.05,100 +10000,0.15632,0.15942,0.05,100 +10000,0.15941,0.16257,0.05,100 +10000,0.15941,0.16257,0.05,100 +10000,0.15941,0.16257,0.05,100 +10000,0.16256,0.16578,0.05,100 +10000,0.16256,0.16578,0.05,100 +10000,0.16256,0.16578,0.05,100 +10000,0.16577,0.16906,0.05,100 +10000,0.16577,0.16906,0.05,100 +10000,0.16577,0.16906,0.05,100 +10000,0.16577,0.16906,0.05,100 +10000,0.16905,0.1724,0.05,100 +10000,0.16905,0.1724,0.05,100 +10000,0.16905,0.1724,0.05,100 +10000,0.17239,0.1758,0.05,100 +10000,0.17239,0.1758,0.05,100 +10000,0.17239,0.1758,0.05,100 +10000,0.17579,0.17928,0.05,100 +10000,0.17579,0.17928,0.05,100 +10000,0.17579,0.17928,0.05,100 +10000,0.17579,0.17928,0.05,100 +10000,0.17927,0.18282,0.05,100 +10000,0.17927,0.18282,0.05,100 +10000,0.17927,0.18282,0.05,100 +10000,0.18281,0.18644,0.05,100 +10000,0.18281,0.18644,0.05,100 +10000,0.18281,0.18644,0.05,100 +10000,0.18281,0.18644,0.05,100 +10000,0.18643,0.19013,0.05,100 +10000,0.18643,0.19013,0.05,100 +10000,0.18643,0.19013,0.05,100 +10000,0.18643,0.19013,0.05,100 +10000,0.19011,0.19388,0.05,100 +10000,0.19011,0.19388,0.05,100 +10000,0.19011,0.19388,0.05,100 +10000,0.19387,0.19772,0.05,100 +10000,0.19387,0.19772,0.05,100 +10000,0.19387,0.19772,0.05,100 +10000,0.19387,0.19772,0.05,100 +10000,0.19771,0.20163,0.05,100 +10000,0.19771,0.20163,0.05,100 +10000,0.19771,0.20163,0.05,100 +10000,0.19771,0.20163,0.05,100 +10000,0.20162,0.20562,0.05,100 +10000,0.20162,0.20562,0.05,100 +10000,0.20162,0.20562,0.05,100 +10000,0.20162,0.20562,0.05,100 +10000,0.2056,0.20968,0.05,100 +10000,0.2056,0.20968,0.05,100 +10000,0.2056,0.20968,0.05,100 +10000,0.2056,0.20968,0.05,100 +10000,0.20967,0.21383,0.05,100 +10000,0.20967,0.21383,0.05,100 +10000,0.20967,0.21383,0.05,100 +10000,0.20967,0.21383,0.05,100 +10000,0.21382,0.21806,0.05,100 +10000,0.21382,0.21806,0.05,100 +10000,0.21382,0.21806,0.05,100 +10000,0.21382,0.21806,0.05,100 +10000,0.21382,0.21806,0.05,100 +10000,0.21805,0.22237,0.05,100 +10000,0.21805,0.22237,0.05,100 +10000,0.21805,0.22237,0.05,100 +10000,0.21805,0.22237,0.05,100 +10000,0.22236,0.22677,0.05,100 +10000,0.22236,0.22677,0.05,100 +10000,0.22236,0.22677,0.05,100 +10000,0.22236,0.22677,0.05,100 +10000,0.22676,0.23125,0.05,100 +10000,0.22676,0.23125,0.05,100 +10000,0.22676,0.23125,0.05,100 +10000,0.22676,0.23125,0.05,100 +10000,0.22676,0.23125,0.05,100 +10000,0.23124,0.23583,0.05,100 +10000,0.23124,0.23583,0.05,100 +10000,0.23124,0.23583,0.05,100 +10000,0.23124,0.23583,0.05,100 +10000,0.23582,0.2405,0.05,100 +10000,0.23582,0.2405,0.05,100 +10000,0.23582,0.2405,0.05,100 +10000,0.23582,0.2405,0.05,100 +10000,0.23582,0.2405,0.05,100 +10000,0.24048,0.24525,0.05,100 +10000,0.24048,0.24525,0.05,100 +10000,0.24048,0.24525,0.05,100 +10000,0.24048,0.24525,0.05,100 +10000,0.24048,0.24525,0.05,100 +10000,0.24524,0.25011,0.05,100 +10000,0.24524,0.25011,0.05,100 +10000,0.24524,0.25011,0.05,100 +10000,0.24524,0.25011,0.05,100 +10000,0.24524,0.25011,0.05,100 +10000,0.25009,0.25505,0.05,100 +10000,0.25009,0.25505,0.05,100 +10000,0.25009,0.25505,0.05,100 +10000,0.25009,0.25505,0.05,100 +10000,0.25009,0.25505,0.05,100 +10000,0.25504,0.2601,0.05,100 +10000,0.25504,0.2601,0.05,100 +10000,0.25504,0.2601,0.05,100 +10000,0.25504,0.2601,0.05,100 +10000,0.25504,0.2601,0.05,100 +10000,0.26009,0.26525,0.05,100 +10000,0.26009,0.26525,0.05,100 +10000,0.26009,0.26525,0.05,100 +10000,0.26009,0.26525,0.05,100 +10000,0.26009,0.26525,0.05,100 +10000,0.26524,0.2705,0.05,100 +10000,0.26524,0.2705,0.05,100 +10000,0.26524,0.2705,0.05,100 +10000,0.26524,0.2705,0.05,100 +10000,0.26524,0.2705,0.05,100 +10000,0.27048,0.27585,0.05,100 +10000,0.27048,0.27585,0.05,100 +10000,0.27048,0.27585,0.05,100 +10000,0.27048,0.27585,0.05,100 +10000,0.27048,0.27585,0.05,100 +10000,0.27584,0.28131,0.05,100 +10000,0.27584,0.28131,0.05,100 +10000,0.27584,0.28131,0.05,100 +10000,0.27584,0.28131,0.05,100 +10000,0.27584,0.28131,0.05,100 +10000,0.27584,0.28131,0.05,100 +10000,0.2813,0.28687,0.05,100 +10000,0.2813,0.28687,0.05,100 +10000,0.2813,0.28687,0.05,100 +10000,0.2813,0.28687,0.05,100 +10000,0.2813,0.28687,0.05,100 +10000,0.28686,0.29255,0.05,100 +10000,0.28686,0.29255,0.05,100 +10000,0.28686,0.29255,0.05,100 +10000,0.28686,0.29255,0.05,100 +10000,0.28686,0.29255,0.05,100 +10000,0.28686,0.29255,0.05,100 +10000,0.29254,0.29834,0.05,100 +10000,0.29254,0.29834,0.05,100 +10000,0.29254,0.29834,0.05,100 +10000,0.29254,0.29834,0.05,100 +10000,0.29254,0.29834,0.05,100 +10000,0.29254,0.29834,0.05,100 +10000,0.29833,0.30425,0.05,100 +10000,0.29833,0.30425,0.05,100 +10000,0.29833,0.30425,0.05,100 +10000,0.29833,0.30425,0.05,100 +10000,0.29833,0.30425,0.05,100 +10000,0.29833,0.30425,0.05,100 +10000,0.30424,0.31027,0.05,100 +10000,0.30424,0.31027,0.05,100 +10000,0.30424,0.31027,0.05,100 +10000,0.30424,0.31027,0.05,100 +10000,0.30424,0.31027,0.05,100 +10000,0.30424,0.31027,0.05,100 +10000,0.31026,0.31641,0.05,100 +10000,0.31026,0.31641,0.05,100 +10000,0.31026,0.31641,0.05,100 +10000,0.31026,0.31641,0.05,100 +10000,0.31026,0.31641,0.05,100 +10000,0.31026,0.31641,0.05,100 +10000,0.3164,0.32267,0.05,100 +10000,0.3164,0.32267,0.05,100 +10000,0.3164,0.32267,0.05,100 +10000,0.3164,0.32267,0.05,100 +10000,0.3164,0.32267,0.05,100 +10000,0.3164,0.32267,0.05,100 +10000,0.32266,0.32906,0.05,100 +10000,0.32266,0.32906,0.05,100 +10000,0.32266,0.32906,0.05,100 +10000,0.32266,0.32906,0.05,100 +10000,0.32266,0.32906,0.05,100 +10000,0.32266,0.32906,0.05,100 +10000,0.32266,0.32906,0.05,100 +10000,0.32905,0.33558,0.05,100 +10000,0.32905,0.33558,0.05,100 +10000,0.32905,0.33558,0.05,100 +10000,0.32905,0.33558,0.05,100 +10000,0.32905,0.33558,0.05,100 +10000,0.32905,0.33558,0.05,100 +10000,0.33556,0.34222,0.05,100 +10000,0.33556,0.34222,0.05,100 +10000,0.33556,0.34222,0.05,100 +10000,0.33556,0.34222,0.05,100 +10000,0.33556,0.34222,0.05,100 +10000,0.33556,0.34222,0.05,100 +10000,0.33556,0.34222,0.05,100 +10000,0.34221,0.34899,0.05,100 +10000,0.34221,0.34899,0.05,100 +10000,0.34221,0.34899,0.05,100 +10000,0.34221,0.34899,0.05,100 +10000,0.34221,0.34899,0.05,100 +10000,0.34221,0.34899,0.05,100 +10000,0.34221,0.34899,0.05,100 +10000,0.34898,0.3559,0.05,100 +10000,0.34898,0.3559,0.05,100 +10000,0.34898,0.3559,0.05,100 +10000,0.34898,0.3559,0.05,100 +10000,0.34898,0.3559,0.05,100 +10000,0.34898,0.3559,0.05,100 +10000,0.35589,0.36295,0.05,100 +10000,0.35589,0.36295,0.05,100 +10000,0.35589,0.36295,0.05,100 +10000,0.35589,0.36295,0.05,100 +10000,0.35589,0.36295,0.05,100 +10000,0.35589,0.36295,0.05,100 +10000,0.35589,0.36295,0.05,100 +10000,0.36294,0.37013,0.05,100 +10000,0.36294,0.37013,0.05,100 +10000,0.36294,0.37013,0.05,100 +10000,0.36294,0.37013,0.05,100 +10000,0.36294,0.37013,0.05,100 +10000,0.36294,0.37013,0.05,100 +10000,0.36294,0.37013,0.05,100 +10000,0.36294,0.37013,0.05,100 +10000,0.37012,0.37746,0.05,100 +10000,0.37012,0.37746,0.05,100 +10000,0.37012,0.37746,0.05,100 +10000,0.37012,0.37746,0.05,100 +10000,0.37012,0.37746,0.05,100 +10000,0.37012,0.37746,0.05,100 +10000,0.37012,0.37746,0.05,100 +10000,0.37745,0.38494,0.05,100 +10000,0.37745,0.38494,0.05,100 +10000,0.37745,0.38494,0.05,100 +10000,0.37745,0.38494,0.05,100 +10000,0.37745,0.38494,0.05,100 +10000,0.37745,0.38494,0.05,100 +10000,0.37745,0.38494,0.05,100 +10000,0.38493,0.39256,0.05,100 +10000,0.38493,0.39256,0.05,100 +10000,0.38493,0.39256,0.05,100 +10000,0.38493,0.39256,0.05,100 +10000,0.38493,0.39256,0.05,100 +10000,0.38493,0.39256,0.05,100 +10000,0.38493,0.39256,0.05,100 +10000,0.38493,0.39256,0.05,100 +10000,0.39255,0.40033,0.05,100 +10000,0.39255,0.40033,0.05,100 +10000,0.39255,0.40033,0.05,100 +10000,0.39255,0.40033,0.05,100 +10000,0.39255,0.40033,0.05,100 +10000,0.39255,0.40033,0.05,100 +10000,0.39255,0.40033,0.05,100 +10000,0.39255,0.40033,0.05,100 +10000,0.40032,0.40826,0.05,100 +10000,0.40032,0.40826,0.05,100 +10000,0.40032,0.40826,0.05,100 +10000,0.40032,0.40826,0.05,100 +10000,0.40032,0.40826,0.05,100 +10000,0.40032,0.40826,0.05,100 +10000,0.40032,0.40826,0.05,100 +10000,0.40032,0.40826,0.05,100 +10000,0.40825,0.41634,0.05,100 +10000,0.40825,0.41634,0.05,100 +10000,0.40825,0.41634,0.05,100 +10000,0.40825,0.41634,0.05,100 +10000,0.40825,0.41634,0.05,100 +10000,0.40825,0.41634,0.05,100 +10000,0.40825,0.41634,0.05,100 +10000,0.40825,0.41634,0.05,100 +10000,0.41633,0.42459,0.05,100 +10000,0.41633,0.42459,0.05,100 +10000,0.41633,0.42459,0.05,100 +10000,0.41633,0.42459,0.05,100 +10000,0.41633,0.42459,0.05,100 +10000,0.41633,0.42459,0.05,100 +10000,0.41633,0.42459,0.05,100 +10000,0.41633,0.42459,0.05,100 +10000,0.42458,0.433,0.05,100 +10000,0.42458,0.433,0.05,100 +10000,0.42458,0.433,0.05,100 +10000,0.42458,0.433,0.05,100 +10000,0.42458,0.433,0.05,100 +10000,0.42458,0.433,0.05,100 +10000,0.42458,0.433,0.05,100 +10000,0.42458,0.433,0.05,100 +10000,0.42458,0.433,0.05,100 +10000,0.43298,0.44157,0.05,100 +10000,0.43298,0.44157,0.05,100 +10000,0.43298,0.44157,0.05,100 +10000,0.43298,0.44157,0.05,100 +10000,0.43298,0.44157,0.05,100 +10000,0.43298,0.44157,0.05,100 +10000,0.43298,0.44157,0.05,100 +10000,0.43298,0.44157,0.05,100 +10000,0.44156,0.45031,0.05,100 +10000,0.44156,0.45031,0.05,100 +10000,0.44156,0.45031,0.05,100 +10000,0.44156,0.45031,0.05,100 +10000,0.44156,0.45031,0.05,100 +10000,0.44156,0.45031,0.05,100 +10000,0.44156,0.45031,0.05,100 +10000,0.44156,0.45031,0.05,100 +10000,0.44156,0.45031,0.05,100 +10000,0.4503,0.45923,0.05,100 +10000,0.4503,0.45923,0.05,100 +10000,0.4503,0.45923,0.05,100 +10000,0.4503,0.45923,0.05,100 +10000,0.4503,0.45923,0.05,100 +10000,0.4503,0.45923,0.05,100 +10000,0.4503,0.45923,0.05,100 +10000,0.4503,0.45923,0.05,100 +10000,0.4503,0.45923,0.05,100 +10000,0.45922,0.46833,0.05,100 +10000,0.45922,0.46833,0.05,100 +10000,0.45922,0.46833,0.05,100 +10000,0.45922,0.46833,0.05,100 +10000,0.45922,0.46833,0.05,100 +10000,0.45922,0.46833,0.05,100 +10000,0.45922,0.46833,0.05,100 +10000,0.45922,0.46833,0.05,100 +10000,0.45922,0.46833,0.05,100 +10000,0.46832,0.4776,0.05,100 +10000,0.46832,0.4776,0.05,100 +10000,0.46832,0.4776,0.05,100 +10000,0.46832,0.4776,0.05,100 +10000,0.46832,0.4776,0.05,100 +10000,0.46832,0.4776,0.05,100 +10000,0.46832,0.4776,0.05,100 +10000,0.46832,0.4776,0.05,100 +10000,0.46832,0.4776,0.05,100 +10000,0.47759,0.48706,0.05,100 +10000,0.47759,0.48706,0.05,100 +10000,0.47759,0.48706,0.05,100 +10000,0.47759,0.48706,0.05,100 +10000,0.47759,0.48706,0.05,100 +10000,0.47759,0.48706,0.05,100 +10000,0.47759,0.48706,0.05,100 +10000,0.47759,0.48706,0.05,100 +10000,0.47759,0.48706,0.05,100 +10000,0.47759,0.48706,0.05,100 +10000,0.48705,0.49671,0.05,100 +10000,0.48705,0.49671,0.05,100 +10000,0.48705,0.49671,0.05,100 +10000,0.48705,0.49671,0.05,100 +10000,0.48705,0.49671,0.05,100 +10000,0.48705,0.49671,0.05,100 +10000,0.48705,0.49671,0.05,100 +10000,0.48705,0.49671,0.05,100 +10000,0.48705,0.49671,0.05,100 +10000,0.4967,0.50655,0.05,100 +10000,0.4967,0.50655,0.05,100 +10000,0.4967,0.50655,0.05,100 +10000,0.4967,0.50655,0.05,100 +10000,0.4967,0.50655,0.05,100 +10000,0.4967,0.50655,0.05,100 +10000,0.4967,0.50655,0.05,100 +10000,0.4967,0.50655,0.05,100 +10000,0.4967,0.50655,0.05,100 +10000,0.4967,0.50655,0.05,100 +10000,0.50654,0.51658,0.05,100 +10000,0.50654,0.51658,0.05,100 +10000,0.50654,0.51658,0.05,100 +10000,0.50654,0.51658,0.05,100 +10000,0.50654,0.51658,0.05,100 +10000,0.50654,0.51658,0.05,100 +10000,0.50654,0.51658,0.05,100 +10000,0.50654,0.51658,0.05,100 +10000,0.50654,0.51658,0.05,100 +10000,0.50654,0.51658,0.05,100 +10000,0.51657,0.52681,0.05,100 +10000,0.51657,0.52681,0.05,100 +10000,0.51657,0.52681,0.05,100 +10000,0.51657,0.52681,0.05,100 +10000,0.51657,0.52681,0.05,100 +10000,0.51657,0.52681,0.05,100 +10000,0.51657,0.52681,0.05,100 +10000,0.51657,0.52681,0.05,100 +10000,0.51657,0.52681,0.05,100 +10000,0.51657,0.52681,0.05,100 +10000,0.5268,0.53725,0.05,100 +10000,0.5268,0.53725,0.05,100 +10000,0.5268,0.53725,0.05,100 +10000,0.5268,0.53725,0.05,100 +10000,0.5268,0.53725,0.05,100 +10000,0.5268,0.53725,0.05,100 +10000,0.5268,0.53725,0.05,100 +10000,0.5268,0.53725,0.05,100 +10000,0.5268,0.53725,0.05,100 +10000,0.5268,0.53725,0.05,100 +10000,0.5268,0.53725,0.05,100 +10000,0.53724,0.54789,0.05,100 +10000,0.53724,0.54789,0.05,100 +10000,0.53724,0.54789,0.05,100 +10000,0.53724,0.54789,0.05,100 +10000,0.53724,0.54789,0.05,100 +10000,0.53724,0.54789,0.05,100 +10000,0.53724,0.54789,0.05,100 +10000,0.53724,0.54789,0.05,100 +10000,0.53724,0.54789,0.05,100 +10000,0.53724,0.54789,0.05,100 +10000,0.54788,0.55874,0.05,100 +10000,0.54788,0.55874,0.05,100 +10000,0.54788,0.55874,0.05,100 +10000,0.54788,0.55874,0.05,100 +10000,0.54788,0.55874,0.05,100 +10000,0.54788,0.55874,0.05,100 +10000,0.54788,0.55874,0.05,100 +10000,0.54788,0.55874,0.05,100 +10000,0.54788,0.55874,0.05,100 +10000,0.54788,0.55874,0.05,100 +10000,0.54788,0.55874,0.05,100 +10000,0.55873,0.56981,0.05,100 +10000,0.55873,0.56981,0.05,100 +10000,0.55873,0.56981,0.05,100 +10000,0.55873,0.56981,0.05,100 +10000,0.55873,0.56981,0.05,100 +10000,0.55873,0.56981,0.05,100 +10000,0.55873,0.56981,0.05,100 +10000,0.55873,0.56981,0.05,100 +10000,0.55873,0.56981,0.05,100 +10000,0.55873,0.56981,0.05,100 +10000,0.55873,0.56981,0.05,100 +10000,0.5698,0.5811,0.05,100 +10000,0.5698,0.5811,0.05,100 +10000,0.5698,0.5811,0.05,100 +10000,0.5698,0.5811,0.05,100 +10000,0.5698,0.5811,0.05,100 +10000,0.5698,0.5811,0.05,100 +10000,0.5698,0.5811,0.05,100 +10000,0.5698,0.5811,0.05,100 +10000,0.5698,0.5811,0.05,100 +10000,0.5698,0.5811,0.05,100 +10000,0.5698,0.5811,0.05,100 +10000,0.5698,0.5811,0.05,100 +10000,0.58109,0.59261,0.05,100 +10000,0.58109,0.59261,0.05,100 +10000,0.58109,0.59261,0.05,100 +10000,0.58109,0.59261,0.05,100 +10000,0.58109,0.59261,0.05,100 +10000,0.58109,0.59261,0.05,100 +10000,0.58109,0.59261,0.05,100 +10000,0.58109,0.59261,0.05,100 +10000,0.58109,0.59261,0.05,100 +10000,0.58109,0.59261,0.05,100 +10000,0.58109,0.59261,0.05,100 +10000,0.5926,0.60435,0.05,100 +10000,0.5926,0.60435,0.05,100 +10000,0.5926,0.60435,0.05,100 +10000,0.5926,0.60435,0.05,100 +10000,0.5926,0.60435,0.05,100 +10000,0.5926,0.60435,0.05,100 +10000,0.5926,0.60435,0.05,100 +10000,0.5926,0.60435,0.05,100 +10000,0.5926,0.60435,0.05,100 +10000,0.5926,0.60435,0.05,100 +10000,0.5926,0.60435,0.05,100 +10000,0.5926,0.60435,0.05,100 +10000,0.60434,0.61632,0.05,100 +10000,0.60434,0.61632,0.05,100 +10000,0.60434,0.61632,0.05,100 +10000,0.60434,0.61632,0.05,100 +10000,0.60434,0.61632,0.05,100 +10000,0.60434,0.61632,0.05,100 +10000,0.60434,0.61632,0.05,100 +10000,0.60434,0.61632,0.05,100 +10000,0.60434,0.61632,0.05,100 +10000,0.60434,0.61632,0.05,100 +10000,0.60434,0.61632,0.05,100 +10000,0.60434,0.61632,0.05,100 +10000,0.61631,0.62853,0.05,100 +10000,0.61631,0.62853,0.05,100 +10000,0.61631,0.62853,0.05,100 +10000,0.61631,0.62853,0.05,100 +10000,0.61631,0.62853,0.05,100 +10000,0.61631,0.62853,0.05,100 +10000,0.61631,0.62853,0.05,100 +10000,0.61631,0.62853,0.05,100 +10000,0.61631,0.62853,0.05,100 +10000,0.61631,0.62853,0.05,100 +10000,0.61631,0.62853,0.05,100 +10000,0.61631,0.62853,0.05,100 +10000,0.62852,0.64098,0.05,100 +10000,0.62852,0.64098,0.05,100 +10000,0.62852,0.64098,0.05,100 +10000,0.62852,0.64098,0.05,100 +10000,0.62852,0.64098,0.05,100 +10000,0.62852,0.64098,0.05,100 +10000,0.62852,0.64098,0.05,100 +10000,0.62852,0.64098,0.05,100 +10000,0.62852,0.64098,0.05,100 +10000,0.62852,0.64098,0.05,100 +10000,0.62852,0.64098,0.05,100 +10000,0.62852,0.64098,0.05,100 +10000,0.62852,0.64098,0.05,100 +10000,0.64097,0.65368,0.05,100 +10000,0.64097,0.65368,0.05,100 +10000,0.64097,0.65368,0.05,100 +10000,0.64097,0.65368,0.05,100 +10000,0.64097,0.65368,0.05,100 +10000,0.64097,0.65368,0.05,100 +10000,0.64097,0.65368,0.05,100 +10000,0.64097,0.65368,0.05,100 +10000,0.64097,0.65368,0.05,100 +10000,0.64097,0.65368,0.05,100 +10000,0.64097,0.65368,0.05,100 +10000,0.64097,0.65368,0.05,100 +10000,0.65367,0.66663,0.05,100 +10000,0.65367,0.66663,0.05,100 +10000,0.65367,0.66663,0.05,100 +10000,0.65367,0.66663,0.05,100 +10000,0.65367,0.66663,0.05,100 +10000,0.65367,0.66663,0.05,100 +10000,0.65367,0.66663,0.05,100 +10000,0.65367,0.66663,0.05,100 +10000,0.65367,0.66663,0.05,100 +10000,0.65367,0.66663,0.05,100 +10000,0.65367,0.66663,0.05,100 +10000,0.65367,0.66663,0.05,100 +10000,0.65367,0.66663,0.05,100 +10000,0.66662,0.67984,0.05,100 +10000,0.66662,0.67984,0.05,100 +10000,0.66662,0.67984,0.05,100 +10000,0.66662,0.67984,0.05,100 +10000,0.66662,0.67984,0.05,100 +10000,0.66662,0.67984,0.05,100 +10000,0.66662,0.67984,0.05,100 +10000,0.66662,0.67984,0.05,100 +10000,0.66662,0.67984,0.05,100 +10000,0.66662,0.67984,0.05,100 +10000,0.66662,0.67984,0.05,100 +10000,0.66662,0.67984,0.05,100 +10000,0.66662,0.67984,0.05,100 +10000,0.67983,0.69331,0.05,100 +10000,0.67983,0.69331,0.05,100 +10000,0.67983,0.69331,0.05,100 +10000,0.67983,0.69331,0.05,100 +10000,0.67983,0.69331,0.05,100 +10000,0.67983,0.69331,0.05,100 +10000,0.67983,0.69331,0.05,100 +10000,0.67983,0.69331,0.05,100 +10000,0.67983,0.69331,0.05,100 +10000,0.67983,0.69331,0.05,100 +10000,0.67983,0.69331,0.05,100 +10000,0.67983,0.69331,0.05,100 +10000,0.67983,0.69331,0.05,100 +10000,0.67983,0.69331,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,0.6933,0.70704,0.05,100 +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan +10000,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/data_10.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/data_10.csv new file mode 100644 index 00000000000..f8bba333145 --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/data_10.csv @@ -0,0 +1,1002 @@ +Time,"elementCenter:0","elementCenter:1","elementCenter:2","temperature" +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,0.07071,0.072112,0.05,-17.679 +1e+05,0.07071,0.072112,0.05,-17.679 +1e+05,0.07211,0.07354,0.05,-13.128 +1e+05,0.07351,0.074968,0.05,-8.6631 +1e+05,0.075155,0.076646,0.05,-3.5144 +1e+05,0.075155,0.076646,0.05,-3.5144 +1e+05,0.077046,0.078574,0.05,2.2548 +1e+05,0.077046,0.078574,0.05,2.2548 +1e+05,0.078936,0.080501,0.05,7.8811 +1e+05,0.078936,0.080501,0.05,7.8811 +1e+05,0.080826,0.082429,0.05,13.366 +1e+05,0.080826,0.082429,0.05,13.366 +1e+05,0.082716,0.084357,0.05,18.708 +1e+05,0.082716,0.084357,0.05,18.708 +1e+05,0.084607,0.086285,0.05,23.905 +1e+05,0.084607,0.086285,0.05,23.905 +1e+05,0.086497,0.088212,0.05,28.953 +1e+05,0.086497,0.088212,0.05,28.953 +1e+05,0.088387,0.09014,0.05,33.846 +1e+05,0.088387,0.09014,0.05,33.846 +1e+05,0.090278,0.092068,0.05,38.579 +1e+05,0.090278,0.092068,0.05,38.579 +1e+05,0.092168,0.093995,0.05,43.144 +1e+05,0.092168,0.093995,0.05,43.144 +1e+05,0.094031,0.095896,0.05,47.472 +1e+05,0.095885,0.097786,0.05,51.606 +1e+05,0.095885,0.097786,0.05,51.606 +1e+05,0.097776,0.099715,0.05,55.636 +1e+05,0.097776,0.099715,0.05,55.636 +1e+05,0.099704,0.10168,0.05,59.545 +1e+05,0.099704,0.10168,0.05,59.545 +1e+05,0.10167,0.10369,0.05,63.317 +1e+05,0.10167,0.10369,0.05,63.317 +1e+05,0.10368,0.10573,0.05,66.937 +1e+05,0.10368,0.10573,0.05,66.937 +1e+05,0.10572,0.10782,0.05,70.39 +1e+05,0.10572,0.10782,0.05,70.39 +1e+05,0.10781,0.10995,0.05,73.659 +1e+05,0.10781,0.10995,0.05,73.659 +1e+05,0.10993,0.11211,0.05,76.734 +1e+05,0.10993,0.11211,0.05,76.734 +1e+05,0.10993,0.11211,0.05,76.734 +1e+05,0.1121,0.11433,0.05,79.604 +1e+05,0.1121,0.11433,0.05,79.604 +1e+05,0.11432,0.11658,0.05,82.259 +1e+05,0.11432,0.11658,0.05,82.259 +1e+05,0.11657,0.11888,0.05,84.696 +1e+05,0.11657,0.11888,0.05,84.696 +1e+05,0.11887,0.12123,0.05,86.911 +1e+05,0.11887,0.12123,0.05,86.911 +1e+05,0.11887,0.12123,0.05,86.911 +1e+05,0.12122,0.12362,0.05,88.906 +1e+05,0.12122,0.12362,0.05,88.906 +1e+05,0.12361,0.12607,0.05,90.684 +1e+05,0.12361,0.12607,0.05,90.684 +1e+05,0.12361,0.12607,0.05,90.684 +1e+05,0.12605,0.12855,0.05,92.253 +1e+05,0.12605,0.12855,0.05,92.253 +1e+05,0.12854,0.13109,0.05,93.623 +1e+05,0.12854,0.13109,0.05,93.623 +1e+05,0.12854,0.13109,0.05,93.623 +1e+05,0.13108,0.13368,0.05,94.805 +1e+05,0.13108,0.13368,0.05,94.805 +1e+05,0.13367,0.13632,0.05,95.814 +1e+05,0.13367,0.13632,0.05,95.814 +1e+05,0.13367,0.13632,0.05,95.814 +1e+05,0.13631,0.13901,0.05,96.664 +1e+05,0.13631,0.13901,0.05,96.664 +1e+05,0.13631,0.13901,0.05,96.664 +1e+05,0.139,0.14176,0.05,97.373 +1e+05,0.139,0.14176,0.05,97.373 +1e+05,0.14175,0.14456,0.05,97.956 +1e+05,0.14175,0.14456,0.05,97.956 +1e+05,0.14175,0.14456,0.05,97.956 +1e+05,0.14455,0.14742,0.05,98.429 +1e+05,0.14455,0.14742,0.05,98.429 +1e+05,0.14455,0.14742,0.05,98.429 +1e+05,0.1474,0.15033,0.05,98.808 +1e+05,0.1474,0.15033,0.05,98.808 +1e+05,0.1474,0.15033,0.05,98.808 +1e+05,0.15032,0.1533,0.05,99.108 +1e+05,0.15032,0.1533,0.05,99.108 +1e+05,0.15032,0.1533,0.05,99.108 +1e+05,0.15329,0.15633,0.05,99.341 +1e+05,0.15329,0.15633,0.05,99.341 +1e+05,0.15329,0.15633,0.05,99.341 +1e+05,0.15632,0.15942,0.05,99.521 +1e+05,0.15632,0.15942,0.05,99.521 +1e+05,0.15632,0.15942,0.05,99.521 +1e+05,0.15941,0.16257,0.05,99.656 +1e+05,0.15941,0.16257,0.05,99.656 +1e+05,0.15941,0.16257,0.05,99.656 +1e+05,0.16256,0.16578,0.05,99.757 +1e+05,0.16256,0.16578,0.05,99.757 +1e+05,0.16256,0.16578,0.05,99.757 +1e+05,0.16577,0.16906,0.05,99.831 +1e+05,0.16577,0.16906,0.05,99.831 +1e+05,0.16577,0.16906,0.05,99.831 +1e+05,0.16577,0.16906,0.05,99.831 +1e+05,0.16905,0.1724,0.05,99.885 +1e+05,0.16905,0.1724,0.05,99.885 +1e+05,0.16905,0.1724,0.05,99.885 +1e+05,0.17239,0.1758,0.05,99.922 +1e+05,0.17239,0.1758,0.05,99.922 +1e+05,0.17239,0.1758,0.05,99.922 +1e+05,0.17579,0.17928,0.05,99.949 +1e+05,0.17579,0.17928,0.05,99.949 +1e+05,0.17579,0.17928,0.05,99.949 +1e+05,0.17579,0.17928,0.05,99.949 +1e+05,0.17927,0.18282,0.05,99.967 +1e+05,0.17927,0.18282,0.05,99.967 +1e+05,0.17927,0.18282,0.05,99.967 +1e+05,0.18281,0.18644,0.05,99.979 +1e+05,0.18281,0.18644,0.05,99.979 +1e+05,0.18281,0.18644,0.05,99.979 +1e+05,0.18281,0.18644,0.05,99.979 +1e+05,0.18643,0.19013,0.05,99.987 +1e+05,0.18643,0.19013,0.05,99.987 +1e+05,0.18643,0.19013,0.05,99.987 +1e+05,0.18643,0.19013,0.05,99.987 +1e+05,0.19011,0.19388,0.05,99.992 +1e+05,0.19011,0.19388,0.05,99.992 +1e+05,0.19011,0.19388,0.05,99.992 +1e+05,0.19387,0.19772,0.05,99.995 +1e+05,0.19387,0.19772,0.05,99.995 +1e+05,0.19387,0.19772,0.05,99.995 +1e+05,0.19387,0.19772,0.05,99.995 +1e+05,0.19771,0.20163,0.05,99.997 +1e+05,0.19771,0.20163,0.05,99.997 +1e+05,0.19771,0.20163,0.05,99.997 +1e+05,0.19771,0.20163,0.05,99.997 +1e+05,0.20162,0.20562,0.05,99.998 +1e+05,0.20162,0.20562,0.05,99.998 +1e+05,0.20162,0.20562,0.05,99.998 +1e+05,0.20162,0.20562,0.05,99.998 +1e+05,0.2056,0.20968,0.05,99.999 +1e+05,0.2056,0.20968,0.05,99.999 +1e+05,0.2056,0.20968,0.05,99.999 +1e+05,0.2056,0.20968,0.05,99.999 +1e+05,0.20967,0.21383,0.05,99.999 +1e+05,0.20967,0.21383,0.05,99.999 +1e+05,0.20967,0.21383,0.05,99.999 +1e+05,0.20967,0.21383,0.05,99.999 +1e+05,0.21382,0.21806,0.05,100 +1e+05,0.21382,0.21806,0.05,100 +1e+05,0.21382,0.21806,0.05,100 +1e+05,0.21382,0.21806,0.05,100 +1e+05,0.21382,0.21806,0.05,100 +1e+05,0.21805,0.22237,0.05,100 +1e+05,0.21805,0.22237,0.05,100 +1e+05,0.21805,0.22237,0.05,100 +1e+05,0.21805,0.22237,0.05,100 +1e+05,0.22236,0.22677,0.05,100 +1e+05,0.22236,0.22677,0.05,100 +1e+05,0.22236,0.22677,0.05,100 +1e+05,0.22236,0.22677,0.05,100 +1e+05,0.22676,0.23125,0.05,100 +1e+05,0.22676,0.23125,0.05,100 +1e+05,0.22676,0.23125,0.05,100 +1e+05,0.22676,0.23125,0.05,100 +1e+05,0.22676,0.23125,0.05,100 +1e+05,0.23124,0.23583,0.05,100 +1e+05,0.23124,0.23583,0.05,100 +1e+05,0.23124,0.23583,0.05,100 +1e+05,0.23124,0.23583,0.05,100 +1e+05,0.23582,0.2405,0.05,100 +1e+05,0.23582,0.2405,0.05,100 +1e+05,0.23582,0.2405,0.05,100 +1e+05,0.23582,0.2405,0.05,100 +1e+05,0.23582,0.2405,0.05,100 +1e+05,0.24048,0.24525,0.05,100 +1e+05,0.24048,0.24525,0.05,100 +1e+05,0.24048,0.24525,0.05,100 +1e+05,0.24048,0.24525,0.05,100 +1e+05,0.24048,0.24525,0.05,100 +1e+05,0.24524,0.25011,0.05,100 +1e+05,0.24524,0.25011,0.05,100 +1e+05,0.24524,0.25011,0.05,100 +1e+05,0.24524,0.25011,0.05,100 +1e+05,0.24524,0.25011,0.05,100 +1e+05,0.25009,0.25505,0.05,100 +1e+05,0.25009,0.25505,0.05,100 +1e+05,0.25009,0.25505,0.05,100 +1e+05,0.25009,0.25505,0.05,100 +1e+05,0.25009,0.25505,0.05,100 +1e+05,0.25504,0.2601,0.05,100 +1e+05,0.25504,0.2601,0.05,100 +1e+05,0.25504,0.2601,0.05,100 +1e+05,0.25504,0.2601,0.05,100 +1e+05,0.25504,0.2601,0.05,100 +1e+05,0.26009,0.26525,0.05,100 +1e+05,0.26009,0.26525,0.05,100 +1e+05,0.26009,0.26525,0.05,100 +1e+05,0.26009,0.26525,0.05,100 +1e+05,0.26009,0.26525,0.05,100 +1e+05,0.26524,0.2705,0.05,100 +1e+05,0.26524,0.2705,0.05,100 +1e+05,0.26524,0.2705,0.05,100 +1e+05,0.26524,0.2705,0.05,100 +1e+05,0.26524,0.2705,0.05,100 +1e+05,0.27048,0.27585,0.05,100 +1e+05,0.27048,0.27585,0.05,100 +1e+05,0.27048,0.27585,0.05,100 +1e+05,0.27048,0.27585,0.05,100 +1e+05,0.27048,0.27585,0.05,100 +1e+05,0.27584,0.28131,0.05,100 +1e+05,0.27584,0.28131,0.05,100 +1e+05,0.27584,0.28131,0.05,100 +1e+05,0.27584,0.28131,0.05,100 +1e+05,0.27584,0.28131,0.05,100 +1e+05,0.27584,0.28131,0.05,100 +1e+05,0.2813,0.28687,0.05,100 +1e+05,0.2813,0.28687,0.05,100 +1e+05,0.2813,0.28687,0.05,100 +1e+05,0.2813,0.28687,0.05,100 +1e+05,0.2813,0.28687,0.05,100 +1e+05,0.28686,0.29255,0.05,100 +1e+05,0.28686,0.29255,0.05,100 +1e+05,0.28686,0.29255,0.05,100 +1e+05,0.28686,0.29255,0.05,100 +1e+05,0.28686,0.29255,0.05,100 +1e+05,0.28686,0.29255,0.05,100 +1e+05,0.29254,0.29834,0.05,100 +1e+05,0.29254,0.29834,0.05,100 +1e+05,0.29254,0.29834,0.05,100 +1e+05,0.29254,0.29834,0.05,100 +1e+05,0.29254,0.29834,0.05,100 +1e+05,0.29254,0.29834,0.05,100 +1e+05,0.29833,0.30425,0.05,100 +1e+05,0.29833,0.30425,0.05,100 +1e+05,0.29833,0.30425,0.05,100 +1e+05,0.29833,0.30425,0.05,100 +1e+05,0.29833,0.30425,0.05,100 +1e+05,0.29833,0.30425,0.05,100 +1e+05,0.30424,0.31027,0.05,100 +1e+05,0.30424,0.31027,0.05,100 +1e+05,0.30424,0.31027,0.05,100 +1e+05,0.30424,0.31027,0.05,100 +1e+05,0.30424,0.31027,0.05,100 +1e+05,0.30424,0.31027,0.05,100 +1e+05,0.31026,0.31641,0.05,100 +1e+05,0.31026,0.31641,0.05,100 +1e+05,0.31026,0.31641,0.05,100 +1e+05,0.31026,0.31641,0.05,100 +1e+05,0.31026,0.31641,0.05,100 +1e+05,0.31026,0.31641,0.05,100 +1e+05,0.3164,0.32267,0.05,100 +1e+05,0.3164,0.32267,0.05,100 +1e+05,0.3164,0.32267,0.05,100 +1e+05,0.3164,0.32267,0.05,100 +1e+05,0.3164,0.32267,0.05,100 +1e+05,0.3164,0.32267,0.05,100 +1e+05,0.32266,0.32906,0.05,100 +1e+05,0.32266,0.32906,0.05,100 +1e+05,0.32266,0.32906,0.05,100 +1e+05,0.32266,0.32906,0.05,100 +1e+05,0.32266,0.32906,0.05,100 +1e+05,0.32266,0.32906,0.05,100 +1e+05,0.32266,0.32906,0.05,100 +1e+05,0.32905,0.33558,0.05,100 +1e+05,0.32905,0.33558,0.05,100 +1e+05,0.32905,0.33558,0.05,100 +1e+05,0.32905,0.33558,0.05,100 +1e+05,0.32905,0.33558,0.05,100 +1e+05,0.32905,0.33558,0.05,100 +1e+05,0.33556,0.34222,0.05,100 +1e+05,0.33556,0.34222,0.05,100 +1e+05,0.33556,0.34222,0.05,100 +1e+05,0.33556,0.34222,0.05,100 +1e+05,0.33556,0.34222,0.05,100 +1e+05,0.33556,0.34222,0.05,100 +1e+05,0.33556,0.34222,0.05,100 +1e+05,0.34221,0.34899,0.05,100 +1e+05,0.34221,0.34899,0.05,100 +1e+05,0.34221,0.34899,0.05,100 +1e+05,0.34221,0.34899,0.05,100 +1e+05,0.34221,0.34899,0.05,100 +1e+05,0.34221,0.34899,0.05,100 +1e+05,0.34221,0.34899,0.05,100 +1e+05,0.34898,0.3559,0.05,100 +1e+05,0.34898,0.3559,0.05,100 +1e+05,0.34898,0.3559,0.05,100 +1e+05,0.34898,0.3559,0.05,100 +1e+05,0.34898,0.3559,0.05,100 +1e+05,0.34898,0.3559,0.05,100 +1e+05,0.35589,0.36295,0.05,100 +1e+05,0.35589,0.36295,0.05,100 +1e+05,0.35589,0.36295,0.05,100 +1e+05,0.35589,0.36295,0.05,100 +1e+05,0.35589,0.36295,0.05,100 +1e+05,0.35589,0.36295,0.05,100 +1e+05,0.35589,0.36295,0.05,100 +1e+05,0.36294,0.37013,0.05,100 +1e+05,0.36294,0.37013,0.05,100 +1e+05,0.36294,0.37013,0.05,100 +1e+05,0.36294,0.37013,0.05,100 +1e+05,0.36294,0.37013,0.05,100 +1e+05,0.36294,0.37013,0.05,100 +1e+05,0.36294,0.37013,0.05,100 +1e+05,0.36294,0.37013,0.05,100 +1e+05,0.37012,0.37746,0.05,100 +1e+05,0.37012,0.37746,0.05,100 +1e+05,0.37012,0.37746,0.05,100 +1e+05,0.37012,0.37746,0.05,100 +1e+05,0.37012,0.37746,0.05,100 +1e+05,0.37012,0.37746,0.05,100 +1e+05,0.37012,0.37746,0.05,100 +1e+05,0.37745,0.38494,0.05,100 +1e+05,0.37745,0.38494,0.05,100 +1e+05,0.37745,0.38494,0.05,100 +1e+05,0.37745,0.38494,0.05,100 +1e+05,0.37745,0.38494,0.05,100 +1e+05,0.37745,0.38494,0.05,100 +1e+05,0.37745,0.38494,0.05,100 +1e+05,0.38493,0.39256,0.05,100 +1e+05,0.38493,0.39256,0.05,100 +1e+05,0.38493,0.39256,0.05,100 +1e+05,0.38493,0.39256,0.05,100 +1e+05,0.38493,0.39256,0.05,100 +1e+05,0.38493,0.39256,0.05,100 +1e+05,0.38493,0.39256,0.05,100 +1e+05,0.38493,0.39256,0.05,100 +1e+05,0.39255,0.40033,0.05,100 +1e+05,0.39255,0.40033,0.05,100 +1e+05,0.39255,0.40033,0.05,100 +1e+05,0.39255,0.40033,0.05,100 +1e+05,0.39255,0.40033,0.05,100 +1e+05,0.39255,0.40033,0.05,100 +1e+05,0.39255,0.40033,0.05,100 +1e+05,0.39255,0.40033,0.05,100 +1e+05,0.40032,0.40826,0.05,100 +1e+05,0.40032,0.40826,0.05,100 +1e+05,0.40032,0.40826,0.05,100 +1e+05,0.40032,0.40826,0.05,100 +1e+05,0.40032,0.40826,0.05,100 +1e+05,0.40032,0.40826,0.05,100 +1e+05,0.40032,0.40826,0.05,100 +1e+05,0.40032,0.40826,0.05,100 +1e+05,0.40825,0.41634,0.05,100 +1e+05,0.40825,0.41634,0.05,100 +1e+05,0.40825,0.41634,0.05,100 +1e+05,0.40825,0.41634,0.05,100 +1e+05,0.40825,0.41634,0.05,100 +1e+05,0.40825,0.41634,0.05,100 +1e+05,0.40825,0.41634,0.05,100 +1e+05,0.40825,0.41634,0.05,100 +1e+05,0.41633,0.42459,0.05,100 +1e+05,0.41633,0.42459,0.05,100 +1e+05,0.41633,0.42459,0.05,100 +1e+05,0.41633,0.42459,0.05,100 +1e+05,0.41633,0.42459,0.05,100 +1e+05,0.41633,0.42459,0.05,100 +1e+05,0.41633,0.42459,0.05,100 +1e+05,0.41633,0.42459,0.05,100 +1e+05,0.42458,0.433,0.05,100 +1e+05,0.42458,0.433,0.05,100 +1e+05,0.42458,0.433,0.05,100 +1e+05,0.42458,0.433,0.05,100 +1e+05,0.42458,0.433,0.05,100 +1e+05,0.42458,0.433,0.05,100 +1e+05,0.42458,0.433,0.05,100 +1e+05,0.42458,0.433,0.05,100 +1e+05,0.42458,0.433,0.05,100 +1e+05,0.43298,0.44157,0.05,100 +1e+05,0.43298,0.44157,0.05,100 +1e+05,0.43298,0.44157,0.05,100 +1e+05,0.43298,0.44157,0.05,100 +1e+05,0.43298,0.44157,0.05,100 +1e+05,0.43298,0.44157,0.05,100 +1e+05,0.43298,0.44157,0.05,100 +1e+05,0.43298,0.44157,0.05,100 +1e+05,0.44156,0.45031,0.05,100 +1e+05,0.44156,0.45031,0.05,100 +1e+05,0.44156,0.45031,0.05,100 +1e+05,0.44156,0.45031,0.05,100 +1e+05,0.44156,0.45031,0.05,100 +1e+05,0.44156,0.45031,0.05,100 +1e+05,0.44156,0.45031,0.05,100 +1e+05,0.44156,0.45031,0.05,100 +1e+05,0.44156,0.45031,0.05,100 +1e+05,0.4503,0.45923,0.05,100 +1e+05,0.4503,0.45923,0.05,100 +1e+05,0.4503,0.45923,0.05,100 +1e+05,0.4503,0.45923,0.05,100 +1e+05,0.4503,0.45923,0.05,100 +1e+05,0.4503,0.45923,0.05,100 +1e+05,0.4503,0.45923,0.05,100 +1e+05,0.4503,0.45923,0.05,100 +1e+05,0.4503,0.45923,0.05,100 +1e+05,0.45922,0.46833,0.05,100 +1e+05,0.45922,0.46833,0.05,100 +1e+05,0.45922,0.46833,0.05,100 +1e+05,0.45922,0.46833,0.05,100 +1e+05,0.45922,0.46833,0.05,100 +1e+05,0.45922,0.46833,0.05,100 +1e+05,0.45922,0.46833,0.05,100 +1e+05,0.45922,0.46833,0.05,100 +1e+05,0.45922,0.46833,0.05,100 +1e+05,0.46832,0.4776,0.05,100 +1e+05,0.46832,0.4776,0.05,100 +1e+05,0.46832,0.4776,0.05,100 +1e+05,0.46832,0.4776,0.05,100 +1e+05,0.46832,0.4776,0.05,100 +1e+05,0.46832,0.4776,0.05,100 +1e+05,0.46832,0.4776,0.05,100 +1e+05,0.46832,0.4776,0.05,100 +1e+05,0.46832,0.4776,0.05,100 +1e+05,0.47759,0.48706,0.05,100 +1e+05,0.47759,0.48706,0.05,100 +1e+05,0.47759,0.48706,0.05,100 +1e+05,0.47759,0.48706,0.05,100 +1e+05,0.47759,0.48706,0.05,100 +1e+05,0.47759,0.48706,0.05,100 +1e+05,0.47759,0.48706,0.05,100 +1e+05,0.47759,0.48706,0.05,100 +1e+05,0.47759,0.48706,0.05,100 +1e+05,0.47759,0.48706,0.05,100 +1e+05,0.48705,0.49671,0.05,100 +1e+05,0.48705,0.49671,0.05,100 +1e+05,0.48705,0.49671,0.05,100 +1e+05,0.48705,0.49671,0.05,100 +1e+05,0.48705,0.49671,0.05,100 +1e+05,0.48705,0.49671,0.05,100 +1e+05,0.48705,0.49671,0.05,100 +1e+05,0.48705,0.49671,0.05,100 +1e+05,0.48705,0.49671,0.05,100 +1e+05,0.4967,0.50655,0.05,100 +1e+05,0.4967,0.50655,0.05,100 +1e+05,0.4967,0.50655,0.05,100 +1e+05,0.4967,0.50655,0.05,100 +1e+05,0.4967,0.50655,0.05,100 +1e+05,0.4967,0.50655,0.05,100 +1e+05,0.4967,0.50655,0.05,100 +1e+05,0.4967,0.50655,0.05,100 +1e+05,0.4967,0.50655,0.05,100 +1e+05,0.4967,0.50655,0.05,100 +1e+05,0.50654,0.51658,0.05,100 +1e+05,0.50654,0.51658,0.05,100 +1e+05,0.50654,0.51658,0.05,100 +1e+05,0.50654,0.51658,0.05,100 +1e+05,0.50654,0.51658,0.05,100 +1e+05,0.50654,0.51658,0.05,100 +1e+05,0.50654,0.51658,0.05,100 +1e+05,0.50654,0.51658,0.05,100 +1e+05,0.50654,0.51658,0.05,100 +1e+05,0.50654,0.51658,0.05,100 +1e+05,0.51657,0.52681,0.05,100 +1e+05,0.51657,0.52681,0.05,100 +1e+05,0.51657,0.52681,0.05,100 +1e+05,0.51657,0.52681,0.05,100 +1e+05,0.51657,0.52681,0.05,100 +1e+05,0.51657,0.52681,0.05,100 +1e+05,0.51657,0.52681,0.05,100 +1e+05,0.51657,0.52681,0.05,100 +1e+05,0.51657,0.52681,0.05,100 +1e+05,0.51657,0.52681,0.05,100 +1e+05,0.5268,0.53725,0.05,100 +1e+05,0.5268,0.53725,0.05,100 +1e+05,0.5268,0.53725,0.05,100 +1e+05,0.5268,0.53725,0.05,100 +1e+05,0.5268,0.53725,0.05,100 +1e+05,0.5268,0.53725,0.05,100 +1e+05,0.5268,0.53725,0.05,100 +1e+05,0.5268,0.53725,0.05,100 +1e+05,0.5268,0.53725,0.05,100 +1e+05,0.5268,0.53725,0.05,100 +1e+05,0.5268,0.53725,0.05,100 +1e+05,0.53724,0.54789,0.05,100 +1e+05,0.53724,0.54789,0.05,100 +1e+05,0.53724,0.54789,0.05,100 +1e+05,0.53724,0.54789,0.05,100 +1e+05,0.53724,0.54789,0.05,100 +1e+05,0.53724,0.54789,0.05,100 +1e+05,0.53724,0.54789,0.05,100 +1e+05,0.53724,0.54789,0.05,100 +1e+05,0.53724,0.54789,0.05,100 +1e+05,0.53724,0.54789,0.05,100 +1e+05,0.54788,0.55874,0.05,100 +1e+05,0.54788,0.55874,0.05,100 +1e+05,0.54788,0.55874,0.05,100 +1e+05,0.54788,0.55874,0.05,100 +1e+05,0.54788,0.55874,0.05,100 +1e+05,0.54788,0.55874,0.05,100 +1e+05,0.54788,0.55874,0.05,100 +1e+05,0.54788,0.55874,0.05,100 +1e+05,0.54788,0.55874,0.05,100 +1e+05,0.54788,0.55874,0.05,100 +1e+05,0.54788,0.55874,0.05,100 +1e+05,0.55873,0.56981,0.05,100 +1e+05,0.55873,0.56981,0.05,100 +1e+05,0.55873,0.56981,0.05,100 +1e+05,0.55873,0.56981,0.05,100 +1e+05,0.55873,0.56981,0.05,100 +1e+05,0.55873,0.56981,0.05,100 +1e+05,0.55873,0.56981,0.05,100 +1e+05,0.55873,0.56981,0.05,100 +1e+05,0.55873,0.56981,0.05,100 +1e+05,0.55873,0.56981,0.05,100 +1e+05,0.55873,0.56981,0.05,100 +1e+05,0.5698,0.5811,0.05,100 +1e+05,0.5698,0.5811,0.05,100 +1e+05,0.5698,0.5811,0.05,100 +1e+05,0.5698,0.5811,0.05,100 +1e+05,0.5698,0.5811,0.05,100 +1e+05,0.5698,0.5811,0.05,100 +1e+05,0.5698,0.5811,0.05,100 +1e+05,0.5698,0.5811,0.05,100 +1e+05,0.5698,0.5811,0.05,100 +1e+05,0.5698,0.5811,0.05,100 +1e+05,0.5698,0.5811,0.05,100 +1e+05,0.5698,0.5811,0.05,100 +1e+05,0.58109,0.59261,0.05,100 +1e+05,0.58109,0.59261,0.05,100 +1e+05,0.58109,0.59261,0.05,100 +1e+05,0.58109,0.59261,0.05,100 +1e+05,0.58109,0.59261,0.05,100 +1e+05,0.58109,0.59261,0.05,100 +1e+05,0.58109,0.59261,0.05,100 +1e+05,0.58109,0.59261,0.05,100 +1e+05,0.58109,0.59261,0.05,100 +1e+05,0.58109,0.59261,0.05,100 +1e+05,0.58109,0.59261,0.05,100 +1e+05,0.5926,0.60435,0.05,100 +1e+05,0.5926,0.60435,0.05,100 +1e+05,0.5926,0.60435,0.05,100 +1e+05,0.5926,0.60435,0.05,100 +1e+05,0.5926,0.60435,0.05,100 +1e+05,0.5926,0.60435,0.05,100 +1e+05,0.5926,0.60435,0.05,100 +1e+05,0.5926,0.60435,0.05,100 +1e+05,0.5926,0.60435,0.05,100 +1e+05,0.5926,0.60435,0.05,100 +1e+05,0.5926,0.60435,0.05,100 +1e+05,0.5926,0.60435,0.05,100 +1e+05,0.60434,0.61632,0.05,100 +1e+05,0.60434,0.61632,0.05,100 +1e+05,0.60434,0.61632,0.05,100 +1e+05,0.60434,0.61632,0.05,100 +1e+05,0.60434,0.61632,0.05,100 +1e+05,0.60434,0.61632,0.05,100 +1e+05,0.60434,0.61632,0.05,100 +1e+05,0.60434,0.61632,0.05,100 +1e+05,0.60434,0.61632,0.05,100 +1e+05,0.60434,0.61632,0.05,100 +1e+05,0.60434,0.61632,0.05,100 +1e+05,0.60434,0.61632,0.05,100 +1e+05,0.61631,0.62853,0.05,100 +1e+05,0.61631,0.62853,0.05,100 +1e+05,0.61631,0.62853,0.05,100 +1e+05,0.61631,0.62853,0.05,100 +1e+05,0.61631,0.62853,0.05,100 +1e+05,0.61631,0.62853,0.05,100 +1e+05,0.61631,0.62853,0.05,100 +1e+05,0.61631,0.62853,0.05,100 +1e+05,0.61631,0.62853,0.05,100 +1e+05,0.61631,0.62853,0.05,100 +1e+05,0.61631,0.62853,0.05,100 +1e+05,0.61631,0.62853,0.05,100 +1e+05,0.62852,0.64098,0.05,100 +1e+05,0.62852,0.64098,0.05,100 +1e+05,0.62852,0.64098,0.05,100 +1e+05,0.62852,0.64098,0.05,100 +1e+05,0.62852,0.64098,0.05,100 +1e+05,0.62852,0.64098,0.05,100 +1e+05,0.62852,0.64098,0.05,100 +1e+05,0.62852,0.64098,0.05,100 +1e+05,0.62852,0.64098,0.05,100 +1e+05,0.62852,0.64098,0.05,100 +1e+05,0.62852,0.64098,0.05,100 +1e+05,0.62852,0.64098,0.05,100 +1e+05,0.62852,0.64098,0.05,100 +1e+05,0.64097,0.65368,0.05,100 +1e+05,0.64097,0.65368,0.05,100 +1e+05,0.64097,0.65368,0.05,100 +1e+05,0.64097,0.65368,0.05,100 +1e+05,0.64097,0.65368,0.05,100 +1e+05,0.64097,0.65368,0.05,100 +1e+05,0.64097,0.65368,0.05,100 +1e+05,0.64097,0.65368,0.05,100 +1e+05,0.64097,0.65368,0.05,100 +1e+05,0.64097,0.65368,0.05,100 +1e+05,0.64097,0.65368,0.05,100 +1e+05,0.64097,0.65368,0.05,100 +1e+05,0.65367,0.66663,0.05,100 +1e+05,0.65367,0.66663,0.05,100 +1e+05,0.65367,0.66663,0.05,100 +1e+05,0.65367,0.66663,0.05,100 +1e+05,0.65367,0.66663,0.05,100 +1e+05,0.65367,0.66663,0.05,100 +1e+05,0.65367,0.66663,0.05,100 +1e+05,0.65367,0.66663,0.05,100 +1e+05,0.65367,0.66663,0.05,100 +1e+05,0.65367,0.66663,0.05,100 +1e+05,0.65367,0.66663,0.05,100 +1e+05,0.65367,0.66663,0.05,100 +1e+05,0.65367,0.66663,0.05,100 +1e+05,0.66662,0.67984,0.05,100 +1e+05,0.66662,0.67984,0.05,100 +1e+05,0.66662,0.67984,0.05,100 +1e+05,0.66662,0.67984,0.05,100 +1e+05,0.66662,0.67984,0.05,100 +1e+05,0.66662,0.67984,0.05,100 +1e+05,0.66662,0.67984,0.05,100 +1e+05,0.66662,0.67984,0.05,100 +1e+05,0.66662,0.67984,0.05,100 +1e+05,0.66662,0.67984,0.05,100 +1e+05,0.66662,0.67984,0.05,100 +1e+05,0.66662,0.67984,0.05,100 +1e+05,0.66662,0.67984,0.05,100 +1e+05,0.67983,0.69331,0.05,100 +1e+05,0.67983,0.69331,0.05,100 +1e+05,0.67983,0.69331,0.05,100 +1e+05,0.67983,0.69331,0.05,100 +1e+05,0.67983,0.69331,0.05,100 +1e+05,0.67983,0.69331,0.05,100 +1e+05,0.67983,0.69331,0.05,100 +1e+05,0.67983,0.69331,0.05,100 +1e+05,0.67983,0.69331,0.05,100 +1e+05,0.67983,0.69331,0.05,100 +1e+05,0.67983,0.69331,0.05,100 +1e+05,0.67983,0.69331,0.05,100 +1e+05,0.67983,0.69331,0.05,100 +1e+05,0.67983,0.69331,0.05,100 +1e+05,0.6933,0.70704,0.05,100 +1e+05,0.6933,0.70704,0.05,100 +1e+05,0.6933,0.70704,0.05,100 +1e+05,0.6933,0.70704,0.05,100 +1e+05,0.6933,0.70704,0.05,100 +1e+05,0.6933,0.70704,0.05,100 +1e+05,0.6933,0.70704,0.05,100 +1e+05,0.6933,0.70704,0.05,100 +1e+05,0.6933,0.70704,0.05,100 +1e+05,0.6933,0.70704,0.05,100 +1e+05,0.6933,0.70704,0.05,100 +1e+05,0.6933,0.70704,0.05,100 +1e+05,0.6933,0.70704,0.05,100 +1e+05,0.6933,0.70704,0.05,100 +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan +1e+05,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/data_2.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/data_2.csv new file mode 100644 index 00000000000..52362b795f0 --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/data_2.csv @@ -0,0 +1,1002 @@ +Time,"elementCenter:0","elementCenter:1","elementCenter:2","temperature" +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,0.07071,0.072112,0.05,-15.478 +20000,0.07071,0.072112,0.05,-15.478 +20000,0.07211,0.07354,0.05,-6.6062 +20000,0.07351,0.074968,0.05,2.1009 +20000,0.075155,0.076646,0.05,12.127 +20000,0.075155,0.076646,0.05,12.127 +20000,0.077046,0.078574,0.05,23.273 +20000,0.077046,0.078574,0.05,23.273 +20000,0.078936,0.080501,0.05,33.948 +20000,0.078936,0.080501,0.05,33.948 +20000,0.080826,0.082429,0.05,44.021 +20000,0.080826,0.082429,0.05,44.021 +20000,0.082716,0.084357,0.05,53.356 +20000,0.082716,0.084357,0.05,53.356 +20000,0.084607,0.086285,0.05,61.822 +20000,0.084607,0.086285,0.05,61.822 +20000,0.086497,0.088212,0.05,69.322 +20000,0.086497,0.088212,0.05,69.322 +20000,0.088387,0.09014,0.05,75.802 +20000,0.088387,0.09014,0.05,75.802 +20000,0.090278,0.092068,0.05,81.26 +20000,0.090278,0.092068,0.05,81.26 +20000,0.092168,0.093995,0.05,85.744 +20000,0.092168,0.093995,0.05,85.744 +20000,0.094031,0.095896,0.05,89.288 +20000,0.095885,0.097786,0.05,92.071 +20000,0.095885,0.097786,0.05,92.071 +20000,0.097776,0.099715,0.05,94.256 +20000,0.097776,0.099715,0.05,94.256 +20000,0.099704,0.10168,0.05,95.926 +20000,0.099704,0.10168,0.05,95.926 +20000,0.10167,0.10369,0.05,97.173 +20000,0.10167,0.10369,0.05,97.173 +20000,0.10368,0.10573,0.05,98.08 +20000,0.10368,0.10573,0.05,98.08 +20000,0.10572,0.10782,0.05,98.724 +20000,0.10572,0.10782,0.05,98.724 +20000,0.10781,0.10995,0.05,99.171 +20000,0.10781,0.10995,0.05,99.171 +20000,0.10993,0.11211,0.05,99.473 +20000,0.10993,0.11211,0.05,99.473 +20000,0.10993,0.11211,0.05,99.473 +20000,0.1121,0.11433,0.05,99.672 +20000,0.1121,0.11433,0.05,99.672 +20000,0.11432,0.11658,0.05,99.801 +20000,0.11432,0.11658,0.05,99.801 +20000,0.11657,0.11888,0.05,99.882 +20000,0.11657,0.11888,0.05,99.882 +20000,0.11887,0.12123,0.05,99.931 +20000,0.11887,0.12123,0.05,99.931 +20000,0.11887,0.12123,0.05,99.931 +20000,0.12122,0.12362,0.05,99.961 +20000,0.12122,0.12362,0.05,99.961 +20000,0.12361,0.12607,0.05,99.978 +20000,0.12361,0.12607,0.05,99.978 +20000,0.12361,0.12607,0.05,99.978 +20000,0.12605,0.12855,0.05,99.988 +20000,0.12605,0.12855,0.05,99.988 +20000,0.12854,0.13109,0.05,99.994 +20000,0.12854,0.13109,0.05,99.994 +20000,0.12854,0.13109,0.05,99.994 +20000,0.13108,0.13368,0.05,99.997 +20000,0.13108,0.13368,0.05,99.997 +20000,0.13367,0.13632,0.05,99.998 +20000,0.13367,0.13632,0.05,99.998 +20000,0.13367,0.13632,0.05,99.998 +20000,0.13631,0.13901,0.05,99.999 +20000,0.13631,0.13901,0.05,99.999 +20000,0.13631,0.13901,0.05,99.999 +20000,0.139,0.14176,0.05,100 +20000,0.139,0.14176,0.05,100 +20000,0.14175,0.14456,0.05,100 +20000,0.14175,0.14456,0.05,100 +20000,0.14175,0.14456,0.05,100 +20000,0.14455,0.14742,0.05,100 +20000,0.14455,0.14742,0.05,100 +20000,0.14455,0.14742,0.05,100 +20000,0.1474,0.15033,0.05,100 +20000,0.1474,0.15033,0.05,100 +20000,0.1474,0.15033,0.05,100 +20000,0.15032,0.1533,0.05,100 +20000,0.15032,0.1533,0.05,100 +20000,0.15032,0.1533,0.05,100 +20000,0.15329,0.15633,0.05,100 +20000,0.15329,0.15633,0.05,100 +20000,0.15329,0.15633,0.05,100 +20000,0.15632,0.15942,0.05,100 +20000,0.15632,0.15942,0.05,100 +20000,0.15632,0.15942,0.05,100 +20000,0.15941,0.16257,0.05,100 +20000,0.15941,0.16257,0.05,100 +20000,0.15941,0.16257,0.05,100 +20000,0.16256,0.16578,0.05,100 +20000,0.16256,0.16578,0.05,100 +20000,0.16256,0.16578,0.05,100 +20000,0.16577,0.16906,0.05,100 +20000,0.16577,0.16906,0.05,100 +20000,0.16577,0.16906,0.05,100 +20000,0.16577,0.16906,0.05,100 +20000,0.16905,0.1724,0.05,100 +20000,0.16905,0.1724,0.05,100 +20000,0.16905,0.1724,0.05,100 +20000,0.17239,0.1758,0.05,100 +20000,0.17239,0.1758,0.05,100 +20000,0.17239,0.1758,0.05,100 +20000,0.17579,0.17928,0.05,100 +20000,0.17579,0.17928,0.05,100 +20000,0.17579,0.17928,0.05,100 +20000,0.17579,0.17928,0.05,100 +20000,0.17927,0.18282,0.05,100 +20000,0.17927,0.18282,0.05,100 +20000,0.17927,0.18282,0.05,100 +20000,0.18281,0.18644,0.05,100 +20000,0.18281,0.18644,0.05,100 +20000,0.18281,0.18644,0.05,100 +20000,0.18281,0.18644,0.05,100 +20000,0.18643,0.19013,0.05,100 +20000,0.18643,0.19013,0.05,100 +20000,0.18643,0.19013,0.05,100 +20000,0.18643,0.19013,0.05,100 +20000,0.19011,0.19388,0.05,100 +20000,0.19011,0.19388,0.05,100 +20000,0.19011,0.19388,0.05,100 +20000,0.19387,0.19772,0.05,100 +20000,0.19387,0.19772,0.05,100 +20000,0.19387,0.19772,0.05,100 +20000,0.19387,0.19772,0.05,100 +20000,0.19771,0.20163,0.05,100 +20000,0.19771,0.20163,0.05,100 +20000,0.19771,0.20163,0.05,100 +20000,0.19771,0.20163,0.05,100 +20000,0.20162,0.20562,0.05,100 +20000,0.20162,0.20562,0.05,100 +20000,0.20162,0.20562,0.05,100 +20000,0.20162,0.20562,0.05,100 +20000,0.2056,0.20968,0.05,100 +20000,0.2056,0.20968,0.05,100 +20000,0.2056,0.20968,0.05,100 +20000,0.2056,0.20968,0.05,100 +20000,0.20967,0.21383,0.05,100 +20000,0.20967,0.21383,0.05,100 +20000,0.20967,0.21383,0.05,100 +20000,0.20967,0.21383,0.05,100 +20000,0.21382,0.21806,0.05,100 +20000,0.21382,0.21806,0.05,100 +20000,0.21382,0.21806,0.05,100 +20000,0.21382,0.21806,0.05,100 +20000,0.21382,0.21806,0.05,100 +20000,0.21805,0.22237,0.05,100 +20000,0.21805,0.22237,0.05,100 +20000,0.21805,0.22237,0.05,100 +20000,0.21805,0.22237,0.05,100 +20000,0.22236,0.22677,0.05,100 +20000,0.22236,0.22677,0.05,100 +20000,0.22236,0.22677,0.05,100 +20000,0.22236,0.22677,0.05,100 +20000,0.22676,0.23125,0.05,100 +20000,0.22676,0.23125,0.05,100 +20000,0.22676,0.23125,0.05,100 +20000,0.22676,0.23125,0.05,100 +20000,0.22676,0.23125,0.05,100 +20000,0.23124,0.23583,0.05,100 +20000,0.23124,0.23583,0.05,100 +20000,0.23124,0.23583,0.05,100 +20000,0.23124,0.23583,0.05,100 +20000,0.23582,0.2405,0.05,100 +20000,0.23582,0.2405,0.05,100 +20000,0.23582,0.2405,0.05,100 +20000,0.23582,0.2405,0.05,100 +20000,0.23582,0.2405,0.05,100 +20000,0.24048,0.24525,0.05,100 +20000,0.24048,0.24525,0.05,100 +20000,0.24048,0.24525,0.05,100 +20000,0.24048,0.24525,0.05,100 +20000,0.24048,0.24525,0.05,100 +20000,0.24524,0.25011,0.05,100 +20000,0.24524,0.25011,0.05,100 +20000,0.24524,0.25011,0.05,100 +20000,0.24524,0.25011,0.05,100 +20000,0.24524,0.25011,0.05,100 +20000,0.25009,0.25505,0.05,100 +20000,0.25009,0.25505,0.05,100 +20000,0.25009,0.25505,0.05,100 +20000,0.25009,0.25505,0.05,100 +20000,0.25009,0.25505,0.05,100 +20000,0.25504,0.2601,0.05,100 +20000,0.25504,0.2601,0.05,100 +20000,0.25504,0.2601,0.05,100 +20000,0.25504,0.2601,0.05,100 +20000,0.25504,0.2601,0.05,100 +20000,0.26009,0.26525,0.05,100 +20000,0.26009,0.26525,0.05,100 +20000,0.26009,0.26525,0.05,100 +20000,0.26009,0.26525,0.05,100 +20000,0.26009,0.26525,0.05,100 +20000,0.26524,0.2705,0.05,100 +20000,0.26524,0.2705,0.05,100 +20000,0.26524,0.2705,0.05,100 +20000,0.26524,0.2705,0.05,100 +20000,0.26524,0.2705,0.05,100 +20000,0.27048,0.27585,0.05,100 +20000,0.27048,0.27585,0.05,100 +20000,0.27048,0.27585,0.05,100 +20000,0.27048,0.27585,0.05,100 +20000,0.27048,0.27585,0.05,100 +20000,0.27584,0.28131,0.05,100 +20000,0.27584,0.28131,0.05,100 +20000,0.27584,0.28131,0.05,100 +20000,0.27584,0.28131,0.05,100 +20000,0.27584,0.28131,0.05,100 +20000,0.27584,0.28131,0.05,100 +20000,0.2813,0.28687,0.05,100 +20000,0.2813,0.28687,0.05,100 +20000,0.2813,0.28687,0.05,100 +20000,0.2813,0.28687,0.05,100 +20000,0.2813,0.28687,0.05,100 +20000,0.28686,0.29255,0.05,100 +20000,0.28686,0.29255,0.05,100 +20000,0.28686,0.29255,0.05,100 +20000,0.28686,0.29255,0.05,100 +20000,0.28686,0.29255,0.05,100 +20000,0.28686,0.29255,0.05,100 +20000,0.29254,0.29834,0.05,100 +20000,0.29254,0.29834,0.05,100 +20000,0.29254,0.29834,0.05,100 +20000,0.29254,0.29834,0.05,100 +20000,0.29254,0.29834,0.05,100 +20000,0.29254,0.29834,0.05,100 +20000,0.29833,0.30425,0.05,100 +20000,0.29833,0.30425,0.05,100 +20000,0.29833,0.30425,0.05,100 +20000,0.29833,0.30425,0.05,100 +20000,0.29833,0.30425,0.05,100 +20000,0.29833,0.30425,0.05,100 +20000,0.30424,0.31027,0.05,100 +20000,0.30424,0.31027,0.05,100 +20000,0.30424,0.31027,0.05,100 +20000,0.30424,0.31027,0.05,100 +20000,0.30424,0.31027,0.05,100 +20000,0.30424,0.31027,0.05,100 +20000,0.31026,0.31641,0.05,100 +20000,0.31026,0.31641,0.05,100 +20000,0.31026,0.31641,0.05,100 +20000,0.31026,0.31641,0.05,100 +20000,0.31026,0.31641,0.05,100 +20000,0.31026,0.31641,0.05,100 +20000,0.3164,0.32267,0.05,100 +20000,0.3164,0.32267,0.05,100 +20000,0.3164,0.32267,0.05,100 +20000,0.3164,0.32267,0.05,100 +20000,0.3164,0.32267,0.05,100 +20000,0.3164,0.32267,0.05,100 +20000,0.32266,0.32906,0.05,100 +20000,0.32266,0.32906,0.05,100 +20000,0.32266,0.32906,0.05,100 +20000,0.32266,0.32906,0.05,100 +20000,0.32266,0.32906,0.05,100 +20000,0.32266,0.32906,0.05,100 +20000,0.32266,0.32906,0.05,100 +20000,0.32905,0.33558,0.05,100 +20000,0.32905,0.33558,0.05,100 +20000,0.32905,0.33558,0.05,100 +20000,0.32905,0.33558,0.05,100 +20000,0.32905,0.33558,0.05,100 +20000,0.32905,0.33558,0.05,100 +20000,0.33556,0.34222,0.05,100 +20000,0.33556,0.34222,0.05,100 +20000,0.33556,0.34222,0.05,100 +20000,0.33556,0.34222,0.05,100 +20000,0.33556,0.34222,0.05,100 +20000,0.33556,0.34222,0.05,100 +20000,0.33556,0.34222,0.05,100 +20000,0.34221,0.34899,0.05,100 +20000,0.34221,0.34899,0.05,100 +20000,0.34221,0.34899,0.05,100 +20000,0.34221,0.34899,0.05,100 +20000,0.34221,0.34899,0.05,100 +20000,0.34221,0.34899,0.05,100 +20000,0.34221,0.34899,0.05,100 +20000,0.34898,0.3559,0.05,100 +20000,0.34898,0.3559,0.05,100 +20000,0.34898,0.3559,0.05,100 +20000,0.34898,0.3559,0.05,100 +20000,0.34898,0.3559,0.05,100 +20000,0.34898,0.3559,0.05,100 +20000,0.35589,0.36295,0.05,100 +20000,0.35589,0.36295,0.05,100 +20000,0.35589,0.36295,0.05,100 +20000,0.35589,0.36295,0.05,100 +20000,0.35589,0.36295,0.05,100 +20000,0.35589,0.36295,0.05,100 +20000,0.35589,0.36295,0.05,100 +20000,0.36294,0.37013,0.05,100 +20000,0.36294,0.37013,0.05,100 +20000,0.36294,0.37013,0.05,100 +20000,0.36294,0.37013,0.05,100 +20000,0.36294,0.37013,0.05,100 +20000,0.36294,0.37013,0.05,100 +20000,0.36294,0.37013,0.05,100 +20000,0.36294,0.37013,0.05,100 +20000,0.37012,0.37746,0.05,100 +20000,0.37012,0.37746,0.05,100 +20000,0.37012,0.37746,0.05,100 +20000,0.37012,0.37746,0.05,100 +20000,0.37012,0.37746,0.05,100 +20000,0.37012,0.37746,0.05,100 +20000,0.37012,0.37746,0.05,100 +20000,0.37745,0.38494,0.05,100 +20000,0.37745,0.38494,0.05,100 +20000,0.37745,0.38494,0.05,100 +20000,0.37745,0.38494,0.05,100 +20000,0.37745,0.38494,0.05,100 +20000,0.37745,0.38494,0.05,100 +20000,0.37745,0.38494,0.05,100 +20000,0.38493,0.39256,0.05,100 +20000,0.38493,0.39256,0.05,100 +20000,0.38493,0.39256,0.05,100 +20000,0.38493,0.39256,0.05,100 +20000,0.38493,0.39256,0.05,100 +20000,0.38493,0.39256,0.05,100 +20000,0.38493,0.39256,0.05,100 +20000,0.38493,0.39256,0.05,100 +20000,0.39255,0.40033,0.05,100 +20000,0.39255,0.40033,0.05,100 +20000,0.39255,0.40033,0.05,100 +20000,0.39255,0.40033,0.05,100 +20000,0.39255,0.40033,0.05,100 +20000,0.39255,0.40033,0.05,100 +20000,0.39255,0.40033,0.05,100 +20000,0.39255,0.40033,0.05,100 +20000,0.40032,0.40826,0.05,100 +20000,0.40032,0.40826,0.05,100 +20000,0.40032,0.40826,0.05,100 +20000,0.40032,0.40826,0.05,100 +20000,0.40032,0.40826,0.05,100 +20000,0.40032,0.40826,0.05,100 +20000,0.40032,0.40826,0.05,100 +20000,0.40032,0.40826,0.05,100 +20000,0.40825,0.41634,0.05,100 +20000,0.40825,0.41634,0.05,100 +20000,0.40825,0.41634,0.05,100 +20000,0.40825,0.41634,0.05,100 +20000,0.40825,0.41634,0.05,100 +20000,0.40825,0.41634,0.05,100 +20000,0.40825,0.41634,0.05,100 +20000,0.40825,0.41634,0.05,100 +20000,0.41633,0.42459,0.05,100 +20000,0.41633,0.42459,0.05,100 +20000,0.41633,0.42459,0.05,100 +20000,0.41633,0.42459,0.05,100 +20000,0.41633,0.42459,0.05,100 +20000,0.41633,0.42459,0.05,100 +20000,0.41633,0.42459,0.05,100 +20000,0.41633,0.42459,0.05,100 +20000,0.42458,0.433,0.05,100 +20000,0.42458,0.433,0.05,100 +20000,0.42458,0.433,0.05,100 +20000,0.42458,0.433,0.05,100 +20000,0.42458,0.433,0.05,100 +20000,0.42458,0.433,0.05,100 +20000,0.42458,0.433,0.05,100 +20000,0.42458,0.433,0.05,100 +20000,0.42458,0.433,0.05,100 +20000,0.43298,0.44157,0.05,100 +20000,0.43298,0.44157,0.05,100 +20000,0.43298,0.44157,0.05,100 +20000,0.43298,0.44157,0.05,100 +20000,0.43298,0.44157,0.05,100 +20000,0.43298,0.44157,0.05,100 +20000,0.43298,0.44157,0.05,100 +20000,0.43298,0.44157,0.05,100 +20000,0.44156,0.45031,0.05,100 +20000,0.44156,0.45031,0.05,100 +20000,0.44156,0.45031,0.05,100 +20000,0.44156,0.45031,0.05,100 +20000,0.44156,0.45031,0.05,100 +20000,0.44156,0.45031,0.05,100 +20000,0.44156,0.45031,0.05,100 +20000,0.44156,0.45031,0.05,100 +20000,0.44156,0.45031,0.05,100 +20000,0.4503,0.45923,0.05,100 +20000,0.4503,0.45923,0.05,100 +20000,0.4503,0.45923,0.05,100 +20000,0.4503,0.45923,0.05,100 +20000,0.4503,0.45923,0.05,100 +20000,0.4503,0.45923,0.05,100 +20000,0.4503,0.45923,0.05,100 +20000,0.4503,0.45923,0.05,100 +20000,0.4503,0.45923,0.05,100 +20000,0.45922,0.46833,0.05,100 +20000,0.45922,0.46833,0.05,100 +20000,0.45922,0.46833,0.05,100 +20000,0.45922,0.46833,0.05,100 +20000,0.45922,0.46833,0.05,100 +20000,0.45922,0.46833,0.05,100 +20000,0.45922,0.46833,0.05,100 +20000,0.45922,0.46833,0.05,100 +20000,0.45922,0.46833,0.05,100 +20000,0.46832,0.4776,0.05,100 +20000,0.46832,0.4776,0.05,100 +20000,0.46832,0.4776,0.05,100 +20000,0.46832,0.4776,0.05,100 +20000,0.46832,0.4776,0.05,100 +20000,0.46832,0.4776,0.05,100 +20000,0.46832,0.4776,0.05,100 +20000,0.46832,0.4776,0.05,100 +20000,0.46832,0.4776,0.05,100 +20000,0.47759,0.48706,0.05,100 +20000,0.47759,0.48706,0.05,100 +20000,0.47759,0.48706,0.05,100 +20000,0.47759,0.48706,0.05,100 +20000,0.47759,0.48706,0.05,100 +20000,0.47759,0.48706,0.05,100 +20000,0.47759,0.48706,0.05,100 +20000,0.47759,0.48706,0.05,100 +20000,0.47759,0.48706,0.05,100 +20000,0.47759,0.48706,0.05,100 +20000,0.48705,0.49671,0.05,100 +20000,0.48705,0.49671,0.05,100 +20000,0.48705,0.49671,0.05,100 +20000,0.48705,0.49671,0.05,100 +20000,0.48705,0.49671,0.05,100 +20000,0.48705,0.49671,0.05,100 +20000,0.48705,0.49671,0.05,100 +20000,0.48705,0.49671,0.05,100 +20000,0.48705,0.49671,0.05,100 +20000,0.4967,0.50655,0.05,100 +20000,0.4967,0.50655,0.05,100 +20000,0.4967,0.50655,0.05,100 +20000,0.4967,0.50655,0.05,100 +20000,0.4967,0.50655,0.05,100 +20000,0.4967,0.50655,0.05,100 +20000,0.4967,0.50655,0.05,100 +20000,0.4967,0.50655,0.05,100 +20000,0.4967,0.50655,0.05,100 +20000,0.4967,0.50655,0.05,100 +20000,0.50654,0.51658,0.05,100 +20000,0.50654,0.51658,0.05,100 +20000,0.50654,0.51658,0.05,100 +20000,0.50654,0.51658,0.05,100 +20000,0.50654,0.51658,0.05,100 +20000,0.50654,0.51658,0.05,100 +20000,0.50654,0.51658,0.05,100 +20000,0.50654,0.51658,0.05,100 +20000,0.50654,0.51658,0.05,100 +20000,0.50654,0.51658,0.05,100 +20000,0.51657,0.52681,0.05,100 +20000,0.51657,0.52681,0.05,100 +20000,0.51657,0.52681,0.05,100 +20000,0.51657,0.52681,0.05,100 +20000,0.51657,0.52681,0.05,100 +20000,0.51657,0.52681,0.05,100 +20000,0.51657,0.52681,0.05,100 +20000,0.51657,0.52681,0.05,100 +20000,0.51657,0.52681,0.05,100 +20000,0.51657,0.52681,0.05,100 +20000,0.5268,0.53725,0.05,100 +20000,0.5268,0.53725,0.05,100 +20000,0.5268,0.53725,0.05,100 +20000,0.5268,0.53725,0.05,100 +20000,0.5268,0.53725,0.05,100 +20000,0.5268,0.53725,0.05,100 +20000,0.5268,0.53725,0.05,100 +20000,0.5268,0.53725,0.05,100 +20000,0.5268,0.53725,0.05,100 +20000,0.5268,0.53725,0.05,100 +20000,0.5268,0.53725,0.05,100 +20000,0.53724,0.54789,0.05,100 +20000,0.53724,0.54789,0.05,100 +20000,0.53724,0.54789,0.05,100 +20000,0.53724,0.54789,0.05,100 +20000,0.53724,0.54789,0.05,100 +20000,0.53724,0.54789,0.05,100 +20000,0.53724,0.54789,0.05,100 +20000,0.53724,0.54789,0.05,100 +20000,0.53724,0.54789,0.05,100 +20000,0.53724,0.54789,0.05,100 +20000,0.54788,0.55874,0.05,100 +20000,0.54788,0.55874,0.05,100 +20000,0.54788,0.55874,0.05,100 +20000,0.54788,0.55874,0.05,100 +20000,0.54788,0.55874,0.05,100 +20000,0.54788,0.55874,0.05,100 +20000,0.54788,0.55874,0.05,100 +20000,0.54788,0.55874,0.05,100 +20000,0.54788,0.55874,0.05,100 +20000,0.54788,0.55874,0.05,100 +20000,0.54788,0.55874,0.05,100 +20000,0.55873,0.56981,0.05,100 +20000,0.55873,0.56981,0.05,100 +20000,0.55873,0.56981,0.05,100 +20000,0.55873,0.56981,0.05,100 +20000,0.55873,0.56981,0.05,100 +20000,0.55873,0.56981,0.05,100 +20000,0.55873,0.56981,0.05,100 +20000,0.55873,0.56981,0.05,100 +20000,0.55873,0.56981,0.05,100 +20000,0.55873,0.56981,0.05,100 +20000,0.55873,0.56981,0.05,100 +20000,0.5698,0.5811,0.05,100 +20000,0.5698,0.5811,0.05,100 +20000,0.5698,0.5811,0.05,100 +20000,0.5698,0.5811,0.05,100 +20000,0.5698,0.5811,0.05,100 +20000,0.5698,0.5811,0.05,100 +20000,0.5698,0.5811,0.05,100 +20000,0.5698,0.5811,0.05,100 +20000,0.5698,0.5811,0.05,100 +20000,0.5698,0.5811,0.05,100 +20000,0.5698,0.5811,0.05,100 +20000,0.5698,0.5811,0.05,100 +20000,0.58109,0.59261,0.05,100 +20000,0.58109,0.59261,0.05,100 +20000,0.58109,0.59261,0.05,100 +20000,0.58109,0.59261,0.05,100 +20000,0.58109,0.59261,0.05,100 +20000,0.58109,0.59261,0.05,100 +20000,0.58109,0.59261,0.05,100 +20000,0.58109,0.59261,0.05,100 +20000,0.58109,0.59261,0.05,100 +20000,0.58109,0.59261,0.05,100 +20000,0.58109,0.59261,0.05,100 +20000,0.5926,0.60435,0.05,100 +20000,0.5926,0.60435,0.05,100 +20000,0.5926,0.60435,0.05,100 +20000,0.5926,0.60435,0.05,100 +20000,0.5926,0.60435,0.05,100 +20000,0.5926,0.60435,0.05,100 +20000,0.5926,0.60435,0.05,100 +20000,0.5926,0.60435,0.05,100 +20000,0.5926,0.60435,0.05,100 +20000,0.5926,0.60435,0.05,100 +20000,0.5926,0.60435,0.05,100 +20000,0.5926,0.60435,0.05,100 +20000,0.60434,0.61632,0.05,100 +20000,0.60434,0.61632,0.05,100 +20000,0.60434,0.61632,0.05,100 +20000,0.60434,0.61632,0.05,100 +20000,0.60434,0.61632,0.05,100 +20000,0.60434,0.61632,0.05,100 +20000,0.60434,0.61632,0.05,100 +20000,0.60434,0.61632,0.05,100 +20000,0.60434,0.61632,0.05,100 +20000,0.60434,0.61632,0.05,100 +20000,0.60434,0.61632,0.05,100 +20000,0.60434,0.61632,0.05,100 +20000,0.61631,0.62853,0.05,100 +20000,0.61631,0.62853,0.05,100 +20000,0.61631,0.62853,0.05,100 +20000,0.61631,0.62853,0.05,100 +20000,0.61631,0.62853,0.05,100 +20000,0.61631,0.62853,0.05,100 +20000,0.61631,0.62853,0.05,100 +20000,0.61631,0.62853,0.05,100 +20000,0.61631,0.62853,0.05,100 +20000,0.61631,0.62853,0.05,100 +20000,0.61631,0.62853,0.05,100 +20000,0.61631,0.62853,0.05,100 +20000,0.62852,0.64098,0.05,100 +20000,0.62852,0.64098,0.05,100 +20000,0.62852,0.64098,0.05,100 +20000,0.62852,0.64098,0.05,100 +20000,0.62852,0.64098,0.05,100 +20000,0.62852,0.64098,0.05,100 +20000,0.62852,0.64098,0.05,100 +20000,0.62852,0.64098,0.05,100 +20000,0.62852,0.64098,0.05,100 +20000,0.62852,0.64098,0.05,100 +20000,0.62852,0.64098,0.05,100 +20000,0.62852,0.64098,0.05,100 +20000,0.62852,0.64098,0.05,100 +20000,0.64097,0.65368,0.05,100 +20000,0.64097,0.65368,0.05,100 +20000,0.64097,0.65368,0.05,100 +20000,0.64097,0.65368,0.05,100 +20000,0.64097,0.65368,0.05,100 +20000,0.64097,0.65368,0.05,100 +20000,0.64097,0.65368,0.05,100 +20000,0.64097,0.65368,0.05,100 +20000,0.64097,0.65368,0.05,100 +20000,0.64097,0.65368,0.05,100 +20000,0.64097,0.65368,0.05,100 +20000,0.64097,0.65368,0.05,100 +20000,0.65367,0.66663,0.05,100 +20000,0.65367,0.66663,0.05,100 +20000,0.65367,0.66663,0.05,100 +20000,0.65367,0.66663,0.05,100 +20000,0.65367,0.66663,0.05,100 +20000,0.65367,0.66663,0.05,100 +20000,0.65367,0.66663,0.05,100 +20000,0.65367,0.66663,0.05,100 +20000,0.65367,0.66663,0.05,100 +20000,0.65367,0.66663,0.05,100 +20000,0.65367,0.66663,0.05,100 +20000,0.65367,0.66663,0.05,100 +20000,0.65367,0.66663,0.05,100 +20000,0.66662,0.67984,0.05,100 +20000,0.66662,0.67984,0.05,100 +20000,0.66662,0.67984,0.05,100 +20000,0.66662,0.67984,0.05,100 +20000,0.66662,0.67984,0.05,100 +20000,0.66662,0.67984,0.05,100 +20000,0.66662,0.67984,0.05,100 +20000,0.66662,0.67984,0.05,100 +20000,0.66662,0.67984,0.05,100 +20000,0.66662,0.67984,0.05,100 +20000,0.66662,0.67984,0.05,100 +20000,0.66662,0.67984,0.05,100 +20000,0.66662,0.67984,0.05,100 +20000,0.67983,0.69331,0.05,100 +20000,0.67983,0.69331,0.05,100 +20000,0.67983,0.69331,0.05,100 +20000,0.67983,0.69331,0.05,100 +20000,0.67983,0.69331,0.05,100 +20000,0.67983,0.69331,0.05,100 +20000,0.67983,0.69331,0.05,100 +20000,0.67983,0.69331,0.05,100 +20000,0.67983,0.69331,0.05,100 +20000,0.67983,0.69331,0.05,100 +20000,0.67983,0.69331,0.05,100 +20000,0.67983,0.69331,0.05,100 +20000,0.67983,0.69331,0.05,100 +20000,0.67983,0.69331,0.05,100 +20000,0.6933,0.70704,0.05,100 +20000,0.6933,0.70704,0.05,100 +20000,0.6933,0.70704,0.05,100 +20000,0.6933,0.70704,0.05,100 +20000,0.6933,0.70704,0.05,100 +20000,0.6933,0.70704,0.05,100 +20000,0.6933,0.70704,0.05,100 +20000,0.6933,0.70704,0.05,100 +20000,0.6933,0.70704,0.05,100 +20000,0.6933,0.70704,0.05,100 +20000,0.6933,0.70704,0.05,100 +20000,0.6933,0.70704,0.05,100 +20000,0.6933,0.70704,0.05,100 +20000,0.6933,0.70704,0.05,100 +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan +20000,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/data_5.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/data_5.csv new file mode 100644 index 00000000000..c4a1fbb52a2 --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/data_5.csv @@ -0,0 +1,1002 @@ +Time,"elementCenter:0","elementCenter:1","elementCenter:2","temperature" +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,0.07071,0.072112,0.05,-16.946 +50000,0.07071,0.072112,0.05,-16.946 +50000,0.07211,0.07354,0.05,-10.957 +50000,0.07351,0.074968,0.05,-5.0805 +50000,0.075155,0.076646,0.05,1.6961 +50000,0.075155,0.076646,0.05,1.6961 +50000,0.077046,0.078574,0.05,9.2828 +50000,0.077046,0.078574,0.05,9.2828 +50000,0.078936,0.080501,0.05,16.663 +50000,0.078936,0.080501,0.05,16.663 +50000,0.080826,0.082429,0.05,23.824 +50000,0.080826,0.082429,0.05,23.824 +50000,0.082716,0.084357,0.05,30.745 +50000,0.082716,0.084357,0.05,30.745 +50000,0.084607,0.086285,0.05,37.403 +50000,0.084607,0.086285,0.05,37.403 +50000,0.086497,0.088212,0.05,43.771 +50000,0.086497,0.088212,0.05,43.771 +50000,0.088387,0.09014,0.05,49.822 +50000,0.088387,0.09014,0.05,49.822 +50000,0.090278,0.092068,0.05,55.527 +50000,0.090278,0.092068,0.05,55.527 +50000,0.092168,0.093995,0.05,60.865 +50000,0.092168,0.093995,0.05,60.865 +50000,0.094031,0.095896,0.05,65.743 +50000,0.095885,0.097786,0.05,70.214 +50000,0.095885,0.097786,0.05,70.214 +50000,0.097776,0.099715,0.05,74.369 +50000,0.097776,0.099715,0.05,74.369 +50000,0.099704,0.10168,0.05,78.184 +50000,0.099704,0.10168,0.05,78.184 +50000,0.10167,0.10369,0.05,81.643 +50000,0.10167,0.10369,0.05,81.643 +50000,0.10368,0.10573,0.05,84.738 +50000,0.10368,0.10573,0.05,84.738 +50000,0.10572,0.10782,0.05,87.469 +50000,0.10572,0.10782,0.05,87.469 +50000,0.10781,0.10995,0.05,89.844 +50000,0.10781,0.10995,0.05,89.844 +50000,0.10993,0.11211,0.05,91.879 +50000,0.10993,0.11211,0.05,91.879 +50000,0.10993,0.11211,0.05,91.879 +50000,0.1121,0.11433,0.05,93.596 +50000,0.1121,0.11433,0.05,93.596 +50000,0.11432,0.11658,0.05,95.022 +50000,0.11432,0.11658,0.05,95.022 +50000,0.11657,0.11888,0.05,96.186 +50000,0.11657,0.11888,0.05,96.186 +50000,0.11887,0.12123,0.05,97.123 +50000,0.11887,0.12123,0.05,97.123 +50000,0.11887,0.12123,0.05,97.123 +50000,0.12122,0.12362,0.05,97.862 +50000,0.12122,0.12362,0.05,97.862 +50000,0.12361,0.12607,0.05,98.437 +50000,0.12361,0.12607,0.05,98.437 +50000,0.12361,0.12607,0.05,98.437 +50000,0.12605,0.12855,0.05,98.876 +50000,0.12605,0.12855,0.05,98.876 +50000,0.12854,0.13109,0.05,99.205 +50000,0.12854,0.13109,0.05,99.205 +50000,0.12854,0.13109,0.05,99.205 +50000,0.13108,0.13368,0.05,99.448 +50000,0.13108,0.13368,0.05,99.448 +50000,0.13367,0.13632,0.05,99.623 +50000,0.13367,0.13632,0.05,99.623 +50000,0.13367,0.13632,0.05,99.623 +50000,0.13631,0.13901,0.05,99.747 +50000,0.13631,0.13901,0.05,99.747 +50000,0.13631,0.13901,0.05,99.747 +50000,0.139,0.14176,0.05,99.834 +50000,0.139,0.14176,0.05,99.834 +50000,0.14175,0.14456,0.05,99.893 +50000,0.14175,0.14456,0.05,99.893 +50000,0.14175,0.14456,0.05,99.893 +50000,0.14455,0.14742,0.05,99.932 +50000,0.14455,0.14742,0.05,99.932 +50000,0.14455,0.14742,0.05,99.932 +50000,0.1474,0.15033,0.05,99.958 +50000,0.1474,0.15033,0.05,99.958 +50000,0.1474,0.15033,0.05,99.958 +50000,0.15032,0.1533,0.05,99.975 +50000,0.15032,0.1533,0.05,99.975 +50000,0.15032,0.1533,0.05,99.975 +50000,0.15329,0.15633,0.05,99.985 +50000,0.15329,0.15633,0.05,99.985 +50000,0.15329,0.15633,0.05,99.985 +50000,0.15632,0.15942,0.05,99.991 +50000,0.15632,0.15942,0.05,99.991 +50000,0.15632,0.15942,0.05,99.991 +50000,0.15941,0.16257,0.05,99.995 +50000,0.15941,0.16257,0.05,99.995 +50000,0.15941,0.16257,0.05,99.995 +50000,0.16256,0.16578,0.05,99.997 +50000,0.16256,0.16578,0.05,99.997 +50000,0.16256,0.16578,0.05,99.997 +50000,0.16577,0.16906,0.05,99.999 +50000,0.16577,0.16906,0.05,99.999 +50000,0.16577,0.16906,0.05,99.999 +50000,0.16577,0.16906,0.05,99.999 +50000,0.16905,0.1724,0.05,99.999 +50000,0.16905,0.1724,0.05,99.999 +50000,0.16905,0.1724,0.05,99.999 +50000,0.17239,0.1758,0.05,100 +50000,0.17239,0.1758,0.05,100 +50000,0.17239,0.1758,0.05,100 +50000,0.17579,0.17928,0.05,100 +50000,0.17579,0.17928,0.05,100 +50000,0.17579,0.17928,0.05,100 +50000,0.17579,0.17928,0.05,100 +50000,0.17927,0.18282,0.05,100 +50000,0.17927,0.18282,0.05,100 +50000,0.17927,0.18282,0.05,100 +50000,0.18281,0.18644,0.05,100 +50000,0.18281,0.18644,0.05,100 +50000,0.18281,0.18644,0.05,100 +50000,0.18281,0.18644,0.05,100 +50000,0.18643,0.19013,0.05,100 +50000,0.18643,0.19013,0.05,100 +50000,0.18643,0.19013,0.05,100 +50000,0.18643,0.19013,0.05,100 +50000,0.19011,0.19388,0.05,100 +50000,0.19011,0.19388,0.05,100 +50000,0.19011,0.19388,0.05,100 +50000,0.19387,0.19772,0.05,100 +50000,0.19387,0.19772,0.05,100 +50000,0.19387,0.19772,0.05,100 +50000,0.19387,0.19772,0.05,100 +50000,0.19771,0.20163,0.05,100 +50000,0.19771,0.20163,0.05,100 +50000,0.19771,0.20163,0.05,100 +50000,0.19771,0.20163,0.05,100 +50000,0.20162,0.20562,0.05,100 +50000,0.20162,0.20562,0.05,100 +50000,0.20162,0.20562,0.05,100 +50000,0.20162,0.20562,0.05,100 +50000,0.2056,0.20968,0.05,100 +50000,0.2056,0.20968,0.05,100 +50000,0.2056,0.20968,0.05,100 +50000,0.2056,0.20968,0.05,100 +50000,0.20967,0.21383,0.05,100 +50000,0.20967,0.21383,0.05,100 +50000,0.20967,0.21383,0.05,100 +50000,0.20967,0.21383,0.05,100 +50000,0.21382,0.21806,0.05,100 +50000,0.21382,0.21806,0.05,100 +50000,0.21382,0.21806,0.05,100 +50000,0.21382,0.21806,0.05,100 +50000,0.21382,0.21806,0.05,100 +50000,0.21805,0.22237,0.05,100 +50000,0.21805,0.22237,0.05,100 +50000,0.21805,0.22237,0.05,100 +50000,0.21805,0.22237,0.05,100 +50000,0.22236,0.22677,0.05,100 +50000,0.22236,0.22677,0.05,100 +50000,0.22236,0.22677,0.05,100 +50000,0.22236,0.22677,0.05,100 +50000,0.22676,0.23125,0.05,100 +50000,0.22676,0.23125,0.05,100 +50000,0.22676,0.23125,0.05,100 +50000,0.22676,0.23125,0.05,100 +50000,0.22676,0.23125,0.05,100 +50000,0.23124,0.23583,0.05,100 +50000,0.23124,0.23583,0.05,100 +50000,0.23124,0.23583,0.05,100 +50000,0.23124,0.23583,0.05,100 +50000,0.23582,0.2405,0.05,100 +50000,0.23582,0.2405,0.05,100 +50000,0.23582,0.2405,0.05,100 +50000,0.23582,0.2405,0.05,100 +50000,0.23582,0.2405,0.05,100 +50000,0.24048,0.24525,0.05,100 +50000,0.24048,0.24525,0.05,100 +50000,0.24048,0.24525,0.05,100 +50000,0.24048,0.24525,0.05,100 +50000,0.24048,0.24525,0.05,100 +50000,0.24524,0.25011,0.05,100 +50000,0.24524,0.25011,0.05,100 +50000,0.24524,0.25011,0.05,100 +50000,0.24524,0.25011,0.05,100 +50000,0.24524,0.25011,0.05,100 +50000,0.25009,0.25505,0.05,100 +50000,0.25009,0.25505,0.05,100 +50000,0.25009,0.25505,0.05,100 +50000,0.25009,0.25505,0.05,100 +50000,0.25009,0.25505,0.05,100 +50000,0.25504,0.2601,0.05,100 +50000,0.25504,0.2601,0.05,100 +50000,0.25504,0.2601,0.05,100 +50000,0.25504,0.2601,0.05,100 +50000,0.25504,0.2601,0.05,100 +50000,0.26009,0.26525,0.05,100 +50000,0.26009,0.26525,0.05,100 +50000,0.26009,0.26525,0.05,100 +50000,0.26009,0.26525,0.05,100 +50000,0.26009,0.26525,0.05,100 +50000,0.26524,0.2705,0.05,100 +50000,0.26524,0.2705,0.05,100 +50000,0.26524,0.2705,0.05,100 +50000,0.26524,0.2705,0.05,100 +50000,0.26524,0.2705,0.05,100 +50000,0.27048,0.27585,0.05,100 +50000,0.27048,0.27585,0.05,100 +50000,0.27048,0.27585,0.05,100 +50000,0.27048,0.27585,0.05,100 +50000,0.27048,0.27585,0.05,100 +50000,0.27584,0.28131,0.05,100 +50000,0.27584,0.28131,0.05,100 +50000,0.27584,0.28131,0.05,100 +50000,0.27584,0.28131,0.05,100 +50000,0.27584,0.28131,0.05,100 +50000,0.27584,0.28131,0.05,100 +50000,0.2813,0.28687,0.05,100 +50000,0.2813,0.28687,0.05,100 +50000,0.2813,0.28687,0.05,100 +50000,0.2813,0.28687,0.05,100 +50000,0.2813,0.28687,0.05,100 +50000,0.28686,0.29255,0.05,100 +50000,0.28686,0.29255,0.05,100 +50000,0.28686,0.29255,0.05,100 +50000,0.28686,0.29255,0.05,100 +50000,0.28686,0.29255,0.05,100 +50000,0.28686,0.29255,0.05,100 +50000,0.29254,0.29834,0.05,100 +50000,0.29254,0.29834,0.05,100 +50000,0.29254,0.29834,0.05,100 +50000,0.29254,0.29834,0.05,100 +50000,0.29254,0.29834,0.05,100 +50000,0.29254,0.29834,0.05,100 +50000,0.29833,0.30425,0.05,100 +50000,0.29833,0.30425,0.05,100 +50000,0.29833,0.30425,0.05,100 +50000,0.29833,0.30425,0.05,100 +50000,0.29833,0.30425,0.05,100 +50000,0.29833,0.30425,0.05,100 +50000,0.30424,0.31027,0.05,100 +50000,0.30424,0.31027,0.05,100 +50000,0.30424,0.31027,0.05,100 +50000,0.30424,0.31027,0.05,100 +50000,0.30424,0.31027,0.05,100 +50000,0.30424,0.31027,0.05,100 +50000,0.31026,0.31641,0.05,100 +50000,0.31026,0.31641,0.05,100 +50000,0.31026,0.31641,0.05,100 +50000,0.31026,0.31641,0.05,100 +50000,0.31026,0.31641,0.05,100 +50000,0.31026,0.31641,0.05,100 +50000,0.3164,0.32267,0.05,100 +50000,0.3164,0.32267,0.05,100 +50000,0.3164,0.32267,0.05,100 +50000,0.3164,0.32267,0.05,100 +50000,0.3164,0.32267,0.05,100 +50000,0.3164,0.32267,0.05,100 +50000,0.32266,0.32906,0.05,100 +50000,0.32266,0.32906,0.05,100 +50000,0.32266,0.32906,0.05,100 +50000,0.32266,0.32906,0.05,100 +50000,0.32266,0.32906,0.05,100 +50000,0.32266,0.32906,0.05,100 +50000,0.32266,0.32906,0.05,100 +50000,0.32905,0.33558,0.05,100 +50000,0.32905,0.33558,0.05,100 +50000,0.32905,0.33558,0.05,100 +50000,0.32905,0.33558,0.05,100 +50000,0.32905,0.33558,0.05,100 +50000,0.32905,0.33558,0.05,100 +50000,0.33556,0.34222,0.05,100 +50000,0.33556,0.34222,0.05,100 +50000,0.33556,0.34222,0.05,100 +50000,0.33556,0.34222,0.05,100 +50000,0.33556,0.34222,0.05,100 +50000,0.33556,0.34222,0.05,100 +50000,0.33556,0.34222,0.05,100 +50000,0.34221,0.34899,0.05,100 +50000,0.34221,0.34899,0.05,100 +50000,0.34221,0.34899,0.05,100 +50000,0.34221,0.34899,0.05,100 +50000,0.34221,0.34899,0.05,100 +50000,0.34221,0.34899,0.05,100 +50000,0.34221,0.34899,0.05,100 +50000,0.34898,0.3559,0.05,100 +50000,0.34898,0.3559,0.05,100 +50000,0.34898,0.3559,0.05,100 +50000,0.34898,0.3559,0.05,100 +50000,0.34898,0.3559,0.05,100 +50000,0.34898,0.3559,0.05,100 +50000,0.35589,0.36295,0.05,100 +50000,0.35589,0.36295,0.05,100 +50000,0.35589,0.36295,0.05,100 +50000,0.35589,0.36295,0.05,100 +50000,0.35589,0.36295,0.05,100 +50000,0.35589,0.36295,0.05,100 +50000,0.35589,0.36295,0.05,100 +50000,0.36294,0.37013,0.05,100 +50000,0.36294,0.37013,0.05,100 +50000,0.36294,0.37013,0.05,100 +50000,0.36294,0.37013,0.05,100 +50000,0.36294,0.37013,0.05,100 +50000,0.36294,0.37013,0.05,100 +50000,0.36294,0.37013,0.05,100 +50000,0.36294,0.37013,0.05,100 +50000,0.37012,0.37746,0.05,100 +50000,0.37012,0.37746,0.05,100 +50000,0.37012,0.37746,0.05,100 +50000,0.37012,0.37746,0.05,100 +50000,0.37012,0.37746,0.05,100 +50000,0.37012,0.37746,0.05,100 +50000,0.37012,0.37746,0.05,100 +50000,0.37745,0.38494,0.05,100 +50000,0.37745,0.38494,0.05,100 +50000,0.37745,0.38494,0.05,100 +50000,0.37745,0.38494,0.05,100 +50000,0.37745,0.38494,0.05,100 +50000,0.37745,0.38494,0.05,100 +50000,0.37745,0.38494,0.05,100 +50000,0.38493,0.39256,0.05,100 +50000,0.38493,0.39256,0.05,100 +50000,0.38493,0.39256,0.05,100 +50000,0.38493,0.39256,0.05,100 +50000,0.38493,0.39256,0.05,100 +50000,0.38493,0.39256,0.05,100 +50000,0.38493,0.39256,0.05,100 +50000,0.38493,0.39256,0.05,100 +50000,0.39255,0.40033,0.05,100 +50000,0.39255,0.40033,0.05,100 +50000,0.39255,0.40033,0.05,100 +50000,0.39255,0.40033,0.05,100 +50000,0.39255,0.40033,0.05,100 +50000,0.39255,0.40033,0.05,100 +50000,0.39255,0.40033,0.05,100 +50000,0.39255,0.40033,0.05,100 +50000,0.40032,0.40826,0.05,100 +50000,0.40032,0.40826,0.05,100 +50000,0.40032,0.40826,0.05,100 +50000,0.40032,0.40826,0.05,100 +50000,0.40032,0.40826,0.05,100 +50000,0.40032,0.40826,0.05,100 +50000,0.40032,0.40826,0.05,100 +50000,0.40032,0.40826,0.05,100 +50000,0.40825,0.41634,0.05,100 +50000,0.40825,0.41634,0.05,100 +50000,0.40825,0.41634,0.05,100 +50000,0.40825,0.41634,0.05,100 +50000,0.40825,0.41634,0.05,100 +50000,0.40825,0.41634,0.05,100 +50000,0.40825,0.41634,0.05,100 +50000,0.40825,0.41634,0.05,100 +50000,0.41633,0.42459,0.05,100 +50000,0.41633,0.42459,0.05,100 +50000,0.41633,0.42459,0.05,100 +50000,0.41633,0.42459,0.05,100 +50000,0.41633,0.42459,0.05,100 +50000,0.41633,0.42459,0.05,100 +50000,0.41633,0.42459,0.05,100 +50000,0.41633,0.42459,0.05,100 +50000,0.42458,0.433,0.05,100 +50000,0.42458,0.433,0.05,100 +50000,0.42458,0.433,0.05,100 +50000,0.42458,0.433,0.05,100 +50000,0.42458,0.433,0.05,100 +50000,0.42458,0.433,0.05,100 +50000,0.42458,0.433,0.05,100 +50000,0.42458,0.433,0.05,100 +50000,0.42458,0.433,0.05,100 +50000,0.43298,0.44157,0.05,100 +50000,0.43298,0.44157,0.05,100 +50000,0.43298,0.44157,0.05,100 +50000,0.43298,0.44157,0.05,100 +50000,0.43298,0.44157,0.05,100 +50000,0.43298,0.44157,0.05,100 +50000,0.43298,0.44157,0.05,100 +50000,0.43298,0.44157,0.05,100 +50000,0.44156,0.45031,0.05,100 +50000,0.44156,0.45031,0.05,100 +50000,0.44156,0.45031,0.05,100 +50000,0.44156,0.45031,0.05,100 +50000,0.44156,0.45031,0.05,100 +50000,0.44156,0.45031,0.05,100 +50000,0.44156,0.45031,0.05,100 +50000,0.44156,0.45031,0.05,100 +50000,0.44156,0.45031,0.05,100 +50000,0.4503,0.45923,0.05,100 +50000,0.4503,0.45923,0.05,100 +50000,0.4503,0.45923,0.05,100 +50000,0.4503,0.45923,0.05,100 +50000,0.4503,0.45923,0.05,100 +50000,0.4503,0.45923,0.05,100 +50000,0.4503,0.45923,0.05,100 +50000,0.4503,0.45923,0.05,100 +50000,0.4503,0.45923,0.05,100 +50000,0.45922,0.46833,0.05,100 +50000,0.45922,0.46833,0.05,100 +50000,0.45922,0.46833,0.05,100 +50000,0.45922,0.46833,0.05,100 +50000,0.45922,0.46833,0.05,100 +50000,0.45922,0.46833,0.05,100 +50000,0.45922,0.46833,0.05,100 +50000,0.45922,0.46833,0.05,100 +50000,0.45922,0.46833,0.05,100 +50000,0.46832,0.4776,0.05,100 +50000,0.46832,0.4776,0.05,100 +50000,0.46832,0.4776,0.05,100 +50000,0.46832,0.4776,0.05,100 +50000,0.46832,0.4776,0.05,100 +50000,0.46832,0.4776,0.05,100 +50000,0.46832,0.4776,0.05,100 +50000,0.46832,0.4776,0.05,100 +50000,0.46832,0.4776,0.05,100 +50000,0.47759,0.48706,0.05,100 +50000,0.47759,0.48706,0.05,100 +50000,0.47759,0.48706,0.05,100 +50000,0.47759,0.48706,0.05,100 +50000,0.47759,0.48706,0.05,100 +50000,0.47759,0.48706,0.05,100 +50000,0.47759,0.48706,0.05,100 +50000,0.47759,0.48706,0.05,100 +50000,0.47759,0.48706,0.05,100 +50000,0.47759,0.48706,0.05,100 +50000,0.48705,0.49671,0.05,100 +50000,0.48705,0.49671,0.05,100 +50000,0.48705,0.49671,0.05,100 +50000,0.48705,0.49671,0.05,100 +50000,0.48705,0.49671,0.05,100 +50000,0.48705,0.49671,0.05,100 +50000,0.48705,0.49671,0.05,100 +50000,0.48705,0.49671,0.05,100 +50000,0.48705,0.49671,0.05,100 +50000,0.4967,0.50655,0.05,100 +50000,0.4967,0.50655,0.05,100 +50000,0.4967,0.50655,0.05,100 +50000,0.4967,0.50655,0.05,100 +50000,0.4967,0.50655,0.05,100 +50000,0.4967,0.50655,0.05,100 +50000,0.4967,0.50655,0.05,100 +50000,0.4967,0.50655,0.05,100 +50000,0.4967,0.50655,0.05,100 +50000,0.4967,0.50655,0.05,100 +50000,0.50654,0.51658,0.05,100 +50000,0.50654,0.51658,0.05,100 +50000,0.50654,0.51658,0.05,100 +50000,0.50654,0.51658,0.05,100 +50000,0.50654,0.51658,0.05,100 +50000,0.50654,0.51658,0.05,100 +50000,0.50654,0.51658,0.05,100 +50000,0.50654,0.51658,0.05,100 +50000,0.50654,0.51658,0.05,100 +50000,0.50654,0.51658,0.05,100 +50000,0.51657,0.52681,0.05,100 +50000,0.51657,0.52681,0.05,100 +50000,0.51657,0.52681,0.05,100 +50000,0.51657,0.52681,0.05,100 +50000,0.51657,0.52681,0.05,100 +50000,0.51657,0.52681,0.05,100 +50000,0.51657,0.52681,0.05,100 +50000,0.51657,0.52681,0.05,100 +50000,0.51657,0.52681,0.05,100 +50000,0.51657,0.52681,0.05,100 +50000,0.5268,0.53725,0.05,100 +50000,0.5268,0.53725,0.05,100 +50000,0.5268,0.53725,0.05,100 +50000,0.5268,0.53725,0.05,100 +50000,0.5268,0.53725,0.05,100 +50000,0.5268,0.53725,0.05,100 +50000,0.5268,0.53725,0.05,100 +50000,0.5268,0.53725,0.05,100 +50000,0.5268,0.53725,0.05,100 +50000,0.5268,0.53725,0.05,100 +50000,0.5268,0.53725,0.05,100 +50000,0.53724,0.54789,0.05,100 +50000,0.53724,0.54789,0.05,100 +50000,0.53724,0.54789,0.05,100 +50000,0.53724,0.54789,0.05,100 +50000,0.53724,0.54789,0.05,100 +50000,0.53724,0.54789,0.05,100 +50000,0.53724,0.54789,0.05,100 +50000,0.53724,0.54789,0.05,100 +50000,0.53724,0.54789,0.05,100 +50000,0.53724,0.54789,0.05,100 +50000,0.54788,0.55874,0.05,100 +50000,0.54788,0.55874,0.05,100 +50000,0.54788,0.55874,0.05,100 +50000,0.54788,0.55874,0.05,100 +50000,0.54788,0.55874,0.05,100 +50000,0.54788,0.55874,0.05,100 +50000,0.54788,0.55874,0.05,100 +50000,0.54788,0.55874,0.05,100 +50000,0.54788,0.55874,0.05,100 +50000,0.54788,0.55874,0.05,100 +50000,0.54788,0.55874,0.05,100 +50000,0.55873,0.56981,0.05,100 +50000,0.55873,0.56981,0.05,100 +50000,0.55873,0.56981,0.05,100 +50000,0.55873,0.56981,0.05,100 +50000,0.55873,0.56981,0.05,100 +50000,0.55873,0.56981,0.05,100 +50000,0.55873,0.56981,0.05,100 +50000,0.55873,0.56981,0.05,100 +50000,0.55873,0.56981,0.05,100 +50000,0.55873,0.56981,0.05,100 +50000,0.55873,0.56981,0.05,100 +50000,0.5698,0.5811,0.05,100 +50000,0.5698,0.5811,0.05,100 +50000,0.5698,0.5811,0.05,100 +50000,0.5698,0.5811,0.05,100 +50000,0.5698,0.5811,0.05,100 +50000,0.5698,0.5811,0.05,100 +50000,0.5698,0.5811,0.05,100 +50000,0.5698,0.5811,0.05,100 +50000,0.5698,0.5811,0.05,100 +50000,0.5698,0.5811,0.05,100 +50000,0.5698,0.5811,0.05,100 +50000,0.5698,0.5811,0.05,100 +50000,0.58109,0.59261,0.05,100 +50000,0.58109,0.59261,0.05,100 +50000,0.58109,0.59261,0.05,100 +50000,0.58109,0.59261,0.05,100 +50000,0.58109,0.59261,0.05,100 +50000,0.58109,0.59261,0.05,100 +50000,0.58109,0.59261,0.05,100 +50000,0.58109,0.59261,0.05,100 +50000,0.58109,0.59261,0.05,100 +50000,0.58109,0.59261,0.05,100 +50000,0.58109,0.59261,0.05,100 +50000,0.5926,0.60435,0.05,100 +50000,0.5926,0.60435,0.05,100 +50000,0.5926,0.60435,0.05,100 +50000,0.5926,0.60435,0.05,100 +50000,0.5926,0.60435,0.05,100 +50000,0.5926,0.60435,0.05,100 +50000,0.5926,0.60435,0.05,100 +50000,0.5926,0.60435,0.05,100 +50000,0.5926,0.60435,0.05,100 +50000,0.5926,0.60435,0.05,100 +50000,0.5926,0.60435,0.05,100 +50000,0.5926,0.60435,0.05,100 +50000,0.60434,0.61632,0.05,100 +50000,0.60434,0.61632,0.05,100 +50000,0.60434,0.61632,0.05,100 +50000,0.60434,0.61632,0.05,100 +50000,0.60434,0.61632,0.05,100 +50000,0.60434,0.61632,0.05,100 +50000,0.60434,0.61632,0.05,100 +50000,0.60434,0.61632,0.05,100 +50000,0.60434,0.61632,0.05,100 +50000,0.60434,0.61632,0.05,100 +50000,0.60434,0.61632,0.05,100 +50000,0.60434,0.61632,0.05,100 +50000,0.61631,0.62853,0.05,100 +50000,0.61631,0.62853,0.05,100 +50000,0.61631,0.62853,0.05,100 +50000,0.61631,0.62853,0.05,100 +50000,0.61631,0.62853,0.05,100 +50000,0.61631,0.62853,0.05,100 +50000,0.61631,0.62853,0.05,100 +50000,0.61631,0.62853,0.05,100 +50000,0.61631,0.62853,0.05,100 +50000,0.61631,0.62853,0.05,100 +50000,0.61631,0.62853,0.05,100 +50000,0.61631,0.62853,0.05,100 +50000,0.62852,0.64098,0.05,100 +50000,0.62852,0.64098,0.05,100 +50000,0.62852,0.64098,0.05,100 +50000,0.62852,0.64098,0.05,100 +50000,0.62852,0.64098,0.05,100 +50000,0.62852,0.64098,0.05,100 +50000,0.62852,0.64098,0.05,100 +50000,0.62852,0.64098,0.05,100 +50000,0.62852,0.64098,0.05,100 +50000,0.62852,0.64098,0.05,100 +50000,0.62852,0.64098,0.05,100 +50000,0.62852,0.64098,0.05,100 +50000,0.62852,0.64098,0.05,100 +50000,0.64097,0.65368,0.05,100 +50000,0.64097,0.65368,0.05,100 +50000,0.64097,0.65368,0.05,100 +50000,0.64097,0.65368,0.05,100 +50000,0.64097,0.65368,0.05,100 +50000,0.64097,0.65368,0.05,100 +50000,0.64097,0.65368,0.05,100 +50000,0.64097,0.65368,0.05,100 +50000,0.64097,0.65368,0.05,100 +50000,0.64097,0.65368,0.05,100 +50000,0.64097,0.65368,0.05,100 +50000,0.64097,0.65368,0.05,100 +50000,0.65367,0.66663,0.05,100 +50000,0.65367,0.66663,0.05,100 +50000,0.65367,0.66663,0.05,100 +50000,0.65367,0.66663,0.05,100 +50000,0.65367,0.66663,0.05,100 +50000,0.65367,0.66663,0.05,100 +50000,0.65367,0.66663,0.05,100 +50000,0.65367,0.66663,0.05,100 +50000,0.65367,0.66663,0.05,100 +50000,0.65367,0.66663,0.05,100 +50000,0.65367,0.66663,0.05,100 +50000,0.65367,0.66663,0.05,100 +50000,0.65367,0.66663,0.05,100 +50000,0.66662,0.67984,0.05,100 +50000,0.66662,0.67984,0.05,100 +50000,0.66662,0.67984,0.05,100 +50000,0.66662,0.67984,0.05,100 +50000,0.66662,0.67984,0.05,100 +50000,0.66662,0.67984,0.05,100 +50000,0.66662,0.67984,0.05,100 +50000,0.66662,0.67984,0.05,100 +50000,0.66662,0.67984,0.05,100 +50000,0.66662,0.67984,0.05,100 +50000,0.66662,0.67984,0.05,100 +50000,0.66662,0.67984,0.05,100 +50000,0.66662,0.67984,0.05,100 +50000,0.67983,0.69331,0.05,100 +50000,0.67983,0.69331,0.05,100 +50000,0.67983,0.69331,0.05,100 +50000,0.67983,0.69331,0.05,100 +50000,0.67983,0.69331,0.05,100 +50000,0.67983,0.69331,0.05,100 +50000,0.67983,0.69331,0.05,100 +50000,0.67983,0.69331,0.05,100 +50000,0.67983,0.69331,0.05,100 +50000,0.67983,0.69331,0.05,100 +50000,0.67983,0.69331,0.05,100 +50000,0.67983,0.69331,0.05,100 +50000,0.67983,0.69331,0.05,100 +50000,0.67983,0.69331,0.05,100 +50000,0.6933,0.70704,0.05,100 +50000,0.6933,0.70704,0.05,100 +50000,0.6933,0.70704,0.05,100 +50000,0.6933,0.70704,0.05,100 +50000,0.6933,0.70704,0.05,100 +50000,0.6933,0.70704,0.05,100 +50000,0.6933,0.70704,0.05,100 +50000,0.6933,0.70704,0.05,100 +50000,0.6933,0.70704,0.05,100 +50000,0.6933,0.70704,0.05,100 +50000,0.6933,0.70704,0.05,100 +50000,0.6933,0.70704,0.05,100 +50000,0.6933,0.70704,0.05,100 +50000,0.6933,0.70704,0.05,100 +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan +50000,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/temperatureDependentVolumetricHeatCapacity_plot.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/temperatureDependentVolumetricHeatCapacity_plot.py new file mode 100644 index 00000000000..20d7eed6613 --- /dev/null +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/nonLinearThermalDiffusion_TemperatureDependentVolumetricHeatCapacity/temperatureDependentVolumetricHeatCapacity_plot.py @@ -0,0 +1,216 @@ +import os +import sys +import os +import argparse + +import numpy as np +import matplotlib.pyplot as plt +import pandas as pd +import scipy.linalg +from scipy import special + +from scipy.sparse import diags +from scipy.sparse.linalg import spsolve + +from xml.etree import ElementTree + +# Analytical results for linear thermal behavior +def steadyState(Tin, Tout, Rin, Rout, radialCoordinate): + return Tin + (Tout - Tin) * (np.log(radialCoordinate) - np.log(Rin)) / (np.log(Rout) - np.log(Rin)) + +def diffusionFunction(radialCoordinate, Rin, diffusionCoefficient, diffusionTime): + return special.erfc( (radialCoordinate - Rin) / 2.0 / np.sqrt( diffusionCoefficient * diffusionTime ) ) + +def computeTransientTemperature(Tin, Tout, Rin, radialCoordinate, thermalDiffusionCoefficient, diffusionTime): + # Ref. Wang and Papamichos (1994), https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/94WR01774 + return Tout + (Tin-Tout) * np.sqrt(Rin/radialCoordinate) * diffusionFunction(radialCoordinate, Rin, thermalDiffusionCoefficient, diffusionTime) + +def computeThermalDiffusionCoefficient(thermalConductivity, volumetricHeatCapacity): + return thermalConductivity / volumetricHeatCapacity + +# Finite difference results for non-linear thermal behavior +def temperatureDependentThermalConductivity(lambda0, lambda_gradient, T, Treference): + return lambda0 + lambda_gradient*(T-Treference) + +def temperatureDependentVolumetricHeat(c0, c_gradient, T, Treference): + return c0 + c_gradient*(T-Treference) + +def coefficientMatrix(thermalConductivity, volumetricHeatCapacity, r, dt, N): + # Coefficients for the matrix + A = np.zeros((N+1, N+1)) + + for i in range(1,N): + dr = r[i] - r[i-1] + r_i = r[i] + + diffusivity_i = thermalConductivity[i]/volumetricHeatCapacity[i] + A[i, i-1] = - diffusivity_i * (dt/(dr**2) - dt/(2 * r_i * dr)) \ + + (thermalConductivity[i+1] - thermalConductivity[i-1])/volumetricHeatCapacity[i]*dt/4/(dr**2) + A[i, i] = 1.0 + 2.0 * diffusivity_i * dt / (dr**2) + A[i, i+1] = - diffusivity_i * (dt/(dr**2) + dt/(2 * r_i * dr)) \ + - (thermalConductivity[i+1] - thermalConductivity[i-1])/volumetricHeatCapacity[i]*dt/4/(dr**2) + + # Boundary conditions + # No-flux at r=0 approximated by setting the flux between the first two cells to zero + A[0, 0] = 1.0 + A[N, N] = 1.0 + return A + +def solve_radial_diffusion(r, tmax, dt, Tin, Tout, lambda0, lambda_gradient, c0, c_gradient, Treference): + N = len(r)-1 + # Time setup + n_steps = int(tmax / dt) + + # Time-stepping + T = np.zeros(N+1) + Tout # initial condition u(r, 0) + T[0] = Tin + for step in range(n_steps): + thermalConductivity = temperatureDependentThermalConductivity(lambda0, lambda_gradient, T, Treference) + + volumetricHeatCapacity = temperatureDependentVolumetricHeat(c0, c_gradient, T, Treference) + + A = coefficientMatrix(thermalConductivity, volumetricHeatCapacity, r, dt, N) + T = spsolve(A, T) + + return T + + +def extractDataFromXMLList(paramList): + # Extract data from a list in XML such as "{ 1, 2, 3}" + return paramList.replace('{', '').replace('}', '').strip().split(',') + +def getWellboreGeometryFromXML(xmlFilePath): + tree = ElementTree.parse(xmlFilePath) + + meshParam = tree.find('Mesh/InternalWellbore') + radii = extractDataFromXMLList( meshParam.get("radius") ) + + Rin = float(radii[0]) + Rout = float(radii[-1]) + + return [Rin, Rout] + +def getLoadingFromXML(xmlFilePath): + tree = ElementTree.parse(xmlFilePath) + fsParams = tree.findall('FieldSpecifications/FieldSpecification') + + for fsParam in fsParams: + if ( (fsParam.get('fieldName') == "pressure") & (fsParam.get('initialCondition') != "1") ): + if fsParam.get('setNames') == "{ rneg }": + Pin = float(fsParam.get('scale')) + if fsParam.get('setNames') == "{ rpos }": + Pout = float(fsParam.get('scale')) + + for fsParam in fsParams: + if ( (fsParam.get('fieldName') == "temperature") & (fsParam.get('initialCondition') != "1") ): + if fsParam.get('setNames') == "{ rneg }": + Tin = float(fsParam.get('scale')) + if fsParam.get('setNames') == "{ rpos }": + Tout = float(fsParam.get('scale')) + + + tree_SinglePhaseThermalConductivities = tree.findall('Constitutive/SinglePhaseThermalConductivity') + + for tree_SinglePhaseThermalConductivity in tree_SinglePhaseThermalConductivities: + if tree_SinglePhaseThermalConductivity.get('name') == "thermalCond_linear": + defaultThermalConductivity = float( extractDataFromXMLList( tree_SinglePhaseThermalConductivity.get('defaultThermalConductivityComponents') )[0] ) + thermalConductivityGradient = 0.0 + + tree_SolidInternalEnergies = tree.findall('Constitutive/SolidInternalEnergy') + + for tree_SolidInternalEnergy in tree_SolidInternalEnergies: + if tree_SolidInternalEnergy.get('name') == "rockInternalEnergy_nonLinear": + referenceVolumetricHeatCapacity = float( tree_SolidInternalEnergy.get('referenceVolumetricHeatCapacity') ) + dVolumetricHeatCapacity_dTemperature = float( tree_SolidInternalEnergy.get('dVolumetricHeatCapacity_dTemperature') ) + referenceTemperature = float( tree_SolidInternalEnergy.get('referenceTemperature') ) + + + permeability = float( extractDataFromXMLList( tree.find('Constitutive/ConstantPermeability').get('permeabilityComponents') )[0] ) + + porosity = float( tree.find('Constitutive/PressurePorosity').get('defaultReferencePorosity') ) + + fluidViscosity = float( tree.find('Constitutive/ThermalCompressibleSinglePhaseFluid').get('defaultViscosity') ) + + fluidCompressibility = float( tree.find('Constitutive/ThermalCompressibleSinglePhaseFluid').get('compressibility') ) + + fluidThermalExpansionCoefficient = float( tree.find('Constitutive/ThermalCompressibleSinglePhaseFluid').get('thermalExpansionCoeff') ) + + return [Pin, Pout, Tin, Tout, defaultThermalConductivity, thermalConductivityGradient, referenceTemperature, referenceVolumetricHeatCapacity, dVolumetricHeatCapacity_dTemperature, permeability, porosity, fluidViscosity, fluidCompressibility, fluidThermalExpansionCoefficient] + + +def main(): + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + + # Parse the command-line arguments + args = parser.parse_args() + + geosDir = args.geosDir + + xmlFilePath = geosDir + "/inputFiles/singlePhaseFlow/" + + Rin, Rout = getWellboreGeometryFromXML(xmlFilePath+"thermalCompressible_temperatureDependentVolumetricHeatCapacity_benchmark.xml") + + Pin, Pout, Tin, Tout, defaultThermalConductivity, thermalConductivityGradient, referenceTemperature, volumetricHeatCapacity, dVolumetricHeatCapacity_dTemperature, permeability, porosity, fluidViscosity, fluidCompressibility, fluidThermalExpansionCoefficient = getLoadingFromXML(xmlFilePath+"thermalCompressible_2d_base.xml") + + plt.figure(figsize=(10,7)) + font = {'size' : 16} + plt.rc('font', **font) + + for chart_idx, idx in enumerate([1, 2, 5, 10]): + # Numerical results + data = pd.read_csv(f'data_{idx}.csv') + data.dropna(inplace=True) + data.drop_duplicates(inplace=True) + data.reset_index(drop=True, inplace=True) + + radialCoordinate = (data['elementCenter:0']**2.0 + data['elementCenter:1']**2.0)**0.5 + temperature = data['temperature'] + #pressure = data['pressure'] + diffusionTime = data['Time'][0] + + # Analytical results for linear thermal behavior, for comparison + radialCoordinate_anal = radialCoordinate# np.arange(Rin, Rout, (Rout-Rin)/100) + + thermalDiffusionCoefficient = computeThermalDiffusionCoefficient(defaultThermalConductivity, volumetricHeatCapacity) + + T_transient_linear = computeTransientTemperature(Tin, Tout, Rin, radialCoordinate_anal, thermalDiffusionCoefficient, diffusionTime) + + # Analytical results of the steady state regime for comparison + T_steadyState = steadyState(Tin, Tout, Rin, Rout, radialCoordinate_anal) + + # Finite different results for non-linear thermal behavior + + T_transient_nonLinear = solve_radial_diffusion(radialCoordinate_anal, diffusionTime, diffusionTime/100, Tin, Tout, defaultThermalConductivity, thermalConductivityGradient, volumetricHeatCapacity, dVolumetricHeatCapacity_dTemperature, referenceTemperature) + + # Visualization + # Temperature + plt.subplot(2,2,chart_idx+1) + plt.plot( radialCoordinate, temperature, 'k+' , label='GEOS' ) + plt.plot( radialCoordinate_anal, T_transient_nonLinear, 'g-' , label='FDM Non-Linear' ) + plt.plot( radialCoordinate_anal, T_transient_linear, 'r-' , label='Analytic Linear' ) + plt.plot( radialCoordinate_anal, T_steadyState, 'b-' , label='Steady State' ) + + if chart_idx==1: + plt.legend() + + if chart_idx in [2,3]: + plt.xlabel('Radial distance from well center') + + if chart_idx in [0,2]: + plt.ylabel('Temperature (°C)') + + plt.ylim(-30,110) + plt.xlim(0.,0.5) + plt.title('t = '+str(diffusionTime)+'(s)') + plt.tight_layout() + + plt.show() + +if __name__ == "__main__": + main() + diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/Example.rst deleted file mode 100644 index 84752f872ea..00000000000 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/Example.rst +++ /dev/null @@ -1,113 +0,0 @@ -.. _AdvancedExamplePureThermalDiffusionWellbore: - - -#################################################### -Pure Thermal Diffusion Around a Wellbore -#################################################### - ------------------------------------------------------------------- -Problem description ------------------------------------------------------------------- - -This example uses the thermal single-phase flow solver to model a pure thermal diffusion problem around a wellbore. To mimic this specific problem, thermal convection and fluid flow are neglected by setting fluid pressure and fluid heat capacity to zero. With a uniform temperature applied on the inner surface of the wellbore, temperature field would radially diffuse as shown in the figure below: - -.. _problemSketchRadialThermalDiffusionWellboreFig: -.. figure:: radialThermalDiffusionSketch.png - :align: center - :width: 500 - :figclass: align-center - - Sketch of the radial thermal diffusion around a wellbore - -Analytical results of the temperature profile along the radial direction is given by `(Wang and Papamichos, 1994) `__ : - -.. math:: - T(r) = T_{in}\sqrt{\frac{R_{in}}{r}}erfc(\frac{r-R_{in}}{2\sqrt{c_{T}t}}) - -where :math:`r` is the radial coordinate, :math:`T_{in}` is the temperature applied on the surface of the wellbore at :math:`r = R_{in}`, :math:`c_{T}` is the thermal diffusion coefficient of rock, which is defined as the ratio between the thermal conductivity and the volumetric heat capacity of rock. - - -**Input file** - -This benchmark example uses no external input file and everything required is -contained within two GEOS xml files that are located at: - -.. code-block:: console - - inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml - -and - -.. code-block:: console - - inputFiles/singlePhaseFlow/thermalCompressible_2d_benchmark.xml - -The corresponding integrated test is - -.. code-block:: console - - inputFiles/singlePhaseFlow/thermalCompressible_2d_smoke.xml - -In this example, we would focus our attention on the ``Constitutive`` and ``FieldSpecifications`` tags. - ------------------------------------------------------------ -Constitutive ------------------------------------------------------------ - -The volumetric heat capacity of the medium around the wellbore is defined in the ``SolidInternalEnergy`` XML block as - -.. literalinclude:: ../../../../../../../inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml - :language: xml - :start-after: - :end-before: - -The thermal conductivity of the medium around the wellbore is defined in the ``SinglePhaseConstantThermalConductivity`` XML block as - -.. literalinclude:: ../../../../../../../inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml - :language: xml - :start-after: - :end-before: - -The volumetric heat capacity of fluid is set to a negligible value to exclude thermal convection effect. It is defined in the ``ThermalCompressibleSinglePhaseFluid`` XML block as - -.. literalinclude:: ../../../../../../../inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml - :language: xml - :start-after: - :end-before: - --------------------------------------------------------------------- -FieldSpecifications --------------------------------------------------------------------- - -The initial temperature, the imposed temperature at the curved wellbore surface as well as the far-field temperature are defined as Dirichlet face boundary conditions using ``faceManager`` as - -.. literalinclude:: ../../../../../../../inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml - :language: xml - :start-after: - :end-before: - -Although a pure thermal diffusion problem is considered, it is also required to define specifications for fluid pressure, as thermal transfer is always coupled with fluid flow in GEOS. In this example, fluid pressure is set to zero everywhere to mimic a pure thermal diffusion problem as - -.. literalinclude:: ../../../../../../../inputFiles/singlePhaseFlow/thermalCompressible_2d_base.xml - :language: xml - :start-after: - :end-before: - ---------------------------------- -Results and benchmark ---------------------------------- - -A good agreement between the GEOS results and analytical results is shown in the figure below: - - -.. plot:: docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/pureThermalDiffusionAroundWellbore.py - - ------------------------------------------------------------------- -To go further ------------------------------------------------------------------- - -**Feedback on this example** - -This concludes the example of pure thermal diffusion problem around a wellbore. -For any feedback on this example, please submit a `GitHub issue on the project's GitHub page `_. diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/data_1.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/data_1.csv deleted file mode 100644 index 4e2e56defb8..00000000000 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/data_1.csv +++ /dev/null @@ -1,1002 +0,0 @@ -Time,"elementCenter:0","elementCenter:1","elementCenter:2","pressure","temperature" -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,nan,nan,nan,nan,nan -10000,0.10099,0.0009915,0.05,11157,98.637 -10000,0.10099,0.0009915,0.05,11157,98.637 -10000,0.10299,0.0010111,0.05,33009,95.965 -10000,0.10299,0.0010111,0.05,33009,95.965 -10000,0.10499,0.0010308,0.05,54404,93.345 -10000,0.10499,0.0010308,0.05,54404,93.345 -10000,0.10734,0.0010538,0.05,79006,90.329 -10000,0.10734,0.0010538,0.05,79006,90.329 -10000,0.10734,0.0010538,0.05,79006,90.329 -10000,0.11004,0.0010803,0.05,1.0645e+05,86.957 -10000,0.11004,0.0010803,0.05,1.0645e+05,86.957 -10000,0.11004,0.0010803,0.05,1.0645e+05,86.957 -10000,0.11274,0.0011068,0.05,1.3309e+05,83.676 -10000,0.11274,0.0011068,0.05,1.3309e+05,83.676 -10000,0.11274,0.0011068,0.05,1.3309e+05,83.676 -10000,0.11544,0.0011334,0.05,1.5893e+05,80.484 -10000,0.11544,0.0011334,0.05,1.5893e+05,80.484 -10000,0.11814,0.0011599,0.05,1.8397e+05,77.381 -10000,0.11814,0.0011599,0.05,1.8397e+05,77.381 -10000,0.11814,0.0011599,0.05,1.8397e+05,77.381 -10000,0.12084,0.0011864,0.05,2.0822e+05,74.363 -10000,0.12084,0.0011864,0.05,2.0822e+05,74.363 -10000,0.12084,0.0011864,0.05,2.0822e+05,74.363 -10000,0.12354,0.0012129,0.05,2.3168e+05,71.432 -10000,0.12354,0.0012129,0.05,2.3168e+05,71.432 -10000,0.12624,0.0012394,0.05,2.5437e+05,68.583 -10000,0.12624,0.0012394,0.05,2.5437e+05,68.583 -10000,0.12624,0.0012394,0.05,2.5437e+05,68.583 -10000,0.12894,0.0012659,0.05,2.7628e+05,65.818 -10000,0.12894,0.0012659,0.05,2.7628e+05,65.818 -10000,0.12894,0.0012659,0.05,2.7628e+05,65.818 -10000,0.13164,0.0012924,0.05,2.9743e+05,63.133 -10000,0.13164,0.0012924,0.05,2.9743e+05,63.133 -10000,0.1343,0.0013185,0.05,3.1752e+05,60.566 -10000,0.1343,0.0013185,0.05,3.1752e+05,60.566 -10000,0.1343,0.0013185,0.05,3.1752e+05,60.566 -10000,0.13695,0.0013445,0.05,3.3679e+05,58.087 -10000,0.13695,0.0013445,0.05,3.3679e+05,58.087 -10000,0.13695,0.0013445,0.05,3.3679e+05,58.087 -10000,0.13965,0.001371,0.05,3.5571e+05,55.635 -10000,0.13965,0.001371,0.05,3.5571e+05,55.635 -10000,0.13965,0.001371,0.05,3.5571e+05,55.635 -10000,0.1424,0.0013981,0.05,3.7423e+05,53.214 -10000,0.1424,0.0013981,0.05,3.7423e+05,53.214 -10000,0.14521,0.0014256,0.05,3.9234e+05,50.826 -10000,0.14521,0.0014256,0.05,3.9234e+05,50.826 -10000,0.14521,0.0014256,0.05,3.9234e+05,50.826 -10000,0.14807,0.0014538,0.05,4.0999e+05,48.473 -10000,0.14807,0.0014538,0.05,4.0999e+05,48.473 -10000,0.14807,0.0014538,0.05,4.0999e+05,48.473 -10000,0.151,0.0014824,0.05,4.2717e+05,46.158 -10000,0.151,0.0014824,0.05,4.2717e+05,46.158 -10000,0.151,0.0014824,0.05,4.2717e+05,46.158 -10000,0.15397,0.0015117,0.05,4.4383e+05,43.883 -10000,0.15397,0.0015117,0.05,4.4383e+05,43.883 -10000,0.15397,0.0015117,0.05,4.4383e+05,43.883 -10000,0.15701,0.0015415,0.05,4.5994e+05,41.652 -10000,0.15701,0.0015415,0.05,4.5994e+05,41.652 -10000,0.15701,0.0015415,0.05,4.5994e+05,41.652 -10000,0.16011,0.0015719,0.05,4.7548e+05,39.466 -10000,0.16011,0.0015719,0.05,4.7548e+05,39.466 -10000,0.16011,0.0015719,0.05,4.7548e+05,39.466 -10000,0.16327,0.001603,0.05,4.9042e+05,37.329 -10000,0.16327,0.001603,0.05,4.9042e+05,37.329 -10000,0.16327,0.001603,0.05,4.9042e+05,37.329 -10000,0.16649,0.0016346,0.05,5.0472e+05,35.242 -10000,0.16649,0.0016346,0.05,5.0472e+05,35.242 -10000,0.16649,0.0016346,0.05,5.0472e+05,35.242 -10000,0.16649,0.0016346,0.05,5.0472e+05,35.242 -10000,0.16978,0.0016669,0.05,5.1835e+05,33.208 -10000,0.16978,0.0016669,0.05,5.1835e+05,33.208 -10000,0.16978,0.0016669,0.05,5.1835e+05,33.208 -10000,0.17313,0.0016998,0.05,5.313e+05,31.23 -10000,0.17313,0.0016998,0.05,5.313e+05,31.23 -10000,0.17313,0.0016998,0.05,5.313e+05,31.23 -10000,0.17655,0.0017333,0.05,5.4352e+05,29.309 -10000,0.17655,0.0017333,0.05,5.4352e+05,29.309 -10000,0.17655,0.0017333,0.05,5.4352e+05,29.309 -10000,0.17655,0.0017333,0.05,5.4352e+05,29.309 -10000,0.18004,0.0017676,0.05,5.55e+05,27.447 -10000,0.18004,0.0017676,0.05,5.55e+05,27.447 -10000,0.18004,0.0017676,0.05,5.55e+05,27.447 -10000,0.18359,0.0018025,0.05,5.6572e+05,25.648 -10000,0.18359,0.0018025,0.05,5.6572e+05,25.648 -10000,0.18359,0.0018025,0.05,5.6572e+05,25.648 -10000,0.18359,0.0018025,0.05,5.6572e+05,25.648 -10000,0.18722,0.001838,0.05,5.7565e+05,23.912 -10000,0.18722,0.001838,0.05,5.7565e+05,23.912 -10000,0.18722,0.001838,0.05,5.7565e+05,23.912 -10000,0.18722,0.001838,0.05,5.7565e+05,23.912 -10000,0.19091,0.0018743,0.05,5.8477e+05,22.24 -10000,0.19091,0.0018743,0.05,5.8477e+05,22.24 -10000,0.19091,0.0018743,0.05,5.8477e+05,22.24 -10000,0.19468,0.0019114,0.05,5.9307e+05,20.635 -10000,0.19468,0.0019114,0.05,5.9307e+05,20.635 -10000,0.19468,0.0019114,0.05,5.9307e+05,20.635 -10000,0.19468,0.0019114,0.05,5.9307e+05,20.635 -10000,0.19853,0.0019491,0.05,6.0054e+05,19.098 -10000,0.19853,0.0019491,0.05,6.0054e+05,19.098 -10000,0.19853,0.0019491,0.05,6.0054e+05,19.098 -10000,0.19853,0.0019491,0.05,6.0054e+05,19.098 -10000,0.20245,0.0019876,0.05,6.0715e+05,17.629 -10000,0.20245,0.0019876,0.05,6.0715e+05,17.629 -10000,0.20245,0.0019876,0.05,6.0715e+05,17.629 -10000,0.20245,0.0019876,0.05,6.0715e+05,17.629 -10000,0.20645,0.0020269,0.05,6.1292e+05,16.229 -10000,0.20645,0.0020269,0.05,6.1292e+05,16.229 -10000,0.20645,0.0020269,0.05,6.1292e+05,16.229 -10000,0.20645,0.0020269,0.05,6.1292e+05,16.229 -10000,0.21053,0.0020669,0.05,6.1782e+05,14.899 -10000,0.21053,0.0020669,0.05,6.1782e+05,14.899 -10000,0.21053,0.0020669,0.05,6.1782e+05,14.899 -10000,0.21053,0.0020669,0.05,6.1782e+05,14.899 -10000,0.21469,0.0021078,0.05,6.2187e+05,13.638 -10000,0.21469,0.0021078,0.05,6.2187e+05,13.638 -10000,0.21469,0.0021078,0.05,6.2187e+05,13.638 -10000,0.21469,0.0021078,0.05,6.2187e+05,13.638 -10000,0.21893,0.0021494,0.05,6.2506e+05,12.447 -10000,0.21893,0.0021494,0.05,6.2506e+05,12.447 -10000,0.21893,0.0021494,0.05,6.2506e+05,12.447 -10000,0.21893,0.0021494,0.05,6.2506e+05,12.447 -10000,0.21893,0.0021494,0.05,6.2506e+05,12.447 -10000,0.22326,0.0021919,0.05,6.274e+05,11.325 -10000,0.22326,0.0021919,0.05,6.274e+05,11.325 -10000,0.22326,0.0021919,0.05,6.274e+05,11.325 -10000,0.22326,0.0021919,0.05,6.274e+05,11.325 -10000,0.22767,0.0022352,0.05,6.289e+05,10.272 -10000,0.22767,0.0022352,0.05,6.289e+05,10.272 -10000,0.22767,0.0022352,0.05,6.289e+05,10.272 -10000,0.22767,0.0022352,0.05,6.289e+05,10.272 -10000,0.23217,0.0022794,0.05,6.2957e+05,9.2858 -10000,0.23217,0.0022794,0.05,6.2957e+05,9.2858 -10000,0.23217,0.0022794,0.05,6.2957e+05,9.2858 -10000,0.23217,0.0022794,0.05,6.2957e+05,9.2858 -10000,0.23217,0.0022794,0.05,6.2957e+05,9.2858 -10000,0.23676,0.0023244,0.05,6.2942e+05,8.3664 -10000,0.23676,0.0023244,0.05,6.2942e+05,8.3664 -10000,0.23676,0.0023244,0.05,6.2942e+05,8.3664 -10000,0.23676,0.0023244,0.05,6.2942e+05,8.3664 -10000,0.23676,0.0023244,0.05,6.2942e+05,8.3664 -10000,0.24144,0.0023704,0.05,6.2848e+05,7.5119 -10000,0.24144,0.0023704,0.05,6.2848e+05,7.5119 -10000,0.24144,0.0023704,0.05,6.2848e+05,7.5119 -10000,0.24144,0.0023704,0.05,6.2848e+05,7.5119 -10000,0.24621,0.0024172,0.05,6.2677e+05,6.7205 -10000,0.24621,0.0024172,0.05,6.2677e+05,6.7205 -10000,0.24621,0.0024172,0.05,6.2677e+05,6.7205 -10000,0.24621,0.0024172,0.05,6.2677e+05,6.7205 -10000,0.24621,0.0024172,0.05,6.2677e+05,6.7205 -10000,0.25108,0.002465,0.05,6.2432e+05,5.9904 -10000,0.25108,0.002465,0.05,6.2432e+05,5.9904 -10000,0.25108,0.002465,0.05,6.2432e+05,5.9904 -10000,0.25108,0.002465,0.05,6.2432e+05,5.9904 -10000,0.25108,0.002465,0.05,6.2432e+05,5.9904 -10000,0.25604,0.0025137,0.05,6.2114e+05,5.3193 -10000,0.25604,0.0025137,0.05,6.2114e+05,5.3193 -10000,0.25604,0.0025137,0.05,6.2114e+05,5.3193 -10000,0.25604,0.0025137,0.05,6.2114e+05,5.3193 -10000,0.25604,0.0025137,0.05,6.2114e+05,5.3193 -10000,0.2611,0.0025634,0.05,6.1727e+05,4.705 -10000,0.2611,0.0025634,0.05,6.1727e+05,4.705 -10000,0.2611,0.0025634,0.05,6.1727e+05,4.705 -10000,0.2611,0.0025634,0.05,6.1727e+05,4.705 -10000,0.2611,0.0025634,0.05,6.1727e+05,4.705 -10000,0.26626,0.0026141,0.05,6.1275e+05,4.145 -10000,0.26626,0.0026141,0.05,6.1275e+05,4.145 -10000,0.26626,0.0026141,0.05,6.1275e+05,4.145 -10000,0.26626,0.0026141,0.05,6.1275e+05,4.145 -10000,0.26626,0.0026141,0.05,6.1275e+05,4.145 -10000,0.27153,0.0026658,0.05,6.076e+05,3.6365 -10000,0.27153,0.0026658,0.05,6.076e+05,3.6365 -10000,0.27153,0.0026658,0.05,6.076e+05,3.6365 -10000,0.27153,0.0026658,0.05,6.076e+05,3.6365 -10000,0.27153,0.0026658,0.05,6.076e+05,3.6365 -10000,0.27153,0.0026658,0.05,6.076e+05,3.6365 -10000,0.2769,0.0027185,0.05,6.0186e+05,3.1768 -10000,0.2769,0.0027185,0.05,6.0186e+05,3.1768 -10000,0.2769,0.0027185,0.05,6.0186e+05,3.1768 -10000,0.2769,0.0027185,0.05,6.0186e+05,3.1768 -10000,0.2769,0.0027185,0.05,6.0186e+05,3.1768 -10000,0.28237,0.0027723,0.05,5.9557e+05,2.7631 -10000,0.28237,0.0027723,0.05,5.9557e+05,2.7631 -10000,0.28237,0.0027723,0.05,5.9557e+05,2.7631 -10000,0.28237,0.0027723,0.05,5.9557e+05,2.7631 -10000,0.28237,0.0027723,0.05,5.9557e+05,2.7631 -10000,0.28237,0.0027723,0.05,5.9557e+05,2.7631 -10000,0.28796,0.0028271,0.05,5.8877e+05,2.3925 -10000,0.28796,0.0028271,0.05,5.8877e+05,2.3925 -10000,0.28796,0.0028271,0.05,5.8877e+05,2.3925 -10000,0.28796,0.0028271,0.05,5.8877e+05,2.3925 -10000,0.28796,0.0028271,0.05,5.8877e+05,2.3925 -10000,0.29365,0.002883,0.05,5.8149e+05,2.062 -10000,0.29365,0.002883,0.05,5.8149e+05,2.062 -10000,0.29365,0.002883,0.05,5.8149e+05,2.062 -10000,0.29365,0.002883,0.05,5.8149e+05,2.062 -10000,0.29365,0.002883,0.05,5.8149e+05,2.062 -10000,0.29365,0.002883,0.05,5.8149e+05,2.062 -10000,0.29946,0.00294,0.05,5.7377e+05,1.7688 -10000,0.29946,0.00294,0.05,5.7377e+05,1.7688 -10000,0.29946,0.00294,0.05,5.7377e+05,1.7688 -10000,0.29946,0.00294,0.05,5.7377e+05,1.7688 -10000,0.29946,0.00294,0.05,5.7377e+05,1.7688 -10000,0.29946,0.00294,0.05,5.7377e+05,1.7688 -10000,0.30538,0.0029982,0.05,5.6564e+05,1.5099 -10000,0.30538,0.0029982,0.05,5.6564e+05,1.5099 -10000,0.30538,0.0029982,0.05,5.6564e+05,1.5099 -10000,0.30538,0.0029982,0.05,5.6564e+05,1.5099 -10000,0.30538,0.0029982,0.05,5.6564e+05,1.5099 -10000,0.30538,0.0029982,0.05,5.6564e+05,1.5099 -10000,0.31142,0.0030575,0.05,5.5715e+05,1.2824 -10000,0.31142,0.0030575,0.05,5.5715e+05,1.2824 -10000,0.31142,0.0030575,0.05,5.5715e+05,1.2824 -10000,0.31142,0.0030575,0.05,5.5715e+05,1.2824 -10000,0.31142,0.0030575,0.05,5.5715e+05,1.2824 -10000,0.31142,0.0030575,0.05,5.5715e+05,1.2824 -10000,0.31758,0.003118,0.05,5.4832e+05,1.0837 -10000,0.31758,0.003118,0.05,5.4832e+05,1.0837 -10000,0.31758,0.003118,0.05,5.4832e+05,1.0837 -10000,0.31758,0.003118,0.05,5.4832e+05,1.0837 -10000,0.31758,0.003118,0.05,5.4832e+05,1.0837 -10000,0.31758,0.003118,0.05,5.4832e+05,1.0837 -10000,0.32386,0.0031796,0.05,5.392e+05,0.91088 -10000,0.32386,0.0031796,0.05,5.392e+05,0.91088 -10000,0.32386,0.0031796,0.05,5.392e+05,0.91088 -10000,0.32386,0.0031796,0.05,5.392e+05,0.91088 -10000,0.32386,0.0031796,0.05,5.392e+05,0.91088 -10000,0.32386,0.0031796,0.05,5.392e+05,0.91088 -10000,0.32386,0.0031796,0.05,5.392e+05,0.91088 -10000,0.33027,0.0032425,0.05,5.2982e+05,0.76151 -10000,0.33027,0.0032425,0.05,5.2982e+05,0.76151 -10000,0.33027,0.0032425,0.05,5.2982e+05,0.76151 -10000,0.33027,0.0032425,0.05,5.2982e+05,0.76151 -10000,0.33027,0.0032425,0.05,5.2982e+05,0.76151 -10000,0.33027,0.0032425,0.05,5.2982e+05,0.76151 -10000,0.3368,0.0033067,0.05,5.202e+05,0.63311 -10000,0.3368,0.0033067,0.05,5.202e+05,0.63311 -10000,0.3368,0.0033067,0.05,5.202e+05,0.63311 -10000,0.3368,0.0033067,0.05,5.202e+05,0.63311 -10000,0.3368,0.0033067,0.05,5.202e+05,0.63311 -10000,0.3368,0.0033067,0.05,5.202e+05,0.63311 -10000,0.3368,0.0033067,0.05,5.202e+05,0.63311 -10000,0.34347,0.0033721,0.05,5.1038e+05,0.52338 -10000,0.34347,0.0033721,0.05,5.1038e+05,0.52338 -10000,0.34347,0.0033721,0.05,5.1038e+05,0.52338 -10000,0.34347,0.0033721,0.05,5.1038e+05,0.52338 -10000,0.34347,0.0033721,0.05,5.1038e+05,0.52338 -10000,0.34347,0.0033721,0.05,5.1038e+05,0.52338 -10000,0.35026,0.0034388,0.05,5.0039e+05,0.43015 -10000,0.35026,0.0034388,0.05,5.0039e+05,0.43015 -10000,0.35026,0.0034388,0.05,5.0039e+05,0.43015 -10000,0.35026,0.0034388,0.05,5.0039e+05,0.43015 -10000,0.35026,0.0034388,0.05,5.0039e+05,0.43015 -10000,0.35026,0.0034388,0.05,5.0039e+05,0.43015 -10000,0.35026,0.0034388,0.05,5.0039e+05,0.43015 -10000,0.35719,0.0035069,0.05,4.9025e+05,0.35142 -10000,0.35719,0.0035069,0.05,4.9025e+05,0.35142 -10000,0.35719,0.0035069,0.05,4.9025e+05,0.35142 -10000,0.35719,0.0035069,0.05,4.9025e+05,0.35142 -10000,0.35719,0.0035069,0.05,4.9025e+05,0.35142 -10000,0.35719,0.0035069,0.05,4.9025e+05,0.35142 -10000,0.35719,0.0035069,0.05,4.9025e+05,0.35142 -10000,0.36426,0.0035762,0.05,4.7999e+05,0.28535 -10000,0.36426,0.0035762,0.05,4.7999e+05,0.28535 -10000,0.36426,0.0035762,0.05,4.7999e+05,0.28535 -10000,0.36426,0.0035762,0.05,4.7999e+05,0.28535 -10000,0.36426,0.0035762,0.05,4.7999e+05,0.28535 -10000,0.36426,0.0035762,0.05,4.7999e+05,0.28535 -10000,0.36426,0.0035762,0.05,4.7999e+05,0.28535 -10000,0.37147,0.003647,0.05,4.6962e+05,0.23025 -10000,0.37147,0.003647,0.05,4.6962e+05,0.23025 -10000,0.37147,0.003647,0.05,4.6962e+05,0.23025 -10000,0.37147,0.003647,0.05,4.6962e+05,0.23025 -10000,0.37147,0.003647,0.05,4.6962e+05,0.23025 -10000,0.37147,0.003647,0.05,4.6962e+05,0.23025 -10000,0.37147,0.003647,0.05,4.6962e+05,0.23025 -10000,0.37147,0.003647,0.05,4.6962e+05,0.23025 -10000,0.37882,0.0037192,0.05,4.5918e+05,0.1846 -10000,0.37882,0.0037192,0.05,4.5918e+05,0.1846 -10000,0.37882,0.0037192,0.05,4.5918e+05,0.1846 -10000,0.37882,0.0037192,0.05,4.5918e+05,0.1846 -10000,0.37882,0.0037192,0.05,4.5918e+05,0.1846 -10000,0.37882,0.0037192,0.05,4.5918e+05,0.1846 -10000,0.37882,0.0037192,0.05,4.5918e+05,0.1846 -10000,0.38632,0.0037928,0.05,4.4867e+05,0.14703 -10000,0.38632,0.0037928,0.05,4.4867e+05,0.14703 -10000,0.38632,0.0037928,0.05,4.4867e+05,0.14703 -10000,0.38632,0.0037928,0.05,4.4867e+05,0.14703 -10000,0.38632,0.0037928,0.05,4.4867e+05,0.14703 -10000,0.38632,0.0037928,0.05,4.4867e+05,0.14703 -10000,0.38632,0.0037928,0.05,4.4867e+05,0.14703 -10000,0.38632,0.0037928,0.05,4.4867e+05,0.14703 -10000,0.39396,0.0038678,0.05,4.3813e+05,0.11632 -10000,0.39396,0.0038678,0.05,4.3813e+05,0.11632 -10000,0.39396,0.0038678,0.05,4.3813e+05,0.11632 -10000,0.39396,0.0038678,0.05,4.3813e+05,0.11632 -10000,0.39396,0.0038678,0.05,4.3813e+05,0.11632 -10000,0.39396,0.0038678,0.05,4.3813e+05,0.11632 -10000,0.39396,0.0038678,0.05,4.3813e+05,0.11632 -10000,0.40176,0.0039444,0.05,4.2755e+05,0.091393 -10000,0.40176,0.0039444,0.05,4.2755e+05,0.091393 -10000,0.40176,0.0039444,0.05,4.2755e+05,0.091393 -10000,0.40176,0.0039444,0.05,4.2755e+05,0.091393 -10000,0.40176,0.0039444,0.05,4.2755e+05,0.091393 -10000,0.40176,0.0039444,0.05,4.2755e+05,0.091393 -10000,0.40176,0.0039444,0.05,4.2755e+05,0.091393 -10000,0.40176,0.0039444,0.05,4.2755e+05,0.091393 -10000,0.40971,0.0040224,0.05,4.1695e+05,0.071303 -10000,0.40971,0.0040224,0.05,4.1695e+05,0.071303 -10000,0.40971,0.0040224,0.05,4.1695e+05,0.071303 -10000,0.40971,0.0040224,0.05,4.1695e+05,0.071303 -10000,0.40971,0.0040224,0.05,4.1695e+05,0.071303 -10000,0.40971,0.0040224,0.05,4.1695e+05,0.071303 -10000,0.40971,0.0040224,0.05,4.1695e+05,0.071303 -10000,0.40971,0.0040224,0.05,4.1695e+05,0.071303 -10000,0.41782,0.004102,0.05,4.0636e+05,0.055229 -10000,0.41782,0.004102,0.05,4.0636e+05,0.055229 -10000,0.41782,0.004102,0.05,4.0636e+05,0.055229 -10000,0.41782,0.004102,0.05,4.0636e+05,0.055229 -10000,0.41782,0.004102,0.05,4.0636e+05,0.055229 -10000,0.41782,0.004102,0.05,4.0636e+05,0.055229 -10000,0.41782,0.004102,0.05,4.0636e+05,0.055229 -10000,0.41782,0.004102,0.05,4.0636e+05,0.055229 -10000,0.42609,0.0041832,0.05,3.9577e+05,0.042464 -10000,0.42609,0.0041832,0.05,3.9577e+05,0.042464 -10000,0.42609,0.0041832,0.05,3.9577e+05,0.042464 -10000,0.42609,0.0041832,0.05,3.9577e+05,0.042464 -10000,0.42609,0.0041832,0.05,3.9577e+05,0.042464 -10000,0.42609,0.0041832,0.05,3.9577e+05,0.042464 -10000,0.42609,0.0041832,0.05,3.9577e+05,0.042464 -10000,0.42609,0.0041832,0.05,3.9577e+05,0.042464 -10000,0.42609,0.0041832,0.05,3.9577e+05,0.042464 -10000,0.43452,0.004266,0.05,3.8519e+05,0.032404 -10000,0.43452,0.004266,0.05,3.8519e+05,0.032404 -10000,0.43452,0.004266,0.05,3.8519e+05,0.032404 -10000,0.43452,0.004266,0.05,3.8519e+05,0.032404 -10000,0.43452,0.004266,0.05,3.8519e+05,0.032404 -10000,0.43452,0.004266,0.05,3.8519e+05,0.032404 -10000,0.43452,0.004266,0.05,3.8519e+05,0.032404 -10000,0.43452,0.004266,0.05,3.8519e+05,0.032404 -10000,0.44312,0.0043505,0.05,3.7464e+05,0.024537 -10000,0.44312,0.0043505,0.05,3.7464e+05,0.024537 -10000,0.44312,0.0043505,0.05,3.7464e+05,0.024537 -10000,0.44312,0.0043505,0.05,3.7464e+05,0.024537 -10000,0.44312,0.0043505,0.05,3.7464e+05,0.024537 -10000,0.44312,0.0043505,0.05,3.7464e+05,0.024537 -10000,0.44312,0.0043505,0.05,3.7464e+05,0.024537 -10000,0.44312,0.0043505,0.05,3.7464e+05,0.024537 -10000,0.44312,0.0043505,0.05,3.7464e+05,0.024537 -10000,0.45189,0.0044366,0.05,3.6413e+05,0.018434 -10000,0.45189,0.0044366,0.05,3.6413e+05,0.018434 -10000,0.45189,0.0044366,0.05,3.6413e+05,0.018434 -10000,0.45189,0.0044366,0.05,3.6413e+05,0.018434 -10000,0.45189,0.0044366,0.05,3.6413e+05,0.018434 -10000,0.45189,0.0044366,0.05,3.6413e+05,0.018434 -10000,0.45189,0.0044366,0.05,3.6413e+05,0.018434 -10000,0.45189,0.0044366,0.05,3.6413e+05,0.018434 -10000,0.45189,0.0044366,0.05,3.6413e+05,0.018434 -10000,0.46084,0.0045244,0.05,3.5365e+05,0.013738 -10000,0.46084,0.0045244,0.05,3.5365e+05,0.013738 -10000,0.46084,0.0045244,0.05,3.5365e+05,0.013738 -10000,0.46084,0.0045244,0.05,3.5365e+05,0.013738 -10000,0.46084,0.0045244,0.05,3.5365e+05,0.013738 -10000,0.46084,0.0045244,0.05,3.5365e+05,0.013738 -10000,0.46084,0.0045244,0.05,3.5365e+05,0.013738 -10000,0.46084,0.0045244,0.05,3.5365e+05,0.013738 -10000,0.46084,0.0045244,0.05,3.5365e+05,0.013738 -10000,0.46996,0.004614,0.05,3.4322e+05,0.010154 -10000,0.46996,0.004614,0.05,3.4322e+05,0.010154 -10000,0.46996,0.004614,0.05,3.4322e+05,0.010154 -10000,0.46996,0.004614,0.05,3.4322e+05,0.010154 -10000,0.46996,0.004614,0.05,3.4322e+05,0.010154 -10000,0.46996,0.004614,0.05,3.4322e+05,0.010154 -10000,0.46996,0.004614,0.05,3.4322e+05,0.010154 -10000,0.46996,0.004614,0.05,3.4322e+05,0.010154 -10000,0.46996,0.004614,0.05,3.4322e+05,0.010154 -10000,0.47926,0.0047053,0.05,3.3284e+05,0.0074422 -10000,0.47926,0.0047053,0.05,3.3284e+05,0.0074422 -10000,0.47926,0.0047053,0.05,3.3284e+05,0.0074422 -10000,0.47926,0.0047053,0.05,3.3284e+05,0.0074422 -10000,0.47926,0.0047053,0.05,3.3284e+05,0.0074422 -10000,0.47926,0.0047053,0.05,3.3284e+05,0.0074422 -10000,0.47926,0.0047053,0.05,3.3284e+05,0.0074422 -10000,0.47926,0.0047053,0.05,3.3284e+05,0.0074422 -10000,0.47926,0.0047053,0.05,3.3284e+05,0.0074422 -10000,0.48875,0.0047985,0.05,3.2251e+05,0.0054079 -10000,0.48875,0.0047985,0.05,3.2251e+05,0.0054079 -10000,0.48875,0.0047985,0.05,3.2251e+05,0.0054079 -10000,0.48875,0.0047985,0.05,3.2251e+05,0.0054079 -10000,0.48875,0.0047985,0.05,3.2251e+05,0.0054079 -10000,0.48875,0.0047985,0.05,3.2251e+05,0.0054079 -10000,0.48875,0.0047985,0.05,3.2251e+05,0.0054079 -10000,0.48875,0.0047985,0.05,3.2251e+05,0.0054079 -10000,0.48875,0.0047985,0.05,3.2251e+05,0.0054079 -10000,0.48875,0.0047985,0.05,3.2251e+05,0.0054079 -10000,0.49843,0.0048935,0.05,3.1224e+05,0.0038952 -10000,0.49843,0.0048935,0.05,3.1224e+05,0.0038952 -10000,0.49843,0.0048935,0.05,3.1224e+05,0.0038952 -10000,0.49843,0.0048935,0.05,3.1224e+05,0.0038952 -10000,0.49843,0.0048935,0.05,3.1224e+05,0.0038952 -10000,0.49843,0.0048935,0.05,3.1224e+05,0.0038952 -10000,0.49843,0.0048935,0.05,3.1224e+05,0.0038952 -10000,0.49843,0.0048935,0.05,3.1224e+05,0.0038952 -10000,0.49843,0.0048935,0.05,3.1224e+05,0.0038952 -10000,0.49843,0.0048935,0.05,3.1224e+05,0.0038952 -10000,0.5083,0.0049903,0.05,3.0204e+05,0.0027806 -10000,0.5083,0.0049903,0.05,3.0204e+05,0.0027806 -10000,0.5083,0.0049903,0.05,3.0204e+05,0.0027806 -10000,0.5083,0.0049903,0.05,3.0204e+05,0.0027806 -10000,0.5083,0.0049903,0.05,3.0204e+05,0.0027806 -10000,0.5083,0.0049903,0.05,3.0204e+05,0.0027806 -10000,0.5083,0.0049903,0.05,3.0204e+05,0.0027806 -10000,0.5083,0.0049903,0.05,3.0204e+05,0.0027806 -10000,0.5083,0.0049903,0.05,3.0204e+05,0.0027806 -10000,0.5083,0.0049903,0.05,3.0204e+05,0.0027806 -10000,0.51836,0.0050891,0.05,2.919e+05,0.0019668 -10000,0.51836,0.0050891,0.05,2.919e+05,0.0019668 -10000,0.51836,0.0050891,0.05,2.919e+05,0.0019668 -10000,0.51836,0.0050891,0.05,2.919e+05,0.0019668 -10000,0.51836,0.0050891,0.05,2.919e+05,0.0019668 -10000,0.51836,0.0050891,0.05,2.919e+05,0.0019668 -10000,0.51836,0.0050891,0.05,2.919e+05,0.0019668 -10000,0.51836,0.0050891,0.05,2.919e+05,0.0019668 -10000,0.51836,0.0050891,0.05,2.919e+05,0.0019668 -10000,0.51836,0.0050891,0.05,2.919e+05,0.0019668 -10000,0.52862,0.0051899,0.05,2.8183e+05,0.0013782 -10000,0.52862,0.0051899,0.05,2.8183e+05,0.0013782 -10000,0.52862,0.0051899,0.05,2.8183e+05,0.0013782 -10000,0.52862,0.0051899,0.05,2.8183e+05,0.0013782 -10000,0.52862,0.0051899,0.05,2.8183e+05,0.0013782 -10000,0.52862,0.0051899,0.05,2.8183e+05,0.0013782 -10000,0.52862,0.0051899,0.05,2.8183e+05,0.0013782 -10000,0.52862,0.0051899,0.05,2.8183e+05,0.0013782 -10000,0.52862,0.0051899,0.05,2.8183e+05,0.0013782 -10000,0.52862,0.0051899,0.05,2.8183e+05,0.0013782 -10000,0.53909,0.0052927,0.05,2.7183e+05,0.00095658 -10000,0.53909,0.0052927,0.05,2.7183e+05,0.00095658 -10000,0.53909,0.0052927,0.05,2.7183e+05,0.00095658 -10000,0.53909,0.0052927,0.05,2.7183e+05,0.00095658 -10000,0.53909,0.0052927,0.05,2.7183e+05,0.00095658 -10000,0.53909,0.0052927,0.05,2.7183e+05,0.00095658 -10000,0.53909,0.0052927,0.05,2.7183e+05,0.00095658 -10000,0.53909,0.0052927,0.05,2.7183e+05,0.00095658 -10000,0.53909,0.0052927,0.05,2.7183e+05,0.00095658 -10000,0.53909,0.0052927,0.05,2.7183e+05,0.00095658 -10000,0.53909,0.0052927,0.05,2.7183e+05,0.00095658 -10000,0.54976,0.0053975,0.05,2.6191e+05,0.00065749 -10000,0.54976,0.0053975,0.05,2.6191e+05,0.00065749 -10000,0.54976,0.0053975,0.05,2.6191e+05,0.00065749 -10000,0.54976,0.0053975,0.05,2.6191e+05,0.00065749 -10000,0.54976,0.0053975,0.05,2.6191e+05,0.00065749 -10000,0.54976,0.0053975,0.05,2.6191e+05,0.00065749 -10000,0.54976,0.0053975,0.05,2.6191e+05,0.00065749 -10000,0.54976,0.0053975,0.05,2.6191e+05,0.00065749 -10000,0.54976,0.0053975,0.05,2.6191e+05,0.00065749 -10000,0.54976,0.0053975,0.05,2.6191e+05,0.00065749 -10000,0.54976,0.0053975,0.05,2.6191e+05,0.00065749 -10000,0.56065,0.0055043,0.05,2.5206e+05,0.00044744 -10000,0.56065,0.0055043,0.05,2.5206e+05,0.00044744 -10000,0.56065,0.0055043,0.05,2.5206e+05,0.00044744 -10000,0.56065,0.0055043,0.05,2.5206e+05,0.00044744 -10000,0.56065,0.0055043,0.05,2.5206e+05,0.00044744 -10000,0.56065,0.0055043,0.05,2.5206e+05,0.00044744 -10000,0.56065,0.0055043,0.05,2.5206e+05,0.00044744 -10000,0.56065,0.0055043,0.05,2.5206e+05,0.00044744 -10000,0.56065,0.0055043,0.05,2.5206e+05,0.00044744 -10000,0.56065,0.0055043,0.05,2.5206e+05,0.00044744 -10000,0.56065,0.0055043,0.05,2.5206e+05,0.00044744 -10000,0.57175,0.0056133,0.05,2.423e+05,0.00030141 -10000,0.57175,0.0056133,0.05,2.423e+05,0.00030141 -10000,0.57175,0.0056133,0.05,2.423e+05,0.00030141 -10000,0.57175,0.0056133,0.05,2.423e+05,0.00030141 -10000,0.57175,0.0056133,0.05,2.423e+05,0.00030141 -10000,0.57175,0.0056133,0.05,2.423e+05,0.00030141 -10000,0.57175,0.0056133,0.05,2.423e+05,0.00030141 -10000,0.57175,0.0056133,0.05,2.423e+05,0.00030141 -10000,0.57175,0.0056133,0.05,2.423e+05,0.00030141 -10000,0.57175,0.0056133,0.05,2.423e+05,0.00030141 -10000,0.57175,0.0056133,0.05,2.423e+05,0.00030141 -10000,0.58307,0.0057245,0.05,2.3261e+05,0.00020095 -10000,0.58307,0.0057245,0.05,2.3261e+05,0.00020095 -10000,0.58307,0.0057245,0.05,2.3261e+05,0.00020095 -10000,0.58307,0.0057245,0.05,2.3261e+05,0.00020095 -10000,0.58307,0.0057245,0.05,2.3261e+05,0.00020095 -10000,0.58307,0.0057245,0.05,2.3261e+05,0.00020095 -10000,0.58307,0.0057245,0.05,2.3261e+05,0.00020095 -10000,0.58307,0.0057245,0.05,2.3261e+05,0.00020095 -10000,0.58307,0.0057245,0.05,2.3261e+05,0.00020095 -10000,0.58307,0.0057245,0.05,2.3261e+05,0.00020095 -10000,0.58307,0.0057245,0.05,2.3261e+05,0.00020095 -10000,0.59462,0.0058378,0.05,2.2301e+05,0.00013256 -10000,0.59462,0.0058378,0.05,2.2301e+05,0.00013256 -10000,0.59462,0.0058378,0.05,2.2301e+05,0.00013256 -10000,0.59462,0.0058378,0.05,2.2301e+05,0.00013256 -10000,0.59462,0.0058378,0.05,2.2301e+05,0.00013256 -10000,0.59462,0.0058378,0.05,2.2301e+05,0.00013256 -10000,0.59462,0.0058378,0.05,2.2301e+05,0.00013256 -10000,0.59462,0.0058378,0.05,2.2301e+05,0.00013256 -10000,0.59462,0.0058378,0.05,2.2301e+05,0.00013256 -10000,0.59462,0.0058378,0.05,2.2301e+05,0.00013256 -10000,0.59462,0.0058378,0.05,2.2301e+05,0.00013256 -10000,0.59462,0.0058378,0.05,2.2301e+05,0.00013256 -10000,0.60639,0.0059535,0.05,2.135e+05,8.6508e-05 -10000,0.60639,0.0059535,0.05,2.135e+05,8.6508e-05 -10000,0.60639,0.0059535,0.05,2.135e+05,8.6508e-05 -10000,0.60639,0.0059535,0.05,2.135e+05,8.6508e-05 -10000,0.60639,0.0059535,0.05,2.135e+05,8.6508e-05 -10000,0.60639,0.0059535,0.05,2.135e+05,8.6508e-05 -10000,0.60639,0.0059535,0.05,2.135e+05,8.6508e-05 -10000,0.60639,0.0059535,0.05,2.135e+05,8.6508e-05 -10000,0.60639,0.0059535,0.05,2.135e+05,8.6508e-05 -10000,0.60639,0.0059535,0.05,2.135e+05,8.6508e-05 -10000,0.60639,0.0059535,0.05,2.135e+05,8.6508e-05 -10000,0.60639,0.0059535,0.05,2.135e+05,8.6508e-05 -10000,0.6184,0.0060714,0.05,2.0407e+05,5.5836e-05 -10000,0.6184,0.0060714,0.05,2.0407e+05,5.5836e-05 -10000,0.6184,0.0060714,0.05,2.0407e+05,5.5836e-05 -10000,0.6184,0.0060714,0.05,2.0407e+05,5.5836e-05 -10000,0.6184,0.0060714,0.05,2.0407e+05,5.5836e-05 -10000,0.6184,0.0060714,0.05,2.0407e+05,5.5836e-05 -10000,0.6184,0.0060714,0.05,2.0407e+05,5.5836e-05 -10000,0.6184,0.0060714,0.05,2.0407e+05,5.5836e-05 -10000,0.6184,0.0060714,0.05,2.0407e+05,5.5836e-05 -10000,0.6184,0.0060714,0.05,2.0407e+05,5.5836e-05 -10000,0.6184,0.0060714,0.05,2.0407e+05,5.5836e-05 -10000,0.6184,0.0060714,0.05,2.0407e+05,5.5836e-05 -10000,0.63065,0.0061916,0.05,1.9473e+05,3.5636e-05 -10000,0.63065,0.0061916,0.05,1.9473e+05,3.5636e-05 -10000,0.63065,0.0061916,0.05,1.9473e+05,3.5636e-05 -10000,0.63065,0.0061916,0.05,1.9473e+05,3.5636e-05 -10000,0.63065,0.0061916,0.05,1.9473e+05,3.5636e-05 -10000,0.63065,0.0061916,0.05,1.9473e+05,3.5636e-05 -10000,0.63065,0.0061916,0.05,1.9473e+05,3.5636e-05 -10000,0.63065,0.0061916,0.05,1.9473e+05,3.5636e-05 -10000,0.63065,0.0061916,0.05,1.9473e+05,3.5636e-05 -10000,0.63065,0.0061916,0.05,1.9473e+05,3.5636e-05 -10000,0.63065,0.0061916,0.05,1.9473e+05,3.5636e-05 -10000,0.63065,0.0061916,0.05,1.9473e+05,3.5636e-05 -10000,0.64314,0.0063142,0.05,1.8548e+05,2.2485e-05 -10000,0.64314,0.0063142,0.05,1.8548e+05,2.2485e-05 -10000,0.64314,0.0063142,0.05,1.8548e+05,2.2485e-05 -10000,0.64314,0.0063142,0.05,1.8548e+05,2.2485e-05 -10000,0.64314,0.0063142,0.05,1.8548e+05,2.2485e-05 -10000,0.64314,0.0063142,0.05,1.8548e+05,2.2485e-05 -10000,0.64314,0.0063142,0.05,1.8548e+05,2.2485e-05 -10000,0.64314,0.0063142,0.05,1.8548e+05,2.2485e-05 -10000,0.64314,0.0063142,0.05,1.8548e+05,2.2485e-05 -10000,0.64314,0.0063142,0.05,1.8548e+05,2.2485e-05 -10000,0.64314,0.0063142,0.05,1.8548e+05,2.2485e-05 -10000,0.64314,0.0063142,0.05,1.8548e+05,2.2485e-05 -10000,0.64314,0.0063142,0.05,1.8548e+05,2.2485e-05 -10000,0.65588,0.0064393,0.05,1.7633e+05,1.4022e-05 -10000,0.65588,0.0064393,0.05,1.7633e+05,1.4022e-05 -10000,0.65588,0.0064393,0.05,1.7633e+05,1.4022e-05 -10000,0.65588,0.0064393,0.05,1.7633e+05,1.4022e-05 -10000,0.65588,0.0064393,0.05,1.7633e+05,1.4022e-05 -10000,0.65588,0.0064393,0.05,1.7633e+05,1.4022e-05 -10000,0.65588,0.0064393,0.05,1.7633e+05,1.4022e-05 -10000,0.65588,0.0064393,0.05,1.7633e+05,1.4022e-05 -10000,0.65588,0.0064393,0.05,1.7633e+05,1.4022e-05 -10000,0.65588,0.0064393,0.05,1.7633e+05,1.4022e-05 -10000,0.65588,0.0064393,0.05,1.7633e+05,1.4022e-05 -10000,0.65588,0.0064393,0.05,1.7633e+05,1.4022e-05 -10000,0.65588,0.0064393,0.05,1.7633e+05,1.4022e-05 -10000,0.66887,0.0065668,0.05,1.6727e+05,8.6404e-06 -10000,0.66887,0.0065668,0.05,1.6727e+05,8.6404e-06 -10000,0.66887,0.0065668,0.05,1.6727e+05,8.6404e-06 -10000,0.66887,0.0065668,0.05,1.6727e+05,8.6404e-06 -10000,0.66887,0.0065668,0.05,1.6727e+05,8.6404e-06 -10000,0.66887,0.0065668,0.05,1.6727e+05,8.6404e-06 -10000,0.66887,0.0065668,0.05,1.6727e+05,8.6404e-06 -10000,0.66887,0.0065668,0.05,1.6727e+05,8.6404e-06 -10000,0.66887,0.0065668,0.05,1.6727e+05,8.6404e-06 -10000,0.66887,0.0065668,0.05,1.6727e+05,8.6404e-06 -10000,0.66887,0.0065668,0.05,1.6727e+05,8.6404e-06 -10000,0.66887,0.0065668,0.05,1.6727e+05,8.6404e-06 -10000,0.66887,0.0065668,0.05,1.6727e+05,8.6404e-06 -10000,0.68211,0.0066969,0.05,1.583e+05,5.2599e-06 -10000,0.68211,0.0066969,0.05,1.583e+05,5.2599e-06 -10000,0.68211,0.0066969,0.05,1.583e+05,5.2599e-06 -10000,0.68211,0.0066969,0.05,1.583e+05,5.2599e-06 -10000,0.68211,0.0066969,0.05,1.583e+05,5.2599e-06 -10000,0.68211,0.0066969,0.05,1.583e+05,5.2599e-06 -10000,0.68211,0.0066969,0.05,1.583e+05,5.2599e-06 -10000,0.68211,0.0066969,0.05,1.583e+05,5.2599e-06 -10000,0.68211,0.0066969,0.05,1.583e+05,5.2599e-06 -10000,0.68211,0.0066969,0.05,1.583e+05,5.2599e-06 -10000,0.68211,0.0066969,0.05,1.583e+05,5.2599e-06 -10000,0.68211,0.0066969,0.05,1.583e+05,5.2599e-06 -10000,0.68211,0.0066969,0.05,1.583e+05,5.2599e-06 -10000,0.69562,0.0068295,0.05,1.4942e+05,3.1624e-06 -10000,0.69562,0.0068295,0.05,1.4942e+05,3.1624e-06 -10000,0.69562,0.0068295,0.05,1.4942e+05,3.1624e-06 -10000,0.69562,0.0068295,0.05,1.4942e+05,3.1624e-06 -10000,0.69562,0.0068295,0.05,1.4942e+05,3.1624e-06 -10000,0.69562,0.0068295,0.05,1.4942e+05,3.1624e-06 -10000,0.69562,0.0068295,0.05,1.4942e+05,3.1624e-06 -10000,0.69562,0.0068295,0.05,1.4942e+05,3.1624e-06 -10000,0.69562,0.0068295,0.05,1.4942e+05,3.1624e-06 -10000,0.69562,0.0068295,0.05,1.4942e+05,3.1624e-06 -10000,0.69562,0.0068295,0.05,1.4942e+05,3.1624e-06 -10000,0.69562,0.0068295,0.05,1.4942e+05,3.1624e-06 -10000,0.69562,0.0068295,0.05,1.4942e+05,3.1624e-06 -10000,0.69562,0.0068295,0.05,1.4942e+05,3.1624e-06 -10000,0.7094,0.0069648,0.05,1.4064e+05,1.8772e-06 -10000,0.7094,0.0069648,0.05,1.4064e+05,1.8772e-06 -10000,0.7094,0.0069648,0.05,1.4064e+05,1.8772e-06 -10000,0.7094,0.0069648,0.05,1.4064e+05,1.8772e-06 -10000,0.7094,0.0069648,0.05,1.4064e+05,1.8772e-06 -10000,0.7094,0.0069648,0.05,1.4064e+05,1.8772e-06 -10000,0.7094,0.0069648,0.05,1.4064e+05,1.8772e-06 -10000,0.7094,0.0069648,0.05,1.4064e+05,1.8772e-06 -10000,0.7094,0.0069648,0.05,1.4064e+05,1.8772e-06 -10000,0.7094,0.0069648,0.05,1.4064e+05,1.8772e-06 -10000,0.7094,0.0069648,0.05,1.4064e+05,1.8772e-06 -10000,0.7094,0.0069648,0.05,1.4064e+05,1.8772e-06 -10000,0.7094,0.0069648,0.05,1.4064e+05,1.8772e-06 -10000,0.7094,0.0069648,0.05,1.4064e+05,1.8772e-06 -10000,0.72345,0.0071027,0.05,1.3195e+05,1.0998e-06 -10000,0.72345,0.0071027,0.05,1.3195e+05,1.0998e-06 -10000,0.72345,0.0071027,0.05,1.3195e+05,1.0998e-06 -10000,0.72345,0.0071027,0.05,1.3195e+05,1.0998e-06 -10000,0.72345,0.0071027,0.05,1.3195e+05,1.0998e-06 -10000,0.72345,0.0071027,0.05,1.3195e+05,1.0998e-06 -10000,0.72345,0.0071027,0.05,1.3195e+05,1.0998e-06 -10000,0.72345,0.0071027,0.05,1.3195e+05,1.0998e-06 -10000,0.72345,0.0071027,0.05,1.3195e+05,1.0998e-06 -10000,0.72345,0.0071027,0.05,1.3195e+05,1.0998e-06 -10000,0.72345,0.0071027,0.05,1.3195e+05,1.0998e-06 -10000,0.72345,0.0071027,0.05,1.3195e+05,1.0998e-06 -10000,0.72345,0.0071027,0.05,1.3195e+05,1.0998e-06 -10000,0.72345,0.0071027,0.05,1.3195e+05,1.0998e-06 -10000,0.73778,0.0072434,0.05,1.2336e+05,6.3578e-07 -10000,0.73778,0.0072434,0.05,1.2336e+05,6.3578e-07 -10000,0.73778,0.0072434,0.05,1.2336e+05,6.3578e-07 -10000,0.73778,0.0072434,0.05,1.2336e+05,6.3578e-07 -10000,0.73778,0.0072434,0.05,1.2336e+05,6.3578e-07 -10000,0.73778,0.0072434,0.05,1.2336e+05,6.3578e-07 -10000,0.73778,0.0072434,0.05,1.2336e+05,6.3578e-07 -10000,0.73778,0.0072434,0.05,1.2336e+05,6.3578e-07 -10000,0.73778,0.0072434,0.05,1.2336e+05,6.3578e-07 -10000,0.73778,0.0072434,0.05,1.2336e+05,6.3578e-07 -10000,0.73778,0.0072434,0.05,1.2336e+05,6.3578e-07 -10000,0.73778,0.0072434,0.05,1.2336e+05,6.3578e-07 -10000,0.73778,0.0072434,0.05,1.2336e+05,6.3578e-07 -10000,0.73778,0.0072434,0.05,1.2336e+05,6.3578e-07 -10000,0.73778,0.0072434,0.05,1.2336e+05,6.3578e-07 -10000,0.7524,0.0073869,0.05,1.1486e+05,3.6242e-07 -10000,0.7524,0.0073869,0.05,1.1486e+05,3.6242e-07 -10000,0.7524,0.0073869,0.05,1.1486e+05,3.6242e-07 -10000,0.7524,0.0073869,0.05,1.1486e+05,3.6242e-07 -10000,0.7524,0.0073869,0.05,1.1486e+05,3.6242e-07 -10000,0.7524,0.0073869,0.05,1.1486e+05,3.6242e-07 -10000,0.7524,0.0073869,0.05,1.1486e+05,3.6242e-07 -10000,0.7524,0.0073869,0.05,1.1486e+05,3.6242e-07 -10000,0.7524,0.0073869,0.05,1.1486e+05,3.6242e-07 -10000,0.7524,0.0073869,0.05,1.1486e+05,3.6242e-07 -10000,0.7524,0.0073869,0.05,1.1486e+05,3.6242e-07 -10000,0.7524,0.0073869,0.05,1.1486e+05,3.6242e-07 -10000,0.7524,0.0073869,0.05,1.1486e+05,3.6242e-07 -10000,0.7524,0.0073869,0.05,1.1486e+05,3.6242e-07 -10000,0.7673,0.0075332,0.05,1.0645e+05,2.0359e-07 -10000,0.7673,0.0075332,0.05,1.0645e+05,2.0359e-07 -10000,0.7673,0.0075332,0.05,1.0645e+05,2.0359e-07 -10000,0.7673,0.0075332,0.05,1.0645e+05,2.0359e-07 -10000,0.7673,0.0075332,0.05,1.0645e+05,2.0359e-07 -10000,0.7673,0.0075332,0.05,1.0645e+05,2.0359e-07 -10000,0.7673,0.0075332,0.05,1.0645e+05,2.0359e-07 -10000,0.7673,0.0075332,0.05,1.0645e+05,2.0359e-07 -10000,0.7673,0.0075332,0.05,1.0645e+05,2.0359e-07 -10000,0.7673,0.0075332,0.05,1.0645e+05,2.0359e-07 -10000,0.7673,0.0075332,0.05,1.0645e+05,2.0359e-07 -10000,0.7673,0.0075332,0.05,1.0645e+05,2.0359e-07 -10000,0.7673,0.0075332,0.05,1.0645e+05,2.0359e-07 -10000,0.7673,0.0075332,0.05,1.0645e+05,2.0359e-07 -10000,0.7673,0.0075332,0.05,1.0645e+05,2.0359e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.7825,0.0076824,0.05,98125,1.1259e-07 -10000,0.798,0.0078346,0.05,89890,6.1195e-08 -10000,0.798,0.0078346,0.05,89890,6.1195e-08 -10000,0.798,0.0078346,0.05,89890,6.1195e-08 -10000,0.798,0.0078346,0.05,89890,6.1195e-08 -10000,0.798,0.0078346,0.05,89890,6.1195e-08 -10000,0.798,0.0078346,0.05,89890,6.1195e-08 -10000,0.798,0.0078346,0.05,89890,6.1195e-08 -10000,0.798,0.0078346,0.05,89890,6.1195e-08 -10000,0.798,0.0078346,0.05,89890,6.1195e-08 -10000,0.798,0.0078346,0.05,89890,6.1195e-08 -10000,0.798,0.0078346,0.05,89890,6.1195e-08 -10000,0.798,0.0078346,0.05,89890,6.1195e-08 -10000,0.798,0.0078346,0.05,89890,6.1195e-08 -10000,0.798,0.0078346,0.05,89890,6.1195e-08 -10000,0.798,0.0078346,0.05,89890,6.1195e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.81381,0.0079898,0.05,81740,3.2607e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.82993,0.0081481,0.05,73670,1.6956e-08 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.84637,0.0083095,0.05,65677,8.5358e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.86314,0.0084741,0.05,57756,4.096e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.88024,0.008642,0.05,49901,1.8143e-09 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.89767,0.0088132,0.05,42106,6.8413e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.91546,0.0089878,0.05,34365,1.585e-10 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.93359,0.0091658,0.05,26670,-5.514e-11 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.95209,0.0093474,0.05,19011,-1.1096e-10 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.97095,0.0095326,0.05,11380,-8.9385e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,0.99019,0.0097215,0.05,3766.6,-3.2912e-11 -10000,nan,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/data_10.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/data_10.csv deleted file mode 100644 index 9de70bbb19f..00000000000 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/data_10.csv +++ /dev/null @@ -1,1002 +0,0 @@ -Time,"elementCenter:0","elementCenter:1","elementCenter:2","pressure","temperature" -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,nan,nan,nan,nan,nan -1e+05,0.10099,0.0009915,0.05,2886.1,99.336 -1e+05,0.10099,0.0009915,0.05,2886.1,99.336 -1e+05,0.10299,0.0010111,0.05,8542.7,98.035 -1e+05,0.10299,0.0010111,0.05,8542.7,98.035 -1e+05,0.10499,0.0010308,0.05,14088,96.759 -1e+05,0.10499,0.0010308,0.05,14088,96.759 -1e+05,0.10734,0.0010538,0.05,20476,95.288 -1e+05,0.10734,0.0010538,0.05,20476,95.288 -1e+05,0.10734,0.0010538,0.05,20476,95.288 -1e+05,0.11004,0.0010803,0.05,27628,93.64 -1e+05,0.11004,0.0010803,0.05,27628,93.64 -1e+05,0.11004,0.0010803,0.05,27628,93.64 -1e+05,0.11274,0.0011068,0.05,34599,92.032 -1e+05,0.11274,0.0011068,0.05,34599,92.032 -1e+05,0.11274,0.0011068,0.05,34599,92.032 -1e+05,0.11544,0.0011334,0.05,41397,90.463 -1e+05,0.11544,0.0011334,0.05,41397,90.463 -1e+05,0.11814,0.0011599,0.05,48030,88.93 -1e+05,0.11814,0.0011599,0.05,48030,88.93 -1e+05,0.11814,0.0011599,0.05,48030,88.93 -1e+05,0.12084,0.0011864,0.05,54503,87.433 -1e+05,0.12084,0.0011864,0.05,54503,87.433 -1e+05,0.12084,0.0011864,0.05,54503,87.433 -1e+05,0.12354,0.0012129,0.05,60824,85.969 -1e+05,0.12354,0.0012129,0.05,60824,85.969 -1e+05,0.12624,0.0012394,0.05,66997,84.537 -1e+05,0.12624,0.0012394,0.05,66997,84.537 -1e+05,0.12624,0.0012394,0.05,66997,84.537 -1e+05,0.12894,0.0012659,0.05,73028,83.137 -1e+05,0.12894,0.0012659,0.05,73028,83.137 -1e+05,0.12894,0.0012659,0.05,73028,83.137 -1e+05,0.13164,0.0012924,0.05,78922,81.766 -1e+05,0.13164,0.0012924,0.05,78922,81.766 -1e+05,0.1343,0.0013185,0.05,84601,80.443 -1e+05,0.1343,0.0013185,0.05,84601,80.443 -1e+05,0.1343,0.0013185,0.05,84601,80.443 -1e+05,0.13695,0.0013445,0.05,90131,79.153 -1e+05,0.13695,0.0013445,0.05,90131,79.153 -1e+05,0.13695,0.0013445,0.05,90131,79.153 -1e+05,0.13965,0.001371,0.05,95647,77.864 -1e+05,0.13965,0.001371,0.05,95647,77.864 -1e+05,0.13965,0.001371,0.05,95647,77.864 -1e+05,0.1424,0.0013981,0.05,1.0115e+05,76.576 -1e+05,0.1424,0.0013981,0.05,1.0115e+05,76.576 -1e+05,0.14521,0.0014256,0.05,1.0663e+05,75.288 -1e+05,0.14521,0.0014256,0.05,1.0663e+05,75.288 -1e+05,0.14521,0.0014256,0.05,1.0663e+05,75.288 -1e+05,0.14807,0.0014538,0.05,1.121e+05,74.002 -1e+05,0.14807,0.0014538,0.05,1.121e+05,74.002 -1e+05,0.14807,0.0014538,0.05,1.121e+05,74.002 -1e+05,0.151,0.0014824,0.05,1.1755e+05,72.717 -1e+05,0.151,0.0014824,0.05,1.1755e+05,72.717 -1e+05,0.151,0.0014824,0.05,1.1755e+05,72.717 -1e+05,0.15397,0.0015117,0.05,1.2298e+05,71.434 -1e+05,0.15397,0.0015117,0.05,1.2298e+05,71.434 -1e+05,0.15397,0.0015117,0.05,1.2298e+05,71.434 -1e+05,0.15701,0.0015415,0.05,1.2839e+05,70.152 -1e+05,0.15701,0.0015415,0.05,1.2839e+05,70.152 -1e+05,0.15701,0.0015415,0.05,1.2839e+05,70.152 -1e+05,0.16011,0.0015719,0.05,1.3377e+05,68.871 -1e+05,0.16011,0.0015719,0.05,1.3377e+05,68.871 -1e+05,0.16011,0.0015719,0.05,1.3377e+05,68.871 -1e+05,0.16327,0.001603,0.05,1.3913e+05,67.592 -1e+05,0.16327,0.001603,0.05,1.3913e+05,67.592 -1e+05,0.16327,0.001603,0.05,1.3913e+05,67.592 -1e+05,0.16649,0.0016346,0.05,1.4447e+05,66.316 -1e+05,0.16649,0.0016346,0.05,1.4447e+05,66.316 -1e+05,0.16649,0.0016346,0.05,1.4447e+05,66.316 -1e+05,0.16649,0.0016346,0.05,1.4447e+05,66.316 -1e+05,0.16978,0.0016669,0.05,1.4977e+05,65.041 -1e+05,0.16978,0.0016669,0.05,1.4977e+05,65.041 -1e+05,0.16978,0.0016669,0.05,1.4977e+05,65.041 -1e+05,0.17313,0.0016998,0.05,1.5504e+05,63.769 -1e+05,0.17313,0.0016998,0.05,1.5504e+05,63.769 -1e+05,0.17313,0.0016998,0.05,1.5504e+05,63.769 -1e+05,0.17655,0.0017333,0.05,1.6028e+05,62.499 -1e+05,0.17655,0.0017333,0.05,1.6028e+05,62.499 -1e+05,0.17655,0.0017333,0.05,1.6028e+05,62.499 -1e+05,0.17655,0.0017333,0.05,1.6028e+05,62.499 -1e+05,0.18004,0.0017676,0.05,1.6548e+05,61.232 -1e+05,0.18004,0.0017676,0.05,1.6548e+05,61.232 -1e+05,0.18004,0.0017676,0.05,1.6548e+05,61.232 -1e+05,0.18359,0.0018025,0.05,1.7064e+05,59.968 -1e+05,0.18359,0.0018025,0.05,1.7064e+05,59.968 -1e+05,0.18359,0.0018025,0.05,1.7064e+05,59.968 -1e+05,0.18359,0.0018025,0.05,1.7064e+05,59.968 -1e+05,0.18722,0.001838,0.05,1.7576e+05,58.707 -1e+05,0.18722,0.001838,0.05,1.7576e+05,58.707 -1e+05,0.18722,0.001838,0.05,1.7576e+05,58.707 -1e+05,0.18722,0.001838,0.05,1.7576e+05,58.707 -1e+05,0.19091,0.0018743,0.05,1.8084e+05,57.449 -1e+05,0.19091,0.0018743,0.05,1.8084e+05,57.449 -1e+05,0.19091,0.0018743,0.05,1.8084e+05,57.449 -1e+05,0.19468,0.0019114,0.05,1.8587e+05,56.195 -1e+05,0.19468,0.0019114,0.05,1.8587e+05,56.195 -1e+05,0.19468,0.0019114,0.05,1.8587e+05,56.195 -1e+05,0.19468,0.0019114,0.05,1.8587e+05,56.195 -1e+05,0.19853,0.0019491,0.05,1.9085e+05,54.944 -1e+05,0.19853,0.0019491,0.05,1.9085e+05,54.944 -1e+05,0.19853,0.0019491,0.05,1.9085e+05,54.944 -1e+05,0.19853,0.0019491,0.05,1.9085e+05,54.944 -1e+05,0.20245,0.0019876,0.05,1.9578e+05,53.698 -1e+05,0.20245,0.0019876,0.05,1.9578e+05,53.698 -1e+05,0.20245,0.0019876,0.05,1.9578e+05,53.698 -1e+05,0.20245,0.0019876,0.05,1.9578e+05,53.698 -1e+05,0.20645,0.0020269,0.05,2.0065e+05,52.456 -1e+05,0.20645,0.0020269,0.05,2.0065e+05,52.456 -1e+05,0.20645,0.0020269,0.05,2.0065e+05,52.456 -1e+05,0.20645,0.0020269,0.05,2.0065e+05,52.456 -1e+05,0.21053,0.0020669,0.05,2.0546e+05,51.219 -1e+05,0.21053,0.0020669,0.05,2.0546e+05,51.219 -1e+05,0.21053,0.0020669,0.05,2.0546e+05,51.219 -1e+05,0.21053,0.0020669,0.05,2.0546e+05,51.219 -1e+05,0.21469,0.0021078,0.05,2.1021e+05,49.986 -1e+05,0.21469,0.0021078,0.05,2.1021e+05,49.986 -1e+05,0.21469,0.0021078,0.05,2.1021e+05,49.986 -1e+05,0.21469,0.0021078,0.05,2.1021e+05,49.986 -1e+05,0.21893,0.0021494,0.05,2.149e+05,48.759 -1e+05,0.21893,0.0021494,0.05,2.149e+05,48.759 -1e+05,0.21893,0.0021494,0.05,2.149e+05,48.759 -1e+05,0.21893,0.0021494,0.05,2.149e+05,48.759 -1e+05,0.21893,0.0021494,0.05,2.149e+05,48.759 -1e+05,0.22326,0.0021919,0.05,2.1951e+05,47.537 -1e+05,0.22326,0.0021919,0.05,2.1951e+05,47.537 -1e+05,0.22326,0.0021919,0.05,2.1951e+05,47.537 -1e+05,0.22326,0.0021919,0.05,2.1951e+05,47.537 -1e+05,0.22767,0.0022352,0.05,2.2404e+05,46.321 -1e+05,0.22767,0.0022352,0.05,2.2404e+05,46.321 -1e+05,0.22767,0.0022352,0.05,2.2404e+05,46.321 -1e+05,0.22767,0.0022352,0.05,2.2404e+05,46.321 -1e+05,0.23217,0.0022794,0.05,2.285e+05,45.111 -1e+05,0.23217,0.0022794,0.05,2.285e+05,45.111 -1e+05,0.23217,0.0022794,0.05,2.285e+05,45.111 -1e+05,0.23217,0.0022794,0.05,2.285e+05,45.111 -1e+05,0.23217,0.0022794,0.05,2.285e+05,45.111 -1e+05,0.23676,0.0023244,0.05,2.3287e+05,43.908 -1e+05,0.23676,0.0023244,0.05,2.3287e+05,43.908 -1e+05,0.23676,0.0023244,0.05,2.3287e+05,43.908 -1e+05,0.23676,0.0023244,0.05,2.3287e+05,43.908 -1e+05,0.23676,0.0023244,0.05,2.3287e+05,43.908 -1e+05,0.24144,0.0023704,0.05,2.3715e+05,42.712 -1e+05,0.24144,0.0023704,0.05,2.3715e+05,42.712 -1e+05,0.24144,0.0023704,0.05,2.3715e+05,42.712 -1e+05,0.24144,0.0023704,0.05,2.3715e+05,42.712 -1e+05,0.24621,0.0024172,0.05,2.4134e+05,41.523 -1e+05,0.24621,0.0024172,0.05,2.4134e+05,41.523 -1e+05,0.24621,0.0024172,0.05,2.4134e+05,41.523 -1e+05,0.24621,0.0024172,0.05,2.4134e+05,41.523 -1e+05,0.24621,0.0024172,0.05,2.4134e+05,41.523 -1e+05,0.25108,0.002465,0.05,2.4544e+05,40.342 -1e+05,0.25108,0.002465,0.05,2.4544e+05,40.342 -1e+05,0.25108,0.002465,0.05,2.4544e+05,40.342 -1e+05,0.25108,0.002465,0.05,2.4544e+05,40.342 -1e+05,0.25108,0.002465,0.05,2.4544e+05,40.342 -1e+05,0.25604,0.0025137,0.05,2.4943e+05,39.169 -1e+05,0.25604,0.0025137,0.05,2.4943e+05,39.169 -1e+05,0.25604,0.0025137,0.05,2.4943e+05,39.169 -1e+05,0.25604,0.0025137,0.05,2.4943e+05,39.169 -1e+05,0.25604,0.0025137,0.05,2.4943e+05,39.169 -1e+05,0.2611,0.0025634,0.05,2.5331e+05,38.005 -1e+05,0.2611,0.0025634,0.05,2.5331e+05,38.005 -1e+05,0.2611,0.0025634,0.05,2.5331e+05,38.005 -1e+05,0.2611,0.0025634,0.05,2.5331e+05,38.005 -1e+05,0.2611,0.0025634,0.05,2.5331e+05,38.005 -1e+05,0.26626,0.0026141,0.05,2.5707e+05,36.85 -1e+05,0.26626,0.0026141,0.05,2.5707e+05,36.85 -1e+05,0.26626,0.0026141,0.05,2.5707e+05,36.85 -1e+05,0.26626,0.0026141,0.05,2.5707e+05,36.85 -1e+05,0.26626,0.0026141,0.05,2.5707e+05,36.85 -1e+05,0.27153,0.0026658,0.05,2.6072e+05,35.704 -1e+05,0.27153,0.0026658,0.05,2.6072e+05,35.704 -1e+05,0.27153,0.0026658,0.05,2.6072e+05,35.704 -1e+05,0.27153,0.0026658,0.05,2.6072e+05,35.704 -1e+05,0.27153,0.0026658,0.05,2.6072e+05,35.704 -1e+05,0.27153,0.0026658,0.05,2.6072e+05,35.704 -1e+05,0.2769,0.0027185,0.05,2.6424e+05,34.568 -1e+05,0.2769,0.0027185,0.05,2.6424e+05,34.568 -1e+05,0.2769,0.0027185,0.05,2.6424e+05,34.568 -1e+05,0.2769,0.0027185,0.05,2.6424e+05,34.568 -1e+05,0.2769,0.0027185,0.05,2.6424e+05,34.568 -1e+05,0.28237,0.0027723,0.05,2.6763e+05,33.443 -1e+05,0.28237,0.0027723,0.05,2.6763e+05,33.443 -1e+05,0.28237,0.0027723,0.05,2.6763e+05,33.443 -1e+05,0.28237,0.0027723,0.05,2.6763e+05,33.443 -1e+05,0.28237,0.0027723,0.05,2.6763e+05,33.443 -1e+05,0.28237,0.0027723,0.05,2.6763e+05,33.443 -1e+05,0.28796,0.0028271,0.05,2.7088e+05,32.329 -1e+05,0.28796,0.0028271,0.05,2.7088e+05,32.329 -1e+05,0.28796,0.0028271,0.05,2.7088e+05,32.329 -1e+05,0.28796,0.0028271,0.05,2.7088e+05,32.329 -1e+05,0.28796,0.0028271,0.05,2.7088e+05,32.329 -1e+05,0.29365,0.002883,0.05,2.7399e+05,31.226 -1e+05,0.29365,0.002883,0.05,2.7399e+05,31.226 -1e+05,0.29365,0.002883,0.05,2.7399e+05,31.226 -1e+05,0.29365,0.002883,0.05,2.7399e+05,31.226 -1e+05,0.29365,0.002883,0.05,2.7399e+05,31.226 -1e+05,0.29365,0.002883,0.05,2.7399e+05,31.226 -1e+05,0.29946,0.00294,0.05,2.7694e+05,30.135 -1e+05,0.29946,0.00294,0.05,2.7694e+05,30.135 -1e+05,0.29946,0.00294,0.05,2.7694e+05,30.135 -1e+05,0.29946,0.00294,0.05,2.7694e+05,30.135 -1e+05,0.29946,0.00294,0.05,2.7694e+05,30.135 -1e+05,0.29946,0.00294,0.05,2.7694e+05,30.135 -1e+05,0.30538,0.0029982,0.05,2.7974e+05,29.057 -1e+05,0.30538,0.0029982,0.05,2.7974e+05,29.057 -1e+05,0.30538,0.0029982,0.05,2.7974e+05,29.057 -1e+05,0.30538,0.0029982,0.05,2.7974e+05,29.057 -1e+05,0.30538,0.0029982,0.05,2.7974e+05,29.057 -1e+05,0.30538,0.0029982,0.05,2.7974e+05,29.057 -1e+05,0.31142,0.0030575,0.05,2.8238e+05,27.992 -1e+05,0.31142,0.0030575,0.05,2.8238e+05,27.992 -1e+05,0.31142,0.0030575,0.05,2.8238e+05,27.992 -1e+05,0.31142,0.0030575,0.05,2.8238e+05,27.992 -1e+05,0.31142,0.0030575,0.05,2.8238e+05,27.992 -1e+05,0.31142,0.0030575,0.05,2.8238e+05,27.992 -1e+05,0.31758,0.003118,0.05,2.8484e+05,26.941 -1e+05,0.31758,0.003118,0.05,2.8484e+05,26.941 -1e+05,0.31758,0.003118,0.05,2.8484e+05,26.941 -1e+05,0.31758,0.003118,0.05,2.8484e+05,26.941 -1e+05,0.31758,0.003118,0.05,2.8484e+05,26.941 -1e+05,0.31758,0.003118,0.05,2.8484e+05,26.941 -1e+05,0.32386,0.0031796,0.05,2.8713e+05,25.903 -1e+05,0.32386,0.0031796,0.05,2.8713e+05,25.903 -1e+05,0.32386,0.0031796,0.05,2.8713e+05,25.903 -1e+05,0.32386,0.0031796,0.05,2.8713e+05,25.903 -1e+05,0.32386,0.0031796,0.05,2.8713e+05,25.903 -1e+05,0.32386,0.0031796,0.05,2.8713e+05,25.903 -1e+05,0.32386,0.0031796,0.05,2.8713e+05,25.903 -1e+05,0.33027,0.0032425,0.05,2.8923e+05,24.881 -1e+05,0.33027,0.0032425,0.05,2.8923e+05,24.881 -1e+05,0.33027,0.0032425,0.05,2.8923e+05,24.881 -1e+05,0.33027,0.0032425,0.05,2.8923e+05,24.881 -1e+05,0.33027,0.0032425,0.05,2.8923e+05,24.881 -1e+05,0.33027,0.0032425,0.05,2.8923e+05,24.881 -1e+05,0.3368,0.0033067,0.05,2.9114e+05,23.874 -1e+05,0.3368,0.0033067,0.05,2.9114e+05,23.874 -1e+05,0.3368,0.0033067,0.05,2.9114e+05,23.874 -1e+05,0.3368,0.0033067,0.05,2.9114e+05,23.874 -1e+05,0.3368,0.0033067,0.05,2.9114e+05,23.874 -1e+05,0.3368,0.0033067,0.05,2.9114e+05,23.874 -1e+05,0.3368,0.0033067,0.05,2.9114e+05,23.874 -1e+05,0.34347,0.0033721,0.05,2.9285e+05,22.883 -1e+05,0.34347,0.0033721,0.05,2.9285e+05,22.883 -1e+05,0.34347,0.0033721,0.05,2.9285e+05,22.883 -1e+05,0.34347,0.0033721,0.05,2.9285e+05,22.883 -1e+05,0.34347,0.0033721,0.05,2.9285e+05,22.883 -1e+05,0.34347,0.0033721,0.05,2.9285e+05,22.883 -1e+05,0.35026,0.0034388,0.05,2.9435e+05,21.909 -1e+05,0.35026,0.0034388,0.05,2.9435e+05,21.909 -1e+05,0.35026,0.0034388,0.05,2.9435e+05,21.909 -1e+05,0.35026,0.0034388,0.05,2.9435e+05,21.909 -1e+05,0.35026,0.0034388,0.05,2.9435e+05,21.909 -1e+05,0.35026,0.0034388,0.05,2.9435e+05,21.909 -1e+05,0.35026,0.0034388,0.05,2.9435e+05,21.909 -1e+05,0.35719,0.0035069,0.05,2.9564e+05,20.951 -1e+05,0.35719,0.0035069,0.05,2.9564e+05,20.951 -1e+05,0.35719,0.0035069,0.05,2.9564e+05,20.951 -1e+05,0.35719,0.0035069,0.05,2.9564e+05,20.951 -1e+05,0.35719,0.0035069,0.05,2.9564e+05,20.951 -1e+05,0.35719,0.0035069,0.05,2.9564e+05,20.951 -1e+05,0.35719,0.0035069,0.05,2.9564e+05,20.951 -1e+05,0.36426,0.0035762,0.05,2.9671e+05,20.012 -1e+05,0.36426,0.0035762,0.05,2.9671e+05,20.012 -1e+05,0.36426,0.0035762,0.05,2.9671e+05,20.012 -1e+05,0.36426,0.0035762,0.05,2.9671e+05,20.012 -1e+05,0.36426,0.0035762,0.05,2.9671e+05,20.012 -1e+05,0.36426,0.0035762,0.05,2.9671e+05,20.012 -1e+05,0.36426,0.0035762,0.05,2.9671e+05,20.012 -1e+05,0.37147,0.003647,0.05,2.9755e+05,19.091 -1e+05,0.37147,0.003647,0.05,2.9755e+05,19.091 -1e+05,0.37147,0.003647,0.05,2.9755e+05,19.091 -1e+05,0.37147,0.003647,0.05,2.9755e+05,19.091 -1e+05,0.37147,0.003647,0.05,2.9755e+05,19.091 -1e+05,0.37147,0.003647,0.05,2.9755e+05,19.091 -1e+05,0.37147,0.003647,0.05,2.9755e+05,19.091 -1e+05,0.37147,0.003647,0.05,2.9755e+05,19.091 -1e+05,0.37882,0.0037192,0.05,2.9816e+05,18.188 -1e+05,0.37882,0.0037192,0.05,2.9816e+05,18.188 -1e+05,0.37882,0.0037192,0.05,2.9816e+05,18.188 -1e+05,0.37882,0.0037192,0.05,2.9816e+05,18.188 -1e+05,0.37882,0.0037192,0.05,2.9816e+05,18.188 -1e+05,0.37882,0.0037192,0.05,2.9816e+05,18.188 -1e+05,0.37882,0.0037192,0.05,2.9816e+05,18.188 -1e+05,0.38632,0.0037928,0.05,2.9853e+05,17.305 -1e+05,0.38632,0.0037928,0.05,2.9853e+05,17.305 -1e+05,0.38632,0.0037928,0.05,2.9853e+05,17.305 -1e+05,0.38632,0.0037928,0.05,2.9853e+05,17.305 -1e+05,0.38632,0.0037928,0.05,2.9853e+05,17.305 -1e+05,0.38632,0.0037928,0.05,2.9853e+05,17.305 -1e+05,0.38632,0.0037928,0.05,2.9853e+05,17.305 -1e+05,0.38632,0.0037928,0.05,2.9853e+05,17.305 -1e+05,0.39396,0.0038678,0.05,2.9864e+05,16.443 -1e+05,0.39396,0.0038678,0.05,2.9864e+05,16.443 -1e+05,0.39396,0.0038678,0.05,2.9864e+05,16.443 -1e+05,0.39396,0.0038678,0.05,2.9864e+05,16.443 -1e+05,0.39396,0.0038678,0.05,2.9864e+05,16.443 -1e+05,0.39396,0.0038678,0.05,2.9864e+05,16.443 -1e+05,0.39396,0.0038678,0.05,2.9864e+05,16.443 -1e+05,0.40176,0.0039444,0.05,2.9851e+05,15.6 -1e+05,0.40176,0.0039444,0.05,2.9851e+05,15.6 -1e+05,0.40176,0.0039444,0.05,2.9851e+05,15.6 -1e+05,0.40176,0.0039444,0.05,2.9851e+05,15.6 -1e+05,0.40176,0.0039444,0.05,2.9851e+05,15.6 -1e+05,0.40176,0.0039444,0.05,2.9851e+05,15.6 -1e+05,0.40176,0.0039444,0.05,2.9851e+05,15.6 -1e+05,0.40176,0.0039444,0.05,2.9851e+05,15.6 -1e+05,0.40971,0.0040224,0.05,2.9811e+05,14.779 -1e+05,0.40971,0.0040224,0.05,2.9811e+05,14.779 -1e+05,0.40971,0.0040224,0.05,2.9811e+05,14.779 -1e+05,0.40971,0.0040224,0.05,2.9811e+05,14.779 -1e+05,0.40971,0.0040224,0.05,2.9811e+05,14.779 -1e+05,0.40971,0.0040224,0.05,2.9811e+05,14.779 -1e+05,0.40971,0.0040224,0.05,2.9811e+05,14.779 -1e+05,0.40971,0.0040224,0.05,2.9811e+05,14.779 -1e+05,0.41782,0.004102,0.05,2.9744e+05,13.979 -1e+05,0.41782,0.004102,0.05,2.9744e+05,13.979 -1e+05,0.41782,0.004102,0.05,2.9744e+05,13.979 -1e+05,0.41782,0.004102,0.05,2.9744e+05,13.979 -1e+05,0.41782,0.004102,0.05,2.9744e+05,13.979 -1e+05,0.41782,0.004102,0.05,2.9744e+05,13.979 -1e+05,0.41782,0.004102,0.05,2.9744e+05,13.979 -1e+05,0.41782,0.004102,0.05,2.9744e+05,13.979 -1e+05,0.42609,0.0041832,0.05,2.965e+05,13.202 -1e+05,0.42609,0.0041832,0.05,2.965e+05,13.202 -1e+05,0.42609,0.0041832,0.05,2.965e+05,13.202 -1e+05,0.42609,0.0041832,0.05,2.965e+05,13.202 -1e+05,0.42609,0.0041832,0.05,2.965e+05,13.202 -1e+05,0.42609,0.0041832,0.05,2.965e+05,13.202 -1e+05,0.42609,0.0041832,0.05,2.965e+05,13.202 -1e+05,0.42609,0.0041832,0.05,2.965e+05,13.202 -1e+05,0.42609,0.0041832,0.05,2.965e+05,13.202 -1e+05,0.43452,0.004266,0.05,2.9528e+05,12.447 -1e+05,0.43452,0.004266,0.05,2.9528e+05,12.447 -1e+05,0.43452,0.004266,0.05,2.9528e+05,12.447 -1e+05,0.43452,0.004266,0.05,2.9528e+05,12.447 -1e+05,0.43452,0.004266,0.05,2.9528e+05,12.447 -1e+05,0.43452,0.004266,0.05,2.9528e+05,12.447 -1e+05,0.43452,0.004266,0.05,2.9528e+05,12.447 -1e+05,0.43452,0.004266,0.05,2.9528e+05,12.447 -1e+05,0.44312,0.0043505,0.05,2.9377e+05,11.715 -1e+05,0.44312,0.0043505,0.05,2.9377e+05,11.715 -1e+05,0.44312,0.0043505,0.05,2.9377e+05,11.715 -1e+05,0.44312,0.0043505,0.05,2.9377e+05,11.715 -1e+05,0.44312,0.0043505,0.05,2.9377e+05,11.715 -1e+05,0.44312,0.0043505,0.05,2.9377e+05,11.715 -1e+05,0.44312,0.0043505,0.05,2.9377e+05,11.715 -1e+05,0.44312,0.0043505,0.05,2.9377e+05,11.715 -1e+05,0.44312,0.0043505,0.05,2.9377e+05,11.715 -1e+05,0.45189,0.0044366,0.05,2.9198e+05,11.006 -1e+05,0.45189,0.0044366,0.05,2.9198e+05,11.006 -1e+05,0.45189,0.0044366,0.05,2.9198e+05,11.006 -1e+05,0.45189,0.0044366,0.05,2.9198e+05,11.006 -1e+05,0.45189,0.0044366,0.05,2.9198e+05,11.006 -1e+05,0.45189,0.0044366,0.05,2.9198e+05,11.006 -1e+05,0.45189,0.0044366,0.05,2.9198e+05,11.006 -1e+05,0.45189,0.0044366,0.05,2.9198e+05,11.006 -1e+05,0.45189,0.0044366,0.05,2.9198e+05,11.006 -1e+05,0.46084,0.0045244,0.05,2.8989e+05,10.321 -1e+05,0.46084,0.0045244,0.05,2.8989e+05,10.321 -1e+05,0.46084,0.0045244,0.05,2.8989e+05,10.321 -1e+05,0.46084,0.0045244,0.05,2.8989e+05,10.321 -1e+05,0.46084,0.0045244,0.05,2.8989e+05,10.321 -1e+05,0.46084,0.0045244,0.05,2.8989e+05,10.321 -1e+05,0.46084,0.0045244,0.05,2.8989e+05,10.321 -1e+05,0.46084,0.0045244,0.05,2.8989e+05,10.321 -1e+05,0.46084,0.0045244,0.05,2.8989e+05,10.321 -1e+05,0.46996,0.004614,0.05,2.875e+05,9.6595 -1e+05,0.46996,0.004614,0.05,2.875e+05,9.6595 -1e+05,0.46996,0.004614,0.05,2.875e+05,9.6595 -1e+05,0.46996,0.004614,0.05,2.875e+05,9.6595 -1e+05,0.46996,0.004614,0.05,2.875e+05,9.6595 -1e+05,0.46996,0.004614,0.05,2.875e+05,9.6595 -1e+05,0.46996,0.004614,0.05,2.875e+05,9.6595 -1e+05,0.46996,0.004614,0.05,2.875e+05,9.6595 -1e+05,0.46996,0.004614,0.05,2.875e+05,9.6595 -1e+05,0.47926,0.0047053,0.05,2.8481e+05,9.0227 -1e+05,0.47926,0.0047053,0.05,2.8481e+05,9.0227 -1e+05,0.47926,0.0047053,0.05,2.8481e+05,9.0227 -1e+05,0.47926,0.0047053,0.05,2.8481e+05,9.0227 -1e+05,0.47926,0.0047053,0.05,2.8481e+05,9.0227 -1e+05,0.47926,0.0047053,0.05,2.8481e+05,9.0227 -1e+05,0.47926,0.0047053,0.05,2.8481e+05,9.0227 -1e+05,0.47926,0.0047053,0.05,2.8481e+05,9.0227 -1e+05,0.47926,0.0047053,0.05,2.8481e+05,9.0227 -1e+05,0.48875,0.0047985,0.05,2.8182e+05,8.4104 -1e+05,0.48875,0.0047985,0.05,2.8182e+05,8.4104 -1e+05,0.48875,0.0047985,0.05,2.8182e+05,8.4104 -1e+05,0.48875,0.0047985,0.05,2.8182e+05,8.4104 -1e+05,0.48875,0.0047985,0.05,2.8182e+05,8.4104 -1e+05,0.48875,0.0047985,0.05,2.8182e+05,8.4104 -1e+05,0.48875,0.0047985,0.05,2.8182e+05,8.4104 -1e+05,0.48875,0.0047985,0.05,2.8182e+05,8.4104 -1e+05,0.48875,0.0047985,0.05,2.8182e+05,8.4104 -1e+05,0.48875,0.0047985,0.05,2.8182e+05,8.4104 -1e+05,0.49843,0.0048935,0.05,2.7852e+05,7.8227 -1e+05,0.49843,0.0048935,0.05,2.7852e+05,7.8227 -1e+05,0.49843,0.0048935,0.05,2.7852e+05,7.8227 -1e+05,0.49843,0.0048935,0.05,2.7852e+05,7.8227 -1e+05,0.49843,0.0048935,0.05,2.7852e+05,7.8227 -1e+05,0.49843,0.0048935,0.05,2.7852e+05,7.8227 -1e+05,0.49843,0.0048935,0.05,2.7852e+05,7.8227 -1e+05,0.49843,0.0048935,0.05,2.7852e+05,7.8227 -1e+05,0.49843,0.0048935,0.05,2.7852e+05,7.8227 -1e+05,0.49843,0.0048935,0.05,2.7852e+05,7.8227 -1e+05,0.5083,0.0049903,0.05,2.7492e+05,7.2599 -1e+05,0.5083,0.0049903,0.05,2.7492e+05,7.2599 -1e+05,0.5083,0.0049903,0.05,2.7492e+05,7.2599 -1e+05,0.5083,0.0049903,0.05,2.7492e+05,7.2599 -1e+05,0.5083,0.0049903,0.05,2.7492e+05,7.2599 -1e+05,0.5083,0.0049903,0.05,2.7492e+05,7.2599 -1e+05,0.5083,0.0049903,0.05,2.7492e+05,7.2599 -1e+05,0.5083,0.0049903,0.05,2.7492e+05,7.2599 -1e+05,0.5083,0.0049903,0.05,2.7492e+05,7.2599 -1e+05,0.5083,0.0049903,0.05,2.7492e+05,7.2599 -1e+05,0.51836,0.0050891,0.05,2.7101e+05,6.722 -1e+05,0.51836,0.0050891,0.05,2.7101e+05,6.722 -1e+05,0.51836,0.0050891,0.05,2.7101e+05,6.722 -1e+05,0.51836,0.0050891,0.05,2.7101e+05,6.722 -1e+05,0.51836,0.0050891,0.05,2.7101e+05,6.722 -1e+05,0.51836,0.0050891,0.05,2.7101e+05,6.722 -1e+05,0.51836,0.0050891,0.05,2.7101e+05,6.722 -1e+05,0.51836,0.0050891,0.05,2.7101e+05,6.722 -1e+05,0.51836,0.0050891,0.05,2.7101e+05,6.722 -1e+05,0.51836,0.0050891,0.05,2.7101e+05,6.722 -1e+05,0.52862,0.0051899,0.05,2.6678e+05,6.209 -1e+05,0.52862,0.0051899,0.05,2.6678e+05,6.209 -1e+05,0.52862,0.0051899,0.05,2.6678e+05,6.209 -1e+05,0.52862,0.0051899,0.05,2.6678e+05,6.209 -1e+05,0.52862,0.0051899,0.05,2.6678e+05,6.209 -1e+05,0.52862,0.0051899,0.05,2.6678e+05,6.209 -1e+05,0.52862,0.0051899,0.05,2.6678e+05,6.209 -1e+05,0.52862,0.0051899,0.05,2.6678e+05,6.209 -1e+05,0.52862,0.0051899,0.05,2.6678e+05,6.209 -1e+05,0.52862,0.0051899,0.05,2.6678e+05,6.209 -1e+05,0.53909,0.0052927,0.05,2.6226e+05,5.7208 -1e+05,0.53909,0.0052927,0.05,2.6226e+05,5.7208 -1e+05,0.53909,0.0052927,0.05,2.6226e+05,5.7208 -1e+05,0.53909,0.0052927,0.05,2.6226e+05,5.7208 -1e+05,0.53909,0.0052927,0.05,2.6226e+05,5.7208 -1e+05,0.53909,0.0052927,0.05,2.6226e+05,5.7208 -1e+05,0.53909,0.0052927,0.05,2.6226e+05,5.7208 -1e+05,0.53909,0.0052927,0.05,2.6226e+05,5.7208 -1e+05,0.53909,0.0052927,0.05,2.6226e+05,5.7208 -1e+05,0.53909,0.0052927,0.05,2.6226e+05,5.7208 -1e+05,0.53909,0.0052927,0.05,2.6226e+05,5.7208 -1e+05,0.54976,0.0053975,0.05,2.5742e+05,5.2574 -1e+05,0.54976,0.0053975,0.05,2.5742e+05,5.2574 -1e+05,0.54976,0.0053975,0.05,2.5742e+05,5.2574 -1e+05,0.54976,0.0053975,0.05,2.5742e+05,5.2574 -1e+05,0.54976,0.0053975,0.05,2.5742e+05,5.2574 -1e+05,0.54976,0.0053975,0.05,2.5742e+05,5.2574 -1e+05,0.54976,0.0053975,0.05,2.5742e+05,5.2574 -1e+05,0.54976,0.0053975,0.05,2.5742e+05,5.2574 -1e+05,0.54976,0.0053975,0.05,2.5742e+05,5.2574 -1e+05,0.54976,0.0053975,0.05,2.5742e+05,5.2574 -1e+05,0.54976,0.0053975,0.05,2.5742e+05,5.2574 -1e+05,0.56065,0.0055043,0.05,2.5228e+05,4.8185 -1e+05,0.56065,0.0055043,0.05,2.5228e+05,4.8185 -1e+05,0.56065,0.0055043,0.05,2.5228e+05,4.8185 -1e+05,0.56065,0.0055043,0.05,2.5228e+05,4.8185 -1e+05,0.56065,0.0055043,0.05,2.5228e+05,4.8185 -1e+05,0.56065,0.0055043,0.05,2.5228e+05,4.8185 -1e+05,0.56065,0.0055043,0.05,2.5228e+05,4.8185 -1e+05,0.56065,0.0055043,0.05,2.5228e+05,4.8185 -1e+05,0.56065,0.0055043,0.05,2.5228e+05,4.8185 -1e+05,0.56065,0.0055043,0.05,2.5228e+05,4.8185 -1e+05,0.56065,0.0055043,0.05,2.5228e+05,4.8185 -1e+05,0.57175,0.0056133,0.05,2.4684e+05,4.4039 -1e+05,0.57175,0.0056133,0.05,2.4684e+05,4.4039 -1e+05,0.57175,0.0056133,0.05,2.4684e+05,4.4039 -1e+05,0.57175,0.0056133,0.05,2.4684e+05,4.4039 -1e+05,0.57175,0.0056133,0.05,2.4684e+05,4.4039 -1e+05,0.57175,0.0056133,0.05,2.4684e+05,4.4039 -1e+05,0.57175,0.0056133,0.05,2.4684e+05,4.4039 -1e+05,0.57175,0.0056133,0.05,2.4684e+05,4.4039 -1e+05,0.57175,0.0056133,0.05,2.4684e+05,4.4039 -1e+05,0.57175,0.0056133,0.05,2.4684e+05,4.4039 -1e+05,0.57175,0.0056133,0.05,2.4684e+05,4.4039 -1e+05,0.58307,0.0057245,0.05,2.411e+05,4.0133 -1e+05,0.58307,0.0057245,0.05,2.411e+05,4.0133 -1e+05,0.58307,0.0057245,0.05,2.411e+05,4.0133 -1e+05,0.58307,0.0057245,0.05,2.411e+05,4.0133 -1e+05,0.58307,0.0057245,0.05,2.411e+05,4.0133 -1e+05,0.58307,0.0057245,0.05,2.411e+05,4.0133 -1e+05,0.58307,0.0057245,0.05,2.411e+05,4.0133 -1e+05,0.58307,0.0057245,0.05,2.411e+05,4.0133 -1e+05,0.58307,0.0057245,0.05,2.411e+05,4.0133 -1e+05,0.58307,0.0057245,0.05,2.411e+05,4.0133 -1e+05,0.58307,0.0057245,0.05,2.411e+05,4.0133 -1e+05,0.59462,0.0058378,0.05,2.3507e+05,3.6464 -1e+05,0.59462,0.0058378,0.05,2.3507e+05,3.6464 -1e+05,0.59462,0.0058378,0.05,2.3507e+05,3.6464 -1e+05,0.59462,0.0058378,0.05,2.3507e+05,3.6464 -1e+05,0.59462,0.0058378,0.05,2.3507e+05,3.6464 -1e+05,0.59462,0.0058378,0.05,2.3507e+05,3.6464 -1e+05,0.59462,0.0058378,0.05,2.3507e+05,3.6464 -1e+05,0.59462,0.0058378,0.05,2.3507e+05,3.6464 -1e+05,0.59462,0.0058378,0.05,2.3507e+05,3.6464 -1e+05,0.59462,0.0058378,0.05,2.3507e+05,3.6464 -1e+05,0.59462,0.0058378,0.05,2.3507e+05,3.6464 -1e+05,0.59462,0.0058378,0.05,2.3507e+05,3.6464 -1e+05,0.60639,0.0059535,0.05,2.2875e+05,3.3027 -1e+05,0.60639,0.0059535,0.05,2.2875e+05,3.3027 -1e+05,0.60639,0.0059535,0.05,2.2875e+05,3.3027 -1e+05,0.60639,0.0059535,0.05,2.2875e+05,3.3027 -1e+05,0.60639,0.0059535,0.05,2.2875e+05,3.3027 -1e+05,0.60639,0.0059535,0.05,2.2875e+05,3.3027 -1e+05,0.60639,0.0059535,0.05,2.2875e+05,3.3027 -1e+05,0.60639,0.0059535,0.05,2.2875e+05,3.3027 -1e+05,0.60639,0.0059535,0.05,2.2875e+05,3.3027 -1e+05,0.60639,0.0059535,0.05,2.2875e+05,3.3027 -1e+05,0.60639,0.0059535,0.05,2.2875e+05,3.3027 -1e+05,0.60639,0.0059535,0.05,2.2875e+05,3.3027 -1e+05,0.6184,0.0060714,0.05,2.2215e+05,2.9816 -1e+05,0.6184,0.0060714,0.05,2.2215e+05,2.9816 -1e+05,0.6184,0.0060714,0.05,2.2215e+05,2.9816 -1e+05,0.6184,0.0060714,0.05,2.2215e+05,2.9816 -1e+05,0.6184,0.0060714,0.05,2.2215e+05,2.9816 -1e+05,0.6184,0.0060714,0.05,2.2215e+05,2.9816 -1e+05,0.6184,0.0060714,0.05,2.2215e+05,2.9816 -1e+05,0.6184,0.0060714,0.05,2.2215e+05,2.9816 -1e+05,0.6184,0.0060714,0.05,2.2215e+05,2.9816 -1e+05,0.6184,0.0060714,0.05,2.2215e+05,2.9816 -1e+05,0.6184,0.0060714,0.05,2.2215e+05,2.9816 -1e+05,0.6184,0.0060714,0.05,2.2215e+05,2.9816 -1e+05,0.63065,0.0061916,0.05,2.1528e+05,2.6827 -1e+05,0.63065,0.0061916,0.05,2.1528e+05,2.6827 -1e+05,0.63065,0.0061916,0.05,2.1528e+05,2.6827 -1e+05,0.63065,0.0061916,0.05,2.1528e+05,2.6827 -1e+05,0.63065,0.0061916,0.05,2.1528e+05,2.6827 -1e+05,0.63065,0.0061916,0.05,2.1528e+05,2.6827 -1e+05,0.63065,0.0061916,0.05,2.1528e+05,2.6827 -1e+05,0.63065,0.0061916,0.05,2.1528e+05,2.6827 -1e+05,0.63065,0.0061916,0.05,2.1528e+05,2.6827 -1e+05,0.63065,0.0061916,0.05,2.1528e+05,2.6827 -1e+05,0.63065,0.0061916,0.05,2.1528e+05,2.6827 -1e+05,0.63065,0.0061916,0.05,2.1528e+05,2.6827 -1e+05,0.64314,0.0063142,0.05,2.0814e+05,2.4053 -1e+05,0.64314,0.0063142,0.05,2.0814e+05,2.4053 -1e+05,0.64314,0.0063142,0.05,2.0814e+05,2.4053 -1e+05,0.64314,0.0063142,0.05,2.0814e+05,2.4053 -1e+05,0.64314,0.0063142,0.05,2.0814e+05,2.4053 -1e+05,0.64314,0.0063142,0.05,2.0814e+05,2.4053 -1e+05,0.64314,0.0063142,0.05,2.0814e+05,2.4053 -1e+05,0.64314,0.0063142,0.05,2.0814e+05,2.4053 -1e+05,0.64314,0.0063142,0.05,2.0814e+05,2.4053 -1e+05,0.64314,0.0063142,0.05,2.0814e+05,2.4053 -1e+05,0.64314,0.0063142,0.05,2.0814e+05,2.4053 -1e+05,0.64314,0.0063142,0.05,2.0814e+05,2.4053 -1e+05,0.64314,0.0063142,0.05,2.0814e+05,2.4053 -1e+05,0.65588,0.0064393,0.05,2.0074e+05,2.1488 -1e+05,0.65588,0.0064393,0.05,2.0074e+05,2.1488 -1e+05,0.65588,0.0064393,0.05,2.0074e+05,2.1488 -1e+05,0.65588,0.0064393,0.05,2.0074e+05,2.1488 -1e+05,0.65588,0.0064393,0.05,2.0074e+05,2.1488 -1e+05,0.65588,0.0064393,0.05,2.0074e+05,2.1488 -1e+05,0.65588,0.0064393,0.05,2.0074e+05,2.1488 -1e+05,0.65588,0.0064393,0.05,2.0074e+05,2.1488 -1e+05,0.65588,0.0064393,0.05,2.0074e+05,2.1488 -1e+05,0.65588,0.0064393,0.05,2.0074e+05,2.1488 -1e+05,0.65588,0.0064393,0.05,2.0074e+05,2.1488 -1e+05,0.65588,0.0064393,0.05,2.0074e+05,2.1488 -1e+05,0.65588,0.0064393,0.05,2.0074e+05,2.1488 -1e+05,0.66887,0.0065668,0.05,1.9309e+05,1.9123 -1e+05,0.66887,0.0065668,0.05,1.9309e+05,1.9123 -1e+05,0.66887,0.0065668,0.05,1.9309e+05,1.9123 -1e+05,0.66887,0.0065668,0.05,1.9309e+05,1.9123 -1e+05,0.66887,0.0065668,0.05,1.9309e+05,1.9123 -1e+05,0.66887,0.0065668,0.05,1.9309e+05,1.9123 -1e+05,0.66887,0.0065668,0.05,1.9309e+05,1.9123 -1e+05,0.66887,0.0065668,0.05,1.9309e+05,1.9123 -1e+05,0.66887,0.0065668,0.05,1.9309e+05,1.9123 -1e+05,0.66887,0.0065668,0.05,1.9309e+05,1.9123 -1e+05,0.66887,0.0065668,0.05,1.9309e+05,1.9123 -1e+05,0.66887,0.0065668,0.05,1.9309e+05,1.9123 -1e+05,0.66887,0.0065668,0.05,1.9309e+05,1.9123 -1e+05,0.68211,0.0066969,0.05,1.8521e+05,1.6952 -1e+05,0.68211,0.0066969,0.05,1.8521e+05,1.6952 -1e+05,0.68211,0.0066969,0.05,1.8521e+05,1.6952 -1e+05,0.68211,0.0066969,0.05,1.8521e+05,1.6952 -1e+05,0.68211,0.0066969,0.05,1.8521e+05,1.6952 -1e+05,0.68211,0.0066969,0.05,1.8521e+05,1.6952 -1e+05,0.68211,0.0066969,0.05,1.8521e+05,1.6952 -1e+05,0.68211,0.0066969,0.05,1.8521e+05,1.6952 -1e+05,0.68211,0.0066969,0.05,1.8521e+05,1.6952 -1e+05,0.68211,0.0066969,0.05,1.8521e+05,1.6952 -1e+05,0.68211,0.0066969,0.05,1.8521e+05,1.6952 -1e+05,0.68211,0.0066969,0.05,1.8521e+05,1.6952 -1e+05,0.68211,0.0066969,0.05,1.8521e+05,1.6952 -1e+05,0.69562,0.0068295,0.05,1.7709e+05,1.4965 -1e+05,0.69562,0.0068295,0.05,1.7709e+05,1.4965 -1e+05,0.69562,0.0068295,0.05,1.7709e+05,1.4965 -1e+05,0.69562,0.0068295,0.05,1.7709e+05,1.4965 -1e+05,0.69562,0.0068295,0.05,1.7709e+05,1.4965 -1e+05,0.69562,0.0068295,0.05,1.7709e+05,1.4965 -1e+05,0.69562,0.0068295,0.05,1.7709e+05,1.4965 -1e+05,0.69562,0.0068295,0.05,1.7709e+05,1.4965 -1e+05,0.69562,0.0068295,0.05,1.7709e+05,1.4965 -1e+05,0.69562,0.0068295,0.05,1.7709e+05,1.4965 -1e+05,0.69562,0.0068295,0.05,1.7709e+05,1.4965 -1e+05,0.69562,0.0068295,0.05,1.7709e+05,1.4965 -1e+05,0.69562,0.0068295,0.05,1.7709e+05,1.4965 -1e+05,0.69562,0.0068295,0.05,1.7709e+05,1.4965 -1e+05,0.7094,0.0069648,0.05,1.6876e+05,1.3154 -1e+05,0.7094,0.0069648,0.05,1.6876e+05,1.3154 -1e+05,0.7094,0.0069648,0.05,1.6876e+05,1.3154 -1e+05,0.7094,0.0069648,0.05,1.6876e+05,1.3154 -1e+05,0.7094,0.0069648,0.05,1.6876e+05,1.3154 -1e+05,0.7094,0.0069648,0.05,1.6876e+05,1.3154 -1e+05,0.7094,0.0069648,0.05,1.6876e+05,1.3154 -1e+05,0.7094,0.0069648,0.05,1.6876e+05,1.3154 -1e+05,0.7094,0.0069648,0.05,1.6876e+05,1.3154 -1e+05,0.7094,0.0069648,0.05,1.6876e+05,1.3154 -1e+05,0.7094,0.0069648,0.05,1.6876e+05,1.3154 -1e+05,0.7094,0.0069648,0.05,1.6876e+05,1.3154 -1e+05,0.7094,0.0069648,0.05,1.6876e+05,1.3154 -1e+05,0.7094,0.0069648,0.05,1.6876e+05,1.3154 -1e+05,0.72345,0.0071027,0.05,1.6022e+05,1.1511 -1e+05,0.72345,0.0071027,0.05,1.6022e+05,1.1511 -1e+05,0.72345,0.0071027,0.05,1.6022e+05,1.1511 -1e+05,0.72345,0.0071027,0.05,1.6022e+05,1.1511 -1e+05,0.72345,0.0071027,0.05,1.6022e+05,1.1511 -1e+05,0.72345,0.0071027,0.05,1.6022e+05,1.1511 -1e+05,0.72345,0.0071027,0.05,1.6022e+05,1.1511 -1e+05,0.72345,0.0071027,0.05,1.6022e+05,1.1511 -1e+05,0.72345,0.0071027,0.05,1.6022e+05,1.1511 -1e+05,0.72345,0.0071027,0.05,1.6022e+05,1.1511 -1e+05,0.72345,0.0071027,0.05,1.6022e+05,1.1511 -1e+05,0.72345,0.0071027,0.05,1.6022e+05,1.1511 -1e+05,0.72345,0.0071027,0.05,1.6022e+05,1.1511 -1e+05,0.72345,0.0071027,0.05,1.6022e+05,1.1511 -1e+05,0.73778,0.0072434,0.05,1.5148e+05,1.0025 -1e+05,0.73778,0.0072434,0.05,1.5148e+05,1.0025 -1e+05,0.73778,0.0072434,0.05,1.5148e+05,1.0025 -1e+05,0.73778,0.0072434,0.05,1.5148e+05,1.0025 -1e+05,0.73778,0.0072434,0.05,1.5148e+05,1.0025 -1e+05,0.73778,0.0072434,0.05,1.5148e+05,1.0025 -1e+05,0.73778,0.0072434,0.05,1.5148e+05,1.0025 -1e+05,0.73778,0.0072434,0.05,1.5148e+05,1.0025 -1e+05,0.73778,0.0072434,0.05,1.5148e+05,1.0025 -1e+05,0.73778,0.0072434,0.05,1.5148e+05,1.0025 -1e+05,0.73778,0.0072434,0.05,1.5148e+05,1.0025 -1e+05,0.73778,0.0072434,0.05,1.5148e+05,1.0025 -1e+05,0.73778,0.0072434,0.05,1.5148e+05,1.0025 -1e+05,0.73778,0.0072434,0.05,1.5148e+05,1.0025 -1e+05,0.73778,0.0072434,0.05,1.5148e+05,1.0025 -1e+05,0.7524,0.0073869,0.05,1.4256e+05,0.86883 -1e+05,0.7524,0.0073869,0.05,1.4256e+05,0.86883 -1e+05,0.7524,0.0073869,0.05,1.4256e+05,0.86883 -1e+05,0.7524,0.0073869,0.05,1.4256e+05,0.86883 -1e+05,0.7524,0.0073869,0.05,1.4256e+05,0.86883 -1e+05,0.7524,0.0073869,0.05,1.4256e+05,0.86883 -1e+05,0.7524,0.0073869,0.05,1.4256e+05,0.86883 -1e+05,0.7524,0.0073869,0.05,1.4256e+05,0.86883 -1e+05,0.7524,0.0073869,0.05,1.4256e+05,0.86883 -1e+05,0.7524,0.0073869,0.05,1.4256e+05,0.86883 -1e+05,0.7524,0.0073869,0.05,1.4256e+05,0.86883 -1e+05,0.7524,0.0073869,0.05,1.4256e+05,0.86883 -1e+05,0.7524,0.0073869,0.05,1.4256e+05,0.86883 -1e+05,0.7524,0.0073869,0.05,1.4256e+05,0.86883 -1e+05,0.7673,0.0075332,0.05,1.3347e+05,0.74899 -1e+05,0.7673,0.0075332,0.05,1.3347e+05,0.74899 -1e+05,0.7673,0.0075332,0.05,1.3347e+05,0.74899 -1e+05,0.7673,0.0075332,0.05,1.3347e+05,0.74899 -1e+05,0.7673,0.0075332,0.05,1.3347e+05,0.74899 -1e+05,0.7673,0.0075332,0.05,1.3347e+05,0.74899 -1e+05,0.7673,0.0075332,0.05,1.3347e+05,0.74899 -1e+05,0.7673,0.0075332,0.05,1.3347e+05,0.74899 -1e+05,0.7673,0.0075332,0.05,1.3347e+05,0.74899 -1e+05,0.7673,0.0075332,0.05,1.3347e+05,0.74899 -1e+05,0.7673,0.0075332,0.05,1.3347e+05,0.74899 -1e+05,0.7673,0.0075332,0.05,1.3347e+05,0.74899 -1e+05,0.7673,0.0075332,0.05,1.3347e+05,0.74899 -1e+05,0.7673,0.0075332,0.05,1.3347e+05,0.74899 -1e+05,0.7673,0.0075332,0.05,1.3347e+05,0.74899 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.7825,0.0076824,0.05,1.2422e+05,0.64203 -1e+05,0.798,0.0078346,0.05,1.1482e+05,0.54698 -1e+05,0.798,0.0078346,0.05,1.1482e+05,0.54698 -1e+05,0.798,0.0078346,0.05,1.1482e+05,0.54698 -1e+05,0.798,0.0078346,0.05,1.1482e+05,0.54698 -1e+05,0.798,0.0078346,0.05,1.1482e+05,0.54698 -1e+05,0.798,0.0078346,0.05,1.1482e+05,0.54698 -1e+05,0.798,0.0078346,0.05,1.1482e+05,0.54698 -1e+05,0.798,0.0078346,0.05,1.1482e+05,0.54698 -1e+05,0.798,0.0078346,0.05,1.1482e+05,0.54698 -1e+05,0.798,0.0078346,0.05,1.1482e+05,0.54698 -1e+05,0.798,0.0078346,0.05,1.1482e+05,0.54698 -1e+05,0.798,0.0078346,0.05,1.1482e+05,0.54698 -1e+05,0.798,0.0078346,0.05,1.1482e+05,0.54698 -1e+05,0.798,0.0078346,0.05,1.1482e+05,0.54698 -1e+05,0.798,0.0078346,0.05,1.1482e+05,0.54698 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.81381,0.0079898,0.05,1.0528e+05,0.46286 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.82993,0.0081481,0.05,95624,0.38869 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.84637,0.0083095,0.05,85855,0.3235 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.86314,0.0084741,0.05,75985,0.26634 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.88024,0.008642,0.05,66028,0.21628 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.89767,0.0088132,0.05,55994,0.17237 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.91546,0.0089878,0.05,45895,0.1337 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.93359,0.0091658,0.05,35742,0.099362 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.95209,0.0093474,0.05,25547,0.068435 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.97095,0.0095326,0.05,15321,0.03999 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,0.99019,0.0097215,0.05,5075.6,0.01307 -1e+05,nan,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/data_2.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/data_2.csv deleted file mode 100644 index 440878fbef7..00000000000 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/data_2.csv +++ /dev/null @@ -1,1002 +0,0 @@ -Time,"elementCenter:0","elementCenter:1","elementCenter:2","pressure","temperature" -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,nan,nan,nan,nan,nan -20000,0.10099,0.0009915,0.05,7867.1,98.936 -20000,0.10099,0.0009915,0.05,7867.1,98.936 -20000,0.10299,0.0010111,0.05,23281,96.849 -20000,0.10299,0.0010111,0.05,23281,96.849 -20000,0.10499,0.0010308,0.05,38382,94.802 -20000,0.10499,0.0010308,0.05,38382,94.802 -20000,0.10734,0.0010538,0.05,55766,92.444 -20000,0.10734,0.0010538,0.05,55766,92.444 -20000,0.10734,0.0010538,0.05,55766,92.444 -20000,0.11004,0.0010803,0.05,75199,89.805 -20000,0.11004,0.0010803,0.05,75199,89.805 -20000,0.11004,0.0010803,0.05,75199,89.805 -20000,0.11274,0.0011068,0.05,94107,87.232 -20000,0.11274,0.0011068,0.05,94107,87.232 -20000,0.11274,0.0011068,0.05,94107,87.232 -20000,0.11544,0.0011334,0.05,1.125e+05,84.724 -20000,0.11544,0.0011334,0.05,1.125e+05,84.724 -20000,0.11814,0.0011599,0.05,1.304e+05,82.279 -20000,0.11814,0.0011599,0.05,1.304e+05,82.279 -20000,0.11814,0.0011599,0.05,1.304e+05,82.279 -20000,0.12084,0.0011864,0.05,1.4782e+05,79.895 -20000,0.12084,0.0011864,0.05,1.4782e+05,79.895 -20000,0.12084,0.0011864,0.05,1.4782e+05,79.895 -20000,0.12354,0.0012129,0.05,1.6476e+05,77.57 -20000,0.12354,0.0012129,0.05,1.6476e+05,77.57 -20000,0.12624,0.0012394,0.05,1.8125e+05,75.301 -20000,0.12624,0.0012394,0.05,1.8125e+05,75.301 -20000,0.12624,0.0012394,0.05,1.8125e+05,75.301 -20000,0.12894,0.0012659,0.05,1.9727e+05,73.088 -20000,0.12894,0.0012659,0.05,1.9727e+05,73.088 -20000,0.12894,0.0012659,0.05,1.9727e+05,73.088 -20000,0.13164,0.0012924,0.05,2.1286e+05,70.93 -20000,0.13164,0.0012924,0.05,2.1286e+05,70.93 -20000,0.1343,0.0013185,0.05,2.2779e+05,68.854 -20000,0.1343,0.0013185,0.05,2.2779e+05,68.854 -20000,0.1343,0.0013185,0.05,2.2779e+05,68.854 -20000,0.13695,0.0013445,0.05,2.4224e+05,66.837 -20000,0.13695,0.0013445,0.05,2.4224e+05,66.837 -20000,0.13695,0.0013445,0.05,2.4224e+05,66.837 -20000,0.13965,0.001371,0.05,2.5657e+05,64.829 -20000,0.13965,0.001371,0.05,2.5657e+05,64.829 -20000,0.13965,0.001371,0.05,2.5657e+05,64.829 -20000,0.1424,0.0013981,0.05,2.7075e+05,62.832 -20000,0.1424,0.0013981,0.05,2.7075e+05,62.832 -20000,0.14521,0.0014256,0.05,2.8478e+05,60.847 -20000,0.14521,0.0014256,0.05,2.8478e+05,60.847 -20000,0.14521,0.0014256,0.05,2.8478e+05,60.847 -20000,0.14807,0.0014538,0.05,2.9865e+05,58.874 -20000,0.14807,0.0014538,0.05,2.9865e+05,58.874 -20000,0.14807,0.0014538,0.05,2.9865e+05,58.874 -20000,0.151,0.0014824,0.05,3.1233e+05,56.915 -20000,0.151,0.0014824,0.05,3.1233e+05,56.915 -20000,0.151,0.0014824,0.05,3.1233e+05,56.915 -20000,0.15397,0.0015117,0.05,3.2583e+05,54.971 -20000,0.15397,0.0015117,0.05,3.2583e+05,54.971 -20000,0.15397,0.0015117,0.05,3.2583e+05,54.971 -20000,0.15701,0.0015415,0.05,3.3912e+05,53.043 -20000,0.15701,0.0015415,0.05,3.3912e+05,53.043 -20000,0.15701,0.0015415,0.05,3.3912e+05,53.043 -20000,0.16011,0.0015719,0.05,3.5218e+05,51.132 -20000,0.16011,0.0015719,0.05,3.5218e+05,51.132 -20000,0.16011,0.0015719,0.05,3.5218e+05,51.132 -20000,0.16327,0.001603,0.05,3.6501e+05,49.24 -20000,0.16327,0.001603,0.05,3.6501e+05,49.24 -20000,0.16327,0.001603,0.05,3.6501e+05,49.24 -20000,0.16649,0.0016346,0.05,3.7758e+05,47.367 -20000,0.16649,0.0016346,0.05,3.7758e+05,47.367 -20000,0.16649,0.0016346,0.05,3.7758e+05,47.367 -20000,0.16649,0.0016346,0.05,3.7758e+05,47.367 -20000,0.16978,0.0016669,0.05,3.8989e+05,45.516 -20000,0.16978,0.0016669,0.05,3.8989e+05,45.516 -20000,0.16978,0.0016669,0.05,3.8989e+05,45.516 -20000,0.17313,0.0016998,0.05,4.0191e+05,43.687 -20000,0.17313,0.0016998,0.05,4.0191e+05,43.687 -20000,0.17313,0.0016998,0.05,4.0191e+05,43.687 -20000,0.17655,0.0017333,0.05,4.1363e+05,41.881 -20000,0.17655,0.0017333,0.05,4.1363e+05,41.881 -20000,0.17655,0.0017333,0.05,4.1363e+05,41.881 -20000,0.17655,0.0017333,0.05,4.1363e+05,41.881 -20000,0.18004,0.0017676,0.05,4.2502e+05,40.101 -20000,0.18004,0.0017676,0.05,4.2502e+05,40.101 -20000,0.18004,0.0017676,0.05,4.2502e+05,40.101 -20000,0.18359,0.0018025,0.05,4.3609e+05,38.348 -20000,0.18359,0.0018025,0.05,4.3609e+05,38.348 -20000,0.18359,0.0018025,0.05,4.3609e+05,38.348 -20000,0.18359,0.0018025,0.05,4.3609e+05,38.348 -20000,0.18722,0.001838,0.05,4.4679e+05,36.623 -20000,0.18722,0.001838,0.05,4.4679e+05,36.623 -20000,0.18722,0.001838,0.05,4.4679e+05,36.623 -20000,0.18722,0.001838,0.05,4.4679e+05,36.623 -20000,0.19091,0.0018743,0.05,4.5713e+05,34.927 -20000,0.19091,0.0018743,0.05,4.5713e+05,34.927 -20000,0.19091,0.0018743,0.05,4.5713e+05,34.927 -20000,0.19468,0.0019114,0.05,4.6707e+05,33.263 -20000,0.19468,0.0019114,0.05,4.6707e+05,33.263 -20000,0.19468,0.0019114,0.05,4.6707e+05,33.263 -20000,0.19468,0.0019114,0.05,4.6707e+05,33.263 -20000,0.19853,0.0019491,0.05,4.7661e+05,31.631 -20000,0.19853,0.0019491,0.05,4.7661e+05,31.631 -20000,0.19853,0.0019491,0.05,4.7661e+05,31.631 -20000,0.19853,0.0019491,0.05,4.7661e+05,31.631 -20000,0.20245,0.0019876,0.05,4.8572e+05,30.032 -20000,0.20245,0.0019876,0.05,4.8572e+05,30.032 -20000,0.20245,0.0019876,0.05,4.8572e+05,30.032 -20000,0.20245,0.0019876,0.05,4.8572e+05,30.032 -20000,0.20645,0.0020269,0.05,4.9439e+05,28.469 -20000,0.20645,0.0020269,0.05,4.9439e+05,28.469 -20000,0.20645,0.0020269,0.05,4.9439e+05,28.469 -20000,0.20645,0.0020269,0.05,4.9439e+05,28.469 -20000,0.21053,0.0020669,0.05,5.026e+05,26.943 -20000,0.21053,0.0020669,0.05,5.026e+05,26.943 -20000,0.21053,0.0020669,0.05,5.026e+05,26.943 -20000,0.21053,0.0020669,0.05,5.026e+05,26.943 -20000,0.21469,0.0021078,0.05,5.1034e+05,25.455 -20000,0.21469,0.0021078,0.05,5.1034e+05,25.455 -20000,0.21469,0.0021078,0.05,5.1034e+05,25.455 -20000,0.21469,0.0021078,0.05,5.1034e+05,25.455 -20000,0.21893,0.0021494,0.05,5.1758e+05,24.006 -20000,0.21893,0.0021494,0.05,5.1758e+05,24.006 -20000,0.21893,0.0021494,0.05,5.1758e+05,24.006 -20000,0.21893,0.0021494,0.05,5.1758e+05,24.006 -20000,0.21893,0.0021494,0.05,5.1758e+05,24.006 -20000,0.22326,0.0021919,0.05,5.2432e+05,22.598 -20000,0.22326,0.0021919,0.05,5.2432e+05,22.598 -20000,0.22326,0.0021919,0.05,5.2432e+05,22.598 -20000,0.22326,0.0021919,0.05,5.2432e+05,22.598 -20000,0.22767,0.0022352,0.05,5.3053e+05,21.232 -20000,0.22767,0.0022352,0.05,5.3053e+05,21.232 -20000,0.22767,0.0022352,0.05,5.3053e+05,21.232 -20000,0.22767,0.0022352,0.05,5.3053e+05,21.232 -20000,0.23217,0.0022794,0.05,5.3622e+05,19.909 -20000,0.23217,0.0022794,0.05,5.3622e+05,19.909 -20000,0.23217,0.0022794,0.05,5.3622e+05,19.909 -20000,0.23217,0.0022794,0.05,5.3622e+05,19.909 -20000,0.23217,0.0022794,0.05,5.3622e+05,19.909 -20000,0.23676,0.0023244,0.05,5.4135e+05,18.63 -20000,0.23676,0.0023244,0.05,5.4135e+05,18.63 -20000,0.23676,0.0023244,0.05,5.4135e+05,18.63 -20000,0.23676,0.0023244,0.05,5.4135e+05,18.63 -20000,0.23676,0.0023244,0.05,5.4135e+05,18.63 -20000,0.24144,0.0023704,0.05,5.4593e+05,17.395 -20000,0.24144,0.0023704,0.05,5.4593e+05,17.395 -20000,0.24144,0.0023704,0.05,5.4593e+05,17.395 -20000,0.24144,0.0023704,0.05,5.4593e+05,17.395 -20000,0.24621,0.0024172,0.05,5.4994e+05,16.207 -20000,0.24621,0.0024172,0.05,5.4994e+05,16.207 -20000,0.24621,0.0024172,0.05,5.4994e+05,16.207 -20000,0.24621,0.0024172,0.05,5.4994e+05,16.207 -20000,0.24621,0.0024172,0.05,5.4994e+05,16.207 -20000,0.25108,0.002465,0.05,5.5337e+05,15.065 -20000,0.25108,0.002465,0.05,5.5337e+05,15.065 -20000,0.25108,0.002465,0.05,5.5337e+05,15.065 -20000,0.25108,0.002465,0.05,5.5337e+05,15.065 -20000,0.25108,0.002465,0.05,5.5337e+05,15.065 -20000,0.25604,0.0025137,0.05,5.5621e+05,13.97 -20000,0.25604,0.0025137,0.05,5.5621e+05,13.97 -20000,0.25604,0.0025137,0.05,5.5621e+05,13.97 -20000,0.25604,0.0025137,0.05,5.5621e+05,13.97 -20000,0.25604,0.0025137,0.05,5.5621e+05,13.97 -20000,0.2611,0.0025634,0.05,5.5847e+05,12.923 -20000,0.2611,0.0025634,0.05,5.5847e+05,12.923 -20000,0.2611,0.0025634,0.05,5.5847e+05,12.923 -20000,0.2611,0.0025634,0.05,5.5847e+05,12.923 -20000,0.2611,0.0025634,0.05,5.5847e+05,12.923 -20000,0.26626,0.0026141,0.05,5.6014e+05,11.924 -20000,0.26626,0.0026141,0.05,5.6014e+05,11.924 -20000,0.26626,0.0026141,0.05,5.6014e+05,11.924 -20000,0.26626,0.0026141,0.05,5.6014e+05,11.924 -20000,0.26626,0.0026141,0.05,5.6014e+05,11.924 -20000,0.27153,0.0026658,0.05,5.6121e+05,10.972 -20000,0.27153,0.0026658,0.05,5.6121e+05,10.972 -20000,0.27153,0.0026658,0.05,5.6121e+05,10.972 -20000,0.27153,0.0026658,0.05,5.6121e+05,10.972 -20000,0.27153,0.0026658,0.05,5.6121e+05,10.972 -20000,0.27153,0.0026658,0.05,5.6121e+05,10.972 -20000,0.2769,0.0027185,0.05,5.6168e+05,10.069 -20000,0.2769,0.0027185,0.05,5.6168e+05,10.069 -20000,0.2769,0.0027185,0.05,5.6168e+05,10.069 -20000,0.2769,0.0027185,0.05,5.6168e+05,10.069 -20000,0.2769,0.0027185,0.05,5.6168e+05,10.069 -20000,0.28237,0.0027723,0.05,5.6156e+05,9.2141 -20000,0.28237,0.0027723,0.05,5.6156e+05,9.2141 -20000,0.28237,0.0027723,0.05,5.6156e+05,9.2141 -20000,0.28237,0.0027723,0.05,5.6156e+05,9.2141 -20000,0.28237,0.0027723,0.05,5.6156e+05,9.2141 -20000,0.28237,0.0027723,0.05,5.6156e+05,9.2141 -20000,0.28796,0.0028271,0.05,5.6085e+05,8.4069 -20000,0.28796,0.0028271,0.05,5.6085e+05,8.4069 -20000,0.28796,0.0028271,0.05,5.6085e+05,8.4069 -20000,0.28796,0.0028271,0.05,5.6085e+05,8.4069 -20000,0.28796,0.0028271,0.05,5.6085e+05,8.4069 -20000,0.29365,0.002883,0.05,5.5955e+05,7.6469 -20000,0.29365,0.002883,0.05,5.5955e+05,7.6469 -20000,0.29365,0.002883,0.05,5.5955e+05,7.6469 -20000,0.29365,0.002883,0.05,5.5955e+05,7.6469 -20000,0.29365,0.002883,0.05,5.5955e+05,7.6469 -20000,0.29365,0.002883,0.05,5.5955e+05,7.6469 -20000,0.29946,0.00294,0.05,5.5768e+05,6.9336 -20000,0.29946,0.00294,0.05,5.5768e+05,6.9336 -20000,0.29946,0.00294,0.05,5.5768e+05,6.9336 -20000,0.29946,0.00294,0.05,5.5768e+05,6.9336 -20000,0.29946,0.00294,0.05,5.5768e+05,6.9336 -20000,0.29946,0.00294,0.05,5.5768e+05,6.9336 -20000,0.30538,0.0029982,0.05,5.5524e+05,6.2663 -20000,0.30538,0.0029982,0.05,5.5524e+05,6.2663 -20000,0.30538,0.0029982,0.05,5.5524e+05,6.2663 -20000,0.30538,0.0029982,0.05,5.5524e+05,6.2663 -20000,0.30538,0.0029982,0.05,5.5524e+05,6.2663 -20000,0.30538,0.0029982,0.05,5.5524e+05,6.2663 -20000,0.31142,0.0030575,0.05,5.5225e+05,5.6441 -20000,0.31142,0.0030575,0.05,5.5225e+05,5.6441 -20000,0.31142,0.0030575,0.05,5.5225e+05,5.6441 -20000,0.31142,0.0030575,0.05,5.5225e+05,5.6441 -20000,0.31142,0.0030575,0.05,5.5225e+05,5.6441 -20000,0.31142,0.0030575,0.05,5.5225e+05,5.6441 -20000,0.31758,0.003118,0.05,5.4871e+05,5.0659 -20000,0.31758,0.003118,0.05,5.4871e+05,5.0659 -20000,0.31758,0.003118,0.05,5.4871e+05,5.0659 -20000,0.31758,0.003118,0.05,5.4871e+05,5.0659 -20000,0.31758,0.003118,0.05,5.4871e+05,5.0659 -20000,0.31758,0.003118,0.05,5.4871e+05,5.0659 -20000,0.32386,0.0031796,0.05,5.4465e+05,4.5304 -20000,0.32386,0.0031796,0.05,5.4465e+05,4.5304 -20000,0.32386,0.0031796,0.05,5.4465e+05,4.5304 -20000,0.32386,0.0031796,0.05,5.4465e+05,4.5304 -20000,0.32386,0.0031796,0.05,5.4465e+05,4.5304 -20000,0.32386,0.0031796,0.05,5.4465e+05,4.5304 -20000,0.32386,0.0031796,0.05,5.4465e+05,4.5304 -20000,0.33027,0.0032425,0.05,5.4008e+05,4.0363 -20000,0.33027,0.0032425,0.05,5.4008e+05,4.0363 -20000,0.33027,0.0032425,0.05,5.4008e+05,4.0363 -20000,0.33027,0.0032425,0.05,5.4008e+05,4.0363 -20000,0.33027,0.0032425,0.05,5.4008e+05,4.0363 -20000,0.33027,0.0032425,0.05,5.4008e+05,4.0363 -20000,0.3368,0.0033067,0.05,5.3502e+05,3.5822 -20000,0.3368,0.0033067,0.05,5.3502e+05,3.5822 -20000,0.3368,0.0033067,0.05,5.3502e+05,3.5822 -20000,0.3368,0.0033067,0.05,5.3502e+05,3.5822 -20000,0.3368,0.0033067,0.05,5.3502e+05,3.5822 -20000,0.3368,0.0033067,0.05,5.3502e+05,3.5822 -20000,0.3368,0.0033067,0.05,5.3502e+05,3.5822 -20000,0.34347,0.0033721,0.05,5.2948e+05,3.1664 -20000,0.34347,0.0033721,0.05,5.2948e+05,3.1664 -20000,0.34347,0.0033721,0.05,5.2948e+05,3.1664 -20000,0.34347,0.0033721,0.05,5.2948e+05,3.1664 -20000,0.34347,0.0033721,0.05,5.2948e+05,3.1664 -20000,0.34347,0.0033721,0.05,5.2948e+05,3.1664 -20000,0.35026,0.0034388,0.05,5.235e+05,2.7873 -20000,0.35026,0.0034388,0.05,5.235e+05,2.7873 -20000,0.35026,0.0034388,0.05,5.235e+05,2.7873 -20000,0.35026,0.0034388,0.05,5.235e+05,2.7873 -20000,0.35026,0.0034388,0.05,5.235e+05,2.7873 -20000,0.35026,0.0034388,0.05,5.235e+05,2.7873 -20000,0.35026,0.0034388,0.05,5.235e+05,2.7873 -20000,0.35719,0.0035069,0.05,5.1709e+05,2.4431 -20000,0.35719,0.0035069,0.05,5.1709e+05,2.4431 -20000,0.35719,0.0035069,0.05,5.1709e+05,2.4431 -20000,0.35719,0.0035069,0.05,5.1709e+05,2.4431 -20000,0.35719,0.0035069,0.05,5.1709e+05,2.4431 -20000,0.35719,0.0035069,0.05,5.1709e+05,2.4431 -20000,0.35719,0.0035069,0.05,5.1709e+05,2.4431 -20000,0.36426,0.0035762,0.05,5.1027e+05,2.132 -20000,0.36426,0.0035762,0.05,5.1027e+05,2.132 -20000,0.36426,0.0035762,0.05,5.1027e+05,2.132 -20000,0.36426,0.0035762,0.05,5.1027e+05,2.132 -20000,0.36426,0.0035762,0.05,5.1027e+05,2.132 -20000,0.36426,0.0035762,0.05,5.1027e+05,2.132 -20000,0.36426,0.0035762,0.05,5.1027e+05,2.132 -20000,0.37147,0.003647,0.05,5.0307e+05,1.8519 -20000,0.37147,0.003647,0.05,5.0307e+05,1.8519 -20000,0.37147,0.003647,0.05,5.0307e+05,1.8519 -20000,0.37147,0.003647,0.05,5.0307e+05,1.8519 -20000,0.37147,0.003647,0.05,5.0307e+05,1.8519 -20000,0.37147,0.003647,0.05,5.0307e+05,1.8519 -20000,0.37147,0.003647,0.05,5.0307e+05,1.8519 -20000,0.37147,0.003647,0.05,5.0307e+05,1.8519 -20000,0.37882,0.0037192,0.05,4.9552e+05,1.6011 -20000,0.37882,0.0037192,0.05,4.9552e+05,1.6011 -20000,0.37882,0.0037192,0.05,4.9552e+05,1.6011 -20000,0.37882,0.0037192,0.05,4.9552e+05,1.6011 -20000,0.37882,0.0037192,0.05,4.9552e+05,1.6011 -20000,0.37882,0.0037192,0.05,4.9552e+05,1.6011 -20000,0.37882,0.0037192,0.05,4.9552e+05,1.6011 -20000,0.38632,0.0037928,0.05,4.8763e+05,1.3775 -20000,0.38632,0.0037928,0.05,4.8763e+05,1.3775 -20000,0.38632,0.0037928,0.05,4.8763e+05,1.3775 -20000,0.38632,0.0037928,0.05,4.8763e+05,1.3775 -20000,0.38632,0.0037928,0.05,4.8763e+05,1.3775 -20000,0.38632,0.0037928,0.05,4.8763e+05,1.3775 -20000,0.38632,0.0037928,0.05,4.8763e+05,1.3775 -20000,0.38632,0.0037928,0.05,4.8763e+05,1.3775 -20000,0.39396,0.0038678,0.05,4.7944e+05,1.1792 -20000,0.39396,0.0038678,0.05,4.7944e+05,1.1792 -20000,0.39396,0.0038678,0.05,4.7944e+05,1.1792 -20000,0.39396,0.0038678,0.05,4.7944e+05,1.1792 -20000,0.39396,0.0038678,0.05,4.7944e+05,1.1792 -20000,0.39396,0.0038678,0.05,4.7944e+05,1.1792 -20000,0.39396,0.0038678,0.05,4.7944e+05,1.1792 -20000,0.40176,0.0039444,0.05,4.7097e+05,1.0042 -20000,0.40176,0.0039444,0.05,4.7097e+05,1.0042 -20000,0.40176,0.0039444,0.05,4.7097e+05,1.0042 -20000,0.40176,0.0039444,0.05,4.7097e+05,1.0042 -20000,0.40176,0.0039444,0.05,4.7097e+05,1.0042 -20000,0.40176,0.0039444,0.05,4.7097e+05,1.0042 -20000,0.40176,0.0039444,0.05,4.7097e+05,1.0042 -20000,0.40176,0.0039444,0.05,4.7097e+05,1.0042 -20000,0.40971,0.0040224,0.05,4.6223e+05,0.85065 -20000,0.40971,0.0040224,0.05,4.6223e+05,0.85065 -20000,0.40971,0.0040224,0.05,4.6223e+05,0.85065 -20000,0.40971,0.0040224,0.05,4.6223e+05,0.85065 -20000,0.40971,0.0040224,0.05,4.6223e+05,0.85065 -20000,0.40971,0.0040224,0.05,4.6223e+05,0.85065 -20000,0.40971,0.0040224,0.05,4.6223e+05,0.85065 -20000,0.40971,0.0040224,0.05,4.6223e+05,0.85065 -20000,0.41782,0.004102,0.05,4.5326e+05,0.71658 -20000,0.41782,0.004102,0.05,4.5326e+05,0.71658 -20000,0.41782,0.004102,0.05,4.5326e+05,0.71658 -20000,0.41782,0.004102,0.05,4.5326e+05,0.71658 -20000,0.41782,0.004102,0.05,4.5326e+05,0.71658 -20000,0.41782,0.004102,0.05,4.5326e+05,0.71658 -20000,0.41782,0.004102,0.05,4.5326e+05,0.71658 -20000,0.41782,0.004102,0.05,4.5326e+05,0.71658 -20000,0.42609,0.0041832,0.05,4.4408e+05,0.60022 -20000,0.42609,0.0041832,0.05,4.4408e+05,0.60022 -20000,0.42609,0.0041832,0.05,4.4408e+05,0.60022 -20000,0.42609,0.0041832,0.05,4.4408e+05,0.60022 -20000,0.42609,0.0041832,0.05,4.4408e+05,0.60022 -20000,0.42609,0.0041832,0.05,4.4408e+05,0.60022 -20000,0.42609,0.0041832,0.05,4.4408e+05,0.60022 -20000,0.42609,0.0041832,0.05,4.4408e+05,0.60022 -20000,0.42609,0.0041832,0.05,4.4408e+05,0.60022 -20000,0.43452,0.004266,0.05,4.3471e+05,0.49981 -20000,0.43452,0.004266,0.05,4.3471e+05,0.49981 -20000,0.43452,0.004266,0.05,4.3471e+05,0.49981 -20000,0.43452,0.004266,0.05,4.3471e+05,0.49981 -20000,0.43452,0.004266,0.05,4.3471e+05,0.49981 -20000,0.43452,0.004266,0.05,4.3471e+05,0.49981 -20000,0.43452,0.004266,0.05,4.3471e+05,0.49981 -20000,0.43452,0.004266,0.05,4.3471e+05,0.49981 -20000,0.44312,0.0043505,0.05,4.2517e+05,0.41369 -20000,0.44312,0.0043505,0.05,4.2517e+05,0.41369 -20000,0.44312,0.0043505,0.05,4.2517e+05,0.41369 -20000,0.44312,0.0043505,0.05,4.2517e+05,0.41369 -20000,0.44312,0.0043505,0.05,4.2517e+05,0.41369 -20000,0.44312,0.0043505,0.05,4.2517e+05,0.41369 -20000,0.44312,0.0043505,0.05,4.2517e+05,0.41369 -20000,0.44312,0.0043505,0.05,4.2517e+05,0.41369 -20000,0.44312,0.0043505,0.05,4.2517e+05,0.41369 -20000,0.45189,0.0044366,0.05,4.1547e+05,0.34028 -20000,0.45189,0.0044366,0.05,4.1547e+05,0.34028 -20000,0.45189,0.0044366,0.05,4.1547e+05,0.34028 -20000,0.45189,0.0044366,0.05,4.1547e+05,0.34028 -20000,0.45189,0.0044366,0.05,4.1547e+05,0.34028 -20000,0.45189,0.0044366,0.05,4.1547e+05,0.34028 -20000,0.45189,0.0044366,0.05,4.1547e+05,0.34028 -20000,0.45189,0.0044366,0.05,4.1547e+05,0.34028 -20000,0.45189,0.0044366,0.05,4.1547e+05,0.34028 -20000,0.46084,0.0045244,0.05,4.0565e+05,0.27811 -20000,0.46084,0.0045244,0.05,4.0565e+05,0.27811 -20000,0.46084,0.0045244,0.05,4.0565e+05,0.27811 -20000,0.46084,0.0045244,0.05,4.0565e+05,0.27811 -20000,0.46084,0.0045244,0.05,4.0565e+05,0.27811 -20000,0.46084,0.0045244,0.05,4.0565e+05,0.27811 -20000,0.46084,0.0045244,0.05,4.0565e+05,0.27811 -20000,0.46084,0.0045244,0.05,4.0565e+05,0.27811 -20000,0.46084,0.0045244,0.05,4.0565e+05,0.27811 -20000,0.46996,0.004614,0.05,3.9572e+05,0.2258 -20000,0.46996,0.004614,0.05,3.9572e+05,0.2258 -20000,0.46996,0.004614,0.05,3.9572e+05,0.2258 -20000,0.46996,0.004614,0.05,3.9572e+05,0.2258 -20000,0.46996,0.004614,0.05,3.9572e+05,0.2258 -20000,0.46996,0.004614,0.05,3.9572e+05,0.2258 -20000,0.46996,0.004614,0.05,3.9572e+05,0.2258 -20000,0.46996,0.004614,0.05,3.9572e+05,0.2258 -20000,0.46996,0.004614,0.05,3.9572e+05,0.2258 -20000,0.47926,0.0047053,0.05,3.8568e+05,0.18209 -20000,0.47926,0.0047053,0.05,3.8568e+05,0.18209 -20000,0.47926,0.0047053,0.05,3.8568e+05,0.18209 -20000,0.47926,0.0047053,0.05,3.8568e+05,0.18209 -20000,0.47926,0.0047053,0.05,3.8568e+05,0.18209 -20000,0.47926,0.0047053,0.05,3.8568e+05,0.18209 -20000,0.47926,0.0047053,0.05,3.8568e+05,0.18209 -20000,0.47926,0.0047053,0.05,3.8568e+05,0.18209 -20000,0.47926,0.0047053,0.05,3.8568e+05,0.18209 -20000,0.48875,0.0047985,0.05,3.7556e+05,0.14582 -20000,0.48875,0.0047985,0.05,3.7556e+05,0.14582 -20000,0.48875,0.0047985,0.05,3.7556e+05,0.14582 -20000,0.48875,0.0047985,0.05,3.7556e+05,0.14582 -20000,0.48875,0.0047985,0.05,3.7556e+05,0.14582 -20000,0.48875,0.0047985,0.05,3.7556e+05,0.14582 -20000,0.48875,0.0047985,0.05,3.7556e+05,0.14582 -20000,0.48875,0.0047985,0.05,3.7556e+05,0.14582 -20000,0.48875,0.0047985,0.05,3.7556e+05,0.14582 -20000,0.48875,0.0047985,0.05,3.7556e+05,0.14582 -20000,0.49843,0.0048935,0.05,3.6538e+05,0.11594 -20000,0.49843,0.0048935,0.05,3.6538e+05,0.11594 -20000,0.49843,0.0048935,0.05,3.6538e+05,0.11594 -20000,0.49843,0.0048935,0.05,3.6538e+05,0.11594 -20000,0.49843,0.0048935,0.05,3.6538e+05,0.11594 -20000,0.49843,0.0048935,0.05,3.6538e+05,0.11594 -20000,0.49843,0.0048935,0.05,3.6538e+05,0.11594 -20000,0.49843,0.0048935,0.05,3.6538e+05,0.11594 -20000,0.49843,0.0048935,0.05,3.6538e+05,0.11594 -20000,0.49843,0.0048935,0.05,3.6538e+05,0.11594 -20000,0.5083,0.0049903,0.05,3.5513e+05,0.091499 -20000,0.5083,0.0049903,0.05,3.5513e+05,0.091499 -20000,0.5083,0.0049903,0.05,3.5513e+05,0.091499 -20000,0.5083,0.0049903,0.05,3.5513e+05,0.091499 -20000,0.5083,0.0049903,0.05,3.5513e+05,0.091499 -20000,0.5083,0.0049903,0.05,3.5513e+05,0.091499 -20000,0.5083,0.0049903,0.05,3.5513e+05,0.091499 -20000,0.5083,0.0049903,0.05,3.5513e+05,0.091499 -20000,0.5083,0.0049903,0.05,3.5513e+05,0.091499 -20000,0.5083,0.0049903,0.05,3.5513e+05,0.091499 -20000,0.51836,0.0050891,0.05,3.4484e+05,0.071665 -20000,0.51836,0.0050891,0.05,3.4484e+05,0.071665 -20000,0.51836,0.0050891,0.05,3.4484e+05,0.071665 -20000,0.51836,0.0050891,0.05,3.4484e+05,0.071665 -20000,0.51836,0.0050891,0.05,3.4484e+05,0.071665 -20000,0.51836,0.0050891,0.05,3.4484e+05,0.071665 -20000,0.51836,0.0050891,0.05,3.4484e+05,0.071665 -20000,0.51836,0.0050891,0.05,3.4484e+05,0.071665 -20000,0.51836,0.0050891,0.05,3.4484e+05,0.071665 -20000,0.51836,0.0050891,0.05,3.4484e+05,0.071665 -20000,0.52862,0.0051899,0.05,3.3451e+05,0.055694 -20000,0.52862,0.0051899,0.05,3.3451e+05,0.055694 -20000,0.52862,0.0051899,0.05,3.3451e+05,0.055694 -20000,0.52862,0.0051899,0.05,3.3451e+05,0.055694 -20000,0.52862,0.0051899,0.05,3.3451e+05,0.055694 -20000,0.52862,0.0051899,0.05,3.3451e+05,0.055694 -20000,0.52862,0.0051899,0.05,3.3451e+05,0.055694 -20000,0.52862,0.0051899,0.05,3.3451e+05,0.055694 -20000,0.52862,0.0051899,0.05,3.3451e+05,0.055694 -20000,0.52862,0.0051899,0.05,3.3451e+05,0.055694 -20000,0.53909,0.0052927,0.05,3.2416e+05,0.042935 -20000,0.53909,0.0052927,0.05,3.2416e+05,0.042935 -20000,0.53909,0.0052927,0.05,3.2416e+05,0.042935 -20000,0.53909,0.0052927,0.05,3.2416e+05,0.042935 -20000,0.53909,0.0052927,0.05,3.2416e+05,0.042935 -20000,0.53909,0.0052927,0.05,3.2416e+05,0.042935 -20000,0.53909,0.0052927,0.05,3.2416e+05,0.042935 -20000,0.53909,0.0052927,0.05,3.2416e+05,0.042935 -20000,0.53909,0.0052927,0.05,3.2416e+05,0.042935 -20000,0.53909,0.0052927,0.05,3.2416e+05,0.042935 -20000,0.53909,0.0052927,0.05,3.2416e+05,0.042935 -20000,0.54976,0.0053975,0.05,3.1378e+05,0.032828 -20000,0.54976,0.0053975,0.05,3.1378e+05,0.032828 -20000,0.54976,0.0053975,0.05,3.1378e+05,0.032828 -20000,0.54976,0.0053975,0.05,3.1378e+05,0.032828 -20000,0.54976,0.0053975,0.05,3.1378e+05,0.032828 -20000,0.54976,0.0053975,0.05,3.1378e+05,0.032828 -20000,0.54976,0.0053975,0.05,3.1378e+05,0.032828 -20000,0.54976,0.0053975,0.05,3.1378e+05,0.032828 -20000,0.54976,0.0053975,0.05,3.1378e+05,0.032828 -20000,0.54976,0.0053975,0.05,3.1378e+05,0.032828 -20000,0.54976,0.0053975,0.05,3.1378e+05,0.032828 -20000,0.56065,0.0055043,0.05,3.0338e+05,0.024888 -20000,0.56065,0.0055043,0.05,3.0338e+05,0.024888 -20000,0.56065,0.0055043,0.05,3.0338e+05,0.024888 -20000,0.56065,0.0055043,0.05,3.0338e+05,0.024888 -20000,0.56065,0.0055043,0.05,3.0338e+05,0.024888 -20000,0.56065,0.0055043,0.05,3.0338e+05,0.024888 -20000,0.56065,0.0055043,0.05,3.0338e+05,0.024888 -20000,0.56065,0.0055043,0.05,3.0338e+05,0.024888 -20000,0.56065,0.0055043,0.05,3.0338e+05,0.024888 -20000,0.56065,0.0055043,0.05,3.0338e+05,0.024888 -20000,0.56065,0.0055043,0.05,3.0338e+05,0.024888 -20000,0.57175,0.0056133,0.05,2.9298e+05,0.018705 -20000,0.57175,0.0056133,0.05,2.9298e+05,0.018705 -20000,0.57175,0.0056133,0.05,2.9298e+05,0.018705 -20000,0.57175,0.0056133,0.05,2.9298e+05,0.018705 -20000,0.57175,0.0056133,0.05,2.9298e+05,0.018705 -20000,0.57175,0.0056133,0.05,2.9298e+05,0.018705 -20000,0.57175,0.0056133,0.05,2.9298e+05,0.018705 -20000,0.57175,0.0056133,0.05,2.9298e+05,0.018705 -20000,0.57175,0.0056133,0.05,2.9298e+05,0.018705 -20000,0.57175,0.0056133,0.05,2.9298e+05,0.018705 -20000,0.57175,0.0056133,0.05,2.9298e+05,0.018705 -20000,0.58307,0.0057245,0.05,2.8257e+05,0.013933 -20000,0.58307,0.0057245,0.05,2.8257e+05,0.013933 -20000,0.58307,0.0057245,0.05,2.8257e+05,0.013933 -20000,0.58307,0.0057245,0.05,2.8257e+05,0.013933 -20000,0.58307,0.0057245,0.05,2.8257e+05,0.013933 -20000,0.58307,0.0057245,0.05,2.8257e+05,0.013933 -20000,0.58307,0.0057245,0.05,2.8257e+05,0.013933 -20000,0.58307,0.0057245,0.05,2.8257e+05,0.013933 -20000,0.58307,0.0057245,0.05,2.8257e+05,0.013933 -20000,0.58307,0.0057245,0.05,2.8257e+05,0.013933 -20000,0.58307,0.0057245,0.05,2.8257e+05,0.013933 -20000,0.59462,0.0058378,0.05,2.7216e+05,0.010284 -20000,0.59462,0.0058378,0.05,2.7216e+05,0.010284 -20000,0.59462,0.0058378,0.05,2.7216e+05,0.010284 -20000,0.59462,0.0058378,0.05,2.7216e+05,0.010284 -20000,0.59462,0.0058378,0.05,2.7216e+05,0.010284 -20000,0.59462,0.0058378,0.05,2.7216e+05,0.010284 -20000,0.59462,0.0058378,0.05,2.7216e+05,0.010284 -20000,0.59462,0.0058378,0.05,2.7216e+05,0.010284 -20000,0.59462,0.0058378,0.05,2.7216e+05,0.010284 -20000,0.59462,0.0058378,0.05,2.7216e+05,0.010284 -20000,0.59462,0.0058378,0.05,2.7216e+05,0.010284 -20000,0.59462,0.0058378,0.05,2.7216e+05,0.010284 -20000,0.60639,0.0059535,0.05,2.6175e+05,0.0075198 -20000,0.60639,0.0059535,0.05,2.6175e+05,0.0075198 -20000,0.60639,0.0059535,0.05,2.6175e+05,0.0075198 -20000,0.60639,0.0059535,0.05,2.6175e+05,0.0075198 -20000,0.60639,0.0059535,0.05,2.6175e+05,0.0075198 -20000,0.60639,0.0059535,0.05,2.6175e+05,0.0075198 -20000,0.60639,0.0059535,0.05,2.6175e+05,0.0075198 -20000,0.60639,0.0059535,0.05,2.6175e+05,0.0075198 -20000,0.60639,0.0059535,0.05,2.6175e+05,0.0075198 -20000,0.60639,0.0059535,0.05,2.6175e+05,0.0075198 -20000,0.60639,0.0059535,0.05,2.6175e+05,0.0075198 -20000,0.60639,0.0059535,0.05,2.6175e+05,0.0075198 -20000,0.6184,0.0060714,0.05,2.5134e+05,0.0054458 -20000,0.6184,0.0060714,0.05,2.5134e+05,0.0054458 -20000,0.6184,0.0060714,0.05,2.5134e+05,0.0054458 -20000,0.6184,0.0060714,0.05,2.5134e+05,0.0054458 -20000,0.6184,0.0060714,0.05,2.5134e+05,0.0054458 -20000,0.6184,0.0060714,0.05,2.5134e+05,0.0054458 -20000,0.6184,0.0060714,0.05,2.5134e+05,0.0054458 -20000,0.6184,0.0060714,0.05,2.5134e+05,0.0054458 -20000,0.6184,0.0060714,0.05,2.5134e+05,0.0054458 -20000,0.6184,0.0060714,0.05,2.5134e+05,0.0054458 -20000,0.6184,0.0060714,0.05,2.5134e+05,0.0054458 -20000,0.6184,0.0060714,0.05,2.5134e+05,0.0054458 -20000,0.63065,0.0061916,0.05,2.4094e+05,0.003905 -20000,0.63065,0.0061916,0.05,2.4094e+05,0.003905 -20000,0.63065,0.0061916,0.05,2.4094e+05,0.003905 -20000,0.63065,0.0061916,0.05,2.4094e+05,0.003905 -20000,0.63065,0.0061916,0.05,2.4094e+05,0.003905 -20000,0.63065,0.0061916,0.05,2.4094e+05,0.003905 -20000,0.63065,0.0061916,0.05,2.4094e+05,0.003905 -20000,0.63065,0.0061916,0.05,2.4094e+05,0.003905 -20000,0.63065,0.0061916,0.05,2.4094e+05,0.003905 -20000,0.63065,0.0061916,0.05,2.4094e+05,0.003905 -20000,0.63065,0.0061916,0.05,2.4094e+05,0.003905 -20000,0.63065,0.0061916,0.05,2.4094e+05,0.003905 -20000,0.64314,0.0063142,0.05,2.3055e+05,0.0027719 -20000,0.64314,0.0063142,0.05,2.3055e+05,0.0027719 -20000,0.64314,0.0063142,0.05,2.3055e+05,0.0027719 -20000,0.64314,0.0063142,0.05,2.3055e+05,0.0027719 -20000,0.64314,0.0063142,0.05,2.3055e+05,0.0027719 -20000,0.64314,0.0063142,0.05,2.3055e+05,0.0027719 -20000,0.64314,0.0063142,0.05,2.3055e+05,0.0027719 -20000,0.64314,0.0063142,0.05,2.3055e+05,0.0027719 -20000,0.64314,0.0063142,0.05,2.3055e+05,0.0027719 -20000,0.64314,0.0063142,0.05,2.3055e+05,0.0027719 -20000,0.64314,0.0063142,0.05,2.3055e+05,0.0027719 -20000,0.64314,0.0063142,0.05,2.3055e+05,0.0027719 -20000,0.64314,0.0063142,0.05,2.3055e+05,0.0027719 -20000,0.65588,0.0064393,0.05,2.2018e+05,0.0019473 -20000,0.65588,0.0064393,0.05,2.2018e+05,0.0019473 -20000,0.65588,0.0064393,0.05,2.2018e+05,0.0019473 -20000,0.65588,0.0064393,0.05,2.2018e+05,0.0019473 -20000,0.65588,0.0064393,0.05,2.2018e+05,0.0019473 -20000,0.65588,0.0064393,0.05,2.2018e+05,0.0019473 -20000,0.65588,0.0064393,0.05,2.2018e+05,0.0019473 -20000,0.65588,0.0064393,0.05,2.2018e+05,0.0019473 -20000,0.65588,0.0064393,0.05,2.2018e+05,0.0019473 -20000,0.65588,0.0064393,0.05,2.2018e+05,0.0019473 -20000,0.65588,0.0064393,0.05,2.2018e+05,0.0019473 -20000,0.65588,0.0064393,0.05,2.2018e+05,0.0019473 -20000,0.65588,0.0064393,0.05,2.2018e+05,0.0019473 -20000,0.66887,0.0065668,0.05,2.0981e+05,0.0013535 -20000,0.66887,0.0065668,0.05,2.0981e+05,0.0013535 -20000,0.66887,0.0065668,0.05,2.0981e+05,0.0013535 -20000,0.66887,0.0065668,0.05,2.0981e+05,0.0013535 -20000,0.66887,0.0065668,0.05,2.0981e+05,0.0013535 -20000,0.66887,0.0065668,0.05,2.0981e+05,0.0013535 -20000,0.66887,0.0065668,0.05,2.0981e+05,0.0013535 -20000,0.66887,0.0065668,0.05,2.0981e+05,0.0013535 -20000,0.66887,0.0065668,0.05,2.0981e+05,0.0013535 -20000,0.66887,0.0065668,0.05,2.0981e+05,0.0013535 -20000,0.66887,0.0065668,0.05,2.0981e+05,0.0013535 -20000,0.66887,0.0065668,0.05,2.0981e+05,0.0013535 -20000,0.66887,0.0065668,0.05,2.0981e+05,0.0013535 -20000,0.68211,0.0066969,0.05,1.9945e+05,0.00093059 -20000,0.68211,0.0066969,0.05,1.9945e+05,0.00093059 -20000,0.68211,0.0066969,0.05,1.9945e+05,0.00093059 -20000,0.68211,0.0066969,0.05,1.9945e+05,0.00093059 -20000,0.68211,0.0066969,0.05,1.9945e+05,0.00093059 -20000,0.68211,0.0066969,0.05,1.9945e+05,0.00093059 -20000,0.68211,0.0066969,0.05,1.9945e+05,0.00093059 -20000,0.68211,0.0066969,0.05,1.9945e+05,0.00093059 -20000,0.68211,0.0066969,0.05,1.9945e+05,0.00093059 -20000,0.68211,0.0066969,0.05,1.9945e+05,0.00093059 -20000,0.68211,0.0066969,0.05,1.9945e+05,0.00093059 -20000,0.68211,0.0066969,0.05,1.9945e+05,0.00093059 -20000,0.68211,0.0066969,0.05,1.9945e+05,0.00093059 -20000,0.69562,0.0068295,0.05,1.8911e+05,0.00063272 -20000,0.69562,0.0068295,0.05,1.8911e+05,0.00063272 -20000,0.69562,0.0068295,0.05,1.8911e+05,0.00063272 -20000,0.69562,0.0068295,0.05,1.8911e+05,0.00063272 -20000,0.69562,0.0068295,0.05,1.8911e+05,0.00063272 -20000,0.69562,0.0068295,0.05,1.8911e+05,0.00063272 -20000,0.69562,0.0068295,0.05,1.8911e+05,0.00063272 -20000,0.69562,0.0068295,0.05,1.8911e+05,0.00063272 -20000,0.69562,0.0068295,0.05,1.8911e+05,0.00063272 -20000,0.69562,0.0068295,0.05,1.8911e+05,0.00063272 -20000,0.69562,0.0068295,0.05,1.8911e+05,0.00063272 -20000,0.69562,0.0068295,0.05,1.8911e+05,0.00063272 -20000,0.69562,0.0068295,0.05,1.8911e+05,0.00063272 -20000,0.69562,0.0068295,0.05,1.8911e+05,0.00063272 -20000,0.7094,0.0069648,0.05,1.7878e+05,0.00042531 -20000,0.7094,0.0069648,0.05,1.7878e+05,0.00042531 -20000,0.7094,0.0069648,0.05,1.7878e+05,0.00042531 -20000,0.7094,0.0069648,0.05,1.7878e+05,0.00042531 -20000,0.7094,0.0069648,0.05,1.7878e+05,0.00042531 -20000,0.7094,0.0069648,0.05,1.7878e+05,0.00042531 -20000,0.7094,0.0069648,0.05,1.7878e+05,0.00042531 -20000,0.7094,0.0069648,0.05,1.7878e+05,0.00042531 -20000,0.7094,0.0069648,0.05,1.7878e+05,0.00042531 -20000,0.7094,0.0069648,0.05,1.7878e+05,0.00042531 -20000,0.7094,0.0069648,0.05,1.7878e+05,0.00042531 -20000,0.7094,0.0069648,0.05,1.7878e+05,0.00042531 -20000,0.7094,0.0069648,0.05,1.7878e+05,0.00042531 -20000,0.7094,0.0069648,0.05,1.7878e+05,0.00042531 -20000,0.72345,0.0071027,0.05,1.6846e+05,0.00028257 -20000,0.72345,0.0071027,0.05,1.6846e+05,0.00028257 -20000,0.72345,0.0071027,0.05,1.6846e+05,0.00028257 -20000,0.72345,0.0071027,0.05,1.6846e+05,0.00028257 -20000,0.72345,0.0071027,0.05,1.6846e+05,0.00028257 -20000,0.72345,0.0071027,0.05,1.6846e+05,0.00028257 -20000,0.72345,0.0071027,0.05,1.6846e+05,0.00028257 -20000,0.72345,0.0071027,0.05,1.6846e+05,0.00028257 -20000,0.72345,0.0071027,0.05,1.6846e+05,0.00028257 -20000,0.72345,0.0071027,0.05,1.6846e+05,0.00028257 -20000,0.72345,0.0071027,0.05,1.6846e+05,0.00028257 -20000,0.72345,0.0071027,0.05,1.6846e+05,0.00028257 -20000,0.72345,0.0071027,0.05,1.6846e+05,0.00028257 -20000,0.72345,0.0071027,0.05,1.6846e+05,0.00028257 -20000,0.73778,0.0072434,0.05,1.5816e+05,0.0001855 -20000,0.73778,0.0072434,0.05,1.5816e+05,0.0001855 -20000,0.73778,0.0072434,0.05,1.5816e+05,0.0001855 -20000,0.73778,0.0072434,0.05,1.5816e+05,0.0001855 -20000,0.73778,0.0072434,0.05,1.5816e+05,0.0001855 -20000,0.73778,0.0072434,0.05,1.5816e+05,0.0001855 -20000,0.73778,0.0072434,0.05,1.5816e+05,0.0001855 -20000,0.73778,0.0072434,0.05,1.5816e+05,0.0001855 -20000,0.73778,0.0072434,0.05,1.5816e+05,0.0001855 -20000,0.73778,0.0072434,0.05,1.5816e+05,0.0001855 -20000,0.73778,0.0072434,0.05,1.5816e+05,0.0001855 -20000,0.73778,0.0072434,0.05,1.5816e+05,0.0001855 -20000,0.73778,0.0072434,0.05,1.5816e+05,0.0001855 -20000,0.73778,0.0072434,0.05,1.5816e+05,0.0001855 -20000,0.73778,0.0072434,0.05,1.5816e+05,0.0001855 -20000,0.7524,0.0073869,0.05,1.4787e+05,0.0001203 -20000,0.7524,0.0073869,0.05,1.4787e+05,0.0001203 -20000,0.7524,0.0073869,0.05,1.4787e+05,0.0001203 -20000,0.7524,0.0073869,0.05,1.4787e+05,0.0001203 -20000,0.7524,0.0073869,0.05,1.4787e+05,0.0001203 -20000,0.7524,0.0073869,0.05,1.4787e+05,0.0001203 -20000,0.7524,0.0073869,0.05,1.4787e+05,0.0001203 -20000,0.7524,0.0073869,0.05,1.4787e+05,0.0001203 -20000,0.7524,0.0073869,0.05,1.4787e+05,0.0001203 -20000,0.7524,0.0073869,0.05,1.4787e+05,0.0001203 -20000,0.7524,0.0073869,0.05,1.4787e+05,0.0001203 -20000,0.7524,0.0073869,0.05,1.4787e+05,0.0001203 -20000,0.7524,0.0073869,0.05,1.4787e+05,0.0001203 -20000,0.7524,0.0073869,0.05,1.4787e+05,0.0001203 -20000,0.7673,0.0075332,0.05,1.3759e+05,7.704e-05 -20000,0.7673,0.0075332,0.05,1.3759e+05,7.704e-05 -20000,0.7673,0.0075332,0.05,1.3759e+05,7.704e-05 -20000,0.7673,0.0075332,0.05,1.3759e+05,7.704e-05 -20000,0.7673,0.0075332,0.05,1.3759e+05,7.704e-05 -20000,0.7673,0.0075332,0.05,1.3759e+05,7.704e-05 -20000,0.7673,0.0075332,0.05,1.3759e+05,7.704e-05 -20000,0.7673,0.0075332,0.05,1.3759e+05,7.704e-05 -20000,0.7673,0.0075332,0.05,1.3759e+05,7.704e-05 -20000,0.7673,0.0075332,0.05,1.3759e+05,7.704e-05 -20000,0.7673,0.0075332,0.05,1.3759e+05,7.704e-05 -20000,0.7673,0.0075332,0.05,1.3759e+05,7.704e-05 -20000,0.7673,0.0075332,0.05,1.3759e+05,7.704e-05 -20000,0.7673,0.0075332,0.05,1.3759e+05,7.704e-05 -20000,0.7673,0.0075332,0.05,1.3759e+05,7.704e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.7825,0.0076824,0.05,1.2733e+05,4.871e-05 -20000,0.798,0.0078346,0.05,1.1708e+05,3.0398e-05 -20000,0.798,0.0078346,0.05,1.1708e+05,3.0398e-05 -20000,0.798,0.0078346,0.05,1.1708e+05,3.0398e-05 -20000,0.798,0.0078346,0.05,1.1708e+05,3.0398e-05 -20000,0.798,0.0078346,0.05,1.1708e+05,3.0398e-05 -20000,0.798,0.0078346,0.05,1.1708e+05,3.0398e-05 -20000,0.798,0.0078346,0.05,1.1708e+05,3.0398e-05 -20000,0.798,0.0078346,0.05,1.1708e+05,3.0398e-05 -20000,0.798,0.0078346,0.05,1.1708e+05,3.0398e-05 -20000,0.798,0.0078346,0.05,1.1708e+05,3.0398e-05 -20000,0.798,0.0078346,0.05,1.1708e+05,3.0398e-05 -20000,0.798,0.0078346,0.05,1.1708e+05,3.0398e-05 -20000,0.798,0.0078346,0.05,1.1708e+05,3.0398e-05 -20000,0.798,0.0078346,0.05,1.1708e+05,3.0398e-05 -20000,0.798,0.0078346,0.05,1.1708e+05,3.0398e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.81381,0.0079898,0.05,1.0684e+05,1.8717e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.82993,0.0081481,0.05,96621,1.1369e-05 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.84637,0.0083095,0.05,86409,6.809e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.86314,0.0084741,0.05,76208,4.02e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.88024,0.008642,0.05,66018,2.3386e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.89767,0.0088132,0.05,55836,1.3395e-06 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.91546,0.0089878,0.05,45663,7.542e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.93359,0.0091658,0.05,35497,4.1541e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.95209,0.0093474,0.05,25337,2.2017e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.97095,0.0095326,0.05,15180,1.0526e-07 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,0.99019,0.0097215,0.05,5026.7,3.0759e-08 -20000,nan,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/data_5.csv b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/data_5.csv deleted file mode 100644 index 00f866b98e9..00000000000 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/data_5.csv +++ /dev/null @@ -1,1002 +0,0 @@ -Time,"elementCenter:0","elementCenter:1","elementCenter:2","pressure","temperature" -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,nan,nan,nan,nan,nan -50000,0.10099,0.0009915,0.05,4623.8,99.199 -50000,0.10099,0.0009915,0.05,4623.8,99.199 -50000,0.10299,0.0010111,0.05,13685,97.628 -50000,0.10299,0.0010111,0.05,13685,97.628 -50000,0.10499,0.0010308,0.05,22567,96.087 -50000,0.10499,0.0010308,0.05,22567,96.087 -50000,0.10734,0.0010538,0.05,32796,94.311 -50000,0.10734,0.0010538,0.05,32796,94.311 -50000,0.10734,0.0010538,0.05,32796,94.311 -50000,0.11004,0.0010803,0.05,44244,92.322 -50000,0.11004,0.0010803,0.05,44244,92.322 -50000,0.11004,0.0010803,0.05,44244,92.322 -50000,0.11274,0.0011068,0.05,55397,90.382 -50000,0.11274,0.0011068,0.05,55397,90.382 -50000,0.11274,0.0011068,0.05,55397,90.382 -50000,0.11544,0.0011334,0.05,66268,88.489 -50000,0.11544,0.0011334,0.05,66268,88.489 -50000,0.11814,0.0011599,0.05,76867,86.641 -50000,0.11814,0.0011599,0.05,76867,86.641 -50000,0.11814,0.0011599,0.05,76867,86.641 -50000,0.12084,0.0011864,0.05,87204,84.836 -50000,0.12084,0.0011864,0.05,87204,84.836 -50000,0.12084,0.0011864,0.05,87204,84.836 -50000,0.12354,0.0012129,0.05,97287,83.072 -50000,0.12354,0.0012129,0.05,97287,83.072 -50000,0.12624,0.0012394,0.05,1.0713e+05,81.348 -50000,0.12624,0.0012394,0.05,1.0713e+05,81.348 -50000,0.12624,0.0012394,0.05,1.0713e+05,81.348 -50000,0.12894,0.0012659,0.05,1.1673e+05,79.663 -50000,0.12894,0.0012659,0.05,1.1673e+05,79.663 -50000,0.12894,0.0012659,0.05,1.1673e+05,79.663 -50000,0.13164,0.0012924,0.05,1.261e+05,78.015 -50000,0.13164,0.0012924,0.05,1.261e+05,78.015 -50000,0.1343,0.0013185,0.05,1.3512e+05,76.425 -50000,0.1343,0.0013185,0.05,1.3512e+05,76.425 -50000,0.1343,0.0013185,0.05,1.3512e+05,76.425 -50000,0.13695,0.0013445,0.05,1.4388e+05,74.877 -50000,0.13695,0.0013445,0.05,1.4388e+05,74.877 -50000,0.13695,0.0013445,0.05,1.4388e+05,74.877 -50000,0.13965,0.001371,0.05,1.5262e+05,73.33 -50000,0.13965,0.001371,0.05,1.5262e+05,73.33 -50000,0.13965,0.001371,0.05,1.5262e+05,73.33 -50000,0.1424,0.0013981,0.05,1.6131e+05,71.786 -50000,0.1424,0.0013981,0.05,1.6131e+05,71.786 -50000,0.14521,0.0014256,0.05,1.6997e+05,70.246 -50000,0.14521,0.0014256,0.05,1.6997e+05,70.246 -50000,0.14521,0.0014256,0.05,1.6997e+05,70.246 -50000,0.14807,0.0014538,0.05,1.7857e+05,68.708 -50000,0.14807,0.0014538,0.05,1.7857e+05,68.708 -50000,0.14807,0.0014538,0.05,1.7857e+05,68.708 -50000,0.151,0.0014824,0.05,1.8713e+05,67.174 -50000,0.151,0.0014824,0.05,1.8713e+05,67.174 -50000,0.151,0.0014824,0.05,1.8713e+05,67.174 -50000,0.15397,0.0015117,0.05,1.9564e+05,65.644 -50000,0.15397,0.0015117,0.05,1.9564e+05,65.644 -50000,0.15397,0.0015117,0.05,1.9564e+05,65.644 -50000,0.15701,0.0015415,0.05,2.0409e+05,64.118 -50000,0.15701,0.0015415,0.05,2.0409e+05,64.118 -50000,0.15701,0.0015415,0.05,2.0409e+05,64.118 -50000,0.16011,0.0015719,0.05,2.1248e+05,62.596 -50000,0.16011,0.0015719,0.05,2.1248e+05,62.596 -50000,0.16011,0.0015719,0.05,2.1248e+05,62.596 -50000,0.16327,0.001603,0.05,2.208e+05,61.08 -50000,0.16327,0.001603,0.05,2.208e+05,61.08 -50000,0.16327,0.001603,0.05,2.208e+05,61.08 -50000,0.16649,0.0016346,0.05,2.2905e+05,59.568 -50000,0.16649,0.0016346,0.05,2.2905e+05,59.568 -50000,0.16649,0.0016346,0.05,2.2905e+05,59.568 -50000,0.16649,0.0016346,0.05,2.2905e+05,59.568 -50000,0.16978,0.0016669,0.05,2.3723e+05,58.063 -50000,0.16978,0.0016669,0.05,2.3723e+05,58.063 -50000,0.16978,0.0016669,0.05,2.3723e+05,58.063 -50000,0.17313,0.0016998,0.05,2.4532e+05,56.564 -50000,0.17313,0.0016998,0.05,2.4532e+05,56.564 -50000,0.17313,0.0016998,0.05,2.4532e+05,56.564 -50000,0.17655,0.0017333,0.05,2.5332e+05,55.071 -50000,0.17655,0.0017333,0.05,2.5332e+05,55.071 -50000,0.17655,0.0017333,0.05,2.5332e+05,55.071 -50000,0.17655,0.0017333,0.05,2.5332e+05,55.071 -50000,0.18004,0.0017676,0.05,2.6124e+05,53.586 -50000,0.18004,0.0017676,0.05,2.6124e+05,53.586 -50000,0.18004,0.0017676,0.05,2.6124e+05,53.586 -50000,0.18359,0.0018025,0.05,2.6905e+05,52.108 -50000,0.18359,0.0018025,0.05,2.6905e+05,52.108 -50000,0.18359,0.0018025,0.05,2.6905e+05,52.108 -50000,0.18359,0.0018025,0.05,2.6905e+05,52.108 -50000,0.18722,0.001838,0.05,2.7676e+05,50.639 -50000,0.18722,0.001838,0.05,2.7676e+05,50.639 -50000,0.18722,0.001838,0.05,2.7676e+05,50.639 -50000,0.18722,0.001838,0.05,2.7676e+05,50.639 -50000,0.19091,0.0018743,0.05,2.8435e+05,49.178 -50000,0.19091,0.0018743,0.05,2.8435e+05,49.178 -50000,0.19091,0.0018743,0.05,2.8435e+05,49.178 -50000,0.19468,0.0019114,0.05,2.9183e+05,47.727 -50000,0.19468,0.0019114,0.05,2.9183e+05,47.727 -50000,0.19468,0.0019114,0.05,2.9183e+05,47.727 -50000,0.19468,0.0019114,0.05,2.9183e+05,47.727 -50000,0.19853,0.0019491,0.05,2.9918e+05,46.285 -50000,0.19853,0.0019491,0.05,2.9918e+05,46.285 -50000,0.19853,0.0019491,0.05,2.9918e+05,46.285 -50000,0.19853,0.0019491,0.05,2.9918e+05,46.285 -50000,0.20245,0.0019876,0.05,3.0639e+05,44.854 -50000,0.20245,0.0019876,0.05,3.0639e+05,44.854 -50000,0.20245,0.0019876,0.05,3.0639e+05,44.854 -50000,0.20245,0.0019876,0.05,3.0639e+05,44.854 -50000,0.20645,0.0020269,0.05,3.1347e+05,43.434 -50000,0.20645,0.0020269,0.05,3.1347e+05,43.434 -50000,0.20645,0.0020269,0.05,3.1347e+05,43.434 -50000,0.20645,0.0020269,0.05,3.1347e+05,43.434 -50000,0.21053,0.0020669,0.05,3.2039e+05,42.025 -50000,0.21053,0.0020669,0.05,3.2039e+05,42.025 -50000,0.21053,0.0020669,0.05,3.2039e+05,42.025 -50000,0.21053,0.0020669,0.05,3.2039e+05,42.025 -50000,0.21469,0.0021078,0.05,3.2716e+05,40.63 -50000,0.21469,0.0021078,0.05,3.2716e+05,40.63 -50000,0.21469,0.0021078,0.05,3.2716e+05,40.63 -50000,0.21469,0.0021078,0.05,3.2716e+05,40.63 -50000,0.21893,0.0021494,0.05,3.3376e+05,39.247 -50000,0.21893,0.0021494,0.05,3.3376e+05,39.247 -50000,0.21893,0.0021494,0.05,3.3376e+05,39.247 -50000,0.21893,0.0021494,0.05,3.3376e+05,39.247 -50000,0.21893,0.0021494,0.05,3.3376e+05,39.247 -50000,0.22326,0.0021919,0.05,3.4019e+05,37.878 -50000,0.22326,0.0021919,0.05,3.4019e+05,37.878 -50000,0.22326,0.0021919,0.05,3.4019e+05,37.878 -50000,0.22326,0.0021919,0.05,3.4019e+05,37.878 -50000,0.22767,0.0022352,0.05,3.4643e+05,36.524 -50000,0.22767,0.0022352,0.05,3.4643e+05,36.524 -50000,0.22767,0.0022352,0.05,3.4643e+05,36.524 -50000,0.22767,0.0022352,0.05,3.4643e+05,36.524 -50000,0.23217,0.0022794,0.05,3.5248e+05,35.185 -50000,0.23217,0.0022794,0.05,3.5248e+05,35.185 -50000,0.23217,0.0022794,0.05,3.5248e+05,35.185 -50000,0.23217,0.0022794,0.05,3.5248e+05,35.185 -50000,0.23217,0.0022794,0.05,3.5248e+05,35.185 -50000,0.23676,0.0023244,0.05,3.5832e+05,33.862 -50000,0.23676,0.0023244,0.05,3.5832e+05,33.862 -50000,0.23676,0.0023244,0.05,3.5832e+05,33.862 -50000,0.23676,0.0023244,0.05,3.5832e+05,33.862 -50000,0.23676,0.0023244,0.05,3.5832e+05,33.862 -50000,0.24144,0.0023704,0.05,3.6396e+05,32.556 -50000,0.24144,0.0023704,0.05,3.6396e+05,32.556 -50000,0.24144,0.0023704,0.05,3.6396e+05,32.556 -50000,0.24144,0.0023704,0.05,3.6396e+05,32.556 -50000,0.24621,0.0024172,0.05,3.6937e+05,31.267 -50000,0.24621,0.0024172,0.05,3.6937e+05,31.267 -50000,0.24621,0.0024172,0.05,3.6937e+05,31.267 -50000,0.24621,0.0024172,0.05,3.6937e+05,31.267 -50000,0.24621,0.0024172,0.05,3.6937e+05,31.267 -50000,0.25108,0.002465,0.05,3.7455e+05,29.997 -50000,0.25108,0.002465,0.05,3.7455e+05,29.997 -50000,0.25108,0.002465,0.05,3.7455e+05,29.997 -50000,0.25108,0.002465,0.05,3.7455e+05,29.997 -50000,0.25108,0.002465,0.05,3.7455e+05,29.997 -50000,0.25604,0.0025137,0.05,3.7949e+05,28.746 -50000,0.25604,0.0025137,0.05,3.7949e+05,28.746 -50000,0.25604,0.0025137,0.05,3.7949e+05,28.746 -50000,0.25604,0.0025137,0.05,3.7949e+05,28.746 -50000,0.25604,0.0025137,0.05,3.7949e+05,28.746 -50000,0.2611,0.0025634,0.05,3.8418e+05,27.516 -50000,0.2611,0.0025634,0.05,3.8418e+05,27.516 -50000,0.2611,0.0025634,0.05,3.8418e+05,27.516 -50000,0.2611,0.0025634,0.05,3.8418e+05,27.516 -50000,0.2611,0.0025634,0.05,3.8418e+05,27.516 -50000,0.26626,0.0026141,0.05,3.8861e+05,26.306 -50000,0.26626,0.0026141,0.05,3.8861e+05,26.306 -50000,0.26626,0.0026141,0.05,3.8861e+05,26.306 -50000,0.26626,0.0026141,0.05,3.8861e+05,26.306 -50000,0.26626,0.0026141,0.05,3.8861e+05,26.306 -50000,0.27153,0.0026658,0.05,3.9276e+05,25.118 -50000,0.27153,0.0026658,0.05,3.9276e+05,25.118 -50000,0.27153,0.0026658,0.05,3.9276e+05,25.118 -50000,0.27153,0.0026658,0.05,3.9276e+05,25.118 -50000,0.27153,0.0026658,0.05,3.9276e+05,25.118 -50000,0.27153,0.0026658,0.05,3.9276e+05,25.118 -50000,0.2769,0.0027185,0.05,3.9664e+05,23.952 -50000,0.2769,0.0027185,0.05,3.9664e+05,23.952 -50000,0.2769,0.0027185,0.05,3.9664e+05,23.952 -50000,0.2769,0.0027185,0.05,3.9664e+05,23.952 -50000,0.2769,0.0027185,0.05,3.9664e+05,23.952 -50000,0.28237,0.0027723,0.05,4.0022e+05,22.81 -50000,0.28237,0.0027723,0.05,4.0022e+05,22.81 -50000,0.28237,0.0027723,0.05,4.0022e+05,22.81 -50000,0.28237,0.0027723,0.05,4.0022e+05,22.81 -50000,0.28237,0.0027723,0.05,4.0022e+05,22.81 -50000,0.28237,0.0027723,0.05,4.0022e+05,22.81 -50000,0.28796,0.0028271,0.05,4.035e+05,21.692 -50000,0.28796,0.0028271,0.05,4.035e+05,21.692 -50000,0.28796,0.0028271,0.05,4.035e+05,21.692 -50000,0.28796,0.0028271,0.05,4.035e+05,21.692 -50000,0.28796,0.0028271,0.05,4.035e+05,21.692 -50000,0.29365,0.002883,0.05,4.0648e+05,20.599 -50000,0.29365,0.002883,0.05,4.0648e+05,20.599 -50000,0.29365,0.002883,0.05,4.0648e+05,20.599 -50000,0.29365,0.002883,0.05,4.0648e+05,20.599 -50000,0.29365,0.002883,0.05,4.0648e+05,20.599 -50000,0.29365,0.002883,0.05,4.0648e+05,20.599 -50000,0.29946,0.00294,0.05,4.0913e+05,19.532 -50000,0.29946,0.00294,0.05,4.0913e+05,19.532 -50000,0.29946,0.00294,0.05,4.0913e+05,19.532 -50000,0.29946,0.00294,0.05,4.0913e+05,19.532 -50000,0.29946,0.00294,0.05,4.0913e+05,19.532 -50000,0.29946,0.00294,0.05,4.0913e+05,19.532 -50000,0.30538,0.0029982,0.05,4.1145e+05,18.491 -50000,0.30538,0.0029982,0.05,4.1145e+05,18.491 -50000,0.30538,0.0029982,0.05,4.1145e+05,18.491 -50000,0.30538,0.0029982,0.05,4.1145e+05,18.491 -50000,0.30538,0.0029982,0.05,4.1145e+05,18.491 -50000,0.30538,0.0029982,0.05,4.1145e+05,18.491 -50000,0.31142,0.0030575,0.05,4.1343e+05,17.477 -50000,0.31142,0.0030575,0.05,4.1343e+05,17.477 -50000,0.31142,0.0030575,0.05,4.1343e+05,17.477 -50000,0.31142,0.0030575,0.05,4.1343e+05,17.477 -50000,0.31142,0.0030575,0.05,4.1343e+05,17.477 -50000,0.31142,0.0030575,0.05,4.1343e+05,17.477 -50000,0.31758,0.003118,0.05,4.1507e+05,16.491 -50000,0.31758,0.003118,0.05,4.1507e+05,16.491 -50000,0.31758,0.003118,0.05,4.1507e+05,16.491 -50000,0.31758,0.003118,0.05,4.1507e+05,16.491 -50000,0.31758,0.003118,0.05,4.1507e+05,16.491 -50000,0.31758,0.003118,0.05,4.1507e+05,16.491 -50000,0.32386,0.0031796,0.05,4.1635e+05,15.534 -50000,0.32386,0.0031796,0.05,4.1635e+05,15.534 -50000,0.32386,0.0031796,0.05,4.1635e+05,15.534 -50000,0.32386,0.0031796,0.05,4.1635e+05,15.534 -50000,0.32386,0.0031796,0.05,4.1635e+05,15.534 -50000,0.32386,0.0031796,0.05,4.1635e+05,15.534 -50000,0.32386,0.0031796,0.05,4.1635e+05,15.534 -50000,0.33027,0.0032425,0.05,4.1727e+05,14.605 -50000,0.33027,0.0032425,0.05,4.1727e+05,14.605 -50000,0.33027,0.0032425,0.05,4.1727e+05,14.605 -50000,0.33027,0.0032425,0.05,4.1727e+05,14.605 -50000,0.33027,0.0032425,0.05,4.1727e+05,14.605 -50000,0.33027,0.0032425,0.05,4.1727e+05,14.605 -50000,0.3368,0.0033067,0.05,4.1782e+05,13.707 -50000,0.3368,0.0033067,0.05,4.1782e+05,13.707 -50000,0.3368,0.0033067,0.05,4.1782e+05,13.707 -50000,0.3368,0.0033067,0.05,4.1782e+05,13.707 -50000,0.3368,0.0033067,0.05,4.1782e+05,13.707 -50000,0.3368,0.0033067,0.05,4.1782e+05,13.707 -50000,0.3368,0.0033067,0.05,4.1782e+05,13.707 -50000,0.34347,0.0033721,0.05,4.1799e+05,12.839 -50000,0.34347,0.0033721,0.05,4.1799e+05,12.839 -50000,0.34347,0.0033721,0.05,4.1799e+05,12.839 -50000,0.34347,0.0033721,0.05,4.1799e+05,12.839 -50000,0.34347,0.0033721,0.05,4.1799e+05,12.839 -50000,0.34347,0.0033721,0.05,4.1799e+05,12.839 -50000,0.35026,0.0034388,0.05,4.1778e+05,12.002 -50000,0.35026,0.0034388,0.05,4.1778e+05,12.002 -50000,0.35026,0.0034388,0.05,4.1778e+05,12.002 -50000,0.35026,0.0034388,0.05,4.1778e+05,12.002 -50000,0.35026,0.0034388,0.05,4.1778e+05,12.002 -50000,0.35026,0.0034388,0.05,4.1778e+05,12.002 -50000,0.35026,0.0034388,0.05,4.1778e+05,12.002 -50000,0.35719,0.0035069,0.05,4.1719e+05,11.195 -50000,0.35719,0.0035069,0.05,4.1719e+05,11.195 -50000,0.35719,0.0035069,0.05,4.1719e+05,11.195 -50000,0.35719,0.0035069,0.05,4.1719e+05,11.195 -50000,0.35719,0.0035069,0.05,4.1719e+05,11.195 -50000,0.35719,0.0035069,0.05,4.1719e+05,11.195 -50000,0.35719,0.0035069,0.05,4.1719e+05,11.195 -50000,0.36426,0.0035762,0.05,4.162e+05,10.421 -50000,0.36426,0.0035762,0.05,4.162e+05,10.421 -50000,0.36426,0.0035762,0.05,4.162e+05,10.421 -50000,0.36426,0.0035762,0.05,4.162e+05,10.421 -50000,0.36426,0.0035762,0.05,4.162e+05,10.421 -50000,0.36426,0.0035762,0.05,4.162e+05,10.421 -50000,0.36426,0.0035762,0.05,4.162e+05,10.421 -50000,0.37147,0.003647,0.05,4.1482e+05,9.6778 -50000,0.37147,0.003647,0.05,4.1482e+05,9.6778 -50000,0.37147,0.003647,0.05,4.1482e+05,9.6778 -50000,0.37147,0.003647,0.05,4.1482e+05,9.6778 -50000,0.37147,0.003647,0.05,4.1482e+05,9.6778 -50000,0.37147,0.003647,0.05,4.1482e+05,9.6778 -50000,0.37147,0.003647,0.05,4.1482e+05,9.6778 -50000,0.37147,0.003647,0.05,4.1482e+05,9.6778 -50000,0.37882,0.0037192,0.05,4.1305e+05,8.9668 -50000,0.37882,0.0037192,0.05,4.1305e+05,8.9668 -50000,0.37882,0.0037192,0.05,4.1305e+05,8.9668 -50000,0.37882,0.0037192,0.05,4.1305e+05,8.9668 -50000,0.37882,0.0037192,0.05,4.1305e+05,8.9668 -50000,0.37882,0.0037192,0.05,4.1305e+05,8.9668 -50000,0.37882,0.0037192,0.05,4.1305e+05,8.9668 -50000,0.38632,0.0037928,0.05,4.1087e+05,8.288 -50000,0.38632,0.0037928,0.05,4.1087e+05,8.288 -50000,0.38632,0.0037928,0.05,4.1087e+05,8.288 -50000,0.38632,0.0037928,0.05,4.1087e+05,8.288 -50000,0.38632,0.0037928,0.05,4.1087e+05,8.288 -50000,0.38632,0.0037928,0.05,4.1087e+05,8.288 -50000,0.38632,0.0037928,0.05,4.1087e+05,8.288 -50000,0.38632,0.0037928,0.05,4.1087e+05,8.288 -50000,0.39396,0.0038678,0.05,4.083e+05,7.6412 -50000,0.39396,0.0038678,0.05,4.083e+05,7.6412 -50000,0.39396,0.0038678,0.05,4.083e+05,7.6412 -50000,0.39396,0.0038678,0.05,4.083e+05,7.6412 -50000,0.39396,0.0038678,0.05,4.083e+05,7.6412 -50000,0.39396,0.0038678,0.05,4.083e+05,7.6412 -50000,0.39396,0.0038678,0.05,4.083e+05,7.6412 -50000,0.40176,0.0039444,0.05,4.0533e+05,7.0266 -50000,0.40176,0.0039444,0.05,4.0533e+05,7.0266 -50000,0.40176,0.0039444,0.05,4.0533e+05,7.0266 -50000,0.40176,0.0039444,0.05,4.0533e+05,7.0266 -50000,0.40176,0.0039444,0.05,4.0533e+05,7.0266 -50000,0.40176,0.0039444,0.05,4.0533e+05,7.0266 -50000,0.40176,0.0039444,0.05,4.0533e+05,7.0266 -50000,0.40176,0.0039444,0.05,4.0533e+05,7.0266 -50000,0.40971,0.0040224,0.05,4.0196e+05,6.4439 -50000,0.40971,0.0040224,0.05,4.0196e+05,6.4439 -50000,0.40971,0.0040224,0.05,4.0196e+05,6.4439 -50000,0.40971,0.0040224,0.05,4.0196e+05,6.4439 -50000,0.40971,0.0040224,0.05,4.0196e+05,6.4439 -50000,0.40971,0.0040224,0.05,4.0196e+05,6.4439 -50000,0.40971,0.0040224,0.05,4.0196e+05,6.4439 -50000,0.40971,0.0040224,0.05,4.0196e+05,6.4439 -50000,0.41782,0.004102,0.05,3.982e+05,5.8929 -50000,0.41782,0.004102,0.05,3.982e+05,5.8929 -50000,0.41782,0.004102,0.05,3.982e+05,5.8929 -50000,0.41782,0.004102,0.05,3.982e+05,5.8929 -50000,0.41782,0.004102,0.05,3.982e+05,5.8929 -50000,0.41782,0.004102,0.05,3.982e+05,5.8929 -50000,0.41782,0.004102,0.05,3.982e+05,5.8929 -50000,0.41782,0.004102,0.05,3.982e+05,5.8929 -50000,0.42609,0.0041832,0.05,3.9405e+05,5.3733 -50000,0.42609,0.0041832,0.05,3.9405e+05,5.3733 -50000,0.42609,0.0041832,0.05,3.9405e+05,5.3733 -50000,0.42609,0.0041832,0.05,3.9405e+05,5.3733 -50000,0.42609,0.0041832,0.05,3.9405e+05,5.3733 -50000,0.42609,0.0041832,0.05,3.9405e+05,5.3733 -50000,0.42609,0.0041832,0.05,3.9405e+05,5.3733 -50000,0.42609,0.0041832,0.05,3.9405e+05,5.3733 -50000,0.42609,0.0041832,0.05,3.9405e+05,5.3733 -50000,0.43452,0.004266,0.05,3.8951e+05,4.8847 -50000,0.43452,0.004266,0.05,3.8951e+05,4.8847 -50000,0.43452,0.004266,0.05,3.8951e+05,4.8847 -50000,0.43452,0.004266,0.05,3.8951e+05,4.8847 -50000,0.43452,0.004266,0.05,3.8951e+05,4.8847 -50000,0.43452,0.004266,0.05,3.8951e+05,4.8847 -50000,0.43452,0.004266,0.05,3.8951e+05,4.8847 -50000,0.43452,0.004266,0.05,3.8951e+05,4.8847 -50000,0.44312,0.0043505,0.05,3.846e+05,4.4267 -50000,0.44312,0.0043505,0.05,3.846e+05,4.4267 -50000,0.44312,0.0043505,0.05,3.846e+05,4.4267 -50000,0.44312,0.0043505,0.05,3.846e+05,4.4267 -50000,0.44312,0.0043505,0.05,3.846e+05,4.4267 -50000,0.44312,0.0043505,0.05,3.846e+05,4.4267 -50000,0.44312,0.0043505,0.05,3.846e+05,4.4267 -50000,0.44312,0.0043505,0.05,3.846e+05,4.4267 -50000,0.44312,0.0043505,0.05,3.846e+05,4.4267 -50000,0.45189,0.0044366,0.05,3.7932e+05,3.9985 -50000,0.45189,0.0044366,0.05,3.7932e+05,3.9985 -50000,0.45189,0.0044366,0.05,3.7932e+05,3.9985 -50000,0.45189,0.0044366,0.05,3.7932e+05,3.9985 -50000,0.45189,0.0044366,0.05,3.7932e+05,3.9985 -50000,0.45189,0.0044366,0.05,3.7932e+05,3.9985 -50000,0.45189,0.0044366,0.05,3.7932e+05,3.9985 -50000,0.45189,0.0044366,0.05,3.7932e+05,3.9985 -50000,0.45189,0.0044366,0.05,3.7932e+05,3.9985 -50000,0.46084,0.0045244,0.05,3.7368e+05,3.5995 -50000,0.46084,0.0045244,0.05,3.7368e+05,3.5995 -50000,0.46084,0.0045244,0.05,3.7368e+05,3.5995 -50000,0.46084,0.0045244,0.05,3.7368e+05,3.5995 -50000,0.46084,0.0045244,0.05,3.7368e+05,3.5995 -50000,0.46084,0.0045244,0.05,3.7368e+05,3.5995 -50000,0.46084,0.0045244,0.05,3.7368e+05,3.5995 -50000,0.46084,0.0045244,0.05,3.7368e+05,3.5995 -50000,0.46084,0.0045244,0.05,3.7368e+05,3.5995 -50000,0.46996,0.004614,0.05,3.6768e+05,3.2291 -50000,0.46996,0.004614,0.05,3.6768e+05,3.2291 -50000,0.46996,0.004614,0.05,3.6768e+05,3.2291 -50000,0.46996,0.004614,0.05,3.6768e+05,3.2291 -50000,0.46996,0.004614,0.05,3.6768e+05,3.2291 -50000,0.46996,0.004614,0.05,3.6768e+05,3.2291 -50000,0.46996,0.004614,0.05,3.6768e+05,3.2291 -50000,0.46996,0.004614,0.05,3.6768e+05,3.2291 -50000,0.46996,0.004614,0.05,3.6768e+05,3.2291 -50000,0.47926,0.0047053,0.05,3.6134e+05,2.8862 -50000,0.47926,0.0047053,0.05,3.6134e+05,2.8862 -50000,0.47926,0.0047053,0.05,3.6134e+05,2.8862 -50000,0.47926,0.0047053,0.05,3.6134e+05,2.8862 -50000,0.47926,0.0047053,0.05,3.6134e+05,2.8862 -50000,0.47926,0.0047053,0.05,3.6134e+05,2.8862 -50000,0.47926,0.0047053,0.05,3.6134e+05,2.8862 -50000,0.47926,0.0047053,0.05,3.6134e+05,2.8862 -50000,0.47926,0.0047053,0.05,3.6134e+05,2.8862 -50000,0.48875,0.0047985,0.05,3.5467e+05,2.57 -50000,0.48875,0.0047985,0.05,3.5467e+05,2.57 -50000,0.48875,0.0047985,0.05,3.5467e+05,2.57 -50000,0.48875,0.0047985,0.05,3.5467e+05,2.57 -50000,0.48875,0.0047985,0.05,3.5467e+05,2.57 -50000,0.48875,0.0047985,0.05,3.5467e+05,2.57 -50000,0.48875,0.0047985,0.05,3.5467e+05,2.57 -50000,0.48875,0.0047985,0.05,3.5467e+05,2.57 -50000,0.48875,0.0047985,0.05,3.5467e+05,2.57 -50000,0.48875,0.0047985,0.05,3.5467e+05,2.57 -50000,0.49843,0.0048935,0.05,3.4768e+05,2.2795 -50000,0.49843,0.0048935,0.05,3.4768e+05,2.2795 -50000,0.49843,0.0048935,0.05,3.4768e+05,2.2795 -50000,0.49843,0.0048935,0.05,3.4768e+05,2.2795 -50000,0.49843,0.0048935,0.05,3.4768e+05,2.2795 -50000,0.49843,0.0048935,0.05,3.4768e+05,2.2795 -50000,0.49843,0.0048935,0.05,3.4768e+05,2.2795 -50000,0.49843,0.0048935,0.05,3.4768e+05,2.2795 -50000,0.49843,0.0048935,0.05,3.4768e+05,2.2795 -50000,0.49843,0.0048935,0.05,3.4768e+05,2.2795 -50000,0.5083,0.0049903,0.05,3.4039e+05,2.0137 -50000,0.5083,0.0049903,0.05,3.4039e+05,2.0137 -50000,0.5083,0.0049903,0.05,3.4039e+05,2.0137 -50000,0.5083,0.0049903,0.05,3.4039e+05,2.0137 -50000,0.5083,0.0049903,0.05,3.4039e+05,2.0137 -50000,0.5083,0.0049903,0.05,3.4039e+05,2.0137 -50000,0.5083,0.0049903,0.05,3.4039e+05,2.0137 -50000,0.5083,0.0049903,0.05,3.4039e+05,2.0137 -50000,0.5083,0.0049903,0.05,3.4039e+05,2.0137 -50000,0.5083,0.0049903,0.05,3.4039e+05,2.0137 -50000,0.51836,0.0050891,0.05,3.328e+05,1.7714 -50000,0.51836,0.0050891,0.05,3.328e+05,1.7714 -50000,0.51836,0.0050891,0.05,3.328e+05,1.7714 -50000,0.51836,0.0050891,0.05,3.328e+05,1.7714 -50000,0.51836,0.0050891,0.05,3.328e+05,1.7714 -50000,0.51836,0.0050891,0.05,3.328e+05,1.7714 -50000,0.51836,0.0050891,0.05,3.328e+05,1.7714 -50000,0.51836,0.0050891,0.05,3.328e+05,1.7714 -50000,0.51836,0.0050891,0.05,3.328e+05,1.7714 -50000,0.51836,0.0050891,0.05,3.328e+05,1.7714 -50000,0.52862,0.0051899,0.05,3.2494e+05,1.5515 -50000,0.52862,0.0051899,0.05,3.2494e+05,1.5515 -50000,0.52862,0.0051899,0.05,3.2494e+05,1.5515 -50000,0.52862,0.0051899,0.05,3.2494e+05,1.5515 -50000,0.52862,0.0051899,0.05,3.2494e+05,1.5515 -50000,0.52862,0.0051899,0.05,3.2494e+05,1.5515 -50000,0.52862,0.0051899,0.05,3.2494e+05,1.5515 -50000,0.52862,0.0051899,0.05,3.2494e+05,1.5515 -50000,0.52862,0.0051899,0.05,3.2494e+05,1.5515 -50000,0.52862,0.0051899,0.05,3.2494e+05,1.5515 -50000,0.53909,0.0052927,0.05,3.1681e+05,1.3528 -50000,0.53909,0.0052927,0.05,3.1681e+05,1.3528 -50000,0.53909,0.0052927,0.05,3.1681e+05,1.3528 -50000,0.53909,0.0052927,0.05,3.1681e+05,1.3528 -50000,0.53909,0.0052927,0.05,3.1681e+05,1.3528 -50000,0.53909,0.0052927,0.05,3.1681e+05,1.3528 -50000,0.53909,0.0052927,0.05,3.1681e+05,1.3528 -50000,0.53909,0.0052927,0.05,3.1681e+05,1.3528 -50000,0.53909,0.0052927,0.05,3.1681e+05,1.3528 -50000,0.53909,0.0052927,0.05,3.1681e+05,1.3528 -50000,0.53909,0.0052927,0.05,3.1681e+05,1.3528 -50000,0.54976,0.0053975,0.05,3.0844e+05,1.174 -50000,0.54976,0.0053975,0.05,3.0844e+05,1.174 -50000,0.54976,0.0053975,0.05,3.0844e+05,1.174 -50000,0.54976,0.0053975,0.05,3.0844e+05,1.174 -50000,0.54976,0.0053975,0.05,3.0844e+05,1.174 -50000,0.54976,0.0053975,0.05,3.0844e+05,1.174 -50000,0.54976,0.0053975,0.05,3.0844e+05,1.174 -50000,0.54976,0.0053975,0.05,3.0844e+05,1.174 -50000,0.54976,0.0053975,0.05,3.0844e+05,1.174 -50000,0.54976,0.0053975,0.05,3.0844e+05,1.174 -50000,0.54976,0.0053975,0.05,3.0844e+05,1.174 -50000,0.56065,0.0055043,0.05,2.9983e+05,1.0139 -50000,0.56065,0.0055043,0.05,2.9983e+05,1.0139 -50000,0.56065,0.0055043,0.05,2.9983e+05,1.0139 -50000,0.56065,0.0055043,0.05,2.9983e+05,1.0139 -50000,0.56065,0.0055043,0.05,2.9983e+05,1.0139 -50000,0.56065,0.0055043,0.05,2.9983e+05,1.0139 -50000,0.56065,0.0055043,0.05,2.9983e+05,1.0139 -50000,0.56065,0.0055043,0.05,2.9983e+05,1.0139 -50000,0.56065,0.0055043,0.05,2.9983e+05,1.0139 -50000,0.56065,0.0055043,0.05,2.9983e+05,1.0139 -50000,0.56065,0.0055043,0.05,2.9983e+05,1.0139 -50000,0.57175,0.0056133,0.05,2.9101e+05,0.87123 -50000,0.57175,0.0056133,0.05,2.9101e+05,0.87123 -50000,0.57175,0.0056133,0.05,2.9101e+05,0.87123 -50000,0.57175,0.0056133,0.05,2.9101e+05,0.87123 -50000,0.57175,0.0056133,0.05,2.9101e+05,0.87123 -50000,0.57175,0.0056133,0.05,2.9101e+05,0.87123 -50000,0.57175,0.0056133,0.05,2.9101e+05,0.87123 -50000,0.57175,0.0056133,0.05,2.9101e+05,0.87123 -50000,0.57175,0.0056133,0.05,2.9101e+05,0.87123 -50000,0.57175,0.0056133,0.05,2.9101e+05,0.87123 -50000,0.57175,0.0056133,0.05,2.9101e+05,0.87123 -50000,0.58307,0.0057245,0.05,2.8199e+05,0.74476 -50000,0.58307,0.0057245,0.05,2.8199e+05,0.74476 -50000,0.58307,0.0057245,0.05,2.8199e+05,0.74476 -50000,0.58307,0.0057245,0.05,2.8199e+05,0.74476 -50000,0.58307,0.0057245,0.05,2.8199e+05,0.74476 -50000,0.58307,0.0057245,0.05,2.8199e+05,0.74476 -50000,0.58307,0.0057245,0.05,2.8199e+05,0.74476 -50000,0.58307,0.0057245,0.05,2.8199e+05,0.74476 -50000,0.58307,0.0057245,0.05,2.8199e+05,0.74476 -50000,0.58307,0.0057245,0.05,2.8199e+05,0.74476 -50000,0.58307,0.0057245,0.05,2.8199e+05,0.74476 -50000,0.59462,0.0058378,0.05,2.7279e+05,0.63322 -50000,0.59462,0.0058378,0.05,2.7279e+05,0.63322 -50000,0.59462,0.0058378,0.05,2.7279e+05,0.63322 -50000,0.59462,0.0058378,0.05,2.7279e+05,0.63322 -50000,0.59462,0.0058378,0.05,2.7279e+05,0.63322 -50000,0.59462,0.0058378,0.05,2.7279e+05,0.63322 -50000,0.59462,0.0058378,0.05,2.7279e+05,0.63322 -50000,0.59462,0.0058378,0.05,2.7279e+05,0.63322 -50000,0.59462,0.0058378,0.05,2.7279e+05,0.63322 -50000,0.59462,0.0058378,0.05,2.7279e+05,0.63322 -50000,0.59462,0.0058378,0.05,2.7279e+05,0.63322 -50000,0.59462,0.0058378,0.05,2.7279e+05,0.63322 -50000,0.60639,0.0059535,0.05,2.6341e+05,0.53539 -50000,0.60639,0.0059535,0.05,2.6341e+05,0.53539 -50000,0.60639,0.0059535,0.05,2.6341e+05,0.53539 -50000,0.60639,0.0059535,0.05,2.6341e+05,0.53539 -50000,0.60639,0.0059535,0.05,2.6341e+05,0.53539 -50000,0.60639,0.0059535,0.05,2.6341e+05,0.53539 -50000,0.60639,0.0059535,0.05,2.6341e+05,0.53539 -50000,0.60639,0.0059535,0.05,2.6341e+05,0.53539 -50000,0.60639,0.0059535,0.05,2.6341e+05,0.53539 -50000,0.60639,0.0059535,0.05,2.6341e+05,0.53539 -50000,0.60639,0.0059535,0.05,2.6341e+05,0.53539 -50000,0.60639,0.0059535,0.05,2.6341e+05,0.53539 -50000,0.6184,0.0060714,0.05,2.5388e+05,0.45006 -50000,0.6184,0.0060714,0.05,2.5388e+05,0.45006 -50000,0.6184,0.0060714,0.05,2.5388e+05,0.45006 -50000,0.6184,0.0060714,0.05,2.5388e+05,0.45006 -50000,0.6184,0.0060714,0.05,2.5388e+05,0.45006 -50000,0.6184,0.0060714,0.05,2.5388e+05,0.45006 -50000,0.6184,0.0060714,0.05,2.5388e+05,0.45006 -50000,0.6184,0.0060714,0.05,2.5388e+05,0.45006 -50000,0.6184,0.0060714,0.05,2.5388e+05,0.45006 -50000,0.6184,0.0060714,0.05,2.5388e+05,0.45006 -50000,0.6184,0.0060714,0.05,2.5388e+05,0.45006 -50000,0.6184,0.0060714,0.05,2.5388e+05,0.45006 -50000,0.63065,0.0061916,0.05,2.4421e+05,0.37607 -50000,0.63065,0.0061916,0.05,2.4421e+05,0.37607 -50000,0.63065,0.0061916,0.05,2.4421e+05,0.37607 -50000,0.63065,0.0061916,0.05,2.4421e+05,0.37607 -50000,0.63065,0.0061916,0.05,2.4421e+05,0.37607 -50000,0.63065,0.0061916,0.05,2.4421e+05,0.37607 -50000,0.63065,0.0061916,0.05,2.4421e+05,0.37607 -50000,0.63065,0.0061916,0.05,2.4421e+05,0.37607 -50000,0.63065,0.0061916,0.05,2.4421e+05,0.37607 -50000,0.63065,0.0061916,0.05,2.4421e+05,0.37607 -50000,0.63065,0.0061916,0.05,2.4421e+05,0.37607 -50000,0.63065,0.0061916,0.05,2.4421e+05,0.37607 -50000,0.64314,0.0063142,0.05,2.3441e+05,0.3123 -50000,0.64314,0.0063142,0.05,2.3441e+05,0.3123 -50000,0.64314,0.0063142,0.05,2.3441e+05,0.3123 -50000,0.64314,0.0063142,0.05,2.3441e+05,0.3123 -50000,0.64314,0.0063142,0.05,2.3441e+05,0.3123 -50000,0.64314,0.0063142,0.05,2.3441e+05,0.3123 -50000,0.64314,0.0063142,0.05,2.3441e+05,0.3123 -50000,0.64314,0.0063142,0.05,2.3441e+05,0.3123 -50000,0.64314,0.0063142,0.05,2.3441e+05,0.3123 -50000,0.64314,0.0063142,0.05,2.3441e+05,0.3123 -50000,0.64314,0.0063142,0.05,2.3441e+05,0.3123 -50000,0.64314,0.0063142,0.05,2.3441e+05,0.3123 -50000,0.64314,0.0063142,0.05,2.3441e+05,0.3123 -50000,0.65588,0.0064393,0.05,2.2449e+05,0.25768 -50000,0.65588,0.0064393,0.05,2.2449e+05,0.25768 -50000,0.65588,0.0064393,0.05,2.2449e+05,0.25768 -50000,0.65588,0.0064393,0.05,2.2449e+05,0.25768 -50000,0.65588,0.0064393,0.05,2.2449e+05,0.25768 -50000,0.65588,0.0064393,0.05,2.2449e+05,0.25768 -50000,0.65588,0.0064393,0.05,2.2449e+05,0.25768 -50000,0.65588,0.0064393,0.05,2.2449e+05,0.25768 -50000,0.65588,0.0064393,0.05,2.2449e+05,0.25768 -50000,0.65588,0.0064393,0.05,2.2449e+05,0.25768 -50000,0.65588,0.0064393,0.05,2.2449e+05,0.25768 -50000,0.65588,0.0064393,0.05,2.2449e+05,0.25768 -50000,0.65588,0.0064393,0.05,2.2449e+05,0.25768 -50000,0.66887,0.0065668,0.05,2.1448e+05,0.21121 -50000,0.66887,0.0065668,0.05,2.1448e+05,0.21121 -50000,0.66887,0.0065668,0.05,2.1448e+05,0.21121 -50000,0.66887,0.0065668,0.05,2.1448e+05,0.21121 -50000,0.66887,0.0065668,0.05,2.1448e+05,0.21121 -50000,0.66887,0.0065668,0.05,2.1448e+05,0.21121 -50000,0.66887,0.0065668,0.05,2.1448e+05,0.21121 -50000,0.66887,0.0065668,0.05,2.1448e+05,0.21121 -50000,0.66887,0.0065668,0.05,2.1448e+05,0.21121 -50000,0.66887,0.0065668,0.05,2.1448e+05,0.21121 -50000,0.66887,0.0065668,0.05,2.1448e+05,0.21121 -50000,0.66887,0.0065668,0.05,2.1448e+05,0.21121 -50000,0.66887,0.0065668,0.05,2.1448e+05,0.21121 -50000,0.68211,0.0066969,0.05,2.0438e+05,0.17193 -50000,0.68211,0.0066969,0.05,2.0438e+05,0.17193 -50000,0.68211,0.0066969,0.05,2.0438e+05,0.17193 -50000,0.68211,0.0066969,0.05,2.0438e+05,0.17193 -50000,0.68211,0.0066969,0.05,2.0438e+05,0.17193 -50000,0.68211,0.0066969,0.05,2.0438e+05,0.17193 -50000,0.68211,0.0066969,0.05,2.0438e+05,0.17193 -50000,0.68211,0.0066969,0.05,2.0438e+05,0.17193 -50000,0.68211,0.0066969,0.05,2.0438e+05,0.17193 -50000,0.68211,0.0066969,0.05,2.0438e+05,0.17193 -50000,0.68211,0.0066969,0.05,2.0438e+05,0.17193 -50000,0.68211,0.0066969,0.05,2.0438e+05,0.17193 -50000,0.68211,0.0066969,0.05,2.0438e+05,0.17193 -50000,0.69562,0.0068295,0.05,1.9419e+05,0.13897 -50000,0.69562,0.0068295,0.05,1.9419e+05,0.13897 -50000,0.69562,0.0068295,0.05,1.9419e+05,0.13897 -50000,0.69562,0.0068295,0.05,1.9419e+05,0.13897 -50000,0.69562,0.0068295,0.05,1.9419e+05,0.13897 -50000,0.69562,0.0068295,0.05,1.9419e+05,0.13897 -50000,0.69562,0.0068295,0.05,1.9419e+05,0.13897 -50000,0.69562,0.0068295,0.05,1.9419e+05,0.13897 -50000,0.69562,0.0068295,0.05,1.9419e+05,0.13897 -50000,0.69562,0.0068295,0.05,1.9419e+05,0.13897 -50000,0.69562,0.0068295,0.05,1.9419e+05,0.13897 -50000,0.69562,0.0068295,0.05,1.9419e+05,0.13897 -50000,0.69562,0.0068295,0.05,1.9419e+05,0.13897 -50000,0.69562,0.0068295,0.05,1.9419e+05,0.13897 -50000,0.7094,0.0069648,0.05,1.8394e+05,0.1115 -50000,0.7094,0.0069648,0.05,1.8394e+05,0.1115 -50000,0.7094,0.0069648,0.05,1.8394e+05,0.1115 -50000,0.7094,0.0069648,0.05,1.8394e+05,0.1115 -50000,0.7094,0.0069648,0.05,1.8394e+05,0.1115 -50000,0.7094,0.0069648,0.05,1.8394e+05,0.1115 -50000,0.7094,0.0069648,0.05,1.8394e+05,0.1115 -50000,0.7094,0.0069648,0.05,1.8394e+05,0.1115 -50000,0.7094,0.0069648,0.05,1.8394e+05,0.1115 -50000,0.7094,0.0069648,0.05,1.8394e+05,0.1115 -50000,0.7094,0.0069648,0.05,1.8394e+05,0.1115 -50000,0.7094,0.0069648,0.05,1.8394e+05,0.1115 -50000,0.7094,0.0069648,0.05,1.8394e+05,0.1115 -50000,0.7094,0.0069648,0.05,1.8394e+05,0.1115 -50000,0.72345,0.0071027,0.05,1.7363e+05,0.088788 -50000,0.72345,0.0071027,0.05,1.7363e+05,0.088788 -50000,0.72345,0.0071027,0.05,1.7363e+05,0.088788 -50000,0.72345,0.0071027,0.05,1.7363e+05,0.088788 -50000,0.72345,0.0071027,0.05,1.7363e+05,0.088788 -50000,0.72345,0.0071027,0.05,1.7363e+05,0.088788 -50000,0.72345,0.0071027,0.05,1.7363e+05,0.088788 -50000,0.72345,0.0071027,0.05,1.7363e+05,0.088788 -50000,0.72345,0.0071027,0.05,1.7363e+05,0.088788 -50000,0.72345,0.0071027,0.05,1.7363e+05,0.088788 -50000,0.72345,0.0071027,0.05,1.7363e+05,0.088788 -50000,0.72345,0.0071027,0.05,1.7363e+05,0.088788 -50000,0.72345,0.0071027,0.05,1.7363e+05,0.088788 -50000,0.72345,0.0071027,0.05,1.7363e+05,0.088788 -50000,0.73778,0.0072434,0.05,1.6327e+05,0.070147 -50000,0.73778,0.0072434,0.05,1.6327e+05,0.070147 -50000,0.73778,0.0072434,0.05,1.6327e+05,0.070147 -50000,0.73778,0.0072434,0.05,1.6327e+05,0.070147 -50000,0.73778,0.0072434,0.05,1.6327e+05,0.070147 -50000,0.73778,0.0072434,0.05,1.6327e+05,0.070147 -50000,0.73778,0.0072434,0.05,1.6327e+05,0.070147 -50000,0.73778,0.0072434,0.05,1.6327e+05,0.070147 -50000,0.73778,0.0072434,0.05,1.6327e+05,0.070147 -50000,0.73778,0.0072434,0.05,1.6327e+05,0.070147 -50000,0.73778,0.0072434,0.05,1.6327e+05,0.070147 -50000,0.73778,0.0072434,0.05,1.6327e+05,0.070147 -50000,0.73778,0.0072434,0.05,1.6327e+05,0.070147 -50000,0.73778,0.0072434,0.05,1.6327e+05,0.070147 -50000,0.73778,0.0072434,0.05,1.6327e+05,0.070147 -50000,0.7524,0.0073869,0.05,1.5287e+05,0.054971 -50000,0.7524,0.0073869,0.05,1.5287e+05,0.054971 -50000,0.7524,0.0073869,0.05,1.5287e+05,0.054971 -50000,0.7524,0.0073869,0.05,1.5287e+05,0.054971 -50000,0.7524,0.0073869,0.05,1.5287e+05,0.054971 -50000,0.7524,0.0073869,0.05,1.5287e+05,0.054971 -50000,0.7524,0.0073869,0.05,1.5287e+05,0.054971 -50000,0.7524,0.0073869,0.05,1.5287e+05,0.054971 -50000,0.7524,0.0073869,0.05,1.5287e+05,0.054971 -50000,0.7524,0.0073869,0.05,1.5287e+05,0.054971 -50000,0.7524,0.0073869,0.05,1.5287e+05,0.054971 -50000,0.7524,0.0073869,0.05,1.5287e+05,0.054971 -50000,0.7524,0.0073869,0.05,1.5287e+05,0.054971 -50000,0.7524,0.0073869,0.05,1.5287e+05,0.054971 -50000,0.7673,0.0075332,0.05,1.4243e+05,0.042717 -50000,0.7673,0.0075332,0.05,1.4243e+05,0.042717 -50000,0.7673,0.0075332,0.05,1.4243e+05,0.042717 -50000,0.7673,0.0075332,0.05,1.4243e+05,0.042717 -50000,0.7673,0.0075332,0.05,1.4243e+05,0.042717 -50000,0.7673,0.0075332,0.05,1.4243e+05,0.042717 -50000,0.7673,0.0075332,0.05,1.4243e+05,0.042717 -50000,0.7673,0.0075332,0.05,1.4243e+05,0.042717 -50000,0.7673,0.0075332,0.05,1.4243e+05,0.042717 -50000,0.7673,0.0075332,0.05,1.4243e+05,0.042717 -50000,0.7673,0.0075332,0.05,1.4243e+05,0.042717 -50000,0.7673,0.0075332,0.05,1.4243e+05,0.042717 -50000,0.7673,0.0075332,0.05,1.4243e+05,0.042717 -50000,0.7673,0.0075332,0.05,1.4243e+05,0.042717 -50000,0.7673,0.0075332,0.05,1.4243e+05,0.042717 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.7825,0.0076824,0.05,1.3196e+05,0.032908 -50000,0.798,0.0078346,0.05,1.2147e+05,0.025123 -50000,0.798,0.0078346,0.05,1.2147e+05,0.025123 -50000,0.798,0.0078346,0.05,1.2147e+05,0.025123 -50000,0.798,0.0078346,0.05,1.2147e+05,0.025123 -50000,0.798,0.0078346,0.05,1.2147e+05,0.025123 -50000,0.798,0.0078346,0.05,1.2147e+05,0.025123 -50000,0.798,0.0078346,0.05,1.2147e+05,0.025123 -50000,0.798,0.0078346,0.05,1.2147e+05,0.025123 -50000,0.798,0.0078346,0.05,1.2147e+05,0.025123 -50000,0.798,0.0078346,0.05,1.2147e+05,0.025123 -50000,0.798,0.0078346,0.05,1.2147e+05,0.025123 -50000,0.798,0.0078346,0.05,1.2147e+05,0.025123 -50000,0.798,0.0078346,0.05,1.2147e+05,0.025123 -50000,0.798,0.0078346,0.05,1.2147e+05,0.025123 -50000,0.798,0.0078346,0.05,1.2147e+05,0.025123 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.81381,0.0079898,0.05,1.1095e+05,0.019002 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.82993,0.0081481,0.05,1.0041e+05,0.014231 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.84637,0.0083095,0.05,89867,0.010549 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.86314,0.0084741,0.05,79309,0.0077325 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.88024,0.008642,0.05,68742,0.0055971 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.89767,0.0088132,0.05,58168,0.0039904 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.91546,0.0089878,0.05,47589,0.0027872 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.93359,0.0091658,0.05,37006,0.0018853 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.95209,0.0093474,0.05,26420,0.0012005 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.97095,0.0095326,0.05,15832,0.00066249 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,0.99019,0.0097215,0.05,5242.9,0.00020997 -50000,nan,nan,nan,nan,nan diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/pureThermalDiffusionAroundWellbore.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/pureThermalDiffusionAroundWellbore.py deleted file mode 100644 index 684854d3b06..00000000000 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/pureThermalDiffusion/pureThermalDiffusionAroundWellbore.py +++ /dev/null @@ -1,127 +0,0 @@ -import os -import sys - -import numpy as np -import matplotlib.pyplot as plt -import pandas as pd -import scipy.linalg -from scipy import special -from xml.etree import ElementTree - -# Analytical results -def steadyState(Tin, Tout, Rin, Rout, radialCoordinate): - return Tin + (Tout - Tin) * (np.log(radialCoordinate) - np.log(Rin)) / (np.log(Rout) - np.log(Rin)) - -def diffusionFunction(radialCoordinate, Rin, diffusionCoefficient, diffusionTime): - return special.erfc( (radialCoordinate - Rin) / 2.0 / np.sqrt( diffusionCoefficient * diffusionTime ) ) - -def computeTransientTemperature(Tin, Rin, radialCoordinate, thermalDiffusionCoefficient, diffusionTime): - # Ref. Wang and Papamichos (1994), https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/94WR01774 - return Tin * np.sqrt(Rin/radialCoordinate) * diffusionFunction(radialCoordinate, Rin, thermalDiffusionCoefficient, diffusionTime) - -def computeThermalDiffusionCoefficient(thermalConductivity, volumetricHeatCapacity): - return thermalConductivity / volumetricHeatCapacity - -def extractDataFromXMLList(paramList): - # Extract data from a list in XML such as "{ 1, 2, 3}" - return paramList.replace('{', '').replace('}', '').strip().split(',') - -def getWellboreGeometryFromXML(xmlFilePath): - tree = ElementTree.parse(xmlFilePath) - - meshParam = tree.find('Mesh/InternalWellbore') - radii = extractDataFromXMLList( meshParam.get("radius") ) - - Rin = float(radii[0]) - Rout = float(radii[-1]) - - return [Rin, Rout] - -def getLoadingFromXML(xmlFilePath): - tree = ElementTree.parse(xmlFilePath) - fsParams = tree.findall('FieldSpecifications/FieldSpecification') - - for fsParam in fsParams: - if ( (fsParam.get('fieldName') == "pressure") & (fsParam.get('initialCondition') != "1") ): - if fsParam.get('setNames') == "{ rneg }": - Pin = float(fsParam.get('scale')) - if fsParam.get('setNames') == "{ rpos }": - Pout = float(fsParam.get('scale')) - - for fsParam in fsParams: - if ( (fsParam.get('fieldName') == "temperature") & (fsParam.get('initialCondition') != "1") ): - if fsParam.get('setNames') == "{ rneg }": - Tin = float(fsParam.get('scale')) - if fsParam.get('setNames') == "{ rpos }": - Tout = float(fsParam.get('scale')) - - thermalConductivity = float( extractDataFromXMLList( tree.find('Constitutive/SinglePhaseConstantThermalConductivity').get('thermalConductivityComponents') )[0] ) - - volumetricHeatCapacity = float( tree.find('Constitutive/SolidInternalEnergy').get('volumetricHeatCapacity') ) - - permeability = float( extractDataFromXMLList( tree.find('Constitutive/ConstantPermeability').get('permeabilityComponents') )[0] ) - - porosity = float( tree.find('Constitutive/PressurePorosity').get('defaultReferencePorosity') ) - - fluidViscosity = float( tree.find('Constitutive/ThermalCompressibleSinglePhaseFluid').get('defaultViscosity') ) - - fluidCompressibility = float( tree.find('Constitutive/ThermalCompressibleSinglePhaseFluid').get('compressibility') ) - - fluidThermalExpansionCoefficient = float( tree.find('Constitutive/ThermalCompressibleSinglePhaseFluid').get('thermalExpansionCoeff') ) - - return [Pin, Pout, Tin, Tout, thermalConductivity, volumetricHeatCapacity, permeability, porosity, fluidViscosity, fluidCompressibility, fluidThermalExpansionCoefficient] - - -def main(): - - xmlFilePath = "../../../../../../../inputFiles/singlePhaseFlow/thermalCompressible_2d" - - Rin, Rout = getWellboreGeometryFromXML(xmlFilePath+"_benchmark.xml") - - Pin, Pout, Tin, Tout, thermalConductivity, volumetricHeatCapacity, permeability, porosity, fluidViscosity, fluidCompressibility, fluidThermalExpansionCoefficient = getLoadingFromXML(xmlFilePath+"_base.xml") - - plt.figure(figsize=(10,7)) - font = {'size' : 16} - plt.rc('font', **font) - - for chart_idx, idx in enumerate([1, 2, 5, 10]): - # Numerical results - data = pd.read_csv(f'data_{idx}.csv') - radialCoordinate = data['elementCenter:0'] - temperature = data['temperature'] - pressure = data['pressure'] - diffusionTime = data['Time'][0] - - # Analytical results - thermalDiffusionCoefficient = computeThermalDiffusionCoefficient(thermalConductivity, volumetricHeatCapacity) - - T_transient = computeTransientTemperature(Tin, Rin, radialCoordinate, thermalDiffusionCoefficient, diffusionTime) - - # Analytical results of the steady state regime for comparison - T_steadyState = steadyState(Tin, Tout, Rin, Rout, radialCoordinate) - - # Visualization - # Temperature - plt.subplot(2,2,chart_idx+1) - plt.plot( radialCoordinate, temperature, 'k+' , label='GEOSX' ) - plt.plot( radialCoordinate, T_transient, 'r-' , label='Analytic' ) - plt.plot( radialCoordinate, T_steadyState, 'b-' , label='Steady State' ) - - if chart_idx==1: - plt.legend() - - if chart_idx in [2,3]: - plt.xlabel('Radial distance from well center') - - if chart_idx in [0,2]: - plt.ylabel('Temperature (°C)') - - plt.ylim(-10,100) - plt.xlim(0,1.0) - plt.title('t = '+str(diffusionTime)+'(s)') - plt.tight_layout() - - plt.show() - -if __name__ == "__main__": - main() diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/Example.rst b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/Example.rst index fa07f267b26..e17d62c0702 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/Example.rst +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/Example.rst @@ -144,8 +144,8 @@ It is important to remark that the initial effective stress of rock must be set .. literalinclude:: ../../../../../../../inputFiles/wellbore/ThermoPoroElasticWellbore_base.xml :language: xml - :start-after: - :end-before: + :start-after: + :end-before: The initial and boundary conditions for pore pressure are defined in the block below: @@ -208,8 +208,6 @@ Results and benchmark A good agreement between the GEOS results and analytical results for temperature and pore pressure distribution around the wellbore is shown in the figures below: -.. plot:: docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/THM_wellbore_temperature_pressure.py - .. _problemThermoPoroElasticWellbore_Temperature_Pressure_Fig: .. figure:: temperature_pressure.png :align: center @@ -220,8 +218,6 @@ A good agreement between the GEOS results and analytical results for temperature and the validation for the radial displacement around the cased wellbore is shown below: -.. plot:: docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/THM_wellbore_displacement.py - .. _problemThermoPoroElasticWellbore_Displacement_Fig: .. figure:: displacement.png :align: center @@ -232,8 +228,6 @@ and the validation for the radial displacement around the cased wellbore is show The validations of the total radial and hoop stress (tangent stress) components computed by GEOS against reference results are shown in the figure below: -.. plot:: docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/THM_wellbore_stress.py - .. _problemThermoPoroElasticWellbore_Stress_Fig: .. figure:: stress.png :align: center diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/THM_wellbore_displacement.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/THM_wellbore_displacement.py index 6ce4afe8f19..6e0bacc654d 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/THM_wellbore_displacement.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/THM_wellbore_displacement.py @@ -9,9 +9,9 @@ def main(): # Plot GEOSX results hf = h5py.File("displacementHistory.hdf5", 'r') - time = np.array( hf.get('totalDisplacement Time') ) - center = np.array( hf.get('totalDisplacement ReferencePosition') ) - displacement = np.array( hf.get('totalDisplacement') ) + time = np.asarray( hf.get('totalDisplacement Time') ) + center = np.asarray( hf.get('totalDisplacement ReferencePosition') ) + displacement = np.asarray( hf.get('totalDisplacement') ) nNodes = center.shape[1] xCoord = center[0, 0:nNodes, 0] diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/THM_wellbore_stress.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/THM_wellbore_stress.py index fa2179aa8c6..4448fa04bc8 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/THM_wellbore_stress.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/THM_wellbore_stress.py @@ -5,6 +5,8 @@ import h5py from numpy import genfromtxt from xml.etree import ElementTree +import os +import argparse import analyticalResults @@ -13,140 +15,153 @@ def stressRotation(stress, phi_x): return np.dot(np.dot(np.transpose(rotx), stress), rotx) def main(): - # Material properties from input XML file - xmlFilePathPrefix = "../../../../../../../inputFiles/wellbore/ThermoPoroElasticWellbore" - - xmlData = analyticalResults.getDataFromXML(xmlFilePathPrefix) - - bulkModulus = xmlData[2] # drained bulk modulus of the porous medium - thermalExpansionCoefficients = xmlData[4] # drained linear thermal expansion coefficient of the porous medium - grainBulkModulus = xmlData[6] - BiotCoefficient = 1.0 - bulkModulus / grainBulkModulus - - # Get solid stress, time and element center from GEOSX results - stress_field_name = 'rockSolid_stress' - hf_stress = h5py.File('stressHistory_rock.hdf5', 'r') - time = np.array( hf_stress.get(stress_field_name + ' Time') ) - center = np.array( hf_stress.get(stress_field_name + ' elementCenter') ) - stress = np.array( hf_stress.get(stress_field_name) ) - - # Get temperature and pore pressure for computing the total stress - hf_temperature = h5py.File('temperatureHistory_rock.hdf5', 'r') - temperature = np.array( hf_temperature.get('temperature') ) - - hf_pressure = h5py.File('pressureHistory_rock.hdf5', 'r') - pressure = np.array( hf_pressure.get('pressure') ) - - # Compute total stress - stress_xx_total = stress[:,:,0] - BiotCoefficient * pressure - 3 * bulkModulus * thermalExpansionCoefficients * temperature - stress_yy_total = stress[:,:,1] - BiotCoefficient * pressure - 3 * bulkModulus * thermalExpansionCoefficients * temperature - stress_zz_total = stress[:,:,2] - BiotCoefficient * pressure - 3 * bulkModulus * thermalExpansionCoefficients * temperature - stress_yz_total = stress[:,:,3] - stress_xz_total = stress[:,:,4] - stress_xy_total = stress[:,:,5] - - # Coordinate of elemnt center - nElements = center.shape[1] - xCoord = center[0, :, 0] - yCoord = center[0, :, 1] - rCoord = np.sqrt( xCoord*xCoord + yCoord*yCoord ) - - # Compute stress components in cylindrical coordinate system - stress_rr_total = np.zeros(stress_xx_total.shape) - stress_tt_total = np.zeros(stress_xx_total.shape) - - for idx_time in range(stress.shape[0]): - for idx_elem in range(stress.shape[1]): - stressMatrix_cartesian = np.array([[stress_xx_total[idx_time][idx_elem],stress_xy_total[idx_time][idx_elem],stress_xz_total[idx_time][idx_elem]],\ - [stress_xy_total[idx_time][idx_elem],stress_yy_total[idx_time][idx_elem],stress_yz_total[idx_time][idx_elem]],\ - [stress_xz_total[idx_time][idx_elem],stress_yz_total[idx_time][idx_elem],stress_zz_total[idx_time][idx_elem]]]) - - if(yCoord[idx_elem] != 0): - phi_x = np.arctan( xCoord[idx_elem]/yCoord[idx_elem] ) - else: - phi_x = 0 - - stressMatrix_cylindirical = stressRotation(stressMatrix_cartesian, phi_x) - stress_rr_total[idx_time][idx_elem] = stressMatrix_cylindirical[1][1] - stress_tt_total[idx_time][idx_elem] = stressMatrix_cylindirical[0][0] - - # Plot GEOSX results - plt.figure(figsize=(10,5)) - - plt.subplot(1,2,1) - - plt.plot( rCoord, - stress_rr_total[10, :], - 'r+', - label='GEOS: t = 1 (min)') - - plt.plot( rCoord, - stress_rr_total[24, :], - 'b+', - label='GEOS: t = 1 (hour)') - - plt.subplot(1,2,2) - - plt.plot( rCoord, - stress_tt_total[10, :], - 'r+', - label='GEOS: t = 1 (min)') - - plt.plot( rCoord, - stress_tt_total[24, :], - 'b+', - label='GEOS: t = 1 (hour)') - - # Plot analytical results at one minute - t = 60 #s - r_anal, T_anal, p_anal, ur_anal, sig_rr_anal, sig_tt_anal, sig_zz_anal = analyticalResults.analyticalResults(t) - - plt.subplot(1,2,1) - plt.plot( r_anal, - sig_rr_anal, - 'r-', - label='Analytical: t = 1 (min)') - - plt.subplot(1,2,2) - plt.plot( r_anal, - sig_tt_anal, - 'r-', - label='Analytical: t = 1 (min)') - - # Plot analytical results at one hour - t = 3600 #s - r_anal, T_anal, p_anal, ur_anal, sig_rr_anal, sig_tt_anal, sig_zz_anal = analyticalResults.analyticalResults(t) - - plt.subplot(1,2,1) - plt.plot( r_anal, - sig_rr_anal, - 'b-', - label='Analytical: t = 1 (hour)') - - plt.subplot(1,2,2) - plt.plot( r_anal, - sig_tt_anal, - 'b-', - label='Analytical: t = 1 (hour)') - - plt.subplot(1,2,1) - plt.grid() - plt.ylabel('Radial stress [Pa]') - plt.xlabel('Radial coordinate [m]') - plt.xlim(0.1,0.3) - #plt.ylim(0,100) - - plt.subplot(1,2,2) - plt.grid() - plt.ylabel('Tangential stress [Pa]') - plt.xlabel('Radial coordinate [m]') - plt.xlim(0.1,0.3) - #plt.ylim(0,70e6) - plt.legend(loc='lower right') - plt.tight_layout() - plt.savefig('stress.png') - plt.isoff() + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + outputDir = args.outputDir + geosDir = args.geosDir + + # Material properties from input XML file + xmlFilePathPrefix = geosDir + "/inputFiles/wellbore/ThermoPoroElasticWellbore" + + xmlData = analyticalResults.getDataFromXML(xmlFilePathPrefix) + + bulkModulus = xmlData[2] # drained bulk modulus of the porous medium + thermalExpansionCoefficients = xmlData[4] # drained linear thermal expansion coefficient of the porous medium + grainBulkModulus = xmlData[6] + BiotCoefficient = 1.0 - bulkModulus / grainBulkModulus + + # Get solid stress, time and element center from GEOSX results + stress_field_name = 'rockSolid_stress' + hf_stress = h5py.File(outputDir + '/stressHistory_rock.hdf5', 'r') + time = np.asarray( hf_stress.get(stress_field_name + ' Time') ) + center = np.asarray( hf_stress.get(stress_field_name + ' elementCenter') ) + stress = np.asarray( hf_stress.get(stress_field_name) ) + + # Get temperature and pore pressure for computing the total stress + hf_temperature = h5py.File(outputDir + '/temperatureHistory_rock.hdf5', 'r') + temperature = np.asarray( hf_temperature.get('temperature') ) + + hf_pressure = h5py.File(outputDir + '/pressureHistory_rock.hdf5', 'r') + pressure = np.asarray( hf_pressure.get('pressure') ) + + # Compute total stress + stress_xx_total = stress[:,:,0] - BiotCoefficient * pressure - 3 * bulkModulus * thermalExpansionCoefficients * temperature + stress_yy_total = stress[:,:,1] - BiotCoefficient * pressure - 3 * bulkModulus * thermalExpansionCoefficients * temperature + stress_zz_total = stress[:,:,2] - BiotCoefficient * pressure - 3 * bulkModulus * thermalExpansionCoefficients * temperature + stress_yz_total = stress[:,:,3] + stress_xz_total = stress[:,:,4] + stress_xy_total = stress[:,:,5] + + # Coordinate of elemnt center + nElements = center.shape[1] + xCoord = center[0, :, 0] + yCoord = center[0, :, 1] + rCoord = np.sqrt( xCoord*xCoord + yCoord*yCoord ) + + # Compute stress components in cylindrical coordinate system + stress_rr_total = np.zeros(stress_xx_total.shape) + stress_tt_total = np.zeros(stress_xx_total.shape) + + for idx_time in range(stress.shape[0]): + for idx_elem in range(stress.shape[1]): + stressMatrix_cartesian = np.array([[stress_xx_total[idx_time][idx_elem],stress_xy_total[idx_time][idx_elem],stress_xz_total[idx_time][idx_elem]],\ + [stress_xy_total[idx_time][idx_elem],stress_yy_total[idx_time][idx_elem],stress_yz_total[idx_time][idx_elem]],\ + [stress_xz_total[idx_time][idx_elem],stress_yz_total[idx_time][idx_elem],stress_zz_total[idx_time][idx_elem]]]) + + if(yCoord[idx_elem] != 0): + phi_x = np.arctan( xCoord[idx_elem]/yCoord[idx_elem] ) + else: + phi_x = 0 + + stressMatrix_cylindirical = stressRotation(stressMatrix_cartesian, phi_x) + stress_rr_total[idx_time][idx_elem] = stressMatrix_cylindirical[1][1] + stress_tt_total[idx_time][idx_elem] = stressMatrix_cylindirical[0][0] + + # Plot GEOSX results + plt.figure(figsize=(10,5)) + + plt.subplot(1,2,1) + + plt.plot( rCoord, + stress_rr_total[10, :], + 'r+', + label='GEOS: t = 1 (min)') + + plt.plot( rCoord, + stress_rr_total[24, :], + 'b+', + label='GEOS: t = 1 (hour)') + + plt.subplot(1,2,2) + + plt.plot( rCoord, + stress_tt_total[10, :], + 'r+', + label='GEOS: t = 1 (min)') + + plt.plot( rCoord, + stress_tt_total[24, :], + 'b+', + label='GEOS: t = 1 (hour)') + + # Plot analytical results at one minute + t = 60 #s + r_anal, T_anal, p_anal, ur_anal, sig_rr_anal, sig_tt_anal, sig_zz_anal = analyticalResults.analyticalResults(t) + + plt.subplot(1,2,1) + plt.plot( r_anal, + sig_rr_anal, + 'r-', + label='Analytical: t = 1 (min)') + + plt.subplot(1,2,2) + plt.plot( r_anal, + sig_tt_anal, + 'r-', + label='Analytical: t = 1 (min)') + + # Plot analytical results at one hour + t = 3600 #s + r_anal, T_anal, p_anal, ur_anal, sig_rr_anal, sig_tt_anal, sig_zz_anal = analyticalResults.analyticalResults(t) + + plt.subplot(1,2,1) + plt.plot( r_anal, + sig_rr_anal, + 'b-', + label='Analytical: t = 1 (hour)') + + plt.subplot(1,2,2) + plt.plot( r_anal, + sig_tt_anal, + 'b-', + label='Analytical: t = 1 (hour)') + + plt.subplot(1,2,1) + plt.grid() + plt.ylabel('Radial stress [Pa]') + plt.xlabel('Radial coordinate [m]') + plt.xlim(0.1,0.3) + #plt.ylim(0,100) + + plt.subplot(1,2,2) + plt.grid() + plt.ylabel('Tangential stress [Pa]') + plt.xlabel('Radial coordinate [m]') + plt.xlim(0.1,0.3) + #plt.ylim(0,70e6) + plt.legend(loc='lower right') + plt.tight_layout() + plt.savefig('stress.png') + plt.isoff() if __name__ == "__main__": - main() - + main() + diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/THM_wellbore_temperature_pressure.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/THM_wellbore_temperature_pressure.py index 9d89633ed58..b1c612e3861 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/THM_wellbore_temperature_pressure.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/THM_wellbore_temperature_pressure.py @@ -10,12 +10,12 @@ def main(): # Plot GEOSX results hf = h5py.File("temperatureHistory_rock.hdf5", 'r') - time = np.array( hf.get('temperature Time') ) - center = np.array( hf.get('temperature elementCenter') ) - temperature = np.array( hf.get('temperature') ) + time = np.asarray( hf.get('temperature Time') ) + center = np.asarray( hf.get('temperature elementCenter') ) + temperature = np.asarray( hf.get('temperature') ) hf = h5py.File("pressureHistory_rock.hdf5", 'r') - pressure = np.array( hf.get('pressure') ) + pressure = np.asarray( hf.get('pressure') ) nElements = center.shape[1] xCoord = center[0, 0:nElements, 0] diff --git a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/analyticalResults.py b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/analyticalResults.py index c4ae5d7c182..938f88b0700 100644 --- a/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/analyticalResults.py +++ b/src/docs/sphinx/advancedExamples/validationStudies/wellboreProblems/thermoPoroElasticWellbore/analyticalResults.py @@ -34,12 +34,12 @@ def getDataFromXML(xmlFilePathPrefix): defaultShearModulus = float( tree.find('Constitutive/ElasticIsotropic').get('defaultShearModulus') ) defaultDrainedLinearTEC = float( tree.find('Constitutive/ElasticIsotropic').get('defaultDrainedLinearTEC') ) defaultReferencePorosity = float( tree.find('Constitutive/BiotPorosity').get('defaultReferencePorosity') ) - grainBulkModulus = float( tree.find('Constitutive/BiotPorosity').get('grainBulkModulus') ) + grainBulkModulus = float( tree.find('Constitutive/BiotPorosity').get('defaultGrainBulkModulus') ) fluidCompressibility = float( tree.find('Constitutive/ThermalCompressibleSinglePhaseFluid').get('compressibility') ) fluidViscosity = float( tree.find('Constitutive/ThermalCompressibleSinglePhaseFluid').get('defaultViscosity') ) fluidThermalExpansionCoefficient = float( tree.find('Constitutive/ThermalCompressibleSinglePhaseFluid').get('thermalExpansionCoeff') ) - thermalConductivity = float( extractDataFromXMLList( tree.find('Constitutive/SinglePhaseConstantThermalConductivity').get('thermalConductivityComponents') )[0] ) - volumetricHeatCapacity = float( tree.find('Constitutive/SolidInternalEnergy').get('volumetricHeatCapacity') ) + thermalConductivity = float( extractDataFromXMLList( tree.find('Constitutive/SinglePhaseThermalConductivity').get('defaultThermalConductivityComponents') )[0] ) + volumetricHeatCapacity = float( tree.find('Constitutive/SolidInternalEnergy').get('referenceVolumetricHeatCapacity') ) permeability = float( extractDataFromXMLList( tree.find('Constitutive/ConstantPermeability').get('permeabilityComponents') )[0] ) return [ri, Ti, drainedBulkModulusRock, defaultShearModulus, defaultDrainedLinearTEC, defaultReferencePorosity, grainBulkModulus, fluidCompressibility, fluidViscosity, fluidThermalExpansionCoefficient, permeability, thermalConductivity, volumetricHeatCapacity] diff --git a/src/docs/sphinx/basicExamples/Index.rst b/src/docs/sphinx/basicExamples/Index.rst index 0c9e9b5e8f5..af43ba213fe 100644 --- a/src/docs/sphinx/basicExamples/Index.rst +++ b/src/docs/sphinx/basicExamples/Index.rst @@ -21,3 +21,4 @@ Basic Examples + diff --git a/src/docs/sphinx/basicExamples/co2Injection/Example.rst b/src/docs/sphinx/basicExamples/co2Injection/Example.rst index cec5f2b464c..d73796de79b 100644 --- a/src/docs/sphinx/basicExamples/co2Injection/Example.rst +++ b/src/docs/sphinx/basicExamples/co2Injection/Example.rst @@ -134,8 +134,9 @@ The **TwoPointFluxApproximation** is chosen for the fluid equation discretizatio Element regions --------------- -We define a **CellElementRegion** pointing to the cell block defining the reservoir mesh, and a **WellElementRegion** for the well. +We define a **CellElementRegion** pointing to all reservoir mesh cells, and a **WellElementRegion** for the well. The two regions contain a list of constitutive model names. +The keyword "all" is used here to automatically select all cells of the mesh. .. literalinclude:: ../../../../../inputFiles/compositionalMultiphaseWell/simpleCo2InjTutorial_base.xml :language: xml @@ -181,12 +182,12 @@ The *pvtgas.txt* and *pvtliquid.txt* files define the models used to compute the .. code:: - DensityFun SpanWagnerCO2Density 1e6 1.5e7 5e4 94 96 1 - ViscosityFun FenghourCO2Viscosity 1e6 1.5e7 5e4 94 96 + DensityFun SpanWagnerCO2Density 1.0e5 7.5e7 1e5 285.15 395.15 5 + ViscosityFun FenghourCO2Viscosity 1.0e5 7.5e7 1e5 285.15 395.15 5 .. code:: - DensityFun PhillipsBrineDensity 1e6 1.5e7 5e4 94 96 1 0 + DensityFun PhillipsBrineDensity 1.0e5 7.5e7 1e5 285.15 395.15 5 0 ViscosityFun PhillipsBrineViscosity 0 In these files, the first keyword of each line is an identifier for the model type (either a density or a viscosity model). @@ -218,6 +219,10 @@ Here, these fields are homogeneous, except for the permeability field that is ta .. _Outputs_tag_co2_field_case: +.. warning:: + This XML file example does not take into account elevation when imposing the intial pressure with ``initialPressure``. + Consider using a "HydrostraticEquilibrium" for a closer answer to modeled physical processes. + ------ Output ------ @@ -260,13 +265,13 @@ The simulation can be launched with 4 cores using MPI-parallelism: .. code-block:: console - mpirun -np 4 geosx -i simpleCo2InjTutorial.xml -x 1 -y 1 -z 4 + mpirun -np 4 geosx -i simpleCo2InjTutorial_smoke.xml -x 1 -y 1 -z 4 A restart from a checkpoint file `simpleCo2InjTutorial_restart_000000024.root` is always available thanks to the following command line : .. code-block:: console - mpirun -np 4 geosx -i simpleCo2InjTutorial.xml -r simpleCo2InjTutorial_restart_000000024 -x 1 -y 1 -z 4 + mpirun -np 4 geosx -i simpleCo2InjTutorial_smoke.xml -r simpleCo2InjTutorial_restart_000000024 -x 1 -y 1 -z 4 The output then shows the loading of HDF5 restart files by each core. diff --git a/src/docs/sphinx/basicExamples/multiphaseFlow/Example.rst b/src/docs/sphinx/basicExamples/multiphaseFlow/Example.rst index b0a8183bfd6..341e7a22d46 100644 --- a/src/docs/sphinx/basicExamples/multiphaseFlow/Example.rst +++ b/src/docs/sphinx/basicExamples/multiphaseFlow/Example.rst @@ -82,7 +82,7 @@ Mesh ------- In this simulation, we define a simple mesh generated internally using the **InternalMesh** generator, as -illustrated in the previous examples. +illustrated in the first tutorial (:ref:`TutorialSinglePhaseFlowWithInternalMesh`). The mesh dimensions and cell sizes are chosen to be those specified in the SPE10 test case, but are limited to the two bottom layers. The mesh description must be done in meters. @@ -173,13 +173,12 @@ Reservoir region In the **ElementRegions** XML block, we define a **CellElementRegion** named ``reservoir`` corresponding to the reservoir mesh. -The attribute ``cellBlocks`` is set to ``block`` to point this element region -to the hexahedral mesh defined internally. +``cellBlocks`` is set to ``{ * }`` to automatically target every cells of the mesh. The **CellElementRegion** must also point to the constitutive models that are used to update the dynamic rock and fluid properties in the cells of the reservoir mesh. The names ``fluid``, ``rock``, and ``relperm`` used for this in the ``materialList`` -correspond to the attribute ``name`` of the **Constitutive** block. +correspond to the **Constitutive** blocks with the coresponding names. .. literalinclude:: ../../../../../inputFiles/compositionalMultiphaseFlow/benchmarks/SPE10/deadOilSpe10Layers84_85_base_iterative.xml :language: xml diff --git a/src/docs/sphinx/basicExamples/multiphaseFlowWithWells/Example.rst b/src/docs/sphinx/basicExamples/multiphaseFlowWithWells/Example.rst index 0c1d7be2a45..7fb95a4a927 100644 --- a/src/docs/sphinx/basicExamples/multiphaseFlowWithWells/Example.rst +++ b/src/docs/sphinx/basicExamples/multiphaseFlowWithWells/Example.rst @@ -119,48 +119,71 @@ Mesh definition and well geometry In the presence of wells, the **Mesh** block of the XML input file includes two parts: - a sub-block **VTKMesh** defining the reservoir mesh (see :ref:`TutorialSinglePhaseFlowExternalMesh` for more on this), - - a collection of sub-blocks **InternalWell** defining the geometry of the wells. + - a collection of sub-blocks defining the geometry of the wells. The reservoir mesh is imported from a ``.vtu`` file that contains the mesh geometry and also includes the permeability values in the x, y, and z directions. These quantities must be specified using the metric unit system, i.e., in meters for the well geometry and square meters for the permeability field. -We note that the mesh file only contains the active cells, so there is no keyword -needed in the XML file to define them. +We note that the mesh file only contains active cells, so there is no keyword +needed in the XML file to define them. + +.. image:: egg_model.png + :width: 400px + :align: center + +.. literalinclude:: ../../../../../inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_benchmark.xml + :language: xml + :start-after: + :end-before: + + +.. _Events_tag_dead_oil_egg_model: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**InternalWell** sub-blocks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Each well is defined internally (i.e., not imported from a file) in a separate **InternalWell** -XML sub-block. An **InternalWell** sub-block must point to the reservoir mesh that the well perforates -using the attribute ``meshName``, to the region corresponding to this well using the attribute +XML sub-block. An **InternalWell** sub-block must point to the region corresponding to this well using the attribute ``wellRegionName``, and to the control of this well using the attribute ``wellControl``. -Each block **InternalWell** must point to the reservoir mesh -(using the attribute ``meshName``), the corresponding well region (using -the attribute ``wellRegionName``), and the corresponding well control -(using the attribute ``wellControlName``). Each well is defined using a vertical polyline going through the seven layers of the -mesh, with a perforation in each layer. +mesh with a perforation in each layer. The well placement implemented here follows the pattern of the original test case. The well geometry must be specified in meters. The location of the perforations is found internally using the linear distance along the wellbore -from the top of the well, specified by the attribute ``distanceFromHead``. +from the top of the well specified by the attribute ``distanceFromHead``. It is the responsibility of the user to make sure that there is a perforation in the bottom cell of the well mesh otherwise an error will be thrown and the simulation will terminate. For each perforation, the well transmissibility factors employed to compute the perforation rates are calculated internally using the Peaceman formulation. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**VTKWell** sub-blocks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. image:: egg_model.png - :width: 400px - :align: center +Each well is loaded from a file in a separate **VTKWell** +XML sub-block. A **VTKWell** sub-block must point to the region corresponding to this well using the attribute +``wellRegionName``, and to the control of this well using the attribute ``wellControl``. -.. literalinclude:: ../../../../../inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_benchmark.xml - :language: xml - :start-after: - :end-before: +Each well is defined using a vertical VTK polyline going through the seven layers of the +mesh with a perforation in each layer. +The well placement implemented here follows the pattern of the original test case. +The well geometry must be specified in meters. +The location of perforations is found internally using the linear distance along the wellbore +from the top of the well specified by the attribute ``distanceFromHead``. +It is the responsibility of the user to make sure that there is a perforation in the bottom cell +of the well mesh otherwise an error will be thrown and the simulation will terminate. +For each perforation, the well transmissibility factors employed to compute the perforation rates are calculated +internally using the Peaceman formulation. -.. _Events_tag_dead_oil_egg_model: +.. literalinclude:: ../../../../../inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEggVTK_benchmark.xml + :language: xml + :start-after: + :end-before: ------------------------ Events @@ -181,11 +204,11 @@ by the attribute ``timeFrequency``. Here, we choose to output the results using the VTK format (see :ref:`TutorialSinglePhaseFlowExternalMesh` for a example that uses the Silo output file format). The ``target`` attribute must point to the **VTK** sub-block of the **Outputs** -block (defined at the end of the XML file) by name (here, ``vtkOutput``). +block defined at the end of the XML file by its user-specified name (here, ``vtkOutput``). -We define the events involved in the collection and output of the well production rates following the procedure defined in :ref:`TasksManager`. -The time history collection events trigger the collection of the well rates at the desired frequency, while the time history output events trigger the output of the HDF5 files containing the time series. -These events point by name to the corresponding blocks of the **Tasks** and **Outputs** XML blocks, respectively. Here, these names are ``wellRateCollection1`` and ``timeHistoryOutput1``. +We define the events involved in the collection and output of well production rates following the procedure defined in :ref:`TasksManager`. +The time-history collection events trigger the collection of well rates at the desired frequency, while the time-history output events trigger the output of HDF5 files containing the time series. +These events point by name to the corresponding blocks of the **Tasks** and **Outputs** XML blocks. Here, these names are ``wellRateCollection1`` and ``timeHistoryOutput1``. .. literalinclude:: ../../../../../inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_iterative.xml :language: xml @@ -199,7 +222,7 @@ These events point by name to the corresponding blocks of the **Tasks** and **Ou Numerical methods ---------------------------------- -In the ``NumericalMethods`` XML block, we instruct GEOS to use a TPFA finite-volume +In the ``NumericalMethods`` XML block, we instruct GEOS to use a TPFA (Two-Point Flux Approximation) finite-volume numerical scheme. This part is similar to the corresponding section of :ref:`TutorialDeadOilBottomLayersSPE10`, and has been adapted to match the specifications of the Egg model. @@ -215,15 +238,12 @@ This part is similar to the corresponding section of :ref:`TutorialDeadOilBottom Reservoir and well regions ----------------------------------- -In this section of the input file, we follow the procedure already described in +In this section of the input file, we follow the procedure described in :ref:`TutorialDeadOilBottomLayersSPE10` for the definition of the reservoir region with multiphase constitutive models. We associate a **CellElementRegion** named ``reservoir`` to the reservoir mesh. -Since we have imported a mesh with one region consisting of hexahedral cells, we -must set the attribute ``cellBlocks`` to ``hexahedra``. - -.. note:: - If you use a name that is not ``hexahedra`` for this attribute, GEOS will throw an error at the beginning of the simulation. +Since we have imported a mesh with only one region, we can set ``cellBlocks`` to ``{ * }`` +(we could also set ``cellBlocks`` to ``{ hexahedra }`` as the mesh has only hexahedral cells). We also associate a **WellElementRegion** to each well. As the **CellElementRegion**, it contains a ``materialList`` that must point (by name) to the constitutive models @@ -421,7 +441,7 @@ We can load this file into Paraview directly and visualize results: :width: 45% We have instructed GEOS to output the time series of rates for each producer. -The data contained in the corresponding hdf5 files can be extracted and plotted +The data contained in the corresponding HDF5 files can be extracted and plotted as shown below. .. plot:: docs/sphinx/basicExamples/multiphaseFlowWithWells/multiphaseFlowWithWellsFigure.py diff --git a/src/docs/sphinx/basicExamples/multiphaseFlowWithWells/multiphaseFlowWithWellsFigure.py b/src/docs/sphinx/basicExamples/multiphaseFlowWithWells/multiphaseFlowWithWellsFigure.py index 0c0cf09bae4..7ef4dd4c370 100644 --- a/src/docs/sphinx/basicExamples/multiphaseFlowWithWells/multiphaseFlowWithWellsFigure.py +++ b/src/docs/sphinx/basicExamples/multiphaseFlowWithWells/multiphaseFlowWithWellsFigure.py @@ -18,9 +18,9 @@ def main(): # Read HDF5 hf = h5py.File(hdf5FilePath, 'r') time = hf.get('Time') - time = np.array(time) + time = np.asarray(time) massRate = hf.get('wellElementMixtureConnectionRate') - massRate = np.array(massRate) + massRate = np.asarray(massRate) # Some comments about the computation of the volumetric rate here: # A proper oil rate constraint for individual wells is currently being implemented diff --git a/src/docs/sphinx/basicExamples/poromechanics/poromechanicsFigure.py b/src/docs/sphinx/basicExamples/poromechanics/poromechanicsFigure.py index b7eb23d2e91..43e76a3a72b 100644 --- a/src/docs/sphinx/basicExamples/poromechanics/poromechanicsFigure.py +++ b/src/docs/sphinx/basicExamples/poromechanics/poromechanicsFigure.py @@ -5,6 +5,8 @@ import xml.etree.ElementTree as ElementTree from mpmath import * import math +import os +import argparse class terzaghi: @@ -60,7 +62,7 @@ def getHydromechanicalParametersFromXML(xmlFilePath): E = hydromechanicalParameters["youngModulus"] nu = hydromechanicalParameters["poissonRation"] K = E / 3.0 / (1.0 - 2.0 * nu) - Kg = float(param2.get("grainBulkModulus")) + Kg = float(param2.get("defaultGrainBulkModulus")) hydromechanicalParameters["biotCoefficient"] = 1.0 - K / Kg hydromechanicalParameters["porosity"] = float(param2.get("defaultReferencePorosity")) @@ -91,10 +93,23 @@ def getDomainMaxMinXCoordFromXML(xmlFilePath): def main(): + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + outputDir = args.outputDir + geosDir = args.geosDir + # File path - hdf5FilePath = "pressure_history.hdf5" - xmlBaseFilePath = "../../../../../inputFiles/poromechanics/PoroElastic_Terzaghi_base_direct.xml" - xmlSmokeFilePath = "../../../../../inputFiles/poromechanics/PoroElastic_Terzaghi_smoke.xml" + hdf5FilePath = outputDir + "/pressure_history.hdf5" + xmlBaseFilePath = geosDir + "/inputFiles/poromechanics/PoroElastic_Terzaghi_base_direct.xml" + xmlSmokeFilePath = geosDir + "/inputFiles/poromechanics/PoroElastic_Terzaghi_smoke.xml" # Read HDF5 hf = h5py.File(hdf5FilePath, 'r') diff --git a/src/docs/sphinx/basicExamples/triaxialDriver/triaxialDriverFigure.py b/src/docs/sphinx/basicExamples/triaxialDriver/triaxialDriverFigure.py index 8de7daa7ca9..b46ec1f300f 100755 --- a/src/docs/sphinx/basicExamples/triaxialDriver/triaxialDriverFigure.py +++ b/src/docs/sphinx/basicExamples/triaxialDriver/triaxialDriverFigure.py @@ -5,6 +5,8 @@ import math from math import sin, cos, tan, exp, atan import xml.etree.ElementTree as ElementTree +import os +import argparse def yieldSurface(xmlFilePath, mechanicalParameters): @@ -166,14 +168,27 @@ def getMechanicalParametersFromXML(xmlFilePath): def main(): + + # Initialize the argument parser + parser = argparse.ArgumentParser(description="Script to generate figure from tutorial.") + + # Add arguments to accept individual file paths + parser.add_argument('--geosDir', help='Path to the GEOS repository ', default='../../../../..') + parser.add_argument('--outputDir', help='Path to output directory', default='.') + + # Parse the command-line arguments + args = parser.parse_args() + # File path - xmlFilePath = "../../../../../inputFiles/triaxialDriver/triaxialDriver_ExtendedDruckerPrager_basicExample.xml" + outputDir = args.outputDir + geosDir = args.geosDir + xmlFilePath = geosDir + "/inputFiles/triaxialDriver/triaxialDriver_ExtendedDruckerPrager_basicExample.xml" # Extract info from XML mechanicalParameters = getMechanicalParametersFromXML(xmlFilePath) # Load GEOSX results - path = "simulationResults.txt" + path = outputDir + "/simulationResults.txt" time, ax_strain, ra_strain1, ra_strain2, ax_stress, ra_stress1, ra_stress2, newton_iter, residual_norm = np.loadtxt( path, skiprows=5, unpack=True) p_num = -(ax_stress + 2.0 * ra_stress1) / 3.0 / 1.0e6 diff --git a/src/docs/sphinx/buildGuide/AppleMacOS.rst b/src/docs/sphinx/buildGuide/AppleMacOS.rst new file mode 100644 index 00000000000..ac2be331852 --- /dev/null +++ b/src/docs/sphinx/buildGuide/AppleMacOS.rst @@ -0,0 +1,93 @@ +.. _AppleMacOS: + +Building Apple MacOS +==================== + +Install homebrew +---------------- +Taken from the [homebrew website](https://brew.sh) +.. code-block:: + + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + (echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> ~/.zprofile + + note: this is the command for `zsh`. Other shells will require different commands. Homebrew should provide the correct command after install is complete. + eval "$(/opt/homebrew/bin/brew shellenv)" + +Install packages using homebrew +------------------------------- + +.. code-block:: + + brew install bison cmake gfortran git-lfs open-mpi lapack python3 ninja m4 + echo 'export PATH="/opt/homebrew/opt/bison/bin:$PATH"' >> ~/.zshrc + echo 'export PATH="/opt/homebrew/opt/m4/bin:$PATH"' >> ~/.zshrc + git lfs install + +Clone GEOS +---------- + +.. code-block:: + + git clone git@github.com:GEOS-DEV/GEOS.git + cd GEOS + git submodule init + git submodule update + cd .. + +Clone thirdPartyLibs +-------------------- + +.. code-block:: + + git clone git@github.com:GEOS-DEV/thirdPartyLibs.git + cd thirdPartyLibs + git submodule init + git submodule update + git lfs pull + + +Configure and build thirdPartyLibs +---------------------------------- + +.. code-block:: + + python3 scripts/config-build.py -hc ../GEOS/host-configs/apple/macOS_arm.cmake -bt Release + +You will get a warning you can ignore + +.. code-block:: + + CMake Warning at /Users/settgast1/Codes/geos/GEOS/host-configs/tpls.cmake:10 (message): + 'GEOS_TPL_DIR' does not exist. + + +Continue with the build + +.. code-block:: + + cd build-macOS_arm-release + make + +You will get an error at the end...you can ignore it. + +.. code-block:: + + [100%] Linking CXX executable ../../../tests/blt_mpi_smoke + ld: warning: -commons use_dylibs is no longer supported, using error treatment instead + ld: file not found: @rpath/libquadmath.0.dylib for architecture arm64 + clang: error: linker command failed with exit code 1 (use -v to see invocation) + make[2]: *** [tests/blt_mpi_smoke] Error 1 + make[1]: *** [blt/tests/smoke/CMakeFiles/blt_mpi_smoke.dir/all] Error 2 + make: *** [all] Error 2 + + +Build GEOS +---------- + +.. code-block:: + + cd ../../GEOS + python3 scripts/config-build.py -hc host-configs/apple/macOS_arm.cmake -bt Release --ninja + cd build-macOS_arm-release + ninja geosx diff --git a/src/docs/sphinx/buildGuide/BuildProcess.rst b/src/docs/sphinx/buildGuide/BuildProcess.rst index 37a5d66d9d3..cd3910c451c 100644 --- a/src/docs/sphinx/buildGuide/BuildProcess.rst +++ b/src/docs/sphinx/buildGuide/BuildProcess.rst @@ -75,10 +75,10 @@ Option Default Explanation ``ENABLE_TOTALVIEW_OUTPUT`` ``OFF`` Enables TotalView debugger custom view of GEOS data structures ``ENABLE_COV`` ``OFF`` Enables code coverage ``GEOS_ENABLE_TESTS`` ``ON`` Enables unit testing targets -``GEOSX_LA_INTERFACE`` ``Hypre`` Choiсe of Linear Algebra backend (Hypre/Petsc/Trilinos) -``GEOSX_BUILD_OBJ_LIBS`` ``ON`` Use CMake Object Libraries build -``GEOSX_BUILD_SHARED_LIBS`` ``OFF`` Build ``geosx_core`` as a shared library instead of static -``GEOSX_PARALLEL_COMPILE_JOBS`` Max. number of compile jobs (when using Ninja), in addition to ``-j`` flag -``GEOSX_PARALLEL_LINK_JOBS`` Max. number of link jobs (when using Ninja), in addition to ``-j`` flag -``GEOSX_INSTALL_SCHEMA`` ``ON`` Enables schema generation and installation +``GEOS_LA_INTERFACE`` ``Hypre`` Choiсe of Linear Algebra backend (Hypre/Petsc/Trilinos) +``GEOS_BUILD_OBJ_LIBS`` ``ON`` Use CMake Object Libraries build +``GEOS_BUILD_SHARED_LIBS`` ``OFF`` Build ``geosx_core`` as a shared library instead of static +``GEOS_PARALLEL_COMPILE_JOBS`` Max. number of compile jobs (when using Ninja), in addition to ``-j`` flag +``GEOS_PARALLEL_LINK_JOBS`` Max. number of link jobs (when using Ninja), in addition to ``-j`` flag +``GEOS_INSTALL_SCHEMA`` ``ON`` Enables schema generation and installation =============================== ========= ============================================================================== diff --git a/src/docs/sphinx/buildGuide/ContinuousIntegration.rst b/src/docs/sphinx/buildGuide/ContinuousIntegration.rst index 3dd72e595d2..3740fe464a3 100644 --- a/src/docs/sphinx/buildGuide/ContinuousIntegration.rst +++ b/src/docs/sphinx/buildGuide/ContinuousIntegration.rst @@ -41,7 +41,7 @@ The .. code-block:: sh - GEOSX_TPL_DIR + GEOS_TPL_DIR variable contains the absolute path of the installation root directory of the third party libraries. GEOS must use it when building. diff --git a/src/docs/sphinx/buildGuide/Index.rst b/src/docs/sphinx/buildGuide/Index.rst index afd042d9561..1ed27e84f1f 100644 --- a/src/docs/sphinx/buildGuide/Index.rst +++ b/src/docs/sphinx/buildGuide/Index.rst @@ -18,3 +18,5 @@ Welcome to the GEOS build guide. SpackUberenv ContinuousIntegration + + AppleMacOS diff --git a/src/docs/sphinx/buildGuide/Prerequisites.rst b/src/docs/sphinx/buildGuide/Prerequisites.rst index 78251f997d5..9bbe5ee6174 100644 --- a/src/docs/sphinx/buildGuide/Prerequisites.rst +++ b/src/docs/sphinx/buildGuide/Prerequisites.rst @@ -10,10 +10,10 @@ List of prerequisites Minimal requirements: -- `CMake `_ build system generator (3.17+). +- `CMake `_ build system generator (3.23.1+). - build tools (`GNU make `_ or `ninja `_ on Linux, XCode on MacOS). -- a C++ compiler with full c++17 standard support (`gcc `_ 8.3+ or `clang `_ 10.0+ are recommended). -- `python `_ (2.7+ or 3.6+). +- a C++ compiler with full c++17 standard support (`gcc `_ 12+ or `clang `_ 13.0+ are recommended). +- `python `_ 3.9-3.11 (versions 3.12+ are untested). - :code:`zlib`, :code:`blas` and :code:`lapack` libraries - any compatible MPI runtime and compilers (if building with MPI) diff --git a/src/docs/sphinx/developerGuide/Contributing/Dockerfile-remote-dev.example b/src/docs/sphinx/developerGuide/Contributing/Dockerfile-remote-dev.example index 15e46a7cf90..1c5f4b9628d 100644 --- a/src/docs/sphinx/developerGuide/Contributing/Dockerfile-remote-dev.example +++ b/src/docs/sphinx/developerGuide/Contributing/Dockerfile-remote-dev.example @@ -47,12 +47,20 @@ RUN touch /root/.ssh/environment &&\ echo "MPIEXEC=${MPIEXEC}" >> /root/.ssh/environment &&\ echo "OMPI_CC=${CC}" >> /root/.ssh/environment &&\ echo "OMPI_CXX=${CXX}" >> /root/.ssh/environment &&\ - echo "GEOSX_TPL_DIR=${GEOSX_TPL_DIR}" >> /root/.ssh/environment + echo "GEOS_TPL_DIR=${GEOS_TPL_DIR}" >> /root/.ssh/environment # If you decide to work as root in your container, you may consider adding # `OMPI_ALLOW_RUN_AS_ROOT=1` and `OMPI_ALLOW_RUN_AS_ROOT_CONFIRM=1` # to your environment. This will prevent you from adding the `--allow-run-as-root` option # when you run mpi. Of course, weigh the benefits and risks and make your own decision. +# In case you want to use `sccache` (https://github.com/mozilla/sccache) to make your builds faster, +# you may configure the `sccache` config file at your convenience. +# Meanwhile, we provide here a simple local configuration. +RUN mkdir -p ${HOME}/.config/sccache +RUN printf '[cache.disk]\n\ +dir = "/tmp/.cache/sccache"\n\ +size = 3221225472 # 3GB\n' > ${HOME}/.config/sccache/config + # Default ssh port 22 is exposed. For _development_ purposes, # it can be useful to expose other ports for remote tools. EXPOSE 22 11111 64010-64020 diff --git a/src/docs/sphinx/developerGuide/Contributing/Doxygen.rst b/src/docs/sphinx/developerGuide/Contributing/Doxygen.rst index 8a25b96ee0c..1b240c99811 100644 --- a/src/docs/sphinx/developerGuide/Contributing/Doxygen.rst +++ b/src/docs/sphinx/developerGuide/Contributing/Doxygen.rst @@ -239,4 +239,18 @@ Example Current Doxygen ==================================== -`Link to Doxygen <../../../doxygen_output/html/classes.html>`__ +`Link to Doxygen Class directory <../../../../doxygen_output/html/classes.html>`__ + +Direct links to some useful class documentation: + +`Group API <../../../../doxygen_output/html/classgeos_1_1data_repository_1_1_group.html>`_ + +`Wrapper API <../../../../doxygen_output/html/classgeos_1_1data_repository_1_1_wrapper.html>`_ + +`ObjectManagerBase API <../../../../doxygen_output/html/classgeos_1_1_object_manager_base.html>`_ + +`MeshLevel API <../../../../doxygen_output/html/classgeos_1_1_mesh_level.html>`_ + +`NodeManager API <../../../../doxygen_output/html/classgeos_1_1_node_manager.html>`_ + +`FaceManager API <../../../../doxygen_output/html/classgeos_1_1_face_manager.html>`_ \ No newline at end of file diff --git a/src/docs/sphinx/developerGuide/Contributing/GitWorkflow.rst b/src/docs/sphinx/developerGuide/Contributing/GitWorkflow.rst index ffc7eb48097..c3cd039dc12 100644 --- a/src/docs/sphinx/developerGuide/Contributing/GitWorkflow.rst +++ b/src/docs/sphinx/developerGuide/Contributing/GitWorkflow.rst @@ -333,6 +333,22 @@ Once you are satisfied with your work on the branch, you may promote the PR out draft status, which will allow our integrated testing suite to execute on the PR branch to ensure all tests are passing prior to merging. +.. note:: + The title of a PR has to follow the `conventional commit specification `_. + The allowed prefixes are: + + - feat: A new feature + - fix: A bug fix, + - docs: Documentation only changes, + - style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc), + - refactor: A code change that neither fixes a bug nor adds a feature, + - perf: A code change that improves performance, + - test: Adding missing tests or correcting existing tests, + - build: Changes that affect the build system or external dependencies (example scopes: cmake), + - ci: Changes to our CI configuration files and scripts (example scopes: github), + - chore: Other changes that don't modify src or test files, + - revert: Reverts a previous commit, + Once the tests are passing -- or in some cases immediately -- add the `flag: ready for review` label to the PR, and be sure to tag any relevant developers to review the PR. The PR *must* be approved by reviewers in order to be merged. diff --git a/src/docs/sphinx/developerGuide/Contributing/InstallWin.rst b/src/docs/sphinx/developerGuide/Contributing/InstallWin.rst index 6fa4b1d6d55..0b9275a9584 100644 --- a/src/docs/sphinx/developerGuide/Contributing/InstallWin.rst +++ b/src/docs/sphinx/developerGuide/Contributing/InstallWin.rst @@ -1,6 +1,6 @@ .. _InstallWin: -[Unsupported] Installing GEOS on Windows machines using Docker +[Best effort] Installing GEOS on Windows machines using Docker ================================================================= In this section, we will install GEOS on a Windows machine using a ``Docker`` container with a precompiled version of diff --git a/src/docs/sphinx/developerGuide/Contributing/IntegratedTests.rst b/src/docs/sphinx/developerGuide/Contributing/IntegratedTests.rst index f2e355372c2..4841a4fab43 100644 --- a/src/docs/sphinx/developerGuide/Contributing/IntegratedTests.rst +++ b/src/docs/sphinx/developerGuide/Contributing/IntegratedTests.rst @@ -6,57 +6,112 @@ Integrated Tests About ================================= -*integratedTests* is a submodule of *GEOS* residing at the top level of the directory structure. -It defines a set of tests that will run *GEOS* with various *.xml* files and partitioning schemes using the `Automated Test System `_ (ATS). -For each scenario, test performance is evaluated by comparing output files to baselines recorded in this repository. +The GEOS integrated test system leverages the `Automated Test System `_ (ATS) and `GEOS ATS `_ packages to run various combinations of input files and machine configurations. +The output of these runs are then compared to baseline files and/or analytic solutions to guarantee the accuracy of the code. Structure ================================= -The *integratedTests* repository includes a python package (*integratedTests/scripts/geos_ats_package*) and a directory containing test definitions (*integratedTests/tests/allTests*). -A typical test directory will include an *.ats* file, which defines the behavior of tests or points to child test directories, symbolic links to any required *.xml* files, and a directory containing baseline files. +GEOS integrated tests are defined in the *GEOS/inputFiles* directory, and are organized into folders based on the physical processes being tested. +A test folder can contain any number of *.ats* configuration files, *.xml* input files, and supporting inputs (tables files, meshes, etc.). .. code-block:: sh - - integratedTests/ - - scripts/ - - geos_ats_package - - tests/ - - allTests/ - - main.ats/ - - sedov/ - - baselines/ - - sedov_XX/ - - - - sedov.ats - - sedov.xml + - inputFiles/ + - main.ats/ + - solidMechanics/ + - sedov.ats + - sedov.xml + - etc. + - .integrated_tests.yaml -High level integrated test results are recorded in the GEOS build directory: */path/to/GEOS/build-xyz/integratedTests/TestsResults*. -These include *.log* and *.err* files for each test and a *test_results.html* summary file, which can be inspected in your browser. +Test baselines are stored as *.tar.gz* archive and share the same directory structure as *GEOS/inputFiles*. +During test execution, the *geos_ats* package will fetch and unpack any necessary baselines described in the top-level *.integrated_tests.yaml* configuration file. + + + +How to Run the Tests +================================= + +GEOS CI Pipeline +--------------------------------- + +In most cases, developers will be able to rely on the integrated tests that are run as part of the GEOS CI Pipeline. +These can be triggered if the **ci: run integrated tests** label is selected for a pull request (this can be added from the right-hand panel on PR page). + +To inspect the results of CI tests, select the *Checks* tab from the top of the pull request and then select *run_integrated_tests/build_test_deploy* from the left-hand panel. + + +.. image:: integrated_test_location_pr_a.png + :width: 400px + + +.. image:: integrated_test_location_pr_b.png + :width: 400px + + +This page will show the full output of GEOS build process and the integrated test suite. +At the bottom of this page, the logs will contain a summary of the test results and a list of any ignored/failed tests. + + +.. code-block:: sh + + ======================= + Integrated test results + ======================= + expected: 0 + created: 0 + batched: 0 + filtered: 104 + skipped: 0 + running: 0 + passed: 215 + timedout: 0 (3 ignored) + halted: 0 + lsferror: 0 + failed: 0 + ======================= + Ignored tests + ======================= + pennyShapedToughnessDominated_smoke_01 + pennyShapedViscosityDominated_smoke_01 + pknViscosityDominated_smoke_01 + ======================= + Overall status: PASSED + ======================= + + +The log will provide instructions on where to download the test results and a baseline ID that can be assigned in the *.integrated_tests.yaml* file. + + + +. code-block:: sh + + Download the bundle at https://storage.googleapis.com/geosx/integratedTests/baseline_integratedTests-pr3044-4400-e6359ca.tar.gz + New baseline ID: baseline_integratedTests-pr3044-4400-e6359ca + .. note:: - Baseline files are stored using the git LFS (large file storage) plugin. - If you followed the suggested commands in the quickstart guide, then your environment is likely already setup. + Integrated tests within GEOS CI pipeline are run on a shared machine, and may take up to 30 minutes to complete. It may take some time for the tests to begin if the machine is in use by other developers. - However, if lfs is not yet activated, then the contents of baseline files may look something like this: - 0to100_restart_000000100/rank_0000003.hdf5 - version https://git-lfs.github.com/spec/v1 - oid sha256:09bbe1e92968852cb915b971af35b0bba519fae7cf5934f3abc7b709ea76308c - size 1761208 +Manual Test Runs +--------------------------------- - If this is the case, try running the following commands: ``git lfs install`` and ``git lfs pull``. +Before running the integrated tests manually, we recommend that you define the following variables in your machine's host configuration file: +* `ATS_WORKING_DIR` : The location where tests should be run (default=*GEOS/[build-dir]/integratedTests/workingDir*) +* `ATS_BASELINE_DIR` : The location where test baselines should be stored (default=*GEOS/integratedTests*) +.. note:: + The `ATS_WORKING_DIR` should be located on a file system that is amenable to parallel file IO. -How to Run the Tests -================================= -In most cases, integrated tests processes can be triggered in the GEOS build directory with the following commands: +After building GEOS, the integrated tests can be triggered in the GEOS build directory with the following commands: * `make ats_environment` : Setup the testing environment (Note: this step is run by default for the other make targets). This process will install packages required for testing into the python environment defined in your current host config file. Depending on how you have built GEOS, you may be prompted to manually run the `make pygeosx` command and then re-run this step. * `make ats_run` : Run all of the available tests (see the below note on testing resources). @@ -66,7 +121,7 @@ In most cases, integrated tests processes can be triggered in the GEOS build dir .. note:: - The `make_ats_environment` step will attempt to collect python packages github and pypi, so it should be run from a machine with internet access. + The `make ats_environment` and `make ats_run` steps may require internet access to collect python packages and baseline files. .. note:: @@ -84,8 +139,10 @@ In most cases, integrated tests processes can be triggered in the GEOS build dir When running test or creating new baselines on LC systems, we recommend that you use the *quartz-gcc-12-release* configuration +.. _overrideTestBehavior: + Override Test Behavior -------------------------- +---------------------- For cases where you need additional control over the integrated tests behavior, you can use this script in your build directory: */path/to/GEOS/build-xyz/integratedTests/geos_ats.sh*. To run the tests, simply call this script with any desired arguments (see the output of `geos_ats.sh --help` for additional details.) @@ -176,7 +233,7 @@ Otherwise, you will need to track down and potentially fix the issue that trigge Test Output -------------------------------- -Output files from the tests will be stored in the TestResults directory (*/path/to/GEOS/build-xyz/integratedTests/TestsResults*) or in a subdirectory next to their corresponding *.xml* file (*integratedTests/tests/allTests/testGroup/testName_xx*). +Output files from the tests will be stored in the specified working directory (linked here: */path/to/GEOS/build-xyz/integratedTests/TestsResults*). Using the serial beam bending test as an example, key output files include: * *beamBending_01.data* : Contains the standard output for all test steps. @@ -395,10 +452,10 @@ They use a Python 3.x syntax, and have a set of ATS-related methods loaded into The root configuration file (*integratedTests/tests/allTests/main.ats*) finds and includes any test definitions in its subdirectories. The remaining configuration files typically add one or more tests with varying partitioning and input xml files to ATS. -The *integratedTests/tests/allTests/sedov/sedov.ats* file shows how to add three groups of tests. +The *inputFiles/solidMechanics/sedov.ats* file shows how to add three groups of tests. This file begins by defining a set of common parameters, which are used later: -.. literalinclude:: ../../../../../integratedTests/tests/allTests/sedov/sedov.ats +.. literalinclude:: ../../../../../inputFiles/solidMechanics/sedov.ats :language: python :start-after: # Integrated Test Docs Begin Parameters :end-before: # Integrated Test Docs End Parameters @@ -406,216 +463,65 @@ This file begins by defining a set of common parameters, which are used later: It then enters over the requested partitioning schemes: -.. literalinclude:: ../../../../../integratedTests/tests/allTests/sedov/sedov.ats +.. literalinclude:: ../../../../../inputFiles/solidMechanics/sedov.ats :language: python :start-after: # Integrated Test Docs Begin Test Loop :end-before: # Integrated Test Docs End Test Loop -and registers a unique test case with the `TestCase` method, which accepts the following arguments: - -* name : The name of the test. The expected convention for this variable is 'testName_N' (N = number of ranks) or 'testName_X_Y_Z' (X, Y, and Z ranks per dimension) -* desc : A brief description of the test -* label : The test label (typically 'auto') -* owner : The point(s) of contact for the test -* independent : A flag indicating whether the test is dependent on another test (typically True) -* steps: A tuple containing the test steps (minimum length = 1) - +and registers a unique test case with the `TestDeck` method, which accepts the following arguments: -Test steps are run sequentially, and are created with the `geos` method. -If a given test step fails, then it will produce an error and any subsequent steps will be canceled. -This method accepts the following keyword arguments: +* name : The name of the test +* description : A brief description of the test +* partitions : A list of partition schemes to be tested +* restart_step : The cycle number where GEOS should test its restart capability +* check_step : The cycle number where GEOS should evaluate output files +* restartcheck_params : Parameters to forward to the restart check (tolerance, etc.) +* curvecheck_params: Parameters to forward to the curve check (tolerance, etc.) -* deck : The name of the input xml file. -* np : The number of parallel processes required to run the step. -* ngpu : The number of GPU devices required to run the step. Note: this argument is typically ignored for geos builds/machines that are not configured to use GPU's. In addition, we typically expect that np=ngpu. -* x_partitions : The number of partitions to use along the x-dimension -* y_partitions : The number of partitions to use along the y-dimension -* z_partitions : The number of partitions to use along the z-dimension -* name : The header to use for output file names -* restartcheck_params : (optional) If this value is defined, run a restart check with these parameters (specified as a dictionary). -* curvecheck_params : (optional) If this value is defined, run a curve check with these parameters (specified as a dictionary). -* restart_file : (optional) The name of a restart file to resume from. To use this option, there must be a previous step that produces the selected restart file. -* baseline_pattern : (optional) The regex for the baseline files to use (required if the name of the step differs from the baseline) -* allow_rebaseline : A flag that indicates whether this step can be rebaselined. This is typically only true for the first step in a test case. - -Note that a given *.ats* file can create any number of tests and link to any number of input xml files. -For any given test step, we expect that at least one restart or curve check be defined. +.. note:: + An *.ats* file can create any number of tests and link to any number of input xml files. + For any given test step, we expect that at least one restart or curve check be defined. Creating a New Test Directory ------------------------------- -To add a new set of tests, create a new folder in the `integratedTests/tests/allTests*` directory. +To add a new set of tests, create a new folder under the `GEOS/inputFiles` directory. This folder needs to include at least one *.ats* file to be included in the integrated tests. Using the sedov example, after creating *sedov.ats* the directory should look like .. code-block:: sh - - integratedTests/tests/allTests/sedov/ - - sedov.ats - - sedov.xml (this file should be a symbolic link to a GEOS input file located somewhere within */path/to/GEOS/inputFiles*) - -At this point you should run the integrated tests (in the build directory run: `make ats_run`). -Assuming that the new *geos* step for your test case was successful, the subsequent *restartcheck* step will fail because the baselines have not yet been created. -At this point the directory should look like this: - -.. code-block:: sh - - - integratedTests/tests/allTests/sedov/ - - sedov/ - - ... - - ... + - inputFiles/solidMechanics - sedov.ats - sedov.xml - - ... -You can then follow the steps in the next section to record the initial baseline files. +These changes will be reflected in the new baselines after triggering the manual rebaseline step. .. _rebaselining-tests: Rebaselining Tests ----------------------------- +===================== Occasionally you may need to add or update baseline files in the repository (possibly due to feature changes in the code). This process is called rebaselining. We suggest the following workflow: -Step 1 -^^^^^^^^^ - -In the GEOS repository, create or checkout a branch with your modifications: - -.. code-block:: sh - - cd /path/to/GEOS - git checkout -b user/feature/newFeature - - -Add your changes, confirm that they produce the expected results, and get approval for a pull request. -If your branch needs to be rebaselined, make sure to indicate this in your pull request with the appropriate Label. - - -Step 2 -^^^^^^^^^ - -Go to the integratedTests submodule, checkout and pull develop, and create a branch with the same name as the one in the main GEOS repository: - -.. code-block:: sh - - cd /path/to/GEOS/integratedTests - git checkout develop - git pull - git checkout -b user/feature/newFeature - - -Step 3 -^^^^^^^^^ - -Go back to your GEOS build directory and run the integrated tests: - -.. code-block:: sh - - # Note: on shared machines, run these commands in an allocation - cd /path/to/GEOS/build-dir/ - make ats_run - - -Inspect the test results that fail and determine which need to be **legitimately** rebaselined. -Arbitrarily changing baselines defeats the purpose of the integrated tests. -In your PR discussion, please identify which tests will change and any unusual behavior. - - -Step 4 -^^^^^^^^^ - -We can then rebaseline the tests. -In most cases, you will want to rebaseline all of the tests marked as **FAILED**. -To do this you can run this command in the build directory: - -.. code-block:: sh - - make ats_rebaseline_failed - - -Otherwise, you can run the following command, and select whether tests should be rebaselined one at a time via a ``[y/n]`` prompt. - -.. code-block:: sh - - make ats_rebaseline_failed - - -Make sure to only answer ``y`` to the tests that you actually want to rebaseline, otherwise correct baselines for already passing tests will still be updated and bloat your pull request and repository size. - - -Step 5 -^^^^^^^^^ - -Confirm that the new baselines are working as expected. -You can do this by cleaning the test directories and re-running the tests: - -.. code-block:: sh - - # Note: on shared machines, run these commands in an allocation - cd /path/to/GEOS/build-dir/ - make ats_clean - make ats_run - - -At this point you should pass all the integratedTests. - - -Step 6 -^^^^^^^^^ - -Clean out unnecessary files and add new ones to the branch: - -.. code-block:: sh - - cd /path/to/GEOS/build-dir/ - make ats_clean - - # Check for new or modified files - cd /path/to/GEOS/integratedTests - git status - - # Add new or modified files - git add file_a file_b ... - git commit -m "Updating baselines" - git push origin user/feature/newFeature - - -Step 6 -^^^^^^^^^ - -If you haven't already done so, create a merge request for your integratedTests branch. -Once you have received approval for your PR and are ready to continue, you can click merge the branch by clicking the button on github. - -You should then checkout the develop branch of integratedTests and pull the new changes. - -.. code-block:: sh - - cd /path/to/GEOS/integratedTests - git checkout develop - git pull - - -You then need to update the integratedTests 'hash' in your associated GEOS branch. - -.. code-block:: sh - - cd /path/to/GEOS/ - git add integratedTests - git commit -m "Updating the integratedTests hash" - git push origin user/feature/newFeature - +#. Open a pull request for your branch on github and select the **ci: run integrated tests** label +#. Wait for the tests to finish +#. Download and unpack the new baselines from the link provided at the bottom of the test logs +#. Inspect the test results using the *test_results.html* file +#. Verify that the changes in the baseline files are desired +#. Update the baseline ID in the *GEOS/.integrated_tests.yaml* file +#. Add a justification for the baseline changes to the *GEOS/BASELINE_NOTES.md* file +#. Commit your changes and push the code +#. Wait for the CI tests to re-run and verify that the integrated tests step passed -At this point, you will need to wait for the CI/CD tests to run on github. -After they succeed, you can merge your branch into develop using the button on github. @@ -628,4 +534,4 @@ We highly recommend running tests and rebaselining on an MPI-aware platform. **Filtering Checks**: A common reason for rebaselining is that you have changed the name of an XML node in the input files. While the baselines may be numerically identical, the restarts will fail because they contain different node names. -In this situation, it can be useful to add a filter to the restart check script using the *geos_ats.sh* script (see the `-e` and `-m` options in :ref:`Override Test Behavior` ) +In this situation, it can be useful to add a filter to the restart check script using the *geos_ats.sh* script (see the `-e` and `-m` options in :ref:`overrideTestBehavior` ) diff --git a/src/docs/sphinx/developerGuide/Contributing/Sphinx.rst b/src/docs/sphinx/developerGuide/Contributing/Sphinx.rst index 6eab163dc43..c08d0890e76 100644 --- a/src/docs/sphinx/developerGuide/Contributing/Sphinx.rst +++ b/src/docs/sphinx/developerGuide/Contributing/Sphinx.rst @@ -5,24 +5,26 @@ Sphinx Documentation Generating the documentation ==================================== -- To generate the documentation files, you will need to install Sphinx using +- To generate the documentation files, you will need to install Sphinx using: .. code-block:: sh - sudo apt install python-sphinx + pip -m install sphinx + pip -m install sphinx-design sphinx-argparse sphinxcontrib-plantuml sphinxcontrib.programoutput sphinx_rtd_theme + pip -m install scipy - Then you can generate the documentation files with the following command +- Then you can generate the documentation files with the following commands: - .. code-block:: sh + .. code-block:: sh - cd GEOS/build-your-platform-release - make geosx_docs + cd /path/to/GEOS/build-your-platform-release + make geosx_docs - That will create a new folder .. code-block:: sh - GEOS/build-your-platform-release/html/docs/sphinx + /path/to/GEOS/build-your-platform-release/html/docs/sphinx which contains all the html files generated. @@ -35,3 +37,21 @@ like those describing a specific class, can instead be found in ``docs`` subdire in the folder containing the source code. Information about how to write ``rst`` files can be found `here `_ . + +Fixing errors the documentation +=============================== +As part of the Continuous Integration process, the documentation is built on readthedocs, and any warnings or errors result in a failure test failure. +What follows is a brief guide on how to fix the most common errors. + +#. Navigate to the readthedocs build logs. This can be done by clicking on the failed test in the github test summary. + +.. image:: githubtestsummary.png + :width: 600 + +#. Download the logs from the failed test on readthedocs through the "view raw" button. + +.. image:: readthedocsbuildsummary.png + :width: 600 + +#. Perform a case sensitive search for "WARNING:" or "ERROR" to locate the sphinx issues. +Note that there will be numerous doxygen warnings that should be ignored. \ No newline at end of file diff --git a/src/docs/sphinx/developerGuide/Contributing/UnitTests.rst b/src/docs/sphinx/developerGuide/Contributing/UnitTests.rst index 4d8c48baf17..45712596faa 100644 --- a/src/docs/sphinx/developerGuide/Contributing/UnitTests.rst +++ b/src/docs/sphinx/developerGuide/Contributing/UnitTests.rst @@ -11,12 +11,12 @@ GEOS Specific Recommendations An informative example is ``testSinglePhaseBaseKernels`` which tests the single phase flow mobility and accumulation kernels on a variety of inputs. -.. literalinclude:: ../../../../coreComponents/unitTests/fluidFlowTests/testSinglePhaseBaseKernels.cpp +.. literalinclude:: ../../../../coreComponents/unitTests/fluidFlowTests/testSinglePhaseMobilityKernel.cpp :language: c++ :start-after: // Sphinx start after test mobility :end-before: // Sphinx end before test mobility -*[Source: coreComponents/physicsSolvers/fluidFlow/unitTests/testSinglePhaseBaseKernels.cpp]* +*[Source: coreComponents/physicsSolvers/fluidFlow/unitTests/testSinglePhaseMobilityKernel.cpp]* What makes this such a good test is that it depends on very little other than kernels themselves. There is no need to involve the data repository or parse an XML file. Sometimes however this is not possible, or at least not without a significant duplication of code. In this case it is better to embed the XML file into the test source as a string instead of creating a separate XML file and passing it to the test as a command line argument or hard coding the path. One example of this is ``testLaplaceFEM`` which tests the laplacian solver. The embedded XML is shown below. diff --git a/src/docs/sphinx/developerGuide/Contributing/UsingDocker.rst b/src/docs/sphinx/developerGuide/Contributing/UsingDocker.rst index 46bbf885b50..5600e7fef3f 100644 --- a/src/docs/sphinx/developerGuide/Contributing/UsingDocker.rst +++ b/src/docs/sphinx/developerGuide/Contributing/UsingDocker.rst @@ -1,6 +1,6 @@ .. _UsingDocker: -[Unsupported] Developing inside Docker with precompiled TPL binaries +[Best effort] Developing inside Docker with precompiled TPL binaries ==================================================================== For development purposes, you may want to use the publicly available docker images instead of compiling them yourself. diff --git a/src/docs/sphinx/developerGuide/Contributing/WorkInteractivelyOnCI.rst b/src/docs/sphinx/developerGuide/Contributing/WorkInteractivelyOnCI.rst new file mode 100644 index 00000000000..64f2e92a07e --- /dev/null +++ b/src/docs/sphinx/developerGuide/Contributing/WorkInteractivelyOnCI.rst @@ -0,0 +1,105 @@ + +.. _WorkingInteractivelyOnCI: + +******************************************** +How to work interactively on the CI Machines +******************************************** + +When developing with GEOS, developers may sometimes face compilation errors or test failures that only manifest in specific Continuous Integration (CI) builds. +To effectively troubleshoot these issues, it's advisable to debug directly in the target environment. The preferred method involves using Docker to locally replicate the problematic image. +However, for those without Docker access on their machines, (or for cases inherently related to the CI configuration), an alternative is to establish a connection to the CI machines. Here are the steps to do so: + +Step 1: Adding a GHA to establish a connection +============================================== + +First, as much as you can, try to reduce the number of jobs you're triggering by commenting out the configurations you do not require for your debugging. +Then in your branch, add the following GHA step to the `.github/build_and_test.yml` (see full documentation of the action `here _`). + +.. code-block:: console + + - name: ssh + uses: lhotari/action-upterm@v1 + with: + ## limits ssh access and adds the ssh public key for the user which triggered the workflow + limit-access-to-actor: true + ## limits ssh access and adds the ssh public keys of the listed GitHub users + limit-access-to-users: GitHubLogin + +The action should be added after whichever step triggers an error. In case of a build failure it is best to add the action after the `build, test and deploy` step. +It is also important to prevent the job to exit upon failure. For instance, it is suggested to comment the following lines in the `build, test and deploy` step. + +.. code-block:: console + + set -e + +.. code-block:: console + + exit ${EXIT_STATUS} + + +You can now commit the changes and push them to your remote branch. + +Step 2: Inspect the CI and grab server address +============================================== + +.. code-block:: console + + Run lhotari/action-upterm@v1 + upterm + + Auto-generating ~/.ssh/known_hosts by attempting connection to uptermd.upterm.dev + Pseudo-terminal will not be allocated because stdin is not a terminal. + + Warning: Permanently added 'uptermd.upterm.dev' (ED25519) to the list of known hosts. + + runner@uptermd.upterm.dev: Permission denied (publickey). + + Adding actor "GitHubLogin" to allowed users. + Fetching SSH keys registered with GitHub profiles: GitHubLogin + Fetched 2 ssh public keys + Creating a new session. Connecting to upterm server ssh://uptermd.upterm.dev:22 + Created new session successfully + Entering main loop + === Q16OBOFBLODJVA3TRXPL + Command: tmux new -s upterm -x 132 -y 43 + Force Command: tmux attach -t upterm + + Host: ssh://uptermd.upterm.dev:22 + SSH Session: ssh Q16oBofblOdjVa3TrXPl:ZTc4NGUxMWRiMjI5MDgudm0udXB0ZXJtLmludGVybmFsOjIyMjI=@uptermd.upterm.dev + + +Step 3: Connect to the machine via ssh +====================================== + +You can now open a terminal in your own machine and sshe to the upterm server, e.g., + + +.. code-block:: console + + ssh Q16oBofblOdjVa3TrXPl:ZTc4NGUxMWRiMjI5MDgudm0udXB0ZXJtLmludGVybmFsOjIyMjI=@uptermd.upterm.dev + + +Step 4: Run the docker container interactively +============================================== +Once you are connected to the machine it is convenient to follow these steps to interactively run the docker container: + +.. code-block:: console + + docker ps -a + + +The id of the existing docker container will be displayed and you can use it to commit the container. + +.. code-block:: console + + docker commit debug_image + +and then run it interactively, e.g. + +.. code-block:: console + + docker run -it --volume=/home/runner/work/GEOS/GEOS:/tmp/geos -e ENABLE_HYPRE=ON -e ENABLE_HYPRE_DEVICE=CUDA -e ENABLE_TRILINOS=OFF --cap-add=SYS_PTRACE --entrypoint /bin/bash debug_image + +Step 5: Cancel the workflow +============================================== +Once you are done, do not forget to cancel the workflow! \ No newline at end of file diff --git a/src/docs/sphinx/developerGuide/Contributing/githubtestsummary.png b/src/docs/sphinx/developerGuide/Contributing/githubtestsummary.png new file mode 100644 index 00000000000..87d77dd9a22 Binary files /dev/null and b/src/docs/sphinx/developerGuide/Contributing/githubtestsummary.png differ diff --git a/src/docs/sphinx/developerGuide/Contributing/index_contributing.rst b/src/docs/sphinx/developerGuide/Contributing/index_contributing.rst index b1649780e84..dbc125fa326 100644 --- a/src/docs/sphinx/developerGuide/Contributing/index_contributing.rst +++ b/src/docs/sphinx/developerGuide/Contributing/index_contributing.rst @@ -1,3 +1,5 @@ +.. _Contributing: + ############################################################################### Contributing ############################################################################### @@ -26,3 +28,5 @@ Contributing UsingDocker.rst InstallWin.rst + + WorkInteractivelyOnCI.rst diff --git a/src/docs/sphinx/developerGuide/Contributing/integrated_test_location_pr_a.png b/src/docs/sphinx/developerGuide/Contributing/integrated_test_location_pr_a.png new file mode 100644 index 00000000000..410939056bd Binary files /dev/null and b/src/docs/sphinx/developerGuide/Contributing/integrated_test_location_pr_a.png differ diff --git a/src/docs/sphinx/developerGuide/Contributing/integrated_test_location_pr_b.png b/src/docs/sphinx/developerGuide/Contributing/integrated_test_location_pr_b.png new file mode 100644 index 00000000000..2d676c12017 Binary files /dev/null and b/src/docs/sphinx/developerGuide/Contributing/integrated_test_location_pr_b.png differ diff --git a/src/docs/sphinx/developerGuide/Contributing/readthedocsbuildsummary.png b/src/docs/sphinx/developerGuide/Contributing/readthedocsbuildsummary.png new file mode 100644 index 00000000000..fc6a42e6a0c Binary files /dev/null and b/src/docs/sphinx/developerGuide/Contributing/readthedocsbuildsummary.png differ diff --git a/src/docs/sphinx/developerGuide/Index.rst b/src/docs/sphinx/developerGuide/Index.rst index 7e06c68461d..9ecf43b846d 100644 --- a/src/docs/sphinx/developerGuide/Index.rst +++ b/src/docs/sphinx/developerGuide/Index.rst @@ -2,7 +2,10 @@ Developer Guide ############################################################################### -Welcome to the GEOS developer guide. +Welcome to the GEOS developer guide. +This guide serves as a reference for developers contributing to the GEOS project. +The :ref:`Contributing` section provides general details and guidelines for contributing to the GEOS project. +The :ref:`KeyComponents` section provides an overview of the some basic components that of the GEOS project. .. toctree:: :maxdepth: 3 diff --git a/src/docs/sphinx/developerGuide/KeyComponents/AddingNewSolver.rst b/src/docs/sphinx/developerGuide/KeyComponents/AddingNewSolver.rst index d8cb998df21..f7db38efaca 100644 --- a/src/docs/sphinx/developerGuide/KeyComponents/AddingNewSolver.rst +++ b/src/docs/sphinx/developerGuide/KeyComponents/AddingNewSolver.rst @@ -33,7 +33,7 @@ Declaration file (reference) The included header is ``physicsSolvers/simplePDE/LaplaceBaseH1.hpp`` which declares the base class ``LaplaceBaseH1``, shared by all Laplace solvers. Moreover, ``physicsSolver/simplePDE/LaplaceBaseH1.hpp`` includes the following headers: - ``common/EnumStrings.hpp`` which includes facilities for enum-string conversion (useful for reading enum values from input); - - ``physicsSolver/SolverBase.hpp`` which declares the abstraction class shared by all physics solvers. + - ``physicsSolver/PhysicsSolverBase.hpp`` which declares the abstraction class shared by all physics solvers. - ``managers/FieldSpecification/FieldSpecificationManager.hpp`` which declares a manager used to access and to set field on the discretized domain. Let us jump forward to the class enum and variable as they contain the data used @@ -114,12 +114,12 @@ Furthermore, the following functions are inherited from the base class. Eventually, ``applyDirichletBCImplicit()`` is the working specialized member functions called when ``applyBoundaryConditions()`` is called in this particular class override. -Browsing the base class ``SolverBase``, it can be noted that most of the solver interface functions are called during -either ``SolverBase::linearImplicitStep()`` or ``SolverBase::nonlinearImplicitStep()`` depending on the solver strategy chosen. +Browsing the base class ``PhysicsSolverBase``, it can be noted that most of the solver interface functions are called during +either ``PhysicsSolverBase::linearImplicitStep()`` or ``PhysicsSolverBase::nonlinearImplicitStep()`` depending on the solver strategy chosen. -Switching to protected members, ``postProcessInput()`` is a central member function and +Switching to protected members, ``postInputInitialization()`` is a central member function and will be called by ``Group`` object after input is read from XML entry file. -It will set and dispatch solver variables from the base class ``SolverBase`` to the most derived class. +It will set and dispatch solver variables from the base class ``PhysicsSolverBase`` to the most derived class. For ``LaplaceFEM``, it will allow us to set the right time integration scheme based on the XML value as will be further explored in the next :ref:`Implementation` section. @@ -202,7 +202,7 @@ to writing our new *LaplaceDiffFEM* solver. .. note:: - We might want to remove final keyword from ``postProcessInput()`` as it will prevent you from overriding it. + We might want to remove final keyword from ``postInputInitialization()`` as it will prevent you from overriding it. Start doing your own Physic solver ================================== @@ -249,7 +249,7 @@ commented afterwards. } laplaceDiffFEMViewKeys; protected: - virtual void postProcessInput() override final; + virtual void postInputInitialization() override final; private: real64 m_diffusion; @@ -268,7 +268,7 @@ Then as mentioned in :ref:`Implementation`, the diffusion coefficient is used wh we will have to override the ``assembleSystem()`` function as detailed below. Moreover, if we want to introduce a new binding between the input XML and the code we will have to work on the three -``struct viewKeyStruct`` , ``postProcessInput()`` and the constructor. +``struct viewKeyStruct`` , ``postInputInitialization()`` and the constructor. Our new solver ``viewKeyStruct`` will have its own structure inheriting from the *LaplaceFEM* one to have the ``timeIntegrationOption`` and ``fieldName`` field. It will also create a ``diffusionCoeff`` field to be bound to the user defined homogeneous coefficient on one hand @@ -293,13 +293,13 @@ an "input uniform diffusion coefficient for the Laplace equation". setDescription("input uniform diffusion coeff for the laplace equation"); } -Another important spot for binding the value of the XML read parameter to our ``m_diffusion`` is in ``postProcessInput()``. +Another important spot for binding the value of the XML read parameter to our ``m_diffusion`` is in ``postInputInitialization()``. .. code-block:: c++ - void LaplaceDiffFEM::postProcessInput() + void LaplaceDiffFEM::postInputInitialization() { - LaplaceFEM::postProcessInput(); + LaplaceFEM::postInputInitialization(); string sDiffCoeff = this->getReference(laplaceDiffFEMViewKeys.diffusionCoeff); this->m_diffusion = std::stof(sDiffCoeff); @@ -359,6 +359,6 @@ After assembling both declarations and implementations for our new solver, the f - add declarations to parent CMakeLists.txt (here add to ``physicsSolvers_headers`` ); - add implementations to parent CMakeLists.txt (here add to ``physicsSolvers_sources``); - check that Doxygen comments are properly set in our solver class; - - uncrustify it to match the code style; + - uncrustify it to match the code style by going to the build folder and running the command: make uncrustify_style; - write unit tests for each new features in the solver class; - write an integratedTests for the solver class. diff --git a/src/docs/sphinx/developerGuide/KeyComponents/WorkingWithData.rst b/src/docs/sphinx/developerGuide/KeyComponents/WorkingWithData.rst index fc629b83af9..3a2023dd733 100644 --- a/src/docs/sphinx/developerGuide/KeyComponents/WorkingWithData.rst +++ b/src/docs/sphinx/developerGuide/KeyComponents/WorkingWithData.rst @@ -81,7 +81,7 @@ We will use the example of registering a ``totalDisplacement`` on the ``NodeMana from the ``SolidMechanics`` solver. The most general approach is to define a string key and call one of the `Group::registerWrapper() <../../../doxygen_output/html/classgeos_1_1data_repository_1_1_group.html#a741c3b5728fc47b33fbaad6c4f124991>`_ -functions from ``SolverBase::registerDataOnMesh()``. +functions from ``PhysicsSolverBase::registerDataOnMesh()``. Then when you want to use the data, you can call ``Group::getReference()``. For example this would look something like: diff --git a/src/docs/sphinx/developerGuide/KeyComponents/XML.rst b/src/docs/sphinx/developerGuide/KeyComponents/XML.rst index 442dd65da46..ddbd3cd1b69 100644 --- a/src/docs/sphinx/developerGuide/KeyComponents/XML.rst +++ b/src/docs/sphinx/developerGuide/KeyComponents/XML.rst @@ -66,7 +66,7 @@ You can have several objects of the same class and hence the same ``catalogName` **How can I add my new externally-accessible class to the ObjectCatalog?** -Let us consider a flow solver class derived from ``FlowSolverBase``, that itself is derived from ``SolverBase``. +Let us consider a flow solver class derived from ``FlowSolverBase``, that itself is derived from ``PhysicsSolverBase``. To instantiate and use this solver, the developer needs to make the derived flow solver class reachable from the XML file, via an XML tag. Internally, this requires adding the derived class information to ``ObjectCatalog``, which is achieved with two main ingredients: 1) a ``CatalogName()`` method in the class that lets GEOS know *what* to search for in the internal ``ObjectCatalog`` to instantiate an object of this class, 2) a macro that specifies *where* to search in the ``ObjectCatalog``. @@ -89,7 +89,7 @@ Internally, this requires adding the derived class information to ``ObjectCatalo 2. To let GEOS know where to search in the ``ObjectCatalog``, a macro needs to be added at the end of the .cpp file implementing the class. - This macro (illustrated below) must contain the type of the base class (in this case, ``SolverBase``), and the name of the derived class (continuing with the example used above, this is ``CompositionalMultiphaseFlow``). + This macro (illustrated below) must contain the type of the base class (in this case, ``PhysicsSolverBase``), and the name of the derived class (continuing with the example used above, this is ``CompositionalMultiphaseFlow``). As a result of this construct, the ``ObjectCatalog`` is not a flat list of ``string`` s mapping the C++ classes. Instead, the ``ObjectCatalog`` forms a tree that reproduces locally the structure of the class diagram, from the base class to the derived classes. @@ -196,7 +196,7 @@ To do this, the method ``CreateChild`` of the ``PhysicsSolverManager`` class is // -------------------------------- // childKey = "XmlNameOfMySolver" (string) // childName = "nameOfThisSolverInstance" (string) - // SolverBase::CatalogInterface = the Catalog attached to the base Solver class + // PhysicsSolverBase::CatalogInterface = the Catalog attached to the base Solver class // hasKeyName = bool method to test if the childKey string is present in the Catalog // registerGroup = method to create a new instance of the solver and add it to the group tree @@ -207,11 +207,11 @@ To do this, the method ``CreateChild`` of the ``PhysicsSolverManager`` class is *[Source: src/coreComponents/physicsSolvers/PhysicsSolverManager.cpp]* -In the code listing above, we see that in the ``PhysicsSolverManager`` class, the ``ObjectCatalog`` is searched to find the ``catalogName`` "CompositionalMultiphaseFlow" in the scope of the ``SolverBase`` class. -Then, the factory function of the base class ``SolverBase`` is called. +In the code listing above, we see that in the ``PhysicsSolverManager`` class, the ``ObjectCatalog`` is searched to find the ``catalogName`` "CompositionalMultiphaseFlow" in the scope of the ``PhysicsSolverBase`` class. +Then, the factory function of the base class ``PhysicsSolverBase`` is called. The ``catalogName`` (stored in ``childKey``) is passed as an argument of the factory function to ensure that it instantiates an object of the desired derived class. -As explained above, this is working because 1) the XML tag matches the ``catalogName`` of the ``CompositionalMultiphaseFlow`` class and 2) a macro is placed at the end of the .cpp file implementing the ``CompositionalMultiphaseFlow`` class to let the ``ObjectCatalog`` know that ``CompositionalMultiphaseFlow`` is a derived class of ``SolverBase``. +As explained above, this is working because 1) the XML tag matches the ``catalogName`` of the ``CompositionalMultiphaseFlow`` class and 2) a macro is placed at the end of the .cpp file implementing the ``CompositionalMultiphaseFlow`` class to let the ``ObjectCatalog`` know that ``CompositionalMultiphaseFlow`` is a derived class of ``PhysicsSolverBase``. Note that several instances of the same type of solver can be created, as long as they each have a different name. diff --git a/src/docs/sphinx/developerGuide/KeyComponents/index_KeyComponents.rst b/src/docs/sphinx/developerGuide/KeyComponents/index_KeyComponents.rst index 6960fe15c24..68899719971 100644 --- a/src/docs/sphinx/developerGuide/KeyComponents/index_KeyComponents.rst +++ b/src/docs/sphinx/developerGuide/KeyComponents/index_KeyComponents.rst @@ -1,3 +1,5 @@ +.. _KeyComponents: + ############################################################################### Code Components ############################################################################### diff --git a/src/docs/sphinx/tutorials/step01/Tutorial.rst b/src/docs/sphinx/tutorials/step01/Tutorial.rst index 0e896f33fa3..8c9b5697689 100644 --- a/src/docs/sphinx/tutorials/step01/Tutorial.rst +++ b/src/docs/sphinx/tutorials/step01/Tutorial.rst @@ -91,6 +91,9 @@ in different regions of the domain at different moments of the simulation. In this first example, we use one type of solver in the entire domain and for the entire duration of the simulation. +The input file for this tutorial can be found in the repository at +`inputFiles/singlePhaseFlow/3D_10x10x10_compressible_smoke.xml `_, which also includes +`inputFiles/singlePhaseFlow/3D_10x10x10_compressible_base.xml `_. The solver we are specifying here is a single-phase flow solver. In GEOS, such a solver is created using a ``SinglePhaseFVM`` element. This type of solver is one among several cell-centered single-phase finite volume methods. @@ -134,7 +137,7 @@ In production runs, you may want to suppress most console output. For solvers of the ``SinglePhaseFVM`` family, one required attribute is a discretization scheme. Here, we use a Two-Point Flux Approximation (TPFA) finite volume discretization scheme called ``singlePhaseTPFA``. -To know the list of admissible values of an attribute, please see GEOS's XML schema. +To know the list of admissible values of an attribute, please see `GEOS's XML schema `_. This discretization type must know how to find permeability values that it uses internally to compute transmissibilities. The ``permeabilityNames`` attribute tells the solver the user-defined name (the *handle*) of the permeability values that will be defined elsewhere in the input file. @@ -199,7 +202,7 @@ Keeping things simple, our element collection has only one type of element: a `` A mesh can contain several geometrical types of elements. For numerical convenience, elements are aggregated by types into ``cellBlocks``. -Here, we only linear 8-node brick elements, so the entire domain is one object called ``cellBlock``. +Here, we only have linear 8-node brick elements, so the entire domain is one object called ``cellBlock``. **xCoords, yCoords, zCoords, nx, ny, nz** @@ -291,14 +294,11 @@ Now to use this scheme, we need to supply more details in the ``NumericalMethods :start-after: :end-before: -The ``fieldName`` attribute specifies which property will be used for flux computations, -and also specifies that for Dirichlet boundary conditions, the pressure value at the element face is used. -The ``coefficientName`` attribute is used for the stencil transmissibility computations. - Note that in GEOS, there is a difference between physics solvers and numerical methods. Their parameterizations are thus independent. We can have multiple solvers using the same numerical scheme but with different tolerances, for instance. +The available numerical methods and their options are listed in the GEOS XML schema documentation which may be found by using the search function in the documentation. .. _ElementRegions_tag_single_phase_internal_mesh: @@ -311,7 +311,9 @@ to regions of elements. Here, we use only one **CellElementRegion** to represent the entire domain (user name: ``mainRegion``). It contains all the blocks called ``cellBlock`` defined in the mesh section. We specify the materials contained in that region using a ``materialList``. -Several materials coexist in ``cellBlock``, and we list them using their user-defined names: ``water``, ``rockPorosity``, and ``rockPerm``, etc. What these names mean, and the physical properties that they are attached to are defined next. +Several materials coexist in ``cellBlock``, and we list them using their user-defined names: +``water`` and ``rock`` in this exemple. +Each material is a definition of physical properties. .. literalinclude:: ../../../../../inputFiles/singlePhaseFlow/3D_10x10x10_compressible_base.xml diff --git a/src/docs/sphinx/tutorials/step02/Tutorial.rst b/src/docs/sphinx/tutorials/step02/Tutorial.rst index c2d0998af32..2682d28d786 100644 --- a/src/docs/sphinx/tutorials/step02/Tutorial.rst +++ b/src/docs/sphinx/tutorials/step02/Tutorial.rst @@ -152,17 +152,16 @@ Here is the ``vtk`` file : .. literalinclude:: ../../../../../inputFiles/singlePhaseFlow/vtk/cube_10x10x10_hex.vtk :caption: cube_10x10x10_hex.vtk - :lines: 1-20 + :lines: 1-7 GEOS can run different physical solvers on different regions of the mesh at different times. Here, to keep things simple, we run one solver (single-phase flow) on the entire domain throughout the simulation. -Even this is trivial, we need to define and name a region encompassing the entire domain -and assign it to the single-phase flow solver. -We also need to provide material properties to the regions. -This is done by specifying ``ElementRegions``. -Here, the entire field is one region called ``Domain``, -and contains multiple constitutive models, including ``water``, ``rockPorosity``, and ``rockPerm``. +To do so, we need to define a region encompassing the entire domain. +We will name it ``Domain``, as refered to in the single-phase flow solver (in its ``targetRegions``), +and list its constitutive models in the ``materialList``, which are ``water`` and ``rock``. +Since we have imported a mesh with only one region, we can set ``cellBlocks`` to ``{ * }`` +(we have could also set ``cellBlocks`` to ``{ hexahedra }`` as the mesh has only hexahedral cells). .. literalinclude:: ../../../../../inputFiles/singlePhaseFlow/vtk/3D_10x10x10_compressible_hex_gravity_base.xml @@ -171,6 +170,11 @@ and contains multiple constitutive models, including ``water``, ``rockPorosity`` :end-before: +.. note:: + If you use a name that is not ``hexahedra`` or ``all`` for this attribute, or if the mesh is + changed and have not-hexahedral cells, GEOS will throw an error at the beginning of the + simulation. See :ref:`Meshes` for more information. + Running GEOS ---------------------------------------- @@ -326,7 +330,9 @@ And the ``vtk`` file starts as follows (notice the tetrahedral point coordinates :caption: cube_10x10x10_tet.vtk :lines: 1-20 -Again, the entire field is one region called ``Domain`` and contains ``water`` and ``rock`` only. +Again, the entire field is one region called ``Domain`` which contains ``water`` and ``rock``. +Since we have imported a mesh with only one region, we can again set ``cellBlocks`` to ``{ * }`` +(we have could also set ``cellBlocks`` to ``{ tetrahedra }`` as the mesh has only tetrahedric cells). .. literalinclude:: ../../../../../inputFiles/singlePhaseFlow/vtk/3D_10x10x10_compressible_tetra_gravity_base.xml :language: xml diff --git a/src/docs/sphinx/tutorials/step03/Tutorial.rst b/src/docs/sphinx/tutorials/step03/Tutorial.rst index e38b55222bd..c9aa49fce57 100644 --- a/src/docs/sphinx/tutorials/step03/Tutorial.rst +++ b/src/docs/sphinx/tutorials/step03/Tutorial.rst @@ -38,9 +38,9 @@ We consider the following mesh as a numerical support to the simulations in this This mesh contains three continuous regions: - - a Top region (overburden, elementary tag = `Overburden`) - - a Middle region (reservoir layer, elementary tag = `Reservoir`) - - a Bottom region (underburden, elementary tag = `Underburden`) + - a Bottom region (underburden, elementary tag = `Underburden`, attribute = ``1``) + - a Middle region (reservoir layer, elementary tag = `Reservoir`, attribute = ``2``) + - a Top region (overburden, elementary tag = `Overburden`, attribute = ``3``) .. image:: reservoir_transparent.png :width: 600px @@ -169,31 +169,17 @@ Regions Assuming that the overburden and the underburden are impermeable, and flow only takes place in the reservoir, we need to define regions. -There are two methods to achieve this regional solve. +We need to define all the ``CellElementRegions`` according to the ``attribute`` values of the VTK file +(which are respectively ``1``, ``2`` and ``3`` for each region). As mentioned above, the solvers is only +applied on the reservoir layer, (on region ``2``). In this case, the **ElementRegions** tag is : -- The first solution is to define a unique ``CellElementRegion`` corresponding to the reservoir. - - .. code-block:: xml - - - - - -- The second solution is to define all the ``CellElementRegions`` as they are in the VTK file, but defining the solvers only on the reservoir layer. In this case, the **ElementRegions** tag is : - - .. literalinclude:: ../../../../../inputFiles/singlePhaseFlow/FieldCaseTutorial3_base.xml - :language: xml - :start-after: - :end-before: - -We opt for the latest as it allows to visualize over- and underburdens and to change regions handling in their tag without needing to amend the **ElementRegion** tag. +.. literalinclude:: ../../../../../inputFiles/singlePhaseFlow/FieldCaseTutorial3_base.xml + :language: xml + :start-after: + :end-before: .. note:: - The material list here was set for a single-phase flow problem. This list is subject - to change if the problem is not a single-phase flow problem. + This material list here is subject to change if the problem is not a single-phase flow problem. .. _Constitutive_tag_field_case: @@ -214,7 +200,8 @@ The constitutive parameters such as the density, the viscosity, and the compress To consider an incompressible fluid, the user has to set the compressibility to 0. .. note:: - GEOS handles permeability as a diagonal matrix, so the three values of the permeability tensor are set individually using the ``component`` field. + Currently GEOS handles permeability as a diagonal matrix, so the three values of the permeability tensor are set individually using the ``component`` field. + The ability for a full tensor permeability is planned for future releases. .. _FieldSpecifications_tag_field_case: diff --git a/src/docs/sphinx/tutorials/step04/Tutorial.rst b/src/docs/sphinx/tutorials/step04/Tutorial.rst index d89f009817e..0be6a99f9dd 100644 --- a/src/docs/sphinx/tutorials/step04/Tutorial.rst +++ b/src/docs/sphinx/tutorials/step04/Tutorial.rst @@ -82,7 +82,7 @@ The computational domain is discretized by ``C3D8`` elements with the first orde functions at each direction in the parent domain. The 2 x 2 x 2 Gauss quadrature rule is adopted to be compatible with the first order interpolation functions. -.. literalinclude:: ../../../../../inputFiles/solidMechanics/beamBending_base.xml +.. literalinclude:: ../../../../../inputFiles/solidMechanics/beamBending_smoke.xml :language: xml :start-after: :end-before: diff --git a/src/docs/sphinx/userGuide/Index.rst b/src/docs/sphinx/userGuide/Index.rst index 1e7330a3f13..66a3c60cf52 100644 --- a/src/docs/sphinx/userGuide/Index.rst +++ b/src/docs/sphinx/userGuide/Index.rst @@ -17,6 +17,8 @@ Welcome to the GEOS user guide. /coreComponents/constitutive/docs/Constitutive + /coreComponents/constitutiveDrivers/docs/ConstitutiveDrivers + /coreComponents/fieldSpecification/docs/FieldSpecification /coreComponents/events/docs/EventManager @@ -25,6 +27,8 @@ Welcome to the GEOS user guide. /coreComponents/functions/docs/FunctionManager + /coreComponents/physicsSolvers/multiphysics/docs/Initialization.rst + /coreComponents/linearAlgebra/docs/LinearSolvers.rst /coreComponents/discretizationMethods/docs/NumericalMethodsManager diff --git a/src/externalComponents/CMakeLists.txt b/src/externalComponents/CMakeLists.txt index 8ac2e8281cd..cd4e91f1352 100644 --- a/src/externalComponents/CMakeLists.txt +++ b/src/externalComponents/CMakeLists.txt @@ -25,7 +25,7 @@ if( ${BUILD_SHARED_LIBS} ) set( externalComponentsLinkList ${externalComponentsList} ) else() foreach(component ${externalComponentsList}) - set( externalComponentsLinkList ${externalComponentsLinkList} ${GEOSX_LINK_PREPEND_FLAG} ${component} ${GEOSX_LINK_POSTPEND_FLAG} ) + set( externalComponentsLinkList ${externalComponentsLinkList} ${GEOS_LINK_PREPEND_FLAG} ${component} ${GEOS_LINK_POSTPEND_FLAG} ) endforeach() endif() diff --git a/src/externalComponents/newComponentTemplate/src/CMakeLists.txt b/src/externalComponents/newComponentTemplate/src/CMakeLists.txt index 2ee1663ec90..e79d970d05c 100644 --- a/src/externalComponents/newComponentTemplate/src/CMakeLists.txt +++ b/src/externalComponents/newComponentTemplate/src/CMakeLists.txt @@ -9,11 +9,7 @@ set( componentSources NewComponent.cpp ) unset( dependencyList ) # Specify dependencies -if ( GEOSX_BUILD_SHARED_LIBS ) - list( APPEND dependencyList geosx_core) -else() - list( APPEND dependencyList ${geosx_core_libs} ) -endif() +list( APPEND dependencyList geosx_core) message("adding newComponentTemplate library") @@ -21,6 +17,6 @@ blt_add_library( NAME newComponentTemplate SOURCES ${componentSources} HEADERS ${componentHeaders} DEPENDS_ON ${dependencyList} - OBJECT ${GEOSX_BUILD_OBJ_LIBS} ) + OBJECT ${GEOS_BUILD_OBJ_LIBS} ) target_include_directories( newComponentTemplate PUBLIC ${CMAKE_CURRENT_LIST_DIR} ) diff --git a/src/externalComponents/newComponentTemplate/src/NewComponent.cpp b/src/externalComponents/newComponentTemplate/src/NewComponent.cpp index 446e163ec6f..a09a49ce425 100644 --- a/src/externalComponents/newComponentTemplate/src/NewComponent.cpp +++ b/src/externalComponents/newComponentTemplate/src/NewComponent.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -23,7 +24,7 @@ namespace geos NewComponent::NewComponent( string const & name, Group * const parent ): - SolverBase(name,parent) + PhysicsSolverBase(name,parent) { } @@ -43,6 +44,6 @@ real64 NewComponent::solverStep( real64 const & /*time_n*/, return 0; } -REGISTER_CATALOG_ENTRY( SolverBase, NewComponent, string const &, dataRepository::Group * const ) +REGISTER_CATALOG_ENTRY( PhysicsSolverBase, NewComponent, string const &, dataRepository::Group * const ) } /* namespace geos */ diff --git a/src/externalComponents/newComponentTemplate/src/NewComponent.hpp b/src/externalComponents/newComponentTemplate/src/NewComponent.hpp index 3352899d2a4..9b8d0424f49 100644 --- a/src/externalComponents/newComponentTemplate/src/NewComponent.hpp +++ b/src/externalComponents/newComponentTemplate/src/NewComponent.hpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -18,7 +19,7 @@ #ifndef COMPONENTS_NEWCOMPONENTTEMPLATE_SRC_NEWCOMPONENT_HPP_ #define COMPONENTS_NEWCOMPONENTTEMPLATE_SRC_NEWCOMPONENT_HPP_ -#include "physicsSolvers/SolverBase.hpp" +#include "physicsSolvers/PhysicsSolverBase.hpp" namespace geos @@ -29,7 +30,7 @@ class Group; } class DomainPartition; -class NewComponent final : public SolverBase +class NewComponent final : public PhysicsSolverBase { public: NewComponent( string const & name, diff --git a/src/externalComponents/newComponentTemplate/tests/CMakeLists.txt b/src/externalComponents/newComponentTemplate/tests/CMakeLists.txt index 272d3f6a8a4..737c1fccebc 100644 --- a/src/externalComponents/newComponentTemplate/tests/CMakeLists.txt +++ b/src/externalComponents/newComponentTemplate/tests/CMakeLists.txt @@ -1,11 +1,7 @@ # Specify list of tests set( dependencyList gtest ) -if ( GEOSX_BUILD_SHARED_LIBS ) - list( APPEND dependencyList geosx_core ) -else() - list( APPEND dependencyList ${geosx_core_libs} ) -endif() +list( APPEND dependencyList geosx_core ) set( newComponentTests testNewComponent.cpp ) diff --git a/src/externalComponents/newComponentTemplate/tests/testNewComponent.cpp b/src/externalComponents/newComponentTemplate/tests/testNewComponent.cpp index 69911571f0a..444e3839226 100644 --- a/src/externalComponents/newComponentTemplate/tests/testNewComponent.cpp +++ b/src/externalComponents/newComponentTemplate/tests/testNewComponent.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. diff --git a/src/index.rst b/src/index.rst index 9dedc1f4d75..a912239cb52 100644 --- a/src/index.rst +++ b/src/index.rst @@ -126,6 +126,22 @@ you have suggestions for improving the guides below, please post an issue on our To the Python Tools Documentation + .. grid-item-card:: + + Feature Requests, Reporting Bugs, and Support + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + To make feature requests, report bugs, or get support (after reviewing the user guide) please submit an issue on Github. + + +++ + + .. button-link:: https://github.com/GEOS-DEV/GEOS/issues/new/choose + :expand: + :color: info + :click-parent: + + To the "New issue" page on the GEOS Github repository + ******************** Table of Contents @@ -150,7 +166,7 @@ Table of Contents docs/sphinx/buildGuide/Index - docs/sphinx/CompleteXMLSchema + docs/sphinx/datastructure/CompleteXMLSchema docs/sphinx/Contributors diff --git a/src/main/main.cpp b/src/main/main.cpp index 795228f32e3..4673f2e228a 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -2,10 +2,11 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. @@ -14,7 +15,7 @@ // Source includes #include "common/DataTypes.hpp" -#include "common/Format.hpp" +#include "common/format/Format.hpp" #include "common/TimingMacros.hpp" #include "common/Units.hpp" #include "mainInterface/initialization.hpp" @@ -70,12 +71,14 @@ int main( int argc, char *argv[] ) // A NotAnError is thrown if "-h" or "--help" option is used. catch( NotAnError const & ) { + basicCleanup(); return 0; } catch( std::exception const & e ) { GEOS_LOG( e.what() ); LvArray::system::callErrorHandler(); + basicCleanup(); std::abort(); } return 0; diff --git a/src/pygeosx/CMakeLists.txt b/src/pygeosx/CMakeLists.txt index 9f03409ef48..74cd9dc4ba7 100644 --- a/src/pygeosx/CMakeLists.txt +++ b/src/pygeosx/CMakeLists.txt @@ -3,7 +3,7 @@ set( python_headers pygeosx.hpp ) set( python_sources pygeosx.cpp ) -set( dependencyList ${extraComponentsLinkList} ${externalComponentsLinkList} Python3::Python ) +set( dependencyList ${extraComponentsLinkList} ${externalComponentsLinkList} mainInterface Python3::Python ) blt_add_library( NAME pygeosx SOURCES ${python_sources} @@ -26,6 +26,7 @@ add_custom_command( TARGET pygeosx COMMAND ln -sf ${CMAKE_BINARY_DIR}/lib/pylvarray.so ${CMAKE_BINARY_DIR}/lib/PYGEOSX/lib/python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}/site-packages/ ) target_include_directories( pygeosx PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) +target_include_directories( pygeosx PUBLIC ${CMAKE_BINARY_DIR}/include ) geosx_add_code_checks( PREFIX pygeosx ) diff --git a/src/pygeosx/pygeosx.cpp b/src/pygeosx/pygeosx.cpp index 3210a2365ea..3f3394307f3 100644 --- a/src/pygeosx/pygeosx.cpp +++ b/src/pygeosx/pygeosx.cpp @@ -2,17 +2,17 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ */ - // Python.h must be included first. #define PY_SSIZE_T_CLEAN #include diff --git a/src/pygeosx/pygeosx.hpp b/src/pygeosx/pygeosx.hpp index 26195ddf02f..087bbaa5529 100644 --- a/src/pygeosx/pygeosx.hpp +++ b/src/pygeosx/pygeosx.hpp @@ -2,11 +2,12 @@ * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * - * Copyright (c) 2018-2019 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2019 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2019 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All right reserved + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved * * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. * ------------------------------------------------------------------------------------------------------------ diff --git a/src/pygeosx/pygeosx_documentation.rst b/src/pygeosx/pygeosx_documentation.rst index 4c1e3c3e346..557999148ba 100644 --- a/src/pygeosx/pygeosx_documentation.rst +++ b/src/pygeosx/pygeosx_documentation.rst @@ -6,7 +6,7 @@ GEOS can be manipulated and executed through a Python script. High-level control of GEOS is managed through the top-level ``pygeosx`` functions, like ``initialize`` and ``run``. GEOS's data can be manipulated by getting -:ref:`pylvarray ` views of LvArray objects living in GEOS's data repository. +`pylvarray `_ views of LvArray objects living in GEOS's data repository. These ``pylvarray`` views are fetched by calling ``Wrapper.value()`` after getting a ``Wrapper`` out of the data repository. diff --git a/src/pygeosx/pyssle.xml b/src/pygeosx/pyssle.xml index 99361955283..82024bb7dc6 100644 --- a/src/pygeosx/pyssle.xml +++ b/src/pygeosx/pyssle.xml @@ -49,7 +49,7 @@ diff --git a/src/pygeosx/unitTests/dataRepositoryTests/pygeosx_only.xml b/src/pygeosx/unitTests/dataRepositoryTests/pygeosx_only.xml index 7625dfd3831..085db97cd7d 100644 --- a/src/pygeosx/unitTests/dataRepositoryTests/pygeosx_only.xml +++ b/src/pygeosx/unitTests/dataRepositoryTests/pygeosx_only.xml @@ -30,7 +30,7 @@